@absolutejs/absolute 0.20.0-beta.66 → 0.20.0-beta.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/build.js +768 -544
- package/dist/build.js.map +10 -8
- package/dist/cli/index.js +1526 -574
- package/dist/dev/serverBootstrap.js +544 -6
- package/dist/index.js +879 -619
- package/dist/index.js.map +13 -10
- package/dist/mobile/index.js +1777 -190
- package/dist/mobile/index.js.map +9 -5
- package/dist/mobile/mobilePreviewClient.ts +246 -0
- package/dist/mobile/remoteMacAgentEntry.js +576 -205
- package/dist/mobile/shellBootstrap.js +152 -0
- package/dist/src/build/chainInlineSourcemaps.d.ts +2 -0
- package/dist/src/build/vueCompileCache.d.ts +43 -0
- package/dist/src/cli/config/server.d.ts +1 -1
- package/dist/src/dev/bootLifecycle.d.ts +11 -0
- package/dist/src/dev/earlyListener.d.ts +41 -0
- package/dist/src/mobile/expoNativeObservability.d.ts +3 -0
- package/dist/src/mobile/index.d.ts +3 -0
- package/dist/src/mobile/mobilePreview.d.ts +1 -1
- package/dist/src/mobile/nativeObservability.d.ts +4 -0
- package/dist/src/mobile/shellNativeObservability.d.ts +21 -0
- package/dist/src/plugins/imageOptimizer.d.ts +1 -1
- package/dist/src/utils/startupTimings.d.ts +4 -0
- package/dist/types/globals.d.ts +15 -0
- package/package.json +7 -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,522 @@ 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 acknowledge(PluginCall call) {
|
|
21148
|
+
JSArray ids = call.getArray("ids");
|
|
21149
|
+
if (ids == null) {
|
|
21150
|
+
call.reject("Native observability acknowledgement requires report ids.");
|
|
21151
|
+
return;
|
|
21152
|
+
}
|
|
21153
|
+
Set<String> accepted = new HashSet<>();
|
|
21154
|
+
for (int index = 0; index < ids.length(); index++) accepted.add(ids.optString(index));
|
|
21155
|
+
Set<String> acknowledged = acknowledged();
|
|
21156
|
+
for (File file : files()) {
|
|
21157
|
+
try (InputStream input = new FileInputStream(file)) {
|
|
21158
|
+
JSONObject report = new JSONObject(new String(read(input), StandardCharsets.UTF_8));
|
|
21159
|
+
String id = report.optString("id");
|
|
21160
|
+
if (accepted.contains(id)) {
|
|
21161
|
+
acknowledged.add(id);
|
|
21162
|
+
file.delete();
|
|
21163
|
+
}
|
|
21164
|
+
} catch (Exception ignored) {}
|
|
21165
|
+
}
|
|
21166
|
+
writeAcknowledged(acknowledged);
|
|
21167
|
+
call.resolve();
|
|
21168
|
+
}
|
|
21169
|
+
}
|
|
21170
|
+
`, androidActivityInRoot2 = async (root) => {
|
|
21171
|
+
let entries;
|
|
21172
|
+
try {
|
|
21173
|
+
entries = await readdir6(root, { recursive: true });
|
|
21174
|
+
} catch (error) {
|
|
21175
|
+
if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
|
|
21176
|
+
return;
|
|
21177
|
+
throw error;
|
|
21178
|
+
}
|
|
21179
|
+
const candidate = entries.find((entry) => entry.endsWith("/MainActivity.java") || entry.endsWith("/MainActivity.kt") || entry === "MainActivity.java" || entry === "MainActivity.kt");
|
|
21180
|
+
return candidate ? join53(root, candidate) : undefined;
|
|
21181
|
+
}, androidActivity2 = async (config) => {
|
|
21182
|
+
const roots = [
|
|
21183
|
+
join53(config.nativeProjectDirectory, "android/app/src/main/java"),
|
|
21184
|
+
join53(config.nativeProjectDirectory, "android/app/src/main/kotlin")
|
|
21185
|
+
];
|
|
21186
|
+
const candidates = await Promise.all(roots.map(androidActivityInRoot2));
|
|
21187
|
+
const candidate = candidates.find((value) => value !== undefined);
|
|
21188
|
+
if (candidate)
|
|
21189
|
+
return candidate;
|
|
21190
|
+
throw new TypeError("Android MainActivity.java or MainActivity.kt was not found.");
|
|
21191
|
+
}, androidRegion2 = (kotlin, generatedMethod) => {
|
|
21192
|
+
if (generatedMethod)
|
|
21193
|
+
return kotlin ? ` ${START2}
|
|
21194
|
+
override fun onCreate(savedInstanceState: android.os.Bundle?) {
|
|
21195
|
+
registerPlugin(AbsoluteMobileObservabilityPlugin::class.java)
|
|
21196
|
+
super.onCreate(savedInstanceState)
|
|
21197
|
+
}
|
|
21198
|
+
${END2}
|
|
21199
|
+
` : ` ${START2}
|
|
21200
|
+
@Override
|
|
21201
|
+
public void onCreate(android.os.Bundle savedInstanceState) {
|
|
21202
|
+
registerPlugin(AbsoluteMobileObservabilityPlugin.class);
|
|
21203
|
+
super.onCreate(savedInstanceState);
|
|
21204
|
+
}
|
|
21205
|
+
${END2}
|
|
21206
|
+
`;
|
|
21207
|
+
return kotlin ? ` ${START2}
|
|
21208
|
+
registerPlugin(AbsoluteMobileObservabilityPlugin::class.java)
|
|
21209
|
+
${END2}
|
|
21210
|
+
` : ` ${START2}
|
|
21211
|
+
registerPlugin(AbsoluteMobileObservabilityPlugin.class);
|
|
21212
|
+
${END2}
|
|
21213
|
+
`;
|
|
21214
|
+
}, injectAndroidActivity2 = (source, enabled) => {
|
|
21215
|
+
const kotlin = /\bfun\s+onCreate\s*\(/u.test(source) || source.includes("BridgeActivity()");
|
|
21216
|
+
const existingStart = source.indexOf(START2);
|
|
21217
|
+
const existingEnd = source.indexOf(END2);
|
|
21218
|
+
if (existingStart < 0 !== existingEnd < 0)
|
|
21219
|
+
throw new TypeError("AbsoluteJS native observability markers are malformed.");
|
|
21220
|
+
if (existingStart >= 0) {
|
|
21221
|
+
const from = source.lastIndexOf(`
|
|
21222
|
+
`, existingStart) + 1;
|
|
21223
|
+
const newline = source.indexOf(`
|
|
21224
|
+
`, existingEnd + END2.length);
|
|
21225
|
+
const through = newline < 0 ? source.length : newline + 1;
|
|
21226
|
+
const generatedMethod = source.slice(from, through).includes("onCreate(");
|
|
21227
|
+
if (!enabled)
|
|
21228
|
+
return `${source.slice(0, from)}${source.slice(through)}`;
|
|
21229
|
+
return `${source.slice(0, from)}${androidRegion2(kotlin, generatedMethod)}${source.slice(through)}`;
|
|
21230
|
+
}
|
|
21231
|
+
if (!enabled)
|
|
21232
|
+
return source;
|
|
21233
|
+
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);
|
|
21234
|
+
if (onCreate >= 0) {
|
|
21235
|
+
const brace = source.indexOf("{", onCreate);
|
|
21236
|
+
const insert = source.indexOf(`
|
|
21237
|
+
`, brace) + 1;
|
|
21238
|
+
return `${source.slice(0, insert)}${androidRegion2(kotlin, false)}${source.slice(insert)}`;
|
|
21239
|
+
}
|
|
21240
|
+
const close = source.lastIndexOf("}");
|
|
21241
|
+
if (close < 0)
|
|
21242
|
+
throw new TypeError("Could not find the Android MainActivity class body.");
|
|
21243
|
+
const separator = source[close - 1] === `
|
|
21244
|
+
` ? "" : `
|
|
21245
|
+
`;
|
|
21246
|
+
return `${source.slice(0, close)}${separator}${androidRegion2(kotlin, true)}${source.slice(close)}`;
|
|
21247
|
+
}, configureAndroid4 = async (config, enabled) => {
|
|
21248
|
+
const activityPath = await androidActivity2(config);
|
|
21249
|
+
const activity = await readFile17(activityPath, "utf8");
|
|
21250
|
+
const packageName = activity.match(/^\s*package\s+([A-Za-z0-9_.]+)\s*[;\n]/mu)?.[1];
|
|
21251
|
+
if (!packageName)
|
|
21252
|
+
throw new TypeError("Android MainActivity package declaration was not found.");
|
|
21253
|
+
const pluginPath = join53(config.nativeProjectDirectory, "android/app/src/main/java", packageName.replaceAll(".", "/"), ANDROID_PLUGIN2);
|
|
21254
|
+
const changed = await Promise.all([
|
|
21255
|
+
writeChanged3(activityPath, injectAndroidActivity2(activity, enabled)),
|
|
21256
|
+
enabled ? writeChanged3(pluginPath, androidPluginSource2(packageName)) : removeOwnedFile2(pluginPath)
|
|
21257
|
+
]);
|
|
21258
|
+
return changed.some(Boolean);
|
|
21259
|
+
}, applyAbsoluteNativeObservability = async (config, platforms = config.platforms) => {
|
|
21260
|
+
if (config.engine !== "capacitor")
|
|
21261
|
+
return { changed: false };
|
|
21262
|
+
const enabled = config.observability !== undefined;
|
|
21263
|
+
const changed = [];
|
|
21264
|
+
if (platforms.includes("ios"))
|
|
21265
|
+
changed.push(await configureIos4(config, enabled));
|
|
21266
|
+
if (platforms.includes("android"))
|
|
21267
|
+
changed.push(await configureAndroid4(config, enabled));
|
|
21268
|
+
return { changed: changed.some(Boolean) };
|
|
21269
|
+
};
|
|
21270
|
+
var init_nativeObservability = __esm(() => {
|
|
21271
|
+
iosPluginRegion2 = `${PLUGIN_START2}
|
|
21272
|
+
@objc(AbsoluteMobileObservabilityPlugin)
|
|
21273
|
+
public final class AbsoluteMobileObservabilityPlugin: CAPPlugin, CAPBridgedPlugin, MXMetricManagerSubscriber {
|
|
21274
|
+
public let identifier = "AbsoluteMobileObservabilityPlugin"
|
|
21275
|
+
public let jsName = "AbsoluteMobileObservability"
|
|
21276
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
21277
|
+
CAPPluginMethod(name: "acknowledge", returnType: CAPPluginReturnPromise),
|
|
21278
|
+
CAPPluginMethod(name: "pending", returnType: CAPPluginReturnPromise)
|
|
21279
|
+
]
|
|
21280
|
+
|
|
21281
|
+
private static let maximumReports = 8
|
|
21282
|
+
private static let maximumReportBytes = 64 * 1024
|
|
21283
|
+
private static let queue = DispatchQueue(label: "dev.absolute.mobile-observability")
|
|
21284
|
+
|
|
21285
|
+
public override func load() {
|
|
21286
|
+
MXMetricManager.shared.add(self)
|
|
21287
|
+
}
|
|
21288
|
+
|
|
21289
|
+
deinit {
|
|
21290
|
+
MXMetricManager.shared.remove(self)
|
|
21291
|
+
}
|
|
21292
|
+
|
|
21293
|
+
private static func root() -> URL? {
|
|
21294
|
+
guard let support = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first else { return nil }
|
|
21295
|
+
let root = support.appendingPathComponent("AbsoluteMobileObservability", isDirectory: true)
|
|
21296
|
+
try? FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)
|
|
21297
|
+
return root
|
|
21298
|
+
}
|
|
21299
|
+
|
|
21300
|
+
private static func files() -> [URL] {
|
|
21301
|
+
guard let root = root() else { return [] }
|
|
21302
|
+
return ((try? FileManager.default.contentsOfDirectory(at: root, includingPropertiesForKeys: nil)) ?? [])
|
|
21303
|
+
.filter { $0.pathExtension == "json" }
|
|
21304
|
+
.sorted { $0.lastPathComponent < $1.lastPathComponent }
|
|
21305
|
+
}
|
|
21306
|
+
|
|
21307
|
+
private static func trim() {
|
|
21308
|
+
let overflow = max(0, files().count - maximumReports)
|
|
21309
|
+
for file in files().prefix(overflow) { try? FileManager.default.removeItem(at: file) }
|
|
21310
|
+
}
|
|
21311
|
+
|
|
21312
|
+
private static func enqueue(kind: String, occurredAt: Double, details: [AnyHashable: Any]) {
|
|
21313
|
+
guard let root = root() else { return }
|
|
21314
|
+
let id = UUID().uuidString.lowercased()
|
|
21315
|
+
var value: [String: Any] = [
|
|
21316
|
+
"details": Dictionary(uniqueKeysWithValues: details.map { (String(describing: $0.key), $0.value) }),
|
|
21317
|
+
"id": id,
|
|
21318
|
+
"kind": kind,
|
|
21319
|
+
"occurredAt": occurredAt,
|
|
21320
|
+
"platform": "ios"
|
|
21321
|
+
]
|
|
21322
|
+
guard JSONSerialization.isValidJSONObject(value),
|
|
21323
|
+
let original = try? JSONSerialization.data(withJSONObject: value) else { return }
|
|
21324
|
+
if original.count > maximumReportBytes {
|
|
21325
|
+
value["details"] = [
|
|
21326
|
+
"diagnosticPrefix": String(decoding: original.prefix(24 * 1024), as: UTF8.self),
|
|
21327
|
+
"originalBytes": original.count,
|
|
21328
|
+
"truncated": true
|
|
21329
|
+
]
|
|
21330
|
+
}
|
|
21331
|
+
guard let data = try? JSONSerialization.data(withJSONObject: value),
|
|
21332
|
+
data.count <= maximumReportBytes else { return }
|
|
21333
|
+
let timestamp = String(format: "%013.0f", occurredAt)
|
|
21334
|
+
try? data.write(to: root.appendingPathComponent("\\(timestamp)-\\(id).json"), options: .atomic)
|
|
21335
|
+
trim()
|
|
21336
|
+
}
|
|
21337
|
+
|
|
21338
|
+
public func didReceive(_ payloads: [MXDiagnosticPayload]) {
|
|
21339
|
+
Self.queue.async {
|
|
21340
|
+
for payload in payloads {
|
|
21341
|
+
let at = payload.timeStampEnd.timeIntervalSince1970 * 1000
|
|
21342
|
+
for value in payload.crashDiagnostics ?? [] { Self.enqueue(kind: "crash", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
21343
|
+
for value in payload.hangDiagnostics ?? [] { Self.enqueue(kind: "hang", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
21344
|
+
for value in payload.cpuExceptionDiagnostics ?? [] { Self.enqueue(kind: "cpu-exception", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
21345
|
+
for value in payload.diskWriteExceptionDiagnostics ?? [] { Self.enqueue(kind: "disk-write-exception", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
21346
|
+
if #available(iOS 16.0, *) {
|
|
21347
|
+
for value in payload.appLaunchDiagnostics ?? [] { Self.enqueue(kind: "app-launch", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
21348
|
+
}
|
|
21349
|
+
}
|
|
21350
|
+
}
|
|
21351
|
+
}
|
|
21352
|
+
|
|
21353
|
+
@objc public func pending(_ call: CAPPluginCall) {
|
|
21354
|
+
Self.queue.async {
|
|
21355
|
+
let reports: [[String: Any]] = Self.files().compactMap { file in
|
|
21356
|
+
guard let data = try? Data(contentsOf: file),
|
|
21357
|
+
let value = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return nil }
|
|
21358
|
+
return value
|
|
21359
|
+
}
|
|
21360
|
+
call.resolve(["reports": reports])
|
|
21361
|
+
}
|
|
21362
|
+
}
|
|
21363
|
+
|
|
21364
|
+
@objc public func acknowledge(_ call: CAPPluginCall) {
|
|
21365
|
+
guard let ids = call.getArray("ids", String.self) else {
|
|
21366
|
+
call.reject("Native observability acknowledgement requires report ids.")
|
|
21367
|
+
return
|
|
21368
|
+
}
|
|
21369
|
+
let accepted = Set(ids)
|
|
21370
|
+
Self.queue.async {
|
|
21371
|
+
for file in Self.files() {
|
|
21372
|
+
guard let data = try? Data(contentsOf: file),
|
|
21373
|
+
let value = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
|
21374
|
+
let id = value["id"] as? String,
|
|
21375
|
+
accepted.contains(id) else { continue }
|
|
21376
|
+
try? FileManager.default.removeItem(at: file)
|
|
21377
|
+
}
|
|
21378
|
+
call.resolve()
|
|
21379
|
+
}
|
|
21380
|
+
}
|
|
21381
|
+
}
|
|
21382
|
+
${PLUGIN_END2}
|
|
21383
|
+
`;
|
|
21384
|
+
});
|
|
21385
|
+
|
|
21386
|
+
// src/mobile/associationFiles.ts
|
|
21387
|
+
import {
|
|
21388
|
+
access as access9,
|
|
21389
|
+
mkdir as mkdir13,
|
|
21390
|
+
readFile as readFile18,
|
|
21391
|
+
rename as rename14,
|
|
21392
|
+
rm as rm11,
|
|
21393
|
+
writeFile as writeFile15
|
|
21394
|
+
} from "fs/promises";
|
|
20448
21395
|
import { resolve as resolve37 } from "path";
|
|
20449
21396
|
import { Elysia } from "elysia";
|
|
20450
21397
|
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 +21445,7 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
|
|
|
20498
21445
|
}, writeAtomic = async (path, source) => {
|
|
20499
21446
|
let current;
|
|
20500
21447
|
try {
|
|
20501
|
-
current = await
|
|
21448
|
+
current = await readFile18(path, "utf8");
|
|
20502
21449
|
} catch (error) {
|
|
20503
21450
|
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
|
|
20504
21451
|
throw error;
|
|
@@ -20507,8 +21454,8 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
|
|
|
20507
21454
|
if (current === source)
|
|
20508
21455
|
return false;
|
|
20509
21456
|
const temporary = `${path}.${crypto.randomUUID()}.tmp`;
|
|
20510
|
-
await
|
|
20511
|
-
await
|
|
21457
|
+
await writeFile15(temporary, source, { flag: "wx" });
|
|
21458
|
+
await rename14(temporary, path);
|
|
20512
21459
|
return true;
|
|
20513
21460
|
}, exists3 = async (path) => {
|
|
20514
21461
|
try {
|
|
@@ -20521,7 +21468,7 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
|
|
|
20521
21468
|
const path = resolve37(root, OWNERSHIP_FILE);
|
|
20522
21469
|
let ownership;
|
|
20523
21470
|
try {
|
|
20524
|
-
ownership = JSON.parse(await
|
|
21471
|
+
ownership = JSON.parse(await readFile18(path, "utf8"));
|
|
20525
21472
|
} catch {
|
|
20526
21473
|
throw new TypeError(`Association output ${root} already exists and is not owned by AbsoluteJS.`);
|
|
20527
21474
|
}
|
|
@@ -20534,19 +21481,19 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
|
|
|
20534
21481
|
await assertOwnedOutput(root);
|
|
20535
21482
|
const backup = `${root}.${crypto.randomUUID()}.previous`;
|
|
20536
21483
|
if (hasCurrent)
|
|
20537
|
-
await
|
|
21484
|
+
await rename14(root, backup);
|
|
20538
21485
|
try {
|
|
20539
|
-
await
|
|
21486
|
+
await rename14(temporary, root);
|
|
20540
21487
|
} catch (error) {
|
|
20541
21488
|
if (hasCurrent)
|
|
20542
|
-
await
|
|
21489
|
+
await rename14(backup, root);
|
|
20543
21490
|
throw error;
|
|
20544
21491
|
}
|
|
20545
21492
|
if (hasCurrent)
|
|
20546
|
-
await
|
|
21493
|
+
await rm11(backup, { force: true, recursive: true });
|
|
20547
21494
|
}, materializeHost = async (root, host2, files) => {
|
|
20548
21495
|
const directory = resolve37(root, host2, ".well-known");
|
|
20549
|
-
await
|
|
21496
|
+
await mkdir13(directory, { recursive: true });
|
|
20550
21497
|
return Promise.all(files.map(async ([name, document2]) => {
|
|
20551
21498
|
const path = resolve37(directory, name);
|
|
20552
21499
|
await writeAtomic(path, `${JSON.stringify(document2, null, 2)}
|
|
@@ -20582,7 +21529,7 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
|
|
|
20582
21529
|
if (documents.apple) {
|
|
20583
21530
|
files.push(["apple-app-site-association", documents.apple]);
|
|
20584
21531
|
}
|
|
20585
|
-
await
|
|
21532
|
+
await mkdir13(temporary, { recursive: true });
|
|
20586
21533
|
try {
|
|
20587
21534
|
const temporaryPaths = (await Promise.all(config.deepLinkHosts.map((host2) => materializeHost(temporary, host2, files)))).flat();
|
|
20588
21535
|
await writeAtomic(resolve37(temporary, OWNERSHIP_FILE), `${JSON.stringify({ format: 1, hosts: config.deepLinkHosts }, null, 2)}
|
|
@@ -20591,7 +21538,7 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
|
|
|
20591
21538
|
const written = temporaryPaths.map((path) => resolve37(root, path.slice(temporary.length + 1)));
|
|
20592
21539
|
return { root, written };
|
|
20593
21540
|
} catch (error) {
|
|
20594
|
-
await
|
|
21541
|
+
await rm11(temporary, { force: true, recursive: true });
|
|
20595
21542
|
throw error;
|
|
20596
21543
|
}
|
|
20597
21544
|
}, verifyAbsoluteMobileAssociationFiles = async (config, request = globalThis.fetch) => {
|
|
@@ -20629,8 +21576,8 @@ var init_associationFiles = __esm(() => {
|
|
|
20629
21576
|
});
|
|
20630
21577
|
|
|
20631
21578
|
// src/mobile/androidWebView.ts
|
|
20632
|
-
import { mkdir as
|
|
20633
|
-
import { dirname as
|
|
21579
|
+
import { mkdir as mkdir14, writeFile as writeFile16 } from "fs/promises";
|
|
21580
|
+
import { dirname as dirname31, resolve as resolve38 } from "path";
|
|
20634
21581
|
|
|
20635
21582
|
class CdpConnection {
|
|
20636
21583
|
#closed;
|
|
@@ -20904,8 +21851,8 @@ var CDP_COMMAND_TIMEOUT_MS = 1e4, WEBVIEW_ATTACH_TIMEOUT_MS = 30000, WEBVIEW_POL
|
|
|
20904
21851
|
throw new Error("Android WebView screenshot returned no image data.");
|
|
20905
21852
|
}
|
|
20906
21853
|
const absolutePath = resolve38(path);
|
|
20907
|
-
await
|
|
20908
|
-
await
|
|
21854
|
+
await mkdir14(dirname31(absolutePath), { recursive: true });
|
|
21855
|
+
await writeFile16(absolutePath, Buffer.from(data, "base64"));
|
|
20909
21856
|
return absolutePath;
|
|
20910
21857
|
},
|
|
20911
21858
|
tap: async (coordinateX, coordinateY) => {
|
|
@@ -21037,8 +21984,8 @@ var DEFAULT_ROUTE_TIMEOUT_MS = 30000, DEFAULT_HMR_TIMEOUT_MS = 30000, routeExpre
|
|
|
21037
21984
|
|
|
21038
21985
|
// src/mobile/mobileBundleInspection.ts
|
|
21039
21986
|
import { createHash as createHash15 } from "crypto";
|
|
21040
|
-
import { access as access10, readFile as
|
|
21041
|
-
import { join as
|
|
21987
|
+
import { access as access10, readFile as readFile19, stat as stat2 } from "fs/promises";
|
|
21988
|
+
import { join as join54, relative as relative25, resolve as resolve39 } from "path";
|
|
21042
21989
|
var MOBILE_FRAMEWORKS, SHA256_PATTERN, isObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), portablePath = (projectRoot, path) => {
|
|
21043
21990
|
const value = relative25(resolve39(projectRoot), resolve39(path)).replaceAll("\\", "/");
|
|
21044
21991
|
return value || ".";
|
|
@@ -21050,7 +21997,7 @@ var MOBILE_FRAMEWORKS, SHA256_PATTERN, isObject2 = (value) => typeof value === "
|
|
|
21050
21997
|
return false;
|
|
21051
21998
|
}
|
|
21052
21999
|
}, readObject = async (path) => {
|
|
21053
|
-
const value = JSON.parse(await
|
|
22000
|
+
const value = JSON.parse(await readFile19(path, "utf8"));
|
|
21054
22001
|
if (!isObject2(value))
|
|
21055
22002
|
throw new TypeError("JSON root must be an object.");
|
|
21056
22003
|
return value;
|
|
@@ -21075,13 +22022,13 @@ var MOBILE_FRAMEWORKS, SHA256_PATTERN, isObject2 = (value) => typeof value === "
|
|
|
21075
22022
|
if (expectedHash !== undefined) {
|
|
21076
22023
|
if (!SHA256_PATTERN.test(expectedHash))
|
|
21077
22024
|
throw new TypeError(`${field} has an invalid SHA-256 digest.`);
|
|
21078
|
-
const actual = createHash15("sha256").update(await
|
|
22025
|
+
const actual = createHash15("sha256").update(await readFile19(path)).digest("hex");
|
|
21079
22026
|
if (actual !== expectedHash)
|
|
21080
22027
|
throw new TypeError(`${field} failed its SHA-256 integrity check.`);
|
|
21081
22028
|
}
|
|
21082
22029
|
return portable;
|
|
21083
22030
|
}, inspectAbsoluteMobileBundle = async (config, projectRoot) => {
|
|
21084
|
-
const manifestPath =
|
|
22031
|
+
const manifestPath = join54(config.bundleDirectory, "absolute-mobile-manifest.json");
|
|
21085
22032
|
const manifest = portablePath(projectRoot, manifestPath);
|
|
21086
22033
|
if (!await pathExists5(manifestPath))
|
|
21087
22034
|
return { manifest, status: "missing" };
|
|
@@ -21188,8 +22135,8 @@ var init_mobileBundleInspection = __esm(() => {
|
|
|
21188
22135
|
});
|
|
21189
22136
|
|
|
21190
22137
|
// src/mobile/releaseDoctor.ts
|
|
21191
|
-
import { access as access11, readFile as
|
|
21192
|
-
import { dirname as
|
|
22138
|
+
import { access as access11, readFile as readFile20, readdir as readdir7 } from "fs/promises";
|
|
22139
|
+
import { dirname as dirname32, extname as extname8, join as join55, relative as relative26 } from "path";
|
|
21193
22140
|
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
22141
|
try {
|
|
21195
22142
|
await access11(path);
|
|
@@ -21202,13 +22149,13 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21202
22149
|
return findHmrAsset(path);
|
|
21203
22150
|
if (!isFile2 || !RELEASE_ASSET_EXTENSIONS.has(extname8(path)))
|
|
21204
22151
|
return;
|
|
21205
|
-
const source = await
|
|
22152
|
+
const source = await readFile20(path, "utf8");
|
|
21206
22153
|
return HMR_ASSET_PATTERN.test(source) ? path : undefined;
|
|
21207
22154
|
}, findHmrAsset = async (root) => {
|
|
21208
22155
|
if (!await pathExists6(root))
|
|
21209
22156
|
return;
|
|
21210
|
-
const entries = await
|
|
21211
|
-
const matches = await Promise.all(entries.map((entry) => inspectReleaseAsset(
|
|
22157
|
+
const entries = await readdir7(root, { withFileTypes: true });
|
|
22158
|
+
const matches = await Promise.all(entries.map((entry) => inspectReleaseAsset(join55(root, entry.name), entry.isDirectory(), entry.isFile())));
|
|
21212
22159
|
return matches.find((match) => match !== undefined);
|
|
21213
22160
|
}, pass = (id, detail, path) => ({ detail, id, path, status: "pass" }), fail5 = (id, detail, path, remediation) => ({
|
|
21214
22161
|
detail,
|
|
@@ -21222,8 +22169,8 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21222
22169
|
path,
|
|
21223
22170
|
remediation,
|
|
21224
22171
|
status: "warn"
|
|
21225
|
-
}),
|
|
21226
|
-
const value = JSON.parse(await
|
|
22172
|
+
}), isRecord16 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), readJsonObject = async (path) => {
|
|
22173
|
+
const value = JSON.parse(await readFile20(path, "utf8"));
|
|
21227
22174
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
21228
22175
|
throw new TypeError("JSON root must be an object.");
|
|
21229
22176
|
return Object.fromEntries(Object.entries(value));
|
|
@@ -21239,7 +22186,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21239
22186
|
}
|
|
21240
22187
|
return declarations;
|
|
21241
22188
|
}, versionCore = (version2) => version2.split("-")[0]?.split(".").slice(0, 2).join("."), capacitorVersionCheck = async (config, projectRoot) => {
|
|
21242
|
-
const manifestPath =
|
|
22189
|
+
const manifestPath = join55(projectRoot, "package.json");
|
|
21243
22190
|
try {
|
|
21244
22191
|
const manifest = await readJsonObject(manifestPath);
|
|
21245
22192
|
const declarations = packageDeclarations(manifest);
|
|
@@ -21252,7 +22199,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21252
22199
|
const declared = declarations.get(name);
|
|
21253
22200
|
if (!declared || !EXACT_VERSION_PATTERN.test(declared))
|
|
21254
22201
|
throw new TypeError(`${name} must be a direct exact dependency.`);
|
|
21255
|
-
const installed = await readJsonObject(
|
|
22202
|
+
const installed = await readJsonObject(join55(projectRoot, "node_modules", name, "package.json"));
|
|
21256
22203
|
if (installed.version !== declared)
|
|
21257
22204
|
throw new TypeError(`${name} does not match its installed version.`);
|
|
21258
22205
|
return declared;
|
|
@@ -21273,7 +22220,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21273
22220
|
const actual = installed.split(".").map(Number);
|
|
21274
22221
|
return actual[0] === expected[0] && actual[1] === expected[1] && (actual[2] ?? NOT_FOUND3) >= (expected[2] ?? 0);
|
|
21275
22222
|
}, expoVersionCheck = async (config) => {
|
|
21276
|
-
const manifestPath =
|
|
22223
|
+
const manifestPath = join55(config.nativeProjectDirectory, "package.json");
|
|
21277
22224
|
try {
|
|
21278
22225
|
const manifest = await readJsonObject(manifestPath);
|
|
21279
22226
|
const declarations = packageDeclarations(manifest);
|
|
@@ -21283,13 +22230,13 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21283
22230
|
throw new TypeError(`Generated Expo project is missing ${missingRequired}.`);
|
|
21284
22231
|
const installedVersions = await Promise.all([...declarations].map(async ([name, declared]) => ({
|
|
21285
22232
|
declared,
|
|
21286
|
-
installed: await readJsonObject(
|
|
22233
|
+
installed: await readJsonObject(join55(config.nativeProjectDirectory, "node_modules", name, "package.json")),
|
|
21287
22234
|
name
|
|
21288
22235
|
})));
|
|
21289
22236
|
const mismatch = installedVersions.find(({ declared, installed }) => typeof installed.version !== "string" || !satisfiesGeneratedVersion(declared, installed.version));
|
|
21290
22237
|
if (mismatch)
|
|
21291
22238
|
throw new TypeError(`Generated Expo dependency ${mismatch.name}@${mismatch.declared} does not match its installed version.`);
|
|
21292
|
-
if (!await pathExists6(
|
|
22239
|
+
if (!await pathExists6(join55(config.nativeProjectDirectory, "bun.lock")))
|
|
21293
22240
|
throw new TypeError("Generated Expo dependency lockfile is missing.");
|
|
21294
22241
|
return pass("mobile.expo-versions", `Generated Expo SDK dependencies are pinned, installed, and locked (${declarations.get("expo")}).`, manifestPath);
|
|
21295
22242
|
} catch (error) {
|
|
@@ -21297,10 +22244,10 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21297
22244
|
}
|
|
21298
22245
|
}, dependencyLockCheck = async (projectRoot) => {
|
|
21299
22246
|
const present = (await Promise.all(LOCK_FILES.map(async (name) => ({
|
|
21300
|
-
exists: await pathExists6(
|
|
22247
|
+
exists: await pathExists6(join55(projectRoot, name)),
|
|
21301
22248
|
name
|
|
21302
22249
|
})))).find(({ exists: exists4 }) => exists4);
|
|
21303
|
-
return present ? pass("mobile.dependency-lock", `Dependency graph is locked by ${present.name}.`,
|
|
22250
|
+
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
22251
|
}, productionOriginCheck = (config, projectRoot) => {
|
|
21305
22252
|
const origin = new URL(config.productionOrigin);
|
|
21306
22253
|
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 +22282,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21335
22282
|
if (!await pathExists6(nativeConfigPath)) {
|
|
21336
22283
|
return fail5("android.capacitor-config", "The generated Android Capacitor config is missing.", nativeConfigPath, "Run `absolute mobile sync android` before release validation.");
|
|
21337
22284
|
}
|
|
21338
|
-
const unsafe = isUnsafeCapacitorConfig(await
|
|
22285
|
+
const unsafe = isUnsafeCapacitorConfig(await readFile20(nativeConfigPath, "utf8"));
|
|
21339
22286
|
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
22287
|
}, capacitorIdentityCheck = async (config, platform6, nativeConfigPath) => {
|
|
21341
22288
|
try {
|
|
@@ -21350,12 +22297,12 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21350
22297
|
if (!await pathExists6(manifestPath)) {
|
|
21351
22298
|
return fail5("android.cleartext", "The Android manifest is missing.", manifestPath, "Run `absolute mobile sync android` before release validation.");
|
|
21352
22299
|
}
|
|
21353
|
-
const source = await
|
|
22300
|
+
const source = await readFile20(manifestPath, "utf8");
|
|
21354
22301
|
const cleartext = /android:usesCleartextTraffic=["']true["']/u.test(source);
|
|
21355
22302
|
const networkConfigName = source.match(/android:networkSecurityConfig=["']@xml\/([a-z0-9_]+)["']/u)?.[1];
|
|
21356
|
-
const networkConfigPath = networkConfigName ?
|
|
22303
|
+
const networkConfigPath = networkConfigName ? join55(dirname32(manifestPath), "res", "xml", `${networkConfigName}.xml`) : undefined;
|
|
21357
22304
|
const developmentTrustReference = /android:networkSecurityConfig=["']@xml\/absolutejs_dev_network_security["']/u.test(source);
|
|
21358
|
-
const developmentTrustContents = networkConfigPath ? await
|
|
22305
|
+
const developmentTrustContents = networkConfigPath ? await readFile20(networkConfigPath, "utf8").then((value) => value.includes("@raw/absolutejs_dev_ca")).catch(() => false) : false;
|
|
21359
22306
|
const developmentTrust = developmentTrustReference || developmentTrustContents;
|
|
21360
22307
|
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
22308
|
}, hmrAssetsReleaseCheck = async (publicRoot) => {
|
|
@@ -21364,12 +22311,12 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21364
22311
|
}, embeddedBundleReleaseCheck = async (config, projectRoot, platform6, publicRoot) => {
|
|
21365
22312
|
const inspection = await inspectAbsoluteMobileBundle({ ...config, bundleDirectory: publicRoot }, projectRoot);
|
|
21366
22313
|
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"}`,
|
|
22314
|
+
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"));
|
|
22315
|
+
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
22316
|
}, contentSecurityPolicyCheck = async (config, platform6, publicRoot) => {
|
|
21370
|
-
const path =
|
|
22317
|
+
const path = join55(publicRoot, "index.html");
|
|
21371
22318
|
try {
|
|
21372
|
-
const source = await
|
|
22319
|
+
const source = await readFile20(path, "utf8");
|
|
21373
22320
|
const requirements = [
|
|
21374
22321
|
"Content-Security-Policy",
|
|
21375
22322
|
"default-src 'self'",
|
|
@@ -21388,26 +22335,26 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21388
22335
|
}
|
|
21389
22336
|
}, validateExpoCodeSigningProjection = async (config, expo) => {
|
|
21390
22337
|
const configuredSigning = config.updates?.expoCodeSigning;
|
|
21391
|
-
const generatedUpdates =
|
|
22338
|
+
const generatedUpdates = isRecord16(expo.updates) ? expo.updates : undefined;
|
|
21392
22339
|
if (config.updates && !configuredSigning)
|
|
21393
22340
|
throw new TypeError("Expo production updates require an embedded code-signing certificate.");
|
|
21394
22341
|
if (!configuredSigning && generatedUpdates && (("codeSigningCertificate" in generatedUpdates) || ("codeSigningMetadata" in generatedUpdates)))
|
|
21395
22342
|
throw new TypeError("Generated Expo config contains unconfigured code-signing material.");
|
|
21396
22343
|
if (!configuredSigning)
|
|
21397
22344
|
return;
|
|
21398
|
-
if (!generatedUpdates || generatedUpdates.codeSigningCertificate !== "./certs/absolute-mobile-update.pem" || !
|
|
22345
|
+
if (!generatedUpdates || generatedUpdates.codeSigningCertificate !== "./certs/absolute-mobile-update.pem" || !isRecord16(generatedUpdates.codeSigningMetadata) || generatedUpdates.codeSigningMetadata.keyid !== configuredSigning.keyId || generatedUpdates.codeSigningMetadata.alg !== configuredSigning.algorithm)
|
|
21399
22346
|
throw new TypeError("Generated Expo code-signing metadata does not match mobile config.");
|
|
21400
|
-
const generatedCertificate = await
|
|
22347
|
+
const generatedCertificate = await readFile20(join55(config.nativeProjectDirectory, "certs", "absolute-mobile-update.pem"), "utf8");
|
|
21401
22348
|
if (generatedCertificate !== configuredSigning.certificatePem)
|
|
21402
22349
|
throw new TypeError("Generated Expo code-signing certificate does not match mobile config.");
|
|
21403
22350
|
}, expoApplicationConfigCheck = async (config, projectRoot) => {
|
|
21404
|
-
const path =
|
|
22351
|
+
const path = join55(config.nativeProjectDirectory, "app.json");
|
|
21405
22352
|
try {
|
|
21406
22353
|
const root = await readJsonObject(path);
|
|
21407
|
-
if (!
|
|
22354
|
+
if (!isRecord16(root.expo))
|
|
21408
22355
|
throw new TypeError("Generated Expo application config is invalid.");
|
|
21409
22356
|
const { expo } = root;
|
|
21410
|
-
if (expo.name !== config.appName || config.platforms.includes("android") && (!
|
|
22357
|
+
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
22358
|
throw new TypeError("Generated Expo application identity does not match mobile config.");
|
|
21412
22359
|
}
|
|
21413
22360
|
const expectedRuntime = resolveAbsoluteMobileUpdateRuntime(config, projectRoot).fingerprint;
|
|
@@ -21423,12 +22370,12 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21423
22370
|
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
22371
|
}
|
|
21425
22372
|
}, expoEmbeddedAssetsCheck = async (config) => {
|
|
21426
|
-
const generated =
|
|
21427
|
-
const assetsRoot =
|
|
22373
|
+
const generated = join55(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
|
|
22374
|
+
const assetsRoot = join55(config.nativeProjectDirectory, "assets", "absolute");
|
|
21428
22375
|
try {
|
|
21429
22376
|
const [source, manifest] = await Promise.all([
|
|
21430
|
-
|
|
21431
|
-
readJsonObject(
|
|
22377
|
+
readFile20(generated, "utf8"),
|
|
22378
|
+
readJsonObject(join55(config.bundleDirectory, "absolute-mobile-manifest.json"))
|
|
21432
22379
|
]);
|
|
21433
22380
|
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
22381
|
throw new TypeError("Generated Expo assets do not contain the prepared production release identity.");
|
|
@@ -21448,8 +22395,8 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21448
22395
|
if (!embedded)
|
|
21449
22396
|
return false;
|
|
21450
22397
|
const [left, right] = await Promise.all([
|
|
21451
|
-
|
|
21452
|
-
|
|
22398
|
+
readFile20(join55(config.bundleDirectory, path)),
|
|
22399
|
+
readFile20(join55(assetsRoot, embedded))
|
|
21453
22400
|
]);
|
|
21454
22401
|
return left.equals(right);
|
|
21455
22402
|
}));
|
|
@@ -21463,18 +22410,18 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21463
22410
|
if (!await pathExists6(root))
|
|
21464
22411
|
return [];
|
|
21465
22412
|
const files = await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: root, onlyFiles: true }));
|
|
21466
|
-
return files.filter((file) => extensions.has(extname8(file))).map((file) =>
|
|
22413
|
+
return files.filter((file) => extensions.has(extname8(file))).map((file) => join55(root, file));
|
|
21467
22414
|
}, containsPattern = async (paths, pattern) => {
|
|
21468
|
-
const sources = await Promise.all(paths.map((path) =>
|
|
22415
|
+
const sources = await Promise.all(paths.map((path) => readFile20(path, "utf8")));
|
|
21469
22416
|
const index = sources.findIndex((source) => pattern.test(source));
|
|
21470
22417
|
return index === NOT_FOUND3 ? undefined : paths[index];
|
|
21471
22418
|
}, androidNativeSecurityCheck = async (androidRoot) => {
|
|
21472
|
-
const manifestPath =
|
|
22419
|
+
const manifestPath = join55(androidRoot, "app/src/main/AndroidManifest.xml");
|
|
21473
22420
|
try {
|
|
21474
|
-
const manifest = await
|
|
22421
|
+
const manifest = await readFile20(manifestPath, "utf8");
|
|
21475
22422
|
if (/android:debuggable=["']true["']/u.test(manifest))
|
|
21476
22423
|
throw new TypeError("Android release manifest explicitly enables application debugging.");
|
|
21477
|
-
const sources = await sourceFiles(
|
|
22424
|
+
const sources = await sourceFiles(join55(androidRoot, "app/src/main"), new Set([".java", ".kt"]));
|
|
21478
22425
|
const debugSource = await containsPattern(sources, /setWebContentsDebuggingEnabled\s*\(\s*true\s*\)/u);
|
|
21479
22426
|
if (debugSource)
|
|
21480
22427
|
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 +22430,14 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21483
22430
|
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
22431
|
}
|
|
21485
22432
|
}, androidExportedComponentsCheck = async (manifestPath) => {
|
|
21486
|
-
const source = await
|
|
22433
|
+
const source = await readFile20(manifestPath, "utf8").catch(() => "");
|
|
21487
22434
|
const exported = [
|
|
21488
22435
|
...source.matchAll(/<(?:activity|activity-alias|provider|receiver|service)\b[^>]*>/giu)
|
|
21489
22436
|
].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
22437
|
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
22438
|
}, androidDeepLinkProjectionCheck = async (config, manifestPath) => {
|
|
21492
22439
|
try {
|
|
21493
|
-
const source = await
|
|
22440
|
+
const source = await readFile20(manifestPath, "utf8");
|
|
21494
22441
|
const hasWebHost = (host2) => [...source.matchAll(/<data\b[^>]*>/giu)].some(([tag]) => tag.includes('android:scheme="https"') && tag.includes(`android:host="${host2}"`));
|
|
21495
22442
|
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
22443
|
throw new TypeError("Android App Link or custom-scheme projection does not match mobile config.");
|
|
@@ -21503,15 +22450,15 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21503
22450
|
return;
|
|
21504
22451
|
const timeout = String(config.updates.bootTimeoutMs);
|
|
21505
22452
|
if (platform6 === "ios") {
|
|
21506
|
-
const path =
|
|
21507
|
-
const configPath2 =
|
|
22453
|
+
const path = join55(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
22454
|
+
const configPath2 = join55(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
|
|
21508
22455
|
const [source, nativeConfig] = await Promise.all([
|
|
21509
|
-
|
|
21510
|
-
|
|
22456
|
+
readFile20(path, "utf8").catch(() => ""),
|
|
22457
|
+
readFile20(configPath2, "utf8").catch(() => "")
|
|
21511
22458
|
]);
|
|
21512
22459
|
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
22460
|
}
|
|
21514
|
-
const sourceRoot =
|
|
22461
|
+
const sourceRoot = join55(config.nativeProjectDirectory, "android/app/src/main");
|
|
21515
22462
|
const sources = await sourceFiles(sourceRoot, new Set([".java", ".kt"]));
|
|
21516
22463
|
const [activity, plugin] = await Promise.all([
|
|
21517
22464
|
containsPattern(sources, /recoverInterruptedBoot\s*\(\s*this\s*\)/u),
|
|
@@ -21530,14 +22477,14 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21530
22477
|
return fail5("ios.native-debugging", "iOS application source unconditionally enables WebView inspection.", debugSource, "Remove unconditional WebView inspection from release source.");
|
|
21531
22478
|
return pass("ios.native-debugging", "iOS source does not enable release debugger attachment or WebView inspection.", entitlementPaths[0] ?? iosRoot);
|
|
21532
22479
|
}, iosDeepLinkProjectionCheck = async (config, iosRoot) => {
|
|
21533
|
-
const infoPath =
|
|
21534
|
-
const entitlementsPath =
|
|
21535
|
-
const projectPath =
|
|
22480
|
+
const infoPath = join55(iosRoot, "App/App/Info.plist");
|
|
22481
|
+
const entitlementsPath = join55(iosRoot, "App/AbsoluteJS.entitlements");
|
|
22482
|
+
const projectPath = join55(iosRoot, "App/App.xcodeproj/project.pbxproj");
|
|
21536
22483
|
try {
|
|
21537
22484
|
const [info2, entitlements, project] = await Promise.all([
|
|
21538
|
-
|
|
21539
|
-
|
|
21540
|
-
|
|
22485
|
+
readFile20(infoPath, "utf8"),
|
|
22486
|
+
readFile20(entitlementsPath, "utf8"),
|
|
22487
|
+
readFile20(projectPath, "utf8")
|
|
21541
22488
|
]);
|
|
21542
22489
|
if (config.deepLinkScheme && (!info2.includes("<key>CFBundleURLTypes</key>") || !info2.includes(`<string>${config.deepLinkScheme}</string>`)))
|
|
21543
22490
|
throw new TypeError("iOS custom URL scheme does not match mobile config.");
|
|
@@ -21552,7 +22499,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21552
22499
|
}, syncSchemaReleaseCheck = (projectRoot) => {
|
|
21553
22500
|
if (!projectUsesAbsoluteSync(projectRoot))
|
|
21554
22501
|
return;
|
|
21555
|
-
const manifestPath =
|
|
22502
|
+
const manifestPath = join55(projectRoot, "package.json");
|
|
21556
22503
|
try {
|
|
21557
22504
|
const schema = discoverAbsoluteSyncSchema(projectRoot);
|
|
21558
22505
|
const versions = schema.components.map((component2) => `${component2.id}@${component2.version}`).join(", ");
|
|
@@ -21574,8 +22521,8 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21574
22521
|
}, IOS_USAGE_KEYS, androidDevicePermissionCheck = async (config, permissions) => {
|
|
21575
22522
|
if (!config.platforms.includes("android") || permissions.length === 0)
|
|
21576
22523
|
return;
|
|
21577
|
-
const path =
|
|
21578
|
-
const source = await
|
|
22524
|
+
const path = join55(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
|
|
22525
|
+
const source = await readFile20(path, "utf8");
|
|
21579
22526
|
const missing = permissions.filter((permission) => !source.includes(`android:name="${permission}"`) && !source.includes(`android:name='${permission}'`));
|
|
21580
22527
|
if (missing.length === 0)
|
|
21581
22528
|
return;
|
|
@@ -21583,9 +22530,9 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21583
22530
|
}, iosDevicePermissionCheck = async (config, purposes) => {
|
|
21584
22531
|
if (!config.platforms.includes("ios") || purposes.length === 0)
|
|
21585
22532
|
return;
|
|
21586
|
-
const iosRoot =
|
|
21587
|
-
const path = config.engine === "expo" ? await uniqueExpoIosFile(iosRoot, "**/Info.plist", "Info.plist") :
|
|
21588
|
-
const source = await
|
|
22533
|
+
const iosRoot = join55(config.nativeProjectDirectory, "ios");
|
|
22534
|
+
const path = config.engine === "expo" ? await uniqueExpoIosFile(iosRoot, "**/Info.plist", "Info.plist") : join55(iosRoot, "App/App/Info.plist");
|
|
22535
|
+
const source = await readFile20(path, "utf8");
|
|
21589
22536
|
const missing = purposes.filter((purpose) => !source.includes(`<key>${IOS_USAGE_KEYS[purpose]}</key>`));
|
|
21590
22537
|
if (missing.length === 0)
|
|
21591
22538
|
return;
|
|
@@ -21594,7 +22541,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21594
22541
|
if (requirements.iosPrivacyAccessedApis.length === 0)
|
|
21595
22542
|
return;
|
|
21596
22543
|
const privacyPath = await uniqueExpoIosFile(iosRoot, "**/PrivacyInfo.xcprivacy", "privacy manifest");
|
|
21597
|
-
const privacy = await
|
|
22544
|
+
const privacy = await readFile20(privacyPath, "utf8");
|
|
21598
22545
|
const missing = requirements.iosPrivacyAccessedApis.some(({ api, reasons }) => !privacy.includes(`<string>${api}</string>`) || reasons.some((reason) => !privacy.includes(`<string>${reason}</string>`)));
|
|
21599
22546
|
if (!missing && project.includes(privacyPath.split(/[\\/]/u).at(-1) ?? ""))
|
|
21600
22547
|
return;
|
|
@@ -21603,14 +22550,14 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21603
22550
|
if (!requirements.iosPushNotifications)
|
|
21604
22551
|
return;
|
|
21605
22552
|
const entitlementsPath = await uniqueExpoIosFile(iosRoot, "**/*.entitlements", "entitlements");
|
|
21606
|
-
const entitlements = await
|
|
22553
|
+
const entitlements = await readFile20(entitlementsPath, "utf8");
|
|
21607
22554
|
if (entitlements.includes("<key>aps-environment</key>"))
|
|
21608
22555
|
return;
|
|
21609
22556
|
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
22557
|
}, expoIosCapabilityProjectionCheck = async (config, requirements) => {
|
|
21611
|
-
const iosRoot =
|
|
22558
|
+
const iosRoot = join55(config.nativeProjectDirectory, "ios");
|
|
21612
22559
|
const projectPath = await uniqueExpoIosFile(iosRoot, "**/*.xcodeproj/project.pbxproj", "Xcode project");
|
|
21613
|
-
const project = await
|
|
22560
|
+
const project = await readFile20(projectPath, "utf8");
|
|
21614
22561
|
const privacy = await expoIosPrivacyCapabilityCheck(iosRoot, project, requirements);
|
|
21615
22562
|
if (privacy)
|
|
21616
22563
|
return privacy;
|
|
@@ -21620,41 +22567,41 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21620
22567
|
return;
|
|
21621
22568
|
if (config.engine === "expo")
|
|
21622
22569
|
return expoIosCapabilityProjectionCheck(config, requirements);
|
|
21623
|
-
const appRoot =
|
|
21624
|
-
const infoPath =
|
|
21625
|
-
const info2 = await
|
|
22570
|
+
const appRoot = join55(config.nativeProjectDirectory, "ios/App/App");
|
|
22571
|
+
const infoPath = join55(appRoot, "Info.plist");
|
|
22572
|
+
const info2 = await readFile20(infoPath, "utf8").catch(() => "");
|
|
21626
22573
|
if (requirements.iosSystemBars && !/<key>UIViewControllerBasedStatusBarAppearance<\/key>\s*<true\s*\/>/u.test(info2))
|
|
21627
22574
|
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
22575
|
if (requirements.iosPrivacyAccessedApis.length > 0) {
|
|
21629
|
-
const privacyPath =
|
|
21630
|
-
const projectPath =
|
|
22576
|
+
const privacyPath = join55(appRoot, "PrivacyInfo.xcprivacy");
|
|
22577
|
+
const projectPath = join55(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
|
|
21631
22578
|
const [privacy, project] = await Promise.all([
|
|
21632
|
-
|
|
21633
|
-
|
|
22579
|
+
readFile20(privacyPath, "utf8").catch(() => ""),
|
|
22580
|
+
readFile20(projectPath, "utf8").catch(() => "")
|
|
21634
22581
|
]);
|
|
21635
22582
|
const missing = requirements.iosPrivacyAccessedApis.some(({ api, reasons }) => !privacy.includes(`<string>${api}</string>`) || reasons.some((reason) => !privacy.includes(`<string>${reason}</string>`)));
|
|
21636
22583
|
if (missing || !project.includes("PrivacyInfo.xcprivacy in Resources"))
|
|
21637
22584
|
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
22585
|
}
|
|
21639
22586
|
if (requirements.iosPushNotifications) {
|
|
21640
|
-
const entitlementsPath =
|
|
21641
|
-
const delegatePath =
|
|
22587
|
+
const entitlementsPath = join55(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
|
|
22588
|
+
const delegatePath = join55(appRoot, "AppDelegate.swift");
|
|
21642
22589
|
const [entitlements, delegate] = await Promise.all([
|
|
21643
|
-
|
|
21644
|
-
|
|
22590
|
+
readFile20(entitlementsPath, "utf8").catch(() => ""),
|
|
22591
|
+
readFile20(delegatePath, "utf8").catch(() => "")
|
|
21645
22592
|
]);
|
|
21646
22593
|
if (!entitlements.includes("<key>aps-environment</key>") || !delegate.includes("capacitorDidRegisterForRemoteNotifications") || !delegate.includes("capacitorDidFailToRegisterForRemoteNotifications"))
|
|
21647
22594
|
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
22595
|
}
|
|
21649
22596
|
return;
|
|
21650
22597
|
}, deviceCapabilityReleaseCheck = async (config, projectRoot) => {
|
|
21651
|
-
const manifestPath =
|
|
22598
|
+
const manifestPath = join55(projectRoot, "package.json");
|
|
21652
22599
|
try {
|
|
21653
22600
|
const plan = resolveAbsoluteDeviceCapabilityPlan(projectRoot, config.engine);
|
|
21654
22601
|
const assertPackages = async () => {
|
|
21655
22602
|
if (config.engine === "capacitor")
|
|
21656
22603
|
return assertAbsoluteDeviceCapabilityPackages(projectRoot, plan);
|
|
21657
|
-
const generated = await readJsonObject(
|
|
22604
|
+
const generated = await readJsonObject(join55(config.nativeProjectDirectory, "package.json"));
|
|
21658
22605
|
const declarations = packageDeclarations(generated);
|
|
21659
22606
|
const missing = plan.requiredPackages.filter((spec) => {
|
|
21660
22607
|
const separator = spec.lastIndexOf("@");
|
|
@@ -21680,11 +22627,11 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21680
22627
|
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
22628
|
}
|
|
21682
22629
|
}, inspectAndroidRelease = async (config, projectRoot) => {
|
|
21683
|
-
const androidRoot =
|
|
21684
|
-
const nativeConfigPath =
|
|
21685
|
-
const manifestPath =
|
|
21686
|
-
const publicRoot =
|
|
21687
|
-
const journalPath =
|
|
22630
|
+
const androidRoot = join55(config.nativeProjectDirectory, "android");
|
|
22631
|
+
const nativeConfigPath = join55(androidRoot, "app", "src", "main", "assets", "capacitor.config.json");
|
|
22632
|
+
const manifestPath = join55(androidRoot, "app", "src", "main", "AndroidManifest.xml");
|
|
22633
|
+
const publicRoot = join55(androidRoot, "app", "src", "main", "assets", "public");
|
|
22634
|
+
const journalPath = join55(projectRoot, ".absolutejs", "mobile", "dev-session", "journal.json");
|
|
21688
22635
|
const checks = await Promise.all([
|
|
21689
22636
|
journalReleaseCheck(journalPath, "android"),
|
|
21690
22637
|
capacitorConfigReleaseCheck(nativeConfigPath),
|
|
@@ -21703,9 +22650,9 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21703
22650
|
path: check2.path ? relative26(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
|
|
21704
22651
|
}));
|
|
21705
22652
|
}, inspectExpoAndroidRelease = async (config, projectRoot) => {
|
|
21706
|
-
const androidRoot =
|
|
21707
|
-
const manifestPath =
|
|
21708
|
-
const journalPath =
|
|
22653
|
+
const androidRoot = join55(config.nativeProjectDirectory, "android");
|
|
22654
|
+
const manifestPath = join55(androidRoot, "app", "src", "main", "AndroidManifest.xml");
|
|
22655
|
+
const journalPath = join55(projectRoot, ".absolutejs", "mobile", "expo-dev-session", "journal.json");
|
|
21709
22656
|
const checks = await Promise.all([
|
|
21710
22657
|
journalReleaseCheck(journalPath, "android"),
|
|
21711
22658
|
expoApplicationConfigCheck(config, projectRoot),
|
|
@@ -21729,7 +22676,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21729
22676
|
const [path] = paths;
|
|
21730
22677
|
if (!path)
|
|
21731
22678
|
throw new TypeError(`Generated Expo iOS project is missing its ${label}.`);
|
|
21732
|
-
return
|
|
22679
|
+
return join55(iosRoot, path);
|
|
21733
22680
|
}, expoIosNativeProjectionCheck = async (config, iosRoot) => {
|
|
21734
22681
|
try {
|
|
21735
22682
|
const [infoPath, entitlementsPath, projectPath] = await Promise.all([
|
|
@@ -21738,9 +22685,9 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21738
22685
|
uniqueExpoIosFile(iosRoot, "**/*.xcodeproj/project.pbxproj", "Xcode project")
|
|
21739
22686
|
]);
|
|
21740
22687
|
const [info2, entitlements, project] = await Promise.all([
|
|
21741
|
-
|
|
21742
|
-
|
|
21743
|
-
|
|
22688
|
+
readFile20(infoPath, "utf8"),
|
|
22689
|
+
readFile20(entitlementsPath, "utf8"),
|
|
22690
|
+
readFile20(projectPath, "utf8")
|
|
21744
22691
|
]);
|
|
21745
22692
|
if (/<key>NSAllowsArbitraryLoads<\/key>\s*<true\s*\/>/u.test(info2))
|
|
21746
22693
|
throw new TypeError("Expo iOS App Transport Security permits arbitrary network loads.");
|
|
@@ -21755,8 +22702,8 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21755
22702
|
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
22703
|
}
|
|
21757
22704
|
}, inspectExpoIosRelease = async (config, projectRoot) => {
|
|
21758
|
-
const iosRoot =
|
|
21759
|
-
const journalPath =
|
|
22705
|
+
const iosRoot = join55(config.nativeProjectDirectory, "ios");
|
|
22706
|
+
const journalPath = join55(projectRoot, ".absolutejs", "mobile", "expo-dev-session", "journal.json");
|
|
21760
22707
|
const checks = [
|
|
21761
22708
|
await journalReleaseCheck(journalPath, "ios")
|
|
21762
22709
|
];
|
|
@@ -21775,11 +22722,11 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21775
22722
|
path: check2.path ? relative26(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
|
|
21776
22723
|
}));
|
|
21777
22724
|
}, inspectIosRelease = async (config, projectRoot) => {
|
|
21778
|
-
const iosAppRoot =
|
|
21779
|
-
const nativeConfigPath =
|
|
21780
|
-
const infoPath =
|
|
21781
|
-
const publicRoot =
|
|
21782
|
-
const journalPath =
|
|
22725
|
+
const iosAppRoot = join55(config.nativeProjectDirectory, "ios", "App", "App");
|
|
22726
|
+
const nativeConfigPath = join55(iosAppRoot, "capacitor.config.json");
|
|
22727
|
+
const infoPath = join55(iosAppRoot, "Info.plist");
|
|
22728
|
+
const publicRoot = join55(iosAppRoot, "public");
|
|
22729
|
+
const journalPath = join55(projectRoot, ".absolutejs", "mobile", "ios-dev-session", "journal.json");
|
|
21783
22730
|
const checks = [
|
|
21784
22731
|
await journalReleaseCheck(journalPath, "ios")
|
|
21785
22732
|
];
|
|
@@ -21791,7 +22738,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21791
22738
|
}
|
|
21792
22739
|
if (!await pathExists6(nativeConfigPath)) {
|
|
21793
22740
|
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
|
|
22741
|
+
} else if (isUnsafeCapacitorConfig(await readFile20(nativeConfigPath, "utf8"))) {
|
|
21795
22742
|
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
22743
|
} else {
|
|
21797
22744
|
checks.push(pass("ios.capacitor-config", "iOS Capacitor config contains no development transport overrides.", nativeConfigPath));
|
|
@@ -21800,12 +22747,12 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
21800
22747
|
if (!await pathExists6(infoPath)) {
|
|
21801
22748
|
checks.push(fail5("ios.transport-security", "The iOS Info.plist is missing.", infoPath, "Run `absolute mobile sync ios` before release validation."));
|
|
21802
22749
|
} else {
|
|
21803
|
-
const info2 = await
|
|
22750
|
+
const info2 = await readFile20(infoPath, "utf8");
|
|
21804
22751
|
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
22752
|
}
|
|
21806
22753
|
const hmrAsset = await findHmrAsset(publicRoot);
|
|
21807
22754
|
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(
|
|
22755
|
+
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")));
|
|
21809
22756
|
if (updateWatchdog)
|
|
21810
22757
|
checks.push(updateWatchdog);
|
|
21811
22758
|
return checks.map((check2) => ({
|
|
@@ -21900,18 +22847,18 @@ import { createHash as createHash16 } from "crypto";
|
|
|
21900
22847
|
import {
|
|
21901
22848
|
access as access12,
|
|
21902
22849
|
copyFile as copyFile5,
|
|
21903
|
-
mkdir as
|
|
22850
|
+
mkdir as mkdir15,
|
|
21904
22851
|
mkdtemp as mkdtemp7,
|
|
21905
|
-
readFile as
|
|
22852
|
+
readFile as readFile21,
|
|
21906
22853
|
realpath as realpath2,
|
|
21907
|
-
rename as
|
|
21908
|
-
rm as
|
|
22854
|
+
rename as rename15,
|
|
22855
|
+
rm as rm12,
|
|
21909
22856
|
stat as stat3,
|
|
21910
|
-
writeFile as
|
|
22857
|
+
writeFile as writeFile17
|
|
21911
22858
|
} from "fs/promises";
|
|
21912
|
-
import { dirname as
|
|
21913
|
-
var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1,
|
|
21914
|
-
if (!
|
|
22859
|
+
import { dirname as dirname33, isAbsolute as isAbsolute7, join as join56, relative as relative27, resolve as resolve40, sep as sep7 } from "path";
|
|
22860
|
+
var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord17 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), requireManifest2 = (value) => {
|
|
22861
|
+
if (!isRecord17(value) || typeof value.appBuild !== "string" || typeof value.appId !== "string" || typeof value.runtime !== "string") {
|
|
21915
22862
|
throw new TypeError("Invalid embedded AbsoluteJS mobile manifest.");
|
|
21916
22863
|
}
|
|
21917
22864
|
return {
|
|
@@ -21973,14 +22920,14 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord16 = (value) => typeof value ==
|
|
|
21973
22920
|
]);
|
|
21974
22921
|
if (result.exitCode !== 0)
|
|
21975
22922
|
throw new TypeError("jarsigner could not sign the Android App Bundle with the configured CI identity.");
|
|
21976
|
-
}, sha256File2 = async (path) => createHash16("sha256").update(await
|
|
22923
|
+
}, sha256File2 = async (path) => createHash16("sha256").update(await readFile21(path)).digest("hex"), fingerprintExpoAndroidProject = async (nativeDirectory) => {
|
|
21977
22924
|
const root = await realpath2(nativeDirectory);
|
|
21978
22925
|
const files = await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: root, onlyFiles: true }));
|
|
21979
22926
|
const records = await Promise.all(files.filter((path) => {
|
|
21980
22927
|
const parts = path.replaceAll("\\", "/").split("/");
|
|
21981
22928
|
return !parts.includes(".gradle") && !parts.includes("build");
|
|
21982
22929
|
}).sort().map(async (path) => {
|
|
21983
|
-
const contents = await
|
|
22930
|
+
const contents = await readFile21(join56(root, path));
|
|
21984
22931
|
return `${path.replaceAll("\\", "/")}\x00${createHash16("sha256").update(contents).digest("hex")}\x00`;
|
|
21985
22932
|
}));
|
|
21986
22933
|
return createHash16("sha256").update(records.join("")).digest("hex");
|
|
@@ -21993,11 +22940,11 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord16 = (value) => typeof value ==
|
|
|
21993
22940
|
}
|
|
21994
22941
|
return output;
|
|
21995
22942
|
}, installRelease2 = async (artifactPath, metadata, outputRoot) => {
|
|
21996
|
-
const releaseRoot =
|
|
22943
|
+
const releaseRoot = join56(outputRoot, metadata.releaseId);
|
|
21997
22944
|
const artifactName = "app-release.aab";
|
|
21998
|
-
const destination =
|
|
22945
|
+
const destination = join56(releaseRoot, artifactName);
|
|
21999
22946
|
if (await pathExists7(releaseRoot)) {
|
|
22000
|
-
const existing = requireManifestIdentity(JSON.parse(await
|
|
22947
|
+
const existing = requireManifestIdentity(JSON.parse(await readFile21(join56(releaseRoot, "release.json"), "utf8")), metadata);
|
|
22001
22948
|
const [installedBytes, installedSha256] = await Promise.all([
|
|
22002
22949
|
stat3(destination).then(({ size }) => size),
|
|
22003
22950
|
sha256File2(destination)
|
|
@@ -22007,25 +22954,25 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord16 = (value) => typeof value ==
|
|
|
22007
22954
|
}
|
|
22008
22955
|
return { artifactPath: destination, metadata: existing, releaseRoot };
|
|
22009
22956
|
}
|
|
22010
|
-
await
|
|
22011
|
-
const staging = await mkdtemp7(
|
|
22957
|
+
await mkdir15(dirname33(releaseRoot), { recursive: true });
|
|
22958
|
+
const staging = await mkdtemp7(join56(dirname33(releaseRoot), ".android-stage-"));
|
|
22012
22959
|
try {
|
|
22013
|
-
await copyFile5(artifactPath,
|
|
22960
|
+
await copyFile5(artifactPath, join56(staging, artifactName));
|
|
22014
22961
|
const complete = {
|
|
22015
22962
|
...metadata,
|
|
22016
22963
|
artifact: artifactName
|
|
22017
22964
|
};
|
|
22018
|
-
await
|
|
22965
|
+
await writeFile17(join56(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
|
|
22019
22966
|
`, { flag: "wx" });
|
|
22020
|
-
await
|
|
22967
|
+
await rename15(staging, releaseRoot);
|
|
22021
22968
|
return { artifactPath: destination, metadata: complete, releaseRoot };
|
|
22022
22969
|
} finally {
|
|
22023
|
-
await
|
|
22970
|
+
await rm12(staging, { force: true, recursive: true }).catch(() => {
|
|
22024
22971
|
return;
|
|
22025
22972
|
});
|
|
22026
22973
|
}
|
|
22027
22974
|
}, requireManifestIdentity = (value, expected) => {
|
|
22028
|
-
if (!
|
|
22975
|
+
if (!isRecord17(value)) {
|
|
22029
22976
|
throw new TypeError("Existing Android release metadata is invalid.");
|
|
22030
22977
|
}
|
|
22031
22978
|
const { artifact } = value;
|
|
@@ -22046,8 +22993,8 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord16 = (value) => typeof value ==
|
|
|
22046
22993
|
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
22994
|
}
|
|
22048
22995
|
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
|
|
22996
|
+
const nativeDirectory = join56(options.config.nativeProjectDirectory, "android");
|
|
22997
|
+
const manifest = requireManifest2(JSON.parse(await readFile21(join56(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
|
|
22051
22998
|
if (manifest.appId !== options.config.appId) {
|
|
22052
22999
|
throw new TypeError("Embedded mobile manifest appId does not match mobile.appId.");
|
|
22053
23000
|
}
|
|
@@ -22161,7 +23108,7 @@ var absoluteIosDeviceAcceptanceCommands = (options) => {
|
|
|
22161
23108
|
};
|
|
22162
23109
|
|
|
22163
23110
|
// src/mobile/iosConformance.ts
|
|
22164
|
-
import { readFile as
|
|
23111
|
+
import { readFile as readFile22, stat as stat4 } from "fs/promises";
|
|
22165
23112
|
var HMR_LINE, parseAbsoluteIosHmrLog = (line) => {
|
|
22166
23113
|
const match = HMR_LINE.exec(line);
|
|
22167
23114
|
if (!match)
|
|
@@ -22196,7 +23143,7 @@ var HMR_LINE, parseAbsoluteIosHmrLog = (line) => {
|
|
|
22196
23143
|
if (Date.now() > deadline)
|
|
22197
23144
|
throw new Error(`No iOS native HMR acknowledgement was observed within ${timeoutMs}ms.`);
|
|
22198
23145
|
options.signal?.throwIfAborted();
|
|
22199
|
-
const contents = await
|
|
23146
|
+
const contents = await readFile22(options.logPath).catch(() => Buffer.alloc(0));
|
|
22200
23147
|
if (contents.byteLength < offset) {
|
|
22201
23148
|
offset = 0;
|
|
22202
23149
|
buffered = "";
|
|
@@ -22220,8 +23167,8 @@ var init_iosConformance = __esm(() => {
|
|
|
22220
23167
|
});
|
|
22221
23168
|
|
|
22222
23169
|
// src/mobile/nativeTestReport.ts
|
|
22223
|
-
import { mkdir as
|
|
22224
|
-
import { join as
|
|
23170
|
+
import { mkdir as mkdir16, readFile as readFile23, writeFile as writeFile18 } from "fs/promises";
|
|
23171
|
+
import { join as join57 } from "path";
|
|
22225
23172
|
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
23173
|
`, "<br>"), createAbsoluteNativeAutomatedChecks = (run) => {
|
|
22227
23174
|
const target = `${run.targetKind} ${run.targetId}`;
|
|
@@ -22323,7 +23270,7 @@ var secretPattern, bearerPattern, coordinatePattern, nativeCredentialPattern, sa
|
|
|
22323
23270
|
reportVersion: 1,
|
|
22324
23271
|
run: options.run
|
|
22325
23272
|
}), readPackageVersionForNativeReport = async (packageJsonPath) => {
|
|
22326
|
-
const manifest = JSON.parse(await
|
|
23273
|
+
const manifest = JSON.parse(await readFile23(packageJsonPath, "utf8"));
|
|
22327
23274
|
if (typeof manifest !== "object" || manifest === null)
|
|
22328
23275
|
return "unknown";
|
|
22329
23276
|
const version2 = Reflect.get(manifest, "version");
|
|
@@ -22359,13 +23306,13 @@ Replace each \`NOT_RUN\` with \`PASS\`, \`FAIL\`, or \`SKIPPED\` after completin
|
|
|
22359
23306
|
${table(report.manualChecks)}
|
|
22360
23307
|
`;
|
|
22361
23308
|
}, writeAbsoluteNativeTestReport = async (directory, report) => {
|
|
22362
|
-
await
|
|
22363
|
-
const jsonPath =
|
|
22364
|
-
const markdownPath =
|
|
23309
|
+
await mkdir16(directory, { recursive: true });
|
|
23310
|
+
const jsonPath = join57(directory, "report.json");
|
|
23311
|
+
const markdownPath = join57(directory, "report.md");
|
|
22365
23312
|
await Promise.all([
|
|
22366
|
-
|
|
23313
|
+
writeFile18(jsonPath, `${JSON.stringify(report, null, 2)}
|
|
22367
23314
|
`),
|
|
22368
|
-
|
|
23315
|
+
writeFile18(markdownPath, renderAbsoluteNativeTestReport(report))
|
|
22369
23316
|
]);
|
|
22370
23317
|
return { directory, jsonPath, markdownPath };
|
|
22371
23318
|
};
|
|
@@ -22649,7 +23596,7 @@ var prepareAbsoluteIosRelease = async (publisher, options) => {
|
|
|
22649
23596
|
throw new TypeError("Google Play publisher returned an invalid Android versionCode.");
|
|
22650
23597
|
}
|
|
22651
23598
|
return versionCode;
|
|
22652
|
-
},
|
|
23599
|
+
}, isRecord18 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), isPublisher = (value) => isRecord18(value) && typeof value.publish === "function", publisherModulePath = (projectRoot, requested) => {
|
|
22653
23600
|
const root = resolve41(projectRoot);
|
|
22654
23601
|
const path = resolve41(root, requested);
|
|
22655
23602
|
const projectRelative = relative28(root, path);
|
|
@@ -22663,7 +23610,7 @@ var prepareAbsoluteIosRelease = async (publisher, options) => {
|
|
|
22663
23610
|
throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
|
|
22664
23611
|
});
|
|
22665
23612
|
const loaded = await import(pathToFileURL2(modulePath).href);
|
|
22666
|
-
const publisher =
|
|
23613
|
+
const publisher = isRecord18(loaded) ? loaded.default ?? loaded.registry : undefined;
|
|
22667
23614
|
if (!isPublisher(publisher)) {
|
|
22668
23615
|
throw new TypeError("Native release registry module must default-export a registry with publish(options).");
|
|
22669
23616
|
}
|
|
@@ -22720,8 +23667,8 @@ var prepareAbsoluteIosRelease = async (publisher, options) => {
|
|
|
22720
23667
|
var init_releasePublisher = () => {};
|
|
22721
23668
|
|
|
22722
23669
|
// src/mobile/mobileInspect.ts
|
|
22723
|
-
import { access as access14, readFile as
|
|
22724
|
-
import { join as
|
|
23670
|
+
import { access as access14, readFile as readFile24 } from "fs/promises";
|
|
23671
|
+
import { join as join58, relative as relative29, resolve as resolve42 } from "path";
|
|
22725
23672
|
var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1, MOBILE_PACKAGE_NAMES, isObject3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), portablePath2 = (projectRoot, path) => {
|
|
22726
23673
|
const value = relative29(resolve42(projectRoot), resolve42(path)).replaceAll("\\", "/");
|
|
22727
23674
|
return value || ".";
|
|
@@ -22733,7 +23680,7 @@ var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1, MOBILE_PACKAGE_NAMES, isObject3 = (va
|
|
|
22733
23680
|
return false;
|
|
22734
23681
|
}
|
|
22735
23682
|
}, readObject2 = async (path) => {
|
|
22736
|
-
const value = JSON.parse(await
|
|
23683
|
+
const value = JSON.parse(await readFile24(path, "utf8"));
|
|
22737
23684
|
if (!isObject3(value))
|
|
22738
23685
|
throw new TypeError("JSON root must be an object.");
|
|
22739
23686
|
return value;
|
|
@@ -22743,13 +23690,13 @@ var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1, MOBILE_PACKAGE_NAMES, isObject3 = (va
|
|
|
22743
23690
|
for (const [name, declared] of Object.entries(value).filter((entry) => typeof entry[1] === "string"))
|
|
22744
23691
|
declarations.set(name, declared);
|
|
22745
23692
|
}, packageInspections = async (projectRoot, additionalNames) => {
|
|
22746
|
-
const project = await readObject2(
|
|
23693
|
+
const project = await readObject2(join58(projectRoot, "package.json"));
|
|
22747
23694
|
const declarations = new Map;
|
|
22748
23695
|
for (const field of ["dependencies", "devDependencies"])
|
|
22749
23696
|
addPackageDeclarations(declarations, project[field]);
|
|
22750
23697
|
const names = [...new Set([...declarations.keys(), ...additionalNames])].filter((name) => MOBILE_PACKAGE_NAMES.has(name) || name.startsWith("@capacitor/") || additionalNames.includes(name)).sort();
|
|
22751
23698
|
return Promise.all(names.map(async (name) => {
|
|
22752
|
-
const installedManifest = await readObject2(
|
|
23699
|
+
const installedManifest = await readObject2(join58(projectRoot, "node_modules", name, "package.json")).catch(() => {
|
|
22753
23700
|
return;
|
|
22754
23701
|
});
|
|
22755
23702
|
const installed = installedManifest?.version;
|
|
@@ -22807,7 +23754,7 @@ var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1, MOBILE_PACKAGE_NAMES, isObject3 = (va
|
|
|
22807
23754
|
},
|
|
22808
23755
|
format: ABSOLUTE_MOBILE_INSPECTION_FORMAT,
|
|
22809
23756
|
nativeProjects: await Promise.all(config.platforms.map(async (platform6) => {
|
|
22810
|
-
const path =
|
|
23757
|
+
const path = join58(config.nativeProjectDirectory, platform6);
|
|
22811
23758
|
return {
|
|
22812
23759
|
initialized: await pathExists8(path),
|
|
22813
23760
|
path: portablePath2(projectRoot, path),
|
|
@@ -22878,8 +23825,8 @@ var init_mobileInspect = __esm(() => {
|
|
|
22878
23825
|
|
|
22879
23826
|
// src/mobile/ciWorkflow.ts
|
|
22880
23827
|
import { existsSync as existsSync43 } from "fs";
|
|
22881
|
-
import { access as access15, mkdir as
|
|
22882
|
-
import { dirname as
|
|
23828
|
+
import { access as access15, mkdir as mkdir17, readFile as readFile25, writeFile as writeFile19 } from "fs/promises";
|
|
23829
|
+
import { dirname as dirname34, extname as extname9, relative as relative30, resolve as resolve43, sep as sep9 } from "path";
|
|
22883
23830
|
var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1, SECRET_NAME_PATTERN, CI_ENV_INDENTATION = 6, RESERVED_SECRET_NAMES, exists4 = async (path) => {
|
|
22884
23831
|
try {
|
|
22885
23832
|
await access15(path);
|
|
@@ -23292,12 +24239,12 @@ ${bundleAuditSteps}${platforms.includes("android") ? androidJob({ customSecrets,
|
|
|
23292
24239
|
}, writeAbsoluteMobileGithubWorkflow = async (options) => {
|
|
23293
24240
|
const path = workflowOutputPath(options.projectRoot, options.outputPath);
|
|
23294
24241
|
const generated = createAbsoluteMobileGithubWorkflow(options);
|
|
23295
|
-
const previous = await exists4(path) ? await
|
|
24242
|
+
const previous = await exists4(path) ? await readFile25(path, "utf8") : undefined;
|
|
23296
24243
|
if (previous !== undefined && previous !== generated.workflow && !options.force)
|
|
23297
24244
|
throw new TypeError(`${relative30(options.projectRoot, path)} already exists and differs. Rerun with --force to replace the generated workflow.`);
|
|
23298
24245
|
if (previous !== generated.workflow) {
|
|
23299
|
-
await
|
|
23300
|
-
await
|
|
24246
|
+
await mkdir17(dirname34(path), { recursive: true });
|
|
24247
|
+
await writeFile19(path, generated.workflow);
|
|
23301
24248
|
}
|
|
23302
24249
|
return {
|
|
23303
24250
|
changed: previous !== generated.workflow,
|
|
@@ -23358,20 +24305,20 @@ var init_ciWorkflow = __esm(() => {
|
|
|
23358
24305
|
import { createHash as createHash17, sign as sign2, verify as verify2 } from "crypto";
|
|
23359
24306
|
import {
|
|
23360
24307
|
cp as cp4,
|
|
23361
|
-
mkdir as
|
|
24308
|
+
mkdir as mkdir18,
|
|
23362
24309
|
mkdtemp as mkdtemp8,
|
|
23363
|
-
readdir as
|
|
23364
|
-
readFile as
|
|
23365
|
-
rename as
|
|
23366
|
-
rm as
|
|
24310
|
+
readdir as readdir8,
|
|
24311
|
+
readFile as readFile26,
|
|
24312
|
+
rename as rename16,
|
|
24313
|
+
rm as rm13,
|
|
23367
24314
|
stat as stat5,
|
|
23368
|
-
writeFile as
|
|
24315
|
+
writeFile as writeFile20
|
|
23369
24316
|
} from "fs/promises";
|
|
23370
|
-
import { dirname as
|
|
24317
|
+
import { dirname as dirname35, join as join59, relative as relative31, resolve as resolve44 } from "path";
|
|
23371
24318
|
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
|
|
24319
|
+
const entries = await readdir8(directory, { withFileTypes: true });
|
|
23373
24320
|
const paths = await Promise.all(entries.map(async (entry) => {
|
|
23374
|
-
const path =
|
|
24321
|
+
const path = join59(directory, entry.name);
|
|
23375
24322
|
if (entry.isDirectory())
|
|
23376
24323
|
return listFiles(root, path);
|
|
23377
24324
|
if (!entry.isFile())
|
|
@@ -23380,10 +24327,10 @@ var UPDATE_MANIFEST_FILE = "update.json", UPDATE_FILES_DIRECTORY = "files", sha2
|
|
|
23380
24327
|
}));
|
|
23381
24328
|
return paths.flat().sort((left, right) => left.localeCompare(right));
|
|
23382
24329
|
}, inspectFiles = async (root, paths) => Promise.all(paths.map(async (path) => {
|
|
23383
|
-
const source =
|
|
24330
|
+
const source = join59(root, path);
|
|
23384
24331
|
const [metadata, contents] = await Promise.all([
|
|
23385
24332
|
stat5(source),
|
|
23386
|
-
|
|
24333
|
+
readFile26(source)
|
|
23387
24334
|
]);
|
|
23388
24335
|
return { bytes: metadata.size, path, sha256: sha2562(contents) };
|
|
23389
24336
|
})), releaseIdFor = (value) => `amu_${sha2562(canonicalizeAbsoluteMobileUpdate(value))}`, buildAbsoluteMobileUpdate = async (options) => {
|
|
@@ -23416,29 +24363,29 @@ var UPDATE_MANIFEST_FILE = "update.json", UPDATE_FILES_DIRECTORY = "files", sha2
|
|
|
23416
24363
|
value: signature.toString("base64")
|
|
23417
24364
|
}
|
|
23418
24365
|
});
|
|
23419
|
-
await
|
|
23420
|
-
const outputDirectory =
|
|
23421
|
-
const staging = await mkdtemp8(
|
|
24366
|
+
await mkdir18(outputRoot, { recursive: true });
|
|
24367
|
+
const outputDirectory = join59(outputRoot, manifest.releaseId);
|
|
24368
|
+
const staging = await mkdtemp8(join59(outputRoot, ".stage-"));
|
|
23422
24369
|
try {
|
|
23423
|
-
await cp4(bundleDirectory,
|
|
24370
|
+
await cp4(bundleDirectory, join59(staging, UPDATE_FILES_DIRECTORY), {
|
|
23424
24371
|
force: true,
|
|
23425
24372
|
recursive: true
|
|
23426
24373
|
});
|
|
23427
|
-
await
|
|
24374
|
+
await writeFile20(join59(staging, UPDATE_MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
|
|
23428
24375
|
`);
|
|
23429
|
-
await
|
|
24376
|
+
await rename16(staging, outputDirectory);
|
|
23430
24377
|
} catch (error) {
|
|
23431
|
-
await
|
|
24378
|
+
await rm13(staging, { force: true, recursive: true });
|
|
23432
24379
|
if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "EEXIST")
|
|
23433
24380
|
throw new TypeError(`Mobile update ${manifest.releaseId} already exists.`, { cause: error });
|
|
23434
24381
|
throw error;
|
|
23435
24382
|
}
|
|
23436
24383
|
return {
|
|
23437
24384
|
manifest,
|
|
23438
|
-
manifestPath:
|
|
24385
|
+
manifestPath: join59(outputDirectory, UPDATE_MANIFEST_FILE),
|
|
23439
24386
|
outputDirectory
|
|
23440
24387
|
};
|
|
23441
|
-
}, readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await
|
|
24388
|
+
}, readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await readFile26(join59(resolve44(directory), UPDATE_MANIFEST_FILE), "utf8"))), verifyAbsoluteMobileUpdateSignature = (manifestValue, publicKey) => {
|
|
23442
24389
|
const manifest = parseAbsoluteMobileUpdateManifest(manifestValue);
|
|
23443
24390
|
const valid = verify2("sha256", absoluteMobileUpdateSigningPayload(unsignedAbsoluteMobileUpdate(manifest)), { dsaEncoding: "ieee-p1363", key: publicKey }, Buffer.from(manifest.signature.value, "base64"));
|
|
23444
24391
|
if (!valid)
|
|
@@ -23450,8 +24397,8 @@ var init_updateSigning = __esm(() => {
|
|
|
23450
24397
|
});
|
|
23451
24398
|
|
|
23452
24399
|
// src/mobile/expoUpdate.ts
|
|
23453
|
-
import { access as access16, mkdir as
|
|
23454
|
-
import { dirname as
|
|
24400
|
+
import { access as access16, mkdir as mkdir19, readFile as readFile27, writeFile as writeFile21 } from "fs/promises";
|
|
24401
|
+
import { dirname as dirname36, extname as extname10, join as join60 } from "path";
|
|
23455
24402
|
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
24403
|
if (typeof value !== "string" || value.length === 0)
|
|
23457
24404
|
throw new TypeError(`Expo update ${field} is invalid.`);
|
|
@@ -23509,7 +24456,7 @@ var ABSOLUTE_EXPO_UPDATE_DESCRIPTOR = "_absolute/expo-update.json", ABSOLUTE_EXP
|
|
|
23509
24456
|
runtimeVersion: value.runtimeVersion
|
|
23510
24457
|
};
|
|
23511
24458
|
}, finalizeAbsoluteExpoUpdateExport = async (options) => {
|
|
23512
|
-
const metadata = JSON.parse(await
|
|
24459
|
+
const metadata = JSON.parse(await readFile27(join60(options.exportDirectory, "metadata.json"), "utf8"));
|
|
23513
24460
|
if (!object4(metadata) || !object4(metadata.fileMetadata))
|
|
23514
24461
|
throw new TypeError("Expo export metadata.json is invalid.");
|
|
23515
24462
|
const descriptor = parseAbsoluteExpoUpdateDescriptor({
|
|
@@ -23520,12 +24467,12 @@ var ABSOLUTE_EXPO_UPDATE_DESCRIPTOR = "_absolute/expo-update.json", ABSOLUTE_EXP
|
|
|
23520
24467
|
runtimeVersion: options.runtimeVersion
|
|
23521
24468
|
});
|
|
23522
24469
|
const referenced = Object.values(descriptor.platforms).flatMap((entry) => entry ? [entry.launchAsset, ...entry.assets] : []);
|
|
23523
|
-
await Promise.all(referenced.map(({ path }) => access16(
|
|
24470
|
+
await Promise.all(referenced.map(({ path }) => access16(join60(options.exportDirectory, path)).catch(() => {
|
|
23524
24471
|
throw new TypeError(`Expo export metadata references missing asset ${path}.`);
|
|
23525
24472
|
})));
|
|
23526
|
-
const destination =
|
|
23527
|
-
await
|
|
23528
|
-
await
|
|
24473
|
+
const destination = join60(options.exportDirectory, ABSOLUTE_EXPO_UPDATE_DESCRIPTOR);
|
|
24474
|
+
await mkdir19(dirname36(destination), { recursive: true });
|
|
24475
|
+
await writeFile21(destination, `${JSON.stringify(descriptor, null, "\t")}
|
|
23529
24476
|
`);
|
|
23530
24477
|
return { descriptor, path: destination };
|
|
23531
24478
|
};
|
|
@@ -40199,8 +41146,8 @@ var require_main = __commonJS(function(exports) {
|
|
|
40199
41146
|
});
|
|
40200
41147
|
|
|
40201
41148
|
// src/mobile/expoCodeSigning.ts
|
|
40202
|
-
import { access as access17, mkdir as
|
|
40203
|
-
import { dirname as
|
|
41149
|
+
import { access as access17, mkdir as mkdir20, writeFile as writeFile22 } from "fs/promises";
|
|
41150
|
+
import { dirname as dirname37, isAbsolute as isAbsolute9, relative as relative32, resolve as resolve45, sep as sep10 } from "path";
|
|
40204
41151
|
var import_code_signing_certificates, exists5 = async (path) => access17(path).then(() => true).catch(() => false), inside = (root, path) => {
|
|
40205
41152
|
const location = relative32(root, path);
|
|
40206
41153
|
return location === "" || location !== ".." && !location.startsWith(`..${sep10}`) && !isAbsolute9(location);
|
|
@@ -40208,7 +41155,7 @@ var import_code_signing_certificates, exists5 = async (path) => access17(path).t
|
|
|
40208
41155
|
const root = resolve45(options.projectRoot);
|
|
40209
41156
|
const certificatePath = resolve45(root, options.certificatePath);
|
|
40210
41157
|
const privateKeyPath = resolve45(root, options.privateKeyPath);
|
|
40211
|
-
const publicKeyPath = resolve45(root, options.publicKeyPath ?? resolve45(
|
|
41158
|
+
const publicKeyPath = resolve45(root, options.publicKeyPath ?? resolve45(dirname37(privateKeyPath), "public-key.pem"));
|
|
40212
41159
|
if (!inside(root, certificatePath))
|
|
40213
41160
|
throw new TypeError("Expo code-signing certificate must be written inside the project so store builds can embed it.");
|
|
40214
41161
|
if (inside(root, privateKeyPath) || inside(root, publicKeyPath))
|
|
@@ -40238,11 +41185,11 @@ var import_code_signing_certificates, exists5 = async (path) => access17(path).t
|
|
|
40238
41185
|
import_code_signing_certificates.validateSelfSignedCertificate(certificate, keyPair);
|
|
40239
41186
|
const { privateKeyPEM, publicKeyPEM } = import_code_signing_certificates.convertKeyPairToPEM(keyPair);
|
|
40240
41187
|
const certificatePem = import_code_signing_certificates.convertCertificateToCertificatePEM(certificate);
|
|
40241
|
-
await Promise.all([certificatePath, privateKeyPath, publicKeyPath].map((path) =>
|
|
41188
|
+
await Promise.all([certificatePath, privateKeyPath, publicKeyPath].map((path) => mkdir20(dirname37(path), { recursive: true })));
|
|
40242
41189
|
await Promise.all([
|
|
40243
|
-
|
|
40244
|
-
|
|
40245
|
-
|
|
41190
|
+
writeFile22(certificatePath, certificatePem, { flag: "wx", mode: 420 }),
|
|
41191
|
+
writeFile22(privateKeyPath, privateKeyPEM, { flag: "wx", mode: 384 }),
|
|
41192
|
+
writeFile22(publicKeyPath, publicKeyPEM, { flag: "wx", mode: 420 })
|
|
40246
41193
|
]);
|
|
40247
41194
|
return {
|
|
40248
41195
|
certificatePath,
|
|
@@ -40321,18 +41268,18 @@ __export(exports_mobile, {
|
|
|
40321
41268
|
});
|
|
40322
41269
|
import {
|
|
40323
41270
|
access as access19,
|
|
40324
|
-
mkdir as
|
|
41271
|
+
mkdir as mkdir21,
|
|
40325
41272
|
mkdtemp as mkdtemp9,
|
|
40326
|
-
readFile as
|
|
40327
|
-
rm as
|
|
40328
|
-
writeFile as
|
|
41273
|
+
readFile as readFile28,
|
|
41274
|
+
rm as rm14,
|
|
41275
|
+
writeFile as writeFile23
|
|
40329
41276
|
} from "fs/promises";
|
|
40330
41277
|
import { createPublicKey as createPublicKey3 } from "crypto";
|
|
40331
|
-
import { join as
|
|
41278
|
+
import { join as join61, relative as relative34, resolve as resolve47 } from "path";
|
|
40332
41279
|
import { createInterface } from "readline/promises";
|
|
40333
|
-
var NOT_FOUND4 = -1,
|
|
41280
|
+
var NOT_FOUND4 = -1, isRecord19 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), expoPublicConfig = (config) => {
|
|
40334
41281
|
const result = { ...config };
|
|
40335
|
-
if (!
|
|
41282
|
+
if (!isRecord19(result.updates))
|
|
40336
41283
|
return result;
|
|
40337
41284
|
const {
|
|
40338
41285
|
codeSigningCertificate: _codeSigningCertificate,
|
|
@@ -40342,21 +41289,21 @@ var NOT_FOUND4 = -1, isRecord18 = (value) => typeof value === "object" && value
|
|
|
40342
41289
|
result.updates = publicUpdates;
|
|
40343
41290
|
return result;
|
|
40344
41291
|
}, 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 (!
|
|
41292
|
+
const manifest = JSON.parse(await readFile28(join61(projectRoot, "package.json"), "utf8"));
|
|
41293
|
+
if (!isRecord19(manifest))
|
|
40347
41294
|
throw new TypeError("Application package.json must contain an object.");
|
|
40348
41295
|
const names = new Set;
|
|
40349
41296
|
for (const field of ["dependencies", "devDependencies"]) {
|
|
40350
41297
|
const dependencies = Reflect.get(manifest, field);
|
|
40351
|
-
if (
|
|
41298
|
+
if (isRecord19(dependencies))
|
|
40352
41299
|
for (const name of Object.keys(dependencies))
|
|
40353
41300
|
names.add(name);
|
|
40354
41301
|
}
|
|
40355
41302
|
return names;
|
|
40356
41303
|
}, resolvedPackageVersion = async (projectRoot, packageName) => {
|
|
40357
41304
|
try {
|
|
40358
|
-
const manifest = JSON.parse(await
|
|
40359
|
-
return
|
|
41305
|
+
const manifest = JSON.parse(await readFile28(join61(projectRoot, "node_modules", packageName, "package.json"), "utf8"));
|
|
41306
|
+
return isRecord19(manifest) && typeof manifest.version === "string" ? manifest.version : undefined;
|
|
40360
41307
|
} catch {
|
|
40361
41308
|
return;
|
|
40362
41309
|
}
|
|
@@ -40397,7 +41344,7 @@ var NOT_FOUND4 = -1, isRecord18 = (value) => typeof value === "object" && value
|
|
|
40397
41344
|
}
|
|
40398
41345
|
return value;
|
|
40399
41346
|
}, capacitorExecutable = async (projectRoot) => {
|
|
40400
|
-
const executable =
|
|
41347
|
+
const executable = join61(projectRoot, "node_modules", ".bin", "cap");
|
|
40401
41348
|
try {
|
|
40402
41349
|
await access19(executable);
|
|
40403
41350
|
return executable;
|
|
@@ -40417,7 +41364,7 @@ var NOT_FOUND4 = -1, isRecord18 = (value) => typeof value === "object" && value
|
|
|
40417
41364
|
throw new TypeError(`Capacitor exited with status ${exitCode}.`);
|
|
40418
41365
|
}
|
|
40419
41366
|
}, runCapacitorForPlatforms = (projectRoot, command, platforms) => platforms.reduce((pending, platform7) => pending.then(() => runCapacitor(projectRoot, [command, platform7])), Promise.resolve()), expoExecutable = async (project) => {
|
|
40420
|
-
const executable =
|
|
41367
|
+
const executable = join61(project, "node_modules", ".bin", "expo");
|
|
40421
41368
|
try {
|
|
40422
41369
|
await access19(executable);
|
|
40423
41370
|
return executable;
|
|
@@ -40448,14 +41395,14 @@ var NOT_FOUND4 = -1, isRecord18 = (value) => typeof value === "object" && value
|
|
|
40448
41395
|
throw new TypeError(`Expo exited with status ${exitCode}.`);
|
|
40449
41396
|
}, ensureExpoPackages = async (project, args) => {
|
|
40450
41397
|
try {
|
|
40451
|
-
const manifest = JSON.parse(await
|
|
41398
|
+
const manifest = JSON.parse(await readFile28(join61(project, "package.json"), "utf8"));
|
|
40452
41399
|
const dependencies = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "dependencies") : undefined;
|
|
40453
41400
|
if (typeof dependencies !== "object" || dependencies === null || Array.isArray(dependencies))
|
|
40454
41401
|
throw new TypeError("Generated Expo dependencies are invalid.");
|
|
40455
41402
|
await Promise.all(Object.entries(dependencies).map(async ([name, expected]) => {
|
|
40456
41403
|
if (typeof expected !== "string")
|
|
40457
41404
|
throw new TypeError("Generated Expo dependency version is invalid.");
|
|
40458
|
-
const installed = JSON.parse(await
|
|
41405
|
+
const installed = JSON.parse(await readFile28(join61(project, "node_modules", name, "package.json"), "utf8"));
|
|
40459
41406
|
const actual = typeof installed === "object" && installed !== null ? Reflect.get(installed, "version") : undefined;
|
|
40460
41407
|
if (typeof actual !== "string")
|
|
40461
41408
|
throw new TypeError("Installed Expo dependency version is invalid.");
|
|
@@ -40604,6 +41551,7 @@ var NOT_FOUND4 = -1, isRecord18 = (value) => typeof value === "object" && value
|
|
|
40604
41551
|
await applyAbsoluteNativeDeviceCapabilities(projectRoot, mobile);
|
|
40605
41552
|
await applyAbsoluteNativeBackgroundSync(projectRoot, mobile);
|
|
40606
41553
|
await applyAbsoluteNativeUpdates(mobile);
|
|
41554
|
+
await applyAbsoluteNativeObservability(mobile);
|
|
40607
41555
|
}, sync = async (args) => {
|
|
40608
41556
|
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
40609
41557
|
if (mobile.engine === "expo") {
|
|
@@ -40637,6 +41585,7 @@ var NOT_FOUND4 = -1, isRecord18 = (value) => typeof value === "object" && value
|
|
|
40637
41585
|
await applyAbsoluteNativeDeviceCapabilities(projectRoot, mobile, platforms);
|
|
40638
41586
|
await applyAbsoluteNativeBackgroundSync(projectRoot, mobile, platforms);
|
|
40639
41587
|
await applyAbsoluteNativeUpdates(mobile, platforms);
|
|
41588
|
+
await applyAbsoluteNativeObservability(mobile, platforms);
|
|
40640
41589
|
}, associations = async (args) => {
|
|
40641
41590
|
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
40642
41591
|
const outputDirectory = resolve47(projectRoot, valueAfter(args, "--outdir") ?? ".absolutejs/mobile/associations");
|
|
@@ -40793,9 +41742,9 @@ Mobile release security and compliance checks failed.`);
|
|
|
40793
41742
|
temporaryDirectory: undefined
|
|
40794
41743
|
};
|
|
40795
41744
|
await ensureExpoPackages(mobile.nativeProjectDirectory, options.args);
|
|
40796
|
-
const temporaryParent =
|
|
40797
|
-
await
|
|
40798
|
-
const temporaryDirectory = await mkdtemp9(
|
|
41745
|
+
const temporaryParent = join61(options.projectRoot, ".absolutejs", "mobile", "expo-update-exports");
|
|
41746
|
+
await mkdir21(temporaryParent, { recursive: true });
|
|
41747
|
+
const temporaryDirectory = await mkdtemp9(join61(temporaryParent, ".stage-"));
|
|
40799
41748
|
try {
|
|
40800
41749
|
await runExpo(mobile.nativeProjectDirectory, [
|
|
40801
41750
|
"export",
|
|
@@ -40807,9 +41756,9 @@ Mobile release security and compliance checks failed.`);
|
|
|
40807
41756
|
temporaryDirectory,
|
|
40808
41757
|
"--clear"
|
|
40809
41758
|
], { production: true });
|
|
40810
|
-
const generatedApp = JSON.parse(await
|
|
40811
|
-
const expoConfig =
|
|
40812
|
-
if (!
|
|
41759
|
+
const generatedApp = JSON.parse(await readFile28(join61(mobile.nativeProjectDirectory, "app.json"), "utf8"));
|
|
41760
|
+
const expoConfig = isRecord19(generatedApp) ? generatedApp.expo : undefined;
|
|
41761
|
+
if (!isRecord19(expoConfig))
|
|
40813
41762
|
throw new TypeError("Generated Expo app configuration is invalid.");
|
|
40814
41763
|
const publicExpoConfig = expoPublicConfig(expoConfig);
|
|
40815
41764
|
const computedRuntime = resolveAbsoluteMobileUpdateRuntime(mobile, options.projectRoot).fingerprint;
|
|
@@ -40825,7 +41774,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
40825
41774
|
temporaryDirectory
|
|
40826
41775
|
};
|
|
40827
41776
|
} catch (error) {
|
|
40828
|
-
await
|
|
41777
|
+
await rm14(temporaryDirectory, { force: true, recursive: true });
|
|
40829
41778
|
throw error;
|
|
40830
41779
|
}
|
|
40831
41780
|
}, buildMobileUpdate = async (args) => {
|
|
@@ -40849,11 +41798,11 @@ Mobile release security and compliance checks failed.`);
|
|
|
40849
41798
|
let expoExportDirectory;
|
|
40850
41799
|
try {
|
|
40851
41800
|
await start(mobileBuildServerEntry(args), valueAfter(args, "--web-outdir"), configPath2, { prepareOnly: true });
|
|
40852
|
-
const embedded = JSON.parse(await
|
|
40853
|
-
const runtimeFingerprint =
|
|
41801
|
+
const embedded = JSON.parse(await readFile28(join61(mobile.bundleDirectory, "absolute-mobile-manifest.json"), "utf8"));
|
|
41802
|
+
const runtimeFingerprint = isRecord19(embedded) ? embedded.nativeRuntime : undefined;
|
|
40854
41803
|
if (typeof runtimeFingerprint !== "string" || !/^[a-f0-9]{64}$/u.test(runtimeFingerprint))
|
|
40855
41804
|
throw new TypeError("Prepared mobile bundle is missing its native runtime fingerprint.");
|
|
40856
|
-
const privateKey = await
|
|
41805
|
+
const privateKey = await readFile28(resolve47(projectRoot, signingKeyPath));
|
|
40857
41806
|
const configuredPublicKey = Buffer.from(mobile.updates.publicKeys[keyId], "base64");
|
|
40858
41807
|
const derivedPublicKey = createPublicKey3(privateKey).export({
|
|
40859
41808
|
format: "der",
|
|
@@ -40874,7 +41823,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
40874
41823
|
channel: mobile.updates.channel,
|
|
40875
41824
|
classification,
|
|
40876
41825
|
keyId,
|
|
40877
|
-
outputDirectory: valueAfter(args, "--outdir") ??
|
|
41826
|
+
outputDirectory: valueAfter(args, "--outdir") ?? join61(projectRoot, ".absolutejs", "mobile", "updates"),
|
|
40878
41827
|
privateKey,
|
|
40879
41828
|
runtimeFingerprint
|
|
40880
41829
|
});
|
|
@@ -40886,7 +41835,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
40886
41835
|
return result;
|
|
40887
41836
|
} finally {
|
|
40888
41837
|
if (expoExportDirectory)
|
|
40889
|
-
await
|
|
41838
|
+
await rm14(expoExportDirectory, { force: true, recursive: true });
|
|
40890
41839
|
sendTelemetryEvent("mobile:update-build", {
|
|
40891
41840
|
classification: classification ?? "invalid",
|
|
40892
41841
|
durationMs: Math.round(performance.now() - startedAt),
|
|
@@ -41147,6 +42096,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
41147
42096
|
await applyAbsoluteNativeDeviceCapabilities(projectRoot, mobile, ["ios"]);
|
|
41148
42097
|
await applyAbsoluteNativeBackgroundSync(projectRoot, mobile, ["ios"]);
|
|
41149
42098
|
await applyAbsoluteNativeUpdates(mobile, ["ios"]);
|
|
42099
|
+
await applyAbsoluteNativeObservability(mobile, ["ios"]);
|
|
41150
42100
|
}, prepareIosReleaseProject = (mobile, projectRoot, args) => mobile.engine === "expo" ? prepareExpoIosReleaseProject(mobile, projectRoot, args) : prepareCapacitorIosReleaseProject(mobile, projectRoot), prepareCapacitorAndroidReleaseProject = async (mobile, projectRoot) => {
|
|
41151
42101
|
await writeAbsoluteCapacitorConfig(mobile, { projectRoot });
|
|
41152
42102
|
await runCapacitorForPlatforms(projectRoot, "sync", ["android"]);
|
|
@@ -41156,6 +42106,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
41156
42106
|
]);
|
|
41157
42107
|
await applyAbsoluteNativeBackgroundSync(projectRoot, mobile, ["android"]);
|
|
41158
42108
|
await applyAbsoluteNativeUpdates(mobile, ["android"]);
|
|
42109
|
+
await applyAbsoluteNativeObservability(mobile, ["android"]);
|
|
41159
42110
|
}, prepareAndroidReleaseProject = (mobile, projectRoot, args) => mobile.engine === "expo" ? prepareExpoAndroidReleaseProject(mobile, projectRoot, args) : prepareCapacitorAndroidReleaseProject(mobile, projectRoot), buildAndroid = async (args, prepareVersionCode) => {
|
|
41160
42111
|
const configPath2 = valueAfter(args, "--config");
|
|
41161
42112
|
const { mobile, projectRoot } = await loadMobile(configPath2);
|
|
@@ -41183,7 +42134,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
41183
42134
|
const durationMs = Math.round(performance.now() - startedAt);
|
|
41184
42135
|
console.log(`Built ${release.metadata.signed ? "signed" : "unsigned"} Android App Bundle in ${getDurationString(durationMs)}.`);
|
|
41185
42136
|
console.log(`Artifact: ${release.artifactPath}`);
|
|
41186
|
-
console.log(`Metadata: ${
|
|
42137
|
+
console.log(`Metadata: ${join61(release.releaseRoot, "release.json")}`);
|
|
41187
42138
|
return release;
|
|
41188
42139
|
} finally {
|
|
41189
42140
|
sendTelemetryEvent("mobile:android-release-build", {
|
|
@@ -41331,7 +42282,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
41331
42282
|
const durationMs = Math.round(performance.now() - startedAt);
|
|
41332
42283
|
console.log(`Built ${release.metadata.signed ? "signed" : "unsigned"} iOS IPA ${release.metadata.marketingVersion}${release.metadata.buildNumber ? ` (${release.metadata.buildNumber})` : ""} in ${getDurationString(durationMs)}.`);
|
|
41333
42284
|
console.log(`Artifact: ${release.artifactPath}`);
|
|
41334
|
-
console.log(`Metadata: ${
|
|
42285
|
+
console.log(`Metadata: ${join61(release.releaseRoot, "release.json")}`);
|
|
41335
42286
|
return release;
|
|
41336
42287
|
} finally {
|
|
41337
42288
|
stopListeningForCancellation();
|
|
@@ -41440,7 +42391,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
41440
42391
|
checks.push({
|
|
41441
42392
|
id: "sync.storage-schema",
|
|
41442
42393
|
label: `Offline schema ${schema.components.map((component2) => `${component2.id}@${component2.version}`).join(", ")}`,
|
|
41443
|
-
path:
|
|
42394
|
+
path: join61(projectRoot, "package.json"),
|
|
41444
42395
|
platform: "host",
|
|
41445
42396
|
status: "pass"
|
|
41446
42397
|
});
|
|
@@ -41448,7 +42399,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
41448
42399
|
checks.push({
|
|
41449
42400
|
id: "sync.storage-schema",
|
|
41450
42401
|
label: "Offline schema metadata is invalid",
|
|
41451
|
-
path:
|
|
42402
|
+
path: join61(projectRoot, "package.json"),
|
|
41452
42403
|
platform: "host",
|
|
41453
42404
|
remediation: error instanceof Error ? error.message : String(error),
|
|
41454
42405
|
status: "fail"
|
|
@@ -41601,12 +42552,12 @@ Emulator setup verification:`);
|
|
|
41601
42552
|
timeoutMs
|
|
41602
42553
|
});
|
|
41603
42554
|
}, writeAndroidFailureArtifacts = async (options) => {
|
|
41604
|
-
await
|
|
41605
|
-
const screenshot = options.session ? await options.session.screenshot(
|
|
42555
|
+
await mkdir21(options.artifactRoot, { recursive: true });
|
|
42556
|
+
const screenshot = options.session ? await options.session.screenshot(join61(options.artifactRoot, "android-failure.png")).catch(() => {
|
|
41606
42557
|
return;
|
|
41607
42558
|
}) : undefined;
|
|
41608
|
-
const diagnosticPath =
|
|
41609
|
-
await
|
|
42559
|
+
const diagnosticPath = join61(options.artifactRoot, "android-failure.json");
|
|
42560
|
+
await writeFile23(diagnosticPath, `${JSON.stringify({
|
|
41610
42561
|
diagnostics: options.session?.diagnostics ?? [],
|
|
41611
42562
|
error: options.error instanceof Error ? options.error.message : String(options.error),
|
|
41612
42563
|
platform: "android",
|
|
@@ -41670,7 +42621,7 @@ Emulator setup verification:`);
|
|
|
41670
42621
|
console.log(JSON.stringify(report, null, 2));
|
|
41671
42622
|
else
|
|
41672
42623
|
printAndroidTestReport(report);
|
|
41673
|
-
const screenshot = reportRoot ? await session.screenshot(
|
|
42624
|
+
const screenshot = reportRoot ? await session.screenshot(join61(artifactRoot, "android-emulator.png")) : undefined;
|
|
41674
42625
|
await writeRequestedAndroidReport({
|
|
41675
42626
|
adb,
|
|
41676
42627
|
args,
|
|
@@ -41762,7 +42713,7 @@ Emulator setup verification:`);
|
|
|
41762
42713
|
return;
|
|
41763
42714
|
});
|
|
41764
42715
|
const status2 = response?.ok ? await response.json().catch(() => null) : null;
|
|
41765
|
-
const targets =
|
|
42716
|
+
const targets = isRecord19(status2) && isRecord19(status2.connectedTargets) ? status2.connectedTargets : undefined;
|
|
41766
42717
|
if (targets && typeof targets["capacitor-ios"] === "number" && targets["capacitor-ios"] > 0)
|
|
41767
42718
|
return;
|
|
41768
42719
|
await Bun.sleep(100);
|
|
@@ -41859,8 +42810,8 @@ Emulator setup verification:`);
|
|
|
41859
42810
|
throw new Error(`${label} failed: ${result.stderr.trim() || result.stdout.trim() || `status ${result.exitCode}`}`);
|
|
41860
42811
|
return result;
|
|
41861
42812
|
}, writeIosFailureArtifacts = async (options) => {
|
|
41862
|
-
await
|
|
41863
|
-
const screenshot =
|
|
42813
|
+
await mkdir21(options.artifactRoot, { recursive: true });
|
|
42814
|
+
const screenshot = join61(options.artifactRoot, "ios-failure.png");
|
|
41864
42815
|
const screenshotResult = captureCommand4([
|
|
41865
42816
|
options.xcrun,
|
|
41866
42817
|
"simctl",
|
|
@@ -41869,8 +42820,8 @@ Emulator setup verification:`);
|
|
|
41869
42820
|
"screenshot",
|
|
41870
42821
|
screenshot
|
|
41871
42822
|
]);
|
|
41872
|
-
const diagnosticPath =
|
|
41873
|
-
await
|
|
42823
|
+
const diagnosticPath = join61(options.artifactRoot, "ios-failure.json");
|
|
42824
|
+
await writeFile23(diagnosticPath, `${JSON.stringify({
|
|
41874
42825
|
appId: options.appId,
|
|
41875
42826
|
error: options.error instanceof Error ? options.error.message : String(options.error),
|
|
41876
42827
|
platform: "ios",
|
|
@@ -42115,8 +43066,8 @@ Emulator setup verification:`);
|
|
|
42115
43066
|
mobile.appId
|
|
42116
43067
|
], "iOS app launch");
|
|
42117
43068
|
await waitForIosHmrClient({ https, port, timeoutMs });
|
|
42118
|
-
await
|
|
42119
|
-
const screenshot =
|
|
43069
|
+
await mkdir21(artifactRoot, { recursive: true });
|
|
43070
|
+
const screenshot = join61(artifactRoot, "ios-simulator.png");
|
|
42120
43071
|
requireCapturedCommand([xcrun, "simctl", "io", simulator.udid, "screenshot", screenshot], "iOS simulator screenshot");
|
|
42121
43072
|
const hmrApply = await waitForRequestedIosHmr(args, instance, timeoutMs);
|
|
42122
43073
|
const report = {
|
|
@@ -42292,6 +43243,7 @@ var init_mobile = __esm(() => {
|
|
|
42292
43243
|
init_nativeDeviceCapabilities();
|
|
42293
43244
|
init_nativeBackgroundSync();
|
|
42294
43245
|
init_nativeUpdates();
|
|
43246
|
+
init_nativeObservability();
|
|
42295
43247
|
init_emulatorDoctor();
|
|
42296
43248
|
init_emulatorInstaller();
|
|
42297
43249
|
init_associationFiles();
|
|
@@ -42359,9 +43311,9 @@ var exports_typecheck = {};
|
|
|
42359
43311
|
__export(exports_typecheck, {
|
|
42360
43312
|
typecheck: () => typecheck
|
|
42361
43313
|
});
|
|
42362
|
-
import { resolve as resolve48, join as
|
|
43314
|
+
import { resolve as resolve48, join as join62 } from "path";
|
|
42363
43315
|
import { existsSync as existsSync44, readFileSync as readFileSync41 } from "fs";
|
|
42364
|
-
import { mkdir as
|
|
43316
|
+
import { mkdir as mkdir22, writeFile as writeFile24 } from "fs/promises";
|
|
42365
43317
|
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
43318
|
if (!existsSync44(resolveConfigPath(configPath2))) {
|
|
42367
43319
|
const defaultService = {};
|
|
@@ -42468,8 +43420,8 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42468
43420
|
console.error("\x1B[31m\u2717\x1B[0m vue-tsc is required for Vue type checking. Install it: bun add -d vue-tsc");
|
|
42469
43421
|
process.exit(1);
|
|
42470
43422
|
}
|
|
42471
|
-
const vueTsconfigPath =
|
|
42472
|
-
await
|
|
43423
|
+
const vueTsconfigPath = join62(cacheDir, "tsconfig.vue-check.json");
|
|
43424
|
+
await writeFile24(vueTsconfigPath, JSON.stringify({
|
|
42473
43425
|
compilerOptions: {
|
|
42474
43426
|
rootDir: ".."
|
|
42475
43427
|
},
|
|
@@ -42488,7 +43440,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42488
43440
|
...base,
|
|
42489
43441
|
"--incremental",
|
|
42490
43442
|
"--tsBuildInfoFile",
|
|
42491
|
-
|
|
43443
|
+
join62(cacheDir, "vue-tsc.tsbuildinfo")
|
|
42492
43444
|
]);
|
|
42493
43445
|
if (cached.exitCode === 0 || cached.output.length > 0)
|
|
42494
43446
|
return cached;
|
|
@@ -42499,8 +43451,8 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42499
43451
|
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
43452
|
process.exit(1);
|
|
42501
43453
|
}
|
|
42502
|
-
const angularTsconfigPath =
|
|
42503
|
-
await
|
|
43454
|
+
const angularTsconfigPath = join62(cacheDir, "tsconfig.angular-check.json");
|
|
43455
|
+
await writeFile24(angularTsconfigPath, JSON.stringify({
|
|
42504
43456
|
angularCompilerOptions: {
|
|
42505
43457
|
strictTemplates: true
|
|
42506
43458
|
},
|
|
@@ -42519,8 +43471,8 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42519
43471
|
console.error("\x1B[31m\u2717\x1B[0m typescript is required for type checking. Install it: bun add -d typescript");
|
|
42520
43472
|
process.exit(1);
|
|
42521
43473
|
}
|
|
42522
|
-
const tscConfigPath =
|
|
42523
|
-
return
|
|
43474
|
+
const tscConfigPath = join62(cacheDir, "tsconfig.typecheck.json");
|
|
43475
|
+
return writeFile24(tscConfigPath, JSON.stringify({
|
|
42524
43476
|
compilerOptions: {
|
|
42525
43477
|
rootDir: ".."
|
|
42526
43478
|
},
|
|
@@ -42534,7 +43486,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42534
43486
|
resolve48(tscConfigPath),
|
|
42535
43487
|
"--incremental",
|
|
42536
43488
|
"--tsBuildInfoFile",
|
|
42537
|
-
|
|
43489
|
+
join62(cacheDir, "tsc.tsbuildinfo"),
|
|
42538
43490
|
"--pretty"
|
|
42539
43491
|
]));
|
|
42540
43492
|
}, buildSvelteCheck = async (cacheDir, svelteDir) => {
|
|
@@ -42543,8 +43495,8 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42543
43495
|
console.error("\x1B[31m\u2717\x1B[0m svelte-check is required for Svelte type checking. Install it: bun add -d svelte-check");
|
|
42544
43496
|
process.exit(1);
|
|
42545
43497
|
}
|
|
42546
|
-
const svelteTsconfigPath =
|
|
42547
|
-
await
|
|
43498
|
+
const svelteTsconfigPath = join62(cacheDir, "tsconfig.svelte-check.json");
|
|
43499
|
+
await writeFile24(svelteTsconfigPath, JSON.stringify({
|
|
42548
43500
|
extends: resolve48("tsconfig.json"),
|
|
42549
43501
|
files: ABSOLUTE_TYPECHECK_FILES,
|
|
42550
43502
|
include: [`../${svelteDir}/**/*`]
|
|
@@ -42573,7 +43525,7 @@ Found ${errorCount} error${suffix}.`;
|
|
|
42573
43525
|
...new Set(targets.map((config) => config.angularDirectory).filter((dir) => typeof dir === "string" && dir.length > 0))
|
|
42574
43526
|
];
|
|
42575
43527
|
const cacheDir = ".absolutejs";
|
|
42576
|
-
await
|
|
43528
|
+
await mkdir22(cacheDir, { recursive: true });
|
|
42577
43529
|
const checks = [];
|
|
42578
43530
|
checks.push(hasVue ? buildVueTscCheck(cacheDir) : buildTscCheck(cacheDir));
|
|
42579
43531
|
for (const svelteDir of hasSvelte ? svelteDirs : []) {
|
|
@@ -42802,7 +43754,7 @@ import {
|
|
|
42802
43754
|
writeFileSync as writeFileSync4
|
|
42803
43755
|
} from "fs";
|
|
42804
43756
|
import { tmpdir as tmpdir2 } from "os";
|
|
42805
|
-
import { join as
|
|
43757
|
+
import { join as join18, resolve as resolvePath2 } from "path";
|
|
42806
43758
|
|
|
42807
43759
|
// src/dev/tunnel/client.ts
|
|
42808
43760
|
var RECONNECT_DELAY_MS = 2000;
|
|
@@ -43312,7 +44264,7 @@ init_expoProject();
|
|
|
43312
44264
|
init_iosPhysicalDeviceTransport();
|
|
43313
44265
|
import { spawn } from "child_process";
|
|
43314
44266
|
import { access as access2 } from "fs/promises";
|
|
43315
|
-
import { join as
|
|
44267
|
+
import { join as join10 } from "path";
|
|
43316
44268
|
var METRO_READY_TIMEOUT_MS = 60000;
|
|
43317
44269
|
var PROCESS_CLOSE_TIMEOUT_MS = 2000;
|
|
43318
44270
|
var commandEnvironment = (options) => ({
|
|
@@ -43325,7 +44277,7 @@ var commandEnvironment = (options) => ({
|
|
|
43325
44277
|
...options.metroHost ? { REACT_NATIVE_PACKAGER_HOSTNAME: options.metroHost } : {}
|
|
43326
44278
|
});
|
|
43327
44279
|
var absoluteExpoExecutable = async (project) => {
|
|
43328
|
-
const executable =
|
|
44280
|
+
const executable = join10(project, "node_modules", ".bin", "expo");
|
|
43329
44281
|
try {
|
|
43330
44282
|
await access2(executable);
|
|
43331
44283
|
return executable;
|
|
@@ -44077,7 +45029,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
44077
45029
|
const generated = await writeAbsoluteExpoProject(normalized, {
|
|
44078
45030
|
projectRoot: process.cwd()
|
|
44079
45031
|
});
|
|
44080
|
-
const dependenciesReady = existsSync6(
|
|
45032
|
+
const dependenciesReady = existsSync6(join18(generated.path, "node_modules", "expo", "package.json")) && existsSync6(join18(generated.path, "node_modules", "expo-dev-client", "package.json"));
|
|
44081
45033
|
if (!dependenciesReady) {
|
|
44082
45034
|
const install = await confirmPrompt("Expo development dependencies are missing. Install the pinned SDK 57 development client now?");
|
|
44083
45035
|
if (!install) {
|
|
@@ -44156,7 +45108,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
44156
45108
|
}
|
|
44157
45109
|
}
|
|
44158
45110
|
if (ready) {
|
|
44159
|
-
const nativeDirectory =
|
|
45111
|
+
const nativeDirectory = join18(normalized.nativeProjectDirectory, "android");
|
|
44160
45112
|
let createNativeProject = false;
|
|
44161
45113
|
if (!existsSync6(nativeDirectory)) {
|
|
44162
45114
|
createNativeProject = await confirmPrompt("Create the managed Capacitor Android project now?");
|
|
@@ -44176,7 +45128,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
44176
45128
|
if (!remote) {
|
|
44177
45129
|
console.log(cliTag("\x1B[33m", "iOS target skipped. Pair a Mac with `absolute mobile pair mac <name> <user@host>`."));
|
|
44178
45130
|
} else {
|
|
44179
|
-
const nativeDirectory =
|
|
45131
|
+
const nativeDirectory = join18(normalized.nativeProjectDirectory, "ios");
|
|
44180
45132
|
if (!existsSync6(nativeDirectory)) {
|
|
44181
45133
|
console.log(cliTag("\x1B[33m", "The iOS project is missing. Run `absolute mobile init` before remote development."));
|
|
44182
45134
|
} else {
|
|
@@ -44197,7 +45149,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
44197
45149
|
}
|
|
44198
45150
|
}
|
|
44199
45151
|
if (ready) {
|
|
44200
|
-
const nativeDirectory =
|
|
45152
|
+
const nativeDirectory = join18(normalized.nativeProjectDirectory, "ios");
|
|
44201
45153
|
let createNativeProject = false;
|
|
44202
45154
|
if (!existsSync6(nativeDirectory)) {
|
|
44203
45155
|
createNativeProject = await confirmPrompt("Create the managed Capacitor iOS project now?");
|
|
@@ -44855,7 +45807,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
44855
45807
|
}
|
|
44856
45808
|
return merged;
|
|
44857
45809
|
};
|
|
44858
|
-
const heapPreloadPath =
|
|
45810
|
+
const heapPreloadPath = join18(tmpdir2(), `absolute-heap-${process.pid}.ts`);
|
|
44859
45811
|
let heapSnapshotEnabled = false;
|
|
44860
45812
|
try {
|
|
44861
45813
|
writeFileSync4(heapPreloadPath, DEV_CHILD_PRELOAD);
|
|
@@ -44988,7 +45940,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
44988
45940
|
if (now - last < 100)
|
|
44989
45941
|
return;
|
|
44990
45942
|
recentlyHandled.set(filename, now);
|
|
44991
|
-
scheduleServerRestart(
|
|
45943
|
+
scheduleServerRestart(join18(serverEntryDir, filename));
|
|
44992
45944
|
};
|
|
44993
45945
|
const recoveryScan = async () => {
|
|
44994
45946
|
let entries;
|
|
@@ -45007,7 +45959,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
45007
45959
|
continue;
|
|
45008
45960
|
let fileStat;
|
|
45009
45961
|
try {
|
|
45010
|
-
fileStat = statSync(
|
|
45962
|
+
fileStat = statSync(join18(serverEntryDir, entry.name));
|
|
45011
45963
|
} catch {
|
|
45012
45964
|
continue;
|
|
45013
45965
|
}
|
|
@@ -45541,7 +46493,7 @@ var info = () => {
|
|
|
45541
46493
|
// src/cli/cache.ts
|
|
45542
46494
|
init_constants();
|
|
45543
46495
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
45544
|
-
import { join as
|
|
46496
|
+
import { join as join19 } from "path";
|
|
45545
46497
|
var {Glob } = globalThis.Bun;
|
|
45546
46498
|
var CACHE_DIR = ".absolutejs";
|
|
45547
46499
|
var MAX_FILES_PER_BATCH = 200;
|
|
@@ -45593,7 +46545,7 @@ var hashFiles = async (paths) => {
|
|
|
45593
46545
|
};
|
|
45594
46546
|
var loadCache = async (tool) => {
|
|
45595
46547
|
try {
|
|
45596
|
-
const path =
|
|
46548
|
+
const path = join19(CACHE_DIR, `${tool}.cache.json`);
|
|
45597
46549
|
const data = await Bun.file(path).json();
|
|
45598
46550
|
const result = data;
|
|
45599
46551
|
return result;
|
|
@@ -45640,7 +46592,7 @@ var runTool = async (adapter, args) => {
|
|
|
45640
46592
|
};
|
|
45641
46593
|
var saveCache = async (tool, data) => {
|
|
45642
46594
|
await mkdir7(CACHE_DIR, { recursive: true });
|
|
45643
|
-
const path =
|
|
46595
|
+
const path = join19(CACHE_DIR, `${tool}.cache.json`);
|
|
45644
46596
|
await Bun.write(path, JSON.stringify(data, null, "\t"));
|
|
45645
46597
|
};
|
|
45646
46598
|
|