@goliapkg/sentori-react-native 0.5.0 → 0.5.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.
@@ -1 +1 @@
1
- {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/handlers/network.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,qBAAqB,QAAO,IA8DxC,CAAC"}
1
+ {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/handlers/network.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,qBAAqB,QAAO,IAKxC,CAAC"}
@@ -5,9 +5,14 @@ const AUTH_PARAMS = ['token', 'key', 'password', 'secret', 'access_token'];
5
5
  export const installNetworkHandler = () => {
6
6
  if (_installed)
7
7
  return;
8
+ _installed = true;
9
+ patchFetch();
10
+ patchXhr();
11
+ };
12
+ // ── fetch ──────────────────────────────────────────────────────────
13
+ function patchFetch() {
8
14
  if (typeof globalThis.fetch !== 'function')
9
15
  return;
10
- _installed = true;
11
16
  const original = globalThis.fetch;
12
17
  globalThis.fetch = (async (input, init) => {
13
18
  const start = Date.now();
@@ -63,7 +68,77 @@ export const installNetworkHandler = () => {
63
68
  throw e;
64
69
  }
65
70
  });
66
- };
71
+ }
72
+ function patchXhr() {
73
+ const XHR = globalThis.XMLHttpRequest;
74
+ if (typeof XHR !== 'function')
75
+ return;
76
+ const proto = XHR.prototype;
77
+ if (proto.__sentoriPatched)
78
+ return;
79
+ proto.__sentoriPatched = true;
80
+ const originalOpen = proto.open;
81
+ const originalSend = proto.send;
82
+ const originalSetHeader = proto.setRequestHeader;
83
+ proto.open = function (method, url, ...rest) {
84
+ this.__sentoriMethod = String(method).toUpperCase();
85
+ this.__sentoriUrl = typeof url === 'string' ? url : String(url);
86
+ // @ts-expect-error variadic forwarding to the native signature
87
+ return originalOpen.call(this, method, url, ...rest);
88
+ };
89
+ proto.send = function (body) {
90
+ const method = this.__sentoriMethod ?? 'GET';
91
+ const url = scrubUrl(this.__sentoriUrl ?? '');
92
+ const span = startSpan('http.client', {
93
+ name: `${method} ${url}`,
94
+ tags: { 'http.method': method, 'http.url': url },
95
+ });
96
+ this.__sentoriSpan = span;
97
+ this.__sentoriStart = Date.now();
98
+ // setRequestHeader must be called between open() and send(); we're
99
+ // inside send() before the underlying call, so this is legal.
100
+ try {
101
+ originalSetHeader.call(this, 'traceparent', toTraceparent(span.traceId, span.spanId));
102
+ }
103
+ catch {
104
+ // Some XHR polyfills are strict about header timing; if it
105
+ // rejects, drop the header rather than fail the request.
106
+ }
107
+ const finish = () => {
108
+ const s = this.__sentoriSpan;
109
+ if (!s)
110
+ return;
111
+ this.__sentoriSpan = undefined;
112
+ const status = this.status;
113
+ s.setTag('http.status', String(status));
114
+ // status 0 means network error / aborted / CORS block — treat
115
+ // as error. The `abort` event handler below downgrades aborts.
116
+ s.finish({ status: status === 0 || status >= 400 ? 'error' : 'ok' });
117
+ addBreadcrumb({
118
+ type: 'net',
119
+ data: {
120
+ method,
121
+ url,
122
+ status,
123
+ durationMs: Date.now() - (this.__sentoriStart ?? Date.now()),
124
+ },
125
+ });
126
+ };
127
+ this.addEventListener('loadend', finish);
128
+ this.addEventListener('abort', () => {
129
+ const s = this.__sentoriSpan;
130
+ if (!s)
131
+ return;
132
+ this.__sentoriSpan = undefined;
133
+ s.finish({ status: 'cancelled' });
134
+ addBreadcrumb({
135
+ type: 'net',
136
+ data: { method, url, status: 0, durationMs: Date.now() - (this.__sentoriStart ?? Date.now()), error: 'aborted' },
137
+ });
138
+ });
139
+ return originalSend.call(this, body);
140
+ };
141
+ }
67
142
  function mergeHeaders(input, init) {
68
143
  const out = new Headers();
69
144
  if (typeof input !== 'string' && !(input instanceof URL)) {
@@ -1 +1 @@
1
- {"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/handlers/network.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/handlers/network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,IAAI,UAAU,GAAG,KAAK,CAAC;AAEvB,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;AAE3E,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAS,EAAE;IAC9C,IAAI,UAAU;QAAE,OAAO;IACvB,UAAU,GAAG,IAAI,CAAC;IAClB,UAAU,EAAE,CAAC;IACb,QAAQ,EAAE,CAAC;AACb,CAAC,CAAC;AAEF,sEAAsE;AAEtE,SAAS,UAAU;IACjB,IAAI,OAAO,UAAU,CAAC,KAAK,KAAK,UAAU;QAAE,OAAO;IACnD,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC;IAElC,UAAU,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,KAAwB,EAAE,IAAkB,EAAE,EAAE;QACzE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM;YAC1B,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,QAAQ,IAAK,KAAiB;gBAC1D,CAAC,CAAE,KAAiB,CAAC,MAAM;gBAC3B,CAAC,CAAC,KAAK,CAAC,CAAW,CAAC;QAExB,+DAA+D;QAC/D,8DAA8D;QAC9D,iEAAiE;QACjE,8DAA8D;QAC9D,MAAM,IAAI,GAAG,SAAS,CAAC,aAAa,EAAE;YACpC,IAAI,EAAE,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,QAAQ,EAAE;YAC3C,IAAI,EAAE,EAAE,aAAa,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE;SACpE,CAAC,CAAC;QAEH,kDAAkD;QAClD,MAAM,OAAO,GAAgB,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC;QACjD,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACrE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;QAE1B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAC5C,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAChD,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7D,aAAa,CAAC;gBACZ,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE;oBACJ,MAAM;oBACN,GAAG,EAAE,QAAQ;oBACb,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;iBAC/B;aACF,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,YAAY,KAAK;gBAAE,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;YAChE,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YACzD,aAAa,CAAC;gBACZ,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE;oBACJ,MAAM;oBACN,GAAG,EAAE,QAAQ;oBACb,MAAM,EAAE,CAAC;oBACT,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;oBAC9B,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;iBACjB;aACF,CAAC,CAAC;YACH,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC,CAAiB,CAAC;AACrB,CAAC;AAiBD,SAAS,QAAQ;IACf,MAAM,GAAG,GAAI,UAAyD,CAAC,cAAc,CAAC;IACtF,IAAI,OAAO,GAAG,KAAK,UAAU;QAAE,OAAO;IACtC,MAAM,KAAK,GAAG,GAAG,CAAC,SAEjB,CAAC;IACF,IAAI,KAAK,CAAC,gBAAgB;QAAE,OAAO;IACnC,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAE9B,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC;IAChC,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC;IAChC,MAAM,iBAAiB,GAAG,KAAK,CAAC,gBAAgB,CAAC;IAEjD,KAAK,CAAC,IAAI,GAAG,UAEX,MAAc,EACd,GAAiB,EACjB,GAAG,IAAe;QAElB,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QACpD,IAAI,CAAC,YAAY,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChE,+DAA+D;QAC/D,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IACvD,CAAC,CAAC;IAEF,KAAK,CAAC,IAAI,GAAG,UAA2B,IAA+C;QACrF,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,IAAI,KAAK,CAAC;QAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,SAAS,CAAC,aAAa,EAAE;YACpC,IAAI,EAAE,GAAG,MAAM,IAAI,GAAG,EAAE;YACxB,IAAI,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE;SACjD,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEjC,mEAAmE;QACnE,8DAA8D;QAC9D,IAAI,CAAC;YACH,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACxF,CAAC;QAAC,MAAM,CAAC;YACP,2DAA2D;YAC3D,yDAAyD;QAC3D,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC;YAC7B,IAAI,CAAC,CAAC;gBAAE,OAAO;YACf,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;YAC3B,CAAC,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YACxC,8DAA8D;YAC9D,+DAA+D;YAC/D,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACrE,aAAa,CAAC;gBACZ,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE;oBACJ,MAAM;oBACN,GAAG;oBACH,MAAM;oBACN,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;iBAC7D;aACF,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YAClC,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC;YAC7B,IAAI,CAAC,CAAC;gBAAE,OAAO;YACf,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;YAC/B,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;YAClC,aAAa,CAAC;gBACZ,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE;aACjH,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAAwB,EAAE,IAAkB;IAChE,MAAM,GAAG,GAAG,IAAI,OAAO,EAAE,CAAC;IAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,YAAY,GAAG,CAAC,EAAE,CAAC;QACxD,KAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,IAAI,EAAE,OAAO,EAAE,CAAC;QAClB,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,aAAa,CAAC,OAAe,EAAE,MAAc;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnE,OAAO,MAAM,KAAK,IAAI,MAAM,KAAK,CAAC;AACpC,CAAC;AAED,SAAS,YAAY,CAAC,GAAY;IAChC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1D,OAAQ,GAA0B,CAAC,IAAI,KAAK,YAAY,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,KAAwB,EAAU,EAAE;IACtD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,YAAY,GAAG;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC;IAC5C,OAAQ,KAAiB,CAAC,GAAG,CAAC;AAChC,CAAC,CAAC;AAEF,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAU,EAAE;IACvC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;YAC5B,IAAI,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1B,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;gBACpC,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;QACD,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goliapkg/sentori-react-native",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Sentori SDK for React Native — JS-layer error capture, native crash handlers (iOS / Android), batched transport, fetch + react-navigation tracing.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://sentori.golia.jp",
@@ -33,9 +33,38 @@ const recorder = (async (input: Request | string | URL, init?: RequestInit) => {
33
33
  return new Response('', { status: r.status });
34
34
  }) as unknown as typeof fetch;
35
35
 
36
+ // Fake XMLHttpRequest so installNetworkHandler()'s patchXhr() has a
37
+ // prototype to patch. RN's native XHR isn't present in bun:test.
38
+ type FakeListener = () => void;
39
+ class FakeXHR {
40
+ status = 0;
41
+ private listeners: Record<string, FakeListener[]> = {};
42
+ private requestHeaders: Record<string, string> = {};
43
+ private opened = false;
44
+
45
+ open(_method: string, _url: string | URL): void {
46
+ this.opened = true;
47
+ }
48
+ setRequestHeader(name: string, value: string): void {
49
+ if (!this.opened) throw new Error('setRequestHeader before open');
50
+ this.requestHeaders[name.toLowerCase()] = value;
51
+ }
52
+ send(_body?: unknown): void {}
53
+ addEventListener(event: string, fn: FakeListener): void {
54
+ (this.listeners[event] ??= []).push(fn);
55
+ }
56
+ getHeader(name: string): string | undefined {
57
+ return this.requestHeaders[name.toLowerCase()];
58
+ }
59
+ fire(event: string): void {
60
+ for (const fn of this.listeners[event] ?? []) fn();
61
+ }
62
+ }
63
+
36
64
  beforeAll(() => {
37
65
  (globalThis as { fetch: typeof fetch }).fetch = recorder;
38
- installNetworkHandler();
66
+ (globalThis as { XMLHttpRequest: unknown }).XMLHttpRequest = FakeXHR as unknown;
67
+ installNetworkHandler(); // patches globalThis.fetch + XMLHttpRequest.prototype
39
68
  });
40
69
 
41
70
  beforeEach(() => {
@@ -106,3 +135,58 @@ describe('RN network handler tracing', () => {
106
135
  expect(h.get('traceparent')).toBeTruthy();
107
136
  });
108
137
  });
138
+
139
+ describe('RN XHR tracing (axios goes through XHR on RN)', () => {
140
+ test('patched XHR emits an http.client span on loadend', () => {
141
+ const x = new FakeXHR();
142
+ x.open('POST', 'https://api.example.com/v1/orders');
143
+ x.send('{}');
144
+ x.status = 201;
145
+ x.fire('loadend');
146
+
147
+ const sp = drainSpans()[0]!;
148
+ expect(sp.op).toBe('http.client');
149
+ expect(sp.name).toBe('POST https://api.example.com/v1/orders');
150
+ expect(sp.tags).toMatchObject({
151
+ 'http.method': 'POST',
152
+ 'http.status': '201',
153
+ 'http.url': 'https://api.example.com/v1/orders',
154
+ });
155
+ expect(sp.status).toBe('ok');
156
+ });
157
+
158
+ test('injects W3C traceparent request header', () => {
159
+ const x = new FakeXHR();
160
+ x.open('GET', 'https://api.example.com/x');
161
+ x.send();
162
+ expect(x.getHeader('traceparent')).toMatch(/^00-[0-9a-f]{32}-[0-9a-f]{16}-01$/);
163
+ x.status = 200;
164
+ x.fire('loadend');
165
+ });
166
+
167
+ test('5xx → span.status = "error"', () => {
168
+ const x = new FakeXHR();
169
+ x.open('GET', 'https://api.example.com/x');
170
+ x.send();
171
+ x.status = 502;
172
+ x.fire('loadend');
173
+ expect(drainSpans()[0]?.status).toBe('error');
174
+ });
175
+
176
+ test('status 0 → span.status = "error"', () => {
177
+ const x = new FakeXHR();
178
+ x.open('GET', 'https://api.example.com/x');
179
+ x.send();
180
+ x.status = 0;
181
+ x.fire('loadend');
182
+ expect(drainSpans()[0]?.status).toBe('error');
183
+ });
184
+
185
+ test('abort → span.status = "cancelled"', () => {
186
+ const x = new FakeXHR();
187
+ x.open('GET', 'https://api.example.com/x');
188
+ x.send();
189
+ x.fire('abort');
190
+ expect(drainSpans()[0]?.status).toBe('cancelled');
191
+ });
192
+ });
@@ -8,9 +8,15 @@ const AUTH_PARAMS = ['token', 'key', 'password', 'secret', 'access_token'];
8
8
 
9
9
  export const installNetworkHandler = (): void => {
10
10
  if (_installed) return;
11
- if (typeof globalThis.fetch !== 'function') return;
12
11
  _installed = true;
12
+ patchFetch();
13
+ patchXhr();
14
+ };
13
15
 
16
+ // ── fetch ──────────────────────────────────────────────────────────
17
+
18
+ function patchFetch(): void {
19
+ if (typeof globalThis.fetch !== 'function') return;
14
20
  const original = globalThis.fetch;
15
21
 
16
22
  globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => {
@@ -68,8 +74,103 @@ export const installNetworkHandler = (): void => {
68
74
  throw e;
69
75
  }
70
76
  }) as typeof fetch;
77
+ }
78
+
79
+ // ── XMLHttpRequest ─────────────────────────────────────────────────
80
+ //
81
+ // React Native's XHR is a native polyfill, not built on fetch — so
82
+ // patching `globalThis.fetch` alone misses every axios / older-style
83
+ // request. axios on RN uses its `xhr` adapter by default. We patch
84
+ // the prototype's `open` + `send` so the instance carries the span
85
+ // from `send()` to `loadend`.
86
+
87
+ type TracedXhr = XMLHttpRequest & {
88
+ __sentoriMethod?: string;
89
+ __sentoriUrl?: string;
90
+ __sentoriSpan?: ReturnType<typeof startSpan>;
91
+ __sentoriStart?: number;
71
92
  };
72
93
 
94
+ function patchXhr(): void {
95
+ const XHR = (globalThis as { XMLHttpRequest?: typeof XMLHttpRequest }).XMLHttpRequest;
96
+ if (typeof XHR !== 'function') return;
97
+ const proto = XHR.prototype as XMLHttpRequest & {
98
+ __sentoriPatched?: boolean;
99
+ };
100
+ if (proto.__sentoriPatched) return;
101
+ proto.__sentoriPatched = true;
102
+
103
+ const originalOpen = proto.open;
104
+ const originalSend = proto.send;
105
+ const originalSetHeader = proto.setRequestHeader;
106
+
107
+ proto.open = function (
108
+ this: TracedXhr,
109
+ method: string,
110
+ url: string | URL,
111
+ ...rest: unknown[]
112
+ ): void {
113
+ this.__sentoriMethod = String(method).toUpperCase();
114
+ this.__sentoriUrl = typeof url === 'string' ? url : String(url);
115
+ // @ts-expect-error variadic forwarding to the native signature
116
+ return originalOpen.call(this, method, url, ...rest);
117
+ };
118
+
119
+ proto.send = function (this: TracedXhr, body?: Document | XMLHttpRequestBodyInit | null): void {
120
+ const method = this.__sentoriMethod ?? 'GET';
121
+ const url = scrubUrl(this.__sentoriUrl ?? '');
122
+ const span = startSpan('http.client', {
123
+ name: `${method} ${url}`,
124
+ tags: { 'http.method': method, 'http.url': url },
125
+ });
126
+ this.__sentoriSpan = span;
127
+ this.__sentoriStart = Date.now();
128
+
129
+ // setRequestHeader must be called between open() and send(); we're
130
+ // inside send() before the underlying call, so this is legal.
131
+ try {
132
+ originalSetHeader.call(this, 'traceparent', toTraceparent(span.traceId, span.spanId));
133
+ } catch {
134
+ // Some XHR polyfills are strict about header timing; if it
135
+ // rejects, drop the header rather than fail the request.
136
+ }
137
+
138
+ const finish = () => {
139
+ const s = this.__sentoriSpan;
140
+ if (!s) return;
141
+ this.__sentoriSpan = undefined;
142
+ const status = this.status;
143
+ s.setTag('http.status', String(status));
144
+ // status 0 means network error / aborted / CORS block — treat
145
+ // as error. The `abort` event handler below downgrades aborts.
146
+ s.finish({ status: status === 0 || status >= 400 ? 'error' : 'ok' });
147
+ addBreadcrumb({
148
+ type: 'net',
149
+ data: {
150
+ method,
151
+ url,
152
+ status,
153
+ durationMs: Date.now() - (this.__sentoriStart ?? Date.now()),
154
+ },
155
+ });
156
+ };
157
+
158
+ this.addEventListener('loadend', finish);
159
+ this.addEventListener('abort', () => {
160
+ const s = this.__sentoriSpan;
161
+ if (!s) return;
162
+ this.__sentoriSpan = undefined;
163
+ s.finish({ status: 'cancelled' });
164
+ addBreadcrumb({
165
+ type: 'net',
166
+ data: { method, url, status: 0, durationMs: Date.now() - (this.__sentoriStart ?? Date.now()), error: 'aborted' },
167
+ });
168
+ });
169
+
170
+ return originalSend.call(this, body);
171
+ };
172
+ }
173
+
73
174
  function mergeHeaders(input: RequestInfo | URL, init?: RequestInit): Headers {
74
175
  const out = new Headers();
75
176
  if (typeof input !== 'string' && !(input instanceof URL)) {