[{"data":1,"prerenderedAt":1060},["ShallowReactive",2],{"docs:/docs/sdks/react-native":3},{"id":4,"title":5,"body":6,"description":1053,"extension":1054,"meta":1055,"navigation":213,"path":1056,"seo":1057,"stem":1058,"__hash__":1059},"docs/docs/sdks/react-native.md","React Native SDK",{"type":7,"value":8,"toc":1040},"minimark",[9,14,27,32,42,131,135,167,178,182,324,331,427,439,443,446,482,485,489,492,630,636,640,665,672,676,686,746,750,757,828,839,843,852,944,968,972,994,1001,1005,1017,1036],[10,11,13],"h1",{"id":12},"nolagreact-native","@nolag/react-native",[15,16,17,18,26],"p",{},"React Native bindings for ",[19,20,22],"a",{"href":21},"/docs/sdks/javascript",[23,24,25],"code",{},"@nolag/js-sdk",".",[28,29,31],"h2",{"id":30},"overview","Overview",[15,33,34,35,37,38,41],{},"This is a convenience layer, not a required one. As of ",[23,36,25],{}," 1.12.0 the core SDK works on React Native by itself, because it ships a ",[23,39,40],{},"react-native"," export condition that Metro resolves correctly. What this package adds is the platform behaviour you would otherwise have to write yourself, and probably get wrong on iOS.",[43,44,45,60],"table",{},[46,47,48],"thead",{},[49,50,51,54,57],"tr",{},[52,53],"th",{},[52,55,56],{},"Without this package",[52,58,59],{},"With it",[61,62,63,81,95,106,117],"tbody",{},[49,64,65,75,78],{},[66,67,68,71,72],"td",{},[23,69,70],{},"TextEncoder","/",[23,73,74],{},"TextDecoder",[66,76,77],{},"msgpack constructs both at module scope; missing globals throw on import, before your code runs",[66,79,80],{},"polyfilled if absent, untouched if present",[49,82,83,86,89],{},[66,84,85],{},"App background/foreground",[66,87,88],{},"no signal at all: the core defaults to the Page Visibility API, which React Native does not have",[66,90,91,94],{},[23,92,93],{},"AppState"," wired to the SDK's lifecycle adapter",[49,96,97,100,103],{},[66,98,99],{},"Token expiry during suspend",[66,101,102],{},"JS timers do not fire reliably while suspended, so a scheduled refresh can be skipped and the held token is already dead",[66,104,105],{},"rechecked on every foreground",[49,107,108,111,114],{},[66,109,110],{},"Network flap",[66,112,113],{},"reconnect backoff grows to 30s and keeps waiting after the radio returns",[66,115,116],{},"NetInfo collapses the backoff and retries immediately",[49,118,119,122,125],{},[66,120,121],{},"Cold start",[66,123,124],{},"a round trip to your backend to mint a token, on the critical path",[66,126,127,128],{},"cached until shortly before ",[23,129,130],{},"exp",[28,132,134],{"id":133},"installation","Installation",[136,137,138],"code-tabs",{},[139,140,146],"pre",{"className":141,"code":142,"filename":143,"language":144,"meta":145,"style":145},"language-bash shiki shiki-themes github-light github-dark","npm install @nolag/react-native @nolag/js-sdk\n","Terminal","bash","",[23,147,148],{"__ignoreMap":145},[149,150,153,157,161,164],"span",{"class":151,"line":152},"line",1,[149,154,156],{"class":155},"sScJk","npm",[149,158,160],{"class":159},"sZZnC"," install",[149,162,163],{"class":159}," @nolag/react-native",[149,165,166],{"class":159}," @nolag/js-sdk\n",[168,169,171],"note",{"title":170},"No native modules",[15,172,173,174,177],{},"This package pulls in no native modules of its own. NetInfo and storage are injected rather than imported, because Metro resolves ",[23,175,176],{},"require()"," statically and fails the build on an unresolved module, so the usual try/catch-around-an-optional-import trick does not work as it does under Node. That is also what lets it run in Expo Go.",[28,179,181],{"id":180},"quick-start","Quick Start",[136,183,184],{},[139,185,190],{"className":186,"code":187,"filename":188,"language":189,"meta":145,"style":145},"language-typescript shiki shiki-themes github-light github-dark","import { NoLag } from '@nolag/react-native'\n\n// Pass a TokenProvider, never a token string.\nconst client = NoLag(async () => {\n  const res = await fetch('https://your-api.example/nolag-token')\n  return (await res.json()).token\n})\n\nawait client.connect()\n","TypeScript","typescript",[23,191,192,208,215,222,253,278,299,305,310],{"__ignoreMap":145},[149,193,194,198,202,205],{"class":151,"line":152},[149,195,197],{"class":196},"szBVR","import",[149,199,201],{"class":200},"sVt8B"," { NoLag } ",[149,203,204],{"class":196},"from",[149,206,207],{"class":159}," '@nolag/react-native'\n",[149,209,211],{"class":151,"line":210},2,[149,212,214],{"emptyLinePlaceholder":213},true,"\n",[149,216,218],{"class":151,"line":217},3,[149,219,221],{"class":220},"sJ8bj","// Pass a TokenProvider, never a token string.\n",[149,223,225,228,232,235,238,241,244,247,250],{"class":151,"line":224},4,[149,226,227],{"class":196},"const",[149,229,231],{"class":230},"sj4cs"," client",[149,233,234],{"class":196}," =",[149,236,237],{"class":155}," NoLag",[149,239,240],{"class":200},"(",[149,242,243],{"class":196},"async",[149,245,246],{"class":200}," () ",[149,248,249],{"class":196},"=>",[149,251,252],{"class":200}," {\n",[149,254,256,259,262,264,267,270,272,275],{"class":151,"line":255},5,[149,257,258],{"class":196},"  const",[149,260,261],{"class":230}," res",[149,263,234],{"class":196},[149,265,266],{"class":196}," await",[149,268,269],{"class":155}," fetch",[149,271,240],{"class":200},[149,273,274],{"class":159},"'https://your-api.example/nolag-token'",[149,276,277],{"class":200},")\n",[149,279,281,284,287,290,293,296],{"class":151,"line":280},6,[149,282,283],{"class":196},"  return",[149,285,286],{"class":200}," (",[149,288,289],{"class":196},"await",[149,291,292],{"class":200}," res.",[149,294,295],{"class":155},"json",[149,297,298],{"class":200},"()).token\n",[149,300,302],{"class":151,"line":301},7,[149,303,304],{"class":200},"})\n",[149,306,308],{"class":151,"line":307},8,[149,309,214],{"emptyLinePlaceholder":213},[149,311,313,315,318,321],{"class":151,"line":312},9,[149,314,289],{"class":196},[149,316,317],{"class":200}," client.",[149,319,320],{"class":155},"connect",[149,322,323],{"class":200},"()\n",[15,325,326,327,330],{},"It returns a genuine ",[23,328,329],{},"NoLagSocket",", so it drops straight into the app SDKs:",[136,332,333],{},[139,334,336],{"className":186,"code":335,"filename":188,"language":189,"meta":145,"style":145},"import { NoLag } from '@nolag/react-native'\nimport { NoLagChat } from '@nolag/chat'\n\nconst client = NoLag(tokenProvider)\nconst chat = new NoLagChat({ client, username: 'Alice' })\n\nawait client.connect()\nawait chat.ready()\n",[23,337,338,348,360,364,377,401,405,415],{"__ignoreMap":145},[149,339,340,342,344,346],{"class":151,"line":152},[149,341,197],{"class":196},[149,343,201],{"class":200},[149,345,204],{"class":196},[149,347,207],{"class":159},[149,349,350,352,355,357],{"class":151,"line":210},[149,351,197],{"class":196},[149,353,354],{"class":200}," { NoLagChat } ",[149,356,204],{"class":196},[149,358,359],{"class":159}," '@nolag/chat'\n",[149,361,362],{"class":151,"line":217},[149,363,214],{"emptyLinePlaceholder":213},[149,365,366,368,370,372,374],{"class":151,"line":224},[149,367,227],{"class":196},[149,369,231],{"class":230},[149,371,234],{"class":196},[149,373,237],{"class":155},[149,375,376],{"class":200},"(tokenProvider)\n",[149,378,379,381,384,386,389,392,395,398],{"class":151,"line":255},[149,380,227],{"class":196},[149,382,383],{"class":230}," chat",[149,385,234],{"class":196},[149,387,388],{"class":196}," new",[149,390,391],{"class":155}," NoLagChat",[149,393,394],{"class":200},"({ client, username: ",[149,396,397],{"class":159},"'Alice'",[149,399,400],{"class":200}," })\n",[149,402,403],{"class":151,"line":280},[149,404,214],{"emptyLinePlaceholder":213},[149,406,407,409,411,413],{"class":151,"line":301},[149,408,289],{"class":196},[149,410,317],{"class":200},[149,412,320],{"class":155},[149,414,323],{"class":200},[149,416,417,419,422,425],{"class":151,"line":307},[149,418,289],{"class":196},[149,420,421],{"class":200}," chat.",[149,423,424],{"class":155},"ready",[149,426,323],{"class":200},[168,428,431],{"title":429,"type":430},"Never ship a long-lived token","warning",[15,432,433,434,438],{},"An actor access token embedded in an app bundle is extractable from the IPA or APK by anyone who downloads your app. The provider should call your backend, which mints a short-lived ",[19,435,437],{"href":436},"/docs/client-tokens","client token"," using a project signing key that never leaves your server.",[28,440,442],{"id":441},"network-reachability","Network reachability",[15,444,445],{},"Pass the NetInfo module in and the client reconnects the moment the radio returns, instead of waiting out a backoff that has already grown to 30 seconds.",[136,447,448],{},[139,449,451],{"className":186,"code":450,"filename":188,"language":189,"meta":145,"style":145},"import NetInfo from '@react-native-community/netinfo'\n\nconst client = NoLag(tokenProvider, { netInfo: NetInfo })\n",[23,452,453,465,469],{"__ignoreMap":145},[149,454,455,457,460,462],{"class":151,"line":152},[149,456,197],{"class":196},[149,458,459],{"class":200}," NetInfo ",[149,461,204],{"class":196},[149,463,464],{"class":159}," '@react-native-community/netinfo'\n",[149,466,467],{"class":151,"line":210},[149,468,214],{"emptyLinePlaceholder":213},[149,470,471,473,475,477,479],{"class":151,"line":217},[149,472,227],{"class":196},[149,474,231],{"class":230},[149,476,234],{"class":196},[149,478,237],{"class":155},[149,480,481],{"class":200},"(tokenProvider, { netInfo: NetInfo })\n",[15,483,484],{},"Omit it and the client still reconnects, just on the normal backoff schedule.",[28,486,488],{"id":487},"token-caching","Token caching",[15,490,491],{},"Skip the token round trip on warm launches. Storage is injected for the same reason as NetInfo.",[136,493,494,595],{},[139,495,498],{"className":186,"code":496,"filename":497,"language":189,"meta":145,"style":145},"import { MMKV } from 'react-native-mmkv'\nimport { NoLag, createCachedTokenProvider, fromMMKV } from '@nolag/react-native'\n\nconst storage = new MMKV()\n\nconst client = NoLag(\n  createCachedTokenProvider({\n    provider: fetchTokenFromYourBackend,\n    storage: fromMMKV(storage)\n  })\n)\n","MMKV",[23,499,500,512,523,527,543,547,560,568,573,584,590],{"__ignoreMap":145},[149,501,502,504,507,509],{"class":151,"line":152},[149,503,197],{"class":196},[149,505,506],{"class":200}," { MMKV } ",[149,508,204],{"class":196},[149,510,511],{"class":159}," 'react-native-mmkv'\n",[149,513,514,516,519,521],{"class":151,"line":210},[149,515,197],{"class":196},[149,517,518],{"class":200}," { NoLag, createCachedTokenProvider, fromMMKV } ",[149,520,204],{"class":196},[149,522,207],{"class":159},[149,524,525],{"class":151,"line":217},[149,526,214],{"emptyLinePlaceholder":213},[149,528,529,531,534,536,538,541],{"class":151,"line":224},[149,530,227],{"class":196},[149,532,533],{"class":230}," storage",[149,535,234],{"class":196},[149,537,388],{"class":196},[149,539,540],{"class":155}," MMKV",[149,542,323],{"class":200},[149,544,545],{"class":151,"line":255},[149,546,214],{"emptyLinePlaceholder":213},[149,548,549,551,553,555,557],{"class":151,"line":280},[149,550,227],{"class":196},[149,552,231],{"class":230},[149,554,234],{"class":196},[149,556,237],{"class":155},[149,558,559],{"class":200},"(\n",[149,561,562,565],{"class":151,"line":301},[149,563,564],{"class":155},"  createCachedTokenProvider",[149,566,567],{"class":200},"({\n",[149,569,570],{"class":151,"line":307},[149,571,572],{"class":200},"    provider: fetchTokenFromYourBackend,\n",[149,574,575,578,581],{"class":151,"line":312},[149,576,577],{"class":200},"    storage: ",[149,579,580],{"class":155},"fromMMKV",[149,582,583],{"class":200},"(storage)\n",[149,585,587],{"class":151,"line":586},10,[149,588,589],{"class":200},"  })\n",[149,591,593],{"class":151,"line":592},11,[149,594,277],{"class":200},[139,596,599],{"className":186,"code":597,"filename":598,"language":189,"meta":145,"style":145},"import AsyncStorage from '@react-native-async-storage/async-storage'\n\n// AsyncStorage satisfies the TokenStore contract directly, no adapter needed.\ncreateCachedTokenProvider({ provider, storage: AsyncStorage })\n","AsyncStorage",[23,600,601,613,617,622],{"__ignoreMap":145},[149,602,603,605,608,610],{"class":151,"line":152},[149,604,197],{"class":196},[149,606,607],{"class":200}," AsyncStorage ",[149,609,204],{"class":196},[149,611,612],{"class":159}," '@react-native-async-storage/async-storage'\n",[149,614,615],{"class":151,"line":210},[149,616,214],{"emptyLinePlaceholder":213},[149,618,619],{"class":151,"line":217},[149,620,621],{"class":220},"// AsyncStorage satisfies the TokenStore contract directly, no adapter needed.\n",[149,623,624,627],{"class":151,"line":224},[149,625,626],{"class":155},"createCachedTokenProvider",[149,628,629],{"class":200},"({ provider, storage: AsyncStorage })\n",[15,631,632,633,635],{},"Opaque (non-JWT) tokens are never cached: without an ",[23,634,130],{}," claim there is no safe way to know when to stop using one. Storage failures are non-fatal, so a locked keychain or a full disk degrades to an uncached fetch rather than a failed connection.",[28,637,639],{"id":638},"backgrounding","Backgrounding",[136,641,642],{},[139,643,645],{"className":186,"code":644,"filename":188,"language":189,"meta":145,"style":145},"const client = NoLag(tokenProvider, { disconnectOnHidden: true })\n",[23,646,647],{"__ignoreMap":145},[149,648,649,651,653,655,657,660,663],{"class":151,"line":152},[149,650,227],{"class":196},[149,652,231],{"class":230},[149,654,234],{"class":196},[149,656,237],{"class":155},[149,658,659],{"class":200},"(tokenProvider, { disconnectOnHidden: ",[149,661,662],{"class":230},"true",[149,664,400],{"class":200},[15,666,667,668,671],{},"Off by default. iOS reports ",[23,669,670],{},"inactive"," for transient states, meaning the app switcher, an incoming call, Control Centre and the biometric prompt. Those are ignored, so only a real background drops the socket.",[28,673,675],{"id":674},"cleaning-up","Cleaning up",[15,677,678,681,682,685],{},[23,679,680],{},"disconnect()"," deliberately keeps the AppState and NetInfo subscriptions alive, because a backgrounded client has to be able to come back. When the client itself is going away, call ",[23,683,684],{},"destroy()",":",[136,687,688],{},[139,689,691],{"className":186,"code":690,"filename":188,"language":189,"meta":145,"style":145},"useEffect(() => {\n  const client = NoLag(tokenProvider)\n  client.connect()\n  return () => client.destroy()\n}, [])\n",[23,692,693,705,717,726,741],{"__ignoreMap":145},[149,694,695,698,701,703],{"class":151,"line":152},[149,696,697],{"class":155},"useEffect",[149,699,700],{"class":200},"(() ",[149,702,249],{"class":196},[149,704,252],{"class":200},[149,706,707,709,711,713,715],{"class":151,"line":210},[149,708,258],{"class":196},[149,710,231],{"class":230},[149,712,234],{"class":196},[149,714,237],{"class":155},[149,716,376],{"class":200},[149,718,719,722,724],{"class":151,"line":217},[149,720,721],{"class":200},"  client.",[149,723,320],{"class":155},[149,725,323],{"class":200},[149,727,728,730,732,734,736,739],{"class":151,"line":224},[149,729,283],{"class":196},[149,731,246],{"class":200},[149,733,249],{"class":196},[149,735,317],{"class":200},[149,737,738],{"class":155},"destroy",[149,740,323],{"class":200},[149,742,743],{"class":151,"line":255},[149,744,745],{"class":200},"}, [])\n",[28,747,749],{"id":748},"options","Options",[15,751,752,753,756],{},"Everything ",[23,754,755],{},"NoLagOptions"," accepts, plus:",[43,758,759,772],{},[46,760,761],{},[49,762,763,766,769],{},[52,764,765],{},"Option",[52,767,768],{},"Type",[52,770,771],{},"Default",[61,773,774,789,808],{},[49,775,776,781,786],{},[66,777,778],{},[23,779,780],{},"netInfo",[66,782,783],{},[23,784,785],{},"NetInfoModule",[66,787,788],{},"none (no reachability signal)",[49,790,791,796,801],{},[66,792,793],{},[23,794,795],{},"lifecycle",[66,797,798],{},[23,799,800],{},"LifecycleAdapter | null",[66,802,803,804,807],{},"AppState adapter; ",[23,805,806],{},"null"," disables",[49,809,810,815,820],{},[66,811,812],{},[23,813,814],{},"network",[66,816,817],{},[23,818,819],{},"NetworkAdapter | null",[66,821,822,823,825,826,807],{},"from ",[23,824,780],{}," if given; ",[23,827,806],{},[15,829,830,832,833,835,836,838],{},[23,831,795],{}," and ",[23,834,814],{}," take precedence over ",[23,837,780],{}," when set explicitly.",[28,840,842],{"id":841},"advanced-bringing-your-own-adapters","Advanced: bringing your own adapters",[15,844,845,848,849,851],{},[23,846,847],{},"NoLag()"," builds both adapters for you, so most apps never need this. Reach for it when your app-state signal does not come from ",[23,850,93],{},", when you use something other than NetInfo, or when you want the same decisions the SDK makes available to your own reconnect logic.",[43,853,854,864],{},[46,855,856],{},[49,857,858,861],{},[52,859,860],{},"Export",[52,862,863],{},"Purpose",[61,865,866,879,892,902,912,927],{},[49,867,868,873],{},[66,869,870],{},[23,871,872],{},"createAppStateLifecycleAdapter(appState?)",[66,874,875,876],{},"Lifecycle adapter from anything with ",[23,877,878],{},"addEventListener",[49,880,881,886],{},[66,882,883],{},[23,884,885],{},"mapAppState(status)",[66,887,888,889,891],{},"The status mapping, or ",[23,890,806],{}," for states that should not move the client",[49,893,894,899],{},[66,895,896],{},[23,897,898],{},"createNetInfoNetworkAdapter(netInfo)",[66,900,901],{},"Network adapter, built explicitly",[49,903,904,909],{},[66,905,906],{},[23,907,908],{},"isReachable(state)",[66,910,911],{},"Whether a NetInfo state means \"worth retrying now\"",[49,913,914,919],{},[66,915,916],{},[23,917,918],{},"decodeJwtExp(token)",[66,920,921,922,924,925],{},"Read the ",[23,923,130],{}," claim without verifying, or ",[23,926,806],{},[49,928,929,934],{},[66,930,931],{},[23,932,933],{},"fromMMKV(mmkv)",[66,935,936,937,940,941],{},"Adapt a ",[23,938,939],{},"react-native-mmkv"," instance to ",[23,942,943],{},"TokenStore",[15,945,946,947,950,951,953,954,956,957,960,961,964,965,967],{},"Two of those encode a judgement worth knowing. ",[23,948,949],{},"mapAppState"," returns ",[23,952,806],{}," for ",[23,955,670],{}," because treating it as background would tear the socket down every time someone swipes down on Control Centre. And ",[23,958,959],{},"isReachable"," treats connected-but-unknown as reachable, because ",[23,962,963],{},"isInternetReachable"," is ",[23,966,806],{}," while NetInfo is still probing and that is exactly the transition worth acting on: a wasted retry costs one connection attempt, a missed signal costs up to 30 seconds.",[28,969,971],{"id":970},"webrtc-is-not-supported-yet","WebRTC is not supported yet",[15,973,974,977,978,981,982,985,986,989,990,993],{},[23,975,976],{},"WebRTCManager"," is not exported here, and the core SDK's React Native build omits it too. Its Node path does a bare require of the ",[23,979,980],{},"wrtc"," package, which Metro collects statically. ",[23,983,984],{},"allowOptionalDependencies"," is on under ",[23,987,988],{},"@expo/metro-config"," but off under bare ",[23,991,992],{},"@react-native/metro-config",", so shipping it would bundle fine on Expo and fail the build on bare React Native.",[15,995,996,997,1000],{},"Voice and video on React Native need ",[23,998,999],{},"react-native-webrtc",", which is separate work. Everything else in the SDK is available.",[28,1002,1004],{"id":1003},"requirements","Requirements",[1006,1007,1008,1012],"ul",{},[1009,1010,1011],"li",{},"React Native >= 0.71",[1009,1013,1014,1016],{},[23,1015,25],{}," >= 1.12.0 (peer dependency)",[168,1018,1020],{"title":1019,"type":430},"Exactly one copy of the core",[15,1021,1022,1024,1025,1027,1028,1031,1032,1035],{},[23,1023,25],{}," must resolve to a single copy in your tree. ",[23,1026,329],{}," has private fields, so TypeScript compares it close to nominally: two copies make passing a client into an app SDK fail to typecheck with a thoroughly unhelpful error. If that happens, add a ",[23,1029,1030],{},"resolutions"," (Yarn) or ",[23,1033,1034],{},"overrides"," (npm) entry pinning a single version.",[1037,1038,1039],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":145,"searchDepth":210,"depth":210,"links":1041},[1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052],{"id":30,"depth":210,"text":31},{"id":133,"depth":210,"text":134},{"id":180,"depth":210,"text":181},{"id":441,"depth":210,"text":442},{"id":487,"depth":210,"text":488},{"id":638,"depth":210,"text":639},{"id":674,"depth":210,"text":675},{"id":748,"depth":210,"text":749},{"id":841,"depth":210,"text":842},{"id":970,"depth":210,"text":971},{"id":1003,"depth":210,"text":1004},"React Native bindings for the NoLag core SDK: AppState lifecycle, NetInfo reachability, token caching and polyfills.","md",{},"/docs/sdks/react-native",{"title":5,"description":1053},"docs/sdks/react-native","VWSner6xMDPuZP-jTKlQLTekCUCWXCN7Dmr8F4_Z3Ks",1788160344742]