@absolutejs/absolute 0.20.0-beta.114 → 0.20.0-beta.116
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/CHANGELOG.md +14 -0
- package/changelog.json +29 -0
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/cli/{compile-ya4kd2sg.js → compile-kbhxgjat.js} +2 -2
- package/dist/cli/{dev-5cqmf7za.js → dev-daa7tdht.js} +1 -1
- package/dist/cli/{expoProject-f5j20xms.js → expoProject-kcfcmfba.js} +1 -1
- package/dist/cli/{index-6mbm4n3g.js → index-82wpxhvv.js} +1 -1
- package/dist/cli/{index-dr21p6ae.js → index-bhcxtf1x.js} +389 -78
- package/dist/cli/{index-5fmgn0nx.js → index-vjepnxr0.js} +1 -1
- package/dist/cli/index.js +5 -5
- package/dist/cli/{mobile-55wjg3nd.js → mobile-03zwncxx.js} +61 -20
- package/dist/cli/{start-jt61f40d.js → start-r606d5v9.js} +3 -3
- package/dist/mobile/index.js +525 -175
- package/dist/mobile/index.js.map +8 -6
- package/dist/mobile/remoteMacAgentEntry.js +475 -209
- package/dist/mobile/shellBootstrap.js +6 -1
- package/dist/react/hooks/index.js +6 -2
- package/dist/react/hooks/index.js.map +3 -3
- package/dist/src/mobile/androidServiceReadiness.d.ts +14 -0
- package/dist/src/mobile/expoEmbeddedAssets.d.ts +1 -0
- package/dist/src/mobile/updateRuntime.d.ts +1 -0
- package/dist/src/react/hooks/useMediaQuery.d.ts +3 -1
- package/dist/src/utils/userAgentFunctions.d.ts +1 -1
- package/package.json +4 -1
package/dist/mobile/index.js
CHANGED
|
@@ -6439,24 +6439,24 @@ var require_pem = __commonJS(function(exports, module) {
|
|
|
6439
6439
|
options = options || {};
|
|
6440
6440
|
var rval = "-----BEGIN " + msg.type + `-----\r
|
|
6441
6441
|
`;
|
|
6442
|
-
var
|
|
6442
|
+
var header2;
|
|
6443
6443
|
if (msg.procType) {
|
|
6444
|
-
|
|
6444
|
+
header2 = {
|
|
6445
6445
|
name: "Proc-Type",
|
|
6446
6446
|
values: [String(msg.procType.version), msg.procType.type]
|
|
6447
6447
|
};
|
|
6448
|
-
rval += foldHeader(
|
|
6448
|
+
rval += foldHeader(header2);
|
|
6449
6449
|
}
|
|
6450
6450
|
if (msg.contentDomain) {
|
|
6451
|
-
|
|
6452
|
-
rval += foldHeader(
|
|
6451
|
+
header2 = { name: "Content-Domain", values: [msg.contentDomain] };
|
|
6452
|
+
rval += foldHeader(header2);
|
|
6453
6453
|
}
|
|
6454
6454
|
if (msg.dekInfo) {
|
|
6455
|
-
|
|
6455
|
+
header2 = { name: "DEK-Info", values: [msg.dekInfo.algorithm] };
|
|
6456
6456
|
if (msg.dekInfo.parameters) {
|
|
6457
|
-
|
|
6457
|
+
header2.values.push(msg.dekInfo.parameters);
|
|
6458
6458
|
}
|
|
6459
|
-
rval += foldHeader(
|
|
6459
|
+
rval += foldHeader(header2);
|
|
6460
6460
|
}
|
|
6461
6461
|
if (msg.headers) {
|
|
6462
6462
|
for (var i = 0;i < msg.headers.length; ++i) {
|
|
@@ -6514,27 +6514,27 @@ var require_pem = __commonJS(function(exports, module) {
|
|
|
6514
6514
|
}
|
|
6515
6515
|
match = line.match(rHeader);
|
|
6516
6516
|
if (match) {
|
|
6517
|
-
var
|
|
6517
|
+
var header2 = { name: match[1], values: [] };
|
|
6518
6518
|
var values = match[2].split(",");
|
|
6519
6519
|
for (var vi = 0;vi < values.length; ++vi) {
|
|
6520
|
-
|
|
6520
|
+
header2.values.push(ltrim(values[vi]));
|
|
6521
6521
|
}
|
|
6522
6522
|
if (!msg.procType) {
|
|
6523
|
-
if (
|
|
6523
|
+
if (header2.name !== "Proc-Type") {
|
|
6524
6524
|
throw new Error("Invalid PEM formatted message. The first " + 'encapsulated header must be "Proc-Type".');
|
|
6525
|
-
} else if (
|
|
6525
|
+
} else if (header2.values.length !== 2) {
|
|
6526
6526
|
throw new Error('Invalid PEM formatted message. The "Proc-Type" ' + "header must have two subfields.");
|
|
6527
6527
|
}
|
|
6528
6528
|
msg.procType = { version: values[0], type: values[1] };
|
|
6529
|
-
} else if (!msg.contentDomain &&
|
|
6529
|
+
} else if (!msg.contentDomain && header2.name === "Content-Domain") {
|
|
6530
6530
|
msg.contentDomain = values[0] || "";
|
|
6531
|
-
} else if (!msg.dekInfo &&
|
|
6532
|
-
if (
|
|
6531
|
+
} else if (!msg.dekInfo && header2.name === "DEK-Info") {
|
|
6532
|
+
if (header2.values.length === 0) {
|
|
6533
6533
|
throw new Error('Invalid PEM formatted message. The "DEK-Info" ' + "header must have at least one subfield.");
|
|
6534
6534
|
}
|
|
6535
6535
|
msg.dekInfo = { algorithm: values[0], parameters: values[1] || null };
|
|
6536
6536
|
} else {
|
|
6537
|
-
msg.headers.push(
|
|
6537
|
+
msg.headers.push(header2);
|
|
6538
6538
|
}
|
|
6539
6539
|
}
|
|
6540
6540
|
++li;
|
|
@@ -6548,14 +6548,14 @@ var require_pem = __commonJS(function(exports, module) {
|
|
|
6548
6548
|
}
|
|
6549
6549
|
return rval;
|
|
6550
6550
|
};
|
|
6551
|
-
function foldHeader(
|
|
6552
|
-
var rval =
|
|
6551
|
+
function foldHeader(header2) {
|
|
6552
|
+
var rval = header2.name + ": ";
|
|
6553
6553
|
var values = [];
|
|
6554
6554
|
var insertSpace = function(match, $1) {
|
|
6555
6555
|
return " " + $1;
|
|
6556
6556
|
};
|
|
6557
|
-
for (var i = 0;i <
|
|
6558
|
-
values.push(
|
|
6557
|
+
for (var i = 0;i < header2.values.length; ++i) {
|
|
6558
|
+
values.push(header2.values[i].replace(/^(\S+\r\n)/, insertSpace));
|
|
6559
6559
|
}
|
|
6560
6560
|
rval += values.join(",") + `\r
|
|
6561
6561
|
`;
|
|
@@ -7172,9 +7172,9 @@ var require_prng = __commonJS(function(exports, module) {
|
|
|
7172
7172
|
_crypto = __require("crypto");
|
|
7173
7173
|
}
|
|
7174
7174
|
var prng = module.exports = forge.prng = forge.prng || {};
|
|
7175
|
-
prng.create = function(
|
|
7175
|
+
prng.create = function(plugin2) {
|
|
7176
7176
|
var ctx = {
|
|
7177
|
-
plugin,
|
|
7177
|
+
plugin: plugin2,
|
|
7178
7178
|
key: null,
|
|
7179
7179
|
seed: null,
|
|
7180
7180
|
time: null,
|
|
@@ -7182,7 +7182,7 @@ var require_prng = __commonJS(function(exports, module) {
|
|
|
7182
7182
|
generated: 0,
|
|
7183
7183
|
keyBytes: ""
|
|
7184
7184
|
};
|
|
7185
|
-
var md =
|
|
7185
|
+
var md = plugin2.md;
|
|
7186
7186
|
var pools2 = new Array(32);
|
|
7187
7187
|
for (var i = 0;i < 32; ++i) {
|
|
7188
7188
|
pools2[i] = md.create();
|
|
@@ -19453,7 +19453,7 @@ var init_compatibilityDispatcher = __esm(() => {
|
|
|
19453
19453
|
// src/cli/scripts/telemetry.ts
|
|
19454
19454
|
import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync6, writeFileSync } from "fs";
|
|
19455
19455
|
import { homedir as homedir4 } from "os";
|
|
19456
|
-
import { join as
|
|
19456
|
+
import { join as join28 } from "path";
|
|
19457
19457
|
var configDir, configPath, getTelemetryConfig = () => {
|
|
19458
19458
|
try {
|
|
19459
19459
|
if (!existsSync5(configPath))
|
|
@@ -19466,14 +19466,14 @@ var configDir, configPath, getTelemetryConfig = () => {
|
|
|
19466
19466
|
}
|
|
19467
19467
|
};
|
|
19468
19468
|
var init_telemetry = __esm(() => {
|
|
19469
|
-
configDir =
|
|
19470
|
-
configPath =
|
|
19469
|
+
configDir = join28(homedir4(), ".absolutejs");
|
|
19470
|
+
configPath = join28(configDir, "telemetry.json");
|
|
19471
19471
|
});
|
|
19472
19472
|
|
|
19473
19473
|
// src/cli/telemetryEvent.ts
|
|
19474
19474
|
import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
19475
19475
|
import { arch, platform as platform3 } from "os";
|
|
19476
|
-
import { dirname as dirname20, join as
|
|
19476
|
+
import { dirname as dirname20, join as join29, parse } from "path";
|
|
19477
19477
|
var checkCandidate = (candidate) => {
|
|
19478
19478
|
if (!existsSync6(candidate)) {
|
|
19479
19479
|
return null;
|
|
@@ -19493,7 +19493,7 @@ var checkCandidate = (candidate) => {
|
|
|
19493
19493
|
}, findPackageVersion = () => {
|
|
19494
19494
|
let { dir } = import.meta;
|
|
19495
19495
|
while (dir !== parse(dir).root) {
|
|
19496
|
-
const candidate =
|
|
19496
|
+
const candidate = join29(dir, "package.json");
|
|
19497
19497
|
const version = checkCandidate(candidate);
|
|
19498
19498
|
if (version) {
|
|
19499
19499
|
return version;
|
|
@@ -25468,6 +25468,40 @@ var buildAbsoluteAndroidRelease = async (options) => {
|
|
|
25468
25468
|
};
|
|
25469
25469
|
// src/mobile/androidReleaseAcceptance.ts
|
|
25470
25470
|
import { createHash as createHash6 } from "crypto";
|
|
25471
|
+
|
|
25472
|
+
// src/mobile/androidServiceReadiness.ts
|
|
25473
|
+
var SERVICE_TIMEOUT_MS = 180000;
|
|
25474
|
+
var SERVICE_POLL_MS = 500;
|
|
25475
|
+
var waitForAbsoluteAndroidNetworkServices = async (options) => {
|
|
25476
|
+
const startedAt = performance.now();
|
|
25477
|
+
const waitForServices = async () => {
|
|
25478
|
+
const states = await Promise.all(["wifi", "phone"].map(async (service) => {
|
|
25479
|
+
const result = await options.run([
|
|
25480
|
+
options.adb,
|
|
25481
|
+
"-s",
|
|
25482
|
+
options.serial,
|
|
25483
|
+
"shell",
|
|
25484
|
+
"service",
|
|
25485
|
+
"check",
|
|
25486
|
+
service
|
|
25487
|
+
]);
|
|
25488
|
+
return {
|
|
25489
|
+
ready: result.exitCode === 0 && result.stdout.trim() === `Service ${service}: found`,
|
|
25490
|
+
service
|
|
25491
|
+
};
|
|
25492
|
+
}));
|
|
25493
|
+
const missing = states.filter(({ ready }) => !ready).map(({ service }) => service);
|
|
25494
|
+
if (missing.length === 0)
|
|
25495
|
+
return;
|
|
25496
|
+
if (performance.now() - startedAt >= (options.timeoutMs ?? SERVICE_TIMEOUT_MS))
|
|
25497
|
+
throw new Error(`Android network services did not become ready: ${missing.join(", ")}. Finish booting or restart the emulator before installed offline acceptance; no network settings were changed.`);
|
|
25498
|
+
await Bun.sleep(options.pollMs ?? SERVICE_POLL_MS);
|
|
25499
|
+
await waitForServices();
|
|
25500
|
+
};
|
|
25501
|
+
await waitForServices();
|
|
25502
|
+
};
|
|
25503
|
+
|
|
25504
|
+
// src/mobile/androidReleaseAcceptance.ts
|
|
25471
25505
|
import {
|
|
25472
25506
|
access as access7,
|
|
25473
25507
|
mkdir as mkdir5,
|
|
@@ -25809,6 +25843,11 @@ var runAbsoluteAndroidReleaseAcceptance = async (options) => {
|
|
|
25809
25843
|
if (options.release.metadata.versionCode !== undefined && installed.versionCode !== options.release.metadata.versionCode)
|
|
25810
25844
|
throw new Error(`Installed Android versionCode ${installed.versionCode ?? "unknown"} does not match release ${options.release.metadata.versionCode}.`);
|
|
25811
25845
|
await requireSuccess2(run, adb(options.adb, options.serial, "logcat", "-c"), "Android release log isolation");
|
|
25846
|
+
await waitForAbsoluteAndroidNetworkServices({
|
|
25847
|
+
adb: options.adb,
|
|
25848
|
+
run,
|
|
25849
|
+
serial: options.serial
|
|
25850
|
+
});
|
|
25812
25851
|
const [wifi, mobile] = await Promise.all([
|
|
25813
25852
|
requireSuccess2(run, adb(options.adb, options.serial, "shell", "settings", "get", "global", "wifi_on"), "Android Wi-Fi state inspection"),
|
|
25814
25853
|
requireSuccess2(run, adb(options.adb, options.serial, "shell", "settings", "get", "global", "mobile_data"), "Android mobile-data state inspection")
|
|
@@ -29337,7 +29376,7 @@ var parseAbsoluteMobileBuildPageMetadata = (value) => {
|
|
|
29337
29376
|
};
|
|
29338
29377
|
// src/mobile/buildPipeline.ts
|
|
29339
29378
|
import { readFile as readFile18 } from "fs/promises";
|
|
29340
|
-
import { join as
|
|
29379
|
+
import { join as join22, resolve as resolve16 } from "path";
|
|
29341
29380
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
29342
29381
|
|
|
29343
29382
|
// src/mobile/buildRelease.ts
|
|
@@ -30115,7 +30154,7 @@ import {
|
|
|
30115
30154
|
writeFile as writeFile14
|
|
30116
30155
|
} from "fs/promises";
|
|
30117
30156
|
import { createHash as createHash15 } from "crypto";
|
|
30118
|
-
import { basename as basename6, dirname as dirname13, join as
|
|
30157
|
+
import { basename as basename6, dirname as dirname13, join as join21, relative as relative13, resolve as resolve15, sep as sep8 } from "path";
|
|
30119
30158
|
|
|
30120
30159
|
// src/mobile/updateRuntime.ts
|
|
30121
30160
|
init_deviceCapabilities();
|
|
@@ -30256,6 +30295,7 @@ var createAbsoluteMobileUpdateRuntimeDescriptor = (options) => ({
|
|
|
30256
30295
|
},
|
|
30257
30296
|
deviceCapabilities: options.deviceCapabilities,
|
|
30258
30297
|
engine: options.config.engine,
|
|
30298
|
+
...options.config.engine === "expo" ? { expoEmbeddedAssetsAbi: 1 } : {},
|
|
30259
30299
|
format: ABSOLUTE_MOBILE_UPDATE_RUNTIME_FORMAT,
|
|
30260
30300
|
shellAbi: ABSOLUTE_MOBILE_SHELL_ABI,
|
|
30261
30301
|
syncSchema: options.syncSchema ?? null,
|
|
@@ -31025,6 +31065,265 @@ var absoluteExpoActivityResultRecoveryFiles = (project) => new Map([
|
|
|
31025
31065
|
]
|
|
31026
31066
|
]);
|
|
31027
31067
|
|
|
31068
|
+
// src/mobile/expoEmbeddedAssets.ts
|
|
31069
|
+
import { join as join20 } from "path";
|
|
31070
|
+
var header = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
|
|
31071
|
+
`;
|
|
31072
|
+
var android = `${header}package expo.modules.absoluteembeddedassets
|
|
31073
|
+
|
|
31074
|
+
import android.content.Context
|
|
31075
|
+
import android.graphics.Bitmap
|
|
31076
|
+
import android.net.Uri
|
|
31077
|
+
import android.util.Log
|
|
31078
|
+
import android.webkit.WebResourceRequest
|
|
31079
|
+
import android.webkit.WebResourceResponse
|
|
31080
|
+
import android.webkit.WebView
|
|
31081
|
+
import androidx.webkit.WebViewAssetLoader
|
|
31082
|
+
import androidx.webkit.WebViewCompat
|
|
31083
|
+
import androidx.webkit.WebViewFeature
|
|
31084
|
+
import androidx.webkit.ScriptHandler
|
|
31085
|
+
import androidx.webkit.WebMessageCompat
|
|
31086
|
+
import com.facebook.react.ReactPackage
|
|
31087
|
+
import com.facebook.react.bridge.NativeModule
|
|
31088
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
31089
|
+
import com.facebook.react.bridge.ReadableMap
|
|
31090
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
31091
|
+
import com.facebook.react.uimanager.ViewManager
|
|
31092
|
+
import com.reactnativecommunity.webview.RNCWebViewClient
|
|
31093
|
+
import com.reactnativecommunity.webview.RNCWebViewManager
|
|
31094
|
+
import com.reactnativecommunity.webview.RNCWebViewWrapper
|
|
31095
|
+
import expo.modules.kotlin.modules.Module
|
|
31096
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
31097
|
+
import java.io.ByteArrayInputStream
|
|
31098
|
+
import java.io.File
|
|
31099
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
31100
|
+
import java.util.WeakHashMap
|
|
31101
|
+
|
|
31102
|
+
private const val HOST = "appassets.androidplatform.net"
|
|
31103
|
+
private const val PREFIX = "/absolutejs/"
|
|
31104
|
+
|
|
31105
|
+
internal object AbsoluteEmbeddedAssets {
|
|
31106
|
+
private val bundles = ConcurrentHashMap<String, Map<String, File>>()
|
|
31107
|
+
|
|
31108
|
+
fun register(context: Context, rootUri: String, paths: List<String>): String {
|
|
31109
|
+
check(WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT) &&
|
|
31110
|
+
WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
|
|
31111
|
+
"Update Android System WebView to load this application."
|
|
31112
|
+
}
|
|
31113
|
+
val uri = Uri.parse(rootUri)
|
|
31114
|
+
require(uri.scheme == "file" && uri.authority.isNullOrEmpty() && uri.query == null && uri.fragment == null)
|
|
31115
|
+
val root = File(requireNotNull(uri.path)).canonicalFile
|
|
31116
|
+
val parent = File(context.filesDir, "absolutejs-web").canonicalFile
|
|
31117
|
+
require(root.parentFile == parent && root.name.matches(Regex("amexpo_[a-f0-9]{64}")))
|
|
31118
|
+
require(paths.isNotEmpty() && paths.size <= 100000 && paths.distinct().size == paths.size)
|
|
31119
|
+
val files = paths.associateWith { path ->
|
|
31120
|
+
require(path.isNotEmpty() && !path.contains('\\\\') && !path.contains('%') &&
|
|
31121
|
+
!path.contains('?') && !path.contains('#') && path.indexOf(0.toChar()) < 0 &&
|
|
31122
|
+
path.split('/').all { it.isNotEmpty() && it != "." && it != ".." })
|
|
31123
|
+
val file = File(root, path).canonicalFile
|
|
31124
|
+
require(file.path.startsWith(root.path + File.separator) && file.isFile)
|
|
31125
|
+
file
|
|
31126
|
+
}
|
|
31127
|
+
require(files.containsKey("index.html") && files.containsKey("absolute-mobile-manifest.json"))
|
|
31128
|
+
bundles[root.name] = files
|
|
31129
|
+
Log.i("AbsoluteJS", "Expo embedded web phase: asset-host-registered")
|
|
31130
|
+
return "https://" + HOST + PREFIX + root.name + "/index.html"
|
|
31131
|
+
}
|
|
31132
|
+
|
|
31133
|
+
private fun empty(status: Int, reason: String) = WebResourceResponse(
|
|
31134
|
+
"text/plain", "UTF-8", status, reason,
|
|
31135
|
+
mapOf("Cache-Control" to "no-store", "X-Content-Type-Options" to "nosniff"),
|
|
31136
|
+
ByteArrayInputStream(ByteArray(0))
|
|
31137
|
+
)
|
|
31138
|
+
|
|
31139
|
+
private fun resource(path: String): WebResourceResponse {
|
|
31140
|
+
val bundle = path.substringBefore('/')
|
|
31141
|
+
val name = path.substringAfter('/', "")
|
|
31142
|
+
val file = bundles[bundle]?.get(name) ?: return empty(404, "Not Found")
|
|
31143
|
+
// Recheck canonical location at read time. Never follow a replaced symlink.
|
|
31144
|
+
if (file.canonicalFile != file || !file.isFile) return empty(404, "Not Found")
|
|
31145
|
+
val mime = when (file.extension.lowercase()) {
|
|
31146
|
+
"html", "htm" -> "text/html"
|
|
31147
|
+
"js", "mjs" -> "text/javascript"
|
|
31148
|
+
"json", "map" -> "application/json"
|
|
31149
|
+
"css" -> "text/css"
|
|
31150
|
+
"svg" -> "image/svg+xml"
|
|
31151
|
+
"wasm" -> "application/wasm"
|
|
31152
|
+
else -> android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(file.extension.lowercase()) ?: "application/octet-stream"
|
|
31153
|
+
}
|
|
31154
|
+
return try {
|
|
31155
|
+
WebResourceResponse(mime, "UTF-8", 200, "OK",
|
|
31156
|
+
mapOf("Cache-Control" to "no-store", "X-Content-Type-Options" to "nosniff"), file.inputStream())
|
|
31157
|
+
} catch (_: Exception) { empty(404, "Not Found") }
|
|
31158
|
+
}
|
|
31159
|
+
|
|
31160
|
+
private val loader = WebViewAssetLoader.Builder()
|
|
31161
|
+
.setDomain(HOST).setHttpAllowed(false)
|
|
31162
|
+
.addPathHandler(PREFIX) { path -> resource(path) }.build()
|
|
31163
|
+
|
|
31164
|
+
fun intercept(request: WebResourceRequest, activeBundle: String?): WebResourceResponse? {
|
|
31165
|
+
val uri = request.url
|
|
31166
|
+
if (uri.host != HOST) return null
|
|
31167
|
+
if (uri.path.orEmpty().endsWith("/index.html")) Log.i("AbsoluteJS", "Expo embedded web phase: document-request")
|
|
31168
|
+
if (uri.path.orEmpty().endsWith("/absolute-mobile-bootstrap.js")) Log.i("AbsoluteJS", "Expo embedded web phase: bootstrap-request")
|
|
31169
|
+
// A reserved asset host must never fall through to DNS/network, even for
|
|
31170
|
+
// unknown bundles, wrong ports/schemes, methods, or malformed paths.
|
|
31171
|
+
if (uri.scheme != "https" || uri.port != -1 || uri.userInfo != null ||
|
|
31172
|
+
request.method != "GET") return empty(403, "Forbidden")
|
|
31173
|
+
// Root-relative image/font/CSS URLs retain their web meaning. Scope them
|
|
31174
|
+
// to this WebView's bundle, not the last bundle registered by another view.
|
|
31175
|
+
if (!uri.path.orEmpty().startsWith(PREFIX)) {
|
|
31176
|
+
if (request.isForMainFrame || activeBundle == null) return empty(404, "Not Found")
|
|
31177
|
+
return resource(activeBundle + "/" + uri.path.orEmpty().removePrefix("/"))
|
|
31178
|
+
}
|
|
31179
|
+
return loader.shouldInterceptRequest(uri) ?: empty(404, "Not Found")
|
|
31180
|
+
}
|
|
31181
|
+
}
|
|
31182
|
+
|
|
31183
|
+
class AbsoluteEmbeddedAssetsModule : Module() {
|
|
31184
|
+
override fun definition() = ModuleDefinition {
|
|
31185
|
+
Name("AbsoluteEmbeddedAssets")
|
|
31186
|
+
AsyncFunction("registerBundle") { root: String, paths: List<String> ->
|
|
31187
|
+
AbsoluteEmbeddedAssets.register(requireNotNull(appContext.reactContext), root, paths)
|
|
31188
|
+
}
|
|
31189
|
+
}
|
|
31190
|
+
}
|
|
31191
|
+
|
|
31192
|
+
class AbsoluteEmbeddedWebViewManager : RNCWebViewManager() {
|
|
31193
|
+
private val scripts = WeakHashMap<RNCWebViewWrapper, ScriptHandler>()
|
|
31194
|
+
override fun getName() = "AbsoluteEmbeddedWebView"
|
|
31195
|
+
override fun setNewSource(view: RNCWebViewWrapper, value: ReadableMap?) {
|
|
31196
|
+
Log.i("AbsoluteJS", "Expo embedded web phase: source-assigned")
|
|
31197
|
+
super.setNewSource(view, value)
|
|
31198
|
+
}
|
|
31199
|
+
override fun setMessagingEnabled(view: RNCWebViewWrapper, value: Boolean) {
|
|
31200
|
+
super.setMessagingEnabled(view, value)
|
|
31201
|
+
// Upstream reports sourceOrigin as event.url and accepts subframe messages.
|
|
31202
|
+
// Retain its event dispatch, but bind this bridge to our main-frame origin
|
|
31203
|
+
// and attach the native-observed document URL, never a JS-supplied URL.
|
|
31204
|
+
if (!WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) return
|
|
31205
|
+
WebViewCompat.removeWebMessageListener(view.webView, "ReactNativeWebView")
|
|
31206
|
+
if (!value) return
|
|
31207
|
+
WebViewCompat.addWebMessageListener(view.webView, "ReactNativeWebView", setOf("https://" + HOST)) {
|
|
31208
|
+
webView, message, sourceOrigin, isMainFrame, _ ->
|
|
31209
|
+
if (isMainFrame && sourceOrigin.scheme == "https" && sourceOrigin.host == HOST &&
|
|
31210
|
+
message.type == WebMessageCompat.TYPE_STRING) {
|
|
31211
|
+
val url = webView.url
|
|
31212
|
+
val data = message.data
|
|
31213
|
+
if (url != null && data != null) view.webView.onMessage(data, url)
|
|
31214
|
+
}
|
|
31215
|
+
}
|
|
31216
|
+
}
|
|
31217
|
+
override fun setInjectedJavaScriptBeforeContentLoaded(view: RNCWebViewWrapper, value: String?) {
|
|
31218
|
+
scripts.remove(view)?.remove()
|
|
31219
|
+
if (value == null) return
|
|
31220
|
+
// onPageStarted injection races module execution on Android. Register with
|
|
31221
|
+
// Chromium before navigation, scoped to our virtual asset origin only.
|
|
31222
|
+
check(WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
|
31223
|
+
"AbsoluteJS requires an Android System WebView with document-start script support."
|
|
31224
|
+
}
|
|
31225
|
+
scripts[view] = WebViewCompat.addDocumentStartJavaScript(view.webView, value, setOf("https://" + HOST))
|
|
31226
|
+
}
|
|
31227
|
+
override fun onDropViewInstance(view: RNCWebViewWrapper) {
|
|
31228
|
+
scripts.remove(view)?.remove()
|
|
31229
|
+
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER))
|
|
31230
|
+
WebViewCompat.removeWebMessageListener(view.webView, "ReactNativeWebView")
|
|
31231
|
+
super.onDropViewInstance(view)
|
|
31232
|
+
}
|
|
31233
|
+
override fun addEventEmitters(context: ThemedReactContext, view: RNCWebViewWrapper) {
|
|
31234
|
+
Log.i("AbsoluteJS", "Expo embedded web phase: asset-host-view-created")
|
|
31235
|
+
view.webView.webViewClient = object : RNCWebViewClient() {
|
|
31236
|
+
@Volatile private var activeBundle: String? = null
|
|
31237
|
+
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
|
|
31238
|
+
Log.i("AbsoluteJS", "Expo embedded web phase: document-started")
|
|
31239
|
+
val uri = Uri.parse(url)
|
|
31240
|
+
activeBundle = if (uri.scheme == "https" && uri.host == HOST && uri.path.orEmpty().startsWith(PREFIX))
|
|
31241
|
+
uri.path!!.removePrefix(PREFIX).substringBefore('/') else null
|
|
31242
|
+
super.onPageStarted(view, url, favicon)
|
|
31243
|
+
}
|
|
31244
|
+
override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? =
|
|
31245
|
+
AbsoluteEmbeddedAssets.intercept(request, activeBundle) ?: super.shouldInterceptRequest(view, request)
|
|
31246
|
+
}
|
|
31247
|
+
}
|
|
31248
|
+
}
|
|
31249
|
+
|
|
31250
|
+
class AbsoluteEmbeddedWebViewPackage : ReactPackage {
|
|
31251
|
+
override fun createNativeModules(context: ReactApplicationContext): List<NativeModule> = emptyList()
|
|
31252
|
+
override fun createViewManagers(context: ReactApplicationContext): List<ViewManager<*, *>> = listOf(AbsoluteEmbeddedWebViewManager())
|
|
31253
|
+
}
|
|
31254
|
+
`;
|
|
31255
|
+
var plugin = `${header}const { withMainApplication } = require('expo/config-plugins');
|
|
31256
|
+
module.exports = config => withMainApplication(config, value => {
|
|
31257
|
+
if (value.modResults.language !== 'kt') throw new Error('AbsoluteJS embedded assets require the managed Kotlin application.');
|
|
31258
|
+
const name = 'expo.modules.absoluteembeddedassets.AbsoluteEmbeddedWebViewPackage';
|
|
31259
|
+
const registration = 'add(' + name + '())';
|
|
31260
|
+
const source = value.modResults.contents;
|
|
31261
|
+
if (!source.includes(registration)) {
|
|
31262
|
+
const anchor = 'PackageList(this).packages.apply {';
|
|
31263
|
+
if (source.split(anchor).length !== 2) throw new Error('Cannot safely register AbsoluteJS embedded WebView in MainApplication.');
|
|
31264
|
+
value.modResults.contents = source.replace(anchor, anchor + '\\n ' + registration);
|
|
31265
|
+
}
|
|
31266
|
+
return value;
|
|
31267
|
+
});
|
|
31268
|
+
`;
|
|
31269
|
+
var runtime2 = `${header}import { requireNativeModule } from 'expo-modules-core';
|
|
31270
|
+
import { Platform, requireNativeComponent } from 'react-native';
|
|
31271
|
+
|
|
31272
|
+
export const absoluteEmbeddedNativeConfig = Platform.OS === 'android'
|
|
31273
|
+
? { component: requireNativeComponent('AbsoluteEmbeddedWebView') }
|
|
31274
|
+
: undefined;
|
|
31275
|
+
|
|
31276
|
+
export const registerAbsoluteEmbeddedBundle = async (rootUri: string, paths: string[], indexUri: string): Promise<string> => {
|
|
31277
|
+
if (Platform.OS !== 'android') return indexUri;
|
|
31278
|
+
const native = requireNativeModule<{ registerBundle(root: string, paths: string[]): Promise<string> }>('AbsoluteEmbeddedAssets');
|
|
31279
|
+
return native.registerBundle(rootUri, paths);
|
|
31280
|
+
};
|
|
31281
|
+
`;
|
|
31282
|
+
var absoluteExpoEmbeddedAssetsFiles = (project) => {
|
|
31283
|
+
const root = join20(project, "modules/absolute-embedded-assets");
|
|
31284
|
+
return new Map([
|
|
31285
|
+
[
|
|
31286
|
+
join20(root, "expo-module.config.json"),
|
|
31287
|
+
`${JSON.stringify({
|
|
31288
|
+
android: {
|
|
31289
|
+
modules: [
|
|
31290
|
+
"expo.modules.absoluteembeddedassets.AbsoluteEmbeddedAssetsModule"
|
|
31291
|
+
]
|
|
31292
|
+
},
|
|
31293
|
+
platforms: ["android"]
|
|
31294
|
+
}, null, 2)}
|
|
31295
|
+
`
|
|
31296
|
+
],
|
|
31297
|
+
[
|
|
31298
|
+
join20(root, "android/build.gradle"),
|
|
31299
|
+
`${header}plugins { id 'com.android.library'; id 'expo-module-gradle-plugin' }
|
|
31300
|
+
group = 'expo.modules.absoluteembeddedassets'
|
|
31301
|
+
version = '0.0.1'
|
|
31302
|
+
android {
|
|
31303
|
+
namespace 'expo.modules.absoluteembeddedassets'
|
|
31304
|
+
defaultConfig { versionCode 1; versionName '0.0.1' }
|
|
31305
|
+
}
|
|
31306
|
+
dependencies {
|
|
31307
|
+
implementation 'com.facebook.react:react-android'
|
|
31308
|
+
implementation project(':react-native-webview')
|
|
31309
|
+
implementation 'androidx.webkit:webkit:1.14.0'
|
|
31310
|
+
}
|
|
31311
|
+
`
|
|
31312
|
+
],
|
|
31313
|
+
[
|
|
31314
|
+
join20(root, "android/src/main/AndroidManifest.xml"),
|
|
31315
|
+
`<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
|
31316
|
+
`
|
|
31317
|
+
],
|
|
31318
|
+
[
|
|
31319
|
+
join20(root, "android/src/main/java/expo/modules/absoluteembeddedassets/AbsoluteEmbeddedAssetsModule.kt"),
|
|
31320
|
+
android
|
|
31321
|
+
],
|
|
31322
|
+
[join20(project, "plugins/withAbsoluteEmbeddedAssets.js"), plugin],
|
|
31323
|
+
[join20(project, "src/generated/AbsoluteEmbeddedAssets.ts"), runtime2]
|
|
31324
|
+
]);
|
|
31325
|
+
};
|
|
31326
|
+
|
|
31028
31327
|
// src/mobile/expoProject.ts
|
|
31029
31328
|
var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
|
|
31030
31329
|
`;
|
|
@@ -31105,7 +31404,7 @@ var routeSegments = (route) => {
|
|
|
31105
31404
|
return segment;
|
|
31106
31405
|
});
|
|
31107
31406
|
};
|
|
31108
|
-
var routeFile = (project, route) =>
|
|
31407
|
+
var routeFile = (project, route) => join21(project, "app", ...routeSegments(route), "index.tsx");
|
|
31109
31408
|
var packageDependencies = (plan) => Object.fromEntries(plan.requiredPackages.map((spec) => {
|
|
31110
31409
|
const separator = spec.lastIndexOf("@");
|
|
31111
31410
|
return [spec.slice(0, separator), spec.slice(separator + 1)];
|
|
@@ -31194,24 +31493,24 @@ var expoAppConfig = (config, auth, sync, devices, runtimeFingerprint) => {
|
|
|
31194
31493
|
const devicePlugins = [
|
|
31195
31494
|
...new Set(devices.capabilities.flatMap((name) => devices.providers[name]?.plugins ?? []))
|
|
31196
31495
|
];
|
|
31197
|
-
const configuredPlugins = devicePlugins.map((
|
|
31198
|
-
if (
|
|
31496
|
+
const configuredPlugins = devicePlugins.map((plugin2) => {
|
|
31497
|
+
if (plugin2 === "expo-image-picker")
|
|
31199
31498
|
return [
|
|
31200
|
-
|
|
31499
|
+
plugin2,
|
|
31201
31500
|
{
|
|
31202
31501
|
cameraPermission: descriptions.NSCameraUsageDescription,
|
|
31203
31502
|
microphonePermission: false,
|
|
31204
31503
|
photosPermission: descriptions.NSPhotoLibraryUsageDescription
|
|
31205
31504
|
}
|
|
31206
31505
|
];
|
|
31207
|
-
if (
|
|
31506
|
+
if (plugin2 === "expo-location")
|
|
31208
31507
|
return [
|
|
31209
|
-
|
|
31508
|
+
plugin2,
|
|
31210
31509
|
{
|
|
31211
31510
|
locationWhenInUsePermission: descriptions.NSLocationWhenInUseUsageDescription
|
|
31212
31511
|
}
|
|
31213
31512
|
];
|
|
31214
|
-
return
|
|
31513
|
+
return plugin2;
|
|
31215
31514
|
});
|
|
31216
31515
|
return {
|
|
31217
31516
|
expo: {
|
|
@@ -31233,7 +31532,7 @@ var expoAppConfig = (config, auth, sync, devices, runtimeFingerprint) => {
|
|
|
31233
31532
|
package: config.appId,
|
|
31234
31533
|
permissions: requirements.androidPermissions
|
|
31235
31534
|
},
|
|
31236
|
-
experiments: { typedRoutes: true },
|
|
31535
|
+
experiments: { tsconfigPaths: false, typedRoutes: true },
|
|
31237
31536
|
ios: {
|
|
31238
31537
|
...branding?.ios ?? {},
|
|
31239
31538
|
associatedDomains: config.deepLinkHosts.map((host2) => `applinks:${host2}`),
|
|
@@ -31256,6 +31555,7 @@ var expoAppConfig = (config, auth, sync, devices, runtimeFingerprint) => {
|
|
|
31256
31555
|
["expo-dev-client", { launchMode: "most-recent" }],
|
|
31257
31556
|
...branding ? [branding.splashPlugin] : [],
|
|
31258
31557
|
"./plugins/withAbsoluteActivityResultRecovery",
|
|
31558
|
+
"./plugins/withAbsoluteEmbeddedAssets",
|
|
31259
31559
|
...auth || config.updates ? ["expo-secure-store"] : [],
|
|
31260
31560
|
...sync ? [
|
|
31261
31561
|
"expo-sqlite",
|
|
@@ -31820,6 +32120,7 @@ import { ActivityIndicator, BackHandler, Platform, Pressable, StyleSheet, Text,
|
|
|
31820
32120
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
31821
32121
|
import { WebView, type WebViewMessageEvent } from 'react-native-webview';
|
|
31822
32122
|
import { materializeAbsoluteWebBundle } from './webAssets';
|
|
32123
|
+
import { absoluteEmbeddedNativeConfig } from './AbsoluteEmbeddedAssets';
|
|
31823
32124
|
import { markAbsoluteEmbeddedWebPhase, markAbsoluteEmbeddedWebReady } from './AbsoluteActivityResultRecovery';
|
|
31824
32125
|
import { createExpoDevicesBridgeHost } from '@absolutejs/devices-expo/bridge';
|
|
31825
32126
|
import { absoluteExpoDevices, beforeAbsoluteExpoDeviceSignOut } from './AbsoluteDevices';
|
|
@@ -31939,7 +32240,16 @@ const bridgeBootstrap = (path: string, safeAreaInsets: { bottom: number; left: n
|
|
|
31939
32240
|
event.preventDefault();
|
|
31940
32241
|
send({ format: 3, kind: 'event', event: 'navigation', path: url.pathname + url.search + url.hash });
|
|
31941
32242
|
}, true);
|
|
31942
|
-
|
|
32243
|
+
let shellRendered = false;
|
|
32244
|
+
addEventListener('absolute:shell-rendered', () => {
|
|
32245
|
+
shellRendered = true;
|
|
32246
|
+
send({ format: 3, kind: 'event', event: 'shell-rendered', path: currentPath });
|
|
32247
|
+
});
|
|
32248
|
+
const startupFailed = () => {
|
|
32249
|
+
if (!shellRendered) send({ format: 3, kind: 'event', event: 'startup-failed', path: currentPath });
|
|
32250
|
+
};
|
|
32251
|
+
addEventListener('error', startupFailed);
|
|
32252
|
+
addEventListener('unhandledrejection', startupFailed);
|
|
31943
32253
|
})(); true;\`;
|
|
31944
32254
|
};
|
|
31945
32255
|
|
|
@@ -31984,11 +32294,18 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
|
|
|
31984
32294
|
const canGoBack = useRef(false);
|
|
31985
32295
|
const [runtimeReady, setRuntimeReady] = useState(!AUTH_ENABLED && !SYNC_ENABLED);
|
|
31986
32296
|
const [devicesReady, setDevicesReady] = useState(false);
|
|
31987
|
-
const [startupError, setStartupError] = useState<'assets' | 'devices'>();
|
|
32297
|
+
const [startupError, setStartupError] = useState<'assets' | 'devices' | 'content'>();
|
|
31988
32298
|
const [startupRevision, setStartupRevision] = useState(0);
|
|
31989
32299
|
const activeWebPath = useRef(pathname);
|
|
31990
32300
|
const embeddedReadyReported = useRef(false);
|
|
31991
32301
|
const webSource = useMemo(() => indexUri ? { uri: indexUri } : undefined, [indexUri]);
|
|
32302
|
+
useEffect(() => {
|
|
32303
|
+
if (!indexUri || DEV_ORIGIN) return;
|
|
32304
|
+
const timeout = setTimeout(() => {
|
|
32305
|
+
if (!embeddedReadyReported.current) setStartupError('content');
|
|
32306
|
+
}, 60000);
|
|
32307
|
+
return () => clearTimeout(timeout);
|
|
32308
|
+
}, [indexUri]);
|
|
31992
32309
|
|
|
31993
32310
|
useEffect(() => {
|
|
31994
32311
|
if (!AUTH_ENABLED && !SYNC_ENABLED) return;
|
|
@@ -32024,6 +32341,7 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
|
|
|
32024
32341
|
markAbsoluteEmbeddedWebPhase('assets-start');
|
|
32025
32342
|
void materializeAbsoluteWebBundle().then(uri => {
|
|
32026
32343
|
markAbsoluteEmbeddedWebPhase('assets-ready');
|
|
32344
|
+
embeddedReadyReported.current = false;
|
|
32027
32345
|
setIndexUri(uri + '?absolutePath=' + encodeURIComponent(pathname));
|
|
32028
32346
|
}).catch(error => {
|
|
32029
32347
|
const phase = error instanceof Error && (error.message === 'assets-root-failed' || error.message === 'assets-directory-failed' || error.message === 'assets-destination-failed' || error.message === 'assets-module-failed' || error.message === 'assets-source-failed' || error.message === 'assets-download-failed' || error.message === 'assets-copy-failed' || error.message === 'assets-read-failed' || error.message === 'assets-write-failed' || error.message === 'assets-finalize-failed')
|
|
@@ -32077,15 +32395,23 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
|
|
|
32077
32395
|
try { return new URL(source).origin === origin; } catch { return false; }
|
|
32078
32396
|
};
|
|
32079
32397
|
const onMessage = async (event: WebViewMessageEvent) => {
|
|
32398
|
+
// Bridge authority belongs only to the currently loaded embedded bundle
|
|
32399
|
+
// (or the explicitly configured development origin), never remote pages.
|
|
32400
|
+
const sourceUrl = event.nativeEvent.url;
|
|
32401
|
+
if (!indexUri || typeof sourceUrl !== 'string' || (DEV_ORIGIN ? !hasOrigin(sourceUrl, DEV_ORIGIN) : !sourceUrl.startsWith(indexUri.slice(0, indexUri.lastIndexOf('/') + 1)))) return;
|
|
32080
32402
|
const source = event.nativeEvent.data;
|
|
32081
32403
|
if (new TextEncoder().encode(source).byteLength > MAX_MESSAGE_BYTES) return;
|
|
32082
32404
|
let message: Record<string, unknown>;
|
|
32083
32405
|
try { message = JSON.parse(source); } catch { return; }
|
|
32084
32406
|
if (message.format !== BRIDGE_FORMAT || typeof message.path !== 'string' || !message.path.startsWith('/') || message.path.startsWith('//')) return;
|
|
32085
|
-
if (message.kind === 'event' &&
|
|
32407
|
+
if (message.kind === 'event' && message.event === 'startup-failed') {
|
|
32408
|
+
if (!embeddedReadyReported.current) setStartupError('content');
|
|
32409
|
+
return;
|
|
32410
|
+
}
|
|
32411
|
+
if (message.kind === 'event' && (message.event === 'navigation' || message.event === 'shell-rendered')) {
|
|
32086
32412
|
const target = new URL(message.path, PRODUCTION_ORIGIN);
|
|
32087
32413
|
if (target.origin !== PRODUCTION_ORIGIN) return;
|
|
32088
|
-
if (message.event === '
|
|
32414
|
+
if (message.event === 'shell-rendered' && !DEV_ORIGIN && !embeddedReadyReported.current) {
|
|
32089
32415
|
embeddedReadyReported.current = true;
|
|
32090
32416
|
markAbsoluteEmbeddedWebReady();
|
|
32091
32417
|
}
|
|
@@ -32139,12 +32465,17 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
|
|
|
32139
32465
|
</View>;
|
|
32140
32466
|
if (!webSource || !runtimeReady || !devicesReady) return <View style={styles.loading}><ActivityIndicator /></View>;
|
|
32141
32467
|
return <WebView
|
|
32142
|
-
|
|
32143
|
-
|
|
32468
|
+
nativeConfig={!DEV_ORIGIN ? absoluteEmbeddedNativeConfig : undefined}
|
|
32469
|
+
allowFileAccess={Platform.OS !== 'android'}
|
|
32470
|
+
allowFileAccessFromFileURLs={Platform.OS !== 'android'}
|
|
32144
32471
|
allowUniversalAccessFromFileURLs={false}
|
|
32472
|
+
originWhitelist={DEV_ORIGIN ? [DEV_ORIGIN] : [Platform.OS === 'android' ? 'https://appassets.androidplatform.net' : 'file://*']}
|
|
32145
32473
|
allowingReadAccessToURL={webSource.uri.slice(0, webSource.uri.lastIndexOf('/') + 1)}
|
|
32146
32474
|
injectedJavaScriptBeforeContentLoaded={bridgeBootstrap(pathname, safeAreaInsets)}
|
|
32147
32475
|
onMessage={onMessage}
|
|
32476
|
+
onError={() => setStartupError('content')}
|
|
32477
|
+
onRenderProcessGone={() => setStartupError('content')}
|
|
32478
|
+
onContentProcessDidTerminate={() => setStartupError('content')}
|
|
32148
32479
|
onNavigationStateChange={state => {
|
|
32149
32480
|
canGoBack.current = state.canGoBack;
|
|
32150
32481
|
if (!DEV_ORIGIN || !hasOrigin(state.url, DEV_ORIGIN)) return;
|
|
@@ -32152,8 +32483,8 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
|
|
|
32152
32483
|
activeWebPath.current = route.pathname + route.search + route.hash;
|
|
32153
32484
|
}}
|
|
32154
32485
|
onShouldStartLoadWithRequest={request => {
|
|
32155
|
-
if (
|
|
32156
|
-
void Linking.openURL(request.url);
|
|
32486
|
+
if (DEV_ORIGIN ? hasOrigin(request.url, DEV_ORIGIN) : request.url.startsWith(webSource.uri.slice(0, webSource.uri.lastIndexOf('/') + 1))) return true;
|
|
32487
|
+
if (/^https?:/.test(request.url)) void Linking.openURL(request.url);
|
|
32157
32488
|
return false;
|
|
32158
32489
|
}}
|
|
32159
32490
|
ref={webView}
|
|
@@ -32356,8 +32687,8 @@ const styles = StyleSheet.create({
|
|
|
32356
32687
|
error: { color: '#b91c1c', fontSize: 16, textAlign: 'center' }
|
|
32357
32688
|
});
|
|
32358
32689
|
`;
|
|
32359
|
-
var nativeWrapperSource = (wrapper, module,
|
|
32360
|
-
import { createAbsoluteNativeRoute, createAbsoluteNativeRouteErrorBoundary } from ${JSON.stringify(portableRelative3(dirname13(wrapper),
|
|
32690
|
+
var nativeWrapperSource = (wrapper, module, runtime3, route) => `${EXPO_GENERATED_HEADER}import ApplicationNativeRoute from ${JSON.stringify(portableRelative3(dirname13(wrapper), module).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
|
|
32691
|
+
import { createAbsoluteNativeRoute, createAbsoluteNativeRouteErrorBoundary } from ${JSON.stringify(portableRelative3(dirname13(wrapper), runtime3).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
|
|
32361
32692
|
|
|
32362
32693
|
export const ErrorBoundary = createAbsoluteNativeRouteErrorBoundary(${JSON.stringify(route)});
|
|
32363
32694
|
export default createAbsoluteNativeRoute(ApplicationNativeRoute, ${JSON.stringify(route)});
|
|
@@ -32426,7 +32757,7 @@ var pruneManagedFiles = async (paths) => {
|
|
|
32426
32757
|
return removed.filter(Boolean).length;
|
|
32427
32758
|
};
|
|
32428
32759
|
var pruneStaleManagedExpoRoutes = async (project, expected) => {
|
|
32429
|
-
const appDirectory =
|
|
32760
|
+
const appDirectory = join21(project, "app");
|
|
32430
32761
|
if (!await exists6(appDirectory))
|
|
32431
32762
|
return 0;
|
|
32432
32763
|
const files = await walkFiles(appDirectory);
|
|
@@ -32474,7 +32805,7 @@ var writeAbsoluteExpoProject = async (config, options) => {
|
|
|
32474
32805
|
if (missing) {
|
|
32475
32806
|
throw new TypeError(`Expo native route ${missing.route} references missing module ${missing.module}.`);
|
|
32476
32807
|
}
|
|
32477
|
-
const marker =
|
|
32808
|
+
const marker = join21(project, EXPO_PROJECT_MARKER);
|
|
32478
32809
|
if (await exists6(project) && !await exists6(marker)) {
|
|
32479
32810
|
const entries = await readdir5(project);
|
|
32480
32811
|
if (entries.length > 0 && !options.force) {
|
|
@@ -32487,7 +32818,7 @@ var writeAbsoluteExpoProject = async (config, options) => {
|
|
|
32487
32818
|
const authEnabled = Boolean(auth);
|
|
32488
32819
|
const files = new Map([
|
|
32489
32820
|
[
|
|
32490
|
-
|
|
32821
|
+
join21(project, ".gitignore"),
|
|
32491
32822
|
`.expo/
|
|
32492
32823
|
android/
|
|
32493
32824
|
ios/
|
|
@@ -32495,80 +32826,82 @@ node_modules/
|
|
|
32495
32826
|
`
|
|
32496
32827
|
],
|
|
32497
32828
|
[
|
|
32498
|
-
|
|
32829
|
+
join21(project, "app.json"),
|
|
32499
32830
|
jsonSource(expoAppConfig(config, authEnabled, syncEnabled, devices, runtimeFingerprint))
|
|
32500
32831
|
],
|
|
32501
|
-
[
|
|
32832
|
+
[join21(project, "app.config.js"), expoDynamicAppConfig],
|
|
32502
32833
|
[
|
|
32503
|
-
|
|
32834
|
+
join21(project, "package.json"),
|
|
32504
32835
|
jsonSource(expoPackage(authEnabled, config.branding !== undefined, syncEnabled, devices, config.updates !== undefined))
|
|
32505
32836
|
],
|
|
32506
|
-
[
|
|
32837
|
+
[join21(project, "metro.config.js"), metroConfig(projectRoot)],
|
|
32507
32838
|
[
|
|
32508
|
-
|
|
32839
|
+
join21(project, "plugins", "withAbsoluteDevelopmentCa.js"),
|
|
32509
32840
|
expoDevelopmentCaPlugin
|
|
32510
32841
|
],
|
|
32511
32842
|
[
|
|
32512
|
-
|
|
32843
|
+
join21(project, "plugins", "withAbsoluteActivityResultRecovery.js"),
|
|
32513
32844
|
expoActivityResultRecoveryPlugin
|
|
32514
32845
|
],
|
|
32515
32846
|
[
|
|
32516
|
-
|
|
32847
|
+
join21(project, "tsconfig.json"),
|
|
32517
32848
|
jsonSource(expoTsConfig(projectRoot, project, authEnabled, syncEnabled))
|
|
32518
32849
|
],
|
|
32519
32850
|
[
|
|
32520
|
-
|
|
32851
|
+
join21(project, "app", "_layout.tsx"),
|
|
32521
32852
|
layoutSource(authEnabled, syncEnabled, config.updates !== undefined, config.observability !== undefined)
|
|
32522
32853
|
],
|
|
32523
32854
|
[
|
|
32524
|
-
|
|
32855
|
+
join21(project, "app", "__absolute", "native", "index.tsx"),
|
|
32525
32856
|
nativeDiagnosticSource
|
|
32526
32857
|
],
|
|
32527
32858
|
[
|
|
32528
|
-
|
|
32859
|
+
join21(project, "src", "generated", "AbsoluteDevices.ts"),
|
|
32529
32860
|
devicesRuntimeSource(config, devices, authEnabled)
|
|
32530
32861
|
],
|
|
32531
32862
|
[
|
|
32532
|
-
|
|
32863
|
+
join21(project, "src", "generated", "AbsoluteNativeRoute.tsx"),
|
|
32533
32864
|
nativeRouteRuntimeSource(authEnabled)
|
|
32534
32865
|
],
|
|
32535
32866
|
[
|
|
32536
|
-
|
|
32867
|
+
join21(project, "src", "generated", "AbsoluteWebHost.tsx"),
|
|
32537
32868
|
webHostSource(config, auth, syncEnabled)
|
|
32538
32869
|
]
|
|
32539
32870
|
]);
|
|
32540
32871
|
for (const [path, source] of absoluteExpoActivityResultRecoveryFiles(project))
|
|
32541
32872
|
files.set(path, source);
|
|
32873
|
+
for (const [path, source] of absoluteExpoEmbeddedAssetsFiles(project))
|
|
32874
|
+
files.set(path, source);
|
|
32542
32875
|
if (config.observability) {
|
|
32543
32876
|
for (const [path, source] of absoluteExpoNativeObservabilityFiles(project))
|
|
32544
32877
|
files.set(path, source);
|
|
32545
32878
|
}
|
|
32546
32879
|
if (config.updates) {
|
|
32547
|
-
files.set(
|
|
32880
|
+
files.set(join21(project, "src", "generated", "AbsoluteUpdates.ts"), updatesRuntimeSource(config));
|
|
32548
32881
|
}
|
|
32549
32882
|
const expoCodeSigning = config.updates?.expoCodeSigning;
|
|
32550
32883
|
if (expoCodeSigning)
|
|
32551
|
-
files.set(
|
|
32884
|
+
files.set(join21(project, "certs", "absolute-mobile-update.pem"), expoCodeSigning.certificatePem);
|
|
32552
32885
|
if (auth) {
|
|
32553
|
-
files.set(
|
|
32886
|
+
files.set(join21(project, "src", "generated", "AbsoluteAuth.ts"), authRuntimeSource(auth, config.appId));
|
|
32554
32887
|
}
|
|
32555
32888
|
if (syncSchema) {
|
|
32556
|
-
files.set(
|
|
32889
|
+
files.set(join21(project, "src", "generated", "AbsoluteSync.ts"), syncRuntimeSource(config, syncSchema));
|
|
32557
32890
|
}
|
|
32558
|
-
const webAssetsPath =
|
|
32891
|
+
const webAssetsPath = join21(project, "src", "generated", "webAssets.ts");
|
|
32559
32892
|
if (!await exists6(webAssetsPath)) {
|
|
32560
32893
|
files.set(webAssetsPath, emptyWebAssetsSource);
|
|
32561
32894
|
}
|
|
32562
32895
|
if (!config.expoNativeRoutes["/"]) {
|
|
32563
|
-
files.set(
|
|
32896
|
+
files.set(join21(project, "app", "index.tsx"), webRouteSource);
|
|
32564
32897
|
}
|
|
32565
|
-
files.set(
|
|
32566
|
-
const nativeRouteRuntime =
|
|
32898
|
+
files.set(join21(project, "app", "[...absolute].tsx"), catchAllRouteSource);
|
|
32899
|
+
const nativeRouteRuntime = join21(project, "src", "generated", "AbsoluteNativeRoute.tsx");
|
|
32567
32900
|
for (const [route, module] of routeModules) {
|
|
32568
|
-
const wrapper = route === "/" ?
|
|
32901
|
+
const wrapper = route === "/" ? join21(project, "app", "index.tsx") : routeFile(project, route);
|
|
32569
32902
|
files.set(wrapper, nativeWrapperSource(wrapper, module, nativeRouteRuntime, route));
|
|
32570
32903
|
}
|
|
32571
|
-
const removedRoutes = await pruneStaleManagedExpoRoutes(project, new Set([...files.keys()].filter((path) => path.startsWith(`${
|
|
32904
|
+
const removedRoutes = await pruneStaleManagedExpoRoutes(project, new Set([...files.keys()].filter((path) => path.startsWith(`${join21(project, "app")}${sep8}`))));
|
|
32572
32905
|
const removedObservability = config.observability ? 0 : await pruneManagedFiles(absoluteExpoNativeObservabilityPaths(project));
|
|
32573
32906
|
const changes = await Promise.all([...files].map(([path, source]) => writeManagedFile(path, source, true)));
|
|
32574
32907
|
await writeAbsoluteExpoBrandingInputs(config, projectRoot);
|
|
@@ -32578,7 +32911,7 @@ node_modules/
|
|
|
32578
32911
|
var walkFiles = async (root, directory = root) => {
|
|
32579
32912
|
const entries = await readdir5(directory, { withFileTypes: true });
|
|
32580
32913
|
const nested = await Promise.all(entries.map((entry) => {
|
|
32581
|
-
const path =
|
|
32914
|
+
const path = join21(directory, entry.name);
|
|
32582
32915
|
if (entry.isDirectory())
|
|
32583
32916
|
return walkFiles(root, path);
|
|
32584
32917
|
if (entry.isFile())
|
|
@@ -32611,13 +32944,16 @@ var installStagedDirectory = async (staging, destination) => {
|
|
|
32611
32944
|
throw error;
|
|
32612
32945
|
}
|
|
32613
32946
|
};
|
|
32614
|
-
var assetModuleSource = (assets, archiveAsset, bundleId, manifest) => `${EXPO_GENERATED_HEADER}import { Asset } from 'expo-asset';
|
|
32947
|
+
var assetModuleSource = (assets, archiveAsset, bundleId, archiveMd5, manifest) => `${EXPO_GENERATED_HEADER}import { Asset } from 'expo-asset';
|
|
32615
32948
|
import { Directory, File, Paths } from 'expo-file-system';
|
|
32616
32949
|
import { copyAsync as copyLegacyAsync } from 'expo-file-system/legacy';
|
|
32950
|
+
import { registerAbsoluteEmbeddedBundle } from './AbsoluteEmbeddedAssets';
|
|
32617
32951
|
|
|
32618
32952
|
${nativeDataManifestTypeSource}
|
|
32619
32953
|
declare const require: (path: string) => number;
|
|
32620
32954
|
const BUNDLE_ID = ${JSON.stringify(bundleId)};
|
|
32955
|
+
const ARCHIVE_MD5 = ${JSON.stringify(archiveMd5)};
|
|
32956
|
+
const ARCHIVE_LENGTH = ${assets.reduce((sum, entry) => sum + entry.length, 0)};
|
|
32621
32957
|
export const ABSOLUTE_MOBILE_MANIFEST: AbsoluteMobileManifest = ${JSON.stringify(manifest)};
|
|
32622
32958
|
const ARCHIVE_MODULE = require(${JSON.stringify(archiveAsset)});
|
|
32623
32959
|
const ASSETS = [
|
|
@@ -32634,10 +32970,12 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
32634
32970
|
let archive: File;
|
|
32635
32971
|
try { archive = new File(root, '.absolutejs-bundle.absasset'); }
|
|
32636
32972
|
catch { throw new Error('assets-destination-failed'); }
|
|
32973
|
+
if (archive.exists && (archive.size !== ARCHIVE_LENGTH || archive.md5 !== ARCHIVE_MD5)) archive.delete();
|
|
32637
32974
|
if (!archive.exists) {
|
|
32638
32975
|
let asset: Asset;
|
|
32639
32976
|
try { asset = Asset.fromModule(ARCHIVE_MODULE); }
|
|
32640
32977
|
catch { throw new Error('assets-module-failed'); }
|
|
32978
|
+
if (asset.type !== 'absasset' || asset.hash !== ARCHIVE_MD5) throw new Error('assets-identity-failed');
|
|
32641
32979
|
try { if (!asset.localUri) asset = await asset.downloadAsync(); }
|
|
32642
32980
|
catch { throw new Error('assets-download-failed'); }
|
|
32643
32981
|
if (!asset.localUri) throw new Error('assets-download-failed');
|
|
@@ -32650,9 +32988,16 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
32650
32988
|
catch { throw new Error('assets-copy-failed'); }
|
|
32651
32989
|
}
|
|
32652
32990
|
}
|
|
32991
|
+
// Checksums detect accidental corruption/registry mismatches, not authenticity;
|
|
32992
|
+
// authenticity comes from the signed application/update containing this table.
|
|
32993
|
+
if (archive.size !== ARCHIVE_LENGTH || archive.md5 !== ARCHIVE_MD5) {
|
|
32994
|
+
archive.delete();
|
|
32995
|
+
throw new Error('assets-integrity-failed');
|
|
32996
|
+
}
|
|
32653
32997
|
let contents: Uint8Array;
|
|
32654
32998
|
try { contents = await archive.bytes(); }
|
|
32655
32999
|
catch { throw new Error('assets-read-failed'); }
|
|
33000
|
+
if (contents.byteLength !== ARCHIVE_LENGTH) throw new Error('assets-integrity-failed');
|
|
32656
33001
|
for (const entry of ASSETS) {
|
|
32657
33002
|
const parts = entry.path.split('/');
|
|
32658
33003
|
const name = parts.pop();
|
|
@@ -32666,27 +33011,28 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
32666
33011
|
let destination: File;
|
|
32667
33012
|
try {
|
|
32668
33013
|
destination = new File(directory, name);
|
|
32669
|
-
if (destination.exists && destination.size === entry.length) continue;
|
|
33014
|
+
if (destination.exists && destination.size === entry.length && destination.md5 === entry.md5) continue;
|
|
32670
33015
|
if (destination.exists) destination.delete();
|
|
32671
33016
|
} catch { throw new Error('assets-destination-failed'); }
|
|
32672
33017
|
try { destination.write(contents.slice(entry.offset, entry.offset + entry.length)); }
|
|
32673
33018
|
catch { throw new Error('assets-write-failed'); }
|
|
33019
|
+
if (destination.size !== entry.length || destination.md5 !== entry.md5) throw new Error('assets-integrity-failed');
|
|
32674
33020
|
}
|
|
32675
33021
|
try { archive.delete(); }
|
|
32676
33022
|
catch { throw new Error('assets-finalize-failed'); }
|
|
32677
33023
|
|
|
32678
|
-
try { return new File(root, 'index.html').uri; }
|
|
33024
|
+
try { return await registerAbsoluteEmbeddedBundle(root.uri, ASSETS.map(entry => entry.path), new File(root, 'index.html').uri); }
|
|
32679
33025
|
catch { throw new Error('assets-finalize-failed'); }
|
|
32680
33026
|
};
|
|
32681
33027
|
`;
|
|
32682
33028
|
var syncAbsoluteExpoWebAssets = async (config) => {
|
|
32683
33029
|
if (config.engine !== "expo")
|
|
32684
33030
|
throw new TypeError("Expo asset sync requires mobile.engine: expo.");
|
|
32685
|
-
const marker =
|
|
33031
|
+
const marker = join21(config.nativeProjectDirectory, EXPO_PROJECT_MARKER);
|
|
32686
33032
|
if (!await exists6(marker)) {
|
|
32687
33033
|
throw new TypeError("Expo asset sync requires an AbsoluteJS-managed Expo project. Run mobile init first.");
|
|
32688
33034
|
}
|
|
32689
|
-
const manifestPath =
|
|
33035
|
+
const manifestPath = join21(config.bundleDirectory, "absolute-mobile-manifest.json");
|
|
32690
33036
|
const manifest = JSON.parse(await readFile17(manifestPath, "utf8"));
|
|
32691
33037
|
const nativeDataManifest = expoNativeDataManifest(manifest);
|
|
32692
33038
|
const { appBuild } = nativeDataManifest;
|
|
@@ -32700,16 +33046,18 @@ var syncAbsoluteExpoWebAssets = async (config) => {
|
|
|
32700
33046
|
bundleHash.update("\x00");
|
|
32701
33047
|
});
|
|
32702
33048
|
const bundleId = `amexpo_${bundleHash.digest("hex")}`;
|
|
32703
|
-
const destination =
|
|
33049
|
+
const destination = join21(config.nativeProjectDirectory, "assets", "absolute");
|
|
32704
33050
|
await mkdir14(dirname13(destination), { recursive: true });
|
|
32705
|
-
const staging = await mkdtemp9(
|
|
33051
|
+
const staging = await mkdtemp9(join21(dirname13(destination), `.${basename6(destination)}.stage-`));
|
|
32706
33052
|
let assets;
|
|
32707
33053
|
let archiveAsset;
|
|
33054
|
+
let archiveMd5;
|
|
32708
33055
|
try {
|
|
32709
33056
|
let offset = 0;
|
|
32710
33057
|
assets = filesWithContents.map(({ contents, file }) => {
|
|
32711
33058
|
const entry = {
|
|
32712
33059
|
length: contents.byteLength,
|
|
33060
|
+
md5: createHash15("md5").update(contents).digest("hex"),
|
|
32713
33061
|
offset,
|
|
32714
33062
|
path: relative13(config.bundleDirectory, file).replaceAll("\\", "/")
|
|
32715
33063
|
};
|
|
@@ -32717,15 +33065,17 @@ var syncAbsoluteExpoWebAssets = async (config) => {
|
|
|
32717
33065
|
return entry;
|
|
32718
33066
|
});
|
|
32719
33067
|
const name = `bundle${EXPO_ASSET_EXTENSION}`;
|
|
32720
|
-
|
|
32721
|
-
|
|
33068
|
+
const archiveContents = Buffer.concat(filesWithContents.map(({ contents }) => contents));
|
|
33069
|
+
archiveMd5 = createHash15("md5").update(archiveContents).digest("hex");
|
|
33070
|
+
await writeFile14(join21(staging, name), archiveContents);
|
|
33071
|
+
archiveAsset = portableRelative3(join21(config.nativeProjectDirectory, "src", "generated"), join21(destination, name));
|
|
32722
33072
|
await installStagedDirectory(staging, destination);
|
|
32723
33073
|
} catch (error) {
|
|
32724
33074
|
await rm13(staging, { force: true, recursive: true });
|
|
32725
33075
|
throw error;
|
|
32726
33076
|
}
|
|
32727
|
-
const generated =
|
|
32728
|
-
await writeManagedFile(generated, assetModuleSource(assets, archiveAsset, bundleId, nativeDataManifest), true);
|
|
33077
|
+
const generated = join21(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
|
|
33078
|
+
await writeManagedFile(generated, assetModuleSource(assets, archiveAsset, bundleId, archiveMd5, nativeDataManifest), true);
|
|
32729
33079
|
return { appBuild, assets: assets.length, bundleId, path: destination };
|
|
32730
33080
|
};
|
|
32731
33081
|
|
|
@@ -32765,9 +33115,9 @@ var loadServerApp = async (producerPath) => {
|
|
|
32765
33115
|
var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
|
|
32766
33116
|
const buildDirectory = resolve16(options.buildDirectory);
|
|
32767
33117
|
const mobile = normalizeAbsoluteMobileConfig(options.mobile, options.projectRoot);
|
|
32768
|
-
const root =
|
|
33118
|
+
const root = join22(buildDirectory, ".absolutejs", "mobile-compatibility");
|
|
32769
33119
|
const [manifestSource, previous] = await Promise.all([
|
|
32770
|
-
readFile18(
|
|
33120
|
+
readFile18(join22(buildDirectory, "manifest.json"), "utf8"),
|
|
32771
33121
|
readAbsoluteMobileMaterializedReleases(root)
|
|
32772
33122
|
]);
|
|
32773
33123
|
const manifest = JSON.parse(manifestSource);
|
|
@@ -33095,7 +33445,7 @@ var parseRequest = (value) => {
|
|
|
33095
33445
|
throw new TypeError("Expo bridge HTTP method cannot contain a body.");
|
|
33096
33446
|
if (!isRecord10(value.params.headers))
|
|
33097
33447
|
throw new TypeError("Expo bridge HTTP headers must be an object.");
|
|
33098
|
-
const headersAllowed = Object.entries(value.params.headers).every(([name,
|
|
33448
|
+
const headersAllowed = Object.entries(value.params.headers).every(([name, header2]) => typeof header2 === "string" && (name.toLowerCase() === "accept" || name.toLowerCase() === "content-type" || name.toLowerCase().startsWith("x-absolute-mobile-")));
|
|
33099
33449
|
if (!headersAllowed) {
|
|
33100
33450
|
throw new TypeError("Expo bridge HTTP header is not allowed.");
|
|
33101
33451
|
}
|
|
@@ -33344,7 +33694,7 @@ var parseAbsoluteAndroidAccessibilityHierarchy = (source) => [...source.matchAll
|
|
|
33344
33694
|
// src/mobile/expoNativeWatcher.ts
|
|
33345
33695
|
import { watch as watch2 } from "fs";
|
|
33346
33696
|
import { access as access15, readdir as readdir6, readFile as readFile19 } from "fs/promises";
|
|
33347
|
-
import { basename as basename7, join as
|
|
33697
|
+
import { basename as basename7, join as join23, relative as relative15 } from "path";
|
|
33348
33698
|
import { createHash as createHash16 } from "crypto";
|
|
33349
33699
|
var NATIVE_CHANGE_DEBOUNCE_MS2 = 500;
|
|
33350
33700
|
var ROOT_NATIVE_INPUTS2 = new Set([
|
|
@@ -33365,7 +33715,7 @@ var filesIn = async (directory, prefix) => {
|
|
|
33365
33715
|
return [];
|
|
33366
33716
|
const entries = await readdir6(directory, { withFileTypes: true });
|
|
33367
33717
|
const nested = await Promise.all(entries.map((entry) => {
|
|
33368
|
-
const path =
|
|
33718
|
+
const path = join23(directory, entry.name);
|
|
33369
33719
|
const name = `${prefix}/${entry.name}`;
|
|
33370
33720
|
if (entry.isDirectory())
|
|
33371
33721
|
return filesIn(path, name);
|
|
@@ -33376,10 +33726,10 @@ var filesIn = async (directory, prefix) => {
|
|
|
33376
33726
|
var fingerprintAbsoluteExpoNativeInputs = async (options) => {
|
|
33377
33727
|
const hash = createHash16("sha256");
|
|
33378
33728
|
const rootFiles = await Promise.all([...ROOT_NATIVE_INPUTS2].sort().map(async (name) => {
|
|
33379
|
-
const path =
|
|
33729
|
+
const path = join23(options.projectRoot, name);
|
|
33380
33730
|
return await exists8(path) ? [{ name: `root/${name}`, path }] : [];
|
|
33381
33731
|
}));
|
|
33382
|
-
const nativeFiles = await Promise.all(EXPO_NATIVE_DIRECTORIES.map((name) => filesIn(
|
|
33732
|
+
const nativeFiles = await Promise.all(EXPO_NATIVE_DIRECTORIES.map((name) => filesIn(join23(options.expoProjectDirectory, name), name)));
|
|
33383
33733
|
const files = [...rootFiles.flat(), ...nativeFiles.flat()].sort((left, right) => left.name.localeCompare(right.name));
|
|
33384
33734
|
const contents = await Promise.all(files.map(({ path }) => readFile19(path)));
|
|
33385
33735
|
files.forEach(({ name }, index) => {
|
|
@@ -33450,14 +33800,14 @@ var createAbsoluteExpoNativeWatcher = async (options) => {
|
|
|
33450
33800
|
}
|
|
33451
33801
|
};
|
|
33452
33802
|
const nativeDirectories = (await Promise.all(EXPO_NATIVE_DIRECTORIES.map(async (name) => {
|
|
33453
|
-
const directory =
|
|
33803
|
+
const directory = join23(options.expoProjectDirectory, name);
|
|
33454
33804
|
return await exists8(directory) ? [directory] : [];
|
|
33455
33805
|
}))).flat();
|
|
33456
33806
|
nativeDirectories.forEach((directory) => {
|
|
33457
33807
|
watchers.push(watch2(directory, { recursive: true }, (_event, filename) => {
|
|
33458
33808
|
if (!filename)
|
|
33459
33809
|
return;
|
|
33460
|
-
record(relative15(options.expoProjectDirectory,
|
|
33810
|
+
record(relative15(options.expoProjectDirectory, join23(directory, String(filename))), false);
|
|
33461
33811
|
}));
|
|
33462
33812
|
});
|
|
33463
33813
|
watchers.push(watch2(options.projectRoot, (_event, filename) => {
|
|
@@ -33473,7 +33823,7 @@ var createAbsoluteExpoNativeWatcher = async (options) => {
|
|
|
33473
33823
|
};
|
|
33474
33824
|
// src/mobile/expoUpdate.ts
|
|
33475
33825
|
import { access as access16, mkdir as mkdir16, readFile as readFile20, writeFile as writeFile16 } from "fs/promises";
|
|
33476
|
-
import { dirname as dirname15, extname as extname4, join as
|
|
33826
|
+
import { dirname as dirname15, extname as extname4, join as join24 } from "path";
|
|
33477
33827
|
var ABSOLUTE_EXPO_UPDATE_DESCRIPTOR = "_absolute/expo-update.json";
|
|
33478
33828
|
var ABSOLUTE_EXPO_UPDATE_FORMAT = 1;
|
|
33479
33829
|
var object4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -33539,7 +33889,7 @@ var parseAbsoluteExpoUpdateDescriptor = (value) => {
|
|
|
33539
33889
|
};
|
|
33540
33890
|
};
|
|
33541
33891
|
var finalizeAbsoluteExpoUpdateExport = async (options) => {
|
|
33542
|
-
const metadata = JSON.parse(await readFile20(
|
|
33892
|
+
const metadata = JSON.parse(await readFile20(join24(options.exportDirectory, "metadata.json"), "utf8"));
|
|
33543
33893
|
if (!object4(metadata) || !object4(metadata.fileMetadata))
|
|
33544
33894
|
throw new TypeError("Expo export metadata.json is invalid.");
|
|
33545
33895
|
const descriptor = parseAbsoluteExpoUpdateDescriptor({
|
|
@@ -33550,10 +33900,10 @@ var finalizeAbsoluteExpoUpdateExport = async (options) => {
|
|
|
33550
33900
|
runtimeVersion: options.runtimeVersion
|
|
33551
33901
|
});
|
|
33552
33902
|
const referenced = Object.values(descriptor.platforms).flatMap((entry) => entry ? [entry.launchAsset, ...entry.assets] : []);
|
|
33553
|
-
await Promise.all(referenced.map(({ path }) => access16(
|
|
33903
|
+
await Promise.all(referenced.map(({ path }) => access16(join24(options.exportDirectory, path)).catch(() => {
|
|
33554
33904
|
throw new TypeError(`Expo export metadata references missing asset ${path}.`);
|
|
33555
33905
|
})));
|
|
33556
|
-
const destination =
|
|
33906
|
+
const destination = join24(options.exportDirectory, ABSOLUTE_EXPO_UPDATE_DESCRIPTOR);
|
|
33557
33907
|
await mkdir16(dirname15(destination), { recursive: true });
|
|
33558
33908
|
await writeFile16(destination, `${JSON.stringify(descriptor, null, "\t")}
|
|
33559
33909
|
`);
|
|
@@ -33575,7 +33925,7 @@ import {
|
|
|
33575
33925
|
stat as stat7,
|
|
33576
33926
|
writeFile as writeFile19
|
|
33577
33927
|
} from "fs/promises";
|
|
33578
|
-
import { dirname as dirname17, isAbsolute as isAbsolute11, join as
|
|
33928
|
+
import { dirname as dirname17, isAbsolute as isAbsolute11, join as join26, relative as relative18, resolve as resolve20, sep as sep12 } from "path";
|
|
33579
33929
|
|
|
33580
33930
|
// src/mobile/certificationVerification.ts
|
|
33581
33931
|
import { access as access17, mkdir as mkdir17, readFile as readFile21, stat as stat6, writeFile as writeFile17 } from "fs/promises";
|
|
@@ -33690,7 +34040,7 @@ import {
|
|
|
33690
34040
|
rm as rm14,
|
|
33691
34041
|
writeFile as writeFile18
|
|
33692
34042
|
} from "fs/promises";
|
|
33693
|
-
import { basename as basename8, isAbsolute as isAbsolute10, join as
|
|
34043
|
+
import { basename as basename8, isAbsolute as isAbsolute10, join as join25, relative as relative17, resolve as resolve19, sep as sep11 } from "path";
|
|
33694
34044
|
var ABSOLUTE_MOBILE_RELEASE_CERTIFICATION_FORMAT = 1;
|
|
33695
34045
|
var CERTIFICATION_PREFIX = "amobile_cert_";
|
|
33696
34046
|
var SHA256 = /^[a-f0-9]{64}$/u;
|
|
@@ -33734,7 +34084,7 @@ var resolveEvidencePath = async (projectRoot, requested) => {
|
|
|
33734
34084
|
throw new TypeError("Mobile certification evidence must remain inside the project.");
|
|
33735
34085
|
if (basename8(selected) === "report.json")
|
|
33736
34086
|
return selected;
|
|
33737
|
-
const report =
|
|
34087
|
+
const report = join25(selected, "report.json");
|
|
33738
34088
|
if (!await exists9(report))
|
|
33739
34089
|
throw new TypeError(`Mobile certification evidence does not contain report.json: ${requested}`);
|
|
33740
34090
|
return report;
|
|
@@ -33999,7 +34349,7 @@ var readAbsoluteMobileReleaseCertification = async (projectRoot, requested) => {
|
|
|
33999
34349
|
const selected = resolve19(projectRoot, requested);
|
|
34000
34350
|
if (!inside4(projectRoot, selected))
|
|
34001
34351
|
throw new TypeError("Mobile release certification must remain inside the project.");
|
|
34002
|
-
const path = basename8(selected) === "certification.json" ? selected :
|
|
34352
|
+
const path = basename8(selected) === "certification.json" ? selected : join25(selected, "certification.json");
|
|
34003
34353
|
const value = JSON.parse(await readFile22(path, "utf8"));
|
|
34004
34354
|
return { certification: parseCertification(value), path };
|
|
34005
34355
|
};
|
|
@@ -34046,15 +34396,15 @@ var verifyAbsoluteMobileReleaseCertification = (certification, release, requirem
|
|
|
34046
34396
|
};
|
|
34047
34397
|
var writeAbsoluteMobileReleaseCertification = async (projectRoot, certification, outputDirectory) => {
|
|
34048
34398
|
const root = resolve19(projectRoot);
|
|
34049
|
-
const parent = resolve19(root, outputDirectory ??
|
|
34399
|
+
const parent = resolve19(root, outputDirectory ?? join25(".absolutejs", "mobile", "certifications", certification.release.platform, certification.release.releaseId));
|
|
34050
34400
|
if (!inside4(root, parent))
|
|
34051
34401
|
throw new TypeError("Mobile certification output must remain inside the project.");
|
|
34052
34402
|
await mkdir18(parent, { recursive: true });
|
|
34053
|
-
const destination =
|
|
34403
|
+
const destination = join25(parent, certification.certificationId);
|
|
34054
34404
|
const paths = {
|
|
34055
34405
|
directory: destination,
|
|
34056
|
-
jsonPath:
|
|
34057
|
-
markdownPath:
|
|
34406
|
+
jsonPath: join25(destination, "certification.json"),
|
|
34407
|
+
markdownPath: join25(destination, "certification.md")
|
|
34058
34408
|
};
|
|
34059
34409
|
const json = serializeAbsoluteMobileReleaseCertification(certification);
|
|
34060
34410
|
const markdown = renderAbsoluteMobileReleaseCertification(certification);
|
|
@@ -34070,13 +34420,13 @@ var writeAbsoluteMobileReleaseCertification = async (projectRoot, certification,
|
|
|
34070
34420
|
await verifyExisting();
|
|
34071
34421
|
return paths;
|
|
34072
34422
|
}
|
|
34073
|
-
const staging = await mkdtemp10(
|
|
34423
|
+
const staging = await mkdtemp10(join25(parent, ".certification-"));
|
|
34074
34424
|
try {
|
|
34075
34425
|
await Promise.all([
|
|
34076
|
-
writeFile18(
|
|
34426
|
+
writeFile18(join25(staging, "certification.json"), json, {
|
|
34077
34427
|
flag: "wx"
|
|
34078
34428
|
}),
|
|
34079
|
-
writeFile18(
|
|
34429
|
+
writeFile18(join25(staging, "certification.md"), markdown, {
|
|
34080
34430
|
flag: "wx"
|
|
34081
34431
|
})
|
|
34082
34432
|
]);
|
|
@@ -34308,7 +34658,7 @@ var findFiles = async (root, name) => {
|
|
|
34308
34658
|
visited += 1;
|
|
34309
34659
|
if (visited > MAX_SEARCH_FILES)
|
|
34310
34660
|
throw new TypeError("Downloaded GitHub artifact contains too many files.");
|
|
34311
|
-
const path =
|
|
34661
|
+
const path = join26(directory, entry.name);
|
|
34312
34662
|
if (entry.isDirectory()) {
|
|
34313
34663
|
await walk(path);
|
|
34314
34664
|
return;
|
|
@@ -34423,9 +34773,9 @@ var auditAbsoluteMobileCiPromotion = async (options) => {
|
|
|
34423
34773
|
if (await access19(output).then(() => true).catch(() => false))
|
|
34424
34774
|
throw new TypeError(`Mobile CI audit output already exists: ${output}`);
|
|
34425
34775
|
await mkdir19(dirname17(output), { recursive: true });
|
|
34426
|
-
const staging = await mkdtemp11(
|
|
34776
|
+
const staging = await mkdtemp11(join26(dirname17(output), ".promotion-audit-"));
|
|
34427
34777
|
try {
|
|
34428
|
-
const evidenceRoot =
|
|
34778
|
+
const evidenceRoot = join26(staging, "promotion-evidence");
|
|
34429
34779
|
await mkdir19(evidenceRoot);
|
|
34430
34780
|
await requireCommand(runner, [
|
|
34431
34781
|
"gh",
|
|
@@ -34456,7 +34806,7 @@ var auditAbsoluteMobileCiPromotion = async (options) => {
|
|
|
34456
34806
|
if (context && options.sourceRunId && context.sourceRunId !== sourceRunId)
|
|
34457
34807
|
throw new TypeError("Requested source run does not match promotion context.");
|
|
34458
34808
|
const sourceArtifact = context?.sourceArtifact ?? `absolute-mobile-${platform3}`;
|
|
34459
|
-
const sourceRoot =
|
|
34809
|
+
const sourceRoot = join26(staging, "source-release");
|
|
34460
34810
|
await mkdir19(sourceRoot);
|
|
34461
34811
|
await requireCommand(runner, [
|
|
34462
34812
|
"gh",
|
|
@@ -34540,9 +34890,9 @@ var auditAbsoluteMobileCiPromotion = async (options) => {
|
|
|
34540
34890
|
verifiedAt: new Date().toISOString()
|
|
34541
34891
|
};
|
|
34542
34892
|
await Promise.all([
|
|
34543
|
-
writeFile19(
|
|
34893
|
+
writeFile19(join26(staging, "audit.json"), `${JSON.stringify(audit, null, 2)}
|
|
34544
34894
|
`, { mode: 384 }),
|
|
34545
|
-
writeFile19(
|
|
34895
|
+
writeFile19(join26(staging, "audit.md"), renderAuditMarkdown(audit), {
|
|
34546
34896
|
mode: 384
|
|
34547
34897
|
})
|
|
34548
34898
|
]);
|
|
@@ -34565,7 +34915,7 @@ import {
|
|
|
34565
34915
|
rename as rename16,
|
|
34566
34916
|
rm as rm16
|
|
34567
34917
|
} from "fs/promises";
|
|
34568
|
-
import { dirname as dirname18, isAbsolute as isAbsolute12, join as
|
|
34918
|
+
import { dirname as dirname18, isAbsolute as isAbsolute12, join as join27, relative as relative19, resolve as resolve21, sep as sep13 } from "path";
|
|
34569
34919
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
34570
34920
|
var ABSOLUTE_MOBILE_CI_PROMOTION_OPERATION_FORMAT = 1;
|
|
34571
34921
|
var MAX_OPERATION_BYTES = 65536;
|
|
@@ -34631,8 +34981,8 @@ var runId2 = (value, label) => {
|
|
|
34631
34981
|
return parsed;
|
|
34632
34982
|
};
|
|
34633
34983
|
var nullableRunId = (value, label) => value === null ? null : runId2(value, label);
|
|
34634
|
-
var operationRoot = (projectRoot) =>
|
|
34635
|
-
var absoluteMobilePromotionOperationPath = (projectRoot, requestedDispatchId) =>
|
|
34984
|
+
var operationRoot = (projectRoot) => join27(resolve21(projectRoot), ".absolutejs", "mobile-ci", "promotions");
|
|
34985
|
+
var absoluteMobilePromotionOperationPath = (projectRoot, requestedDispatchId) => join27(operationRoot(projectRoot), dispatchId2(requestedDispatchId), "operation.json");
|
|
34636
34986
|
var operationPhase = (value) => {
|
|
34637
34987
|
const phase = PHASES.find((candidate) => candidate === value);
|
|
34638
34988
|
if (!phase)
|
|
@@ -34703,7 +35053,7 @@ var writeSynced = async (path, source) => {
|
|
|
34703
35053
|
};
|
|
34704
35054
|
var atomicWrite = async (path, source, exclusive) => {
|
|
34705
35055
|
await mkdir20(dirname18(path), { recursive: true });
|
|
34706
|
-
const temporary =
|
|
35056
|
+
const temporary = join27(dirname18(path), `.operation-${randomUUID5()}.tmp`);
|
|
34707
35057
|
try {
|
|
34708
35058
|
await writeSynced(temporary, source);
|
|
34709
35059
|
if (exclusive)
|
|
@@ -35605,7 +35955,7 @@ init_mobilePreview();
|
|
|
35605
35955
|
|
|
35606
35956
|
// src/mobile/nativeDeepLinks.ts
|
|
35607
35957
|
import { readFile as readFile26, rename as rename17, writeFile as writeFile21 } from "fs/promises";
|
|
35608
|
-
import { join as
|
|
35958
|
+
import { join as join30 } from "path";
|
|
35609
35959
|
var START_MARKER = "<!-- absolutejs:deep-links:start -->";
|
|
35610
35960
|
var END_MARKER = "<!-- absolutejs:deep-links:end -->";
|
|
35611
35961
|
var IOS_ENTITLEMENTS = "App/AbsoluteJS.entitlements";
|
|
@@ -35662,7 +36012,7 @@ ${hosts}
|
|
|
35662
36012
|
`;
|
|
35663
36013
|
};
|
|
35664
36014
|
var configureAndroid = async (config) => {
|
|
35665
|
-
const path =
|
|
36015
|
+
const path = join30(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
|
|
35666
36016
|
const source = await readFile26(path, "utf8");
|
|
35667
36017
|
const mainActivity = source.indexOf('android:name=".MainActivity"');
|
|
35668
36018
|
if (mainActivity === NOT_FOUND) {
|
|
@@ -35688,7 +36038,7 @@ var iosSchemeRegion = (scheme) => ` ${START_MARKER}
|
|
|
35688
36038
|
${END_MARKER}
|
|
35689
36039
|
`;
|
|
35690
36040
|
var configureIosInfo = async (config) => {
|
|
35691
|
-
const path =
|
|
36041
|
+
const path = join30(config.nativeProjectDirectory, "ios/App/App/Info.plist");
|
|
35692
36042
|
const source = await readFile26(path, "utf8");
|
|
35693
36043
|
const region = config.deepLinkScheme ? iosSchemeRegion(config.deepLinkScheme) : ` ${START_MARKER}
|
|
35694
36044
|
${END_MARKER}
|
|
@@ -35712,7 +36062,7 @@ ${domains}
|
|
|
35712
36062
|
`;
|
|
35713
36063
|
};
|
|
35714
36064
|
var configureIosEntitlements = async (config) => {
|
|
35715
|
-
const path =
|
|
36065
|
+
const path = join30(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
|
|
35716
36066
|
let current = "";
|
|
35717
36067
|
try {
|
|
35718
36068
|
current = await readFile26(path, "utf8");
|
|
@@ -35730,7 +36080,7 @@ var configureIosEntitlements = async (config) => {
|
|
|
35730
36080
|
return true;
|
|
35731
36081
|
};
|
|
35732
36082
|
var configureIosProject = async (config) => {
|
|
35733
|
-
const path =
|
|
36083
|
+
const path = join30(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
|
|
35734
36084
|
const source = await readFile26(path, "utf8");
|
|
35735
36085
|
const declarations = [
|
|
35736
36086
|
...source.matchAll(/CODE_SIGN_ENTITLEMENTS = ([^;]+);/g)
|
|
@@ -35771,7 +36121,7 @@ var applyAbsoluteNativeDeepLinks = async (config, platforms = config.platforms)
|
|
|
35771
36121
|
// src/mobile/nativeDeviceCapabilities.ts
|
|
35772
36122
|
init_deviceCapabilities();
|
|
35773
36123
|
import { readFile as readFile27, rename as rename18, writeFile as writeFile22 } from "fs/promises";
|
|
35774
|
-
import { join as
|
|
36124
|
+
import { join as join31 } from "path";
|
|
35775
36125
|
var START_MARKER2 = "<!-- absolutejs:device-capabilities:start -->";
|
|
35776
36126
|
var END_MARKER2 = "<!-- absolutejs:device-capabilities:end -->";
|
|
35777
36127
|
var NOT_FOUND2 = -1;
|
|
@@ -35921,7 +36271,7 @@ var writeIosPrivacyManifest = async (path, current, source) => {
|
|
|
35921
36271
|
var configureIosPrivacyProject = async (config, requirements) => {
|
|
35922
36272
|
if (requirements.iosPrivacyAccessedApis.length === 0)
|
|
35923
36273
|
return false;
|
|
35924
|
-
const projectPath3 =
|
|
36274
|
+
const projectPath3 = join31(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
|
|
35925
36275
|
const project = await readFile27(projectPath3, "utf8");
|
|
35926
36276
|
return writeChangedFile2(projectPath3, addIosPrivacyProjectReference(project));
|
|
35927
36277
|
};
|
|
@@ -35974,7 +36324,7 @@ ${next.slice(index)}`;
|
|
|
35974
36324
|
return next;
|
|
35975
36325
|
};
|
|
35976
36326
|
var configureIos2 = async (config, plan) => {
|
|
35977
|
-
const path =
|
|
36327
|
+
const path = join31(config.nativeProjectDirectory, "ios/App/App/Info.plist");
|
|
35978
36328
|
const source = await readFile27(path, "utf8");
|
|
35979
36329
|
const requirements = absoluteDeviceNativeRequirements(plan);
|
|
35980
36330
|
const existingSystemBars = source.match(/<key>UIViewControllerBasedStatusBarAppearance<\/key>\s*<(true|false)\s*\/>/u);
|
|
@@ -35995,7 +36345,7 @@ ${content}
|
|
|
35995
36345
|
${END_MARKER2}
|
|
35996
36346
|
` : "";
|
|
35997
36347
|
const infoChanged = await writeChangedFile2(path, managed(source, region, source.lastIndexOf("</dict>")));
|
|
35998
|
-
const privacyPath =
|
|
36348
|
+
const privacyPath = join31(config.nativeProjectDirectory, "ios/App/App/PrivacyInfo.xcprivacy");
|
|
35999
36349
|
const privacyCurrent = await optionalSource(privacyPath);
|
|
36000
36350
|
const privacySource = privacyManifestSource(privacyCurrent, requirements);
|
|
36001
36351
|
const [privacyChanged, projectChanged, pushChanged] = await Promise.all([
|
|
@@ -36006,7 +36356,7 @@ ${content}
|
|
|
36006
36356
|
return infoChanged || privacyChanged || projectChanged || pushChanged;
|
|
36007
36357
|
};
|
|
36008
36358
|
var configureIosPushNotifications = async (config, enabled) => {
|
|
36009
|
-
const entitlementsPath =
|
|
36359
|
+
const entitlementsPath = join31(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
|
|
36010
36360
|
const entitlements = await optionalSource(entitlementsPath);
|
|
36011
36361
|
if (entitlements === null && !enabled)
|
|
36012
36362
|
return false;
|
|
@@ -36018,7 +36368,7 @@ var configureIosPushNotifications = async (config, enabled) => {
|
|
|
36018
36368
|
<!-- ${PUSH_END_MARKER} -->
|
|
36019
36369
|
` : "";
|
|
36020
36370
|
const nextEntitlements = replacePushRegion(entitlements, entitlementRegion, entitlements.lastIndexOf("</dict>"));
|
|
36021
|
-
const delegatePath =
|
|
36371
|
+
const delegatePath = join31(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
36022
36372
|
const delegate = await optionalSource(delegatePath);
|
|
36023
36373
|
if (delegate === null && !enabled)
|
|
36024
36374
|
return false;
|
|
@@ -36067,7 +36417,7 @@ var replacePushRegion = (source, region, insertion) => {
|
|
|
36067
36417
|
return `${source.slice(0, insertion)}${region}${source.slice(insertion)}`;
|
|
36068
36418
|
};
|
|
36069
36419
|
var configureAndroid2 = async (config, plan) => {
|
|
36070
|
-
const path =
|
|
36420
|
+
const path = join31(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
|
|
36071
36421
|
const source = await readFile27(path, "utf8");
|
|
36072
36422
|
const permissions = absoluteDeviceNativeRequirements(plan).androidPermissions;
|
|
36073
36423
|
const content = permissions.map((permission) => ` <uses-permission android:name="${escapeXml2(permission)}" />`).join(`
|
|
@@ -36096,14 +36446,14 @@ ${content}
|
|
|
36096
36446
|
const clients = typeof firebase === "object" && firebase !== null ? Reflect.get(firebase, "client") : undefined;
|
|
36097
36447
|
const matchesApp = Array.isArray(clients) && clients.some((client) => {
|
|
36098
36448
|
const info = typeof client === "object" && client !== null ? Reflect.get(client, "client_info") : undefined;
|
|
36099
|
-
const
|
|
36100
|
-
return typeof
|
|
36449
|
+
const android2 = typeof info === "object" && info !== null ? Reflect.get(info, "android_client_info") : undefined;
|
|
36450
|
+
return typeof android2 === "object" && android2 !== null && Reflect.get(android2, "package_name") === config.appId;
|
|
36101
36451
|
});
|
|
36102
36452
|
if (!matchesApp)
|
|
36103
36453
|
throw new TypeError(`Android google-services.json does not contain package ${config.appId}.`);
|
|
36104
36454
|
const [manifestChanged, firebaseChanged] = await Promise.all([
|
|
36105
36455
|
writeChangedFile2(path, nextManifest),
|
|
36106
|
-
writeOptionalChangedFile(
|
|
36456
|
+
writeOptionalChangedFile(join31(config.nativeProjectDirectory, "android/app/google-services.json"), firebaseSource)
|
|
36107
36457
|
]);
|
|
36108
36458
|
return manifestChanged || firebaseChanged;
|
|
36109
36459
|
};
|
|
@@ -36129,7 +36479,7 @@ import {
|
|
|
36129
36479
|
rm as rm17,
|
|
36130
36480
|
writeFile as writeFile23
|
|
36131
36481
|
} from "fs/promises";
|
|
36132
|
-
import { dirname as dirname21, join as
|
|
36482
|
+
import { dirname as dirname21, join as join32 } from "path";
|
|
36133
36483
|
var START = "// absolutejs:mobile-updates:start";
|
|
36134
36484
|
var END = "// absolutejs:mobile-updates:end";
|
|
36135
36485
|
var PLUGIN_START = "// absolutejs:mobile-update-plugin:start";
|
|
@@ -36299,8 +36649,8 @@ public final class AbsoluteMobileUpdateWatchdogPlugin: CAPPlugin, CAPBridgedPlug
|
|
|
36299
36649
|
${PLUGIN_END}
|
|
36300
36650
|
`;
|
|
36301
36651
|
var configureIos3 = async (config, enabled) => {
|
|
36302
|
-
const path =
|
|
36303
|
-
const capacitorConfigPath =
|
|
36652
|
+
const path = join32(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
36653
|
+
const capacitorConfigPath = join32(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
|
|
36304
36654
|
let source = await readFile28(path, "utf8");
|
|
36305
36655
|
const launch2 = source.indexOf("didFinishLaunchingWithOptions");
|
|
36306
36656
|
const brace = launch2 < 0 ? -1 : source.indexOf("{", launch2);
|
|
@@ -36310,8 +36660,8 @@ var configureIos3 = async (config, enabled) => {
|
|
|
36310
36660
|
` : "";
|
|
36311
36661
|
source = replaceMarkedRegion(source, START, END, launchRegion, brace < 0 ? -1 : source.indexOf(`
|
|
36312
36662
|
`, brace) + 1, "Could not find a safe iOS location for mobile update recovery.");
|
|
36313
|
-
const
|
|
36314
|
-
source = replaceMarkedRegion(source, PLUGIN_START, PLUGIN_END,
|
|
36663
|
+
const plugin2 = enabled ? iosPluginRegion(config.updates?.bootTimeoutMs ?? 20000) : "";
|
|
36664
|
+
source = replaceMarkedRegion(source, PLUGIN_START, PLUGIN_END, plugin2, source.length, "Could not find a safe iOS location for the mobile update watchdog.");
|
|
36315
36665
|
const capacitorConfigSource2 = await readFile28(capacitorConfigPath, "utf8");
|
|
36316
36666
|
let capacitorConfig;
|
|
36317
36667
|
try {
|
|
@@ -36492,12 +36842,12 @@ var androidActivityInRoot = async (root) => {
|
|
|
36492
36842
|
throw error;
|
|
36493
36843
|
}
|
|
36494
36844
|
const candidate = entries.find((entry) => entry.endsWith("/MainActivity.java") || entry.endsWith("/MainActivity.kt") || entry === "MainActivity.java" || entry === "MainActivity.kt");
|
|
36495
|
-
return candidate ?
|
|
36845
|
+
return candidate ? join32(root, candidate) : undefined;
|
|
36496
36846
|
};
|
|
36497
36847
|
var androidActivity = async (config) => {
|
|
36498
36848
|
const roots = [
|
|
36499
|
-
|
|
36500
|
-
|
|
36849
|
+
join32(config.nativeProjectDirectory, "android/app/src/main/java"),
|
|
36850
|
+
join32(config.nativeProjectDirectory, "android/app/src/main/kotlin")
|
|
36501
36851
|
];
|
|
36502
36852
|
const candidates = await Promise.all(roots.map(androidActivityInRoot));
|
|
36503
36853
|
const candidate = candidates.find((value) => value !== undefined);
|
|
@@ -36601,7 +36951,7 @@ var configureAndroid3 = async (config, enabled) => {
|
|
|
36601
36951
|
if (!packageName)
|
|
36602
36952
|
throw new TypeError("Android MainActivity package declaration was not found.");
|
|
36603
36953
|
const packagePath = packageName.replaceAll(".", "/");
|
|
36604
|
-
const pluginPath =
|
|
36954
|
+
const pluginPath = join32(config.nativeProjectDirectory, "android/app/src/main/java", packagePath, ANDROID_PLUGIN);
|
|
36605
36955
|
const changed = await Promise.all([
|
|
36606
36956
|
writeChanged(activityPath, injectAndroidActivity(activity, enabled)),
|
|
36607
36957
|
enabled ? writeChanged(pluginPath, androidPluginSource(packageName, config.updates?.bootTimeoutMs ?? 20000)) : removeOwnedFile(pluginPath)
|
|
@@ -36628,7 +36978,7 @@ import {
|
|
|
36628
36978
|
rm as rm18,
|
|
36629
36979
|
writeFile as writeFile24
|
|
36630
36980
|
} from "fs/promises";
|
|
36631
|
-
import { dirname as dirname22, join as
|
|
36981
|
+
import { dirname as dirname22, join as join33 } from "path";
|
|
36632
36982
|
var START2 = "// absolutejs:native-observability:start";
|
|
36633
36983
|
var END2 = "// absolutejs:native-observability:end";
|
|
36634
36984
|
var PLUGIN_START2 = "// absolutejs:native-observability-plugin:start";
|
|
@@ -36796,8 +37146,8 @@ public final class AbsoluteMobileObservabilityPlugin: CAPPlugin, CAPBridgedPlugi
|
|
|
36796
37146
|
${PLUGIN_END2}
|
|
36797
37147
|
`;
|
|
36798
37148
|
var configureIos4 = async (config, enabled) => {
|
|
36799
|
-
const path =
|
|
36800
|
-
const capacitorConfigPath =
|
|
37149
|
+
const path = join33(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
37150
|
+
const capacitorConfigPath = join33(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
|
|
36801
37151
|
let source = await readFile29(path, "utf8");
|
|
36802
37152
|
if (enabled && !source.includes("import MetricKit")) {
|
|
36803
37153
|
const capacitorImport = source.lastIndexOf("import Capacitor");
|
|
@@ -37057,12 +37407,12 @@ var androidActivityInRoot2 = async (root) => {
|
|
|
37057
37407
|
throw error;
|
|
37058
37408
|
}
|
|
37059
37409
|
const candidate = entries.find((entry) => entry.endsWith("/MainActivity.java") || entry.endsWith("/MainActivity.kt") || entry === "MainActivity.java" || entry === "MainActivity.kt");
|
|
37060
|
-
return candidate ?
|
|
37410
|
+
return candidate ? join33(root, candidate) : undefined;
|
|
37061
37411
|
};
|
|
37062
37412
|
var androidActivity2 = async (config) => {
|
|
37063
37413
|
const roots = [
|
|
37064
|
-
|
|
37065
|
-
|
|
37414
|
+
join33(config.nativeProjectDirectory, "android/app/src/main/java"),
|
|
37415
|
+
join33(config.nativeProjectDirectory, "android/app/src/main/kotlin")
|
|
37066
37416
|
];
|
|
37067
37417
|
const candidates = await Promise.all(roots.map(androidActivityInRoot2));
|
|
37068
37418
|
const candidate = candidates.find((value) => value !== undefined);
|
|
@@ -37134,7 +37484,7 @@ var configureAndroid4 = async (config, enabled) => {
|
|
|
37134
37484
|
const packageName = activity.match(/^\s*package\s+([A-Za-z0-9_.]+)\s*[;\n]/mu)?.[1];
|
|
37135
37485
|
if (!packageName)
|
|
37136
37486
|
throw new TypeError("Android MainActivity package declaration was not found.");
|
|
37137
|
-
const pluginPath =
|
|
37487
|
+
const pluginPath = join33(config.nativeProjectDirectory, "android/app/src/main/java", packageName.replaceAll(".", "/"), ANDROID_PLUGIN2);
|
|
37138
37488
|
const changed = await Promise.all([
|
|
37139
37489
|
writeChanged2(activityPath, injectAndroidActivity2(activity, enabled)),
|
|
37140
37490
|
enabled ? writeChanged2(pluginPath, androidPluginSource2(packageName)) : removeOwnedFile2(pluginPath)
|
|
@@ -37154,7 +37504,7 @@ var applyAbsoluteNativeObservability = async (config, platforms = config.platfor
|
|
|
37154
37504
|
};
|
|
37155
37505
|
// src/mobile/nativeReleaseReadiness.ts
|
|
37156
37506
|
import { mkdir as mkdir24, readFile as readFile30, readdir as readdir11, rename as rename21, writeFile as writeFile25 } from "fs/promises";
|
|
37157
|
-
import { dirname as dirname23, join as
|
|
37507
|
+
import { dirname as dirname23, join as join34 } from "path";
|
|
37158
37508
|
var START3 = "// absolutejs:release-readiness:start";
|
|
37159
37509
|
var END3 = "// absolutejs:release-readiness:end";
|
|
37160
37510
|
var IOS_PLUGIN_START = "// absolutejs:release-readiness-plugin:start";
|
|
@@ -37193,12 +37543,12 @@ var activityInRoot = async (root) => {
|
|
|
37193
37543
|
throw error;
|
|
37194
37544
|
}
|
|
37195
37545
|
const candidate = entries.find((entry) => entry.endsWith("/MainActivity.java") || entry.endsWith("/MainActivity.kt") || entry === "MainActivity.java" || entry === "MainActivity.kt");
|
|
37196
|
-
return candidate ?
|
|
37546
|
+
return candidate ? join34(root, candidate) : undefined;
|
|
37197
37547
|
};
|
|
37198
37548
|
var activityPath = async (config) => {
|
|
37199
37549
|
const roots = [
|
|
37200
|
-
|
|
37201
|
-
|
|
37550
|
+
join34(config.nativeProjectDirectory, "android/app/src/main/java"),
|
|
37551
|
+
join34(config.nativeProjectDirectory, "android/app/src/main/kotlin")
|
|
37202
37552
|
];
|
|
37203
37553
|
const candidates = await Promise.all(roots.map(activityInRoot));
|
|
37204
37554
|
const candidate = candidates.find((value) => value !== undefined);
|
|
@@ -37308,8 +37658,8 @@ var replaceIosPluginRegion = (appDelegate, existingStart, existingEnd) => {
|
|
|
37308
37658
|
return `${appDelegate.slice(0, from)}${iosPluginRegion3}${appDelegate.slice(through)}`;
|
|
37309
37659
|
};
|
|
37310
37660
|
var configureIos5 = async (config) => {
|
|
37311
|
-
const appDelegatePath =
|
|
37312
|
-
const capacitorConfigPath =
|
|
37661
|
+
const appDelegatePath = join34(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
37662
|
+
const capacitorConfigPath = join34(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
|
|
37313
37663
|
const appDelegate = await readFile30(appDelegatePath, "utf8");
|
|
37314
37664
|
const existingStart = appDelegate.indexOf(IOS_PLUGIN_START);
|
|
37315
37665
|
const existingEnd = appDelegate.indexOf(IOS_PLUGIN_END);
|
|
@@ -37349,7 +37699,7 @@ var configureAndroid5 = async (config) => {
|
|
|
37349
37699
|
const packageName = activity.match(/^\s*package\s+([A-Za-z0-9_.]+)\s*[;\n]/mu)?.[1];
|
|
37350
37700
|
if (!packageName)
|
|
37351
37701
|
throw new TypeError("Android MainActivity package declaration was not found.");
|
|
37352
|
-
const pluginPath =
|
|
37702
|
+
const pluginPath = join34(config.nativeProjectDirectory, "android/app/src/main/java", packageName.replaceAll(".", "/"), ANDROID_PLUGIN3);
|
|
37353
37703
|
const changed = await Promise.all([
|
|
37354
37704
|
writeChanged3(mainActivityPath, injectRegistration(activity)),
|
|
37355
37705
|
writeChanged3(pluginPath, pluginSource(packageName))
|
|
@@ -38090,11 +38440,11 @@ var resolveAbsoluteHttpUrl = (target, origin) => {
|
|
|
38090
38440
|
var createAbsoluteHttpTransport = ({
|
|
38091
38441
|
fetch: fetchImpl = globalThis.fetch,
|
|
38092
38442
|
origin,
|
|
38093
|
-
runtime:
|
|
38443
|
+
runtime: runtime3
|
|
38094
38444
|
}) => ({
|
|
38095
38445
|
fetch: fetchImpl,
|
|
38096
38446
|
origin: normalizeAbsoluteHttpOrigin(origin),
|
|
38097
|
-
runtime:
|
|
38447
|
+
runtime: runtime3
|
|
38098
38448
|
});
|
|
38099
38449
|
var createWebHttpTransport = (options = {}) => {
|
|
38100
38450
|
const origin = options.origin ?? globalThis.location?.origin;
|
|
@@ -38277,8 +38627,8 @@ var createCapacitor = (win) => {
|
|
|
38277
38627
|
};
|
|
38278
38628
|
const isNativePlatform = () => getPlatform() !== "web";
|
|
38279
38629
|
const isPluginAvailable = (pluginName) => {
|
|
38280
|
-
const
|
|
38281
|
-
if (
|
|
38630
|
+
const plugin2 = registeredPlugins.get(pluginName);
|
|
38631
|
+
if (plugin2 === null || plugin2 === undefined ? undefined : plugin2.platforms.has(getPlatform())) {
|
|
38282
38632
|
return true;
|
|
38283
38633
|
}
|
|
38284
38634
|
if (getPluginHeader(pluginName)) {
|
|
@@ -38833,12 +39183,12 @@ var drainAbsoluteMobileNativeObservability = async (manifest, fetch2, options =
|
|
|
38833
39183
|
const config = manifest.observability;
|
|
38834
39184
|
if (!config || !(options.native ?? Capacitor.isNativePlatform()))
|
|
38835
39185
|
return 0;
|
|
38836
|
-
const
|
|
38837
|
-
const pending = await
|
|
39186
|
+
const plugin2 = options.plugin ?? nativeObservability;
|
|
39187
|
+
const pending = await plugin2.pending();
|
|
38838
39188
|
const reports = pending.reports.slice(0, MAX_REPORTS).map(parseReport).filter((report) => report !== undefined);
|
|
38839
39189
|
const discarded = reports.filter((report) => !sampled(report.id, config.sampleRate));
|
|
38840
39190
|
if (discarded.length > 0)
|
|
38841
|
-
await
|
|
39191
|
+
await plugin2.acknowledge({
|
|
38842
39192
|
ids: discarded.map(({ id }) => id)
|
|
38843
39193
|
});
|
|
38844
39194
|
const selected = reports.filter((report) => sampled(report.id, config.sampleRate));
|
|
@@ -38858,7 +39208,7 @@ var drainAbsoluteMobileNativeObservability = async (manifest, fetch2, options =
|
|
|
38858
39208
|
});
|
|
38859
39209
|
if (!response.ok)
|
|
38860
39210
|
return 0;
|
|
38861
|
-
await
|
|
39211
|
+
await plugin2.acknowledge({
|
|
38862
39212
|
ids: selected.map(({ id }) => id)
|
|
38863
39213
|
});
|
|
38864
39214
|
return selected.length;
|
|
@@ -44240,14 +44590,14 @@ import {
|
|
|
44240
44590
|
stat as stat8,
|
|
44241
44591
|
writeFile as writeFile26
|
|
44242
44592
|
} from "fs/promises";
|
|
44243
|
-
import { dirname as dirname25, join as
|
|
44593
|
+
import { dirname as dirname25, join as join35, relative as relative23, resolve as resolve25 } from "path";
|
|
44244
44594
|
var UPDATE_MANIFEST_FILE = "update.json";
|
|
44245
44595
|
var UPDATE_FILES_DIRECTORY = "files";
|
|
44246
44596
|
var sha2565 = (value) => createHash18("sha256").update(value).digest("hex");
|
|
44247
44597
|
var listFiles = async (root, directory = root) => {
|
|
44248
44598
|
const entries = await readdir12(directory, { withFileTypes: true });
|
|
44249
44599
|
const paths = await Promise.all(entries.map(async (entry) => {
|
|
44250
|
-
const path =
|
|
44600
|
+
const path = join35(directory, entry.name);
|
|
44251
44601
|
if (entry.isDirectory())
|
|
44252
44602
|
return listFiles(root, path);
|
|
44253
44603
|
if (!entry.isFile())
|
|
@@ -44257,7 +44607,7 @@ var listFiles = async (root, directory = root) => {
|
|
|
44257
44607
|
return paths.flat().sort((left, right) => left.localeCompare(right));
|
|
44258
44608
|
};
|
|
44259
44609
|
var inspectFiles = async (root, paths) => Promise.all(paths.map(async (path) => {
|
|
44260
|
-
const source =
|
|
44610
|
+
const source = join35(root, path);
|
|
44261
44611
|
const [metadata, contents] = await Promise.all([
|
|
44262
44612
|
stat8(source),
|
|
44263
44613
|
readFile31(source)
|
|
@@ -44296,14 +44646,14 @@ var buildAbsoluteMobileUpdate = async (options) => {
|
|
|
44296
44646
|
}
|
|
44297
44647
|
});
|
|
44298
44648
|
await mkdir25(outputRoot, { recursive: true });
|
|
44299
|
-
const outputDirectory =
|
|
44300
|
-
const staging = await mkdtemp12(
|
|
44649
|
+
const outputDirectory = join35(outputRoot, manifest.releaseId);
|
|
44650
|
+
const staging = await mkdtemp12(join35(outputRoot, ".stage-"));
|
|
44301
44651
|
try {
|
|
44302
|
-
await cp2(bundleDirectory,
|
|
44652
|
+
await cp2(bundleDirectory, join35(staging, UPDATE_FILES_DIRECTORY), {
|
|
44303
44653
|
force: true,
|
|
44304
44654
|
recursive: true
|
|
44305
44655
|
});
|
|
44306
|
-
await writeFile26(
|
|
44656
|
+
await writeFile26(join35(staging, UPDATE_MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
|
|
44307
44657
|
`);
|
|
44308
44658
|
await rename22(staging, outputDirectory);
|
|
44309
44659
|
} catch (error) {
|
|
@@ -44314,7 +44664,7 @@ var buildAbsoluteMobileUpdate = async (options) => {
|
|
|
44314
44664
|
}
|
|
44315
44665
|
return {
|
|
44316
44666
|
manifest,
|
|
44317
|
-
manifestPath:
|
|
44667
|
+
manifestPath: join35(outputDirectory, UPDATE_MANIFEST_FILE),
|
|
44318
44668
|
outputDirectory
|
|
44319
44669
|
};
|
|
44320
44670
|
};
|
|
@@ -44326,7 +44676,7 @@ var copyAbsoluteMobileUpdateFile = async (updateDirectory, path, destination) =>
|
|
|
44326
44676
|
await mkdir25(dirname25(destination), { recursive: true });
|
|
44327
44677
|
await cp2(source, destination, { force: true });
|
|
44328
44678
|
};
|
|
44329
|
-
var readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await readFile31(
|
|
44679
|
+
var readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await readFile31(join35(resolve25(directory), UPDATE_MANIFEST_FILE), "utf8")));
|
|
44330
44680
|
var verifyAbsoluteMobileUpdateSignature = (manifestValue, publicKey) => {
|
|
44331
44681
|
const manifest = parseAbsoluteMobileUpdateManifest(manifestValue);
|
|
44332
44682
|
const valid = verify("sha256", absoluteMobileUpdateSigningPayload(unsignedAbsoluteMobileUpdate(manifest)), { dsaEncoding: "ieee-p1363", key: publicKey }, Buffer.from(manifest.signature.value, "base64"));
|
|
@@ -44851,5 +45201,5 @@ export {
|
|
|
44851
45201
|
writeAbsoluteMobileUpdateRegistry
|
|
44852
45202
|
};
|
|
44853
45203
|
|
|
44854
|
-
//# debugId=
|
|
45204
|
+
//# debugId=F06A772036512CCC64756E2164756E21
|
|
44855
45205
|
//# sourceMappingURL=index.js.map
|