@apps-in-toss/framework 0.0.13 → 0.0.15
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.cjs +251 -32
- package/dist/index.d.cts +424 -7
- package/dist/index.d.ts +424 -7
- package/dist/index.js +246 -25
- package/dist/plugins/index.cjs +344 -308
- package/dist/plugins/index.d.cts +23 -3
- package/dist/plugins/index.d.ts +23 -3
- package/dist/plugins/index.js +350 -317
- package/package.json +8 -8
- package/src/async-bridges.ts +2 -0
package/dist/index.cjs
CHANGED
|
@@ -32,6 +32,7 @@ var src_exports = {};
|
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
Accuracy: () => Accuracy2,
|
|
34
34
|
AppsInToss: () => AppsInToss,
|
|
35
|
+
TossPay: () => TossPay,
|
|
35
36
|
WebView: () => WebView,
|
|
36
37
|
appLogin: () => appLogin,
|
|
37
38
|
env: () => env,
|
|
@@ -48,10 +49,49 @@ __export(src_exports, {
|
|
|
48
49
|
module.exports = __toCommonJS(src_exports);
|
|
49
50
|
|
|
50
51
|
// src/core/registerApp.tsx
|
|
52
|
+
var import_react_native2 = require("@toss-design-system/react-native");
|
|
51
53
|
var import_react_native_bedrock = require("react-native-bedrock");
|
|
54
|
+
|
|
55
|
+
// src/core/hooks/useAppsInTossBridge.ts
|
|
56
|
+
var import_react_native = require("@toss-design-system/react-native");
|
|
57
|
+
var import_react = require("react");
|
|
58
|
+
|
|
59
|
+
// src/core/utils/getAppsInTossGlobals.ts
|
|
60
|
+
function getAppsInTossGlobals() {
|
|
61
|
+
if (global.__appsInToss == null) {
|
|
62
|
+
throw new Error("invalid apps-in-toss globals");
|
|
63
|
+
}
|
|
64
|
+
return global.__appsInToss;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/core/utils/toIcon.ts
|
|
68
|
+
function toIcon(source) {
|
|
69
|
+
return source.startsWith("http") ? { source: { uri: source } } : { name: source };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/core/hooks/useAppsInTossBridge.ts
|
|
73
|
+
function useAppsInTossBridge() {
|
|
74
|
+
const controller = (0, import_react_native.useBridge)();
|
|
75
|
+
const appsInTossGlobals2 = getAppsInTossGlobals();
|
|
76
|
+
(0, import_react.useEffect)(() => {
|
|
77
|
+
const commonProps = {
|
|
78
|
+
serviceName: appsInTossGlobals2.brandDisplayName,
|
|
79
|
+
icon: toIcon(appsInTossGlobals2.brandIcon),
|
|
80
|
+
color: appsInTossGlobals2.brandPrimaryColor,
|
|
81
|
+
colorMode: appsInTossGlobals2.brandBridgeColorMode
|
|
82
|
+
};
|
|
83
|
+
controller.open({ ...commonProps });
|
|
84
|
+
}, []);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/core/registerApp.tsx
|
|
52
88
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
53
89
|
function AppsInTossContainer(Container, { children, ...initialProps }) {
|
|
54
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Container, { ...initialProps, children });
|
|
90
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Container, { ...initialProps, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TDSProvider, { colorPreference: "light", token: { color: { primary: getAppsInTossGlobals().brandPrimaryColor } }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TDSContainer, { ...initialProps, children }) }) });
|
|
91
|
+
}
|
|
92
|
+
function TDSContainer({ children }) {
|
|
93
|
+
useAppsInTossBridge();
|
|
94
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
55
95
|
}
|
|
56
96
|
function registerApp(container, { context }) {
|
|
57
97
|
return import_react_native_bedrock.Bedrock.registerApp(AppsInTossContainer.bind(null, container), {
|
|
@@ -80,8 +120,8 @@ var import_react_native_bedrock3 = require("react-native-bedrock");
|
|
|
80
120
|
var import_react_native_bedrock2 = require("react-native-bedrock");
|
|
81
121
|
|
|
82
122
|
// src/native-modules/AppsInTossModule.ts
|
|
83
|
-
var
|
|
84
|
-
var AppsInTossModuleInstance =
|
|
123
|
+
var import_react_native3 = require("react-native");
|
|
124
|
+
var AppsInTossModuleInstance = import_react_native3.NativeModules.AppsInTossModule;
|
|
85
125
|
var AppsInTossModule = AppsInTossModuleInstance;
|
|
86
126
|
|
|
87
127
|
// src/native-modules/getPermission.ts
|
|
@@ -107,8 +147,8 @@ async function requestPermission(permission) {
|
|
|
107
147
|
}
|
|
108
148
|
|
|
109
149
|
// src/native-event-emitter/nativeEventEmitter.ts
|
|
110
|
-
var
|
|
111
|
-
var nativeEventEmitter = new
|
|
150
|
+
var import_react_native4 = require("react-native");
|
|
151
|
+
var nativeEventEmitter = new import_react_native4.NativeEventEmitter(AppsInTossModuleInstance);
|
|
112
152
|
|
|
113
153
|
// src/native-event-emitter/event-plugins/UpdateLocationEvent.ts
|
|
114
154
|
var UpdateLocationEvent = class extends import_react_native_bedrock2.BedrockEventDefinition {
|
|
@@ -146,6 +186,16 @@ function startUpdateLocation(eventParams) {
|
|
|
146
186
|
return appsInTossEvent.addEventListener("updateLocationEvent", eventParams);
|
|
147
187
|
}
|
|
148
188
|
|
|
189
|
+
// src/native-modules/checkoutPayment.ts
|
|
190
|
+
async function checkoutPayment(options) {
|
|
191
|
+
return AppsInTossModule.checkoutPayment(options);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/native-modules/executePayment.ts
|
|
195
|
+
async function executePayment(options) {
|
|
196
|
+
return AppsInTossModule.executePayment(options);
|
|
197
|
+
}
|
|
198
|
+
|
|
149
199
|
// src/native-modules/setClipboardText.ts
|
|
150
200
|
async function setClipboardText(text) {
|
|
151
201
|
const permissionStatus = await requestPermission({ name: "clipboard", access: "write" });
|
|
@@ -232,17 +282,140 @@ function getOperationalEnvironment() {
|
|
|
232
282
|
return AppsInTossModule.operationalEnvironment;
|
|
233
283
|
}
|
|
234
284
|
|
|
285
|
+
// src/native-modules/index.ts
|
|
286
|
+
var TossPay = {
|
|
287
|
+
checkoutPayment,
|
|
288
|
+
executePayment
|
|
289
|
+
};
|
|
290
|
+
|
|
235
291
|
// src/components/WebView.tsx
|
|
236
|
-
var
|
|
237
|
-
var
|
|
238
|
-
var
|
|
292
|
+
var import_react_native11 = require("@toss-design-system/react-native");
|
|
293
|
+
var import_react3 = require("react");
|
|
294
|
+
var import_react_native_bedrock5 = require("react-native-bedrock");
|
|
239
295
|
var bedrockAsyncBridges = __toESM(require("react-native-bedrock/async-bridges"), 1);
|
|
240
296
|
var bedrockConstantBridges = __toESM(require("react-native-bedrock/constant-bridges"), 1);
|
|
241
297
|
|
|
298
|
+
// src/components/GameWebView.tsx
|
|
299
|
+
var import_react_native_webview = require("@react-native-bedrock/native/react-native-webview");
|
|
300
|
+
var import_react2 = require("react");
|
|
301
|
+
var import_react_native10 = require("react-native");
|
|
302
|
+
var import_react_native_bedrock4 = require("react-native-bedrock");
|
|
303
|
+
|
|
304
|
+
// src/components/GameWebViewNavigationBar/GameNavigationBar.tsx
|
|
305
|
+
var import_react_native_svg = require("@react-native-bedrock/native/react-native-svg");
|
|
306
|
+
var import_react_native8 = require("@toss-design-system/react-native");
|
|
307
|
+
var import_react_native9 = require("react-native");
|
|
308
|
+
|
|
309
|
+
// src/components/GameWebViewNavigationBar/HeaderRight.tsx
|
|
310
|
+
var import_react_native6 = require("react-native");
|
|
311
|
+
|
|
312
|
+
// src/components/GameWebViewNavigationBar/byPlatform.ts
|
|
313
|
+
var import_react_native5 = require("react-native");
|
|
314
|
+
function byPlatform({
|
|
315
|
+
...props
|
|
316
|
+
}) {
|
|
317
|
+
return (props[import_react_native5.Platform.OS] ?? props.fallback)();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// src/components/GameWebViewNavigationBar/constants.ts
|
|
321
|
+
var RIGHT_MARGIN = 24;
|
|
322
|
+
var IOS_DEFAULT_MARGIN = 20;
|
|
323
|
+
|
|
324
|
+
// src/components/GameWebViewNavigationBar/HeaderRight.tsx
|
|
325
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
326
|
+
function IOSHeaderRight(props) {
|
|
327
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native6.View, { style: styles.ios, ...props });
|
|
328
|
+
}
|
|
329
|
+
function AndroidHeaderRight(props) {
|
|
330
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native6.View, { style: styles.android, ...props });
|
|
331
|
+
}
|
|
332
|
+
function HeaderRight(props) {
|
|
333
|
+
return byPlatform({
|
|
334
|
+
ios: () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IOSHeaderRight, { ...props }),
|
|
335
|
+
android: () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AndroidHeaderRight, { ...props }),
|
|
336
|
+
fallback: () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(IOSHeaderRight, { ...props })
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
var styles = import_react_native6.StyleSheet.create({
|
|
340
|
+
ios: {
|
|
341
|
+
marginRight: -IOS_DEFAULT_MARGIN + RIGHT_MARGIN,
|
|
342
|
+
flexDirection: "row"
|
|
343
|
+
},
|
|
344
|
+
android: {
|
|
345
|
+
flexDirection: "row"
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// src/components/GameWebViewNavigationBar/useSafeAreaTop.ts
|
|
350
|
+
var import_react_native_safe_area_context = require("@react-native-bedrock/native/react-native-safe-area-context");
|
|
351
|
+
var import_react_native7 = require("react-native");
|
|
352
|
+
function useSafeAreaTop() {
|
|
353
|
+
const safeAreaInsets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
|
|
354
|
+
const hasDynamicIsland = import_react_native7.Platform.OS === "ios" && safeAreaInsets.top > 50;
|
|
355
|
+
const safeAreaTop = hasDynamicIsland ? safeAreaInsets.top - 5 : safeAreaInsets.top;
|
|
356
|
+
return safeAreaTop;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/components/GameWebViewNavigationBar/GameNavigationBar.tsx
|
|
360
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
361
|
+
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>';
|
|
362
|
+
function GameNavigationBar({ onClose }) {
|
|
363
|
+
const safeAreaTop = useSafeAreaTop();
|
|
364
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
365
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native8.PageNavbar, { preference: { type: "none" } }),
|
|
366
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
367
|
+
import_react_native9.View,
|
|
368
|
+
{
|
|
369
|
+
style: {
|
|
370
|
+
width: "100%",
|
|
371
|
+
height: import_react_native9.Platform.OS === "ios" ? 44 : 54,
|
|
372
|
+
flexDirection: "row",
|
|
373
|
+
alignItems: "center",
|
|
374
|
+
justifyContent: "flex-end",
|
|
375
|
+
position: "absolute",
|
|
376
|
+
zIndex: 9999,
|
|
377
|
+
marginTop: safeAreaTop,
|
|
378
|
+
paddingRight: import_react_native9.Platform.OS === "ios" ? 10 : 8
|
|
379
|
+
},
|
|
380
|
+
pointerEvents: "box-none",
|
|
381
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(HeaderRight, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
382
|
+
import_react_native9.TouchableOpacity,
|
|
383
|
+
{
|
|
384
|
+
hitSlop: { left: 8, right: 8 },
|
|
385
|
+
style: {
|
|
386
|
+
padding: import_react_native9.Platform.OS === "ios" ? 7 : 9
|
|
387
|
+
},
|
|
388
|
+
onPress: onClose,
|
|
389
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_svg.SvgXml, { xml: originXML, width: 30, height: 30 })
|
|
390
|
+
}
|
|
391
|
+
) })
|
|
392
|
+
}
|
|
393
|
+
)
|
|
394
|
+
] });
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// src/components/GameWebView.tsx
|
|
398
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
399
|
+
var GameWebView = (0, import_react2.forwardRef)(function GameWebView2(props, ref) {
|
|
400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
401
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
402
|
+
GameNavigationBar,
|
|
403
|
+
{
|
|
404
|
+
onClose: () => {
|
|
405
|
+
(0, import_react_native_bedrock4.closeView)();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
),
|
|
409
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native10.View, { style: { flex: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_webview.WebView, { ref, ...props }) })
|
|
410
|
+
] });
|
|
411
|
+
});
|
|
412
|
+
|
|
242
413
|
// src/async-bridges.ts
|
|
243
414
|
var async_bridges_exports = {};
|
|
244
415
|
__export(async_bridges_exports, {
|
|
245
416
|
appLogin: () => appLogin,
|
|
417
|
+
checkoutPayment: () => checkoutPayment,
|
|
418
|
+
executePayment: () => executePayment,
|
|
246
419
|
fetchAlbumPhotos: () => fetchAlbumPhotos,
|
|
247
420
|
fetchContacts: () => fetchContacts,
|
|
248
421
|
getClipboardText: () => getClipboardText,
|
|
@@ -269,20 +442,38 @@ __export(event_bridges_exports, {
|
|
|
269
442
|
});
|
|
270
443
|
|
|
271
444
|
// src/components/WebView.tsx
|
|
272
|
-
var
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
445
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
446
|
+
var appsInTossGlobals = getAppsInTossGlobals();
|
|
447
|
+
var WEBVIEW_TYPES = {
|
|
448
|
+
partner: import_react_native11.PartnerWebViewScreen,
|
|
449
|
+
external: import_react_native11.ExternalWebViewScreen,
|
|
450
|
+
game: GameWebView
|
|
451
|
+
};
|
|
452
|
+
function mergeSchemeQueryParamsInto(url) {
|
|
453
|
+
const baseUrl = new URL(url);
|
|
454
|
+
const schemeUrl = new URL((0, import_react_native_bedrock5.getSchemeUri)());
|
|
455
|
+
baseUrl.pathname = schemeUrl.pathname;
|
|
456
|
+
for (const [key, value] of schemeUrl.searchParams.entries()) {
|
|
457
|
+
baseUrl.searchParams.set(key, value);
|
|
458
|
+
}
|
|
459
|
+
return baseUrl;
|
|
460
|
+
}
|
|
461
|
+
function getWebViewUri(local) {
|
|
462
|
+
if (__DEV__) {
|
|
463
|
+
const devUrl = `http://${local.host}:${local.port}`;
|
|
464
|
+
return mergeSchemeQueryParamsInto(devUrl).toString();
|
|
465
|
+
}
|
|
466
|
+
const { url: rawUrl } = AppsInTossModule.getWebBundleURL({});
|
|
467
|
+
const url = mergeSchemeQueryParamsInto(rawUrl);
|
|
468
|
+
const deploymentId = env.getDeploymentId();
|
|
469
|
+
if (deploymentId) {
|
|
470
|
+
url.searchParams.set("_deploymentId", deploymentId);
|
|
471
|
+
}
|
|
472
|
+
return url.toString();
|
|
473
|
+
}
|
|
474
|
+
function WebView({ type, local, onMessage, ...props }) {
|
|
475
|
+
const uri = (0, import_react3.useMemo)(() => getWebViewUri(local), [local]);
|
|
476
|
+
const handler = (0, import_react_native_bedrock5.useBridgeHandler)({
|
|
286
477
|
onMessage,
|
|
287
478
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
288
479
|
eventListenerMap: event_bridges_exports,
|
|
@@ -299,14 +490,41 @@ function WebView({ local, onMessage, ...props }) {
|
|
|
299
490
|
...async_bridges_exports
|
|
300
491
|
}
|
|
301
492
|
});
|
|
302
|
-
|
|
303
|
-
|
|
493
|
+
const baseProps = (0, import_react3.useMemo)(() => {
|
|
494
|
+
switch (type) {
|
|
495
|
+
case "partner": {
|
|
496
|
+
return {
|
|
497
|
+
header: {
|
|
498
|
+
...props.header,
|
|
499
|
+
icon: toIcon(appsInTossGlobals.brandIcon),
|
|
500
|
+
title: appsInTossGlobals.brandDisplayName,
|
|
501
|
+
rightButtons: void 0
|
|
502
|
+
// TODO: onClick 이벤트를 받아야 하기에 런타임에서 설정 받아야 함
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
case "external": {
|
|
507
|
+
return {
|
|
508
|
+
header: {
|
|
509
|
+
...props.header,
|
|
510
|
+
icon: toIcon(appsInTossGlobals.brandIcon),
|
|
511
|
+
title: appsInTossGlobals.brandDisplayName
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
default: {
|
|
516
|
+
return {};
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}, [type, props]);
|
|
520
|
+
const BaseWebView = WEBVIEW_TYPES[type];
|
|
521
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
522
|
+
BaseWebView,
|
|
304
523
|
{
|
|
305
524
|
ref: handler.ref,
|
|
525
|
+
...baseProps,
|
|
306
526
|
...props,
|
|
307
|
-
source: {
|
|
308
|
-
uri
|
|
309
|
-
},
|
|
527
|
+
source: { uri },
|
|
310
528
|
sharedCookiesEnabled: true,
|
|
311
529
|
thirdPartyCookiesEnabled: true,
|
|
312
530
|
cacheEnabled: false,
|
|
@@ -319,12 +537,12 @@ function WebView({ local, onMessage, ...props }) {
|
|
|
319
537
|
}
|
|
320
538
|
|
|
321
539
|
// src/hooks/useGeolocation.ts
|
|
322
|
-
var
|
|
323
|
-
var
|
|
540
|
+
var import_react4 = require("react");
|
|
541
|
+
var import_react_native_bedrock6 = require("react-native-bedrock");
|
|
324
542
|
function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
|
|
325
|
-
const isVisible = (0,
|
|
326
|
-
const [location, setLocation] = (0,
|
|
327
|
-
(0,
|
|
543
|
+
const isVisible = (0, import_react_native_bedrock6.useVisibility)();
|
|
544
|
+
const [location, setLocation] = (0, import_react4.useState)(null);
|
|
545
|
+
(0, import_react4.useEffect)(() => {
|
|
328
546
|
if (!isVisible) {
|
|
329
547
|
return;
|
|
330
548
|
}
|
|
@@ -355,6 +573,7 @@ var Accuracy2 = /* @__PURE__ */ ((Accuracy3) => {
|
|
|
355
573
|
0 && (module.exports = {
|
|
356
574
|
Accuracy,
|
|
357
575
|
AppsInToss,
|
|
576
|
+
TossPay,
|
|
358
577
|
WebView,
|
|
359
578
|
appLogin,
|
|
360
579
|
env,
|