@absolutejs/absolute 0.20.0-beta.43 → 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/browser.js +378 -361
- package/dist/angular/browser.js.map +2 -2
- package/dist/angular/components/core/streamingSlotRegistrar.js +7 -7
- package/dist/angular/components/core/streamingSlotRegistry.js +4 -4
- package/dist/angular/index.js +300 -294
- package/dist/angular/index.js.map +2 -2
- package/dist/angular/server.js +54 -50
- package/dist/angular/server.js.map +2 -2
- package/dist/build.js +201 -204
- package/dist/build.js.map +3 -3
- package/dist/cli/config/client.js +12 -12
- package/dist/cli/config/server.js +1096 -1090
- package/dist/cli/index.js +1573 -1297
- package/dist/client/index.js +29 -25
- package/dist/client/index.js.map +2 -2
- package/dist/core/streamingSlotRegistrar.js +15 -13
- package/dist/core/streamingSlotRegistrar.js.map +2 -2
- package/dist/core/streamingSlotRegistry.js +11 -9
- package/dist/core/streamingSlotRegistry.js.map +2 -2
- package/dist/image-client/imageClient.js +7 -7
- package/dist/index.js +810 -733
- package/dist/index.js.map +7 -6
- package/dist/islands/browser.js +11 -9
- package/dist/islands/browser.js.map +2 -2
- package/dist/islands/index.js +39 -35
- package/dist/islands/index.js.map +2 -2
- package/dist/mobile/browser.js +23 -22
- package/dist/mobile/browser.js.map +3 -3
- package/dist/mobile/index.js +739 -426
- package/dist/mobile/index.js.map +11 -11
- package/dist/mobile/remoteMacAgentEntry.js +227 -37
- package/dist/mobile/shellBootstrap.js +0 -1
- package/dist/mobile/shellExpoAuth.js +184 -0
- package/dist/mobile/shellExpoDevices.js +4 -5
- package/dist/mobile/shellExpoSync.js +104 -0
- package/dist/mobile/shellSync.js +4 -4
- package/dist/react/browser.js +17 -15
- package/dist/react/browser.js.map +2 -2
- package/dist/react/components/browser/index.js +107 -107
- package/dist/react/components/index.js +118 -116
- package/dist/react/components/index.js.map +2 -2
- package/dist/react/hooks/index.js +11 -9
- package/dist/react/hooks/index.js.map +2 -2
- package/dist/react/index.js +53 -49
- package/dist/react/index.js.map +2 -2
- package/dist/react/jsxDevRuntimeCompat.js +11 -9
- package/dist/react/jsxDevRuntimeCompat.js.map +2 -2
- package/dist/react/jsxRuntimeCompat.js +11 -9
- package/dist/react/jsxRuntimeCompat.js.map +2 -2
- package/dist/react/router/browser.js +9 -7
- package/dist/react/router/browser.js.map +2 -2
- package/dist/react/router/index.js +9 -7
- package/dist/react/router/index.js.map +2 -2
- package/dist/react/server.js +12 -10
- package/dist/react/server.js.map +2 -2
- 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 +6 -0
- package/dist/src/mobile/shellExpoAuth.d.ts +12 -0
- package/dist/src/mobile/shellExpoSync.d.ts +18 -0
- package/dist/svelte/browser.js +12 -10
- package/dist/svelte/browser.js.map +2 -2
- package/dist/svelte/index.js +47 -43
- package/dist/svelte/index.js.map +2 -2
- package/dist/svelte/server.js +29 -27
- package/dist/svelte/server.js.map +2 -2
- package/dist/vue/browser.js +14 -12
- package/dist/vue/browser.js.map +2 -2
- package/dist/vue/components/Image.js +9 -7
- package/dist/vue/components/Image.js.map +2 -2
- package/dist/vue/components/index.js +11 -9
- package/dist/vue/components/index.js.map +2 -2
- package/dist/vue/index.js +52 -48
- package/dist/vue/index.js.map +2 -2
- package/dist/vue/server.js +14 -12
- package/dist/vue/server.js.map +2 -2
- package/package.json +3 -2
package/dist/cli/index.js
CHANGED
|
@@ -847,122 +847,755 @@ var init_config = __esm(() => {
|
|
|
847
847
|
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])?))*$/;
|
|
848
848
|
});
|
|
849
849
|
|
|
850
|
-
// src/mobile/
|
|
851
|
-
import {
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
mkdir,
|
|
855
|
-
mkdtemp,
|
|
856
|
-
readdir,
|
|
857
|
-
readFile,
|
|
858
|
-
rename,
|
|
859
|
-
rm,
|
|
860
|
-
writeFile
|
|
861
|
-
} from "fs/promises";
|
|
862
|
-
import { createHash } from "crypto";
|
|
863
|
-
import { basename as basename2, dirname as dirname3, join as join5, relative, resolve as resolve3 } from "path";
|
|
864
|
-
var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
|
|
865
|
-
`, EXPO_ASSET_EXTENSION = ".absasset", EXPO_PROJECT_MARKER = ".absolutejs-expo-project", exists = async (path) => {
|
|
850
|
+
// src/mobile/nativeAuth.ts
|
|
851
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
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_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) => {
|
|
866
854
|
try {
|
|
867
|
-
|
|
868
|
-
return true;
|
|
855
|
+
return JSON.parse(readFileSync5(join5(projectRoot, "package.json"), "utf8"));
|
|
869
856
|
} catch {
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
}, packageManifestHas = (manifest, packageName) => {
|
|
860
|
+
if (typeof manifest !== "object" || manifest === null)
|
|
870
861
|
return false;
|
|
862
|
+
return [
|
|
863
|
+
Reflect.get(manifest, "dependencies"),
|
|
864
|
+
Reflect.get(manifest, "devDependencies"),
|
|
865
|
+
Reflect.get(manifest, "optionalDependencies"),
|
|
866
|
+
Reflect.get(manifest, "peerDependencies")
|
|
867
|
+
].some((dependencies) => typeof dependencies === "object" && dependencies !== null && Object.hasOwn(dependencies, packageName));
|
|
868
|
+
}, createAbsoluteMobileAuthManifest = (config) => {
|
|
869
|
+
const scheme = config.deepLinkScheme ?? config.appId.toLowerCase();
|
|
870
|
+
return {
|
|
871
|
+
clientId: `absolutejs-native:${config.appId}`,
|
|
872
|
+
issuer: config.productionOrigin,
|
|
873
|
+
redirectUri: `${scheme}://auth/callback`,
|
|
874
|
+
scopes: [...ABSOLUTE_NATIVE_AUTH_SCOPES]
|
|
875
|
+
};
|
|
876
|
+
}, installAbsoluteMobileAuthEnvironment = (projectRoot, config) => {
|
|
877
|
+
const auth = resolveAbsoluteMobileAuthManifest(projectRoot, config);
|
|
878
|
+
const serialized = serializeAbsoluteMobileAuthEnvironment(config, auth);
|
|
879
|
+
if (serialized === undefined)
|
|
880
|
+
delete process.env[ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV];
|
|
881
|
+
else
|
|
882
|
+
process.env[ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV] = serialized;
|
|
883
|
+
return auth;
|
|
884
|
+
}, projectUsesAbsoluteAuth = (projectRoot) => packageManifestHas(readPackageManifest(projectRoot), ABSOLUTE_AUTH_PACKAGE), projectUsesAbsoluteSync = (projectRoot) => packageManifestHas(readPackageManifest(projectRoot), ABSOLUTE_SYNC_PACKAGE), resolveAbsoluteMobileAuthManifest = (projectRoot, config) => projectUsesAbsoluteAuth(projectRoot) ? createAbsoluteMobileAuthManifest(config) : undefined, serializeAbsoluteMobileAuthEnvironment = (config, auth) => auth === undefined ? undefined : JSON.stringify([
|
|
885
|
+
{
|
|
886
|
+
...auth,
|
|
887
|
+
name: `${config.appName} native app`
|
|
871
888
|
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
889
|
+
]);
|
|
890
|
+
var init_nativeAuth = __esm(() => {
|
|
891
|
+
ABSOLUTE_NATIVE_AUTH_SCOPES = ["openid", "profile"];
|
|
892
|
+
});
|
|
893
|
+
|
|
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.`);
|
|
880
913
|
}
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
"
|
|
890
|
-
|
|
891
|
-
"
|
|
892
|
-
|
|
893
|
-
"react-native": "0.86.3",
|
|
894
|
-
"react-native-safe-area-context": "~5.7.0",
|
|
895
|
-
"react-native-screens": "4.26.0",
|
|
896
|
-
"react-native-webview": "13.16.1"
|
|
897
|
-
},
|
|
898
|
-
devDependencies: {
|
|
899
|
-
"@types/react": "~19.2.2",
|
|
900
|
-
typescript: "~6.0.3"
|
|
901
|
-
},
|
|
902
|
-
main: "expo-router/entry",
|
|
903
|
-
name: "absolutejs-expo-shell",
|
|
904
|
-
private: true,
|
|
905
|
-
scripts: {
|
|
906
|
-
android: "expo run:android",
|
|
907
|
-
ios: "expo run:ios",
|
|
908
|
-
start: "expo start --dev-client"
|
|
909
|
-
},
|
|
910
|
-
version: "0.0.0"
|
|
911
|
-
}), expoAppConfig = (config) => ({
|
|
912
|
-
expo: {
|
|
913
|
-
android: {
|
|
914
|
-
intentFilters: config.deepLinkHosts.map((host) => ({
|
|
915
|
-
action: "VIEW",
|
|
916
|
-
autoVerify: true,
|
|
917
|
-
category: ["BROWSABLE", "DEFAULT"],
|
|
918
|
-
data: [{ host, pathPrefix: "/", scheme: "https" }]
|
|
919
|
-
})),
|
|
920
|
-
package: config.appId
|
|
921
|
-
},
|
|
922
|
-
experiments: { typedRoutes: true },
|
|
923
|
-
ios: {
|
|
924
|
-
associatedDomains: config.deepLinkHosts.map((host) => `applinks:${host}`),
|
|
925
|
-
bundleIdentifier: config.appId,
|
|
926
|
-
...config.iosVersion ? { buildNumber: config.iosVersion } : {}
|
|
927
|
-
},
|
|
928
|
-
name: config.appName,
|
|
929
|
-
plugins: [
|
|
930
|
-
"expo-router",
|
|
931
|
-
["expo-dev-client", { launchMode: "most-recent" }]
|
|
932
|
-
],
|
|
933
|
-
runtimeVersion: { policy: "appVersion" },
|
|
934
|
-
scheme: config.deepLinkScheme,
|
|
935
|
-
slug: config.appId.toLowerCase().replaceAll(".", "-"),
|
|
936
|
-
version: config.iosVersion ?? "0.1.0"
|
|
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.`);
|
|
937
926
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
const
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
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`);
|
|
939
|
+
}
|
|
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
|
+
};
|
|
1021
|
+
});
|
|
950
1022
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
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)
|
|
1587
|
+
];
|
|
1588
|
+
return `${EXPO_GENERATED_HEADER}import * as Haptics from 'expo-haptics';
|
|
1589
|
+
import * as Linking from 'expo-linking';
|
|
1590
|
+
import { router, usePathname } from 'expo-router';
|
|
1591
|
+
import { useEffect, useRef, useState } from 'react';
|
|
1592
|
+
import { ActivityIndicator, BackHandler, Platform, StyleSheet, View } from 'react-native';
|
|
1593
|
+
import { WebView, type WebViewMessageEvent } from 'react-native-webview';
|
|
963
1594
|
import { materializeAbsoluteWebBundle } from './webAssets';
|
|
1595
|
+
${auth ? "import { absoluteExpoAuth, getAbsoluteExpoAuthPrincipal, startAbsoluteExpoAuth } from './AbsoluteAuth';" : ""}
|
|
1596
|
+
${sync ? "import { createAbsoluteExpoSyncBridge, startAbsoluteExpoSync } from './AbsoluteSync';" : ""}
|
|
964
1597
|
|
|
965
|
-
const BRIDGE_FORMAT =
|
|
1598
|
+
const BRIDGE_FORMAT = 3;
|
|
966
1599
|
const MAX_MESSAGE_BYTES = 64 * 1024;
|
|
967
1600
|
const MAX_HTTP_BODY_BYTES = 48 * 1024;
|
|
968
1601
|
const NATIVE_ROUTES = new Set(${JSON.stringify(nativeRoutes)});
|
|
@@ -971,6 +1604,8 @@ const DEV_ORIGIN = Platform.OS === 'android'
|
|
|
971
1604
|
? process.env.EXPO_PUBLIC_ABSOLUTE_DEV_ANDROID_ORIGIN
|
|
972
1605
|
: process.env.EXPO_PUBLIC_ABSOLUTE_DEV_IOS_ORIGIN;
|
|
973
1606
|
const HMR_TARGET = Platform.OS === 'android' ? 'expo-android' : 'expo-ios';
|
|
1607
|
+
const AUTH_ENABLED = ${auth ? "true" : "false"};
|
|
1608
|
+
const SYNC_ENABLED = ${sync ? "true" : "false"};
|
|
974
1609
|
|
|
975
1610
|
const bridgeBootstrap = (path: string) => {
|
|
976
1611
|
const initialPath = DEV_ORIGIN
|
|
@@ -978,6 +1613,7 @@ const bridgeBootstrap = (path: string) => {
|
|
|
978
1613
|
: JSON.stringify(path);
|
|
979
1614
|
return \`(() => {
|
|
980
1615
|
const pending = new Map();
|
|
1616
|
+
const listeners = new Map();
|
|
981
1617
|
let sequence = 0;
|
|
982
1618
|
let currentPath = \${initialPath};
|
|
983
1619
|
const send = value => {
|
|
@@ -987,6 +1623,10 @@ const bridgeBootstrap = (path: string) => {
|
|
|
987
1623
|
};
|
|
988
1624
|
globalThis.__absoluteExpoReceive = source => {
|
|
989
1625
|
const message = JSON.parse(source);
|
|
1626
|
+
if (message.kind === 'event') {
|
|
1627
|
+
for (const listener of listeners.get(message.event) || []) listener(message.payload || {});
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
990
1630
|
const operation = pending.get(message.id);
|
|
991
1631
|
if (!operation) return;
|
|
992
1632
|
pending.delete(message.id);
|
|
@@ -994,9 +1634,18 @@ const bridgeBootstrap = (path: string) => {
|
|
|
994
1634
|
message.error ? operation.reject(new Error(message.error.message)) : operation.resolve(message.result);
|
|
995
1635
|
};
|
|
996
1636
|
globalThis.__absoluteExpoBridge = {
|
|
1637
|
+
on(event, listener) {
|
|
1638
|
+
const values = listeners.get(event) || new Set();
|
|
1639
|
+
values.add(listener);
|
|
1640
|
+
listeners.set(event, values);
|
|
1641
|
+
return () => {
|
|
1642
|
+
values.delete(listener);
|
|
1643
|
+
if (values.size === 0) listeners.delete(event);
|
|
1644
|
+
};
|
|
1645
|
+
},
|
|
997
1646
|
request(method, params) {
|
|
998
1647
|
const id = 'web_' + Date.now().toString(36) + '_' + (++sequence).toString(36);
|
|
999
|
-
send({ format:
|
|
1648
|
+
send({ format: 3, id, kind: 'request', method, params, path: currentPath });
|
|
1000
1649
|
return new Promise((resolve, reject) => {
|
|
1001
1650
|
const timer = setTimeout(() => {
|
|
1002
1651
|
pending.delete(id);
|
|
@@ -1007,7 +1656,7 @@ const bridgeBootstrap = (path: string) => {
|
|
|
1007
1656
|
},
|
|
1008
1657
|
setPath(path) {
|
|
1009
1658
|
currentPath = path;
|
|
1010
|
-
send({ format:
|
|
1659
|
+
send({ format: 3, kind: 'event', event: 'navigation', path });
|
|
1011
1660
|
}
|
|
1012
1661
|
};
|
|
1013
1662
|
if (\${DEV_ORIGIN ? 'true' : 'false'}) {
|
|
@@ -1015,7 +1664,7 @@ const bridgeBootstrap = (path: string) => {
|
|
|
1015
1664
|
const path = location.pathname + location.search + location.hash;
|
|
1016
1665
|
if (path === currentPath) return;
|
|
1017
1666
|
currentPath = path;
|
|
1018
|
-
send({ format:
|
|
1667
|
+
send({ format: 3, kind: 'event', event: 'navigation', path });
|
|
1019
1668
|
};
|
|
1020
1669
|
for (const method of ['pushState', 'replaceState']) {
|
|
1021
1670
|
const original = history[method];
|
|
@@ -1034,9 +1683,9 @@ const bridgeBootstrap = (path: string) => {
|
|
|
1034
1683
|
const url = new URL(anchor.href, location.href);
|
|
1035
1684
|
if (!${JSON.stringify(nativeRoutes)}.includes(url.pathname)) return;
|
|
1036
1685
|
event.preventDefault();
|
|
1037
|
-
send({ format:
|
|
1686
|
+
send({ format: 3, kind: 'event', event: 'navigation', path: url.pathname + url.search + url.hash });
|
|
1038
1687
|
}, true);
|
|
1039
|
-
send({ format:
|
|
1688
|
+
send({ format: 3, kind: 'event', event: 'ready', path: currentPath });
|
|
1040
1689
|
})(); true;\`;
|
|
1041
1690
|
};
|
|
1042
1691
|
|
|
@@ -1052,16 +1701,16 @@ const impact = async (params: Record<string, unknown>) => {
|
|
|
1052
1701
|
};
|
|
1053
1702
|
|
|
1054
1703
|
const bridgeFetch = async (params: Record<string, unknown>) => {
|
|
1055
|
-
if (params.method !== 'GET' || typeof params.url !== 'string' || typeof params.headers !== 'object' || params.headers === null || Array.isArray(params.headers)) throw new Error('Expo bridge HTTP request is invalid.');
|
|
1704
|
+
if (typeof params.method !== 'string' || !['DELETE', 'GET', 'PATCH', 'POST', 'PUT'].includes(params.method) || typeof params.url !== 'string' || typeof params.headers !== 'object' || params.headers === null || Array.isArray(params.headers) || params.body !== undefined && typeof params.body !== 'string') throw new Error('Expo bridge HTTP request is invalid.');
|
|
1056
1705
|
const url = new URL(params.url);
|
|
1057
1706
|
if (url.origin !== PRODUCTION_ORIGIN || url.username || url.password) throw new Error('Expo bridge HTTP request left productionOrigin.');
|
|
1058
1707
|
const headers = new Headers();
|
|
1059
1708
|
for (const [name, value] of Object.entries(params.headers as Record<string, unknown>)) {
|
|
1060
1709
|
const normalized = name.toLowerCase();
|
|
1061
|
-
if (typeof value !== 'string' || (normalized !== 'accept' && !normalized.startsWith('x-absolute-mobile-'))) throw new Error('Expo bridge HTTP header is not allowed.');
|
|
1710
|
+
if (typeof value !== 'string' || (normalized !== 'accept' && normalized !== 'content-type' && !normalized.startsWith('x-absolute-mobile-'))) throw new Error('Expo bridge HTTP header is not allowed.');
|
|
1062
1711
|
headers.set(normalized, value);
|
|
1063
1712
|
}
|
|
1064
|
-
const response = await fetch(url, { headers, method:
|
|
1713
|
+
const response = await ${auth ? "absoluteExpoAuth.fetchOptional" : "fetch"}(url, { ...(typeof params.body === 'string' ? { body: params.body } : {}), headers, method: params.method, redirect: 'manual' });
|
|
1065
1714
|
if (new URL(response.url || url.href).origin !== PRODUCTION_ORIGIN || response.status >= 300 && response.status < 400) throw new Error('Expo bridge HTTP redirects are not allowed.');
|
|
1066
1715
|
const body = await response.text();
|
|
1067
1716
|
if (new TextEncoder().encode(body).byteLength > MAX_HTTP_BODY_BYTES) throw new Error('Expo bridge HTTP response exceeds 48 KiB.');
|
|
@@ -1073,13 +1722,45 @@ const bridgeFetch = async (params: Record<string, unknown>) => {
|
|
|
1073
1722
|
return { body, headers: responseHeaders, status: response.status };
|
|
1074
1723
|
};
|
|
1075
1724
|
|
|
1725
|
+
const authStatus = async () => {
|
|
1726
|
+
${auth ? `const user = await absoluteExpoAuth.status();
|
|
1727
|
+
const principal = getAbsoluteExpoAuthPrincipal();
|
|
1728
|
+
return { principal: principal ? { namespace: principal.namespace } : null, user };` : "throw new Error('Expo Auth is not configured.');"}
|
|
1729
|
+
};
|
|
1730
|
+
|
|
1076
1731
|
export function AbsoluteWebHost() {
|
|
1077
1732
|
const pathname = usePathname() || '/';
|
|
1078
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);
|
|
1079
1735
|
const [indexUri, setIndexUri] = useState<string>();
|
|
1080
1736
|
const [canGoBack, setCanGoBack] = useState(false);
|
|
1737
|
+
const [runtimeReady, setRuntimeReady] = useState(!AUTH_ENABLED && !SYNC_ENABLED);
|
|
1081
1738
|
const activeWebPath = useRef(pathname);
|
|
1082
1739
|
|
|
1740
|
+
useEffect(() => {
|
|
1741
|
+
if (!AUTH_ENABLED && !SYNC_ENABLED) return;
|
|
1742
|
+
let active = true;
|
|
1743
|
+
${auth ? `const stop = absoluteExpoAuth.onPrincipalChange(principal => {
|
|
1744
|
+
if (!active) return;
|
|
1745
|
+
const source = JSON.stringify({ event: 'auth.principal', format: BRIDGE_FORMAT, kind: 'event', path: activeWebPath.current, payload: { principal: principal ? { namespace: principal.namespace } : null } });
|
|
1746
|
+
webView.current?.injectJavaScript(\`globalThis.__absoluteExpoReceive(\${JSON.stringify(source)}); true;\`);
|
|
1747
|
+
});
|
|
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
|
+
};` : ""}
|
|
1762
|
+
}, []);
|
|
1763
|
+
|
|
1083
1764
|
useEffect(() => {
|
|
1084
1765
|
if (DEV_ORIGIN) {
|
|
1085
1766
|
const target = new URL(pathname, DEV_ORIGIN);
|
|
@@ -1129,6 +1810,19 @@ export function AbsoluteWebHost() {
|
|
|
1129
1810
|
respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: null });
|
|
1130
1811
|
} else if (message.method === 'http.fetch') {
|
|
1131
1812
|
respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await bridgeFetch(message.params as Record<string, unknown>) });
|
|
1813
|
+
} else if (message.method === 'auth.signIn') {
|
|
1814
|
+
${auth ? `const params = message.params as Record<string, unknown>;
|
|
1815
|
+
if (typeof params.email !== 'string' || typeof params.signup !== 'boolean') throw new Error('Expo Auth sign-in params are invalid.');
|
|
1816
|
+
await absoluteExpoAuth.signIn({ authorizationParameters: { login_hint: params.email, ...(params.signup ? { screen_hint: 'signup' } : {}) } });
|
|
1817
|
+
respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await authStatus() });` : "throw new Error('Expo Auth is not configured.');"}
|
|
1818
|
+
} else if (message.method === 'auth.signOut') {
|
|
1819
|
+
${auth ? `await absoluteExpoAuth.signOut();
|
|
1820
|
+
respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: null });` : "throw new Error('Expo Auth is not configured.');"}
|
|
1821
|
+
} else if (message.method === 'auth.status') {
|
|
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>) });
|
|
1132
1826
|
} else {
|
|
1133
1827
|
throw new Error('Expo bridge method is not allowed.');
|
|
1134
1828
|
}
|
|
@@ -1137,7 +1831,7 @@ export function AbsoluteWebHost() {
|
|
|
1137
1831
|
}
|
|
1138
1832
|
};
|
|
1139
1833
|
|
|
1140
|
-
if (!indexUri) return <View style={styles.loading}><ActivityIndicator /></View>;
|
|
1834
|
+
if (!indexUri || !runtimeReady) return <View style={styles.loading}><ActivityIndicator /></View>;
|
|
1141
1835
|
return <WebView
|
|
1142
1836
|
allowFileAccess
|
|
1143
1837
|
allowFileAccessFromFileURLs
|
|
@@ -1159,10 +1853,32 @@ export function AbsoluteWebHost() {
|
|
|
1159
1853
|
|
|
1160
1854
|
const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, justifyContent: 'center' }, web: { flex: 1 } });
|
|
1161
1855
|
`;
|
|
1162
|
-
}, webRouteSource, catchAllRouteSource, nativeWrapperSource = (wrapper, module) => `${EXPO_GENERATED_HEADER}export { default } from ${JSON.stringify(portableRelative(
|
|
1163
|
-
`, expoTsConfig = (projectRoot, project) => ({
|
|
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) => ({
|
|
1164
1858
|
compilerOptions: {
|
|
1165
1859
|
paths: {
|
|
1860
|
+
...auth ? {
|
|
1861
|
+
"@absolutejs/auth": [
|
|
1862
|
+
"./node_modules/@absolutejs/auth/dist/index.d.ts"
|
|
1863
|
+
],
|
|
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/*"
|
|
1880
|
+
]
|
|
1881
|
+
} : {},
|
|
1166
1882
|
"*": [
|
|
1167
1883
|
"./node_modules/*",
|
|
1168
1884
|
`${portableRelative(project, projectRoot)}/node_modules/*`
|
|
@@ -1174,7 +1890,7 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
|
|
|
1174
1890
|
},
|
|
1175
1891
|
extends: "expo/tsconfig.base"
|
|
1176
1892
|
}), writeManagedFile = async (path, source, force) => {
|
|
1177
|
-
await mkdir(
|
|
1893
|
+
await mkdir(dirname4(path), { recursive: true });
|
|
1178
1894
|
if (await exists(path)) {
|
|
1179
1895
|
const current = await readFile(path, "utf8");
|
|
1180
1896
|
if (current === source)
|
|
@@ -1191,8 +1907,11 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
|
|
|
1191
1907
|
`, emptyWebAssetsSource, writeAbsoluteExpoProject = async (config, options) => {
|
|
1192
1908
|
if (config.engine !== "expo")
|
|
1193
1909
|
throw new TypeError("Expo project generation requires mobile.engine: expo.");
|
|
1194
|
-
const projectRoot =
|
|
1910
|
+
const projectRoot = resolve4(options.projectRoot);
|
|
1195
1911
|
const project = config.nativeProjectDirectory;
|
|
1912
|
+
const auth = resolveAbsoluteMobileAuthManifest(projectRoot, config);
|
|
1913
|
+
const syncEnabled = Boolean(auth && projectUsesAbsoluteSync(projectRoot));
|
|
1914
|
+
const syncSchema = syncEnabled ? { components: discoverAbsoluteSyncSchema(projectRoot).components } : undefined;
|
|
1196
1915
|
const routeModules = Object.entries(config.expoNativeRoutes);
|
|
1197
1916
|
const moduleChecks = await Promise.all(routeModules.map(async ([route, module]) => ({
|
|
1198
1917
|
exists: await exists(module),
|
|
@@ -1203,7 +1922,7 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
|
|
|
1203
1922
|
if (missing) {
|
|
1204
1923
|
throw new TypeError(`Expo native route ${missing.route} references missing module ${missing.module}.`);
|
|
1205
1924
|
}
|
|
1206
|
-
const marker =
|
|
1925
|
+
const marker = join7(project, EXPO_PROJECT_MARKER);
|
|
1207
1926
|
if (await exists(project) && !await exists(marker)) {
|
|
1208
1927
|
const entries = await readdir(project);
|
|
1209
1928
|
if (entries.length > 0 && !options.force) {
|
|
@@ -1213,47 +1932,63 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
|
|
|
1213
1932
|
await mkdir(project, { recursive: true });
|
|
1214
1933
|
await writeFile(marker, `format=1
|
|
1215
1934
|
`);
|
|
1935
|
+
const authEnabled = Boolean(auth);
|
|
1216
1936
|
const files = new Map([
|
|
1217
1937
|
[
|
|
1218
|
-
|
|
1938
|
+
join7(project, ".gitignore"),
|
|
1219
1939
|
`.expo/
|
|
1220
1940
|
android/
|
|
1221
1941
|
ios/
|
|
1222
1942
|
node_modules/
|
|
1223
1943
|
`
|
|
1224
1944
|
],
|
|
1225
|
-
[join5(project, "app.json"), jsonSource(expoAppConfig(config))],
|
|
1226
|
-
[join5(project, "app.config.js"), expoDynamicAppConfig],
|
|
1227
|
-
[join5(project, "package.json"), jsonSource(expoPackage())],
|
|
1228
|
-
[join5(project, "metro.config.js"), metroConfig(projectRoot)],
|
|
1229
1945
|
[
|
|
1230
|
-
|
|
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))
|
|
1953
|
+
],
|
|
1954
|
+
[join7(project, "metro.config.js"), metroConfig(projectRoot)],
|
|
1955
|
+
[
|
|
1956
|
+
join7(project, "plugins", "withAbsoluteDevelopmentCa.js"),
|
|
1231
1957
|
expoDevelopmentCaPlugin
|
|
1232
1958
|
],
|
|
1233
1959
|
[
|
|
1234
|
-
|
|
1235
|
-
jsonSource(expoTsConfig(projectRoot, project))
|
|
1960
|
+
join7(project, "tsconfig.json"),
|
|
1961
|
+
jsonSource(expoTsConfig(projectRoot, project, authEnabled, syncEnabled))
|
|
1962
|
+
],
|
|
1963
|
+
[
|
|
1964
|
+
join7(project, "app", "_layout.tsx"),
|
|
1965
|
+
layoutSource(authEnabled, syncEnabled)
|
|
1236
1966
|
],
|
|
1237
|
-
[join5(project, "app", "_layout.tsx"), layoutSource],
|
|
1238
1967
|
[
|
|
1239
|
-
|
|
1968
|
+
join7(project, "app", "__absolute", "native", "index.tsx"),
|
|
1240
1969
|
nativeDiagnosticSource
|
|
1241
1970
|
],
|
|
1242
1971
|
[
|
|
1243
|
-
|
|
1244
|
-
webHostSource(config)
|
|
1972
|
+
join7(project, "src", "generated", "AbsoluteWebHost.tsx"),
|
|
1973
|
+
webHostSource(config, auth, syncEnabled)
|
|
1245
1974
|
]
|
|
1246
1975
|
]);
|
|
1247
|
-
|
|
1976
|
+
if (auth) {
|
|
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));
|
|
1981
|
+
}
|
|
1982
|
+
const webAssetsPath = join7(project, "src", "generated", "webAssets.ts");
|
|
1248
1983
|
if (!await exists(webAssetsPath)) {
|
|
1249
1984
|
files.set(webAssetsPath, emptyWebAssetsSource);
|
|
1250
1985
|
}
|
|
1251
1986
|
if (!config.expoNativeRoutes["/"]) {
|
|
1252
|
-
files.set(
|
|
1987
|
+
files.set(join7(project, "app", "index.tsx"), webRouteSource);
|
|
1253
1988
|
}
|
|
1254
|
-
files.set(
|
|
1989
|
+
files.set(join7(project, "app", "[...absolute].tsx"), catchAllRouteSource);
|
|
1255
1990
|
for (const [route, module] of routeModules) {
|
|
1256
|
-
const wrapper = route === "/" ?
|
|
1991
|
+
const wrapper = route === "/" ? join7(project, "app", "index.tsx") : routeFile(project, route);
|
|
1257
1992
|
files.set(wrapper, nativeWrapperSource(wrapper, module));
|
|
1258
1993
|
}
|
|
1259
1994
|
const changes = await Promise.all([...files].map(([path, source]) => writeManagedFile(path, source, true)));
|
|
@@ -1262,7 +1997,7 @@ node_modules/
|
|
|
1262
1997
|
}, walkFiles = async (root, directory = root) => {
|
|
1263
1998
|
const entries = await readdir(directory, { withFileTypes: true });
|
|
1264
1999
|
const nested = await Promise.all(entries.map((entry) => {
|
|
1265
|
-
const path =
|
|
2000
|
+
const path = join7(directory, entry.name);
|
|
1266
2001
|
if (entry.isDirectory())
|
|
1267
2002
|
return walkFiles(root, path);
|
|
1268
2003
|
if (entry.isFile())
|
|
@@ -1323,11 +2058,11 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
1323
2058
|
`, syncAbsoluteExpoWebAssets = async (config) => {
|
|
1324
2059
|
if (config.engine !== "expo")
|
|
1325
2060
|
throw new TypeError("Expo asset sync requires mobile.engine: expo.");
|
|
1326
|
-
const marker =
|
|
2061
|
+
const marker = join7(config.nativeProjectDirectory, EXPO_PROJECT_MARKER);
|
|
1327
2062
|
if (!await exists(marker)) {
|
|
1328
2063
|
throw new TypeError("Expo asset sync requires an AbsoluteJS-managed Expo project. Run mobile init first.");
|
|
1329
2064
|
}
|
|
1330
|
-
const manifestPath =
|
|
2065
|
+
const manifestPath = join7(config.bundleDirectory, "absolute-mobile-manifest.json");
|
|
1331
2066
|
const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
1332
2067
|
const appBuild = typeof manifest === "object" && manifest !== null && typeof Reflect.get(manifest, "appBuild") === "string" ? String(Reflect.get(manifest, "appBuild")) : undefined;
|
|
1333
2068
|
if (!appBuild)
|
|
@@ -1342,16 +2077,16 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
1342
2077
|
bundleHash.update("\x00");
|
|
1343
2078
|
});
|
|
1344
2079
|
const bundleId = `amexpo_${bundleHash.digest("hex")}`;
|
|
1345
|
-
const destination =
|
|
1346
|
-
await mkdir(
|
|
1347
|
-
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-`));
|
|
1348
2083
|
let assets;
|
|
1349
2084
|
try {
|
|
1350
2085
|
assets = await Promise.all(files.map(async (source, index) => {
|
|
1351
2086
|
const name = `${String(index).padStart(6, "0")}${EXPO_ASSET_EXTENSION}`;
|
|
1352
|
-
await cp(source,
|
|
2087
|
+
await cp(source, join7(staging, name));
|
|
1353
2088
|
return {
|
|
1354
|
-
asset: portableRelative(
|
|
2089
|
+
asset: portableRelative(join7(config.nativeProjectDirectory, "src", "generated"), join7(destination, name)),
|
|
1355
2090
|
path: relative(config.bundleDirectory, source).replaceAll("\\", "/")
|
|
1356
2091
|
};
|
|
1357
2092
|
}));
|
|
@@ -1360,11 +2095,13 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
1360
2095
|
await rm(staging, { force: true, recursive: true });
|
|
1361
2096
|
throw error;
|
|
1362
2097
|
}
|
|
1363
|
-
const generated =
|
|
2098
|
+
const generated = join7(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
|
|
1364
2099
|
await writeManagedFile(generated, assetModuleSource(assets, bundleId), true);
|
|
1365
2100
|
return { appBuild, assets: assets.length, bundleId, path: destination };
|
|
1366
2101
|
};
|
|
1367
2102
|
var init_expoProject = __esm(() => {
|
|
2103
|
+
init_nativeAuth();
|
|
2104
|
+
init_syncSchema();
|
|
1368
2105
|
expoDynamicAppConfig = `${EXPO_GENERATED_HEADER}const config = require('./app.json');
|
|
1369
2106
|
|
|
1370
2107
|
if (process.env.ABSOLUTE_EXPO_DEVELOPMENT === '1' && process.env.ABSOLUTE_EXPO_DEVELOPMENT_CA_PATH) {
|
|
@@ -1415,12 +2152,6 @@ const withAbsoluteDevelopmentCa = config => {
|
|
|
1415
2152
|
};
|
|
1416
2153
|
|
|
1417
2154
|
module.exports = withAbsoluteDevelopmentCa;
|
|
1418
|
-
`;
|
|
1419
|
-
layoutSource = `${EXPO_GENERATED_HEADER}import { Stack } from 'expo-router';
|
|
1420
|
-
|
|
1421
|
-
export default function AbsoluteLayout() {
|
|
1422
|
-
return <Stack screenOptions={{ headerShown: false }} />;
|
|
1423
|
-
}
|
|
1424
2155
|
`;
|
|
1425
2156
|
nativeDiagnosticSource = `${EXPO_GENERATED_HEADER}import * as Haptics from 'expo-haptics';
|
|
1426
2157
|
import { Link } from 'expo-router';
|
|
@@ -1476,14 +2207,14 @@ import {
|
|
|
1476
2207
|
isIP
|
|
1477
2208
|
} from "net";
|
|
1478
2209
|
import { readFile as readFile2 } from "fs/promises";
|
|
1479
|
-
var closeServer = (server) => new Promise((
|
|
2210
|
+
var closeServer = (server) => new Promise((resolve5, reject) => {
|
|
1480
2211
|
server.close((error) => {
|
|
1481
2212
|
if (error)
|
|
1482
2213
|
reject(error);
|
|
1483
2214
|
else
|
|
1484
|
-
|
|
2215
|
+
resolve5();
|
|
1485
2216
|
});
|
|
1486
|
-
}), listen = (server, port) => new Promise((
|
|
2217
|
+
}), listen = (server, port) => new Promise((resolve5, reject) => {
|
|
1487
2218
|
server.once("error", reject);
|
|
1488
2219
|
server.listen(port, "0.0.0.0", () => {
|
|
1489
2220
|
server.off("error", reject);
|
|
@@ -1492,11 +2223,11 @@ var closeServer = (server) => new Promise((resolve4, reject) => {
|
|
|
1492
2223
|
reject(new Error("Could not determine the iOS device helper port."));
|
|
1493
2224
|
return;
|
|
1494
2225
|
}
|
|
1495
|
-
|
|
2226
|
+
resolve5(address.port);
|
|
1496
2227
|
});
|
|
1497
2228
|
}), findEphemeralPort = async () => {
|
|
1498
2229
|
const probe = createTcpServer();
|
|
1499
|
-
const port = await new Promise((
|
|
2230
|
+
const port = await new Promise((resolve5, reject) => {
|
|
1500
2231
|
probe.once("error", reject);
|
|
1501
2232
|
probe.listen(0, "127.0.0.1", () => {
|
|
1502
2233
|
const address = probe.address();
|
|
@@ -1504,7 +2235,7 @@ var closeServer = (server) => new Promise((resolve4, reject) => {
|
|
|
1504
2235
|
reject(new Error("Could not allocate the iOS CA enrollment port."));
|
|
1505
2236
|
return;
|
|
1506
2237
|
}
|
|
1507
|
-
|
|
2238
|
+
resolve5(address.port);
|
|
1508
2239
|
});
|
|
1509
2240
|
});
|
|
1510
2241
|
await closeServer(probe);
|
|
@@ -1519,9 +2250,9 @@ var closeServer = (server) => new Promise((resolve4, reject) => {
|
|
|
1519
2250
|
if (!normalized || normalized.length > 256 || /[\0\r\n]/u.test(normalized))
|
|
1520
2251
|
throw new TypeError("--ios-device requires a valid Xcode device identifier or name.");
|
|
1521
2252
|
return normalized;
|
|
1522
|
-
}, urlForHost = (protocol,
|
|
2253
|
+
}, urlForHost = (protocol, host2, port) => {
|
|
1523
2254
|
const url = new URL(`${protocol}://localhost:${port}`);
|
|
1524
|
-
const normalizedHost = normalizeAbsoluteIosDeviceHost(
|
|
2255
|
+
const normalizedHost = normalizeAbsoluteIosDeviceHost(host2);
|
|
1525
2256
|
url.hostname = isIP(normalizedHost) === 6 ? `[${normalizedHost}]` : normalizedHost;
|
|
1526
2257
|
return url;
|
|
1527
2258
|
}, startAbsoluteIosCaEnrollmentServer = async (options) => {
|
|
@@ -1544,73 +2275,29 @@ var closeServer = (server) => new Promise((resolve4, reject) => {
|
|
|
1544
2275
|
"Content-Length": String(certificateBytes.byteLength),
|
|
1545
2276
|
"Content-Type": "application/x-x509-ca-cert",
|
|
1546
2277
|
"X-Content-Type-Options": "nosniff"
|
|
1547
|
-
});
|
|
1548
|
-
response.end(certificateBytes);
|
|
1549
|
-
});
|
|
1550
|
-
const port = await findEphemeralPort();
|
|
1551
|
-
await listen(server, port);
|
|
1552
|
-
const url = urlForHost("http", options.displayHost, port);
|
|
1553
|
-
url.pathname = certificatePath;
|
|
1554
|
-
return {
|
|
1555
|
-
url: url.href,
|
|
1556
|
-
close: () => closeServer(server)
|
|
1557
|
-
};
|
|
1558
|
-
};
|
|
1559
|
-
var init_iosPhysicalDeviceTransport = () => {};
|
|
1560
|
-
|
|
1561
|
-
// src/mobile/nativeAuth.ts
|
|
1562
|
-
import { readFileSync as readFileSync5 } from "fs";
|
|
1563
|
-
import { join as join7 } from "path";
|
|
1564
|
-
var ABSOLUTE_AUTH_PACKAGE = "@absolutejs/auth", ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV = "ABSOLUTE_AUTH_NATIVE_CLIENTS", ABSOLUTE_NATIVE_AUTH_SCOPES, ABSOLUTE_SYNC_PACKAGE = "@absolutejs/sync", readPackageManifest = (projectRoot) => {
|
|
1565
|
-
try {
|
|
1566
|
-
return JSON.parse(readFileSync5(join7(projectRoot, "package.json"), "utf8"));
|
|
1567
|
-
} catch {
|
|
1568
|
-
return;
|
|
1569
|
-
}
|
|
1570
|
-
}, packageManifestHas = (manifest, packageName) => {
|
|
1571
|
-
if (typeof manifest !== "object" || manifest === null)
|
|
1572
|
-
return false;
|
|
1573
|
-
return [
|
|
1574
|
-
Reflect.get(manifest, "dependencies"),
|
|
1575
|
-
Reflect.get(manifest, "devDependencies"),
|
|
1576
|
-
Reflect.get(manifest, "optionalDependencies"),
|
|
1577
|
-
Reflect.get(manifest, "peerDependencies")
|
|
1578
|
-
].some((dependencies) => typeof dependencies === "object" && dependencies !== null && Object.hasOwn(dependencies, packageName));
|
|
1579
|
-
}, createAbsoluteMobileAuthManifest = (config) => {
|
|
1580
|
-
const scheme = config.deepLinkScheme ?? config.appId.toLowerCase();
|
|
1581
|
-
return {
|
|
1582
|
-
clientId: `absolutejs-native:${config.appId}`,
|
|
1583
|
-
issuer: config.productionOrigin,
|
|
1584
|
-
redirectUri: `${scheme}://auth/callback`,
|
|
1585
|
-
scopes: [...ABSOLUTE_NATIVE_AUTH_SCOPES]
|
|
1586
|
-
};
|
|
1587
|
-
}, installAbsoluteMobileAuthEnvironment = (projectRoot, config) => {
|
|
1588
|
-
const auth = resolveAbsoluteMobileAuthManifest(projectRoot, config);
|
|
1589
|
-
const serialized = serializeAbsoluteMobileAuthEnvironment(config, auth);
|
|
1590
|
-
if (serialized === undefined)
|
|
1591
|
-
delete process.env[ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV];
|
|
1592
|
-
else
|
|
1593
|
-
process.env[ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV] = serialized;
|
|
1594
|
-
return auth;
|
|
1595
|
-
}, projectUsesAbsoluteAuth = (projectRoot) => packageManifestHas(readPackageManifest(projectRoot), ABSOLUTE_AUTH_PACKAGE), projectUsesAbsoluteSync = (projectRoot) => packageManifestHas(readPackageManifest(projectRoot), ABSOLUTE_SYNC_PACKAGE), resolveAbsoluteMobileAuthManifest = (projectRoot, config) => projectUsesAbsoluteAuth(projectRoot) ? createAbsoluteMobileAuthManifest(config) : undefined, serializeAbsoluteMobileAuthEnvironment = (config, auth) => auth === undefined ? undefined : JSON.stringify([
|
|
1596
|
-
{
|
|
1597
|
-
...auth,
|
|
1598
|
-
name: `${config.appName} native app`
|
|
1599
|
-
}
|
|
1600
|
-
]);
|
|
1601
|
-
var init_nativeAuth = __esm(() => {
|
|
1602
|
-
ABSOLUTE_NATIVE_AUTH_SCOPES = ["openid", "profile"];
|
|
1603
|
-
});
|
|
2278
|
+
});
|
|
2279
|
+
response.end(certificateBytes);
|
|
2280
|
+
});
|
|
2281
|
+
const port = await findEphemeralPort();
|
|
2282
|
+
await listen(server, port);
|
|
2283
|
+
const url = urlForHost("http", options.displayHost, port);
|
|
2284
|
+
url.pathname = certificatePath;
|
|
2285
|
+
return {
|
|
2286
|
+
url: url.href,
|
|
2287
|
+
close: () => closeServer(server)
|
|
2288
|
+
};
|
|
2289
|
+
};
|
|
2290
|
+
var init_iosPhysicalDeviceTransport = () => {};
|
|
1604
2291
|
|
|
1605
2292
|
// src/cli/utils.ts
|
|
1606
2293
|
var {$: $2 } = globalThis.Bun;
|
|
1607
2294
|
import { execSync } from "child_process";
|
|
1608
|
-
import { existsSync as existsSync3, readFileSync as
|
|
2295
|
+
import { existsSync as existsSync3, readFileSync as readFileSync7 } from "fs";
|
|
1609
2296
|
import { createServer as createServer3 } from "net";
|
|
1610
|
-
import { resolve as
|
|
2297
|
+
import { resolve as resolve5 } from "path";
|
|
1611
2298
|
var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backend/server.ts", isWSLEnvironment = () => {
|
|
1612
2299
|
try {
|
|
1613
|
-
const release =
|
|
2300
|
+
const release = readFileSync7("/proc/version", "utf-8");
|
|
1614
2301
|
return /microsoft|wsl/i.test(release);
|
|
1615
2302
|
} catch {
|
|
1616
2303
|
return false;
|
|
@@ -1709,7 +2396,7 @@ var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backe
|
|
|
1709
2396
|
}, printHint = () => {
|
|
1710
2397
|
console.log("\x1B[90mpress h + enter to show shortcuts\x1B[0m");
|
|
1711
2398
|
}, readDbScripts = async () => {
|
|
1712
|
-
const pkgPath =
|
|
2399
|
+
const pkgPath = resolve5("package.json");
|
|
1713
2400
|
if (!existsSync3(pkgPath))
|
|
1714
2401
|
return null;
|
|
1715
2402
|
const pkg = await Bun.file(pkgPath).json();
|
|
@@ -1744,7 +2431,7 @@ var init_utils = __esm(() => {
|
|
|
1744
2431
|
// src/mobile/emulatorDoctor.ts
|
|
1745
2432
|
import { access as access3 } from "fs/promises";
|
|
1746
2433
|
import { homedir as homedir3 } from "os";
|
|
1747
|
-
import { join as
|
|
2434
|
+
import { join as join9 } from "path";
|
|
1748
2435
|
var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command) => {
|
|
1749
2436
|
try {
|
|
1750
2437
|
const result = Bun.spawnSync(command, {
|
|
@@ -1787,17 +2474,17 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1787
2474
|
} catch {
|
|
1788
2475
|
return;
|
|
1789
2476
|
}
|
|
1790
|
-
}, absoluteManagedAndroidSdkRoot = (
|
|
1791
|
-
if (
|
|
1792
|
-
return
|
|
2477
|
+
}, absoluteManagedAndroidSdkRoot = (host2, env = process.env) => {
|
|
2478
|
+
if (host2 === "windows") {
|
|
2479
|
+
return join9(env.LOCALAPPDATA ?? join9(homedir3(), "AppData", "Local"), "AbsoluteJS", "Android", "Sdk");
|
|
1793
2480
|
}
|
|
1794
|
-
if (
|
|
2481
|
+
if (host2 === "wsl") {
|
|
1795
2482
|
const localAppData = windowsLocalAppDataFromWsl();
|
|
1796
2483
|
if (localAppData) {
|
|
1797
|
-
return
|
|
2484
|
+
return join9(localAppData, "AbsoluteJS", "Android", "Sdk");
|
|
1798
2485
|
}
|
|
1799
2486
|
}
|
|
1800
|
-
return
|
|
2487
|
+
return join9(homedir3(), ".absolutejs", "android-sdk");
|
|
1801
2488
|
}, pathExists = async (path) => {
|
|
1802
2489
|
try {
|
|
1803
2490
|
await access3(path);
|
|
@@ -1813,18 +2500,18 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1813
2500
|
if (platform2 === "linux" && wsl)
|
|
1814
2501
|
return "wsl";
|
|
1815
2502
|
return "linux";
|
|
1816
|
-
}, executableNames = (
|
|
1817
|
-
if (
|
|
2503
|
+
}, executableNames = (host2, name) => {
|
|
2504
|
+
if (host2 === "wsl")
|
|
1818
2505
|
return [`${name}.exe`, `${name}.bat`, name];
|
|
1819
|
-
if (
|
|
2506
|
+
if (host2 === "windows")
|
|
1820
2507
|
return [name, `${name}.exe`, `${name}.bat`];
|
|
1821
2508
|
return [name];
|
|
1822
|
-
}, findExecutable = async (name, paths, options,
|
|
2509
|
+
}, findExecutable = async (name, paths, options, host2) => {
|
|
1823
2510
|
const existing = await Promise.all(paths.map(async (path) => await options.exists(path) ? path : undefined));
|
|
1824
2511
|
const configured = existing.find((path) => path !== undefined);
|
|
1825
2512
|
if (configured)
|
|
1826
2513
|
return configured;
|
|
1827
|
-
for (const candidate of executableNames(
|
|
2514
|
+
for (const candidate of executableNames(host2, name)) {
|
|
1828
2515
|
const path = options.which(candidate);
|
|
1829
2516
|
if (path)
|
|
1830
2517
|
return path;
|
|
@@ -1844,23 +2531,23 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1844
2531
|
status: "fail"
|
|
1845
2532
|
}, inspectAbsoluteMobileToolchain = async (input = {}) => {
|
|
1846
2533
|
const env = input.env ?? process.env;
|
|
1847
|
-
const
|
|
2534
|
+
const host2 = input.host ?? detectAbsoluteMobileHost();
|
|
1848
2535
|
const exists2 = input.exists ?? pathExists;
|
|
1849
2536
|
const which = input.which ?? ((command) => Bun.which(command));
|
|
1850
2537
|
const capture = input.capture ?? captureCommand;
|
|
1851
|
-
const androidRoot = input.androidRoot === null ? undefined : input.androidRoot ?? env.ANDROID_HOME ?? env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(
|
|
1852
|
-
const windowsAndroidTools =
|
|
1853
|
-
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;
|
|
1854
2541
|
const paths = (values) => values.filter((value) => Boolean(value));
|
|
1855
2542
|
const adb = await findExecutable("adb", paths([
|
|
1856
2543
|
android(["platform-tools", windowsAndroidTools ? "adb.exe" : "adb"])
|
|
1857
|
-
]), { exists: exists2, which },
|
|
2544
|
+
]), { exists: exists2, which }, host2);
|
|
1858
2545
|
const emulator = await findExecutable("emulator", paths([
|
|
1859
2546
|
android([
|
|
1860
2547
|
"emulator",
|
|
1861
2548
|
windowsAndroidTools ? "emulator.exe" : "emulator"
|
|
1862
2549
|
])
|
|
1863
|
-
]), { exists: exists2, which },
|
|
2550
|
+
]), { exists: exists2, which }, host2);
|
|
1864
2551
|
const sdkmanager = await findExecutable("sdkmanager", paths([
|
|
1865
2552
|
android([
|
|
1866
2553
|
"cmdline-tools",
|
|
@@ -1868,7 +2555,7 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1868
2555
|
"bin",
|
|
1869
2556
|
windowsAndroidTools ? "sdkmanager.bat" : "sdkmanager"
|
|
1870
2557
|
])
|
|
1871
|
-
]), { exists: exists2, which },
|
|
2558
|
+
]), { exists: exists2, which }, host2);
|
|
1872
2559
|
const avdmanager = await findExecutable("avdmanager", paths([
|
|
1873
2560
|
android([
|
|
1874
2561
|
"cmdline-tools",
|
|
@@ -1876,12 +2563,12 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1876
2563
|
"bin",
|
|
1877
2564
|
windowsAndroidTools ? "avdmanager.bat" : "avdmanager"
|
|
1878
2565
|
])
|
|
1879
|
-
]), { exists: exists2, which },
|
|
1880
|
-
const java = await findExecutable("java", [], { exists: exists2, which },
|
|
2566
|
+
]), { exists: exists2, which }, host2);
|
|
2567
|
+
const java = await findExecutable("java", [], { exists: exists2, which }, host2);
|
|
1881
2568
|
const checks = [
|
|
1882
2569
|
{
|
|
1883
2570
|
id: "host",
|
|
1884
|
-
label: `Development host: ${
|
|
2571
|
+
label: `Development host: ${host2}`,
|
|
1885
2572
|
platform: "host",
|
|
1886
2573
|
status: "pass"
|
|
1887
2574
|
},
|
|
@@ -1902,7 +2589,7 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1902
2589
|
status: hasManagedAvd ? "pass" : "fail"
|
|
1903
2590
|
});
|
|
1904
2591
|
}
|
|
1905
|
-
if (
|
|
2592
|
+
if (host2 === "wsl") {
|
|
1906
2593
|
checks.push({
|
|
1907
2594
|
id: "android.virtualization",
|
|
1908
2595
|
label: adb?.endsWith(".exe") ? "Windows-host Android bridge available to WSL" : "WSL requires a Windows-host emulator bridge or Linux KVM",
|
|
@@ -1910,7 +2597,7 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1910
2597
|
remediation: adb?.endsWith(".exe") ? undefined : "Expose the Windows Android SDK adb.exe to WSL, or enable /dev/kvm for a Linux SDK.",
|
|
1911
2598
|
status: adb?.endsWith(".exe") ? "pass" : "warn"
|
|
1912
2599
|
});
|
|
1913
|
-
} else if (
|
|
2600
|
+
} else if (host2 === "linux") {
|
|
1914
2601
|
const hasKvm = await exists2("/dev/kvm");
|
|
1915
2602
|
checks.push({
|
|
1916
2603
|
id: "android.virtualization",
|
|
@@ -1920,7 +2607,7 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1920
2607
|
status: hasKvm ? "pass" : "warn"
|
|
1921
2608
|
});
|
|
1922
2609
|
}
|
|
1923
|
-
if (
|
|
2610
|
+
if (host2 !== "macos") {
|
|
1924
2611
|
checks.push({
|
|
1925
2612
|
id: "ios.simulator",
|
|
1926
2613
|
label: "iOS Simulator requires macOS and Xcode",
|
|
@@ -1929,8 +2616,8 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1929
2616
|
});
|
|
1930
2617
|
return checks;
|
|
1931
2618
|
}
|
|
1932
|
-
const xcrun = await findExecutable("xcrun", [], { exists: exists2, which },
|
|
1933
|
-
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);
|
|
1934
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."));
|
|
1935
2622
|
if (xcrun) {
|
|
1936
2623
|
const runtimes = capture([
|
|
@@ -1957,7 +2644,7 @@ var init_emulatorDoctor = __esm(() => {
|
|
|
1957
2644
|
|
|
1958
2645
|
// src/mobile/capacitorProject.ts
|
|
1959
2646
|
import { access as access4, readFile as readFile3, rename as rename2, writeFile as writeFile2 } from "fs/promises";
|
|
1960
|
-
import { relative as relative2, resolve as
|
|
2647
|
+
import { relative as relative2, resolve as resolve6 } from "path";
|
|
1961
2648
|
var CONFIG_FILE = "capacitor.config.ts", portableRelative2 = (root, path) => relative2(root, path).replaceAll("\\", "/"), capacitorConfigSource = (config, projectRoot) => `import type { CapacitorConfig } from '@capacitor/cli';
|
|
1962
2649
|
|
|
1963
2650
|
const config: CapacitorConfig = {
|
|
@@ -1981,8 +2668,8 @@ export default config;
|
|
|
1981
2668
|
return false;
|
|
1982
2669
|
}
|
|
1983
2670
|
}, writeAbsoluteCapacitorConfig = async (config, options) => {
|
|
1984
|
-
const projectRoot =
|
|
1985
|
-
const destination =
|
|
2671
|
+
const projectRoot = resolve6(options.projectRoot);
|
|
2672
|
+
const destination = resolve6(projectRoot, CONFIG_FILE);
|
|
1986
2673
|
const source = capacitorConfigSource(config, projectRoot);
|
|
1987
2674
|
if (await exists2(destination)) {
|
|
1988
2675
|
const current = await readFile3(destination, "utf8");
|
|
@@ -2015,11 +2702,11 @@ import {
|
|
|
2015
2702
|
} from "fs/promises";
|
|
2016
2703
|
import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
|
|
2017
2704
|
import {
|
|
2018
|
-
dirname as
|
|
2705
|
+
dirname as dirname5,
|
|
2019
2706
|
isAbsolute,
|
|
2020
|
-
join as
|
|
2707
|
+
join as join10,
|
|
2021
2708
|
relative as relative3,
|
|
2022
|
-
resolve as
|
|
2709
|
+
resolve as resolve7,
|
|
2023
2710
|
sep,
|
|
2024
2711
|
win32
|
|
2025
2712
|
} from "path";
|
|
@@ -2189,21 +2876,21 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2189
2876
|
return;
|
|
2190
2877
|
throw new DOMException("Android development startup was cancelled.", "AbortError");
|
|
2191
2878
|
}, journalPaths = (projectRoot) => {
|
|
2192
|
-
const root =
|
|
2879
|
+
const root = join10(projectRoot, ".absolutejs", "mobile", "dev-session");
|
|
2193
2880
|
return {
|
|
2194
|
-
backup:
|
|
2195
|
-
caBackup:
|
|
2196
|
-
journal:
|
|
2197
|
-
manifestBackup:
|
|
2198
|
-
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"),
|
|
2199
2886
|
root
|
|
2200
2887
|
};
|
|
2201
2888
|
}, isInside = (root, path) => {
|
|
2202
|
-
const resolvedRoot =
|
|
2203
|
-
const resolvedPath =
|
|
2889
|
+
const resolvedRoot = resolve7(root);
|
|
2890
|
+
const resolvedPath = resolve7(path);
|
|
2204
2891
|
const relativePath = relative3(resolvedRoot, resolvedPath);
|
|
2205
2892
|
return relativePath === "" || relativePath !== ".." && !relativePath.startsWith(`..${sep}`) && !isAbsolute(relativePath);
|
|
2206
|
-
}, 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) => {
|
|
2207
2894
|
if (!isRecord(value))
|
|
2208
2895
|
return null;
|
|
2209
2896
|
const { appId, fingerprint, format, installations } = value;
|
|
@@ -2222,7 +2909,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2222
2909
|
}, readNativeCache = async (projectRoot) => readFile4(nativeCachePath(projectRoot), "utf8").then((source) => parseNativeCache(JSON.parse(source))).catch(() => null), writeNativeCache = async (projectRoot, cache) => {
|
|
2223
2910
|
const destination = nativeCachePath(projectRoot);
|
|
2224
2911
|
const temporary = `${destination}.${process.pid}.${randomUUID2()}.tmp`;
|
|
2225
|
-
await mkdir2(
|
|
2912
|
+
await mkdir2(dirname5(destination), { recursive: true });
|
|
2226
2913
|
try {
|
|
2227
2914
|
await writeFile3(temporary, `${JSON.stringify(cache, null, "\t")}
|
|
2228
2915
|
`, {
|
|
@@ -2235,11 +2922,11 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2235
2922
|
});
|
|
2236
2923
|
}
|
|
2237
2924
|
}, nativeDependencySources = async (nativeDirectory) => {
|
|
2238
|
-
const settings = await readFile4(
|
|
2925
|
+
const settings = await readFile4(join10(nativeDirectory, "capacitor.settings.gradle"), "utf8");
|
|
2239
2926
|
const pattern = new RegExp(CAPACITOR_PROJECT_DIRECTORY_PATTERN.source, CAPACITOR_PROJECT_DIRECTORY_PATTERN.flags);
|
|
2240
2927
|
const dependencies = [...settings.matchAll(pattern)].map((match) => ({
|
|
2241
2928
|
name: (match[1] ?? "").slice(1).replaceAll(/[^a-zA-Z0-9_.-]/gu, "_"),
|
|
2242
|
-
source:
|
|
2929
|
+
source: resolve7(nativeDirectory, match[2] ?? "")
|
|
2243
2930
|
}));
|
|
2244
2931
|
if (dependencies.length === 0) {
|
|
2245
2932
|
throw new Error("Capacitor Android settings did not declare any native dependencies.");
|
|
@@ -2275,7 +2962,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2275
2962
|
}, collectNativeDirectory = async (root, label, directory, ignorePublicBundle) => {
|
|
2276
2963
|
const entries = await readdir2(directory, { withFileTypes: true });
|
|
2277
2964
|
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
2278
|
-
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)));
|
|
2279
2966
|
return records.flat();
|
|
2280
2967
|
}, hashNativeTree = async (root, label, ignorePublicBundle) => {
|
|
2281
2968
|
const resolvedRoot = await realpath(root);
|
|
@@ -2328,7 +3015,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2328
3015
|
await rm2(file.path, { force: true });
|
|
2329
3016
|
return;
|
|
2330
3017
|
}
|
|
2331
|
-
await mkdir2(
|
|
3018
|
+
await mkdir2(dirname5(file.path), { recursive: true });
|
|
2332
3019
|
await copyFile(file.backupPath, file.path);
|
|
2333
3020
|
}, repairAbsoluteAndroidDevSession = async (projectRoot) => {
|
|
2334
3021
|
const paths = journalPaths(projectRoot);
|
|
@@ -2341,11 +3028,11 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2341
3028
|
throw new Error(`Refusing unsafe or invalid mobile dev journal at ${paths.journal}.`);
|
|
2342
3029
|
}
|
|
2343
3030
|
if (await pathExists2(journal.backupPath)) {
|
|
2344
|
-
await mkdir2(
|
|
3031
|
+
await mkdir2(dirname5(journal.nativeConfigPath), { recursive: true });
|
|
2345
3032
|
await copyFile(journal.backupPath, journal.nativeConfigPath);
|
|
2346
3033
|
}
|
|
2347
3034
|
if (journal.manifestBackupPath && journal.nativeManifestPath && await pathExists2(journal.manifestBackupPath)) {
|
|
2348
|
-
await mkdir2(
|
|
3035
|
+
await mkdir2(dirname5(journal.nativeManifestPath), { recursive: true });
|
|
2349
3036
|
await copyFile(journal.manifestBackupPath, journal.nativeManifestPath);
|
|
2350
3037
|
}
|
|
2351
3038
|
await Promise.all((journal.projectedFiles ?? []).map(restoreAndroidProjectedFile));
|
|
@@ -2404,11 +3091,11 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2404
3091
|
await mkdir2(paths.root, { recursive: true });
|
|
2405
3092
|
await writeFile3(paths.backup, source, { flag: "wx" });
|
|
2406
3093
|
await writeFile3(paths.manifestBackup, manifestSource, { flag: "wx" });
|
|
2407
|
-
const resourceRoot =
|
|
2408
|
-
const caPath =
|
|
3094
|
+
const resourceRoot = join10(dirname5(nativeManifestPath), "res");
|
|
3095
|
+
const caPath = join10(resourceRoot, "raw", "absolutejs_dev_ca.pem");
|
|
2409
3096
|
const existingNetworkConfig = manifestSource.match(/android:networkSecurityConfig=["']@xml\/([a-z0-9_]+)["']/u)?.[1];
|
|
2410
3097
|
const networkConfigName = existingNetworkConfig ?? "absolutejs_dev_network_security";
|
|
2411
|
-
const networkConfigPath =
|
|
3098
|
+
const networkConfigPath = join10(resourceRoot, "xml", `${networkConfigName}.xml`);
|
|
2412
3099
|
const backupProjectedFile = async ([path, backupPath]) => {
|
|
2413
3100
|
if (!await pathExists2(path))
|
|
2414
3101
|
return { path };
|
|
@@ -2445,8 +3132,8 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2445
3132
|
`);
|
|
2446
3133
|
if (https && certificateAuthorityPath) {
|
|
2447
3134
|
await Promise.all([
|
|
2448
|
-
mkdir2(
|
|
2449
|
-
mkdir2(
|
|
3135
|
+
mkdir2(dirname5(caPath), { recursive: true }),
|
|
3136
|
+
mkdir2(dirname5(networkConfigPath), { recursive: true })
|
|
2450
3137
|
]);
|
|
2451
3138
|
await copyFile(certificateAuthorityPath, caPath);
|
|
2452
3139
|
const existingNetworkConfigSource = existingNetworkConfig ? await readFile4(networkConfigPath, "utf8") : `<?xml version="1.0" encoding="utf-8"?>
|
|
@@ -2501,12 +3188,12 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2501
3188
|
}
|
|
2502
3189
|
return result.stdout.trim();
|
|
2503
3190
|
}, mirroredCapacitorDependencies = async (project, capture) => {
|
|
2504
|
-
const settingsPath =
|
|
3191
|
+
const settingsPath = join10(project.nativeDirectory, "capacitor.settings.gradle");
|
|
2505
3192
|
const settings = await readFile4(settingsPath, "utf8");
|
|
2506
3193
|
const dependencies = [];
|
|
2507
3194
|
const rewrittenSettings = settings.replace(CAPACITOR_PROJECT_DIRECTORY_PATTERN, (_statement, projectName, sourcePath) => {
|
|
2508
3195
|
const name = projectName.slice(1).replaceAll(/[^a-zA-Z0-9_.-]/gu, "_");
|
|
2509
|
-
const source =
|
|
3196
|
+
const source = resolve7(project.nativeDirectory, sourcePath);
|
|
2510
3197
|
dependencies.push({
|
|
2511
3198
|
name,
|
|
2512
3199
|
windowsSource: windowsPathFromWsl(source, capture)
|
|
@@ -2547,7 +3234,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2547
3234
|
].join("; ");
|
|
2548
3235
|
return Buffer.from(source, "utf16le").toString("base64");
|
|
2549
3236
|
}, gradleArtifactPath = (nativeDirectory, task, windows = false) => {
|
|
2550
|
-
const pathJoin = windows ? win32.join :
|
|
3237
|
+
const pathJoin = windows ? win32.join : join10;
|
|
2551
3238
|
if (task === "assembleDebug") {
|
|
2552
3239
|
return pathJoin(nativeDirectory, "app", "build", "outputs", "apk", "debug", "app-debug.apk");
|
|
2553
3240
|
}
|
|
@@ -2560,7 +3247,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2560
3247
|
if (task !== "assembleRelease" || await pathExists2(primary)) {
|
|
2561
3248
|
return primary;
|
|
2562
3249
|
}
|
|
2563
|
-
return
|
|
3250
|
+
return join10(nativeDirectory, "app", "build", "outputs", "apk", "release", "app-release-unsigned.apk");
|
|
2564
3251
|
}, buildAbsoluteAndroidGradleArtifact = async (options) => {
|
|
2565
3252
|
const { project, task } = options;
|
|
2566
3253
|
const capture = options.capture ?? captureCommand2;
|
|
@@ -2570,7 +3257,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2570
3257
|
if (project.host === "wsl") {
|
|
2571
3258
|
const windowsSource = windowsPathFromWsl(project.nativeDirectory, capture);
|
|
2572
3259
|
const buildId = Bun.hash(project.projectRoot).toString(HASH_RADIX);
|
|
2573
|
-
const managedBuildDirectory =
|
|
3260
|
+
const managedBuildDirectory = resolve7(project.androidRoot, "..", "..", "Builds", `${project.config.appId}-${buildId}`);
|
|
2574
3261
|
const windowsDirectory = windowsPathFromWsl(managedBuildDirectory, capture);
|
|
2575
3262
|
const windowsAndroidRoot = windowsPathFromWsl(project.androidRoot, capture);
|
|
2576
3263
|
const { dependencies, rewrittenSettings } = await mirroredCapacitorDependencies(project, capture);
|
|
@@ -2753,10 +3440,10 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2753
3440
|
"chromium:I"
|
|
2754
3441
|
], { env }, onLine);
|
|
2755
3442
|
}, prepareAbsoluteAndroidDevProject = async (config, options) => {
|
|
2756
|
-
const projectRoot =
|
|
2757
|
-
const
|
|
2758
|
-
const androidRoot = process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(
|
|
2759
|
-
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 });
|
|
2760
3447
|
const deviceOnlyChecks = new Set([
|
|
2761
3448
|
"android.avd",
|
|
2762
3449
|
"android.avdmanager",
|
|
@@ -2772,18 +3459,18 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2772
3459
|
if (!adb || options.target !== "device" && !emulator) {
|
|
2773
3460
|
throw new Error("Android SDK tools disappeared after readiness checks.");
|
|
2774
3461
|
}
|
|
2775
|
-
const cap =
|
|
3462
|
+
const cap = join10(projectRoot, "node_modules", ".bin", host2 === "windows" ? "cap.cmd" : "cap");
|
|
2776
3463
|
if (!await pathExists2(cap)) {
|
|
2777
3464
|
throw new Error("Capacitor CLI is not installed. Run absolute mobile init first.");
|
|
2778
3465
|
}
|
|
2779
3466
|
await writeAbsoluteCapacitorConfig(config, { projectRoot });
|
|
2780
3467
|
await mkdir2(config.bundleDirectory, { recursive: true });
|
|
2781
|
-
const placeholder =
|
|
3468
|
+
const placeholder = join10(config.bundleDirectory, "index.html");
|
|
2782
3469
|
if (!await pathExists2(placeholder)) {
|
|
2783
3470
|
await writeFile3(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
|
|
2784
3471
|
`);
|
|
2785
3472
|
}
|
|
2786
|
-
const nativeDirectory =
|
|
3473
|
+
const nativeDirectory = join10(config.nativeProjectDirectory, "android");
|
|
2787
3474
|
if (!await pathExists2(nativeDirectory)) {
|
|
2788
3475
|
if (!options.createNativeProject) {
|
|
2789
3476
|
throw new Error("Android native project has not been created.");
|
|
@@ -2801,7 +3488,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2801
3488
|
cap,
|
|
2802
3489
|
config,
|
|
2803
3490
|
...emulator ? { emulator } : {},
|
|
2804
|
-
host,
|
|
3491
|
+
host: host2,
|
|
2805
3492
|
nativeDirectory,
|
|
2806
3493
|
projectRoot
|
|
2807
3494
|
};
|
|
@@ -2844,8 +3531,8 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2844
3531
|
await requireSuccess([project.cap, "sync", "android"], "Capacitor Android synchronization", run, { cwd: project.projectRoot, env, signal: options.signal });
|
|
2845
3532
|
throwIfAborted(options.signal);
|
|
2846
3533
|
transition("configuring");
|
|
2847
|
-
const nativeConfigPath =
|
|
2848
|
-
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");
|
|
2849
3536
|
let connectedSerial;
|
|
2850
3537
|
let nativeLogs = null;
|
|
2851
3538
|
const closeNativeLogs = async () => {
|
|
@@ -3004,7 +3691,7 @@ var init_androidEmulatorController = __esm(() => {
|
|
|
3004
3691
|
import { createHash as createHash3 } from "crypto";
|
|
3005
3692
|
import { cp as cp2, mkdir as mkdir3, mkdtemp as mkdtemp2, readFile as readFile5, rm as rm3 } from "fs/promises";
|
|
3006
3693
|
import { tmpdir } from "os";
|
|
3007
|
-
import { basename as basename3, join as
|
|
3694
|
+
import { basename as basename3, join as join11 } from "path";
|
|
3008
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 = {}) => {
|
|
3009
3696
|
const subprocess = Bun.spawn(command, {
|
|
3010
3697
|
env: options.env,
|
|
@@ -3036,33 +3723,33 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3036
3723
|
exitCode: result.exitCode,
|
|
3037
3724
|
stdout: result.stdout.toString()
|
|
3038
3725
|
};
|
|
3039
|
-
}, 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) => {
|
|
3040
3727
|
const match = /^\/mnt\/([a-z])\/(.*)$/i.exec(path);
|
|
3041
3728
|
if (!match)
|
|
3042
3729
|
return path;
|
|
3043
3730
|
return `${match[1]?.toUpperCase()}:\\${match[2]?.replaceAll("/", "\\")}`;
|
|
3044
|
-
}, runnableCommand = (
|
|
3045
|
-
if (
|
|
3731
|
+
}, runnableCommand = (host2, path, args) => {
|
|
3732
|
+
if (host2 !== "wsl" || !path.endsWith(".bat"))
|
|
3046
3733
|
return [path, ...args];
|
|
3047
3734
|
return ["cmd.exe", "/d", "/c", windowsPath(path), ...args];
|
|
3048
|
-
}, systemImageFor = (
|
|
3049
|
-
const imageArch =
|
|
3735
|
+
}, systemImageFor = (host2, arch2) => {
|
|
3736
|
+
const imageArch = host2 === "macos" && arch2 === "arm64" ? "arm64-v8a" : "x86_64";
|
|
3050
3737
|
return `system-images;android-${ANDROID_API};google_apis;${imageArch}`;
|
|
3051
3738
|
}, planAbsoluteMobileEmulatorInstall = (platform2, input = {}) => {
|
|
3052
|
-
const
|
|
3739
|
+
const host2 = input.host ?? detectAbsoluteMobileHost();
|
|
3053
3740
|
const env = {
|
|
3054
3741
|
...process.env,
|
|
3055
3742
|
...input.env
|
|
3056
3743
|
};
|
|
3057
|
-
const androidRoot = env.ANDROID_HOME ?? env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(
|
|
3744
|
+
const androidRoot = env.ANDROID_HOME ?? env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host2, env);
|
|
3058
3745
|
if (platform2 === "ios") {
|
|
3059
3746
|
return {
|
|
3060
3747
|
androidRoot,
|
|
3061
|
-
host,
|
|
3748
|
+
host: host2,
|
|
3062
3749
|
platform: platform2,
|
|
3063
3750
|
steps: [
|
|
3064
3751
|
{
|
|
3065
|
-
detail:
|
|
3752
|
+
detail: host2 === "macos" ? "Use Xcode to download the current iOS Simulator runtime." : "iOS Simulator setup must run on a macOS host.",
|
|
3066
3753
|
id: "ios.runtime",
|
|
3067
3754
|
label: "Install iOS Simulator runtime"
|
|
3068
3755
|
}
|
|
@@ -3071,7 +3758,7 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3071
3758
|
}
|
|
3072
3759
|
return {
|
|
3073
3760
|
androidRoot,
|
|
3074
|
-
host,
|
|
3761
|
+
host: host2,
|
|
3075
3762
|
platform: platform2,
|
|
3076
3763
|
steps: [
|
|
3077
3764
|
{
|
|
@@ -3091,15 +3778,15 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3091
3778
|
}
|
|
3092
3779
|
]
|
|
3093
3780
|
};
|
|
3094
|
-
}, releaseFor = (
|
|
3095
|
-
let platform2 =
|
|
3096
|
-
if (
|
|
3781
|
+
}, releaseFor = (host2, arch2) => {
|
|
3782
|
+
let platform2 = host2;
|
|
3783
|
+
if (host2 === "wsl")
|
|
3097
3784
|
platform2 = "windows";
|
|
3098
|
-
if (
|
|
3785
|
+
if (host2 === "macos")
|
|
3099
3786
|
platform2 = "darwin";
|
|
3100
3787
|
const release = COMMAND_LINE_TOOLS[`${platform2}-${arch2}`];
|
|
3101
3788
|
if (!release) {
|
|
3102
|
-
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}.`);
|
|
3103
3790
|
}
|
|
3104
3791
|
return release;
|
|
3105
3792
|
}, installCommandLineTools = async (plan, input) => {
|
|
@@ -3110,10 +3797,10 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3110
3797
|
if (digest !== release.sha256) {
|
|
3111
3798
|
throw new Error(`Android command-line-tools checksum mismatch: expected ${release.sha256}, received ${digest}.`);
|
|
3112
3799
|
}
|
|
3113
|
-
const temporary = await mkdtemp2(
|
|
3800
|
+
const temporary = await mkdtemp2(join11(tmpdir(), "absolutejs-android-sdk-"));
|
|
3114
3801
|
try {
|
|
3115
|
-
const archive =
|
|
3116
|
-
const extracted =
|
|
3802
|
+
const archive = join11(temporary, "command-line-tools.zip");
|
|
3803
|
+
const extracted = join11(temporary, "extracted");
|
|
3117
3804
|
await Bun.write(archive, bytes);
|
|
3118
3805
|
await mkdir3(extracted, { recursive: true });
|
|
3119
3806
|
const extraction = plan.host === "windows" ? [
|
|
@@ -3130,12 +3817,12 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3130
3817
|
if (await input.run(extraction) !== 0) {
|
|
3131
3818
|
throw new Error("Failed to extract Android command-line tools.");
|
|
3132
3819
|
}
|
|
3133
|
-
const destination =
|
|
3134
|
-
await mkdir3(
|
|
3820
|
+
const destination = join11(plan.androidRoot, "cmdline-tools", "latest");
|
|
3821
|
+
await mkdir3(join11(plan.androidRoot, "cmdline-tools"), {
|
|
3135
3822
|
recursive: true
|
|
3136
3823
|
});
|
|
3137
3824
|
await rm3(destination, { force: true, recursive: true });
|
|
3138
|
-
await cp2(
|
|
3825
|
+
await cp2(join11(extracted, "cmdline-tools"), destination, {
|
|
3139
3826
|
recursive: true
|
|
3140
3827
|
});
|
|
3141
3828
|
} finally {
|
|
@@ -3145,9 +3832,9 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3145
3832
|
if (await run(command, options) !== 0) {
|
|
3146
3833
|
throw new Error(`${label} failed.`);
|
|
3147
3834
|
}
|
|
3148
|
-
}, installJavaRuntime = async (
|
|
3149
|
-
if (
|
|
3150
|
-
const winget =
|
|
3835
|
+
}, installJavaRuntime = async (host2, run, which) => {
|
|
3836
|
+
if (host2 === "windows" || host2 === "wsl") {
|
|
3837
|
+
const winget = host2 === "wsl" ? "winget.exe" : "winget";
|
|
3151
3838
|
if (!which(winget)) {
|
|
3152
3839
|
throw new Error("Java 21 is required. Install Temurin 21 or make winget available, then run mobile doctor --fix again.");
|
|
3153
3840
|
}
|
|
@@ -3160,10 +3847,10 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3160
3847
|
"--accept-package-agreements",
|
|
3161
3848
|
"--accept-source-agreements"
|
|
3162
3849
|
];
|
|
3163
|
-
await ensureCommand(
|
|
3850
|
+
await ensureCommand(host2 === "wsl" ? ["cmd.exe", "/d", "/c", ...command] : command, "Java 21 installation", run);
|
|
3164
3851
|
return;
|
|
3165
3852
|
}
|
|
3166
|
-
if (
|
|
3853
|
+
if (host2 === "macos") {
|
|
3167
3854
|
if (!which("brew")) {
|
|
3168
3855
|
throw new Error("Java 21 is required. Install Homebrew or Temurin 21, then run mobile doctor --fix again.");
|
|
3169
3856
|
}
|
|
@@ -3320,7 +4007,7 @@ import {
|
|
|
3320
4007
|
stat,
|
|
3321
4008
|
writeFile as writeFile4
|
|
3322
4009
|
} from "fs/promises";
|
|
3323
|
-
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";
|
|
3324
4011
|
var developmentTeamArgument = (value) => {
|
|
3325
4012
|
if (value === undefined)
|
|
3326
4013
|
return;
|
|
@@ -3377,7 +4064,7 @@ var developmentTeamArgument = (value) => {
|
|
|
3377
4064
|
}, ignoredFingerprintDirectories, fingerprintFiles = async (root, current = root, options = {}) => {
|
|
3378
4065
|
const entries = await readdir3(current, { withFileTypes: true });
|
|
3379
4066
|
const nested = await Promise.all(entries.sort((left, right) => left.name.localeCompare(right.name)).map(async (entry) => {
|
|
3380
|
-
const path =
|
|
4067
|
+
const path = join12(current, entry.name);
|
|
3381
4068
|
const projectRelative = relative4(root, path).replaceAll("\\", "/");
|
|
3382
4069
|
const ignored = entry.isDirectory() && (ignoredFingerprintDirectories.has(entry.name) || projectRelative === "App/App/public" && options.includePublicBundle !== true);
|
|
3383
4070
|
if (ignored)
|
|
@@ -3399,8 +4086,8 @@ var developmentTeamArgument = (value) => {
|
|
|
3399
4086
|
});
|
|
3400
4087
|
return hasher.digest("hex");
|
|
3401
4088
|
}, safeOutputDirectory = (projectRoot, requested) => {
|
|
3402
|
-
const root =
|
|
3403
|
-
const output =
|
|
4089
|
+
const root = resolve8(projectRoot);
|
|
4090
|
+
const output = resolve8(root, requested ?? ".absolutejs/mobile/releases/ios");
|
|
3404
4091
|
const projectRelative = relative4(root, output);
|
|
3405
4092
|
if (projectRelative === ".." || projectRelative.startsWith(`..${sep2}`) || isAbsolute2(projectRelative)) {
|
|
3406
4093
|
throw new TypeError("mobile build --outdir must remain inside the project.");
|
|
@@ -3411,7 +4098,7 @@ var developmentTeamArgument = (value) => {
|
|
|
3411
4098
|
return;
|
|
3412
4099
|
const entries = await readdir3(root, { withFileTypes: true });
|
|
3413
4100
|
const matches = await Promise.all(entries.map(async (entry) => {
|
|
3414
|
-
const path =
|
|
4101
|
+
const path = join12(root, entry.name);
|
|
3415
4102
|
if (entry.isDirectory() && entry.name.endsWith(extension))
|
|
3416
4103
|
return path;
|
|
3417
4104
|
if (entry.isFile() && entry.name.endsWith(extension))
|
|
@@ -3434,10 +4121,10 @@ var developmentTeamArgument = (value) => {
|
|
|
3434
4121
|
throw new TypeError("iOS build number must be a positive integer.");
|
|
3435
4122
|
return value;
|
|
3436
4123
|
}, installRelease = async (artifactPath, metadata, outputRoot) => {
|
|
3437
|
-
const releaseRoot =
|
|
3438
|
-
const destination =
|
|
4124
|
+
const releaseRoot = join12(outputRoot, metadata.releaseId);
|
|
4125
|
+
const destination = join12(releaseRoot, "App.ipa");
|
|
3439
4126
|
if (await pathExists3(releaseRoot)) {
|
|
3440
|
-
const value = JSON.parse(await readFile6(
|
|
4127
|
+
const value = JSON.parse(await readFile6(join12(releaseRoot, "release.json"), "utf8"));
|
|
3441
4128
|
if (!isRecord2(value) || value.artifact !== "App.ipa" || Object.entries(metadata).some(([key, expected]) => Reflect.get(value, key) !== expected)) {
|
|
3442
4129
|
throw new TypeError(`Immutable iOS release ${metadata.releaseId} does not match its content.`);
|
|
3443
4130
|
}
|
|
@@ -3456,15 +4143,15 @@ var developmentTeamArgument = (value) => {
|
|
|
3456
4143
|
releaseRoot
|
|
3457
4144
|
};
|
|
3458
4145
|
}
|
|
3459
|
-
await mkdir4(
|
|
3460
|
-
const staging = await mkdtemp3(
|
|
4146
|
+
await mkdir4(dirname6(releaseRoot), { recursive: true });
|
|
4147
|
+
const staging = await mkdtemp3(join12(dirname6(releaseRoot), ".ios-stage-"));
|
|
3461
4148
|
try {
|
|
3462
|
-
await copyFile2(artifactPath,
|
|
4149
|
+
await copyFile2(artifactPath, join12(staging, "App.ipa"));
|
|
3463
4150
|
const complete = {
|
|
3464
4151
|
...metadata,
|
|
3465
4152
|
artifact: "App.ipa"
|
|
3466
4153
|
};
|
|
3467
|
-
await writeFile4(
|
|
4154
|
+
await writeFile4(join12(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
|
|
3468
4155
|
`, { flag: "wx" });
|
|
3469
4156
|
await rename4(staging, releaseRoot);
|
|
3470
4157
|
return { artifactPath: destination, metadata: complete, releaseRoot };
|
|
@@ -3481,22 +4168,22 @@ var developmentTeamArgument = (value) => {
|
|
|
3481
4168
|
const marketingVersion = options.config.iosVersion;
|
|
3482
4169
|
if (!marketingVersion)
|
|
3483
4170
|
throw new TypeError("iOS release builds require mobile.ios.version in absolutejs.config.ts.");
|
|
3484
|
-
const manifest = requireManifest(JSON.parse(await readFile6(
|
|
4171
|
+
const manifest = requireManifest(JSON.parse(await readFile6(join12(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
|
|
3485
4172
|
if (manifest.appId !== options.config.appId)
|
|
3486
4173
|
throw new TypeError("Embedded mobile manifest appId does not match mobile.appId.");
|
|
3487
|
-
const nativeDirectory =
|
|
4174
|
+
const nativeDirectory = join12(options.config.nativeProjectDirectory, "ios");
|
|
3488
4175
|
let buildNumber = requireBuildNumber(options.buildNumber);
|
|
3489
4176
|
if (options.prepareBuildNumber) {
|
|
3490
4177
|
const nativeFingerprint = await fingerprintAbsoluteIosNativeProject(nativeDirectory);
|
|
3491
4178
|
const buildIdentity = createHash4("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}\x00${marketingVersion}`).digest("hex");
|
|
3492
4179
|
buildNumber = requireBuildNumber(await options.prepareBuildNumber(buildIdentity));
|
|
3493
4180
|
}
|
|
3494
|
-
const stagingParent =
|
|
4181
|
+
const stagingParent = resolve8(options.projectRoot, ".absolutejs/mobile");
|
|
3495
4182
|
await mkdir4(stagingParent, { recursive: true });
|
|
3496
|
-
const staging = await mkdtemp3(
|
|
3497
|
-
const archivePath =
|
|
3498
|
-
const exportPath =
|
|
3499
|
-
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");
|
|
3500
4187
|
await mkdir4(exportPath, { recursive: true });
|
|
3501
4188
|
await writeFile4(exportPlist, exportOptions());
|
|
3502
4189
|
const run = options.run ?? defaultRun2;
|
|
@@ -3510,7 +4197,7 @@ var developmentTeamArgument = (value) => {
|
|
|
3510
4197
|
const archiveExit = await run([
|
|
3511
4198
|
"xcodebuild",
|
|
3512
4199
|
"-workspace",
|
|
3513
|
-
|
|
4200
|
+
join12(nativeDirectory, "App", "App.xcworkspace"),
|
|
3514
4201
|
"-scheme",
|
|
3515
4202
|
"App",
|
|
3516
4203
|
"-configuration",
|
|
@@ -3524,7 +4211,7 @@ var developmentTeamArgument = (value) => {
|
|
|
3524
4211
|
], { cwd: nativeDirectory });
|
|
3525
4212
|
if (archiveExit !== 0)
|
|
3526
4213
|
throw new TypeError("Xcode failed to archive the iOS app.");
|
|
3527
|
-
const archivedApp = await findByExtension(
|
|
4214
|
+
const archivedApp = await findByExtension(join12(archivePath, "Products", "Applications"), ".app");
|
|
3528
4215
|
const capture = options.capture ?? defaultCapture2;
|
|
3529
4216
|
const signed = archivedApp ? capture([
|
|
3530
4217
|
"codesign",
|
|
@@ -3598,7 +4285,7 @@ import {
|
|
|
3598
4285
|
writeFile as writeFile5
|
|
3599
4286
|
} from "fs/promises";
|
|
3600
4287
|
import { isIP as isIP2 } from "net";
|
|
3601
|
-
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";
|
|
3602
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) => {
|
|
3603
4290
|
try {
|
|
3604
4291
|
await access7(path);
|
|
@@ -3816,15 +4503,15 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
3816
4503
|
const leftPro = left.name.includes("Pro") ? 1 : 0;
|
|
3817
4504
|
return rightPro - leftPro;
|
|
3818
4505
|
})[0], journalPaths2 = (projectRoot) => {
|
|
3819
|
-
const root =
|
|
4506
|
+
const root = join13(projectRoot, ".absolutejs", "mobile", "ios-dev-session");
|
|
3820
4507
|
return {
|
|
3821
|
-
configBackup:
|
|
3822
|
-
infoBackup:
|
|
3823
|
-
journal:
|
|
4508
|
+
configBackup: join13(root, "capacitor-config.backup"),
|
|
4509
|
+
infoBackup: join13(root, "Info.plist.backup"),
|
|
4510
|
+
journal: join13(root, "journal.json"),
|
|
3824
4511
|
root
|
|
3825
4512
|
};
|
|
3826
|
-
}, nativeCachePath2 = (projectRoot) =>
|
|
3827
|
-
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));
|
|
3828
4515
|
return value === "" || !value.startsWith(`..${sep3}`) && value !== ".." && !isAbsolute3(value);
|
|
3829
4516
|
}, parseJournal2 = (value) => {
|
|
3830
4517
|
if (!isRecord3(value) || value.format !== DEV_JOURNAL_FORMAT2)
|
|
@@ -3880,8 +4567,8 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
3880
4567
|
}, writeDevProjection = async (project, port, https, serverHost = "localhost") => {
|
|
3881
4568
|
const paths = journalPaths2(project.projectRoot);
|
|
3882
4569
|
await repairAbsoluteIosDevSession(project.projectRoot);
|
|
3883
|
-
const nativeConfigPath =
|
|
3884
|
-
const infoPath =
|
|
4570
|
+
const nativeConfigPath = join13(project.nativeDirectory, "App", "App", "capacitor.config.json");
|
|
4571
|
+
const infoPath = join13(project.nativeDirectory, "App", "App", "Info.plist");
|
|
3885
4572
|
const [configSource, infoSource] = await Promise.all([
|
|
3886
4573
|
readFile7(nativeConfigPath, "utf8"),
|
|
3887
4574
|
readFile7(infoPath, "utf8")
|
|
@@ -3937,7 +4624,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
3937
4624
|
}, readNativeCache2 = (projectRoot) => readFile7(nativeCachePath2(projectRoot), "utf8").then((source) => parseNativeCache2(JSON.parse(source))).catch(() => null), writeNativeCache2 = async (projectRoot, cache) => {
|
|
3938
4625
|
const destination = nativeCachePath2(projectRoot);
|
|
3939
4626
|
const temporary = `${destination}.${process.pid}.${randomUUID3()}.tmp`;
|
|
3940
|
-
await mkdir5(
|
|
4627
|
+
await mkdir5(dirname7(destination), { recursive: true });
|
|
3941
4628
|
try {
|
|
3942
4629
|
await writeFile5(temporary, `${JSON.stringify(cache, null, "\t")}
|
|
3943
4630
|
`, {
|
|
@@ -4042,12 +4729,12 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4042
4729
|
]);
|
|
4043
4730
|
return result.exitCode === 0 && result.stdout.includes(project.config.appId);
|
|
4044
4731
|
}, buildIosDebugApp = async (project, udid, fingerprint, run, signal) => {
|
|
4045
|
-
const derivedDataPath =
|
|
4732
|
+
const derivedDataPath = join13(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash5("sha256").update(project.config.appId).digest("hex").slice(0, 16));
|
|
4046
4733
|
await mkdir5(derivedDataPath, { recursive: true });
|
|
4047
4734
|
await requireSuccess2([
|
|
4048
4735
|
project.xcodebuild,
|
|
4049
4736
|
"-workspace",
|
|
4050
|
-
|
|
4737
|
+
join13(project.nativeDirectory, "App", "App.xcworkspace"),
|
|
4051
4738
|
"-scheme",
|
|
4052
4739
|
"App",
|
|
4053
4740
|
"-configuration",
|
|
@@ -4058,17 +4745,17 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4058
4745
|
derivedDataPath,
|
|
4059
4746
|
"build"
|
|
4060
4747
|
], "iOS simulator build", run, { cwd: project.nativeDirectory, signal });
|
|
4061
|
-
const appPath =
|
|
4748
|
+
const appPath = join13(derivedDataPath, "Build", "Products", "Debug-iphonesimulator", "App.app");
|
|
4062
4749
|
if (!await pathExists4(appPath))
|
|
4063
4750
|
throw new Error(`Xcode did not produce the simulator app at ${appPath}.`);
|
|
4064
4751
|
return appPath;
|
|
4065
4752
|
}, buildPhysicalIosDebugApp = async (project, identifier, run, signal) => {
|
|
4066
|
-
const derivedDataPath =
|
|
4753
|
+
const derivedDataPath = join13(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash5("sha256").update(project.config.appId).digest("hex").slice(0, 16));
|
|
4067
4754
|
await mkdir5(derivedDataPath, { recursive: true });
|
|
4068
4755
|
await requireSuccess2([
|
|
4069
4756
|
project.xcodebuild,
|
|
4070
4757
|
"-workspace",
|
|
4071
|
-
|
|
4758
|
+
join13(project.nativeDirectory, "App", "App.xcworkspace"),
|
|
4072
4759
|
"-scheme",
|
|
4073
4760
|
"App",
|
|
4074
4761
|
"-configuration",
|
|
@@ -4080,7 +4767,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4080
4767
|
"-allowProvisioningUpdates",
|
|
4081
4768
|
"build"
|
|
4082
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 });
|
|
4083
|
-
const appPath =
|
|
4770
|
+
const appPath = join13(derivedDataPath, "Build", "Products", "Debug-iphoneos", "App.app");
|
|
4084
4771
|
if (!await pathExists4(appPath))
|
|
4085
4772
|
throw new Error(`Xcode did not produce the physical-device app at ${appPath}.`);
|
|
4086
4773
|
return appPath;
|
|
@@ -4191,7 +4878,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4191
4878
|
if (detectAbsoluteMobileHost() !== "macos")
|
|
4192
4879
|
throw new Error("iOS development requires macOS and Xcode.");
|
|
4193
4880
|
const target = options.target ?? "simulator";
|
|
4194
|
-
const projectRoot =
|
|
4881
|
+
const projectRoot = resolve9(options.projectRoot);
|
|
4195
4882
|
const checks = await inspectAbsoluteMobileToolchain({ host: "macos" });
|
|
4196
4883
|
const failed = checks.filter((check) => check.platform === "ios" && !(target === "device" && check.id === "ios.runtime") && (check.status === "fail" || check.status === "warn"));
|
|
4197
4884
|
if (failed.length > 0)
|
|
@@ -4200,16 +4887,16 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4200
4887
|
const xcodebuild = checks.find((check) => check.id === "ios.xcodebuild")?.path;
|
|
4201
4888
|
if (!xcrun || !xcodebuild)
|
|
4202
4889
|
throw new Error("Xcode tools disappeared after readiness checks.");
|
|
4203
|
-
const cap =
|
|
4890
|
+
const cap = join13(projectRoot, "node_modules", ".bin", "cap");
|
|
4204
4891
|
if (!await pathExists4(cap))
|
|
4205
4892
|
throw new Error("Capacitor CLI is not installed. Run absolute mobile init first.");
|
|
4206
4893
|
await writeAbsoluteCapacitorConfig(config, { projectRoot });
|
|
4207
4894
|
await mkdir5(config.bundleDirectory, { recursive: true });
|
|
4208
|
-
const placeholder =
|
|
4895
|
+
const placeholder = join13(config.bundleDirectory, "index.html");
|
|
4209
4896
|
if (!await pathExists4(placeholder))
|
|
4210
4897
|
await writeFile5(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
|
|
4211
4898
|
`);
|
|
4212
|
-
const nativeDirectory =
|
|
4899
|
+
const nativeDirectory = join13(config.nativeProjectDirectory, "ios");
|
|
4213
4900
|
if (!await pathExists4(nativeDirectory)) {
|
|
4214
4901
|
if (!options.createNativeProject)
|
|
4215
4902
|
throw new Error("iOS native project has not been created.");
|
|
@@ -4434,10 +5121,10 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4434
5121
|
screenshot: async (destination) => {
|
|
4435
5122
|
if (deviceIdentifier)
|
|
4436
5123
|
throw new Error("Physical iOS screenshots are captured in Xcode Device Hub; the CLI never records a device screen automatically.");
|
|
4437
|
-
const resolved =
|
|
5124
|
+
const resolved = resolve9(project.projectRoot, destination);
|
|
4438
5125
|
if (!isInside2(project.projectRoot, resolved))
|
|
4439
5126
|
throw new Error("iOS screenshot destination must remain inside the project.");
|
|
4440
|
-
await mkdir5(
|
|
5127
|
+
await mkdir5(dirname7(resolved), { recursive: true });
|
|
4441
5128
|
await requireSuccess2([
|
|
4442
5129
|
project.xcrun,
|
|
4443
5130
|
"simctl",
|
|
@@ -4496,15 +5183,15 @@ import { chmod, mkdir as mkdir6, readFile as readFile8, rename as rename6, write
|
|
|
4496
5183
|
import { homedir as homedir4 } from "os";
|
|
4497
5184
|
import { isIP as isIP3 } from "net";
|
|
4498
5185
|
import {
|
|
4499
|
-
dirname as
|
|
5186
|
+
dirname as dirname8,
|
|
4500
5187
|
isAbsolute as isAbsolute4,
|
|
4501
|
-
join as
|
|
5188
|
+
join as join14,
|
|
4502
5189
|
posix,
|
|
4503
5190
|
relative as relative6,
|
|
4504
5191
|
resolve as resolvePath,
|
|
4505
5192
|
sep as sep4
|
|
4506
5193
|
} from "path";
|
|
4507
|
-
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 = () => ({
|
|
4508
5195
|
format: PROFILE_FORMAT,
|
|
4509
5196
|
profiles: {}
|
|
4510
5197
|
}), loadStore = async (path = defaultProfilePath()) => {
|
|
@@ -4525,7 +5212,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4525
5212
|
throw error;
|
|
4526
5213
|
}
|
|
4527
5214
|
}, saveStore = async (store, path = defaultProfilePath()) => {
|
|
4528
|
-
await mkdir6(
|
|
5215
|
+
await mkdir6(dirname8(path), { recursive: true });
|
|
4529
5216
|
const temporary = `${path}.${randomUUID4()}.tmp`;
|
|
4530
5217
|
await writeFile6(temporary, `${JSON.stringify(store, null, 2)}
|
|
4531
5218
|
`, {
|
|
@@ -4627,10 +5314,10 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4627
5314
|
"/bin/sh -lc",
|
|
4628
5315
|
shellQuote(script)
|
|
4629
5316
|
]);
|
|
4630
|
-
const
|
|
4631
|
-
if (isIP3(
|
|
5317
|
+
const host2 = requireRemoteSuccess(result, "Remote Mac LAN address discovery").trim();
|
|
5318
|
+
if (isIP3(host2) === 0)
|
|
4632
5319
|
throw new Error("The Remote Mac did not report a device-reachable LAN address.");
|
|
4633
|
-
return
|
|
5320
|
+
return host2;
|
|
4634
5321
|
}, listAbsoluteRemoteMacProfiles = async (profilePath) => {
|
|
4635
5322
|
const store = await loadStore(profilePath);
|
|
4636
5323
|
return {
|
|
@@ -4680,9 +5367,9 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4680
5367
|
throw new TypeError("Remote Expo execution requires mobile.engine: expo.");
|
|
4681
5368
|
return createAbsoluteRemoteIosDevProject(config, projectRoot, profile);
|
|
4682
5369
|
}, createAbsoluteRemoteIosDevProject = (config, projectRoot, profile) => ({
|
|
4683
|
-
cap:
|
|
5370
|
+
cap: join14(resolvePath(projectRoot), "node_modules", ".bin", "cap"),
|
|
4684
5371
|
config,
|
|
4685
|
-
nativeDirectory:
|
|
5372
|
+
nativeDirectory: join14(config.nativeProjectDirectory, "ios"),
|
|
4686
5373
|
profile,
|
|
4687
5374
|
projectRoot: resolvePath(projectRoot),
|
|
4688
5375
|
remote: true,
|
|
@@ -4729,8 +5416,8 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4729
5416
|
return { ...artifact, remotePath, uploaded: true };
|
|
4730
5417
|
}, materializeAbsoluteRemoteMacAgent = async (projectRoot) => {
|
|
4731
5418
|
const shippedCandidates = [
|
|
4732
|
-
|
|
4733
|
-
|
|
5419
|
+
join14(import.meta.dir, "remoteMacAgentEntry.js"),
|
|
5420
|
+
join14(import.meta.dir, "..", "mobile", "remoteMacAgentEntry.js")
|
|
4734
5421
|
];
|
|
4735
5422
|
let path;
|
|
4736
5423
|
for (const candidate of shippedCandidates) {
|
|
@@ -4741,13 +5428,13 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4741
5428
|
}
|
|
4742
5429
|
if (!path) {
|
|
4743
5430
|
const sourceCandidates = [
|
|
4744
|
-
|
|
4745
|
-
|
|
5431
|
+
join14(import.meta.dir, "remoteMacAgentEntry.ts"),
|
|
5432
|
+
join14(import.meta.dir, "..", "..", "src", "mobile", "remoteMacAgentEntry.ts")
|
|
4746
5433
|
];
|
|
4747
5434
|
const source = await sourceCandidates.reduce(async (found, candidate) => await found ?? (await Bun.file(candidate).exists() ? candidate : undefined), Promise.resolve(undefined));
|
|
4748
5435
|
if (!source)
|
|
4749
5436
|
throw new Error("The AbsoluteJS installation does not contain its remote Mac agent artifact.");
|
|
4750
|
-
const outdir =
|
|
5437
|
+
const outdir = join14(resolvePath(projectRoot), ".absolutejs", "mobile", "remote-agent");
|
|
4751
5438
|
await mkdir6(outdir, { recursive: true });
|
|
4752
5439
|
const result = await Bun.build({
|
|
4753
5440
|
entrypoints: [source],
|
|
@@ -4757,7 +5444,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4757
5444
|
});
|
|
4758
5445
|
if (!result.success)
|
|
4759
5446
|
throw new AggregateError(result.logs, "Failed to build the AbsoluteJS remote Mac agent.");
|
|
4760
|
-
path =
|
|
5447
|
+
path = join14(outdir, "remoteMacAgentEntry.js");
|
|
4761
5448
|
}
|
|
4762
5449
|
const bytes = await Bun.file(path).arrayBuffer();
|
|
4763
5450
|
const sha256 = createHash6("sha256").update(new Uint8Array(bytes)).digest("hex");
|
|
@@ -4978,8 +5665,8 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4978
5665
|
const pending = new Map;
|
|
4979
5666
|
let resolveReady;
|
|
4980
5667
|
let rejectReady;
|
|
4981
|
-
const readyPromise = new Promise((
|
|
4982
|
-
resolveReady =
|
|
5668
|
+
const readyPromise = new Promise((resolve10, reject) => {
|
|
5669
|
+
resolveReady = resolve10;
|
|
4983
5670
|
rejectReady = reject;
|
|
4984
5671
|
});
|
|
4985
5672
|
const handleEvent = (event) => {
|
|
@@ -5080,7 +5767,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
5080
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.`);
|
|
5081
5768
|
const request = (commandName) => {
|
|
5082
5769
|
const id = randomUUID4();
|
|
5083
|
-
const response = new Promise((
|
|
5770
|
+
const response = new Promise((resolve10, reject) => pending.set(id, { reject, resolve: resolve10 }));
|
|
5084
5771
|
process2.stdin.write(`${JSON.stringify({ command: commandName, id, v: ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION })}
|
|
5085
5772
|
`);
|
|
5086
5773
|
const flush = async () => {
|
|
@@ -5100,7 +5787,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
5100
5787
|
if (closed)
|
|
5101
5788
|
return;
|
|
5102
5789
|
closed = true;
|
|
5103
|
-
const timeout = () => new Promise((
|
|
5790
|
+
const timeout = () => new Promise((resolve10) => setTimeout(() => resolve10("timeout"), REMOTE_SESSION_CLOSE_TIMEOUT_MS));
|
|
5104
5791
|
await Promise.race([
|
|
5105
5792
|
request("close").catch(() => {
|
|
5106
5793
|
return;
|
|
@@ -5151,7 +5838,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
5151
5838
|
const targetRelative = relative6(options.project.projectRoot, target);
|
|
5152
5839
|
if (targetRelative.startsWith("..") || isAbsolute4(targetRelative))
|
|
5153
5840
|
throw new Error("iOS screenshot must remain inside the project.");
|
|
5154
|
-
await mkdir6(
|
|
5841
|
+
await mkdir6(dirname8(target), { recursive: true });
|
|
5155
5842
|
await writeFile6(target, Buffer.from(result.data, "base64"));
|
|
5156
5843
|
return target;
|
|
5157
5844
|
},
|
|
@@ -5178,44 +5865,44 @@ var init_remoteMacProtocol = __esm(() => {
|
|
|
5178
5865
|
// src/dev/devCert.ts
|
|
5179
5866
|
var exports_devCert = {};
|
|
5180
5867
|
__export(exports_devCert, {
|
|
5181
|
-
|
|
5182
|
-
normalizeDevCertificateHosts: () => normalizeDevCertificateHosts,
|
|
5183
|
-
loadDevCert: () => loadDevCert,
|
|
5184
|
-
hasMkcert: () => hasMkcert,
|
|
5185
|
-
hasCert: () => hasCert,
|
|
5868
|
+
ensureDevCert: () => ensureDevCert,
|
|
5186
5869
|
getDevCertificateAuthorityPath: () => getDevCertificateAuthorityPath,
|
|
5187
|
-
|
|
5870
|
+
hasCert: () => hasCert,
|
|
5871
|
+
hasMkcert: () => hasMkcert,
|
|
5872
|
+
loadDevCert: () => loadDevCert,
|
|
5873
|
+
normalizeDevCertificateHosts: () => normalizeDevCertificateHosts,
|
|
5874
|
+
setupMkcert: () => setupMkcert
|
|
5188
5875
|
});
|
|
5189
5876
|
import {
|
|
5190
5877
|
copyFileSync,
|
|
5191
5878
|
existsSync as existsSync4,
|
|
5192
5879
|
mkdirSync as mkdirSync4,
|
|
5193
|
-
readFileSync as
|
|
5880
|
+
readFileSync as readFileSync8,
|
|
5194
5881
|
rmSync
|
|
5195
5882
|
} from "fs";
|
|
5196
5883
|
import { X509Certificate as X509Certificate2 } from "crypto";
|
|
5197
5884
|
import { isIP as isIP4 } from "net";
|
|
5198
5885
|
import { platform as platform2 } from "os";
|
|
5199
|
-
import { join as
|
|
5886
|
+
import { join as join15 } from "path";
|
|
5200
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 = []) => {
|
|
5201
5888
|
const normalized = new Set(DEFAULT_CERTIFICATE_HOSTS);
|
|
5202
|
-
for (const
|
|
5203
|
-
const value =
|
|
5889
|
+
for (const host2 of hosts) {
|
|
5890
|
+
const value = host2.trim().toLowerCase();
|
|
5204
5891
|
if (!value || value === "0.0.0.0" || value === "::")
|
|
5205
5892
|
continue;
|
|
5206
5893
|
if (isIP4(value) === 0 && !CERTIFICATE_HOSTNAME_PATTERN.test(value)) {
|
|
5207
|
-
throw new TypeError(`Invalid development certificate host: ${
|
|
5894
|
+
throw new TypeError(`Invalid development certificate host: ${host2}`);
|
|
5208
5895
|
}
|
|
5209
5896
|
normalized.add(value);
|
|
5210
5897
|
}
|
|
5211
5898
|
return [...normalized];
|
|
5212
5899
|
}, certificateIsUsable = (hosts) => {
|
|
5213
5900
|
try {
|
|
5214
|
-
const certPem =
|
|
5901
|
+
const certPem = readFileSync8(CERT_PATH, "utf-8");
|
|
5215
5902
|
const certificate = new X509Certificate2(certPem);
|
|
5216
5903
|
if (new Date(certificate.validTo).getTime() <= Date.now())
|
|
5217
5904
|
return false;
|
|
5218
|
-
return normalizeDevCertificateHosts(hosts).every((
|
|
5905
|
+
return normalizeDevCertificateHosts(hosts).every((host2) => isIP4(host2) ? certificate.checkIP(host2) !== undefined : certificate.checkHost(host2) !== undefined);
|
|
5219
5906
|
} catch {
|
|
5220
5907
|
return false;
|
|
5221
5908
|
}
|
|
@@ -5243,7 +5930,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5243
5930
|
throw new Error(`mkcert failed: ${err}`);
|
|
5244
5931
|
}
|
|
5245
5932
|
}, generateSelfSigned = (hosts = []) => {
|
|
5246
|
-
const subjectAlternativeNames = normalizeDevCertificateHosts(hosts).map((
|
|
5933
|
+
const subjectAlternativeNames = normalizeDevCertificateHosts(hosts).map((host2) => `${isIP4(host2) ? "IP" : "DNS"}:${host2}`).join(",");
|
|
5247
5934
|
const proc = Bun.spawnSync([
|
|
5248
5935
|
"openssl",
|
|
5249
5936
|
"req",
|
|
@@ -5296,8 +5983,8 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5296
5983
|
return null;
|
|
5297
5984
|
try {
|
|
5298
5985
|
return {
|
|
5299
|
-
cert:
|
|
5300
|
-
key:
|
|
5986
|
+
cert: readFileSync8(paths.cert, "utf-8"),
|
|
5987
|
+
key: readFileSync8(paths.key, "utf-8")
|
|
5301
5988
|
};
|
|
5302
5989
|
} catch {
|
|
5303
5990
|
return null;
|
|
@@ -5393,7 +6080,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5393
6080
|
if (platform2() !== "linux")
|
|
5394
6081
|
return false;
|
|
5395
6082
|
try {
|
|
5396
|
-
return /microsoft|wsl/i.test(
|
|
6083
|
+
return /microsoft|wsl/i.test(readFileSync8("/proc/version", "utf-8"));
|
|
5397
6084
|
} catch {
|
|
5398
6085
|
return false;
|
|
5399
6086
|
}
|
|
@@ -5409,7 +6096,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5409
6096
|
}
|
|
5410
6097
|
}, mkcertCaRoot = () => runCapture(["mkcert", "-CAROOT"]), getDevCertificateAuthorityPath = () => {
|
|
5411
6098
|
const caRoot = hasMkcert() ? mkcertCaRoot() : null;
|
|
5412
|
-
const rootCertificate = caRoot ?
|
|
6099
|
+
const rootCertificate = caRoot ? join15(caRoot, "rootCA.pem") : null;
|
|
5413
6100
|
if (rootCertificate && existsSync4(rootCertificate))
|
|
5414
6101
|
return rootCertificate;
|
|
5415
6102
|
if (certFilesExist())
|
|
@@ -5424,13 +6111,13 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5424
6111
|
const caRoot = mkcertCaRoot();
|
|
5425
6112
|
if (!caRoot)
|
|
5426
6113
|
return false;
|
|
5427
|
-
const rootCa =
|
|
6114
|
+
const rootCa = join15(caRoot, "rootCA.pem");
|
|
5428
6115
|
if (!existsSync4(rootCa))
|
|
5429
6116
|
return false;
|
|
5430
6117
|
const winTemp = windowsTempDir();
|
|
5431
6118
|
if (!winTemp)
|
|
5432
6119
|
return false;
|
|
5433
|
-
const staged =
|
|
6120
|
+
const staged = join15(winTemp, "absolutejs-mkcert-rootCA.crt");
|
|
5434
6121
|
try {
|
|
5435
6122
|
copyFileSync(rootCa, staged);
|
|
5436
6123
|
} catch {
|
|
@@ -5466,7 +6153,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5466
6153
|
devLog("Trusted the local CA in the Windows store \u2014 Chrome/Edge on Windows now accept dev HTTPS");
|
|
5467
6154
|
} else {
|
|
5468
6155
|
const caRoot = mkcertCaRoot();
|
|
5469
|
-
const hint = caRoot ? toWindowsPath(
|
|
6156
|
+
const hint = caRoot ? toWindowsPath(join15(caRoot, "rootCA.pem")) : null;
|
|
5470
6157
|
devWarn("Could not auto-trust the local CA on Windows; Windows browsers may warn.");
|
|
5471
6158
|
if (hint) {
|
|
5472
6159
|
console.log(` Run in PowerShell: Import-Certificate -FilePath "${hint}" -CertStoreLocation Cert:\\CurrentUser\\Root`);
|
|
@@ -5482,9 +6169,9 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5482
6169
|
return true;
|
|
5483
6170
|
};
|
|
5484
6171
|
var init_devCert = __esm(() => {
|
|
5485
|
-
CERT_DIR =
|
|
5486
|
-
CERT_PATH =
|
|
5487
|
-
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");
|
|
5488
6175
|
DEFAULT_CERTIFICATE_HOSTS = ["localhost", "127.0.0.1", "::1"];
|
|
5489
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;
|
|
5490
6177
|
});
|
|
@@ -5492,16 +6179,16 @@ var init_devCert = __esm(() => {
|
|
|
5492
6179
|
// src/cli/scripts/eslintChunked.ts
|
|
5493
6180
|
var exports_eslintChunked = {};
|
|
5494
6181
|
__export(exports_eslintChunked, {
|
|
5495
|
-
|
|
5496
|
-
ruleSummary: () => ruleSummary,
|
|
5497
|
-
resolveLintTargets: () => resolveLintTargets,
|
|
5498
|
-
parseChunkedArgs: () => parseChunkedArgs,
|
|
5499
|
-
gitVisibleFiles: () => gitVisibleFiles,
|
|
6182
|
+
eslintChunked: () => eslintChunked,
|
|
5500
6183
|
gitChangedFiles: () => gitChangedFiles,
|
|
5501
|
-
|
|
6184
|
+
gitVisibleFiles: () => gitVisibleFiles,
|
|
6185
|
+
parseChunkedArgs: () => parseChunkedArgs,
|
|
6186
|
+
resolveLintTargets: () => resolveLintTargets,
|
|
6187
|
+
ruleSummary: () => ruleSummary,
|
|
6188
|
+
upstreamRef: () => upstreamRef
|
|
5502
6189
|
});
|
|
5503
6190
|
import { existsSync as existsSync6 } from "fs";
|
|
5504
|
-
import { relative as relative7, resolve as
|
|
6191
|
+
import { relative as relative7, resolve as resolve10 } from "path";
|
|
5505
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(`
|
|
5506
6193
|
`).map((line) => line.trimEnd()).filter(Boolean), applyChangedBase = (parsed, base) => {
|
|
5507
6194
|
parsed.changedOnly = true;
|
|
@@ -5513,7 +6200,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
|
|
|
5513
6200
|
}, matchesAnyGlob = (file, globs) => globs.some((pattern) => new Bun.Glob(pattern).match(file)), resolveLintSet = (parsed, cwd) => {
|
|
5514
6201
|
const visible = gitVisibleFiles(cwd);
|
|
5515
6202
|
const matched = parsed.globs.length === 0 ? visible.filter((file) => LINTABLE_EXTENSIONS.test(file)) : visible.filter((file) => matchesAnyGlob(file, parsed.globs));
|
|
5516
|
-
return matched.filter((file) => existsSync6(
|
|
6203
|
+
return matched.filter((file) => existsSync6(resolve10(cwd, file))).sort();
|
|
5517
6204
|
}, resolveLintTargets = (args, cwd = process.cwd()) => resolveLintSet(parseChunkedArgs(args), cwd), buildShardChunks = (files, shards, chunkSize) => {
|
|
5518
6205
|
const shardFiles = Array.from({ length: shards }, () => []);
|
|
5519
6206
|
for (const file of files)
|
|
@@ -5535,7 +6222,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
|
|
|
5535
6222
|
"content"
|
|
5536
6223
|
];
|
|
5537
6224
|
const proc = Bun.spawn([
|
|
5538
|
-
|
|
6225
|
+
resolve10(cwd, "node_modules/.bin/eslint"),
|
|
5539
6226
|
"--color",
|
|
5540
6227
|
...hasMaxWarnings ? [] : ["--max-warnings", "0"],
|
|
5541
6228
|
...cacheArgs,
|
|
@@ -5582,7 +6269,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
|
|
|
5582
6269
|
const fingerprint = createEslintCacheFingerprint(cwd);
|
|
5583
6270
|
for (let shard = 0;shard < parsed.shards; shard++)
|
|
5584
6271
|
prepareEslintCache({
|
|
5585
|
-
cacheLocation: relative7(cwd,
|
|
6272
|
+
cacheLocation: relative7(cwd, resolve10(cwd, `${cachePrefix}${shard}`)),
|
|
5586
6273
|
cwd,
|
|
5587
6274
|
fingerprint
|
|
5588
6275
|
});
|
|
@@ -5623,7 +6310,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
|
|
|
5623
6310
|
const header = `eslint report \u2014 ${files.length} files, ${totalChunks} chunks, ${elapsed}s
|
|
5624
6311
|
${"=".repeat(SUMMARY_RULE_WIDTH)}
|
|
5625
6312
|
`;
|
|
5626
|
-
await Bun.write(
|
|
6313
|
+
await Bun.write(resolve10(cwd, parsed.outFile), header + report + summary);
|
|
5627
6314
|
console.log(summary);
|
|
5628
6315
|
console.log(`Full report written to ${parsed.outFile}`);
|
|
5629
6316
|
if (failedChunks > 0) {
|
|
@@ -5712,12 +6399,12 @@ import { createHash as createHash7 } from "crypto";
|
|
|
5712
6399
|
import {
|
|
5713
6400
|
existsSync as existsSync7,
|
|
5714
6401
|
mkdirSync as mkdirSync5,
|
|
5715
|
-
readFileSync as
|
|
6402
|
+
readFileSync as readFileSync10,
|
|
5716
6403
|
renameSync,
|
|
5717
6404
|
rmSync as rmSync3,
|
|
5718
6405
|
writeFileSync as writeFileSync5
|
|
5719
6406
|
} from "fs";
|
|
5720
|
-
import { dirname as
|
|
6407
|
+
import { dirname as dirname9, relative as relative8, resolve as resolve11 } from "path";
|
|
5721
6408
|
var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION = "1", CACHE_FINGERPRINT_SUFFIX = ".fingerprint", flagValue = (args, flag) => {
|
|
5722
6409
|
const assignment = args.find((arg) => arg.startsWith(`${flag}=`));
|
|
5723
6410
|
if (assignment)
|
|
@@ -5741,20 +6428,20 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
|
|
|
5741
6428
|
return false;
|
|
5742
6429
|
}, findEslintConfigPath = (cwd = process.cwd()) => {
|
|
5743
6430
|
for (const name of CONFIG_CANDIDATES) {
|
|
5744
|
-
const candidate =
|
|
6431
|
+
const candidate = resolve11(cwd, name);
|
|
5745
6432
|
if (existsSync7(candidate))
|
|
5746
6433
|
return candidate;
|
|
5747
6434
|
}
|
|
5748
6435
|
return null;
|
|
5749
6436
|
}, fingerprintLocation = (cacheLocation, cwd) => {
|
|
5750
|
-
const absolute =
|
|
5751
|
-
return /[\\/]$/.test(cacheLocation) ?
|
|
6437
|
+
const absolute = resolve11(cwd, cacheLocation);
|
|
6438
|
+
return /[\\/]$/.test(cacheLocation) ? resolve11(absolute, CACHE_FINGERPRINT_SUFFIX.slice(1)) : `${absolute}${CACHE_FINGERPRINT_SUFFIX}`;
|
|
5752
6439
|
}, addFileToFingerprint = (hash, path, label) => {
|
|
5753
6440
|
if (!existsSync7(path))
|
|
5754
6441
|
return;
|
|
5755
6442
|
hash.update(label);
|
|
5756
6443
|
hash.update("\x00");
|
|
5757
|
-
hash.update(
|
|
6444
|
+
hash.update(readFileSync10(path));
|
|
5758
6445
|
hash.update("\x00");
|
|
5759
6446
|
}, packageNameFor = (specifier) => {
|
|
5760
6447
|
if (specifier.startsWith("@"))
|
|
@@ -5764,7 +6451,7 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
|
|
|
5764
6451
|
}, configPackageNames = (configPath2) => {
|
|
5765
6452
|
if (!configPath2)
|
|
5766
6453
|
return [];
|
|
5767
|
-
const source =
|
|
6454
|
+
const source = readFileSync10(configPath2, "utf-8");
|
|
5768
6455
|
const names = new Set;
|
|
5769
6456
|
for (const match of source.matchAll(/(?:from\s+|import\s*(?:\(\s*)?|require\s*\(\s*)(['"])([^'".][^'"]*)\1/g)) {
|
|
5770
6457
|
const [, , specifier] = match;
|
|
@@ -5783,11 +6470,11 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
|
|
|
5783
6470
|
return Object.keys(value);
|
|
5784
6471
|
});
|
|
5785
6472
|
}, lintDependencyNames = (cwd, configPath2) => {
|
|
5786
|
-
const manifestPath =
|
|
6473
|
+
const manifestPath = resolve11(cwd, "package.json");
|
|
5787
6474
|
if (!existsSync7(manifestPath))
|
|
5788
6475
|
return configPackageNames(configPath2);
|
|
5789
6476
|
try {
|
|
5790
|
-
const manifest = JSON.parse(
|
|
6477
|
+
const manifest = JSON.parse(readFileSync10(manifestPath, "utf-8"));
|
|
5791
6478
|
const lintPackages = manifestDependencyNames(manifest).filter((name) => /eslint|typescript/.test(name));
|
|
5792
6479
|
return [
|
|
5793
6480
|
...new Set([...lintPackages, ...configPackageNames(configPath2)])
|
|
@@ -5798,10 +6485,10 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
|
|
|
5798
6485
|
}, findInstalledManifest = (cwd, dependency) => {
|
|
5799
6486
|
let directory = cwd;
|
|
5800
6487
|
while (true) {
|
|
5801
|
-
const candidate =
|
|
6488
|
+
const candidate = resolve11(directory, "node_modules", dependency, "package.json");
|
|
5802
6489
|
if (existsSync7(candidate))
|
|
5803
6490
|
return candidate;
|
|
5804
|
-
const parent =
|
|
6491
|
+
const parent = dirname9(directory);
|
|
5805
6492
|
if (parent === directory)
|
|
5806
6493
|
return null;
|
|
5807
6494
|
directory = parent;
|
|
@@ -5824,17 +6511,17 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
|
|
|
5824
6511
|
addFileToFingerprint(hash, configPath2, relative8(cwd, configPath2));
|
|
5825
6512
|
return hash.digest("hex");
|
|
5826
6513
|
}, writeFingerprint = (path, fingerprint) => {
|
|
5827
|
-
mkdirSync5(
|
|
6514
|
+
mkdirSync5(dirname9(path), { recursive: true });
|
|
5828
6515
|
const temporary = `${path}.${process.pid}.tmp`;
|
|
5829
6516
|
writeFileSync5(temporary, `${fingerprint}
|
|
5830
6517
|
`);
|
|
5831
6518
|
renameSync(temporary, path);
|
|
5832
6519
|
}, prepareEslintCache = (options) => {
|
|
5833
6520
|
const cwd = options.cwd ?? process.cwd();
|
|
5834
|
-
const cachePath =
|
|
6521
|
+
const cachePath = resolve11(cwd, options.cacheLocation);
|
|
5835
6522
|
const metadataPath = fingerprintLocation(options.cacheLocation, cwd);
|
|
5836
6523
|
const fingerprint = options.fingerprint ?? createEslintCacheFingerprint(cwd);
|
|
5837
|
-
const prior = existsSync7(metadataPath) ?
|
|
6524
|
+
const prior = existsSync7(metadataPath) ? readFileSync10(metadataPath, "utf-8").trim() : null;
|
|
5838
6525
|
if (prior === fingerprint)
|
|
5839
6526
|
return false;
|
|
5840
6527
|
rmSync3(cachePath, { force: true, recursive: true });
|
|
@@ -5922,7 +6609,7 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
|
|
|
5922
6609
|
return;
|
|
5923
6610
|
let source;
|
|
5924
6611
|
try {
|
|
5925
|
-
source =
|
|
6612
|
+
source = readFileSync10(configPath2, "utf-8");
|
|
5926
6613
|
} catch {
|
|
5927
6614
|
return;
|
|
5928
6615
|
}
|
|
@@ -5961,7 +6648,7 @@ Detected at: ${configPath2}${reset}`);
|
|
|
5961
6648
|
return `${minutes}m ${seconds}s`;
|
|
5962
6649
|
}, handleClearCache = (cacheLocation, cwd = process.cwd()) => {
|
|
5963
6650
|
try {
|
|
5964
|
-
const cachePath =
|
|
6651
|
+
const cachePath = resolve11(cwd, cacheLocation);
|
|
5965
6652
|
const metadataPath = fingerprintLocation(cacheLocation, cwd);
|
|
5966
6653
|
rmSync3(cachePath, { force: true, recursive: true });
|
|
5967
6654
|
rmSync3(metadataPath, { force: true, recursive: true });
|
|
@@ -5990,7 +6677,7 @@ Detected at: ${configPath2}${reset}`);
|
|
|
5990
6677
|
return;
|
|
5991
6678
|
}
|
|
5992
6679
|
if (args.includes("--chunked")) {
|
|
5993
|
-
if (!existsSync7(
|
|
6680
|
+
if (!existsSync7(resolve11("node_modules", ".bin", "eslint"))) {
|
|
5994
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");
|
|
5995
6682
|
process.exit(1);
|
|
5996
6683
|
}
|
|
@@ -5998,7 +6685,7 @@ Detected at: ${configPath2}${reset}`);
|
|
|
5998
6685
|
await eslintChunked2(args);
|
|
5999
6686
|
return;
|
|
6000
6687
|
}
|
|
6001
|
-
if (!existsSync7(
|
|
6688
|
+
if (!existsSync7(resolve11("node_modules", ".bin", "eslint"))) {
|
|
6002
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");
|
|
6003
6690
|
process.exit(1);
|
|
6004
6691
|
}
|
|
@@ -6175,21 +6862,21 @@ var stripStringsAndComments = (source) => {
|
|
|
6175
6862
|
};
|
|
6176
6863
|
|
|
6177
6864
|
// src/core/islandManifest.ts
|
|
6178
|
-
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}`;
|
|
6179
6866
|
|
|
6180
6867
|
// src/core/islands.ts
|
|
6181
|
-
var isRecord4 = (value) => typeof value === "object" && value !== null, getIslandBuildReference = (
|
|
6182
|
-
if (!isIslandComponentDefinition(
|
|
6868
|
+
var isRecord4 = (value) => typeof value === "object" && value !== null, getIslandBuildReference = (component2) => {
|
|
6869
|
+
if (!isIslandComponentDefinition(component2))
|
|
6183
6870
|
return null;
|
|
6184
6871
|
return {
|
|
6185
|
-
export:
|
|
6186
|
-
source:
|
|
6872
|
+
export: component2.export,
|
|
6873
|
+
source: component2.source
|
|
6187
6874
|
};
|
|
6188
6875
|
}, isIslandComponentDefinition = (value) => isRecord4(value) && ("component" in value) && ("source" in value) && typeof value.source === "string";
|
|
6189
6876
|
var init_islands = () => {};
|
|
6190
6877
|
|
|
6191
6878
|
// src/build/islandEntries.ts
|
|
6192
|
-
import { dirname as
|
|
6879
|
+
import { dirname as dirname10, extname, join as join18, relative as relative9, resolve as resolve13 } from "path";
|
|
6193
6880
|
import ts from "typescript";
|
|
6194
6881
|
var frameworks, isRecord5 = (value) => typeof value === "object" && value !== null, resolveRegistryExport = (mod) => {
|
|
6195
6882
|
if (isRecord5(mod.islandRegistry))
|
|
@@ -6201,7 +6888,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
|
|
|
6201
6888
|
if (sourcePath.startsWith("file://")) {
|
|
6202
6889
|
return new URL(sourcePath).pathname;
|
|
6203
6890
|
}
|
|
6204
|
-
return
|
|
6891
|
+
return resolve13(dirname10(registryPath), sourcePath);
|
|
6205
6892
|
}, getObjectPropertyName = (name) => {
|
|
6206
6893
|
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
|
|
6207
6894
|
return name.text;
|
|
@@ -6244,9 +6931,9 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
|
|
|
6244
6931
|
component: reference.source,
|
|
6245
6932
|
export: reference.export,
|
|
6246
6933
|
source: reference.source
|
|
6247
|
-
}), addRegistryEntries = (frameworkNode, framework, imports, definitions,
|
|
6248
|
-
const frameworkRegistry =
|
|
6249
|
-
|
|
6934
|
+
}), addRegistryEntries = (frameworkNode, framework, imports, definitions, registry2) => {
|
|
6935
|
+
const frameworkRegistry = registry2[framework] ?? {};
|
|
6936
|
+
registry2[framework] = frameworkRegistry;
|
|
6250
6937
|
for (const property of frameworkNode.properties) {
|
|
6251
6938
|
if (!ts.isPropertyAssignment(property) && !ts.isShorthandPropertyAssignment(property))
|
|
6252
6939
|
continue;
|
|
@@ -6266,7 +6953,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
|
|
|
6266
6953
|
framework
|
|
6267
6954
|
});
|
|
6268
6955
|
}
|
|
6269
|
-
}, processDefineIslandRegistry = (node, imports, definitions,
|
|
6956
|
+
}, processDefineIslandRegistry = (node, imports, definitions, registry2) => {
|
|
6270
6957
|
const [firstArg] = node.arguments;
|
|
6271
6958
|
if (!firstArg || !ts.isObjectLiteralExpression(firstArg))
|
|
6272
6959
|
return;
|
|
@@ -6287,13 +6974,13 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
|
|
|
6287
6974
|
continue;
|
|
6288
6975
|
if (!ts.isObjectLiteralExpression(property.initializer))
|
|
6289
6976
|
continue;
|
|
6290
|
-
addRegistryEntries(property.initializer, framework, imports, definitions,
|
|
6977
|
+
addRegistryEntries(property.initializer, framework, imports, definitions, registry2);
|
|
6291
6978
|
}
|
|
6292
|
-
}, walkRegistryNode = (node, imports, registryFactoryNames, registryNamespaceNames, definitions,
|
|
6979
|
+
}, walkRegistryNode = (node, imports, registryFactoryNames, registryNamespaceNames, definitions, registry2) => {
|
|
6293
6980
|
if (ts.isCallExpression(node) && isDefineIslandRegistryCall(node.expression, registryFactoryNames, registryNamespaceNames)) {
|
|
6294
|
-
processDefineIslandRegistry(node, imports, definitions,
|
|
6981
|
+
processDefineIslandRegistry(node, imports, definitions, registry2);
|
|
6295
6982
|
}
|
|
6296
|
-
ts.forEachChild(node, (child) => walkRegistryNode(child, imports, registryFactoryNames, registryNamespaceNames, definitions,
|
|
6983
|
+
ts.forEachChild(node, (child) => walkRegistryNode(child, imports, registryFactoryNames, registryNamespaceNames, definitions, registry2));
|
|
6297
6984
|
}, isDefineIslandRegistryCall = (expression, registryFactoryNames, registryNamespaceNames) => {
|
|
6298
6985
|
if (ts.isIdentifier(expression)) {
|
|
6299
6986
|
return registryFactoryNames.has(expression.text);
|
|
@@ -6331,34 +7018,34 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
|
|
|
6331
7018
|
const registryFactoryNames = new Set(["defineIslandRegistry"]);
|
|
6332
7019
|
const registryNamespaceNames = new Set;
|
|
6333
7020
|
const definitions = [];
|
|
6334
|
-
const
|
|
7021
|
+
const registry2 = {};
|
|
6335
7022
|
collectImportDeclarations(sourceFile, registryPath, imports, registryFactoryNames, registryNamespaceNames);
|
|
6336
|
-
walkRegistryNode(sourceFile, imports, registryFactoryNames, registryNamespaceNames, definitions,
|
|
7023
|
+
walkRegistryNode(sourceFile, imports, registryFactoryNames, registryNamespaceNames, definitions, registry2);
|
|
6337
7024
|
return {
|
|
6338
7025
|
definitions,
|
|
6339
7026
|
hasNamedExport: hasIslandRegistryNamedExport(sourceFile),
|
|
6340
|
-
registry
|
|
7027
|
+
registry: registry2
|
|
6341
7028
|
};
|
|
6342
7029
|
}, loadDynamicIslandRegistryBuildInfo = async (resolvedRegistryPath) => {
|
|
6343
7030
|
const registryModule = await import(resolvedRegistryPath);
|
|
6344
|
-
const
|
|
7031
|
+
const registry2 = resolveRegistryExport(registryModule);
|
|
6345
7032
|
const definitions = frameworks.flatMap((framework) => {
|
|
6346
|
-
const frameworkRegistry =
|
|
7033
|
+
const frameworkRegistry = registry2[framework];
|
|
6347
7034
|
if (!isRecord5(frameworkRegistry))
|
|
6348
7035
|
return [];
|
|
6349
|
-
return Object.entries(frameworkRegistry).map(([
|
|
7036
|
+
return Object.entries(frameworkRegistry).map(([component2, value]) => ({
|
|
6350
7037
|
buildReference: getIslandBuildReference(value),
|
|
6351
|
-
component,
|
|
7038
|
+
component: component2,
|
|
6352
7039
|
framework
|
|
6353
7040
|
}));
|
|
6354
7041
|
});
|
|
6355
7042
|
return {
|
|
6356
7043
|
definitions,
|
|
6357
7044
|
hasNamedExport: isRecord5(registryModule.islandRegistry),
|
|
6358
|
-
registry
|
|
7045
|
+
registry: registry2
|
|
6359
7046
|
};
|
|
6360
7047
|
}, loadIslandRegistryBuildInfo = async (registryPath) => {
|
|
6361
|
-
const resolvedRegistryPath =
|
|
7048
|
+
const resolvedRegistryPath = resolve13(registryPath);
|
|
6362
7049
|
const registrySource = Bun.file(resolvedRegistryPath);
|
|
6363
7050
|
const registrySourceText = await registrySource.text();
|
|
6364
7051
|
const parsedInfo = parseIslandRegistryBuildInfo(registrySourceText, resolvedRegistryPath);
|
|
@@ -6892,7 +7579,7 @@ var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-
|
|
|
6892
7579
|
// src/mobile/buildRelease.ts
|
|
6893
7580
|
import { createHash as createHash9 } from "crypto";
|
|
6894
7581
|
import { mkdir as mkdir8, readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
|
|
6895
|
-
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";
|
|
6896
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) => {
|
|
6897
7584
|
if (path.endsWith("/htmx.min.js"))
|
|
6898
7585
|
return match;
|
|
@@ -6900,12 +7587,12 @@ var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex"), STATI
|
|
|
6900
7587
|
const builtPath = manifest[key];
|
|
6901
7588
|
return builtPath ? `${prefix}${builtPath}${suffix}` : match;
|
|
6902
7589
|
}), readPageMetadata = (route) => parseAbsoluteMobileBuildPageMetadata(route.hooks?.detail?.[ABSOLUTE_MOBILE_ROUTE_DETAIL]), resolveAssetPath = (buildDirectory, assetPath) => {
|
|
6903
|
-
const resolvedBuildDirectory =
|
|
6904
|
-
const resolvedAsset =
|
|
7590
|
+
const resolvedBuildDirectory = resolve14(buildDirectory);
|
|
7591
|
+
const resolvedAsset = resolve14(assetPath);
|
|
6905
7592
|
if (resolvedAsset.startsWith(`${resolvedBuildDirectory}/`)) {
|
|
6906
7593
|
return resolvedAsset;
|
|
6907
7594
|
}
|
|
6908
|
-
return
|
|
7595
|
+
return join19(buildDirectory, assetPath.replace(/^\/+/, ""));
|
|
6909
7596
|
}, pageFor = async (metadata, manifest, buildDirectory) => {
|
|
6910
7597
|
const assetPath = manifest[metadata.bundleKey];
|
|
6911
7598
|
if (!assetPath) {
|
|
@@ -6916,8 +7603,8 @@ var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex"), STATI
|
|
|
6916
7603
|
const source = await readFile9(resolvedAssetPath, "utf8");
|
|
6917
7604
|
const rewritten = rewriteStaticScriptPaths(source, manifest);
|
|
6918
7605
|
const documentHash = sha256(new TextEncoder().encode(rewritten));
|
|
6919
|
-
resolvedAssetPath =
|
|
6920
|
-
await mkdir8(
|
|
7606
|
+
resolvedAssetPath = join19(buildDirectory, ".absolutejs", "mobile-pages", `${documentHash}.html`);
|
|
7607
|
+
await mkdir8(dirname11(resolvedAssetPath), { recursive: true });
|
|
6921
7608
|
await writeFile7(resolvedAssetPath, rewritten);
|
|
6922
7609
|
}
|
|
6923
7610
|
const pageAssetKey = metadata.bundleKey.replace(/Index$/u, "");
|
|
@@ -6930,8 +7617,8 @@ var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex"), STATI
|
|
|
6930
7617
|
readFile9(resolvedAssetPath),
|
|
6931
7618
|
resolvedStylePath ? readFile9(resolvedStylePath) : undefined
|
|
6932
7619
|
]);
|
|
6933
|
-
const bundlePath = `/${relative10(
|
|
6934
|
-
const styleBundlePath = resolvedStylePath ? `/${relative10(
|
|
7620
|
+
const bundlePath = `/${relative10(resolve14(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
|
|
7621
|
+
const styleBundlePath = resolvedStylePath ? `/${relative10(resolve14(buildDirectory), resolvedStylePath).replaceAll("\\", "/")}` : undefined;
|
|
6935
7622
|
return {
|
|
6936
7623
|
bundleHash: sha256(bytes),
|
|
6937
7624
|
bundlePath,
|
|
@@ -7094,7 +7781,7 @@ var init_pageProtocol = __esm(() => {
|
|
|
7094
7781
|
|
|
7095
7782
|
// src/mobile/client.ts
|
|
7096
7783
|
var frameworks5, upgradeReasons;
|
|
7097
|
-
var
|
|
7784
|
+
var init_client2 = __esm(() => {
|
|
7098
7785
|
init_pageProtocol();
|
|
7099
7786
|
frameworks5 = new Set([
|
|
7100
7787
|
"angular",
|
|
@@ -7116,7 +7803,7 @@ var init_client = __esm(() => {
|
|
|
7116
7803
|
// src/mobile/transport.ts
|
|
7117
7804
|
var ABSOLUTE_MOBILE_CLIENT_MANIFEST_FORMAT = 1;
|
|
7118
7805
|
var init_transport = __esm(() => {
|
|
7119
|
-
|
|
7806
|
+
init_client2();
|
|
7120
7807
|
init_pageProtocol();
|
|
7121
7808
|
init_routeMatcher();
|
|
7122
7809
|
});
|
|
@@ -7133,29 +7820,39 @@ import {
|
|
|
7133
7820
|
writeFile as writeFile8
|
|
7134
7821
|
} from "fs/promises";
|
|
7135
7822
|
import { existsSync as existsSync9 } from "fs";
|
|
7136
|
-
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";
|
|
7137
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 = () => {
|
|
7138
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
7825
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellBootstrap.${extension}`)).find(existsSync9);
|
|
7139
7826
|
if (candidate)
|
|
7140
7827
|
return candidate;
|
|
7141
7828
|
throw new TypeError("AbsoluteJS mobile shell bootstrap module is missing.");
|
|
7142
7829
|
}, shellAuthModule = () => {
|
|
7143
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
7830
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellAuth.${extension}`)).find(existsSync9);
|
|
7144
7831
|
if (candidate)
|
|
7145
7832
|
return candidate;
|
|
7146
7833
|
throw new TypeError("AbsoluteJS mobile auth shell module is missing.");
|
|
7834
|
+
}, shellExpoAuthModule = () => {
|
|
7835
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellExpoAuth.${extension}`)).find(existsSync9);
|
|
7836
|
+
if (candidate)
|
|
7837
|
+
return candidate;
|
|
7838
|
+
throw new TypeError("AbsoluteJS Expo auth bridge module is missing.");
|
|
7147
7839
|
}, shellSyncModule = () => {
|
|
7148
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
7840
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellSync.${extension}`)).find(existsSync9);
|
|
7149
7841
|
if (candidate)
|
|
7150
7842
|
return candidate;
|
|
7151
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.");
|
|
7152
7849
|
}, shellPushModule = () => {
|
|
7153
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
7850
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellPush.${extension}`)).find(existsSync9);
|
|
7154
7851
|
if (candidate)
|
|
7155
7852
|
return candidate;
|
|
7156
7853
|
throw new TypeError("AbsoluteJS mobile push shell module is missing.");
|
|
7157
7854
|
}, shellExpoDevicesModule = () => {
|
|
7158
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
7855
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellExpoDevices.${extension}`)).find(existsSync9);
|
|
7159
7856
|
if (candidate)
|
|
7160
7857
|
return candidate;
|
|
7161
7858
|
throw new TypeError("AbsoluteJS Expo device bridge module is missing.");
|
|
@@ -7186,8 +7883,8 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
|
|
|
7186
7883
|
</body>
|
|
7187
7884
|
</html>
|
|
7188
7885
|
`, sourceAssetPath = (buildDirectory, bundlePath) => {
|
|
7189
|
-
const root =
|
|
7190
|
-
const asset =
|
|
7886
|
+
const root = resolve15(buildDirectory);
|
|
7887
|
+
const asset = resolve15(root, bundlePath.replace(/^\/+/, ""));
|
|
7191
7888
|
if (!asset.startsWith(`${root}/`)) {
|
|
7192
7889
|
throw new TypeError("Mobile page bundle escaped the build directory.");
|
|
7193
7890
|
}
|
|
@@ -7202,25 +7899,27 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
|
|
|
7202
7899
|
const segments = specifier.split("/");
|
|
7203
7900
|
const packageName = specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0] ?? "";
|
|
7204
7901
|
const subpath = specifier.slice(packageName.length);
|
|
7205
|
-
const packageDirectory =
|
|
7206
|
-
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"));
|
|
7207
7904
|
const exports = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "exports") : undefined;
|
|
7208
7905
|
const entry = typeof exports === "object" && exports !== null ? Reflect.get(exports, subpath ? `.${subpath}` : ".") : undefined;
|
|
7209
7906
|
const target = importEntryTarget(entry);
|
|
7210
7907
|
if (typeof target !== "string" || !target.startsWith("./"))
|
|
7211
7908
|
throw new TypeError(`${specifier} does not publish an import entry.`);
|
|
7212
|
-
const resolved =
|
|
7213
|
-
if (!resolved.startsWith(`${
|
|
7909
|
+
const resolved = resolve15(packageDirectory, target);
|
|
7910
|
+
if (!resolved.startsWith(`${resolve15(packageDirectory)}/`))
|
|
7214
7911
|
throw new TypeError(`${specifier} has an unsafe import entry.`);
|
|
7215
7912
|
return resolved;
|
|
7216
7913
|
}, buildShellBootstrap = async (staging, auth, sync, storagePrefix, engine, deviceCapabilities, projectRoot) => {
|
|
7217
7914
|
const capacitor = engine !== "expo";
|
|
7218
7915
|
const shellCapabilities = capacitor ? deviceCapabilities.capabilities : [];
|
|
7219
7916
|
const modulePath = shellBootstrapModule();
|
|
7220
|
-
const
|
|
7917
|
+
const authFactory = capacitor ? "createAbsoluteMobileShellAuth" : "createAbsoluteExpoShellAuth";
|
|
7918
|
+
const syncFactory = capacitor ? "installAbsoluteMobileShellSync" : "installAbsoluteExpoShellSync";
|
|
7919
|
+
const authImport = auth ? `import { ${authFactory} } from ${JSON.stringify(capacitor ? shellAuthModule() : shellExpoAuthModule())};
|
|
7221
7920
|
` : "";
|
|
7222
|
-
const options = auth ? `{ createAuth:
|
|
7223
|
-
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())};
|
|
7224
7923
|
` : "";
|
|
7225
7924
|
const pushIndex = shellCapabilities.indexOf("pushNotifications");
|
|
7226
7925
|
const push = pushIndex !== -1;
|
|
@@ -7237,15 +7936,15 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
|
|
|
7237
7936
|
const absoluteMobilePushCapability = absoluteDeviceCapability${pushIndex}(absoluteMobilePush.capabilityOptions);
|
|
7238
7937
|
` : "";
|
|
7239
7938
|
const capabilityOptions = shellCapabilities.map((name, index) => `${JSON.stringify(name)}: ${name === "pushNotifications" ? "absoluteMobilePushCapability" : `absoluteDeviceCapability${index}()`}`).join(", ");
|
|
7240
|
-
const entryPath =
|
|
7939
|
+
const entryPath = join20(staging, ".absolute-mobile-entry.ts");
|
|
7241
7940
|
const baseAdapterModule = capacitor ? await resolveProjectImport(projectRoot, "@absolutejs/devices-capacitor") : shellExpoDevicesModule();
|
|
7242
7941
|
const adapterImport = capacitor ? `import { installCapacitorDeviceAdapterIfNative } from ${JSON.stringify(baseAdapterModule)};` : `import { createAbsoluteExpoBridgeFetch, installAbsoluteExpoWebDeviceAdapter } from ${JSON.stringify(baseAdapterModule)};`;
|
|
7243
7942
|
const adapterInstall = capacitor ? `installCapacitorDeviceAdapterIfNative({ storagePrefix: ${JSON.stringify(storagePrefix)}${capabilityOptions ? `, ${capabilityOptions}` : ""} });` : "installAbsoluteExpoWebDeviceAdapter();";
|
|
7244
|
-
let shellOptions = "{ createFetch: createAbsoluteExpoBridgeFetch }";
|
|
7943
|
+
let shellOptions = auth ? options : "{ createFetch: createAbsoluteExpoBridgeFetch }";
|
|
7245
7944
|
if (capacitor)
|
|
7246
7945
|
shellOptions = options;
|
|
7247
7946
|
if (push) {
|
|
7248
|
-
shellOptions = `{ createAuth: (config, options) => createAbsoluteMobileShellAuth(config, options), beforeSignOut: absoluteMobilePush.beforeSignOut, connectPush: (auth) => absoluteMobilePush.connect(auth, absoluteMobilePushCapability)${sync ?
|
|
7947
|
+
shellOptions = `{ createAuth: (config, options) => createAbsoluteMobileShellAuth(config, options), beforeSignOut: absoluteMobilePush.beforeSignOut, connectPush: (auth) => absoluteMobilePush.connect(auth, absoluteMobilePushCapability)${sync ? `, installSync: ${syncFactory}` : ""} }`;
|
|
7249
7948
|
}
|
|
7250
7949
|
await writeFile8(entryPath, `import { startAbsoluteMobileShell } from ${JSON.stringify(modulePath)};
|
|
7251
7950
|
${adapterImport}
|
|
@@ -7256,751 +7955,329 @@ void startAbsoluteMobileShell(${shellOptions});
|
|
|
7256
7955
|
const build = await Bun.build({
|
|
7257
7956
|
entrypoints: [entryPath],
|
|
7258
7957
|
minify: true,
|
|
7259
|
-
outdir: staging,
|
|
7260
|
-
target: "browser"
|
|
7261
|
-
});
|
|
7262
|
-
if (!build.success || build.outputs.length !== 1) {
|
|
7263
|
-
throw new AggregateError(build.logs, "Failed to build the AbsoluteJS Capacitor shell.");
|
|
7264
|
-
}
|
|
7265
|
-
await rename7(build.outputs[0]?.path ?? "", join19(staging, BOOTSTRAP_FILE));
|
|
7266
|
-
await rm6(entryPath, { force: true });
|
|
7267
|
-
}, removePreviousBundle = async (backup, moved) => {
|
|
7268
|
-
if (!moved)
|
|
7269
|
-
return;
|
|
7270
|
-
await rm6(backup, { force: true, recursive: true });
|
|
7271
|
-
}, restorePreviousBundle = async (backup, destination, moved) => {
|
|
7272
|
-
if (!moved)
|
|
7273
|
-
return;
|
|
7274
|
-
await rename7(backup, destination);
|
|
7275
|
-
}, installBundle = async (staging, destination) => {
|
|
7276
|
-
const backup = `${destination}.previous-${crypto.randomUUID()}`;
|
|
7277
|
-
let movedPrevious = false;
|
|
7278
|
-
try {
|
|
7279
|
-
await rename7(destination, backup);
|
|
7280
|
-
movedPrevious = true;
|
|
7281
|
-
} catch (error) {
|
|
7282
|
-
if (!errorHasCode(error, "ENOENT"))
|
|
7283
|
-
throw error;
|
|
7284
|
-
}
|
|
7285
|
-
try {
|
|
7286
|
-
await rename7(staging, destination);
|
|
7287
|
-
await removePreviousBundle(backup, movedPrevious);
|
|
7288
|
-
} catch (error) {
|
|
7289
|
-
await restorePreviousBundle(backup, destination, movedPrevious);
|
|
7290
|
-
throw error;
|
|
7291
|
-
}
|
|
7292
|
-
}, copyClientPage = async (page, buildDirectory, staging, copiedDependencies) => {
|
|
7293
|
-
if (!CAPACITOR_CLIENT_FRAMEWORKS.has(page.framework)) {
|
|
7294
|
-
throw new TypeError(`Capacitor client rendering does not yet support ${page.framework} page ${page.pageId}.`);
|
|
7295
|
-
}
|
|
7296
|
-
const extension = extname4(page.bundlePath) || ".js";
|
|
7297
|
-
const localBundlePath = `./pages/${page.bundleHash}${extension}`;
|
|
7298
|
-
const source = sourceAssetPath(buildDirectory, page.bundlePath);
|
|
7299
|
-
await copyFile4(source, join19(staging, localBundlePath));
|
|
7300
|
-
await copyAbsoluteClientDependencies(source, buildDirectory, staging, copiedDependencies);
|
|
7301
|
-
let localStylePath;
|
|
7302
|
-
if (page.styleBundlePath && page.styleBundleHash) {
|
|
7303
|
-
const styleExtension = extname4(page.styleBundlePath) || ".css";
|
|
7304
|
-
localStylePath = `./styles/${page.styleBundleHash}${styleExtension}`;
|
|
7305
|
-
const styleSource = sourceAssetPath(buildDirectory, page.styleBundlePath);
|
|
7306
|
-
await mkdir9(dirname11(join19(staging, localStylePath)), {
|
|
7307
|
-
recursive: true
|
|
7308
|
-
});
|
|
7309
|
-
await copyFile4(styleSource, join19(staging, localStylePath));
|
|
7310
|
-
await copyAbsoluteClientDependencies(styleSource, buildDirectory, staging, copiedDependencies);
|
|
7311
|
-
}
|
|
7312
|
-
return {
|
|
7313
|
-
...page,
|
|
7314
|
-
localBundlePath,
|
|
7315
|
-
...localStylePath ? { localStylePath } : {}
|
|
7316
|
-
};
|
|
7317
|
-
}, absoluteClientImports = async (sourcePath, buildDirectory) => {
|
|
7318
|
-
const source = await readFile10(sourcePath, "utf8");
|
|
7319
|
-
const extension = extname4(sourcePath).toLowerCase();
|
|
7320
|
-
let scriptLoader;
|
|
7321
|
-
if (extension === ".tsx")
|
|
7322
|
-
scriptLoader = "tsx";
|
|
7323
|
-
else if (extension === ".ts")
|
|
7324
|
-
scriptLoader = "ts";
|
|
7325
|
-
else if (extension === ".jsx")
|
|
7326
|
-
scriptLoader = "jsx";
|
|
7327
|
-
else if ([".js", ".mjs", ".cjs"].includes(extension))
|
|
7328
|
-
scriptLoader = "js";
|
|
7329
|
-
const scriptImports = scriptLoader ? new Bun.Transpiler({ loader: scriptLoader }).scanImports(source).map(({ path }) => path) : [];
|
|
7330
|
-
const cssImports = extension === ".css" ? [...source.matchAll(CLIENT_CSS_DEPENDENCY_PATTERN)].flatMap((match) => match[1] ?? []) : [];
|
|
7331
|
-
const markupImports = extension === ".html" ? [...source.matchAll(CLIENT_MARKUP_DEPENDENCY_PATTERN)].flatMap((match) => match[1] ?? []) : [];
|
|
7332
|
-
return [...scriptImports, ...cssImports, ...markupImports].flatMap((specifier) => {
|
|
7333
|
-
if (!specifier)
|
|
7334
|
-
return [];
|
|
7335
|
-
if (!specifier.startsWith("/") && !specifier.startsWith("./") && !specifier.startsWith("../")) {
|
|
7336
|
-
return [];
|
|
7337
|
-
}
|
|
7338
|
-
const clean = specifier.split(/[?#]/u, 1)[0] ?? specifier;
|
|
7339
|
-
if (clean.startsWith("/"))
|
|
7340
|
-
return [clean];
|
|
7341
|
-
const resolved = resolve14(dirname11(sourcePath), clean);
|
|
7342
|
-
const root = resolve14(buildDirectory);
|
|
7343
|
-
const relativePath = relative11(root, resolved).replaceAll("\\", "/");
|
|
7344
|
-
if (relativePath === ".." || relativePath.startsWith("../")) {
|
|
7345
|
-
throw new TypeError(`Mobile client dependency escaped the build directory: ${specifier}`);
|
|
7346
|
-
}
|
|
7347
|
-
return [`/${relativePath}`];
|
|
7348
|
-
});
|
|
7349
|
-
}, copyAbsoluteClientDependency = async (specifier, buildDirectory, staging, copied) => {
|
|
7350
|
-
if (copied.has(specifier))
|
|
7351
|
-
return;
|
|
7352
|
-
copied.add(specifier);
|
|
7353
|
-
const source = sourceAssetPath(buildDirectory, specifier);
|
|
7354
|
-
const destination = join19(staging, specifier.replace(/^\/+/, ""));
|
|
7355
|
-
await mkdir9(dirname11(destination), { recursive: true });
|
|
7356
|
-
await copyFile4(source, destination);
|
|
7357
|
-
await copyAbsoluteClientDependencies(source, buildDirectory, staging, copied);
|
|
7358
|
-
}, copyAbsoluteClientDependencies = async (sourcePath, buildDirectory, staging, copied) => {
|
|
7359
|
-
const dependencies = await absoluteClientImports(sourcePath, buildDirectory);
|
|
7360
|
-
await Promise.all(dependencies.map((specifier) => copyAbsoluteClientDependency(specifier, buildDirectory, staging, copied)));
|
|
7361
|
-
}, materializeAbsoluteCapacitorWebBundle = async (options) => {
|
|
7362
|
-
if (!resolveAbsoluteMobileRoute(options.artifact.routes, new URL(options.config.entry, "https://absolute.invalid").pathname)) {
|
|
7363
|
-
throw new TypeError(`mobile.entry ${options.config.entry} is not a captured mobile page route.`);
|
|
7364
|
-
}
|
|
7365
|
-
const destination = options.config.bundleDirectory;
|
|
7366
|
-
await mkdir9(dirname11(destination), { recursive: true });
|
|
7367
|
-
const staging = await mkdtemp4(join19(dirname11(destination), `.${basename8(destination)}.stage-`));
|
|
7368
|
-
try {
|
|
7369
|
-
const pageDirectory = join19(staging, "pages");
|
|
7370
|
-
await mkdir9(pageDirectory, { recursive: true });
|
|
7371
|
-
await Promise.all(CLIENT_ASSET_DIRECTORIES.map((directory) => ({
|
|
7372
|
-
destination: join19(staging, directory),
|
|
7373
|
-
source: join19(options.buildDirectory, directory)
|
|
7374
|
-
})).filter(({ source }) => existsSync9(source)).map(({ destination: assetDestination, source }) => cp3(source, assetDestination, { recursive: true })));
|
|
7375
|
-
const copiedDependencies = new Set;
|
|
7376
|
-
const pages = await Promise.all(options.artifact.pages.map((page) => copyClientPage(page, options.buildDirectory, staging, copiedDependencies)));
|
|
7377
|
-
const manifest = {
|
|
7378
|
-
appBuild: options.artifact.appBuild,
|
|
7379
|
-
...options.auth ? { auth: options.auth } : {},
|
|
7380
|
-
appId: options.config.appId,
|
|
7381
|
-
appName: options.config.appName,
|
|
7382
|
-
deepLinkHosts: options.config.deepLinkHosts,
|
|
7383
|
-
deepLinkScheme: options.config.deepLinkScheme,
|
|
7384
|
-
deviceCapabilities: options.deviceCapabilities.capabilities,
|
|
7385
|
-
entry: options.config.entry,
|
|
7386
|
-
format: ABSOLUTE_MOBILE_CLIENT_MANIFEST_FORMAT,
|
|
7387
|
-
pages,
|
|
7388
|
-
productionOrigin: options.config.productionOrigin,
|
|
7389
|
-
routes: options.artifact.routes,
|
|
7390
|
-
runtime: options.artifact.runtime,
|
|
7391
|
-
...options.sync ? {
|
|
7392
|
-
sync: {
|
|
7393
|
-
background: {
|
|
7394
|
-
endpoint: new URL("/__absolute/sync/background", options.config.productionOrigin).href,
|
|
7395
|
-
intervalMinutes: 15
|
|
7396
|
-
},
|
|
7397
|
-
socketTickets: true,
|
|
7398
|
-
storageSchema: options.syncSchema ?? {
|
|
7399
|
-
components: [
|
|
7400
|
-
{ id: "@absolutejs/app", version: 1 }
|
|
7401
|
-
]
|
|
7402
|
-
}
|
|
7403
|
-
}
|
|
7404
|
-
} : {}
|
|
7405
|
-
};
|
|
7406
|
-
await Promise.all([
|
|
7407
|
-
writeFile8(join19(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
|
|
7408
|
-
`),
|
|
7409
|
-
writeFile8(join19(staging, INDEX_FILE), indexHtml(options.config.appName, options.config.productionOrigin)),
|
|
7410
|
-
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)
|
|
7411
|
-
]);
|
|
7412
|
-
await installBundle(staging, destination);
|
|
7413
|
-
return manifest;
|
|
7414
|
-
} catch (error) {
|
|
7415
|
-
await rm6(staging, { force: true, recursive: true });
|
|
7416
|
-
throw error;
|
|
7417
|
-
}
|
|
7418
|
-
};
|
|
7419
|
-
var init_capacitorBundle = __esm(() => {
|
|
7420
|
-
init_routeMatcher();
|
|
7421
|
-
init_transport();
|
|
7422
|
-
CLIENT_CSS_DEPENDENCY_PATTERN = /(?:@import\s+(?:url\(\s*)?|url\(\s*)["']?((?:\/|\.\.\/|\.\/)[^"')\s]+)["']?\s*\)?/gu;
|
|
7423
|
-
CLIENT_MARKUP_DEPENDENCY_PATTERN = /<(?:script\b[^>]*\bsrc|link\b[^>]*\bhref|img\b[^>]*\bsrc|source\b[^>]*\bsrcset)\s*=\s*["']((?:\/|\.\.\/|\.\/)[^"',\s]+)/giu;
|
|
7424
|
-
CAPACITOR_CLIENT_FRAMEWORKS = new Set([
|
|
7425
|
-
"angular",
|
|
7426
|
-
"html",
|
|
7427
|
-
"htmx",
|
|
7428
|
-
"react",
|
|
7429
|
-
"svelte",
|
|
7430
|
-
"vue"
|
|
7431
|
-
]);
|
|
7432
|
-
CLIENT_ASSET_DIRECTORIES = ["assets", "html", "htmx", "indexes"];
|
|
7433
|
-
});
|
|
7434
|
-
|
|
7435
|
-
// src/mobile/artifactStore.ts
|
|
7436
|
-
import { createHash as createHash10 } from "crypto";
|
|
7437
|
-
var DEFAULT_MAX_PRODUCER_BYTES = 134217728, SHA_2562 = "sha256", hashBlob = async (blob) => {
|
|
7438
|
-
const bytes = new Uint8Array(await blob.arrayBuffer());
|
|
7439
|
-
return createHash10(SHA_2562).update(bytes).digest("hex");
|
|
7440
|
-
}, verifyAbsoluteMobileCompatibilityProducer = async (release, maxProducerBytes = DEFAULT_MAX_PRODUCER_BYTES) => {
|
|
7441
|
-
const { artifact, producer } = release;
|
|
7442
|
-
if (producer.size !== artifact.producer.bytes || producer.size > maxProducerBytes) {
|
|
7443
|
-
throw new TypeError("Mobile compatibility producer size does not match its artifact.");
|
|
7444
|
-
}
|
|
7445
|
-
if (await hashBlob(producer) !== artifact.producer.bundleHash) {
|
|
7446
|
-
throw new TypeError("Mobile compatibility producer hash does not match its artifact.");
|
|
7447
|
-
}
|
|
7448
|
-
return release;
|
|
7449
|
-
};
|
|
7450
|
-
var init_artifactStore = __esm(() => {
|
|
7451
|
-
init_releaseArtifact();
|
|
7452
|
-
});
|
|
7453
|
-
|
|
7454
|
-
// src/mobile/materializedBundle.ts
|
|
7455
|
-
import { createHash as createHash11 } from "crypto";
|
|
7456
|
-
import {
|
|
7457
|
-
access as access8,
|
|
7458
|
-
mkdir as mkdir10,
|
|
7459
|
-
mkdtemp as mkdtemp5,
|
|
7460
|
-
readFile as readFile11,
|
|
7461
|
-
rename as rename8,
|
|
7462
|
-
rm as rm7,
|
|
7463
|
-
writeFile as writeFile9
|
|
7464
|
-
} from "fs/promises";
|
|
7465
|
-
import { dirname as dirname12, join as join20, resolve as resolvePath3 } from "path";
|
|
7466
|
-
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) => {
|
|
7467
|
-
const identity = JSON.stringify({
|
|
7468
|
-
currentReleaseId,
|
|
7469
|
-
releases: releases.map(({ releaseId }) => releaseId)
|
|
7470
|
-
});
|
|
7471
|
-
return `amb_${createHash11("sha256").update(identity).digest("hex")}`;
|
|
7472
|
-
}, parseBundleIndex = (value) => {
|
|
7473
|
-
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)) {
|
|
7474
|
-
throw new TypeError("Invalid materialized mobile compatibility bundle.");
|
|
7475
|
-
}
|
|
7476
|
-
const releases = value.releases.map(parseAbsoluteMobileCompatibilityArtifact);
|
|
7477
|
-
const retained = retainAbsoluteMobileCompatibilityArtifacts(releases);
|
|
7478
|
-
if (retained.length !== releases.length || retained.some(({ releaseId }, index) => releaseId !== releases[index]?.releaseId)) {
|
|
7479
|
-
throw new TypeError("Materialized mobile bundle releases are not a retained generation window.");
|
|
7480
|
-
}
|
|
7481
|
-
const expectedBundleId = bundleIdFor(value.currentReleaseId, releases);
|
|
7482
|
-
if (value.bundleId !== expectedBundleId) {
|
|
7483
|
-
throw new TypeError("Materialized mobile bundle integrity failed.");
|
|
7484
|
-
}
|
|
7485
|
-
if (releases[0]?.releaseId !== value.currentReleaseId) {
|
|
7486
|
-
throw new TypeError("Materialized mobile bundle current release is not its newest generation.");
|
|
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.");
|
|
7487
7963
|
}
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
};
|
|
7494
|
-
},
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
await
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
writeFile9(producerPath, new Uint8Array(await release.producer.arrayBuffer()))
|
|
7502
|
-
]);
|
|
7503
|
-
}, installImmutableBundle = async (bundlesRoot, bundleId, releases) => {
|
|
7504
|
-
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;
|
|
7505
7977
|
try {
|
|
7506
|
-
await
|
|
7507
|
-
|
|
7978
|
+
await rename7(destination, backup);
|
|
7979
|
+
movedPrevious = true;
|
|
7508
7980
|
} catch (error) {
|
|
7509
|
-
if (!
|
|
7981
|
+
if (!errorHasCode(error, "ENOENT"))
|
|
7510
7982
|
throw error;
|
|
7511
7983
|
}
|
|
7512
|
-
const staging = await mkdtemp5(join20(bundlesRoot, ".stage-"));
|
|
7513
7984
|
try {
|
|
7514
|
-
await
|
|
7515
|
-
await
|
|
7985
|
+
await rename7(staging, destination);
|
|
7986
|
+
await removePreviousBundle(backup, movedPrevious);
|
|
7516
7987
|
} catch (error) {
|
|
7517
|
-
await
|
|
7518
|
-
if (errorHasCode2(error, "EEXIST") || errorHasCode2(error, "ENOTEMPTY")) {
|
|
7519
|
-
return destination;
|
|
7520
|
-
}
|
|
7988
|
+
await restorePreviousBundle(backup, destination, movedPrevious);
|
|
7521
7989
|
throw error;
|
|
7522
7990
|
}
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
const artifacts = retainAbsoluteMobileCompatibilityArtifacts(releases.map(({ artifact }) => artifact));
|
|
7527
|
-
if (artifacts.length !== releases.length) {
|
|
7528
|
-
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}.`);
|
|
7529
7994
|
}
|
|
7530
|
-
|
|
7531
|
-
|
|
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);
|
|
7532
8010
|
}
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
}
|
|
7538
|
-
return release;
|
|
7539
|
-
});
|
|
7540
|
-
const root = resolvePath3(input.root);
|
|
7541
|
-
const bundlesRoot = join20(root, BUNDLES_DIRECTORY);
|
|
7542
|
-
await mkdir10(bundlesRoot, { recursive: true });
|
|
7543
|
-
const bundleId = bundleIdFor(input.currentReleaseId, artifacts);
|
|
7544
|
-
await installImmutableBundle(bundlesRoot, bundleId, orderedReleases);
|
|
7545
|
-
const index = {
|
|
7546
|
-
bundleId,
|
|
7547
|
-
currentReleaseId: input.currentReleaseId,
|
|
7548
|
-
format: ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
|
|
7549
|
-
releases: artifacts
|
|
8011
|
+
return {
|
|
8012
|
+
...page,
|
|
8013
|
+
localBundlePath,
|
|
8014
|
+
...localStylePath ? { localStylePath } : {}
|
|
7550
8015
|
};
|
|
7551
|
-
|
|
7552
|
-
const
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
return { artifact, producer };
|
|
7571
|
-
}));
|
|
7572
|
-
} catch (error) {
|
|
7573
|
-
if (errorHasCode2(error, "ENOENT"))
|
|
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("../")) {
|
|
7574
8035
|
return [];
|
|
7575
|
-
throw error;
|
|
7576
|
-
}
|
|
7577
|
-
};
|
|
7578
|
-
var init_materializedBundle = __esm(() => {
|
|
7579
|
-
init_artifactStore();
|
|
7580
|
-
init_releaseArtifact();
|
|
7581
|
-
BUNDLE_ID_PATTERN = /^amb_[a-f0-9]{64}$/;
|
|
7582
|
-
});
|
|
7583
|
-
|
|
7584
|
-
// node_modules/@absolutejs/sync/dist/client/index.js
|
|
7585
|
-
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) => {
|
|
7586
|
-
if (!Number.isSafeInteger(value) || value < 1)
|
|
7587
|
-
throw new SyncLocalStoreSchemaError("INVALID_PLAN", `${label} must be a positive safe integer`);
|
|
7588
|
-
return value;
|
|
7589
|
-
}, isSchemaBundle = (schema) => ("components" in schema), validatePolicyMatch = (match, label) => {
|
|
7590
|
-
if (match.length === 0 || match.trim() !== match || /^\*+$/.test(match) || match.includes("**"))
|
|
7591
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.match must be an exact name or a non-empty glob without adjacent wildcards.`);
|
|
7592
|
-
}, validateSyncLocalDataPolicy = (policy, label = "localData") => {
|
|
7593
|
-
if (policy.maxBytesPerNamespace !== undefined && (!Number.isSafeInteger(policy.maxBytesPerNamespace) || policy.maxBytesPerNamespace < 1))
|
|
7594
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.maxBytesPerNamespace must be a positive safe integer.`);
|
|
7595
|
-
for (const [index, rule] of (policy.collections ?? []).entries()) {
|
|
7596
|
-
validatePolicyMatch(rule.match, `${label}.collections[${index}]`);
|
|
7597
|
-
if (rule.maxAgeMs !== undefined && (!Number.isSafeInteger(rule.maxAgeMs) || rule.maxAgeMs < 1))
|
|
7598
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}].maxAgeMs must be a positive safe integer.`);
|
|
7599
|
-
if (rule.persistence === "memory-only" && rule.protection === "required")
|
|
7600
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] cannot require at-rest protection when it is memory-only.`);
|
|
7601
|
-
if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
|
|
7602
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] declares ${rule.sensitivity} data without required protection or memory-only persistence.`);
|
|
7603
|
-
}
|
|
7604
|
-
for (const [index, rule] of (policy.mutations ?? []).entries()) {
|
|
7605
|
-
validatePolicyMatch(rule.match, `${label}.mutations[${index}]`);
|
|
7606
|
-
if (rule.conflict !== undefined && rule.conflict.strategy !== "client-wins" && rule.conflict.strategy !== "manual" && rule.conflict.strategy !== "server-wins")
|
|
7607
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}].conflict.strategy is invalid.`);
|
|
7608
|
-
if (rule.conflict?.maxAttempts !== undefined && (!Number.isSafeInteger(rule.conflict.maxAttempts) || rule.conflict.maxAttempts < 1))
|
|
7609
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}].conflict.maxAttempts must be a positive safe integer.`);
|
|
7610
|
-
if (rule.conflict?.maxAttempts !== undefined && rule.conflict.strategy !== "client-wins")
|
|
7611
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}].conflict.maxAttempts is only valid for client-wins.`);
|
|
7612
|
-
if (rule.persistence === "memory-only" && rule.protection === "required")
|
|
7613
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}] cannot require at-rest protection when it is memory-only.`);
|
|
7614
|
-
if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
|
|
7615
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}] declares ${rule.sensitivity} arguments without required protection.`);
|
|
7616
|
-
}
|
|
7617
|
-
return policy;
|
|
7618
|
-
}, normalizeSyncLocalSchemaComponents = (schema = { version: 1 }) => {
|
|
7619
|
-
const components = isSchemaBundle(schema) ? [...schema.components] : [{ ...schema, id: "@absolutejs/app" }];
|
|
7620
|
-
const ids = new Set;
|
|
7621
|
-
for (const component of components) {
|
|
7622
|
-
if (typeof component.id !== "string" || component.id.trim() !== component.id || component.id.length === 0)
|
|
7623
|
-
throw new SyncLocalStoreSchemaError("INVALID_PLAN", "Sync schema component id must be non-empty and trimmed");
|
|
7624
|
-
if (ids.has(component.id))
|
|
7625
|
-
throw new SyncLocalStoreSchemaError("INVALID_PLAN", `Sync schema component "${component.id}" is declared more than once`);
|
|
7626
|
-
ids.add(component.id);
|
|
7627
|
-
if (component.localData)
|
|
7628
|
-
validateSyncLocalDataPolicy(component.localData, `${component.id}.localData`);
|
|
7629
|
-
}
|
|
7630
|
-
return components.sort((a, b) => a.id.localeCompare(b.id));
|
|
7631
|
-
}, resolveSyncLocalSchemaComponents = (storedVersions, schema = { version: 1 }) => {
|
|
7632
|
-
const components = normalizeSyncLocalSchemaComponents(schema).map((component) => {
|
|
7633
|
-
const current = resolveSyncLocalMigrations(component.version, component);
|
|
7634
|
-
return {
|
|
7635
|
-
id: component.id,
|
|
7636
|
-
...resolveSyncLocalMigrations(storedVersions[component.id] ?? current.minimumCompatibleVersion, component)
|
|
7637
|
-
};
|
|
7638
|
-
});
|
|
7639
|
-
const active = new Set(components.map((component) => component.id));
|
|
7640
|
-
const orphanedComponents = Object.keys(storedVersions).filter((id) => !active.has(id)).sort();
|
|
7641
|
-
return { components, orphanedComponents };
|
|
7642
|
-
}, resolveSyncLocalMigrations = (storedVersion, schema = { version: 1 }) => {
|
|
7643
|
-
positiveVersion(storedVersion, "Stored Sync schema version");
|
|
7644
|
-
const targetVersion = positiveVersion(schema.version, "Target Sync schema version");
|
|
7645
|
-
const migrations = [...schema.migrations ?? []].sort((a, b) => a.toVersion - b.toVersion);
|
|
7646
|
-
const versions = new Set;
|
|
7647
|
-
for (const migration of migrations) {
|
|
7648
|
-
positiveVersion(migration.toVersion, "Sync migration toVersion");
|
|
7649
|
-
if (versions.has(migration.toVersion))
|
|
7650
|
-
throw new SyncLocalStoreSchemaError("INVALID_PLAN", `Sync migration ${migration.toVersion} is declared more than once`);
|
|
7651
|
-
versions.add(migration.toVersion);
|
|
7652
|
-
}
|
|
7653
|
-
const inferredMinimum = migrations[0] ? migrations[0].toVersion - 1 : targetVersion;
|
|
7654
|
-
const minimumCompatibleVersion = positiveVersion(schema.minimumCompatibleVersion ?? inferredMinimum, "Minimum compatible Sync schema version");
|
|
7655
|
-
if (minimumCompatibleVersion > targetVersion)
|
|
7656
|
-
throw new SyncLocalStoreSchemaError("INVALID_PLAN", "Minimum compatible Sync schema version cannot exceed its target");
|
|
7657
|
-
if (storedVersion > targetVersion)
|
|
7658
|
-
throw new SyncLocalStoreSchemaError("SCHEMA_TOO_NEW", `Stored Sync schema ${storedVersion} is newer than this runtime's schema ${targetVersion}`, { storedVersion, targetVersion });
|
|
7659
|
-
if (storedVersion < minimumCompatibleVersion)
|
|
7660
|
-
throw new SyncLocalStoreSchemaError("SCHEMA_TOO_OLD", `Stored Sync schema ${storedVersion} is older than the minimum compatible schema ${minimumCompatibleVersion}`, { storedVersion, targetVersion });
|
|
7661
|
-
const steps = [];
|
|
7662
|
-
for (let version2 = storedVersion + 1;version2 <= targetVersion; version2++) {
|
|
7663
|
-
const migration = migrations.find((candidate) => candidate.toVersion === version2);
|
|
7664
|
-
if (migration === undefined)
|
|
7665
|
-
throw new SyncLocalStoreSchemaError("MIGRATION_MISSING", `Sync migration ${version2 - 1} -> ${version2} is missing`, { storedVersion, targetVersion });
|
|
7666
|
-
steps.push(migration);
|
|
7667
|
-
}
|
|
7668
|
-
return { minimumCompatibleVersion, steps, targetVersion };
|
|
7669
|
-
};
|
|
7670
|
-
var init_client2 = __esm(() => {
|
|
7671
|
-
RUNTIME_TRANSPORT = Symbol.for("@absolutejs/sync/client-runtime-transport");
|
|
7672
|
-
host = globalThis;
|
|
7673
|
-
registry = (() => {
|
|
7674
|
-
const existing = host[RUNTIME_TRANSPORT];
|
|
7675
|
-
if (isRegistry(existing))
|
|
7676
|
-
return existing;
|
|
7677
|
-
if (typeof existing === "object" && existing !== null && Array.isArray(Reflect.get(existing, "installations"))) {
|
|
7678
|
-
Reflect.set(existing, "clients", []);
|
|
7679
|
-
return existing;
|
|
7680
|
-
}
|
|
7681
|
-
const created = { clients: [], installations: [] };
|
|
7682
|
-
Object.defineProperty(host, RUNTIME_TRANSPORT, {
|
|
7683
|
-
configurable: false,
|
|
7684
|
-
enumerable: false,
|
|
7685
|
-
value: created,
|
|
7686
|
-
writable: false
|
|
7687
|
-
});
|
|
7688
|
-
return created;
|
|
7689
|
-
})();
|
|
7690
|
-
SyncLocalDataPolicyError = class SyncLocalDataPolicyError extends Error {
|
|
7691
|
-
code;
|
|
7692
|
-
constructor(code, message) {
|
|
7693
|
-
super(message);
|
|
7694
|
-
this.name = "SyncLocalDataPolicyError";
|
|
7695
|
-
this.code = code;
|
|
7696
8036
|
}
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
this.code = code;
|
|
7706
|
-
this.storedVersion = versions.storedVersion;
|
|
7707
|
-
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}`);
|
|
7708
8045
|
}
|
|
7709
|
-
|
|
7710
|
-
});
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
import { readFileSync as readFileSync11 } from "fs";
|
|
7714
|
-
import { dirname as dirname13, join as join21, resolve as resolve15 } from "path";
|
|
7715
|
-
var object = (value) => typeof value === "object" && value !== null && !Array.isArray(value), manifestAt = (path) => {
|
|
7716
|
-
try {
|
|
7717
|
-
const value = JSON.parse(readFileSync11(path, "utf8"));
|
|
7718
|
-
return object(value) ? value : undefined;
|
|
7719
|
-
} catch {
|
|
7720
|
-
return;
|
|
7721
|
-
}
|
|
7722
|
-
}, localSchemaMetadata = (manifest) => {
|
|
7723
|
-
const absolutejs = Reflect.get(manifest, "absolutejs");
|
|
7724
|
-
if (!object(absolutejs))
|
|
7725
|
-
return;
|
|
7726
|
-
const sync = Reflect.get(absolutejs, "sync");
|
|
7727
|
-
if (!object(sync))
|
|
8046
|
+
return [`/${relativePath}`];
|
|
8047
|
+
});
|
|
8048
|
+
}, copyAbsoluteClientDependency = async (specifier, buildDirectory, staging, copied) => {
|
|
8049
|
+
if (copied.has(specifier))
|
|
7728
8050
|
return;
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
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.`);
|
|
7741
8063
|
}
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
const field = nonEmpty(Reflect.get(record, "field"), id, `operation ${index}.field`);
|
|
7781
|
-
if (type === "remove-field")
|
|
7782
|
-
return { collection, field, type };
|
|
7783
|
-
if (type === "set-default")
|
|
7784
|
-
return {
|
|
7785
|
-
collection,
|
|
7786
|
-
field,
|
|
7787
|
-
type,
|
|
7788
|
-
value: normalizeJsonValue(Reflect.get(record, "value"), id, `operation ${index}.value`)
|
|
7789
|
-
};
|
|
7790
|
-
throw metadataError(id, `operation ${index}.type is not supported.`);
|
|
7791
|
-
}, migration = (value, id, index) => {
|
|
7792
|
-
const record = requireObject(value, id, `migration ${index} must be an object.`);
|
|
7793
|
-
const allowed = new Set(["operations", "toVersion"]);
|
|
7794
|
-
const unsupported = Object.keys(record).find((key) => !allowed.has(key));
|
|
7795
|
-
if (unsupported)
|
|
7796
|
-
throw metadataError(id, `migration ${index}.${unsupported} is not declarative metadata.`);
|
|
7797
|
-
const declaredOperations = Reflect.get(record, "operations");
|
|
7798
|
-
if (declaredOperations !== undefined && !Array.isArray(declaredOperations))
|
|
7799
|
-
throw metadataError(id, `migration ${index}.operations must be an array.`);
|
|
7800
|
-
const operations = Array.isArray(declaredOperations) ? declaredOperations : [];
|
|
7801
|
-
return {
|
|
7802
|
-
operations: operations.map((entry, operationIndex) => operation(entry, id, operationIndex)),
|
|
7803
|
-
toVersion: positiveVersion2(Reflect.get(record, "toVersion"), id, `migration ${index}.toVersion`)
|
|
7804
|
-
};
|
|
7805
|
-
}, localDataPolicy = (value, id) => {
|
|
7806
|
-
const record = requireObject(value, id, "localData must be an object.");
|
|
7807
|
-
const allowed = new Set([
|
|
7808
|
-
"collections",
|
|
7809
|
-
"maxBytesPerNamespace",
|
|
7810
|
-
"mutations"
|
|
7811
|
-
]);
|
|
7812
|
-
const unsupported = Object.keys(record).find((key) => !allowed.has(key));
|
|
7813
|
-
if (unsupported)
|
|
7814
|
-
throw metadataError(id, `localData.${unsupported} is not supported.`);
|
|
7815
|
-
const collectionRules = Reflect.get(record, "collections");
|
|
7816
|
-
const mutationRules = Reflect.get(record, "mutations");
|
|
7817
|
-
if (collectionRules !== undefined && !Array.isArray(collectionRules))
|
|
7818
|
-
throw metadataError(id, "localData.collections must be an array.");
|
|
7819
|
-
if (mutationRules !== undefined && !Array.isArray(mutationRules))
|
|
7820
|
-
throw metadataError(id, "localData.mutations must be an array.");
|
|
7821
|
-
const collections = Array.isArray(collectionRules) ? collectionRules.map((entry, index) => {
|
|
7822
|
-
const rule = requireObject(entry, id, `localData.collections[${index}] must be an object.`);
|
|
7823
|
-
const allowedRuleKeys = new Set([
|
|
7824
|
-
"evictionPriority",
|
|
7825
|
-
"match",
|
|
7826
|
-
"maxAgeMs",
|
|
7827
|
-
"onProtectionUnavailable",
|
|
7828
|
-
"persistence",
|
|
7829
|
-
"protection",
|
|
7830
|
-
"sensitivity"
|
|
7831
|
-
]);
|
|
7832
|
-
const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
|
|
7833
|
-
if (unsupportedRuleKey)
|
|
7834
|
-
throw metadataError(id, `localData.collections[${index}].${unsupportedRuleKey} is not supported.`);
|
|
7835
|
-
const match = nonEmpty(Reflect.get(rule, "match"), id, `localData.collections[${index}].match`);
|
|
7836
|
-
const persistence = unknownField(rule, "persistence");
|
|
7837
|
-
const sensitivity = unknownField(rule, "sensitivity");
|
|
7838
|
-
const protection = unknownField(rule, "protection");
|
|
7839
|
-
const onProtectionUnavailable = unknownField(rule, "onProtectionUnavailable");
|
|
7840
|
-
const evictionPriority = unknownField(rule, "evictionPriority");
|
|
7841
|
-
const maxAge = unknownField(rule, "maxAgeMs");
|
|
7842
|
-
if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
|
|
7843
|
-
throw metadataError(id, `localData.collections[${index}].persistence is invalid.`);
|
|
7844
|
-
if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
|
|
7845
|
-
throw metadataError(id, `localData.collections[${index}].sensitivity is invalid.`);
|
|
7846
|
-
if (protection !== undefined && protection !== "none" && protection !== "required")
|
|
7847
|
-
throw metadataError(id, `localData.collections[${index}].protection is invalid.`);
|
|
7848
|
-
if (onProtectionUnavailable !== undefined && onProtectionUnavailable !== "error" && onProtectionUnavailable !== "memory-only")
|
|
7849
|
-
throw metadataError(id, `localData.collections[${index}].onProtectionUnavailable is invalid.`);
|
|
7850
|
-
if (evictionPriority !== undefined && evictionPriority !== "critical" && evictionPriority !== "normal" && evictionPriority !== "disposable")
|
|
7851
|
-
throw metadataError(id, `localData.collections[${index}].evictionPriority is invalid.`);
|
|
7852
|
-
return {
|
|
7853
|
-
match,
|
|
7854
|
-
...sensitivity ? { sensitivity } : {},
|
|
7855
|
-
...persistence ? { persistence } : {},
|
|
7856
|
-
...protection ? { protection } : {},
|
|
7857
|
-
...onProtectionUnavailable ? {
|
|
7858
|
-
onProtectionUnavailable
|
|
7859
|
-
} : {},
|
|
7860
|
-
...evictionPriority ? { evictionPriority } : {},
|
|
7861
|
-
...maxAge === undefined ? {} : {
|
|
7862
|
-
maxAgeMs: positiveVersion2(maxAge, id, `localData.collections[${index}].maxAgeMs`)
|
|
7863
|
-
}
|
|
7864
|
-
};
|
|
7865
|
-
}) : undefined;
|
|
7866
|
-
const mutations = Array.isArray(mutationRules) ? mutationRules.map((entry, index) => {
|
|
7867
|
-
const rule = requireObject(entry, id, `localData.mutations[${index}] must be an object.`);
|
|
7868
|
-
const allowedRuleKeys = new Set([
|
|
7869
|
-
"conflict",
|
|
7870
|
-
"match",
|
|
7871
|
-
"onProtectionUnavailable",
|
|
7872
|
-
"persistence",
|
|
7873
|
-
"protection",
|
|
7874
|
-
"sensitivity"
|
|
7875
|
-
]);
|
|
7876
|
-
const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
|
|
7877
|
-
if (unsupportedRuleKey)
|
|
7878
|
-
throw metadataError(id, `localData.mutations[${index}].${unsupportedRuleKey} is not supported.`);
|
|
7879
|
-
const protection = unknownField(rule, "protection");
|
|
7880
|
-
const sensitivity = unknownField(rule, "sensitivity");
|
|
7881
|
-
const persistence = unknownField(rule, "persistence");
|
|
7882
|
-
const onProtectionUnavailable = unknownField(rule, "onProtectionUnavailable");
|
|
7883
|
-
const declaredConflict = unknownField(rule, "conflict");
|
|
7884
|
-
let conflict;
|
|
7885
|
-
if (declaredConflict !== undefined) {
|
|
7886
|
-
const conflictRecord = requireObject(declaredConflict, id, `localData.mutations[${index}].conflict must be an object.`);
|
|
7887
|
-
const unsupportedConflictKey = Object.keys(conflictRecord).find((key) => key !== "maxAttempts" && key !== "strategy");
|
|
7888
|
-
if (unsupportedConflictKey)
|
|
7889
|
-
throw metadataError(id, `localData.mutations[${index}].conflict.${unsupportedConflictKey} is not supported.`);
|
|
7890
|
-
const strategy = unknownField(conflictRecord, "strategy");
|
|
7891
|
-
if (strategy !== "client-wins" && strategy !== "manual" && strategy !== "server-wins")
|
|
7892
|
-
throw metadataError(id, `localData.mutations[${index}].conflict.strategy is invalid.`);
|
|
7893
|
-
const maxAttempts = unknownField(conflictRecord, "maxAttempts");
|
|
7894
|
-
if (maxAttempts !== undefined && strategy !== "client-wins")
|
|
7895
|
-
throw metadataError(id, `localData.mutations[${index}].conflict.maxAttempts requires client-wins.`);
|
|
7896
|
-
conflict = {
|
|
7897
|
-
strategy,
|
|
7898
|
-
...maxAttempts === undefined ? {} : {
|
|
7899
|
-
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
|
+
}
|
|
7900
8102
|
}
|
|
7901
|
-
}
|
|
7902
|
-
}
|
|
7903
|
-
if (protection !== undefined && protection !== "none" && protection !== "required")
|
|
7904
|
-
throw metadataError(id, `localData.mutations[${index}].protection is invalid.`);
|
|
7905
|
-
if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
|
|
7906
|
-
throw metadataError(id, `localData.mutations[${index}].sensitivity is invalid.`);
|
|
7907
|
-
if (onProtectionUnavailable !== undefined && onProtectionUnavailable !== "error" && onProtectionUnavailable !== "memory-only")
|
|
7908
|
-
throw metadataError(id, `localData.mutations[${index}].onProtectionUnavailable is invalid.`);
|
|
7909
|
-
if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
|
|
7910
|
-
throw metadataError(id, `localData.mutations[${index}].persistence is invalid.`);
|
|
7911
|
-
return {
|
|
7912
|
-
match: nonEmpty(Reflect.get(rule, "match"), id, `localData.mutations[${index}].match`),
|
|
7913
|
-
...conflict ? { conflict } : {},
|
|
7914
|
-
...sensitivity ? { sensitivity } : {},
|
|
7915
|
-
...onProtectionUnavailable ? { onProtectionUnavailable } : {},
|
|
7916
|
-
...persistence ? {
|
|
7917
|
-
persistence
|
|
7918
|
-
} : {},
|
|
7919
|
-
...protection ? { protection } : {}
|
|
8103
|
+
} : {}
|
|
7920
8104
|
};
|
|
7921
|
-
|
|
7922
|
-
|
|
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
|
+
}
|
|
7923
8187
|
return {
|
|
7924
|
-
|
|
7925
|
-
|
|
7926
|
-
|
|
7927
|
-
|
|
7928
|
-
}
|
|
8188
|
+
bundleId: value.bundleId,
|
|
8189
|
+
currentReleaseId: value.currentReleaseId,
|
|
8190
|
+
format: ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
|
|
8191
|
+
releases
|
|
7929
8192
|
};
|
|
7930
|
-
},
|
|
7931
|
-
const
|
|
7932
|
-
const
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
"
|
|
7936
|
-
|
|
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()))
|
|
7937
8201
|
]);
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
|
|
7950
|
-
|
|
7951
|
-
|
|
7952
|
-
|
|
7953
|
-
|
|
7954
|
-
|
|
7955
|
-
}
|
|
7956
|
-
|
|
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
|
|
7957
8249
|
};
|
|
7958
|
-
|
|
7959
|
-
|
|
7960
|
-
|
|
7961
|
-
|
|
7962
|
-
|
|
7963
|
-
|
|
7964
|
-
|
|
7965
|
-
const
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
];
|
|
7984
|
-
for (const name of dependencyNames(appManifest)) {
|
|
7985
|
-
const manifestPath = packageManifestPath(projectRoot, name);
|
|
7986
|
-
if (!manifestPath)
|
|
7987
|
-
continue;
|
|
7988
|
-
const manifest = manifestAt(manifestPath);
|
|
7989
|
-
if (!manifest)
|
|
7990
|
-
continue;
|
|
7991
|
-
const metadata = localSchemaMetadata(manifest);
|
|
7992
|
-
if (metadata === undefined)
|
|
7993
|
-
continue;
|
|
7994
|
-
components.push(component(name, metadata));
|
|
7995
|
-
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;
|
|
7996
8275
|
}
|
|
7997
|
-
components.sort((left, right) => left.id.localeCompare(right.id));
|
|
7998
|
-
sources.sort((left, right) => left.id.localeCompare(right.id));
|
|
7999
|
-
resolveSyncLocalSchemaComponents({}, { components });
|
|
8000
|
-
return { components, sources };
|
|
8001
8276
|
};
|
|
8002
|
-
var
|
|
8003
|
-
|
|
8277
|
+
var init_materializedBundle = __esm(() => {
|
|
8278
|
+
init_artifactStore();
|
|
8279
|
+
init_releaseArtifact();
|
|
8280
|
+
BUNDLE_ID_PATTERN = /^amb_[a-f0-9]{64}$/;
|
|
8004
8281
|
});
|
|
8005
8282
|
|
|
8006
8283
|
// src/mobile/deviceCapabilities.ts
|
|
@@ -8327,9 +8604,6 @@ var isElysiaApp = (value) => typeof value === "object" && value !== null && type
|
|
|
8327
8604
|
runtime: String(ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION)
|
|
8328
8605
|
});
|
|
8329
8606
|
const auth = resolveAbsoluteMobileAuthManifest(options.projectRoot, mobile);
|
|
8330
|
-
if (mobile.engine === "expo" && auth) {
|
|
8331
|
-
throw new TypeError("Expo mobile Auth is not released yet. The experimental Expo shell cannot safely substitute Capacitor credentials; remove engine: 'expo' or wait for @absolutejs/auth-expo.");
|
|
8332
|
-
}
|
|
8333
8607
|
const sync = auth !== undefined && projectUsesAbsoluteSync(options.projectRoot);
|
|
8334
8608
|
const syncSchema = sync ? discoverAbsoluteSyncSchema(options.projectRoot) : undefined;
|
|
8335
8609
|
const deviceCapabilities = resolveAbsoluteDeviceCapabilityPlan(options.projectRoot);
|
|
@@ -8956,12 +9230,12 @@ var init_serverBundleExternals = __esm(() => {
|
|
|
8956
9230
|
// src/core/prerender.ts
|
|
8957
9231
|
var exports_prerender = {};
|
|
8958
9232
|
__export(exports_prerender, {
|
|
8959
|
-
|
|
8960
|
-
rerenderRoute: () => rerenderRoute,
|
|
8961
|
-
readTimestamp: () => readTimestamp,
|
|
8962
|
-
prerenderWithServer: () => prerenderWithServer,
|
|
9233
|
+
PRERENDER_BYPASS_HEADER: () => PRERENDER_BYPASS_HEADER,
|
|
8963
9234
|
prerender: () => prerender,
|
|
8964
|
-
|
|
9235
|
+
prerenderWithServer: () => prerenderWithServer,
|
|
9236
|
+
readTimestamp: () => readTimestamp,
|
|
9237
|
+
rerenderRoute: () => rerenderRoute,
|
|
9238
|
+
routeToFilename: () => routeToFilename
|
|
8965
9239
|
});
|
|
8966
9240
|
import { mkdirSync as mkdirSync6, readFileSync as readFileSync14 } from "fs";
|
|
8967
9241
|
import { join as join24 } from "path";
|
|
@@ -9621,8 +9895,8 @@ var init_rewriteImportsPlugin = __esm(() => {
|
|
|
9621
9895
|
// src/build/rewriteImports.ts
|
|
9622
9896
|
var exports_rewriteImports = {};
|
|
9623
9897
|
__export(exports_rewriteImports, {
|
|
9624
|
-
|
|
9625
|
-
|
|
9898
|
+
rewriteImports: () => rewriteImports,
|
|
9899
|
+
rewriteVendorDirectories: () => rewriteVendorDirectories2
|
|
9626
9900
|
});
|
|
9627
9901
|
var rewriteImports = async (outputPaths, vendorPaths) => {
|
|
9628
9902
|
const jsFiles = outputPaths.filter((path) => path.endsWith(".js"));
|
|
@@ -10285,11 +10559,11 @@ var init_build = __esm(() => {
|
|
|
10285
10559
|
// src/cli/scripts/lintProof.ts
|
|
10286
10560
|
var exports_lintProof = {};
|
|
10287
10561
|
__export(exports_lintProof, {
|
|
10288
|
-
|
|
10289
|
-
verifyLintProof: () => verifyLintProof,
|
|
10290
|
-
runLintProof: () => runLintProof,
|
|
10562
|
+
createLintProof: () => createLintProof,
|
|
10291
10563
|
createLintSourceTree: () => createLintSourceTree,
|
|
10292
|
-
|
|
10564
|
+
runLintProof: () => runLintProof,
|
|
10565
|
+
verifyLintProof: () => verifyLintProof,
|
|
10566
|
+
writeLintProof: () => writeLintProof
|
|
10293
10567
|
});
|
|
10294
10568
|
import {
|
|
10295
10569
|
createHash as createHash12,
|
|
@@ -15063,9 +15337,9 @@ var init_htmx = __esm(() => {
|
|
|
15063
15337
|
// src/cli/scripts/env.ts
|
|
15064
15338
|
var exports_env = {};
|
|
15065
15339
|
__export(exports_env, {
|
|
15066
|
-
|
|
15340
|
+
collectEnvVars: () => collectEnvVars,
|
|
15067
15341
|
runEnv: () => runEnv,
|
|
15068
|
-
|
|
15342
|
+
scanEnvUsage: () => scanEnvUsage
|
|
15069
15343
|
});
|
|
15070
15344
|
import { existsSync as existsSync33, readFileSync as readFileSync33 } from "fs";
|
|
15071
15345
|
import { join as join41 } from "path";
|
|
@@ -15129,12 +15403,12 @@ var init_env = __esm(() => {
|
|
|
15129
15403
|
// src/cli/scripts/db.ts
|
|
15130
15404
|
var exports_db = {};
|
|
15131
15405
|
__export(exports_db, {
|
|
15132
|
-
|
|
15133
|
-
quoteIdent: () => quoteIdent,
|
|
15134
|
-
encodeValue: () => encodeValue,
|
|
15135
|
-
dependencyOrder: () => dependencyOrder,
|
|
15406
|
+
chunkRows: () => chunkRows,
|
|
15136
15407
|
conflictClause: () => conflictClause,
|
|
15137
|
-
|
|
15408
|
+
dependencyOrder: () => dependencyOrder,
|
|
15409
|
+
encodeValue: () => encodeValue,
|
|
15410
|
+
quoteIdent: () => quoteIdent,
|
|
15411
|
+
runDb: () => runDb
|
|
15138
15412
|
});
|
|
15139
15413
|
import { existsSync as existsSync34, mkdirSync as mkdirSync15, readFileSync as readFileSync34, writeFileSync as writeFileSync18 } from "fs";
|
|
15140
15414
|
import { join as join42 } from "path";
|
|
@@ -16474,8 +16748,8 @@ var init_externalAssetPlugin = () => {};
|
|
|
16474
16748
|
// src/cli/scripts/compile.ts
|
|
16475
16749
|
var exports_compile = {};
|
|
16476
16750
|
__export(exports_compile, {
|
|
16477
|
-
|
|
16478
|
-
|
|
16751
|
+
compile: () => compile,
|
|
16752
|
+
shouldEmbedCompiledAsset: () => shouldEmbedCompiledAsset
|
|
16479
16753
|
});
|
|
16480
16754
|
var {env: env5 } = globalThis.Bun;
|
|
16481
16755
|
import {
|
|
@@ -18434,12 +18708,38 @@ import { mkdir as mkdir12, writeFile as writeFile14 } from "fs/promises";
|
|
|
18434
18708
|
import { dirname as dirname29, resolve as resolve38 } from "path";
|
|
18435
18709
|
|
|
18436
18710
|
class CdpConnection {
|
|
18437
|
-
|
|
18438
|
-
|
|
18439
|
-
#
|
|
18440
|
-
#nextId = 1;
|
|
18441
|
-
#pending = new Map;
|
|
18711
|
+
#closed;
|
|
18712
|
+
#nextId;
|
|
18713
|
+
#pending;
|
|
18442
18714
|
constructor(socket) {
|
|
18715
|
+
this.diagnostics = [];
|
|
18716
|
+
this.#closed = false;
|
|
18717
|
+
this.#nextId = 1;
|
|
18718
|
+
this.#pending = new Map;
|
|
18719
|
+
this.command = (method, params = {}, timeoutMs = CDP_COMMAND_TIMEOUT_MS) => {
|
|
18720
|
+
if (this.#closed) {
|
|
18721
|
+
return Promise.reject(new Error("Android WebView debugger is closed."));
|
|
18722
|
+
}
|
|
18723
|
+
const id = this.#nextId++;
|
|
18724
|
+
return new Promise((_resolve, reject) => {
|
|
18725
|
+
const timer = setTimeout(() => {
|
|
18726
|
+
this.#pending.delete(id);
|
|
18727
|
+
reject(new Error(`CDP ${method} timed out after ${timeoutMs}ms.`));
|
|
18728
|
+
}, timeoutMs);
|
|
18729
|
+
this.#pending.set(id, {
|
|
18730
|
+
reject,
|
|
18731
|
+
resolve: _resolve,
|
|
18732
|
+
timer
|
|
18733
|
+
});
|
|
18734
|
+
this.socket.send(JSON.stringify({ id, method, params }));
|
|
18735
|
+
});
|
|
18736
|
+
};
|
|
18737
|
+
this.close = async () => {
|
|
18738
|
+
if (this.#closed)
|
|
18739
|
+
return;
|
|
18740
|
+
this.#closed = true;
|
|
18741
|
+
this.socket.close();
|
|
18742
|
+
};
|
|
18443
18743
|
this.socket = socket;
|
|
18444
18744
|
socket.addEventListener("message", (event) => {
|
|
18445
18745
|
this.onMessage(event.data);
|
|
@@ -18518,30 +18818,6 @@ class CdpConnection {
|
|
|
18518
18818
|
}
|
|
18519
18819
|
pending.resolve(message.result);
|
|
18520
18820
|
}
|
|
18521
|
-
command = (method, params = {}, timeoutMs = CDP_COMMAND_TIMEOUT_MS) => {
|
|
18522
|
-
if (this.#closed) {
|
|
18523
|
-
return Promise.reject(new Error("Android WebView debugger is closed."));
|
|
18524
|
-
}
|
|
18525
|
-
const id = this.#nextId++;
|
|
18526
|
-
return new Promise((_resolve, reject) => {
|
|
18527
|
-
const timer = setTimeout(() => {
|
|
18528
|
-
this.#pending.delete(id);
|
|
18529
|
-
reject(new Error(`CDP ${method} timed out after ${timeoutMs}ms.`));
|
|
18530
|
-
}, timeoutMs);
|
|
18531
|
-
this.#pending.set(id, {
|
|
18532
|
-
reject,
|
|
18533
|
-
resolve: _resolve,
|
|
18534
|
-
timer
|
|
18535
|
-
});
|
|
18536
|
-
this.socket.send(JSON.stringify({ id, method, params }));
|
|
18537
|
-
});
|
|
18538
|
-
};
|
|
18539
|
-
close = async () => {
|
|
18540
|
-
if (this.#closed)
|
|
18541
|
-
return;
|
|
18542
|
-
this.#closed = true;
|
|
18543
|
-
this.socket.close();
|
|
18544
|
-
};
|
|
18545
18821
|
}
|
|
18546
18822
|
var CDP_COMMAND_TIMEOUT_MS = 1e4, WEBVIEW_ATTACH_TIMEOUT_MS = 30000, WEBVIEW_POLL_MS = 200, captureCommand3 = (command) => {
|
|
18547
18823
|
const result = Bun.spawnSync(command, {
|
|
@@ -21019,7 +21295,7 @@ var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value
|
|
|
21019
21295
|
}, initialize = async (args) => {
|
|
21020
21296
|
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
21021
21297
|
if (mobile.engine === "expo") {
|
|
21022
|
-
console.warn("Experimental: Expo Auth
|
|
21298
|
+
console.warn("Experimental: Expo Auth and authenticated HTTP are available; Sync, release publishing, and physical-device acceptance are not complete.");
|
|
21023
21299
|
const generated2 = await writeAbsoluteExpoProject(mobile, {
|
|
21024
21300
|
force: args.includes("--force"),
|
|
21025
21301
|
projectRoot
|
|
@@ -22940,12 +23216,12 @@ import { spawn as nodeSpawn } from "child_process";
|
|
|
22940
23216
|
import {
|
|
22941
23217
|
createWriteStream,
|
|
22942
23218
|
existsSync as existsSync5,
|
|
22943
|
-
readFileSync as
|
|
23219
|
+
readFileSync as readFileSync9,
|
|
22944
23220
|
rmSync as rmSync2,
|
|
22945
23221
|
writeFileSync as writeFileSync4
|
|
22946
23222
|
} from "fs";
|
|
22947
23223
|
import { tmpdir as tmpdir2 } from "os";
|
|
22948
|
-
import { join as
|
|
23224
|
+
import { join as join16, resolve as resolvePath2 } from "path";
|
|
22949
23225
|
|
|
22950
23226
|
// src/dev/tunnel/client.ts
|
|
22951
23227
|
var RECONNECT_DELAY_MS = 2000;
|
|
@@ -23455,7 +23731,7 @@ init_expoProject();
|
|
|
23455
23731
|
init_iosPhysicalDeviceTransport();
|
|
23456
23732
|
import { spawn } from "child_process";
|
|
23457
23733
|
import { access as access2 } from "fs/promises";
|
|
23458
|
-
import { join as
|
|
23734
|
+
import { join as join8 } from "path";
|
|
23459
23735
|
var METRO_READY_TIMEOUT_MS = 60000;
|
|
23460
23736
|
var PROCESS_CLOSE_TIMEOUT_MS = 2000;
|
|
23461
23737
|
var commandEnvironment = (options) => ({
|
|
@@ -23468,7 +23744,7 @@ var commandEnvironment = (options) => ({
|
|
|
23468
23744
|
...options.metroHost ? { REACT_NATIVE_PACKAGER_HOSTNAME: options.metroHost } : {}
|
|
23469
23745
|
});
|
|
23470
23746
|
var absoluteExpoExecutable = async (project) => {
|
|
23471
|
-
const executable =
|
|
23747
|
+
const executable = join8(project, "node_modules", ".bin", "expo");
|
|
23472
23748
|
try {
|
|
23473
23749
|
await access2(executable);
|
|
23474
23750
|
return executable;
|
|
@@ -23564,18 +23840,18 @@ var stopProcess = async (process2) => {
|
|
|
23564
23840
|
return;
|
|
23565
23841
|
process2.kill("SIGTERM");
|
|
23566
23842
|
await Promise.race([
|
|
23567
|
-
new Promise((
|
|
23568
|
-
new Promise((
|
|
23843
|
+
new Promise((resolve5) => process2.once("exit", () => resolve5())),
|
|
23844
|
+
new Promise((resolve5) => setTimeout(resolve5, PROCESS_CLOSE_TIMEOUT_MS))
|
|
23569
23845
|
]);
|
|
23570
23846
|
if (process2.exitCode === null)
|
|
23571
23847
|
process2.kill("SIGKILL");
|
|
23572
23848
|
};
|
|
23573
|
-
var waitForExit = (process2) => new Promise((
|
|
23849
|
+
var waitForExit = (process2) => new Promise((resolve5) => {
|
|
23574
23850
|
if (process2.exitCode !== null) {
|
|
23575
|
-
|
|
23851
|
+
resolve5(process2.exitCode);
|
|
23576
23852
|
return;
|
|
23577
23853
|
}
|
|
23578
|
-
process2.once("exit", (code) =>
|
|
23854
|
+
process2.once("exit", (code) => resolve5(code ?? 1));
|
|
23579
23855
|
});
|
|
23580
23856
|
var runUtilityCommand = async (run, command, args, options) => {
|
|
23581
23857
|
const child = run(command, args, {
|
|
@@ -23655,9 +23931,9 @@ var startAbsoluteExpoDevSession = async (options) => {
|
|
|
23655
23931
|
}) : undefined;
|
|
23656
23932
|
let metroReady = false;
|
|
23657
23933
|
let resolveMetro;
|
|
23658
|
-
const metroPromise = new Promise((
|
|
23934
|
+
const metroPromise = new Promise((resolve5, reject) => {
|
|
23659
23935
|
if (!metro) {
|
|
23660
|
-
|
|
23936
|
+
resolve5();
|
|
23661
23937
|
return;
|
|
23662
23938
|
}
|
|
23663
23939
|
const timeout = setTimeout(() => {
|
|
@@ -23665,7 +23941,7 @@ var startAbsoluteExpoDevSession = async (options) => {
|
|
|
23665
23941
|
}, METRO_READY_TIMEOUT_MS);
|
|
23666
23942
|
resolveMetro = () => {
|
|
23667
23943
|
clearTimeout(timeout);
|
|
23668
|
-
|
|
23944
|
+
resolve5();
|
|
23669
23945
|
};
|
|
23670
23946
|
metro.once("exit", (code) => {
|
|
23671
23947
|
if (!metroReady) {
|
|
@@ -24123,9 +24399,9 @@ var setupHttpsCert = async (hosts = []) => {
|
|
|
24123
24399
|
await setupCertWithPrompt(ensureDevCert2, setupMkcert2, hosts);
|
|
24124
24400
|
return getDevCertificateAuthorityPath2();
|
|
24125
24401
|
};
|
|
24126
|
-
var mobileReachableHost = (
|
|
24127
|
-
if (
|
|
24128
|
-
return
|
|
24402
|
+
var mobileReachableHost = (host2) => {
|
|
24403
|
+
if (host2 !== "0.0.0.0" && host2 !== "::")
|
|
24404
|
+
return host2;
|
|
24129
24405
|
const address = getLocalIPAddress();
|
|
24130
24406
|
if (address === "localhost") {
|
|
24131
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.");
|
|
@@ -24220,7 +24496,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24220
24496
|
const generated = await writeAbsoluteExpoProject(normalized, {
|
|
24221
24497
|
projectRoot: process.cwd()
|
|
24222
24498
|
});
|
|
24223
|
-
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"));
|
|
24224
24500
|
if (!dependenciesReady) {
|
|
24225
24501
|
const install = await confirmPrompt("Expo development dependencies are missing. Install the pinned SDK 57 development client now?");
|
|
24226
24502
|
if (!install) {
|
|
@@ -24230,7 +24506,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24230
24506
|
cwd: generated.path,
|
|
24231
24507
|
stdio: "inherit"
|
|
24232
24508
|
});
|
|
24233
|
-
const installExit = await new Promise((
|
|
24509
|
+
const installExit = await new Promise((resolve10) => installProcess.once("exit", (code) => resolve10(code ?? 1)));
|
|
24234
24510
|
if (installExit !== 0) {
|
|
24235
24511
|
throw new TypeError(`Expo dependency installation exited with status ${installExit}.`);
|
|
24236
24512
|
}
|
|
@@ -24299,7 +24575,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24299
24575
|
}
|
|
24300
24576
|
}
|
|
24301
24577
|
if (ready) {
|
|
24302
|
-
const nativeDirectory =
|
|
24578
|
+
const nativeDirectory = join16(normalized.nativeProjectDirectory, "android");
|
|
24303
24579
|
let createNativeProject = false;
|
|
24304
24580
|
if (!existsSync5(nativeDirectory)) {
|
|
24305
24581
|
createNativeProject = await confirmPrompt("Create the managed Capacitor Android project now?");
|
|
@@ -24319,7 +24595,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24319
24595
|
if (!remote) {
|
|
24320
24596
|
console.log(cliTag("\x1B[33m", "iOS target skipped. Pair a Mac with `absolute mobile pair mac <name> <user@host>`."));
|
|
24321
24597
|
} else {
|
|
24322
|
-
const nativeDirectory =
|
|
24598
|
+
const nativeDirectory = join16(normalized.nativeProjectDirectory, "ios");
|
|
24323
24599
|
if (!existsSync5(nativeDirectory)) {
|
|
24324
24600
|
console.log(cliTag("\x1B[33m", "The iOS project is missing. Run `absolute mobile init` before remote development."));
|
|
24325
24601
|
} else {
|
|
@@ -24340,7 +24616,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24340
24616
|
}
|
|
24341
24617
|
}
|
|
24342
24618
|
if (ready) {
|
|
24343
|
-
const nativeDirectory =
|
|
24619
|
+
const nativeDirectory = join16(normalized.nativeProjectDirectory, "ios");
|
|
24344
24620
|
let createNativeProject = false;
|
|
24345
24621
|
if (!existsSync5(nativeDirectory)) {
|
|
24346
24622
|
createNativeProject = await confirmPrompt("Create the managed Capacitor iOS project now?");
|
|
@@ -24692,9 +24968,9 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24692
24968
|
iosDevStart = null;
|
|
24693
24969
|
});
|
|
24694
24970
|
};
|
|
24695
|
-
const absoluteDevOrigin = (
|
|
24971
|
+
const absoluteDevOrigin = (host2) => {
|
|
24696
24972
|
const url = new URL(`${httpsEnabled ? "https" : "http"}://localhost`);
|
|
24697
|
-
url.hostname =
|
|
24973
|
+
url.hostname = host2;
|
|
24698
24974
|
url.port = String(port);
|
|
24699
24975
|
return url.origin;
|
|
24700
24976
|
};
|
|
@@ -24960,8 +25236,8 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24960
25236
|
});
|
|
24961
25237
|
if (probe && probe.port !== port) {
|
|
24962
25238
|
const { port: nextPort } = probe;
|
|
24963
|
-
const { host } = refreshedDevConfig;
|
|
24964
|
-
const displayHost =
|
|
25239
|
+
const { host: host2 } = refreshedDevConfig;
|
|
25240
|
+
const displayHost = host2 === "0.0.0.0" ? "localhost" : host2;
|
|
24965
25241
|
console.log(cliTag("\x1B[36m", `Port changed in config \u2014 switching to http://${displayHost}:${nextPort}/`));
|
|
24966
25242
|
port = nextPort;
|
|
24967
25243
|
updateLockMetadata(buildDirectory, { port });
|
|
@@ -24976,7 +25252,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24976
25252
|
for (const name of candidates) {
|
|
24977
25253
|
let text;
|
|
24978
25254
|
try {
|
|
24979
|
-
text =
|
|
25255
|
+
text = readFileSync9(resolvePath2(process.cwd(), name), "utf8");
|
|
24980
25256
|
} catch {
|
|
24981
25257
|
continue;
|
|
24982
25258
|
}
|
|
@@ -24998,7 +25274,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24998
25274
|
}
|
|
24999
25275
|
return merged;
|
|
25000
25276
|
};
|
|
25001
|
-
const heapPreloadPath =
|
|
25277
|
+
const heapPreloadPath = join16(tmpdir2(), `absolute-heap-${process.pid}.ts`);
|
|
25002
25278
|
let heapSnapshotEnabled = false;
|
|
25003
25279
|
try {
|
|
25004
25280
|
writeFileSync4(heapPreloadPath, DEV_CHILD_PRELOAD);
|
|
@@ -25097,9 +25373,9 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
25097
25373
|
};
|
|
25098
25374
|
try {
|
|
25099
25375
|
const { watch: watch3 } = await import("fs");
|
|
25100
|
-
const { dirname:
|
|
25376
|
+
const { dirname: dirname9 } = await import("path");
|
|
25101
25377
|
const absServerEntry = resolvePath2(serverEntry);
|
|
25102
|
-
const serverEntryDir =
|
|
25378
|
+
const serverEntryDir = dirname9(absServerEntry);
|
|
25103
25379
|
const ROOT_RESTART_DENY = new Set([
|
|
25104
25380
|
"build",
|
|
25105
25381
|
"dist",
|
|
@@ -25131,7 +25407,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
25131
25407
|
if (now - last < 100)
|
|
25132
25408
|
return;
|
|
25133
25409
|
recentlyHandled.set(filename, now);
|
|
25134
|
-
scheduleServerRestart(
|
|
25410
|
+
scheduleServerRestart(join16(serverEntryDir, filename));
|
|
25135
25411
|
};
|
|
25136
25412
|
const recoveryScan = async () => {
|
|
25137
25413
|
let entries;
|
|
@@ -25150,7 +25426,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
25150
25426
|
continue;
|
|
25151
25427
|
let fileStat;
|
|
25152
25428
|
try {
|
|
25153
|
-
fileStat = statSync(
|
|
25429
|
+
fileStat = statSync(join16(serverEntryDir, entry.name));
|
|
25154
25430
|
} catch {
|
|
25155
25431
|
continue;
|
|
25156
25432
|
}
|
|
@@ -25538,9 +25814,9 @@ init_eslint();
|
|
|
25538
25814
|
init_constants();
|
|
25539
25815
|
init_utils();
|
|
25540
25816
|
import { execSync as execSync2 } from "child_process";
|
|
25541
|
-
import { existsSync as existsSync8, readFileSync as
|
|
25817
|
+
import { existsSync as existsSync8, readFileSync as readFileSync11 } from "fs";
|
|
25542
25818
|
import { arch as arch2, cpus, platform as platform3, totalmem, version } from "os";
|
|
25543
|
-
import { resolve as
|
|
25819
|
+
import { resolve as resolve12 } from "path";
|
|
25544
25820
|
var bold = (str) => `\x1B[1m${str}\x1B[0m`;
|
|
25545
25821
|
var getBinaryVersion = (binary, flag = "--version") => {
|
|
25546
25822
|
try {
|
|
@@ -25560,7 +25836,7 @@ var getPackageVersion = (packageName) => {
|
|
|
25560
25836
|
const pkgPath = __require.resolve(`${packageName}/package.json`, {
|
|
25561
25837
|
paths: [process.cwd()]
|
|
25562
25838
|
});
|
|
25563
|
-
const pkg = JSON.parse(
|
|
25839
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
25564
25840
|
const ver = pkg.version;
|
|
25565
25841
|
return ver;
|
|
25566
25842
|
} catch {
|
|
@@ -25570,8 +25846,8 @@ var getPackageVersion = (packageName) => {
|
|
|
25570
25846
|
var getAbsoluteVersion = () => {
|
|
25571
25847
|
try {
|
|
25572
25848
|
const candidates = [
|
|
25573
|
-
|
|
25574
|
-
|
|
25849
|
+
resolve12(import.meta.dir, "..", "..", "package.json"),
|
|
25850
|
+
resolve12(import.meta.dir, "..", "..", "..", "package.json")
|
|
25575
25851
|
];
|
|
25576
25852
|
const pkgPath = candidates.find((candidate) => existsSync8(candidate));
|
|
25577
25853
|
if (pkgPath)
|
|
@@ -25582,7 +25858,7 @@ var getAbsoluteVersion = () => {
|
|
|
25582
25858
|
return getPackageVersion("@absolutejs/absolute");
|
|
25583
25859
|
};
|
|
25584
25860
|
var readPackageVersion = (pkgPath) => {
|
|
25585
|
-
const pkg = JSON.parse(
|
|
25861
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
25586
25862
|
const ver = pkg.version;
|
|
25587
25863
|
return ver;
|
|
25588
25864
|
};
|
|
@@ -25684,7 +25960,7 @@ var info = () => {
|
|
|
25684
25960
|
// src/cli/cache.ts
|
|
25685
25961
|
init_constants();
|
|
25686
25962
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
25687
|
-
import { join as
|
|
25963
|
+
import { join as join17 } from "path";
|
|
25688
25964
|
var {Glob } = globalThis.Bun;
|
|
25689
25965
|
var CACHE_DIR = ".absolutejs";
|
|
25690
25966
|
var MAX_FILES_PER_BATCH = 200;
|
|
@@ -25736,7 +26012,7 @@ var hashFiles = async (paths) => {
|
|
|
25736
26012
|
};
|
|
25737
26013
|
var loadCache = async (tool) => {
|
|
25738
26014
|
try {
|
|
25739
|
-
const path =
|
|
26015
|
+
const path = join17(CACHE_DIR, `${tool}.cache.json`);
|
|
25740
26016
|
const data = await Bun.file(path).json();
|
|
25741
26017
|
const result = data;
|
|
25742
26018
|
return result;
|
|
@@ -25783,7 +26059,7 @@ var runTool = async (adapter, args) => {
|
|
|
25783
26059
|
};
|
|
25784
26060
|
var saveCache = async (tool, data) => {
|
|
25785
26061
|
await mkdir7(CACHE_DIR, { recursive: true });
|
|
25786
|
-
const path =
|
|
26062
|
+
const path = join17(CACHE_DIR, `${tool}.cache.json`);
|
|
25787
26063
|
await Bun.write(path, JSON.stringify(data, null, "\t"));
|
|
25788
26064
|
};
|
|
25789
26065
|
|