@goliapkg/sentori-react-native 7.0.0 → 7.0.1

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.
Files changed (45) hide show
  1. package/README.md +25 -1
  2. package/android/src/main/java-core/com/sentori/SentoriConfig.kt +1 -1
  3. package/android/src/main/java-core/com/sentori/SentoriNativeSignals.kt +1 -2
  4. package/android/src/main/java-core/com/sentori/SentoriPush.kt +36 -3
  5. package/android/src/main/java-core/com/sentori/SentoriScope.kt +17 -1
  6. package/android/src/main/java-core/com/sentori/SentoriTransport.kt +30 -4
  7. package/android/src/test/java-core/com/sentori/SentoriTransportTest.kt +82 -0
  8. package/ios/core/SentoriHangWatchdog.swift +3 -3
  9. package/ios/core/SentoriThreadSampler.swift +3 -3
  10. package/lib/handlers/network.js +2 -2
  11. package/lib/handlers/network.js.map +1 -1
  12. package/lib/index.js +1 -1
  13. package/lib/index.js.map +1 -1
  14. package/lib/init.js +2 -2
  15. package/lib/init.js.map +1 -1
  16. package/lib/long-task-monitor.js +1 -1
  17. package/lib/long-task-monitor.js.map +1 -1
  18. package/lib/mobile-vitals.js +2 -2
  19. package/lib/mobile-vitals.js.map +1 -1
  20. package/lib/push.d.ts.map +1 -1
  21. package/lib/push.js +39 -7
  22. package/lib/push.js.map +1 -1
  23. package/lib/rage-tap.js +2 -2
  24. package/lib/rage-tap.js.map +1 -1
  25. package/lib/scope.d.ts.map +1 -1
  26. package/lib/scope.js +18 -1
  27. package/lib/scope.js.map +1 -1
  28. package/lib/transport.js +2 -2
  29. package/lib/transport.js.map +1 -1
  30. package/lib/verbs.js +3 -3
  31. package/lib/verbs.js.map +1 -1
  32. package/package.json +1 -1
  33. package/src/__tests__/iron-rule.test.ts +79 -1
  34. package/src/__tests__/push.test.ts +38 -0
  35. package/src/handlers/network.ts +2 -2
  36. package/src/index.ts +1 -1
  37. package/src/init.ts +2 -2
  38. package/src/long-task-monitor.ts +1 -1
  39. package/src/mobile-vitals.ts +2 -2
  40. package/src/push.ts +42 -6
  41. package/src/rage-tap.tsx +2 -2
  42. package/src/scope.ts +19 -1
  43. package/src/transport.ts +2 -2
  44. package/src/verbs.ts +3 -3
  45. package/ios/PRIVACY_AND_REVIEW.md +0 -122
package/src/transport.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // Event transport — the only place the SDK talks to the network.
2
2
  //
3
- // Quiet by default, complete when it matters (design.md §4): events
3
+ // Quiet by default, complete when it matters: events
4
4
  // batch on a 5 s timer or a 10-deep queue, whichever first; assert
5
5
  // pass-counts piggyback on whatever batch goes out next (never their
6
6
  // own request); failures back off and finally persist to an offline
@@ -20,7 +20,7 @@ const STORAGE_KEY = '@sentori/pending';
20
20
  const MAX_PERSISTED = 1000;
21
21
 
22
22
  // Pinned to package.json by a test — bump both together.
23
- const SDK_VERSION = '7.0.0';
23
+ const SDK_VERSION = '7.0.1';
24
24
 
25
25
  let _queue: WireEvent[] = [];
26
26
  let _assertStats = new Map<string, AssertStat>();
package/src/verbs.ts CHANGED
@@ -1,4 +1,4 @@
1
- // The five event verbs (design.md §4). Everything here is
1
+ // The five event verbs. Everything here is
2
2
  // synchronous, never throws, and returns the client-minted event id
3
3
  // — the zero-cost iron rule made code.
4
4
  //
@@ -36,7 +36,7 @@ import { countAssert, enqueue } from './transport';
36
36
  declare const __DEV__: boolean | undefined;
37
37
 
38
38
  /** Serialize any Error instances found in the data argument — the
39
- * error-in-data convention (design.md §4): a caught-but-noteworthy
39
+ * error-in-data convention: a caught-but-noteworthy
40
40
  * exception needs no special API. One level deep is enough; nested
41
41
  * containers of errors are an anti-pattern we don't reward. */
42
42
  const serializeData = (data?: EventData): Record<string, unknown> | undefined => {
@@ -220,7 +220,7 @@ export const assert = safeFn(
220
220
 
221
221
  export const probe = safeFn('probe', (ref: string, data?: EventData): string => {
222
222
  // A tripwire: reaching this call IS the signal. Never throws,
223
- // never changes control flow (design.md §4).
223
+ // never changes control flow.
224
224
  return emit('probe', { name: ref, data });
225
225
  });
226
226
 
@@ -1,122 +0,0 @@
1
- # iOS Main Thread Sampler — Privacy & App Store Review Notes
2
-
3
- > **Status:** Phase 29 sub-A step 1. Documents the Mach + pthread + dyld
4
- > APIs the upcoming `SentoriThreadSampler.swift` will call, the App
5
- > Store review risk for each, and the privacy boundary. Written before
6
- > the Swift implementation lands so we can rule API choices in or out
7
- > before writing code we'd later need to rip out.
8
-
9
- ## Why we need this
10
-
11
- `SentoriHangWatchdog.swift` currently captures
12
- `Thread.callStackSymbols` from the watchdog thread itself, not from
13
- main, because main is wedged when we want to sample it. The captured
14
- stack therefore points into our own timer machinery, which is useless
15
- for diagnosing the user's hang. (The file's own comment at line 100
16
- flags this as a stop-gap.)
17
-
18
- To get the actual wedged main-thread frames we have to walk a remote
19
- thread's frame pointer chain — main is alive but not running our
20
- code, so we resolve it via Mach + pthread APIs. This document checks
21
- those APIs against App Store Review Guideline 2.5.1 ("Apps must use
22
- only public APIs") before we commit to them.
23
-
24
- ## API inventory
25
-
26
- ### Public, App Store-safe
27
-
28
- | API | Header | Purpose | Risk |
29
- |---|---|---|---|
30
- | `pthread_main_np()` | `<pthread.h>` | bool: am I on main? Sanity-check before sampling. | none |
31
- | `pthread_self()` | `<pthread.h>` | get current pthread for `pthread_mach_thread_np`. | none |
32
- | `pthread_mach_thread_np(pthread_t)` | `<pthread.h>` | pthread → mach port. The `_np` suffix is Apple's mark for "non-portable extension"; it's a public API, just not POSIX-portable. | none |
33
- | `mach_task_self()` | `<mach/mach.h>` | this process's task port. We pass our own task only; we never look up another. | none |
34
- | `thread_get_state(thread, ARM_THREAD_STATE64, ...)` | `<mach/thread_act.h>` | read main thread's PC / FP / SP / LR. Same call sentry-cocoa, Firebase Crashlytics, and Bugsnag use. | low — public Mach API; reviewers expect to see it from crash-reporter SDKs. |
35
- | `vm_read_overwrite(self_task, addr, size, dst, ...)` | `<mach/vm_map.h>` | safe (no SIGSEGV) read of own-process memory. We restrict to `mach_task_self()` and small reads (each frame is two pointers). | low — public; flagged only when used to read other processes' memory. |
36
- | `_dyld_image_count()` / `_dyld_get_image_header()` / `_dyld_get_image_vmaddr_slide()` / `_dyld_get_image_uuid()` | `<mach-o/dyld.h>` | LC_UUID for dSYM matching, ASLR slide for offset calc. Public dyld API. | none |
37
-
38
- ### Explicitly NOT used (private API risk)
39
-
40
- | API | Why we don't use it |
41
- |---|---|
42
- | `_pthread_main_thread_np` (underscore prefix) | private alias of `pthread_main_np()`; underscore prefix in Apple SDK = SPI, rejection-grade. |
43
- | `task_threads(other_task, ...)` cross-task | requires `task-port` entitlement and is reviewer-flagged. We only ever look at our own task. |
44
- | `task_for_pid` | gated by entitlement; not appropriate for our same-process use. |
45
- | `__platform_call_*` / `kdebug_trace` / signal hooking | private. |
46
- | `_dyld_register_func_for_*` introspection beyond UUID | not needed for stack walking. |
47
-
48
- ## Why this is App Store safe
49
-
50
- Direct prior art shipping the same call set, no review issues:
51
-
52
- - **sentry-cocoa** — uses `thread_get_state` + `vm_read_overwrite` for
53
- slow-frame and ANR sampling, in millions of apps.
54
- - **Firebase Crashlytics** — same primitives for ANR + hang capture.
55
- - **Bugsnag**, **Embrace** — likewise.
56
- - **Apple's MetricKit** (`MXCallStackTree`) walks call stacks via the
57
- same public Darwin primitives. Apple themselves consume this
58
- surface.
59
-
60
- Apple's stance: Review Guideline 2.5.1 forbids non-public APIs, but
61
- "non-public" means undocumented / underscore-prefixed / not in the
62
- public SDK. All calls in the public-safe table above are documented
63
- in Apple's developer reference and shipped in `<mach/...>` /
64
- `<pthread.h>` / `<mach-o/dyld.h>` headers that come with Xcode by
65
- default.
66
-
67
- ## Privacy considerations
68
-
69
- What we capture per hang event:
70
-
71
- - Up to 64 PC values (program counter addresses) from the main
72
- thread's frame pointer chain.
73
- - The `LC_UUID` of each loaded image and its ASLR vmaddr slide, so
74
- the server can match PCs back to a dSYM (Phase 22 sub-B field).
75
- - Hang duration in milliseconds (already captured today).
76
-
77
- What we explicitly do NOT capture:
78
-
79
- - Other processes' memory. We only pass `mach_task_self()` to
80
- `vm_read_overwrite`.
81
- - Function arguments, local variables, or register contents — PC
82
- only, never the rest of the `arm_thread_state64_t` struct.
83
- - Heap content, NSString contents, user-typed text, PII.
84
- - Continuous-rate samples. Sampling fires only on a detected hang
85
- (≥ 2s main-thread block) and is one-shot per hang (see watchdog
86
- `reportedThisHang` flag at `SentoriHangWatchdog.swift:54`).
87
-
88
- Symbolication happens **server-side** against the uploaded dSYM
89
- (`server/src/symbolicate.rs`). On-device,
90
- `frames[].instructionAddress` is an ASLR-slid pointer with no
91
- semantic content until paired with the dSYM.
92
-
93
- For the user-facing privacy doc (what data Sentori collects and why),
94
- see `docs/legal/privacy.md`.
95
-
96
- ## Rejection contingency
97
-
98
- If Apple Review ever rejects with reference to `vm_read_overwrite` or
99
- `thread_get_state`:
100
-
101
- 1. Confirm sentry-cocoa / Firebase / Bugsnag are still shipping the
102
- same call set. They're the canary; rejection there means a policy
103
- change everyone needs to handle.
104
- 2. Switch to `backtrace()` from `<execinfo.h>` — pure libc, walks
105
- only the *current* thread, which is the watchdog thread, not
106
- main. Lower fidelity (back where we started), zero risk.
107
- 3. Last resort: ship without main-thread sampler; emit hang events
108
- with empty `frames[]` and `tags.source = "sentori.hangWatchdog.no-sampler"`
109
- so the dashboard can flag the gap. Feature degrades, doesn't
110
- break.
111
-
112
- ## Implementation references
113
-
114
- - `sdk/react-native/ios/SentoriThreadSampler.swift` — to be created in
115
- Phase 29 sub-A step 2: `captureMainThreadFrames(maxFrames: Int = 64) -> [(pc: UInt64, fp: UInt64)]`
116
- - `sdk/react-native/ios/SentoriHangWatchdog.swift` — current
117
- `Thread.callStackSymbols` capture (line 108) replaced by sampler
118
- call in step 4.
119
- - `server/src/symbolicate.rs` — dSYM lookup + frame resolution
120
- (existing, Phase 22 sub-B).
121
- - `docs/protocol.md` — `frames[].instructionAddress` + `debugId` +
122
- `arch` field definitions (existing, Phase 22 sub-B).