@everframe/react-native 1.0.0 → 1.2.0
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/EverframeRN.podspec +5 -1
- package/README.md +295 -7
- package/android/build.gradle.kts +7 -6
- package/android/src/main/java/dev/everframe/rn/EverframeModule.kt +80 -49
- package/android/src/main/java/dev/everframe/rn/ReporterBridge.kt +89 -0
- package/dist/NativeEverframe.d.ts +26 -1
- package/dist/chunk-ENPQ66EV.js +1 -0
- package/dist/chunk-POE5CSO5.js +1 -0
- package/dist/index.d.ts +451 -67
- package/dist/index.js +31 -25
- package/dist/index.web.d.ts +12 -0
- package/dist/index.web.js +1 -1
- package/dist/integrations/console.js +1 -1
- package/dist/integrations/react-navigation.js +1 -1
- package/dist/integrations/react.d.ts +15 -0
- package/dist/integrations/react.js +1 -0
- package/dist/promise-rejection-types-C-lxCdDl.d.ts +101 -0
- package/ios/Sources/EverframeBridge.swift +58 -56
- package/ios/Sources/EverframeModule.mm +21 -4
- package/package.json +9 -4
- package/src/NativeEverframe.ts +28 -2
- package/dist/chunk-QRPINMCR.js +0 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 ScriptX
|
|
3
|
+
package dev.everframe.rn
|
|
4
|
+
|
|
5
|
+
import android.app.Activity
|
|
6
|
+
import android.content.Context
|
|
7
|
+
import android.os.Handler
|
|
8
|
+
import android.os.Looper
|
|
9
|
+
import android.util.Log
|
|
10
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
11
|
+
import com.facebook.react.common.LifecycleState
|
|
12
|
+
import dev.everframe.Everframe
|
|
13
|
+
import dev.everframe.config.ReportResult
|
|
14
|
+
import java.lang.reflect.InvocationTargetException
|
|
15
|
+
import java.lang.reflect.Method
|
|
16
|
+
import kotlin.coroutines.Continuation
|
|
17
|
+
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
|
|
18
|
+
import kotlinx.coroutines.CancellationException
|
|
19
|
+
import kotlinx.coroutines.Dispatchers
|
|
20
|
+
import kotlinx.coroutines.withContext
|
|
21
|
+
|
|
22
|
+
/** Reflection preserves compatibility with separately built native reporter artifacts. */
|
|
23
|
+
internal class ReporterBridge(
|
|
24
|
+
private val resolveInstaller: () -> Class<*> = { Class.forName("dev.everframe.ui.ReporterResolverInstaller") },
|
|
25
|
+
) {
|
|
26
|
+
fun scheduleInstall(context: Context) {
|
|
27
|
+
val application = context.applicationContext
|
|
28
|
+
val install = Runnable {
|
|
29
|
+
try {
|
|
30
|
+
val type = installerType()
|
|
31
|
+
invoke(type.getMethod("create", Context::class.java), type.getDeclaredConstructor().newInstance(), application)
|
|
32
|
+
} catch (_: Throwable) {
|
|
33
|
+
Log.w("Everframe.rn", "Reporter initialization deferred; opening will retry")
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (Looper.myLooper() == Looper.getMainLooper()) install.run()
|
|
37
|
+
else Handler(Looper.getMainLooper()).post(install)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
suspend fun open(context: ReactApplicationContext): ReportResult = withContext(Dispatchers.Main.immediate) {
|
|
41
|
+
val activity = context.currentActivity
|
|
42
|
+
if (context.lifecycleState != LifecycleState.RESUMED || activity == null ||
|
|
43
|
+
activity.isFinishing || activity.isDestroyed || activity.application !== context.applicationContext) {
|
|
44
|
+
return@withContext ReportResult.Cancelled("no_active_activity")
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
val type = installerType()
|
|
48
|
+
val instance = type.getDeclaredConstructor().newInstance()
|
|
49
|
+
val method = try {
|
|
50
|
+
type.getMethod("openForActivity", Context::class.java, Activity::class.java, Continuation::class.java)
|
|
51
|
+
} catch (_: NoSuchMethodException) { null }
|
|
52
|
+
if (method == null) {
|
|
53
|
+
// Absence is the only legacy fallback. A present method's failure is final.
|
|
54
|
+
invoke(type.getMethod("create", Context::class.java), instance, context.applicationContext)
|
|
55
|
+
Everframe.report.open()
|
|
56
|
+
} else {
|
|
57
|
+
suspendCoroutineUninterceptedOrReturn<ReportResult> { continuation ->
|
|
58
|
+
invoke(method, instance, context.applicationContext, activity, continuation)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} catch (failure: Throwable) {
|
|
62
|
+
when (failure) {
|
|
63
|
+
is CancellationException -> throw failure
|
|
64
|
+
is ReporterBridgeFailure -> throw failure
|
|
65
|
+
is NoSuchMethodException -> throw ReporterBridgeFailure("Reporter UI is incompatible; update the native reporter dependency")
|
|
66
|
+
else -> throw ReporterBridgeFailure("Reporter initialization or opening failed")
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private fun installerType(): Class<*> = try { resolveInstaller() }
|
|
72
|
+
catch (_: ClassNotFoundException) {
|
|
73
|
+
throw ReporterBridgeFailure("Reporter UI dependency is missing; add dev.everframe:reporter-ui")
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private fun invoke(method: Method, instance: Any, vararg arguments: Any?): Any? =
|
|
77
|
+
try { method.invoke(instance, *arguments) }
|
|
78
|
+
catch (failure: InvocationTargetException) { throw failure.targetException }
|
|
79
|
+
|
|
80
|
+
/** Only SDK-owned constant messages may cross the JS promise boundary. */
|
|
81
|
+
fun rejectionMessage(failure: Throwable): String = when (failure) {
|
|
82
|
+
is ReporterBridgeFailure -> failure.message!!
|
|
83
|
+
is CancellationException -> "Reporter opening was cancelled"
|
|
84
|
+
else -> "Reporter initialization or opening failed"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// No host exception/cause is forwarded to JS or diagnostic logs.
|
|
88
|
+
private class ReporterBridgeFailure(message: String) : IllegalStateException(message)
|
|
89
|
+
}
|
|
@@ -23,7 +23,7 @@ type Rect = {
|
|
|
23
23
|
* Rich variants (e.g., callbacks, function refs) MUST stay on the JS side.
|
|
24
24
|
*/
|
|
25
25
|
type ConfigOpts = {
|
|
26
|
-
|
|
26
|
+
sdkKey?: string;
|
|
27
27
|
sdkVersion?: string;
|
|
28
28
|
/**
|
|
29
29
|
* If true, the native side captures a UIWindow/SurfaceFlinger screenshot
|
|
@@ -49,6 +49,14 @@ type ConfigOpts = {
|
|
|
49
49
|
* once polarity is flipped.
|
|
50
50
|
*/
|
|
51
51
|
installIdentifierDisabled?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Client veto for automatic crash capture. `true` turns off the native SDKs' crash capture
|
|
54
|
+
* (JVM, native crashes and ANRs on Android; native crashes on iOS) as well as the JS handlers:
|
|
55
|
+
* both natives store `capture.crash = !crashReportingDisabled`. Flat because RN codegen rejects
|
|
56
|
+
* nested objects; `extractBridgeConfig` flattens the host-facing `crashReporting: { disabled }`.
|
|
57
|
+
* Absent means capture stays on.
|
|
58
|
+
*/
|
|
59
|
+
crashReportingDisabled?: boolean;
|
|
52
60
|
/**
|
|
53
61
|
* Built-in attach-PIN surface mode (spec 2026-08-19): 'builtin' (default —
|
|
54
62
|
* the native SDK presents the code itself), 'custom' (host renders it from
|
|
@@ -128,6 +136,21 @@ type ConfigOpts = {
|
|
|
128
136
|
vitalsEnabled?: boolean;
|
|
129
137
|
vitalsSampleRate?: number;
|
|
130
138
|
vitalsCaptureSourceQuery?: boolean;
|
|
139
|
+
/**
|
|
140
|
+
* Whether this is a debug build, which Everframe never makes a release out of. The JS facade always
|
|
141
|
+
* sends it (the config's `debugBuild`, else `__DEV__`). Absent means the native SDK decides for itself.
|
|
142
|
+
*/
|
|
143
|
+
debugBuild?: boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Native foreground monitoring (release health). The JS facade always sends this flag: `true` with a
|
|
146
|
+
* validated loaded bundle, or `false` to revoke monitoring. A bridge that finds it missing treats it as
|
|
147
|
+
* on, and only an explicit `false` as off. The native SDK reads the app version.
|
|
148
|
+
*/
|
|
149
|
+
releaseHealthEnabled?: boolean;
|
|
150
|
+
releaseHealthLoadedBuildId?: string;
|
|
151
|
+
releaseHealthUserId?: string;
|
|
152
|
+
/** Count debug builds, which the native SDKs skip by default. Absent means false. */
|
|
153
|
+
releaseHealthIncludeDebugBuilds?: boolean;
|
|
131
154
|
};
|
|
132
155
|
/**
|
|
133
156
|
* Host-declared user for self-declared recognition (spec 2026-08-12). Flat by
|
|
@@ -228,6 +251,8 @@ interface Spec extends TurboModule {
|
|
|
228
251
|
* freeform-object escape hatch; `from`/`to` win over its keys.
|
|
229
252
|
*/
|
|
230
253
|
recordScreen(name: string, data?: UnsafeObject): void;
|
|
254
|
+
/** Additive diagnostic bridge: bounded JSON of cached native observations; no I/O. */
|
|
255
|
+
getReportDeliveryStatusJson(): string;
|
|
231
256
|
/**
|
|
232
257
|
* Crash/error reporting (spec 2026-07-18). SYNCHRONOUS by design (non-void
|
|
233
258
|
* return forces a sync TurboModule method): the fatal path must complete
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as o}from"./chunk-XUSV3KOD.js";var h=["native-handled","bridge-handled","bridge-automatic","jvm-uncaught"],A=["persisted","disabled","admission-suppressed","reentrant","invalid-input","ownership-lost","storage-unavailable","failed"],S=["enqueue-committed","enqueue-failed","capacity-evicted","removed-after-acceptance","removed-after-terminal","removal-failed","read-failed"],T=["capacity","key-unavailable","corrupt","io","revoked","invalid-entry","busy","unknown","unsupported-format"],R=["live-submit","outbox-drain"],K=["server-accepted","retryable-http","terminal-http","network-failure","authorization-cancelled","cancelled","failed"],V=JSON.parse,H=Object.keys,y=Object.hasOwn,Q=Array.isArray,U=Number.isInteger,I=Reflect.apply,z=RegExp.prototype.test,_=/[^\x00-\x7f]/,k=2147483647;function d(e,t){let r={};for(let n=0;n<e.length;n++){let a=e[n];r[a]=t(a)}return r}o(d,"mapKeys");function J(e,t){return{schemaVersion:1,status:e,reason:t,scope:"native-runtime-observations",coverage:"best-effort",revision:0,capture:{enabled:!1,paths:d(h,()=>({supported:!1,settledAttempts:0,outcomes:d(A,()=>0)}))},queue:{scope:"sdk-report-outbox",observation:"not-observed",quality:"unknown",capacityPolicy:"unknown",terminalHttpPolicy:"unknown",operations:d(S,()=>0),migration:"not-observed"},transport:d(R,()=>({settledAttempts:0,outcomes:d(K,()=>0)}))}}o(J,"emptyReportDeliveryStatus");function l(e,t,r=[]){if(!e||typeof e!="object"||Q(e))throw new Error;let n=H(e);for(let a=0;a<t.length;a++)if(!y(e,t[a]))throw new Error;for(let a=0;a<n.length;a++){let i=n[a];if(!g(t,i)&&!g(r,i))throw new Error}return e}o(l,"record");function g(e,t){for(let r=0;r<e.length;r++)if(e[r]===t)return!0;return!1}o(g,"contains");function c(e,t){if(typeof e!="string"||!g(t,e))throw new Error;return e}o(c,"enumeration");function v(e){if(typeof e!="number"||!U(e)||e<0||e>k)throw new Error;return e}o(v,"counter");function P(e){if(typeof e!="boolean")throw new Error;return e}o(P,"boolean");function q(e,t){let r=l(e,t);return d(t,n=>v(r[n]))}o(q,"counters");function j(e,t){let r=q(e.outcomes,t),n=v(e.settledAttempts),a=0;for(let b=0;b<t.length;b++)a+=r[t[b]];if((a>k?k:a)!==n)throw new Error;let i=y(e,"lastOutcome")?c(e.lastOutcome,t):void 0;if(n>0!=(i!==void 0)||i!==void 0&&r[i]===0)throw new Error;return{settledAttempts:n,outcomes:r,...i===void 0?{}:{lastOutcome:i}}}o(j,"settled");function C(e,t,r){for(let n=0;n<t.length;n++)if(r(e[t[n]])!==0)return!0;return!1}o(C,"nonzero");function M(e){try{if(typeof e!="string"||e.length>16384||I(z,_,[e]))return null;let t=l(V(e),["schemaVersion","status","reason","scope","coverage","revision","capture","queue","transport"]);if(t.schemaVersion!==1||t.scope!=="native-runtime-observations"||t.coverage!=="best-effort")return null;let r=c(t.status,["active","not-started","disabled","unavailable"]),n=c(t.reason,["none","no-start","capture-disabled","snapshot-busy"]);if({active:"none","not-started":"no-start",disabled:"capture-disabled",unavailable:"snapshot-busy"}[r]!==n)return null;let a=l(t.capture,["enabled","paths"]),i=l(a.paths,h),b=d(h,p=>{let f=l(i[p],["supported","settledAttempts","outcomes"],["lastOutcome"]),m={supported:P(f.supported),...j(f,A)};if(!m.supported&&m.settledAttempts!==0)throw new Error;return m}),u=l(t.queue,["scope","observation","quality","capacityPolicy","terminalHttpPolicy","operations","migration"],["pendingCount","lastFailure"]);if(u.scope!=="sdk-report-outbox")return null;let s={scope:"sdk-report-outbox",observation:c(u.observation,["not-observed","observed","failed"]),quality:c(u.quality,["complete","partial","unknown"]),capacityPolicy:c(u.capacityPolicy,["reject-new","evict-oldest"]),terminalHttpPolicy:c(u.terminalHttpPolicy,["retain","attempt-remove"]),operations:q(u.operations,S),migration:c(u.migration,["not-observed","clear","blocked","unknown"]),...y(u,"pendingCount")?{pendingCount:v(u.pendingCount)}:{},...y(u,"lastFailure")?{lastFailure:c(u.lastFailure,T)}:{}};if(s.capacityPolicy==="reject-new"!=(s.terminalHttpPolicy==="retain")||(s.observation!=="observed"||s.quality==="unknown")&&s.pendingCount!==void 0||s.observation!=="observed"&&s.quality!=="unknown"||s.observation==="failed"!=(s.lastFailure!==void 0))return null;let D=l(t.transport,R),E=d(R,p=>{let f=l(D[p],["settledAttempts","outcomes"],["lastOutcome","lastHttpStatus"]),m=j(f,K);if(y(f,"lastHttpStatus")){let x=v(f.lastHttpStatus);if(x<100||x>599||!g(["server-accepted","retryable-http","terminal-http"],m.lastOutcome??""))throw new Error;m.lastHttpStatus=x}return m}),w={schemaVersion:1,status:r,reason:n,scope:"native-runtime-observations",coverage:"best-effort",revision:v(t.revision),capture:{enabled:P(a.enabled),paths:b},queue:s,transport:E};return r!=="active"&&(w.revision!==0||w.capture.enabled||s.observation!=="not-observed"||C(b,h,p=>p.settledAttempts)||C(E,R,p=>p.settledAttempts)||C(s.operations,S,p=>p))?null:w}catch{return null}}o(M,"parseReportDeliveryStatus");function O(){return{attempted:0,accepted:0,duplicateSuppressed:0,allowanceSuppressed:0,bridgeUnavailable:0,nativeRefused:0,captureFailed:0,reentrantSuppressed:0,inactiveAborted:0,legacyAttempted:0}}o(O,"emptyCounters");function N(e,t){return{status:e,reason:t,scope:"mounted-js-admission",limits:{handled:10,automatic:10},counters:{handled:O(),errorUtils:O(),rejection:O()}}}o(N,"emptyErrorCaptureStatus");function F(e,t){e[t]=Math.min(2147483647,e[t]+1)}o(F,"incrementErrorCaptureCounter");function B(){let e=N("active","none").counters;return{begin(t){F(e[t],"attempted");let r=!1;return n=>{r||(r=!0,F(e[t],n))}},snapshot(){return{handled:{...e.handled},errorUtils:{...e.errorUtils},rejection:{...e.rejection}}}}}o(B,"createErrorCaptureLedger");function Y(e,t){return{status:e,reason:t,previousCallbacksPresent:!1,counters:{pending:0,accepted:0,cancelled:0,capacityDropped:0,sizeDropped:0,expired:0,duplicateSuppressed:0,allowanceSuppressed:0,nativeRefused:0,captureFailed:0,discarded:0}}}o(Y,"emptyPromiseRejectionStatus");export{J as a,M as b,N as c,B as d,Y as e};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as i,c as s,e as u}from"./chunk-ENPQ66EV.js";import{a as t}from"./chunk-XUSV3KOD.js";var n=class extends Error{static{t(this,"EverframeNotMountedError")}name="EverframeNotMountedError";constructor(o){super(o??"EverframeProvider is not mounted; wrap your app root.")}};var r=null,a={};function x(){return a}t(x,"__getContextEpoch");function f(){try{return r?.getPromiseRejectionStatus?.()??u("not-mounted","no-mount")}catch{return u("install-failed","hook-install")}}t(f,"getPromiseRejectionStatus");function E(e){r=e,a={}}t(E,"__setCurrentContext");function g(){return r}t(g,"__getCurrentContext");function R(){let e=r;return e?e.open():Promise.reject(new n("EverframeProvider not mounted; wrap your root with <EverframeProvider>."))}t(R,"open");function S(e){r?.setExtra(e)}t(S,"setExtra");function y(e){r?.addBreadcrumb(e)}t(y,"addBreadcrumb");function C(e,o){o!==void 0?r?.recordScreen(e,o):r?.recordScreen(e)}t(C,"recordScreen");function b(e){r?.setUser(e)}t(b,"setUser");function j(e,o){r?.captureException(e,o)}t(j,"captureException");function w(){try{return r?.getErrorCaptureStatus?.()??s("not-mounted","no-mount")}catch{return s("not-mounted","no-mount")}}t(w,"getErrorCaptureStatus");function P(){let e=r;try{let o=e?.getReportDeliveryStatus?.();return e===r&&o?o:i("not-mounted","no-mount")}catch{return i("unavailable","native-call-failed")}}t(P,"getReportDeliveryStatus");export{n as a,x as b,f as c,E as d,g as e,R as f,S as g,y as h,C as i,b as j,j as k,w as l,P as m};
|