@absolutejs/absolute 0.20.0-beta.67 → 0.20.0-beta.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/cli/index.js +1581 -577
- package/dist/mobile/index.js +1789 -190
- package/dist/mobile/index.js.map +9 -5
- package/dist/mobile/remoteMacAgentEntry.js +580 -209
- package/dist/mobile/shellBootstrap.js +152 -0
- package/dist/src/mobile/expoNativeObservability.d.ts +3 -0
- package/dist/src/mobile/index.d.ts +3 -0
- package/dist/src/mobile/nativeObservability.d.ts +4 -0
- package/dist/src/mobile/shellNativeObservability.d.ts +21 -0
- package/package.json +8 -7
package/dist/mobile/index.js
CHANGED
|
@@ -17893,7 +17893,7 @@ var require_main = __commonJS(function(exports) {
|
|
|
17893
17893
|
// src/cli/scripts/telemetry.ts
|
|
17894
17894
|
import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync6, writeFileSync } from "fs";
|
|
17895
17895
|
import { homedir as homedir3 } from "os";
|
|
17896
|
-
import { join as
|
|
17896
|
+
import { join as join19 } from "path";
|
|
17897
17897
|
var configDir, configPath, getTelemetryConfig = () => {
|
|
17898
17898
|
try {
|
|
17899
17899
|
if (!existsSync5(configPath))
|
|
@@ -17906,14 +17906,14 @@ var configDir, configPath, getTelemetryConfig = () => {
|
|
|
17906
17906
|
}
|
|
17907
17907
|
};
|
|
17908
17908
|
var init_telemetry = __esm(() => {
|
|
17909
|
-
configDir =
|
|
17910
|
-
configPath =
|
|
17909
|
+
configDir = join19(homedir3(), ".absolutejs");
|
|
17910
|
+
configPath = join19(configDir, "telemetry.json");
|
|
17911
17911
|
});
|
|
17912
17912
|
|
|
17913
17913
|
// src/cli/telemetryEvent.ts
|
|
17914
17914
|
import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
17915
17915
|
import { arch, platform as platform3 } from "os";
|
|
17916
|
-
import { dirname as dirname14, join as
|
|
17916
|
+
import { dirname as dirname14, join as join20, parse } from "path";
|
|
17917
17917
|
var checkCandidate = (candidate) => {
|
|
17918
17918
|
if (!existsSync6(candidate)) {
|
|
17919
17919
|
return null;
|
|
@@ -17933,7 +17933,7 @@ var checkCandidate = (candidate) => {
|
|
|
17933
17933
|
}, findPackageVersion = () => {
|
|
17934
17934
|
let { dir } = import.meta;
|
|
17935
17935
|
while (dir !== parse(dir).root) {
|
|
17936
|
-
const candidate =
|
|
17936
|
+
const candidate = join20(dir, "package.json");
|
|
17937
17937
|
const version = checkCandidate(candidate);
|
|
17938
17938
|
if (version) {
|
|
17939
17939
|
return version;
|
|
@@ -24092,7 +24092,7 @@ var parseAbsoluteMobileBuildPageMetadata = (value) => {
|
|
|
24092
24092
|
};
|
|
24093
24093
|
// src/mobile/buildPipeline.ts
|
|
24094
24094
|
import { readFile as readFile15 } from "fs/promises";
|
|
24095
|
-
import { join as
|
|
24095
|
+
import { join as join16, resolve as resolve13 } from "path";
|
|
24096
24096
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
24097
24097
|
|
|
24098
24098
|
// src/mobile/buildRelease.ts
|
|
@@ -25330,7 +25330,7 @@ import {
|
|
|
25330
25330
|
writeFile as writeFile12
|
|
25331
25331
|
} from "fs/promises";
|
|
25332
25332
|
import { createHash as createHash12 } from "crypto";
|
|
25333
|
-
import { basename as basename4, dirname as dirname10, join as
|
|
25333
|
+
import { basename as basename4, dirname as dirname10, join as join15, relative as relative10, resolve as resolve12, sep as sep6 } from "path";
|
|
25334
25334
|
|
|
25335
25335
|
// src/mobile/updateRuntime.ts
|
|
25336
25336
|
init_deviceCapabilities();
|
|
@@ -25498,6 +25498,426 @@ var resolveAbsoluteMobileUpdateRuntime = (config, projectRoot) => {
|
|
|
25498
25498
|
};
|
|
25499
25499
|
};
|
|
25500
25500
|
|
|
25501
|
+
// src/mobile/expoNativeObservability.ts
|
|
25502
|
+
import { join as join14 } from "path";
|
|
25503
|
+
var HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
|
|
25504
|
+
`;
|
|
25505
|
+
var moduleConfig = `${JSON.stringify({
|
|
25506
|
+
android: {
|
|
25507
|
+
modules: [
|
|
25508
|
+
"expo.modules.absolutemobileobservability.AbsoluteMobileObservabilityModule"
|
|
25509
|
+
]
|
|
25510
|
+
},
|
|
25511
|
+
apple: { modules: ["AbsoluteMobileObservabilityModule"] },
|
|
25512
|
+
platforms: ["apple", "android"]
|
|
25513
|
+
}, null, 2)}
|
|
25514
|
+
`;
|
|
25515
|
+
var podspec = `${HEADER}Pod::Spec.new do |s|
|
|
25516
|
+
s.name = 'AbsoluteMobileObservability'
|
|
25517
|
+
s.version = '0.0.1'
|
|
25518
|
+
s.summary = 'AbsoluteJS provider-neutral native process diagnostics'
|
|
25519
|
+
s.description = 'Generated MetricKit bridge for an AbsoluteJS Expo application.'
|
|
25520
|
+
s.author = 'AbsoluteJS'
|
|
25521
|
+
s.homepage = 'https://absolutejs.com'
|
|
25522
|
+
s.platforms = { :ios => '16.4' }
|
|
25523
|
+
s.source = { git: '' }
|
|
25524
|
+
s.static_framework = true
|
|
25525
|
+
s.dependency 'ExpoModulesCore'
|
|
25526
|
+
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
|
|
25527
|
+
s.source_files = '**/*.{h,m,mm,swift,hpp,cpp}'
|
|
25528
|
+
end
|
|
25529
|
+
`;
|
|
25530
|
+
var iosModule = `${HEADER}import ExpoModulesCore
|
|
25531
|
+
import MetricKit
|
|
25532
|
+
|
|
25533
|
+
public final class AbsoluteMobileObservabilityModule: Module, MXMetricManagerSubscriber {
|
|
25534
|
+
private static let maximumReports = 8
|
|
25535
|
+
private static let maximumReportBytes = 64 * 1024
|
|
25536
|
+
private static let queue = DispatchQueue(label: "dev.absolute.expo-mobile-observability")
|
|
25537
|
+
|
|
25538
|
+
public func definition() -> ModuleDefinition {
|
|
25539
|
+
Name("AbsoluteMobileObservability")
|
|
25540
|
+
|
|
25541
|
+
OnCreate { MXMetricManager.shared.add(self) }
|
|
25542
|
+
OnDestroy { MXMetricManager.shared.remove(self) }
|
|
25543
|
+
|
|
25544
|
+
AsyncFunction("pending") { () -> [String: Any] in
|
|
25545
|
+
Self.queue.sync {
|
|
25546
|
+
let reports: [[String: Any]] = Self.files().compactMap { file in
|
|
25547
|
+
guard let data = try? Data(contentsOf: file),
|
|
25548
|
+
let value = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return nil }
|
|
25549
|
+
return value
|
|
25550
|
+
}
|
|
25551
|
+
return ["reports": reports]
|
|
25552
|
+
}
|
|
25553
|
+
}
|
|
25554
|
+
|
|
25555
|
+
AsyncFunction("acknowledge") { (options: [String: Any]) in
|
|
25556
|
+
let accepted = Set(options["ids"] as? [String] ?? [])
|
|
25557
|
+
Self.queue.sync {
|
|
25558
|
+
for file in Self.files() {
|
|
25559
|
+
guard let data = try? Data(contentsOf: file),
|
|
25560
|
+
let value = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
|
25561
|
+
let id = value["id"] as? String,
|
|
25562
|
+
accepted.contains(id) else { continue }
|
|
25563
|
+
try? FileManager.default.removeItem(at: file)
|
|
25564
|
+
}
|
|
25565
|
+
}
|
|
25566
|
+
}
|
|
25567
|
+
}
|
|
25568
|
+
|
|
25569
|
+
private static func root() -> URL? {
|
|
25570
|
+
guard let support = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first else { return nil }
|
|
25571
|
+
let root = support.appendingPathComponent("AbsoluteMobileObservability", isDirectory: true)
|
|
25572
|
+
try? FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)
|
|
25573
|
+
return root
|
|
25574
|
+
}
|
|
25575
|
+
|
|
25576
|
+
private static func files() -> [URL] {
|
|
25577
|
+
guard let root = root() else { return [] }
|
|
25578
|
+
return ((try? FileManager.default.contentsOfDirectory(at: root, includingPropertiesForKeys: nil)) ?? [])
|
|
25579
|
+
.filter { $0.pathExtension == "json" }
|
|
25580
|
+
.sorted { $0.lastPathComponent < $1.lastPathComponent }
|
|
25581
|
+
}
|
|
25582
|
+
|
|
25583
|
+
private static func enqueue(kind: String, occurredAt: Double, details: [AnyHashable: Any]) {
|
|
25584
|
+
guard let root = root() else { return }
|
|
25585
|
+
let id = UUID().uuidString.lowercased()
|
|
25586
|
+
var report: [String: Any] = [
|
|
25587
|
+
"details": Dictionary(uniqueKeysWithValues: details.map { (String(describing: $0.key), $0.value) }),
|
|
25588
|
+
"id": id,
|
|
25589
|
+
"kind": kind,
|
|
25590
|
+
"occurredAt": occurredAt,
|
|
25591
|
+
"platform": "ios"
|
|
25592
|
+
]
|
|
25593
|
+
guard JSONSerialization.isValidJSONObject(report),
|
|
25594
|
+
let original = try? JSONSerialization.data(withJSONObject: report) else { return }
|
|
25595
|
+
if original.count > maximumReportBytes {
|
|
25596
|
+
report["details"] = [
|
|
25597
|
+
"diagnosticPrefix": String(decoding: original.prefix(24 * 1024), as: UTF8.self),
|
|
25598
|
+
"originalBytes": original.count,
|
|
25599
|
+
"truncated": true
|
|
25600
|
+
]
|
|
25601
|
+
}
|
|
25602
|
+
guard let data = try? JSONSerialization.data(withJSONObject: report),
|
|
25603
|
+
data.count <= maximumReportBytes else { return }
|
|
25604
|
+
let timestamp = String(format: "%013.0f", occurredAt)
|
|
25605
|
+
try? data.write(to: root.appendingPathComponent("\\(timestamp)-\\(id).json"), options: .atomic)
|
|
25606
|
+
let overflow = max(0, files().count - maximumReports)
|
|
25607
|
+
for file in files().prefix(overflow) { try? FileManager.default.removeItem(at: file) }
|
|
25608
|
+
}
|
|
25609
|
+
|
|
25610
|
+
public func didReceive(_ payloads: [MXDiagnosticPayload]) {
|
|
25611
|
+
Self.queue.async {
|
|
25612
|
+
for payload in payloads {
|
|
25613
|
+
let at = payload.timeStampEnd.timeIntervalSince1970 * 1000
|
|
25614
|
+
for value in payload.crashDiagnostics ?? [] { Self.enqueue(kind: "crash", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
25615
|
+
for value in payload.hangDiagnostics ?? [] { Self.enqueue(kind: "hang", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
25616
|
+
for value in payload.cpuExceptionDiagnostics ?? [] { Self.enqueue(kind: "cpu-exception", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
25617
|
+
for value in payload.diskWriteExceptionDiagnostics ?? [] { Self.enqueue(kind: "disk-write-exception", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
25618
|
+
if #available(iOS 16.0, *) {
|
|
25619
|
+
for value in payload.appLaunchDiagnostics ?? [] { Self.enqueue(kind: "app-launch", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
25620
|
+
}
|
|
25621
|
+
}
|
|
25622
|
+
}
|
|
25623
|
+
}
|
|
25624
|
+
}
|
|
25625
|
+
`;
|
|
25626
|
+
var androidBuild = `${HEADER}plugins {
|
|
25627
|
+
id 'com.android.library'
|
|
25628
|
+
id 'expo-module-gradle-plugin'
|
|
25629
|
+
}
|
|
25630
|
+
|
|
25631
|
+
group = 'expo.modules.absolutemobileobservability'
|
|
25632
|
+
version = '0.0.1'
|
|
25633
|
+
|
|
25634
|
+
android {
|
|
25635
|
+
namespace 'expo.modules.absolutemobileobservability'
|
|
25636
|
+
defaultConfig {
|
|
25637
|
+
versionCode 1
|
|
25638
|
+
versionName '0.0.1'
|
|
25639
|
+
}
|
|
25640
|
+
lintOptions { abortOnError false }
|
|
25641
|
+
}
|
|
25642
|
+
`;
|
|
25643
|
+
var androidManifest = `${HEADER}<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
|
25644
|
+
`;
|
|
25645
|
+
var androidModule = `${HEADER}package expo.modules.absolutemobileobservability
|
|
25646
|
+
|
|
25647
|
+
import android.app.ActivityManager
|
|
25648
|
+
import android.app.ApplicationExitInfo
|
|
25649
|
+
import android.os.Build
|
|
25650
|
+
import android.util.Base64
|
|
25651
|
+
import expo.modules.kotlin.modules.Module
|
|
25652
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
25653
|
+
import java.io.ByteArrayOutputStream
|
|
25654
|
+
import java.io.File
|
|
25655
|
+
import java.io.FileInputStream
|
|
25656
|
+
import java.io.FileOutputStream
|
|
25657
|
+
import java.io.InputStream
|
|
25658
|
+
import java.nio.charset.StandardCharsets
|
|
25659
|
+
import java.util.UUID
|
|
25660
|
+
import org.json.JSONArray
|
|
25661
|
+
import org.json.JSONObject
|
|
25662
|
+
|
|
25663
|
+
class AbsoluteMobileObservabilityModule : Module() {
|
|
25664
|
+
companion object {
|
|
25665
|
+
private const val MAX_REPORTS = 8
|
|
25666
|
+
private const val MAX_TRACE_BYTES = 32 * 1024
|
|
25667
|
+
private const val ACKNOWLEDGED_KEY = "acknowledged"
|
|
25668
|
+
private const val PREFERENCES = "AbsoluteMobileObservability"
|
|
25669
|
+
}
|
|
25670
|
+
|
|
25671
|
+
override fun definition() = ModuleDefinition {
|
|
25672
|
+
Name("AbsoluteMobileObservability")
|
|
25673
|
+
|
|
25674
|
+
AsyncFunction("pending") {
|
|
25675
|
+
collect()
|
|
25676
|
+
mapOf("reports" to files().mapNotNull { readReport(it) })
|
|
25677
|
+
}
|
|
25678
|
+
|
|
25679
|
+
AsyncFunction("acknowledge") { options: Map<String, List<String>> ->
|
|
25680
|
+
val accepted = options["ids"]?.toSet() ?: emptySet()
|
|
25681
|
+
val acknowledged = acknowledged().toMutableSet()
|
|
25682
|
+
files().forEach { file ->
|
|
25683
|
+
val report = readReport(file)
|
|
25684
|
+
val id = report?.get("id") as? String
|
|
25685
|
+
if (id != null && accepted.contains(id)) {
|
|
25686
|
+
acknowledged.add(id)
|
|
25687
|
+
file.delete()
|
|
25688
|
+
}
|
|
25689
|
+
}
|
|
25690
|
+
writeAcknowledged(acknowledged)
|
|
25691
|
+
}
|
|
25692
|
+
}
|
|
25693
|
+
|
|
25694
|
+
private fun context() = appContext.reactContext
|
|
25695
|
+
|
|
25696
|
+
private fun root(): File? {
|
|
25697
|
+
val context = context() ?: return null
|
|
25698
|
+
return File(context.filesDir, "absolute-mobile-observability").also { it.mkdirs() }
|
|
25699
|
+
}
|
|
25700
|
+
|
|
25701
|
+
private fun files(): List<File> = root()?.listFiles { _, name -> name.endsWith(".json") }
|
|
25702
|
+
?.sortedBy { it.name } ?: emptyList()
|
|
25703
|
+
|
|
25704
|
+
private fun acknowledged(): Set<String> {
|
|
25705
|
+
val context = context() ?: return emptySet()
|
|
25706
|
+
return try {
|
|
25707
|
+
val values = JSONArray(context.getSharedPreferences(PREFERENCES, 0).getString(ACKNOWLEDGED_KEY, "[]"))
|
|
25708
|
+
(0 until values.length()).map { values.optString(it) }.toSet()
|
|
25709
|
+
} catch (_: Exception) { emptySet() }
|
|
25710
|
+
}
|
|
25711
|
+
|
|
25712
|
+
private fun writeAcknowledged(values: Set<String>) {
|
|
25713
|
+
val context = context() ?: return
|
|
25714
|
+
val bounded = values.sorted().takeLast(64)
|
|
25715
|
+
context.getSharedPreferences(PREFERENCES, 0).edit()
|
|
25716
|
+
.putString(ACKNOWLEDGED_KEY, JSONArray(bounded).toString()).apply()
|
|
25717
|
+
}
|
|
25718
|
+
|
|
25719
|
+
private fun kind(reason: Int): String? = when (reason) {
|
|
25720
|
+
ApplicationExitInfo.REASON_ANR -> "anr"
|
|
25721
|
+
ApplicationExitInfo.REASON_CRASH -> "crash"
|
|
25722
|
+
ApplicationExitInfo.REASON_CRASH_NATIVE -> "native-crash"
|
|
25723
|
+
ApplicationExitInfo.REASON_LOW_MEMORY -> "low-memory"
|
|
25724
|
+
ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE -> "resource-exhaustion"
|
|
25725
|
+
ApplicationExitInfo.REASON_INITIALIZATION_FAILURE -> "initialization-failure"
|
|
25726
|
+
ApplicationExitInfo.REASON_SIGNALED -> "signal"
|
|
25727
|
+
else -> null
|
|
25728
|
+
}
|
|
25729
|
+
|
|
25730
|
+
private fun trace(info: ApplicationExitInfo): ByteArray? = try {
|
|
25731
|
+
info.traceInputStream?.use { input ->
|
|
25732
|
+
val output = ByteArrayOutputStream()
|
|
25733
|
+
val buffer = ByteArray(4096)
|
|
25734
|
+
var total = 0
|
|
25735
|
+
while (true) {
|
|
25736
|
+
val count = input.read(buffer, 0, minOf(buffer.size, MAX_TRACE_BYTES + 1 - total))
|
|
25737
|
+
if (count <= 0) break
|
|
25738
|
+
output.write(buffer, 0, count)
|
|
25739
|
+
total += count
|
|
25740
|
+
if (total > MAX_TRACE_BYTES) return null
|
|
25741
|
+
}
|
|
25742
|
+
output.toByteArray()
|
|
25743
|
+
}
|
|
25744
|
+
} catch (_: Exception) { null }
|
|
25745
|
+
|
|
25746
|
+
private fun report(info: ApplicationExitInfo): JSONObject? {
|
|
25747
|
+
val kind = kind(info.reason) ?: return null
|
|
25748
|
+
val id = "android:" + info.timestamp + ":" + info.reason + ":" + info.status
|
|
25749
|
+
return try {
|
|
25750
|
+
val details = JSONObject()
|
|
25751
|
+
.put("importance", info.importance)
|
|
25752
|
+
.put("pssKb", info.pss)
|
|
25753
|
+
.put("reason", info.reason)
|
|
25754
|
+
.put("rssKb", info.rss)
|
|
25755
|
+
.put("status", info.status)
|
|
25756
|
+
info.description?.let { details.put("description", it) }
|
|
25757
|
+
trace(info)?.takeIf { it.isNotEmpty() }?.let { trace ->
|
|
25758
|
+
if (info.reason == ApplicationExitInfo.REASON_CRASH_NATIVE) {
|
|
25759
|
+
details.put("trace", Base64.encodeToString(trace, Base64.NO_WRAP))
|
|
25760
|
+
details.put("traceEncoding", "android-tombstone-protobuf-base64")
|
|
25761
|
+
} else {
|
|
25762
|
+
details.put("trace", String(trace, StandardCharsets.UTF_8))
|
|
25763
|
+
details.put("traceEncoding", "utf-8")
|
|
25764
|
+
}
|
|
25765
|
+
}
|
|
25766
|
+
JSONObject().put("details", details).put("id", id).put("kind", kind)
|
|
25767
|
+
.put("occurredAt", info.timestamp).put("platform", "android")
|
|
25768
|
+
} catch (_: Exception) { null }
|
|
25769
|
+
}
|
|
25770
|
+
|
|
25771
|
+
private fun collect() {
|
|
25772
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return
|
|
25773
|
+
val context = context() ?: return
|
|
25774
|
+
val directory = root() ?: return
|
|
25775
|
+
val manager = context.getSystemService(ActivityManager::class.java) ?: return
|
|
25776
|
+
val ignored = (acknowledged() + files().mapNotNull { readReport(it)?.get("id") as? String }).toMutableSet()
|
|
25777
|
+
manager.getHistoricalProcessExitReasons(null, 0, 16).forEach { exit ->
|
|
25778
|
+
val report = report(exit) ?: return@forEach
|
|
25779
|
+
val id = report.optString("id")
|
|
25780
|
+
if (ignored.contains(id)) return@forEach
|
|
25781
|
+
val target = File(directory, String.format(java.util.Locale.ROOT, "%013d-%s.json", exit.timestamp, UUID.randomUUID()))
|
|
25782
|
+
try {
|
|
25783
|
+
FileOutputStream(target).use { it.write(report.toString().toByteArray(StandardCharsets.UTF_8)) }
|
|
25784
|
+
ignored.add(id)
|
|
25785
|
+
} catch (_: Exception) {}
|
|
25786
|
+
}
|
|
25787
|
+
files().dropLast(MAX_REPORTS).forEach { it.delete() }
|
|
25788
|
+
}
|
|
25789
|
+
|
|
25790
|
+
private fun read(input: InputStream): ByteArray {
|
|
25791
|
+
val output = ByteArrayOutputStream()
|
|
25792
|
+
val buffer = ByteArray(4096)
|
|
25793
|
+
while (true) {
|
|
25794
|
+
val count = input.read(buffer)
|
|
25795
|
+
if (count < 0) break
|
|
25796
|
+
output.write(buffer, 0, count)
|
|
25797
|
+
}
|
|
25798
|
+
return output.toByteArray()
|
|
25799
|
+
}
|
|
25800
|
+
|
|
25801
|
+
private fun readReport(file: File): Map<String, Any?>? = try {
|
|
25802
|
+
FileInputStream(file).use { JSONObject(String(read(it), StandardCharsets.UTF_8)).toMap() }
|
|
25803
|
+
} catch (_: Exception) { null }
|
|
25804
|
+
|
|
25805
|
+
private fun JSONObject.toMap(): Map<String, Any?> = keys().asSequence().associateWith { key ->
|
|
25806
|
+
when (val value = get(key)) {
|
|
25807
|
+
is JSONObject -> value.toMap()
|
|
25808
|
+
is JSONArray -> (0 until value.length()).map { index ->
|
|
25809
|
+
when (val item = value.get(index)) {
|
|
25810
|
+
is JSONObject -> item.toMap()
|
|
25811
|
+
else -> item
|
|
25812
|
+
}
|
|
25813
|
+
}
|
|
25814
|
+
JSONObject.NULL -> null
|
|
25815
|
+
else -> value
|
|
25816
|
+
}
|
|
25817
|
+
}
|
|
25818
|
+
}
|
|
25819
|
+
`;
|
|
25820
|
+
var expoNativeObservabilityRuntimeSource = `${HEADER}import { requireNativeModule } from 'expo';
|
|
25821
|
+
import { AppState, Platform } from 'react-native';
|
|
25822
|
+
import { ABSOLUTE_MOBILE_MANIFEST } from './webAssets';
|
|
25823
|
+
|
|
25824
|
+
type NativeObservabilityModule = {
|
|
25825
|
+
acknowledge(options: { ids: string[] }): Promise<void>;
|
|
25826
|
+
pending(): Promise<{ reports: unknown[] }>;
|
|
25827
|
+
};
|
|
25828
|
+
type NativeReport = { details: Record<string, unknown>; id: string; kind: string; occurredAt: number; platform: 'android' | 'ios' };
|
|
25829
|
+
const native = requireNativeModule<NativeObservabilityModule>('AbsoluteMobileObservability');
|
|
25830
|
+
const KINDS = new Set(['anr', 'app-launch', 'cpu-exception', 'crash', 'disk-write-exception', 'hang', 'initialization-failure', 'low-memory', 'native-crash', 'resource-exhaustion', 'signal']);
|
|
25831
|
+
const ID = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
25832
|
+
const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
25833
|
+
const redactText = (value: string) => value.slice(0, 8192)
|
|
25834
|
+
.replace(/\\b(Bearer)\\s+[A-Za-z0-9._~+/-]+=*/gi, '$1 [REDACTED]')
|
|
25835
|
+
.replace(/([?&](?:access_token|api_?key|authorization|code|id_token|password|refresh_token|secret|token)=)[^&#\\s]*/gi, '$1[REDACTED]')
|
|
25836
|
+
.replace(/\\b((?:access_?token|api_?key|authorization|client_?secret|cookie|id_?token|password|passwd|refresh_?token|secret|token)\\s*[:=]\\s*)[^,\\s;]+/gi, '$1[REDACTED]')
|
|
25837
|
+
.replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/g, '[REDACTED]');
|
|
25838
|
+
const redact = (value: unknown, depth = 0): unknown => {
|
|
25839
|
+
if (depth >= 8) return '[TRUNCATED]';
|
|
25840
|
+
if (typeof value === 'string') return redactText(value);
|
|
25841
|
+
if (value === null || typeof value === 'number' || typeof value === 'boolean') return value;
|
|
25842
|
+
if (Array.isArray(value)) return value.slice(0, 64).map(entry => redact(entry, depth + 1));
|
|
25843
|
+
if (!isRecord(value)) return String(value).slice(0, 8192);
|
|
25844
|
+
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)]));
|
|
25845
|
+
};
|
|
25846
|
+
const parse = (value: unknown): NativeReport | undefined => {
|
|
25847
|
+
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;
|
|
25848
|
+
const details = redact(value.details);
|
|
25849
|
+
if (!isRecord(details) || new TextEncoder().encode(JSON.stringify(details)).byteLength > 64 * 1024) return;
|
|
25850
|
+
return { details, id: value.id, kind: value.kind, occurredAt: value.occurredAt, platform: value.platform };
|
|
25851
|
+
};
|
|
25852
|
+
const sampled = (id: string, rate: number) => {
|
|
25853
|
+
if (rate >= 1) return true;
|
|
25854
|
+
let hash = 2166136261;
|
|
25855
|
+
for (const character of id) { hash ^= character.codePointAt(0) ?? 0; hash = Math.imul(hash, 16777619); }
|
|
25856
|
+
return (hash >>> 0) / 4294967296 < rate;
|
|
25857
|
+
};
|
|
25858
|
+
let drainPromise: Promise<void> | undefined;
|
|
25859
|
+
let started = false;
|
|
25860
|
+
const drain = () => {
|
|
25861
|
+
drainPromise ??= (async () => {
|
|
25862
|
+
const manifest = ABSOLUTE_MOBILE_MANIFEST;
|
|
25863
|
+
const config = manifest?.observability;
|
|
25864
|
+
if (!manifest || !config || Platform.OS !== 'android' && Platform.OS !== 'ios') return;
|
|
25865
|
+
const reports = (await native.pending()).reports.slice(0, 8).map(parse).filter((report): report is NativeReport => report !== undefined);
|
|
25866
|
+
const discarded = reports.filter(report => !sampled(report.id, config.sampleRate));
|
|
25867
|
+
if (discarded.length) await native.acknowledge({ ids: discarded.map(report => report.id) });
|
|
25868
|
+
const selected = reports.filter(report => sampled(report.id, config.sampleRate));
|
|
25869
|
+
if (!selected.length) return;
|
|
25870
|
+
const response = await fetch(config.endpoint, {
|
|
25871
|
+
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 }),
|
|
25872
|
+
headers: { 'content-type': 'application/json' },
|
|
25873
|
+
method: 'POST'
|
|
25874
|
+
});
|
|
25875
|
+
if (response.ok) await native.acknowledge({ ids: selected.map(report => report.id) });
|
|
25876
|
+
})().catch(() => undefined).finally(() => { drainPromise = undefined; });
|
|
25877
|
+
return drainPromise;
|
|
25878
|
+
};
|
|
25879
|
+
export const startAbsoluteExpoNativeObservability = () => {
|
|
25880
|
+
if (!started) {
|
|
25881
|
+
started = true;
|
|
25882
|
+
AppState.addEventListener('change', state => { if (state === 'active') void drain(); });
|
|
25883
|
+
}
|
|
25884
|
+
return drain();
|
|
25885
|
+
};
|
|
25886
|
+
`;
|
|
25887
|
+
var absoluteExpoNativeObservabilityFiles = (project) => new Map([
|
|
25888
|
+
[
|
|
25889
|
+
join14(project, "modules/absolute-mobile-observability/expo-module.config.json"),
|
|
25890
|
+
moduleConfig
|
|
25891
|
+
],
|
|
25892
|
+
[
|
|
25893
|
+
join14(project, "modules/absolute-mobile-observability/ios/AbsoluteMobileObservability.podspec"),
|
|
25894
|
+
podspec
|
|
25895
|
+
],
|
|
25896
|
+
[
|
|
25897
|
+
join14(project, "modules/absolute-mobile-observability/ios/AbsoluteMobileObservabilityModule.swift"),
|
|
25898
|
+
iosModule
|
|
25899
|
+
],
|
|
25900
|
+
[
|
|
25901
|
+
join14(project, "modules/absolute-mobile-observability/android/build.gradle"),
|
|
25902
|
+
androidBuild
|
|
25903
|
+
],
|
|
25904
|
+
[
|
|
25905
|
+
join14(project, "modules/absolute-mobile-observability/android/src/main/AndroidManifest.xml"),
|
|
25906
|
+
androidManifest
|
|
25907
|
+
],
|
|
25908
|
+
[
|
|
25909
|
+
join14(project, "modules/absolute-mobile-observability/android/src/main/java/expo/modules/absolutemobileobservability/AbsoluteMobileObservabilityModule.kt"),
|
|
25910
|
+
androidModule
|
|
25911
|
+
],
|
|
25912
|
+
[
|
|
25913
|
+
join14(project, "src/generated/AbsoluteNativeObservability.ts"),
|
|
25914
|
+
expoNativeObservabilityRuntimeSource
|
|
25915
|
+
]
|
|
25916
|
+
]);
|
|
25917
|
+
var absoluteExpoNativeObservabilityPaths = (project) => [
|
|
25918
|
+
...absoluteExpoNativeObservabilityFiles(project).keys()
|
|
25919
|
+
];
|
|
25920
|
+
|
|
25501
25921
|
// src/mobile/expoProject.ts
|
|
25502
25922
|
var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
|
|
25503
25923
|
`;
|
|
@@ -25578,7 +25998,7 @@ var routeSegments = (route) => {
|
|
|
25578
25998
|
return segment;
|
|
25579
25999
|
});
|
|
25580
26000
|
};
|
|
25581
|
-
var routeFile = (project, route) =>
|
|
26001
|
+
var routeFile = (project, route) => join15(project, "app", ...routeSegments(route), "index.tsx");
|
|
25582
26002
|
var packageDependencies = (plan) => Object.fromEntries(plan.requiredPackages.map((spec) => {
|
|
25583
26003
|
const separator = spec.lastIndexOf("@");
|
|
25584
26004
|
return [spec.slice(0, separator), spec.slice(separator + 1)];
|
|
@@ -25826,16 +26246,19 @@ config.watchFolders = [appRoot];
|
|
|
25826
26246
|
|
|
25827
26247
|
module.exports = config;
|
|
25828
26248
|
`;
|
|
25829
|
-
var layoutSource = (auth, sync, updates) => `${EXPO_GENERATED_HEADER}import { Stack } from 'expo-router';
|
|
26249
|
+
var layoutSource = (auth, sync, updates, observability) => `${EXPO_GENERATED_HEADER}import { Stack } from 'expo-router';
|
|
25830
26250
|
import '../src/generated/AbsoluteDevices';
|
|
25831
26251
|
${auth ? `import { useEffect, useState } from 'react';
|
|
25832
26252
|
import { startAbsoluteExpoAuth } from '../src/generated/AbsoluteAuth';` : ""}
|
|
25833
26253
|
${sync ? "import { startAbsoluteExpoSync } from '../src/generated/AbsoluteSync';" : ""}
|
|
25834
26254
|
${updates ? `import { useEffect as useUpdateEffect } from 'react';
|
|
25835
26255
|
import { startAbsoluteExpoUpdates } from '../src/generated/AbsoluteUpdates';` : ""}
|
|
26256
|
+
${observability ? `import { useEffect as useNativeObservabilityEffect } from 'react';
|
|
26257
|
+
import { startAbsoluteExpoNativeObservability } from '../src/generated/AbsoluteNativeObservability';` : ""}
|
|
25836
26258
|
|
|
25837
26259
|
export default function AbsoluteLayout() {
|
|
25838
26260
|
${updates ? "useUpdateEffect(() => { void startAbsoluteExpoUpdates(); }, []);" : ""}
|
|
26261
|
+
${observability ? "useNativeObservabilityEffect(() => { void startAbsoluteExpoNativeObservability(); }, []);" : ""}
|
|
25839
26262
|
${auth ? `const [ready, setReady] = useState(false);
|
|
25840
26263
|
useEffect(() => {
|
|
25841
26264
|
let active = true;
|
|
@@ -26675,8 +27098,20 @@ var writeManagedFile = async (path, source, force) => {
|
|
|
26675
27098
|
await rename11(temporary, path);
|
|
26676
27099
|
return true;
|
|
26677
27100
|
};
|
|
27101
|
+
var pruneManagedFiles = async (paths) => {
|
|
27102
|
+
const removed = await Promise.all(paths.map(async (path) => {
|
|
27103
|
+
if (!await exists3(path))
|
|
27104
|
+
return false;
|
|
27105
|
+
const source = await readFile14(path, "utf8");
|
|
27106
|
+
if (!source.startsWith(EXPO_GENERATED_HEADER) && !path.endsWith("expo-module.config.json"))
|
|
27107
|
+
return false;
|
|
27108
|
+
await rm10(path, { force: true });
|
|
27109
|
+
return true;
|
|
27110
|
+
}));
|
|
27111
|
+
return removed.filter(Boolean).length;
|
|
27112
|
+
};
|
|
26678
27113
|
var pruneStaleManagedExpoRoutes = async (project, expected) => {
|
|
26679
|
-
const appDirectory =
|
|
27114
|
+
const appDirectory = join15(project, "app");
|
|
26680
27115
|
if (!await exists3(appDirectory))
|
|
26681
27116
|
return 0;
|
|
26682
27117
|
const files = await walkFiles(appDirectory);
|
|
@@ -26724,7 +27159,7 @@ var writeAbsoluteExpoProject = async (config, options) => {
|
|
|
26724
27159
|
if (missing) {
|
|
26725
27160
|
throw new TypeError(`Expo native route ${missing.route} references missing module ${missing.module}.`);
|
|
26726
27161
|
}
|
|
26727
|
-
const marker =
|
|
27162
|
+
const marker = join15(project, EXPO_PROJECT_MARKER);
|
|
26728
27163
|
if (await exists3(project) && !await exists3(marker)) {
|
|
26729
27164
|
const entries = await readdir4(project);
|
|
26730
27165
|
if (entries.length > 0 && !options.force) {
|
|
@@ -26737,7 +27172,7 @@ var writeAbsoluteExpoProject = async (config, options) => {
|
|
|
26737
27172
|
const authEnabled = Boolean(auth);
|
|
26738
27173
|
const files = new Map([
|
|
26739
27174
|
[
|
|
26740
|
-
|
|
27175
|
+
join15(project, ".gitignore"),
|
|
26741
27176
|
`.expo/
|
|
26742
27177
|
android/
|
|
26743
27178
|
ios/
|
|
@@ -26745,78 +27180,83 @@ node_modules/
|
|
|
26745
27180
|
`
|
|
26746
27181
|
],
|
|
26747
27182
|
[
|
|
26748
|
-
|
|
27183
|
+
join15(project, "app.json"),
|
|
26749
27184
|
jsonSource(expoAppConfig(config, authEnabled, syncEnabled, devices, runtimeFingerprint))
|
|
26750
27185
|
],
|
|
26751
|
-
[
|
|
27186
|
+
[join15(project, "app.config.js"), expoDynamicAppConfig],
|
|
26752
27187
|
[
|
|
26753
|
-
|
|
27188
|
+
join15(project, "package.json"),
|
|
26754
27189
|
jsonSource(expoPackage(authEnabled, syncEnabled, devices, config.updates !== undefined))
|
|
26755
27190
|
],
|
|
26756
|
-
[
|
|
27191
|
+
[join15(project, "metro.config.js"), metroConfig(projectRoot)],
|
|
26757
27192
|
[
|
|
26758
|
-
|
|
27193
|
+
join15(project, "plugins", "withAbsoluteDevelopmentCa.js"),
|
|
26759
27194
|
expoDevelopmentCaPlugin
|
|
26760
27195
|
],
|
|
26761
27196
|
[
|
|
26762
|
-
|
|
27197
|
+
join15(project, "tsconfig.json"),
|
|
26763
27198
|
jsonSource(expoTsConfig(projectRoot, project, authEnabled, syncEnabled))
|
|
26764
27199
|
],
|
|
26765
27200
|
[
|
|
26766
|
-
|
|
26767
|
-
layoutSource(authEnabled, syncEnabled, config.updates !== undefined)
|
|
27201
|
+
join15(project, "app", "_layout.tsx"),
|
|
27202
|
+
layoutSource(authEnabled, syncEnabled, config.updates !== undefined, config.observability !== undefined)
|
|
26768
27203
|
],
|
|
26769
27204
|
[
|
|
26770
|
-
|
|
27205
|
+
join15(project, "app", "__absolute", "native", "index.tsx"),
|
|
26771
27206
|
nativeDiagnosticSource
|
|
26772
27207
|
],
|
|
26773
27208
|
[
|
|
26774
|
-
|
|
27209
|
+
join15(project, "src", "generated", "AbsoluteDevices.ts"),
|
|
26775
27210
|
devicesRuntimeSource(config, devices, authEnabled)
|
|
26776
27211
|
],
|
|
26777
27212
|
[
|
|
26778
|
-
|
|
27213
|
+
join15(project, "src", "generated", "AbsoluteNativeRoute.tsx"),
|
|
26779
27214
|
nativeRouteRuntimeSource(authEnabled)
|
|
26780
27215
|
],
|
|
26781
27216
|
[
|
|
26782
|
-
|
|
27217
|
+
join15(project, "src", "generated", "AbsoluteWebHost.tsx"),
|
|
26783
27218
|
webHostSource(config, auth, syncEnabled)
|
|
26784
27219
|
]
|
|
26785
27220
|
]);
|
|
27221
|
+
if (config.observability) {
|
|
27222
|
+
for (const [path, source] of absoluteExpoNativeObservabilityFiles(project))
|
|
27223
|
+
files.set(path, source);
|
|
27224
|
+
}
|
|
26786
27225
|
if (config.updates) {
|
|
26787
|
-
files.set(
|
|
27226
|
+
files.set(join15(project, "src", "generated", "AbsoluteUpdates.ts"), updatesRuntimeSource(config));
|
|
26788
27227
|
}
|
|
26789
27228
|
const expoCodeSigning = config.updates?.expoCodeSigning;
|
|
26790
27229
|
if (expoCodeSigning)
|
|
26791
|
-
files.set(
|
|
27230
|
+
files.set(join15(project, "certs", "absolute-mobile-update.pem"), expoCodeSigning.certificatePem);
|
|
26792
27231
|
if (auth) {
|
|
26793
|
-
files.set(
|
|
27232
|
+
files.set(join15(project, "src", "generated", "AbsoluteAuth.ts"), authRuntimeSource(auth, config.appId));
|
|
26794
27233
|
}
|
|
26795
27234
|
if (syncSchema) {
|
|
26796
|
-
files.set(
|
|
27235
|
+
files.set(join15(project, "src", "generated", "AbsoluteSync.ts"), syncRuntimeSource(config, syncSchema));
|
|
26797
27236
|
}
|
|
26798
|
-
const webAssetsPath =
|
|
27237
|
+
const webAssetsPath = join15(project, "src", "generated", "webAssets.ts");
|
|
26799
27238
|
if (!await exists3(webAssetsPath)) {
|
|
26800
27239
|
files.set(webAssetsPath, emptyWebAssetsSource);
|
|
26801
27240
|
}
|
|
26802
27241
|
if (!config.expoNativeRoutes["/"]) {
|
|
26803
|
-
files.set(
|
|
27242
|
+
files.set(join15(project, "app", "index.tsx"), webRouteSource);
|
|
26804
27243
|
}
|
|
26805
|
-
files.set(
|
|
26806
|
-
const nativeRouteRuntime =
|
|
27244
|
+
files.set(join15(project, "app", "[...absolute].tsx"), catchAllRouteSource);
|
|
27245
|
+
const nativeRouteRuntime = join15(project, "src", "generated", "AbsoluteNativeRoute.tsx");
|
|
26807
27246
|
for (const [route, module] of routeModules) {
|
|
26808
|
-
const wrapper = route === "/" ?
|
|
27247
|
+
const wrapper = route === "/" ? join15(project, "app", "index.tsx") : routeFile(project, route);
|
|
26809
27248
|
files.set(wrapper, nativeWrapperSource(wrapper, module, nativeRouteRuntime, route));
|
|
26810
27249
|
}
|
|
26811
|
-
const
|
|
27250
|
+
const removedRoutes = await pruneStaleManagedExpoRoutes(project, new Set([...files.keys()].filter((path) => path.startsWith(`${join15(project, "app")}${sep6}`))));
|
|
27251
|
+
const removedObservability = config.observability ? 0 : await pruneManagedFiles(absoluteExpoNativeObservabilityPaths(project));
|
|
26812
27252
|
const changes = await Promise.all([...files].map(([path, source]) => writeManagedFile(path, source, true)));
|
|
26813
|
-
const changed =
|
|
27253
|
+
const changed = removedRoutes + removedObservability + changes.filter(Boolean).length;
|
|
26814
27254
|
return { changed, path: project, written: [...files.keys()] };
|
|
26815
27255
|
};
|
|
26816
27256
|
var walkFiles = async (root, directory = root) => {
|
|
26817
27257
|
const entries = await readdir4(directory, { withFileTypes: true });
|
|
26818
27258
|
const nested = await Promise.all(entries.map((entry) => {
|
|
26819
|
-
const path =
|
|
27259
|
+
const path = join15(directory, entry.name);
|
|
26820
27260
|
if (entry.isDirectory())
|
|
26821
27261
|
return walkFiles(root, path);
|
|
26822
27262
|
if (entry.isFile())
|
|
@@ -26883,11 +27323,11 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
26883
27323
|
var syncAbsoluteExpoWebAssets = async (config) => {
|
|
26884
27324
|
if (config.engine !== "expo")
|
|
26885
27325
|
throw new TypeError("Expo asset sync requires mobile.engine: expo.");
|
|
26886
|
-
const marker =
|
|
27326
|
+
const marker = join15(config.nativeProjectDirectory, EXPO_PROJECT_MARKER);
|
|
26887
27327
|
if (!await exists3(marker)) {
|
|
26888
27328
|
throw new TypeError("Expo asset sync requires an AbsoluteJS-managed Expo project. Run mobile init first.");
|
|
26889
27329
|
}
|
|
26890
|
-
const manifestPath =
|
|
27330
|
+
const manifestPath = join15(config.bundleDirectory, "absolute-mobile-manifest.json");
|
|
26891
27331
|
const manifest = JSON.parse(await readFile14(manifestPath, "utf8"));
|
|
26892
27332
|
const nativeDataManifest = expoNativeDataManifest(manifest);
|
|
26893
27333
|
const { appBuild } = nativeDataManifest;
|
|
@@ -26901,16 +27341,16 @@ var syncAbsoluteExpoWebAssets = async (config) => {
|
|
|
26901
27341
|
bundleHash.update("\x00");
|
|
26902
27342
|
});
|
|
26903
27343
|
const bundleId = `amexpo_${bundleHash.digest("hex")}`;
|
|
26904
|
-
const destination =
|
|
27344
|
+
const destination = join15(config.nativeProjectDirectory, "assets", "absolute");
|
|
26905
27345
|
await mkdir11(dirname10(destination), { recursive: true });
|
|
26906
|
-
const staging = await mkdtemp7(
|
|
27346
|
+
const staging = await mkdtemp7(join15(dirname10(destination), `.${basename4(destination)}.stage-`));
|
|
26907
27347
|
let assets;
|
|
26908
27348
|
try {
|
|
26909
27349
|
assets = await Promise.all(files.map(async (source, index) => {
|
|
26910
27350
|
const name = `${String(index).padStart(6, "0")}${EXPO_ASSET_EXTENSION}`;
|
|
26911
|
-
await cp2(source,
|
|
27351
|
+
await cp2(source, join15(staging, name));
|
|
26912
27352
|
return {
|
|
26913
|
-
asset: portableRelative2(
|
|
27353
|
+
asset: portableRelative2(join15(config.nativeProjectDirectory, "src", "generated"), join15(destination, name)),
|
|
26914
27354
|
path: relative10(config.bundleDirectory, source).replaceAll("\\", "/")
|
|
26915
27355
|
};
|
|
26916
27356
|
}));
|
|
@@ -26919,7 +27359,7 @@ var syncAbsoluteExpoWebAssets = async (config) => {
|
|
|
26919
27359
|
await rm10(staging, { force: true, recursive: true });
|
|
26920
27360
|
throw error;
|
|
26921
27361
|
}
|
|
26922
|
-
const generated =
|
|
27362
|
+
const generated = join15(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
|
|
26923
27363
|
await writeManagedFile(generated, assetModuleSource(assets, bundleId, nativeDataManifest), true);
|
|
26924
27364
|
return { appBuild, assets: assets.length, bundleId, path: destination };
|
|
26925
27365
|
};
|
|
@@ -26960,9 +27400,9 @@ var loadServerApp = async (producerPath) => {
|
|
|
26960
27400
|
var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
|
|
26961
27401
|
const buildDirectory = resolve13(options.buildDirectory);
|
|
26962
27402
|
const mobile = normalizeAbsoluteMobileConfig(options.mobile, options.projectRoot);
|
|
26963
|
-
const root =
|
|
27403
|
+
const root = join16(buildDirectory, ".absolutejs", "mobile-compatibility");
|
|
26964
27404
|
const [manifestSource, previous] = await Promise.all([
|
|
26965
|
-
readFile15(
|
|
27405
|
+
readFile15(join16(buildDirectory, "manifest.json"), "utf8"),
|
|
26966
27406
|
readAbsoluteMobileMaterializedReleases(root)
|
|
26967
27407
|
]);
|
|
26968
27408
|
const manifest = JSON.parse(manifestSource);
|
|
@@ -27447,7 +27887,7 @@ var generateAbsoluteExpoCodeSigning = async (options) => {
|
|
|
27447
27887
|
// src/mobile/expoDevController.ts
|
|
27448
27888
|
import { spawn } from "child_process";
|
|
27449
27889
|
import { access as access11 } from "fs/promises";
|
|
27450
|
-
import { join as
|
|
27890
|
+
import { join as join17 } from "path";
|
|
27451
27891
|
var METRO_READY_TIMEOUT_MS = 60000;
|
|
27452
27892
|
var PROCESS_CLOSE_TIMEOUT_MS = 2000;
|
|
27453
27893
|
var commandEnvironment = (options) => ({
|
|
@@ -27460,7 +27900,7 @@ var commandEnvironment = (options) => ({
|
|
|
27460
27900
|
...options.metroHost ? { REACT_NATIVE_PACKAGER_HOSTNAME: options.metroHost } : {}
|
|
27461
27901
|
});
|
|
27462
27902
|
var absoluteExpoExecutable = async (project) => {
|
|
27463
|
-
const executable =
|
|
27903
|
+
const executable = join17(project, "node_modules", ".bin", "expo");
|
|
27464
27904
|
try {
|
|
27465
27905
|
await access11(executable);
|
|
27466
27906
|
return executable;
|
|
@@ -27786,7 +28226,7 @@ var startAbsoluteExpoDevSession = async (options) => {
|
|
|
27786
28226
|
};
|
|
27787
28227
|
// src/mobile/expoUpdate.ts
|
|
27788
28228
|
import { access as access12, mkdir as mkdir13, readFile as readFile16, writeFile as writeFile14 } from "fs/promises";
|
|
27789
|
-
import { dirname as dirname12, extname as extname4, join as
|
|
28229
|
+
import { dirname as dirname12, extname as extname4, join as join18 } from "path";
|
|
27790
28230
|
var ABSOLUTE_EXPO_UPDATE_DESCRIPTOR = "_absolute/expo-update.json";
|
|
27791
28231
|
var ABSOLUTE_EXPO_UPDATE_FORMAT = 1;
|
|
27792
28232
|
var object4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -27852,7 +28292,7 @@ var parseAbsoluteExpoUpdateDescriptor = (value) => {
|
|
|
27852
28292
|
};
|
|
27853
28293
|
};
|
|
27854
28294
|
var finalizeAbsoluteExpoUpdateExport = async (options) => {
|
|
27855
|
-
const metadata = JSON.parse(await readFile16(
|
|
28295
|
+
const metadata = JSON.parse(await readFile16(join18(options.exportDirectory, "metadata.json"), "utf8"));
|
|
27856
28296
|
if (!object4(metadata) || !object4(metadata.fileMetadata))
|
|
27857
28297
|
throw new TypeError("Expo export metadata.json is invalid.");
|
|
27858
28298
|
const descriptor = parseAbsoluteExpoUpdateDescriptor({
|
|
@@ -27863,10 +28303,10 @@ var finalizeAbsoluteExpoUpdateExport = async (options) => {
|
|
|
27863
28303
|
runtimeVersion: options.runtimeVersion
|
|
27864
28304
|
});
|
|
27865
28305
|
const referenced = Object.values(descriptor.platforms).flatMap((entry) => entry ? [entry.launchAsset, ...entry.assets] : []);
|
|
27866
|
-
await Promise.all(referenced.map(({ path }) => access12(
|
|
28306
|
+
await Promise.all(referenced.map(({ path }) => access12(join18(options.exportDirectory, path)).catch(() => {
|
|
27867
28307
|
throw new TypeError(`Expo export metadata references missing asset ${path}.`);
|
|
27868
28308
|
})));
|
|
27869
|
-
const destination =
|
|
28309
|
+
const destination = join18(options.exportDirectory, ABSOLUTE_EXPO_UPDATE_DESCRIPTOR);
|
|
27870
28310
|
await mkdir13(dirname12(destination), { recursive: true });
|
|
27871
28311
|
await writeFile14(destination, `${JSON.stringify(descriptor, null, "\t")}
|
|
27872
28312
|
`);
|
|
@@ -28587,7 +29027,7 @@ var createAbsoluteMobilePreviewPlugin = (mobile) => {
|
|
|
28587
29027
|
};
|
|
28588
29028
|
// src/mobile/nativeDeepLinks.ts
|
|
28589
29029
|
import { readFile as readFile18, rename as rename12, writeFile as writeFile16 } from "fs/promises";
|
|
28590
|
-
import { join as
|
|
29030
|
+
import { join as join21 } from "path";
|
|
28591
29031
|
var START_MARKER = "<!-- absolutejs:deep-links:start -->";
|
|
28592
29032
|
var END_MARKER = "<!-- absolutejs:deep-links:end -->";
|
|
28593
29033
|
var IOS_ENTITLEMENTS = "App/AbsoluteJS.entitlements";
|
|
@@ -28644,7 +29084,7 @@ ${hosts}
|
|
|
28644
29084
|
`;
|
|
28645
29085
|
};
|
|
28646
29086
|
var configureAndroid = async (config) => {
|
|
28647
|
-
const path =
|
|
29087
|
+
const path = join21(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
|
|
28648
29088
|
const source = await readFile18(path, "utf8");
|
|
28649
29089
|
const mainActivity = source.indexOf('android:name=".MainActivity"');
|
|
28650
29090
|
if (mainActivity === NOT_FOUND) {
|
|
@@ -28670,7 +29110,7 @@ var iosSchemeRegion = (scheme) => ` ${START_MARKER}
|
|
|
28670
29110
|
${END_MARKER}
|
|
28671
29111
|
`;
|
|
28672
29112
|
var configureIosInfo = async (config) => {
|
|
28673
|
-
const path =
|
|
29113
|
+
const path = join21(config.nativeProjectDirectory, "ios/App/App/Info.plist");
|
|
28674
29114
|
const source = await readFile18(path, "utf8");
|
|
28675
29115
|
const region = config.deepLinkScheme ? iosSchemeRegion(config.deepLinkScheme) : ` ${START_MARKER}
|
|
28676
29116
|
${END_MARKER}
|
|
@@ -28694,7 +29134,7 @@ ${domains}
|
|
|
28694
29134
|
`;
|
|
28695
29135
|
};
|
|
28696
29136
|
var configureIosEntitlements = async (config) => {
|
|
28697
|
-
const path =
|
|
29137
|
+
const path = join21(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
|
|
28698
29138
|
let current = "";
|
|
28699
29139
|
try {
|
|
28700
29140
|
current = await readFile18(path, "utf8");
|
|
@@ -28712,7 +29152,7 @@ var configureIosEntitlements = async (config) => {
|
|
|
28712
29152
|
return true;
|
|
28713
29153
|
};
|
|
28714
29154
|
var configureIosProject = async (config) => {
|
|
28715
|
-
const path =
|
|
29155
|
+
const path = join21(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
|
|
28716
29156
|
const source = await readFile18(path, "utf8");
|
|
28717
29157
|
const declarations = [
|
|
28718
29158
|
...source.matchAll(/CODE_SIGN_ENTITLEMENTS = ([^;]+);/g)
|
|
@@ -28753,7 +29193,7 @@ var applyAbsoluteNativeDeepLinks = async (config, platforms = config.platforms)
|
|
|
28753
29193
|
// src/mobile/nativeDeviceCapabilities.ts
|
|
28754
29194
|
init_deviceCapabilities();
|
|
28755
29195
|
import { readFile as readFile19, rename as rename13, writeFile as writeFile17 } from "fs/promises";
|
|
28756
|
-
import { join as
|
|
29196
|
+
import { join as join22 } from "path";
|
|
28757
29197
|
var START_MARKER2 = "<!-- absolutejs:device-capabilities:start -->";
|
|
28758
29198
|
var END_MARKER2 = "<!-- absolutejs:device-capabilities:end -->";
|
|
28759
29199
|
var NOT_FOUND2 = -1;
|
|
@@ -28903,7 +29343,7 @@ var writeIosPrivacyManifest = async (path, current, source) => {
|
|
|
28903
29343
|
var configureIosPrivacyProject = async (config, requirements) => {
|
|
28904
29344
|
if (requirements.iosPrivacyAccessedApis.length === 0)
|
|
28905
29345
|
return false;
|
|
28906
|
-
const projectPath2 =
|
|
29346
|
+
const projectPath2 = join22(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
|
|
28907
29347
|
const project = await readFile19(projectPath2, "utf8");
|
|
28908
29348
|
return writeChangedFile2(projectPath2, addIosPrivacyProjectReference(project));
|
|
28909
29349
|
};
|
|
@@ -28956,7 +29396,7 @@ ${next.slice(index)}`;
|
|
|
28956
29396
|
return next;
|
|
28957
29397
|
};
|
|
28958
29398
|
var configureIos2 = async (config, plan) => {
|
|
28959
|
-
const path =
|
|
29399
|
+
const path = join22(config.nativeProjectDirectory, "ios/App/App/Info.plist");
|
|
28960
29400
|
const source = await readFile19(path, "utf8");
|
|
28961
29401
|
const requirements = absoluteDeviceNativeRequirements(plan);
|
|
28962
29402
|
const existingSystemBars = source.match(/<key>UIViewControllerBasedStatusBarAppearance<\/key>\s*<(true|false)\s*\/>/u);
|
|
@@ -28977,7 +29417,7 @@ ${content}
|
|
|
28977
29417
|
${END_MARKER2}
|
|
28978
29418
|
` : "";
|
|
28979
29419
|
const infoChanged = await writeChangedFile2(path, managed(source, region, source.lastIndexOf("</dict>")));
|
|
28980
|
-
const privacyPath =
|
|
29420
|
+
const privacyPath = join22(config.nativeProjectDirectory, "ios/App/App/PrivacyInfo.xcprivacy");
|
|
28981
29421
|
const privacyCurrent = await optionalSource(privacyPath);
|
|
28982
29422
|
const privacySource = privacyManifestSource(privacyCurrent, requirements);
|
|
28983
29423
|
const [privacyChanged, projectChanged, pushChanged] = await Promise.all([
|
|
@@ -28988,7 +29428,7 @@ ${content}
|
|
|
28988
29428
|
return infoChanged || privacyChanged || projectChanged || pushChanged;
|
|
28989
29429
|
};
|
|
28990
29430
|
var configureIosPushNotifications = async (config, enabled) => {
|
|
28991
|
-
const entitlementsPath =
|
|
29431
|
+
const entitlementsPath = join22(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
|
|
28992
29432
|
const entitlements = await optionalSource(entitlementsPath);
|
|
28993
29433
|
if (entitlements === null && !enabled)
|
|
28994
29434
|
return false;
|
|
@@ -29000,7 +29440,7 @@ var configureIosPushNotifications = async (config, enabled) => {
|
|
|
29000
29440
|
<!-- ${PUSH_END_MARKER} -->
|
|
29001
29441
|
` : "";
|
|
29002
29442
|
const nextEntitlements = replacePushRegion(entitlements, entitlementRegion, entitlements.lastIndexOf("</dict>"));
|
|
29003
|
-
const delegatePath =
|
|
29443
|
+
const delegatePath = join22(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
29004
29444
|
const delegate = await optionalSource(delegatePath);
|
|
29005
29445
|
if (delegate === null && !enabled)
|
|
29006
29446
|
return false;
|
|
@@ -29049,7 +29489,7 @@ var replacePushRegion = (source, region, insertion) => {
|
|
|
29049
29489
|
return `${source.slice(0, insertion)}${region}${source.slice(insertion)}`;
|
|
29050
29490
|
};
|
|
29051
29491
|
var configureAndroid2 = async (config, plan) => {
|
|
29052
|
-
const path =
|
|
29492
|
+
const path = join22(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
|
|
29053
29493
|
const source = await readFile19(path, "utf8");
|
|
29054
29494
|
const permissions = absoluteDeviceNativeRequirements(plan).androidPermissions;
|
|
29055
29495
|
const content = permissions.map((permission) => ` <uses-permission android:name="${escapeXml2(permission)}" />`).join(`
|
|
@@ -29085,7 +29525,7 @@ ${content}
|
|
|
29085
29525
|
throw new TypeError(`Android google-services.json does not contain package ${config.appId}.`);
|
|
29086
29526
|
const [manifestChanged, firebaseChanged] = await Promise.all([
|
|
29087
29527
|
writeChangedFile2(path, nextManifest),
|
|
29088
|
-
writeOptionalChangedFile(
|
|
29528
|
+
writeOptionalChangedFile(join22(config.nativeProjectDirectory, "android/app/google-services.json"), firebaseSource)
|
|
29089
29529
|
]);
|
|
29090
29530
|
return manifestChanged || firebaseChanged;
|
|
29091
29531
|
};
|
|
@@ -29111,7 +29551,7 @@ import {
|
|
|
29111
29551
|
rm as rm11,
|
|
29112
29552
|
writeFile as writeFile18
|
|
29113
29553
|
} from "fs/promises";
|
|
29114
|
-
import { dirname as dirname15, join as
|
|
29554
|
+
import { dirname as dirname15, join as join23 } from "path";
|
|
29115
29555
|
var START = "// absolutejs:mobile-updates:start";
|
|
29116
29556
|
var END = "// absolutejs:mobile-updates:end";
|
|
29117
29557
|
var PLUGIN_START = "// absolutejs:mobile-update-plugin:start";
|
|
@@ -29278,8 +29718,8 @@ public final class AbsoluteMobileUpdateWatchdogPlugin: CAPPlugin, CAPBridgedPlug
|
|
|
29278
29718
|
${PLUGIN_END}
|
|
29279
29719
|
`;
|
|
29280
29720
|
var configureIos3 = async (config, enabled) => {
|
|
29281
|
-
const path =
|
|
29282
|
-
const capacitorConfigPath =
|
|
29721
|
+
const path = join23(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
29722
|
+
const capacitorConfigPath = join23(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
|
|
29283
29723
|
let source = await readFile20(path, "utf8");
|
|
29284
29724
|
const launch = source.indexOf("didFinishLaunchingWithOptions");
|
|
29285
29725
|
const brace = launch < 0 ? -1 : source.indexOf("{", launch);
|
|
@@ -29443,91 +29883,650 @@ public final class AbsoluteMobileUpdateWatchdogPlugin extends Plugin {
|
|
|
29443
29883
|
}
|
|
29444
29884
|
|
|
29445
29885
|
@PluginMethod
|
|
29446
|
-
public void confirm(PluginCall call) {
|
|
29447
|
-
if (deadline != null) handler.removeCallbacks(deadline);
|
|
29448
|
-
deadline = null;
|
|
29449
|
-
call.resolve(new JSObject());
|
|
29886
|
+
public void confirm(PluginCall call) {
|
|
29887
|
+
if (deadline != null) handler.removeCallbacks(deadline);
|
|
29888
|
+
deadline = null;
|
|
29889
|
+
call.resolve(new JSObject());
|
|
29890
|
+
}
|
|
29891
|
+
|
|
29892
|
+
private static final class Recovery {
|
|
29893
|
+
final String previousPath;
|
|
29894
|
+
final boolean hasActive;
|
|
29895
|
+
Recovery(String previousPath, boolean hasActive) {
|
|
29896
|
+
this.previousPath = previousPath;
|
|
29897
|
+
this.hasActive = hasActive;
|
|
29898
|
+
}
|
|
29899
|
+
}
|
|
29900
|
+
}
|
|
29901
|
+
`;
|
|
29902
|
+
var androidActivityInRoot = async (root) => {
|
|
29903
|
+
let entries;
|
|
29904
|
+
try {
|
|
29905
|
+
entries = await readdir5(root, { recursive: true });
|
|
29906
|
+
} catch (error) {
|
|
29907
|
+
if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
|
|
29908
|
+
return;
|
|
29909
|
+
throw error;
|
|
29910
|
+
}
|
|
29911
|
+
const candidate = entries.find((entry) => entry.endsWith("/MainActivity.java") || entry.endsWith("/MainActivity.kt") || entry === "MainActivity.java" || entry === "MainActivity.kt");
|
|
29912
|
+
return candidate ? join23(root, candidate) : undefined;
|
|
29913
|
+
};
|
|
29914
|
+
var androidActivity = async (config) => {
|
|
29915
|
+
const roots = [
|
|
29916
|
+
join23(config.nativeProjectDirectory, "android/app/src/main/java"),
|
|
29917
|
+
join23(config.nativeProjectDirectory, "android/app/src/main/kotlin")
|
|
29918
|
+
];
|
|
29919
|
+
const candidates = await Promise.all(roots.map(androidActivityInRoot));
|
|
29920
|
+
const candidate = candidates.find((value) => value !== undefined);
|
|
29921
|
+
if (candidate)
|
|
29922
|
+
return candidate;
|
|
29923
|
+
throw new TypeError("Android MainActivity.java or MainActivity.kt was not found.");
|
|
29924
|
+
};
|
|
29925
|
+
var androidManagedRegion = (kotlin, generatedMethod) => {
|
|
29926
|
+
if (generatedMethod)
|
|
29927
|
+
return kotlin ? ` ${START}
|
|
29928
|
+
override fun onCreate(savedInstanceState: android.os.Bundle?) {
|
|
29929
|
+
AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot(this)
|
|
29930
|
+
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin::class.java)
|
|
29931
|
+
super.onCreate(savedInstanceState)
|
|
29932
|
+
}
|
|
29933
|
+
${END}
|
|
29934
|
+
` : ` ${START}
|
|
29935
|
+
@Override
|
|
29936
|
+
public void onCreate(android.os.Bundle savedInstanceState) {
|
|
29937
|
+
AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot(this);
|
|
29938
|
+
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin.class);
|
|
29939
|
+
super.onCreate(savedInstanceState);
|
|
29940
|
+
}
|
|
29941
|
+
${END}
|
|
29942
|
+
`;
|
|
29943
|
+
return kotlin ? ` ${START}
|
|
29944
|
+
AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot(this)
|
|
29945
|
+
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin::class.java)
|
|
29946
|
+
${END}
|
|
29947
|
+
` : ` ${START}
|
|
29948
|
+
AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot(this);
|
|
29949
|
+
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin.class);
|
|
29950
|
+
${END}
|
|
29951
|
+
`;
|
|
29952
|
+
};
|
|
29953
|
+
var injectAndroidActivity = (source, enabled) => {
|
|
29954
|
+
const kotlin = /\bfun\s+onCreate\s*\(/u.test(source) || source.includes("BridgeActivity()");
|
|
29955
|
+
const existingStart = source.indexOf(START);
|
|
29956
|
+
const existingEnd = source.indexOf(END);
|
|
29957
|
+
if (existingStart < 0 !== existingEnd < 0)
|
|
29958
|
+
throw new TypeError("AbsoluteJS mobile update markers are malformed.");
|
|
29959
|
+
if (existingStart >= 0) {
|
|
29960
|
+
const from = source.lastIndexOf(`
|
|
29961
|
+
`, existingStart) + 1;
|
|
29962
|
+
const newline = source.indexOf(`
|
|
29963
|
+
`, existingEnd + END.length);
|
|
29964
|
+
const through = newline < 0 ? source.length : newline + 1;
|
|
29965
|
+
const owned = source.slice(from, through);
|
|
29966
|
+
const generatedMethod = owned.includes("onCreate(");
|
|
29967
|
+
if (!enabled)
|
|
29968
|
+
return `${source.slice(0, from)}${source.slice(through)}`;
|
|
29969
|
+
const region2 = androidManagedRegion(kotlin, generatedMethod);
|
|
29970
|
+
return `${source.slice(0, from)}${region2}${source.slice(through)}`;
|
|
29971
|
+
}
|
|
29972
|
+
if (!enabled)
|
|
29973
|
+
return source;
|
|
29974
|
+
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);
|
|
29975
|
+
if (onCreate >= 0) {
|
|
29976
|
+
const brace = source.indexOf("{", onCreate);
|
|
29977
|
+
const insert = source.indexOf(`
|
|
29978
|
+
`, brace) + 1;
|
|
29979
|
+
const region2 = kotlin ? ` ${START}
|
|
29980
|
+
AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot(this)
|
|
29981
|
+
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin::class.java)
|
|
29982
|
+
${END}
|
|
29983
|
+
` : ` ${START}
|
|
29984
|
+
AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot(this);
|
|
29985
|
+
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin.class);
|
|
29986
|
+
${END}
|
|
29987
|
+
`;
|
|
29988
|
+
return `${source.slice(0, insert)}${region2}${source.slice(insert)}`;
|
|
29989
|
+
}
|
|
29990
|
+
const close = source.lastIndexOf("}");
|
|
29991
|
+
if (close < 0)
|
|
29992
|
+
throw new TypeError("Could not find the Android MainActivity class body.");
|
|
29993
|
+
const region = kotlin ? ` ${START}
|
|
29994
|
+
override fun onCreate(savedInstanceState: android.os.Bundle?) {
|
|
29995
|
+
AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot(this)
|
|
29996
|
+
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin::class.java)
|
|
29997
|
+
super.onCreate(savedInstanceState)
|
|
29998
|
+
}
|
|
29999
|
+
${END}
|
|
30000
|
+
` : ` ${START}
|
|
30001
|
+
@Override
|
|
30002
|
+
public void onCreate(android.os.Bundle savedInstanceState) {
|
|
30003
|
+
AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot(this);
|
|
30004
|
+
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin.class);
|
|
30005
|
+
super.onCreate(savedInstanceState);
|
|
30006
|
+
}
|
|
30007
|
+
${END}
|
|
30008
|
+
`;
|
|
30009
|
+
const separator = source[close - 1] === `
|
|
30010
|
+
` ? "" : `
|
|
30011
|
+
`;
|
|
30012
|
+
return `${source.slice(0, close)}${separator}${region}${source.slice(close)}`;
|
|
30013
|
+
};
|
|
30014
|
+
var configureAndroid3 = async (config, enabled) => {
|
|
30015
|
+
const activityPath = await androidActivity(config);
|
|
30016
|
+
const activity = await readFile20(activityPath, "utf8");
|
|
30017
|
+
const packageName = activity.match(/^\s*package\s+([A-Za-z0-9_.]+)\s*[;\n]/mu)?.[1];
|
|
30018
|
+
if (!packageName)
|
|
30019
|
+
throw new TypeError("Android MainActivity package declaration was not found.");
|
|
30020
|
+
const packagePath = packageName.replaceAll(".", "/");
|
|
30021
|
+
const pluginPath = join23(config.nativeProjectDirectory, "android/app/src/main/java", packagePath, ANDROID_PLUGIN);
|
|
30022
|
+
const changed = await Promise.all([
|
|
30023
|
+
writeChanged(activityPath, injectAndroidActivity(activity, enabled)),
|
|
30024
|
+
enabled ? writeChanged(pluginPath, androidPluginSource(packageName, config.updates?.bootTimeoutMs ?? 20000)) : removeOwnedFile(pluginPath)
|
|
30025
|
+
]);
|
|
30026
|
+
return changed.some(Boolean);
|
|
30027
|
+
};
|
|
30028
|
+
var applyAbsoluteNativeUpdates = async (config, platforms = config.platforms) => {
|
|
30029
|
+
if (config.engine !== "capacitor")
|
|
30030
|
+
return { changed: false };
|
|
30031
|
+
const enabled = config.updates !== undefined;
|
|
30032
|
+
const changed = [];
|
|
30033
|
+
if (platforms.includes("ios"))
|
|
30034
|
+
changed.push(await configureIos3(config, enabled));
|
|
30035
|
+
if (platforms.includes("android"))
|
|
30036
|
+
changed.push(await configureAndroid3(config, enabled));
|
|
30037
|
+
return { changed: changed.some(Boolean) };
|
|
30038
|
+
};
|
|
30039
|
+
// src/mobile/nativeObservability.ts
|
|
30040
|
+
import {
|
|
30041
|
+
mkdir as mkdir16,
|
|
30042
|
+
readFile as readFile21,
|
|
30043
|
+
readdir as readdir6,
|
|
30044
|
+
rename as rename15,
|
|
30045
|
+
rm as rm12,
|
|
30046
|
+
writeFile as writeFile19
|
|
30047
|
+
} from "fs/promises";
|
|
30048
|
+
import { dirname as dirname16, join as join24 } from "path";
|
|
30049
|
+
var START2 = "// absolutejs:native-observability:start";
|
|
30050
|
+
var END2 = "// absolutejs:native-observability:end";
|
|
30051
|
+
var PLUGIN_START2 = "// absolutejs:native-observability-plugin:start";
|
|
30052
|
+
var PLUGIN_END2 = "// absolutejs:native-observability-plugin:end";
|
|
30053
|
+
var ANDROID_PLUGIN2 = "AbsoluteMobileObservabilityPlugin.java";
|
|
30054
|
+
var optionalSource3 = async (path) => {
|
|
30055
|
+
try {
|
|
30056
|
+
return await readFile21(path, "utf8");
|
|
30057
|
+
} catch (error) {
|
|
30058
|
+
if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
|
|
30059
|
+
return null;
|
|
30060
|
+
throw error;
|
|
30061
|
+
}
|
|
30062
|
+
};
|
|
30063
|
+
var writeChanged2 = async (path, source) => {
|
|
30064
|
+
const current = await optionalSource3(path);
|
|
30065
|
+
if (current === source)
|
|
30066
|
+
return false;
|
|
30067
|
+
await mkdir16(dirname16(path), { recursive: true });
|
|
30068
|
+
if (current === null) {
|
|
30069
|
+
await writeFile19(path, source, { flag: "wx" });
|
|
30070
|
+
return true;
|
|
30071
|
+
}
|
|
30072
|
+
const temporary = `${path}.${crypto.randomUUID()}.tmp`;
|
|
30073
|
+
await writeFile19(temporary, source, { flag: "wx" });
|
|
30074
|
+
await rename15(temporary, path);
|
|
30075
|
+
return true;
|
|
30076
|
+
};
|
|
30077
|
+
var removeOwnedFile2 = async (path) => {
|
|
30078
|
+
if (await optionalSource3(path) === null)
|
|
30079
|
+
return false;
|
|
30080
|
+
await rm12(path);
|
|
30081
|
+
return true;
|
|
30082
|
+
};
|
|
30083
|
+
var isRecord12 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30084
|
+
var replaceMarkedRegion2 = (source, start, end, region, insertion, error) => {
|
|
30085
|
+
const existingStart = source.indexOf(start);
|
|
30086
|
+
const existingEnd = source.indexOf(end);
|
|
30087
|
+
if (existingStart < 0 !== existingEnd < 0 || existingStart >= 0 && existingEnd < existingStart)
|
|
30088
|
+
throw new TypeError("AbsoluteJS native observability markers are malformed.");
|
|
30089
|
+
if (existingStart >= 0) {
|
|
30090
|
+
const from = source.lastIndexOf(`
|
|
30091
|
+
`, existingStart) + 1;
|
|
30092
|
+
const newline = source.indexOf(`
|
|
30093
|
+
`, existingEnd + end.length);
|
|
30094
|
+
return `${source.slice(0, from)}${region}${source.slice(newline < 0 ? source.length : newline + 1)}`;
|
|
30095
|
+
}
|
|
30096
|
+
if (!region)
|
|
30097
|
+
return source;
|
|
30098
|
+
if (insertion < 0)
|
|
30099
|
+
throw new TypeError(error);
|
|
30100
|
+
return `${source.slice(0, insertion)}${region}${source.slice(insertion)}`;
|
|
30101
|
+
};
|
|
30102
|
+
var iosPluginRegion2 = `${PLUGIN_START2}
|
|
30103
|
+
@objc(AbsoluteMobileObservabilityPlugin)
|
|
30104
|
+
public final class AbsoluteMobileObservabilityPlugin: CAPPlugin, CAPBridgedPlugin, MXMetricManagerSubscriber {
|
|
30105
|
+
public let identifier = "AbsoluteMobileObservabilityPlugin"
|
|
30106
|
+
public let jsName = "AbsoluteMobileObservability"
|
|
30107
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
30108
|
+
CAPPluginMethod(name: "acknowledge", returnType: CAPPluginReturnPromise),
|
|
30109
|
+
CAPPluginMethod(name: "pending", returnType: CAPPluginReturnPromise)
|
|
30110
|
+
]
|
|
30111
|
+
|
|
30112
|
+
private static let maximumReports = 8
|
|
30113
|
+
private static let maximumReportBytes = 64 * 1024
|
|
30114
|
+
private static let queue = DispatchQueue(label: "dev.absolute.mobile-observability")
|
|
30115
|
+
|
|
30116
|
+
public override func load() {
|
|
30117
|
+
MXMetricManager.shared.add(self)
|
|
30118
|
+
}
|
|
30119
|
+
|
|
30120
|
+
deinit {
|
|
30121
|
+
MXMetricManager.shared.remove(self)
|
|
30122
|
+
}
|
|
30123
|
+
|
|
30124
|
+
private static func root() -> URL? {
|
|
30125
|
+
guard let support = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first else { return nil }
|
|
30126
|
+
let root = support.appendingPathComponent("AbsoluteMobileObservability", isDirectory: true)
|
|
30127
|
+
try? FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)
|
|
30128
|
+
return root
|
|
30129
|
+
}
|
|
30130
|
+
|
|
30131
|
+
private static func files() -> [URL] {
|
|
30132
|
+
guard let root = root() else { return [] }
|
|
30133
|
+
return ((try? FileManager.default.contentsOfDirectory(at: root, includingPropertiesForKeys: nil)) ?? [])
|
|
30134
|
+
.filter { $0.pathExtension == "json" }
|
|
30135
|
+
.sorted { $0.lastPathComponent < $1.lastPathComponent }
|
|
30136
|
+
}
|
|
30137
|
+
|
|
30138
|
+
private static func trim() {
|
|
30139
|
+
let overflow = max(0, files().count - maximumReports)
|
|
30140
|
+
for file in files().prefix(overflow) { try? FileManager.default.removeItem(at: file) }
|
|
30141
|
+
}
|
|
30142
|
+
|
|
30143
|
+
private static func enqueue(kind: String, occurredAt: Double, details: [AnyHashable: Any]) {
|
|
30144
|
+
guard let root = root() else { return }
|
|
30145
|
+
let id = UUID().uuidString.lowercased()
|
|
30146
|
+
var value: [String: Any] = [
|
|
30147
|
+
"details": Dictionary(uniqueKeysWithValues: details.map { (String(describing: $0.key), $0.value) }),
|
|
30148
|
+
"id": id,
|
|
30149
|
+
"kind": kind,
|
|
30150
|
+
"occurredAt": occurredAt,
|
|
30151
|
+
"platform": "ios"
|
|
30152
|
+
]
|
|
30153
|
+
guard JSONSerialization.isValidJSONObject(value),
|
|
30154
|
+
let original = try? JSONSerialization.data(withJSONObject: value) else { return }
|
|
30155
|
+
if original.count > maximumReportBytes {
|
|
30156
|
+
value["details"] = [
|
|
30157
|
+
"diagnosticPrefix": String(decoding: original.prefix(24 * 1024), as: UTF8.self),
|
|
30158
|
+
"originalBytes": original.count,
|
|
30159
|
+
"truncated": true
|
|
30160
|
+
]
|
|
30161
|
+
}
|
|
30162
|
+
guard let data = try? JSONSerialization.data(withJSONObject: value),
|
|
30163
|
+
data.count <= maximumReportBytes else { return }
|
|
30164
|
+
let timestamp = String(format: "%013.0f", occurredAt)
|
|
30165
|
+
try? data.write(to: root.appendingPathComponent("\\(timestamp)-\\(id).json"), options: .atomic)
|
|
30166
|
+
trim()
|
|
30167
|
+
}
|
|
30168
|
+
|
|
30169
|
+
public func didReceive(_ payloads: [MXDiagnosticPayload]) {
|
|
30170
|
+
Self.queue.async {
|
|
30171
|
+
for payload in payloads {
|
|
30172
|
+
let at = payload.timeStampEnd.timeIntervalSince1970 * 1000
|
|
30173
|
+
for value in payload.crashDiagnostics ?? [] { Self.enqueue(kind: "crash", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
30174
|
+
for value in payload.hangDiagnostics ?? [] { Self.enqueue(kind: "hang", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
30175
|
+
for value in payload.cpuExceptionDiagnostics ?? [] { Self.enqueue(kind: "cpu-exception", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
30176
|
+
for value in payload.diskWriteExceptionDiagnostics ?? [] { Self.enqueue(kind: "disk-write-exception", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
30177
|
+
if #available(iOS 16.0, *) {
|
|
30178
|
+
for value in payload.appLaunchDiagnostics ?? [] { Self.enqueue(kind: "app-launch", occurredAt: at, details: value.dictionaryRepresentation()) }
|
|
30179
|
+
}
|
|
30180
|
+
}
|
|
30181
|
+
}
|
|
30182
|
+
}
|
|
30183
|
+
|
|
30184
|
+
@objc public func pending(_ call: CAPPluginCall) {
|
|
30185
|
+
Self.queue.async {
|
|
30186
|
+
let reports: [[String: Any]] = Self.files().compactMap { file in
|
|
30187
|
+
guard let data = try? Data(contentsOf: file),
|
|
30188
|
+
let value = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return nil }
|
|
30189
|
+
return value
|
|
30190
|
+
}
|
|
30191
|
+
call.resolve(["reports": reports])
|
|
30192
|
+
}
|
|
30193
|
+
}
|
|
30194
|
+
|
|
30195
|
+
@objc public func acknowledge(_ call: CAPPluginCall) {
|
|
30196
|
+
guard let ids = call.getArray("ids", String.self) else {
|
|
30197
|
+
call.reject("Native observability acknowledgement requires report ids.")
|
|
30198
|
+
return
|
|
30199
|
+
}
|
|
30200
|
+
let accepted = Set(ids)
|
|
30201
|
+
Self.queue.async {
|
|
30202
|
+
for file in Self.files() {
|
|
30203
|
+
guard let data = try? Data(contentsOf: file),
|
|
30204
|
+
let value = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
|
30205
|
+
let id = value["id"] as? String,
|
|
30206
|
+
accepted.contains(id) else { continue }
|
|
30207
|
+
try? FileManager.default.removeItem(at: file)
|
|
30208
|
+
}
|
|
30209
|
+
call.resolve()
|
|
30210
|
+
}
|
|
30211
|
+
}
|
|
30212
|
+
}
|
|
30213
|
+
${PLUGIN_END2}
|
|
30214
|
+
`;
|
|
30215
|
+
var configureIos4 = async (config, enabled) => {
|
|
30216
|
+
const path = join24(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
|
|
30217
|
+
const capacitorConfigPath = join24(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
|
|
30218
|
+
let source = await readFile21(path, "utf8");
|
|
30219
|
+
if (enabled && !source.includes("import MetricKit")) {
|
|
30220
|
+
const capacitorImport = source.lastIndexOf("import Capacitor");
|
|
30221
|
+
if (capacitorImport < 0)
|
|
30222
|
+
throw new TypeError("Capacitor AppDelegate import was not found.");
|
|
30223
|
+
const newline = source.indexOf(`
|
|
30224
|
+
`, capacitorImport);
|
|
30225
|
+
source = `${source.slice(0, newline + 1)}import MetricKit
|
|
30226
|
+
${source.slice(newline + 1)}`;
|
|
30227
|
+
}
|
|
30228
|
+
if (!enabled)
|
|
30229
|
+
source = source.replace(`import MetricKit
|
|
30230
|
+
`, "");
|
|
30231
|
+
source = replaceMarkedRegion2(source, PLUGIN_START2, PLUGIN_END2, enabled ? iosPluginRegion2 : "", source.length, "Could not find a safe iOS location for native observability.");
|
|
30232
|
+
const capacitorConfigSource2 = await readFile21(capacitorConfigPath, "utf8");
|
|
30233
|
+
let capacitorConfig;
|
|
30234
|
+
try {
|
|
30235
|
+
const value = JSON.parse(capacitorConfigSource2);
|
|
30236
|
+
if (!isRecord12(value))
|
|
30237
|
+
throw new TypeError;
|
|
30238
|
+
capacitorConfig = value;
|
|
30239
|
+
} catch {
|
|
30240
|
+
throw new TypeError("iOS capacitor.config.json is invalid; run Capacitor sync before projecting native observability.");
|
|
30241
|
+
}
|
|
30242
|
+
const packageClassList = Reflect.get(capacitorConfig, "packageClassList");
|
|
30243
|
+
if (!Array.isArray(packageClassList))
|
|
30244
|
+
throw new TypeError("iOS capacitor.config.json has no packageClassList; run Capacitor sync before projecting native observability.");
|
|
30245
|
+
const classes = packageClassList.filter((value) => typeof value === "string");
|
|
30246
|
+
const nextClasses = enabled ? [...new Set([...classes, "AbsoluteMobileObservabilityPlugin"])] : classes.filter((value) => value !== "AbsoluteMobileObservabilityPlugin");
|
|
30247
|
+
const nextCapacitorConfig = `${JSON.stringify({ ...capacitorConfig, packageClassList: nextClasses }, null, "\t")}
|
|
30248
|
+
`;
|
|
30249
|
+
const changed = await Promise.all([
|
|
30250
|
+
writeChanged2(path, source),
|
|
30251
|
+
writeChanged2(capacitorConfigPath, nextCapacitorConfig)
|
|
30252
|
+
]);
|
|
30253
|
+
return changed.some(Boolean);
|
|
30254
|
+
};
|
|
30255
|
+
var androidPluginSource2 = (packageName) => `package ${packageName};
|
|
30256
|
+
|
|
30257
|
+
import android.app.ActivityManager;
|
|
30258
|
+
import android.app.ApplicationExitInfo;
|
|
30259
|
+
import android.os.Build;
|
|
30260
|
+
import android.util.Base64;
|
|
30261
|
+
import com.getcapacitor.JSArray;
|
|
30262
|
+
import com.getcapacitor.JSObject;
|
|
30263
|
+
import com.getcapacitor.Plugin;
|
|
30264
|
+
import com.getcapacitor.PluginCall;
|
|
30265
|
+
import com.getcapacitor.PluginMethod;
|
|
30266
|
+
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
30267
|
+
import java.io.ByteArrayOutputStream;
|
|
30268
|
+
import java.io.File;
|
|
30269
|
+
import java.io.FileInputStream;
|
|
30270
|
+
import java.io.FileOutputStream;
|
|
30271
|
+
import java.io.InputStream;
|
|
30272
|
+
import java.nio.charset.StandardCharsets;
|
|
30273
|
+
import java.util.ArrayList;
|
|
30274
|
+
import java.util.HashSet;
|
|
30275
|
+
import java.util.List;
|
|
30276
|
+
import java.util.Set;
|
|
30277
|
+
import org.json.JSONArray;
|
|
30278
|
+
import org.json.JSONObject;
|
|
30279
|
+
|
|
30280
|
+
@CapacitorPlugin(name = "AbsoluteMobileObservability")
|
|
30281
|
+
public final class AbsoluteMobileObservabilityPlugin extends Plugin {
|
|
30282
|
+
private static final int MAX_REPORTS = 8;
|
|
30283
|
+
private static final int MAX_TRACE_BYTES = 32 * 1024;
|
|
30284
|
+
private static final String ACKNOWLEDGED_KEY = "acknowledged";
|
|
30285
|
+
private static final String PREFERENCES = "AbsoluteMobileObservability";
|
|
30286
|
+
|
|
30287
|
+
private File root() {
|
|
30288
|
+
File value = new File(getContext().getFilesDir(), "absolute-mobile-observability");
|
|
30289
|
+
value.mkdirs();
|
|
30290
|
+
return value;
|
|
30291
|
+
}
|
|
30292
|
+
|
|
30293
|
+
private Set<String> acknowledged() {
|
|
30294
|
+
Set<String> result = new HashSet<>();
|
|
30295
|
+
try {
|
|
30296
|
+
JSONArray values = new JSONArray(getContext().getSharedPreferences(PREFERENCES, 0).getString(ACKNOWLEDGED_KEY, "[]"));
|
|
30297
|
+
for (int index = 0; index < values.length(); index++) result.add(values.optString(index));
|
|
30298
|
+
} catch (Exception ignored) {}
|
|
30299
|
+
return result;
|
|
30300
|
+
}
|
|
30301
|
+
|
|
30302
|
+
private void writeAcknowledged(Set<String> values) {
|
|
30303
|
+
List<String> sorted = new ArrayList<>(values);
|
|
30304
|
+
sorted.sort(String::compareTo);
|
|
30305
|
+
if (sorted.size() > 64) sorted = sorted.subList(sorted.size() - 64, sorted.size());
|
|
30306
|
+
getContext().getSharedPreferences(PREFERENCES, 0).edit().putString(ACKNOWLEDGED_KEY, new JSONArray(sorted).toString()).apply();
|
|
30307
|
+
}
|
|
30308
|
+
|
|
30309
|
+
private static String kind(int reason) {
|
|
30310
|
+
if (reason == ApplicationExitInfo.REASON_ANR) return "anr";
|
|
30311
|
+
if (reason == ApplicationExitInfo.REASON_CRASH) return "crash";
|
|
30312
|
+
if (reason == ApplicationExitInfo.REASON_CRASH_NATIVE) return "native-crash";
|
|
30313
|
+
if (reason == ApplicationExitInfo.REASON_LOW_MEMORY) return "low-memory";
|
|
30314
|
+
if (reason == ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE) return "resource-exhaustion";
|
|
30315
|
+
if (reason == ApplicationExitInfo.REASON_INITIALIZATION_FAILURE) return "initialization-failure";
|
|
30316
|
+
if (reason == ApplicationExitInfo.REASON_SIGNALED) return "signal";
|
|
30317
|
+
return null;
|
|
30318
|
+
}
|
|
30319
|
+
|
|
30320
|
+
private static byte[] trace(ApplicationExitInfo info) {
|
|
30321
|
+
try (InputStream input = info.getTraceInputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
|
30322
|
+
if (input == null) return null;
|
|
30323
|
+
byte[] buffer = new byte[4096];
|
|
30324
|
+
int total = 0;
|
|
30325
|
+
int read;
|
|
30326
|
+
while ((read = input.read(buffer, 0, Math.min(buffer.length, MAX_TRACE_BYTES + 1 - total))) > 0) {
|
|
30327
|
+
output.write(buffer, 0, read);
|
|
30328
|
+
total += read;
|
|
30329
|
+
if (total > MAX_TRACE_BYTES) return null;
|
|
30330
|
+
}
|
|
30331
|
+
return output.toByteArray();
|
|
30332
|
+
} catch (Exception ignored) {
|
|
30333
|
+
return null;
|
|
30334
|
+
}
|
|
30335
|
+
}
|
|
30336
|
+
|
|
30337
|
+
private static JSONObject report(ApplicationExitInfo info) {
|
|
30338
|
+
String kind = kind(info.getReason());
|
|
30339
|
+
if (kind == null) return null;
|
|
30340
|
+
String id = "android:" + info.getTimestamp() + ":" + info.getReason() + ":" + info.getStatus();
|
|
30341
|
+
JSONObject details = new JSONObject();
|
|
30342
|
+
try {
|
|
30343
|
+
details.put("importance", info.getImportance());
|
|
30344
|
+
details.put("pssKb", info.getPss());
|
|
30345
|
+
details.put("reason", info.getReason());
|
|
30346
|
+
details.put("rssKb", info.getRss());
|
|
30347
|
+
details.put("status", info.getStatus());
|
|
30348
|
+
String description = info.getDescription();
|
|
30349
|
+
if (description != null) details.put("description", description);
|
|
30350
|
+
byte[] trace = trace(info);
|
|
30351
|
+
if (trace != null && trace.length > 0) {
|
|
30352
|
+
if (info.getReason() == ApplicationExitInfo.REASON_CRASH_NATIVE) {
|
|
30353
|
+
details.put("trace", Base64.encodeToString(trace, Base64.NO_WRAP));
|
|
30354
|
+
details.put("traceEncoding", "android-tombstone-protobuf-base64");
|
|
30355
|
+
} else {
|
|
30356
|
+
details.put("trace", new String(trace, StandardCharsets.UTF_8));
|
|
30357
|
+
details.put("traceEncoding", "utf-8");
|
|
30358
|
+
}
|
|
30359
|
+
}
|
|
30360
|
+
return new JSONObject()
|
|
30361
|
+
.put("details", details)
|
|
30362
|
+
.put("id", id)
|
|
30363
|
+
.put("kind", kind)
|
|
30364
|
+
.put("occurredAt", info.getTimestamp())
|
|
30365
|
+
.put("platform", "android");
|
|
30366
|
+
} catch (Exception ignored) {
|
|
30367
|
+
return null;
|
|
30368
|
+
}
|
|
30369
|
+
}
|
|
30370
|
+
|
|
30371
|
+
private Set<String> queuedIds() {
|
|
30372
|
+
Set<String> ids = new HashSet<>();
|
|
30373
|
+
for (File file : files()) {
|
|
30374
|
+
try (InputStream input = new FileInputStream(file)) {
|
|
30375
|
+
JSONObject report = new JSONObject(new String(read(input), StandardCharsets.UTF_8));
|
|
30376
|
+
ids.add(report.optString("id"));
|
|
30377
|
+
} catch (Exception ignored) {}
|
|
30378
|
+
}
|
|
30379
|
+
return ids;
|
|
30380
|
+
}
|
|
30381
|
+
|
|
30382
|
+
private File[] files() {
|
|
30383
|
+
File[] values = root().listFiles((directory, name) -> name.endsWith(".json"));
|
|
30384
|
+
if (values == null) return new File[0];
|
|
30385
|
+
java.util.Arrays.sort(values, java.util.Comparator.comparing(File::getName));
|
|
30386
|
+
return values;
|
|
30387
|
+
}
|
|
30388
|
+
|
|
30389
|
+
private static byte[] read(InputStream input) throws java.io.IOException {
|
|
30390
|
+
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
|
30391
|
+
byte[] buffer = new byte[4096];
|
|
30392
|
+
int count;
|
|
30393
|
+
while ((count = input.read(buffer)) >= 0) output.write(buffer, 0, count);
|
|
30394
|
+
return output.toByteArray();
|
|
30395
|
+
}
|
|
30396
|
+
|
|
30397
|
+
private void collect() {
|
|
30398
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return;
|
|
30399
|
+
ActivityManager manager = getContext().getSystemService(ActivityManager.class);
|
|
30400
|
+
if (manager == null) return;
|
|
30401
|
+
Set<String> ignored = acknowledged();
|
|
30402
|
+
ignored.addAll(queuedIds());
|
|
30403
|
+
List<ApplicationExitInfo> exits = manager.getHistoricalProcessExitReasons(null, 0, 16);
|
|
30404
|
+
for (ApplicationExitInfo exit : exits) {
|
|
30405
|
+
JSONObject report = report(exit);
|
|
30406
|
+
if (report == null || ignored.contains(report.optString("id"))) continue;
|
|
30407
|
+
String name = String.format(java.util.Locale.ROOT, "%013d-%s.json", exit.getTimestamp(), java.util.UUID.randomUUID());
|
|
30408
|
+
File target = new File(root(), name);
|
|
30409
|
+
try (FileOutputStream output = new FileOutputStream(target)) {
|
|
30410
|
+
output.write(report.toString().getBytes(StandardCharsets.UTF_8));
|
|
30411
|
+
ignored.add(report.optString("id"));
|
|
30412
|
+
} catch (Exception ignoredWrite) {}
|
|
30413
|
+
}
|
|
30414
|
+
File[] files = files();
|
|
30415
|
+
for (int index = 0; index < files.length - MAX_REPORTS; index++) files[index].delete();
|
|
30416
|
+
}
|
|
30417
|
+
|
|
30418
|
+
@PluginMethod
|
|
30419
|
+
public void pending(PluginCall call) {
|
|
30420
|
+
collect();
|
|
30421
|
+
JSArray reports = new JSArray();
|
|
30422
|
+
for (File file : files()) {
|
|
30423
|
+
try (InputStream input = new FileInputStream(file)) {
|
|
30424
|
+
reports.put(new JSONObject(new String(read(input), StandardCharsets.UTF_8)));
|
|
30425
|
+
} catch (Exception ignored) {}
|
|
30426
|
+
}
|
|
30427
|
+
call.resolve(new JSObject().put("reports", reports));
|
|
29450
30428
|
}
|
|
29451
30429
|
|
|
29452
|
-
|
|
29453
|
-
|
|
29454
|
-
|
|
29455
|
-
|
|
29456
|
-
|
|
29457
|
-
|
|
30430
|
+
@PluginMethod
|
|
30431
|
+
public void crashForTesting(PluginCall call) {
|
|
30432
|
+
boolean debuggable = (getContext().getApplicationInfo().flags & android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE) != 0;
|
|
30433
|
+
if (!debuggable) {
|
|
30434
|
+
call.reject("Native crash injection is available only in debuggable builds.");
|
|
30435
|
+
return;
|
|
30436
|
+
}
|
|
30437
|
+
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
|
30438
|
+
throw new RuntimeException("AbsoluteJS native observability acceptance crash");
|
|
30439
|
+
});
|
|
30440
|
+
}
|
|
30441
|
+
|
|
30442
|
+
@PluginMethod
|
|
30443
|
+
public void acknowledge(PluginCall call) {
|
|
30444
|
+
JSArray ids = call.getArray("ids");
|
|
30445
|
+
if (ids == null) {
|
|
30446
|
+
call.reject("Native observability acknowledgement requires report ids.");
|
|
30447
|
+
return;
|
|
30448
|
+
}
|
|
30449
|
+
Set<String> accepted = new HashSet<>();
|
|
30450
|
+
for (int index = 0; index < ids.length(); index++) accepted.add(ids.optString(index));
|
|
30451
|
+
Set<String> acknowledged = acknowledged();
|
|
30452
|
+
for (File file : files()) {
|
|
30453
|
+
try (InputStream input = new FileInputStream(file)) {
|
|
30454
|
+
JSONObject report = new JSONObject(new String(read(input), StandardCharsets.UTF_8));
|
|
30455
|
+
String id = report.optString("id");
|
|
30456
|
+
if (accepted.contains(id)) {
|
|
30457
|
+
acknowledged.add(id);
|
|
30458
|
+
file.delete();
|
|
30459
|
+
}
|
|
30460
|
+
} catch (Exception ignored) {}
|
|
29458
30461
|
}
|
|
30462
|
+
writeAcknowledged(acknowledged);
|
|
30463
|
+
call.resolve();
|
|
29459
30464
|
}
|
|
29460
30465
|
}
|
|
29461
30466
|
`;
|
|
29462
|
-
var
|
|
30467
|
+
var androidActivityInRoot2 = async (root) => {
|
|
29463
30468
|
let entries;
|
|
29464
30469
|
try {
|
|
29465
|
-
entries = await
|
|
30470
|
+
entries = await readdir6(root, { recursive: true });
|
|
29466
30471
|
} catch (error) {
|
|
29467
30472
|
if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
|
|
29468
30473
|
return;
|
|
29469
30474
|
throw error;
|
|
29470
30475
|
}
|
|
29471
30476
|
const candidate = entries.find((entry) => entry.endsWith("/MainActivity.java") || entry.endsWith("/MainActivity.kt") || entry === "MainActivity.java" || entry === "MainActivity.kt");
|
|
29472
|
-
return candidate ?
|
|
30477
|
+
return candidate ? join24(root, candidate) : undefined;
|
|
29473
30478
|
};
|
|
29474
|
-
var
|
|
30479
|
+
var androidActivity2 = async (config) => {
|
|
29475
30480
|
const roots = [
|
|
29476
|
-
|
|
29477
|
-
|
|
30481
|
+
join24(config.nativeProjectDirectory, "android/app/src/main/java"),
|
|
30482
|
+
join24(config.nativeProjectDirectory, "android/app/src/main/kotlin")
|
|
29478
30483
|
];
|
|
29479
|
-
const candidates = await Promise.all(roots.map(
|
|
30484
|
+
const candidates = await Promise.all(roots.map(androidActivityInRoot2));
|
|
29480
30485
|
const candidate = candidates.find((value) => value !== undefined);
|
|
29481
30486
|
if (candidate)
|
|
29482
30487
|
return candidate;
|
|
29483
30488
|
throw new TypeError("Android MainActivity.java or MainActivity.kt was not found.");
|
|
29484
30489
|
};
|
|
29485
|
-
var
|
|
30490
|
+
var androidRegion2 = (kotlin, generatedMethod) => {
|
|
29486
30491
|
if (generatedMethod)
|
|
29487
|
-
return kotlin ? ` ${
|
|
30492
|
+
return kotlin ? ` ${START2}
|
|
29488
30493
|
override fun onCreate(savedInstanceState: android.os.Bundle?) {
|
|
29489
|
-
|
|
29490
|
-
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin::class.java)
|
|
30494
|
+
registerPlugin(AbsoluteMobileObservabilityPlugin::class.java)
|
|
29491
30495
|
super.onCreate(savedInstanceState)
|
|
29492
30496
|
}
|
|
29493
|
-
${
|
|
29494
|
-
` : ` ${
|
|
30497
|
+
${END2}
|
|
30498
|
+
` : ` ${START2}
|
|
29495
30499
|
@Override
|
|
29496
30500
|
public void onCreate(android.os.Bundle savedInstanceState) {
|
|
29497
|
-
|
|
29498
|
-
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin.class);
|
|
30501
|
+
registerPlugin(AbsoluteMobileObservabilityPlugin.class);
|
|
29499
30502
|
super.onCreate(savedInstanceState);
|
|
29500
30503
|
}
|
|
29501
|
-
${
|
|
30504
|
+
${END2}
|
|
29502
30505
|
`;
|
|
29503
|
-
return kotlin ? ` ${
|
|
29504
|
-
|
|
29505
|
-
|
|
29506
|
-
${
|
|
29507
|
-
|
|
29508
|
-
|
|
29509
|
-
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin.class);
|
|
29510
|
-
${END}
|
|
30506
|
+
return kotlin ? ` ${START2}
|
|
30507
|
+
registerPlugin(AbsoluteMobileObservabilityPlugin::class.java)
|
|
30508
|
+
${END2}
|
|
30509
|
+
` : ` ${START2}
|
|
30510
|
+
registerPlugin(AbsoluteMobileObservabilityPlugin.class);
|
|
30511
|
+
${END2}
|
|
29511
30512
|
`;
|
|
29512
30513
|
};
|
|
29513
|
-
var
|
|
30514
|
+
var injectAndroidActivity2 = (source, enabled) => {
|
|
29514
30515
|
const kotlin = /\bfun\s+onCreate\s*\(/u.test(source) || source.includes("BridgeActivity()");
|
|
29515
|
-
const existingStart = source.indexOf(
|
|
29516
|
-
const existingEnd = source.indexOf(
|
|
30516
|
+
const existingStart = source.indexOf(START2);
|
|
30517
|
+
const existingEnd = source.indexOf(END2);
|
|
29517
30518
|
if (existingStart < 0 !== existingEnd < 0)
|
|
29518
|
-
throw new TypeError("AbsoluteJS
|
|
30519
|
+
throw new TypeError("AbsoluteJS native observability markers are malformed.");
|
|
29519
30520
|
if (existingStart >= 0) {
|
|
29520
30521
|
const from = source.lastIndexOf(`
|
|
29521
30522
|
`, existingStart) + 1;
|
|
29522
30523
|
const newline = source.indexOf(`
|
|
29523
|
-
`, existingEnd +
|
|
30524
|
+
`, existingEnd + END2.length);
|
|
29524
30525
|
const through = newline < 0 ? source.length : newline + 1;
|
|
29525
|
-
const
|
|
29526
|
-
const generatedMethod = owned.includes("onCreate(");
|
|
30526
|
+
const generatedMethod = source.slice(from, through).includes("onCreate(");
|
|
29527
30527
|
if (!enabled)
|
|
29528
30528
|
return `${source.slice(0, from)}${source.slice(through)}`;
|
|
29529
|
-
|
|
29530
|
-
return `${source.slice(0, from)}${region2}${source.slice(through)}`;
|
|
30529
|
+
return `${source.slice(0, from)}${androidRegion2(kotlin, generatedMethod)}${source.slice(through)}`;
|
|
29531
30530
|
}
|
|
29532
30531
|
if (!enabled)
|
|
29533
30532
|
return source;
|
|
@@ -29536,64 +30535,38 @@ var injectAndroidActivity = (source, enabled) => {
|
|
|
29536
30535
|
const brace = source.indexOf("{", onCreate);
|
|
29537
30536
|
const insert = source.indexOf(`
|
|
29538
30537
|
`, brace) + 1;
|
|
29539
|
-
|
|
29540
|
-
AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot(this)
|
|
29541
|
-
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin::class.java)
|
|
29542
|
-
${END}
|
|
29543
|
-
` : ` ${START}
|
|
29544
|
-
AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot(this);
|
|
29545
|
-
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin.class);
|
|
29546
|
-
${END}
|
|
29547
|
-
`;
|
|
29548
|
-
return `${source.slice(0, insert)}${region2}${source.slice(insert)}`;
|
|
30538
|
+
return `${source.slice(0, insert)}${androidRegion2(kotlin, false)}${source.slice(insert)}`;
|
|
29549
30539
|
}
|
|
29550
30540
|
const close = source.lastIndexOf("}");
|
|
29551
30541
|
if (close < 0)
|
|
29552
30542
|
throw new TypeError("Could not find the Android MainActivity class body.");
|
|
29553
|
-
const region = kotlin ? ` ${START}
|
|
29554
|
-
override fun onCreate(savedInstanceState: android.os.Bundle?) {
|
|
29555
|
-
AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot(this)
|
|
29556
|
-
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin::class.java)
|
|
29557
|
-
super.onCreate(savedInstanceState)
|
|
29558
|
-
}
|
|
29559
|
-
${END}
|
|
29560
|
-
` : ` ${START}
|
|
29561
|
-
@Override
|
|
29562
|
-
public void onCreate(android.os.Bundle savedInstanceState) {
|
|
29563
|
-
AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot(this);
|
|
29564
|
-
registerPlugin(AbsoluteMobileUpdateWatchdogPlugin.class);
|
|
29565
|
-
super.onCreate(savedInstanceState);
|
|
29566
|
-
}
|
|
29567
|
-
${END}
|
|
29568
|
-
`;
|
|
29569
30543
|
const separator = source[close - 1] === `
|
|
29570
30544
|
` ? "" : `
|
|
29571
30545
|
`;
|
|
29572
|
-
return `${source.slice(0, close)}${separator}${
|
|
30546
|
+
return `${source.slice(0, close)}${separator}${androidRegion2(kotlin, true)}${source.slice(close)}`;
|
|
29573
30547
|
};
|
|
29574
|
-
var
|
|
29575
|
-
const activityPath = await
|
|
29576
|
-
const activity = await
|
|
30548
|
+
var configureAndroid4 = async (config, enabled) => {
|
|
30549
|
+
const activityPath = await androidActivity2(config);
|
|
30550
|
+
const activity = await readFile21(activityPath, "utf8");
|
|
29577
30551
|
const packageName = activity.match(/^\s*package\s+([A-Za-z0-9_.]+)\s*[;\n]/mu)?.[1];
|
|
29578
30552
|
if (!packageName)
|
|
29579
30553
|
throw new TypeError("Android MainActivity package declaration was not found.");
|
|
29580
|
-
const
|
|
29581
|
-
const pluginPath = join22(config.nativeProjectDirectory, "android/app/src/main/java", packagePath, ANDROID_PLUGIN);
|
|
30554
|
+
const pluginPath = join24(config.nativeProjectDirectory, "android/app/src/main/java", packageName.replaceAll(".", "/"), ANDROID_PLUGIN2);
|
|
29582
30555
|
const changed = await Promise.all([
|
|
29583
|
-
|
|
29584
|
-
enabled ?
|
|
30556
|
+
writeChanged2(activityPath, injectAndroidActivity2(activity, enabled)),
|
|
30557
|
+
enabled ? writeChanged2(pluginPath, androidPluginSource2(packageName)) : removeOwnedFile2(pluginPath)
|
|
29585
30558
|
]);
|
|
29586
30559
|
return changed.some(Boolean);
|
|
29587
30560
|
};
|
|
29588
|
-
var
|
|
30561
|
+
var applyAbsoluteNativeObservability = async (config, platforms = config.platforms) => {
|
|
29589
30562
|
if (config.engine !== "capacitor")
|
|
29590
30563
|
return { changed: false };
|
|
29591
|
-
const enabled = config.
|
|
30564
|
+
const enabled = config.observability !== undefined;
|
|
29592
30565
|
const changed = [];
|
|
29593
30566
|
if (platforms.includes("ios"))
|
|
29594
|
-
changed.push(await
|
|
30567
|
+
changed.push(await configureIos4(config, enabled));
|
|
29595
30568
|
if (platforms.includes("android"))
|
|
29596
|
-
changed.push(await
|
|
30569
|
+
changed.push(await configureAndroid4(config, enabled));
|
|
29597
30570
|
return { changed: changed.some(Boolean) };
|
|
29598
30571
|
};
|
|
29599
30572
|
// src/mobile/releasePublisher.ts
|
|
@@ -29621,8 +30594,8 @@ var prepareAbsoluteAndroidRelease = async (publisher, options) => {
|
|
|
29621
30594
|
}
|
|
29622
30595
|
return versionCode;
|
|
29623
30596
|
};
|
|
29624
|
-
var
|
|
29625
|
-
var isPublisher = (value) =>
|
|
30597
|
+
var isRecord13 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30598
|
+
var isPublisher = (value) => isRecord13(value) && typeof value.publish === "function";
|
|
29626
30599
|
var publisherModulePath = (projectRoot, requested) => {
|
|
29627
30600
|
const root = resolve16(projectRoot);
|
|
29628
30601
|
const path = resolve16(root, requested);
|
|
@@ -29638,7 +30611,7 @@ var loadAbsoluteNativeReleasePublisher = async (projectRoot, requestedModulePath
|
|
|
29638
30611
|
throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
|
|
29639
30612
|
});
|
|
29640
30613
|
const loaded = await import(pathToFileURL3(modulePath).href);
|
|
29641
|
-
const publisher =
|
|
30614
|
+
const publisher = isRecord13(loaded) ? loaded.default ?? loaded.registry : undefined;
|
|
29642
30615
|
if (!isPublisher(publisher)) {
|
|
29643
30616
|
throw new TypeError("Native release registry module must default-export a registry with publish(options).");
|
|
29644
30617
|
}
|
|
@@ -29696,7 +30669,7 @@ var publishAbsoluteIosRelease = async (options) => {
|
|
|
29696
30669
|
};
|
|
29697
30670
|
// src/mobile/routeMetadataTransform.ts
|
|
29698
30671
|
import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
|
|
29699
|
-
import { dirname as
|
|
30672
|
+
import { dirname as dirname17, extname as extname6, relative as relative14, resolve as resolve17 } from "path";
|
|
29700
30673
|
import ts2 from "typescript";
|
|
29701
30674
|
var ROUTE_METHODS = new Set(["get", "head"]);
|
|
29702
30675
|
var SOURCE_FILTER = /\.[cm]?[jt]sx?$/;
|
|
@@ -29747,7 +30720,7 @@ var PAGE_HANDLERS = new Map([
|
|
|
29747
30720
|
]
|
|
29748
30721
|
]);
|
|
29749
30722
|
var posixPath = (value) => value.replace(/\\/g, "/");
|
|
29750
|
-
var findTsconfig = (entry, projectRoot) => ts2.findConfigFile(
|
|
30723
|
+
var findTsconfig = (entry, projectRoot) => ts2.findConfigFile(dirname17(entry), existsSync7, "tsconfig.json") ?? ts2.findConfigFile(projectRoot, existsSync7, "tsconfig.json");
|
|
29751
30724
|
var createProgram = (entry, projectRoot) => {
|
|
29752
30725
|
const configPath2 = findTsconfig(entry, projectRoot);
|
|
29753
30726
|
if (!configPath2) {
|
|
@@ -29759,7 +30732,7 @@ var createProgram = (entry, projectRoot) => {
|
|
|
29759
30732
|
target: ts2.ScriptTarget.ESNext
|
|
29760
30733
|
});
|
|
29761
30734
|
}
|
|
29762
|
-
const parsed = ts2.parseJsonConfigFileContent(ts2.readConfigFile(configPath2, (path) => readFileSync8(path, "utf8")).config, ts2.sys,
|
|
30735
|
+
const parsed = ts2.parseJsonConfigFileContent(ts2.readConfigFile(configPath2, (path) => readFileSync8(path, "utf8")).config, ts2.sys, dirname17(configPath2));
|
|
29763
30736
|
if (!parsed.fileNames.includes(entry))
|
|
29764
30737
|
parsed.fileNames.push(entry);
|
|
29765
30738
|
return ts2.createProgram(parsed.fileNames, parsed.options);
|
|
@@ -30428,6 +31401,627 @@ var http = createAbsoluteHttpClient();
|
|
|
30428
31401
|
|
|
30429
31402
|
// src/mobile/shellHttp.ts
|
|
30430
31403
|
var installAbsoluteMobileShellHttp = (origin, fetch2 = globalThis.fetch) => installAbsoluteHttpTransport(createAbsoluteHttpTransport({ fetch: fetch2, origin, runtime: "native" }));
|
|
31404
|
+
// node_modules/@capacitor/core/dist/index.js
|
|
31405
|
+
/*! Capacitor: https://capacitorjs.com/ - MIT License */
|
|
31406
|
+
var ExceptionCode;
|
|
31407
|
+
(function(ExceptionCode2) {
|
|
31408
|
+
ExceptionCode2["Unimplemented"] = "UNIMPLEMENTED";
|
|
31409
|
+
ExceptionCode2["Unavailable"] = "UNAVAILABLE";
|
|
31410
|
+
})(ExceptionCode || (ExceptionCode = {}));
|
|
31411
|
+
|
|
31412
|
+
class CapacitorException extends Error {
|
|
31413
|
+
constructor(message, code, data) {
|
|
31414
|
+
super(message);
|
|
31415
|
+
this.message = message;
|
|
31416
|
+
this.code = code;
|
|
31417
|
+
this.data = data;
|
|
31418
|
+
}
|
|
31419
|
+
}
|
|
31420
|
+
var getPlatformId = (win) => {
|
|
31421
|
+
var _a, _b;
|
|
31422
|
+
if (win === null || win === undefined ? undefined : win.androidBridge) {
|
|
31423
|
+
return "android";
|
|
31424
|
+
} else if ((_b = (_a = win === null || win === undefined ? undefined : win.webkit) === null || _a === undefined ? undefined : _a.messageHandlers) === null || _b === undefined ? undefined : _b.bridge) {
|
|
31425
|
+
return "ios";
|
|
31426
|
+
} else {
|
|
31427
|
+
return "web";
|
|
31428
|
+
}
|
|
31429
|
+
};
|
|
31430
|
+
var createCapacitor = (win) => {
|
|
31431
|
+
const capCustomPlatform = win.CapacitorCustomPlatform || null;
|
|
31432
|
+
const cap = win.Capacitor || {};
|
|
31433
|
+
const Plugins = cap.Plugins = cap.Plugins || {};
|
|
31434
|
+
const getPlatform = () => {
|
|
31435
|
+
return capCustomPlatform !== null ? capCustomPlatform.name : getPlatformId(win);
|
|
31436
|
+
};
|
|
31437
|
+
const isNativePlatform = () => getPlatform() !== "web";
|
|
31438
|
+
const isPluginAvailable = (pluginName) => {
|
|
31439
|
+
const plugin = registeredPlugins.get(pluginName);
|
|
31440
|
+
if (plugin === null || plugin === undefined ? undefined : plugin.platforms.has(getPlatform())) {
|
|
31441
|
+
return true;
|
|
31442
|
+
}
|
|
31443
|
+
if (getPluginHeader(pluginName)) {
|
|
31444
|
+
return true;
|
|
31445
|
+
}
|
|
31446
|
+
return false;
|
|
31447
|
+
};
|
|
31448
|
+
const getPluginHeader = (pluginName) => {
|
|
31449
|
+
var _a;
|
|
31450
|
+
return (_a = cap.PluginHeaders) === null || _a === undefined ? undefined : _a.find((h) => h.name === pluginName);
|
|
31451
|
+
};
|
|
31452
|
+
const handleError = (err) => win.console.error(err);
|
|
31453
|
+
const registeredPlugins = new Map;
|
|
31454
|
+
const registerPlugin = (pluginName, jsImplementations = {}) => {
|
|
31455
|
+
const registeredPlugin = registeredPlugins.get(pluginName);
|
|
31456
|
+
if (registeredPlugin) {
|
|
31457
|
+
console.warn(`Capacitor plugin "${pluginName}" already registered. Cannot register plugins twice.`);
|
|
31458
|
+
return registeredPlugin.proxy;
|
|
31459
|
+
}
|
|
31460
|
+
const platform4 = getPlatform();
|
|
31461
|
+
const pluginHeader = getPluginHeader(pluginName);
|
|
31462
|
+
let jsImplementation;
|
|
31463
|
+
const loadPluginImplementation = async () => {
|
|
31464
|
+
if (!jsImplementation && platform4 in jsImplementations) {
|
|
31465
|
+
jsImplementation = typeof jsImplementations[platform4] === "function" ? jsImplementation = await jsImplementations[platform4]() : jsImplementation = jsImplementations[platform4];
|
|
31466
|
+
} else if (capCustomPlatform !== null && !jsImplementation && "web" in jsImplementations) {
|
|
31467
|
+
jsImplementation = typeof jsImplementations["web"] === "function" ? jsImplementation = await jsImplementations["web"]() : jsImplementation = jsImplementations["web"];
|
|
31468
|
+
}
|
|
31469
|
+
return jsImplementation;
|
|
31470
|
+
};
|
|
31471
|
+
const createPluginMethod = (impl, prop) => {
|
|
31472
|
+
var _a, _b;
|
|
31473
|
+
if (pluginHeader) {
|
|
31474
|
+
const methodHeader = pluginHeader === null || pluginHeader === undefined ? undefined : pluginHeader.methods.find((m) => prop === m.name);
|
|
31475
|
+
if (methodHeader) {
|
|
31476
|
+
if (methodHeader.rtype === "promise") {
|
|
31477
|
+
return (options) => cap.nativePromise(pluginName, prop.toString(), options);
|
|
31478
|
+
} else {
|
|
31479
|
+
return (options, callback) => cap.nativeCallback(pluginName, prop.toString(), options, callback);
|
|
31480
|
+
}
|
|
31481
|
+
} else if (impl) {
|
|
31482
|
+
return (_a = impl[prop]) === null || _a === undefined ? undefined : _a.bind(impl);
|
|
31483
|
+
}
|
|
31484
|
+
} else if (impl) {
|
|
31485
|
+
return (_b = impl[prop]) === null || _b === undefined ? undefined : _b.bind(impl);
|
|
31486
|
+
} else {
|
|
31487
|
+
throw new CapacitorException(`"${pluginName}" plugin is not implemented on ${platform4}`, ExceptionCode.Unimplemented);
|
|
31488
|
+
}
|
|
31489
|
+
};
|
|
31490
|
+
const createPluginMethodWrapper = (prop) => {
|
|
31491
|
+
let remove;
|
|
31492
|
+
const wrapper = (...args) => {
|
|
31493
|
+
const p = loadPluginImplementation().then((impl) => {
|
|
31494
|
+
const fn = createPluginMethod(impl, prop);
|
|
31495
|
+
if (fn) {
|
|
31496
|
+
const p2 = fn(...args);
|
|
31497
|
+
remove = p2 === null || p2 === undefined ? undefined : p2.remove;
|
|
31498
|
+
return p2;
|
|
31499
|
+
} else {
|
|
31500
|
+
throw new CapacitorException(`"${pluginName}.${prop}()" is not implemented on ${platform4}`, ExceptionCode.Unimplemented);
|
|
31501
|
+
}
|
|
31502
|
+
});
|
|
31503
|
+
if (prop === "addListener") {
|
|
31504
|
+
p.remove = async () => remove();
|
|
31505
|
+
}
|
|
31506
|
+
return p;
|
|
31507
|
+
};
|
|
31508
|
+
wrapper.toString = () => `${prop.toString()}() { [capacitor code] }`;
|
|
31509
|
+
Object.defineProperty(wrapper, "name", {
|
|
31510
|
+
value: prop,
|
|
31511
|
+
writable: false,
|
|
31512
|
+
configurable: false
|
|
31513
|
+
});
|
|
31514
|
+
return wrapper;
|
|
31515
|
+
};
|
|
31516
|
+
const addListener = createPluginMethodWrapper("addListener");
|
|
31517
|
+
const removeListener = createPluginMethodWrapper("removeListener");
|
|
31518
|
+
const addListenerNative = (eventName, callback) => {
|
|
31519
|
+
const call = addListener({ eventName }, callback);
|
|
31520
|
+
const remove = async () => {
|
|
31521
|
+
const callbackId = await call;
|
|
31522
|
+
removeListener({
|
|
31523
|
+
eventName,
|
|
31524
|
+
callbackId
|
|
31525
|
+
}, callback);
|
|
31526
|
+
};
|
|
31527
|
+
const p = new Promise((resolve18) => call.then(() => resolve18({ remove })));
|
|
31528
|
+
p.remove = async () => {
|
|
31529
|
+
console.warn(`Using addListener() without 'await' is deprecated.`);
|
|
31530
|
+
await remove();
|
|
31531
|
+
};
|
|
31532
|
+
return p;
|
|
31533
|
+
};
|
|
31534
|
+
const proxy = new Proxy({}, {
|
|
31535
|
+
get(_, prop) {
|
|
31536
|
+
switch (prop) {
|
|
31537
|
+
case "$$typeof":
|
|
31538
|
+
return;
|
|
31539
|
+
case "toJSON":
|
|
31540
|
+
return () => ({});
|
|
31541
|
+
case "addListener":
|
|
31542
|
+
return pluginHeader ? addListenerNative : addListener;
|
|
31543
|
+
case "removeListener":
|
|
31544
|
+
return removeListener;
|
|
31545
|
+
default:
|
|
31546
|
+
return createPluginMethodWrapper(prop);
|
|
31547
|
+
}
|
|
31548
|
+
}
|
|
31549
|
+
});
|
|
31550
|
+
Plugins[pluginName] = proxy;
|
|
31551
|
+
registeredPlugins.set(pluginName, {
|
|
31552
|
+
name: pluginName,
|
|
31553
|
+
proxy,
|
|
31554
|
+
platforms: new Set([...Object.keys(jsImplementations), ...pluginHeader ? [platform4] : []])
|
|
31555
|
+
});
|
|
31556
|
+
return proxy;
|
|
31557
|
+
};
|
|
31558
|
+
if (!cap.convertFileSrc) {
|
|
31559
|
+
cap.convertFileSrc = (filePath) => filePath;
|
|
31560
|
+
}
|
|
31561
|
+
cap.getPlatform = getPlatform;
|
|
31562
|
+
cap.handleError = handleError;
|
|
31563
|
+
cap.isNativePlatform = isNativePlatform;
|
|
31564
|
+
cap.isPluginAvailable = isPluginAvailable;
|
|
31565
|
+
cap.registerPlugin = registerPlugin;
|
|
31566
|
+
cap.Exception = CapacitorException;
|
|
31567
|
+
cap.DEBUG = !!cap.DEBUG;
|
|
31568
|
+
cap.isLoggingEnabled = !!cap.isLoggingEnabled;
|
|
31569
|
+
return cap;
|
|
31570
|
+
};
|
|
31571
|
+
var initCapacitorGlobal = (win) => win.Capacitor = createCapacitor(win);
|
|
31572
|
+
var Capacitor = /* @__PURE__ */ initCapacitorGlobal(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {});
|
|
31573
|
+
var registerPlugin = Capacitor.registerPlugin;
|
|
31574
|
+
|
|
31575
|
+
class WebPlugin {
|
|
31576
|
+
constructor() {
|
|
31577
|
+
this.listeners = {};
|
|
31578
|
+
this.retainedEventArguments = {};
|
|
31579
|
+
this.windowListeners = {};
|
|
31580
|
+
}
|
|
31581
|
+
addListener(eventName, listenerFunc) {
|
|
31582
|
+
let firstListener = false;
|
|
31583
|
+
const listeners = this.listeners[eventName];
|
|
31584
|
+
if (!listeners) {
|
|
31585
|
+
this.listeners[eventName] = [];
|
|
31586
|
+
firstListener = true;
|
|
31587
|
+
}
|
|
31588
|
+
this.listeners[eventName].push(listenerFunc);
|
|
31589
|
+
const windowListener = this.windowListeners[eventName];
|
|
31590
|
+
if (windowListener && !windowListener.registered) {
|
|
31591
|
+
this.addWindowListener(windowListener);
|
|
31592
|
+
}
|
|
31593
|
+
if (firstListener) {
|
|
31594
|
+
this.sendRetainedArgumentsForEvent(eventName);
|
|
31595
|
+
}
|
|
31596
|
+
const remove = async () => this.removeListener(eventName, listenerFunc);
|
|
31597
|
+
const p = Promise.resolve({ remove });
|
|
31598
|
+
return p;
|
|
31599
|
+
}
|
|
31600
|
+
async removeAllListeners() {
|
|
31601
|
+
this.listeners = {};
|
|
31602
|
+
for (const listener in this.windowListeners) {
|
|
31603
|
+
this.removeWindowListener(this.windowListeners[listener]);
|
|
31604
|
+
}
|
|
31605
|
+
this.windowListeners = {};
|
|
31606
|
+
}
|
|
31607
|
+
notifyListeners(eventName, data, retainUntilConsumed) {
|
|
31608
|
+
const listeners = this.listeners[eventName];
|
|
31609
|
+
if (!listeners) {
|
|
31610
|
+
if (retainUntilConsumed) {
|
|
31611
|
+
let args = this.retainedEventArguments[eventName];
|
|
31612
|
+
if (!args) {
|
|
31613
|
+
args = [];
|
|
31614
|
+
}
|
|
31615
|
+
args.push(data);
|
|
31616
|
+
this.retainedEventArguments[eventName] = args;
|
|
31617
|
+
}
|
|
31618
|
+
return;
|
|
31619
|
+
}
|
|
31620
|
+
listeners.forEach((listener) => listener(data));
|
|
31621
|
+
}
|
|
31622
|
+
hasListeners(eventName) {
|
|
31623
|
+
var _a;
|
|
31624
|
+
return !!((_a = this.listeners[eventName]) === null || _a === undefined ? undefined : _a.length);
|
|
31625
|
+
}
|
|
31626
|
+
registerWindowListener(windowEventName, pluginEventName) {
|
|
31627
|
+
this.windowListeners[pluginEventName] = {
|
|
31628
|
+
registered: false,
|
|
31629
|
+
windowEventName,
|
|
31630
|
+
pluginEventName,
|
|
31631
|
+
handler: (event) => {
|
|
31632
|
+
this.notifyListeners(pluginEventName, event);
|
|
31633
|
+
}
|
|
31634
|
+
};
|
|
31635
|
+
}
|
|
31636
|
+
unimplemented(msg = "not implemented") {
|
|
31637
|
+
return new Capacitor.Exception(msg, ExceptionCode.Unimplemented);
|
|
31638
|
+
}
|
|
31639
|
+
unavailable(msg = "not available") {
|
|
31640
|
+
return new Capacitor.Exception(msg, ExceptionCode.Unavailable);
|
|
31641
|
+
}
|
|
31642
|
+
async removeListener(eventName, listenerFunc) {
|
|
31643
|
+
const listeners = this.listeners[eventName];
|
|
31644
|
+
if (!listeners) {
|
|
31645
|
+
return;
|
|
31646
|
+
}
|
|
31647
|
+
const index = listeners.indexOf(listenerFunc);
|
|
31648
|
+
this.listeners[eventName].splice(index, 1);
|
|
31649
|
+
if (!this.listeners[eventName].length) {
|
|
31650
|
+
this.removeWindowListener(this.windowListeners[eventName]);
|
|
31651
|
+
}
|
|
31652
|
+
}
|
|
31653
|
+
addWindowListener(handle) {
|
|
31654
|
+
window.addEventListener(handle.windowEventName, handle.handler);
|
|
31655
|
+
handle.registered = true;
|
|
31656
|
+
}
|
|
31657
|
+
removeWindowListener(handle) {
|
|
31658
|
+
if (!handle) {
|
|
31659
|
+
return;
|
|
31660
|
+
}
|
|
31661
|
+
window.removeEventListener(handle.windowEventName, handle.handler);
|
|
31662
|
+
handle.registered = false;
|
|
31663
|
+
}
|
|
31664
|
+
sendRetainedArgumentsForEvent(eventName) {
|
|
31665
|
+
const args = this.retainedEventArguments[eventName];
|
|
31666
|
+
if (!args) {
|
|
31667
|
+
return;
|
|
31668
|
+
}
|
|
31669
|
+
delete this.retainedEventArguments[eventName];
|
|
31670
|
+
args.forEach((arg) => {
|
|
31671
|
+
this.notifyListeners(eventName, arg);
|
|
31672
|
+
});
|
|
31673
|
+
}
|
|
31674
|
+
}
|
|
31675
|
+
var encode = (str) => encodeURIComponent(str).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent).replace(/[()]/g, escape);
|
|
31676
|
+
var decode = (str) => str.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent);
|
|
31677
|
+
|
|
31678
|
+
class CapacitorCookiesPluginWeb extends WebPlugin {
|
|
31679
|
+
async getCookies() {
|
|
31680
|
+
const cookies = document.cookie;
|
|
31681
|
+
const cookieMap = {};
|
|
31682
|
+
cookies.split(";").forEach((cookie) => {
|
|
31683
|
+
if (cookie.length <= 0)
|
|
31684
|
+
return;
|
|
31685
|
+
let [key, value] = cookie.replace(/=/, "CAP_COOKIE").split("CAP_COOKIE");
|
|
31686
|
+
key = decode(key).trim();
|
|
31687
|
+
value = decode(value).trim();
|
|
31688
|
+
cookieMap[key] = value;
|
|
31689
|
+
});
|
|
31690
|
+
return cookieMap;
|
|
31691
|
+
}
|
|
31692
|
+
async setCookie(options) {
|
|
31693
|
+
try {
|
|
31694
|
+
const encodedKey = encode(options.key);
|
|
31695
|
+
const encodedValue = encode(options.value);
|
|
31696
|
+
const expires = options.expires ? `; expires=${options.expires.replace("expires=", "")}` : "";
|
|
31697
|
+
const path = (options.path || "/").replace("path=", "");
|
|
31698
|
+
const domain = options.url != null && options.url.length > 0 ? `domain=${options.url}` : "";
|
|
31699
|
+
document.cookie = `${encodedKey}=${encodedValue || ""}${expires}; path=${path}; ${domain};`;
|
|
31700
|
+
} catch (error) {
|
|
31701
|
+
return Promise.reject(error);
|
|
31702
|
+
}
|
|
31703
|
+
}
|
|
31704
|
+
async deleteCookie(options) {
|
|
31705
|
+
try {
|
|
31706
|
+
document.cookie = `${options.key}=; Max-Age=0`;
|
|
31707
|
+
} catch (error) {
|
|
31708
|
+
return Promise.reject(error);
|
|
31709
|
+
}
|
|
31710
|
+
}
|
|
31711
|
+
async clearCookies() {
|
|
31712
|
+
try {
|
|
31713
|
+
const cookies = document.cookie.split(";") || [];
|
|
31714
|
+
for (const cookie of cookies) {
|
|
31715
|
+
document.cookie = cookie.replace(/^ +/, "").replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`);
|
|
31716
|
+
}
|
|
31717
|
+
} catch (error) {
|
|
31718
|
+
return Promise.reject(error);
|
|
31719
|
+
}
|
|
31720
|
+
}
|
|
31721
|
+
async clearAllCookies() {
|
|
31722
|
+
try {
|
|
31723
|
+
await this.clearCookies();
|
|
31724
|
+
} catch (error) {
|
|
31725
|
+
return Promise.reject(error);
|
|
31726
|
+
}
|
|
31727
|
+
}
|
|
31728
|
+
}
|
|
31729
|
+
var CapacitorCookies = registerPlugin("CapacitorCookies", {
|
|
31730
|
+
web: () => new CapacitorCookiesPluginWeb
|
|
31731
|
+
});
|
|
31732
|
+
var readBlobAsBase64 = async (blob) => new Promise((resolve18, reject) => {
|
|
31733
|
+
const reader = new FileReader;
|
|
31734
|
+
reader.onload = () => {
|
|
31735
|
+
const base64String = reader.result;
|
|
31736
|
+
resolve18(base64String.indexOf(",") >= 0 ? base64String.split(",")[1] : base64String);
|
|
31737
|
+
};
|
|
31738
|
+
reader.onerror = (error) => reject(error);
|
|
31739
|
+
reader.readAsDataURL(blob);
|
|
31740
|
+
});
|
|
31741
|
+
var normalizeHttpHeaders = (headers = {}) => {
|
|
31742
|
+
const originalKeys = Object.keys(headers);
|
|
31743
|
+
const loweredKeys = Object.keys(headers).map((k) => k.toLocaleLowerCase());
|
|
31744
|
+
const normalized = loweredKeys.reduce((acc, key, index) => {
|
|
31745
|
+
acc[key] = headers[originalKeys[index]];
|
|
31746
|
+
return acc;
|
|
31747
|
+
}, {});
|
|
31748
|
+
return normalized;
|
|
31749
|
+
};
|
|
31750
|
+
var buildUrlParams = (params, shouldEncode = true) => {
|
|
31751
|
+
if (!params)
|
|
31752
|
+
return null;
|
|
31753
|
+
const output = Object.entries(params).reduce((accumulator, entry) => {
|
|
31754
|
+
const [key, value] = entry;
|
|
31755
|
+
let encodedValue;
|
|
31756
|
+
let item;
|
|
31757
|
+
if (Array.isArray(value)) {
|
|
31758
|
+
item = "";
|
|
31759
|
+
value.forEach((str) => {
|
|
31760
|
+
encodedValue = shouldEncode ? encodeURIComponent(str) : str;
|
|
31761
|
+
item += `${key}=${encodedValue}&`;
|
|
31762
|
+
});
|
|
31763
|
+
item.slice(0, -1);
|
|
31764
|
+
} else {
|
|
31765
|
+
encodedValue = shouldEncode ? encodeURIComponent(value) : value;
|
|
31766
|
+
item = `${key}=${encodedValue}`;
|
|
31767
|
+
}
|
|
31768
|
+
return `${accumulator}&${item}`;
|
|
31769
|
+
}, "");
|
|
31770
|
+
return output.substr(1);
|
|
31771
|
+
};
|
|
31772
|
+
var buildRequestInit = (options, extra = {}) => {
|
|
31773
|
+
const output = Object.assign({ method: options.method || "GET", headers: options.headers }, extra);
|
|
31774
|
+
const headers = normalizeHttpHeaders(options.headers);
|
|
31775
|
+
const type = headers["content-type"] || "";
|
|
31776
|
+
if (typeof options.data === "string") {
|
|
31777
|
+
output.body = options.data;
|
|
31778
|
+
} else if (type.includes("application/x-www-form-urlencoded")) {
|
|
31779
|
+
const params = new URLSearchParams;
|
|
31780
|
+
for (const [key, value] of Object.entries(options.data || {})) {
|
|
31781
|
+
params.set(key, value);
|
|
31782
|
+
}
|
|
31783
|
+
output.body = params.toString();
|
|
31784
|
+
} else if (type.includes("multipart/form-data") || options.data instanceof FormData) {
|
|
31785
|
+
const form = new FormData;
|
|
31786
|
+
if (options.data instanceof FormData) {
|
|
31787
|
+
options.data.forEach((value, key) => {
|
|
31788
|
+
form.append(key, value);
|
|
31789
|
+
});
|
|
31790
|
+
} else {
|
|
31791
|
+
for (const key of Object.keys(options.data)) {
|
|
31792
|
+
form.append(key, options.data[key]);
|
|
31793
|
+
}
|
|
31794
|
+
}
|
|
31795
|
+
output.body = form;
|
|
31796
|
+
const headers2 = new Headers(output.headers);
|
|
31797
|
+
headers2.delete("content-type");
|
|
31798
|
+
output.headers = headers2;
|
|
31799
|
+
} else if (type.includes("application/json") || typeof options.data === "object") {
|
|
31800
|
+
output.body = JSON.stringify(options.data);
|
|
31801
|
+
}
|
|
31802
|
+
return output;
|
|
31803
|
+
};
|
|
31804
|
+
|
|
31805
|
+
class CapacitorHttpPluginWeb extends WebPlugin {
|
|
31806
|
+
async request(options) {
|
|
31807
|
+
const requestInit = buildRequestInit(options, options.webFetchExtra);
|
|
31808
|
+
const urlParams = buildUrlParams(options.params, options.shouldEncodeUrlParams);
|
|
31809
|
+
const url = urlParams ? `${options.url}?${urlParams}` : options.url;
|
|
31810
|
+
const response = await fetch(url, requestInit);
|
|
31811
|
+
const contentType = response.headers.get("content-type") || "";
|
|
31812
|
+
let { responseType = "text" } = response.ok ? options : {};
|
|
31813
|
+
if (contentType.includes("application/json")) {
|
|
31814
|
+
responseType = "json";
|
|
31815
|
+
}
|
|
31816
|
+
let data;
|
|
31817
|
+
let blob;
|
|
31818
|
+
switch (responseType) {
|
|
31819
|
+
case "arraybuffer":
|
|
31820
|
+
case "blob":
|
|
31821
|
+
blob = await response.blob();
|
|
31822
|
+
data = await readBlobAsBase64(blob);
|
|
31823
|
+
break;
|
|
31824
|
+
case "json":
|
|
31825
|
+
data = await response.json();
|
|
31826
|
+
break;
|
|
31827
|
+
case "document":
|
|
31828
|
+
case "text":
|
|
31829
|
+
default:
|
|
31830
|
+
data = await response.text();
|
|
31831
|
+
}
|
|
31832
|
+
const headers = {};
|
|
31833
|
+
response.headers.forEach((value, key) => {
|
|
31834
|
+
headers[key] = value;
|
|
31835
|
+
});
|
|
31836
|
+
return {
|
|
31837
|
+
data,
|
|
31838
|
+
headers,
|
|
31839
|
+
status: response.status,
|
|
31840
|
+
url: response.url
|
|
31841
|
+
};
|
|
31842
|
+
}
|
|
31843
|
+
async get(options) {
|
|
31844
|
+
return this.request(Object.assign(Object.assign({}, options), { method: "GET" }));
|
|
31845
|
+
}
|
|
31846
|
+
async post(options) {
|
|
31847
|
+
return this.request(Object.assign(Object.assign({}, options), { method: "POST" }));
|
|
31848
|
+
}
|
|
31849
|
+
async put(options) {
|
|
31850
|
+
return this.request(Object.assign(Object.assign({}, options), { method: "PUT" }));
|
|
31851
|
+
}
|
|
31852
|
+
async patch(options) {
|
|
31853
|
+
return this.request(Object.assign(Object.assign({}, options), { method: "PATCH" }));
|
|
31854
|
+
}
|
|
31855
|
+
async delete(options) {
|
|
31856
|
+
return this.request(Object.assign(Object.assign({}, options), { method: "DELETE" }));
|
|
31857
|
+
}
|
|
31858
|
+
}
|
|
31859
|
+
var CapacitorHttp = registerPlugin("CapacitorHttp", {
|
|
31860
|
+
web: () => new CapacitorHttpPluginWeb
|
|
31861
|
+
});
|
|
31862
|
+
var SystemBarsStyle;
|
|
31863
|
+
(function(SystemBarsStyle2) {
|
|
31864
|
+
SystemBarsStyle2["Dark"] = "DARK";
|
|
31865
|
+
SystemBarsStyle2["Light"] = "LIGHT";
|
|
31866
|
+
SystemBarsStyle2["Default"] = "DEFAULT";
|
|
31867
|
+
})(SystemBarsStyle || (SystemBarsStyle = {}));
|
|
31868
|
+
var SystemBarType;
|
|
31869
|
+
(function(SystemBarType2) {
|
|
31870
|
+
SystemBarType2["StatusBar"] = "StatusBar";
|
|
31871
|
+
SystemBarType2["NavigationBar"] = "NavigationBar";
|
|
31872
|
+
})(SystemBarType || (SystemBarType = {}));
|
|
31873
|
+
|
|
31874
|
+
class SystemBarsPluginWeb extends WebPlugin {
|
|
31875
|
+
async setStyle() {
|
|
31876
|
+
this.unavailable("not available for web");
|
|
31877
|
+
}
|
|
31878
|
+
async setAnimation() {
|
|
31879
|
+
this.unavailable("not available for web");
|
|
31880
|
+
}
|
|
31881
|
+
async show() {
|
|
31882
|
+
this.unavailable("not available for web");
|
|
31883
|
+
}
|
|
31884
|
+
async hide() {
|
|
31885
|
+
this.unavailable("not available for web");
|
|
31886
|
+
}
|
|
31887
|
+
}
|
|
31888
|
+
var SystemBars = registerPlugin("SystemBars", {
|
|
31889
|
+
web: () => new SystemBarsPluginWeb
|
|
31890
|
+
});
|
|
31891
|
+
|
|
31892
|
+
// src/mobile/shellNativeObservability.ts
|
|
31893
|
+
var MAX_REPORTS = 8;
|
|
31894
|
+
var MAX_DETAIL_BYTES = 64 * 1024;
|
|
31895
|
+
var MAX_STRING_LENGTH = 8 * 1024;
|
|
31896
|
+
var MAX_REDACTION_DEPTH = 8;
|
|
31897
|
+
var REPORT_ID = /^[A-Za-z0-9._:-]{1,128}$/u;
|
|
31898
|
+
var REPORT_KINDS = new Set([
|
|
31899
|
+
"anr",
|
|
31900
|
+
"app-launch",
|
|
31901
|
+
"cpu-exception",
|
|
31902
|
+
"crash",
|
|
31903
|
+
"disk-write-exception",
|
|
31904
|
+
"hang",
|
|
31905
|
+
"initialization-failure",
|
|
31906
|
+
"low-memory",
|
|
31907
|
+
"native-crash",
|
|
31908
|
+
"resource-exhaustion",
|
|
31909
|
+
"signal"
|
|
31910
|
+
]);
|
|
31911
|
+
var nativeObservability = registerPlugin("AbsoluteMobileObservability");
|
|
31912
|
+
var isRecord14 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31913
|
+
var redactText = (value) => value.slice(0, MAX_STRING_LENGTH).replace(/\b(Bearer)\s+[A-Za-z0-9._~+/-]+=*/giu, "$1 [REDACTED]").replace(/([?&](?:access_token|api_?key|authorization|code|id_token|password|refresh_token|secret|token)=)[^&#\s]*/giu, "$1[REDACTED]").replace(/\b((?:access_?token|api_?key|authorization|client_?secret|cookie|id_?token|password|passwd|refresh_?token|secret|token)\s*[:=]\s*)[^,\s;]+/giu, "$1[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu, "[REDACTED]");
|
|
31914
|
+
var redactValue = (value, depth = 0) => {
|
|
31915
|
+
if (depth >= MAX_REDACTION_DEPTH)
|
|
31916
|
+
return "[TRUNCATED]";
|
|
31917
|
+
if (typeof value === "string")
|
|
31918
|
+
return redactText(value);
|
|
31919
|
+
if (value === null || typeof value === "number" || typeof value === "boolean")
|
|
31920
|
+
return value;
|
|
31921
|
+
if (Array.isArray(value))
|
|
31922
|
+
return value.slice(0, 64).map((entry) => redactValue(entry, depth + 1));
|
|
31923
|
+
if (!isRecord14(value))
|
|
31924
|
+
return String(value).slice(0, MAX_STRING_LENGTH);
|
|
31925
|
+
return Object.fromEntries(Object.entries(value).slice(0, 128).map(([key, entry]) => [
|
|
31926
|
+
key,
|
|
31927
|
+
/(?:authorization|cookie|password|secret|token)/iu.test(key) ? "[REDACTED]" : redactValue(entry, depth + 1)
|
|
31928
|
+
]));
|
|
31929
|
+
};
|
|
31930
|
+
var parseReport = (value) => {
|
|
31931
|
+
if (!isRecord14(value) || !isRecord14(value.details))
|
|
31932
|
+
return;
|
|
31933
|
+
if (typeof value.id !== "string" || !REPORT_ID.test(value.id))
|
|
31934
|
+
return;
|
|
31935
|
+
if (typeof value.kind !== "string" || !REPORT_KINDS.has(value.kind))
|
|
31936
|
+
return;
|
|
31937
|
+
if (typeof value.occurredAt !== "number" || !Number.isFinite(value.occurredAt) || value.occurredAt <= 0)
|
|
31938
|
+
return;
|
|
31939
|
+
if (value.platform !== "android" && value.platform !== "ios")
|
|
31940
|
+
return;
|
|
31941
|
+
const details = redactValue(value.details);
|
|
31942
|
+
if (!isRecord14(details))
|
|
31943
|
+
return;
|
|
31944
|
+
if (new TextEncoder().encode(JSON.stringify(details)).byteLength > MAX_DETAIL_BYTES)
|
|
31945
|
+
return;
|
|
31946
|
+
return {
|
|
31947
|
+
details,
|
|
31948
|
+
id: value.id,
|
|
31949
|
+
kind: value.kind,
|
|
31950
|
+
occurredAt: value.occurredAt,
|
|
31951
|
+
platform: value.platform
|
|
31952
|
+
};
|
|
31953
|
+
};
|
|
31954
|
+
var sampled = (id, sampleRate) => {
|
|
31955
|
+
if (sampleRate >= 1)
|
|
31956
|
+
return true;
|
|
31957
|
+
let hash = 2166136261;
|
|
31958
|
+
for (const character of id) {
|
|
31959
|
+
hash ^= character.codePointAt(0) ?? 0;
|
|
31960
|
+
hash = Math.imul(hash, 16777619);
|
|
31961
|
+
}
|
|
31962
|
+
return (hash >>> 0) / 4294967296 < sampleRate;
|
|
31963
|
+
};
|
|
31964
|
+
var reportEvent = (report, manifest) => ({
|
|
31965
|
+
at: report.occurredAt,
|
|
31966
|
+
extra: {
|
|
31967
|
+
nativeDiagnostic: report.details,
|
|
31968
|
+
nativeDiagnosticId: report.id
|
|
31969
|
+
},
|
|
31970
|
+
groupingKey: `absolute-native:${report.platform}:${report.kind}`,
|
|
31971
|
+
level: [
|
|
31972
|
+
"app-launch",
|
|
31973
|
+
"cpu-exception",
|
|
31974
|
+
"disk-write-exception",
|
|
31975
|
+
"low-memory",
|
|
31976
|
+
"resource-exhaustion",
|
|
31977
|
+
"signal"
|
|
31978
|
+
].includes(report.kind) ? "warning" : "error",
|
|
31979
|
+
message: `Native process diagnostic \u2014 ${report.kind}`,
|
|
31980
|
+
name: "AbsoluteMobileNativeDiagnostic",
|
|
31981
|
+
tags: {
|
|
31982
|
+
absoluteMobile: "true",
|
|
31983
|
+
mobileAppBuild: manifest.appBuild,
|
|
31984
|
+
mobileFailurePhase: "native-process",
|
|
31985
|
+
mobileManifestFormat: String(manifest.format),
|
|
31986
|
+
mobileNativeRuntime: manifest.nativeRuntime,
|
|
31987
|
+
mobilePlatform: report.platform,
|
|
31988
|
+
mobileRuntime: manifest.runtime
|
|
31989
|
+
}
|
|
31990
|
+
});
|
|
31991
|
+
var drainAbsoluteMobileNativeObservability = async (manifest, fetch2, options = {}) => {
|
|
31992
|
+
const config = manifest.observability;
|
|
31993
|
+
if (!config || !(options.native ?? Capacitor.isNativePlatform()))
|
|
31994
|
+
return 0;
|
|
31995
|
+
const plugin = options.plugin ?? nativeObservability;
|
|
31996
|
+
const pending = await plugin.pending();
|
|
31997
|
+
const reports = pending.reports.slice(0, MAX_REPORTS).map(parseReport).filter((report) => report !== undefined);
|
|
31998
|
+
const discarded = reports.filter((report) => !sampled(report.id, config.sampleRate));
|
|
31999
|
+
if (discarded.length > 0)
|
|
32000
|
+
await plugin.acknowledge({
|
|
32001
|
+
ids: discarded.map(({ id }) => id)
|
|
32002
|
+
});
|
|
32003
|
+
const selected = reports.filter((report) => sampled(report.id, config.sampleRate));
|
|
32004
|
+
if (selected.length === 0)
|
|
32005
|
+
return 0;
|
|
32006
|
+
const envelope = {
|
|
32007
|
+
...config.environment ? { environment: config.environment } : {},
|
|
32008
|
+
events: selected.map((report) => reportEvent(report, manifest)),
|
|
32009
|
+
project: config.project,
|
|
32010
|
+
release: manifest.appBuild,
|
|
32011
|
+
v: 1
|
|
32012
|
+
};
|
|
32013
|
+
const response = await fetch2(config.endpoint, {
|
|
32014
|
+
body: JSON.stringify(envelope),
|
|
32015
|
+
headers: { "content-type": "application/json" },
|
|
32016
|
+
method: "POST"
|
|
32017
|
+
});
|
|
32018
|
+
if (!response.ok)
|
|
32019
|
+
return 0;
|
|
32020
|
+
await plugin.acknowledge({
|
|
32021
|
+
ids: selected.map(({ id }) => id)
|
|
32022
|
+
});
|
|
32023
|
+
return selected.length;
|
|
32024
|
+
};
|
|
30431
32025
|
// node_modules/@absolutejs/beacon/dist/index.js
|
|
30432
32026
|
var BEACON_SIGNAL = {
|
|
30433
32027
|
AUTH_FAILURE_STORM: "auth_failure_storm",
|
|
@@ -30703,7 +32297,7 @@ var redactUrl = (value) => {
|
|
|
30703
32297
|
};
|
|
30704
32298
|
var redactUrlsInText = (value) => value.replace(/(?:[a-z][a-z\d+.-]*:\/\/|\/)[^\s"'<>]*[?#][^\s"'<>]*/gi, (candidate) => redactUrl(candidate));
|
|
30705
32299
|
var redactString = (value) => redactUrlsInText(value).replace(/\b(Bearer)\s+[A-Za-z0-9._~+/-]+=*/gi, (_match, scheme) => `${scheme} ${REDACTED}`).replace(/([?&](?:access_token|api_?key|authorization|code|id_token|password|refresh_token|secret|token)=)[^&#\s]*/gi, `$1${REDACTED}`).replace(/\b((?:access_?token|api_?key|authorization|client_?secret|cookie|id_?token|password|passwd|refresh_?token|secret|token)\s*[:=]\s*)(?!Bearer\b|\[REDACTED\])[^,\s;]+/gi, `$1${REDACTED}`).replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, REDACTED);
|
|
30706
|
-
var
|
|
32300
|
+
var redactValue2 = (value, key, seen, depth = 0) => {
|
|
30707
32301
|
if (key !== undefined && isSensitiveField(key))
|
|
30708
32302
|
return REDACTED;
|
|
30709
32303
|
if (typeof value === "string") {
|
|
@@ -30721,9 +32315,9 @@ var redactValue = (value, key, seen, depth = 0) => {
|
|
|
30721
32315
|
if (seen.has(value))
|
|
30722
32316
|
return "[Circular]";
|
|
30723
32317
|
seen.add(value);
|
|
30724
|
-
const redacted = Array.isArray(value) ? value.map((entry) =>
|
|
32318
|
+
const redacted = Array.isArray(value) ? value.map((entry) => redactValue2(entry, undefined, seen, depth + 1)) : Object.fromEntries(Object.entries(value).map(([field2, entry]) => [
|
|
30725
32319
|
field2,
|
|
30726
|
-
|
|
32320
|
+
redactValue2(entry, field2, seen, depth + 1)
|
|
30727
32321
|
]));
|
|
30728
32322
|
seen.delete(value);
|
|
30729
32323
|
return redacted;
|
|
@@ -30741,11 +32335,11 @@ var redactBeaconEvent = (event) => {
|
|
|
30741
32335
|
if (event.tags !== undefined) {
|
|
30742
32336
|
redacted.tags = Object.fromEntries(Object.entries(event.tags).map(([key, value]) => [
|
|
30743
32337
|
key,
|
|
30744
|
-
|
|
32338
|
+
redactValue2(value, key, new Set)
|
|
30745
32339
|
]));
|
|
30746
32340
|
}
|
|
30747
32341
|
if (event.extra !== undefined) {
|
|
30748
|
-
redacted.extra =
|
|
32342
|
+
redacted.extra = redactValue2(event.extra, undefined, new Set);
|
|
30749
32343
|
}
|
|
30750
32344
|
return redacted;
|
|
30751
32345
|
};
|
|
@@ -32790,9 +34384,9 @@ var createBeacon = (options) => {
|
|
|
32790
34384
|
const viewportWidth = document.documentElement.clientWidth;
|
|
32791
34385
|
const viewportHeight = document.documentElement.clientHeight;
|
|
32792
34386
|
const controls = document.querySelectorAll(CONTROL_SELECTOR);
|
|
32793
|
-
let
|
|
34387
|
+
let sampled2 = 0;
|
|
32794
34388
|
for (const control of Array.from(controls)) {
|
|
32795
|
-
if (
|
|
34389
|
+
if (sampled2 >= OCCLUSION_SAMPLE_LIMIT)
|
|
32796
34390
|
return;
|
|
32797
34391
|
if (isScanExempt(control) || hasHiddenAncestor(control, true))
|
|
32798
34392
|
continue;
|
|
@@ -32802,7 +34396,7 @@ var createBeacon = (options) => {
|
|
|
32802
34396
|
const visibleRect = visibleControlRect(control, rect, viewportWidth, viewportHeight);
|
|
32803
34397
|
if (visibleRect === null)
|
|
32804
34398
|
continue;
|
|
32805
|
-
|
|
34399
|
+
sampled2 += 1;
|
|
32806
34400
|
const top = document.elementFromPoint((visibleRect.left + visibleRect.right) / 2, (visibleRect.top + visibleRect.bottom) / 2);
|
|
32807
34401
|
if (top === null || top === control || control.contains(top) || top.contains(control) || crossesDialogBoundary(control, top) || isExtensionOwnedCover(top)) {
|
|
32808
34402
|
continue;
|
|
@@ -32946,9 +34540,9 @@ var createBeacon = (options) => {
|
|
|
32946
34540
|
...Array.from(priorityCandidates),
|
|
32947
34541
|
...Array.from(proseCandidates)
|
|
32948
34542
|
];
|
|
32949
|
-
let
|
|
34543
|
+
let sampled2 = 0;
|
|
32950
34544
|
for (const element of candidates) {
|
|
32951
|
-
if (
|
|
34545
|
+
if (sampled2 >= INVISIBLE_TEXT_SAMPLE_LIMIT)
|
|
32952
34546
|
return;
|
|
32953
34547
|
if (isScanExempt(element))
|
|
32954
34548
|
continue;
|
|
@@ -32966,7 +34560,7 @@ var createBeacon = (options) => {
|
|
|
32966
34560
|
const foreground = parseColor(style.color);
|
|
32967
34561
|
if (foreground === null)
|
|
32968
34562
|
continue;
|
|
32969
|
-
|
|
34563
|
+
sampled2 += 1;
|
|
32970
34564
|
const background = effectiveBackground(element);
|
|
32971
34565
|
if (background === null)
|
|
32972
34566
|
continue;
|
|
@@ -33009,11 +34603,11 @@ var createBeacon = (options) => {
|
|
|
33009
34603
|
const roots = document.querySelectorAll(`[${BEACON_ATTRIBUTE.THEME}="adaptive"]`);
|
|
33010
34604
|
const viewportWidth = document.documentElement.clientWidth;
|
|
33011
34605
|
const viewportHeight = document.documentElement.clientHeight;
|
|
33012
|
-
let
|
|
34606
|
+
let sampled2 = 0;
|
|
33013
34607
|
for (const root of Array.from(roots)) {
|
|
33014
34608
|
const candidates = [root, ...Array.from(root.querySelectorAll("*"))];
|
|
33015
34609
|
for (const element of candidates) {
|
|
33016
|
-
if (
|
|
34610
|
+
if (sampled2 >= THEME_SURFACE_SAMPLE_LIMIT)
|
|
33017
34611
|
return;
|
|
33018
34612
|
if (element.closest(`[${BEACON_ATTRIBUTE.THEME}="allow"]`) !== null || isScanExempt(element) || element.matches("canvas, iframe, img, picture, svg, video")) {
|
|
33019
34613
|
continue;
|
|
@@ -33035,7 +34629,7 @@ var createBeacon = (options) => {
|
|
|
33035
34629
|
const surface = parseColor(style.backgroundColor);
|
|
33036
34630
|
if (surface === null || surface.a < 0.95)
|
|
33037
34631
|
continue;
|
|
33038
|
-
|
|
34632
|
+
sampled2 += 1;
|
|
33039
34633
|
const luminance = relativeLuminance(surface);
|
|
33040
34634
|
const opposite = theme === "dark" ? luminance >= THEME_LIGHT_SURFACE_LUMINANCE_MIN : luminance <= THEME_DARK_SURFACE_LUMINANCE_MAX;
|
|
33041
34635
|
if (!opposite)
|
|
@@ -35599,23 +37193,23 @@ import { pathToFileURL as pathToFileURL4 } from "url";
|
|
|
35599
37193
|
import { createHash as createHash13, sign, verify } from "crypto";
|
|
35600
37194
|
import {
|
|
35601
37195
|
cp as cp3,
|
|
35602
|
-
mkdir as
|
|
37196
|
+
mkdir as mkdir17,
|
|
35603
37197
|
mkdtemp as mkdtemp8,
|
|
35604
|
-
readdir as
|
|
35605
|
-
readFile as
|
|
35606
|
-
rename as
|
|
35607
|
-
rm as
|
|
37198
|
+
readdir as readdir7,
|
|
37199
|
+
readFile as readFile22,
|
|
37200
|
+
rename as rename16,
|
|
37201
|
+
rm as rm13,
|
|
35608
37202
|
stat as stat4,
|
|
35609
|
-
writeFile as
|
|
37203
|
+
writeFile as writeFile20
|
|
35610
37204
|
} from "fs/promises";
|
|
35611
|
-
import { dirname as
|
|
37205
|
+
import { dirname as dirname18, join as join25, relative as relative15, resolve as resolve18 } from "path";
|
|
35612
37206
|
var UPDATE_MANIFEST_FILE = "update.json";
|
|
35613
37207
|
var UPDATE_FILES_DIRECTORY = "files";
|
|
35614
37208
|
var sha2562 = (value) => createHash13("sha256").update(value).digest("hex");
|
|
35615
37209
|
var listFiles = async (root, directory = root) => {
|
|
35616
|
-
const entries = await
|
|
37210
|
+
const entries = await readdir7(directory, { withFileTypes: true });
|
|
35617
37211
|
const paths = await Promise.all(entries.map(async (entry) => {
|
|
35618
|
-
const path =
|
|
37212
|
+
const path = join25(directory, entry.name);
|
|
35619
37213
|
if (entry.isDirectory())
|
|
35620
37214
|
return listFiles(root, path);
|
|
35621
37215
|
if (!entry.isFile())
|
|
@@ -35625,10 +37219,10 @@ var listFiles = async (root, directory = root) => {
|
|
|
35625
37219
|
return paths.flat().sort((left, right) => left.localeCompare(right));
|
|
35626
37220
|
};
|
|
35627
37221
|
var inspectFiles = async (root, paths) => Promise.all(paths.map(async (path) => {
|
|
35628
|
-
const source =
|
|
37222
|
+
const source = join25(root, path);
|
|
35629
37223
|
const [metadata, contents] = await Promise.all([
|
|
35630
37224
|
stat4(source),
|
|
35631
|
-
|
|
37225
|
+
readFile22(source)
|
|
35632
37226
|
]);
|
|
35633
37227
|
return { bytes: metadata.size, path, sha256: sha2562(contents) };
|
|
35634
37228
|
}));
|
|
@@ -35663,26 +37257,26 @@ var buildAbsoluteMobileUpdate = async (options) => {
|
|
|
35663
37257
|
value: signature.toString("base64")
|
|
35664
37258
|
}
|
|
35665
37259
|
});
|
|
35666
|
-
await
|
|
35667
|
-
const outputDirectory =
|
|
35668
|
-
const staging = await mkdtemp8(
|
|
37260
|
+
await mkdir17(outputRoot, { recursive: true });
|
|
37261
|
+
const outputDirectory = join25(outputRoot, manifest.releaseId);
|
|
37262
|
+
const staging = await mkdtemp8(join25(outputRoot, ".stage-"));
|
|
35669
37263
|
try {
|
|
35670
|
-
await cp3(bundleDirectory,
|
|
37264
|
+
await cp3(bundleDirectory, join25(staging, UPDATE_FILES_DIRECTORY), {
|
|
35671
37265
|
force: true,
|
|
35672
37266
|
recursive: true
|
|
35673
37267
|
});
|
|
35674
|
-
await
|
|
37268
|
+
await writeFile20(join25(staging, UPDATE_MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
|
|
35675
37269
|
`);
|
|
35676
|
-
await
|
|
37270
|
+
await rename16(staging, outputDirectory);
|
|
35677
37271
|
} catch (error) {
|
|
35678
|
-
await
|
|
37272
|
+
await rm13(staging, { force: true, recursive: true });
|
|
35679
37273
|
if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "EEXIST")
|
|
35680
37274
|
throw new TypeError(`Mobile update ${manifest.releaseId} already exists.`, { cause: error });
|
|
35681
37275
|
throw error;
|
|
35682
37276
|
}
|
|
35683
37277
|
return {
|
|
35684
37278
|
manifest,
|
|
35685
|
-
manifestPath:
|
|
37279
|
+
manifestPath: join25(outputDirectory, UPDATE_MANIFEST_FILE),
|
|
35686
37280
|
outputDirectory
|
|
35687
37281
|
};
|
|
35688
37282
|
};
|
|
@@ -35691,10 +37285,10 @@ var copyAbsoluteMobileUpdateFile = async (updateDirectory, path, destination) =>
|
|
|
35691
37285
|
const root = resolve18(updateDirectory, UPDATE_FILES_DIRECTORY);
|
|
35692
37286
|
if (!source.startsWith(`${root}/`))
|
|
35693
37287
|
throw new TypeError("Update file escaped its release.");
|
|
35694
|
-
await
|
|
37288
|
+
await mkdir17(dirname18(destination), { recursive: true });
|
|
35695
37289
|
await cp3(source, destination, { force: true });
|
|
35696
37290
|
};
|
|
35697
|
-
var readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await
|
|
37291
|
+
var readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await readFile22(join25(resolve18(directory), UPDATE_MANIFEST_FILE), "utf8")));
|
|
35698
37292
|
var verifyAbsoluteMobileUpdateSignature = (manifestValue, publicKey) => {
|
|
35699
37293
|
const manifest = parseAbsoluteMobileUpdateManifest(manifestValue);
|
|
35700
37294
|
const valid = verify("sha256", absoluteMobileUpdateSigningPayload(unsignedAbsoluteMobileUpdate(manifest)), { dsaEncoding: "ieee-p1363", key: publicKey }, Buffer.from(manifest.signature.value, "base64"));
|
|
@@ -35841,6 +37435,8 @@ export {
|
|
|
35841
37435
|
MOBILE_PAGE_REQUEST_HEADERS,
|
|
35842
37436
|
absoluteDeviceNativeRequirements,
|
|
35843
37437
|
absoluteExpoExecutable,
|
|
37438
|
+
absoluteExpoNativeObservabilityFiles,
|
|
37439
|
+
absoluteExpoNativeObservabilityPaths,
|
|
35844
37440
|
absoluteIosDeviceAcceptanceCommands,
|
|
35845
37441
|
absoluteMobilePreviewDocument,
|
|
35846
37442
|
absoluteMobileUpdateSigningPayload,
|
|
@@ -35853,6 +37449,7 @@ export {
|
|
|
35853
37449
|
activateAbsoluteMobilePage,
|
|
35854
37450
|
applyAbsoluteNativeDeepLinks,
|
|
35855
37451
|
applyAbsoluteNativeDeviceCapabilities,
|
|
37452
|
+
applyAbsoluteNativeObservability,
|
|
35856
37453
|
applyAbsoluteNativeUpdates,
|
|
35857
37454
|
assertAbsoluteDeviceCapabilityPackages,
|
|
35858
37455
|
buildAbsoluteAndroidRelease,
|
|
@@ -35892,6 +37489,8 @@ export {
|
|
|
35892
37489
|
discoverAbsoluteDeviceCapabilities,
|
|
35893
37490
|
discoverAbsoluteSyncSchema,
|
|
35894
37491
|
disposeAbsoluteMobilePage,
|
|
37492
|
+
drainAbsoluteMobileNativeObservability,
|
|
37493
|
+
expoNativeObservabilityRuntimeSource,
|
|
35895
37494
|
fetchAbsoluteMobilePage,
|
|
35896
37495
|
finalizeAbsoluteExpoUpdateExport,
|
|
35897
37496
|
finalizeAbsoluteMobileCompatibilityBuild,
|
|
@@ -36007,5 +37606,5 @@ export {
|
|
|
36007
37606
|
writeAbsoluteMobileGithubWorkflow
|
|
36008
37607
|
};
|
|
36009
37608
|
|
|
36010
|
-
//# debugId=
|
|
37609
|
+
//# debugId=E4E383CA64D4F3BE64756E2164756E21
|
|
36011
37610
|
//# sourceMappingURL=index.js.map
|