@absolutejs/absolute 0.20.0-beta.67 → 0.20.0-beta.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/cli/index.js +1581 -577
- package/dist/mobile/index.js +1789 -190
- package/dist/mobile/index.js.map +9 -5
- package/dist/mobile/remoteMacAgentEntry.js +580 -209
- package/dist/mobile/shellBootstrap.js +152 -0
- package/dist/src/mobile/expoNativeObservability.d.ts +3 -0
- package/dist/src/mobile/index.d.ts +3 -0
- package/dist/src/mobile/nativeObservability.d.ts +4 -0
- package/dist/src/mobile/shellNativeObservability.d.ts +21 -0
- package/package.json +8 -7
package/dist/cli/index.js
CHANGED
|
@@ -1939,6 +1939,426 @@ var init_updateRuntime = __esm(() => {
|
|
|
1939
1939
|
init_syncSchema();
|
|
1940
1940
|
});
|
|
1941
1941
|
|
|
1942
|
+
// src/mobile/expoNativeObservability.ts
|
|
1943
|
+
import { join as join8 } from "path";
|
|
1944
|
+
var HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
|
|
1945
|
+
`, moduleConfig, podspec, iosModule, androidBuild, androidManifest, androidModule, expoNativeObservabilityRuntimeSource, absoluteExpoNativeObservabilityFiles = (project) => new Map([
|
|
1946
|
+
[
|
|
1947
|
+
join8(project, "modules/absolute-mobile-observability/expo-module.config.json"),
|
|
1948
|
+
moduleConfig
|
|
1949
|
+
],
|
|
1950
|
+
[
|
|
1951
|
+
join8(project, "modules/absolute-mobile-observability/ios/AbsoluteMobileObservability.podspec"),
|
|
1952
|
+
podspec
|
|
1953
|
+
],
|
|
1954
|
+
[
|
|
1955
|
+
join8(project, "modules/absolute-mobile-observability/ios/AbsoluteMobileObservabilityModule.swift"),
|
|
1956
|
+
iosModule
|
|
1957
|
+
],
|
|
1958
|
+
[
|
|
1959
|
+
join8(project, "modules/absolute-mobile-observability/android/build.gradle"),
|
|
1960
|
+
androidBuild
|
|
1961
|
+
],
|
|
1962
|
+
[
|
|
1963
|
+
join8(project, "modules/absolute-mobile-observability/android/src/main/AndroidManifest.xml"),
|
|
1964
|
+
androidManifest
|
|
1965
|
+
],
|
|
1966
|
+
[
|
|
1967
|
+
join8(project, "modules/absolute-mobile-observability/android/src/main/java/expo/modules/absolutemobileobservability/AbsoluteMobileObservabilityModule.kt"),
|
|
1968
|
+
androidModule
|
|
1969
|
+
],
|
|
1970
|
+
[
|
|
1971
|
+
join8(project, "src/generated/AbsoluteNativeObservability.ts"),
|
|
1972
|
+
expoNativeObservabilityRuntimeSource
|
|
1973
|
+
]
|
|
1974
|
+
]), absoluteExpoNativeObservabilityPaths = (project) => [
|
|
1975
|
+
...absoluteExpoNativeObservabilityFiles(project).keys()
|
|
1976
|
+
];
|
|
1977
|
+
var init_expoNativeObservability = __esm(() => {
|
|
1978
|
+
moduleConfig = `${JSON.stringify({
|
|
1979
|
+
android: {
|
|
1980
|
+
modules: [
|
|
1981
|
+
"expo.modules.absolutemobileobservability.AbsoluteMobileObservabilityModule"
|
|
1982
|
+
]
|
|
1983
|
+
},
|
|
1984
|
+
apple: { modules: ["AbsoluteMobileObservabilityModule"] },
|
|
1985
|
+
platforms: ["apple", "android"]
|
|
1986
|
+
}, null, 2)}
|
|
1987
|
+
`;
|
|
1988
|
+
podspec = `${HEADER}Pod::Spec.new do |s|
|
|
1989
|
+
s.name = 'AbsoluteMobileObservability'
|
|
1990
|
+
s.version = '0.0.1'
|
|
1991
|
+
s.summary = 'AbsoluteJS provider-neutral native process diagnostics'
|
|
1992
|
+
s.description = 'Generated MetricKit bridge for an AbsoluteJS Expo application.'
|
|
1993
|
+
s.author = 'AbsoluteJS'
|
|
1994
|
+
s.homepage = 'https://absolutejs.com'
|
|
1995
|
+
s.platforms = { :ios => '16.4' }
|
|
1996
|
+
s.source = { git: '' }
|
|
1997
|
+
s.static_framework = true
|
|
1998
|
+
s.dependency 'ExpoModulesCore'
|
|
1999
|
+
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
|
|
2000
|
+
s.source_files = '**/*.{h,m,mm,swift,hpp,cpp}'
|
|
2001
|
+
end
|
|
2002
|
+
`;
|
|
2003
|
+
iosModule = `${HEADER}import ExpoModulesCore
|
|
2004
|
+
import MetricKit
|
|
2005
|
+
|
|
2006
|
+
public final class AbsoluteMobileObservabilityModule: Module, MXMetricManagerSubscriber {
|
|
2007
|
+
private static let maximumReports = 8
|
|
2008
|
+
private static let maximumReportBytes = 64 * 1024
|
|
2009
|
+
private static let queue = DispatchQueue(label: "dev.absolute.expo-mobile-observability")
|
|
2010
|
+
|
|
2011
|
+
public func definition() -> ModuleDefinition {
|
|
2012
|
+
Name("AbsoluteMobileObservability")
|
|
2013
|
+
|
|
2014
|
+
OnCreate { MXMetricManager.shared.add(self) }
|
|
2015
|
+
OnDestroy { MXMetricManager.shared.remove(self) }
|
|
2016
|
+
|
|
2017
|
+
AsyncFunction("pending") { () -> [String: Any] in
|
|
2018
|
+
Self.queue.sync {
|
|
2019
|
+
let reports: [[String: Any]] = Self.files().compactMap { file in
|
|
2020
|
+
guard let data = try? Data(contentsOf: file),
|
|
2021
|
+
let value = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return nil }
|
|
2022
|
+
return value
|
|
2023
|
+
}
|
|
2024
|
+
return ["reports": reports]
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
AsyncFunction("acknowledge") { (options: [String: Any]) in
|
|
2029
|
+
let accepted = Set(options["ids"] as? [String] ?? [])
|
|
2030
|
+
Self.queue.sync {
|
|
2031
|
+
for file in Self.files() {
|
|
2032
|
+
guard let data = try? Data(contentsOf: file),
|
|
2033
|
+
let value = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
|
2034
|
+
let id = value["id"] as? String,
|
|
2035
|
+
accepted.contains(id) else { continue }
|
|
2036
|
+
try? FileManager.default.removeItem(at: file)
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
private static func root() -> URL? {
|
|
2043
|
+
guard let support = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first else { return nil }
|
|
2044
|
+
let root = support.appendingPathComponent("AbsoluteMobileObservability", isDirectory: true)
|
|
2045
|
+
try? FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)
|
|
2046
|
+
return root
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
private static func files() -> [URL] {
|
|
2050
|
+
guard let root = root() else { return [] }
|
|
2051
|
+
return ((try? FileManager.default.contentsOfDirectory(at: root, includingPropertiesForKeys: nil)) ?? [])
|
|
2052
|
+
.filter { $0.pathExtension == "json" }
|
|
2053
|
+
.sorted { $0.lastPathComponent < $1.lastPathComponent }
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
private static func enqueue(kind: String, occurredAt: Double, details: [AnyHashable: Any]) {
|
|
2057
|
+
guard let root = root() else { return }
|
|
2058
|
+
let id = UUID().uuidString.lowercased()
|
|
2059
|
+
var report: [String: Any] = [
|
|
2060
|
+
"details": Dictionary(uniqueKeysWithValues: details.map { (String(describing: $0.key), $0.value) }),
|
|
2061
|
+
"id": id,
|
|
2062
|
+
"kind": kind,
|
|
2063
|
+
"occurredAt": occurredAt,
|
|
2064
|
+
"platform": "ios"
|
|
2065
|
+
]
|
|
2066
|
+
guard JSONSerialization.isValidJSONObject(report),
|
|
2067
|
+
let original = try? JSONSerialization.data(withJSONObject: report) else { return }
|
|
2068
|
+
if original.count > maximumReportBytes {
|
|
2069
|
+
report["details"] = [
|
|
2070
|
+
"diagnosticPrefix": String(decoding: original.prefix(24 * 1024), as: UTF8.self),
|
|
2071
|
+
"originalBytes": original.count,
|
|
2072
|
+
"truncated": true
|
|
2073
|
+
]
|
|
2074
|
+
}
|
|
2075
|
+
guard let data = try? JSONSerialization.data(withJSONObject: report),
|
|
2076
|
+
data.count <= maximumReportBytes else { return }
|
|
2077
|
+
let timestamp = String(format: "%013.0f", occurredAt)
|
|
2078
|
+
try? data.write(to: root.appendingPathComponent("\\(timestamp)-\\(id).json"), options: .atomic)
|
|
2079
|
+
let overflow = max(0, files().count - maximumReports)
|
|
2080
|
+
for file in files().prefix(overflow) { try? FileManager.default.removeItem(at: file) }
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
public func didReceive(_ payloads: [MXDiagnosticPayload]) {
|
|
2084
|
+
Self.queue.async {
|
|
2085
|
+
for payload in payloads {
|
|
2086
|
+
let at = payload.timeStampEnd.timeIntervalSince1970 * 1000
|
|
2087
|
+
for value in payload.crashDiagnostics ?? [] { Self.enqueue(kind: "crash", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
2088
|
+
for value in payload.hangDiagnostics ?? [] { Self.enqueue(kind: "hang", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
2089
|
+
for value in payload.cpuExceptionDiagnostics ?? [] { Self.enqueue(kind: "cpu-exception", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
2090
|
+
for value in payload.diskWriteExceptionDiagnostics ?? [] { Self.enqueue(kind: "disk-write-exception", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
2091
|
+
if #available(iOS 16.0, *) {
|
|
2092
|
+
for value in payload.appLaunchDiagnostics ?? [] { Self.enqueue(kind: "app-launch", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
`;
|
|
2099
|
+
androidBuild = `${HEADER}plugins {
|
|
2100
|
+
id 'com.android.library'
|
|
2101
|
+
id 'expo-module-gradle-plugin'
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
group = 'expo.modules.absolutemobileobservability'
|
|
2105
|
+
version = '0.0.1'
|
|
2106
|
+
|
|
2107
|
+
android {
|
|
2108
|
+
namespace 'expo.modules.absolutemobileobservability'
|
|
2109
|
+
defaultConfig {
|
|
2110
|
+
versionCode 1
|
|
2111
|
+
versionName '0.0.1'
|
|
2112
|
+
}
|
|
2113
|
+
lintOptions { abortOnError false }
|
|
2114
|
+
}
|
|
2115
|
+
`;
|
|
2116
|
+
androidManifest = `${HEADER}<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
|
2117
|
+
`;
|
|
2118
|
+
androidModule = `${HEADER}package expo.modules.absolutemobileobservability
|
|
2119
|
+
|
|
2120
|
+
import android.app.ActivityManager
|
|
2121
|
+
import android.app.ApplicationExitInfo
|
|
2122
|
+
import android.os.Build
|
|
2123
|
+
import android.util.Base64
|
|
2124
|
+
import expo.modules.kotlin.modules.Module
|
|
2125
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
2126
|
+
import java.io.ByteArrayOutputStream
|
|
2127
|
+
import java.io.File
|
|
2128
|
+
import java.io.FileInputStream
|
|
2129
|
+
import java.io.FileOutputStream
|
|
2130
|
+
import java.io.InputStream
|
|
2131
|
+
import java.nio.charset.StandardCharsets
|
|
2132
|
+
import java.util.UUID
|
|
2133
|
+
import org.json.JSONArray
|
|
2134
|
+
import org.json.JSONObject
|
|
2135
|
+
|
|
2136
|
+
class AbsoluteMobileObservabilityModule : Module() {
|
|
2137
|
+
companion object {
|
|
2138
|
+
private const val MAX_REPORTS = 8
|
|
2139
|
+
private const val MAX_TRACE_BYTES = 32 * 1024
|
|
2140
|
+
private const val ACKNOWLEDGED_KEY = "acknowledged"
|
|
2141
|
+
private const val PREFERENCES = "AbsoluteMobileObservability"
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
override fun definition() = ModuleDefinition {
|
|
2145
|
+
Name("AbsoluteMobileObservability")
|
|
2146
|
+
|
|
2147
|
+
AsyncFunction("pending") {
|
|
2148
|
+
collect()
|
|
2149
|
+
mapOf("reports" to files().mapNotNull { readReport(it) })
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
AsyncFunction("acknowledge") { options: Map<String, List<String>> ->
|
|
2153
|
+
val accepted = options["ids"]?.toSet() ?: emptySet()
|
|
2154
|
+
val acknowledged = acknowledged().toMutableSet()
|
|
2155
|
+
files().forEach { file ->
|
|
2156
|
+
val report = readReport(file)
|
|
2157
|
+
val id = report?.get("id") as? String
|
|
2158
|
+
if (id != null && accepted.contains(id)) {
|
|
2159
|
+
acknowledged.add(id)
|
|
2160
|
+
file.delete()
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
writeAcknowledged(acknowledged)
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
private fun context() = appContext.reactContext
|
|
2168
|
+
|
|
2169
|
+
private fun root(): File? {
|
|
2170
|
+
val context = context() ?: return null
|
|
2171
|
+
return File(context.filesDir, "absolute-mobile-observability").also { it.mkdirs() }
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
private fun files(): List<File> = root()?.listFiles { _, name -> name.endsWith(".json") }
|
|
2175
|
+
?.sortedBy { it.name } ?: emptyList()
|
|
2176
|
+
|
|
2177
|
+
private fun acknowledged(): Set<String> {
|
|
2178
|
+
val context = context() ?: return emptySet()
|
|
2179
|
+
return try {
|
|
2180
|
+
val values = JSONArray(context.getSharedPreferences(PREFERENCES, 0).getString(ACKNOWLEDGED_KEY, "[]"))
|
|
2181
|
+
(0 until values.length()).map { values.optString(it) }.toSet()
|
|
2182
|
+
} catch (_: Exception) { emptySet() }
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
private fun writeAcknowledged(values: Set<String>) {
|
|
2186
|
+
val context = context() ?: return
|
|
2187
|
+
val bounded = values.sorted().takeLast(64)
|
|
2188
|
+
context.getSharedPreferences(PREFERENCES, 0).edit()
|
|
2189
|
+
.putString(ACKNOWLEDGED_KEY, JSONArray(bounded).toString()).apply()
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
private fun kind(reason: Int): String? = when (reason) {
|
|
2193
|
+
ApplicationExitInfo.REASON_ANR -> "anr"
|
|
2194
|
+
ApplicationExitInfo.REASON_CRASH -> "crash"
|
|
2195
|
+
ApplicationExitInfo.REASON_CRASH_NATIVE -> "native-crash"
|
|
2196
|
+
ApplicationExitInfo.REASON_LOW_MEMORY -> "low-memory"
|
|
2197
|
+
ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE -> "resource-exhaustion"
|
|
2198
|
+
ApplicationExitInfo.REASON_INITIALIZATION_FAILURE -> "initialization-failure"
|
|
2199
|
+
ApplicationExitInfo.REASON_SIGNALED -> "signal"
|
|
2200
|
+
else -> null
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
private fun trace(info: ApplicationExitInfo): ByteArray? = try {
|
|
2204
|
+
info.traceInputStream?.use { input ->
|
|
2205
|
+
val output = ByteArrayOutputStream()
|
|
2206
|
+
val buffer = ByteArray(4096)
|
|
2207
|
+
var total = 0
|
|
2208
|
+
while (true) {
|
|
2209
|
+
val count = input.read(buffer, 0, minOf(buffer.size, MAX_TRACE_BYTES + 1 - total))
|
|
2210
|
+
if (count <= 0) break
|
|
2211
|
+
output.write(buffer, 0, count)
|
|
2212
|
+
total += count
|
|
2213
|
+
if (total > MAX_TRACE_BYTES) return null
|
|
2214
|
+
}
|
|
2215
|
+
output.toByteArray()
|
|
2216
|
+
}
|
|
2217
|
+
} catch (_: Exception) { null }
|
|
2218
|
+
|
|
2219
|
+
private fun report(info: ApplicationExitInfo): JSONObject? {
|
|
2220
|
+
val kind = kind(info.reason) ?: return null
|
|
2221
|
+
val id = "android:" + info.timestamp + ":" + info.reason + ":" + info.status
|
|
2222
|
+
return try {
|
|
2223
|
+
val details = JSONObject()
|
|
2224
|
+
.put("importance", info.importance)
|
|
2225
|
+
.put("pssKb", info.pss)
|
|
2226
|
+
.put("reason", info.reason)
|
|
2227
|
+
.put("rssKb", info.rss)
|
|
2228
|
+
.put("status", info.status)
|
|
2229
|
+
info.description?.let { details.put("description", it) }
|
|
2230
|
+
trace(info)?.takeIf { it.isNotEmpty() }?.let { trace ->
|
|
2231
|
+
if (info.reason == ApplicationExitInfo.REASON_CRASH_NATIVE) {
|
|
2232
|
+
details.put("trace", Base64.encodeToString(trace, Base64.NO_WRAP))
|
|
2233
|
+
details.put("traceEncoding", "android-tombstone-protobuf-base64")
|
|
2234
|
+
} else {
|
|
2235
|
+
details.put("trace", String(trace, StandardCharsets.UTF_8))
|
|
2236
|
+
details.put("traceEncoding", "utf-8")
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
JSONObject().put("details", details).put("id", id).put("kind", kind)
|
|
2240
|
+
.put("occurredAt", info.timestamp).put("platform", "android")
|
|
2241
|
+
} catch (_: Exception) { null }
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
private fun collect() {
|
|
2245
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return
|
|
2246
|
+
val context = context() ?: return
|
|
2247
|
+
val directory = root() ?: return
|
|
2248
|
+
val manager = context.getSystemService(ActivityManager::class.java) ?: return
|
|
2249
|
+
val ignored = (acknowledged() + files().mapNotNull { readReport(it)?.get("id") as? String }).toMutableSet()
|
|
2250
|
+
manager.getHistoricalProcessExitReasons(null, 0, 16).forEach { exit ->
|
|
2251
|
+
val report = report(exit) ?: return@forEach
|
|
2252
|
+
val id = report.optString("id")
|
|
2253
|
+
if (ignored.contains(id)) return@forEach
|
|
2254
|
+
val target = File(directory, String.format(java.util.Locale.ROOT, "%013d-%s.json", exit.timestamp, UUID.randomUUID()))
|
|
2255
|
+
try {
|
|
2256
|
+
FileOutputStream(target).use { it.write(report.toString().toByteArray(StandardCharsets.UTF_8)) }
|
|
2257
|
+
ignored.add(id)
|
|
2258
|
+
} catch (_: Exception) {}
|
|
2259
|
+
}
|
|
2260
|
+
files().dropLast(MAX_REPORTS).forEach { it.delete() }
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
private fun read(input: InputStream): ByteArray {
|
|
2264
|
+
val output = ByteArrayOutputStream()
|
|
2265
|
+
val buffer = ByteArray(4096)
|
|
2266
|
+
while (true) {
|
|
2267
|
+
val count = input.read(buffer)
|
|
2268
|
+
if (count < 0) break
|
|
2269
|
+
output.write(buffer, 0, count)
|
|
2270
|
+
}
|
|
2271
|
+
return output.toByteArray()
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
private fun readReport(file: File): Map<String, Any?>? = try {
|
|
2275
|
+
FileInputStream(file).use { JSONObject(String(read(it), StandardCharsets.UTF_8)).toMap() }
|
|
2276
|
+
} catch (_: Exception) { null }
|
|
2277
|
+
|
|
2278
|
+
private fun JSONObject.toMap(): Map<String, Any?> = keys().asSequence().associateWith { key ->
|
|
2279
|
+
when (val value = get(key)) {
|
|
2280
|
+
is JSONObject -> value.toMap()
|
|
2281
|
+
is JSONArray -> (0 until value.length()).map { index ->
|
|
2282
|
+
when (val item = value.get(index)) {
|
|
2283
|
+
is JSONObject -> item.toMap()
|
|
2284
|
+
else -> item
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
JSONObject.NULL -> null
|
|
2288
|
+
else -> value
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
`;
|
|
2293
|
+
expoNativeObservabilityRuntimeSource = `${HEADER}import { requireNativeModule } from 'expo';
|
|
2294
|
+
import { AppState, Platform } from 'react-native';
|
|
2295
|
+
import { ABSOLUTE_MOBILE_MANIFEST } from './webAssets';
|
|
2296
|
+
|
|
2297
|
+
type NativeObservabilityModule = {
|
|
2298
|
+
acknowledge(options: { ids: string[] }): Promise<void>;
|
|
2299
|
+
pending(): Promise<{ reports: unknown[] }>;
|
|
2300
|
+
};
|
|
2301
|
+
type NativeReport = { details: Record<string, unknown>; id: string; kind: string; occurredAt: number; platform: 'android' | 'ios' };
|
|
2302
|
+
const native = requireNativeModule<NativeObservabilityModule>('AbsoluteMobileObservability');
|
|
2303
|
+
const KINDS = new Set(['anr', 'app-launch', 'cpu-exception', 'crash', 'disk-write-exception', 'hang', 'initialization-failure', 'low-memory', 'native-crash', 'resource-exhaustion', 'signal']);
|
|
2304
|
+
const ID = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
2305
|
+
const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
2306
|
+
const redactText = (value: string) => value.slice(0, 8192)
|
|
2307
|
+
.replace(/\\b(Bearer)\\s+[A-Za-z0-9._~+/-]+=*/gi, '$1 [REDACTED]')
|
|
2308
|
+
.replace(/([?&](?:access_token|api_?key|authorization|code|id_token|password|refresh_token|secret|token)=)[^&#\\s]*/gi, '$1[REDACTED]')
|
|
2309
|
+
.replace(/\\b((?:access_?token|api_?key|authorization|client_?secret|cookie|id_?token|password|passwd|refresh_?token|secret|token)\\s*[:=]\\s*)[^,\\s;]+/gi, '$1[REDACTED]')
|
|
2310
|
+
.replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/g, '[REDACTED]');
|
|
2311
|
+
const redact = (value: unknown, depth = 0): unknown => {
|
|
2312
|
+
if (depth >= 8) return '[TRUNCATED]';
|
|
2313
|
+
if (typeof value === 'string') return redactText(value);
|
|
2314
|
+
if (value === null || typeof value === 'number' || typeof value === 'boolean') return value;
|
|
2315
|
+
if (Array.isArray(value)) return value.slice(0, 64).map(entry => redact(entry, depth + 1));
|
|
2316
|
+
if (!isRecord(value)) return String(value).slice(0, 8192);
|
|
2317
|
+
return Object.fromEntries(Object.entries(value).slice(0, 128).map(([key, entry]) => [key, /(?:authorization|cookie|password|secret|token)/i.test(key) ? '[REDACTED]' : redact(entry, depth + 1)]));
|
|
2318
|
+
};
|
|
2319
|
+
const parse = (value: unknown): NativeReport | undefined => {
|
|
2320
|
+
if (!isRecord(value) || !isRecord(value.details) || typeof value.id !== 'string' || !ID.test(value.id) || typeof value.kind !== 'string' || !KINDS.has(value.kind) || typeof value.occurredAt !== 'number' || !Number.isFinite(value.occurredAt) || value.occurredAt <= 0 || value.platform !== 'android' && value.platform !== 'ios') return;
|
|
2321
|
+
const details = redact(value.details);
|
|
2322
|
+
if (!isRecord(details) || new TextEncoder().encode(JSON.stringify(details)).byteLength > 64 * 1024) return;
|
|
2323
|
+
return { details, id: value.id, kind: value.kind, occurredAt: value.occurredAt, platform: value.platform };
|
|
2324
|
+
};
|
|
2325
|
+
const sampled = (id: string, rate: number) => {
|
|
2326
|
+
if (rate >= 1) return true;
|
|
2327
|
+
let hash = 2166136261;
|
|
2328
|
+
for (const character of id) { hash ^= character.codePointAt(0) ?? 0; hash = Math.imul(hash, 16777619); }
|
|
2329
|
+
return (hash >>> 0) / 4294967296 < rate;
|
|
2330
|
+
};
|
|
2331
|
+
let drainPromise: Promise<void> | undefined;
|
|
2332
|
+
let started = false;
|
|
2333
|
+
const drain = () => {
|
|
2334
|
+
drainPromise ??= (async () => {
|
|
2335
|
+
const manifest = ABSOLUTE_MOBILE_MANIFEST;
|
|
2336
|
+
const config = manifest?.observability;
|
|
2337
|
+
if (!manifest || !config || Platform.OS !== 'android' && Platform.OS !== 'ios') return;
|
|
2338
|
+
const reports = (await native.pending()).reports.slice(0, 8).map(parse).filter((report): report is NativeReport => report !== undefined);
|
|
2339
|
+
const discarded = reports.filter(report => !sampled(report.id, config.sampleRate));
|
|
2340
|
+
if (discarded.length) await native.acknowledge({ ids: discarded.map(report => report.id) });
|
|
2341
|
+
const selected = reports.filter(report => sampled(report.id, config.sampleRate));
|
|
2342
|
+
if (!selected.length) return;
|
|
2343
|
+
const response = await fetch(config.endpoint, {
|
|
2344
|
+
body: JSON.stringify({ ...(config.environment ? { environment: config.environment } : {}), events: selected.map(report => ({ at: report.occurredAt, extra: { nativeDiagnostic: report.details, nativeDiagnosticId: report.id }, groupingKey: 'absolute-native:' + report.platform + ':' + report.kind, level: ['app-launch', 'cpu-exception', 'disk-write-exception', 'low-memory', 'resource-exhaustion', 'signal'].includes(report.kind) ? 'warning' : 'error', message: 'Native process diagnostic \u2014 ' + report.kind, name: 'AbsoluteMobileNativeDiagnostic', tags: { absoluteMobile: 'true', mobileAppBuild: manifest.appBuild, mobileEngine: 'expo', mobileFailurePhase: 'native-process', mobileManifestFormat: '1', mobileNativeRuntime: 'expo', mobilePlatform: report.platform, mobileRuntime: manifest.runtime } })), project: config.project, release: manifest.appBuild, v: 1 }),
|
|
2345
|
+
headers: { 'content-type': 'application/json' },
|
|
2346
|
+
method: 'POST'
|
|
2347
|
+
});
|
|
2348
|
+
if (response.ok) await native.acknowledge({ ids: selected.map(report => report.id) });
|
|
2349
|
+
})().catch(() => undefined).finally(() => { drainPromise = undefined; });
|
|
2350
|
+
return drainPromise;
|
|
2351
|
+
};
|
|
2352
|
+
export const startAbsoluteExpoNativeObservability = () => {
|
|
2353
|
+
if (!started) {
|
|
2354
|
+
started = true;
|
|
2355
|
+
AppState.addEventListener('change', state => { if (state === 'active') void drain(); });
|
|
2356
|
+
}
|
|
2357
|
+
return drain();
|
|
2358
|
+
};
|
|
2359
|
+
`;
|
|
2360
|
+
});
|
|
2361
|
+
|
|
1942
2362
|
// src/mobile/expoProject.ts
|
|
1943
2363
|
import {
|
|
1944
2364
|
access,
|
|
@@ -1952,7 +2372,7 @@ import {
|
|
|
1952
2372
|
writeFile
|
|
1953
2373
|
} from "fs/promises";
|
|
1954
2374
|
import { createHash as createHash3 } from "crypto";
|
|
1955
|
-
import { basename as basename2, dirname as dirname4, join as
|
|
2375
|
+
import { basename as basename2, dirname as dirname4, join as join9, relative as relative2, resolve as resolve5, sep } from "path";
|
|
1956
2376
|
var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
|
|
1957
2377
|
`, EXPO_ASSET_EXTENSION = ".absasset", EXPO_PROJECT_MARKER = ".absolutejs-expo-project", exists = async (path) => {
|
|
1958
2378
|
try {
|
|
@@ -2023,7 +2443,7 @@ var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts
|
|
|
2023
2443
|
}
|
|
2024
2444
|
return segment;
|
|
2025
2445
|
});
|
|
2026
|
-
}, routeFile = (project, route) =>
|
|
2446
|
+
}, routeFile = (project, route) => join9(project, "app", ...routeSegments(route), "index.tsx"), packageDependencies = (plan) => Object.fromEntries(plan.requiredPackages.map((spec) => {
|
|
2027
2447
|
const separator = spec.lastIndexOf("@");
|
|
2028
2448
|
return [spec.slice(0, separator), spec.slice(separator + 1)];
|
|
2029
2449
|
})), expoPackage = (auth, sync, devices, updates) => ({
|
|
@@ -2210,16 +2630,19 @@ config.resolver.nodeModulesPaths = [
|
|
|
2210
2630
|
config.watchFolders = [appRoot];
|
|
2211
2631
|
|
|
2212
2632
|
module.exports = config;
|
|
2213
|
-
`, layoutSource = (auth, sync, updates) => `${EXPO_GENERATED_HEADER}import { Stack } from 'expo-router';
|
|
2633
|
+
`, layoutSource = (auth, sync, updates, observability) => `${EXPO_GENERATED_HEADER}import { Stack } from 'expo-router';
|
|
2214
2634
|
import '../src/generated/AbsoluteDevices';
|
|
2215
2635
|
${auth ? `import { useEffect, useState } from 'react';
|
|
2216
2636
|
import { startAbsoluteExpoAuth } from '../src/generated/AbsoluteAuth';` : ""}
|
|
2217
2637
|
${sync ? "import { startAbsoluteExpoSync } from '../src/generated/AbsoluteSync';" : ""}
|
|
2218
2638
|
${updates ? `import { useEffect as useUpdateEffect } from 'react';
|
|
2219
2639
|
import { startAbsoluteExpoUpdates } from '../src/generated/AbsoluteUpdates';` : ""}
|
|
2640
|
+
${observability ? `import { useEffect as useNativeObservabilityEffect } from 'react';
|
|
2641
|
+
import { startAbsoluteExpoNativeObservability } from '../src/generated/AbsoluteNativeObservability';` : ""}
|
|
2220
2642
|
|
|
2221
2643
|
export default function AbsoluteLayout() {
|
|
2222
2644
|
${updates ? "useUpdateEffect(() => { void startAbsoluteExpoUpdates(); }, []);" : ""}
|
|
2645
|
+
${observability ? "useNativeObservabilityEffect(() => { void startAbsoluteExpoNativeObservability(); }, []);" : ""}
|
|
2223
2646
|
${auth ? `const [ready, setReady] = useState(false);
|
|
2224
2647
|
useEffect(() => {
|
|
2225
2648
|
let active = true;
|
|
@@ -3010,8 +3433,19 @@ export default createAbsoluteNativeRoute(ApplicationNativeRoute, ${JSON.stringif
|
|
|
3010
3433
|
await writeFile(temporary, source, { flag: "wx" });
|
|
3011
3434
|
await rename(temporary, path);
|
|
3012
3435
|
return true;
|
|
3436
|
+
}, pruneManagedFiles = async (paths) => {
|
|
3437
|
+
const removed = await Promise.all(paths.map(async (path) => {
|
|
3438
|
+
if (!await exists(path))
|
|
3439
|
+
return false;
|
|
3440
|
+
const source = await readFile(path, "utf8");
|
|
3441
|
+
if (!source.startsWith(EXPO_GENERATED_HEADER) && !path.endsWith("expo-module.config.json"))
|
|
3442
|
+
return false;
|
|
3443
|
+
await rm(path, { force: true });
|
|
3444
|
+
return true;
|
|
3445
|
+
}));
|
|
3446
|
+
return removed.filter(Boolean).length;
|
|
3013
3447
|
}, pruneStaleManagedExpoRoutes = async (project, expected) => {
|
|
3014
|
-
const appDirectory =
|
|
3448
|
+
const appDirectory = join9(project, "app");
|
|
3015
3449
|
if (!await exists(appDirectory))
|
|
3016
3450
|
return 0;
|
|
3017
3451
|
const files = await walkFiles(appDirectory);
|
|
@@ -3050,7 +3484,7 @@ export default createAbsoluteNativeRoute(ApplicationNativeRoute, ${JSON.stringif
|
|
|
3050
3484
|
if (missing) {
|
|
3051
3485
|
throw new TypeError(`Expo native route ${missing.route} references missing module ${missing.module}.`);
|
|
3052
3486
|
}
|
|
3053
|
-
const marker =
|
|
3487
|
+
const marker = join9(project, EXPO_PROJECT_MARKER);
|
|
3054
3488
|
if (await exists(project) && !await exists(marker)) {
|
|
3055
3489
|
const entries = await readdir(project);
|
|
3056
3490
|
if (entries.length > 0 && !options.force) {
|
|
@@ -3063,7 +3497,7 @@ export default createAbsoluteNativeRoute(ApplicationNativeRoute, ${JSON.stringif
|
|
|
3063
3497
|
const authEnabled = Boolean(auth);
|
|
3064
3498
|
const files = new Map([
|
|
3065
3499
|
[
|
|
3066
|
-
|
|
3500
|
+
join9(project, ".gitignore"),
|
|
3067
3501
|
`.expo/
|
|
3068
3502
|
android/
|
|
3069
3503
|
ios/
|
|
@@ -3071,77 +3505,82 @@ node_modules/
|
|
|
3071
3505
|
`
|
|
3072
3506
|
],
|
|
3073
3507
|
[
|
|
3074
|
-
|
|
3508
|
+
join9(project, "app.json"),
|
|
3075
3509
|
jsonSource(expoAppConfig(config, authEnabled, syncEnabled, devices, runtimeFingerprint))
|
|
3076
3510
|
],
|
|
3077
|
-
[
|
|
3511
|
+
[join9(project, "app.config.js"), expoDynamicAppConfig],
|
|
3078
3512
|
[
|
|
3079
|
-
|
|
3513
|
+
join9(project, "package.json"),
|
|
3080
3514
|
jsonSource(expoPackage(authEnabled, syncEnabled, devices, config.updates !== undefined))
|
|
3081
3515
|
],
|
|
3082
|
-
[
|
|
3516
|
+
[join9(project, "metro.config.js"), metroConfig(projectRoot)],
|
|
3083
3517
|
[
|
|
3084
|
-
|
|
3518
|
+
join9(project, "plugins", "withAbsoluteDevelopmentCa.js"),
|
|
3085
3519
|
expoDevelopmentCaPlugin
|
|
3086
3520
|
],
|
|
3087
3521
|
[
|
|
3088
|
-
|
|
3522
|
+
join9(project, "tsconfig.json"),
|
|
3089
3523
|
jsonSource(expoTsConfig(projectRoot, project, authEnabled, syncEnabled))
|
|
3090
3524
|
],
|
|
3091
3525
|
[
|
|
3092
|
-
|
|
3093
|
-
layoutSource(authEnabled, syncEnabled, config.updates !== undefined)
|
|
3526
|
+
join9(project, "app", "_layout.tsx"),
|
|
3527
|
+
layoutSource(authEnabled, syncEnabled, config.updates !== undefined, config.observability !== undefined)
|
|
3094
3528
|
],
|
|
3095
3529
|
[
|
|
3096
|
-
|
|
3530
|
+
join9(project, "app", "__absolute", "native", "index.tsx"),
|
|
3097
3531
|
nativeDiagnosticSource
|
|
3098
3532
|
],
|
|
3099
3533
|
[
|
|
3100
|
-
|
|
3534
|
+
join9(project, "src", "generated", "AbsoluteDevices.ts"),
|
|
3101
3535
|
devicesRuntimeSource(config, devices, authEnabled)
|
|
3102
3536
|
],
|
|
3103
3537
|
[
|
|
3104
|
-
|
|
3538
|
+
join9(project, "src", "generated", "AbsoluteNativeRoute.tsx"),
|
|
3105
3539
|
nativeRouteRuntimeSource(authEnabled)
|
|
3106
3540
|
],
|
|
3107
3541
|
[
|
|
3108
|
-
|
|
3542
|
+
join9(project, "src", "generated", "AbsoluteWebHost.tsx"),
|
|
3109
3543
|
webHostSource(config, auth, syncEnabled)
|
|
3110
3544
|
]
|
|
3111
3545
|
]);
|
|
3546
|
+
if (config.observability) {
|
|
3547
|
+
for (const [path, source] of absoluteExpoNativeObservabilityFiles(project))
|
|
3548
|
+
files.set(path, source);
|
|
3549
|
+
}
|
|
3112
3550
|
if (config.updates) {
|
|
3113
|
-
files.set(
|
|
3551
|
+
files.set(join9(project, "src", "generated", "AbsoluteUpdates.ts"), updatesRuntimeSource(config));
|
|
3114
3552
|
}
|
|
3115
3553
|
const expoCodeSigning = config.updates?.expoCodeSigning;
|
|
3116
3554
|
if (expoCodeSigning)
|
|
3117
|
-
files.set(
|
|
3555
|
+
files.set(join9(project, "certs", "absolute-mobile-update.pem"), expoCodeSigning.certificatePem);
|
|
3118
3556
|
if (auth) {
|
|
3119
|
-
files.set(
|
|
3557
|
+
files.set(join9(project, "src", "generated", "AbsoluteAuth.ts"), authRuntimeSource(auth, config.appId));
|
|
3120
3558
|
}
|
|
3121
3559
|
if (syncSchema) {
|
|
3122
|
-
files.set(
|
|
3560
|
+
files.set(join9(project, "src", "generated", "AbsoluteSync.ts"), syncRuntimeSource(config, syncSchema));
|
|
3123
3561
|
}
|
|
3124
|
-
const webAssetsPath =
|
|
3562
|
+
const webAssetsPath = join9(project, "src", "generated", "webAssets.ts");
|
|
3125
3563
|
if (!await exists(webAssetsPath)) {
|
|
3126
3564
|
files.set(webAssetsPath, emptyWebAssetsSource);
|
|
3127
3565
|
}
|
|
3128
3566
|
if (!config.expoNativeRoutes["/"]) {
|
|
3129
|
-
files.set(
|
|
3567
|
+
files.set(join9(project, "app", "index.tsx"), webRouteSource);
|
|
3130
3568
|
}
|
|
3131
|
-
files.set(
|
|
3132
|
-
const nativeRouteRuntime =
|
|
3569
|
+
files.set(join9(project, "app", "[...absolute].tsx"), catchAllRouteSource);
|
|
3570
|
+
const nativeRouteRuntime = join9(project, "src", "generated", "AbsoluteNativeRoute.tsx");
|
|
3133
3571
|
for (const [route, module] of routeModules) {
|
|
3134
|
-
const wrapper = route === "/" ?
|
|
3572
|
+
const wrapper = route === "/" ? join9(project, "app", "index.tsx") : routeFile(project, route);
|
|
3135
3573
|
files.set(wrapper, nativeWrapperSource(wrapper, module, nativeRouteRuntime, route));
|
|
3136
3574
|
}
|
|
3137
|
-
const
|
|
3575
|
+
const removedRoutes = await pruneStaleManagedExpoRoutes(project, new Set([...files.keys()].filter((path) => path.startsWith(`${join9(project, "app")}${sep}`))));
|
|
3576
|
+
const removedObservability = config.observability ? 0 : await pruneManagedFiles(absoluteExpoNativeObservabilityPaths(project));
|
|
3138
3577
|
const changes = await Promise.all([...files].map(([path, source]) => writeManagedFile(path, source, true)));
|
|
3139
|
-
const changed =
|
|
3578
|
+
const changed = removedRoutes + removedObservability + changes.filter(Boolean).length;
|
|
3140
3579
|
return { changed, path: project, written: [...files.keys()] };
|
|
3141
3580
|
}, walkFiles = async (root, directory = root) => {
|
|
3142
3581
|
const entries = await readdir(directory, { withFileTypes: true });
|
|
3143
3582
|
const nested = await Promise.all(entries.map((entry) => {
|
|
3144
|
-
const path =
|
|
3583
|
+
const path = join9(directory, entry.name);
|
|
3145
3584
|
if (entry.isDirectory())
|
|
3146
3585
|
return walkFiles(root, path);
|
|
3147
3586
|
if (entry.isFile())
|
|
@@ -3204,11 +3643,11 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
3204
3643
|
`, syncAbsoluteExpoWebAssets = async (config) => {
|
|
3205
3644
|
if (config.engine !== "expo")
|
|
3206
3645
|
throw new TypeError("Expo asset sync requires mobile.engine: expo.");
|
|
3207
|
-
const marker =
|
|
3646
|
+
const marker = join9(config.nativeProjectDirectory, EXPO_PROJECT_MARKER);
|
|
3208
3647
|
if (!await exists(marker)) {
|
|
3209
3648
|
throw new TypeError("Expo asset sync requires an AbsoluteJS-managed Expo project. Run mobile init first.");
|
|
3210
3649
|
}
|
|
3211
|
-
const manifestPath =
|
|
3650
|
+
const manifestPath = join9(config.bundleDirectory, "absolute-mobile-manifest.json");
|
|
3212
3651
|
const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
3213
3652
|
const nativeDataManifest = expoNativeDataManifest(manifest);
|
|
3214
3653
|
const { appBuild } = nativeDataManifest;
|
|
@@ -3222,16 +3661,16 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
3222
3661
|
bundleHash.update("\x00");
|
|
3223
3662
|
});
|
|
3224
3663
|
const bundleId = `amexpo_${bundleHash.digest("hex")}`;
|
|
3225
|
-
const destination =
|
|
3664
|
+
const destination = join9(config.nativeProjectDirectory, "assets", "absolute");
|
|
3226
3665
|
await mkdir(dirname4(destination), { recursive: true });
|
|
3227
|
-
const staging = await mkdtemp(
|
|
3666
|
+
const staging = await mkdtemp(join9(dirname4(destination), `.${basename2(destination)}.stage-`));
|
|
3228
3667
|
let assets;
|
|
3229
3668
|
try {
|
|
3230
3669
|
assets = await Promise.all(files.map(async (source, index) => {
|
|
3231
3670
|
const name = `${String(index).padStart(6, "0")}${EXPO_ASSET_EXTENSION}`;
|
|
3232
|
-
await cp(source,
|
|
3671
|
+
await cp(source, join9(staging, name));
|
|
3233
3672
|
return {
|
|
3234
|
-
asset: portableRelative(
|
|
3673
|
+
asset: portableRelative(join9(config.nativeProjectDirectory, "src", "generated"), join9(destination, name)),
|
|
3235
3674
|
path: relative2(config.bundleDirectory, source).replaceAll("\\", "/")
|
|
3236
3675
|
};
|
|
3237
3676
|
}));
|
|
@@ -3240,7 +3679,7 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
3240
3679
|
await rm(staging, { force: true, recursive: true });
|
|
3241
3680
|
throw error;
|
|
3242
3681
|
}
|
|
3243
|
-
const generated =
|
|
3682
|
+
const generated = join9(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
|
|
3244
3683
|
await writeManagedFile(generated, assetModuleSource(assets, bundleId, nativeDataManifest), true);
|
|
3245
3684
|
return { appBuild, assets: assets.length, bundleId, path: destination };
|
|
3246
3685
|
};
|
|
@@ -3249,6 +3688,7 @@ var init_expoProject = __esm(() => {
|
|
|
3249
3688
|
init_syncSchema();
|
|
3250
3689
|
init_deviceCapabilities();
|
|
3251
3690
|
init_updateRuntime();
|
|
3691
|
+
init_expoNativeObservability();
|
|
3252
3692
|
expoDynamicAppConfig = `${EXPO_GENERATED_HEADER}const config = require('./app.json');
|
|
3253
3693
|
|
|
3254
3694
|
if (process.env.ABSOLUTE_EXPO_DEVELOPMENT === '1' && process.env.ABSOLUTE_EXPO_DEVELOPMENT_CA_PATH) {
|
|
@@ -3585,7 +4025,7 @@ var init_utils = __esm(() => {
|
|
|
3585
4025
|
// src/mobile/emulatorDoctor.ts
|
|
3586
4026
|
import { access as access3 } from "fs/promises";
|
|
3587
4027
|
import { homedir as homedir3 } from "os";
|
|
3588
|
-
import { join as
|
|
4028
|
+
import { join as join11 } from "path";
|
|
3589
4029
|
var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command) => {
|
|
3590
4030
|
try {
|
|
3591
4031
|
const result = Bun.spawnSync(command, {
|
|
@@ -3630,15 +4070,15 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
3630
4070
|
}
|
|
3631
4071
|
}, absoluteManagedAndroidSdkRoot = (host2, env = process.env) => {
|
|
3632
4072
|
if (host2 === "windows") {
|
|
3633
|
-
return
|
|
4073
|
+
return join11(env.LOCALAPPDATA ?? join11(homedir3(), "AppData", "Local"), "AbsoluteJS", "Android", "Sdk");
|
|
3634
4074
|
}
|
|
3635
4075
|
if (host2 === "wsl") {
|
|
3636
4076
|
const localAppData = windowsLocalAppDataFromWsl();
|
|
3637
4077
|
if (localAppData) {
|
|
3638
|
-
return
|
|
4078
|
+
return join11(localAppData, "AbsoluteJS", "Android", "Sdk");
|
|
3639
4079
|
}
|
|
3640
4080
|
}
|
|
3641
|
-
return
|
|
4081
|
+
return join11(homedir3(), ".absolutejs", "android-sdk");
|
|
3642
4082
|
}, pathExists = async (path) => {
|
|
3643
4083
|
try {
|
|
3644
4084
|
await access3(path);
|
|
@@ -3691,7 +4131,7 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
3691
4131
|
const capture = input.capture ?? captureCommand;
|
|
3692
4132
|
const androidRoot = input.androidRoot === null ? undefined : input.androidRoot ?? env.ANDROID_HOME ?? env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host2, env);
|
|
3693
4133
|
const windowsAndroidTools = host2 === "windows" || host2 === "wsl";
|
|
3694
|
-
const android = (segments) => androidRoot ?
|
|
4134
|
+
const android = (segments) => androidRoot ? join11(androidRoot, ...segments) : undefined;
|
|
3695
4135
|
const paths = (values) => values.filter((value) => Boolean(value));
|
|
3696
4136
|
const adb = await findExecutable("adb", paths([
|
|
3697
4137
|
android(["platform-tools", windowsAndroidTools ? "adb.exe" : "adb"])
|
|
@@ -3858,7 +4298,7 @@ import { createHash as createHash4, randomUUID as randomUUID2 } from "crypto";
|
|
|
3858
4298
|
import {
|
|
3859
4299
|
dirname as dirname5,
|
|
3860
4300
|
isAbsolute,
|
|
3861
|
-
join as
|
|
4301
|
+
join as join12,
|
|
3862
4302
|
relative as relative4,
|
|
3863
4303
|
resolve as resolve8,
|
|
3864
4304
|
sep as sep2,
|
|
@@ -4031,13 +4471,13 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, ANDROID_CAPTU
|
|
|
4031
4471
|
return;
|
|
4032
4472
|
throw new DOMException("Android development startup was cancelled.", "AbortError");
|
|
4033
4473
|
}, journalPaths = (projectRoot) => {
|
|
4034
|
-
const root =
|
|
4474
|
+
const root = join12(projectRoot, ".absolutejs", "mobile", "dev-session");
|
|
4035
4475
|
return {
|
|
4036
|
-
backup:
|
|
4037
|
-
caBackup:
|
|
4038
|
-
journal:
|
|
4039
|
-
manifestBackup:
|
|
4040
|
-
networkConfigBackup:
|
|
4476
|
+
backup: join12(root, "capacitor.config.backup.json"),
|
|
4477
|
+
caBackup: join12(root, "absolutejs_dev_ca.backup.pem"),
|
|
4478
|
+
journal: join12(root, "journal.json"),
|
|
4479
|
+
manifestBackup: join12(root, "AndroidManifest.backup.xml"),
|
|
4480
|
+
networkConfigBackup: join12(root, "absolutejs_dev_network_security.backup.xml"),
|
|
4041
4481
|
root
|
|
4042
4482
|
};
|
|
4043
4483
|
}, isInside = (root, path) => {
|
|
@@ -4045,7 +4485,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, ANDROID_CAPTU
|
|
|
4045
4485
|
const resolvedPath = resolve8(path);
|
|
4046
4486
|
const relativePath = relative4(resolvedRoot, resolvedPath);
|
|
4047
4487
|
return relativePath === "" || relativePath !== ".." && !relativePath.startsWith(`..${sep2}`) && !isAbsolute(relativePath);
|
|
4048
|
-
}, isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), nativeCachePath = (projectRoot) =>
|
|
4488
|
+
}, isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), nativeCachePath = (projectRoot) => join12(projectRoot, ".absolutejs", "mobile", "cache", "android-debug.json"), parseNativeCache = (value) => {
|
|
4049
4489
|
if (!isRecord2(value))
|
|
4050
4490
|
return null;
|
|
4051
4491
|
const { appId, fingerprint, format, installations } = value;
|
|
@@ -4077,7 +4517,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, ANDROID_CAPTU
|
|
|
4077
4517
|
});
|
|
4078
4518
|
}
|
|
4079
4519
|
}, nativeDependencySources = async (nativeDirectory) => {
|
|
4080
|
-
const settings = await readFile4(
|
|
4520
|
+
const settings = await readFile4(join12(nativeDirectory, "capacitor.settings.gradle"), "utf8");
|
|
4081
4521
|
const pattern = new RegExp(CAPACITOR_PROJECT_DIRECTORY_PATTERN.source, CAPACITOR_PROJECT_DIRECTORY_PATTERN.flags);
|
|
4082
4522
|
const dependencies = [...settings.matchAll(pattern)].map((match) => ({
|
|
4083
4523
|
name: (match[1] ?? "").slice(1).replaceAll(/[^a-zA-Z0-9_.-]/gu, "_"),
|
|
@@ -4117,7 +4557,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, ANDROID_CAPTU
|
|
|
4117
4557
|
}, collectNativeDirectory = async (root, label, directory, ignorePublicBundle) => {
|
|
4118
4558
|
const entries = await readdir2(directory, { withFileTypes: true });
|
|
4119
4559
|
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
4120
|
-
const records = await Promise.all(entries.map((entry) => collectNativePath(root, label,
|
|
4560
|
+
const records = await Promise.all(entries.map((entry) => collectNativePath(root, label, join12(directory, entry.name), entry.isDirectory(), entry.isFile(), entry.isSymbolicLink(), ignorePublicBundle)));
|
|
4121
4561
|
return records.flat();
|
|
4122
4562
|
}, hashNativeTree = async (root, label, ignorePublicBundle) => {
|
|
4123
4563
|
const resolvedRoot = await realpath(root);
|
|
@@ -4246,11 +4686,11 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, ANDROID_CAPTU
|
|
|
4246
4686
|
await mkdir2(paths.root, { recursive: true });
|
|
4247
4687
|
await writeFile3(paths.backup, source, { flag: "wx" });
|
|
4248
4688
|
await writeFile3(paths.manifestBackup, manifestSource, { flag: "wx" });
|
|
4249
|
-
const resourceRoot =
|
|
4250
|
-
const caPath =
|
|
4689
|
+
const resourceRoot = join12(dirname5(nativeManifestPath), "res");
|
|
4690
|
+
const caPath = join12(resourceRoot, "raw", "absolutejs_dev_ca.pem");
|
|
4251
4691
|
const existingNetworkConfig = manifestSource.match(/android:networkSecurityConfig=["']@xml\/([a-z0-9_]+)["']/u)?.[1];
|
|
4252
4692
|
const networkConfigName = existingNetworkConfig ?? "absolutejs_dev_network_security";
|
|
4253
|
-
const networkConfigPath =
|
|
4693
|
+
const networkConfigPath = join12(resourceRoot, "xml", `${networkConfigName}.xml`);
|
|
4254
4694
|
const backupProjectedFile = async ([path, backupPath]) => {
|
|
4255
4695
|
if (!await pathExists2(path))
|
|
4256
4696
|
return { path };
|
|
@@ -4343,7 +4783,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, ANDROID_CAPTU
|
|
|
4343
4783
|
}
|
|
4344
4784
|
return result.stdout.trim();
|
|
4345
4785
|
}, mirroredCapacitorDependencies = async (project, capture) => {
|
|
4346
|
-
const settingsPath =
|
|
4786
|
+
const settingsPath = join12(project.nativeDirectory, "capacitor.settings.gradle");
|
|
4347
4787
|
const settings = await readFile4(settingsPath, "utf8");
|
|
4348
4788
|
const dependencies = [];
|
|
4349
4789
|
const rewrittenSettings = settings.replace(CAPACITOR_PROJECT_DIRECTORY_PATTERN, (_statement, projectName, sourcePath) => {
|
|
@@ -4389,7 +4829,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, ANDROID_CAPTU
|
|
|
4389
4829
|
].join("; ");
|
|
4390
4830
|
return Buffer.from(source, "utf16le").toString("base64");
|
|
4391
4831
|
}, gradleArtifactPath = (nativeDirectory, task, windows = false) => {
|
|
4392
|
-
const pathJoin = windows ? win32.join :
|
|
4832
|
+
const pathJoin = windows ? win32.join : join12;
|
|
4393
4833
|
if (task === "assembleDebug") {
|
|
4394
4834
|
return pathJoin(nativeDirectory, "app", "build", "outputs", "apk", "debug", "app-debug.apk");
|
|
4395
4835
|
}
|
|
@@ -4402,7 +4842,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, ANDROID_CAPTU
|
|
|
4402
4842
|
if (task !== "assembleRelease" || await pathExists2(primary)) {
|
|
4403
4843
|
return primary;
|
|
4404
4844
|
}
|
|
4405
|
-
return
|
|
4845
|
+
return join12(nativeDirectory, "app", "build", "outputs", "apk", "release", "app-release-unsigned.apk");
|
|
4406
4846
|
}, buildAbsoluteAndroidGradleArtifact = async (options) => {
|
|
4407
4847
|
const { project, task } = options;
|
|
4408
4848
|
const capture = options.capture ?? captureCommand2;
|
|
@@ -4630,18 +5070,18 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, ANDROID_CAPTU
|
|
|
4630
5070
|
if (!adb || options.target !== "device" && !emulator) {
|
|
4631
5071
|
throw new Error("Android SDK tools disappeared after readiness checks.");
|
|
4632
5072
|
}
|
|
4633
|
-
const cap =
|
|
5073
|
+
const cap = join12(projectRoot, "node_modules", ".bin", host2 === "windows" ? "cap.cmd" : "cap");
|
|
4634
5074
|
if (!await pathExists2(cap)) {
|
|
4635
5075
|
throw new Error("Capacitor CLI is not installed. Run absolute mobile init first.");
|
|
4636
5076
|
}
|
|
4637
5077
|
await writeAbsoluteCapacitorConfig(config, { projectRoot });
|
|
4638
5078
|
await mkdir2(config.bundleDirectory, { recursive: true });
|
|
4639
|
-
const placeholder =
|
|
5079
|
+
const placeholder = join12(config.bundleDirectory, "index.html");
|
|
4640
5080
|
if (!await pathExists2(placeholder)) {
|
|
4641
5081
|
await writeFile3(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
|
|
4642
5082
|
`);
|
|
4643
5083
|
}
|
|
4644
|
-
const nativeDirectory =
|
|
5084
|
+
const nativeDirectory = join12(config.nativeProjectDirectory, "android");
|
|
4645
5085
|
if (!await pathExists2(nativeDirectory)) {
|
|
4646
5086
|
if (!options.createNativeProject) {
|
|
4647
5087
|
throw new Error("Android native project has not been created.");
|
|
@@ -4702,8 +5142,8 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, ANDROID_CAPTU
|
|
|
4702
5142
|
await requireSuccess([project.cap, "sync", "android"], "Capacitor Android synchronization", run, { cwd: project.projectRoot, env, signal: options.signal });
|
|
4703
5143
|
throwIfAborted(options.signal);
|
|
4704
5144
|
transition("configuring");
|
|
4705
|
-
const nativeConfigPath =
|
|
4706
|
-
const nativeManifestPath =
|
|
5145
|
+
const nativeConfigPath = join12(project.nativeDirectory, "app", "src", "main", "assets", "capacitor.config.json");
|
|
5146
|
+
const nativeManifestPath = join12(project.nativeDirectory, "app", "src", "main", "AndroidManifest.xml");
|
|
4707
5147
|
let connectedSerial;
|
|
4708
5148
|
let nativeLogs = null;
|
|
4709
5149
|
const closeNativeLogs = async () => {
|
|
@@ -4862,7 +5302,7 @@ var init_androidEmulatorController = __esm(() => {
|
|
|
4862
5302
|
import { createHash as createHash5 } from "crypto";
|
|
4863
5303
|
import { cp as cp2, mkdir as mkdir3, mkdtemp as mkdtemp2, readFile as readFile5, rm as rm3 } from "fs/promises";
|
|
4864
5304
|
import { tmpdir } from "os";
|
|
4865
|
-
import { basename as basename3, join as
|
|
5305
|
+
import { basename as basename3, join as join13 } from "path";
|
|
4866
5306
|
var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION = "15859902", LICENSE_ACCEPTANCE_RESPONSES = 100, COMMAND_LINE_TOOLS, defaultRun = async (command, options = {}) => {
|
|
4867
5307
|
const subprocess = Bun.spawn(command, {
|
|
4868
5308
|
env: options.env,
|
|
@@ -4894,7 +5334,7 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
4894
5334
|
exitCode: result.exitCode,
|
|
4895
5335
|
stdout: result.stdout.toString()
|
|
4896
5336
|
};
|
|
4897
|
-
}, commandPath = (root, host2, tool) =>
|
|
5337
|
+
}, commandPath = (root, host2, tool) => join13(root, "cmdline-tools", "latest", "bin", host2 === "windows" || host2 === "wsl" ? `${tool}.bat` : tool), executablePath = (root, host2, directory, tool) => join13(root, directory, host2 === "windows" || host2 === "wsl" ? `${tool}.exe` : tool), windowsPath = (path) => {
|
|
4898
5338
|
const match = /^\/mnt\/([a-z])\/(.*)$/i.exec(path);
|
|
4899
5339
|
if (!match)
|
|
4900
5340
|
return path;
|
|
@@ -4968,10 +5408,10 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
4968
5408
|
if (digest !== release.sha256) {
|
|
4969
5409
|
throw new Error(`Android command-line-tools checksum mismatch: expected ${release.sha256}, received ${digest}.`);
|
|
4970
5410
|
}
|
|
4971
|
-
const temporary = await mkdtemp2(
|
|
5411
|
+
const temporary = await mkdtemp2(join13(tmpdir(), "absolutejs-android-sdk-"));
|
|
4972
5412
|
try {
|
|
4973
|
-
const archive =
|
|
4974
|
-
const extracted =
|
|
5413
|
+
const archive = join13(temporary, "command-line-tools.zip");
|
|
5414
|
+
const extracted = join13(temporary, "extracted");
|
|
4975
5415
|
await Bun.write(archive, bytes);
|
|
4976
5416
|
await mkdir3(extracted, { recursive: true });
|
|
4977
5417
|
const extraction = plan.host === "windows" ? [
|
|
@@ -4988,12 +5428,12 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
4988
5428
|
if (await input.run(extraction) !== 0) {
|
|
4989
5429
|
throw new Error("Failed to extract Android command-line tools.");
|
|
4990
5430
|
}
|
|
4991
|
-
const destination =
|
|
4992
|
-
await mkdir3(
|
|
5431
|
+
const destination = join13(plan.androidRoot, "cmdline-tools", "latest");
|
|
5432
|
+
await mkdir3(join13(plan.androidRoot, "cmdline-tools"), {
|
|
4993
5433
|
recursive: true
|
|
4994
5434
|
});
|
|
4995
5435
|
await rm3(destination, { force: true, recursive: true });
|
|
4996
|
-
await cp2(
|
|
5436
|
+
await cp2(join13(extracted, "cmdline-tools"), destination, {
|
|
4997
5437
|
recursive: true
|
|
4998
5438
|
});
|
|
4999
5439
|
} finally {
|
|
@@ -5178,7 +5618,7 @@ import {
|
|
|
5178
5618
|
stat,
|
|
5179
5619
|
writeFile as writeFile4
|
|
5180
5620
|
} from "fs/promises";
|
|
5181
|
-
import { dirname as dirname6, isAbsolute as isAbsolute2, join as
|
|
5621
|
+
import { dirname as dirname6, isAbsolute as isAbsolute2, join as join14, relative as relative5, resolve as resolve9, sep as sep3 } from "path";
|
|
5182
5622
|
var ABSOLUTE_IOS_RELEASE_FORMAT = 1, developmentTeamArgument = (value) => {
|
|
5183
5623
|
if (value === undefined)
|
|
5184
5624
|
return;
|
|
@@ -5235,7 +5675,7 @@ var ABSOLUTE_IOS_RELEASE_FORMAT = 1, developmentTeamArgument = (value) => {
|
|
|
5235
5675
|
}, ignoredFingerprintDirectories, fingerprintFiles = async (root, current = root, options = {}) => {
|
|
5236
5676
|
const entries = await readdir3(current, { withFileTypes: true });
|
|
5237
5677
|
const nested = await Promise.all(entries.sort((left, right) => left.name.localeCompare(right.name)).map(async (entry) => {
|
|
5238
|
-
const path =
|
|
5678
|
+
const path = join14(current, entry.name);
|
|
5239
5679
|
const projectRelative = relative5(root, path).replaceAll("\\", "/");
|
|
5240
5680
|
const ignored = entry.isDirectory() && (ignoredFingerprintDirectories.has(entry.name) || projectRelative === "App/App/public" && options.includePublicBundle !== true);
|
|
5241
5681
|
if (ignored)
|
|
@@ -5269,7 +5709,7 @@ var ABSOLUTE_IOS_RELEASE_FORMAT = 1, developmentTeamArgument = (value) => {
|
|
|
5269
5709
|
return;
|
|
5270
5710
|
const entries = await readdir3(root, { withFileTypes: true });
|
|
5271
5711
|
const matches = await Promise.all(entries.map(async (entry) => {
|
|
5272
|
-
const path =
|
|
5712
|
+
const path = join14(root, entry.name);
|
|
5273
5713
|
if (entry.isDirectory() && entry.name.endsWith(extension))
|
|
5274
5714
|
return path;
|
|
5275
5715
|
if (entry.isFile() && entry.name.endsWith(extension))
|
|
@@ -5282,7 +5722,7 @@ var ABSOLUTE_IOS_RELEASE_FORMAT = 1, developmentTeamArgument = (value) => {
|
|
|
5282
5722
|
return [];
|
|
5283
5723
|
const entries = await readdir3(root, { withFileTypes: true });
|
|
5284
5724
|
const matches = await Promise.all(entries.map(async (entry) => {
|
|
5285
|
-
const path =
|
|
5725
|
+
const path = join14(root, entry.name);
|
|
5286
5726
|
if (entry.name.endsWith(extension))
|
|
5287
5727
|
return [path];
|
|
5288
5728
|
if (!entry.isDirectory() || options.excludedDirectories?.has(entry.name))
|
|
@@ -5351,10 +5791,10 @@ var ABSOLUTE_IOS_RELEASE_FORMAT = 1, developmentTeamArgument = (value) => {
|
|
|
5351
5791
|
type: value.type
|
|
5352
5792
|
};
|
|
5353
5793
|
}, installRelease = async (artifactPath, metadata, outputRoot) => {
|
|
5354
|
-
const releaseRoot =
|
|
5355
|
-
const destination =
|
|
5794
|
+
const releaseRoot = join14(outputRoot, metadata.releaseId);
|
|
5795
|
+
const destination = join14(releaseRoot, "App.ipa");
|
|
5356
5796
|
if (await pathExists3(releaseRoot)) {
|
|
5357
|
-
const value = JSON.parse(await readFile6(
|
|
5797
|
+
const value = JSON.parse(await readFile6(join14(releaseRoot, "release.json"), "utf8"));
|
|
5358
5798
|
if (!isRecord3(value) || value.artifact !== "App.ipa" || Object.entries(metadata).some(([key, expected]) => Reflect.get(value, key) !== expected)) {
|
|
5359
5799
|
throw new TypeError(`Immutable iOS release ${metadata.releaseId} does not match its content.`);
|
|
5360
5800
|
}
|
|
@@ -5374,14 +5814,14 @@ var ABSOLUTE_IOS_RELEASE_FORMAT = 1, developmentTeamArgument = (value) => {
|
|
|
5374
5814
|
};
|
|
5375
5815
|
}
|
|
5376
5816
|
await mkdir4(dirname6(releaseRoot), { recursive: true });
|
|
5377
|
-
const staging = await mkdtemp3(
|
|
5817
|
+
const staging = await mkdtemp3(join14(dirname6(releaseRoot), ".ios-stage-"));
|
|
5378
5818
|
try {
|
|
5379
|
-
await copyFile2(artifactPath,
|
|
5819
|
+
await copyFile2(artifactPath, join14(staging, "App.ipa"));
|
|
5380
5820
|
const complete = {
|
|
5381
5821
|
...metadata,
|
|
5382
5822
|
artifact: "App.ipa"
|
|
5383
5823
|
};
|
|
5384
|
-
await writeFile4(
|
|
5824
|
+
await writeFile4(join14(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
|
|
5385
5825
|
`, { flag: "wx" });
|
|
5386
5826
|
await rename4(staging, releaseRoot);
|
|
5387
5827
|
return { artifactPath: destination, metadata: complete, releaseRoot };
|
|
@@ -5398,10 +5838,10 @@ var ABSOLUTE_IOS_RELEASE_FORMAT = 1, developmentTeamArgument = (value) => {
|
|
|
5398
5838
|
const marketingVersion = options.config.iosVersion;
|
|
5399
5839
|
if (!marketingVersion)
|
|
5400
5840
|
throw new TypeError("iOS release builds require mobile.ios.version in absolutejs.config.ts.");
|
|
5401
|
-
const manifest = requireManifest(JSON.parse(await readFile6(
|
|
5841
|
+
const manifest = requireManifest(JSON.parse(await readFile6(join14(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
|
|
5402
5842
|
if (manifest.appId !== options.config.appId)
|
|
5403
5843
|
throw new TypeError("Embedded mobile manifest appId does not match mobile.appId.");
|
|
5404
|
-
const nativeDirectory =
|
|
5844
|
+
const nativeDirectory = join14(options.config.nativeProjectDirectory, "ios");
|
|
5405
5845
|
const xcode = await resolveAbsoluteIosXcodeProject(nativeDirectory, {
|
|
5406
5846
|
scheme: options.scheme,
|
|
5407
5847
|
workspacePath: options.workspacePath
|
|
@@ -5414,10 +5854,10 @@ var ABSOLUTE_IOS_RELEASE_FORMAT = 1, developmentTeamArgument = (value) => {
|
|
|
5414
5854
|
}
|
|
5415
5855
|
const stagingParent = resolve9(options.projectRoot, ".absolutejs/mobile");
|
|
5416
5856
|
await mkdir4(stagingParent, { recursive: true });
|
|
5417
|
-
const staging = await mkdtemp3(
|
|
5418
|
-
const archivePath =
|
|
5419
|
-
const exportPath =
|
|
5420
|
-
const exportPlist =
|
|
5857
|
+
const staging = await mkdtemp3(join14(stagingParent, ".ios-build-"));
|
|
5858
|
+
const archivePath = join14(staging, "App.xcarchive");
|
|
5859
|
+
const exportPath = join14(staging, "export");
|
|
5860
|
+
const exportPlist = join14(staging, "ExportOptions.plist");
|
|
5421
5861
|
await mkdir4(exportPath, { recursive: true });
|
|
5422
5862
|
await writeFile4(exportPlist, exportOptions());
|
|
5423
5863
|
const run = options.run ?? defaultRun2;
|
|
@@ -5445,7 +5885,7 @@ var ABSOLUTE_IOS_RELEASE_FORMAT = 1, developmentTeamArgument = (value) => {
|
|
|
5445
5885
|
], { cwd: nativeDirectory, env: options.env });
|
|
5446
5886
|
if (archiveExit !== 0)
|
|
5447
5887
|
throw new TypeError("Xcode failed to archive the iOS app.");
|
|
5448
|
-
const archivedApp = await findByExtension(
|
|
5888
|
+
const archivedApp = await findByExtension(join14(archivePath, "Products", "Applications"), ".app");
|
|
5449
5889
|
const capture = options.capture ?? defaultCapture2;
|
|
5450
5890
|
const signed = archivedApp ? capture([
|
|
5451
5891
|
"codesign",
|
|
@@ -5529,7 +5969,7 @@ import {
|
|
|
5529
5969
|
writeFile as writeFile5
|
|
5530
5970
|
} from "fs/promises";
|
|
5531
5971
|
import { isIP as isIP2 } from "net";
|
|
5532
|
-
import { dirname as dirname7, isAbsolute as isAbsolute3, join as
|
|
5972
|
+
import { dirname as dirname7, isAbsolute as isAbsolute3, join as join15, relative as relative6, resolve as resolve10, sep as sep4 } from "path";
|
|
5533
5973
|
var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000, BOOT_POLL_MS = 1000, DEV_JOURNAL_FORMAT2 = 1, NATIVE_CACHE_FORMAT2 = 1, isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), pathExists4 = async (path) => {
|
|
5534
5974
|
try {
|
|
5535
5975
|
await access7(path);
|
|
@@ -5747,14 +6187,14 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
5747
6187
|
const leftPro = left.name.includes("Pro") ? 1 : 0;
|
|
5748
6188
|
return rightPro - leftPro;
|
|
5749
6189
|
})[0], journalPaths2 = (projectRoot) => {
|
|
5750
|
-
const root =
|
|
6190
|
+
const root = join15(projectRoot, ".absolutejs", "mobile", "ios-dev-session");
|
|
5751
6191
|
return {
|
|
5752
|
-
configBackup:
|
|
5753
|
-
infoBackup:
|
|
5754
|
-
journal:
|
|
6192
|
+
configBackup: join15(root, "capacitor-config.backup"),
|
|
6193
|
+
infoBackup: join15(root, "Info.plist.backup"),
|
|
6194
|
+
journal: join15(root, "journal.json"),
|
|
5755
6195
|
root
|
|
5756
6196
|
};
|
|
5757
|
-
}, nativeCachePath2 = (projectRoot) =>
|
|
6197
|
+
}, nativeCachePath2 = (projectRoot) => join15(projectRoot, ".absolutejs", "mobile", "ios-native-cache.json"), isInside2 = (root, path) => {
|
|
5758
6198
|
const value = relative6(resolve10(root), resolve10(path));
|
|
5759
6199
|
return value === "" || !value.startsWith(`..${sep4}`) && value !== ".." && !isAbsolute3(value);
|
|
5760
6200
|
}, parseJournal2 = (value) => {
|
|
@@ -5811,8 +6251,8 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
5811
6251
|
}, writeDevProjection = async (project, port, https, serverHost = "localhost") => {
|
|
5812
6252
|
const paths = journalPaths2(project.projectRoot);
|
|
5813
6253
|
await repairAbsoluteIosDevSession(project.projectRoot);
|
|
5814
|
-
const nativeConfigPath =
|
|
5815
|
-
const infoPath =
|
|
6254
|
+
const nativeConfigPath = join15(project.nativeDirectory, "App", "App", "capacitor.config.json");
|
|
6255
|
+
const infoPath = join15(project.nativeDirectory, "App", "App", "Info.plist");
|
|
5816
6256
|
const [configSource, infoSource] = await Promise.all([
|
|
5817
6257
|
readFile7(nativeConfigPath, "utf8"),
|
|
5818
6258
|
readFile7(infoPath, "utf8")
|
|
@@ -5973,12 +6413,12 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
5973
6413
|
]);
|
|
5974
6414
|
return result.exitCode === 0 && result.stdout.includes(project.config.appId);
|
|
5975
6415
|
}, buildIosDebugApp = async (project, udid, fingerprint, run, signal) => {
|
|
5976
|
-
const derivedDataPath =
|
|
6416
|
+
const derivedDataPath = join15(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash7("sha256").update(project.config.appId).digest("hex").slice(0, 16));
|
|
5977
6417
|
await mkdir5(derivedDataPath, { recursive: true });
|
|
5978
6418
|
await requireSuccess2([
|
|
5979
6419
|
project.xcodebuild,
|
|
5980
6420
|
"-workspace",
|
|
5981
|
-
|
|
6421
|
+
join15(project.nativeDirectory, "App", "App.xcworkspace"),
|
|
5982
6422
|
"-scheme",
|
|
5983
6423
|
"App",
|
|
5984
6424
|
"-configuration",
|
|
@@ -5989,17 +6429,17 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
5989
6429
|
derivedDataPath,
|
|
5990
6430
|
"build"
|
|
5991
6431
|
], "iOS simulator build", run, { cwd: project.nativeDirectory, signal });
|
|
5992
|
-
const appPath =
|
|
6432
|
+
const appPath = join15(derivedDataPath, "Build", "Products", "Debug-iphonesimulator", "App.app");
|
|
5993
6433
|
if (!await pathExists4(appPath))
|
|
5994
6434
|
throw new Error(`Xcode did not produce the simulator app at ${appPath}.`);
|
|
5995
6435
|
return appPath;
|
|
5996
6436
|
}, buildPhysicalIosDebugApp = async (project, identifier, run, signal) => {
|
|
5997
|
-
const derivedDataPath =
|
|
6437
|
+
const derivedDataPath = join15(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash7("sha256").update(project.config.appId).digest("hex").slice(0, 16));
|
|
5998
6438
|
await mkdir5(derivedDataPath, { recursive: true });
|
|
5999
6439
|
await requireSuccess2([
|
|
6000
6440
|
project.xcodebuild,
|
|
6001
6441
|
"-workspace",
|
|
6002
|
-
|
|
6442
|
+
join15(project.nativeDirectory, "App", "App.xcworkspace"),
|
|
6003
6443
|
"-scheme",
|
|
6004
6444
|
"App",
|
|
6005
6445
|
"-configuration",
|
|
@@ -6011,7 +6451,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
6011
6451
|
"-allowProvisioningUpdates",
|
|
6012
6452
|
"build"
|
|
6013
6453
|
], "iOS physical-device build (configure automatic signing and a Development Team in Xcode if this is the first run)", run, { cwd: project.nativeDirectory, signal });
|
|
6014
|
-
const appPath =
|
|
6454
|
+
const appPath = join15(derivedDataPath, "Build", "Products", "Debug-iphoneos", "App.app");
|
|
6015
6455
|
if (!await pathExists4(appPath))
|
|
6016
6456
|
throw new Error(`Xcode did not produce the physical-device app at ${appPath}.`);
|
|
6017
6457
|
return appPath;
|
|
@@ -6131,16 +6571,16 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
6131
6571
|
const xcodebuild = checks.find((check) => check.id === "ios.xcodebuild")?.path;
|
|
6132
6572
|
if (!xcrun || !xcodebuild)
|
|
6133
6573
|
throw new Error("Xcode tools disappeared after readiness checks.");
|
|
6134
|
-
const cap =
|
|
6574
|
+
const cap = join15(projectRoot, "node_modules", ".bin", "cap");
|
|
6135
6575
|
if (!await pathExists4(cap))
|
|
6136
6576
|
throw new Error("Capacitor CLI is not installed. Run absolute mobile init first.");
|
|
6137
6577
|
await writeAbsoluteCapacitorConfig(config, { projectRoot });
|
|
6138
6578
|
await mkdir5(config.bundleDirectory, { recursive: true });
|
|
6139
|
-
const placeholder =
|
|
6579
|
+
const placeholder = join15(config.bundleDirectory, "index.html");
|
|
6140
6580
|
if (!await pathExists4(placeholder))
|
|
6141
6581
|
await writeFile5(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
|
|
6142
6582
|
`);
|
|
6143
|
-
const nativeDirectory =
|
|
6583
|
+
const nativeDirectory = join15(config.nativeProjectDirectory, "ios");
|
|
6144
6584
|
if (!await pathExists4(nativeDirectory)) {
|
|
6145
6585
|
if (!options.createNativeProject)
|
|
6146
6586
|
throw new Error("iOS native project has not been created.");
|
|
@@ -6437,13 +6877,13 @@ import { isIP as isIP3 } from "net";
|
|
|
6437
6877
|
import {
|
|
6438
6878
|
dirname as dirname8,
|
|
6439
6879
|
isAbsolute as isAbsolute4,
|
|
6440
|
-
join as
|
|
6880
|
+
join as join16,
|
|
6441
6881
|
posix,
|
|
6442
6882
|
relative as relative7,
|
|
6443
6883
|
resolve as resolvePath,
|
|
6444
6884
|
sep as sep5
|
|
6445
6885
|
} from "path";
|
|
6446
|
-
var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TIMEOUT_MS = 2000, REMOTE_RELEASE_LEASE_HEARTBEAT_MS = 15000, REMOTE_RELEASE_LEASE_STALE_SECONDS = 120, PROFILE_NAME, SSH_DESTINATION, defaultProfilePath = () =>
|
|
6886
|
+
var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TIMEOUT_MS = 2000, REMOTE_RELEASE_LEASE_HEARTBEAT_MS = 15000, REMOTE_RELEASE_LEASE_STALE_SECONDS = 120, PROFILE_NAME, SSH_DESTINATION, defaultProfilePath = () => join16(homedir4(), ".absolutejs", "mobile", "remote-macs.json"), emptyStore = () => ({
|
|
6447
6887
|
format: PROFILE_FORMAT,
|
|
6448
6888
|
profiles: {}
|
|
6449
6889
|
}), loadStore = async (path = defaultProfilePath()) => {
|
|
@@ -6619,9 +7059,9 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
6619
7059
|
throw new TypeError("Remote Expo execution requires mobile.engine: expo.");
|
|
6620
7060
|
return createAbsoluteRemoteIosDevProject(config, projectRoot, profile);
|
|
6621
7061
|
}, createAbsoluteRemoteIosDevProject = (config, projectRoot, profile) => ({
|
|
6622
|
-
cap:
|
|
7062
|
+
cap: join16(resolvePath(projectRoot), "node_modules", ".bin", "cap"),
|
|
6623
7063
|
config,
|
|
6624
|
-
nativeDirectory:
|
|
7064
|
+
nativeDirectory: join16(config.nativeProjectDirectory, "ios"),
|
|
6625
7065
|
profile,
|
|
6626
7066
|
projectRoot: resolvePath(projectRoot),
|
|
6627
7067
|
remote: true,
|
|
@@ -6772,8 +7212,8 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
6772
7212
|
return { ...artifact, remotePath, uploaded: true };
|
|
6773
7213
|
}, materializeAbsoluteRemoteMacAgent = async (projectRoot) => {
|
|
6774
7214
|
const shippedCandidates = [
|
|
6775
|
-
|
|
6776
|
-
|
|
7215
|
+
join16(import.meta.dir, "remoteMacAgentEntry.js"),
|
|
7216
|
+
join16(import.meta.dir, "..", "mobile", "remoteMacAgentEntry.js")
|
|
6777
7217
|
];
|
|
6778
7218
|
let path;
|
|
6779
7219
|
for (const candidate of shippedCandidates) {
|
|
@@ -6784,13 +7224,13 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
6784
7224
|
}
|
|
6785
7225
|
if (!path) {
|
|
6786
7226
|
const sourceCandidates = [
|
|
6787
|
-
|
|
6788
|
-
|
|
7227
|
+
join16(import.meta.dir, "remoteMacAgentEntry.ts"),
|
|
7228
|
+
join16(import.meta.dir, "..", "..", "src", "mobile", "remoteMacAgentEntry.ts")
|
|
6789
7229
|
];
|
|
6790
7230
|
const source = await sourceCandidates.reduce(async (found, candidate) => await found ?? (await Bun.file(candidate).exists() ? candidate : undefined), Promise.resolve(undefined));
|
|
6791
7231
|
if (!source)
|
|
6792
7232
|
throw new Error("The AbsoluteJS installation does not contain its remote Mac agent artifact.");
|
|
6793
|
-
const outdir =
|
|
7233
|
+
const outdir = join16(resolvePath(projectRoot), ".absolutejs", "mobile", "remote-agent");
|
|
6794
7234
|
await mkdir6(outdir, { recursive: true });
|
|
6795
7235
|
const result = await Bun.build({
|
|
6796
7236
|
entrypoints: [source],
|
|
@@ -6800,7 +7240,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
6800
7240
|
});
|
|
6801
7241
|
if (!result.success)
|
|
6802
7242
|
throw new AggregateError(result.logs, "Failed to build the AbsoluteJS remote Mac agent.");
|
|
6803
|
-
path =
|
|
7243
|
+
path = join16(outdir, "remoteMacAgentEntry.js");
|
|
6804
7244
|
}
|
|
6805
7245
|
const bytes = await Bun.file(path).arrayBuffer();
|
|
6806
7246
|
const sha256 = createHash8("sha256").update(new Uint8Array(bytes)).digest("hex");
|
|
@@ -6978,9 +7418,9 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
6978
7418
|
}
|
|
6979
7419
|
}, retrieveAbsoluteRemoteIosRelease = async (project, metadata, outputDirectory) => {
|
|
6980
7420
|
const releaseRoot = posix.join(project.remoteProjectRoot, ".absolutejs", "mobile", "releases", "ios", metadata.releaseId);
|
|
6981
|
-
const stagingParent =
|
|
7421
|
+
const stagingParent = join16(project.projectRoot, ".absolutejs", "mobile");
|
|
6982
7422
|
await mkdir6(stagingParent, { recursive: true });
|
|
6983
|
-
const staging = await mkdtemp4(
|
|
7423
|
+
const staging = await mkdtemp4(join16(stagingParent, ".remote-ios-"));
|
|
6984
7424
|
try {
|
|
6985
7425
|
const remoteMetadata = requireRemoteSuccess(await defaultTransport.capture([
|
|
6986
7426
|
...absoluteRemoteMacSshBase(project.profile),
|
|
@@ -6990,7 +7430,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
6990
7430
|
const downloadedMetadata = JSON.parse(remoteMetadata);
|
|
6991
7431
|
if (JSON.stringify(requireAbsoluteIosReleaseMetadata(downloadedMetadata)) !== JSON.stringify(metadata))
|
|
6992
7432
|
throw new TypeError("Remote iOS release metadata changed during retrieval.");
|
|
6993
|
-
const artifactPath =
|
|
7433
|
+
const artifactPath = join16(staging, "App.ipa");
|
|
6994
7434
|
const download = Bun.spawn([
|
|
6995
7435
|
...absoluteRemoteMacSshBase(project.profile),
|
|
6996
7436
|
"/bin/sh -lc",
|
|
@@ -7528,7 +7968,7 @@ import {
|
|
|
7528
7968
|
import { X509Certificate as X509Certificate3 } from "crypto";
|
|
7529
7969
|
import { isIP as isIP4 } from "net";
|
|
7530
7970
|
import { platform as platform2 } from "os";
|
|
7531
|
-
import { join as
|
|
7971
|
+
import { join as join17 } from "path";
|
|
7532
7972
|
var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE_HOSTS, CERTIFICATE_HOSTNAME_PATTERN, devLog = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[36m[dev]\x1B[0m ${msg}`), devWarn = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[33m[dev]\x1B[0m \x1B[33m${msg}\x1B[0m`), certFilesExist = () => existsSync5(CERT_PATH) && existsSync5(KEY_PATH), normalizeDevCertificateHosts = (hosts = []) => {
|
|
7533
7973
|
const normalized = new Set(DEFAULT_CERTIFICATE_HOSTS);
|
|
7534
7974
|
for (const host2 of hosts) {
|
|
@@ -7741,7 +8181,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
7741
8181
|
}
|
|
7742
8182
|
}, mkcertCaRoot = () => runCapture(["mkcert", "-CAROOT"]), getDevCertificateAuthorityPath = () => {
|
|
7743
8183
|
const caRoot = hasMkcert() ? mkcertCaRoot() : null;
|
|
7744
|
-
const rootCertificate = caRoot ?
|
|
8184
|
+
const rootCertificate = caRoot ? join17(caRoot, "rootCA.pem") : null;
|
|
7745
8185
|
if (rootCertificate && existsSync5(rootCertificate))
|
|
7746
8186
|
return rootCertificate;
|
|
7747
8187
|
if (certFilesExist())
|
|
@@ -7756,13 +8196,13 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
7756
8196
|
const caRoot = mkcertCaRoot();
|
|
7757
8197
|
if (!caRoot)
|
|
7758
8198
|
return false;
|
|
7759
|
-
const rootCa =
|
|
8199
|
+
const rootCa = join17(caRoot, "rootCA.pem");
|
|
7760
8200
|
if (!existsSync5(rootCa))
|
|
7761
8201
|
return false;
|
|
7762
8202
|
const winTemp = windowsTempDir();
|
|
7763
8203
|
if (!winTemp)
|
|
7764
8204
|
return false;
|
|
7765
|
-
const staged =
|
|
8205
|
+
const staged = join17(winTemp, "absolutejs-mkcert-rootCA.crt");
|
|
7766
8206
|
try {
|
|
7767
8207
|
copyFileSync(rootCa, staged);
|
|
7768
8208
|
} catch {
|
|
@@ -7798,7 +8238,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
7798
8238
|
devLog("Trusted the local CA in the Windows store \u2014 Chrome/Edge on Windows now accept dev HTTPS");
|
|
7799
8239
|
} else {
|
|
7800
8240
|
const caRoot = mkcertCaRoot();
|
|
7801
|
-
const hint = caRoot ? toWindowsPath(
|
|
8241
|
+
const hint = caRoot ? toWindowsPath(join17(caRoot, "rootCA.pem")) : null;
|
|
7802
8242
|
devWarn("Could not auto-trust the local CA on Windows; Windows browsers may warn.");
|
|
7803
8243
|
if (hint) {
|
|
7804
8244
|
console.log(` Run in PowerShell: Import-Certificate -FilePath "${hint}" -CertStoreLocation Cert:\\CurrentUser\\Root`);
|
|
@@ -7814,9 +8254,9 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
7814
8254
|
return true;
|
|
7815
8255
|
};
|
|
7816
8256
|
var init_devCert = __esm(() => {
|
|
7817
|
-
CERT_DIR =
|
|
7818
|
-
CERT_PATH =
|
|
7819
|
-
KEY_PATH =
|
|
8257
|
+
CERT_DIR = join17(process.cwd(), ".absolutejs");
|
|
8258
|
+
CERT_PATH = join17(CERT_DIR, "cert.pem");
|
|
8259
|
+
KEY_PATH = join17(CERT_DIR, "key.pem");
|
|
7820
8260
|
DEFAULT_CERTIFICATE_HOSTS = ["localhost", "127.0.0.1", "::1"];
|
|
7821
8261
|
CERTIFICATE_HOSTNAME_PATTERN = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/u;
|
|
7822
8262
|
});
|
|
@@ -8521,7 +8961,7 @@ var isRecord5 = (value) => typeof value === "object" && value !== null, getIslan
|
|
|
8521
8961
|
var init_islands = () => {};
|
|
8522
8962
|
|
|
8523
8963
|
// src/build/islandEntries.ts
|
|
8524
|
-
import { dirname as dirname10, extname as extname2, join as
|
|
8964
|
+
import { dirname as dirname10, extname as extname2, join as join20, relative as relative10, resolve as resolve14 } from "path";
|
|
8525
8965
|
import ts2 from "typescript";
|
|
8526
8966
|
var frameworks, isRecord6 = (value) => typeof value === "object" && value !== null, resolveRegistryExport = (mod) => {
|
|
8527
8967
|
if (isRecord6(mod.islandRegistry))
|
|
@@ -9224,7 +9664,7 @@ var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-
|
|
|
9224
9664
|
// src/mobile/buildRelease.ts
|
|
9225
9665
|
import { createHash as createHash11 } from "crypto";
|
|
9226
9666
|
import { mkdir as mkdir8, readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
|
|
9227
|
-
import { basename as basename7, dirname as dirname11, extname as extname4, join as
|
|
9667
|
+
import { basename as basename7, dirname as dirname11, extname as extname4, join as join21, relative as relative11, resolve as resolve15 } from "path";
|
|
9228
9668
|
var sha256 = (bytes) => createHash11("sha256").update(bytes).digest("hex"), STATIC_SCRIPT_PATTERN, rewriteStaticScriptPaths = (source, manifest) => source.replace(STATIC_SCRIPT_PATTERN, (match, prefix, path, suffix) => {
|
|
9229
9669
|
if (path.endsWith("/htmx.min.js"))
|
|
9230
9670
|
return match;
|
|
@@ -9237,7 +9677,7 @@ var sha256 = (bytes) => createHash11("sha256").update(bytes).digest("hex"), STAT
|
|
|
9237
9677
|
if (resolvedAsset.startsWith(`${resolvedBuildDirectory}/`)) {
|
|
9238
9678
|
return resolvedAsset;
|
|
9239
9679
|
}
|
|
9240
|
-
return
|
|
9680
|
+
return join21(buildDirectory, assetPath.replace(/^\/+/, ""));
|
|
9241
9681
|
}, pageFor = async (metadata, manifest, buildDirectory) => {
|
|
9242
9682
|
const assetPath = manifest[metadata.bundleKey];
|
|
9243
9683
|
if (!assetPath) {
|
|
@@ -9248,7 +9688,7 @@ var sha256 = (bytes) => createHash11("sha256").update(bytes).digest("hex"), STAT
|
|
|
9248
9688
|
const source = await readFile9(resolvedAssetPath, "utf8");
|
|
9249
9689
|
const rewritten = rewriteStaticScriptPaths(source, manifest);
|
|
9250
9690
|
const documentHash = sha256(new TextEncoder().encode(rewritten));
|
|
9251
|
-
resolvedAssetPath =
|
|
9691
|
+
resolvedAssetPath = join21(buildDirectory, ".absolutejs", "mobile-pages", `${documentHash}.html`);
|
|
9252
9692
|
await mkdir8(dirname11(resolvedAssetPath), { recursive: true });
|
|
9253
9693
|
await writeFile7(resolvedAssetPath, rewritten);
|
|
9254
9694
|
}
|
|
@@ -9465,44 +9905,44 @@ import {
|
|
|
9465
9905
|
writeFile as writeFile8
|
|
9466
9906
|
} from "fs/promises";
|
|
9467
9907
|
import { existsSync as existsSync10 } from "fs";
|
|
9468
|
-
import { basename as basename8, dirname as dirname12, extname as extname5, join as
|
|
9908
|
+
import { basename as basename8, dirname as dirname12, extname as extname5, join as join22, relative as relative12, resolve as resolve16 } from "path";
|
|
9469
9909
|
var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-mobile-bootstrap.js", INDEX_FILE = "index.html", CLIENT_CSS_DEPENDENCY_PATTERN, CLIENT_MARKUP_DEPENDENCY_PATTERN, CAPACITOR_CLIENT_FRAMEWORKS, CLIENT_ASSET_DIRECTORIES, errorHasCode = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code, shellBootstrapModule = () => {
|
|
9470
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
9910
|
+
const candidate = ["js", "ts"].map((extension) => join22(import.meta.dir, `shellBootstrap.${extension}`)).find(existsSync10);
|
|
9471
9911
|
if (candidate)
|
|
9472
9912
|
return candidate;
|
|
9473
9913
|
throw new TypeError("AbsoluteJS mobile shell bootstrap module is missing.");
|
|
9474
9914
|
}, shellAuthModule = () => {
|
|
9475
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
9915
|
+
const candidate = ["js", "ts"].map((extension) => join22(import.meta.dir, `shellAuth.${extension}`)).find(existsSync10);
|
|
9476
9916
|
if (candidate)
|
|
9477
9917
|
return candidate;
|
|
9478
9918
|
throw new TypeError("AbsoluteJS mobile auth shell module is missing.");
|
|
9479
9919
|
}, shellExpoAuthModule = () => {
|
|
9480
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
9920
|
+
const candidate = ["js", "ts"].map((extension) => join22(import.meta.dir, `shellExpoAuth.${extension}`)).find(existsSync10);
|
|
9481
9921
|
if (candidate)
|
|
9482
9922
|
return candidate;
|
|
9483
9923
|
throw new TypeError("AbsoluteJS Expo auth bridge module is missing.");
|
|
9484
9924
|
}, shellSyncModule = () => {
|
|
9485
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
9925
|
+
const candidate = ["js", "ts"].map((extension) => join22(import.meta.dir, `shellSync.${extension}`)).find(existsSync10);
|
|
9486
9926
|
if (candidate)
|
|
9487
9927
|
return candidate;
|
|
9488
9928
|
throw new TypeError("AbsoluteJS mobile Sync shell module is missing.");
|
|
9489
9929
|
}, shellExpoSyncModule = () => {
|
|
9490
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
9930
|
+
const candidate = ["js", "ts"].map((extension) => join22(import.meta.dir, `shellExpoSync.${extension}`)).find(existsSync10);
|
|
9491
9931
|
if (candidate)
|
|
9492
9932
|
return candidate;
|
|
9493
9933
|
throw new TypeError("AbsoluteJS Expo Sync bridge module is missing.");
|
|
9494
9934
|
}, shellPushModule = () => {
|
|
9495
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
9935
|
+
const candidate = ["js", "ts"].map((extension) => join22(import.meta.dir, `shellPush.${extension}`)).find(existsSync10);
|
|
9496
9936
|
if (candidate)
|
|
9497
9937
|
return candidate;
|
|
9498
9938
|
throw new TypeError("AbsoluteJS mobile push shell module is missing.");
|
|
9499
9939
|
}, shellExpoDevicesModule = () => {
|
|
9500
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
9940
|
+
const candidate = ["js", "ts"].map((extension) => join22(import.meta.dir, `shellExpoDevices.${extension}`)).find(existsSync10);
|
|
9501
9941
|
if (candidate)
|
|
9502
9942
|
return candidate;
|
|
9503
9943
|
throw new TypeError("AbsoluteJS Expo device bridge module is missing.");
|
|
9504
9944
|
}, shellUpdateModule = () => {
|
|
9505
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
9945
|
+
const candidate = ["js", "ts"].map((extension) => join22(import.meta.dir, `shellUpdate.${extension}`)).find(existsSync10);
|
|
9506
9946
|
if (candidate)
|
|
9507
9947
|
return candidate;
|
|
9508
9948
|
throw new TypeError("AbsoluteJS mobile update shell module is missing.");
|
|
@@ -9549,8 +9989,8 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
|
|
|
9549
9989
|
const segments = specifier.split("/");
|
|
9550
9990
|
const packageName = specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0] ?? "";
|
|
9551
9991
|
const subpath = specifier.slice(packageName.length);
|
|
9552
|
-
const packageDirectory =
|
|
9553
|
-
const manifest = JSON.parse(await readFile10(
|
|
9992
|
+
const packageDirectory = join22(resolve16(projectRoot), "node_modules", packageName);
|
|
9993
|
+
const manifest = JSON.parse(await readFile10(join22(packageDirectory, "package.json"), "utf8"));
|
|
9554
9994
|
const exports = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "exports") : undefined;
|
|
9555
9995
|
const entry = typeof exports === "object" && exports !== null ? Reflect.get(exports, subpath ? `.${subpath}` : ".") : undefined;
|
|
9556
9996
|
const target = importEntryTarget(entry);
|
|
@@ -9587,7 +10027,7 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
|
|
|
9587
10027
|
const absoluteMobilePushCapability = absoluteDeviceCapability${pushIndex}(absoluteMobilePush.capabilityOptions);
|
|
9588
10028
|
` : "";
|
|
9589
10029
|
const capabilityOptions = shellCapabilities.map((name, index) => `${JSON.stringify(name)}: ${name === "pushNotifications" ? "absoluteMobilePushCapability" : `absoluteDeviceCapability${index}()`}`).join(", ");
|
|
9590
|
-
const entryPath =
|
|
10030
|
+
const entryPath = join22(staging, ".absolute-mobile-entry.ts");
|
|
9591
10031
|
const baseAdapterModule = capacitor ? await resolveProjectImport(projectRoot, "@absolutejs/devices-capacitor") : shellExpoDevicesModule();
|
|
9592
10032
|
const adapterImport = capacitor ? `import { installCapacitorDeviceAdapterIfNative } from ${JSON.stringify(baseAdapterModule)};` : `import { createAbsoluteExpoBridgeFetch, installAbsoluteExpoWebDeviceAdapter } from ${JSON.stringify(baseAdapterModule)};`;
|
|
9593
10033
|
const adapterInstall = capacitor ? `installCapacitorDeviceAdapterIfNative({ storagePrefix: ${JSON.stringify(storagePrefix)}${capabilityOptions ? `, ${capabilityOptions}` : ""} });` : `installAbsoluteExpoWebDeviceAdapter(${JSON.stringify(deviceCapabilities.capabilities)});`;
|
|
@@ -9621,7 +10061,7 @@ void startAbsoluteMobileShell(${shellOptions});
|
|
|
9621
10061
|
if (!build.success || build.outputs.length !== 1) {
|
|
9622
10062
|
throw new AggregateError(build.logs, "Failed to build the AbsoluteJS Capacitor shell.");
|
|
9623
10063
|
}
|
|
9624
|
-
await rename7(build.outputs[0]?.path ?? "",
|
|
10064
|
+
await rename7(build.outputs[0]?.path ?? "", join22(staging, BOOTSTRAP_FILE));
|
|
9625
10065
|
await rm7(entryPath, { force: true });
|
|
9626
10066
|
}, removePreviousBundle = async (backup, moved) => {
|
|
9627
10067
|
if (!moved)
|
|
@@ -9655,17 +10095,17 @@ void startAbsoluteMobileShell(${shellOptions});
|
|
|
9655
10095
|
const extension = extname5(page.bundlePath) || ".js";
|
|
9656
10096
|
const localBundlePath = `./pages/${page.bundleHash}${extension}`;
|
|
9657
10097
|
const source = sourceAssetPath(buildDirectory, page.bundlePath);
|
|
9658
|
-
await copyFile4(source,
|
|
10098
|
+
await copyFile4(source, join22(staging, localBundlePath));
|
|
9659
10099
|
await copyAbsoluteClientDependencies(source, buildDirectory, staging, copiedDependencies);
|
|
9660
10100
|
let localStylePath;
|
|
9661
10101
|
if (page.styleBundlePath && page.styleBundleHash) {
|
|
9662
10102
|
const styleExtension = extname5(page.styleBundlePath) || ".css";
|
|
9663
10103
|
localStylePath = `./styles/${page.styleBundleHash}${styleExtension}`;
|
|
9664
10104
|
const styleSource = sourceAssetPath(buildDirectory, page.styleBundlePath);
|
|
9665
|
-
await mkdir9(dirname12(
|
|
10105
|
+
await mkdir9(dirname12(join22(staging, localStylePath)), {
|
|
9666
10106
|
recursive: true
|
|
9667
10107
|
});
|
|
9668
|
-
await copyFile4(styleSource,
|
|
10108
|
+
await copyFile4(styleSource, join22(staging, localStylePath));
|
|
9669
10109
|
await copyAbsoluteClientDependencies(styleSource, buildDirectory, staging, copiedDependencies);
|
|
9670
10110
|
}
|
|
9671
10111
|
return {
|
|
@@ -9680,11 +10120,11 @@ void startAbsoluteMobileShell(${shellOptions});
|
|
|
9680
10120
|
return value;
|
|
9681
10121
|
};
|
|
9682
10122
|
const release = safeLeaf(appBuild, "Mobile app build");
|
|
9683
|
-
const privateRoot =
|
|
9684
|
-
const releaseRoot =
|
|
10123
|
+
const privateRoot = join22(projectRoot, "sourcemaps");
|
|
10124
|
+
const releaseRoot = join22(privateRoot, "mobile", release);
|
|
9685
10125
|
const copied = [];
|
|
9686
10126
|
const available = pages.flatMap((page) => {
|
|
9687
|
-
const source =
|
|
10127
|
+
const source = join22(privateRoot, `${basename8(page.bundlePath)}.map`);
|
|
9688
10128
|
return existsSync10(source) ? [{ page, source }] : [];
|
|
9689
10129
|
});
|
|
9690
10130
|
if (available.length > 0)
|
|
@@ -9695,11 +10135,11 @@ void startAbsoluteMobileShell(${shellOptions});
|
|
|
9695
10135
|
throw new TypeError("Mobile page extension is not a safe source-map key.");
|
|
9696
10136
|
const bundleHash = safeLeaf(page.bundleHash, "Mobile page bundle hash");
|
|
9697
10137
|
const file = `${bundleHash}${extension}.map`;
|
|
9698
|
-
await copyFile4(source,
|
|
10138
|
+
await copyFile4(source, join22(releaseRoot, file));
|
|
9699
10139
|
copied.push({ bundleHash, file, pageId: page.pageId });
|
|
9700
10140
|
}));
|
|
9701
10141
|
if (copied.length > 0) {
|
|
9702
|
-
await writeFile8(
|
|
10142
|
+
await writeFile8(join22(releaseRoot, "manifest.json"), `${JSON.stringify({
|
|
9703
10143
|
appBuild,
|
|
9704
10144
|
format: 1,
|
|
9705
10145
|
pages: copied.sort((left, right) => left.pageId.localeCompare(right.pageId))
|
|
@@ -9744,7 +10184,7 @@ void startAbsoluteMobileShell(${shellOptions});
|
|
|
9744
10184
|
return;
|
|
9745
10185
|
copied.add(specifier);
|
|
9746
10186
|
const source = sourceAssetPath(buildDirectory, specifier);
|
|
9747
|
-
const destination =
|
|
10187
|
+
const destination = join22(staging, specifier.replace(/^\/+/, ""));
|
|
9748
10188
|
await mkdir9(dirname12(destination), { recursive: true });
|
|
9749
10189
|
await copyFile4(source, destination);
|
|
9750
10190
|
await copyAbsoluteClientDependencies(source, buildDirectory, staging, copied);
|
|
@@ -9757,13 +10197,13 @@ void startAbsoluteMobileShell(${shellOptions});
|
|
|
9757
10197
|
}
|
|
9758
10198
|
const destination = options.config.bundleDirectory;
|
|
9759
10199
|
await mkdir9(dirname12(destination), { recursive: true });
|
|
9760
|
-
const staging = await mkdtemp5(
|
|
10200
|
+
const staging = await mkdtemp5(join22(dirname12(destination), `.${basename8(destination)}.stage-`));
|
|
9761
10201
|
try {
|
|
9762
|
-
const pageDirectory =
|
|
10202
|
+
const pageDirectory = join22(staging, "pages");
|
|
9763
10203
|
await mkdir9(pageDirectory, { recursive: true });
|
|
9764
10204
|
await Promise.all(CLIENT_ASSET_DIRECTORIES.map((directory) => ({
|
|
9765
|
-
destination:
|
|
9766
|
-
source:
|
|
10205
|
+
destination: join22(staging, directory),
|
|
10206
|
+
source: join22(options.buildDirectory, directory)
|
|
9767
10207
|
})).filter(({ source }) => existsSync10(source)).map(({ destination: assetDestination, source }) => cp3(source, assetDestination, { recursive: true })));
|
|
9768
10208
|
const copiedDependencies = new Set;
|
|
9769
10209
|
const pages = await Promise.all(options.artifact.pages.map((page) => copyClientPage(page, options.buildDirectory, staging, copiedDependencies)));
|
|
@@ -9800,9 +10240,9 @@ void startAbsoluteMobileShell(${shellOptions});
|
|
|
9800
10240
|
} : {}
|
|
9801
10241
|
};
|
|
9802
10242
|
await Promise.all([
|
|
9803
|
-
writeFile8(
|
|
10243
|
+
writeFile8(join22(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
|
|
9804
10244
|
`),
|
|
9805
|
-
writeFile8(
|
|
10245
|
+
writeFile8(join22(staging, INDEX_FILE), indexHtml(options.config.appName, options.config.productionOrigin)),
|
|
9806
10246
|
buildShellBootstrap(staging, options.auth !== undefined, options.auth !== undefined && options.sync === true, `absolutejs.${options.auth?.clientId ?? options.config.appId}.`, options.config.engine, options.config.engine === "capacitor" && options.config.updates !== undefined, options.deviceCapabilities, options.projectRoot)
|
|
9807
10247
|
]);
|
|
9808
10248
|
await installBundle(staging, destination);
|
|
@@ -9859,7 +10299,7 @@ import {
|
|
|
9859
10299
|
rm as rm8,
|
|
9860
10300
|
writeFile as writeFile9
|
|
9861
10301
|
} from "fs/promises";
|
|
9862
|
-
import { dirname as dirname13, join as
|
|
10302
|
+
import { dirname as dirname13, join as join23, resolve as resolvePath3 } from "path";
|
|
9863
10303
|
var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "current.json", BUNDLES_DIRECTORY = "bundles", ARTIFACT_FILE = "artifact.json", BUNDLE_ID_PATTERN, isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), errorHasCode2 = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code, bundleIdFor = (currentReleaseId, releases) => {
|
|
9864
10304
|
const identity = JSON.stringify({
|
|
9865
10305
|
currentReleaseId,
|
|
@@ -9889,16 +10329,16 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
|
|
|
9889
10329
|
releases
|
|
9890
10330
|
};
|
|
9891
10331
|
}, writeRelease = async (root, release) => {
|
|
9892
|
-
const directory =
|
|
9893
|
-
const producerPath =
|
|
10332
|
+
const directory = join23(root, release.artifact.releaseId);
|
|
10333
|
+
const producerPath = join23(directory, release.artifact.producer.module);
|
|
9894
10334
|
await mkdir10(dirname13(producerPath), { recursive: true });
|
|
9895
10335
|
await Promise.all([
|
|
9896
|
-
writeFile9(
|
|
10336
|
+
writeFile9(join23(directory, ARTIFACT_FILE), `${JSON.stringify(release.artifact, null, "\t")}
|
|
9897
10337
|
`),
|
|
9898
10338
|
writeFile9(producerPath, new Uint8Array(await release.producer.arrayBuffer()))
|
|
9899
10339
|
]);
|
|
9900
10340
|
}, installImmutableBundle = async (bundlesRoot, bundleId, releases) => {
|
|
9901
|
-
const destination =
|
|
10341
|
+
const destination = join23(bundlesRoot, bundleId);
|
|
9902
10342
|
try {
|
|
9903
10343
|
await access8(destination);
|
|
9904
10344
|
return destination;
|
|
@@ -9906,7 +10346,7 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
|
|
|
9906
10346
|
if (!errorHasCode2(error, "ENOENT"))
|
|
9907
10347
|
throw error;
|
|
9908
10348
|
}
|
|
9909
|
-
const staging = await mkdtemp6(
|
|
10349
|
+
const staging = await mkdtemp6(join23(bundlesRoot, ".stage-"));
|
|
9910
10350
|
try {
|
|
9911
10351
|
await Promise.all(releases.map((release) => writeRelease(staging, release)));
|
|
9912
10352
|
await rename8(staging, destination);
|
|
@@ -9935,7 +10375,7 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
|
|
|
9935
10375
|
return release;
|
|
9936
10376
|
});
|
|
9937
10377
|
const root = resolvePath3(input.root);
|
|
9938
|
-
const bundlesRoot =
|
|
10378
|
+
const bundlesRoot = join23(root, BUNDLES_DIRECTORY);
|
|
9939
10379
|
await mkdir10(bundlesRoot, { recursive: true });
|
|
9940
10380
|
const bundleId = bundleIdFor(input.currentReleaseId, artifacts);
|
|
9941
10381
|
await installImmutableBundle(bundlesRoot, bundleId, orderedReleases);
|
|
@@ -9945,8 +10385,8 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
|
|
|
9945
10385
|
format: ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
|
|
9946
10386
|
releases: artifacts
|
|
9947
10387
|
};
|
|
9948
|
-
const pointerPath =
|
|
9949
|
-
const temporaryPointerPath =
|
|
10388
|
+
const pointerPath = join23(root, CURRENT_BUNDLE_FILE);
|
|
10389
|
+
const temporaryPointerPath = join23(root, `.current-${crypto.randomUUID()}.json`);
|
|
9950
10390
|
await writeFile9(temporaryPointerPath, `${JSON.stringify(index, null, "\t")}
|
|
9951
10391
|
`, { flag: "wx" });
|
|
9952
10392
|
await rename8(temporaryPointerPath, pointerPath);
|
|
@@ -9954,12 +10394,12 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
|
|
|
9954
10394
|
}, readAbsoluteMobileMaterializedReleases = async (root) => {
|
|
9955
10395
|
const resolvedRoot = resolvePath3(root);
|
|
9956
10396
|
try {
|
|
9957
|
-
const serialized = await readFile11(
|
|
10397
|
+
const serialized = await readFile11(join23(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
|
|
9958
10398
|
const parsed = JSON.parse(serialized);
|
|
9959
10399
|
const index = parseBundleIndex(parsed);
|
|
9960
|
-
const bundleRoot =
|
|
10400
|
+
const bundleRoot = join23(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
|
|
9961
10401
|
return Promise.all(index.releases.map(async (artifact) => {
|
|
9962
|
-
const producer = Bun.file(
|
|
10402
|
+
const producer = Bun.file(join23(bundleRoot, artifact.releaseId, artifact.producer.module));
|
|
9963
10403
|
await verifyAbsoluteMobileCompatibilityProducer({
|
|
9964
10404
|
artifact,
|
|
9965
10405
|
producer
|
|
@@ -9980,7 +10420,7 @@ var init_materializedBundle = __esm(() => {
|
|
|
9980
10420
|
|
|
9981
10421
|
// src/mobile/buildPipeline.ts
|
|
9982
10422
|
import { readFile as readFile12 } from "fs/promises";
|
|
9983
|
-
import { join as
|
|
10423
|
+
import { join as join24, resolve as resolve17 } from "path";
|
|
9984
10424
|
import { pathToFileURL } from "url";
|
|
9985
10425
|
var isElysiaApp = (value) => typeof value === "object" && value !== null && typeof Reflect.get(value, "compile") === "function" && Array.isArray(Reflect.get(value, "routes")), isStringRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && Object.values(value).every((entry) => typeof entry === "string"), serverExportName = (loaded, app) => {
|
|
9986
10426
|
if (loaded.server === app)
|
|
@@ -10011,9 +10451,9 @@ var isElysiaApp = (value) => typeof value === "object" && value !== null && type
|
|
|
10011
10451
|
}, finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
|
|
10012
10452
|
const buildDirectory = resolve17(options.buildDirectory);
|
|
10013
10453
|
const mobile = normalizeAbsoluteMobileConfig(options.mobile, options.projectRoot);
|
|
10014
|
-
const root =
|
|
10454
|
+
const root = join24(buildDirectory, ".absolutejs", "mobile-compatibility");
|
|
10015
10455
|
const [manifestSource, previous] = await Promise.all([
|
|
10016
|
-
readFile12(
|
|
10456
|
+
readFile12(join24(buildDirectory, "manifest.json"), "utf8"),
|
|
10017
10457
|
readAbsoluteMobileMaterializedReleases(root)
|
|
10018
10458
|
]);
|
|
10019
10459
|
const manifest = JSON.parse(manifestSource);
|
|
@@ -10681,7 +11121,7 @@ __export(exports_prerender, {
|
|
|
10681
11121
|
routeToFilename: () => routeToFilename
|
|
10682
11122
|
});
|
|
10683
11123
|
import { mkdirSync as mkdirSync6, readFileSync as readFileSync15 } from "fs";
|
|
10684
|
-
import { join as
|
|
11124
|
+
import { join as join25 } from "path";
|
|
10685
11125
|
var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_TIMEOUT_MS = 30000, DEFAULT_FETCH_TIMEOUT_MS = 1e4, PRERENDER_BYPASS_HEADER = "X-Absolute-Prerender-Bypass", routeToFilename = (route) => route === "/" ? "index.html" : `${route.slice(1).replace(/\//g, "-")}.html`, writeTimestamp = async (htmlPath) => {
|
|
10686
11126
|
const metaPath = htmlPath.replace(/\.html$/, ".meta");
|
|
10687
11127
|
await Bun.write(metaPath, String(Date.now()));
|
|
@@ -10751,7 +11191,7 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
|
|
|
10751
11191
|
if (!isCompleteHtml(html))
|
|
10752
11192
|
return false;
|
|
10753
11193
|
const fileName = routeToFilename(route);
|
|
10754
|
-
const filePath =
|
|
11194
|
+
const filePath = join25(prerenderDir, fileName);
|
|
10755
11195
|
await Bun.write(filePath, html);
|
|
10756
11196
|
await writeTimestamp(filePath);
|
|
10757
11197
|
return true;
|
|
@@ -10781,13 +11221,13 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
|
|
|
10781
11221
|
return;
|
|
10782
11222
|
}
|
|
10783
11223
|
const fileName = routeToFilename(route);
|
|
10784
|
-
const filePath =
|
|
11224
|
+
const filePath = join25(prerenderDir, fileName);
|
|
10785
11225
|
await Bun.write(filePath, html);
|
|
10786
11226
|
await writeTimestamp(filePath);
|
|
10787
11227
|
result.routes.set(route, filePath);
|
|
10788
11228
|
log?.(` Pre-rendered ${route} \u2192 ${fileName} (${html.length} bytes)`);
|
|
10789
11229
|
}, prerender = async (port, outDir, staticConfig, log) => {
|
|
10790
|
-
const prerenderDir =
|
|
11230
|
+
const prerenderDir = join25(outDir, "_prerendered");
|
|
10791
11231
|
mkdirSync6(prerenderDir, { recursive: true });
|
|
10792
11232
|
const baseUrl = `http://localhost:${port}`;
|
|
10793
11233
|
let routes;
|
|
@@ -11223,7 +11663,7 @@ var init_nativeRewrite = __esm(() => {
|
|
|
11223
11663
|
|
|
11224
11664
|
// src/build/rewriteImportsPlugin.ts
|
|
11225
11665
|
import { readdir as readdir4 } from "fs/promises";
|
|
11226
|
-
import { join as
|
|
11666
|
+
import { join as join26 } from "path";
|
|
11227
11667
|
var escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), jsRewriteImports = (content, replacements) => {
|
|
11228
11668
|
let result = content;
|
|
11229
11669
|
for (const [specifier, webPath] of replacements) {
|
|
@@ -11302,7 +11742,7 @@ ${content}`;
|
|
|
11302
11742
|
const entries = await readdir4(dir);
|
|
11303
11743
|
for (const entry of entries) {
|
|
11304
11744
|
if (entry.endsWith(".js"))
|
|
11305
|
-
allFiles.push(
|
|
11745
|
+
allFiles.push(join26(dir, entry));
|
|
11306
11746
|
}
|
|
11307
11747
|
} catch {}
|
|
11308
11748
|
}
|
|
@@ -11378,7 +11818,7 @@ var init_rewriteImports = __esm(() => {
|
|
|
11378
11818
|
// src/cli/scripts/start.ts
|
|
11379
11819
|
var {env: env2 } = globalThis.Bun;
|
|
11380
11820
|
import { existsSync as existsSync12, readFileSync as readFileSync16, rmSync as rmSync4 } from "fs";
|
|
11381
|
-
import { basename as basename9, join as
|
|
11821
|
+
import { basename as basename9, join as join27, resolve as resolve21 } from "path";
|
|
11382
11822
|
var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, resolvePackageVersion = (candidates) => {
|
|
11383
11823
|
for (const candidate of candidates) {
|
|
11384
11824
|
const version2 = readPackageVersion2(candidate);
|
|
@@ -11610,7 +12050,7 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
11610
12050
|
if (!build)
|
|
11611
12051
|
throw new Error("Could not locate build module");
|
|
11612
12052
|
await build(buildConfig);
|
|
11613
|
-
rmSync4(
|
|
12053
|
+
rmSync4(join27(resolvedOutdir, "_prerendered"), {
|
|
11614
12054
|
force: true,
|
|
11615
12055
|
recursive: true
|
|
11616
12056
|
});
|
|
@@ -11914,16 +12354,16 @@ __export(exports_build, {
|
|
|
11914
12354
|
build: () => build
|
|
11915
12355
|
});
|
|
11916
12356
|
import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync as readFileSync18 } from "fs";
|
|
11917
|
-
import { join as
|
|
12357
|
+
import { join as join28, resolve as resolve23 } from "path";
|
|
11918
12358
|
var PROFILE_TOP = 15, PROFILE_COL = 8, FRAMEWORK_KEYS, cliTag3 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, printProfile = (buildDir) => {
|
|
11919
|
-
const traceDir =
|
|
12359
|
+
const traceDir = join28(buildDir, ".absolute-trace");
|
|
11920
12360
|
if (!existsSync14(traceDir))
|
|
11921
12361
|
return;
|
|
11922
12362
|
const files = readdirSync3(traceDir).filter((file) => file.endsWith(".json")).sort();
|
|
11923
12363
|
const latest = files[files.length - 1];
|
|
11924
12364
|
if (latest === undefined)
|
|
11925
12365
|
return;
|
|
11926
|
-
const trace = JSON.parse(readFileSync18(
|
|
12366
|
+
const trace = JSON.parse(readFileSync18(join28(traceDir, latest), "utf-8"));
|
|
11927
12367
|
const events = Array.isArray(trace.events) ? trace.events : [];
|
|
11928
12368
|
if (events.length === 0)
|
|
11929
12369
|
return;
|
|
@@ -12386,7 +12826,7 @@ __export(exports_ls, {
|
|
|
12386
12826
|
runLs: () => runLs
|
|
12387
12827
|
});
|
|
12388
12828
|
import { existsSync as existsSync17, readFileSync as readFileSync20, statSync } from "fs";
|
|
12389
|
-
import { basename as basename11, extname as extname7, join as
|
|
12829
|
+
import { basename as basename11, extname as extname7, join as join29, relative as relative15 } from "path";
|
|
12390
12830
|
var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELDS, readStringField = (source, key) => {
|
|
12391
12831
|
const value = Reflect.get(source, key);
|
|
12392
12832
|
return typeof value === "string" ? value : undefined;
|
|
@@ -12408,13 +12848,13 @@ var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELD
|
|
|
12408
12848
|
const dir = readStringField(source, framework.field);
|
|
12409
12849
|
return dir === undefined ? [] : [
|
|
12410
12850
|
{
|
|
12411
|
-
dir:
|
|
12851
|
+
dir: join29(baseDir, dir),
|
|
12412
12852
|
label: framework.label,
|
|
12413
12853
|
pattern: framework.pattern
|
|
12414
12854
|
}
|
|
12415
12855
|
];
|
|
12416
12856
|
}), scanFramework = async (spec) => {
|
|
12417
|
-
const { pageFiles } = await scanConventions(
|
|
12857
|
+
const { pageFiles } = await scanConventions(join29(spec.dir, "pages"), spec.pattern);
|
|
12418
12858
|
if (pageFiles.length === 0)
|
|
12419
12859
|
return null;
|
|
12420
12860
|
const pages = pageFiles.map((file) => ({
|
|
@@ -12438,10 +12878,10 @@ var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELD
|
|
|
12438
12878
|
}, resolveDiskPath = (buildDir, value) => {
|
|
12439
12879
|
if (existsSync17(value))
|
|
12440
12880
|
return value;
|
|
12441
|
-
const underBuild =
|
|
12881
|
+
const underBuild = join29(buildDir, value);
|
|
12442
12882
|
if (existsSync17(underBuild))
|
|
12443
12883
|
return underBuild;
|
|
12444
|
-
return
|
|
12884
|
+
return join29(process.cwd(), value);
|
|
12445
12885
|
}, fileSize = (diskPath) => {
|
|
12446
12886
|
try {
|
|
12447
12887
|
return statSync(diskPath).size;
|
|
@@ -12449,7 +12889,7 @@ var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELD
|
|
|
12449
12889
|
return 0;
|
|
12450
12890
|
}
|
|
12451
12891
|
}, readManifestSizes = (manifestDir) => {
|
|
12452
|
-
const manifest = JSON.parse(readFileSync20(
|
|
12892
|
+
const manifest = JSON.parse(readFileSync20(join29(manifestDir, "manifest.json"), "utf-8"));
|
|
12453
12893
|
const sizes = new Map;
|
|
12454
12894
|
Object.entries(manifest).forEach(([key, value]) => {
|
|
12455
12895
|
sizes.set(key, fileSize(resolveDiskPath(manifestDir, value)));
|
|
@@ -12468,7 +12908,7 @@ var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELD
|
|
|
12468
12908
|
}))
|
|
12469
12909
|
})), manifestAge = (manifestPath) => getDurationString(Date.now() - statSync(manifestPath).mtimeMs), firstBuildDir = (candidates) => candidates.map((candidate) => {
|
|
12470
12910
|
const dir = readStringField(candidate.source, "buildDirectory");
|
|
12471
|
-
return dir === undefined ? undefined :
|
|
12911
|
+
return dir === undefined ? undefined : join29(candidate.baseDir, dir);
|
|
12472
12912
|
}).find((dir) => dir !== undefined), resolveSizesDir = (args, candidates) => parseFlagValue(args, "--outdir") ?? firstBuildDir(candidates) ?? DEFAULT_BUILD_DIR, formatSize = (bytes) => {
|
|
12473
12913
|
if (bytes === null || bytes === 0)
|
|
12474
12914
|
return "-";
|
|
@@ -12566,7 +13006,7 @@ ${colors.dim}${frameworkCount} ${frameworkCount === 1 ? "framework" : "framework
|
|
|
12566
13006
|
return;
|
|
12567
13007
|
}
|
|
12568
13008
|
const sizesDir = resolveSizesDir(args, candidates);
|
|
12569
|
-
const manifestPath =
|
|
13009
|
+
const manifestPath = join29(sizesDir, "manifest.json");
|
|
12570
13010
|
if (!existsSync17(manifestPath)) {
|
|
12571
13011
|
printDim(`No build at ${relativeOrSelf(manifestPath)}. Run \`absolute build\` first, or pass \`--outdir <dir>\`.`);
|
|
12572
13012
|
return;
|
|
@@ -14033,7 +14473,7 @@ var init_frameworks = __esm(() => {
|
|
|
14033
14473
|
});
|
|
14034
14474
|
|
|
14035
14475
|
// src/cli/generate/context.ts
|
|
14036
|
-
import { dirname as dirname17, isAbsolute as isAbsolute5, join as
|
|
14476
|
+
import { dirname as dirname17, isAbsolute as isAbsolute5, join as join30, relative as relative16, resolve as resolve27 } from "path";
|
|
14037
14477
|
var asString = (value) => typeof value === "string" ? value : undefined, isRecord11 = (value) => typeof value === "object" && value !== null, resolveDir = (cwd, value) => isAbsolute5(value) ? value : resolve27(cwd, value), resolveStylesDir = (cwd, config) => {
|
|
14038
14478
|
const styles = config.stylesConfig;
|
|
14039
14479
|
if (typeof styles === "string")
|
|
@@ -14096,7 +14536,7 @@ var asString = (value) => typeof value === "string" ? value : undefined, isRecor
|
|
|
14096
14536
|
message: `Multiple frameworks configured (${configured.join(", ")}). Pass --framework <name>.`,
|
|
14097
14537
|
ok: false
|
|
14098
14538
|
};
|
|
14099
|
-
}, sharedDirFor = (project, framework) =>
|
|
14539
|
+
}, sharedDirFor = (project, framework) => join30(frontendRootFor(project, framework), "shared"), toModuleSpecifier = (fromDir, toFileNoExt) => {
|
|
14100
14540
|
const rel = relative16(fromDir, toFileNoExt).split("\\").join("/");
|
|
14101
14541
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
14102
14542
|
};
|
|
@@ -14126,7 +14566,7 @@ var emptyOutcome = () => ({
|
|
|
14126
14566
|
// src/cli/generate/routeWiring.ts
|
|
14127
14567
|
import ts8 from "typescript";
|
|
14128
14568
|
import { existsSync as existsSync21, readFileSync as readFileSync24, readdirSync as readdirSync4, writeFileSync as writeFileSync9 } from "fs";
|
|
14129
|
-
import { dirname as dirname18, join as
|
|
14569
|
+
import { dirname as dirname18, join as join31 } from "path";
|
|
14130
14570
|
var DEFAULT_SEPARATOR = `
|
|
14131
14571
|
`, BOUNDARY_USE, applyEdits = (text2, edits) => {
|
|
14132
14572
|
const ordered = [...edits].sort((first, second) => second.start - first.start);
|
|
@@ -14285,14 +14725,14 @@ ${newLines.join(`
|
|
|
14285
14725
|
for (const name of readdirSync4(pluginsDir)) {
|
|
14286
14726
|
if (!name.endsWith(".ts"))
|
|
14287
14727
|
continue;
|
|
14288
|
-
const candidate =
|
|
14728
|
+
const candidate = join31(pluginsDir, name);
|
|
14289
14729
|
if (hasChain(candidate))
|
|
14290
14730
|
return candidate;
|
|
14291
14731
|
}
|
|
14292
14732
|
return null;
|
|
14293
14733
|
}, findRoutingFile = (serverEntry) => {
|
|
14294
|
-
const pluginsDir =
|
|
14295
|
-
const preferred =
|
|
14734
|
+
const pluginsDir = join31(dirname18(serverEntry), "plugins");
|
|
14735
|
+
const preferred = join31(pluginsDir, "pagesPlugin.ts");
|
|
14296
14736
|
if (hasChain(preferred))
|
|
14297
14737
|
return preferred;
|
|
14298
14738
|
const scanned = firstChainFile(pluginsDir);
|
|
@@ -14384,7 +14824,7 @@ var init_routeWiring = __esm(() => {
|
|
|
14384
14824
|
|
|
14385
14825
|
// src/cli/generate/generateApi.ts
|
|
14386
14826
|
import { existsSync as existsSync22, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
|
|
14387
|
-
import { dirname as dirname19, join as
|
|
14827
|
+
import { dirname as dirname19, join as join32 } from "path";
|
|
14388
14828
|
var apiPluginTemplate = (pluginName, base) => `import { Elysia } from 'elysia';
|
|
14389
14829
|
|
|
14390
14830
|
export const ${pluginName} = new Elysia()
|
|
@@ -14396,8 +14836,8 @@ export const ${pluginName} = new Elysia()
|
|
|
14396
14836
|
const pluginName = `${camel}Plugin`;
|
|
14397
14837
|
const base = `/api/${kebab}`;
|
|
14398
14838
|
const outcome = { ...emptyOutcome(), route: base };
|
|
14399
|
-
const pluginsDir =
|
|
14400
|
-
const fileAbs =
|
|
14839
|
+
const pluginsDir = join32(dirname19(project.serverEntry), "plugins");
|
|
14840
|
+
const fileAbs = join32(pluginsDir, `${pluginName}.ts`);
|
|
14401
14841
|
if (existsSync22(fileAbs)) {
|
|
14402
14842
|
outcome.notes.push(`${pluginName} already exists at ${fileAbs} \u2014 skipped.`);
|
|
14403
14843
|
return outcome;
|
|
@@ -14472,7 +14912,7 @@ var init_componentTemplates = __esm(() => {
|
|
|
14472
14912
|
|
|
14473
14913
|
// src/cli/generate/generateComponent.ts
|
|
14474
14914
|
import { existsSync as existsSync23, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
|
|
14475
|
-
import { dirname as dirname20, join as
|
|
14915
|
+
import { dirname as dirname20, join as join33 } from "path";
|
|
14476
14916
|
var generateComponent = (project, framework, rawName) => {
|
|
14477
14917
|
const def = frameworks6[framework];
|
|
14478
14918
|
const pascal = toPascalCase(rawName);
|
|
@@ -14483,7 +14923,7 @@ var generateComponent = (project, framework, rawName) => {
|
|
|
14483
14923
|
outcome.manual = { reason: "framework directory missing", snippet: "" };
|
|
14484
14924
|
return outcome;
|
|
14485
14925
|
}
|
|
14486
|
-
const fileAbs =
|
|
14926
|
+
const fileAbs = join33(frameworkDir, "components", def.componentFile({ kebab, pascal }));
|
|
14487
14927
|
if (existsSync23(fileAbs)) {
|
|
14488
14928
|
outcome.notes.push(`${pascal} already exists at ${fileAbs} \u2014 skipped.`);
|
|
14489
14929
|
return outcome;
|
|
@@ -14505,7 +14945,7 @@ var init_generateComponent = __esm(() => {
|
|
|
14505
14945
|
// src/cli/generate/cssStrategy.ts
|
|
14506
14946
|
import ts9 from "typescript";
|
|
14507
14947
|
import { existsSync as existsSync24 } from "fs";
|
|
14508
|
-
import { join as
|
|
14948
|
+
import { join as join34 } from "path";
|
|
14509
14949
|
var CSS_SUFFIX = "CSS", SHARED_MIN_USES = 2, DEFAULT_CSS = `main {
|
|
14510
14950
|
margin: 0 auto;
|
|
14511
14951
|
max-width: 64rem;
|
|
@@ -14544,7 +14984,7 @@ var CSS_SUFFIX = "CSS", SHARED_MIN_USES = 2, DEFAULT_CSS = `main {
|
|
|
14544
14984
|
return null;
|
|
14545
14985
|
}, fileForKey = (stylesDir, assetKey2) => {
|
|
14546
14986
|
const base = assetKey2.endsWith(CSS_SUFFIX) ? assetKey2.slice(0, -CSS_SUFFIX.length) : assetKey2;
|
|
14547
|
-
return
|
|
14987
|
+
return join34(stylesDir, `${toKebabCase(base)}.css`);
|
|
14548
14988
|
}, planCss = (routingText, stylesDir, pascal, kebab) => {
|
|
14549
14989
|
const sharedKey = detectSharedKey(routingText);
|
|
14550
14990
|
if (sharedKey) {
|
|
@@ -14557,7 +14997,7 @@ var CSS_SUFFIX = "CSS", SHARED_MIN_USES = 2, DEFAULT_CSS = `main {
|
|
|
14557
14997
|
shared: true
|
|
14558
14998
|
};
|
|
14559
14999
|
}
|
|
14560
|
-
const cssFileAbs =
|
|
15000
|
+
const cssFileAbs = join34(stylesDir, `${kebab}.css`);
|
|
14561
15001
|
return {
|
|
14562
15002
|
assetKey: `${pascal}${CSS_SUFFIX}`,
|
|
14563
15003
|
contents: DEFAULT_CSS,
|
|
@@ -14818,14 +15258,14 @@ import {
|
|
|
14818
15258
|
readdirSync as readdirSync5,
|
|
14819
15259
|
writeFileSync as writeFileSync13
|
|
14820
15260
|
} from "fs";
|
|
14821
|
-
import { dirname as dirname22, join as
|
|
15261
|
+
import { dirname as dirname22, join as join35, relative as relative17 } from "path";
|
|
14822
15262
|
var writeNew = (path, contents) => {
|
|
14823
15263
|
mkdirSync13(dirname22(path), { recursive: true });
|
|
14824
15264
|
writeFileSync13(path, contents, "utf-8");
|
|
14825
15265
|
}, toHref = (fromDir, toFile) => {
|
|
14826
15266
|
const rel = relative17(fromDir, toFile).split("\\").join("/");
|
|
14827
15267
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
14828
|
-
}, staticPageFiles = (project) => ["html", "htmx"].map((key) => project.frameworkDirs[key]).map((dir) => dir ?
|
|
15268
|
+
}, staticPageFiles = (project) => ["html", "htmx"].map((key) => project.frameworkDirs[key]).map((dir) => dir ? join35(dir, "pages") : null).filter((pagesDir) => pagesDir !== null && existsSync26(pagesDir)).flatMap((pagesDir) => readdirSync5(pagesDir).filter((name) => name.endsWith(".html")).map((name) => join35(pagesDir, name))), resyncPage = (file, items) => {
|
|
14829
15269
|
const html = readFileSync26(file, "utf-8");
|
|
14830
15270
|
const synced = syncStaticNav(html, items);
|
|
14831
15271
|
if (synced === null || synced === html)
|
|
@@ -14853,7 +15293,7 @@ var writeNew = (path, contents) => {
|
|
|
14853
15293
|
outcome.manual = { reason: "framework directory missing", snippet: "" };
|
|
14854
15294
|
return outcome;
|
|
14855
15295
|
}
|
|
14856
|
-
const pageFileAbs =
|
|
15296
|
+
const pageFileAbs = join35(frameworkDir, "pages", def.pageFile({ kebab, pascal }));
|
|
14857
15297
|
if (existsSync26(pageFileAbs)) {
|
|
14858
15298
|
outcome.notes.push(`${pascal} already exists at ${pageFileAbs} \u2014 skipped.`);
|
|
14859
15299
|
return outcome;
|
|
@@ -14861,7 +15301,7 @@ var writeNew = (path, contents) => {
|
|
|
14861
15301
|
const routingFile = findRoutingFile(project.serverEntry);
|
|
14862
15302
|
const routingText = routingFile ? readFileSync26(routingFile, "utf-8") : "";
|
|
14863
15303
|
const css = planCss(routingText, project.stylesDir, pascal, kebab);
|
|
14864
|
-
const navDataPath =
|
|
15304
|
+
const navDataPath = join35(sharedDirFor(project, framework), "navData.ts");
|
|
14865
15305
|
const nav = upsertNavItem(navDataPath, { href: route, label: title });
|
|
14866
15306
|
const navImportPath = toModuleSpecifier(dirname22(pageFileAbs), navDataPath.replace(/\.ts$/, ""));
|
|
14867
15307
|
writeNew(pageFileAbs, pageTemplates[framework]({
|
|
@@ -15241,9 +15681,9 @@ var init_catalog = __esm(() => {
|
|
|
15241
15681
|
|
|
15242
15682
|
// src/cli/integrations/addPlugin.ts
|
|
15243
15683
|
import { existsSync as existsSync27, readFileSync as readFileSync28 } from "fs";
|
|
15244
|
-
import { join as
|
|
15684
|
+
import { join as join36 } from "path";
|
|
15245
15685
|
var isRecord12 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), readPackageJson = (cwd) => {
|
|
15246
|
-
const path =
|
|
15686
|
+
const path = join36(cwd, "package.json");
|
|
15247
15687
|
if (!existsSync27(path))
|
|
15248
15688
|
return null;
|
|
15249
15689
|
try {
|
|
@@ -15845,7 +16285,7 @@ var init_resolveAuthSettings = __esm(() => {
|
|
|
15845
16285
|
// src/cli/config/auth/resolveAuthState.ts
|
|
15846
16286
|
import ts13 from "typescript";
|
|
15847
16287
|
import { existsSync as existsSync29, readdirSync as readdirSync6, readFileSync as readFileSync30 } from "fs";
|
|
15848
|
-
import { join as
|
|
16288
|
+
import { join as join37, relative as relative19, resolve as resolve29 } from "path";
|
|
15849
16289
|
var AUTH_PACKAGE2 = "@absolutejs/auth", REPO_URL = "https://github.com/absolutejs/absolute-auth", NPM_URL = "https://www.npmjs.com/package/@absolutejs/auth", SKIP_DIRS, MAX_FILES = 4000, SETUP_EXPORTS, isRecord13 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), readJson2 = (path) => {
|
|
15850
16290
|
if (!existsSync29(path))
|
|
15851
16291
|
return null;
|
|
@@ -15859,7 +16299,7 @@ var AUTH_PACKAGE2 = "@absolutejs/auth", REPO_URL = "https://github.com/absolutej
|
|
|
15859
16299
|
const value = record?.[key];
|
|
15860
16300
|
return typeof value === "string" ? value : null;
|
|
15861
16301
|
}, declaredVersionFor = (cwd) => {
|
|
15862
|
-
const pkg = readJson2(
|
|
16302
|
+
const pkg = readJson2(join37(cwd, "package.json"));
|
|
15863
16303
|
if (!pkg)
|
|
15864
16304
|
return null;
|
|
15865
16305
|
for (const field of ["dependencies", "devDependencies"]) {
|
|
@@ -15871,14 +16311,14 @@ var AUTH_PACKAGE2 = "@absolutejs/auth", REPO_URL = "https://github.com/absolutej
|
|
|
15871
16311
|
return version2;
|
|
15872
16312
|
}
|
|
15873
16313
|
return null;
|
|
15874
|
-
}, installedVersionFor = (cwd) => stringField(readJson2(
|
|
16314
|
+
}, installedVersionFor = (cwd) => stringField(readJson2(join37(cwd, "node_modules", AUTH_PACKAGE2, "package.json")), "version"), SOURCE_FILE, safeReaddir = (dir) => {
|
|
15875
16315
|
try {
|
|
15876
16316
|
return readdirSync6(dir, { withFileTypes: true });
|
|
15877
16317
|
} catch {
|
|
15878
16318
|
return [];
|
|
15879
16319
|
}
|
|
15880
16320
|
}, sortEntry = (dir, entry, found, dirs) => {
|
|
15881
|
-
const full =
|
|
16321
|
+
const full = join37(dir, entry.name);
|
|
15882
16322
|
if (entry.isDirectory()) {
|
|
15883
16323
|
if (SKIP_DIRS.has(entry.name) || entry.name.startsWith("."))
|
|
15884
16324
|
return;
|
|
@@ -15976,7 +16416,7 @@ var AUTH_PACKAGE2 = "@absolutejs/auth", REPO_URL = "https://github.com/absolutej
|
|
|
15976
16416
|
scaffoldable: isScaffoldableFeature(feature.id)
|
|
15977
16417
|
})), resolveAuthState = (cwd) => {
|
|
15978
16418
|
const installedVersion = installedVersionFor(cwd);
|
|
15979
|
-
const root = existsSync29(
|
|
16419
|
+
const root = existsSync29(join37(cwd, "src")) ? join37(cwd, "src") : cwd;
|
|
15980
16420
|
let match = null;
|
|
15981
16421
|
let setupPath = null;
|
|
15982
16422
|
for (const file of candidateFiles(root)) {
|
|
@@ -16022,7 +16462,7 @@ var init_resolveAuthState = __esm(() => {
|
|
|
16022
16462
|
|
|
16023
16463
|
// src/cli/config/auth/scaffoldAuthFeature.ts
|
|
16024
16464
|
import { existsSync as existsSync30, writeFileSync as writeFileSync15 } from "fs";
|
|
16025
|
-
import { dirname as dirname23, join as
|
|
16465
|
+
import { dirname as dirname23, join as join38, relative as relative20, resolve as resolve30 } from "path";
|
|
16026
16466
|
var renderScaffold = (scaffold) => {
|
|
16027
16467
|
const importNames = [...scaffold.imports, `type ${scaffold.typeName}`];
|
|
16028
16468
|
const importLine = `import { ${importNames.join(", ")} } from '@absolutejs/auth';`;
|
|
@@ -16048,7 +16488,7 @@ ${body}
|
|
|
16048
16488
|
const { setupPath } = resolveAuthState(cwd);
|
|
16049
16489
|
if (setupPath)
|
|
16050
16490
|
return dirname23(resolve30(cwd, setupPath));
|
|
16051
|
-
const src =
|
|
16491
|
+
const src = join38(cwd, "src");
|
|
16052
16492
|
return existsSync30(src) ? src : cwd;
|
|
16053
16493
|
}, spreadFor = (scaffold) => `import { ${scaffold.exportName} } from './${scaffold.exportName}';
|
|
16054
16494
|
// add to your auth() call:
|
|
@@ -16062,7 +16502,7 @@ ${scaffold.configKey}: ${scaffold.exportName}`, failure2 = (message) => ({
|
|
|
16062
16502
|
const scaffold = AUTH_SCAFFOLDS[id];
|
|
16063
16503
|
if (!scaffold)
|
|
16064
16504
|
return failure2(`Unknown auth feature "${id}".`);
|
|
16065
|
-
const filePath =
|
|
16505
|
+
const filePath = join38(targetDir(cwd), `${scaffold.exportName}.ts`);
|
|
16066
16506
|
const relPath = relative20(cwd, filePath);
|
|
16067
16507
|
if (existsSync30(filePath)) {
|
|
16068
16508
|
return {
|
|
@@ -16092,11 +16532,11 @@ var init_scaffoldAuthFeature = __esm(() => {
|
|
|
16092
16532
|
|
|
16093
16533
|
// src/cli/htmx/install.ts
|
|
16094
16534
|
import { existsSync as existsSync31, mkdirSync as mkdirSync14, readFileSync as readFileSync31, writeFileSync as writeFileSync16 } from "fs";
|
|
16095
|
-
import { join as
|
|
16535
|
+
import { join as join39 } from "path";
|
|
16096
16536
|
var VENDORED_HTMX_VERSION = "2.0.6", vendoredHtmxFile = () => [
|
|
16097
|
-
|
|
16098
|
-
|
|
16099
|
-
|
|
16537
|
+
join39(import.meta.dir, "htmx.min.js"),
|
|
16538
|
+
join39(import.meta.dir, "htmx", "htmx.min.js"),
|
|
16539
|
+
join39(import.meta.dir, "..", "htmx", "htmx.min.js")
|
|
16100
16540
|
].find((path) => existsSync31(path)) ?? null, detectHtmxVersion = (content) => {
|
|
16101
16541
|
const match = content.match(/version:"([0-9.]+)"/);
|
|
16102
16542
|
return match ? match[1] : null;
|
|
@@ -16108,7 +16548,7 @@ var VENDORED_HTMX_VERSION = "2.0.6", vendoredHtmxFile = () => [
|
|
|
16108
16548
|
}
|
|
16109
16549
|
return response.text();
|
|
16110
16550
|
}, installedHtmxVersion = (htmxDir) => {
|
|
16111
|
-
const file =
|
|
16551
|
+
const file = join39(htmxDir, "htmx.min.js");
|
|
16112
16552
|
if (!existsSync31(file))
|
|
16113
16553
|
return null;
|
|
16114
16554
|
return detectHtmxVersion(readFileSync31(file, "utf-8"));
|
|
@@ -16117,7 +16557,7 @@ var VENDORED_HTMX_VERSION = "2.0.6", vendoredHtmxFile = () => [
|
|
|
16117
16557
|
return file ? readFileSync31(file, "utf-8") : null;
|
|
16118
16558
|
}, writeHtmx = (htmxDir, content) => {
|
|
16119
16559
|
mkdirSync14(htmxDir, { recursive: true });
|
|
16120
|
-
const file =
|
|
16560
|
+
const file = join39(htmxDir, "htmx.min.js");
|
|
16121
16561
|
writeFileSync16(file, content, "utf-8");
|
|
16122
16562
|
return file;
|
|
16123
16563
|
};
|
|
@@ -16128,7 +16568,7 @@ var exports_add = {};
|
|
|
16128
16568
|
__export(exports_add, {
|
|
16129
16569
|
runAdd: () => runAdd
|
|
16130
16570
|
});
|
|
16131
|
-
import { dirname as dirname24, join as
|
|
16571
|
+
import { dirname as dirname24, join as join40, relative as relative21 } from "path";
|
|
16132
16572
|
var write2 = (text2) => process.stdout.write(`${text2}
|
|
16133
16573
|
`), fail2 = (message) => {
|
|
16134
16574
|
process.stdout.write(`${colors.red}${message}${colors.reset}
|
|
@@ -16143,7 +16583,7 @@ var write2 = (text2) => process.stdout.write(`${text2}
|
|
|
16143
16583
|
}, frontendRoot = (project, cwd) => {
|
|
16144
16584
|
const [firstKey] = configuredFrameworks(project);
|
|
16145
16585
|
const firstDir = firstKey ? project.frameworkDirs[firstKey] : undefined;
|
|
16146
|
-
return firstDir ? dirname24(firstDir) :
|
|
16586
|
+
return firstDir ? dirname24(firstDir) : join40(cwd, "src", "frontend");
|
|
16147
16587
|
}, addIntegrationCli = (id, install) => {
|
|
16148
16588
|
const result = addIntegration(process.cwd(), id, { install });
|
|
16149
16589
|
if (!result.ok) {
|
|
@@ -16207,7 +16647,7 @@ var write2 = (text2) => process.stdout.write(`${text2}
|
|
|
16207
16647
|
write2(`${colors.yellow}!${colors.reset} ${frameworks6[framework].label} is already configured \u2014 nothing to do.`);
|
|
16208
16648
|
return;
|
|
16209
16649
|
}
|
|
16210
|
-
const dirAbs =
|
|
16650
|
+
const dirAbs = join40(frontendRoot(project, cwd), framework);
|
|
16211
16651
|
const dirRel = `./${relative21(cwd, dirAbs).split("\\").join("/")}`;
|
|
16212
16652
|
let depNote = "Skipped dependency install (--no-install).";
|
|
16213
16653
|
if (!noInstall) {
|
|
@@ -16278,7 +16718,7 @@ __export(exports_analyze, {
|
|
|
16278
16718
|
runAnalyze: () => runAnalyze
|
|
16279
16719
|
});
|
|
16280
16720
|
import { existsSync as existsSync32, readFileSync as readFileSync32, statSync as statSync3, writeFileSync as writeFileSync17 } from "fs";
|
|
16281
|
-
import { join as
|
|
16721
|
+
import { join as join41, resolve as resolve31 } from "path";
|
|
16282
16722
|
var BASELINE_FILE = ".absolute-size-baseline.json", TOP_CHANGES = 12, CATEGORY_WIDTH = 16, SIZE_WIDTH = 12, CHANGE_WIDTH = 10, CATEGORY_ORDER, categoryOf = (key) => {
|
|
16283
16723
|
if (key.startsWith("Island"))
|
|
16284
16724
|
return "Islands";
|
|
@@ -16298,17 +16738,17 @@ var BASELINE_FILE = ".absolute-size-baseline.json", TOP_CHANGES = 12, CATEGORY_W
|
|
|
16298
16738
|
return 0;
|
|
16299
16739
|
}
|
|
16300
16740
|
}, readSizes = (manifestDir) => {
|
|
16301
|
-
const manifestPath =
|
|
16741
|
+
const manifestPath = join41(manifestDir, "manifest.json");
|
|
16302
16742
|
if (!existsSync32(manifestPath))
|
|
16303
16743
|
return null;
|
|
16304
16744
|
const manifest = JSON.parse(readFileSync32(manifestPath, "utf-8"));
|
|
16305
16745
|
const sizes = {};
|
|
16306
16746
|
for (const [key, value] of Object.entries(manifest)) {
|
|
16307
|
-
sizes[key] = fileSize2(
|
|
16747
|
+
sizes[key] = fileSize2(join41(manifestDir, value.replace(/^\//, "")));
|
|
16308
16748
|
}
|
|
16309
16749
|
return sizes;
|
|
16310
16750
|
}, readBaseline = (cwd) => {
|
|
16311
|
-
const path =
|
|
16751
|
+
const path = join41(cwd, BASELINE_FILE);
|
|
16312
16752
|
if (!existsSync32(path))
|
|
16313
16753
|
return null;
|
|
16314
16754
|
try {
|
|
@@ -16397,7 +16837,7 @@ var BASELINE_FILE = ".absolute-size-baseline.json", TOP_CHANGES = 12, CATEGORY_W
|
|
|
16397
16837
|
return;
|
|
16398
16838
|
}
|
|
16399
16839
|
if (args.includes("--save")) {
|
|
16400
|
-
writeFileSync17(
|
|
16840
|
+
writeFileSync17(join41(cwd, BASELINE_FILE), `${JSON.stringify(sizes, null, 2)}
|
|
16401
16841
|
`);
|
|
16402
16842
|
process.stdout.write(`${colors.green}\u2713${colors.reset} Saved size baseline (${Object.keys(sizes).length} entries) to ${BASELINE_FILE}
|
|
16403
16843
|
`);
|
|
@@ -16785,9 +17225,9 @@ __export(exports_env, {
|
|
|
16785
17225
|
scanEnvUsage: () => scanEnvUsage
|
|
16786
17226
|
});
|
|
16787
17227
|
import { existsSync as existsSync34, readFileSync as readFileSync34 } from "fs";
|
|
16788
|
-
import { join as
|
|
17228
|
+
import { join as join42 } from "path";
|
|
16789
17229
|
var {env: env3, Glob: Glob3 } = globalThis.Bun;
|
|
16790
|
-
var EXTENSIONS = "ts,tsx,js,jsx,mjs,cjs,svelte,vue", STATUS_WIDTH2, keysInFile = (text2) => [...text2.matchAll(/getEnv\(\s*['"]([^'"]+)['"]\s*\)/g)].map((match) => match[1]).filter((key) => key !== undefined), scanPatterns = () => existsSync34(
|
|
17230
|
+
var EXTENSIONS = "ts,tsx,js,jsx,mjs,cjs,svelte,vue", STATUS_WIDTH2, keysInFile = (text2) => [...text2.matchAll(/getEnv\(\s*['"]([^'"]+)['"]\s*\)/g)].map((match) => match[1]).filter((key) => key !== undefined), scanPatterns = () => existsSync34(join42(process.cwd(), "src")) ? [`src/**/*.{${EXTENSIONS}}`] : [`*.{${EXTENSIONS}}`], scanEnvUsage = async () => {
|
|
16791
17231
|
const scans = scanPatterns().map((pattern) => Array.fromAsync(new Glob3(pattern).scan({ cwd: process.cwd() })));
|
|
16792
17232
|
const files = (await Promise.all(scans)).flat();
|
|
16793
17233
|
const usage = new Map;
|
|
@@ -16854,7 +17294,7 @@ __export(exports_db, {
|
|
|
16854
17294
|
runDb: () => runDb
|
|
16855
17295
|
});
|
|
16856
17296
|
import { existsSync as existsSync35, mkdirSync as mkdirSync15, readFileSync as readFileSync35, writeFileSync as writeFileSync18 } from "fs";
|
|
16857
|
-
import { join as
|
|
17297
|
+
import { join as join43 } from "path";
|
|
16858
17298
|
var {env: env4, spawn: spawn3, SQL } = globalThis.Bun;
|
|
16859
17299
|
var BACKUP_FORMAT_VERSION = 1, RESTORE_CHUNK_ROWS = 500, URL_ENV_KEYS, JSON_DATA_TYPES, SEED_CANDIDATES, VALUE_FLAGS, paint = (text2, color) => `${color}${text2}${colors.reset}`, chunkRows = (items, size) => Array.from({ length: Math.ceil(items.length / size) }, (_, idx) => items.slice(idx * size, idx * size + size)), quoteIdent = (name) => `"${name.replace(/"/g, '""')}"`, resolveUrl = (explicit) => {
|
|
16860
17300
|
const found = explicit ?? URL_ENV_KEYS.map((key) => env4[key]).find((value) => typeof value === "string" && value !== "");
|
|
@@ -16964,12 +17404,12 @@ var BACKUP_FORMAT_VERSION = 1, RESTORE_CHUNK_ROWS = 500, URL_ENV_KEYS, JSON_DATA
|
|
|
16964
17404
|
tables,
|
|
16965
17405
|
v: BACKUP_FORMAT_VERSION
|
|
16966
17406
|
};
|
|
16967
|
-
const dir = options.out ??
|
|
17407
|
+
const dir = options.out ?? join43(process.cwd(), "backups");
|
|
16968
17408
|
mkdirSync15(dir, { recursive: true });
|
|
16969
17409
|
const json = JSON.stringify(payload, (_, value) => typeof value === "bigint" ? value.toString() : value);
|
|
16970
|
-
const file =
|
|
17410
|
+
const file = join43(dir, `backup-${payload.at.replace(/[:.]/g, "-")}.json`);
|
|
16971
17411
|
writeFileSync18(file, json);
|
|
16972
|
-
writeFileSync18(
|
|
17412
|
+
writeFileSync18(join43(dir, "latest.json"), json);
|
|
16973
17413
|
const total = chosen.reduce((sum, name) => sum + (tables[name]?.length ?? 0), 0);
|
|
16974
17414
|
console.log(paint(`\u2713 backup \u2192 ${file}`, colors.green));
|
|
16975
17415
|
console.log(paint(` ${chosen.length} tables, ${total} rows`, colors.dim));
|
|
@@ -16998,7 +17438,7 @@ var BACKUP_FORMAT_VERSION = 1, RESTORE_CHUNK_ROWS = 500, URL_ENV_KEYS, JSON_DATA
|
|
|
16998
17438
|
const total = order.reduce((sum, name) => sum + (payload.tables[name]?.length ?? 0), 0);
|
|
16999
17439
|
console.log(paint(`\u2713 restored ${order.length} tables, ${total} rows (idempotent upsert by primary key)`, colors.green));
|
|
17000
17440
|
}, runSeed = async (entry) => {
|
|
17001
|
-
const target = entry ?? SEED_CANDIDATES.find((candidate) => existsSync35(
|
|
17441
|
+
const target = entry ?? SEED_CANDIDATES.find((candidate) => existsSync35(join43(process.cwd(), candidate)));
|
|
17002
17442
|
if (target === undefined)
|
|
17003
17443
|
throw new Error(`No seed script found (looked for ${SEED_CANDIDATES.join(", ")}). Pass a path: absolute db seed <file>.`);
|
|
17004
17444
|
console.log(paint(`seeding via ${target}\u2026`, colors.cyan));
|
|
@@ -17033,7 +17473,7 @@ var BACKUP_FORMAT_VERSION = 1, RESTORE_CHUNK_ROWS = 500, URL_ENV_KEYS, JSON_DATA
|
|
|
17033
17473
|
return;
|
|
17034
17474
|
}
|
|
17035
17475
|
if (sub === "restore") {
|
|
17036
|
-
const file = positionalArgs(rest)[0] ??
|
|
17476
|
+
const file = positionalArgs(rest)[0] ?? join43(process.cwd(), "backups", "latest.json");
|
|
17037
17477
|
await runRestore(file, parseOptions(rest));
|
|
17038
17478
|
return;
|
|
17039
17479
|
}
|
|
@@ -17153,7 +17593,7 @@ import {
|
|
|
17153
17593
|
writeFileSync as writeFileSync19
|
|
17154
17594
|
} from "fs";
|
|
17155
17595
|
import { createRequire } from "module";
|
|
17156
|
-
import { dirname as dirname25, join as
|
|
17596
|
+
import { dirname as dirname25, join as join44, resolve as resolve32, sep as sep6 } from "path";
|
|
17157
17597
|
var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
|
|
17158
17598
|
try {
|
|
17159
17599
|
const parsed = JSON.parse(readFileSync36(path, "utf-8"));
|
|
@@ -17175,7 +17615,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
|
|
|
17175
17615
|
}, packageJsonFromEntry = (entry, expectedName) => {
|
|
17176
17616
|
let directory = dirname25(entry);
|
|
17177
17617
|
for (;; ) {
|
|
17178
|
-
const candidate =
|
|
17618
|
+
const candidate = join44(directory, "package.json");
|
|
17179
17619
|
const manifest = readManifest(candidate);
|
|
17180
17620
|
if (manifest && manifestName(manifest, "") === expectedName)
|
|
17181
17621
|
return candidate;
|
|
@@ -17197,7 +17637,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
|
|
|
17197
17637
|
}, findInstallRoot = (cwd) => {
|
|
17198
17638
|
let directory = resolve32(cwd);
|
|
17199
17639
|
for (;; ) {
|
|
17200
|
-
if (existsSync37(
|
|
17640
|
+
if (existsSync37(join44(directory, "bun.lock")) || existsSync37(join44(directory, "bun.lockb"))) {
|
|
17201
17641
|
return directory;
|
|
17202
17642
|
}
|
|
17203
17643
|
const parent = dirname25(directory);
|
|
@@ -17208,14 +17648,14 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
|
|
|
17208
17648
|
}, findProjectManifest = (cwd, installRoot) => {
|
|
17209
17649
|
let directory = resolve32(cwd);
|
|
17210
17650
|
for (;; ) {
|
|
17211
|
-
const candidate =
|
|
17651
|
+
const candidate = join44(directory, "package.json");
|
|
17212
17652
|
if (existsSync37(candidate))
|
|
17213
17653
|
return candidate;
|
|
17214
17654
|
if (directory === installRoot)
|
|
17215
|
-
return
|
|
17655
|
+
return join44(installRoot, "package.json");
|
|
17216
17656
|
const parent = dirname25(directory);
|
|
17217
17657
|
if (parent === directory)
|
|
17218
|
-
return
|
|
17658
|
+
return join44(installRoot, "package.json");
|
|
17219
17659
|
directory = parent;
|
|
17220
17660
|
}
|
|
17221
17661
|
}, appendConsumer = (consumers, consumerPaths, path, manifest) => {
|
|
@@ -17253,7 +17693,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
|
|
|
17253
17693
|
appendConsumer(consumers, consumerPaths, inspection.consumer.path, inspection.consumer.manifest);
|
|
17254
17694
|
}, inspectTypeGraph = (cwd) => {
|
|
17255
17695
|
const installRoot = findInstallRoot(cwd);
|
|
17256
|
-
const rootManifestPath =
|
|
17696
|
+
const rootManifestPath = join44(installRoot, "package.json");
|
|
17257
17697
|
const rootManifest = readManifest(rootManifestPath) ?? {};
|
|
17258
17698
|
const consumers = [
|
|
17259
17699
|
{ manifest: rootManifest, path: rootManifestPath }
|
|
@@ -17289,7 +17729,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
|
|
|
17289
17729
|
const duplicates = duplicateTypeGraphPackages(report);
|
|
17290
17730
|
if (duplicates.length === 0)
|
|
17291
17731
|
return [];
|
|
17292
|
-
const manifestPath =
|
|
17732
|
+
const manifestPath = join44(report.installRoot, "package.json");
|
|
17293
17733
|
const manifest = readManifest(manifestPath);
|
|
17294
17734
|
if (!manifest)
|
|
17295
17735
|
return [];
|
|
@@ -17311,7 +17751,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
|
|
|
17311
17751
|
}
|
|
17312
17752
|
return changes;
|
|
17313
17753
|
}, removeDuplicateTypeGraphPackages = (report) => {
|
|
17314
|
-
const manifest = readManifest(
|
|
17754
|
+
const manifest = readManifest(join44(report.installRoot, "package.json")) ?? {};
|
|
17315
17755
|
const rootName = manifestName(manifest, "<workspace>");
|
|
17316
17756
|
const installPrefix = `${realpathSync2(report.installRoot)}${sep6}`;
|
|
17317
17757
|
const nodeModulesSegment = `${sep6}node_modules${sep6}`;
|
|
@@ -17353,7 +17793,7 @@ __export(exports_doctor, {
|
|
|
17353
17793
|
import { existsSync as existsSync38, mkdirSync as mkdirSync16, readFileSync as readFileSync37, writeFileSync as writeFileSync20 } from "fs";
|
|
17354
17794
|
import { createRequire as createRequire2 } from "module";
|
|
17355
17795
|
import { arch as arch4, platform as platform5 } from "os";
|
|
17356
|
-
import { join as
|
|
17796
|
+
import { join as join45 } from "path";
|
|
17357
17797
|
var FRAMEWORK_FIELDS2, projectRequire, check = (status2, label, detail) => ({
|
|
17358
17798
|
detail,
|
|
17359
17799
|
label,
|
|
@@ -17388,7 +17828,7 @@ var FRAMEWORK_FIELDS2, projectRequire, check = (status2, label, detail) => ({
|
|
|
17388
17828
|
return [];
|
|
17389
17829
|
const label = `${field.replace("Directory", "")} pages`;
|
|
17390
17830
|
return [
|
|
17391
|
-
existsSync38(
|
|
17831
|
+
existsSync38(join45(process.cwd(), dir)) ? check("ok", label, dir) : check("fail", label, `${dir} (missing)`)
|
|
17392
17832
|
];
|
|
17393
17833
|
}), envCheck = async () => {
|
|
17394
17834
|
const vars = await collectEnvVars();
|
|
@@ -17450,9 +17890,9 @@ ${colors.dim}${checks.length} checks \xB7 ${colors.reset}${summary}${colors.dim}
|
|
|
17450
17890
|
const fixes = [];
|
|
17451
17891
|
for (const field of FRAMEWORK_FIELDS2) {
|
|
17452
17892
|
const dir = readString2(config, field);
|
|
17453
|
-
if (dir === undefined || existsSync38(
|
|
17893
|
+
if (dir === undefined || existsSync38(join45(cwd, dir)))
|
|
17454
17894
|
continue;
|
|
17455
|
-
mkdirSync16(
|
|
17895
|
+
mkdirSync16(join45(cwd, dir, "pages"), { recursive: true });
|
|
17456
17896
|
fixes.push(`created ${dir}/pages`);
|
|
17457
17897
|
}
|
|
17458
17898
|
return fixes;
|
|
@@ -17460,7 +17900,7 @@ ${colors.dim}${checks.length} checks \xB7 ${colors.reset}${summary}${colors.dim}
|
|
|
17460
17900
|
const missing = (await collectEnvVars()).filter((entry) => !entry.set);
|
|
17461
17901
|
if (missing.length === 0)
|
|
17462
17902
|
return null;
|
|
17463
|
-
const envExample =
|
|
17903
|
+
const envExample = join45(cwd, ".env.example");
|
|
17464
17904
|
const existing = existsSync38(envExample) ? readFileSync37(envExample, "utf-8") : "";
|
|
17465
17905
|
const existingKeys = new Set(existing.split(`
|
|
17466
17906
|
`).map((line) => line.split("=")[0]?.trim()));
|
|
@@ -17531,7 +17971,7 @@ var init_doctor = __esm(() => {
|
|
|
17531
17971
|
"htmlDirectory",
|
|
17532
17972
|
"htmxDirectory"
|
|
17533
17973
|
];
|
|
17534
|
-
projectRequire = createRequire2(
|
|
17974
|
+
projectRequire = createRequire2(join45(process.cwd(), "package.json"));
|
|
17535
17975
|
STATUS_MARK = {
|
|
17536
17976
|
fail: `${colors.red}\u2717${colors.reset}`,
|
|
17537
17977
|
ok: `${colors.green}\u2713${colors.reset}`,
|
|
@@ -17991,7 +18431,7 @@ __export(exports_islands, {
|
|
|
17991
18431
|
runIslands: () => runIslands
|
|
17992
18432
|
});
|
|
17993
18433
|
import { existsSync as existsSync40, readFileSync as readFileSync39, statSync as statSync5 } from "fs";
|
|
17994
|
-
import { join as
|
|
18434
|
+
import { join as join46, relative as relative23, resolve as resolve34 } from "path";
|
|
17995
18435
|
var FRAMEWORK_DIR_KEY, FRAMEWORK_COLOR, printDim6 = (message) => process.stdout.write(`${colors.dim}${message}${colors.reset}
|
|
17996
18436
|
`), hostFrameworkOf = (pagePath, cwd, config) => {
|
|
17997
18437
|
const resolved = resolve34(cwd, pagePath);
|
|
@@ -18009,13 +18449,13 @@ var FRAMEWORK_DIR_KEY, FRAMEWORK_COLOR, printDim6 = (message) => process.stdout.
|
|
|
18009
18449
|
return 0;
|
|
18010
18450
|
}
|
|
18011
18451
|
}, readManifestSizes2 = (manifestDir) => {
|
|
18012
|
-
const manifestPath =
|
|
18452
|
+
const manifestPath = join46(manifestDir, "manifest.json");
|
|
18013
18453
|
if (!existsSync40(manifestPath))
|
|
18014
18454
|
return null;
|
|
18015
18455
|
const manifest = JSON.parse(readFileSync39(manifestPath, "utf-8"));
|
|
18016
18456
|
const sizes = new Map;
|
|
18017
18457
|
for (const [key, value] of Object.entries(manifest)) {
|
|
18018
|
-
sizes.set(key, fileSize3(
|
|
18458
|
+
sizes.set(key, fileSize3(join46(manifestDir, value.replace(/^\//, ""))));
|
|
18019
18459
|
}
|
|
18020
18460
|
return sizes;
|
|
18021
18461
|
}, collectIslands = async (cwd, config, sizes) => {
|
|
@@ -18151,7 +18591,7 @@ var init_islands2 = __esm(() => {
|
|
|
18151
18591
|
|
|
18152
18592
|
// src/build/externalAssetPlugin.ts
|
|
18153
18593
|
import { copyFileSync as copyFileSync2, existsSync as existsSync41, mkdirSync as mkdirSync17, statSync as statSync6 } from "fs";
|
|
18154
|
-
import { basename as basename12, dirname as dirname27, join as
|
|
18594
|
+
import { basename as basename12, dirname as dirname27, join as join47, resolve as resolve35 } from "path";
|
|
18155
18595
|
var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
|
|
18156
18596
|
name: "absolute-external-asset",
|
|
18157
18597
|
setup(bld) {
|
|
@@ -18176,7 +18616,7 @@ var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
|
|
|
18176
18616
|
continue;
|
|
18177
18617
|
if (!statSync6(assetPath).isFile())
|
|
18178
18618
|
continue;
|
|
18179
|
-
const targetPath =
|
|
18619
|
+
const targetPath = join47(outDir, basename12(assetPath));
|
|
18180
18620
|
if (existsSync41(targetPath))
|
|
18181
18621
|
continue;
|
|
18182
18622
|
mkdirSync17(dirname27(targetPath), { recursive: true });
|
|
@@ -18211,7 +18651,7 @@ import {
|
|
|
18211
18651
|
basename as basename13,
|
|
18212
18652
|
dirname as dirname28,
|
|
18213
18653
|
isAbsolute as isAbsolute6,
|
|
18214
|
-
join as
|
|
18654
|
+
join as join48,
|
|
18215
18655
|
relative as relative24,
|
|
18216
18656
|
resolve as resolve36
|
|
18217
18657
|
} from "path";
|
|
@@ -18227,7 +18667,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
18227
18667
|
const entry = pending.pop();
|
|
18228
18668
|
if (!entry)
|
|
18229
18669
|
continue;
|
|
18230
|
-
const fullPath =
|
|
18670
|
+
const fullPath = join48(entry.parentPath, entry.name);
|
|
18231
18671
|
if (entry.isDirectory())
|
|
18232
18672
|
pending = pending.concat(readdirSync7(fullPath, { withFileTypes: true }));
|
|
18233
18673
|
else
|
|
@@ -18273,7 +18713,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
18273
18713
|
const entry = pending.pop();
|
|
18274
18714
|
if (!entry)
|
|
18275
18715
|
continue;
|
|
18276
|
-
const fullPath =
|
|
18716
|
+
const fullPath = join48(entry.parentPath, entry.name);
|
|
18277
18717
|
if (entry.isDirectory()) {
|
|
18278
18718
|
if (SERVER_RUNTIME_SCAN_SKIP_DIRS.has(entry.name))
|
|
18279
18719
|
continue;
|
|
@@ -18412,7 +18852,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
18412
18852
|
return nativeAssetEnv;
|
|
18413
18853
|
}, tryReadNodePackageJson = (packageDir) => {
|
|
18414
18854
|
try {
|
|
18415
|
-
return JSON.parse(readFileSync40(
|
|
18855
|
+
return JSON.parse(readFileSync40(join48(packageDir, "package.json"), "utf-8"));
|
|
18416
18856
|
} catch {
|
|
18417
18857
|
return null;
|
|
18418
18858
|
}
|
|
@@ -18424,7 +18864,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
18424
18864
|
if (!pkg)
|
|
18425
18865
|
return;
|
|
18426
18866
|
seen.add(specifier);
|
|
18427
|
-
const destDir =
|
|
18867
|
+
const destDir = join48(outdir, "node_modules", ...specifier.split("/"));
|
|
18428
18868
|
rmSync7(destDir, { force: true, recursive: true });
|
|
18429
18869
|
cpSync(srcDir, destDir, {
|
|
18430
18870
|
force: true,
|
|
@@ -18465,7 +18905,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
18465
18905
|
copyAngularRuntimePackages(buildConfig, outdir);
|
|
18466
18906
|
copyChunkReferencedPackages(outdir, seen);
|
|
18467
18907
|
}, collectRuntimePackageSpecifiers = (distDir) => {
|
|
18468
|
-
const nodeModulesDir =
|
|
18908
|
+
const nodeModulesDir = join48(distDir, "node_modules");
|
|
18469
18909
|
if (!existsSync42(nodeModulesDir))
|
|
18470
18910
|
return [];
|
|
18471
18911
|
const specifiers = [];
|
|
@@ -18473,7 +18913,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
18473
18913
|
if (!entry.isDirectory())
|
|
18474
18914
|
continue;
|
|
18475
18915
|
if (entry.name.startsWith("@")) {
|
|
18476
|
-
const scopeDir =
|
|
18916
|
+
const scopeDir = join48(nodeModulesDir, entry.name);
|
|
18477
18917
|
for (const scopedEntry of readdirSync7(scopeDir, {
|
|
18478
18918
|
withFileTypes: true
|
|
18479
18919
|
})) {
|
|
@@ -18504,18 +18944,18 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
18504
18944
|
const packageSpecifier = packageSpecifiers.find((root) => specifier === root || specifier.startsWith(`${root}/`));
|
|
18505
18945
|
if (!packageSpecifier)
|
|
18506
18946
|
return null;
|
|
18507
|
-
const packageDir =
|
|
18947
|
+
const packageDir = join48(distDir, "node_modules", ...packageSpecifier.split("/"));
|
|
18508
18948
|
const subpath = specifier.slice(packageSpecifier.length);
|
|
18509
|
-
const subPackageDir = subpath ?
|
|
18510
|
-
const resolvedPackageDir = subPackageDir && existsSync42(
|
|
18511
|
-
const packageJsonPath =
|
|
18949
|
+
const subPackageDir = subpath ? join48(packageDir, ...subpath.slice(1).split("/")) : null;
|
|
18950
|
+
const resolvedPackageDir = subPackageDir && existsSync42(join48(subPackageDir, "package.json")) ? subPackageDir : packageDir;
|
|
18951
|
+
const packageJsonPath = join48(resolvedPackageDir, "package.json");
|
|
18512
18952
|
if (!existsSync42(packageJsonPath))
|
|
18513
18953
|
return null;
|
|
18514
18954
|
const pkg = JSON.parse(readFileSync40(packageJsonPath, "utf-8"));
|
|
18515
18955
|
const exportKey = resolvedPackageDir !== subPackageDir && subpath ? `.${subpath}` : ".";
|
|
18516
18956
|
const rootExport = pkg.exports?.[exportKey];
|
|
18517
18957
|
const entry = pickExportEntry(rootExport) ?? (resolvedPackageDir === subPackageDir || !subpath ? pkg.module ?? pkg.main ?? "index.js" : `.${subpath}`);
|
|
18518
|
-
return
|
|
18958
|
+
return join48(resolvedPackageDir, entry);
|
|
18519
18959
|
}, RUNTIME_JS_EXTENSIONS, MODULE_SPECIFIER_RE, isRuntimeJsFile = (filePath) => RUNTIME_JS_EXTENSIONS.some((extension) => filePath.endsWith(extension)), isNodeModulesPath = (filePath) => filePath.split(/[\\/]/).includes("node_modules"), isFile = (filePath) => {
|
|
18520
18960
|
try {
|
|
18521
18961
|
return statSync7(filePath).isFile();
|
|
@@ -18528,13 +18968,13 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
18528
18968
|
const candidates = [
|
|
18529
18969
|
candidate,
|
|
18530
18970
|
...RUNTIME_JS_EXTENSIONS.map((extension) => `${candidate}${extension}`),
|
|
18531
|
-
...RUNTIME_JS_EXTENSIONS.map((extension) =>
|
|
18971
|
+
...RUNTIME_JS_EXTENSIONS.map((extension) => join48(candidate, `index${extension}`))
|
|
18532
18972
|
];
|
|
18533
18973
|
return candidates.find((filePath) => isRuntimeJsFile(filePath) && isFile(filePath)) ?? null;
|
|
18534
18974
|
}, findContainingRuntimePackageDir = (filePath) => {
|
|
18535
18975
|
let dir = dirname28(filePath);
|
|
18536
18976
|
while (dir !== dirname28(dir)) {
|
|
18537
|
-
if (isNodeModulesPath(dir) && existsSync42(
|
|
18977
|
+
if (isNodeModulesPath(dir) && existsSync42(join48(dir, "package.json"))) {
|
|
18538
18978
|
return dir;
|
|
18539
18979
|
}
|
|
18540
18980
|
dir = dirname28(dir);
|
|
@@ -18550,7 +18990,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
|
|
|
18550
18990
|
const entry = pickExportEntry(pkg?.imports?.[specifier]);
|
|
18551
18991
|
if (!entry)
|
|
18552
18992
|
return null;
|
|
18553
|
-
return
|
|
18993
|
+
return join48(packageDir, entry);
|
|
18554
18994
|
}, collectRuntimeRewriteRoots = (distDir) => collectFiles2(distDir).filter((filePath) => isRuntimeJsFile(filePath) && !isNodeModulesPath(filePath)), toTopLevelPackage = (specifier) => specifier.split("/").slice(0, specifier.startsWith("@") ? 2 : 1).join("/"), FRAMEWORK_PACKAGE_NAME = "@absolutejs/absolute", copyChunkReferencedPackages = (distDir, seen) => {
|
|
18555
18995
|
const distRoot = resolve36(distDir);
|
|
18556
18996
|
for (const filePath of collectRuntimeRewriteRoots(distDir)) {
|
|
@@ -19117,7 +19557,7 @@ console.log(\`
|
|
|
19117
19557
|
const resolvedOutdir = resolve36(outdir ?? "dist");
|
|
19118
19558
|
await withBuildDirectoryLock(resolvedOutdir, () => compileUnlocked(serverEntry, resolvedOutdir, outfile, configPath2));
|
|
19119
19559
|
}, compileUnlocked = async (serverEntry, resolvedOutdir, outfile, configPath2) => {
|
|
19120
|
-
rmSync7(
|
|
19560
|
+
rmSync7(join48(resolvedOutdir, "node_modules"), {
|
|
19121
19561
|
force: true,
|
|
19122
19562
|
recursive: true
|
|
19123
19563
|
});
|
|
@@ -19165,10 +19605,10 @@ console.log(\`
|
|
|
19165
19605
|
].filter((dir) => Boolean(dir));
|
|
19166
19606
|
const islandRegistrySpec = buildConfig.islands?.registry;
|
|
19167
19607
|
const islandRegistryPlugin = islandRegistrySpec ? createIslandRegistryDefinitionPlugin(await loadIslandRegistryBuildInfo(resolve36(islandRegistrySpec))) : undefined;
|
|
19168
|
-
const serverBundleEntryDirectory =
|
|
19608
|
+
const serverBundleEntryDirectory = join48(resolvedOutdir, ".absolutejs-server-entry");
|
|
19169
19609
|
mkdirSync18(serverBundleEntryDirectory, { recursive: true });
|
|
19170
|
-
const typeboxSetupEntry =
|
|
19171
|
-
const serverBundleEntry =
|
|
19610
|
+
const typeboxSetupEntry = join48(serverBundleEntryDirectory, "_typebox_setup.ts");
|
|
19611
|
+
const serverBundleEntry = join48(serverBundleEntryDirectory, basename13(serverEntry));
|
|
19172
19612
|
writeFileSync21(typeboxSetupEntry, `import { setupTypebox } from 'elysia';
|
|
19173
19613
|
import * as compile from 'typebox/compile';
|
|
19174
19614
|
import * as schema from 'typebox/schema';
|
|
@@ -19244,7 +19684,7 @@ export default server;
|
|
|
19244
19684
|
copyServerRuntimeAssetReferences(resolvedOutdir);
|
|
19245
19685
|
const prerenderStart = performance.now();
|
|
19246
19686
|
process.stdout.write(cliTag4("\x1B[36m", "Pre-rendering pages"));
|
|
19247
|
-
rmSync7(
|
|
19687
|
+
rmSync7(join48(resolvedOutdir, "_prerendered"), {
|
|
19248
19688
|
force: true,
|
|
19249
19689
|
recursive: true
|
|
19250
19690
|
});
|
|
@@ -19274,7 +19714,7 @@ export default server;
|
|
|
19274
19714
|
const compileStart = performance.now();
|
|
19275
19715
|
process.stdout.write(cliTag4("\x1B[36m", "Compiling standalone executable"));
|
|
19276
19716
|
const entrypointCode = generateEntrypoint(resolvedOutdir, serverEntry, prerenderMap, absoluteVersion, buildConfig);
|
|
19277
|
-
const entrypointPath =
|
|
19717
|
+
const entrypointPath = join48(resolvedOutdir, "_compile_entrypoint.ts");
|
|
19278
19718
|
await Bun.write(entrypointPath, entrypointCode);
|
|
19279
19719
|
mkdirSync18(dirname28(resolvedOutfile), { recursive: true });
|
|
19280
19720
|
const result = await Bun.build({
|
|
@@ -19360,7 +19800,7 @@ var init_compile = __esm(() => {
|
|
|
19360
19800
|
|
|
19361
19801
|
// src/mobile/nativeDeepLinks.ts
|
|
19362
19802
|
import { readFile as readFile13, rename as rename9, writeFile as writeFile10 } from "fs/promises";
|
|
19363
|
-
import { join as
|
|
19803
|
+
import { join as join49 } from "path";
|
|
19364
19804
|
var START_MARKER = "<!-- absolutejs:deep-links:start -->", END_MARKER = "<!-- absolutejs:deep-links:end -->", IOS_ENTITLEMENTS = "App/AbsoluteJS.entitlements", NOT_FOUND = -1, escapeXml = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">"), writeChangedFile = async (path, source) => {
|
|
19365
19805
|
const current = await readFile13(path, "utf8");
|
|
19366
19806
|
if (current === source)
|
|
@@ -19409,7 +19849,7 @@ ${hosts}
|
|
|
19409
19849
|
${END_MARKER}
|
|
19410
19850
|
`;
|
|
19411
19851
|
}, configureAndroid = async (config) => {
|
|
19412
|
-
const path =
|
|
19852
|
+
const path = join49(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
|
|
19413
19853
|
const source = await readFile13(path, "utf8");
|
|
19414
19854
|
const mainActivity = source.indexOf('android:name=".MainActivity"');
|
|
19415
19855
|
if (mainActivity === NOT_FOUND) {
|
|
@@ -19433,7 +19873,7 @@ ${hosts}
|
|
|
19433
19873
|
</array>
|
|
19434
19874
|
${END_MARKER}
|
|
19435
19875
|
`, configureIosInfo = async (config) => {
|
|
19436
|
-
const path =
|
|
19876
|
+
const path = join49(config.nativeProjectDirectory, "ios/App/App/Info.plist");
|
|
19437
19877
|
const source = await readFile13(path, "utf8");
|
|
19438
19878
|
const region = config.deepLinkScheme ? iosSchemeRegion(config.deepLinkScheme) : ` ${START_MARKER}
|
|
19439
19879
|
${END_MARKER}
|
|
@@ -19455,7 +19895,7 @@ ${domains}
|
|
|
19455
19895
|
</plist>
|
|
19456
19896
|
`;
|
|
19457
19897
|
}, configureIosEntitlements = async (config) => {
|
|
19458
|
-
const path =
|
|
19898
|
+
const path = join49(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
|
|
19459
19899
|
let current = "";
|
|
19460
19900
|
try {
|
|
19461
19901
|
current = await readFile13(path, "utf8");
|
|
@@ -19472,7 +19912,7 @@ ${domains}
|
|
|
19472
19912
|
await rename9(temporary, path);
|
|
19473
19913
|
return true;
|
|
19474
19914
|
}, configureIosProject = async (config) => {
|
|
19475
|
-
const path =
|
|
19915
|
+
const path = join49(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
|
|
19476
19916
|
const source = await readFile13(path, "utf8");
|
|
19477
19917
|
const declarations = [
|
|
19478
19918
|
...source.matchAll(/CODE_SIGN_ENTITLEMENTS = ([^;]+);/g)
|
|
@@ -19512,7 +19952,7 @@ var init_nativeDeepLinks = () => {};
|
|
|
19512
19952
|
|
|
19513
19953
|
// src/mobile/nativeDeviceCapabilities.ts
|
|
19514
19954
|
import { readFile as readFile14, rename as rename10, writeFile as writeFile11 } from "fs/promises";
|
|
19515
|
-
import { join as
|
|
19955
|
+
import { join as join50 } from "path";
|
|
19516
19956
|
var START_MARKER2 = "<!-- absolutejs:device-capabilities:start -->", END_MARKER2 = "<!-- absolutejs:device-capabilities:end -->", NOT_FOUND2 = -1, IOS_PRIVACY_FILE_REFERENCE = "A85D0C000000000000000001", IOS_PRIVACY_BUILD_FILE = "A85D0C000000000000000002", PUSH_START_MARKER = "absolutejs:push-notifications:start", PUSH_END_MARKER = "absolutejs:push-notifications:end", escapeXml2 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">"), writeChangedFile2 = async (path, source) => {
|
|
19517
19957
|
const current = await readFile14(path, "utf8");
|
|
19518
19958
|
if (current === source)
|
|
@@ -19639,7 +20079,7 @@ ${entries}
|
|
|
19639
20079
|
}, configureIosPrivacyProject = async (config, requirements) => {
|
|
19640
20080
|
if (requirements.iosPrivacyAccessedApis.length === 0)
|
|
19641
20081
|
return false;
|
|
19642
|
-
const projectPath =
|
|
20082
|
+
const projectPath = join50(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
|
|
19643
20083
|
const project = await readFile14(projectPath, "utf8");
|
|
19644
20084
|
return writeChangedFile2(projectPath, addIosPrivacyProjectReference(project));
|
|
19645
20085
|
}, addIosPrivacyProjectReference = (source) => {
|
|
@@ -19690,7 +20130,7 @@ ${next.slice(index)}`;
|
|
|
19690
20130
|
}
|
|
19691
20131
|
return next;
|
|
19692
20132
|
}, configureIos2 = async (config, plan) => {
|
|
19693
|
-
const path =
|
|
20133
|
+
const path = join50(config.nativeProjectDirectory, "ios/App/App/Info.plist");
|
|
19694
20134
|
const source = await readFile14(path, "utf8");
|
|
19695
20135
|
const requirements = absoluteDeviceNativeRequirements(plan);
|
|
19696
20136
|
const existingSystemBars = source.match(/<key>UIViewControllerBasedStatusBarAppearance<\/key>\s*<(true|false)\s*\/>/u);
|
|
@@ -19711,7 +20151,7 @@ ${content}
|
|
|
19711
20151
|
${END_MARKER2}
|
|
19712
20152
|
` : "";
|
|
19713
20153
|
const infoChanged = await writeChangedFile2(path, managed(source, region, source.lastIndexOf("</dict>")));
|
|
19714
|
-
const privacyPath =
|
|
20154
|
+
const privacyPath = join50(config.nativeProjectDirectory, "ios/App/App/PrivacyInfo.xcprivacy");
|
|
19715
20155
|
const privacyCurrent = await optionalSource(privacyPath);
|
|
19716
20156
|
const privacySource = privacyManifestSource(privacyCurrent, requirements);
|
|
19717
20157
|
const [privacyChanged, projectChanged, pushChanged] = await Promise.all([
|
|
@@ -19721,7 +20161,7 @@ ${content}
|
|
|
19721
20161
|
]);
|
|
19722
20162
|
return infoChanged || privacyChanged || projectChanged || pushChanged;
|
|
19723
20163
|
}, configureIosPushNotifications = async (config, enabled) => {
|
|
19724
|
-
const entitlementsPath =
|
|
20164
|
+
const entitlementsPath = join50(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
|
|
19725
20165
|
const entitlements = await optionalSource(entitlementsPath);
|
|
19726
20166
|
if (entitlements === null && !enabled)
|
|
19727
20167
|
return false;
|
|
@@ -19733,7 +20173,7 @@ ${content}
|
|
|
19733
20173
|
<!-- ${PUSH_END_MARKER} -->
|
|
19734
20174
|
` : "";
|
|
19735
20175
|
const nextEntitlements = replacePushRegion(entitlements, entitlementRegion, entitlements.lastIndexOf("</dict>"));
|
|
19736
|
-
const delegatePath =
|
|
20176
|
+
const delegatePath = join50(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
19737
20177
|
const delegate = await optionalSource(delegatePath);
|
|
19738
20178
|
if (delegate === null && !enabled)
|
|
19739
20179
|
return false;
|
|
@@ -19780,7 +20220,7 @@ ${content}
|
|
|
19780
20220
|
throw new TypeError("Could not find a safe native project location for push notifications.");
|
|
19781
20221
|
return `${source.slice(0, insertion)}${region}${source.slice(insertion)}`;
|
|
19782
20222
|
}, configureAndroid2 = async (config, plan) => {
|
|
19783
|
-
const path =
|
|
20223
|
+
const path = join50(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
|
|
19784
20224
|
const source = await readFile14(path, "utf8");
|
|
19785
20225
|
const permissions = absoluteDeviceNativeRequirements(plan).androidPermissions;
|
|
19786
20226
|
const content = permissions.map((permission) => ` <uses-permission android:name="${escapeXml2(permission)}" />`).join(`
|
|
@@ -19816,7 +20256,7 @@ ${content}
|
|
|
19816
20256
|
throw new TypeError(`Android google-services.json does not contain package ${config.appId}.`);
|
|
19817
20257
|
const [manifestChanged, firebaseChanged] = await Promise.all([
|
|
19818
20258
|
writeChangedFile2(path, nextManifest),
|
|
19819
|
-
writeOptionalChangedFile(
|
|
20259
|
+
writeOptionalChangedFile(join50(config.nativeProjectDirectory, "android/app/google-services.json"), firebaseSource)
|
|
19820
20260
|
]);
|
|
19821
20261
|
return manifestChanged || firebaseChanged;
|
|
19822
20262
|
}, applyAbsoluteNativeDeviceCapabilities = async (projectRoot, config, platforms = config.platforms, plan = resolveAbsoluteDeviceCapabilityPlan(projectRoot)) => {
|
|
@@ -19841,7 +20281,7 @@ var init_nativeDeviceCapabilities = __esm(() => {
|
|
|
19841
20281
|
|
|
19842
20282
|
// src/mobile/nativeBackgroundSync.ts
|
|
19843
20283
|
import { readFile as readFile15, rename as rename11, writeFile as writeFile12 } from "fs/promises";
|
|
19844
|
-
import { join as
|
|
20284
|
+
import { join as join51 } from "path";
|
|
19845
20285
|
var writeChanged = async (path, source) => {
|
|
19846
20286
|
const current = await readFile15(path, "utf8");
|
|
19847
20287
|
if (current === source)
|
|
@@ -19924,10 +20364,10 @@ ${makeRegion(values)} </array>
|
|
|
19924
20364
|
if (!platforms.includes("ios") || !projectUsesAbsoluteAuth(projectRoot) || !projectUsesAbsoluteSync(projectRoot))
|
|
19925
20365
|
return { changed: false };
|
|
19926
20366
|
const identifier = `${config.appId}.absolutejs.background-sync`;
|
|
19927
|
-
const infoPath =
|
|
20367
|
+
const infoPath = join51(config.nativeProjectDirectory, "ios/App/App/Info.plist");
|
|
19928
20368
|
const info2 = await readFile15(infoPath, "utf8");
|
|
19929
20369
|
const nextInfo = ensurePlistArrayValues(ensurePlistArrayValues(info2, "BGTaskSchedulerPermittedIdentifiers", [identifier], "background-sync-identifiers"), "UIBackgroundModes", ["fetch", "processing"], "background-sync-modes");
|
|
19930
|
-
const delegatePath =
|
|
20370
|
+
const delegatePath = join51(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
19931
20371
|
let delegate = await readFile15(delegatePath, "utf8");
|
|
19932
20372
|
if (!delegate.includes("import AbsoluteSyncCapacitor")) {
|
|
19933
20373
|
const importIndex = delegate.lastIndexOf("import Capacitor");
|
|
@@ -19967,7 +20407,7 @@ import {
|
|
|
19967
20407
|
rm as rm9,
|
|
19968
20408
|
writeFile as writeFile13
|
|
19969
20409
|
} from "fs/promises";
|
|
19970
|
-
import { dirname as dirname29, join as
|
|
20410
|
+
import { dirname as dirname29, join as join52 } from "path";
|
|
19971
20411
|
var START = "// absolutejs:mobile-updates:start", END = "// absolutejs:mobile-updates:end", PLUGIN_START = "// absolutejs:mobile-update-plugin:start", PLUGIN_END = "// absolutejs:mobile-update-plugin:end", ANDROID_PLUGIN = "AbsoluteMobileUpdateWatchdogPlugin.java", optionalSource2 = async (path) => {
|
|
19972
20412
|
try {
|
|
19973
20413
|
return await readFile16(path, "utf8");
|
|
@@ -20123,8 +20563,8 @@ public final class AbsoluteMobileUpdateWatchdogPlugin: CAPPlugin, CAPBridgedPlug
|
|
|
20123
20563
|
}
|
|
20124
20564
|
${PLUGIN_END}
|
|
20125
20565
|
`, configureIos3 = async (config, enabled) => {
|
|
20126
|
-
const path =
|
|
20127
|
-
const capacitorConfigPath =
|
|
20566
|
+
const path = join52(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
20567
|
+
const capacitorConfigPath = join52(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
|
|
20128
20568
|
let source = await readFile16(path, "utf8");
|
|
20129
20569
|
const launch = source.indexOf("didFinishLaunchingWithOptions");
|
|
20130
20570
|
const brace = launch < 0 ? -1 : source.indexOf("{", launch);
|
|
@@ -20312,11 +20752,11 @@ public final class AbsoluteMobileUpdateWatchdogPlugin extends Plugin {
|
|
|
20312
20752
|
throw error;
|
|
20313
20753
|
}
|
|
20314
20754
|
const candidate = entries.find((entry) => entry.endsWith("/MainActivity.java") || entry.endsWith("/MainActivity.kt") || entry === "MainActivity.java" || entry === "MainActivity.kt");
|
|
20315
|
-
return candidate ?
|
|
20755
|
+
return candidate ? join52(root, candidate) : undefined;
|
|
20316
20756
|
}, androidActivity = async (config) => {
|
|
20317
20757
|
const roots = [
|
|
20318
|
-
|
|
20319
|
-
|
|
20758
|
+
join52(config.nativeProjectDirectory, "android/app/src/main/java"),
|
|
20759
|
+
join52(config.nativeProjectDirectory, "android/app/src/main/kotlin")
|
|
20320
20760
|
];
|
|
20321
20761
|
const candidates = await Promise.all(roots.map(androidActivityInRoot));
|
|
20322
20762
|
const candidate = candidates.find((value) => value !== undefined);
|
|
@@ -20417,7 +20857,7 @@ public final class AbsoluteMobileUpdateWatchdogPlugin extends Plugin {
|
|
|
20417
20857
|
if (!packageName)
|
|
20418
20858
|
throw new TypeError("Android MainActivity package declaration was not found.");
|
|
20419
20859
|
const packagePath = packageName.replaceAll(".", "/");
|
|
20420
|
-
const pluginPath =
|
|
20860
|
+
const pluginPath = join52(config.nativeProjectDirectory, "android/app/src/main/java", packagePath, ANDROID_PLUGIN);
|
|
20421
20861
|
const changed = await Promise.all([
|
|
20422
20862
|
writeChanged2(activityPath, injectAndroidActivity(activity, enabled)),
|
|
20423
20863
|
enabled ? writeChanged2(pluginPath, androidPluginSource(packageName, config.updates?.bootTimeoutMs ?? 20000)) : removeOwnedFile(pluginPath)
|
|
@@ -20436,15 +20876,534 @@ public final class AbsoluteMobileUpdateWatchdogPlugin extends Plugin {
|
|
|
20436
20876
|
};
|
|
20437
20877
|
var init_nativeUpdates = () => {};
|
|
20438
20878
|
|
|
20439
|
-
// src/mobile/
|
|
20879
|
+
// src/mobile/nativeObservability.ts
|
|
20440
20880
|
import {
|
|
20441
|
-
access as access9,
|
|
20442
20881
|
mkdir as mkdir12,
|
|
20443
20882
|
readFile as readFile17,
|
|
20883
|
+
readdir as readdir6,
|
|
20444
20884
|
rename as rename13,
|
|
20445
20885
|
rm as rm10,
|
|
20446
20886
|
writeFile as writeFile14
|
|
20447
20887
|
} from "fs/promises";
|
|
20888
|
+
import { dirname as dirname30, join as join53 } from "path";
|
|
20889
|
+
var START2 = "// absolutejs:native-observability:start", END2 = "// absolutejs:native-observability:end", PLUGIN_START2 = "// absolutejs:native-observability-plugin:start", PLUGIN_END2 = "// absolutejs:native-observability-plugin:end", ANDROID_PLUGIN2 = "AbsoluteMobileObservabilityPlugin.java", optionalSource3 = async (path) => {
|
|
20890
|
+
try {
|
|
20891
|
+
return await readFile17(path, "utf8");
|
|
20892
|
+
} catch (error) {
|
|
20893
|
+
if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
|
|
20894
|
+
return null;
|
|
20895
|
+
throw error;
|
|
20896
|
+
}
|
|
20897
|
+
}, writeChanged3 = async (path, source) => {
|
|
20898
|
+
const current = await optionalSource3(path);
|
|
20899
|
+
if (current === source)
|
|
20900
|
+
return false;
|
|
20901
|
+
await mkdir12(dirname30(path), { recursive: true });
|
|
20902
|
+
if (current === null) {
|
|
20903
|
+
await writeFile14(path, source, { flag: "wx" });
|
|
20904
|
+
return true;
|
|
20905
|
+
}
|
|
20906
|
+
const temporary = `${path}.${crypto.randomUUID()}.tmp`;
|
|
20907
|
+
await writeFile14(temporary, source, { flag: "wx" });
|
|
20908
|
+
await rename13(temporary, path);
|
|
20909
|
+
return true;
|
|
20910
|
+
}, removeOwnedFile2 = async (path) => {
|
|
20911
|
+
if (await optionalSource3(path) === null)
|
|
20912
|
+
return false;
|
|
20913
|
+
await rm10(path);
|
|
20914
|
+
return true;
|
|
20915
|
+
}, isRecord15 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), replaceMarkedRegion2 = (source, start2, end, region, insertion, error) => {
|
|
20916
|
+
const existingStart = source.indexOf(start2);
|
|
20917
|
+
const existingEnd = source.indexOf(end);
|
|
20918
|
+
if (existingStart < 0 !== existingEnd < 0 || existingStart >= 0 && existingEnd < existingStart)
|
|
20919
|
+
throw new TypeError("AbsoluteJS native observability markers are malformed.");
|
|
20920
|
+
if (existingStart >= 0) {
|
|
20921
|
+
const from = source.lastIndexOf(`
|
|
20922
|
+
`, existingStart) + 1;
|
|
20923
|
+
const newline = source.indexOf(`
|
|
20924
|
+
`, existingEnd + end.length);
|
|
20925
|
+
return `${source.slice(0, from)}${region}${source.slice(newline < 0 ? source.length : newline + 1)}`;
|
|
20926
|
+
}
|
|
20927
|
+
if (!region)
|
|
20928
|
+
return source;
|
|
20929
|
+
if (insertion < 0)
|
|
20930
|
+
throw new TypeError(error);
|
|
20931
|
+
return `${source.slice(0, insertion)}${region}${source.slice(insertion)}`;
|
|
20932
|
+
}, iosPluginRegion2, configureIos4 = async (config, enabled) => {
|
|
20933
|
+
const path = join53(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
20934
|
+
const capacitorConfigPath = join53(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
|
|
20935
|
+
let source = await readFile17(path, "utf8");
|
|
20936
|
+
if (enabled && !source.includes("import MetricKit")) {
|
|
20937
|
+
const capacitorImport = source.lastIndexOf("import Capacitor");
|
|
20938
|
+
if (capacitorImport < 0)
|
|
20939
|
+
throw new TypeError("Capacitor AppDelegate import was not found.");
|
|
20940
|
+
const newline = source.indexOf(`
|
|
20941
|
+
`, capacitorImport);
|
|
20942
|
+
source = `${source.slice(0, newline + 1)}import MetricKit
|
|
20943
|
+
${source.slice(newline + 1)}`;
|
|
20944
|
+
}
|
|
20945
|
+
if (!enabled)
|
|
20946
|
+
source = source.replace(`import MetricKit
|
|
20947
|
+
`, "");
|
|
20948
|
+
source = replaceMarkedRegion2(source, PLUGIN_START2, PLUGIN_END2, enabled ? iosPluginRegion2 : "", source.length, "Could not find a safe iOS location for native observability.");
|
|
20949
|
+
const capacitorConfigSource2 = await readFile17(capacitorConfigPath, "utf8");
|
|
20950
|
+
let capacitorConfig;
|
|
20951
|
+
try {
|
|
20952
|
+
const value = JSON.parse(capacitorConfigSource2);
|
|
20953
|
+
if (!isRecord15(value))
|
|
20954
|
+
throw new TypeError;
|
|
20955
|
+
capacitorConfig = value;
|
|
20956
|
+
} catch {
|
|
20957
|
+
throw new TypeError("iOS capacitor.config.json is invalid; run Capacitor sync before projecting native observability.");
|
|
20958
|
+
}
|
|
20959
|
+
const packageClassList = Reflect.get(capacitorConfig, "packageClassList");
|
|
20960
|
+
if (!Array.isArray(packageClassList))
|
|
20961
|
+
throw new TypeError("iOS capacitor.config.json has no packageClassList; run Capacitor sync before projecting native observability.");
|
|
20962
|
+
const classes = packageClassList.filter((value) => typeof value === "string");
|
|
20963
|
+
const nextClasses = enabled ? [...new Set([...classes, "AbsoluteMobileObservabilityPlugin"])] : classes.filter((value) => value !== "AbsoluteMobileObservabilityPlugin");
|
|
20964
|
+
const nextCapacitorConfig = `${JSON.stringify({ ...capacitorConfig, packageClassList: nextClasses }, null, "\t")}
|
|
20965
|
+
`;
|
|
20966
|
+
const changed = await Promise.all([
|
|
20967
|
+
writeChanged3(path, source),
|
|
20968
|
+
writeChanged3(capacitorConfigPath, nextCapacitorConfig)
|
|
20969
|
+
]);
|
|
20970
|
+
return changed.some(Boolean);
|
|
20971
|
+
}, androidPluginSource2 = (packageName) => `package ${packageName};
|
|
20972
|
+
|
|
20973
|
+
import android.app.ActivityManager;
|
|
20974
|
+
import android.app.ApplicationExitInfo;
|
|
20975
|
+
import android.os.Build;
|
|
20976
|
+
import android.util.Base64;
|
|
20977
|
+
import com.getcapacitor.JSArray;
|
|
20978
|
+
import com.getcapacitor.JSObject;
|
|
20979
|
+
import com.getcapacitor.Plugin;
|
|
20980
|
+
import com.getcapacitor.PluginCall;
|
|
20981
|
+
import com.getcapacitor.PluginMethod;
|
|
20982
|
+
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
20983
|
+
import java.io.ByteArrayOutputStream;
|
|
20984
|
+
import java.io.File;
|
|
20985
|
+
import java.io.FileInputStream;
|
|
20986
|
+
import java.io.FileOutputStream;
|
|
20987
|
+
import java.io.InputStream;
|
|
20988
|
+
import java.nio.charset.StandardCharsets;
|
|
20989
|
+
import java.util.ArrayList;
|
|
20990
|
+
import java.util.HashSet;
|
|
20991
|
+
import java.util.List;
|
|
20992
|
+
import java.util.Set;
|
|
20993
|
+
import org.json.JSONArray;
|
|
20994
|
+
import org.json.JSONObject;
|
|
20995
|
+
|
|
20996
|
+
@CapacitorPlugin(name = "AbsoluteMobileObservability")
|
|
20997
|
+
public final class AbsoluteMobileObservabilityPlugin extends Plugin {
|
|
20998
|
+
private static final int MAX_REPORTS = 8;
|
|
20999
|
+
private static final int MAX_TRACE_BYTES = 32 * 1024;
|
|
21000
|
+
private static final String ACKNOWLEDGED_KEY = "acknowledged";
|
|
21001
|
+
private static final String PREFERENCES = "AbsoluteMobileObservability";
|
|
21002
|
+
|
|
21003
|
+
private File root() {
|
|
21004
|
+
File value = new File(getContext().getFilesDir(), "absolute-mobile-observability");
|
|
21005
|
+
value.mkdirs();
|
|
21006
|
+
return value;
|
|
21007
|
+
}
|
|
21008
|
+
|
|
21009
|
+
private Set<String> acknowledged() {
|
|
21010
|
+
Set<String> result = new HashSet<>();
|
|
21011
|
+
try {
|
|
21012
|
+
JSONArray values = new JSONArray(getContext().getSharedPreferences(PREFERENCES, 0).getString(ACKNOWLEDGED_KEY, "[]"));
|
|
21013
|
+
for (int index = 0; index < values.length(); index++) result.add(values.optString(index));
|
|
21014
|
+
} catch (Exception ignored) {}
|
|
21015
|
+
return result;
|
|
21016
|
+
}
|
|
21017
|
+
|
|
21018
|
+
private void writeAcknowledged(Set<String> values) {
|
|
21019
|
+
List<String> sorted = new ArrayList<>(values);
|
|
21020
|
+
sorted.sort(String::compareTo);
|
|
21021
|
+
if (sorted.size() > 64) sorted = sorted.subList(sorted.size() - 64, sorted.size());
|
|
21022
|
+
getContext().getSharedPreferences(PREFERENCES, 0).edit().putString(ACKNOWLEDGED_KEY, new JSONArray(sorted).toString()).apply();
|
|
21023
|
+
}
|
|
21024
|
+
|
|
21025
|
+
private static String kind(int reason) {
|
|
21026
|
+
if (reason == ApplicationExitInfo.REASON_ANR) return "anr";
|
|
21027
|
+
if (reason == ApplicationExitInfo.REASON_CRASH) return "crash";
|
|
21028
|
+
if (reason == ApplicationExitInfo.REASON_CRASH_NATIVE) return "native-crash";
|
|
21029
|
+
if (reason == ApplicationExitInfo.REASON_LOW_MEMORY) return "low-memory";
|
|
21030
|
+
if (reason == ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE) return "resource-exhaustion";
|
|
21031
|
+
if (reason == ApplicationExitInfo.REASON_INITIALIZATION_FAILURE) return "initialization-failure";
|
|
21032
|
+
if (reason == ApplicationExitInfo.REASON_SIGNALED) return "signal";
|
|
21033
|
+
return null;
|
|
21034
|
+
}
|
|
21035
|
+
|
|
21036
|
+
private static byte[] trace(ApplicationExitInfo info) {
|
|
21037
|
+
try (InputStream input = info.getTraceInputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
|
21038
|
+
if (input == null) return null;
|
|
21039
|
+
byte[] buffer = new byte[4096];
|
|
21040
|
+
int total = 0;
|
|
21041
|
+
int read;
|
|
21042
|
+
while ((read = input.read(buffer, 0, Math.min(buffer.length, MAX_TRACE_BYTES + 1 - total))) > 0) {
|
|
21043
|
+
output.write(buffer, 0, read);
|
|
21044
|
+
total += read;
|
|
21045
|
+
if (total > MAX_TRACE_BYTES) return null;
|
|
21046
|
+
}
|
|
21047
|
+
return output.toByteArray();
|
|
21048
|
+
} catch (Exception ignored) {
|
|
21049
|
+
return null;
|
|
21050
|
+
}
|
|
21051
|
+
}
|
|
21052
|
+
|
|
21053
|
+
private static JSONObject report(ApplicationExitInfo info) {
|
|
21054
|
+
String kind = kind(info.getReason());
|
|
21055
|
+
if (kind == null) return null;
|
|
21056
|
+
String id = "android:" + info.getTimestamp() + ":" + info.getReason() + ":" + info.getStatus();
|
|
21057
|
+
JSONObject details = new JSONObject();
|
|
21058
|
+
try {
|
|
21059
|
+
details.put("importance", info.getImportance());
|
|
21060
|
+
details.put("pssKb", info.getPss());
|
|
21061
|
+
details.put("reason", info.getReason());
|
|
21062
|
+
details.put("rssKb", info.getRss());
|
|
21063
|
+
details.put("status", info.getStatus());
|
|
21064
|
+
String description = info.getDescription();
|
|
21065
|
+
if (description != null) details.put("description", description);
|
|
21066
|
+
byte[] trace = trace(info);
|
|
21067
|
+
if (trace != null && trace.length > 0) {
|
|
21068
|
+
if (info.getReason() == ApplicationExitInfo.REASON_CRASH_NATIVE) {
|
|
21069
|
+
details.put("trace", Base64.encodeToString(trace, Base64.NO_WRAP));
|
|
21070
|
+
details.put("traceEncoding", "android-tombstone-protobuf-base64");
|
|
21071
|
+
} else {
|
|
21072
|
+
details.put("trace", new String(trace, StandardCharsets.UTF_8));
|
|
21073
|
+
details.put("traceEncoding", "utf-8");
|
|
21074
|
+
}
|
|
21075
|
+
}
|
|
21076
|
+
return new JSONObject()
|
|
21077
|
+
.put("details", details)
|
|
21078
|
+
.put("id", id)
|
|
21079
|
+
.put("kind", kind)
|
|
21080
|
+
.put("occurredAt", info.getTimestamp())
|
|
21081
|
+
.put("platform", "android");
|
|
21082
|
+
} catch (Exception ignored) {
|
|
21083
|
+
return null;
|
|
21084
|
+
}
|
|
21085
|
+
}
|
|
21086
|
+
|
|
21087
|
+
private Set<String> queuedIds() {
|
|
21088
|
+
Set<String> ids = new HashSet<>();
|
|
21089
|
+
for (File file : files()) {
|
|
21090
|
+
try (InputStream input = new FileInputStream(file)) {
|
|
21091
|
+
JSONObject report = new JSONObject(new String(read(input), StandardCharsets.UTF_8));
|
|
21092
|
+
ids.add(report.optString("id"));
|
|
21093
|
+
} catch (Exception ignored) {}
|
|
21094
|
+
}
|
|
21095
|
+
return ids;
|
|
21096
|
+
}
|
|
21097
|
+
|
|
21098
|
+
private File[] files() {
|
|
21099
|
+
File[] values = root().listFiles((directory, name) -> name.endsWith(".json"));
|
|
21100
|
+
if (values == null) return new File[0];
|
|
21101
|
+
java.util.Arrays.sort(values, java.util.Comparator.comparing(File::getName));
|
|
21102
|
+
return values;
|
|
21103
|
+
}
|
|
21104
|
+
|
|
21105
|
+
private static byte[] read(InputStream input) throws java.io.IOException {
|
|
21106
|
+
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
|
21107
|
+
byte[] buffer = new byte[4096];
|
|
21108
|
+
int count;
|
|
21109
|
+
while ((count = input.read(buffer)) >= 0) output.write(buffer, 0, count);
|
|
21110
|
+
return output.toByteArray();
|
|
21111
|
+
}
|
|
21112
|
+
|
|
21113
|
+
private void collect() {
|
|
21114
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return;
|
|
21115
|
+
ActivityManager manager = getContext().getSystemService(ActivityManager.class);
|
|
21116
|
+
if (manager == null) return;
|
|
21117
|
+
Set<String> ignored = acknowledged();
|
|
21118
|
+
ignored.addAll(queuedIds());
|
|
21119
|
+
List<ApplicationExitInfo> exits = manager.getHistoricalProcessExitReasons(null, 0, 16);
|
|
21120
|
+
for (ApplicationExitInfo exit : exits) {
|
|
21121
|
+
JSONObject report = report(exit);
|
|
21122
|
+
if (report == null || ignored.contains(report.optString("id"))) continue;
|
|
21123
|
+
String name = String.format(java.util.Locale.ROOT, "%013d-%s.json", exit.getTimestamp(), java.util.UUID.randomUUID());
|
|
21124
|
+
File target = new File(root(), name);
|
|
21125
|
+
try (FileOutputStream output = new FileOutputStream(target)) {
|
|
21126
|
+
output.write(report.toString().getBytes(StandardCharsets.UTF_8));
|
|
21127
|
+
ignored.add(report.optString("id"));
|
|
21128
|
+
} catch (Exception ignoredWrite) {}
|
|
21129
|
+
}
|
|
21130
|
+
File[] files = files();
|
|
21131
|
+
for (int index = 0; index < files.length - MAX_REPORTS; index++) files[index].delete();
|
|
21132
|
+
}
|
|
21133
|
+
|
|
21134
|
+
@PluginMethod
|
|
21135
|
+
public void pending(PluginCall call) {
|
|
21136
|
+
collect();
|
|
21137
|
+
JSArray reports = new JSArray();
|
|
21138
|
+
for (File file : files()) {
|
|
21139
|
+
try (InputStream input = new FileInputStream(file)) {
|
|
21140
|
+
reports.put(new JSONObject(new String(read(input), StandardCharsets.UTF_8)));
|
|
21141
|
+
} catch (Exception ignored) {}
|
|
21142
|
+
}
|
|
21143
|
+
call.resolve(new JSObject().put("reports", reports));
|
|
21144
|
+
}
|
|
21145
|
+
|
|
21146
|
+
@PluginMethod
|
|
21147
|
+
public void crashForTesting(PluginCall call) {
|
|
21148
|
+
boolean debuggable = (getContext().getApplicationInfo().flags & android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE) != 0;
|
|
21149
|
+
if (!debuggable) {
|
|
21150
|
+
call.reject("Native crash injection is available only in debuggable builds.");
|
|
21151
|
+
return;
|
|
21152
|
+
}
|
|
21153
|
+
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
|
21154
|
+
throw new RuntimeException("AbsoluteJS native observability acceptance crash");
|
|
21155
|
+
});
|
|
21156
|
+
}
|
|
21157
|
+
|
|
21158
|
+
@PluginMethod
|
|
21159
|
+
public void acknowledge(PluginCall call) {
|
|
21160
|
+
JSArray ids = call.getArray("ids");
|
|
21161
|
+
if (ids == null) {
|
|
21162
|
+
call.reject("Native observability acknowledgement requires report ids.");
|
|
21163
|
+
return;
|
|
21164
|
+
}
|
|
21165
|
+
Set<String> accepted = new HashSet<>();
|
|
21166
|
+
for (int index = 0; index < ids.length(); index++) accepted.add(ids.optString(index));
|
|
21167
|
+
Set<String> acknowledged = acknowledged();
|
|
21168
|
+
for (File file : files()) {
|
|
21169
|
+
try (InputStream input = new FileInputStream(file)) {
|
|
21170
|
+
JSONObject report = new JSONObject(new String(read(input), StandardCharsets.UTF_8));
|
|
21171
|
+
String id = report.optString("id");
|
|
21172
|
+
if (accepted.contains(id)) {
|
|
21173
|
+
acknowledged.add(id);
|
|
21174
|
+
file.delete();
|
|
21175
|
+
}
|
|
21176
|
+
} catch (Exception ignored) {}
|
|
21177
|
+
}
|
|
21178
|
+
writeAcknowledged(acknowledged);
|
|
21179
|
+
call.resolve();
|
|
21180
|
+
}
|
|
21181
|
+
}
|
|
21182
|
+
`, androidActivityInRoot2 = async (root) => {
|
|
21183
|
+
let entries;
|
|
21184
|
+
try {
|
|
21185
|
+
entries = await readdir6(root, { recursive: true });
|
|
21186
|
+
} catch (error) {
|
|
21187
|
+
if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
|
|
21188
|
+
return;
|
|
21189
|
+
throw error;
|
|
21190
|
+
}
|
|
21191
|
+
const candidate = entries.find((entry) => entry.endsWith("/MainActivity.java") || entry.endsWith("/MainActivity.kt") || entry === "MainActivity.java" || entry === "MainActivity.kt");
|
|
21192
|
+
return candidate ? join53(root, candidate) : undefined;
|
|
21193
|
+
}, androidActivity2 = async (config) => {
|
|
21194
|
+
const roots = [
|
|
21195
|
+
join53(config.nativeProjectDirectory, "android/app/src/main/java"),
|
|
21196
|
+
join53(config.nativeProjectDirectory, "android/app/src/main/kotlin")
|
|
21197
|
+
];
|
|
21198
|
+
const candidates = await Promise.all(roots.map(androidActivityInRoot2));
|
|
21199
|
+
const candidate = candidates.find((value) => value !== undefined);
|
|
21200
|
+
if (candidate)
|
|
21201
|
+
return candidate;
|
|
21202
|
+
throw new TypeError("Android MainActivity.java or MainActivity.kt was not found.");
|
|
21203
|
+
}, androidRegion2 = (kotlin, generatedMethod) => {
|
|
21204
|
+
if (generatedMethod)
|
|
21205
|
+
return kotlin ? ` ${START2}
|
|
21206
|
+
override fun onCreate(savedInstanceState: android.os.Bundle?) {
|
|
21207
|
+
registerPlugin(AbsoluteMobileObservabilityPlugin::class.java)
|
|
21208
|
+
super.onCreate(savedInstanceState)
|
|
21209
|
+
}
|
|
21210
|
+
${END2}
|
|
21211
|
+
` : ` ${START2}
|
|
21212
|
+
@Override
|
|
21213
|
+
public void onCreate(android.os.Bundle savedInstanceState) {
|
|
21214
|
+
registerPlugin(AbsoluteMobileObservabilityPlugin.class);
|
|
21215
|
+
super.onCreate(savedInstanceState);
|
|
21216
|
+
}
|
|
21217
|
+
${END2}
|
|
21218
|
+
`;
|
|
21219
|
+
return kotlin ? ` ${START2}
|
|
21220
|
+
registerPlugin(AbsoluteMobileObservabilityPlugin::class.java)
|
|
21221
|
+
${END2}
|
|
21222
|
+
` : ` ${START2}
|
|
21223
|
+
registerPlugin(AbsoluteMobileObservabilityPlugin.class);
|
|
21224
|
+
${END2}
|
|
21225
|
+
`;
|
|
21226
|
+
}, injectAndroidActivity2 = (source, enabled) => {
|
|
21227
|
+
const kotlin = /\bfun\s+onCreate\s*\(/u.test(source) || source.includes("BridgeActivity()");
|
|
21228
|
+
const existingStart = source.indexOf(START2);
|
|
21229
|
+
const existingEnd = source.indexOf(END2);
|
|
21230
|
+
if (existingStart < 0 !== existingEnd < 0)
|
|
21231
|
+
throw new TypeError("AbsoluteJS native observability markers are malformed.");
|
|
21232
|
+
if (existingStart >= 0) {
|
|
21233
|
+
const from = source.lastIndexOf(`
|
|
21234
|
+
`, existingStart) + 1;
|
|
21235
|
+
const newline = source.indexOf(`
|
|
21236
|
+
`, existingEnd + END2.length);
|
|
21237
|
+
const through = newline < 0 ? source.length : newline + 1;
|
|
21238
|
+
const generatedMethod = source.slice(from, through).includes("onCreate(");
|
|
21239
|
+
if (!enabled)
|
|
21240
|
+
return `${source.slice(0, from)}${source.slice(through)}`;
|
|
21241
|
+
return `${source.slice(0, from)}${androidRegion2(kotlin, generatedMethod)}${source.slice(through)}`;
|
|
21242
|
+
}
|
|
21243
|
+
if (!enabled)
|
|
21244
|
+
return source;
|
|
21245
|
+
const onCreate = kotlin ? source.search(/\boverride\s+fun\s+onCreate\s*\([^)]*\)\s*\{/u) : source.search(/\b(?:public|protected)\s+void\s+onCreate\s*\([^)]*\)\s*\{/u);
|
|
21246
|
+
if (onCreate >= 0) {
|
|
21247
|
+
const brace = source.indexOf("{", onCreate);
|
|
21248
|
+
const insert = source.indexOf(`
|
|
21249
|
+
`, brace) + 1;
|
|
21250
|
+
return `${source.slice(0, insert)}${androidRegion2(kotlin, false)}${source.slice(insert)}`;
|
|
21251
|
+
}
|
|
21252
|
+
const close = source.lastIndexOf("}");
|
|
21253
|
+
if (close < 0)
|
|
21254
|
+
throw new TypeError("Could not find the Android MainActivity class body.");
|
|
21255
|
+
const separator = source[close - 1] === `
|
|
21256
|
+
` ? "" : `
|
|
21257
|
+
`;
|
|
21258
|
+
return `${source.slice(0, close)}${separator}${androidRegion2(kotlin, true)}${source.slice(close)}`;
|
|
21259
|
+
}, configureAndroid4 = async (config, enabled) => {
|
|
21260
|
+
const activityPath = await androidActivity2(config);
|
|
21261
|
+
const activity = await readFile17(activityPath, "utf8");
|
|
21262
|
+
const packageName = activity.match(/^\s*package\s+([A-Za-z0-9_.]+)\s*[;\n]/mu)?.[1];
|
|
21263
|
+
if (!packageName)
|
|
21264
|
+
throw new TypeError("Android MainActivity package declaration was not found.");
|
|
21265
|
+
const pluginPath = join53(config.nativeProjectDirectory, "android/app/src/main/java", packageName.replaceAll(".", "/"), ANDROID_PLUGIN2);
|
|
21266
|
+
const changed = await Promise.all([
|
|
21267
|
+
writeChanged3(activityPath, injectAndroidActivity2(activity, enabled)),
|
|
21268
|
+
enabled ? writeChanged3(pluginPath, androidPluginSource2(packageName)) : removeOwnedFile2(pluginPath)
|
|
21269
|
+
]);
|
|
21270
|
+
return changed.some(Boolean);
|
|
21271
|
+
}, applyAbsoluteNativeObservability = async (config, platforms = config.platforms) => {
|
|
21272
|
+
if (config.engine !== "capacitor")
|
|
21273
|
+
return { changed: false };
|
|
21274
|
+
const enabled = config.observability !== undefined;
|
|
21275
|
+
const changed = [];
|
|
21276
|
+
if (platforms.includes("ios"))
|
|
21277
|
+
changed.push(await configureIos4(config, enabled));
|
|
21278
|
+
if (platforms.includes("android"))
|
|
21279
|
+
changed.push(await configureAndroid4(config, enabled));
|
|
21280
|
+
return { changed: changed.some(Boolean) };
|
|
21281
|
+
};
|
|
21282
|
+
var init_nativeObservability = __esm(() => {
|
|
21283
|
+
iosPluginRegion2 = `${PLUGIN_START2}
|
|
21284
|
+
@objc(AbsoluteMobileObservabilityPlugin)
|
|
21285
|
+
public final class AbsoluteMobileObservabilityPlugin: CAPPlugin, CAPBridgedPlugin, MXMetricManagerSubscriber {
|
|
21286
|
+
public let identifier = "AbsoluteMobileObservabilityPlugin"
|
|
21287
|
+
public let jsName = "AbsoluteMobileObservability"
|
|
21288
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
21289
|
+
CAPPluginMethod(name: "acknowledge", returnType: CAPPluginReturnPromise),
|
|
21290
|
+
CAPPluginMethod(name: "pending", returnType: CAPPluginReturnPromise)
|
|
21291
|
+
]
|
|
21292
|
+
|
|
21293
|
+
private static let maximumReports = 8
|
|
21294
|
+
private static let maximumReportBytes = 64 * 1024
|
|
21295
|
+
private static let queue = DispatchQueue(label: "dev.absolute.mobile-observability")
|
|
21296
|
+
|
|
21297
|
+
public override func load() {
|
|
21298
|
+
MXMetricManager.shared.add(self)
|
|
21299
|
+
}
|
|
21300
|
+
|
|
21301
|
+
deinit {
|
|
21302
|
+
MXMetricManager.shared.remove(self)
|
|
21303
|
+
}
|
|
21304
|
+
|
|
21305
|
+
private static func root() -> URL? {
|
|
21306
|
+
guard let support = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first else { return nil }
|
|
21307
|
+
let root = support.appendingPathComponent("AbsoluteMobileObservability", isDirectory: true)
|
|
21308
|
+
try? FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)
|
|
21309
|
+
return root
|
|
21310
|
+
}
|
|
21311
|
+
|
|
21312
|
+
private static func files() -> [URL] {
|
|
21313
|
+
guard let root = root() else { return [] }
|
|
21314
|
+
return ((try? FileManager.default.contentsOfDirectory(at: root, includingPropertiesForKeys: nil)) ?? [])
|
|
21315
|
+
.filter { $0.pathExtension == "json" }
|
|
21316
|
+
.sorted { $0.lastPathComponent < $1.lastPathComponent }
|
|
21317
|
+
}
|
|
21318
|
+
|
|
21319
|
+
private static func trim() {
|
|
21320
|
+
let overflow = max(0, files().count - maximumReports)
|
|
21321
|
+
for file in files().prefix(overflow) { try? FileManager.default.removeItem(at: file) }
|
|
21322
|
+
}
|
|
21323
|
+
|
|
21324
|
+
private static func enqueue(kind: String, occurredAt: Double, details: [AnyHashable: Any]) {
|
|
21325
|
+
guard let root = root() else { return }
|
|
21326
|
+
let id = UUID().uuidString.lowercased()
|
|
21327
|
+
var value: [String: Any] = [
|
|
21328
|
+
"details": Dictionary(uniqueKeysWithValues: details.map { (String(describing: $0.key), $0.value) }),
|
|
21329
|
+
"id": id,
|
|
21330
|
+
"kind": kind,
|
|
21331
|
+
"occurredAt": occurredAt,
|
|
21332
|
+
"platform": "ios"
|
|
21333
|
+
]
|
|
21334
|
+
guard JSONSerialization.isValidJSONObject(value),
|
|
21335
|
+
let original = try? JSONSerialization.data(withJSONObject: value) else { return }
|
|
21336
|
+
if original.count > maximumReportBytes {
|
|
21337
|
+
value["details"] = [
|
|
21338
|
+
"diagnosticPrefix": String(decoding: original.prefix(24 * 1024), as: UTF8.self),
|
|
21339
|
+
"originalBytes": original.count,
|
|
21340
|
+
"truncated": true
|
|
21341
|
+
]
|
|
21342
|
+
}
|
|
21343
|
+
guard let data = try? JSONSerialization.data(withJSONObject: value),
|
|
21344
|
+
data.count <= maximumReportBytes else { return }
|
|
21345
|
+
let timestamp = String(format: "%013.0f", occurredAt)
|
|
21346
|
+
try? data.write(to: root.appendingPathComponent("\\(timestamp)-\\(id).json"), options: .atomic)
|
|
21347
|
+
trim()
|
|
21348
|
+
}
|
|
21349
|
+
|
|
21350
|
+
public func didReceive(_ payloads: [MXDiagnosticPayload]) {
|
|
21351
|
+
Self.queue.async {
|
|
21352
|
+
for payload in payloads {
|
|
21353
|
+
let at = payload.timeStampEnd.timeIntervalSince1970 * 1000
|
|
21354
|
+
for value in payload.crashDiagnostics ?? [] { Self.enqueue(kind: "crash", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
21355
|
+
for value in payload.hangDiagnostics ?? [] { Self.enqueue(kind: "hang", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
21356
|
+
for value in payload.cpuExceptionDiagnostics ?? [] { Self.enqueue(kind: "cpu-exception", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
21357
|
+
for value in payload.diskWriteExceptionDiagnostics ?? [] { Self.enqueue(kind: "disk-write-exception", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
21358
|
+
if #available(iOS 16.0, *) {
|
|
21359
|
+
for value in payload.appLaunchDiagnostics ?? [] { Self.enqueue(kind: "app-launch", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
21360
|
+
}
|
|
21361
|
+
}
|
|
21362
|
+
}
|
|
21363
|
+
}
|
|
21364
|
+
|
|
21365
|
+
@objc public func pending(_ call: CAPPluginCall) {
|
|
21366
|
+
Self.queue.async {
|
|
21367
|
+
let reports: [[String: Any]] = Self.files().compactMap { file in
|
|
21368
|
+
guard let data = try? Data(contentsOf: file),
|
|
21369
|
+
let value = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return nil }
|
|
21370
|
+
return value
|
|
21371
|
+
}
|
|
21372
|
+
call.resolve(["reports": reports])
|
|
21373
|
+
}
|
|
21374
|
+
}
|
|
21375
|
+
|
|
21376
|
+
@objc public func acknowledge(_ call: CAPPluginCall) {
|
|
21377
|
+
guard let ids = call.getArray("ids", String.self) else {
|
|
21378
|
+
call.reject("Native observability acknowledgement requires report ids.")
|
|
21379
|
+
return
|
|
21380
|
+
}
|
|
21381
|
+
let accepted = Set(ids)
|
|
21382
|
+
Self.queue.async {
|
|
21383
|
+
for file in Self.files() {
|
|
21384
|
+
guard let data = try? Data(contentsOf: file),
|
|
21385
|
+
let value = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
|
21386
|
+
let id = value["id"] as? String,
|
|
21387
|
+
accepted.contains(id) else { continue }
|
|
21388
|
+
try? FileManager.default.removeItem(at: file)
|
|
21389
|
+
}
|
|
21390
|
+
call.resolve()
|
|
21391
|
+
}
|
|
21392
|
+
}
|
|
21393
|
+
}
|
|
21394
|
+
${PLUGIN_END2}
|
|
21395
|
+
`;
|
|
21396
|
+
});
|
|
21397
|
+
|
|
21398
|
+
// src/mobile/associationFiles.ts
|
|
21399
|
+
import {
|
|
21400
|
+
access as access9,
|
|
21401
|
+
mkdir as mkdir13,
|
|
21402
|
+
readFile as readFile18,
|
|
21403
|
+
rename as rename14,
|
|
21404
|
+
rm as rm11,
|
|
21405
|
+
writeFile as writeFile15
|
|
21406
|
+
} from "fs/promises";
|
|
20448
21407
|
import { resolve as resolve37 } from "path";
|
|
20449
21408
|
import { Elysia } from "elysia";
|
|
20450
21409
|
var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERIFY_TIMEOUT_MS = 1e4, ANDROID_ASSOCIATION_PATH = "/.well-known/assetlinks.json", APPLE_ASSOCIATION_PATH = "/.well-known/apple-app-site-association", missingIdentity = (field, platform6) => new TypeError(`${field} is required to publish ${platform6} deep-link association files.`), createAppleDocument = (config, requireAll) => {
|
|
@@ -20498,7 +21457,7 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
|
|
|
20498
21457
|
}, writeAtomic = async (path, source) => {
|
|
20499
21458
|
let current;
|
|
20500
21459
|
try {
|
|
20501
|
-
current = await
|
|
21460
|
+
current = await readFile18(path, "utf8");
|
|
20502
21461
|
} catch (error) {
|
|
20503
21462
|
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
|
|
20504
21463
|
throw error;
|
|
@@ -20507,8 +21466,8 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
|
|
|
20507
21466
|
if (current === source)
|
|
20508
21467
|
return false;
|
|
20509
21468
|
const temporary = `${path}.${crypto.randomUUID()}.tmp`;
|
|
20510
|
-
await
|
|
20511
|
-
await
|
|
21469
|
+
await writeFile15(temporary, source, { flag: "wx" });
|
|
21470
|
+
await rename14(temporary, path);
|
|
20512
21471
|
return true;
|
|
20513
21472
|
}, exists3 = async (path) => {
|
|
20514
21473
|
try {
|
|
@@ -20521,7 +21480,7 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
|
|
|
20521
21480
|
const path = resolve37(root, OWNERSHIP_FILE);
|
|
20522
21481
|
let ownership;
|
|
20523
21482
|
try {
|
|
20524
|
-
ownership = JSON.parse(await
|
|
21483
|
+
ownership = JSON.parse(await readFile18(path, "utf8"));
|
|
20525
21484
|
} catch {
|
|
20526
21485
|
throw new TypeError(`Association output ${root} already exists and is not owned by AbsoluteJS.`);
|
|
20527
21486
|
}
|
|
@@ -20534,19 +21493,19 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
|
|
|
20534
21493
|
await assertOwnedOutput(root);
|
|
20535
21494
|
const backup = `${root}.${crypto.randomUUID()}.previous`;
|
|
20536
21495
|
if (hasCurrent)
|
|
20537
|
-
await
|
|
21496
|
+
await rename14(root, backup);
|
|
20538
21497
|
try {
|
|
20539
|
-
await
|
|
21498
|
+
await rename14(temporary, root);
|
|
20540
21499
|
} catch (error) {
|
|
20541
21500
|
if (hasCurrent)
|
|
20542
|
-
await
|
|
21501
|
+
await rename14(backup, root);
|
|
20543
21502
|
throw error;
|
|
20544
21503
|
}
|
|
20545
21504
|
if (hasCurrent)
|
|
20546
|
-
await
|
|
21505
|
+
await rm11(backup, { force: true, recursive: true });
|
|
20547
21506
|
}, materializeHost = async (root, host2, files) => {
|
|
20548
21507
|
const directory = resolve37(root, host2, ".well-known");
|
|
20549
|
-
await
|
|
21508
|
+
await mkdir13(directory, { recursive: true });
|
|
20550
21509
|
return Promise.all(files.map(async ([name, document2]) => {
|
|
20551
21510
|
const path = resolve37(directory, name);
|
|
20552
21511
|
await writeAtomic(path, `${JSON.stringify(document2, null, 2)}
|
|
@@ -20582,7 +21541,7 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
|
|
|
20582
21541
|
if (documents.apple) {
|
|
20583
21542
|
files.push(["apple-app-site-association", documents.apple]);
|
|
20584
21543
|
}
|
|
20585
|
-
await
|
|
21544
|
+
await mkdir13(temporary, { recursive: true });
|
|
20586
21545
|
try {
|
|
20587
21546
|
const temporaryPaths = (await Promise.all(config.deepLinkHosts.map((host2) => materializeHost(temporary, host2, files)))).flat();
|
|
20588
21547
|
await writeAtomic(resolve37(temporary, OWNERSHIP_FILE), `${JSON.stringify({ format: 1, hosts: config.deepLinkHosts }, null, 2)}
|
|
@@ -20591,7 +21550,7 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
|
|
|
20591
21550
|
const written = temporaryPaths.map((path) => resolve37(root, path.slice(temporary.length + 1)));
|
|
20592
21551
|
return { root, written };
|
|
20593
21552
|
} catch (error) {
|
|
20594
|
-
await
|
|
21553
|
+
await rm11(temporary, { force: true, recursive: true });
|
|
20595
21554
|
throw error;
|
|
20596
21555
|
}
|
|
20597
21556
|
}, verifyAbsoluteMobileAssociationFiles = async (config, request = globalThis.fetch) => {
|
|
@@ -20629,8 +21588,8 @@ var init_associationFiles = __esm(() => {
|
|
|
20629
21588
|
});
|
|
20630
21589
|
|
|
20631
21590
|
// src/mobile/androidWebView.ts
|
|
20632
|
-
import { mkdir as
|
|
20633
|
-
import { dirname as
|
|
21591
|
+
import { mkdir as mkdir14, writeFile as writeFile16 } from "fs/promises";
|
|
21592
|
+
import { dirname as dirname31, resolve as resolve38 } from "path";
|
|
20634
21593
|
|
|
20635
21594
|
class CdpConnection {
|
|
20636
21595
|
#closed;
|
|
@@ -20904,8 +21863,8 @@ var CDP_COMMAND_TIMEOUT_MS = 1e4, WEBVIEW_ATTACH_TIMEOUT_MS = 30000, WEBVIEW_POL
|
|
|
20904
21863
|
throw new Error("Android WebView screenshot returned no image data.");
|
|
20905
21864
|
}
|
|
20906
21865
|
const absolutePath = resolve38(path);
|
|
20907
|
-
await
|
|
20908
|
-
await
|
|
21866
|
+
await mkdir14(dirname31(absolutePath), { recursive: true });
|
|
21867
|
+
await writeFile16(absolutePath, Buffer.from(data, "base64"));
|
|
20909
21868
|
return absolutePath;
|
|
20910
21869
|
},
|
|
20911
21870
|
tap: async (coordinateX, coordinateY) => {
|
|
@@ -21037,8 +21996,8 @@ var DEFAULT_ROUTE_TIMEOUT_MS = 30000, DEFAULT_HMR_TIMEOUT_MS = 30000, routeExpre
|
|
|
21037
21996
|
|
|
21038
21997
|
// src/mobile/mobileBundleInspection.ts
|
|
21039
21998
|
import { createHash as createHash15 } from "crypto";
|
|
21040
|
-
import { access as access10, readFile as
|
|
21041
|
-
import { join as
|
|
21999
|
+
import { access as access10, readFile as readFile19, stat as stat2 } from "fs/promises";
|
|
22000
|
+
import { join as join54, relative as relative25, resolve as resolve39 } from "path";
|
|
21042
22001
|
var MOBILE_FRAMEWORKS, SHA256_PATTERN, isObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), portablePath = (projectRoot, path) => {
|
|
21043
22002
|
const value = relative25(resolve39(projectRoot), resolve39(path)).replaceAll("\\", "/");
|
|
21044
22003
|
return value || ".";
|
|
@@ -21050,7 +22009,7 @@ var MOBILE_FRAMEWORKS, SHA256_PATTERN, isObject2 = (value) => typeof value === "
|
|
|
21050
22009
|
return false;
|
|
21051
22010
|
}
|
|
21052
22011
|
}, readObject = async (path) => {
|
|
21053
|
-
const value = JSON.parse(await
|
|
22012
|
+
const value = JSON.parse(await readFile19(path, "utf8"));
|
|
21054
22013
|
if (!isObject2(value))
|
|
21055
22014
|
throw new TypeError("JSON root must be an object.");
|
|
21056
22015
|
return value;
|
|
@@ -21075,13 +22034,13 @@ var MOBILE_FRAMEWORKS, SHA256_PATTERN, isObject2 = (value) => typeof value === "
|
|
|
21075
22034
|
if (expectedHash !== undefined) {
|
|
21076
22035
|
if (!SHA256_PATTERN.test(expectedHash))
|
|
21077
22036
|
throw new TypeError(`${field} has an invalid SHA-256 digest.`);
|
|
21078
|
-
const actual = createHash15("sha256").update(await
|
|
22037
|
+
const actual = createHash15("sha256").update(await readFile19(path)).digest("hex");
|
|
21079
22038
|
if (actual !== expectedHash)
|
|
21080
22039
|
throw new TypeError(`${field} failed its SHA-256 integrity check.`);
|
|
21081
22040
|
}
|
|
21082
22041
|
return portable;
|
|
21083
22042
|
}, inspectAbsoluteMobileBundle = async (config, projectRoot) => {
|
|
21084
|
-
const manifestPath =
|
|
22043
|
+
const manifestPath = join54(config.bundleDirectory, "absolute-mobile-manifest.json");
|
|
21085
22044
|
const manifest = portablePath(projectRoot, manifestPath);
|
|
21086
22045
|
if (!await pathExists5(manifestPath))
|
|
21087
22046
|
return { manifest, status: "missing" };
|
|
@@ -21188,8 +22147,8 @@ var init_mobileBundleInspection = __esm(() => {
|
|
|
21188
22147
|
});
|
|
21189
22148
|
|
|
21190
22149
|
// src/mobile/releaseDoctor.ts
|
|
21191
|
-
import { access as access11, readFile as
|
|
21192
|
-
import { dirname as
|
|
22150
|
+
import { access as access11, readFile as readFile20, readdir as readdir7 } from "fs/promises";
|
|
22151
|
+
import { dirname as dirname32, extname as extname8, join as join55, relative as relative26 } from "path";
|
|
21193
22152
|
var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASSET_EXTENSIONS, EXACT_VERSION_PATTERN, NOT_FOUND3 = -1, LOCK_FILES, MANUAL_REVIEW, pathExists6 = async (path) => {
|
|
21194
22153
|
try {
|
|
21195
22154
|
await access11(path);
|
|
@@ -21202,13 +22161,13 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21202
22161
|
return findHmrAsset(path);
|
|
21203
22162
|
if (!isFile2 || !RELEASE_ASSET_EXTENSIONS.has(extname8(path)))
|
|
21204
22163
|
return;
|
|
21205
|
-
const source = await
|
|
22164
|
+
const source = await readFile20(path, "utf8");
|
|
21206
22165
|
return HMR_ASSET_PATTERN.test(source) ? path : undefined;
|
|
21207
22166
|
}, findHmrAsset = async (root) => {
|
|
21208
22167
|
if (!await pathExists6(root))
|
|
21209
22168
|
return;
|
|
21210
|
-
const entries = await
|
|
21211
|
-
const matches = await Promise.all(entries.map((entry) => inspectReleaseAsset(
|
|
22169
|
+
const entries = await readdir7(root, { withFileTypes: true });
|
|
22170
|
+
const matches = await Promise.all(entries.map((entry) => inspectReleaseAsset(join55(root, entry.name), entry.isDirectory(), entry.isFile())));
|
|
21212
22171
|
return matches.find((match) => match !== undefined);
|
|
21213
22172
|
}, pass = (id, detail, path) => ({ detail, id, path, status: "pass" }), fail5 = (id, detail, path, remediation) => ({
|
|
21214
22173
|
detail,
|
|
@@ -21222,8 +22181,8 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21222
22181
|
path,
|
|
21223
22182
|
remediation,
|
|
21224
22183
|
status: "warn"
|
|
21225
|
-
}),
|
|
21226
|
-
const value = JSON.parse(await
|
|
22184
|
+
}), isRecord16 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), readJsonObject = async (path) => {
|
|
22185
|
+
const value = JSON.parse(await readFile20(path, "utf8"));
|
|
21227
22186
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
21228
22187
|
throw new TypeError("JSON root must be an object.");
|
|
21229
22188
|
return Object.fromEntries(Object.entries(value));
|
|
@@ -21239,7 +22198,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21239
22198
|
}
|
|
21240
22199
|
return declarations;
|
|
21241
22200
|
}, versionCore = (version2) => version2.split("-")[0]?.split(".").slice(0, 2).join("."), capacitorVersionCheck = async (config, projectRoot) => {
|
|
21242
|
-
const manifestPath =
|
|
22201
|
+
const manifestPath = join55(projectRoot, "package.json");
|
|
21243
22202
|
try {
|
|
21244
22203
|
const manifest = await readJsonObject(manifestPath);
|
|
21245
22204
|
const declarations = packageDeclarations(manifest);
|
|
@@ -21252,7 +22211,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21252
22211
|
const declared = declarations.get(name);
|
|
21253
22212
|
if (!declared || !EXACT_VERSION_PATTERN.test(declared))
|
|
21254
22213
|
throw new TypeError(`${name} must be a direct exact dependency.`);
|
|
21255
|
-
const installed = await readJsonObject(
|
|
22214
|
+
const installed = await readJsonObject(join55(projectRoot, "node_modules", name, "package.json"));
|
|
21256
22215
|
if (installed.version !== declared)
|
|
21257
22216
|
throw new TypeError(`${name} does not match its installed version.`);
|
|
21258
22217
|
return declared;
|
|
@@ -21273,7 +22232,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21273
22232
|
const actual = installed.split(".").map(Number);
|
|
21274
22233
|
return actual[0] === expected[0] && actual[1] === expected[1] && (actual[2] ?? NOT_FOUND3) >= (expected[2] ?? 0);
|
|
21275
22234
|
}, expoVersionCheck = async (config) => {
|
|
21276
|
-
const manifestPath =
|
|
22235
|
+
const manifestPath = join55(config.nativeProjectDirectory, "package.json");
|
|
21277
22236
|
try {
|
|
21278
22237
|
const manifest = await readJsonObject(manifestPath);
|
|
21279
22238
|
const declarations = packageDeclarations(manifest);
|
|
@@ -21283,13 +22242,13 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21283
22242
|
throw new TypeError(`Generated Expo project is missing ${missingRequired}.`);
|
|
21284
22243
|
const installedVersions = await Promise.all([...declarations].map(async ([name, declared]) => ({
|
|
21285
22244
|
declared,
|
|
21286
|
-
installed: await readJsonObject(
|
|
22245
|
+
installed: await readJsonObject(join55(config.nativeProjectDirectory, "node_modules", name, "package.json")),
|
|
21287
22246
|
name
|
|
21288
22247
|
})));
|
|
21289
22248
|
const mismatch = installedVersions.find(({ declared, installed }) => typeof installed.version !== "string" || !satisfiesGeneratedVersion(declared, installed.version));
|
|
21290
22249
|
if (mismatch)
|
|
21291
22250
|
throw new TypeError(`Generated Expo dependency ${mismatch.name}@${mismatch.declared} does not match its installed version.`);
|
|
21292
|
-
if (!await pathExists6(
|
|
22251
|
+
if (!await pathExists6(join55(config.nativeProjectDirectory, "bun.lock")))
|
|
21293
22252
|
throw new TypeError("Generated Expo dependency lockfile is missing.");
|
|
21294
22253
|
return pass("mobile.expo-versions", `Generated Expo SDK dependencies are pinned, installed, and locked (${declarations.get("expo")}).`, manifestPath);
|
|
21295
22254
|
} catch (error) {
|
|
@@ -21297,10 +22256,10 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21297
22256
|
}
|
|
21298
22257
|
}, dependencyLockCheck = async (projectRoot) => {
|
|
21299
22258
|
const present = (await Promise.all(LOCK_FILES.map(async (name) => ({
|
|
21300
|
-
exists: await pathExists6(
|
|
22259
|
+
exists: await pathExists6(join55(projectRoot, name)),
|
|
21301
22260
|
name
|
|
21302
22261
|
})))).find(({ exists: exists4 }) => exists4);
|
|
21303
|
-
return present ? pass("mobile.dependency-lock", `Dependency graph is locked by ${present.name}.`,
|
|
22262
|
+
return present ? pass("mobile.dependency-lock", `Dependency graph is locked by ${present.name}.`, join55(projectRoot, present.name)) : fail5("mobile.dependency-lock", "No supported dependency lockfile is present.", projectRoot, "Install dependencies with the project package manager and commit its lockfile before release.");
|
|
21304
22263
|
}, productionOriginCheck = (config, projectRoot) => {
|
|
21305
22264
|
const origin = new URL(config.productionOrigin);
|
|
21306
22265
|
return origin.protocol === "https:" ? pass("mobile.production-origin", "Production transport uses an HTTPS origin.") : fail5("mobile.production-origin", "A loopback development origin cannot be used for a signed release.", projectRoot, "Configure mobile.server.productionOrigin with the deployed HTTPS origin.");
|
|
@@ -21335,7 +22294,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21335
22294
|
if (!await pathExists6(nativeConfigPath)) {
|
|
21336
22295
|
return fail5("android.capacitor-config", "The generated Android Capacitor config is missing.", nativeConfigPath, "Run `absolute mobile sync android` before release validation.");
|
|
21337
22296
|
}
|
|
21338
|
-
const unsafe = isUnsafeCapacitorConfig(await
|
|
22297
|
+
const unsafe = isUnsafeCapacitorConfig(await readFile20(nativeConfigPath, "utf8"));
|
|
21339
22298
|
return unsafe ? fail5("android.capacitor-config", "Android Capacitor config contains a development server URL, cleartext transport, navigation allowlist, or invalid JSON.", nativeConfigPath, "Run `absolute mobile sync android`; do not ship development transport overrides.") : pass("android.capacitor-config", "Android Capacitor config contains no development transport overrides.", nativeConfigPath);
|
|
21340
22299
|
}, capacitorIdentityCheck = async (config, platform6, nativeConfigPath) => {
|
|
21341
22300
|
try {
|
|
@@ -21350,12 +22309,12 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21350
22309
|
if (!await pathExists6(manifestPath)) {
|
|
21351
22310
|
return fail5("android.cleartext", "The Android manifest is missing.", manifestPath, "Run `absolute mobile sync android` before release validation.");
|
|
21352
22311
|
}
|
|
21353
|
-
const source = await
|
|
22312
|
+
const source = await readFile20(manifestPath, "utf8");
|
|
21354
22313
|
const cleartext = /android:usesCleartextTraffic=["']true["']/u.test(source);
|
|
21355
22314
|
const networkConfigName = source.match(/android:networkSecurityConfig=["']@xml\/([a-z0-9_]+)["']/u)?.[1];
|
|
21356
|
-
const networkConfigPath = networkConfigName ?
|
|
22315
|
+
const networkConfigPath = networkConfigName ? join55(dirname32(manifestPath), "res", "xml", `${networkConfigName}.xml`) : undefined;
|
|
21357
22316
|
const developmentTrustReference = /android:networkSecurityConfig=["']@xml\/absolutejs_dev_network_security["']/u.test(source);
|
|
21358
|
-
const developmentTrustContents = networkConfigPath ? await
|
|
22317
|
+
const developmentTrustContents = networkConfigPath ? await readFile20(networkConfigPath, "utf8").then((value) => value.includes("@raw/absolutejs_dev_ca")).catch(() => false) : false;
|
|
21359
22318
|
const developmentTrust = developmentTrustReference || developmentTrustContents;
|
|
21360
22319
|
return cleartext || developmentTrust ? fail5("android.cleartext", developmentTrust ? "Android still references the AbsoluteJS development certificate authority." : "Android explicitly permits cleartext traffic.", manifestPath, "Run `absolute mobile sync android`; do not ship development transport or trust overrides.") : pass("android.cleartext", "Android does not explicitly permit cleartext traffic.", manifestPath);
|
|
21361
22320
|
}, hmrAssetsReleaseCheck = async (publicRoot) => {
|
|
@@ -21364,12 +22323,12 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21364
22323
|
}, embeddedBundleReleaseCheck = async (config, projectRoot, platform6, publicRoot) => {
|
|
21365
22324
|
const inspection = await inspectAbsoluteMobileBundle({ ...config, bundleDirectory: publicRoot }, projectRoot);
|
|
21366
22325
|
if (inspection.status === "valid")
|
|
21367
|
-
return pass(`${platform6}.bundle-integrity`, `Packaged mobile manifest, runtime, routes, and ${inspection.pageCount ?? 0} page asset(s) passed structural and SHA-256 validation.`,
|
|
21368
|
-
return fail5(`${platform6}.bundle-integrity`, inspection.status === "missing" ? "The packaged mobile manifest is missing." : `The packaged mobile bundle is invalid: ${inspection.issue ?? "unknown validation error"}`,
|
|
22326
|
+
return pass(`${platform6}.bundle-integrity`, `Packaged mobile manifest, runtime, routes, and ${inspection.pageCount ?? 0} page asset(s) passed structural and SHA-256 validation.`, join55(publicRoot, "absolute-mobile-manifest.json"));
|
|
22327
|
+
return fail5(`${platform6}.bundle-integrity`, inspection.status === "missing" ? "The packaged mobile manifest is missing." : `The packaged mobile bundle is invalid: ${inspection.issue ?? "unknown validation error"}`, join55(publicRoot, "absolute-mobile-manifest.json"), "Rebuild the production mobile bundle and run Capacitor sync for this platform.");
|
|
21369
22328
|
}, contentSecurityPolicyCheck = async (config, platform6, publicRoot) => {
|
|
21370
|
-
const path =
|
|
22329
|
+
const path = join55(publicRoot, "index.html");
|
|
21371
22330
|
try {
|
|
21372
|
-
const source = await
|
|
22331
|
+
const source = await readFile20(path, "utf8");
|
|
21373
22332
|
const requirements = [
|
|
21374
22333
|
"Content-Security-Policy",
|
|
21375
22334
|
"default-src 'self'",
|
|
@@ -21388,26 +22347,26 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21388
22347
|
}
|
|
21389
22348
|
}, validateExpoCodeSigningProjection = async (config, expo) => {
|
|
21390
22349
|
const configuredSigning = config.updates?.expoCodeSigning;
|
|
21391
|
-
const generatedUpdates =
|
|
22350
|
+
const generatedUpdates = isRecord16(expo.updates) ? expo.updates : undefined;
|
|
21392
22351
|
if (config.updates && !configuredSigning)
|
|
21393
22352
|
throw new TypeError("Expo production updates require an embedded code-signing certificate.");
|
|
21394
22353
|
if (!configuredSigning && generatedUpdates && (("codeSigningCertificate" in generatedUpdates) || ("codeSigningMetadata" in generatedUpdates)))
|
|
21395
22354
|
throw new TypeError("Generated Expo config contains unconfigured code-signing material.");
|
|
21396
22355
|
if (!configuredSigning)
|
|
21397
22356
|
return;
|
|
21398
|
-
if (!generatedUpdates || generatedUpdates.codeSigningCertificate !== "./certs/absolute-mobile-update.pem" || !
|
|
22357
|
+
if (!generatedUpdates || generatedUpdates.codeSigningCertificate !== "./certs/absolute-mobile-update.pem" || !isRecord16(generatedUpdates.codeSigningMetadata) || generatedUpdates.codeSigningMetadata.keyid !== configuredSigning.keyId || generatedUpdates.codeSigningMetadata.alg !== configuredSigning.algorithm)
|
|
21399
22358
|
throw new TypeError("Generated Expo code-signing metadata does not match mobile config.");
|
|
21400
|
-
const generatedCertificate = await
|
|
22359
|
+
const generatedCertificate = await readFile20(join55(config.nativeProjectDirectory, "certs", "absolute-mobile-update.pem"), "utf8");
|
|
21401
22360
|
if (generatedCertificate !== configuredSigning.certificatePem)
|
|
21402
22361
|
throw new TypeError("Generated Expo code-signing certificate does not match mobile config.");
|
|
21403
22362
|
}, expoApplicationConfigCheck = async (config, projectRoot) => {
|
|
21404
|
-
const path =
|
|
22363
|
+
const path = join55(config.nativeProjectDirectory, "app.json");
|
|
21405
22364
|
try {
|
|
21406
22365
|
const root = await readJsonObject(path);
|
|
21407
|
-
if (!
|
|
22366
|
+
if (!isRecord16(root.expo))
|
|
21408
22367
|
throw new TypeError("Generated Expo application config is invalid.");
|
|
21409
22368
|
const { expo } = root;
|
|
21410
|
-
if (expo.name !== config.appName || config.platforms.includes("android") && (!
|
|
22369
|
+
if (expo.name !== config.appName || config.platforms.includes("android") && (!isRecord16(expo.android) || expo.android.package !== config.appId) || config.platforms.includes("ios") && (!isRecord16(expo.ios) || expo.ios.bundleIdentifier !== config.appId)) {
|
|
21411
22370
|
throw new TypeError("Generated Expo application identity does not match mobile config.");
|
|
21412
22371
|
}
|
|
21413
22372
|
const expectedRuntime = resolveAbsoluteMobileUpdateRuntime(config, projectRoot).fingerprint;
|
|
@@ -21423,12 +22382,12 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21423
22382
|
return fail5("expo.app-config", error instanceof Error ? error.message : "Generated Expo application config could not be validated.", path, "Run `absolute mobile build <platform>`; do not edit the generated Expo project.");
|
|
21424
22383
|
}
|
|
21425
22384
|
}, expoEmbeddedAssetsCheck = async (config) => {
|
|
21426
|
-
const generated =
|
|
21427
|
-
const assetsRoot =
|
|
22385
|
+
const generated = join55(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
|
|
22386
|
+
const assetsRoot = join55(config.nativeProjectDirectory, "assets", "absolute");
|
|
21428
22387
|
try {
|
|
21429
22388
|
const [source, manifest] = await Promise.all([
|
|
21430
|
-
|
|
21431
|
-
readJsonObject(
|
|
22389
|
+
readFile20(generated, "utf8"),
|
|
22390
|
+
readJsonObject(join55(config.bundleDirectory, "absolute-mobile-manifest.json"))
|
|
21432
22391
|
]);
|
|
21433
22392
|
if (source.includes("embedded AbsoluteJS bundle is unavailable") || typeof manifest.appBuild !== "string" || !source.includes(JSON.stringify(manifest.appBuild)) || !source.includes(JSON.stringify(config.productionOrigin))) {
|
|
21434
22393
|
throw new TypeError("Generated Expo assets do not contain the prepared production release identity.");
|
|
@@ -21448,8 +22407,8 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21448
22407
|
if (!embedded)
|
|
21449
22408
|
return false;
|
|
21450
22409
|
const [left, right] = await Promise.all([
|
|
21451
|
-
|
|
21452
|
-
|
|
22410
|
+
readFile20(join55(config.bundleDirectory, path)),
|
|
22411
|
+
readFile20(join55(assetsRoot, embedded))
|
|
21453
22412
|
]);
|
|
21454
22413
|
return left.equals(right);
|
|
21455
22414
|
}));
|
|
@@ -21463,18 +22422,18 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21463
22422
|
if (!await pathExists6(root))
|
|
21464
22423
|
return [];
|
|
21465
22424
|
const files = await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: root, onlyFiles: true }));
|
|
21466
|
-
return files.filter((file) => extensions.has(extname8(file))).map((file) =>
|
|
22425
|
+
return files.filter((file) => extensions.has(extname8(file))).map((file) => join55(root, file));
|
|
21467
22426
|
}, containsPattern = async (paths, pattern) => {
|
|
21468
|
-
const sources = await Promise.all(paths.map((path) =>
|
|
22427
|
+
const sources = await Promise.all(paths.map((path) => readFile20(path, "utf8")));
|
|
21469
22428
|
const index = sources.findIndex((source) => pattern.test(source));
|
|
21470
22429
|
return index === NOT_FOUND3 ? undefined : paths[index];
|
|
21471
22430
|
}, androidNativeSecurityCheck = async (androidRoot) => {
|
|
21472
|
-
const manifestPath =
|
|
22431
|
+
const manifestPath = join55(androidRoot, "app/src/main/AndroidManifest.xml");
|
|
21473
22432
|
try {
|
|
21474
|
-
const manifest = await
|
|
22433
|
+
const manifest = await readFile20(manifestPath, "utf8");
|
|
21475
22434
|
if (/android:debuggable=["']true["']/u.test(manifest))
|
|
21476
22435
|
throw new TypeError("Android release manifest explicitly enables application debugging.");
|
|
21477
|
-
const sources = await sourceFiles(
|
|
22436
|
+
const sources = await sourceFiles(join55(androidRoot, "app/src/main"), new Set([".java", ".kt"]));
|
|
21478
22437
|
const debugSource = await containsPattern(sources, /setWebContentsDebuggingEnabled\s*\(\s*true\s*\)/u);
|
|
21479
22438
|
if (debugSource)
|
|
21480
22439
|
return fail5("android.native-debugging", "Android application source unconditionally enables WebView debugging.", debugSource, "Remove the unconditional WebView debugging call; use the platform debug-build behavior during development.");
|
|
@@ -21483,14 +22442,14 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21483
22442
|
return fail5("android.native-debugging", error instanceof Error ? error.message : "Android native debugging configuration could not be validated.", manifestPath, "Remove explicit release debugging settings and rerun mobile sync.");
|
|
21484
22443
|
}
|
|
21485
22444
|
}, androidExportedComponentsCheck = async (manifestPath) => {
|
|
21486
|
-
const source = await
|
|
22445
|
+
const source = await readFile20(manifestPath, "utf8").catch(() => "");
|
|
21487
22446
|
const exported = [
|
|
21488
22447
|
...source.matchAll(/<(?:activity|activity-alias|provider|receiver|service)\b[^>]*>/giu)
|
|
21489
22448
|
].map(([tag]) => tag).filter((tag) => /android:exported=["']true["']/iu.test(tag)).map((tag) => tag.match(/android:name=["']([^"']+)["']/iu)?.[1]).filter((name) => Boolean(name) && name !== ".MainActivity");
|
|
21490
22449
|
return exported.length === 0 ? pass("android.exported-components", "No non-launcher Android component is explicitly exported.", manifestPath) : warn("android.exported-components", `${exported.length} non-launcher Android component(s) are exported and require manual authorization review.`, manifestPath, "Confirm each exported component is intentional, permission-protected where appropriate, and documented in the mobile threat model review.");
|
|
21491
22450
|
}, androidDeepLinkProjectionCheck = async (config, manifestPath) => {
|
|
21492
22451
|
try {
|
|
21493
|
-
const source = await
|
|
22452
|
+
const source = await readFile20(manifestPath, "utf8");
|
|
21494
22453
|
const hasWebHost = (host2) => [...source.matchAll(/<data\b[^>]*>/giu)].some(([tag]) => tag.includes('android:scheme="https"') && tag.includes(`android:host="${host2}"`));
|
|
21495
22454
|
if (!source.includes('android:autoVerify="true"') || !source.includes("android.intent.category.BROWSABLE") || config.deepLinkHosts.some((host2) => !hasWebHost(host2)) || config.deepLinkScheme && !source.includes(`android:scheme="${config.deepLinkScheme}"`))
|
|
21496
22455
|
throw new TypeError("Android App Link or custom-scheme projection does not match mobile config.");
|
|
@@ -21503,21 +22462,53 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21503
22462
|
return;
|
|
21504
22463
|
const timeout = String(config.updates.bootTimeoutMs);
|
|
21505
22464
|
if (platform6 === "ios") {
|
|
21506
|
-
const path =
|
|
21507
|
-
const configPath2 =
|
|
22465
|
+
const path = join55(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
22466
|
+
const configPath2 = join55(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
|
|
21508
22467
|
const [source, nativeConfig] = await Promise.all([
|
|
21509
|
-
|
|
21510
|
-
|
|
22468
|
+
readFile20(path, "utf8").catch(() => ""),
|
|
22469
|
+
readFile20(configPath2, "utf8").catch(() => "")
|
|
21511
22470
|
]);
|
|
21512
22471
|
return source.includes("AbsoluteMobileUpdateWatchdogPlugin") && source.includes("recoverInterruptedBoot()") && source.includes(`.milliseconds(${timeout})`) && source.includes("quarantinedReleases") && nativeConfig.includes("AbsoluteMobileUpdateWatchdogPlugin") ? pass("ios.update-watchdog", `The native update boot watchdog is projected with a ${timeout}ms deadline.`, path) : fail5("ios.update-watchdog", "The iOS update boot watchdog does not match mobile config.", path, "Run `absolute mobile sync ios` before building the release.");
|
|
21513
22472
|
}
|
|
21514
|
-
const sourceRoot =
|
|
22473
|
+
const sourceRoot = join55(config.nativeProjectDirectory, "android/app/src/main");
|
|
21515
22474
|
const sources = await sourceFiles(sourceRoot, new Set([".java", ".kt"]));
|
|
21516
22475
|
const [activity, plugin] = await Promise.all([
|
|
21517
22476
|
containsPattern(sources, /recoverInterruptedBoot\s*\(\s*this\s*\)/u),
|
|
21518
22477
|
containsPattern(sources, new RegExp(`handler\\.postDelayed\\(deadline,\\s*${timeout}L\\)`, "u"))
|
|
21519
22478
|
]);
|
|
21520
22479
|
return activity && plugin ? pass("android.update-watchdog", `The native update boot watchdog is projected with a ${timeout}ms deadline.`, plugin) : fail5("android.update-watchdog", "The Android update boot watchdog does not match mobile config.", plugin ?? sourceRoot, "Run `absolute mobile sync android` before building the release.");
|
|
22480
|
+
}, nativeObservabilityProjectionCheck = async (config, platform6) => {
|
|
22481
|
+
if (!config.observability)
|
|
22482
|
+
return;
|
|
22483
|
+
const nativeRoot = config.nativeProjectDirectory;
|
|
22484
|
+
if (config.engine === "expo") {
|
|
22485
|
+
const moduleRoot = join55(nativeRoot, "modules", "absolute-mobile-observability");
|
|
22486
|
+
const configPath2 = join55(moduleRoot, "expo-module.config.json");
|
|
22487
|
+
const sourcePath = platform6 === "android" ? join55(moduleRoot, "android/src/main/java/expo/modules/absolutemobileobservability/AbsoluteMobileObservabilityModule.kt") : join55(moduleRoot, "ios/AbsoluteMobileObservabilityModule.swift");
|
|
22488
|
+
const [moduleConfig2, source] = await Promise.all([
|
|
22489
|
+
readFile20(configPath2, "utf8").catch(() => ""),
|
|
22490
|
+
readFile20(sourcePath, "utf8").catch(() => "")
|
|
22491
|
+
]);
|
|
22492
|
+
const valid = moduleConfig2.includes("AbsoluteMobileObservabilityModule") && source.includes("AbsoluteMobileObservability") && (platform6 === "android" ? source.includes("getHistoricalProcessExitReasons") : source.includes("MXMetricManagerSubscriber"));
|
|
22493
|
+
return valid ? pass(`${platform6}.native-observability`, `The Expo ${platform6} native process collector is projected and autolinkable.`, sourcePath) : fail5(`${platform6}.native-observability`, `The Expo ${platform6} native process collector is missing or incomplete.`, sourcePath, `Run \`absolute mobile build ${platform6}\` before building the release.`);
|
|
22494
|
+
}
|
|
22495
|
+
if (platform6 === "ios") {
|
|
22496
|
+
const delegatePath = join55(nativeRoot, "ios/App/App/AppDelegate.swift");
|
|
22497
|
+
const configPath2 = join55(nativeRoot, "ios/App/App/capacitor.config.json");
|
|
22498
|
+
const [delegate, nativeConfig] = await Promise.all([
|
|
22499
|
+
readFile20(delegatePath, "utf8").catch(() => ""),
|
|
22500
|
+
readFile20(configPath2, "utf8").catch(() => "")
|
|
22501
|
+
]);
|
|
22502
|
+
const valid = delegate.includes("AbsoluteMobileObservabilityPlugin") && delegate.includes("MXMetricManagerSubscriber") && nativeConfig.includes("AbsoluteMobileObservabilityPlugin");
|
|
22503
|
+
return valid ? pass("ios.native-observability", "The iOS MetricKit native process collector is projected and registered.", delegatePath) : fail5("ios.native-observability", "The iOS MetricKit native process collector is missing or unregistered.", delegatePath, "Run `absolute mobile sync ios` before building the release.");
|
|
22504
|
+
}
|
|
22505
|
+
const sourceRoot = join55(nativeRoot, "android/app/src/main");
|
|
22506
|
+
const sources = await sourceFiles(sourceRoot, new Set([".java", ".kt"]));
|
|
22507
|
+
const [registration, plugin] = await Promise.all([
|
|
22508
|
+
containsPattern(sources, /registerPlugin\s*\(\s*AbsoluteMobileObservabilityPlugin(?:::class\.java|\.class)\s*\)/u),
|
|
22509
|
+
containsPattern(sources, /getHistoricalProcessExitReasons\s*\(/u)
|
|
22510
|
+
]);
|
|
22511
|
+
return registration && plugin ? pass("android.native-observability", "The Android process-exit collector is projected and registered.", plugin) : fail5("android.native-observability", "The Android process-exit collector is missing or unregistered.", plugin ?? sourceRoot, "Run `absolute mobile sync android` before building the release.");
|
|
21521
22512
|
}, iosNativeSecurityCheck = async (iosRoot) => {
|
|
21522
22513
|
const applicationFiles = async (extensions) => (await sourceFiles(iosRoot, extensions)).filter((path) => !relative26(iosRoot, path).split(/[\\/]/u).some((part) => ["Pods", "DerivedData", "build"].includes(part)));
|
|
21523
22514
|
const entitlementPaths = await applicationFiles(new Set([".entitlements"]));
|
|
@@ -21530,14 +22521,14 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21530
22521
|
return fail5("ios.native-debugging", "iOS application source unconditionally enables WebView inspection.", debugSource, "Remove unconditional WebView inspection from release source.");
|
|
21531
22522
|
return pass("ios.native-debugging", "iOS source does not enable release debugger attachment or WebView inspection.", entitlementPaths[0] ?? iosRoot);
|
|
21532
22523
|
}, iosDeepLinkProjectionCheck = async (config, iosRoot) => {
|
|
21533
|
-
const infoPath =
|
|
21534
|
-
const entitlementsPath =
|
|
21535
|
-
const projectPath =
|
|
22524
|
+
const infoPath = join55(iosRoot, "App/App/Info.plist");
|
|
22525
|
+
const entitlementsPath = join55(iosRoot, "App/AbsoluteJS.entitlements");
|
|
22526
|
+
const projectPath = join55(iosRoot, "App/App.xcodeproj/project.pbxproj");
|
|
21536
22527
|
try {
|
|
21537
22528
|
const [info2, entitlements, project] = await Promise.all([
|
|
21538
|
-
|
|
21539
|
-
|
|
21540
|
-
|
|
22529
|
+
readFile20(infoPath, "utf8"),
|
|
22530
|
+
readFile20(entitlementsPath, "utf8"),
|
|
22531
|
+
readFile20(projectPath, "utf8")
|
|
21541
22532
|
]);
|
|
21542
22533
|
if (config.deepLinkScheme && (!info2.includes("<key>CFBundleURLTypes</key>") || !info2.includes(`<string>${config.deepLinkScheme}</string>`)))
|
|
21543
22534
|
throw new TypeError("iOS custom URL scheme does not match mobile config.");
|
|
@@ -21552,7 +22543,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21552
22543
|
}, syncSchemaReleaseCheck = (projectRoot) => {
|
|
21553
22544
|
if (!projectUsesAbsoluteSync(projectRoot))
|
|
21554
22545
|
return;
|
|
21555
|
-
const manifestPath =
|
|
22546
|
+
const manifestPath = join55(projectRoot, "package.json");
|
|
21556
22547
|
try {
|
|
21557
22548
|
const schema = discoverAbsoluteSyncSchema(projectRoot);
|
|
21558
22549
|
const versions = schema.components.map((component2) => `${component2.id}@${component2.version}`).join(", ");
|
|
@@ -21574,8 +22565,8 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21574
22565
|
}, IOS_USAGE_KEYS, androidDevicePermissionCheck = async (config, permissions) => {
|
|
21575
22566
|
if (!config.platforms.includes("android") || permissions.length === 0)
|
|
21576
22567
|
return;
|
|
21577
|
-
const path =
|
|
21578
|
-
const source = await
|
|
22568
|
+
const path = join55(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
|
|
22569
|
+
const source = await readFile20(path, "utf8");
|
|
21579
22570
|
const missing = permissions.filter((permission) => !source.includes(`android:name="${permission}"`) && !source.includes(`android:name='${permission}'`));
|
|
21580
22571
|
if (missing.length === 0)
|
|
21581
22572
|
return;
|
|
@@ -21583,9 +22574,9 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21583
22574
|
}, iosDevicePermissionCheck = async (config, purposes) => {
|
|
21584
22575
|
if (!config.platforms.includes("ios") || purposes.length === 0)
|
|
21585
22576
|
return;
|
|
21586
|
-
const iosRoot =
|
|
21587
|
-
const path = config.engine === "expo" ? await uniqueExpoIosFile(iosRoot, "**/Info.plist", "Info.plist") :
|
|
21588
|
-
const source = await
|
|
22577
|
+
const iosRoot = join55(config.nativeProjectDirectory, "ios");
|
|
22578
|
+
const path = config.engine === "expo" ? await uniqueExpoIosFile(iosRoot, "**/Info.plist", "Info.plist") : join55(iosRoot, "App/App/Info.plist");
|
|
22579
|
+
const source = await readFile20(path, "utf8");
|
|
21589
22580
|
const missing = purposes.filter((purpose) => !source.includes(`<key>${IOS_USAGE_KEYS[purpose]}</key>`));
|
|
21590
22581
|
if (missing.length === 0)
|
|
21591
22582
|
return;
|
|
@@ -21594,7 +22585,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21594
22585
|
if (requirements.iosPrivacyAccessedApis.length === 0)
|
|
21595
22586
|
return;
|
|
21596
22587
|
const privacyPath = await uniqueExpoIosFile(iosRoot, "**/PrivacyInfo.xcprivacy", "privacy manifest");
|
|
21597
|
-
const privacy = await
|
|
22588
|
+
const privacy = await readFile20(privacyPath, "utf8");
|
|
21598
22589
|
const missing = requirements.iosPrivacyAccessedApis.some(({ api, reasons }) => !privacy.includes(`<string>${api}</string>`) || reasons.some((reason) => !privacy.includes(`<string>${reason}</string>`)));
|
|
21599
22590
|
if (!missing && project.includes(privacyPath.split(/[\\/]/u).at(-1) ?? ""))
|
|
21600
22591
|
return;
|
|
@@ -21603,14 +22594,14 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21603
22594
|
if (!requirements.iosPushNotifications)
|
|
21604
22595
|
return;
|
|
21605
22596
|
const entitlementsPath = await uniqueExpoIosFile(iosRoot, "**/*.entitlements", "entitlements");
|
|
21606
|
-
const entitlements = await
|
|
22597
|
+
const entitlements = await readFile20(entitlementsPath, "utf8");
|
|
21607
22598
|
if (entitlements.includes("<key>aps-environment</key>"))
|
|
21608
22599
|
return;
|
|
21609
22600
|
return fail5("mobile.device-capabilities", "Expo iOS push entitlement does not match detected capabilities.", entitlementsPath, "Run `absolute mobile build ios` to regenerate native push integration.");
|
|
21610
22601
|
}, expoIosCapabilityProjectionCheck = async (config, requirements) => {
|
|
21611
|
-
const iosRoot =
|
|
22602
|
+
const iosRoot = join55(config.nativeProjectDirectory, "ios");
|
|
21612
22603
|
const projectPath = await uniqueExpoIosFile(iosRoot, "**/*.xcodeproj/project.pbxproj", "Xcode project");
|
|
21613
|
-
const project = await
|
|
22604
|
+
const project = await readFile20(projectPath, "utf8");
|
|
21614
22605
|
const privacy = await expoIosPrivacyCapabilityCheck(iosRoot, project, requirements);
|
|
21615
22606
|
if (privacy)
|
|
21616
22607
|
return privacy;
|
|
@@ -21620,41 +22611,41 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21620
22611
|
return;
|
|
21621
22612
|
if (config.engine === "expo")
|
|
21622
22613
|
return expoIosCapabilityProjectionCheck(config, requirements);
|
|
21623
|
-
const appRoot =
|
|
21624
|
-
const infoPath =
|
|
21625
|
-
const info2 = await
|
|
22614
|
+
const appRoot = join55(config.nativeProjectDirectory, "ios/App/App");
|
|
22615
|
+
const infoPath = join55(appRoot, "Info.plist");
|
|
22616
|
+
const info2 = await readFile20(infoPath, "utf8").catch(() => "");
|
|
21626
22617
|
if (requirements.iosSystemBars && !/<key>UIViewControllerBasedStatusBarAppearance<\/key>\s*<true\s*\/>/u.test(info2))
|
|
21627
22618
|
return fail5("mobile.device-capabilities", "iOS system-bar capability is missing its required view-controller setting.", infoPath, "Run `absolute mobile sync ios` to regenerate native capability settings.");
|
|
21628
22619
|
if (requirements.iosPrivacyAccessedApis.length > 0) {
|
|
21629
|
-
const privacyPath =
|
|
21630
|
-
const projectPath =
|
|
22620
|
+
const privacyPath = join55(appRoot, "PrivacyInfo.xcprivacy");
|
|
22621
|
+
const projectPath = join55(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
|
|
21631
22622
|
const [privacy, project] = await Promise.all([
|
|
21632
|
-
|
|
21633
|
-
|
|
22623
|
+
readFile20(privacyPath, "utf8").catch(() => ""),
|
|
22624
|
+
readFile20(projectPath, "utf8").catch(() => "")
|
|
21634
22625
|
]);
|
|
21635
22626
|
const missing = requirements.iosPrivacyAccessedApis.some(({ api, reasons }) => !privacy.includes(`<string>${api}</string>`) || reasons.some((reason) => !privacy.includes(`<string>${reason}</string>`)));
|
|
21636
22627
|
if (missing || !project.includes("PrivacyInfo.xcprivacy in Resources"))
|
|
21637
22628
|
return fail5("mobile.device-capabilities", "iOS privacy manifest or target membership does not match detected native capabilities.", privacyPath, "Run `absolute mobile sync ios` to regenerate and target PrivacyInfo.xcprivacy.");
|
|
21638
22629
|
}
|
|
21639
22630
|
if (requirements.iosPushNotifications) {
|
|
21640
|
-
const entitlementsPath =
|
|
21641
|
-
const delegatePath =
|
|
22631
|
+
const entitlementsPath = join55(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
|
|
22632
|
+
const delegatePath = join55(appRoot, "AppDelegate.swift");
|
|
21642
22633
|
const [entitlements, delegate] = await Promise.all([
|
|
21643
|
-
|
|
21644
|
-
|
|
22634
|
+
readFile20(entitlementsPath, "utf8").catch(() => ""),
|
|
22635
|
+
readFile20(delegatePath, "utf8").catch(() => "")
|
|
21645
22636
|
]);
|
|
21646
22637
|
if (!entitlements.includes("<key>aps-environment</key>") || !delegate.includes("capacitorDidRegisterForRemoteNotifications") || !delegate.includes("capacitorDidFailToRegisterForRemoteNotifications"))
|
|
21647
22638
|
return fail5("mobile.device-capabilities", "iOS push entitlement or AppDelegate forwarding does not match detected capabilities.", entitlementsPath, "Run `absolute mobile sync ios` to regenerate native push integration.");
|
|
21648
22639
|
}
|
|
21649
22640
|
return;
|
|
21650
22641
|
}, deviceCapabilityReleaseCheck = async (config, projectRoot) => {
|
|
21651
|
-
const manifestPath =
|
|
22642
|
+
const manifestPath = join55(projectRoot, "package.json");
|
|
21652
22643
|
try {
|
|
21653
22644
|
const plan = resolveAbsoluteDeviceCapabilityPlan(projectRoot, config.engine);
|
|
21654
22645
|
const assertPackages = async () => {
|
|
21655
22646
|
if (config.engine === "capacitor")
|
|
21656
22647
|
return assertAbsoluteDeviceCapabilityPackages(projectRoot, plan);
|
|
21657
|
-
const generated = await readJsonObject(
|
|
22648
|
+
const generated = await readJsonObject(join55(config.nativeProjectDirectory, "package.json"));
|
|
21658
22649
|
const declarations = packageDeclarations(generated);
|
|
21659
22650
|
const missing = plan.requiredPackages.filter((spec) => {
|
|
21660
22651
|
const separator = spec.lastIndexOf("@");
|
|
@@ -21680,11 +22671,11 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21680
22671
|
return fail5("mobile.device-capabilities", error instanceof Error ? error.message : "Native device capability provisioning is invalid.", manifestPath, "Run `absolute mobile sync` and approve the exact capability plugins before releasing.");
|
|
21681
22672
|
}
|
|
21682
22673
|
}, inspectAndroidRelease = async (config, projectRoot) => {
|
|
21683
|
-
const androidRoot =
|
|
21684
|
-
const nativeConfigPath =
|
|
21685
|
-
const manifestPath =
|
|
21686
|
-
const publicRoot =
|
|
21687
|
-
const journalPath =
|
|
22674
|
+
const androidRoot = join55(config.nativeProjectDirectory, "android");
|
|
22675
|
+
const nativeConfigPath = join55(androidRoot, "app", "src", "main", "assets", "capacitor.config.json");
|
|
22676
|
+
const manifestPath = join55(androidRoot, "app", "src", "main", "AndroidManifest.xml");
|
|
22677
|
+
const publicRoot = join55(androidRoot, "app", "src", "main", "assets", "public");
|
|
22678
|
+
const journalPath = join55(projectRoot, ".absolutejs", "mobile", "dev-session", "journal.json");
|
|
21688
22679
|
const checks = await Promise.all([
|
|
21689
22680
|
journalReleaseCheck(journalPath, "android"),
|
|
21690
22681
|
capacitorConfigReleaseCheck(nativeConfigPath),
|
|
@@ -21696,16 +22687,17 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21696
22687
|
androidNativeSecurityCheck(androidRoot),
|
|
21697
22688
|
androidExportedComponentsCheck(manifestPath),
|
|
21698
22689
|
androidDeepLinkProjectionCheck(config, manifestPath),
|
|
21699
|
-
nativeUpdateWatchdogCheck(config, "android")
|
|
22690
|
+
nativeUpdateWatchdogCheck(config, "android"),
|
|
22691
|
+
nativeObservabilityProjectionCheck(config, "android")
|
|
21700
22692
|
]);
|
|
21701
22693
|
return checks.filter((check2) => check2 !== undefined).map((check2) => ({
|
|
21702
22694
|
...check2,
|
|
21703
22695
|
path: check2.path ? relative26(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
|
|
21704
22696
|
}));
|
|
21705
22697
|
}, inspectExpoAndroidRelease = async (config, projectRoot) => {
|
|
21706
|
-
const androidRoot =
|
|
21707
|
-
const manifestPath =
|
|
21708
|
-
const journalPath =
|
|
22698
|
+
const androidRoot = join55(config.nativeProjectDirectory, "android");
|
|
22699
|
+
const manifestPath = join55(androidRoot, "app", "src", "main", "AndroidManifest.xml");
|
|
22700
|
+
const journalPath = join55(projectRoot, ".absolutejs", "mobile", "expo-dev-session", "journal.json");
|
|
21709
22701
|
const checks = await Promise.all([
|
|
21710
22702
|
journalReleaseCheck(journalPath, "android"),
|
|
21711
22703
|
expoApplicationConfigCheck(config, projectRoot),
|
|
@@ -21716,9 +22708,10 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21716
22708
|
contentSecurityPolicyCheck(config, "android", config.bundleDirectory),
|
|
21717
22709
|
androidNativeSecurityCheck(androidRoot),
|
|
21718
22710
|
androidExportedComponentsCheck(manifestPath),
|
|
21719
|
-
androidDeepLinkProjectionCheck(config, manifestPath)
|
|
22711
|
+
androidDeepLinkProjectionCheck(config, manifestPath),
|
|
22712
|
+
nativeObservabilityProjectionCheck(config, "android")
|
|
21720
22713
|
]);
|
|
21721
|
-
return checks.map((check2) => ({
|
|
22714
|
+
return checks.filter((check2) => check2 !== undefined).map((check2) => ({
|
|
21722
22715
|
...check2,
|
|
21723
22716
|
path: check2.path ? relative26(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
|
|
21724
22717
|
}));
|
|
@@ -21729,7 +22722,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21729
22722
|
const [path] = paths;
|
|
21730
22723
|
if (!path)
|
|
21731
22724
|
throw new TypeError(`Generated Expo iOS project is missing its ${label}.`);
|
|
21732
|
-
return
|
|
22725
|
+
return join55(iosRoot, path);
|
|
21733
22726
|
}, expoIosNativeProjectionCheck = async (config, iosRoot) => {
|
|
21734
22727
|
try {
|
|
21735
22728
|
const [infoPath, entitlementsPath, projectPath] = await Promise.all([
|
|
@@ -21738,9 +22731,9 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21738
22731
|
uniqueExpoIosFile(iosRoot, "**/*.xcodeproj/project.pbxproj", "Xcode project")
|
|
21739
22732
|
]);
|
|
21740
22733
|
const [info2, entitlements, project] = await Promise.all([
|
|
21741
|
-
|
|
21742
|
-
|
|
21743
|
-
|
|
22734
|
+
readFile20(infoPath, "utf8"),
|
|
22735
|
+
readFile20(entitlementsPath, "utf8"),
|
|
22736
|
+
readFile20(projectPath, "utf8")
|
|
21744
22737
|
]);
|
|
21745
22738
|
if (/<key>NSAllowsArbitraryLoads<\/key>\s*<true\s*\/>/u.test(info2))
|
|
21746
22739
|
throw new TypeError("Expo iOS App Transport Security permits arbitrary network loads.");
|
|
@@ -21755,8 +22748,8 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21755
22748
|
return fail5("ios.expo-native-projection", error instanceof Error ? error.message : "Expo iOS native projection could not be validated.", iosRoot, "Run `absolute mobile build ios` to regenerate the production Expo CNG project.");
|
|
21756
22749
|
}
|
|
21757
22750
|
}, inspectExpoIosRelease = async (config, projectRoot) => {
|
|
21758
|
-
const iosRoot =
|
|
21759
|
-
const journalPath =
|
|
22751
|
+
const iosRoot = join55(config.nativeProjectDirectory, "ios");
|
|
22752
|
+
const journalPath = join55(projectRoot, ".absolutejs", "mobile", "expo-dev-session", "journal.json");
|
|
21760
22753
|
const checks = [
|
|
21761
22754
|
await journalReleaseCheck(journalPath, "ios")
|
|
21762
22755
|
];
|
|
@@ -21770,16 +22763,19 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21770
22763
|
expoIosNativeProjectionCheck(config, iosRoot),
|
|
21771
22764
|
iosNativeSecurityCheck(iosRoot)
|
|
21772
22765
|
]));
|
|
22766
|
+
const nativeObservability = await nativeObservabilityProjectionCheck(config, "ios");
|
|
22767
|
+
if (nativeObservability)
|
|
22768
|
+
checks.push(nativeObservability);
|
|
21773
22769
|
return checks.map((check2) => ({
|
|
21774
22770
|
...check2,
|
|
21775
22771
|
path: check2.path ? relative26(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
|
|
21776
22772
|
}));
|
|
21777
22773
|
}, inspectIosRelease = async (config, projectRoot) => {
|
|
21778
|
-
const iosAppRoot =
|
|
21779
|
-
const nativeConfigPath =
|
|
21780
|
-
const infoPath =
|
|
21781
|
-
const publicRoot =
|
|
21782
|
-
const journalPath =
|
|
22774
|
+
const iosAppRoot = join55(config.nativeProjectDirectory, "ios", "App", "App");
|
|
22775
|
+
const nativeConfigPath = join55(iosAppRoot, "capacitor.config.json");
|
|
22776
|
+
const infoPath = join55(iosAppRoot, "Info.plist");
|
|
22777
|
+
const publicRoot = join55(iosAppRoot, "public");
|
|
22778
|
+
const journalPath = join55(projectRoot, ".absolutejs", "mobile", "ios-dev-session", "journal.json");
|
|
21783
22779
|
const checks = [
|
|
21784
22780
|
await journalReleaseCheck(journalPath, "ios")
|
|
21785
22781
|
];
|
|
@@ -21791,7 +22787,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21791
22787
|
}
|
|
21792
22788
|
if (!await pathExists6(nativeConfigPath)) {
|
|
21793
22789
|
checks.push(fail5("ios.capacitor-config", "The generated iOS Capacitor config is missing.", nativeConfigPath, "Run `absolute mobile sync ios` before release validation."));
|
|
21794
|
-
} else if (isUnsafeCapacitorConfig(await
|
|
22790
|
+
} else if (isUnsafeCapacitorConfig(await readFile20(nativeConfigPath, "utf8"))) {
|
|
21795
22791
|
checks.push(fail5("ios.capacitor-config", "iOS Capacitor config contains a development server URL, cleartext transport, navigation allowlist, or invalid JSON.", nativeConfigPath, "Run `absolute mobile sync ios`; do not ship development transport overrides."));
|
|
21796
22792
|
} else {
|
|
21797
22793
|
checks.push(pass("ios.capacitor-config", "iOS Capacitor config contains no development transport overrides.", nativeConfigPath));
|
|
@@ -21800,12 +22796,15 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21800
22796
|
if (!await pathExists6(infoPath)) {
|
|
21801
22797
|
checks.push(fail5("ios.transport-security", "The iOS Info.plist is missing.", infoPath, "Run `absolute mobile sync ios` before release validation."));
|
|
21802
22798
|
} else {
|
|
21803
|
-
const info2 = await
|
|
22799
|
+
const info2 = await readFile20(infoPath, "utf8");
|
|
21804
22800
|
checks.push(/<key>NSAllowsArbitraryLoads<\/key>\s*<true\s*\/>/u.test(info2) ? fail5("ios.transport-security", "iOS App Transport Security permits arbitrary network loads.", infoPath, "Remove NSAllowsArbitraryLoads from the release Info.plist.") : pass("ios.transport-security", "iOS App Transport Security does not permit arbitrary loads.", infoPath));
|
|
21805
22801
|
}
|
|
21806
22802
|
const hmrAsset = await findHmrAsset(publicRoot);
|
|
21807
22803
|
checks.push(hmrAsset ? fail5("ios.hmr-assets", "A packaged iOS asset contains the development HMR client.", hmrAsset, "Rebuild the production mobile bundle and run Capacitor sync again.") : pass("ios.hmr-assets", "Packaged iOS assets contain no development HMR markers.", publicRoot));
|
|
21808
|
-
checks.push(await embeddedBundleReleaseCheck(config, projectRoot, "ios", publicRoot), await contentSecurityPolicyCheck(config, "ios", publicRoot), await iosNativeSecurityCheck(
|
|
22804
|
+
checks.push(await embeddedBundleReleaseCheck(config, projectRoot, "ios", publicRoot), await contentSecurityPolicyCheck(config, "ios", publicRoot), await iosNativeSecurityCheck(join55(config.nativeProjectDirectory, "ios")), await iosDeepLinkProjectionCheck(config, join55(config.nativeProjectDirectory, "ios")));
|
|
22805
|
+
const nativeObservability = await nativeObservabilityProjectionCheck(config, "ios");
|
|
22806
|
+
if (nativeObservability)
|
|
22807
|
+
checks.push(nativeObservability);
|
|
21809
22808
|
if (updateWatchdog)
|
|
21810
22809
|
checks.push(updateWatchdog);
|
|
21811
22810
|
return checks.map((check2) => ({
|
|
@@ -21900,18 +22899,18 @@ import { createHash as createHash16 } from "crypto";
|
|
|
21900
22899
|
import {
|
|
21901
22900
|
access as access12,
|
|
21902
22901
|
copyFile as copyFile5,
|
|
21903
|
-
mkdir as
|
|
22902
|
+
mkdir as mkdir15,
|
|
21904
22903
|
mkdtemp as mkdtemp7,
|
|
21905
|
-
readFile as
|
|
22904
|
+
readFile as readFile21,
|
|
21906
22905
|
realpath as realpath2,
|
|
21907
|
-
rename as
|
|
21908
|
-
rm as
|
|
22906
|
+
rename as rename15,
|
|
22907
|
+
rm as rm12,
|
|
21909
22908
|
stat as stat3,
|
|
21910
|
-
writeFile as
|
|
22909
|
+
writeFile as writeFile17
|
|
21911
22910
|
} from "fs/promises";
|
|
21912
|
-
import { dirname as
|
|
21913
|
-
var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1,
|
|
21914
|
-
if (!
|
|
22911
|
+
import { dirname as dirname33, isAbsolute as isAbsolute7, join as join56, relative as relative27, resolve as resolve40, sep as sep7 } from "path";
|
|
22912
|
+
var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord17 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), requireManifest2 = (value) => {
|
|
22913
|
+
if (!isRecord17(value) || typeof value.appBuild !== "string" || typeof value.appId !== "string" || typeof value.runtime !== "string") {
|
|
21915
22914
|
throw new TypeError("Invalid embedded AbsoluteJS mobile manifest.");
|
|
21916
22915
|
}
|
|
21917
22916
|
return {
|
|
@@ -21973,14 +22972,14 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord16 = (value) => typeof value ==
|
|
|
21973
22972
|
]);
|
|
21974
22973
|
if (result.exitCode !== 0)
|
|
21975
22974
|
throw new TypeError("jarsigner could not sign the Android App Bundle with the configured CI identity.");
|
|
21976
|
-
}, sha256File2 = async (path) => createHash16("sha256").update(await
|
|
22975
|
+
}, sha256File2 = async (path) => createHash16("sha256").update(await readFile21(path)).digest("hex"), fingerprintExpoAndroidProject = async (nativeDirectory) => {
|
|
21977
22976
|
const root = await realpath2(nativeDirectory);
|
|
21978
22977
|
const files = await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: root, onlyFiles: true }));
|
|
21979
22978
|
const records = await Promise.all(files.filter((path) => {
|
|
21980
22979
|
const parts = path.replaceAll("\\", "/").split("/");
|
|
21981
22980
|
return !parts.includes(".gradle") && !parts.includes("build");
|
|
21982
22981
|
}).sort().map(async (path) => {
|
|
21983
|
-
const contents = await
|
|
22982
|
+
const contents = await readFile21(join56(root, path));
|
|
21984
22983
|
return `${path.replaceAll("\\", "/")}\x00${createHash16("sha256").update(contents).digest("hex")}\x00`;
|
|
21985
22984
|
}));
|
|
21986
22985
|
return createHash16("sha256").update(records.join("")).digest("hex");
|
|
@@ -21993,11 +22992,11 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord16 = (value) => typeof value ==
|
|
|
21993
22992
|
}
|
|
21994
22993
|
return output;
|
|
21995
22994
|
}, installRelease2 = async (artifactPath, metadata, outputRoot) => {
|
|
21996
|
-
const releaseRoot =
|
|
22995
|
+
const releaseRoot = join56(outputRoot, metadata.releaseId);
|
|
21997
22996
|
const artifactName = "app-release.aab";
|
|
21998
|
-
const destination =
|
|
22997
|
+
const destination = join56(releaseRoot, artifactName);
|
|
21999
22998
|
if (await pathExists7(releaseRoot)) {
|
|
22000
|
-
const existing = requireManifestIdentity(JSON.parse(await
|
|
22999
|
+
const existing = requireManifestIdentity(JSON.parse(await readFile21(join56(releaseRoot, "release.json"), "utf8")), metadata);
|
|
22001
23000
|
const [installedBytes, installedSha256] = await Promise.all([
|
|
22002
23001
|
stat3(destination).then(({ size }) => size),
|
|
22003
23002
|
sha256File2(destination)
|
|
@@ -22007,25 +23006,25 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord16 = (value) => typeof value ==
|
|
|
22007
23006
|
}
|
|
22008
23007
|
return { artifactPath: destination, metadata: existing, releaseRoot };
|
|
22009
23008
|
}
|
|
22010
|
-
await
|
|
22011
|
-
const staging = await mkdtemp7(
|
|
23009
|
+
await mkdir15(dirname33(releaseRoot), { recursive: true });
|
|
23010
|
+
const staging = await mkdtemp7(join56(dirname33(releaseRoot), ".android-stage-"));
|
|
22012
23011
|
try {
|
|
22013
|
-
await copyFile5(artifactPath,
|
|
23012
|
+
await copyFile5(artifactPath, join56(staging, artifactName));
|
|
22014
23013
|
const complete = {
|
|
22015
23014
|
...metadata,
|
|
22016
23015
|
artifact: artifactName
|
|
22017
23016
|
};
|
|
22018
|
-
await
|
|
23017
|
+
await writeFile17(join56(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
|
|
22019
23018
|
`, { flag: "wx" });
|
|
22020
|
-
await
|
|
23019
|
+
await rename15(staging, releaseRoot);
|
|
22021
23020
|
return { artifactPath: destination, metadata: complete, releaseRoot };
|
|
22022
23021
|
} finally {
|
|
22023
|
-
await
|
|
23022
|
+
await rm12(staging, { force: true, recursive: true }).catch(() => {
|
|
22024
23023
|
return;
|
|
22025
23024
|
});
|
|
22026
23025
|
}
|
|
22027
23026
|
}, requireManifestIdentity = (value, expected) => {
|
|
22028
|
-
if (!
|
|
23027
|
+
if (!isRecord17(value)) {
|
|
22029
23028
|
throw new TypeError("Existing Android release metadata is invalid.");
|
|
22030
23029
|
}
|
|
22031
23030
|
const { artifact } = value;
|
|
@@ -22046,8 +23045,8 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord16 = (value) => typeof value ==
|
|
|
22046
23045
|
throw new TypeError("Expo Android production builds from WSL are not available yet. Run the generated CI workflow on Linux or build from native Windows while the WSL projection is completed.");
|
|
22047
23046
|
}
|
|
22048
23047
|
const androidRoot = options.androidRoot ?? process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host2);
|
|
22049
|
-
const nativeDirectory =
|
|
22050
|
-
const manifest = requireManifest2(JSON.parse(await
|
|
23048
|
+
const nativeDirectory = join56(options.config.nativeProjectDirectory, "android");
|
|
23049
|
+
const manifest = requireManifest2(JSON.parse(await readFile21(join56(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
|
|
22051
23050
|
if (manifest.appId !== options.config.appId) {
|
|
22052
23051
|
throw new TypeError("Embedded mobile manifest appId does not match mobile.appId.");
|
|
22053
23052
|
}
|
|
@@ -22161,7 +23160,7 @@ var absoluteIosDeviceAcceptanceCommands = (options) => {
|
|
|
22161
23160
|
};
|
|
22162
23161
|
|
|
22163
23162
|
// src/mobile/iosConformance.ts
|
|
22164
|
-
import { readFile as
|
|
23163
|
+
import { readFile as readFile22, stat as stat4 } from "fs/promises";
|
|
22165
23164
|
var HMR_LINE, parseAbsoluteIosHmrLog = (line) => {
|
|
22166
23165
|
const match = HMR_LINE.exec(line);
|
|
22167
23166
|
if (!match)
|
|
@@ -22196,7 +23195,7 @@ var HMR_LINE, parseAbsoluteIosHmrLog = (line) => {
|
|
|
22196
23195
|
if (Date.now() > deadline)
|
|
22197
23196
|
throw new Error(`No iOS native HMR acknowledgement was observed within ${timeoutMs}ms.`);
|
|
22198
23197
|
options.signal?.throwIfAborted();
|
|
22199
|
-
const contents = await
|
|
23198
|
+
const contents = await readFile22(options.logPath).catch(() => Buffer.alloc(0));
|
|
22200
23199
|
if (contents.byteLength < offset) {
|
|
22201
23200
|
offset = 0;
|
|
22202
23201
|
buffered = "";
|
|
@@ -22220,8 +23219,8 @@ var init_iosConformance = __esm(() => {
|
|
|
22220
23219
|
});
|
|
22221
23220
|
|
|
22222
23221
|
// src/mobile/nativeTestReport.ts
|
|
22223
|
-
import { mkdir as
|
|
22224
|
-
import { join as
|
|
23222
|
+
import { mkdir as mkdir16, readFile as readFile23, writeFile as writeFile18 } from "fs/promises";
|
|
23223
|
+
import { join as join57 } from "path";
|
|
22225
23224
|
var secretPattern, bearerPattern, coordinatePattern, nativeCredentialPattern, sanitizeNativeReportText = (value) => value.replace(nativeCredentialPattern, "[REDACTED]").replace(bearerPattern, "Bearer [REDACTED]").replace(secretPattern, "$1$2[REDACTED]").replace(coordinatePattern, "$1$2[REDACTED]").replace(/(https?:\/\/[^\s?#]+)[?#][^\s]*/giu, "$1?[REDACTED]"), markdownCell = (value) => sanitizeNativeReportText(value).replaceAll("|", "\\|").replaceAll(`
|
|
22226
23225
|
`, "<br>"), createAbsoluteNativeAutomatedChecks = (run) => {
|
|
22227
23226
|
const target = `${run.targetKind} ${run.targetId}`;
|
|
@@ -22323,7 +23322,7 @@ var secretPattern, bearerPattern, coordinatePattern, nativeCredentialPattern, sa
|
|
|
22323
23322
|
reportVersion: 1,
|
|
22324
23323
|
run: options.run
|
|
22325
23324
|
}), readPackageVersionForNativeReport = async (packageJsonPath) => {
|
|
22326
|
-
const manifest = JSON.parse(await
|
|
23325
|
+
const manifest = JSON.parse(await readFile23(packageJsonPath, "utf8"));
|
|
22327
23326
|
if (typeof manifest !== "object" || manifest === null)
|
|
22328
23327
|
return "unknown";
|
|
22329
23328
|
const version2 = Reflect.get(manifest, "version");
|
|
@@ -22359,13 +23358,13 @@ Replace each \`NOT_RUN\` with \`PASS\`, \`FAIL\`, or \`SKIPPED\` after completin
|
|
|
22359
23358
|
${table(report.manualChecks)}
|
|
22360
23359
|
`;
|
|
22361
23360
|
}, writeAbsoluteNativeTestReport = async (directory, report) => {
|
|
22362
|
-
await
|
|
22363
|
-
const jsonPath =
|
|
22364
|
-
const markdownPath =
|
|
23361
|
+
await mkdir16(directory, { recursive: true });
|
|
23362
|
+
const jsonPath = join57(directory, "report.json");
|
|
23363
|
+
const markdownPath = join57(directory, "report.md");
|
|
22365
23364
|
await Promise.all([
|
|
22366
|
-
|
|
23365
|
+
writeFile18(jsonPath, `${JSON.stringify(report, null, 2)}
|
|
22367
23366
|
`),
|
|
22368
|
-
|
|
23367
|
+
writeFile18(markdownPath, renderAbsoluteNativeTestReport(report))
|
|
22369
23368
|
]);
|
|
22370
23369
|
return { directory, jsonPath, markdownPath };
|
|
22371
23370
|
};
|
|
@@ -22649,7 +23648,7 @@ var prepareAbsoluteIosRelease = async (publisher, options) => {
|
|
|
22649
23648
|
throw new TypeError("Google Play publisher returned an invalid Android versionCode.");
|
|
22650
23649
|
}
|
|
22651
23650
|
return versionCode;
|
|
22652
|
-
},
|
|
23651
|
+
}, isRecord18 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), isPublisher = (value) => isRecord18(value) && typeof value.publish === "function", publisherModulePath = (projectRoot, requested) => {
|
|
22653
23652
|
const root = resolve41(projectRoot);
|
|
22654
23653
|
const path = resolve41(root, requested);
|
|
22655
23654
|
const projectRelative = relative28(root, path);
|
|
@@ -22663,7 +23662,7 @@ var prepareAbsoluteIosRelease = async (publisher, options) => {
|
|
|
22663
23662
|
throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
|
|
22664
23663
|
});
|
|
22665
23664
|
const loaded = await import(pathToFileURL2(modulePath).href);
|
|
22666
|
-
const publisher =
|
|
23665
|
+
const publisher = isRecord18(loaded) ? loaded.default ?? loaded.registry : undefined;
|
|
22667
23666
|
if (!isPublisher(publisher)) {
|
|
22668
23667
|
throw new TypeError("Native release registry module must default-export a registry with publish(options).");
|
|
22669
23668
|
}
|
|
@@ -22720,8 +23719,8 @@ var prepareAbsoluteIosRelease = async (publisher, options) => {
|
|
|
22720
23719
|
var init_releasePublisher = () => {};
|
|
22721
23720
|
|
|
22722
23721
|
// src/mobile/mobileInspect.ts
|
|
22723
|
-
import { access as access14, readFile as
|
|
22724
|
-
import { join as
|
|
23722
|
+
import { access as access14, readFile as readFile24 } from "fs/promises";
|
|
23723
|
+
import { join as join58, relative as relative29, resolve as resolve42 } from "path";
|
|
22725
23724
|
var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1, MOBILE_PACKAGE_NAMES, isObject3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), portablePath2 = (projectRoot, path) => {
|
|
22726
23725
|
const value = relative29(resolve42(projectRoot), resolve42(path)).replaceAll("\\", "/");
|
|
22727
23726
|
return value || ".";
|
|
@@ -22733,7 +23732,7 @@ var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1, MOBILE_PACKAGE_NAMES, isObject3 = (va
|
|
|
22733
23732
|
return false;
|
|
22734
23733
|
}
|
|
22735
23734
|
}, readObject2 = async (path) => {
|
|
22736
|
-
const value = JSON.parse(await
|
|
23735
|
+
const value = JSON.parse(await readFile24(path, "utf8"));
|
|
22737
23736
|
if (!isObject3(value))
|
|
22738
23737
|
throw new TypeError("JSON root must be an object.");
|
|
22739
23738
|
return value;
|
|
@@ -22743,13 +23742,13 @@ var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1, MOBILE_PACKAGE_NAMES, isObject3 = (va
|
|
|
22743
23742
|
for (const [name, declared] of Object.entries(value).filter((entry) => typeof entry[1] === "string"))
|
|
22744
23743
|
declarations.set(name, declared);
|
|
22745
23744
|
}, packageInspections = async (projectRoot, additionalNames) => {
|
|
22746
|
-
const project = await readObject2(
|
|
23745
|
+
const project = await readObject2(join58(projectRoot, "package.json"));
|
|
22747
23746
|
const declarations = new Map;
|
|
22748
23747
|
for (const field of ["dependencies", "devDependencies"])
|
|
22749
23748
|
addPackageDeclarations(declarations, project[field]);
|
|
22750
23749
|
const names = [...new Set([...declarations.keys(), ...additionalNames])].filter((name) => MOBILE_PACKAGE_NAMES.has(name) || name.startsWith("@capacitor/") || additionalNames.includes(name)).sort();
|
|
22751
23750
|
return Promise.all(names.map(async (name) => {
|
|
22752
|
-
const installedManifest = await readObject2(
|
|
23751
|
+
const installedManifest = await readObject2(join58(projectRoot, "node_modules", name, "package.json")).catch(() => {
|
|
22753
23752
|
return;
|
|
22754
23753
|
});
|
|
22755
23754
|
const installed = installedManifest?.version;
|
|
@@ -22807,7 +23806,7 @@ var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1, MOBILE_PACKAGE_NAMES, isObject3 = (va
|
|
|
22807
23806
|
},
|
|
22808
23807
|
format: ABSOLUTE_MOBILE_INSPECTION_FORMAT,
|
|
22809
23808
|
nativeProjects: await Promise.all(config.platforms.map(async (platform6) => {
|
|
22810
|
-
const path =
|
|
23809
|
+
const path = join58(config.nativeProjectDirectory, platform6);
|
|
22811
23810
|
return {
|
|
22812
23811
|
initialized: await pathExists8(path),
|
|
22813
23812
|
path: portablePath2(projectRoot, path),
|
|
@@ -22878,8 +23877,8 @@ var init_mobileInspect = __esm(() => {
|
|
|
22878
23877
|
|
|
22879
23878
|
// src/mobile/ciWorkflow.ts
|
|
22880
23879
|
import { existsSync as existsSync43 } from "fs";
|
|
22881
|
-
import { access as access15, mkdir as
|
|
22882
|
-
import { dirname as
|
|
23880
|
+
import { access as access15, mkdir as mkdir17, readFile as readFile25, writeFile as writeFile19 } from "fs/promises";
|
|
23881
|
+
import { dirname as dirname34, extname as extname9, relative as relative30, resolve as resolve43, sep as sep9 } from "path";
|
|
22883
23882
|
var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1, SECRET_NAME_PATTERN, CI_ENV_INDENTATION = 6, RESERVED_SECRET_NAMES, exists4 = async (path) => {
|
|
22884
23883
|
try {
|
|
22885
23884
|
await access15(path);
|
|
@@ -23292,12 +24291,12 @@ ${bundleAuditSteps}${platforms.includes("android") ? androidJob({ customSecrets,
|
|
|
23292
24291
|
}, writeAbsoluteMobileGithubWorkflow = async (options) => {
|
|
23293
24292
|
const path = workflowOutputPath(options.projectRoot, options.outputPath);
|
|
23294
24293
|
const generated = createAbsoluteMobileGithubWorkflow(options);
|
|
23295
|
-
const previous = await exists4(path) ? await
|
|
24294
|
+
const previous = await exists4(path) ? await readFile25(path, "utf8") : undefined;
|
|
23296
24295
|
if (previous !== undefined && previous !== generated.workflow && !options.force)
|
|
23297
24296
|
throw new TypeError(`${relative30(options.projectRoot, path)} already exists and differs. Rerun with --force to replace the generated workflow.`);
|
|
23298
24297
|
if (previous !== generated.workflow) {
|
|
23299
|
-
await
|
|
23300
|
-
await
|
|
24298
|
+
await mkdir17(dirname34(path), { recursive: true });
|
|
24299
|
+
await writeFile19(path, generated.workflow);
|
|
23301
24300
|
}
|
|
23302
24301
|
return {
|
|
23303
24302
|
changed: previous !== generated.workflow,
|
|
@@ -23358,20 +24357,20 @@ var init_ciWorkflow = __esm(() => {
|
|
|
23358
24357
|
import { createHash as createHash17, sign as sign2, verify as verify2 } from "crypto";
|
|
23359
24358
|
import {
|
|
23360
24359
|
cp as cp4,
|
|
23361
|
-
mkdir as
|
|
24360
|
+
mkdir as mkdir18,
|
|
23362
24361
|
mkdtemp as mkdtemp8,
|
|
23363
|
-
readdir as
|
|
23364
|
-
readFile as
|
|
23365
|
-
rename as
|
|
23366
|
-
rm as
|
|
24362
|
+
readdir as readdir8,
|
|
24363
|
+
readFile as readFile26,
|
|
24364
|
+
rename as rename16,
|
|
24365
|
+
rm as rm13,
|
|
23367
24366
|
stat as stat5,
|
|
23368
|
-
writeFile as
|
|
24367
|
+
writeFile as writeFile20
|
|
23369
24368
|
} from "fs/promises";
|
|
23370
|
-
import { dirname as
|
|
24369
|
+
import { dirname as dirname35, join as join59, relative as relative31, resolve as resolve44 } from "path";
|
|
23371
24370
|
var UPDATE_MANIFEST_FILE = "update.json", UPDATE_FILES_DIRECTORY = "files", sha2562 = (value) => createHash17("sha256").update(value).digest("hex"), listFiles = async (root, directory = root) => {
|
|
23372
|
-
const entries = await
|
|
24371
|
+
const entries = await readdir8(directory, { withFileTypes: true });
|
|
23373
24372
|
const paths = await Promise.all(entries.map(async (entry) => {
|
|
23374
|
-
const path =
|
|
24373
|
+
const path = join59(directory, entry.name);
|
|
23375
24374
|
if (entry.isDirectory())
|
|
23376
24375
|
return listFiles(root, path);
|
|
23377
24376
|
if (!entry.isFile())
|
|
@@ -23380,10 +24379,10 @@ var UPDATE_MANIFEST_FILE = "update.json", UPDATE_FILES_DIRECTORY = "files", sha2
|
|
|
23380
24379
|
}));
|
|
23381
24380
|
return paths.flat().sort((left, right) => left.localeCompare(right));
|
|
23382
24381
|
}, inspectFiles = async (root, paths) => Promise.all(paths.map(async (path) => {
|
|
23383
|
-
const source =
|
|
24382
|
+
const source = join59(root, path);
|
|
23384
24383
|
const [metadata, contents] = await Promise.all([
|
|
23385
24384
|
stat5(source),
|
|
23386
|
-
|
|
24385
|
+
readFile26(source)
|
|
23387
24386
|
]);
|
|
23388
24387
|
return { bytes: metadata.size, path, sha256: sha2562(contents) };
|
|
23389
24388
|
})), releaseIdFor = (value) => `amu_${sha2562(canonicalizeAbsoluteMobileUpdate(value))}`, buildAbsoluteMobileUpdate = async (options) => {
|
|
@@ -23416,29 +24415,29 @@ var UPDATE_MANIFEST_FILE = "update.json", UPDATE_FILES_DIRECTORY = "files", sha2
|
|
|
23416
24415
|
value: signature.toString("base64")
|
|
23417
24416
|
}
|
|
23418
24417
|
});
|
|
23419
|
-
await
|
|
23420
|
-
const outputDirectory =
|
|
23421
|
-
const staging = await mkdtemp8(
|
|
24418
|
+
await mkdir18(outputRoot, { recursive: true });
|
|
24419
|
+
const outputDirectory = join59(outputRoot, manifest.releaseId);
|
|
24420
|
+
const staging = await mkdtemp8(join59(outputRoot, ".stage-"));
|
|
23422
24421
|
try {
|
|
23423
|
-
await cp4(bundleDirectory,
|
|
24422
|
+
await cp4(bundleDirectory, join59(staging, UPDATE_FILES_DIRECTORY), {
|
|
23424
24423
|
force: true,
|
|
23425
24424
|
recursive: true
|
|
23426
24425
|
});
|
|
23427
|
-
await
|
|
24426
|
+
await writeFile20(join59(staging, UPDATE_MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
|
|
23428
24427
|
`);
|
|
23429
|
-
await
|
|
24428
|
+
await rename16(staging, outputDirectory);
|
|
23430
24429
|
} catch (error) {
|
|
23431
|
-
await
|
|
24430
|
+
await rm13(staging, { force: true, recursive: true });
|
|
23432
24431
|
if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "EEXIST")
|
|
23433
24432
|
throw new TypeError(`Mobile update ${manifest.releaseId} already exists.`, { cause: error });
|
|
23434
24433
|
throw error;
|
|
23435
24434
|
}
|
|
23436
24435
|
return {
|
|
23437
24436
|
manifest,
|
|
23438
|
-
manifestPath:
|
|
24437
|
+
manifestPath: join59(outputDirectory, UPDATE_MANIFEST_FILE),
|
|
23439
24438
|
outputDirectory
|
|
23440
24439
|
};
|
|
23441
|
-
}, readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await
|
|
24440
|
+
}, readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await readFile26(join59(resolve44(directory), UPDATE_MANIFEST_FILE), "utf8"))), verifyAbsoluteMobileUpdateSignature = (manifestValue, publicKey) => {
|
|
23442
24441
|
const manifest = parseAbsoluteMobileUpdateManifest(manifestValue);
|
|
23443
24442
|
const valid = verify2("sha256", absoluteMobileUpdateSigningPayload(unsignedAbsoluteMobileUpdate(manifest)), { dsaEncoding: "ieee-p1363", key: publicKey }, Buffer.from(manifest.signature.value, "base64"));
|
|
23444
24443
|
if (!valid)
|
|
@@ -23450,8 +24449,8 @@ var init_updateSigning = __esm(() => {
|
|
|
23450
24449
|
});
|
|
23451
24450
|
|
|
23452
24451
|
// src/mobile/expoUpdate.ts
|
|
23453
|
-
import { access as access16, mkdir as
|
|
23454
|
-
import { dirname as
|
|
24452
|
+
import { access as access16, mkdir as mkdir19, readFile as readFile27, writeFile as writeFile21 } from "fs/promises";
|
|
24453
|
+
import { dirname as dirname36, extname as extname10, join as join60 } from "path";
|
|
23455
24454
|
var ABSOLUTE_EXPO_UPDATE_DESCRIPTOR = "_absolute/expo-update.json", ABSOLUTE_EXPO_UPDATE_FORMAT = 1, object4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), safePath = (value, field) => {
|
|
23456
24455
|
if (typeof value !== "string" || value.length === 0)
|
|
23457
24456
|
throw new TypeError(`Expo update ${field} is invalid.`);
|
|
@@ -23509,7 +24508,7 @@ var ABSOLUTE_EXPO_UPDATE_DESCRIPTOR = "_absolute/expo-update.json", ABSOLUTE_EXP
|
|
|
23509
24508
|
runtimeVersion: value.runtimeVersion
|
|
23510
24509
|
};
|
|
23511
24510
|
}, finalizeAbsoluteExpoUpdateExport = async (options) => {
|
|
23512
|
-
const metadata = JSON.parse(await
|
|
24511
|
+
const metadata = JSON.parse(await readFile27(join60(options.exportDirectory, "metadata.json"), "utf8"));
|
|
23513
24512
|
if (!object4(metadata) || !object4(metadata.fileMetadata))
|
|
23514
24513
|
throw new TypeError("Expo export metadata.json is invalid.");
|
|
23515
24514
|
const descriptor = parseAbsoluteExpoUpdateDescriptor({
|
|
@@ -23520,12 +24519,12 @@ var ABSOLUTE_EXPO_UPDATE_DESCRIPTOR = "_absolute/expo-update.json", ABSOLUTE_EXP
|
|
|
23520
24519
|
runtimeVersion: options.runtimeVersion
|
|
23521
24520
|
});
|
|
23522
24521
|
const referenced = Object.values(descriptor.platforms).flatMap((entry) => entry ? [entry.launchAsset, ...entry.assets] : []);
|
|
23523
|
-
await Promise.all(referenced.map(({ path }) => access16(
|
|
24522
|
+
await Promise.all(referenced.map(({ path }) => access16(join60(options.exportDirectory, path)).catch(() => {
|
|
23524
24523
|
throw new TypeError(`Expo export metadata references missing asset ${path}.`);
|
|
23525
24524
|
})));
|
|
23526
|
-
const destination =
|
|
23527
|
-
await
|
|
23528
|
-
await
|
|
24525
|
+
const destination = join60(options.exportDirectory, ABSOLUTE_EXPO_UPDATE_DESCRIPTOR);
|
|
24526
|
+
await mkdir19(dirname36(destination), { recursive: true });
|
|
24527
|
+
await writeFile21(destination, `${JSON.stringify(descriptor, null, "\t")}
|
|
23529
24528
|
`);
|
|
23530
24529
|
return { descriptor, path: destination };
|
|
23531
24530
|
};
|
|
@@ -40199,8 +41198,8 @@ var require_main = __commonJS(function(exports) {
|
|
|
40199
41198
|
});
|
|
40200
41199
|
|
|
40201
41200
|
// src/mobile/expoCodeSigning.ts
|
|
40202
|
-
import { access as access17, mkdir as
|
|
40203
|
-
import { dirname as
|
|
41201
|
+
import { access as access17, mkdir as mkdir20, writeFile as writeFile22 } from "fs/promises";
|
|
41202
|
+
import { dirname as dirname37, isAbsolute as isAbsolute9, relative as relative32, resolve as resolve45, sep as sep10 } from "path";
|
|
40204
41203
|
var import_code_signing_certificates, exists5 = async (path) => access17(path).then(() => true).catch(() => false), inside = (root, path) => {
|
|
40205
41204
|
const location = relative32(root, path);
|
|
40206
41205
|
return location === "" || location !== ".." && !location.startsWith(`..${sep10}`) && !isAbsolute9(location);
|
|
@@ -40208,7 +41207,7 @@ var import_code_signing_certificates, exists5 = async (path) => access17(path).t
|
|
|
40208
41207
|
const root = resolve45(options.projectRoot);
|
|
40209
41208
|
const certificatePath = resolve45(root, options.certificatePath);
|
|
40210
41209
|
const privateKeyPath = resolve45(root, options.privateKeyPath);
|
|
40211
|
-
const publicKeyPath = resolve45(root, options.publicKeyPath ?? resolve45(
|
|
41210
|
+
const publicKeyPath = resolve45(root, options.publicKeyPath ?? resolve45(dirname37(privateKeyPath), "public-key.pem"));
|
|
40212
41211
|
if (!inside(root, certificatePath))
|
|
40213
41212
|
throw new TypeError("Expo code-signing certificate must be written inside the project so store builds can embed it.");
|
|
40214
41213
|
if (inside(root, privateKeyPath) || inside(root, publicKeyPath))
|
|
@@ -40238,11 +41237,11 @@ var import_code_signing_certificates, exists5 = async (path) => access17(path).t
|
|
|
40238
41237
|
import_code_signing_certificates.validateSelfSignedCertificate(certificate, keyPair);
|
|
40239
41238
|
const { privateKeyPEM, publicKeyPEM } = import_code_signing_certificates.convertKeyPairToPEM(keyPair);
|
|
40240
41239
|
const certificatePem = import_code_signing_certificates.convertCertificateToCertificatePEM(certificate);
|
|
40241
|
-
await Promise.all([certificatePath, privateKeyPath, publicKeyPath].map((path) =>
|
|
41240
|
+
await Promise.all([certificatePath, privateKeyPath, publicKeyPath].map((path) => mkdir20(dirname37(path), { recursive: true })));
|
|
40242
41241
|
await Promise.all([
|
|
40243
|
-
|
|
40244
|
-
|
|
40245
|
-
|
|
41242
|
+
writeFile22(certificatePath, certificatePem, { flag: "wx", mode: 420 }),
|
|
41243
|
+
writeFile22(privateKeyPath, privateKeyPEM, { flag: "wx", mode: 384 }),
|
|
41244
|
+
writeFile22(publicKeyPath, publicKeyPEM, { flag: "wx", mode: 420 })
|
|
40246
41245
|
]);
|
|
40247
41246
|
return {
|
|
40248
41247
|
certificatePath,
|
|
@@ -40321,18 +41320,18 @@ __export(exports_mobile, {
|
|
|
40321
41320
|
});
|
|
40322
41321
|
import {
|
|
40323
41322
|
access as access19,
|
|
40324
|
-
mkdir as
|
|
41323
|
+
mkdir as mkdir21,
|
|
40325
41324
|
mkdtemp as mkdtemp9,
|
|
40326
|
-
readFile as
|
|
40327
|
-
rm as
|
|
40328
|
-
writeFile as
|
|
41325
|
+
readFile as readFile28,
|
|
41326
|
+
rm as rm14,
|
|
41327
|
+
writeFile as writeFile23
|
|
40329
41328
|
} from "fs/promises";
|
|
40330
41329
|
import { createPublicKey as createPublicKey3 } from "crypto";
|
|
40331
|
-
import { join as
|
|
41330
|
+
import { join as join61, relative as relative34, resolve as resolve47 } from "path";
|
|
40332
41331
|
import { createInterface } from "readline/promises";
|
|
40333
|
-
var NOT_FOUND4 = -1,
|
|
41332
|
+
var NOT_FOUND4 = -1, isRecord19 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), expoPublicConfig = (config) => {
|
|
40334
41333
|
const result = { ...config };
|
|
40335
|
-
if (!
|
|
41334
|
+
if (!isRecord19(result.updates))
|
|
40336
41335
|
return result;
|
|
40337
41336
|
const {
|
|
40338
41337
|
codeSigningCertificate: _codeSigningCertificate,
|
|
@@ -40342,21 +41341,21 @@ var NOT_FOUND4 = -1, isRecord18 = (value) => typeof value === "object" && value
|
|
|
40342
41341
|
result.updates = publicUpdates;
|
|
40343
41342
|
return result;
|
|
40344
41343
|
}, CAPACITOR_PACKAGES, CAPACITOR_PACKAGE_SPECS, CAPACITOR_SYNC_PACKAGE_SPECS, packageNameFromSpec = (spec) => spec.slice(0, spec.lastIndexOf("@")), directProjectPackages = async (projectRoot) => {
|
|
40345
|
-
const manifest = JSON.parse(await
|
|
40346
|
-
if (!
|
|
41344
|
+
const manifest = JSON.parse(await readFile28(join61(projectRoot, "package.json"), "utf8"));
|
|
41345
|
+
if (!isRecord19(manifest))
|
|
40347
41346
|
throw new TypeError("Application package.json must contain an object.");
|
|
40348
41347
|
const names = new Set;
|
|
40349
41348
|
for (const field of ["dependencies", "devDependencies"]) {
|
|
40350
41349
|
const dependencies = Reflect.get(manifest, field);
|
|
40351
|
-
if (
|
|
41350
|
+
if (isRecord19(dependencies))
|
|
40352
41351
|
for (const name of Object.keys(dependencies))
|
|
40353
41352
|
names.add(name);
|
|
40354
41353
|
}
|
|
40355
41354
|
return names;
|
|
40356
41355
|
}, resolvedPackageVersion = async (projectRoot, packageName) => {
|
|
40357
41356
|
try {
|
|
40358
|
-
const manifest = JSON.parse(await
|
|
40359
|
-
return
|
|
41357
|
+
const manifest = JSON.parse(await readFile28(join61(projectRoot, "node_modules", packageName, "package.json"), "utf8"));
|
|
41358
|
+
return isRecord19(manifest) && typeof manifest.version === "string" ? manifest.version : undefined;
|
|
40360
41359
|
} catch {
|
|
40361
41360
|
return;
|
|
40362
41361
|
}
|
|
@@ -40397,7 +41396,7 @@ var NOT_FOUND4 = -1, isRecord18 = (value) => typeof value === "object" && value
|
|
|
40397
41396
|
}
|
|
40398
41397
|
return value;
|
|
40399
41398
|
}, capacitorExecutable = async (projectRoot) => {
|
|
40400
|
-
const executable =
|
|
41399
|
+
const executable = join61(projectRoot, "node_modules", ".bin", "cap");
|
|
40401
41400
|
try {
|
|
40402
41401
|
await access19(executable);
|
|
40403
41402
|
return executable;
|
|
@@ -40417,7 +41416,7 @@ var NOT_FOUND4 = -1, isRecord18 = (value) => typeof value === "object" && value
|
|
|
40417
41416
|
throw new TypeError(`Capacitor exited with status ${exitCode}.`);
|
|
40418
41417
|
}
|
|
40419
41418
|
}, runCapacitorForPlatforms = (projectRoot, command, platforms) => platforms.reduce((pending, platform7) => pending.then(() => runCapacitor(projectRoot, [command, platform7])), Promise.resolve()), expoExecutable = async (project) => {
|
|
40420
|
-
const executable =
|
|
41419
|
+
const executable = join61(project, "node_modules", ".bin", "expo");
|
|
40421
41420
|
try {
|
|
40422
41421
|
await access19(executable);
|
|
40423
41422
|
return executable;
|
|
@@ -40448,14 +41447,14 @@ var NOT_FOUND4 = -1, isRecord18 = (value) => typeof value === "object" && value
|
|
|
40448
41447
|
throw new TypeError(`Expo exited with status ${exitCode}.`);
|
|
40449
41448
|
}, ensureExpoPackages = async (project, args) => {
|
|
40450
41449
|
try {
|
|
40451
|
-
const manifest = JSON.parse(await
|
|
41450
|
+
const manifest = JSON.parse(await readFile28(join61(project, "package.json"), "utf8"));
|
|
40452
41451
|
const dependencies = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "dependencies") : undefined;
|
|
40453
41452
|
if (typeof dependencies !== "object" || dependencies === null || Array.isArray(dependencies))
|
|
40454
41453
|
throw new TypeError("Generated Expo dependencies are invalid.");
|
|
40455
41454
|
await Promise.all(Object.entries(dependencies).map(async ([name, expected]) => {
|
|
40456
41455
|
if (typeof expected !== "string")
|
|
40457
41456
|
throw new TypeError("Generated Expo dependency version is invalid.");
|
|
40458
|
-
const installed = JSON.parse(await
|
|
41457
|
+
const installed = JSON.parse(await readFile28(join61(project, "node_modules", name, "package.json"), "utf8"));
|
|
40459
41458
|
const actual = typeof installed === "object" && installed !== null ? Reflect.get(installed, "version") : undefined;
|
|
40460
41459
|
if (typeof actual !== "string")
|
|
40461
41460
|
throw new TypeError("Installed Expo dependency version is invalid.");
|
|
@@ -40604,6 +41603,7 @@ var NOT_FOUND4 = -1, isRecord18 = (value) => typeof value === "object" && value
|
|
|
40604
41603
|
await applyAbsoluteNativeDeviceCapabilities(projectRoot, mobile);
|
|
40605
41604
|
await applyAbsoluteNativeBackgroundSync(projectRoot, mobile);
|
|
40606
41605
|
await applyAbsoluteNativeUpdates(mobile);
|
|
41606
|
+
await applyAbsoluteNativeObservability(mobile);
|
|
40607
41607
|
}, sync = async (args) => {
|
|
40608
41608
|
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
40609
41609
|
if (mobile.engine === "expo") {
|
|
@@ -40637,6 +41637,7 @@ var NOT_FOUND4 = -1, isRecord18 = (value) => typeof value === "object" && value
|
|
|
40637
41637
|
await applyAbsoluteNativeDeviceCapabilities(projectRoot, mobile, platforms);
|
|
40638
41638
|
await applyAbsoluteNativeBackgroundSync(projectRoot, mobile, platforms);
|
|
40639
41639
|
await applyAbsoluteNativeUpdates(mobile, platforms);
|
|
41640
|
+
await applyAbsoluteNativeObservability(mobile, platforms);
|
|
40640
41641
|
}, associations = async (args) => {
|
|
40641
41642
|
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
40642
41643
|
const outputDirectory = resolve47(projectRoot, valueAfter(args, "--outdir") ?? ".absolutejs/mobile/associations");
|
|
@@ -40793,9 +41794,9 @@ Mobile release security and compliance checks failed.`);
|
|
|
40793
41794
|
temporaryDirectory: undefined
|
|
40794
41795
|
};
|
|
40795
41796
|
await ensureExpoPackages(mobile.nativeProjectDirectory, options.args);
|
|
40796
|
-
const temporaryParent =
|
|
40797
|
-
await
|
|
40798
|
-
const temporaryDirectory = await mkdtemp9(
|
|
41797
|
+
const temporaryParent = join61(options.projectRoot, ".absolutejs", "mobile", "expo-update-exports");
|
|
41798
|
+
await mkdir21(temporaryParent, { recursive: true });
|
|
41799
|
+
const temporaryDirectory = await mkdtemp9(join61(temporaryParent, ".stage-"));
|
|
40799
41800
|
try {
|
|
40800
41801
|
await runExpo(mobile.nativeProjectDirectory, [
|
|
40801
41802
|
"export",
|
|
@@ -40807,9 +41808,9 @@ Mobile release security and compliance checks failed.`);
|
|
|
40807
41808
|
temporaryDirectory,
|
|
40808
41809
|
"--clear"
|
|
40809
41810
|
], { production: true });
|
|
40810
|
-
const generatedApp = JSON.parse(await
|
|
40811
|
-
const expoConfig =
|
|
40812
|
-
if (!
|
|
41811
|
+
const generatedApp = JSON.parse(await readFile28(join61(mobile.nativeProjectDirectory, "app.json"), "utf8"));
|
|
41812
|
+
const expoConfig = isRecord19(generatedApp) ? generatedApp.expo : undefined;
|
|
41813
|
+
if (!isRecord19(expoConfig))
|
|
40813
41814
|
throw new TypeError("Generated Expo app configuration is invalid.");
|
|
40814
41815
|
const publicExpoConfig = expoPublicConfig(expoConfig);
|
|
40815
41816
|
const computedRuntime = resolveAbsoluteMobileUpdateRuntime(mobile, options.projectRoot).fingerprint;
|
|
@@ -40825,7 +41826,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
40825
41826
|
temporaryDirectory
|
|
40826
41827
|
};
|
|
40827
41828
|
} catch (error) {
|
|
40828
|
-
await
|
|
41829
|
+
await rm14(temporaryDirectory, { force: true, recursive: true });
|
|
40829
41830
|
throw error;
|
|
40830
41831
|
}
|
|
40831
41832
|
}, buildMobileUpdate = async (args) => {
|
|
@@ -40849,11 +41850,11 @@ Mobile release security and compliance checks failed.`);
|
|
|
40849
41850
|
let expoExportDirectory;
|
|
40850
41851
|
try {
|
|
40851
41852
|
await start(mobileBuildServerEntry(args), valueAfter(args, "--web-outdir"), configPath2, { prepareOnly: true });
|
|
40852
|
-
const embedded = JSON.parse(await
|
|
40853
|
-
const runtimeFingerprint =
|
|
41853
|
+
const embedded = JSON.parse(await readFile28(join61(mobile.bundleDirectory, "absolute-mobile-manifest.json"), "utf8"));
|
|
41854
|
+
const runtimeFingerprint = isRecord19(embedded) ? embedded.nativeRuntime : undefined;
|
|
40854
41855
|
if (typeof runtimeFingerprint !== "string" || !/^[a-f0-9]{64}$/u.test(runtimeFingerprint))
|
|
40855
41856
|
throw new TypeError("Prepared mobile bundle is missing its native runtime fingerprint.");
|
|
40856
|
-
const privateKey = await
|
|
41857
|
+
const privateKey = await readFile28(resolve47(projectRoot, signingKeyPath));
|
|
40857
41858
|
const configuredPublicKey = Buffer.from(mobile.updates.publicKeys[keyId], "base64");
|
|
40858
41859
|
const derivedPublicKey = createPublicKey3(privateKey).export({
|
|
40859
41860
|
format: "der",
|
|
@@ -40874,7 +41875,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
40874
41875
|
channel: mobile.updates.channel,
|
|
40875
41876
|
classification,
|
|
40876
41877
|
keyId,
|
|
40877
|
-
outputDirectory: valueAfter(args, "--outdir") ??
|
|
41878
|
+
outputDirectory: valueAfter(args, "--outdir") ?? join61(projectRoot, ".absolutejs", "mobile", "updates"),
|
|
40878
41879
|
privateKey,
|
|
40879
41880
|
runtimeFingerprint
|
|
40880
41881
|
});
|
|
@@ -40886,7 +41887,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
40886
41887
|
return result;
|
|
40887
41888
|
} finally {
|
|
40888
41889
|
if (expoExportDirectory)
|
|
40889
|
-
await
|
|
41890
|
+
await rm14(expoExportDirectory, { force: true, recursive: true });
|
|
40890
41891
|
sendTelemetryEvent("mobile:update-build", {
|
|
40891
41892
|
classification: classification ?? "invalid",
|
|
40892
41893
|
durationMs: Math.round(performance.now() - startedAt),
|
|
@@ -41147,6 +42148,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
41147
42148
|
await applyAbsoluteNativeDeviceCapabilities(projectRoot, mobile, ["ios"]);
|
|
41148
42149
|
await applyAbsoluteNativeBackgroundSync(projectRoot, mobile, ["ios"]);
|
|
41149
42150
|
await applyAbsoluteNativeUpdates(mobile, ["ios"]);
|
|
42151
|
+
await applyAbsoluteNativeObservability(mobile, ["ios"]);
|
|
41150
42152
|
}, prepareIosReleaseProject = (mobile, projectRoot, args) => mobile.engine === "expo" ? prepareExpoIosReleaseProject(mobile, projectRoot, args) : prepareCapacitorIosReleaseProject(mobile, projectRoot), prepareCapacitorAndroidReleaseProject = async (mobile, projectRoot) => {
|
|
41151
42153
|
await writeAbsoluteCapacitorConfig(mobile, { projectRoot });
|
|
41152
42154
|
await runCapacitorForPlatforms(projectRoot, "sync", ["android"]);
|
|
@@ -41156,6 +42158,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
41156
42158
|
]);
|
|
41157
42159
|
await applyAbsoluteNativeBackgroundSync(projectRoot, mobile, ["android"]);
|
|
41158
42160
|
await applyAbsoluteNativeUpdates(mobile, ["android"]);
|
|
42161
|
+
await applyAbsoluteNativeObservability(mobile, ["android"]);
|
|
41159
42162
|
}, prepareAndroidReleaseProject = (mobile, projectRoot, args) => mobile.engine === "expo" ? prepareExpoAndroidReleaseProject(mobile, projectRoot, args) : prepareCapacitorAndroidReleaseProject(mobile, projectRoot), buildAndroid = async (args, prepareVersionCode) => {
|
|
41160
42163
|
const configPath2 = valueAfter(args, "--config");
|
|
41161
42164
|
const { mobile, projectRoot } = await loadMobile(configPath2);
|
|
@@ -41183,7 +42186,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
41183
42186
|
const durationMs = Math.round(performance.now() - startedAt);
|
|
41184
42187
|
console.log(`Built ${release.metadata.signed ? "signed" : "unsigned"} Android App Bundle in ${getDurationString(durationMs)}.`);
|
|
41185
42188
|
console.log(`Artifact: ${release.artifactPath}`);
|
|
41186
|
-
console.log(`Metadata: ${
|
|
42189
|
+
console.log(`Metadata: ${join61(release.releaseRoot, "release.json")}`);
|
|
41187
42190
|
return release;
|
|
41188
42191
|
} finally {
|
|
41189
42192
|
sendTelemetryEvent("mobile:android-release-build", {
|
|
@@ -41331,7 +42334,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
41331
42334
|
const durationMs = Math.round(performance.now() - startedAt);
|
|
41332
42335
|
console.log(`Built ${release.metadata.signed ? "signed" : "unsigned"} iOS IPA ${release.metadata.marketingVersion}${release.metadata.buildNumber ? ` (${release.metadata.buildNumber})` : ""} in ${getDurationString(durationMs)}.`);
|
|
41333
42336
|
console.log(`Artifact: ${release.artifactPath}`);
|
|
41334
|
-
console.log(`Metadata: ${
|
|
42337
|
+
console.log(`Metadata: ${join61(release.releaseRoot, "release.json")}`);
|
|
41335
42338
|
return release;
|
|
41336
42339
|
} finally {
|
|
41337
42340
|
stopListeningForCancellation();
|
|
@@ -41440,7 +42443,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
41440
42443
|
checks.push({
|
|
41441
42444
|
id: "sync.storage-schema",
|
|
41442
42445
|
label: `Offline schema ${schema.components.map((component2) => `${component2.id}@${component2.version}`).join(", ")}`,
|
|
41443
|
-
path:
|
|
42446
|
+
path: join61(projectRoot, "package.json"),
|
|
41444
42447
|
platform: "host",
|
|
41445
42448
|
status: "pass"
|
|
41446
42449
|
});
|
|
@@ -41448,7 +42451,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
41448
42451
|
checks.push({
|
|
41449
42452
|
id: "sync.storage-schema",
|
|
41450
42453
|
label: "Offline schema metadata is invalid",
|
|
41451
|
-
path:
|
|
42454
|
+
path: join61(projectRoot, "package.json"),
|
|
41452
42455
|
platform: "host",
|
|
41453
42456
|
remediation: error instanceof Error ? error.message : String(error),
|
|
41454
42457
|
status: "fail"
|
|
@@ -41601,12 +42604,12 @@ Emulator setup verification:`);
|
|
|
41601
42604
|
timeoutMs
|
|
41602
42605
|
});
|
|
41603
42606
|
}, writeAndroidFailureArtifacts = async (options) => {
|
|
41604
|
-
await
|
|
41605
|
-
const screenshot = options.session ? await options.session.screenshot(
|
|
42607
|
+
await mkdir21(options.artifactRoot, { recursive: true });
|
|
42608
|
+
const screenshot = options.session ? await options.session.screenshot(join61(options.artifactRoot, "android-failure.png")).catch(() => {
|
|
41606
42609
|
return;
|
|
41607
42610
|
}) : undefined;
|
|
41608
|
-
const diagnosticPath =
|
|
41609
|
-
await
|
|
42611
|
+
const diagnosticPath = join61(options.artifactRoot, "android-failure.json");
|
|
42612
|
+
await writeFile23(diagnosticPath, `${JSON.stringify({
|
|
41610
42613
|
diagnostics: options.session?.diagnostics ?? [],
|
|
41611
42614
|
error: options.error instanceof Error ? options.error.message : String(options.error),
|
|
41612
42615
|
platform: "android",
|
|
@@ -41670,7 +42673,7 @@ Emulator setup verification:`);
|
|
|
41670
42673
|
console.log(JSON.stringify(report, null, 2));
|
|
41671
42674
|
else
|
|
41672
42675
|
printAndroidTestReport(report);
|
|
41673
|
-
const screenshot = reportRoot ? await session.screenshot(
|
|
42676
|
+
const screenshot = reportRoot ? await session.screenshot(join61(artifactRoot, "android-emulator.png")) : undefined;
|
|
41674
42677
|
await writeRequestedAndroidReport({
|
|
41675
42678
|
adb,
|
|
41676
42679
|
args,
|
|
@@ -41762,7 +42765,7 @@ Emulator setup verification:`);
|
|
|
41762
42765
|
return;
|
|
41763
42766
|
});
|
|
41764
42767
|
const status2 = response?.ok ? await response.json().catch(() => null) : null;
|
|
41765
|
-
const targets =
|
|
42768
|
+
const targets = isRecord19(status2) && isRecord19(status2.connectedTargets) ? status2.connectedTargets : undefined;
|
|
41766
42769
|
if (targets && typeof targets["capacitor-ios"] === "number" && targets["capacitor-ios"] > 0)
|
|
41767
42770
|
return;
|
|
41768
42771
|
await Bun.sleep(100);
|
|
@@ -41859,8 +42862,8 @@ Emulator setup verification:`);
|
|
|
41859
42862
|
throw new Error(`${label} failed: ${result.stderr.trim() || result.stdout.trim() || `status ${result.exitCode}`}`);
|
|
41860
42863
|
return result;
|
|
41861
42864
|
}, writeIosFailureArtifacts = async (options) => {
|
|
41862
|
-
await
|
|
41863
|
-
const screenshot =
|
|
42865
|
+
await mkdir21(options.artifactRoot, { recursive: true });
|
|
42866
|
+
const screenshot = join61(options.artifactRoot, "ios-failure.png");
|
|
41864
42867
|
const screenshotResult = captureCommand4([
|
|
41865
42868
|
options.xcrun,
|
|
41866
42869
|
"simctl",
|
|
@@ -41869,8 +42872,8 @@ Emulator setup verification:`);
|
|
|
41869
42872
|
"screenshot",
|
|
41870
42873
|
screenshot
|
|
41871
42874
|
]);
|
|
41872
|
-
const diagnosticPath =
|
|
41873
|
-
await
|
|
42875
|
+
const diagnosticPath = join61(options.artifactRoot, "ios-failure.json");
|
|
42876
|
+
await writeFile23(diagnosticPath, `${JSON.stringify({
|
|
41874
42877
|
appId: options.appId,
|
|
41875
42878
|
error: options.error instanceof Error ? options.error.message : String(options.error),
|
|
41876
42879
|
platform: "ios",
|
|
@@ -42115,8 +43118,8 @@ Emulator setup verification:`);
|
|
|
42115
43118
|
mobile.appId
|
|
42116
43119
|
], "iOS app launch");
|
|
42117
43120
|
await waitForIosHmrClient({ https, port, timeoutMs });
|
|
42118
|
-
await
|
|
42119
|
-
const screenshot =
|
|
43121
|
+
await mkdir21(artifactRoot, { recursive: true });
|
|
43122
|
+
const screenshot = join61(artifactRoot, "ios-simulator.png");
|
|
42120
43123
|
requireCapturedCommand([xcrun, "simctl", "io", simulator.udid, "screenshot", screenshot], "iOS simulator screenshot");
|
|
42121
43124
|
const hmrApply = await waitForRequestedIosHmr(args, instance, timeoutMs);
|
|
42122
43125
|
const report = {
|
|
@@ -42292,6 +43295,7 @@ var init_mobile = __esm(() => {
|
|
|
42292
43295
|
init_nativeDeviceCapabilities();
|
|
42293
43296
|
init_nativeBackgroundSync();
|
|
42294
43297
|
init_nativeUpdates();
|
|
43298
|
+
init_nativeObservability();
|
|
42295
43299
|
init_emulatorDoctor();
|
|
42296
43300
|
init_emulatorInstaller();
|
|
42297
43301
|
init_associationFiles();
|
|
@@ -42359,9 +43363,9 @@ var exports_typecheck = {};
|
|
|
42359
43363
|
__export(exports_typecheck, {
|
|
42360
43364
|
typecheck: () => typecheck
|
|
42361
43365
|
});
|
|
42362
|
-
import { resolve as resolve48, join as
|
|
43366
|
+
import { resolve as resolve48, join as join62 } from "path";
|
|
42363
43367
|
import { existsSync as existsSync44, readFileSync as readFileSync41 } from "fs";
|
|
42364
|
-
import { mkdir as
|
|
43368
|
+
import { mkdir as mkdir22, writeFile as writeFile24 } from "fs/promises";
|
|
42365
43369
|
var isCommandService3 = (service) => service.kind === "command" || Array.isArray(service.command), resolveConfigPath = (configPath2) => resolve48(configPath2 ?? process.env.ABSOLUTE_CONFIG ?? "absolute.config.ts"), getTypecheckTargets = async (configPath2) => {
|
|
42366
43370
|
if (!existsSync44(resolveConfigPath(configPath2))) {
|
|
42367
43371
|
const defaultService = {};
|
|
@@ -42468,8 +43472,8 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42468
43472
|
console.error("\x1B[31m\u2717\x1B[0m vue-tsc is required for Vue type checking. Install it: bun add -d vue-tsc");
|
|
42469
43473
|
process.exit(1);
|
|
42470
43474
|
}
|
|
42471
|
-
const vueTsconfigPath =
|
|
42472
|
-
await
|
|
43475
|
+
const vueTsconfigPath = join62(cacheDir, "tsconfig.vue-check.json");
|
|
43476
|
+
await writeFile24(vueTsconfigPath, JSON.stringify({
|
|
42473
43477
|
compilerOptions: {
|
|
42474
43478
|
rootDir: ".."
|
|
42475
43479
|
},
|
|
@@ -42488,7 +43492,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42488
43492
|
...base,
|
|
42489
43493
|
"--incremental",
|
|
42490
43494
|
"--tsBuildInfoFile",
|
|
42491
|
-
|
|
43495
|
+
join62(cacheDir, "vue-tsc.tsbuildinfo")
|
|
42492
43496
|
]);
|
|
42493
43497
|
if (cached.exitCode === 0 || cached.output.length > 0)
|
|
42494
43498
|
return cached;
|
|
@@ -42499,8 +43503,8 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42499
43503
|
console.error("\x1B[31m\u2717\x1B[0m @angular/compiler-cli is required for Angular type checking. Install it: bun add -d @angular/compiler-cli");
|
|
42500
43504
|
process.exit(1);
|
|
42501
43505
|
}
|
|
42502
|
-
const angularTsconfigPath =
|
|
42503
|
-
await
|
|
43506
|
+
const angularTsconfigPath = join62(cacheDir, "tsconfig.angular-check.json");
|
|
43507
|
+
await writeFile24(angularTsconfigPath, JSON.stringify({
|
|
42504
43508
|
angularCompilerOptions: {
|
|
42505
43509
|
strictTemplates: true
|
|
42506
43510
|
},
|
|
@@ -42519,8 +43523,8 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42519
43523
|
console.error("\x1B[31m\u2717\x1B[0m typescript is required for type checking. Install it: bun add -d typescript");
|
|
42520
43524
|
process.exit(1);
|
|
42521
43525
|
}
|
|
42522
|
-
const tscConfigPath =
|
|
42523
|
-
return
|
|
43526
|
+
const tscConfigPath = join62(cacheDir, "tsconfig.typecheck.json");
|
|
43527
|
+
return writeFile24(tscConfigPath, JSON.stringify({
|
|
42524
43528
|
compilerOptions: {
|
|
42525
43529
|
rootDir: ".."
|
|
42526
43530
|
},
|
|
@@ -42534,7 +43538,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42534
43538
|
resolve48(tscConfigPath),
|
|
42535
43539
|
"--incremental",
|
|
42536
43540
|
"--tsBuildInfoFile",
|
|
42537
|
-
|
|
43541
|
+
join62(cacheDir, "tsc.tsbuildinfo"),
|
|
42538
43542
|
"--pretty"
|
|
42539
43543
|
]));
|
|
42540
43544
|
}, buildSvelteCheck = async (cacheDir, svelteDir) => {
|
|
@@ -42543,8 +43547,8 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42543
43547
|
console.error("\x1B[31m\u2717\x1B[0m svelte-check is required for Svelte type checking. Install it: bun add -d svelte-check");
|
|
42544
43548
|
process.exit(1);
|
|
42545
43549
|
}
|
|
42546
|
-
const svelteTsconfigPath =
|
|
42547
|
-
await
|
|
43550
|
+
const svelteTsconfigPath = join62(cacheDir, "tsconfig.svelte-check.json");
|
|
43551
|
+
await writeFile24(svelteTsconfigPath, JSON.stringify({
|
|
42548
43552
|
extends: resolve48("tsconfig.json"),
|
|
42549
43553
|
files: ABSOLUTE_TYPECHECK_FILES,
|
|
42550
43554
|
include: [`../${svelteDir}/**/*`]
|
|
@@ -42573,7 +43577,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42573
43577
|
...new Set(targets.map((config) => config.angularDirectory).filter((dir) => typeof dir === "string" && dir.length > 0))
|
|
42574
43578
|
];
|
|
42575
43579
|
const cacheDir = ".absolutejs";
|
|
42576
|
-
await
|
|
43580
|
+
await mkdir22(cacheDir, { recursive: true });
|
|
42577
43581
|
const checks = [];
|
|
42578
43582
|
checks.push(hasVue ? buildVueTscCheck(cacheDir) : buildTscCheck(cacheDir));
|
|
42579
43583
|
for (const svelteDir of hasSvelte ? svelteDirs : []) {
|
|
@@ -42802,7 +43806,7 @@ import {
|
|
|
42802
43806
|
writeFileSync as writeFileSync4
|
|
42803
43807
|
} from "fs";
|
|
42804
43808
|
import { tmpdir as tmpdir2 } from "os";
|
|
42805
|
-
import { join as
|
|
43809
|
+
import { join as join18, resolve as resolvePath2 } from "path";
|
|
42806
43810
|
|
|
42807
43811
|
// src/dev/tunnel/client.ts
|
|
42808
43812
|
var RECONNECT_DELAY_MS = 2000;
|
|
@@ -43312,7 +44316,7 @@ init_expoProject();
|
|
|
43312
44316
|
init_iosPhysicalDeviceTransport();
|
|
43313
44317
|
import { spawn } from "child_process";
|
|
43314
44318
|
import { access as access2 } from "fs/promises";
|
|
43315
|
-
import { join as
|
|
44319
|
+
import { join as join10 } from "path";
|
|
43316
44320
|
var METRO_READY_TIMEOUT_MS = 60000;
|
|
43317
44321
|
var PROCESS_CLOSE_TIMEOUT_MS = 2000;
|
|
43318
44322
|
var commandEnvironment = (options) => ({
|
|
@@ -43325,7 +44329,7 @@ var commandEnvironment = (options) => ({
|
|
|
43325
44329
|
...options.metroHost ? { REACT_NATIVE_PACKAGER_HOSTNAME: options.metroHost } : {}
|
|
43326
44330
|
});
|
|
43327
44331
|
var absoluteExpoExecutable = async (project) => {
|
|
43328
|
-
const executable =
|
|
44332
|
+
const executable = join10(project, "node_modules", ".bin", "expo");
|
|
43329
44333
|
try {
|
|
43330
44334
|
await access2(executable);
|
|
43331
44335
|
return executable;
|
|
@@ -44077,7 +45081,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
44077
45081
|
const generated = await writeAbsoluteExpoProject(normalized, {
|
|
44078
45082
|
projectRoot: process.cwd()
|
|
44079
45083
|
});
|
|
44080
|
-
const dependenciesReady = existsSync6(
|
|
45084
|
+
const dependenciesReady = existsSync6(join18(generated.path, "node_modules", "expo", "package.json")) && existsSync6(join18(generated.path, "node_modules", "expo-dev-client", "package.json"));
|
|
44081
45085
|
if (!dependenciesReady) {
|
|
44082
45086
|
const install = await confirmPrompt("Expo development dependencies are missing. Install the pinned SDK 57 development client now?");
|
|
44083
45087
|
if (!install) {
|
|
@@ -44156,7 +45160,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
44156
45160
|
}
|
|
44157
45161
|
}
|
|
44158
45162
|
if (ready) {
|
|
44159
|
-
const nativeDirectory =
|
|
45163
|
+
const nativeDirectory = join18(normalized.nativeProjectDirectory, "android");
|
|
44160
45164
|
let createNativeProject = false;
|
|
44161
45165
|
if (!existsSync6(nativeDirectory)) {
|
|
44162
45166
|
createNativeProject = await confirmPrompt("Create the managed Capacitor Android project now?");
|
|
@@ -44176,7 +45180,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
44176
45180
|
if (!remote) {
|
|
44177
45181
|
console.log(cliTag("\x1B[33m", "iOS target skipped. Pair a Mac with `absolute mobile pair mac <name> <user@host>`."));
|
|
44178
45182
|
} else {
|
|
44179
|
-
const nativeDirectory =
|
|
45183
|
+
const nativeDirectory = join18(normalized.nativeProjectDirectory, "ios");
|
|
44180
45184
|
if (!existsSync6(nativeDirectory)) {
|
|
44181
45185
|
console.log(cliTag("\x1B[33m", "The iOS project is missing. Run `absolute mobile init` before remote development."));
|
|
44182
45186
|
} else {
|
|
@@ -44197,7 +45201,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
44197
45201
|
}
|
|
44198
45202
|
}
|
|
44199
45203
|
if (ready) {
|
|
44200
|
-
const nativeDirectory =
|
|
45204
|
+
const nativeDirectory = join18(normalized.nativeProjectDirectory, "ios");
|
|
44201
45205
|
let createNativeProject = false;
|
|
44202
45206
|
if (!existsSync6(nativeDirectory)) {
|
|
44203
45207
|
createNativeProject = await confirmPrompt("Create the managed Capacitor iOS project now?");
|
|
@@ -44855,7 +45859,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
44855
45859
|
}
|
|
44856
45860
|
return merged;
|
|
44857
45861
|
};
|
|
44858
|
-
const heapPreloadPath =
|
|
45862
|
+
const heapPreloadPath = join18(tmpdir2(), `absolute-heap-${process.pid}.ts`);
|
|
44859
45863
|
let heapSnapshotEnabled = false;
|
|
44860
45864
|
try {
|
|
44861
45865
|
writeFileSync4(heapPreloadPath, DEV_CHILD_PRELOAD);
|
|
@@ -44988,7 +45992,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
44988
45992
|
if (now - last < 100)
|
|
44989
45993
|
return;
|
|
44990
45994
|
recentlyHandled.set(filename, now);
|
|
44991
|
-
scheduleServerRestart(
|
|
45995
|
+
scheduleServerRestart(join18(serverEntryDir, filename));
|
|
44992
45996
|
};
|
|
44993
45997
|
const recoveryScan = async () => {
|
|
44994
45998
|
let entries;
|
|
@@ -45007,7 +46011,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
45007
46011
|
continue;
|
|
45008
46012
|
let fileStat;
|
|
45009
46013
|
try {
|
|
45010
|
-
fileStat = statSync(
|
|
46014
|
+
fileStat = statSync(join18(serverEntryDir, entry.name));
|
|
45011
46015
|
} catch {
|
|
45012
46016
|
continue;
|
|
45013
46017
|
}
|
|
@@ -45541,7 +46545,7 @@ var info = () => {
|
|
|
45541
46545
|
// src/cli/cache.ts
|
|
45542
46546
|
init_constants();
|
|
45543
46547
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
45544
|
-
import { join as
|
|
46548
|
+
import { join as join19 } from "path";
|
|
45545
46549
|
var {Glob } = globalThis.Bun;
|
|
45546
46550
|
var CACHE_DIR = ".absolutejs";
|
|
45547
46551
|
var MAX_FILES_PER_BATCH = 200;
|
|
@@ -45593,7 +46597,7 @@ var hashFiles = async (paths) => {
|
|
|
45593
46597
|
};
|
|
45594
46598
|
var loadCache = async (tool) => {
|
|
45595
46599
|
try {
|
|
45596
|
-
const path =
|
|
46600
|
+
const path = join19(CACHE_DIR, `${tool}.cache.json`);
|
|
45597
46601
|
const data = await Bun.file(path).json();
|
|
45598
46602
|
const result = data;
|
|
45599
46603
|
return result;
|
|
@@ -45640,7 +46644,7 @@ var runTool = async (adapter, args) => {
|
|
|
45640
46644
|
};
|
|
45641
46645
|
var saveCache = async (tool, data) => {
|
|
45642
46646
|
await mkdir7(CACHE_DIR, { recursive: true });
|
|
45643
|
-
const path =
|
|
46647
|
+
const path = join19(CACHE_DIR, `${tool}.cache.json`);
|
|
45644
46648
|
await Bun.write(path, JSON.stringify(data, null, "\t"));
|
|
45645
46649
|
};
|
|
45646
46650
|
|