@apps-in-toss/framework 0.0.0-dev.1743135526084 → 0.0.0-dev.1747216176095

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/dist/index.js CHANGED
@@ -4,81 +4,225 @@ var __export = (target, all) => {
4
4
  __defProp(target, name, { get: all[name], enumerable: true });
5
5
  };
6
6
 
7
+ // src/index.ts
8
+ import { Analytics as InternalAnalytics } from "@apps-in-toss/analytics";
9
+
7
10
  // src/core/registerApp.tsx
11
+ import { Analytics } from "@apps-in-toss/analytics";
8
12
  import { TDSProvider } from "@toss-design-system/react-native";
9
- import { Bedrock } from "react-native-bedrock";
13
+ import { Bedrock as Bedrock2 } from "react-native-bedrock";
10
14
 
11
- // src/core/hooks/useAppsInTossBridge.ts
12
- import { useBridge } from "@toss-design-system/react-native";
15
+ // src/core/components/AppEvent.tsx
13
16
  import { useEffect } from "react";
17
+ import { Bedrock, getSchemeUri as getSchemeUri2 } from "react-native-bedrock";
14
18
 
15
- // src/core/utils/getAppsInTossGlobals.ts
16
- function getAppsInTossGlobals() {
17
- if (global.__appsInToss == null) {
18
- throw new Error("invalid apps-in-toss globals");
19
+ // src/env.ts
20
+ var env = {
21
+ getDeploymentId: () => __DEV__ ? "local" : global.__appsInToss?.deploymentId
22
+ };
23
+
24
+ // src/native-modules/tossCore.ts
25
+ import { NativeModules as NativeModules2 } from "react-native";
26
+
27
+ // src/native-modules/AppsInTossModule.ts
28
+ import { NativeModules } from "react-native";
29
+ var AppsInTossModuleInstance = NativeModules.AppsInTossModule;
30
+ var AppsInTossModule = AppsInTossModuleInstance;
31
+
32
+ // src/native-modules/getOperationalEnvironment.ts
33
+ function getOperationalEnvironment() {
34
+ return AppsInTossModule.operationalEnvironment;
35
+ }
36
+
37
+ // src/native-modules/isMinVersionSupported.ts
38
+ import { Platform } from "react-native";
39
+
40
+ // src/utils/compareVersion.ts
41
+ var SEMVER_REGEX = /^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\\-]+(?:\.[\da-z\\-]+)*))?(?:\+[\da-z\\-]+(?:\.[\da-z\\-]+)*)?)?)?$/i;
42
+ var isWildcard = (val) => ["*", "x", "X"].includes(val);
43
+ var tryParse = (val) => {
44
+ const num = parseInt(val, 10);
45
+ return isNaN(num) ? val : num;
46
+ };
47
+ var coerceTypes = (a, b) => {
48
+ return typeof a === typeof b ? [a, b] : [String(a), String(b)];
49
+ };
50
+ var compareValues = (a, b) => {
51
+ if (isWildcard(a) || isWildcard(b)) {
52
+ return 0;
19
53
  }
20
- return global.__appsInToss;
54
+ const [aVal, bVal] = coerceTypes(tryParse(a), tryParse(b));
55
+ if (aVal > bVal) {
56
+ return 1;
57
+ }
58
+ if (aVal < bVal) {
59
+ return -1;
60
+ }
61
+ return 0;
62
+ };
63
+ var parseVersion = (version) => {
64
+ if (typeof version !== "string") {
65
+ throw new TypeError("Invalid argument: expected a string");
66
+ }
67
+ const match = version.match(SEMVER_REGEX);
68
+ if (!match) {
69
+ throw new Error(`Invalid semver: '${version}'`);
70
+ }
71
+ const [, major, minor, patch, build, preRelease] = match;
72
+ return [major, minor, patch, build, preRelease];
73
+ };
74
+ var compareSegments = (a, b) => {
75
+ const maxLength = Math.max(a.length, b.length);
76
+ for (let i = 0; i < maxLength; i++) {
77
+ const segA = a[i] ?? "0";
78
+ const segB = b[i] ?? "0";
79
+ const result = compareValues(segA, segB);
80
+ if (result !== 0) {
81
+ return result;
82
+ }
83
+ }
84
+ return 0;
85
+ };
86
+ var compareVersions = (v1, v2) => {
87
+ const seg1 = parseVersion(v1);
88
+ const seg2 = parseVersion(v2);
89
+ const preRelease1 = seg1.pop();
90
+ const preRelease2 = seg2.pop();
91
+ const mainCompare = compareSegments(seg1, seg2);
92
+ if (mainCompare !== 0) {
93
+ return mainCompare;
94
+ }
95
+ if (preRelease1 && preRelease2) {
96
+ return compareSegments(preRelease1.split("."), preRelease2.split("."));
97
+ }
98
+ if (preRelease1) {
99
+ return -1;
100
+ }
101
+ if (preRelease2) {
102
+ return 1;
103
+ }
104
+ return 0;
105
+ };
106
+
107
+ // src/native-modules/isMinVersionSupported.ts
108
+ function isMinVersionSupported(minVersions) {
109
+ const operationalEnvironment2 = AppsInTossModule.operationalEnvironment;
110
+ if (operationalEnvironment2 === "sandbox") {
111
+ return true;
112
+ }
113
+ const currentVersion = AppsInTossModule.tossAppVersion;
114
+ const isIOS = Platform.OS === "ios";
115
+ const minVersion = isIOS ? minVersions.ios : minVersions.android;
116
+ if (minVersion === void 0) {
117
+ return false;
118
+ }
119
+ if (minVersion === "always") {
120
+ return true;
121
+ }
122
+ if (minVersion === "never") {
123
+ return false;
124
+ }
125
+ return compareVersions(currentVersion, minVersion) >= 0;
21
126
  }
22
127
 
23
- // src/core/utils/toIcon.ts
24
- function toIcon(source) {
25
- return source.startsWith("http") ? { source: { uri: source } } : { name: source };
128
+ // src/native-modules/tossCore.ts
129
+ var TossCoreModule = NativeModules2.TossCoreModule;
130
+ function tossCoreEventLog(params) {
131
+ const supported = isMinVersionSupported({ ios: "5.210.0", android: "5.210.0" });
132
+ const isSandbox = getOperationalEnvironment() === "sandbox";
133
+ if (!supported || isSandbox) {
134
+ return;
135
+ }
136
+ TossCoreModule.eventLog({
137
+ params: {
138
+ log_name: params.log_name,
139
+ log_type: params.log_type,
140
+ params: params.params
141
+ }
142
+ });
26
143
  }
27
144
 
28
- // src/core/hooks/useAppsInTossBridge.ts
29
- function useAppsInTossBridge() {
30
- const controller = useBridge();
31
- const appsInTossGlobals2 = getAppsInTossGlobals();
32
- useEffect(() => {
33
- const commonProps = {
34
- serviceName: appsInTossGlobals2.brandDisplayName,
35
- icon: toIcon(appsInTossGlobals2.brandIcon),
36
- color: appsInTossGlobals2.brandPrimaryColor,
37
- colorMode: appsInTossGlobals2.brandBridgeColorMode
38
- };
39
- controller.open({ ...commonProps });
145
+ // src/core/hooks/useReferrer.ts
146
+ import { useMemo } from "react";
147
+ import { getSchemeUri } from "react-native-bedrock";
148
+ function useReferrer() {
149
+ return useMemo(() => {
150
+ try {
151
+ return new URL(getSchemeUri()).searchParams.get("referrer");
152
+ } catch {
153
+ return null;
154
+ }
40
155
  }, []);
41
156
  }
42
157
 
43
- // src/core/registerApp.tsx
44
- import { Fragment, jsx } from "react/jsx-runtime";
45
- function AppsInTossContainer(Container, { children, ...initialProps }) {
46
- return /* @__PURE__ */ jsx(Container, { ...initialProps, children: /* @__PURE__ */ jsx(TDSProvider, { colorPreference: "light", token: { color: { primary: getAppsInTossGlobals().brandPrimaryColor } }, children: /* @__PURE__ */ jsx(TDSContainer, { ...initialProps, children }) }) });
47
- }
48
- function TDSContainer({ children }) {
49
- useAppsInTossBridge();
50
- return /* @__PURE__ */ jsx(Fragment, { children });
51
- }
52
- function registerApp(container, { context }) {
53
- return Bedrock.registerApp(AppsInTossContainer.bind(null, container), {
54
- appName: getAppName(),
55
- context
56
- });
57
- }
58
- function getAppName() {
158
+ // src/core/components/AppEvent.tsx
159
+ var ENTRY_APP_EVENT_SCHEMA_ID = 1562181;
160
+ function isPrivateScheme() {
59
161
  try {
60
- return global.__bedrock.app.name;
61
- } catch (error) {
62
- console.error("unexpected error occurred while getting app name");
63
- throw error;
162
+ return new URL(getSchemeUri2()).protocol === "intoss-private:";
163
+ } catch {
164
+ return false;
64
165
  }
65
166
  }
66
-
67
- // src/core/index.ts
68
- var AppsInToss = {
69
- registerApp
167
+ function EntryAppEvent() {
168
+ const referrer = useReferrer() ?? "";
169
+ useEffect(() => {
170
+ tossCoreEventLog({
171
+ log_name: "appsintoss_app_visit::impression__enter_appsintoss",
172
+ log_type: "info",
173
+ params: {
174
+ is_transform: true,
175
+ schema_id: ENTRY_APP_EVENT_SCHEMA_ID,
176
+ referrer,
177
+ deployment_id: env.getDeploymentId(),
178
+ app_name: Bedrock.appName,
179
+ is_private: isPrivateScheme()
180
+ }
181
+ });
182
+ }, [referrer]);
183
+ return null;
184
+ }
185
+ function SystemAppEvent({ ...initialProps }) {
186
+ useEffect(() => {
187
+ tossCoreEventLog({
188
+ log_name: "AppsInTossInitialProps",
189
+ log_type: "debug",
190
+ params: {
191
+ ...initialProps,
192
+ schemeUri: getSchemeUri2(),
193
+ deployment_id: env.getDeploymentId(),
194
+ app_name: Bedrock.appName,
195
+ is_private: isPrivateScheme()
196
+ }
197
+ });
198
+ }, [initialProps]);
199
+ return null;
200
+ }
201
+ var AppEvent = {
202
+ Entry: EntryAppEvent,
203
+ System: SystemAppEvent
70
204
  };
71
205
 
72
- // src/native-event-emitter/bedrock-event.ts
206
+ // src/core/hooks/useAppsInTossBridge.ts
207
+ import { useBridge } from "@toss-design-system/react-native";
208
+ import { useEffect as useEffect2 } from "react";
209
+
210
+ // src/native-event-emitter/appsInTossEvent.ts
73
211
  import { BedrockEvent } from "react-native-bedrock";
74
212
 
75
- // src/native-event-emitter/event-plugins/UpdateLocationEvent.ts
213
+ // src/native-event-emitter/event-plugins/EntryMessageExitedEvent.ts
76
214
  import { BedrockEventDefinition } from "react-native-bedrock";
215
+ var EntryMessageExitedEvent = class extends BedrockEventDefinition {
216
+ name = "entryMessageExited";
217
+ remove() {
218
+ }
219
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
220
+ listener(_) {
221
+ }
222
+ };
77
223
 
78
- // src/native-modules/AppsInTossModule.ts
79
- import { NativeModules } from "react-native";
80
- var AppsInTossModuleInstance = NativeModules.AppsInTossModule;
81
- var AppsInTossModule = AppsInTossModuleInstance;
224
+ // src/native-event-emitter/event-plugins/UpdateLocationEvent.ts
225
+ import { BedrockEventDefinition as BedrockEventDefinition2 } from "react-native-bedrock";
82
226
 
83
227
  // src/native-modules/getPermission.ts
84
228
  function getPermission(permission) {
@@ -107,7 +251,7 @@ import { NativeEventEmitter } from "react-native";
107
251
  var nativeEventEmitter = new NativeEventEmitter(AppsInTossModuleInstance);
108
252
 
109
253
  // src/native-event-emitter/event-plugins/UpdateLocationEvent.ts
110
- var UpdateLocationEvent = class extends BedrockEventDefinition {
254
+ var UpdateLocationEvent = class extends BedrockEventDefinition2 {
111
255
  name = "updateLocationEvent";
112
256
  subscriptionCount = 0;
113
257
  ref = {
@@ -115,7 +259,9 @@ var UpdateLocationEvent = class extends BedrockEventDefinition {
115
259
  }
116
260
  };
117
261
  remove() {
118
- --this.subscriptionCount === 0 && AppsInTossModuleInstance.stopUpdateLocation({});
262
+ if (--this.subscriptionCount === 0) {
263
+ AppsInTossModuleInstance.stopUpdateLocation({});
264
+ }
119
265
  this.ref.remove();
120
266
  }
121
267
  listener(options, onEvent, onError) {
@@ -134,24 +280,148 @@ var UpdateLocationEvent = class extends BedrockEventDefinition {
134
280
  }
135
281
  };
136
282
 
137
- // src/native-event-emitter/bedrock-event.ts
138
- var appsInTossEvent = new BedrockEvent([new UpdateLocationEvent()]);
283
+ // src/native-event-emitter/internal/AppBridgeCallbackEvent.ts
284
+ import { BedrockEventDefinition as BedrockEventDefinition3 } from "react-native-bedrock";
139
285
 
140
- // src/native-event-emitter/startUpdateLocation.ts
141
- function startUpdateLocation(eventParams) {
142
- return appsInTossEvent.addEventListener("updateLocationEvent", eventParams);
286
+ // src/utils/generateUUID.ts
287
+ function generateUUID(placeholder) {
288
+ return placeholder ? (placeholder ^ Math.random() * 16 >> placeholder / 4).toString(16) : (String(1e7) + 1e3 + 4e3 + 8e3 + 1e11).replace(/[018]/g, generateUUID);
143
289
  }
144
290
 
145
- // src/native-modules/checkoutPayment.ts
146
- async function checkoutPayment(options) {
147
- return AppsInTossModule.checkoutPayment(options);
291
+ // src/native-event-emitter/internal/appBridge.ts
292
+ var INTERNAL__callbacks = /* @__PURE__ */ new Map();
293
+ function invokeAppBridgeCallback(id, ...args) {
294
+ const callback = INTERNAL__callbacks.get(id);
295
+ callback?.call(null, ...args);
296
+ return Boolean(callback);
297
+ }
298
+ function invokeAppBridgeMethod(methodName, params, callbacks) {
299
+ const { onSuccess, onError, ...appBridgeCallbacks } = callbacks;
300
+ const { callbackMap, unregisterAll } = registerCallbacks(appBridgeCallbacks);
301
+ const promise = AppsInTossModuleInstance[methodName]({
302
+ params,
303
+ callbacks: callbackMap
304
+ });
305
+ void promise.then(onSuccess).catch(onError);
306
+ return unregisterAll;
307
+ }
308
+ function registerCallbacks(callbacks) {
309
+ const callbackMap = {};
310
+ for (const [callbackName, callback] of Object.entries(callbacks)) {
311
+ const id = registerCallback(callback, callbackName);
312
+ callbackMap[callbackName] = id;
313
+ }
314
+ const unregisterAll = () => {
315
+ Object.values(callbackMap).forEach(unregisterCallback);
316
+ };
317
+ return { callbackMap, unregisterAll };
318
+ }
319
+ function registerCallback(callback, name = "unnamed") {
320
+ const uniqueId = generateUUID();
321
+ const callbackId = `${uniqueId}__${name}`;
322
+ INTERNAL__callbacks.set(callbackId, callback);
323
+ return callbackId;
324
+ }
325
+ function unregisterCallback(id) {
326
+ INTERNAL__callbacks.delete(id);
327
+ }
328
+ function getCallbackIds() {
329
+ return Array.from(INTERNAL__callbacks.keys());
148
330
  }
331
+ var INTERNAL__appBridgeHandler = {
332
+ invokeAppBridgeCallback,
333
+ invokeAppBridgeMethod,
334
+ registerCallback,
335
+ unregisterCallback,
336
+ getCallbackIds
337
+ };
149
338
 
150
- // src/native-modules/executePayment.ts
151
- async function executePayment(options) {
152
- return AppsInTossModule.executePayment(options);
339
+ // src/native-event-emitter/internal/AppBridgeCallbackEvent.ts
340
+ var UNSAFE__nativeEventEmitter = nativeEventEmitter;
341
+ var AppBridgeCallbackEvent = class _AppBridgeCallbackEvent extends BedrockEventDefinition3 {
342
+ static INTERNAL__appBridgeSubscription;
343
+ name = "appBridgeCallbackEvent";
344
+ constructor() {
345
+ super();
346
+ this.registerAppBridgeCallbackEventListener();
347
+ }
348
+ remove() {
349
+ }
350
+ listener() {
351
+ }
352
+ registerAppBridgeCallbackEventListener() {
353
+ if (_AppBridgeCallbackEvent.INTERNAL__appBridgeSubscription != null) {
354
+ return;
355
+ }
356
+ _AppBridgeCallbackEvent.INTERNAL__appBridgeSubscription = UNSAFE__nativeEventEmitter.addListener(
357
+ "appBridgeCallback",
358
+ this.ensureInvokeAppBridgeCallback
359
+ );
360
+ }
361
+ ensureInvokeAppBridgeCallback(result) {
362
+ if (typeof result === "object" && typeof result.name === "string") {
363
+ INTERNAL__appBridgeHandler.invokeAppBridgeCallback(result.name, result.params);
364
+ } else {
365
+ console.warn("Invalid app bridge callback result:", result);
366
+ }
367
+ }
368
+ };
369
+
370
+ // src/native-event-emitter/appsInTossEvent.ts
371
+ var appsInTossEvent = new BedrockEvent([
372
+ new AppBridgeCallbackEvent(),
373
+ new UpdateLocationEvent(),
374
+ new EntryMessageExitedEvent()
375
+ ]);
376
+
377
+ // src/core/utils/getAppsInTossGlobals.ts
378
+ function getAppsInTossGlobals() {
379
+ if (global.__appsInToss == null) {
380
+ throw new Error("invalid apps-in-toss globals");
381
+ }
382
+ return global.__appsInToss;
383
+ }
384
+
385
+ // src/core/utils/toIcon.ts
386
+ function toIcon(source) {
387
+ return source.startsWith("http") ? { source: { uri: source } } : { name: source };
153
388
  }
154
389
 
390
+ // src/core/hooks/useAppsInTossBridge.ts
391
+ function useAppsInTossBridge() {
392
+ const controller = useBridge();
393
+ const appsInTossGlobals2 = getAppsInTossGlobals();
394
+ useEffect2(() => {
395
+ const commonProps = {
396
+ serviceName: appsInTossGlobals2.brandDisplayName,
397
+ icon: toIcon(appsInTossGlobals2.brandIcon),
398
+ color: appsInTossGlobals2.brandPrimaryColor,
399
+ colorMode: appsInTossGlobals2.brandBridgeColorMode
400
+ };
401
+ controller.open({
402
+ ...commonProps,
403
+ onExited: () => {
404
+ appsInTossEvent.emit("entryMessageExited", void 0);
405
+ }
406
+ });
407
+ }, []);
408
+ }
409
+
410
+ // src/async-bridges.ts
411
+ var async_bridges_exports = {};
412
+ __export(async_bridges_exports, {
413
+ appLogin: () => appLogin,
414
+ checkoutPayment: () => checkoutPayment,
415
+ eventLog: () => eventLog,
416
+ fetchAlbumPhotos: () => fetchAlbumPhotos,
417
+ fetchContacts: () => fetchContacts,
418
+ getClipboardText: () => getClipboardText,
419
+ getCurrentLocation: () => getCurrentLocation,
420
+ getTossShareLink: () => getTossShareLink,
421
+ openCamera: () => openCamera,
422
+ setClipboardText: () => setClipboardText
423
+ });
424
+
155
425
  // src/native-modules/setClipboardText.ts
156
426
  async function setClipboardText(text) {
157
427
  const permissionStatus = await requestPermission({ name: "clipboard", access: "write" });
@@ -233,15 +503,246 @@ async function appLogin() {
233
503
  return AppsInTossModule.appLogin({});
234
504
  }
235
505
 
236
- // src/native-modules/getOperationalEnvironment.ts
237
- function getOperationalEnvironment() {
238
- return AppsInTossModule.operationalEnvironment;
506
+ // src/native-modules/checkoutPayment.ts
507
+ async function checkoutPayment(options) {
508
+ return AppsInTossModule.checkoutPayment({ params: options });
509
+ }
510
+
511
+ // src/native-modules/eventLog.ts
512
+ function normalizeParams(params) {
513
+ return Object.fromEntries(
514
+ Object.entries(params).filter(([, value]) => value !== void 0).map(([key, value]) => [key, String(value)])
515
+ );
516
+ }
517
+ async function eventLog(params) {
518
+ if (AppsInTossModule.operationalEnvironment === "sandbox") {
519
+ console.log("[eventLogDebug]", {
520
+ log_name: params.log_name,
521
+ log_type: params.log_type,
522
+ params: normalizeParams(params.params)
523
+ });
524
+ return;
525
+ }
526
+ const isSupported = isMinVersionSupported({
527
+ android: "5.208.0",
528
+ ios: "5.208.0"
529
+ });
530
+ if (!isSupported) {
531
+ return;
532
+ }
533
+ return AppsInTossModule.eventLog({
534
+ log_name: params.log_name,
535
+ log_type: params.log_type,
536
+ params: normalizeParams(params.params)
537
+ });
538
+ }
539
+
540
+ // src/native-modules/getTossShareLink.ts
541
+ async function getTossShareLink(path) {
542
+ const { shareLink } = await AppsInTossModule.getTossShareLink({});
543
+ const shareUrl = new URL(shareLink);
544
+ shareUrl.searchParams.set("deep_link_value", path);
545
+ shareUrl.searchParams.set("af_dp", path);
546
+ return shareUrl.toString();
547
+ }
548
+
549
+ // src/core/registerApp.tsx
550
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
551
+ function AppsInTossContainer(Container, { children, ...initialProps }) {
552
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
553
+ /* @__PURE__ */ jsx(AppEvent.Entry, {}),
554
+ /* @__PURE__ */ jsx(AppEvent.System, { ...initialProps }),
555
+ /* @__PURE__ */ jsx(Container, { ...initialProps, children: /* @__PURE__ */ jsx(TDSProvider, { colorPreference: "light", token: { color: { primary: getAppsInTossGlobals().brandPrimaryColor } }, children: /* @__PURE__ */ jsx(TDSContainer, { ...initialProps, children }) }) })
556
+ ] });
557
+ }
558
+ function TDSContainer({ children }) {
559
+ useAppsInTossBridge();
560
+ return /* @__PURE__ */ jsx(Fragment, { children });
561
+ }
562
+ function registerApp(container, { context, analytics }) {
563
+ Analytics.init({
564
+ logger: (params) => void eventLog(params),
565
+ debug: analytics?.debug ?? __DEV__
566
+ });
567
+ return Bedrock2.registerApp(AppsInTossContainer.bind(null, container), {
568
+ appName: getAppName(),
569
+ context,
570
+ router: {
571
+ screenContainer: Analytics.Screen,
572
+ defaultScreenOption: {
573
+ statusBarStyle: "dark"
574
+ }
575
+ }
576
+ });
577
+ }
578
+ function getAppName() {
579
+ try {
580
+ return global.__bedrock.app.name;
581
+ } catch (error) {
582
+ console.error("unexpected error occurred while getting app name");
583
+ throw error;
584
+ }
585
+ }
586
+
587
+ // src/core/index.ts
588
+ var AppsInToss = {
589
+ registerApp
590
+ };
591
+
592
+ // src/native-event-emitter/startUpdateLocation.ts
593
+ function startUpdateLocation(eventParams) {
594
+ return appsInTossEvent.addEventListener("updateLocationEvent", eventParams);
595
+ }
596
+
597
+ // ../../.yarn/cache/es-toolkit-npm-1.34.1-4cd6371dcb-aab6d07be3.zip/node_modules/es-toolkit/dist/function/noop.mjs
598
+ function noop() {
599
+ }
600
+
601
+ // src/native-modules/ads/googleAdMob.ts
602
+ function loadAdMobInterstitialAd(params) {
603
+ if (!loadAdMobInterstitialAd.isSupported()) {
604
+ params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE));
605
+ return noop;
606
+ }
607
+ const { onEvent, onError, options } = params;
608
+ const unregisterCallbacks = INTERNAL__appBridgeHandler.invokeAppBridgeMethod("loadAdMobInterstitialAd", options, {
609
+ onAdClicked: () => {
610
+ onEvent({ type: "clicked" });
611
+ },
612
+ onAdDismissed: () => {
613
+ onEvent({ type: "dismissed" });
614
+ },
615
+ onAdFailedToShow: () => {
616
+ onEvent({ type: "failedToShow" });
617
+ },
618
+ onAdImpression: () => {
619
+ onEvent({ type: "impression" });
620
+ },
621
+ onAdShow: () => {
622
+ onEvent({ type: "show" });
623
+ },
624
+ onSuccess: (result) => onEvent({ type: "loaded", data: result }),
625
+ onError
626
+ });
627
+ return unregisterCallbacks;
628
+ }
629
+ function showAdMobInterstitialAd(params) {
630
+ if (!showAdMobInterstitialAd.isSupported()) {
631
+ params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE));
632
+ return noop;
633
+ }
634
+ const { onEvent, onError, options } = params;
635
+ const unregisterCallbacks = INTERNAL__appBridgeHandler.invokeAppBridgeMethod("showAdMobInterstitialAd", options, {
636
+ onSuccess: () => onEvent({ type: "requested" }),
637
+ onError
638
+ });
639
+ return unregisterCallbacks;
640
+ }
641
+ function loadAdMobRewardedAd(params) {
642
+ if (!loadAdMobRewardedAd.isSupported()) {
643
+ params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE));
644
+ return noop;
645
+ }
646
+ const { onEvent, onError, options } = params;
647
+ const unregisterCallbacks = INTERNAL__appBridgeHandler.invokeAppBridgeMethod("loadAdMobRewardedAd", options, {
648
+ onAdClicked: () => {
649
+ onEvent({ type: "clicked" });
650
+ },
651
+ onAdDismissed: () => {
652
+ onEvent({ type: "dismissed" });
653
+ },
654
+ onAdFailedToShow: () => {
655
+ onEvent({ type: "failedToShow" });
656
+ },
657
+ onAdImpression: () => {
658
+ onEvent({ type: "impression" });
659
+ },
660
+ onAdShow: () => {
661
+ onEvent({ type: "show" });
662
+ },
663
+ onUserEarnedReward: () => {
664
+ onEvent({ type: "userEarnedReward" });
665
+ },
666
+ onSuccess: (result) => onEvent({ type: "loaded", data: result }),
667
+ onError
668
+ });
669
+ return unregisterCallbacks;
670
+ }
671
+ function showAdMobRewardedAd(params) {
672
+ if (!showAdMobRewardedAd.isSupported()) {
673
+ params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE));
674
+ return noop;
675
+ }
676
+ const { onEvent, onError, options } = params;
677
+ const unregisterCallbacks = INTERNAL__appBridgeHandler.invokeAppBridgeMethod("showAdMobRewardedAd", options, {
678
+ onSuccess: () => onEvent({ type: "requested" }),
679
+ onError
680
+ });
681
+ return unregisterCallbacks;
682
+ }
683
+ var ANDROID_GOOGLE_AD_MOB_SUPPORTED_VERSION = "5.209.0";
684
+ var IOS_GOOGLE_AD_MOB_SUPPORTED_VERSION = "5.209.0";
685
+ var UNSUPPORTED_ERROR_MESSAGE = "This feature is not supported in the current environment";
686
+ var ENVIRONMENT = getOperationalEnvironment();
687
+ function createIsSupported() {
688
+ return () => {
689
+ if (ENVIRONMENT !== "toss") {
690
+ console.warn("Google AdMob is not supported in the current environment");
691
+ return false;
692
+ }
693
+ return isMinVersionSupported({
694
+ android: ANDROID_GOOGLE_AD_MOB_SUPPORTED_VERSION,
695
+ ios: IOS_GOOGLE_AD_MOB_SUPPORTED_VERSION
696
+ });
697
+ };
698
+ }
699
+ loadAdMobInterstitialAd.isSupported = createIsSupported();
700
+ loadAdMobRewardedAd.isSupported = createIsSupported();
701
+ showAdMobInterstitialAd.isSupported = createIsSupported();
702
+ showAdMobRewardedAd.isSupported = createIsSupported();
703
+
704
+ // src/native-modules/getTossAppVersion.ts
705
+ function getTossAppVersion() {
706
+ return AppsInTossModule.tossAppVersion;
707
+ }
708
+
709
+ // src/native-modules/getDeviceId.ts
710
+ function getDeviceId() {
711
+ return AppsInTossModule.deviceId;
712
+ }
713
+
714
+ // src/native-modules/storage.ts
715
+ function getItem(key) {
716
+ return AppsInTossModule.getStorageItem({ key });
717
+ }
718
+ function setItem(key, value) {
719
+ return AppsInTossModule.setStorageItem({
720
+ key,
721
+ value
722
+ });
723
+ }
724
+ function removeItem(key) {
725
+ return AppsInTossModule.removeStorageItem({ key });
239
726
  }
727
+ function clearItems() {
728
+ return AppsInTossModule.clearStorage({});
729
+ }
730
+ var Storage = {
731
+ getItem,
732
+ setItem,
733
+ removeItem,
734
+ clearItems
735
+ };
240
736
 
241
737
  // src/native-modules/index.ts
242
738
  var TossPay = {
243
- checkoutPayment,
244
- executePayment
739
+ checkoutPayment
740
+ };
741
+ var GoogleAdMob = {
742
+ loadAdMobInterstitialAd,
743
+ showAdMobInterstitialAd,
744
+ loadAdMobRewardedAd,
745
+ showAdMobRewardedAd
245
746
  };
246
747
 
247
748
  // src/components/WebView.tsx
@@ -249,8 +750,9 @@ import {
249
750
  PartnerWebViewScreen,
250
751
  ExternalWebViewScreen
251
752
  } from "@toss-design-system/react-native";
252
- import { useMemo } from "react";
253
- import { getSchemeUri, useBridgeHandler } from "react-native-bedrock";
753
+ import { useSafeAreaBottom, useSafeAreaTop as useSafeAreaTop2 } from "@toss-design-system/react-native/private";
754
+ import { useCallback as useCallback3, useMemo as useMemo3 } from "react";
755
+ import { getSchemeUri as getSchemeUri4, useBedrockEvent } from "react-native-bedrock";
254
756
  import * as bedrockAsyncBridges from "react-native-bedrock/async-bridges";
255
757
  import * as bedrockConstantBridges from "react-native-bedrock/constant-bridges";
256
758
 
@@ -258,24 +760,26 @@ import * as bedrockConstantBridges from "react-native-bedrock/constant-bridges";
258
760
  import {
259
761
  WebView as PlainWebView
260
762
  } from "@react-native-bedrock/native/react-native-webview";
261
- import { forwardRef } from "react";
262
- import { View as View3 } from "react-native";
263
- import { closeView } from "react-native-bedrock";
763
+ import { useDialog } from "@toss-design-system/react-native";
764
+ import { josa } from "es-hangul";
765
+ import { forwardRef, useCallback, useEffect as useEffect3 } from "react";
766
+ import { BackHandler, Platform as Platform5, View as View3 } from "react-native";
767
+ import { closeView, setIosSwipeGestureEnabled } from "react-native-bedrock";
264
768
 
265
769
  // src/components/GameWebViewNavigationBar/GameNavigationBar.tsx
266
770
  import { SvgXml } from "@react-native-bedrock/native/react-native-svg";
267
771
  import { PageNavbar } from "@toss-design-system/react-native";
268
- import { Platform as Platform3, TouchableOpacity, View as View2 } from "react-native";
772
+ import { Platform as Platform4, TouchableOpacity, View as View2 } from "react-native";
269
773
 
270
774
  // src/components/GameWebViewNavigationBar/HeaderRight.tsx
271
775
  import { StyleSheet, View } from "react-native";
272
776
 
273
777
  // src/components/GameWebViewNavigationBar/byPlatform.ts
274
- import { Platform } from "react-native";
778
+ import { Platform as Platform2 } from "react-native";
275
779
  function byPlatform({
276
780
  ...props
277
781
  }) {
278
- return (props[Platform.OS] ?? props.fallback)();
782
+ return (props[Platform2.OS] ?? props.fallback)();
279
783
  }
280
784
 
281
785
  // src/components/GameWebViewNavigationBar/constants.ts
@@ -309,42 +813,45 @@ var styles = StyleSheet.create({
309
813
 
310
814
  // src/components/GameWebViewNavigationBar/useSafeAreaTop.ts
311
815
  import { useSafeAreaInsets } from "@react-native-bedrock/native/react-native-safe-area-context";
312
- import { Platform as Platform2 } from "react-native";
816
+ import { Platform as Platform3 } from "react-native";
313
817
  function useSafeAreaTop() {
314
818
  const safeAreaInsets = useSafeAreaInsets();
315
- const hasDynamicIsland = Platform2.OS === "ios" && safeAreaInsets.top > 50;
819
+ const hasDynamicIsland = Platform3.OS === "ios" && safeAreaInsets.top > 50;
316
820
  const safeAreaTop = hasDynamicIsland ? safeAreaInsets.top - 5 : safeAreaInsets.top;
317
821
  return safeAreaTop;
318
822
  }
319
823
 
320
824
  // src/components/GameWebViewNavigationBar/GameNavigationBar.tsx
321
- import { Fragment as Fragment2, jsx as jsx3, jsxs } from "react/jsx-runtime";
825
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
322
826
  var originXML = '<svg fill="none" height="30" viewBox="0 0 30 30" width="30" xmlns="https://www.w3.org/2000/svg"><rect fill="#031832" fill-opacity=".46" height="30" rx="15" width="30"/><rect height="29.5" rx="14.75" stroke="#d9d9ff" stroke-opacity=".11" stroke-width=".5" width="29.5" x=".25" y=".25"/><path clip-rule="evenodd" d="m16.5119 15.0014 4.7092-4.7092c.0929-.0928.1666-.2031.2169-.32441.0503-.12134.0762-.25141.0762-.38276.0001-.13136-.0258-.26144-.076-.38281s-.1239-.23166-.2167-.32457c-.0929-.09291-.2031-.16662-.3245-.21692-.1213-.05031-.2514-.07622-.3827-.07626-.1314-.00004-.2615.0258-.3828.07603-.1214.05023-.2317.12388-.3246.21673l-4.7092 4.70997-4.71-4.70997c-.1897-.17718-.4408-.27373-.70034-.26927s-.5072.10959-.69069.2932c-.1835.1836-.28848.43132-.29279.69087-.00432.25954.09238.51057.26968.70017l4.71004 4.7092-4.71004 4.7092c-.1392.1401-.23385.3183-.27204.5121-.0382.1939-.01823.3946.05739.5771s.20351.3386.36759.4486.35702.169.55456.1697c.25583 0 .51164-.0975.70664-.2925l4.71-4.71 4.7092 4.71c.0927.093.2029.1668.3243.2172.1213.0504.2514.0763.3828.0763s.2614-.0259.3828-.0763c.1213-.0504.2315-.1242.3243-.2172.0929-.0929.1667-.2032.217-.3246s.0762-.2515.0762-.3829-.0259-.2616-.0762-.383-.1241-.2317-.217-.3245z" fill="#fdfdfe" fill-opacity=".89" fill-rule="evenodd"/></svg>';
323
827
  function GameNavigationBar({ onClose }) {
324
828
  const safeAreaTop = useSafeAreaTop();
325
- return /* @__PURE__ */ jsxs(Fragment2, { children: [
829
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
326
830
  /* @__PURE__ */ jsx3(PageNavbar, { preference: { type: "none" } }),
327
831
  /* @__PURE__ */ jsx3(
328
832
  View2,
329
833
  {
330
834
  style: {
331
835
  width: "100%",
332
- height: Platform3.OS === "ios" ? 44 : 54,
836
+ height: Platform4.OS === "ios" ? 44 : 54,
333
837
  flexDirection: "row",
334
838
  alignItems: "center",
335
839
  justifyContent: "flex-end",
336
840
  position: "absolute",
337
841
  zIndex: 9999,
338
842
  marginTop: safeAreaTop,
339
- paddingRight: Platform3.OS === "ios" ? 10 : 8
843
+ paddingRight: Platform4.OS === "ios" ? 10 : 8
340
844
  },
341
845
  pointerEvents: "box-none",
342
846
  children: /* @__PURE__ */ jsx3(HeaderRight, { children: /* @__PURE__ */ jsx3(
343
847
  TouchableOpacity,
344
848
  {
345
849
  hitSlop: { left: 8, right: 8 },
850
+ accessibilityRole: "button",
851
+ accessible: true,
852
+ accessibilityLabel: "\uAC8C\uC784\uC885\uB8CC",
346
853
  style: {
347
- padding: Platform3.OS === "ios" ? 7 : 9
854
+ padding: Platform4.OS === "ios" ? 7 : 9
348
855
  },
349
856
  onPress: onClose,
350
857
  children: /* @__PURE__ */ jsx3(SvgXml, { xml: originXML, width: 30, height: 30 })
@@ -356,55 +863,240 @@ function GameNavigationBar({ onClose }) {
356
863
  }
357
864
 
358
865
  // src/components/GameWebView.tsx
359
- import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
866
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
360
867
  var GameWebView = forwardRef(function GameWebView2(props, ref) {
361
- return /* @__PURE__ */ jsxs2(Fragment3, { children: [
362
- /* @__PURE__ */ jsx4(
363
- GameNavigationBar,
364
- {
365
- onClose: () => {
366
- closeView();
367
- }
368
- }
369
- ),
868
+ const { openConfirm } = useDialog();
869
+ const { brandDisplayName } = getAppsInTossGlobals();
870
+ const handleClose = useCallback(async () => {
871
+ const isConfirmed = await openConfirm({
872
+ title: `${josa(brandDisplayName, "\uC744/\uB97C")} \uC885\uB8CC\uD560\uAE4C\uC694?`,
873
+ leftButton: "\uCDE8\uC18C",
874
+ rightButton: "\uC885\uB8CC\uD558\uAE30",
875
+ closeOnDimmerClick: true
876
+ });
877
+ if (isConfirmed) {
878
+ closeView();
879
+ }
880
+ }, [brandDisplayName, openConfirm]);
881
+ useEffect3(() => {
882
+ if (Platform5.OS === "ios") {
883
+ setIosSwipeGestureEnabled({ isEnabled: false });
884
+ return () => {
885
+ setIosSwipeGestureEnabled({ isEnabled: true });
886
+ };
887
+ }
888
+ return;
889
+ }, []);
890
+ useEffect3(() => {
891
+ const backHandler = () => {
892
+ handleClose();
893
+ return true;
894
+ };
895
+ BackHandler.addEventListener("hardwareBackPress", backHandler);
896
+ return () => {
897
+ BackHandler.removeEventListener("hardwareBackPress", backHandler);
898
+ };
899
+ }, [handleClose]);
900
+ return /* @__PURE__ */ jsxs3(Fragment3, { children: [
901
+ /* @__PURE__ */ jsx4(GameNavigationBar, { onClose: handleClose }),
370
902
  /* @__PURE__ */ jsx4(View3, { style: { flex: 1 }, children: /* @__PURE__ */ jsx4(PlainWebView, { ref, ...props }) })
371
903
  ] });
372
904
  });
373
905
 
374
- // src/async-bridges.ts
375
- var async_bridges_exports = {};
376
- __export(async_bridges_exports, {
377
- appLogin: () => appLogin,
378
- checkoutPayment: () => checkoutPayment,
379
- executePayment: () => executePayment,
380
- fetchAlbumPhotos: () => fetchAlbumPhotos,
381
- fetchContacts: () => fetchContacts,
382
- getClipboardText: () => getClipboardText,
383
- getCurrentLocation: () => getCurrentLocation,
384
- openCamera: () => openCamera,
385
- setClipboardText: () => setClipboardText
386
- });
906
+ // src/bridge-handler/useBridgeHandler.tsx
907
+ import { useCallback as useCallback2, useMemo as useMemo2, useRef } from "react";
908
+ function serializeError(error) {
909
+ return JSON.stringify(error, (_, value) => {
910
+ if (value instanceof Error) {
911
+ return {
912
+ name: value.name,
913
+ message: value.message,
914
+ stack: value.stack,
915
+ __isError: true
916
+ };
917
+ }
918
+ return value;
919
+ });
920
+ }
921
+ function methodHandler({
922
+ args,
923
+ eventId,
924
+ functionName,
925
+ handlerMap,
926
+ injectJavaScript
927
+ }) {
928
+ const func = handlerMap[functionName];
929
+ if (!func) {
930
+ console.error(`${functionName} is not a function`);
931
+ return;
932
+ }
933
+ const wrappedFunc = async (...args2) => {
934
+ const result = await func(...args2);
935
+ return result;
936
+ };
937
+ wrappedFunc(...args).then((result) => {
938
+ injectJavaScript?.(`
939
+ window.__BEDROCK_NATIVE_EMITTER.emit('${functionName}/resolve/${eventId}', ${JSON.stringify(result, null, 0)});
940
+ `);
941
+ }).catch((error) => {
942
+ const serializedError = serializeError(error);
943
+ injectJavaScript?.(`
944
+ window.__BEDROCK_NATIVE_EMITTER.emit('${functionName}/reject/${eventId}', ${serializedError});
945
+ `);
946
+ });
947
+ }
948
+ var globalEventListenerMap = /* @__PURE__ */ new Map();
949
+ function useBridgeHandler({
950
+ onMessage,
951
+ constantHandlerMap,
952
+ asyncHandlerMap,
953
+ eventListenerMap,
954
+ injectedJavaScript: originalInjectedJavaScript
955
+ }) {
956
+ const ref = useRef(null);
957
+ const injectedJavaScript = useMemo2(
958
+ () => [
959
+ `window.__CONSTANT_HANDLER_MAP = ${JSON.stringify(
960
+ Object.entries(constantHandlerMap).reduce(
961
+ (acc, [key, value]) => {
962
+ acc[key] = typeof value === "function" ? value() : value;
963
+ return acc;
964
+ },
965
+ {}
966
+ )
967
+ )}`,
968
+ originalInjectedJavaScript,
969
+ "true"
970
+ ].join("\n"),
971
+ [constantHandlerMap, originalInjectedJavaScript]
972
+ );
973
+ const createHandleOnEvent = (functionName, eventId) => (response) => {
974
+ ref.current?.injectJavaScript(`
975
+ window.__BEDROCK_NATIVE_EMITTER.emit('${functionName}/onEvent/${eventId}', ${JSON.stringify(response, null, 0)});
976
+ `);
977
+ };
978
+ const createHandleOnError = (functionName, eventId) => (error) => {
979
+ ref.current?.injectJavaScript(`
980
+ window.__BEDROCK_NATIVE_EMITTER.emit('${functionName}/onError/${eventId}', ${JSON.stringify(error, null, 0)});
981
+ `);
982
+ };
983
+ const $onMessage = useCallback2(
984
+ async (e) => {
985
+ onMessage?.(e);
986
+ const data = JSON.parse(e.nativeEvent.data);
987
+ if (typeof data !== "object" || data === null || typeof data.functionName !== "string" || typeof data.eventId !== "string" || typeof data.type !== "string" || !["addEventListener", "removeEventListener", "method"].includes(data.type)) {
988
+ return;
989
+ }
990
+ switch (data.type) {
991
+ case "addEventListener": {
992
+ const handleOnEvent = createHandleOnEvent(data.functionName, data.eventId);
993
+ const handleOnError = createHandleOnError(data.functionName, data.eventId);
994
+ const remove = eventListenerMap[data.functionName]?.({
995
+ onEvent: handleOnEvent,
996
+ onError: handleOnError,
997
+ options: data.args
998
+ });
999
+ if (remove) {
1000
+ globalEventListenerMap.set(`${data.functionName}/${data.eventId}`, remove);
1001
+ }
1002
+ break;
1003
+ }
1004
+ case "removeEventListener": {
1005
+ const key = `${data.functionName}/${data.eventId}`;
1006
+ const remove = globalEventListenerMap.get(key);
1007
+ remove?.();
1008
+ globalEventListenerMap.delete(key);
1009
+ break;
1010
+ }
1011
+ case "method": {
1012
+ methodHandler({
1013
+ args: data.args,
1014
+ eventId: data.eventId,
1015
+ functionName: data.functionName,
1016
+ handlerMap: asyncHandlerMap,
1017
+ injectJavaScript: ref.current?.injectJavaScript
1018
+ });
1019
+ break;
1020
+ }
1021
+ }
1022
+ },
1023
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1024
+ [onMessage]
1025
+ );
1026
+ return {
1027
+ ref,
1028
+ injectedJavaScript,
1029
+ onMessage: $onMessage
1030
+ };
1031
+ }
387
1032
 
388
1033
  // src/constant-bridges.ts
389
1034
  var constant_bridges_exports = {};
390
1035
  __export(constant_bridges_exports, {
391
- getOperationalEnvironment: () => getOperationalEnvironment
1036
+ getDeviceId: () => getDeviceId,
1037
+ getOperationalEnvironment: () => getOperationalEnvironment,
1038
+ getTossAppVersion: () => getTossAppVersion
392
1039
  });
393
1040
 
394
- // src/env.ts
395
- var env = {
396
- getDeploymentId: () => __DEV__ ? "local" : global.__appsInToss?.deploymentId
397
- };
398
-
399
1041
  // src/event-bridges.ts
400
1042
  var event_bridges_exports = {};
401
1043
  __export(event_bridges_exports, {
402
1044
  startUpdateLocation: () => startUpdateLocation
403
1045
  });
404
1046
 
1047
+ // src/utils/log.ts
1048
+ import { getSchemeUri as getSchemeUri3 } from "react-native-bedrock";
1049
+
1050
+ // src/utils/extractDateFromUUIDv7.ts
1051
+ var extractDateFromUUIDv7 = (uuid) => {
1052
+ const timestampHex = uuid.split("-").join("").slice(0, 12);
1053
+ const timestamp = Number.parseInt(timestampHex, 16);
1054
+ return new Date(timestamp);
1055
+ };
1056
+
1057
+ // src/utils/log.ts
1058
+ var getGroupId = (url) => {
1059
+ try {
1060
+ const urlObject = new URL(url);
1061
+ return {
1062
+ groupId: urlObject.pathname,
1063
+ search: urlObject.search.startsWith("?") ? urlObject.search.substring(1) : urlObject.search
1064
+ };
1065
+ } catch {
1066
+ return {
1067
+ groupId: "unknown",
1068
+ search: "unknown"
1069
+ };
1070
+ }
1071
+ };
1072
+ var getReferrer = () => {
1073
+ try {
1074
+ const referrer = new URL(getSchemeUri3());
1075
+ return referrer.searchParams.get("referrer");
1076
+ } catch {
1077
+ return "";
1078
+ }
1079
+ };
1080
+ var trackScreen = (url) => {
1081
+ const { groupId, search } = getGroupId(url);
1082
+ const log = {
1083
+ log_type: "screen",
1084
+ log_name: `${groupId}::screen`,
1085
+ params: {
1086
+ search,
1087
+ referrer: getReferrer(),
1088
+ deployment_id: env.getDeploymentId(),
1089
+ deployment_timestamp: extractDateFromUUIDv7(env.getDeploymentId()).getTime()
1090
+ }
1091
+ };
1092
+ return eventLog(log);
1093
+ };
1094
+
405
1095
  // src/components/WebView.tsx
406
1096
  import { jsx as jsx5 } from "react/jsx-runtime";
407
1097
  var appsInTossGlobals = getAppsInTossGlobals();
1098
+ var operationalEnvironment = getOperationalEnvironment();
1099
+ var TYPES = ["partner", "external", "game"];
408
1100
  var WEBVIEW_TYPES = {
409
1101
  partner: PartnerWebViewScreen,
410
1102
  external: ExternalWebViewScreen,
@@ -412,7 +1104,7 @@ var WEBVIEW_TYPES = {
412
1104
  };
413
1105
  function mergeSchemeQueryParamsInto(url) {
414
1106
  const baseUrl = new URL(url);
415
- const schemeUrl = new URL(getSchemeUri());
1107
+ const schemeUrl = new URL(getSchemeUri4());
416
1108
  baseUrl.pathname = schemeUrl.pathname;
417
1109
  for (const [key, value] of schemeUrl.searchParams.entries()) {
418
1110
  baseUrl.searchParams.set(key, value);
@@ -433,45 +1125,77 @@ function getWebViewUri(local) {
433
1125
  return url.toString();
434
1126
  }
435
1127
  function WebView({ type, local, onMessage, ...props }) {
436
- const uri = useMemo(() => getWebViewUri(local), [local]);
1128
+ if (!TYPES.includes(type)) {
1129
+ throw new Error(`Invalid WebView type: '${type}'`);
1130
+ }
1131
+ const bedrockEvent = useBedrockEvent();
1132
+ const uri = useMemo3(() => getWebViewUri(local), [local]);
1133
+ const top = useSafeAreaTop2();
1134
+ const bottom = useSafeAreaBottom();
437
1135
  const handler = useBridgeHandler({
438
1136
  onMessage,
439
1137
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
440
- eventListenerMap: event_bridges_exports,
441
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
442
- // @ts-expect-error
1138
+ eventListenerMap: {
1139
+ ...event_bridges_exports,
1140
+ backEvent: ({ onEvent, onError, options }) => bedrockEvent.addEventListener("backEvent", { onEvent, onError, options }),
1141
+ entryMessageExited: ({ onEvent, onError }) => appsInTossEvent.addEventListener("entryMessageExited", { onEvent, onError }),
1142
+ updateLocationEvent: ({ onEvent, onError, options }) => appsInTossEvent.addEventListener("updateLocationEvent", { onEvent, onError, options }),
1143
+ /** @internal */
1144
+ appBridgeCallbackEvent: ({ onEvent, onError, options }) => appsInTossEvent.addEventListener("appBridgeCallbackEvent", { onEvent, onError, options }),
1145
+ /** AdMob */
1146
+ loadAdMobInterstitialAd: GoogleAdMob.loadAdMobInterstitialAd,
1147
+ showAdMobInterstitialAd: GoogleAdMob.showAdMobInterstitialAd,
1148
+ loadAdMobRewardedAd: GoogleAdMob.loadAdMobRewardedAd,
1149
+ showAdMobRewardedAd: GoogleAdMob.showAdMobRewardedAd
1150
+ },
443
1151
  constantHandlerMap: {
444
1152
  ...bedrockConstantBridges,
445
- ...constant_bridges_exports
1153
+ ...constant_bridges_exports,
1154
+ getSafeAreaTop: () => top,
1155
+ getSafeAreaBottom: () => bottom,
1156
+ /** AdMob */
1157
+ loadAdMobInterstitialAd_isSupported: GoogleAdMob.loadAdMobInterstitialAd.isSupported,
1158
+ showAdMobInterstitialAd_isSupported: GoogleAdMob.showAdMobInterstitialAd.isSupported,
1159
+ loadAdMobRewardedAd_isSupported: GoogleAdMob.loadAdMobRewardedAd.isSupported,
1160
+ showAdMobRewardedAd_isSupported: GoogleAdMob.showAdMobRewardedAd.isSupported,
1161
+ /** env */
1162
+ getDeploymentId: env.getDeploymentId
446
1163
  },
447
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
448
- // @ts-expect-error
449
1164
  asyncHandlerMap: {
450
1165
  ...bedrockAsyncBridges,
451
- ...async_bridges_exports
1166
+ ...async_bridges_exports,
1167
+ /** internal */
1168
+ openPermissionDialog: AppsInTossModule.openPermissionDialog,
1169
+ /** Storage */
1170
+ getStorageItem: Storage.getItem,
1171
+ setStorageItem: Storage.setItem,
1172
+ removeStorageItem: Storage.removeItem,
1173
+ clearItems: Storage.clearItems
452
1174
  }
453
1175
  });
454
- const baseProps = useMemo(() => {
1176
+ const baseProps = useMemo3(() => {
455
1177
  switch (type) {
456
1178
  case "partner": {
457
- return {
1179
+ const headerOnlyProp = {
458
1180
  header: {
459
- ...props.header,
460
- icon: toIcon(appsInTossGlobals.brandIcon),
461
- title: appsInTossGlobals.brandDisplayName,
1181
+ ..."header" in props ? props.header : {},
1182
+ icon: toIcon(ensureValue(appsInTossGlobals.brandIcon, "icon")),
1183
+ title: ensureValue(appsInTossGlobals.brandDisplayName, "displayName"),
462
1184
  rightButtons: void 0
463
1185
  // TODO: onClick 이벤트를 받아야 하기에 런타임에서 설정 받아야 함
464
1186
  }
465
1187
  };
1188
+ return headerOnlyProp;
466
1189
  }
467
1190
  case "external": {
468
- return {
1191
+ const headerOnlyProp = {
469
1192
  header: {
470
- ...props.header,
471
- icon: toIcon(appsInTossGlobals.brandIcon),
472
- title: appsInTossGlobals.brandDisplayName
1193
+ ..."header" in props ? props.header : {},
1194
+ icon: toIcon(ensureValue(appsInTossGlobals.brandIcon, "icon")),
1195
+ title: ensureValue(appsInTossGlobals.brandDisplayName, "displayName")
473
1196
  }
474
1197
  };
1198
+ return headerOnlyProp;
475
1199
  }
476
1200
  default: {
477
1201
  return {};
@@ -479,31 +1203,43 @@ function WebView({ type, local, onMessage, ...props }) {
479
1203
  }
480
1204
  }, [type, props]);
481
1205
  const BaseWebView = WEBVIEW_TYPES[type];
1206
+ const webViewDebuggingEnabled = operationalEnvironment === "sandbox";
1207
+ const handleNavigationStateChange = useCallback3((event) => {
1208
+ if (event.url) {
1209
+ trackScreen(event.url);
1210
+ }
1211
+ }, []);
482
1212
  return /* @__PURE__ */ jsx5(
483
1213
  BaseWebView,
484
1214
  {
485
1215
  ref: handler.ref,
486
- ...baseProps,
487
1216
  ...props,
1217
+ ...baseProps,
488
1218
  source: { uri },
489
1219
  sharedCookiesEnabled: true,
1220
+ webviewDebuggingEnabled: webViewDebuggingEnabled,
490
1221
  thirdPartyCookiesEnabled: true,
491
- cacheEnabled: false,
492
- cacheMode: "LOAD_NO_CACHE",
493
1222
  onMessage: handler.onMessage,
1223
+ onNavigationStateChange: handleNavigationStateChange,
494
1224
  injectedJavaScript: handler.injectedJavaScript,
495
1225
  injectedJavaScriptBeforeContentLoaded: handler.injectedJavaScript
496
1226
  }
497
1227
  );
498
1228
  }
1229
+ function ensureValue(value, name) {
1230
+ if (value === void 0) {
1231
+ throw new Error(`${name} is required`);
1232
+ }
1233
+ return value;
1234
+ }
499
1235
 
500
1236
  // src/hooks/useGeolocation.ts
501
- import { useState, useEffect as useEffect2 } from "react";
1237
+ import { useState, useEffect as useEffect4 } from "react";
502
1238
  import { useVisibility } from "react-native-bedrock";
503
1239
  function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
504
1240
  const isVisible = useVisibility();
505
1241
  const [location, setLocation] = useState(null);
506
- useEffect2(() => {
1242
+ useEffect4(() => {
507
1243
  if (!isVisible) {
508
1244
  return;
509
1245
  }
@@ -530,18 +1266,36 @@ var Accuracy2 = /* @__PURE__ */ ((Accuracy3) => {
530
1266
  Accuracy3[Accuracy3["BestForNavigation"] = 6] = "BestForNavigation";
531
1267
  return Accuracy3;
532
1268
  })(Accuracy2 || {});
1269
+
1270
+ // src/index.ts
1271
+ export * from "@apps-in-toss/analytics";
1272
+ var Analytics2 = {
1273
+ init: InternalAnalytics.init,
1274
+ Impression: InternalAnalytics.Impression,
1275
+ Press: InternalAnalytics.Press,
1276
+ Area: InternalAnalytics.Area
1277
+ };
533
1278
  export {
534
1279
  Accuracy2 as Accuracy,
1280
+ Analytics2 as Analytics,
535
1281
  AppsInToss,
1282
+ GoogleAdMob,
1283
+ Storage,
536
1284
  TossPay,
537
1285
  WebView,
538
1286
  appLogin,
1287
+ appsInTossEvent,
539
1288
  env,
1289
+ eventLog,
540
1290
  fetchAlbumPhotos,
541
1291
  fetchContacts,
542
1292
  getClipboardText,
543
1293
  getCurrentLocation,
1294
+ getDeviceId,
544
1295
  getOperationalEnvironment,
1296
+ getTossAppVersion,
1297
+ getTossShareLink,
1298
+ isMinVersionSupported,
545
1299
  openCamera,
546
1300
  setClipboardText,
547
1301
  startUpdateLocation,