react-native-nitro-fetch 1.3.2 → 1.4.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.
Files changed (39) hide show
  1. package/NitroFetch.podspec +1 -3
  2. package/README.md +39 -11
  3. package/android/src/main/java/com/margelo/nitro/nitrofetch/AutoPrefetcher.kt +6 -2
  4. package/android/src/main/java/com/margelo/nitro/nitrofetch/DevToolsReporterImpl.kt +27 -36
  5. package/android/src/main/java/com/margelo/nitro/nitrofetch/NitroFetchClient.kt +45 -0
  6. package/ios/NitroAutoPrefetcher.swift +4 -0
  7. package/ios/NitroDevToolsReporter.mm +37 -31
  8. package/ios/NitroFetchClient.swift +56 -0
  9. package/lib/module/CurlGenerator.js.map +1 -2
  10. package/lib/module/Headers.js.map +2 -1
  11. package/lib/module/HermesProfiler.js.map +2 -1
  12. package/lib/module/NetworkInspector.js +1 -5
  13. package/lib/module/NetworkInspector.js.map +2 -1
  14. package/lib/module/NitroCronet.nitro.js.map +2 -1
  15. package/lib/module/NitroFetch.nitro.js.map +2 -1
  16. package/lib/module/NitroInstances.js.map +2 -1
  17. package/lib/module/Request.js.map +1 -2
  18. package/lib/module/Response.js.map +2 -2
  19. package/lib/module/fetch.js +147 -1
  20. package/lib/module/fetch.js.map +1 -1
  21. package/lib/module/index.web.js +1 -0
  22. package/lib/module/index.web.js.map +1 -2
  23. package/lib/module/tokenRefresh.js.map +1 -2
  24. package/lib/module/utf8.js.map +1 -2
  25. package/lib/typescript/src/fetch.d.ts.map +1 -1
  26. package/package.json +1 -1
  27. package/src/CurlGenerator.js +26 -23
  28. package/src/Headers.js +116 -108
  29. package/src/HermesProfiler.js +18 -16
  30. package/src/NetworkInspector.js +179 -171
  31. package/src/NitroInstances.js +1 -2
  32. package/src/Request.js +164 -167
  33. package/src/Response.js +242 -244
  34. package/src/fetch.js +842 -706
  35. package/src/fetch.ts +170 -1
  36. package/src/index.js +2 -17
  37. package/src/index.web.js +67 -69
  38. package/src/tokenRefresh.js +77 -75
  39. package/src/utf8.js +27 -28
package/src/fetch.ts CHANGED
@@ -438,6 +438,169 @@ async function resolveBlobBody(
438
438
  return init;
439
439
  }
440
440
 
441
+ // http(s) -> native client; anything else is a local resource (hot path).
442
+ function isHttpUrl(url: string): boolean {
443
+ if (url.startsWith('http://') || url.startsWith('https://')) return true;
444
+ const c = url.charCodeAt(0);
445
+ if (c !== 104 && c !== 72) return false; // not 'h'/'H'
446
+ return /^https?:/i.test(url);
447
+ }
448
+
449
+ function getUrlString(input: RequestInfo | URL): string {
450
+ if (typeof input === 'string') return input;
451
+ if (input instanceof URL) return input.toString();
452
+ const u = (input as { url?: unknown } | null)?.url;
453
+ return typeof u === 'string' ? u : String(input);
454
+ }
455
+
456
+ function base64ToBytes(b64: string): Uint8Array {
457
+ const decode = (globalThis as { atob?: (s: string) => string }).atob;
458
+ if (typeof decode === 'function') {
459
+ const bin = decode(b64);
460
+ const out = new Uint8Array(bin.length);
461
+ for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
462
+ return out;
463
+ }
464
+ // base64 fallback for runtimes without a global atob.
465
+ /* eslint-disable no-bitwise */
466
+ const chars =
467
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
468
+ const clean = b64.replace(/[^A-Za-z0-9+/]/g, '');
469
+ const out = new Uint8Array(Math.floor((clean.length * 3) / 4));
470
+ let p = 0;
471
+ let buf = 0;
472
+ let bits = 0;
473
+ for (let i = 0; i < clean.length; i++) {
474
+ buf = (buf << 6) | chars.indexOf(clean[i]!);
475
+ bits += 6;
476
+ if (bits >= 8) {
477
+ bits -= 8;
478
+ out[p++] = (buf >> bits) & 0xff;
479
+ }
480
+ }
481
+ return out;
482
+ /* eslint-enable no-bitwise */
483
+ }
484
+
485
+ type MinimalTextDecoder = {
486
+ decode(input: ArrayBufferView): string;
487
+ };
488
+ type TextDecoderCtor = new (
489
+ label?: string,
490
+ options?: { fatal?: boolean }
491
+ ) => MinimalTextDecoder;
492
+
493
+ // Cached: our nitro-text-decoder if the app bundles it (aliased require keeps it optional, not a dep), else a global TextDecoder.
494
+ let _decoder: MinimalTextDecoder | null | undefined;
495
+ function resolveTextDecoder(): MinimalTextDecoder | null {
496
+ if (_decoder !== undefined) return _decoder;
497
+ try {
498
+ const dynamicRequire = require;
499
+ const mod = dynamicRequire('react-native-nitro-text-decoder') as {
500
+ TextDecoder?: TextDecoderCtor;
501
+ };
502
+ if (mod && typeof mod.TextDecoder === 'function') {
503
+ _decoder = new mod.TextDecoder('utf-8', { fatal: true });
504
+ return _decoder;
505
+ }
506
+ } catch {
507
+ // optional, not bundled
508
+ }
509
+ const GlobalTextDecoder = (globalThis as { TextDecoder?: TextDecoderCtor })
510
+ .TextDecoder;
511
+ if (typeof GlobalTextDecoder === 'function') {
512
+ _decoder = new GlobalTextDecoder('utf-8', { fatal: true });
513
+ return _decoder;
514
+ }
515
+ _decoder = null;
516
+ return _decoder;
517
+ }
518
+
519
+ // data: text via a TextDecoder; null (bytes-only) + a one-time warn if none.
520
+ let _warnedNoTextDecoder = false;
521
+ function decodeUtf8(bytes: Uint8Array): string | null {
522
+ const decoder = resolveTextDecoder();
523
+ if (decoder) {
524
+ try {
525
+ return decoder.decode(bytes);
526
+ } catch {
527
+ return null; // invalid UTF-8 -> keep bytes only
528
+ }
529
+ }
530
+ if (!_warnedNoTextDecoder) {
531
+ _warnedNoTextDecoder = true;
532
+ console.warn(
533
+ '[nitro-fetch] Reading a data: URL as text needs a TextDecoder. Install ' +
534
+ 'react-native-nitro-text-decoder or expose a global TextDecoder. The ' +
535
+ 'body is still available via response.arrayBuffer()/bytes().'
536
+ );
537
+ }
538
+ return null;
539
+ }
540
+
541
+ // Decode a data: URL into a synthetic 200 response, entirely in JS.
542
+ function decodeDataUrl(url: string): NitroResponseNative {
543
+ const comma = url.indexOf(',');
544
+ if (comma < 0) throw new TypeError('Failed to fetch: invalid data: URL');
545
+ const meta = url.slice(5, comma); // strip leading "data:"
546
+ const rawData = url.slice(comma + 1);
547
+ const isBase64 = /;base64\s*$/i.test(meta);
548
+ const mediaType =
549
+ (isBase64 ? meta.replace(/;base64\s*$/i, '') : meta).trim() ||
550
+ 'text/plain;charset=US-ASCII';
551
+
552
+ let bodyString: string | undefined;
553
+ let bodyBytes: ArrayBuffer | undefined;
554
+ let length: number;
555
+ if (isBase64) {
556
+ const bytes = base64ToBytes(rawData);
557
+ length = bytes.byteLength;
558
+ // bytes for arrayBuffer/bytes; string for text/json when a decoder exists.
559
+ bodyBytes = bytes.buffer as ArrayBuffer;
560
+ const decoded = decodeUtf8(bytes);
561
+ if (decoded != null) bodyString = decoded;
562
+ } else {
563
+ bodyString = decodeURIComponent(rawData);
564
+ length =
565
+ typeof TextEncoder !== 'undefined'
566
+ ? new TextEncoder().encode(bodyString).length
567
+ : bodyString.length;
568
+ }
569
+
570
+ return {
571
+ url,
572
+ status: 200,
573
+ statusText: 'OK',
574
+ ok: true,
575
+ redirected: false,
576
+ headers: [
577
+ { key: 'Content-Type', value: mediaType },
578
+ { key: 'Content-Length', value: String(length) },
579
+ ],
580
+ bodyString,
581
+ bodyBytes,
582
+ } as NitroResponseNative;
583
+ }
584
+
585
+ // Non-http(s): decode data: in JS, reject blob:, read file/content/path natively.
586
+ async function fetchLocalResource(
587
+ req: NitroRequestNative
588
+ ): Promise<NitroResponseNative> {
589
+ const url = req.url;
590
+ if (url.startsWith('data:')) return decodeDataUrl(url);
591
+ if (url.startsWith('blob:')) {
592
+ throw new TypeError(
593
+ 'nitro-fetch cannot read blob: URLs (the React Native blob registry is not ' +
594
+ 'reachable from native). Read blobs with the platform fetch/FileReader instead.'
595
+ );
596
+ }
597
+ ensureClient();
598
+ if (!client || typeof client.request !== 'function') {
599
+ throw new Error('NitroFetch client not available');
600
+ }
601
+ return client.request(req);
602
+ }
603
+
441
604
  async function nitroFetchRaw(
442
605
  input: RequestInfo | URL,
443
606
  init?: RequestInit
@@ -478,6 +641,11 @@ async function nitroFetchRaw(
478
641
 
479
642
  const req = buildNitroRequest(input, init);
480
643
 
644
+ // Route non-http(s) (data:/file://content://scheme-less) off the HTTP client.
645
+ if (!isHttpUrl(req.url)) {
646
+ return fetchLocalResource(req);
647
+ }
648
+
481
649
  // Inspector: record start (zero cost when disabled — single boolean check)
482
650
  let inspectorId: string | undefined;
483
651
  if (NetworkInspector.isEnabled()) {
@@ -696,7 +864,8 @@ export async function nitroFetch(
696
864
  } as any;
697
865
  }
698
866
 
699
- if ((init as any)?.stream === true) {
867
+ // Streaming is http(s)-only; local URLs fall through to nitroFetchRaw (check runs only when streaming).
868
+ if ((init as any)?.stream === true && isHttpUrl(getUrlString(input))) {
700
869
  return nitroStreamFetch(input, init);
701
870
  }
702
871
 
package/src/index.js CHANGED
@@ -1,24 +1,9 @@
1
- export {
2
- nitroFetch as fetch,
3
- nitroFetchOnWorklet,
4
- prefetch,
5
- prefetchOnAppStart,
6
- removeFromAutoPrefetch,
7
- removeAllFromAutoprefetch,
8
- __readAutoPrefetchQueue,
9
- } from './fetch';
1
+ export { nitroFetch as fetch, nitroFetchOnWorklet, prefetch, prefetchOnAppStart, removeFromAutoPrefetch, removeAllFromAutoprefetch, __readAutoPrefetchQueue, } from './fetch';
10
2
  export { NitroHeaders as Headers } from './Headers';
11
3
  export { NitroResponse as Response } from './Response';
12
4
  export { NitroRequest as Request } from './Request';
13
5
  export { NitroFetch } from './NitroInstances';
14
- export {
15
- registerTokenRefresh,
16
- clearTokenRefresh,
17
- callRefreshEndpoint,
18
- getStoredTokenRefreshConfig,
19
- getNestedField,
20
- applyTemplate,
21
- } from './tokenRefresh';
6
+ export { registerTokenRefresh, clearTokenRefresh, callRefreshEndpoint, getStoredTokenRefreshConfig, getNestedField, applyTemplate, } from './tokenRefresh';
22
7
  export { NetworkInspector } from './NetworkInspector';
23
8
  export { generateCurl } from './CurlGenerator';
24
9
  export { profileFetch } from './HermesProfiler';
package/src/index.web.js CHANGED
@@ -9,98 +9,96 @@ export { NetworkInspector } from './NetworkInspector';
9
9
  export { generateCurl } from './CurlGenerator';
10
10
  export { profileFetch } from './HermesProfiler';
11
11
  export async function fetch(input, init) {
12
- let resolvedInput = input;
13
- let resolvedInit = init;
14
- if (input instanceof NitroRequestClass) {
15
- const method = (init?.method ?? input.method).toUpperCase();
16
- const hasBodyMethod = method !== 'GET' && method !== 'HEAD';
17
- let body = init?.body;
18
- if (body === undefined && hasBodyMethod) {
19
- const bytes = await input.arrayBuffer().catch(() => undefined);
20
- body = bytes && bytes.byteLength > 0 ? bytes : null;
12
+ let resolvedInput = input;
13
+ let resolvedInit = init;
14
+ if (input instanceof NitroRequestClass) {
15
+ const method = (init?.method ?? input.method).toUpperCase();
16
+ const hasBodyMethod = method !== 'GET' && method !== 'HEAD';
17
+ let body = init?.body;
18
+ if (body === undefined && hasBodyMethod) {
19
+ const bytes = await input.arrayBuffer().catch(() => undefined);
20
+ body = bytes && bytes.byteLength > 0 ? bytes : null;
21
+ }
22
+ resolvedInput = input.url;
23
+ resolvedInit = {
24
+ ...init,
25
+ method,
26
+ headers: (init?.headers ??
27
+ input.headers),
28
+ body,
29
+ redirect: init?.redirect ?? input.redirect,
30
+ cache: init?.cache ?? input.cache,
31
+ signal: init?.signal ?? input.signal,
32
+ };
21
33
  }
22
- resolvedInput = input.url;
23
- resolvedInit = {
24
- ...init,
25
- method,
26
- headers: init?.headers ?? input.headers,
27
- body,
28
- redirect: init?.redirect ?? input.redirect,
29
- cache: init?.cache ?? input.cache,
30
- signal: init?.signal ?? input.signal,
31
- };
32
- }
33
- return globalThis.fetch(resolvedInput, resolvedInit);
34
+ return globalThis.fetch(resolvedInput, resolvedInit);
34
35
  }
35
36
  export async function nitroFetchOnWorklet(input, init, mapWorklet, _options) {
36
- console.warn(
37
- 'nitroFetchOnWorklet: worklets are not available on web; running on the JS thread'
38
- );
39
- const res = await globalThis.fetch(input, init);
40
- const bodyBytes = await res.clone().arrayBuffer();
41
- let bodyString;
42
- try {
43
- bodyString = await res.clone().text();
44
- } catch {
45
- bodyString = undefined;
46
- }
47
- const headers = [];
48
- res.headers.forEach((v, k) => headers.push({ key: k, value: v }));
49
- return mapWorklet({
50
- url: res.url,
51
- status: res.status,
52
- statusText: res.statusText,
53
- ok: res.ok,
54
- redirected: res.redirected ?? false,
55
- headers,
56
- bodyBytes,
57
- bodyString,
58
- });
37
+ console.warn('nitroFetchOnWorklet: worklets are not available on web; running on the JS thread');
38
+ const res = await globalThis.fetch(input, init);
39
+ const bodyBytes = await res.clone().arrayBuffer();
40
+ let bodyString;
41
+ try {
42
+ bodyString = await res.clone().text();
43
+ }
44
+ catch {
45
+ bodyString = undefined;
46
+ }
47
+ const headers = [];
48
+ res.headers.forEach((v, k) => headers.push({ key: k, value: v }));
49
+ return mapWorklet({
50
+ url: res.url,
51
+ status: res.status,
52
+ statusText: res.statusText,
53
+ ok: res.ok,
54
+ redirected: res.redirected ?? false,
55
+ headers,
56
+ bodyBytes,
57
+ bodyString,
58
+ });
59
59
  }
60
60
  export async function prefetch(_input, _init) {
61
- console.warn('prefetch is not available on web');
61
+ console.warn('prefetch is not available on web');
62
62
  }
63
63
  export async function prefetchOnAppStart(_input, _init) {
64
- console.warn('prefetchOnAppStart is not available on web');
64
+ console.warn('prefetchOnAppStart is not available on web');
65
65
  }
66
66
  export async function removeFromAutoPrefetch(_prefetchKey) {
67
- console.warn('removeFromAutoPrefetch is not available on web');
67
+ console.warn('removeFromAutoPrefetch is not available on web');
68
68
  }
69
69
  export async function removeAllFromAutoprefetch() {
70
- console.warn('removeAllFromAutoprefetch is not available on web');
70
+ console.warn('removeAllFromAutoprefetch is not available on web');
71
71
  }
72
- export const NitroFetch = new Proxy(
73
- {},
74
- {
72
+ export const NitroFetch = new Proxy({}, {
75
73
  get(_target, prop) {
76
- console.warn(`NitroFetch.${String(prop)} is not available on web`);
77
- return undefined;
74
+ console.warn(`NitroFetch.${String(prop)} is not available on web`);
75
+ return undefined;
78
76
  },
79
- }
80
- );
77
+ });
81
78
  export function registerTokenRefresh(_options) {
82
- console.warn('registerTokenRefresh is not available on web');
79
+ console.warn('registerTokenRefresh is not available on web');
83
80
  }
84
81
  export function clearTokenRefresh(_target) {
85
- console.warn('clearTokenRefresh is not available on web');
82
+ console.warn('clearTokenRefresh is not available on web');
86
83
  }
87
84
  export async function callRefreshEndpoint(_config) {
88
- console.warn('callRefreshEndpoint is not available on web');
89
- return {};
85
+ console.warn('callRefreshEndpoint is not available on web');
86
+ return {};
90
87
  }
91
88
  export function getStoredTokenRefreshConfig(_target) {
92
- console.warn('getStoredTokenRefreshConfig is not available on web');
93
- return null;
89
+ console.warn('getStoredTokenRefreshConfig is not available on web');
90
+ return null;
94
91
  }
95
92
  export function getNestedField(obj, dotPath) {
96
- const parts = dotPath.split('.');
97
- let current = obj;
98
- for (const part of parts) {
99
- if (current == null || typeof current !== 'object') return undefined;
100
- current = current[part];
101
- }
102
- return current != null ? String(current) : undefined;
93
+ const parts = dotPath.split('.');
94
+ let current = obj;
95
+ for (const part of parts) {
96
+ if (current == null || typeof current !== 'object')
97
+ return undefined;
98
+ current = current[part];
99
+ }
100
+ return current != null ? String(current) : undefined;
103
101
  }
104
102
  export function applyTemplate(template, value) {
105
- return template.replace(/\{\{value\}\}/g, value);
103
+ return template.replace(/\{\{value\}\}/g, value);
106
104
  }
@@ -9,94 +9,96 @@ const KEY_FETCH_CACHE = 'nitro_token_refresh_fetch_cache';
9
9
  * Resolve a dot-notation path inside a parsed JSON object.
10
10
  */
11
11
  export function getNestedField(obj, dotPath) {
12
- const parts = dotPath.split('.');
13
- let current = obj;
14
- for (const part of parts) {
15
- if (current == null || typeof current !== 'object') return undefined;
16
- current = current[part];
17
- }
18
- return current != null ? String(current) : undefined;
12
+ const parts = dotPath.split('.');
13
+ let current = obj;
14
+ for (const part of parts) {
15
+ if (current == null || typeof current !== 'object')
16
+ return undefined;
17
+ current = current[part];
18
+ }
19
+ return current != null ? String(current) : undefined;
19
20
  }
20
21
  export function applyTemplate(template, value) {
21
- return template.replace(/\{\{value\}\}/g, value);
22
+ return template.replace(/\{\{value\}\}/g, value);
22
23
  }
23
24
  function applyCompositeTemplate(template, values) {
24
- return template.replace(/\{\{(\w+)\}\}/g, (_, key) => values[key] ?? '');
25
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => values[key] ?? '');
25
26
  }
26
27
  export async function callRefreshEndpoint(config) {
27
- const method = config.method ?? 'POST';
28
- const response = await fetch(config.url, {
29
- method,
30
- headers: config.headers,
31
- body: config.body,
32
- });
33
- if (!response.ok) {
34
- throw new Error(
35
- `Token refresh failed: ${response.status} ${response.statusText}`
36
- );
37
- }
38
- const headers = {};
39
- if (config.responseType === 'text') {
40
- const text = await response.text();
41
- if (config.textHeader) {
42
- headers[config.textHeader] = config.textTemplate
43
- ? applyTemplate(config.textTemplate, text)
44
- : text;
28
+ const method = config.method ?? 'POST';
29
+ const response = await fetch(config.url, {
30
+ method,
31
+ headers: config.headers,
32
+ body: config.body,
33
+ });
34
+ if (!response.ok) {
35
+ throw new Error(`Token refresh failed: ${response.status} ${response.statusText}`);
45
36
  }
46
- return headers;
47
- }
48
- // Default: json
49
- const json = await response.json();
50
- if (config.mappings) {
51
- for (const mapping of config.mappings) {
52
- const value = getNestedField(json, mapping.jsonPath);
53
- if (value != null) {
54
- headers[mapping.header] = mapping.valueTemplate
55
- ? applyTemplate(mapping.valueTemplate, value)
56
- : value;
57
- }
37
+ const headers = {};
38
+ if (config.responseType === 'text') {
39
+ const text = await response.text();
40
+ if (config.textHeader) {
41
+ headers[config.textHeader] = config.textTemplate
42
+ ? applyTemplate(config.textTemplate, text)
43
+ : text;
44
+ }
45
+ return headers;
46
+ }
47
+ // Default: json
48
+ const json = await response.json();
49
+ if (config.mappings) {
50
+ for (const mapping of config.mappings) {
51
+ const value = getNestedField(json, mapping.jsonPath);
52
+ if (value != null) {
53
+ headers[mapping.header] = mapping.valueTemplate
54
+ ? applyTemplate(mapping.valueTemplate, value)
55
+ : value;
56
+ }
57
+ }
58
58
  }
59
- }
60
- if (config.compositeHeaders) {
61
- for (const comp of config.compositeHeaders) {
62
- const values = {};
63
- for (const [placeholder, jsonPath] of Object.entries(comp.paths)) {
64
- const val = getNestedField(json, jsonPath);
65
- if (val != null) values[placeholder] = val;
66
- }
67
- headers[comp.header] = applyCompositeTemplate(comp.template, values);
59
+ if (config.compositeHeaders) {
60
+ for (const comp of config.compositeHeaders) {
61
+ const values = {};
62
+ for (const [placeholder, jsonPath] of Object.entries(comp.paths)) {
63
+ const val = getNestedField(json, jsonPath);
64
+ if (val != null)
65
+ values[placeholder] = val;
66
+ }
67
+ headers[comp.header] = applyCompositeTemplate(comp.template, values);
68
+ }
68
69
  }
69
- }
70
- return headers;
70
+ return headers;
71
71
  }
72
72
  export function registerTokenRefresh(options) {
73
- const { target, ...config } = options;
74
- const raw = JSON.stringify(config);
75
- if (target === 'websocket' || target === 'all') {
76
- NativeStorageSingleton.setSecureString(KEY_WS, raw);
77
- }
78
- if (target === 'fetch' || target === 'all') {
79
- NativeStorageSingleton.setSecureString(KEY_FETCH, raw);
80
- }
73
+ const { target, ...config } = options;
74
+ const raw = JSON.stringify(config);
75
+ if (target === 'websocket' || target === 'all') {
76
+ NativeStorageSingleton.setSecureString(KEY_WS, raw);
77
+ }
78
+ if (target === 'fetch' || target === 'all') {
79
+ NativeStorageSingleton.setSecureString(KEY_FETCH, raw);
80
+ }
81
81
  }
82
82
  export function clearTokenRefresh(target) {
83
- const t = target ?? 'all';
84
- if (t === 'websocket' || t === 'all') {
85
- NativeStorageSingleton.removeSecureString(KEY_WS);
86
- NativeStorageSingleton.removeSecureString(KEY_WS_CACHE);
87
- }
88
- if (t === 'fetch' || t === 'all') {
89
- NativeStorageSingleton.removeSecureString(KEY_FETCH);
90
- NativeStorageSingleton.removeSecureString(KEY_FETCH_CACHE);
91
- }
83
+ const t = target ?? 'all';
84
+ if (t === 'websocket' || t === 'all') {
85
+ NativeStorageSingleton.removeSecureString(KEY_WS);
86
+ NativeStorageSingleton.removeSecureString(KEY_WS_CACHE);
87
+ }
88
+ if (t === 'fetch' || t === 'all') {
89
+ NativeStorageSingleton.removeSecureString(KEY_FETCH);
90
+ NativeStorageSingleton.removeSecureString(KEY_FETCH_CACHE);
91
+ }
92
92
  }
93
93
  export function getStoredTokenRefreshConfig(target) {
94
- const key = target === 'websocket' ? KEY_WS : KEY_FETCH;
95
- try {
96
- const raw = NativeStorageSingleton.getSecureString(key);
97
- if (!raw) return null;
98
- return JSON.parse(raw);
99
- } catch {
100
- return null;
101
- }
94
+ const key = target === 'websocket' ? KEY_WS : KEY_FETCH;
95
+ try {
96
+ const raw = NativeStorageSingleton.getSecureString(key);
97
+ if (!raw)
98
+ return null;
99
+ return JSON.parse(raw);
100
+ }
101
+ catch {
102
+ return null;
103
+ }
102
104
  }
package/src/utf8.js CHANGED
@@ -2,40 +2,39 @@ let _TextEncoder;
2
2
  let _TextDecoder;
3
3
  const NITRO_TEXT_DECODER_PKG = 'react-native-nitro-text-decoder';
4
4
  function loadOptionalTextCodec() {
5
- try {
6
- // Hide require from the bundler so the package stays truly optional.
7
- // eslint-disable-next-line no-new-func
8
- const dynamicRequire = new Function('mod', 'return require(mod);');
9
- return dynamicRequire(NITRO_TEXT_DECODER_PKG);
10
- } catch {
11
- return {};
12
- }
5
+ try {
6
+ // Hide require from the bundler so the package stays truly optional.
7
+ // eslint-disable-next-line no-new-func
8
+ const dynamicRequire = new Function('mod', 'return require(mod);');
9
+ return dynamicRequire(NITRO_TEXT_DECODER_PKG);
10
+ }
11
+ catch {
12
+ return {};
13
+ }
13
14
  }
14
15
  if (typeof TextEncoder !== 'undefined') {
15
- _TextEncoder = TextEncoder;
16
- } else {
17
- _TextEncoder = loadOptionalTextCodec().TextEncoder;
16
+ _TextEncoder = TextEncoder;
17
+ }
18
+ else {
19
+ _TextEncoder = loadOptionalTextCodec().TextEncoder;
18
20
  }
19
21
  if (typeof TextDecoder !== 'undefined') {
20
- _TextDecoder = TextDecoder;
21
- } else {
22
- _TextDecoder = loadOptionalTextCodec().TextDecoder;
22
+ _TextDecoder = TextDecoder;
23
+ }
24
+ else {
25
+ _TextDecoder = loadOptionalTextCodec().TextDecoder;
23
26
  }
24
27
  export function stringToUTF8(str) {
25
- if (!_TextEncoder) {
26
- console.warn(
27
- 'stringToUTF8: TextEncoder not available. Install react-native-nitro-text-decoder.'
28
- );
29
- return new Uint8Array(0);
30
- }
31
- return new _TextEncoder().encode(str);
28
+ if (!_TextEncoder) {
29
+ console.warn('stringToUTF8: TextEncoder not available. Install react-native-nitro-text-decoder.');
30
+ return new Uint8Array(0);
31
+ }
32
+ return new _TextEncoder().encode(str);
32
33
  }
33
34
  export function utf8ToString(bytes) {
34
- if (!_TextDecoder) {
35
- console.warn(
36
- 'utf8ToString: TextDecoder not available. Install react-native-nitro-text-decoder.'
37
- );
38
- return '';
39
- }
40
- return new _TextDecoder().decode(bytes);
35
+ if (!_TextDecoder) {
36
+ console.warn('utf8ToString: TextDecoder not available. Install react-native-nitro-text-decoder.');
37
+ return '';
38
+ }
39
+ return new _TextDecoder().decode(bytes);
41
40
  }