@lorikeetai/react-native-sdk 2.1.0 → 2.2.0-beta.2

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.
package/README.md CHANGED
@@ -397,6 +397,219 @@ WebView component that handles the widget content.
397
397
  - `webviewProps` (optional): Passed through to the webview component. The SDK
398
398
  adds external-link handling on `onNavigationStateChange` and then calls yours
399
399
 
400
+ ## Voice calls (beta)
401
+
402
+ `@lorikeetai/react-native-sdk/voice` runs a Lorikeet voice call inside your
403
+ app with native audio, so the customer can keep talking while the app is in
404
+ the background. It is a beta. Install it from the `beta` tag, and expect its
405
+ API to change before it is stable.
406
+
407
+ Nothing here touches the chat widget. Only the `voice` entry point loads
408
+ LiveKit, so an app that never imports it installs nothing new and needs no
409
+ native rebuild.
410
+
411
+ ### Install
412
+
413
+ The LiveKit packages are optional peer dependencies, so install them yourself:
414
+
415
+ ```bash
416
+ pnpm add @lorikeetai/react-native-sdk@beta \
417
+ @livekit/react-native@^3.1.0 \
418
+ @livekit/react-native-webrtc@^150.1.0 \
419
+ livekit-client@^2.20.0
420
+ ```
421
+
422
+ `@livekit/react-native` depends on `@livekit/components-react`, which needs
423
+ `react-dom`. Install the `react-dom` version that matches your `react`, or the
424
+ package manager may pick a newer one that your `react` does not satisfy.
425
+
426
+ Do not install `@livekit/krisp-noise-filter`. The call does not use it, and
427
+ its license is not open source.
428
+
429
+ Voice requires React Native 0.79 or later, though the chat widget's peer range
430
+ is unchanged. The `voice` subpath is in the package's `exports` map, and 0.79
431
+ ships the first Metro (0.82) that reads that map by default. TypeScript reads
432
+ it with `moduleResolution` set to `bundler` or `node16`, and Expo's base
433
+ `tsconfig` uses `bundler`.
434
+
435
+ ### Native setup
436
+
437
+ These are native modules. Expo Go does not include them, so use a
438
+ [development build](https://docs.expo.dev/develop/development-builds/introduction/)
439
+ on Expo, and rebuild native code after installing.
440
+
441
+ With Expo SDK 56 or later, add the two config plugins, the iOS microphone
442
+ string and audio background mode, and the Android audio permissions to
443
+ `app.json`, then run `expo prebuild`:
444
+
445
+ ```bash
446
+ npx expo install @livekit/react-native-expo-plugin @config-plugins/react-native-webrtc
447
+ ```
448
+
449
+ ```json
450
+ {
451
+ "expo": {
452
+ "platforms": ["ios", "android"],
453
+ "plugins": [
454
+ "@livekit/react-native-expo-plugin",
455
+ "@config-plugins/react-native-webrtc"
456
+ ],
457
+ "ios": {
458
+ "infoPlist": {
459
+ "NSMicrophoneUsageDescription": "Talk to our support team.",
460
+ "UIBackgroundModes": ["audio"]
461
+ }
462
+ },
463
+ "android": {
464
+ "permissions": [
465
+ "android.permission.RECORD_AUDIO",
466
+ "android.permission.MODIFY_AUDIO_SETTINGS"
467
+ ]
468
+ }
469
+ }
470
+ }
471
+ ```
472
+
473
+ Set `platforms` to iOS and Android. Expo treats an app with `react-dom`
474
+ installed as web-capable, so `expo export` would also try a web bundle, which
475
+ LiveKit's native modules cannot build.
476
+
477
+ Use version 1.1.0 or later of `@livekit/react-native-expo-plugin`. It adds the
478
+ `livekit/podspecs` CocoaPods source, which LiveKit's iOS pods need once
479
+ CocoaPods trunk stops accepting new pods on 2 December 2026.
480
+
481
+ Without Expo, follow LiveKit's
482
+ [installation steps](https://github.com/livekit/client-sdk-react-native#installation).
483
+ Add the `livekit/podspecs` source to your `Podfile`, call
484
+ `LiveKitReactNative.setup` in `MainApplication` and `LivekitReactNative.setup`
485
+ in `AppDelegate`, and add the same permissions and background mode as above.
486
+
487
+ On Android, the microphone keeps working in the background only while your
488
+ app runs a foreground service of type `microphone`, which the SDK does not
489
+ start for you. Without one, the agent can still be heard, but the customer's
490
+ microphone goes silent when the app leaves the foreground.
491
+
492
+ ### Usage
493
+
494
+ Your backend creates the session with
495
+ `POST /v1/conversation/voice/web/create`, using your API credentials, and
496
+ returns its `{ conversationId, wsUrl, token }` to the app. Never put your API
497
+ credentials in the app.
498
+
499
+ ### Call screen
500
+
501
+ `LorikeetCallView` draws the web Voice Widget's call screen, with its copy.
502
+ It shows the logo, the title, the call status and clock, the call wave, and
503
+ the start, mute, speaker and end buttons. Every control has an accessibility
504
+ label, and screen readers hear each change in the call.
505
+
506
+ ```tsx
507
+ import { LorikeetCallView } from '@lorikeetai/react-native-sdk/voice'
508
+
509
+ const getSession = async () => {
510
+ const response = await fetch('https://api.example.com/support/call', {
511
+ method: 'POST',
512
+ })
513
+ if (response.status === 404) return null
514
+ if (!response.ok) throw new Error(`Call session: ${response.status}`)
515
+ return response.json()
516
+ }
517
+
518
+ export function SupportCallScreen() {
519
+ return (
520
+ <LorikeetCallView
521
+ customisations={{
522
+ title: 'Acme support',
523
+ theme: { brandColor: '214 100% 50%' },
524
+ }}
525
+ getSession={getSession}
526
+ />
527
+ )
528
+ }
529
+ ```
530
+
531
+ The view runs the call itself, so the call ends when the view unmounts. To
532
+ keep a call going across screens, run `useLorikeetCall` above them and build
533
+ the screen yourself.
534
+
535
+ It takes the hook's `getSession` and `onError`, a `style` for its outer view,
536
+ and these `customisations`, as the chat widget reads them:
537
+
538
+ - `title`: the heading. Defaults to "Lorikeet AI Agent".
539
+ - `logoUrl`: the image above the heading, PNG, JPEG or SVG. Defaults to the
540
+ Lorikeet mark. An SVG is drawn only when the URL's path ends in `.svg`.
541
+ - `useSubtleBranding`: hides "Powered by Lorikeet".
542
+ - `theme`: `colorMode`, `brandColor`, `brandAccentColor`, `subtleBrandColor`,
543
+ `backgroundColor`, `textColor` and `inverseTextColor`, as the web Voice
544
+ Widget reads them. `background` and `headerBackground` apply when they are
545
+ plain colours. React Native cannot draw a CSS gradient, so a gradient falls
546
+ back to `backgroundColor` or `brandAccentColor`. `fontFamily` and `fontUrl`
547
+ do not apply.
548
+
549
+ ### Your own call screen
550
+
551
+ `useLorikeetCall` runs the call without any UI.
552
+
553
+ ```tsx
554
+ import { Button, Text, View } from 'react-native'
555
+
556
+ import { useLorikeetCall } from '@lorikeetai/react-native-sdk/voice'
557
+
558
+ export function SupportCall() {
559
+ const call = useLorikeetCall({
560
+ getSession: async () => {
561
+ const response = await fetch('https://api.example.com/support/call', {
562
+ method: 'POST',
563
+ })
564
+ if (response.status === 404) return null
565
+ if (!response.ok) throw new Error(`Call session: ${response.status}`)
566
+ return response.json()
567
+ },
568
+ onError: (cause) => console.warn('Support call failed', cause),
569
+ })
570
+
571
+ return (
572
+ <View>
573
+ <Text>{call.state}</Text>
574
+ {call.state === 'idle' || call.state === 'error' ? (
575
+ <Button title="Start call" onPress={() => void call.start()} />
576
+ ) : (
577
+ <Button title="End call" onPress={call.end} />
578
+ )}
579
+ </View>
580
+ )
581
+ }
582
+ ```
583
+
584
+ `useLorikeetCall({ getSession, onError })` returns:
585
+
586
+ - `state`: `idle`, `starting`, `connecting`, `active` or `error`, as in the web
587
+ Voice Widget. `starting` covers asking for the microphone and fetching the
588
+ session, and `connecting` covers joining the call.
589
+ - `error`: why the call is in `error`. `microphone_denied` means the customer
590
+ refused the microphone, or it is off for the app in the device's settings.
591
+ `not_available` means `getSession` returned `null`. `failed` is anything
592
+ else, and `onError` receives its cause. `microphone_system_denied` is the web
593
+ Voice Widget's code for a browser blocked by the operating system, and a
594
+ mobile device never reports it.
595
+ - `start()`: start a call from `idle` or `error`. The hook asks for microphone
596
+ access before it calls `getSession`, so a refusal starts no conversation.
597
+ - `end()`: hang up, or abandon a call still starting. The call also ends, and
598
+ returns to `idle`, when the agent leaves.
599
+ - `ended`: whether the last call ended after it began connecting.
600
+ - `microphoneMuted` and `setMicrophoneMuted(muted)`: mute the customer.
601
+ - `speakerMuted` and `setSpeakerMuted(muted)`: mute the agent.
602
+
603
+ The call has no live transcript. The conversation is in Lorikeet under its
604
+ `conversationId`.
605
+
606
+ If your app already calls LiveKit's `registerGlobals()`, the hook leaves your
607
+ configuration alone. Otherwise the hook calls it when the first call starts.
608
+
609
+ The hook owns the native audio session for the length of a call and stops it
610
+ when the call ends. An app that runs its own LiveKit call at the same time
611
+ should not use the hook.
612
+
400
613
  ## Development
401
614
 
402
615
  This package is outside the root pnpm workspace, on its own lockfile, so run these from `packages/react-native-widget` after `pnpm install` there.
@@ -0,0 +1,137 @@
1
+ /**
2
+ * What the chat page accepts as `customisations`, as the SDK's own types.
3
+ *
4
+ * A copy of the web SDK's shape rather than an import of it. The web SDK is a
5
+ * browser bundle an app has no reason to install, and importing a type from it
6
+ * left the published `dist/index.d.ts` referencing a module consumers do not
7
+ * have: `Customisations` then degraded to `any` and typed nothing.
8
+ * `ConversationMetadata` is duplicated here for the same reason.
9
+ *
10
+ * `src/customisations.web-sdk-parity.ts` fails `typecheck` if the two drift. Not
11
+ * the build: that file is unreachable from `index.ts`, so the declaration build
12
+ * never sees it.
13
+ *
14
+ * Fields that only mean something on a web page are kept so the page's behaviour
15
+ * is unchanged and so a host sharing one configuration object with its web
16
+ * widget still type-checks. The viewport sizes, the launcher button and `mode`
17
+ * are all read by the web SDK rather than by the page, so none of them reaches
18
+ * anything this SDK renders.
19
+ */
20
+ /**
21
+ * Sizing for one viewport. Mostly desktop: the page is full-screen on mobile, so
22
+ * `height`, `width` and `borderRadius` are read for `desktop` alone, while
23
+ * `topClearance` and `default_open` are read for whichever viewport applies.
24
+ */
25
+ interface ViewportCustomisations {
26
+ /** Clamped to a 2rem maximum. */
27
+ borderRadius?: string;
28
+ default_open?: boolean;
29
+ /** Clamped to the viewport minus `topClearance`, and to a 20rem minimum. */
30
+ height?: string;
31
+ /** Reserved space above the widget. Desktop default 6.5rem. */
32
+ topClearance?: string;
33
+ width?: string;
34
+ }
35
+ interface Customisations {
36
+ /** Falls back to the logo image. */
37
+ avatarUrl?: string;
38
+ botName?: string;
39
+ desktop?: ViewportCustomisations;
40
+ /**
41
+ * Which header the customer gets, not whether there is one. `true` hides the
42
+ * page's own; `false` keeps it, and with it the page's way out of a
43
+ * conversation. Ending and minimising are what that header is for, and which
44
+ * controls it offers depends on the subscriber's configuration, so hiding it
45
+ * leaves the customer no way to end or minimise unless the host supplies one.
46
+ *
47
+ * What replaces a hidden one is the host's business, so there is no one
48
+ * default to quote. `LorikeetWidgetView` substitutes its own header, a title
49
+ * and new chat, and does so when this is omitted. `LorikeetClient` only
50
+ * serialises the flag and renders nothing, so a composed host keeps the page's
51
+ * header unless it asks for it to go, and must render `LorikeetWidgetHeader`
52
+ * itself when it does.
53
+ */
54
+ hideHeader?: boolean;
55
+ /** @default '_blank' */
56
+ linkTarget?: '_blank' | '_parent';
57
+ logoUrl?: string;
58
+ messages?: {
59
+ /** Shown when the widget is in an unexpectedly failed state. */
60
+ failOver?: string;
61
+ /**
62
+ * Shown when live chat has been switched off deliberately. Reachable only
63
+ * where the live agent bridge is on for the subscriber; without it the widget
64
+ * has no unavailable state for this to label.
65
+ */
66
+ unavailable?: string;
67
+ /**
68
+ * Replaces the line under "Someone is taking a look", for a conversation
69
+ * handed to a person. Say where the reply will come from when the default
70
+ * should not promise it. Shown only where the live chat experience is on,
71
+ * which is what puts the notice on screen in the first place.
72
+ */
73
+ escalated?: string;
74
+ };
75
+ mobile?: ViewportCustomisations;
76
+ mode?: 'controlled' | 'uncontrolled';
77
+ /**
78
+ * Styling for the launcher button the web widget renders. The React Native
79
+ * SDK renders no launcher, so this reaches the page and does nothing.
80
+ *
81
+ * @danger Experimental and may change.
82
+ */
83
+ rootElement?: {
84
+ border?: string;
85
+ borderRadius?: string;
86
+ zIndex?: number;
87
+ bottom?: string;
88
+ right?: string;
89
+ /** Any CSS size value. Defaults to 3rem. */
90
+ size?: string;
91
+ };
92
+ /** Show dates as well as times, on every message. */
93
+ showVerboseTimestamps?: boolean;
94
+ theme?: CustomisationTheme;
95
+ title?: string;
96
+ /** @default false */
97
+ useSubtleBranding?: boolean;
98
+ }
99
+ interface CustomisationTheme {
100
+ /**
101
+ * Colour or gradient for the main area. Any colour value, and any gradient
102
+ * function including multiple layers. Image-based backgrounds are not
103
+ * supported. Takes precedence over `backgroundColor`.
104
+ */
105
+ background?: string;
106
+ backgroundColor?: string;
107
+ /** Accent fill, currently the header. Resolves to a neutral when unset. */
108
+ brandAccentColor?: string;
109
+ brandColor?: string;
110
+ /** @default 'light' */
111
+ colorMode?: 'light' | 'dark';
112
+ fontFamily?: string;
113
+ /**
114
+ * Google Fonts CSS URL declaring the `@font-face` rules for `fontFamily`.
115
+ * The page ships Inter only, so a brand font the device lacks falls back
116
+ * unless its files are loaded. Must be https, host `fonts.googleapis.com`,
117
+ * path `/css` or `/css2`, and carry `family` plus at most a standard
118
+ * `display`. A URL failing any of that is dropped whole rather than trimmed,
119
+ * so one stray query param means no font loads at all.
120
+ */
121
+ fontUrl?: string;
122
+ /**
123
+ * Colour or gradient for the header, on the same terms as `background`.
124
+ * Takes precedence over `brandAccentColor`.
125
+ */
126
+ headerBackground?: string;
127
+ /** For text on a dark background. */
128
+ inverseTextColor?: string;
129
+ /** Falls back to the brand colour. */
130
+ linkColor?: string;
131
+ linkHoverColor?: string;
132
+ secondaryBrandColor?: string;
133
+ subtleBrandColor?: string;
134
+ textColor?: string;
135
+ }
136
+ export { Customisations as n, CustomisationTheme as t };
137
+ //# sourceMappingURL=customisations-BTaJ84md.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customisations-BTaJ84md.d.cts","names":[],"sources":["../src/customisations.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;UAyBU;;EAER;EACA;;EAEA;;EAEA;EACA;;UAGe;;EAEf;EACA;EACA,UAAU;;;;;;;;;;;;;;;EAeV;;EAEA;EACA;EACA;;IAEE;;;;;;IAMA;;;;;;;IAOA;;EAEF,SAAS;EACT;;;;;;;EAOA;IACE;IACA;IACA;IACA;IACA;;IAEA;;;EAGF;EACA,QAAQ;EACR;;EAEA;;UAGe;;;;;;EAMf;EACA;;EAEA;EACA;;EAEA;EACA;;;;;;;;;EASA;;;;;EAKA;;EAEA;;EAEA;EACA;EACA;EACA;EACA"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * What the chat page accepts as `customisations`, as the SDK's own types.
3
+ *
4
+ * A copy of the web SDK's shape rather than an import of it. The web SDK is a
5
+ * browser bundle an app has no reason to install, and importing a type from it
6
+ * left the published `dist/index.d.ts` referencing a module consumers do not
7
+ * have: `Customisations` then degraded to `any` and typed nothing.
8
+ * `ConversationMetadata` is duplicated here for the same reason.
9
+ *
10
+ * `src/customisations.web-sdk-parity.ts` fails `typecheck` if the two drift. Not
11
+ * the build: that file is unreachable from `index.ts`, so the declaration build
12
+ * never sees it.
13
+ *
14
+ * Fields that only mean something on a web page are kept so the page's behaviour
15
+ * is unchanged and so a host sharing one configuration object with its web
16
+ * widget still type-checks. The viewport sizes, the launcher button and `mode`
17
+ * are all read by the web SDK rather than by the page, so none of them reaches
18
+ * anything this SDK renders.
19
+ */
20
+ /**
21
+ * Sizing for one viewport. Mostly desktop: the page is full-screen on mobile, so
22
+ * `height`, `width` and `borderRadius` are read for `desktop` alone, while
23
+ * `topClearance` and `default_open` are read for whichever viewport applies.
24
+ */
25
+ interface ViewportCustomisations {
26
+ /** Clamped to a 2rem maximum. */
27
+ borderRadius?: string;
28
+ default_open?: boolean;
29
+ /** Clamped to the viewport minus `topClearance`, and to a 20rem minimum. */
30
+ height?: string;
31
+ /** Reserved space above the widget. Desktop default 6.5rem. */
32
+ topClearance?: string;
33
+ width?: string;
34
+ }
35
+ interface Customisations {
36
+ /** Falls back to the logo image. */
37
+ avatarUrl?: string;
38
+ botName?: string;
39
+ desktop?: ViewportCustomisations;
40
+ /**
41
+ * Which header the customer gets, not whether there is one. `true` hides the
42
+ * page's own; `false` keeps it, and with it the page's way out of a
43
+ * conversation. Ending and minimising are what that header is for, and which
44
+ * controls it offers depends on the subscriber's configuration, so hiding it
45
+ * leaves the customer no way to end or minimise unless the host supplies one.
46
+ *
47
+ * What replaces a hidden one is the host's business, so there is no one
48
+ * default to quote. `LorikeetWidgetView` substitutes its own header, a title
49
+ * and new chat, and does so when this is omitted. `LorikeetClient` only
50
+ * serialises the flag and renders nothing, so a composed host keeps the page's
51
+ * header unless it asks for it to go, and must render `LorikeetWidgetHeader`
52
+ * itself when it does.
53
+ */
54
+ hideHeader?: boolean;
55
+ /** @default '_blank' */
56
+ linkTarget?: '_blank' | '_parent';
57
+ logoUrl?: string;
58
+ messages?: {
59
+ /** Shown when the widget is in an unexpectedly failed state. */
60
+ failOver?: string;
61
+ /**
62
+ * Shown when live chat has been switched off deliberately. Reachable only
63
+ * where the live agent bridge is on for the subscriber; without it the widget
64
+ * has no unavailable state for this to label.
65
+ */
66
+ unavailable?: string;
67
+ /**
68
+ * Replaces the line under "Someone is taking a look", for a conversation
69
+ * handed to a person. Say where the reply will come from when the default
70
+ * should not promise it. Shown only where the live chat experience is on,
71
+ * which is what puts the notice on screen in the first place.
72
+ */
73
+ escalated?: string;
74
+ };
75
+ mobile?: ViewportCustomisations;
76
+ mode?: 'controlled' | 'uncontrolled';
77
+ /**
78
+ * Styling for the launcher button the web widget renders. The React Native
79
+ * SDK renders no launcher, so this reaches the page and does nothing.
80
+ *
81
+ * @danger Experimental and may change.
82
+ */
83
+ rootElement?: {
84
+ border?: string;
85
+ borderRadius?: string;
86
+ zIndex?: number;
87
+ bottom?: string;
88
+ right?: string;
89
+ /** Any CSS size value. Defaults to 3rem. */
90
+ size?: string;
91
+ };
92
+ /** Show dates as well as times, on every message. */
93
+ showVerboseTimestamps?: boolean;
94
+ theme?: CustomisationTheme;
95
+ title?: string;
96
+ /** @default false */
97
+ useSubtleBranding?: boolean;
98
+ }
99
+ interface CustomisationTheme {
100
+ /**
101
+ * Colour or gradient for the main area. Any colour value, and any gradient
102
+ * function including multiple layers. Image-based backgrounds are not
103
+ * supported. Takes precedence over `backgroundColor`.
104
+ */
105
+ background?: string;
106
+ backgroundColor?: string;
107
+ /** Accent fill, currently the header. Resolves to a neutral when unset. */
108
+ brandAccentColor?: string;
109
+ brandColor?: string;
110
+ /** @default 'light' */
111
+ colorMode?: 'light' | 'dark';
112
+ fontFamily?: string;
113
+ /**
114
+ * Google Fonts CSS URL declaring the `@font-face` rules for `fontFamily`.
115
+ * The page ships Inter only, so a brand font the device lacks falls back
116
+ * unless its files are loaded. Must be https, host `fonts.googleapis.com`,
117
+ * path `/css` or `/css2`, and carry `family` plus at most a standard
118
+ * `display`. A URL failing any of that is dropped whole rather than trimmed,
119
+ * so one stray query param means no font loads at all.
120
+ */
121
+ fontUrl?: string;
122
+ /**
123
+ * Colour or gradient for the header, on the same terms as `background`.
124
+ * Takes precedence over `brandAccentColor`.
125
+ */
126
+ headerBackground?: string;
127
+ /** For text on a dark background. */
128
+ inverseTextColor?: string;
129
+ /** Falls back to the brand colour. */
130
+ linkColor?: string;
131
+ linkHoverColor?: string;
132
+ secondaryBrandColor?: string;
133
+ subtleBrandColor?: string;
134
+ textColor?: string;
135
+ }
136
+ export { Customisations as n, CustomisationTheme as t };
137
+ //# sourceMappingURL=customisations-BTaJ84md.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customisations-BTaJ84md.d.ts","names":[],"sources":["../src/customisations.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;UAyBU;;EAER;EACA;;EAEA;;EAEA;EACA;;UAGe;;EAEf;EACA;EACA,UAAU;;;;;;;;;;;;;;;EAeV;;EAEA;EACA;EACA;;IAEE;;;;;;IAMA;;;;;;;IAOA;;EAEF,SAAS;EACT;;;;;;;EAOA;IACE;IACA;IACA;IACA;IACA;;IAEA;;;EAGF;EACA,QAAQ;EACR;;EAEA;;UAGe;;;;;;EAMf;EACA;;EAEA;EACA;;EAEA;EACA;;;;;;;;;EASA;;;;;EAKA;;EAEA;;EAEA;EACA;EACA;EACA;EACA"}
package/dist/index.cjs CHANGED
@@ -1,36 +1,11 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- // \0rolldown/runtime.js
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") {
11
- for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
- key = keys[i];
13
- if (!__hasOwnProp.call(to, key) && key !== except) {
14
- __defProp(to, key, {
15
- get: ((k) => from[k]).bind(null, key),
16
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
- });
18
- }
19
- }
20
- }
21
- return to;
22
- };
23
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
24
- value: mod,
25
- enumerable: true
26
- }) : target, mod));
27
-
2
+ const require_rolldown_runtime = require("./rolldown-runtime-xuxB8TGW.cjs");
28
3
  let react = require("react");
29
4
  let react_native = require("react-native");
30
5
  let react_native_safe_area_context = require("react-native-safe-area-context");
31
6
  let react_native_webview = require("react-native-webview");
32
7
  let react_native_svg = require("react-native-svg");
33
- react_native_svg = __toESM(react_native_svg, 1);
8
+ react_native_svg = require_rolldown_runtime.__toESM(react_native_svg, 1);
34
9
  let react_jsx_runtime = require("react/jsx-runtime");
35
10
 
36
11
  // src/bridge.ts