@apps-in-toss/framework 1.1.1 → 1.1.3

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 (3) hide show
  1. package/dist/index.cjs +563 -386
  2. package/dist/index.js +469 -287
  3. package/package.json +9 -9
package/dist/index.js CHANGED
@@ -149,16 +149,56 @@ function AppUpdate() {
149
149
  return /* @__PURE__ */ jsx(Fragment, {});
150
150
  }
151
151
 
152
- // src/core/components/BuiltinNavigationBar/index.tsx
152
+ // src/core/hooks/useAppsInTossBridge.ts
153
153
  import { appsInTossEvent } from "@apps-in-toss/native-modules";
154
+ import { useBridge } from "@toss-design-system/react-native";
155
+ import { useEffect as useEffect4 } from "react";
156
+
157
+ // src/core/utils/getAppsInTossGlobals.ts
158
+ function getAppsInTossGlobals() {
159
+ if (global.__appsInToss == null) {
160
+ throw new Error("invalid apps-in-toss globals");
161
+ }
162
+ return global.__appsInToss;
163
+ }
164
+
165
+ // src/core/utils/toIcon.ts
166
+ function toIcon(source) {
167
+ return source.startsWith("http") ? { source: { uri: source } } : { name: source };
168
+ }
169
+
170
+ // src/core/hooks/useAppsInTossBridge.ts
171
+ function useAppsInTossBridge() {
172
+ const controller = useBridge();
173
+ const appsInTossGlobals = getAppsInTossGlobals();
174
+ useEffect4(() => {
175
+ const commonProps = {
176
+ serviceName: appsInTossGlobals.brandDisplayName,
177
+ icon: toIcon(appsInTossGlobals.brandIcon),
178
+ color: appsInTossGlobals.brandPrimaryColor,
179
+ colorMode: appsInTossGlobals.brandBridgeColorMode
180
+ };
181
+ controller.open({
182
+ ...commonProps,
183
+ onExited: () => {
184
+ appsInTossEvent.emit("entryMessageExited", void 0);
185
+ }
186
+ });
187
+ }, []);
188
+ }
189
+
190
+ // src/components/NavigationBar/RNNavigationBar.tsx
154
191
  import { closeView, useBackEventContext, useNavigation } from "@granite-js/react-native";
155
192
  import { useDialog as useDialog2 } from "@toss-design-system/react-native";
156
193
  import { NavigationBackButton, NavigationLeft, TopNavigation } from "@toss-design-system/react-native/private";
157
194
  import { josa } from "es-hangul";
158
- import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef2 } from "react";
195
+ import { useCallback as useCallback3, useEffect as useEffect7 } from "react";
159
196
  import { BackHandler } from "react-native";
160
197
 
161
- // src/core/components/BuiltinNavigationBar/useBuiltinNavigationBarLogging.tsx
198
+ // src/components/NavigationBar/common/NavigationBarImpressionArea.tsx
199
+ import { useEffect as useEffect5, useRef as useRef2 } from "react";
200
+
201
+ // src/components/NavigationBar/common/useNavigationBarLogging.tsx
162
202
  import { INTERNAL__module as INTERNAL__module3 } from "@apps-in-toss/native-modules";
163
203
  import { Granite as Granite3 } from "@granite-js/react-native";
164
204
  var NAVI_BAR_IMPRESSION_SCHEMA_ID = 1596837;
@@ -171,7 +211,7 @@ var CLOSE_POPUP_CTA_CLICK_SCHEMA_ID = 1644492;
171
211
  var CLOSE_POPUP_CTA_CLICK_LOG_NAME = "appsintoss_app_visit__common_module::popup__close_app::click__cta";
172
212
  var HOME_BUTTON_CLICK_SCHEMA_ID = 1596839;
173
213
  var HOME_BUTTON_CLICK_LOG_NAME = "appsintoss_app_visit__common_module::click__icon_home";
174
- function useBuiltinNavigationBarLogging() {
214
+ function useNavigationBarLogging() {
175
215
  const referrer = useReferrer();
176
216
  const baseParams = {
177
217
  referrer,
@@ -242,12 +282,29 @@ function useBuiltinNavigationBarLogging() {
242
282
  };
243
283
  }
244
284
 
285
+ // src/components/NavigationBar/common/NavigationBarImpressionArea.tsx
286
+ import { Fragment as Fragment2, jsx as jsx2 } from "react/jsx-runtime";
287
+ function NavigationBarImpressionArea({
288
+ children,
289
+ withHomeButton
290
+ }) {
291
+ const hasLogged = useRef2(false);
292
+ const logging = useNavigationBarLogging();
293
+ useEffect5(() => {
294
+ if (hasLogged.current === false) {
295
+ logging.navBarImpression({ home_icon_yn: withHomeButton ? "Y" : "N" });
296
+ hasLogged.current = true;
297
+ }
298
+ }, [logging, withHomeButton]);
299
+ return /* @__PURE__ */ jsx2(Fragment2, { children });
300
+ }
301
+
245
302
  // src/core/hooks/useMoreButtonBottomSheet/index.tsx
246
303
  import { INTERNAL__appBridgeHandler, isMinVersionSupported } from "@apps-in-toss/native-modules";
247
304
  import { openURL as openURL3 } from "@granite-js/react-native";
248
305
  import { BottomSheet, List, ListHeader, ListRow } from "@toss-design-system/react-native";
249
306
  import { useAdaptive, useOverlay } from "@toss-design-system/react-native/private";
250
- import { useEffect as useEffect4, useState } from "react";
307
+ import { useEffect as useEffect6, useState } from "react";
251
308
 
252
309
  // src/core/hooks/useMoreButtonBottomSheet/useMoreButtonBottomSheetLogging.tsx
253
310
  import { INTERNAL__module as INTERNAL__module4 } from "@apps-in-toss/native-modules";
@@ -420,16 +477,8 @@ function ensureValue(value, name) {
420
477
  return value;
421
478
  }
422
479
 
423
- // src/core/utils/getAppsInTossGlobals.ts
424
- function getAppsInTossGlobals() {
425
- if (global.__appsInToss == null) {
426
- throw new Error("invalid apps-in-toss globals");
427
- }
428
- return global.__appsInToss;
429
- }
430
-
431
480
  // src/core/hooks/useMoreButtonBottomSheet/index.tsx
432
- import { Fragment as Fragment2, jsx as jsx2 } from "react/jsx-runtime";
481
+ import { Fragment as Fragment3, jsx as jsx3 } from "react/jsx-runtime";
433
482
  var APP_BRIDGE_METHOD_NAME = "getMiniAppsSupportContact";
434
483
  function useMoreButtonBottomSheet() {
435
484
  const globals = getAppsInTossGlobals();
@@ -443,7 +492,7 @@ function useMoreButtonBottomSheet() {
443
492
  android: "5.226.0",
444
493
  ios: "5.226.0"
445
494
  });
446
- useEffect4(() => {
495
+ useEffect6(() => {
447
496
  if (!isSupported) {
448
497
  return;
449
498
  }
@@ -470,17 +519,17 @@ function useMoreButtonBottomSheet() {
470
519
  logging.close();
471
520
  close();
472
521
  };
473
- return /* @__PURE__ */ jsx2(BottomSheetImpressionArea, { children: /* @__PURE__ */ jsx2(
522
+ return /* @__PURE__ */ jsx3(BottomSheetImpressionArea, { children: /* @__PURE__ */ jsx3(
474
523
  BottomSheet.Root,
475
524
  {
476
- header: /* @__PURE__ */ jsx2(
525
+ header: /* @__PURE__ */ jsx3(
477
526
  ListHeader,
478
527
  {
479
- title: /* @__PURE__ */ jsx2(ListHeader.TitleParagraph, { color: adaptive.grey800, fontWeight: "bold", typography: "t5", children: title })
528
+ title: /* @__PURE__ */ jsx3(ListHeader.TitleParagraph, { color: adaptive.grey800, fontWeight: "bold", typography: "t5", children: title })
480
529
  }
481
530
  ),
482
531
  open: isOpen,
483
- cta: /* @__PURE__ */ jsx2(
532
+ cta: /* @__PURE__ */ jsx3(
484
533
  BottomSheet.CTA,
485
534
  {
486
535
  size: "large",
@@ -494,11 +543,11 @@ function useMoreButtonBottomSheet() {
494
543
  ),
495
544
  onClose: handleClose,
496
545
  onExited: exit,
497
- children: /* @__PURE__ */ jsx2(List, { rowSeparator: "none", children: itemList.map((item) => {
498
- return /* @__PURE__ */ jsx2(
546
+ children: /* @__PURE__ */ jsx3(List, { rowSeparator: "none", children: itemList.map((item) => {
547
+ return /* @__PURE__ */ jsx3(
499
548
  ListRow,
500
549
  {
501
- left: /* @__PURE__ */ jsx2(
550
+ left: /* @__PURE__ */ jsx3(
502
551
  ListRow.Icon,
503
552
  {
504
553
  color: globals.brandPrimaryColor,
@@ -506,7 +555,7 @@ function useMoreButtonBottomSheet() {
506
555
  type: "background"
507
556
  }
508
557
  ),
509
- contents: /* @__PURE__ */ jsx2(
558
+ contents: /* @__PURE__ */ jsx3(
510
559
  ListRow.Texts,
511
560
  {
512
561
  type: "1RowTypeA",
@@ -531,10 +580,10 @@ function useMoreButtonBottomSheet() {
531
580
  }
532
581
  function BottomSheetImpressionArea({ children }) {
533
582
  const logging = useMoreButtonBottomSheetLogging();
534
- useEffect4(() => {
583
+ useEffect6(() => {
535
584
  logging.show();
536
585
  }, [logging]);
537
- return /* @__PURE__ */ jsx2(Fragment2, { children });
586
+ return /* @__PURE__ */ jsx3(Fragment3, { children });
538
587
  }
539
588
 
540
589
  // src/core/utils/safeParseNavigationBar.ts
@@ -549,47 +598,25 @@ function safeParseNavigationBar(navigationBar) {
549
598
  }
550
599
  }
551
600
 
552
- // src/core/utils/toIcon.ts
553
- function toIcon(source) {
554
- return source.startsWith("http") ? { source: { uri: source } } : { name: source };
555
- }
556
-
557
- // src/core/components/BuiltinNavigationBar/index.tsx
558
- import { Fragment as Fragment3, jsx as jsx3 } from "react/jsx-runtime";
559
- function BuiltinNavigationBar() {
601
+ // src/components/NavigationBar/RNNavigationBar.tsx
602
+ import { jsx as jsx4 } from "react/jsx-runtime";
603
+ function RNNavigationBar() {
560
604
  const globals = getAppsInTossGlobals();
561
605
  const { captureExitLog } = useCaptureExitLog();
562
- const logging = useBuiltinNavigationBarLogging();
606
+ const logging = useNavigationBarLogging();
563
607
  const { openConfirm } = useDialog2();
564
608
  const { open: openMoreButtonBottomSheet } = useMoreButtonBottomSheet();
565
609
  const parsedNavigationBar = globals.navigationBar != null ? safeParseNavigationBar(globals.navigationBar) : null;
566
610
  const withHomeButton = parsedNavigationBar?.withHomeButton ?? false;
567
611
  const withBackButton = parsedNavigationBar?.withBackButton ?? true;
568
612
  const initialAccessoryButton = parsedNavigationBar?.initialAccessoryButton;
569
- const isExternalWebView = globals.webViewType === "external";
570
- const isGameWebView = globals.webViewType === "game";
571
613
  const backEventContext = useBackEventContext();
572
614
  const handleBackOrClose = useBackOrCloseNavigation();
573
615
  const navigation = useNavigation();
574
616
  const handlePressTitle = useCallback3(() => {
575
617
  logging.homeButtonClick();
576
- if (globals.webViewType != null) {
577
- appsInTossEvent.emit("homeIconButtonClickEvent", void 0);
578
- return;
579
- }
580
618
  navigation.navigate("/");
581
- }, [logging, globals.webViewType, navigation]);
582
- const handleBack = useCallback3(() => {
583
- if (globals.webViewType != null) {
584
- appsInTossEvent.emit("backButtonClickEvent", void 0);
585
- return;
586
- }
587
- if (backEventContext.hasBackEvent) {
588
- backEventContext.onBack();
589
- return;
590
- }
591
- handleBackOrClose();
592
- }, [globals.webViewType, backEventContext, handleBackOrClose]);
619
+ }, [logging, navigation]);
593
620
  const handleClose = useCallback3(async () => {
594
621
  logging.closeButtonClick();
595
622
  const isConfirmed = await openConfirm({
@@ -605,26 +632,30 @@ function BuiltinNavigationBar() {
605
632
  closeView();
606
633
  }
607
634
  }, [captureExitLog, globals.brandDisplayName, logging, openConfirm]);
608
- const handleBackEvent = useCallback3(() => {
609
- handleBack();
610
- return true;
611
- }, [handleBack]);
612
- useEffect5(() => {
613
- BackHandler.addEventListener("hardwareBackPress", handleBackEvent);
635
+ const handleBack = useCallback3(() => {
636
+ if (backEventContext.hasBackEvent) {
637
+ backEventContext.onBack();
638
+ return;
639
+ }
640
+ handleBackOrClose();
641
+ }, [backEventContext, handleBackOrClose]);
642
+ useEffect7(() => {
643
+ const handleAndroidBackEvent = () => {
644
+ handleBack();
645
+ return true;
646
+ };
647
+ BackHandler.addEventListener("hardwareBackPress", handleAndroidBackEvent);
614
648
  return () => {
615
- BackHandler.removeEventListener("hardwareBackPress", handleBackEvent);
649
+ BackHandler.removeEventListener("hardwareBackPress", handleAndroidBackEvent);
616
650
  };
617
- }, [handleBackEvent]);
618
- if (isExternalWebView) {
619
- return /* @__PURE__ */ jsx3(Fragment3, {});
620
- }
621
- return /* @__PURE__ */ jsx3(BuiltinNavigationBarImpressionArea, { withHomeButton, children: /* @__PURE__ */ jsx3(
651
+ }, [handleBack]);
652
+ return /* @__PURE__ */ jsx4(NavigationBarImpressionArea, { withHomeButton, children: /* @__PURE__ */ jsx4(
622
653
  TopNavigation,
623
654
  {
624
655
  title: globals.brandDisplayName,
625
656
  icon: toIcon(globals.brandIcon),
626
657
  onPressDots: openMoreButtonBottomSheet,
627
- contentVisible: isGameWebView ? false : true,
658
+ contentVisible: true,
628
659
  onPressTitle: withHomeButton ? handlePressTitle : void 0,
629
660
  onPressClose: handleClose,
630
661
  withHome: withHomeButton,
@@ -633,7 +664,7 @@ function BuiltinNavigationBar() {
633
664
  icon: initialAccessoryButton.icon,
634
665
  id: initialAccessoryButton.id
635
666
  } : void 0,
636
- children: isGameWebView === false ? /* @__PURE__ */ jsx3(NavigationLeft, { visible: withBackButton, children: /* @__PURE__ */ jsx3(NavigationBackButton, { onPress: handleBack, canGoBack: false }) }) : null
667
+ children: /* @__PURE__ */ jsx4(NavigationLeft, { visible: withBackButton, children: /* @__PURE__ */ jsx4(NavigationBackButton, { onPress: handleBack, canGoBack: false }) })
637
668
  }
638
669
  ) });
639
670
  }
@@ -647,69 +678,32 @@ function useBackOrCloseNavigation() {
647
678
  captureExitLog(Date.now());
648
679
  closeView();
649
680
  }
650
- }, [navigation]);
651
- }
652
- function BuiltinNavigationBarImpressionArea({
653
- children,
654
- withHomeButton
655
- }) {
656
- const hasLogged = useRef2(false);
657
- const logging = useBuiltinNavigationBarLogging();
658
- useEffect5(() => {
659
- if (hasLogged.current === false) {
660
- logging.navBarImpression({ home_icon_yn: withHomeButton ? "Y" : "N" });
661
- hasLogged.current = true;
662
- }
663
- }, []);
664
- return /* @__PURE__ */ jsx3(Fragment3, { children });
665
- }
666
-
667
- // src/core/hooks/useAppsInTossBridge.ts
668
- import { appsInTossEvent as appsInTossEvent2 } from "@apps-in-toss/native-modules";
669
- import { useBridge } from "@toss-design-system/react-native";
670
- import { useEffect as useEffect6 } from "react";
671
- function useAppsInTossBridge() {
672
- const controller = useBridge();
673
- const appsInTossGlobals = getAppsInTossGlobals();
674
- useEffect6(() => {
675
- const commonProps = {
676
- serviceName: appsInTossGlobals.brandDisplayName,
677
- icon: toIcon(appsInTossGlobals.brandIcon),
678
- color: appsInTossGlobals.brandPrimaryColor,
679
- colorMode: appsInTossGlobals.brandBridgeColorMode
680
- };
681
- controller.open({
682
- ...commonProps,
683
- onExited: () => {
684
- appsInTossEvent2.emit("entryMessageExited", void 0);
685
- }
686
- });
687
- }, []);
681
+ }, [captureExitLog, navigation]);
688
682
  }
689
683
 
690
684
  // src/core/registerApp.tsx
691
- import { Fragment as Fragment4, jsx as jsx4, jsxs } from "react/jsx-runtime";
685
+ import { Fragment as Fragment4, jsx as jsx5, jsxs } from "react/jsx-runtime";
692
686
  function AppsInTossContainer(Container, { children, ...initialProps }) {
693
687
  if (!isMinVersionSupported2({
694
688
  android: "5.220.0",
695
689
  ios: "5.221.0"
696
690
  })) {
697
691
  return /* @__PURE__ */ jsxs(Fragment4, { children: [
698
- /* @__PURE__ */ jsx4(AppEvent.Entry, {}),
699
- /* @__PURE__ */ jsx4(AppEvent.System, { ...initialProps }),
700
- /* @__PURE__ */ jsx4(AppUpdate, {})
692
+ /* @__PURE__ */ jsx5(AppEvent.Entry, {}),
693
+ /* @__PURE__ */ jsx5(AppEvent.System, { ...initialProps }),
694
+ /* @__PURE__ */ jsx5(AppUpdate, {})
701
695
  ] });
702
696
  }
703
697
  return /* @__PURE__ */ jsxs(Fragment4, { children: [
704
- /* @__PURE__ */ jsx4(AppEvent.StayTime, {}),
705
- /* @__PURE__ */ jsx4(AppEvent.Entry, {}),
706
- /* @__PURE__ */ jsx4(AppEvent.System, { ...initialProps }),
707
- /* @__PURE__ */ jsx4(Container, { ...initialProps, children: /* @__PURE__ */ jsx4(TDSProvider, { colorPreference: "light", token: { color: { primary: getAppsInTossGlobals().brandPrimaryColor } }, children: /* @__PURE__ */ jsx4(TDSContainer, { ...initialProps, children }) }) })
698
+ /* @__PURE__ */ jsx5(AppEvent.StayTime, {}),
699
+ /* @__PURE__ */ jsx5(AppEvent.Entry, {}),
700
+ /* @__PURE__ */ jsx5(AppEvent.System, { ...initialProps }),
701
+ /* @__PURE__ */ jsx5(Container, { ...initialProps, children: /* @__PURE__ */ jsx5(TDSProvider, { colorPreference: "light", token: { color: { primary: getAppsInTossGlobals().brandPrimaryColor } }, children: /* @__PURE__ */ jsx5(TDSContainer, { ...initialProps, children }) }) })
708
702
  ] });
709
703
  }
710
704
  function TDSContainer({ children }) {
711
705
  useAppsInTossBridge();
712
- return /* @__PURE__ */ jsx4(Fragment4, { children });
706
+ return /* @__PURE__ */ jsx5(Fragment4, { children });
713
707
  }
714
708
  function registerApp(container, { context, analytics }) {
715
709
  const appName = getAppName();
@@ -735,8 +729,9 @@ function registerApp(container, { context, analytics }) {
735
729
  return global.Page;
736
730
  }
737
731
  function AppsInTossScreenContainer({ children }) {
732
+ const isReactNativeService = getAppsInTossGlobals().webViewType == null;
738
733
  return /* @__PURE__ */ jsxs(Analytics.Screen, { children: [
739
- /* @__PURE__ */ jsx4(BuiltinNavigationBar, {}),
734
+ isReactNativeService && /* @__PURE__ */ jsx5(RNNavigationBar, {}),
740
735
  children
741
736
  ] });
742
737
  }
@@ -755,39 +750,43 @@ var AppsInToss = {
755
750
  };
756
751
 
757
752
  // src/components/WebView.tsx
758
- import { GoogleAdMob, IAP, Storage, AppsInTossModule, appsInTossEvent as appsInTossEvent4 } from "@apps-in-toss/native-modules";
753
+ import {
754
+ GoogleAdMob,
755
+ IAP,
756
+ Storage,
757
+ AppsInTossModule,
758
+ appsInTossEvent as appsInTossEvent3,
759
+ iapCreateOneTimePurchaseOrder,
760
+ processProductGrant,
761
+ requestOneTimePurchase
762
+ } from "@apps-in-toss/native-modules";
759
763
  import * as appsInTossAsyncBridges from "@apps-in-toss/native-modules/async-bridges";
760
764
  import * as appsInTossConstantBridges from "@apps-in-toss/native-modules/constant-bridges";
761
765
  import * as appsInTossEventBridges from "@apps-in-toss/native-modules/event-bridges";
762
- import { closeView as closeView3, getSchemeUri as getSchemeUri5, useGraniteEvent } from "@granite-js/react-native";
766
+ import { getSchemeUri as getSchemeUri5, useGraniteEvent } from "@granite-js/react-native";
763
767
  import * as graniteAsyncBridges from "@granite-js/react-native/async-bridges";
764
768
  import * as graniteConstantBridges from "@granite-js/react-native/constant-bridges";
765
- import {
766
- ExternalWebViewScreen,
767
- tdsEvent,
768
- useDialog as useDialog4
769
- } from "@toss-design-system/react-native";
770
- import { useSafeAreaBottom, useSafeAreaTop, useTopNavigation } from "@toss-design-system/react-native/private";
771
- import { josa as josa3 } from "es-hangul";
772
- import { useCallback as useCallback6, useEffect as useEffect10, useMemo as useMemo3, useState as useState5 } from "react";
773
- import { BackHandler as BackHandler2, Platform as Platform3 } from "react-native";
769
+ import { ExternalWebViewScreen, tdsEvent } from "@toss-design-system/react-native";
770
+ import { useSafeAreaBottom, useSafeAreaTop as useSafeAreaTop2, useTopNavigation } from "@toss-design-system/react-native/private";
771
+ import { useMemo as useMemo4, useState as useState5 } from "react";
772
+ import { Platform as Platform4 } from "react-native";
774
773
 
775
774
  // src/components/GameWebView.tsx
776
- import { setIosSwipeGestureEnabled as setIosSwipeGestureEnabled2, appsInTossEvent as appsInTossEvent3, getOperationalEnvironment } from "@apps-in-toss/native-modules";
775
+ import { setIosSwipeGestureEnabled as setIosSwipeGestureEnabled2, appsInTossEvent as appsInTossEvent2, getOperationalEnvironment } from "@apps-in-toss/native-modules";
777
776
  import {
778
777
  WebView as PlainWebView
779
778
  } from "@granite-js/native/react-native-webview";
780
- import { forwardRef, useEffect as useEffect8, useState as useState3 } from "react";
781
- import { Platform as Platform2 } from "react-native";
779
+ import { forwardRef, useEffect as useEffect10, useState as useState3 } from "react";
780
+ import { Platform as Platform3 } from "react-native";
782
781
 
783
782
  // src/components/GameProfile.tsx
784
783
  import { getGameCenterGameProfile as getGameCenterGameProfile2, isMinVersionSupported as isMinVersionSupported3 } from "@apps-in-toss/native-modules";
785
784
  import { Loader } from "@toss-design-system/react-native";
786
- import { useEffect as useEffect7 } from "react";
785
+ import { useEffect as useEffect8 } from "react";
787
786
  import { Pressable, View } from "react-native";
788
787
 
789
788
  // src/constant/game-center.ts
790
- var GAME_PROFILE_WEBVIEW_URL = "https://service.toss.im/game-center/profile";
789
+ var GAME_PROFILE_WEBVIEW_URL = "servicetoss://game-center/profile";
791
790
  var GAME_CENTER_MIN_VERSION = {
792
791
  android: "5.221.0",
793
792
  ios: "5.221.0"
@@ -803,13 +802,13 @@ import { useCallback as useCallback4, useRef as useRef3, useState as useState2 }
803
802
  // src/components/GameProfileToast.tsx
804
803
  import { Asset, Toast } from "@toss-design-system/react-native";
805
804
  import { AdaptiveColorProvider, ColorPreferenceProvider, useOverlay as useOverlay2 } from "@toss-design-system/react-native/private";
806
- import { jsx as jsx5 } from "react/jsx-runtime";
805
+ import { jsx as jsx6 } from "react/jsx-runtime";
807
806
  var useGameProfileToast = () => {
808
807
  const overlay = useOverlay2();
809
808
  const openGameProfileToast = (nickname, profileImageUri) => {
810
809
  return new Promise((resolve) => {
811
810
  overlay.open(({ isOpen, close, exit }) => {
812
- return /* @__PURE__ */ jsx5(ColorPreferenceProvider, { colorPreference: "dark", children: /* @__PURE__ */ jsx5(AdaptiveColorProvider, { children: /* @__PURE__ */ jsx5(
811
+ return /* @__PURE__ */ jsx6(ColorPreferenceProvider, { colorPreference: "dark", children: /* @__PURE__ */ jsx6(AdaptiveColorProvider, { children: /* @__PURE__ */ jsx6(
813
812
  Toast,
814
813
  {
815
814
  open: isOpen,
@@ -820,7 +819,7 @@ var useGameProfileToast = () => {
820
819
  onExited: exit,
821
820
  position: "top",
822
821
  text: `${nickname}\uB2D8 \uBC18\uAC00\uC6CC\uC694!`,
823
- icon: /* @__PURE__ */ jsx5(
822
+ icon: /* @__PURE__ */ jsx6(
824
823
  Asset.Image,
825
824
  {
826
825
  style: { borderRadius: 64, overflow: "hidden" },
@@ -975,7 +974,7 @@ var Z_INDEX = {
975
974
  };
976
975
 
977
976
  // src/components/GameProfile.tsx
978
- import { Fragment as Fragment5, jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
977
+ import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
979
978
  var GameProfile = ({ children, isReadyForProfileUI }) => {
980
979
  const {
981
980
  profileData,
@@ -991,7 +990,7 @@ var GameProfile = ({ children, isReadyForProfileUI }) => {
991
990
  openErrorAlert,
992
991
  openGameProfileToast
993
992
  } = useGameCenterProfile(isReadyForProfileUI);
994
- useEffect7(() => {
993
+ useEffect8(() => {
995
994
  try {
996
995
  const getProfileData = async () => {
997
996
  const data = await getGameCenterGameProfile2();
@@ -1004,7 +1003,7 @@ var GameProfile = ({ children, isReadyForProfileUI }) => {
1004
1003
  setIsProfileDataLoading(false);
1005
1004
  }
1006
1005
  }, []);
1007
- useEffect7(() => {
1006
+ useEffect8(() => {
1008
1007
  const handleGameProfileFlow = async () => {
1009
1008
  if (!canShowBottomSheetOrToast) {
1010
1009
  return;
@@ -1036,8 +1035,8 @@ var GameProfile = ({ children, isReadyForProfileUI }) => {
1036
1035
  ]);
1037
1036
  if (!isMinVersionSupported3(GAME_CENTER_MIN_VERSION)) {
1038
1037
  return /* @__PURE__ */ jsxs2(Fragment5, { children: [
1039
- /* @__PURE__ */ jsx6(View, { style: { flex: 1, position: "relative" }, children }),
1040
- /* @__PURE__ */ jsx6(
1038
+ /* @__PURE__ */ jsx7(View, { style: { flex: 1, position: "relative" }, children }),
1039
+ /* @__PURE__ */ jsx7(
1041
1040
  Pressable,
1042
1041
  {
1043
1042
  style: {
@@ -1052,8 +1051,8 @@ var GameProfile = ({ children, isReadyForProfileUI }) => {
1052
1051
  }
1053
1052
  if (shouldShowLoadingOverlay || isProfileDataRefetching) {
1054
1053
  return /* @__PURE__ */ jsxs2(Fragment5, { children: [
1055
- /* @__PURE__ */ jsx6(View, { style: { flex: 1, position: "relative" }, children }),
1056
- /* @__PURE__ */ jsx6(
1054
+ /* @__PURE__ */ jsx7(View, { style: { flex: 1, position: "relative" }, children }),
1055
+ /* @__PURE__ */ jsx7(
1057
1056
  View,
1058
1057
  {
1059
1058
  style: {
@@ -1062,15 +1061,15 @@ var GameProfile = ({ children, isReadyForProfileUI }) => {
1062
1061
  alignItems: "center",
1063
1062
  backgroundColor: "rgba(0, 0, 0, 0.2)"
1064
1063
  },
1065
- children: /* @__PURE__ */ jsx6(Loader, { size: "large", type: "light" })
1064
+ children: /* @__PURE__ */ jsx7(Loader, { size: "large", type: "light" })
1066
1065
  }
1067
1066
  )
1068
1067
  ] });
1069
1068
  }
1070
1069
  if (shouldShowProfileNotFoundOverlay) {
1071
1070
  return /* @__PURE__ */ jsxs2(Fragment5, { children: [
1072
- /* @__PURE__ */ jsx6(View, { style: { flex: 1, position: "relative" }, children }),
1073
- shouldShowProfileNotFoundOverlay && /* @__PURE__ */ jsx6(
1071
+ /* @__PURE__ */ jsx7(View, { style: { flex: 1, position: "relative" }, children }),
1072
+ shouldShowProfileNotFoundOverlay && /* @__PURE__ */ jsx7(
1074
1073
  Pressable,
1075
1074
  {
1076
1075
  style: {
@@ -1083,7 +1082,7 @@ var GameProfile = ({ children, isReadyForProfileUI }) => {
1083
1082
  )
1084
1083
  ] });
1085
1084
  }
1086
- return /* @__PURE__ */ jsx6(Fragment5, { children: /* @__PURE__ */ jsx6(View, { style: { flex: 1, position: "relative" }, children }) });
1085
+ return /* @__PURE__ */ jsx7(Fragment5, { children: /* @__PURE__ */ jsx7(View, { style: { flex: 1, position: "relative" }, children }) });
1087
1086
  };
1088
1087
  var overlayStyle = {
1089
1088
  position: "absolute",
@@ -1094,12 +1093,86 @@ var overlayStyle = {
1094
1093
  zIndex: Z_INDEX.PROFILE_OVERLAY
1095
1094
  };
1096
1095
 
1096
+ // src/components/NavigationBar/GameWebviewNavigationBar.tsx
1097
+ import { closeView as closeView3 } from "@granite-js/react-native";
1098
+ import { PageNavbar, useDialog as useDialog4 } from "@toss-design-system/react-native";
1099
+ import { NavigationRightContent, useSafeAreaTop } from "@toss-design-system/react-native/private";
1100
+ import { josa as josa3 } from "es-hangul";
1101
+ import { useCallback as useCallback5, useEffect as useEffect9 } from "react";
1102
+ import { BackHandler as BackHandler2, Platform as Platform2, View as View2 } from "react-native";
1103
+ import { Fragment as Fragment6, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
1104
+ function GameWebviewNavigationBar() {
1105
+ const safeAreaTop = useSafeAreaTop();
1106
+ const { openConfirm } = useDialog4();
1107
+ const { captureExitLog } = useCaptureExitLog();
1108
+ const global2 = getAppsInTossGlobals();
1109
+ const logging = useNavigationBarLogging();
1110
+ const { open: openMoreButtonBottomSheet } = useMoreButtonBottomSheet();
1111
+ const parsedNavigationBar = global2.navigationBar != null ? safeParseNavigationBar(global2.navigationBar) : null;
1112
+ const initialAccessoryButton = parsedNavigationBar?.initialAccessoryButton;
1113
+ const handleGameWebviewClose = useCallback5(async () => {
1114
+ const isConfirmed = await openConfirm({
1115
+ title: `${josa3(global2.brandDisplayName, "\uC744/\uB97C")} \uC885\uB8CC\uD560\uAE4C\uC694?`,
1116
+ leftButton: "\uCDE8\uC18C",
1117
+ rightButton: "\uC885\uB8CC\uD558\uAE30",
1118
+ closeOnDimmerClick: true,
1119
+ onEntered: logging.closePopupShow
1120
+ });
1121
+ logging.closePopupCtaClick(isConfirmed);
1122
+ if (isConfirmed) {
1123
+ captureExitLog(Date.now());
1124
+ closeView3();
1125
+ }
1126
+ }, [captureExitLog, global2.brandDisplayName, logging, openConfirm]);
1127
+ useEffect9(() => {
1128
+ const handleAndroidBackEvent = () => {
1129
+ handleGameWebviewClose();
1130
+ return true;
1131
+ };
1132
+ BackHandler2.addEventListener("hardwareBackPress", handleAndroidBackEvent);
1133
+ return () => BackHandler2.removeEventListener("hardwareBackPress", handleAndroidBackEvent);
1134
+ }, [handleGameWebviewClose]);
1135
+ return /* @__PURE__ */ jsxs3(Fragment6, { children: [
1136
+ /* @__PURE__ */ jsx8(PageNavbar, { preference: { type: "none" } }),
1137
+ /* @__PURE__ */ jsx8(
1138
+ View2,
1139
+ {
1140
+ style: {
1141
+ width: "100%",
1142
+ // TODO: UI관련 스타일 설정은 TDS로 이관
1143
+ height: Platform2.OS === "ios" ? 44 : 54,
1144
+ flexDirection: "row",
1145
+ alignItems: "center",
1146
+ justifyContent: "flex-end",
1147
+ position: "absolute",
1148
+ zIndex: Z_INDEX.CLOSE_BUTTON,
1149
+ marginTop: safeAreaTop,
1150
+ paddingRight: 10
1151
+ },
1152
+ pointerEvents: "box-none",
1153
+ children: /* @__PURE__ */ jsx8(
1154
+ NavigationRightContent,
1155
+ {
1156
+ fixedRightButton: initialAccessoryButton,
1157
+ onPressDots: openMoreButtonBottomSheet,
1158
+ onPressClose: () => {
1159
+ logging.closeButtonClick();
1160
+ handleGameWebviewClose();
1161
+ },
1162
+ theme: "dark"
1163
+ }
1164
+ )
1165
+ }
1166
+ )
1167
+ ] });
1168
+ }
1169
+
1097
1170
  // src/components/GameWebView.tsx
1098
- import { Fragment as Fragment6, jsx as jsx7 } from "react/jsx-runtime";
1171
+ import { Fragment as Fragment7, jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
1099
1172
  var GameWebView = forwardRef(function GameWebView2(props, ref) {
1100
1173
  const [isEntryMessageExited, setIsEntryMessageExited] = useState3(false);
1101
- useEffect8(() => {
1102
- if (Platform2.OS === "ios") {
1174
+ useEffect10(() => {
1175
+ if (Platform3.OS === "ios") {
1103
1176
  setIosSwipeGestureEnabled2({ isEnabled: false });
1104
1177
  return () => {
1105
1178
  setIosSwipeGestureEnabled2({ isEnabled: true });
@@ -1107,21 +1180,78 @@ var GameWebView = forwardRef(function GameWebView2(props, ref) {
1107
1180
  }
1108
1181
  return;
1109
1182
  }, []);
1110
- useEffect8(() => {
1111
- appsInTossEvent3.addEventListener("entryMessageExited", {
1183
+ useEffect10(() => {
1184
+ appsInTossEvent2.addEventListener("entryMessageExited", {
1112
1185
  onEvent: () => {
1113
1186
  setIsEntryMessageExited(true);
1114
1187
  }
1115
1188
  });
1116
1189
  }, []);
1117
- return /* @__PURE__ */ jsx7(Fragment6, { children: getOperationalEnvironment() === "toss" ? /* @__PURE__ */ jsx7(GameProfile, { isReadyForProfileUI: isEntryMessageExited, children: /* @__PURE__ */ jsx7(PlainWebView, { ref, ...props }) }) : /* @__PURE__ */ jsx7(PlainWebView, { ref, ...props }) });
1190
+ return /* @__PURE__ */ jsxs4(Fragment7, { children: [
1191
+ /* @__PURE__ */ jsx9(GameWebviewNavigationBar, {}),
1192
+ getOperationalEnvironment() === "toss" ? /* @__PURE__ */ jsx9(GameProfile, { isReadyForProfileUI: isEntryMessageExited, children: /* @__PURE__ */ jsx9(PlainWebView, { ref, ...props }) }) : /* @__PURE__ */ jsx9(PlainWebView, { ref, ...props })
1193
+ ] });
1118
1194
  });
1119
1195
 
1120
1196
  // src/components/PartnerWebView.tsx
1197
+ import { closeView as closeView5 } from "@apps-in-toss/native-modules";
1121
1198
  import {
1122
1199
  WebView as PlainWebView2
1123
1200
  } from "@granite-js/native/react-native-webview";
1124
- import { forwardRef as forwardRef2, useRef as useRef4 } from "react";
1201
+ import { forwardRef as forwardRef2, useCallback as useCallback8, useEffect as useEffect11, useRef as useRef4 } from "react";
1202
+ import { BackHandler as BackHandler3 } from "react-native";
1203
+
1204
+ // src/components/NavigationBar/PartnerWebviewNavigationBar.tsx
1205
+ import { closeView as closeView4 } from "@granite-js/react-native";
1206
+ import { useDialog as useDialog5 } from "@toss-design-system/react-native";
1207
+ import { NavigationBackButton as NavigationBackButton2, NavigationLeft as NavigationLeft2, TopNavigation as TopNavigation2 } from "@toss-design-system/react-native/private";
1208
+ import { josa as josa4 } from "es-hangul";
1209
+ import { useCallback as useCallback6 } from "react";
1210
+ import { jsx as jsx10 } from "react/jsx-runtime";
1211
+ function PartnerWebviewNavigationBar({ handleBackEvent, handleHomeIconButtonClick }) {
1212
+ const globals = getAppsInTossGlobals();
1213
+ const { captureExitLog } = useCaptureExitLog();
1214
+ const logging = useNavigationBarLogging();
1215
+ const { openConfirm } = useDialog5();
1216
+ const { open: openMoreButtonBottomSheet } = useMoreButtonBottomSheet();
1217
+ const parsedNavigationBar = globals.navigationBar != null ? safeParseNavigationBar(globals.navigationBar) : null;
1218
+ const withHomeButton = parsedNavigationBar?.withHomeButton ?? false;
1219
+ const withBackButton = parsedNavigationBar?.withBackButton ?? true;
1220
+ const initialAccessoryButton = parsedNavigationBar?.initialAccessoryButton;
1221
+ const handlePressTitle = useCallback6(() => {
1222
+ logging.homeButtonClick();
1223
+ handleHomeIconButtonClick();
1224
+ }, [handleHomeIconButtonClick, logging]);
1225
+ const handleClose = useCallback6(async () => {
1226
+ logging.closeButtonClick();
1227
+ const isConfirmed = await openConfirm({
1228
+ title: `${josa4(globals.brandDisplayName, "\uC744/\uB97C")} \uC885\uB8CC\uD560\uAE4C\uC694?`,
1229
+ leftButton: "\uCDE8\uC18C",
1230
+ rightButton: "\uC885\uB8CC\uD558\uAE30",
1231
+ closeOnDimmerClick: true,
1232
+ onEntered: logging.closePopupShow
1233
+ });
1234
+ logging.closePopupCtaClick(isConfirmed);
1235
+ if (isConfirmed) {
1236
+ captureExitLog(Date.now());
1237
+ closeView4();
1238
+ }
1239
+ }, [captureExitLog, globals.brandDisplayName, logging, openConfirm]);
1240
+ return /* @__PURE__ */ jsx10(NavigationBarImpressionArea, { withHomeButton, children: /* @__PURE__ */ jsx10(
1241
+ TopNavigation2,
1242
+ {
1243
+ title: globals.brandDisplayName,
1244
+ icon: toIcon(globals.brandIcon),
1245
+ onPressDots: openMoreButtonBottomSheet,
1246
+ contentVisible: true,
1247
+ onPressTitle: withHomeButton ? handlePressTitle : void 0,
1248
+ onPressClose: handleClose,
1249
+ withHome: withHomeButton,
1250
+ fixedRightButton: initialAccessoryButton,
1251
+ children: /* @__PURE__ */ jsx10(NavigationLeft2, { visible: withBackButton, children: /* @__PURE__ */ jsx10(NavigationBackButton2, { onPress: handleBackEvent, canGoBack: false }) })
1252
+ }
1253
+ ) });
1254
+ }
1125
1255
 
1126
1256
  // src/core/utils/mergeRefs.ts
1127
1257
  function mergeRefs(...refs) {
@@ -1136,22 +1266,186 @@ function mergeRefs(...refs) {
1136
1266
  };
1137
1267
  }
1138
1268
 
1269
+ // src/hooks/useWebviewHistoryStack.tsx
1270
+ import { useCallback as useCallback7, useMemo as useMemo2, useReducer } from "react";
1271
+ var INITIAL_STATE = { stack: [], index: -1 };
1272
+ function reducer(state, action) {
1273
+ switch (action.type) {
1274
+ case "NAVIGATION_CHANGE": {
1275
+ const { url, canGoForward } = action;
1276
+ if (state.stack.length === 0) {
1277
+ return { stack: [url], index: 0 };
1278
+ }
1279
+ const { stack, index } = state;
1280
+ const cur = stack[index];
1281
+ if (url === cur) {
1282
+ return state;
1283
+ }
1284
+ const prev = index > 0 ? stack[index - 1] : void 0;
1285
+ const next = index < stack.length - 1 ? stack[index + 1] : void 0;
1286
+ if (prev && url === prev && canGoForward) {
1287
+ return { ...state, index: index - 1 };
1288
+ }
1289
+ if (next && url === next) {
1290
+ return { ...state, index: index + 1 };
1291
+ }
1292
+ const base = stack.slice(0, index + 1);
1293
+ const nextStack = [...base, url];
1294
+ return { stack: nextStack, index: nextStack.length - 1 };
1295
+ }
1296
+ default:
1297
+ return state;
1298
+ }
1299
+ }
1300
+ function useWebViewHistory() {
1301
+ const [state, dispatch] = useReducer(reducer, INITIAL_STATE);
1302
+ const onNavigationStateChange = useCallback7(({ url, canGoForward: canGoForward2 }) => {
1303
+ dispatch({ type: "NAVIGATION_CHANGE", url, canGoForward: canGoForward2 });
1304
+ }, []);
1305
+ const { canGoBack, canGoForward } = useMemo2(() => {
1306
+ const canBack = state.index > 0;
1307
+ const canFwd = state.index >= 0 && state.index < state.stack.length - 1;
1308
+ return { canGoBack: canBack, canGoForward: canFwd };
1309
+ }, [state.index, state.stack.length]);
1310
+ return { onNavigationStateChange, canGoBack, canGoForward };
1311
+ }
1312
+
1313
+ // src/utils/log.ts
1314
+ import { eventLog as eventLogNative } from "@apps-in-toss/native-modules";
1315
+ import { getSchemeUri as getSchemeUri4 } from "@granite-js/react-native";
1316
+
1317
+ // src/utils/extractDateFromUUIDv7.ts
1318
+ var extractDateFromUUIDv7 = (uuid) => {
1319
+ const timestampHex = uuid.split("-").join("").slice(0, 12);
1320
+ const timestamp = Number.parseInt(timestampHex, 16);
1321
+ return new Date(timestamp);
1322
+ };
1323
+
1324
+ // src/utils/log.ts
1325
+ var getGroupId = (url) => {
1326
+ try {
1327
+ const urlObject = new URL(url);
1328
+ return {
1329
+ groupId: urlObject.pathname,
1330
+ search: urlObject.search.startsWith("?") ? urlObject.search.substring(1) : urlObject.search
1331
+ };
1332
+ } catch {
1333
+ return {
1334
+ groupId: "unknown",
1335
+ search: "unknown"
1336
+ };
1337
+ }
1338
+ };
1339
+ var getReferrer = () => {
1340
+ try {
1341
+ const referrer = new URL(getSchemeUri4());
1342
+ return referrer.searchParams.get("referrer");
1343
+ } catch {
1344
+ return "";
1345
+ }
1346
+ };
1347
+ var trackScreen = (url) => {
1348
+ const { groupId, search } = getGroupId(url);
1349
+ const log = {
1350
+ log_type: "screen",
1351
+ log_name: `${groupId}::screen`,
1352
+ params: {
1353
+ search,
1354
+ referrer: getReferrer(),
1355
+ deployment_id: env.getDeploymentId(),
1356
+ deployment_timestamp: extractDateFromUUIDv7(env.getDeploymentId()).getTime()
1357
+ }
1358
+ };
1359
+ return eventLogNative(log);
1360
+ };
1361
+
1139
1362
  // src/components/PartnerWebView.tsx
1140
- import { jsx as jsx8 } from "react/jsx-runtime";
1363
+ import { Fragment as Fragment8, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
1141
1364
  var PartnerWebView = forwardRef2(
1142
1365
  function PartnerWebViewScreen(webViewProps, ref) {
1143
1366
  const webViewRef = useRef4(null);
1144
1367
  const refs = mergeRefs(ref, webViewRef);
1145
- return /* @__PURE__ */ jsx8(PlainWebView2, { ref: refs, ...webViewProps, style: { flex: 1 } });
1368
+ const { captureExitLog } = useCaptureExitLog();
1369
+ const { canGoBack, onNavigationStateChange } = useWebViewHistory();
1370
+ const historyBackScript = `
1371
+ (function() {
1372
+ window.history.back();
1373
+ true;
1374
+ })();
1375
+ `;
1376
+ const historyHomeScript = `
1377
+ (function() {
1378
+ window.location.href = '/';
1379
+ true;
1380
+ })();
1381
+ `;
1382
+ const handleBackEvent = useCallback8(() => {
1383
+ if (canGoBack) {
1384
+ webViewRef.current?.injectJavaScript(historyBackScript);
1385
+ } else {
1386
+ captureExitLog(Date.now());
1387
+ closeView5();
1388
+ }
1389
+ }, [canGoBack, captureExitLog, historyBackScript]);
1390
+ useEffect11(() => {
1391
+ const handleAndroidBackEvent = () => {
1392
+ if (canGoBack) {
1393
+ webViewRef.current?.injectJavaScript(historyBackScript);
1394
+ return true;
1395
+ } else {
1396
+ captureExitLog(Date.now());
1397
+ return false;
1398
+ }
1399
+ };
1400
+ BackHandler3.addEventListener("hardwareBackPress", handleAndroidBackEvent);
1401
+ return () => BackHandler3.removeEventListener("hardwareBackPress", handleAndroidBackEvent);
1402
+ }, [canGoBack, captureExitLog, historyBackScript]);
1403
+ const handleHomeIconButtonClick = useCallback8(() => {
1404
+ webViewRef.current?.injectJavaScript(historyHomeScript);
1405
+ }, [historyHomeScript]);
1406
+ const handleNavigationStateChange = useCallback8(
1407
+ (event) => {
1408
+ if (event.url) {
1409
+ trackScreen(event.url);
1410
+ }
1411
+ onNavigationStateChange(event);
1412
+ },
1413
+ [onNavigationStateChange]
1414
+ );
1415
+ return /* @__PURE__ */ jsxs5(Fragment8, { children: [
1416
+ /* @__PURE__ */ jsx11(
1417
+ PartnerWebviewNavigationBar,
1418
+ {
1419
+ handleBackEvent,
1420
+ handleHomeIconButtonClick
1421
+ }
1422
+ ),
1423
+ /* @__PURE__ */ jsx11(
1424
+ PlainWebView2,
1425
+ {
1426
+ ref: refs,
1427
+ ...webViewProps,
1428
+ style: { flex: 1 },
1429
+ onNavigationStateChange: (event) => {
1430
+ webViewProps?.onNavigationStateChange?.(event);
1431
+ handleNavigationStateChange(event);
1432
+ }
1433
+ }
1434
+ )
1435
+ ] });
1146
1436
  }
1147
1437
  );
1148
1438
 
1149
1439
  // src/bridge-handler/useBridgeHandler.tsx
1150
- import { useCallback as useCallback5, useMemo as useMemo2, useRef as useRef5 } from "react";
1440
+ import { useCallback as useCallback9, useMemo as useMemo3, useRef as useRef5 } from "react";
1151
1441
  function serializeError(error) {
1152
1442
  return JSON.stringify(error, (_, value) => {
1153
1443
  if (value instanceof Error) {
1154
1444
  return {
1445
+ ...Object.entries(value).reduce((acc, [key, value2]) => {
1446
+ acc[key] = value2;
1447
+ return acc;
1448
+ }, {}),
1155
1449
  name: value.name,
1156
1450
  message: value.message,
1157
1451
  stack: value.stack,
@@ -1197,7 +1491,7 @@ function useBridgeHandler({
1197
1491
  injectedJavaScript: originalInjectedJavaScript
1198
1492
  }) {
1199
1493
  const ref = useRef5(null);
1200
- const injectedJavaScript = useMemo2(
1494
+ const injectedJavaScript = useMemo3(
1201
1495
  () => [
1202
1496
  `window.__CONSTANT_HANDLER_MAP = ${JSON.stringify(
1203
1497
  Object.entries(constantHandlerMap).reduce(
@@ -1224,7 +1518,7 @@ function useBridgeHandler({
1224
1518
  window.__GRANITE_NATIVE_EMITTER.emit('${functionName}/onError/${eventId}', ${serializedError});
1225
1519
  `);
1226
1520
  };
1227
- const $onMessage = useCallback5(
1521
+ const $onMessage = useCallback9(
1228
1522
  async (e) => {
1229
1523
  onMessage?.(e);
1230
1524
  const data = JSON.parse(e.nativeEvent.data);
@@ -1433,11 +1727,11 @@ function useCreateUserAgent({
1433
1727
  // src/hooks/useGeolocation.ts
1434
1728
  import { startUpdateLocation } from "@apps-in-toss/native-modules";
1435
1729
  import { useVisibility as useVisibility3 } from "@granite-js/react-native";
1436
- import { useEffect as useEffect9, useState as useState4 } from "react";
1730
+ import { useEffect as useEffect12, useState as useState4 } from "react";
1437
1731
  function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
1438
1732
  const isVisible = useVisibility3();
1439
1733
  const [location, setLocation] = useState4(null);
1440
- useEffect9(() => {
1734
+ useEffect12(() => {
1441
1735
  if (!isVisible) {
1442
1736
  return;
1443
1737
  }
@@ -1454,57 +1748,8 @@ function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
1454
1748
  return location;
1455
1749
  }
1456
1750
 
1457
- // src/utils/log.ts
1458
- import { eventLog as eventLogNative } from "@apps-in-toss/native-modules";
1459
- import { getSchemeUri as getSchemeUri4 } from "@granite-js/react-native";
1460
-
1461
- // src/utils/extractDateFromUUIDv7.ts
1462
- var extractDateFromUUIDv7 = (uuid) => {
1463
- const timestampHex = uuid.split("-").join("").slice(0, 12);
1464
- const timestamp = Number.parseInt(timestampHex, 16);
1465
- return new Date(timestamp);
1466
- };
1467
-
1468
- // src/utils/log.ts
1469
- var getGroupId = (url) => {
1470
- try {
1471
- const urlObject = new URL(url);
1472
- return {
1473
- groupId: urlObject.pathname,
1474
- search: urlObject.search.startsWith("?") ? urlObject.search.substring(1) : urlObject.search
1475
- };
1476
- } catch {
1477
- return {
1478
- groupId: "unknown",
1479
- search: "unknown"
1480
- };
1481
- }
1482
- };
1483
- var getReferrer = () => {
1484
- try {
1485
- const referrer = new URL(getSchemeUri4());
1486
- return referrer.searchParams.get("referrer");
1487
- } catch {
1488
- return "";
1489
- }
1490
- };
1491
- var trackScreen = (url) => {
1492
- const { groupId, search } = getGroupId(url);
1493
- const log = {
1494
- log_type: "screen",
1495
- log_name: `${groupId}::screen`,
1496
- params: {
1497
- search,
1498
- referrer: getReferrer(),
1499
- deployment_id: env.getDeploymentId(),
1500
- deployment_timestamp: extractDateFromUUIDv7(env.getDeploymentId()).getTime()
1501
- }
1502
- };
1503
- return eventLogNative(log);
1504
- };
1505
-
1506
1751
  // src/components/WebView.tsx
1507
- import { jsx as jsx9 } from "react/jsx-runtime";
1752
+ import { jsx as jsx12 } from "react/jsx-runtime";
1508
1753
  var operationalEnvironment = appsInTossConstantBridges.getOperationalEnvironment();
1509
1754
  var TYPES = ["partner", "external", "game"];
1510
1755
  var WEBVIEW_TYPES = {
@@ -1538,11 +1783,9 @@ function WebView({ type, local, onMessage, ...props }) {
1538
1783
  if (!TYPES.includes(type)) {
1539
1784
  throw new Error(`Invalid WebView type: '${type}'`);
1540
1785
  }
1541
- const { openConfirm } = useDialog4();
1542
- const { captureExitLog } = useCaptureExitLog();
1543
1786
  const graniteEvent = useGraniteEvent();
1544
- const uri = useMemo3(() => getWebViewUri(local), [local]);
1545
- const top = useSafeAreaTop();
1787
+ const uri = useMemo4(() => getWebViewUri(local), [local]);
1788
+ const top = useSafeAreaTop2();
1546
1789
  const bottom = useSafeAreaBottom();
1547
1790
  const global2 = getAppsInTossGlobals();
1548
1791
  const topNavigation = useTopNavigation();
@@ -1564,10 +1807,10 @@ function WebView({ type, local, onMessage, ...props }) {
1564
1807
  ...appsInTossEventBridges,
1565
1808
  navigationAccessoryEvent: ({ onEvent, onError }) => tdsEvent.addEventListener("navigationAccessoryEvent", { onEvent, onError }),
1566
1809
  backEvent: ({ onEvent, onError, options }) => graniteEvent.addEventListener("backEvent", { onEvent, onError, options }),
1567
- entryMessageExited: ({ onEvent, onError }) => appsInTossEvent4.addEventListener("entryMessageExited", { onEvent, onError }),
1568
- updateLocationEvent: ({ onEvent, onError, options }) => appsInTossEvent4.addEventListener("updateLocationEvent", { onEvent, onError, options }),
1810
+ entryMessageExited: ({ onEvent, onError }) => appsInTossEvent3.addEventListener("entryMessageExited", { onEvent, onError }),
1811
+ updateLocationEvent: ({ onEvent, onError, options }) => appsInTossEvent3.addEventListener("updateLocationEvent", { onEvent, onError, options }),
1569
1812
  /** @internal */
1570
- appBridgeCallbackEvent: ({ onEvent, onError, options }) => appsInTossEvent4.addEventListener("appBridgeCallbackEvent", { onEvent, onError, options }),
1813
+ appBridgeCallbackEvent: ({ onEvent, onError, options }) => appsInTossEvent3.addEventListener("appBridgeCallbackEvent", { onEvent, onError, options }),
1571
1814
  /** AdMob */
1572
1815
  loadAdMobInterstitialAd: GoogleAdMob.loadAdMobInterstitialAd,
1573
1816
  showAdMobInterstitialAd: GoogleAdMob.showAdMobInterstitialAd,
@@ -1575,7 +1818,10 @@ function WebView({ type, local, onMessage, ...props }) {
1575
1818
  showAdMobRewardedAd: GoogleAdMob.showAdMobRewardedAd,
1576
1819
  /** AdMobV2 */
1577
1820
  loadAppsInTossAdMob: GoogleAdMob.loadAppsInTossAdMob,
1578
- showAppsInTossAdMob: GoogleAdMob.showAppsInTossAdMob
1821
+ showAppsInTossAdMob: GoogleAdMob.showAppsInTossAdMob,
1822
+ /** IAP */
1823
+ iapCreateOneTimePurchaseOrder: IAP.createOneTimePurchaseOrder,
1824
+ requestOneTimePurchase
1579
1825
  },
1580
1826
  constantHandlerMap: {
1581
1827
  ...graniteConstantBridges,
@@ -1619,11 +1865,12 @@ function WebView({ type, local, onMessage, ...props }) {
1619
1865
  removeStorageItem: Storage.removeItem,
1620
1866
  clearItems: Storage.clearItems,
1621
1867
  /** IAP */
1622
- iapCreateOneTimePurchaseOrder: IAP.createOneTimePurchaseOrder,
1623
- iapGetProductItemList: IAP.getProductItemList
1868
+ iapGetProductItemList: IAP.getProductItemList,
1869
+ iapCreateOneTimePurchaseOrder,
1870
+ processProductGrant
1624
1871
  }
1625
1872
  });
1626
- const headerPropForExternalWebView = useMemo3(() => {
1873
+ const headerPropForExternalWebView = useMemo4(() => {
1627
1874
  const parsedNavigationBar = global2.navigationBar != null ? safeParseNavigationBar(global2.navigationBar) : null;
1628
1875
  const initialAccessoryButton = parsedNavigationBar?.initialAccessoryButton;
1629
1876
  const withBackButton = parsedNavigationBar?.withBackButton ?? true;
@@ -1640,74 +1887,10 @@ function WebView({ type, local, onMessage, ...props }) {
1640
1887
  }, [global2.navigationBar, type]);
1641
1888
  const BaseWebView = WEBVIEW_TYPES[type];
1642
1889
  const webViewDebuggingEnabled = operationalEnvironment === "sandbox";
1643
- const [canHistoryGoBack, setCanHistoryGoBack] = useState5(false);
1644
- const handleNavigationStateChange = useCallback6(
1645
- (event) => {
1646
- if (event.url) {
1647
- trackScreen(event.url);
1648
- }
1649
- setCanHistoryGoBack(event.canGoBack);
1650
- },
1651
- [setCanHistoryGoBack]
1652
- );
1653
1890
  const userAgent = useCreateUserAgent({
1654
1891
  colorPreference: "light"
1655
1892
  });
1656
- const handleGameWebviewClose = useCallback6(async () => {
1657
- const isConfirmed = await openConfirm({
1658
- title: `${josa3(global2.brandDisplayName, "\uC744/\uB97C")} \uC885\uB8CC\uD560\uAE4C\uC694?`,
1659
- leftButton: "\uCDE8\uC18C",
1660
- rightButton: "\uC885\uB8CC\uD558\uAE30",
1661
- closeOnDimmerClick: true
1662
- });
1663
- if (isConfirmed) {
1664
- captureExitLog(Date.now());
1665
- closeView3();
1666
- }
1667
- }, [captureExitLog, openConfirm, global2.brandDisplayName]);
1668
- const handleBackEvent = useCallback6(() => {
1669
- if (type === "game") {
1670
- handleGameWebviewClose();
1671
- return true;
1672
- }
1673
- if (canHistoryGoBack) {
1674
- handler.ref.current?.goBack();
1675
- return true;
1676
- } else {
1677
- return false;
1678
- }
1679
- }, [canHistoryGoBack, handleGameWebviewClose, handler.ref, type]);
1680
- useEffect10(() => {
1681
- BackHandler2.addEventListener("hardwareBackPress", handleBackEvent);
1682
- return () => BackHandler2.removeEventListener("hardwareBackPress", handleBackEvent);
1683
- }, [handleBackEvent]);
1684
- useEffect10(() => {
1685
- return appsInTossEvent4.addEventListener("homeIconButtonClickEvent", {
1686
- onEvent: () => {
1687
- handler.ref?.current?.injectJavaScript(`
1688
- (function() {
1689
- window.history.replaceState(null, '', '/');
1690
- true;
1691
- })();
1692
- `);
1693
- }
1694
- });
1695
- }, [handler.ref]);
1696
- useEffect10(() => {
1697
- return appsInTossEvent4.addEventListener("backButtonClickEvent", {
1698
- onEvent: () => {
1699
- if (type === "game") {
1700
- handleGameWebviewClose();
1701
- } else if (canHistoryGoBack) {
1702
- handler.ref.current?.goBack();
1703
- } else {
1704
- captureExitLog(Date.now());
1705
- closeView3();
1706
- }
1707
- }
1708
- });
1709
- }, [handler.ref, canHistoryGoBack, handleGameWebviewClose, captureExitLog, type]);
1710
- return /* @__PURE__ */ jsx9(
1893
+ return /* @__PURE__ */ jsx12(
1711
1894
  BaseWebView,
1712
1895
  {
1713
1896
  ref: handler.ref,
@@ -1720,15 +1903,14 @@ function WebView({ type, local, onMessage, ...props }) {
1720
1903
  "User-Agent": userAgent
1721
1904
  }
1722
1905
  },
1723
- userAgent: Platform3.OS === "ios" ? userAgent : void 0,
1906
+ userAgent: Platform4.OS === "ios" ? userAgent : void 0,
1724
1907
  sharedCookiesEnabled: true,
1725
1908
  webviewDebuggingEnabled: webViewDebuggingEnabled,
1726
1909
  thirdPartyCookiesEnabled: true,
1727
1910
  onMessage: handler.onMessage,
1728
- onNavigationStateChange: handleNavigationStateChange,
1729
1911
  injectedJavaScript: handler.injectedJavaScript,
1730
1912
  injectedJavaScriptBeforeContentLoaded: handler.injectedJavaScript,
1731
- decelerationRate: Platform3.OS === "ios" ? 1 : void 0,
1913
+ decelerationRate: Platform4.OS === "ios" ? 1 : void 0,
1732
1914
  allowsBackForwardNavigationGestures
1733
1915
  }
1734
1916
  );