@sazabi/react-native 0.0.0-stage → 0.1.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 (38) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +286 -2
  3. package/dist/chunk-h2nxjrr9.js +5 -0
  4. package/dist/chunk-h2nxjrr9.js.map +15 -0
  5. package/dist/client-sdk-core/attributes.d.ts +8 -0
  6. package/dist/client-sdk-core/before-send.d.ts +15 -0
  7. package/dist/client-sdk-core/clock.d.ts +6 -0
  8. package/dist/client-sdk-core/console.d.ts +23 -0
  9. package/dist/client-sdk-core/index.d.ts +22 -0
  10. package/dist/client-sdk-core/intake-url.d.ts +38 -0
  11. package/dist/client-sdk-core/network-capture.d.ts +90 -0
  12. package/dist/client-sdk-core/patch-marker.d.ts +8 -0
  13. package/dist/client-sdk-core/pointer.d.ts +73 -0
  14. package/dist/client-sdk-core/random.d.ts +11 -0
  15. package/dist/client-sdk-core/sdk-health.d.ts +37 -0
  16. package/dist/client-sdk-core/session.d.ts +44 -0
  17. package/dist/client-sdk-core/trace-context.d.ts +33 -0
  18. package/dist/client-sdk-core/transport.d.ts +142 -0
  19. package/dist/client-sdk-core/types.d.ts +82 -0
  20. package/dist/client-sdk-core/url.d.ts +30 -0
  21. package/dist/errors.d.ts +46 -0
  22. package/dist/host.d.ts +30 -0
  23. package/dist/index.d.ts +52 -0
  24. package/dist/index.js +6 -0
  25. package/dist/index.js.map +28 -0
  26. package/dist/interactions.d.ts +40 -0
  27. package/dist/lifecycle.d.ts +16 -0
  28. package/dist/navigation.d.ts +24 -0
  29. package/dist/network.d.ts +12 -0
  30. package/dist/outbox.d.ts +53 -0
  31. package/dist/process-state.d.ts +49 -0
  32. package/dist/register.d.ts +1 -0
  33. package/dist/register.js +4 -0
  34. package/dist/register.js.map +10 -0
  35. package/dist/storage.d.ts +42 -0
  36. package/dist/types.d.ts +117 -0
  37. package/dist/version.d.ts +4 -0
  38. package/package.json +62 -4
@@ -0,0 +1,53 @@
1
+ import type { SdkHealthReporter, Transport } from "./client-sdk-core/index.js";
2
+ import type { StorageAdapter } from "./types.js";
3
+ export declare const OUTBOX_INDEX_KEY = "sazabi.outbox.index";
4
+ /** Stamped on every record of a stashed batch; a re-sent copy carries the same value. */
5
+ export declare const OUTBOX_REPLAY_ID_KEY = "app.outbox.id";
6
+ /**
7
+ * Route the outbox's health reports to the running instance. Set before
8
+ * `loadOutbox`, so what the first read discards is reported on this launch.
9
+ */
10
+ export declare const watchOutbox: (adapter: StorageAdapter, report: SdkHealthReporter) => void;
11
+ /** The instance is gone: nothing it would have reported is reported. */
12
+ export declare const unwatchOutbox: (adapter: StorageAdapter, report: SdkHealthReporter) => void;
13
+ /**
14
+ * Read the stored outbox once per adapter. Started by `init()` before any
15
+ * capture installs: a synchronous adapter is loaded before this returns, so
16
+ * a crash at any later point merges into the stored report instead of
17
+ * writing beside it.
18
+ */
19
+ export declare const loadOutbox: (adapter: StorageAdapter, warn?: (message: string) => void) => Promise<void>;
20
+ /**
21
+ * The crash outbox replaces the browser's keepalive flush. A fatal JavaScript
22
+ * error terminates the process shortly after the global handler returns, so
23
+ * the pending queue (the error row included) is encoded into standalone
24
+ * envelopes stamped with one replay id and written to storage: the batch's
25
+ * own key first, then the index that lists it.
26
+ *
27
+ * Nothing the dying process sends can be cleared afterwards: an upload the
28
+ * intake accepted just before the process died would be posted again by the
29
+ * next launch. So when a synchronous adapter took both writes (`true`),
30
+ * nothing is sent here; the caller delivers the outbox once the process has
31
+ * proved it survived, and otherwise the next `init()` does. A
32
+ * promise-returning adapter may never finish the writes, so its batch is
33
+ * also sent at once, and a copy the next launch re-sends carries the same
34
+ * replay id. The saved queue goes once both writes were accepted (every row
35
+ * it held is in this batch), never before: a store that refuses the batch
36
+ * near its limit must not cost the only copy of those rows.
37
+ */
38
+ export declare const stashOutbox: (adapter: StorageAdapter, transport: Transport, replayId: string) => boolean;
39
+ /** Post everything the outbox holds once the stored keys have been read. */
40
+ export declare const deliverOutbox: (adapter: StorageAdapter, transport: Transport) => Promise<void>;
41
+ /**
42
+ * Save the live queue, within the outbox caps, as the app leaves the
43
+ * foreground: the OS may kill a backgrounded app without another callback,
44
+ * and an offline queue would die with it. The queued records are stamped
45
+ * with the replay id, so the live upload and the copy a later launch sends
46
+ * share it. Not before the previous launch's saved queue has been read.
47
+ */
48
+ export declare const saveQueue: (adapter: StorageAdapter, transport: Transport, replayId: string) => void;
49
+ /**
50
+ * `transport`'s live queue was delivered (or stashed by a crash): its saved
51
+ * copy goes, unless the key now holds another transport's queue.
52
+ */
53
+ export declare const clearQueue: (adapter: StorageAdapter, transport: Transport) => void;
@@ -0,0 +1,49 @@
1
+ import type { ClientEvent, EventSeverity, PointerTracker } from "./client-sdk-core/index.js";
2
+ export interface SdkInstance {
3
+ identify(distinctId: string, traits?: Record<string, unknown>): void;
4
+ reset(): void;
5
+ addEvent(name: string, attributes?: Record<string, unknown>): void;
6
+ log(severity: EventSeverity, message: string, metadata?: Record<string, unknown>): void;
7
+ flush(): Promise<void>;
8
+ shutdown(): Promise<void>;
9
+ }
10
+ interface PendingIdentity {
11
+ distinctId: string;
12
+ traits?: Record<string, unknown>;
13
+ }
14
+ export interface CurrentScreen {
15
+ name?: string;
16
+ path?: string;
17
+ /** The navigator's per-visit route key: two pushes of one screen are two visits. */
18
+ key?: string;
19
+ }
20
+ interface SdkState {
21
+ instance?: SdkInstance;
22
+ initialized: boolean;
23
+ warnedWebHost: boolean;
24
+ /** Bumped by every init() and shutdown(), so a consent promise that resolves after a shutdown starts nothing. */
25
+ generation: number;
26
+ pendingIdentity?: PendingIdentity;
27
+ pendingReset: boolean;
28
+ /** The running instance's pointer tracker, fed by every `<SazabiRoot>`. */
29
+ tracker?: PointerTracker;
30
+ /** Where `<SazabiRoot>` reports a render or commit error it caught. */
31
+ renderErrorSink?: (error: unknown) => void;
32
+ /** Where `trackNavigation()` sends its rows. */
33
+ navigationEmit?: (event: ClientEvent) => void;
34
+ /** Applied to the route path a navigation row records: a deep link can carry a query string. */
35
+ navigationRedactUrl?: (url: string) => string;
36
+ /** The route the user is on, stamped on every row as `app.screen.*`. */
37
+ screen: CurrentScreen;
38
+ /** The development note about the unreadable rejection slot, printed once per process. */
39
+ warnedRejectionSlot: boolean;
40
+ }
41
+ /**
42
+ * Process-wide, not module-wide: a second evaluation of this module (a
43
+ * duplicate copy in the bundle, a module registry reset in development)
44
+ * finds the running instance instead of installing a second `ErrorUtils`
45
+ * handler, rejection tracker, and transport beside it, and a `<SazabiRoot>`
46
+ * or `trackNavigation()` imported from that copy feeds the running instance.
47
+ */
48
+ export declare const state: SdkState;
49
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import{s,d}from"./chunk-h2nxjrr9.js";try{if(!s())d()}catch{}
2
+
3
+ //# debugId=1C55478F3E7B6A0D64756E2164756E21
4
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/register.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Early-instrumentation entrypoint: `import \"@sazabi/react-native/register\"`.\n *\n * Importing this module installs the SDK's `XMLHttpRequest` patch as a\n * dormant, transparent passthrough at module-evaluation time, before any\n * other library's module-scope code can capture the prototype methods\n * (Metro evaluates an entry file's imports in order, and every static import\n * runs before the first statement). `init()` later activates it with\n * configuration; until then it observes nothing, stores nothing, and sends\n * nothing.\n *\n * Put this import above all other imports in your app's entry module.\n */\nimport { isWebHost } from \"./host\";\nimport { ensureNetworkPatches } from \"./network\";\n\ntry {\n // react-native-web runs in a browser, where @sazabi/browser owns capture.\n if (!isWebHost()) {\n ensureNetworkPatches();\n }\n} catch {\n // Registration must never break the host app; init() re-ensures.\n}\n"
6
+ ],
7
+ "mappings": "qCAgBA,GAAI,CAEF,GAAI,CAAC,EAAU,EACb,EAAqB,EAEvB,KAAM",
8
+ "debugId": "1C55478F3E7B6A0D64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,42 @@
1
+ import { type SessionStore } from "./client-sdk-core/index.js";
2
+ import type { StorageAdapter } from "./types.js";
3
+ /**
4
+ * Storage adapters may be synchronous (MMKV) or promise-returning
5
+ * (AsyncStorage). Every call here is best-effort: an adapter that throws or
6
+ * rejects degrades the SDK to in-memory state and never surfaces to the app.
7
+ */
8
+ export declare const readKey: (adapter: StorageAdapter, key: string) => Promise<string | null>;
9
+ export declare const isThenable: (value: unknown) => value is PromiseLike<unknown>;
10
+ /** What a read found; `undefined` means the adapter failed to answer. */
11
+ export type ReadResult = {
12
+ value: string | null;
13
+ } | undefined;
14
+ /** Read a key, synchronously when the adapter can, so the crash outbox loads inside `init()`. */
15
+ export declare const readKeyNow: (adapter: StorageAdapter, key: string) => ReadResult | Promise<ReadResult>;
16
+ /**
17
+ * Every key the adapter holds. `undefined` when the adapter has no listing
18
+ * or it failed: the caller then knows only what the indexes list, never
19
+ * that a key is absent.
20
+ */
21
+ export declare const listKeysNow: (adapter: StorageAdapter) => readonly string[] | undefined | Promise<readonly string[] | undefined>;
22
+ /**
23
+ * `true` once the adapter accepted the write, `false` when it refused. A
24
+ * synchronous adapter answers synchronously, which is how the crash path
25
+ * knows the batch is on disk before the process can die.
26
+ */
27
+ export declare const writeKey: (adapter: StorageAdapter, key: string, value: string) => boolean | Promise<boolean>;
28
+ /** `true` once the adapter accepted the removal, synchronously when it can. */
29
+ export declare const removeKey: (adapter: StorageAdapter, key: string) => boolean | Promise<boolean>;
30
+ export interface HydratingStore {
31
+ /** Synchronous view the session machine reads through. */
32
+ store: SessionStore;
33
+ /** Resolves once every key has been read from the adapter. */
34
+ ready: Promise<void>;
35
+ }
36
+ /**
37
+ * The session machine needs synchronous reads, so persisted state is read
38
+ * once into an in-memory mirror and every later write goes through to the
39
+ * adapter. A key written locally before hydration finishes keeps the local
40
+ * value: a `reset()` must not be undone by a slow read of the old identity.
41
+ */
42
+ export declare const createHydratingStore: (adapter: StorageAdapter, keys: readonly string[]) => HydratingStore;
@@ -0,0 +1,117 @@
1
+ import type { BeforeSend, ConsoleCaptureConfig, NetworkCaptureConfig as CoreNetworkCaptureConfig, PointerCaptureConfig } from "./client-sdk-core/index.js";
2
+ export type { AttributeValue, BeforeSend, ClientEvent, ClientEventType, ConsoleCaptureConfig, ConsoleCaptureLevel, EventAttributes, EventSeverity, PointerCaptureConfig, } from "./client-sdk-core/index.js";
3
+ /**
4
+ * Persistent key-value storage the SDK writes sessions, identity, and the
5
+ * crash outbox to. `@react-native-async-storage/async-storage`, MMKV
6
+ * wrappers, and `expo-sqlite/kv-store` all satisfy it; a synchronous store
7
+ * makes the crash outbox reliable on a fatal error.
8
+ */
9
+ export interface StorageAdapter {
10
+ getItem(key: string): string | null | Promise<string | null>;
11
+ setItem(key: string, value: string): void | Promise<void>;
12
+ removeItem(key: string): void | Promise<void>;
13
+ /**
14
+ * Every key the store holds (AsyncStorage's `getAllKeys`, MMKV's
15
+ * `getAllKeys`). Optional: with it, a launch recovers a crash report whose
16
+ * own key was written but whose index entry never landed because the
17
+ * process died between the two writes. Without it such a report is lost.
18
+ */
19
+ getAllKeys?(): readonly string[] | Promise<readonly string[]>;
20
+ }
21
+ export interface NetworkCaptureConfig extends CoreNetworkCaptureConfig {
22
+ /**
23
+ * Requests eligible for `traceparent` injection. A string is a host
24
+ * (`api.example.com`), a domain with every subdomain (`.example.com`), or
25
+ * an origin with an optional path prefix (`https://api.example.com`); a
26
+ * RegExp is tested against the full URL. Default: every request except
27
+ * the intake endpoint. A native app has no origin and no CORS preflight,
28
+ * so injection is on everywhere unless narrowed here.
29
+ */
30
+ allowlist?: (string | RegExp)[];
31
+ }
32
+ /**
33
+ * What `HermesInternal.enablePromiseRejectionTracker` takes: the shape every
34
+ * React Native crash reporter installs.
35
+ */
36
+ export interface RejectionTracker {
37
+ allRejections: boolean;
38
+ onUnhandled(id: number, rejection: unknown): void;
39
+ onHandled?(id: number): void;
40
+ }
41
+ export interface ErrorCaptureConfig {
42
+ /**
43
+ * Track unhandled promise rejections through Hermes's rejection tracker.
44
+ * Hermes has one tracker slot, so turn this off when another SDK owns it.
45
+ * Default true.
46
+ */
47
+ unhandledRejections?: boolean;
48
+ /**
49
+ * The tracker another library installed before `init()`, to run after the
50
+ * SDK's own on every rejection. Hermes gives no way to read the slot's
51
+ * occupant (`HermesInternal` is frozen and its global pinned), so `init()`
52
+ * replaces whatever holds it; hand that tracker over here to keep it
53
+ * running. A tracker installed after `init()` replaces the SDK's instead.
54
+ */
55
+ previousRejectionTracker?: RejectionTracker;
56
+ }
57
+ /** The subset of a React Navigation container ref the SDK subscribes to. */
58
+ export interface NavigationContainerRefLike {
59
+ addListener(type: "state", listener: () => void): () => void;
60
+ getCurrentRoute(): {
61
+ key?: string | undefined;
62
+ name: string;
63
+ params?: object | undefined;
64
+ path?: string | undefined;
65
+ } | undefined;
66
+ }
67
+ export interface ReactNativeSdkConfig {
68
+ /**
69
+ * The project's intake URL, exactly as the log source issues it, e.g.
70
+ * `https://<key>.us-west-2.intake.sazabi.com`. The credential is embedded in
71
+ * the hostname, so this is normally the only endpoint config needed; `/v1/logs`
72
+ * may be included or omitted.
73
+ */
74
+ intakeUrl?: string;
75
+ /**
76
+ * Public ingest key (`sazabi_public_...`). Optional: derived from `intakeUrl`
77
+ * when that URL is a keyed intake host. Set it only for a proxy or custom
78
+ * endpoint whose hostname carries no key.
79
+ */
80
+ publicKey?: string;
81
+ /** Logical service name for the app. */
82
+ serviceName: string;
83
+ /** App version (e.g. the marketing version or a git SHA). */
84
+ serviceVersion?: string;
85
+ /** Deployment environment (e.g. "production"). */
86
+ environment?: string;
87
+ /** Session persistence and the crash outbox. Without it, sessions last one launch. */
88
+ storage?: StorageAdapter;
89
+ network?: NetworkCaptureConfig;
90
+ console?: ConsoleCaptureConfig;
91
+ pointer?: PointerCaptureConfig;
92
+ errors?: ErrorCaptureConfig;
93
+ /**
94
+ * Consent gate: capture holds until this resolves true. When it resolves
95
+ * false the SDK stays dormant.
96
+ */
97
+ consent?: () => boolean | Promise<boolean>;
98
+ /** Batch flush cadence in ms. Default 5000. */
99
+ flushIntervalMs?: number;
100
+ /** Soft cap per OTLP request body in bytes. Default 57344. */
101
+ maxBatchBytes?: number;
102
+ /**
103
+ * Max buffered events (and at most 1 MiB) while the intake is unreachable;
104
+ * the oldest are dropped first and counted in `app.sdk.dropped_events`.
105
+ * Default 500.
106
+ */
107
+ maxQueuedEvents?: number;
108
+ /**
109
+ * Edit or drop events before they are queued: return the event to send it,
110
+ * `null` to drop it. Runs for every event type, `sdk_health` included. A
111
+ * hook that throws drops the event and warns once; an event captured
112
+ * synchronously while the hook runs (a `log()` inside it) is dropped. A
113
+ * request the hook makes produces its own network event later, which the
114
+ * hook sees like any other and must exclude itself.
115
+ */
116
+ beforeSend?: BeforeSend;
117
+ }
@@ -0,0 +1,4 @@
1
+ export declare const SDK_NAME = "@sazabi/react-native";
2
+ export declare const SDK_VERSION = "0.1.1";
3
+ /** SDK-emitted console lines carry this prefix and are never re-captured. */
4
+ export declare const SDK_CONSOLE_PREFIX = "[@sazabi/react-native]";
package/package.json CHANGED
@@ -1,6 +1,64 @@
1
1
  {
2
2
  "name": "@sazabi/react-native",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "description": "Sazabi React Native observability SDK — semantic event stream capture with W3C trace context propagation",
4
+ "version": "0.1.1",
5
+ "keywords": [
6
+ "sazabi",
7
+ "react-native",
8
+ "expo",
9
+ "observability",
10
+ "monitoring",
11
+ "logging",
12
+ "error-tracking",
13
+ "crash-reporting",
14
+ "opentelemetry",
15
+ "otlp",
16
+ "tracing"
17
+ ],
18
+ "type": "module",
19
+ "main": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "default": "./dist/index.js"
25
+ },
26
+ "./register": {
27
+ "types": "./dist/register.d.ts",
28
+ "default": "./dist/register.js"
29
+ },
30
+ "./dist/register.js": {
31
+ "types": "./dist/register.d.ts",
32
+ "default": "./dist/register.js"
33
+ },
34
+ "./package.json": "./package.json"
35
+ },
36
+ "react-native": {
37
+ "./register": "./dist/register.js"
38
+ },
39
+ "files": [
40
+ "dist"
41
+ ],
42
+ "peerDependencies": {
43
+ "react": ">=18",
44
+ "react-native": ">=0.76"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "react-native": {
48
+ "optional": true
49
+ }
50
+ },
51
+ "sideEffects": [
52
+ "./dist/register.js"
53
+ ],
54
+ "license": "Apache-2.0",
55
+ "homepage": "https://github.com/sazabi/react-native",
56
+ "repository": {
57
+ "type": "git",
58
+ "url": "git+https://github.com/sazabi/react-native.git"
59
+ },
60
+ "publishConfig": {
61
+ "access": "public",
62
+ "registry": "https://registry.npmjs.org"
63
+ }
64
+ }