@apps-in-toss/framework 2.9.3 → 2.10.1

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
@@ -1329,7 +1329,7 @@ function AppTitle({ title, iconUrl, theme = "light" }) {
1329
1329
  }
1330
1330
  }
1331
1331
  ),
1332
- /* @__PURE__ */ jsx13(
1332
+ title != null && /* @__PURE__ */ jsx13(
1333
1333
  Text,
1334
1334
  {
1335
1335
  numberOfLines: 1,
@@ -1445,6 +1445,10 @@ function DefaultNavigationBar() {
1445
1445
  const parsedNavigationBar = globals.navigationBar != null ? safeParseNavigationBar(globals.navigationBar) : null;
1446
1446
  const withHomeButton = parsedNavigationBar?.withHomeButton ?? false;
1447
1447
  const withBackButton = parsedNavigationBar?.withBackButton ?? true;
1448
+ const withIcon = parsedNavigationBar?.withIcon ?? true;
1449
+ const withTitle = parsedNavigationBar?.withTitle ?? true;
1450
+ const iconURL = withIcon ? globals.brandIcon : void 0;
1451
+ const title = withTitle ? globals.brandDisplayName : void 0;
1448
1452
  const theme = parsedNavigationBar?.theme ?? "light";
1449
1453
  const { navigationRightButton } = useNavigationBarContext();
1450
1454
  const navigationEvent = useNavigationEvent();
@@ -1453,7 +1457,7 @@ function DefaultNavigationBar() {
1453
1457
  TopNavigation,
1454
1458
  {
1455
1459
  left: withBackButton ? /* @__PURE__ */ jsx16(BackButton, { theme, onPress: navigationEvent.handleBack }) : null,
1456
- center: withHomeButton ? /* @__PURE__ */ jsx16(HomeButton, { theme, onPress: navigationEvent.handleHomeButtonClick, children: /* @__PURE__ */ jsx16(AppTitle, { theme, title: globals.brandDisplayName, iconUrl: globals.brandIcon }) }) : /* @__PURE__ */ jsx16(AppTitle, { theme, title: globals.brandDisplayName, iconUrl: globals.brandIcon }),
1460
+ center: title || iconURL ? withHomeButton ? /* @__PURE__ */ jsx16(HomeButton, { theme, onPress: navigationEvent.handleHomeButtonClick, children: /* @__PURE__ */ jsx16(AppTitle, { theme, title, iconUrl: iconURL }) }) : /* @__PURE__ */ jsx16(AppTitle, { theme, title, iconUrl: iconURL }) : null,
1457
1461
  right: /* @__PURE__ */ jsx16(
1458
1462
  Menu2,
1459
1463
  {
@@ -1625,6 +1629,7 @@ import {
1625
1629
  IAP,
1626
1630
  Storage,
1627
1631
  appsInTossEvent,
1632
+ getDeclaredAgeRange,
1628
1633
  getServerTime,
1629
1634
  requestReview,
1630
1635
  requestNotificationAgreement,
@@ -1731,6 +1736,10 @@ function PartnerWebviewNavigationBar({ onBackButtonClick, onHomeButtonClick }) {
1731
1736
  const parsedNavigationBar = globals.navigationBar != null ? safeParseNavigationBar(globals.navigationBar) : null;
1732
1737
  const withHomeButton = parsedNavigationBar?.withHomeButton ?? false;
1733
1738
  const withBackButton = parsedNavigationBar?.withBackButton ?? true;
1739
+ const withIcon = parsedNavigationBar?.withIcon ?? true;
1740
+ const withTitle = parsedNavigationBar?.withTitle ?? true;
1741
+ const iconURL = withIcon ? globals.brandIcon : void 0;
1742
+ const title = withTitle ? globals.brandDisplayName : void 0;
1734
1743
  const theme = parsedNavigationBar?.theme ?? "light";
1735
1744
  const { navigationRightButton } = useNavigationBarContext();
1736
1745
  const handleClose = useCallback8(async () => {
@@ -1741,7 +1750,7 @@ function PartnerWebviewNavigationBar({ onBackButtonClick, onHomeButtonClick }) {
1741
1750
  TopNavigation,
1742
1751
  {
1743
1752
  left: withBackButton ? /* @__PURE__ */ jsx22(BackButton, { theme, onPress: onBackButtonClick }) : null,
1744
- center: withHomeButton ? /* @__PURE__ */ jsx22(HomeButton, { theme, onPress: onHomeButtonClick, children: /* @__PURE__ */ jsx22(AppTitle, { theme, title: globals.brandDisplayName, iconUrl: globals.brandIcon }) }) : /* @__PURE__ */ jsx22(AppTitle, { theme, title: globals.brandDisplayName, iconUrl: globals.brandIcon }),
1753
+ center: title || iconURL ? withHomeButton ? /* @__PURE__ */ jsx22(HomeButton, { theme, onPress: onHomeButtonClick, children: /* @__PURE__ */ jsx22(AppTitle, { theme, title, iconUrl: iconURL }) }) : /* @__PURE__ */ jsx22(AppTitle, { theme, title, iconUrl: iconURL }) : null,
1745
1754
  right: /* @__PURE__ */ jsx22(
1746
1755
  Menu2,
1747
1756
  {
@@ -1777,7 +1786,7 @@ function convertIntentURL(url) {
1777
1786
  return `${scheme}://${url.hostname}${url.pathname}${url.search}`;
1778
1787
  }
1779
1788
 
1780
- // src/ads/fetchTossAd.ts
1789
+ // src/ads/fetchAppsInTossAd.ts
1781
1790
  import {
1782
1791
  getOperationalEnvironment as getOperationalEnvironment6,
1783
1792
  INTERNAL__appBridgeHandler as INTERNAL__appBridgeHandler3,
@@ -1809,14 +1818,54 @@ function generateSessionId() {
1809
1818
  // src/ads/constants.ts
1810
1819
  var sessionId = generateSessionId();
1811
1820
 
1821
+ // src/ads/fetchAppsInTossAd.ts
1822
+ var ANDROID_SUPPORTED_VERSION = "5.264.0";
1823
+ var IOS_SUPPORTED_VERSION = "5.264.0";
1824
+ var APP_BRIDGE_METHOD_NAME2 = "fetchAppsInTossAd";
1825
+ var UNSUPPORTED_ERROR_MESSAGE = "This feature is not supported in the current environment";
1826
+ function fetchAppsInTossAd(params) {
1827
+ const { body, onEvent, onError } = params;
1828
+ if (!fetchAppsInTossAd.isSupported()) {
1829
+ onError(new Error(UNSUPPORTED_ERROR_MESSAGE));
1830
+ return noop;
1831
+ }
1832
+ const spaceUnitId = normalizeAdGroupId(body.spaceUnitId);
1833
+ if (spaceUnitId.length === 0) {
1834
+ onError(createInvalidAdGroupIdError());
1835
+ return noop;
1836
+ }
1837
+ return INTERNAL__appBridgeHandler3.invokeAppBridgeMethod(
1838
+ APP_BRIDGE_METHOD_NAME2,
1839
+ { ...body, spaceUnitId, sessionId: body.sessionId ?? sessionId },
1840
+ {
1841
+ onSuccess: onEvent,
1842
+ onError
1843
+ }
1844
+ );
1845
+ }
1846
+ fetchAppsInTossAd.isSupported = () => {
1847
+ if (getOperationalEnvironment6() !== "toss") {
1848
+ return false;
1849
+ }
1850
+ return isMinVersionSupported4({
1851
+ android: ANDROID_SUPPORTED_VERSION,
1852
+ ios: IOS_SUPPORTED_VERSION
1853
+ });
1854
+ };
1855
+
1812
1856
  // src/ads/fetchTossAd.ts
1857
+ import {
1858
+ getOperationalEnvironment as getOperationalEnvironment7,
1859
+ INTERNAL__appBridgeHandler as INTERNAL__appBridgeHandler4,
1860
+ isMinVersionSupported as isMinVersionSupported5
1861
+ } from "@apps-in-toss/native-modules";
1813
1862
  var ANDROID_FETCH_TOSS_AD_SUPPORTED_VERSION = "5.241.0";
1814
1863
  var IOS_FETCH_TOSS_AD_SUPPORTED_VERSION = "5.241.0";
1815
- var UNSUPPORTED_ERROR_MESSAGE = "This feature is not supported in the current environment";
1816
- var ENVIRONMENT = getOperationalEnvironment6();
1864
+ var UNSUPPORTED_ERROR_MESSAGE2 = "This feature is not supported in the current environment";
1865
+ var ENVIRONMENT = getOperationalEnvironment7();
1817
1866
  function fetchTossAd(params) {
1818
1867
  if (!fetchTossAd.isSupported()) {
1819
- params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE));
1868
+ params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE2));
1820
1869
  return noop;
1821
1870
  }
1822
1871
  const { onEvent, onError, options } = params;
@@ -1826,7 +1875,7 @@ function fetchTossAd(params) {
1826
1875
  return noop;
1827
1876
  }
1828
1877
  const wireHeaders = options.headers;
1829
- const unregisterCallbacks = INTERNAL__appBridgeHandler3.invokeAppBridgeMethod(
1878
+ const unregisterCallbacks = INTERNAL__appBridgeHandler4.invokeAppBridgeMethod(
1830
1879
  "fetchTossAd",
1831
1880
  {
1832
1881
  spaceUnitId: adGroupId,
@@ -1850,14 +1899,14 @@ fetchTossAd.isSupported = () => {
1850
1899
  if (ENVIRONMENT !== "toss") {
1851
1900
  return false;
1852
1901
  }
1853
- return isMinVersionSupported4({
1902
+ return isMinVersionSupported5({
1854
1903
  android: ANDROID_FETCH_TOSS_AD_SUPPORTED_VERSION,
1855
1904
  ios: IOS_FETCH_TOSS_AD_SUPPORTED_VERSION
1856
1905
  });
1857
1906
  };
1858
1907
 
1859
1908
  // src/ads/integratedAd.ts
1860
- import { GoogleAdMob, INTERNAL__appBridgeHandler as INTERNAL__appBridgeHandler4, isMinVersionSupported as isMinVersionSupported5 } from "@apps-in-toss/native-modules";
1909
+ import { GoogleAdMob, INTERNAL__appBridgeHandler as INTERNAL__appBridgeHandler5, isMinVersionSupported as isMinVersionSupported6 } from "@apps-in-toss/native-modules";
1861
1910
 
1862
1911
  // src/ads/generateRequestId.ts
1863
1912
  function generateRequestId() {
@@ -1877,7 +1926,7 @@ function getReferrer() {
1877
1926
  }
1878
1927
 
1879
1928
  // src/ads/remotes.ts
1880
- import { getOperationalEnvironment as getOperationalEnvironment7, getPlatformOS, getTossAppVersion } from "@apps-in-toss/native-modules";
1929
+ import { getOperationalEnvironment as getOperationalEnvironment8, getPlatformOS, getTossAppVersion } from "@apps-in-toss/native-modules";
1881
1930
 
1882
1931
  // src/ads/getIsDev.ts
1883
1932
  import { getSchemeUri as getSchemeUri7 } from "@granite-js/react-native";
@@ -1890,7 +1939,7 @@ function getIsDev() {
1890
1939
  }
1891
1940
 
1892
1941
  // src/ads/remotes.ts
1893
- var OPERATIONAL_ENVIRONMENT = getOperationalEnvironment7();
1942
+ var OPERATIONAL_ENVIRONMENT = getOperationalEnvironment8();
1894
1943
  var OS = getPlatformOS();
1895
1944
  var APP_VER = getTossAppVersion();
1896
1945
  var ALPHA_EVENT_TRACKER_HTTP_ENDPOINT = "https://alpha-trillion.toss.im/trk/sdk-mediation/event";
@@ -1924,10 +1973,10 @@ function postEventTracking(params) {
1924
1973
  var INTEGRATED_AD_SDK_VERSION = "0.0.0";
1925
1974
  var ANDROID_INTEGRATED_AD_SUPPORTED_VERSION = "5.247.0";
1926
1975
  var IOS_INTEGRATED_AD_SUPPORTED_VERSION = "5.247.0";
1927
- var UNSUPPORTED_ERROR_MESSAGE2 = "This feature is not supported in the current environment";
1976
+ var UNSUPPORTED_ERROR_MESSAGE3 = "This feature is not supported in the current environment";
1928
1977
  var INTG_AD_ADM_FALLBACK_RID_MAP = {};
1929
1978
  function integratedAdIsSupported() {
1930
- return isMinVersionSupported5({
1979
+ return isMinVersionSupported6({
1931
1980
  android: ANDROID_INTEGRATED_AD_SUPPORTED_VERSION,
1932
1981
  ios: IOS_INTEGRATED_AD_SUPPORTED_VERSION
1933
1982
  });
@@ -1935,7 +1984,7 @@ function integratedAdIsSupported() {
1935
1984
  function generateLoadFullScreenAd(sdkId) {
1936
1985
  const fn = (params) => {
1937
1986
  if (!GoogleAdMob.loadAppsInTossAdMob.isSupported()) {
1938
- params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE2));
1987
+ params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE3));
1939
1988
  return noop;
1940
1989
  }
1941
1990
  const normalizedAdGroupId = normalizeAdGroupId(params.options.adGroupId);
@@ -1993,7 +2042,7 @@ function generateLoadFullScreenAd(sdkId) {
1993
2042
  const { adGroupId } = options;
1994
2043
  const referrer = getReferrer();
1995
2044
  const wireHeaders = options.headers;
1996
- const unregisterCallbacks = INTERNAL__appBridgeHandler4.invokeAppBridgeMethod(
2045
+ const unregisterCallbacks = INTERNAL__appBridgeHandler5.invokeAppBridgeMethod(
1997
2046
  "loadTossAdOrAdmob",
1998
2047
  {
1999
2048
  spaceUnitId: adGroupId,
@@ -2020,7 +2069,7 @@ var loadFullScreenAd = generateLoadFullScreenAd("107");
2020
2069
  var loadFullScreenAdForWeb = generateLoadFullScreenAd("107");
2021
2070
  function showFullScreenAd(params) {
2022
2071
  if (!GoogleAdMob.showAppsInTossAdMob.isSupported()) {
2023
- params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE2));
2072
+ params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE3));
2024
2073
  return noop;
2025
2074
  }
2026
2075
  const normalizedAdGroupId = normalizeAdGroupId(params.options.adGroupId);
@@ -2135,7 +2184,7 @@ function showFullScreenAd(params) {
2135
2184
  const { onEvent, onError, options } = normalizedParams;
2136
2185
  const { adGroupId } = options;
2137
2186
  const referrer = getReferrer();
2138
- const unregisterCallbacks = INTERNAL__appBridgeHandler4.invokeAppBridgeMethod(
2187
+ const unregisterCallbacks = INTERNAL__appBridgeHandler5.invokeAppBridgeMethod(
2139
2188
  "showTossAdOrAdmob",
2140
2189
  { spaceUnitId: adGroupId, referrer, sessionId },
2141
2190
  {
@@ -2701,7 +2750,7 @@ function useTopNavigation() {
2701
2750
  }
2702
2751
 
2703
2752
  // src/hooks/useWebViewMemoryDebug.tsx
2704
- import { getOperationalEnvironment as getOperationalEnvironment8 } from "@apps-in-toss/native-modules";
2753
+ import { getOperationalEnvironment as getOperationalEnvironment9 } from "@apps-in-toss/native-modules";
2705
2754
  import { Granite as Granite8 } from "@granite-js/react-native";
2706
2755
  import { useToast } from "@toss/tds-react-native";
2707
2756
  function useHandleWebViewProcessDidTerminate(webViewRef) {
@@ -2729,7 +2778,7 @@ function webViewDebugLog(logName, params) {
2729
2778
  deployment_id: global2.deploymentId
2730
2779
  }
2731
2780
  };
2732
- if (getOperationalEnvironment8() === "toss") {
2781
+ if (getOperationalEnvironment9() === "toss") {
2733
2782
  sendLog(event, { pipelines: ["core"] });
2734
2783
  } else {
2735
2784
  console.log("[webViewDebugLog]", event);
@@ -2875,6 +2924,8 @@ function WebView({ type, local, onMessage, ...props }) {
2875
2924
  showFullScreenAd,
2876
2925
  /** TossAd */
2877
2926
  fetchTossAd,
2927
+ // v1.4 배너: web 이벤트 브릿지는 payload를 options로 전달하지만 fetchAppsInTossAd는 body로 받으므로 어댑팅한다.
2928
+ fetchAppsInTossAd: ({ onEvent, onError, options }) => fetchAppsInTossAd({ body: options, onEvent, onError }),
2878
2929
  /** IAP */
2879
2930
  iapCreateOneTimePurchaseOrder: IAP.createOneTimePurchaseOrder,
2880
2931
  requestSubscriptionPurchase,
@@ -2887,6 +2938,7 @@ function WebView({ type, local, onMessage, ...props }) {
2887
2938
  ...Object.fromEntries(Object.entries(global2).map(([key, value]) => [key, () => value])),
2888
2939
  getServerTime_isSupported: getServerTime.isSupported,
2889
2940
  requestReview_isSupported: requestReview.isSupported,
2941
+ getDeclaredAgeRange_isSupported: getDeclaredAgeRange.isSupported,
2890
2942
  /** AdMobV2 */
2891
2943
  loadAppsInTossAdMob_isSupported: GoogleAdMob2.loadAppsInTossAdMob.isSupported,
2892
2944
  showAppsInTossAdMob_isSupported: GoogleAdMob2.showAppsInTossAdMob.isSupported,
@@ -2896,6 +2948,7 @@ function WebView({ type, local, onMessage, ...props }) {
2896
2948
  showFullScreenAd_isSupported: showFullScreenAd.isSupported,
2897
2949
  /** TossAd */
2898
2950
  fetchTossAd_isSupported: fetchTossAd.isSupported,
2951
+ fetchAppsInTossAd_isSupported: fetchAppsInTossAd.isSupported,
2899
2952
  /** env */
2900
2953
  getDeploymentId: env.getDeploymentId,
2901
2954
  getWebViewType: env.getWebViewType,
@@ -3159,6 +3212,159 @@ var AD_STATUS_ERROR_MAP = {
3159
3212
  }
3160
3213
  };
3161
3214
 
3215
+ // src/ads/inlineAd/errorTracking.ts
3216
+ var BANNER_ERROR_LOG_NAME = "display_ads_all::error__banner";
3217
+ var MAX_STACK_TRACE_LENGTH = 255;
3218
+ function logBannerErrorToAppLog(info) {
3219
+ void tossAdEventLog({
3220
+ log_name: BANNER_ERROR_LOG_NAME,
3221
+ log_type: "debug",
3222
+ params: {
3223
+ error_code: info.errorCode,
3224
+ error_message: info.errorMessage,
3225
+ ad_group_id: info.adGroupId,
3226
+ mediation_id: info.mediationId,
3227
+ event_context_token: info.eventContextToken
3228
+ }
3229
+ }).catch(noop);
3230
+ }
3231
+ function trackBannerError(info) {
3232
+ if (info.endpointError) {
3233
+ void fetch(info.endpointError, {
3234
+ method: "POST",
3235
+ headers: { "Content-Type": "application/json" },
3236
+ body: JSON.stringify({
3237
+ eventContextToken: info.eventContextToken,
3238
+ mediationId: info.mediationId,
3239
+ errorCode: info.errorCode,
3240
+ errorMessage: info.errorMessage,
3241
+ stackTrace: info.stackTrace?.slice(0, MAX_STACK_TRACE_LENGTH)
3242
+ })
3243
+ // POST 실패(CORS·네트워크) → 앱로그 fallback (endpoint와 같은 채널이라 함께 막히는 경우 대비).
3244
+ }).catch(() => logBannerErrorToAppLog(info));
3245
+ return;
3246
+ }
3247
+ logBannerErrorToAppLog(info);
3248
+ }
3249
+
3250
+ // src/ads/inlineAd/loadAd.ts
3251
+ import { getPlatformOS as getPlatformOS3, getTossAppVersion as getTossAppVersion3 } from "@apps-in-toss/native-modules";
3252
+
3253
+ // src/ads/fetchAppsInTossAdSchema.ts
3254
+ var APPS_IN_TOSS_AD_SPEC_VERSION = "1.4.1";
3255
+ var FETCH_APPS_IN_TOSS_AD_DEVICE_MACRO = "{{device}}";
3256
+ var TOSS_APP_BUNDLE_IDS = {
3257
+ ios: "com.vivarepublica.cash",
3258
+ android: "viva.republica.toss"
3259
+ };
3260
+ function resolveTossAppBundleId(os) {
3261
+ return TOSS_APP_BUNDLE_IDS[os];
3262
+ }
3263
+
3264
+ // package.json
3265
+ var package_default = {
3266
+ name: "@apps-in-toss/framework",
3267
+ type: "module",
3268
+ version: "2.10.1",
3269
+ description: "The framework for Apps In Toss",
3270
+ scripts: {
3271
+ typecheck: "tsc --noEmit",
3272
+ test: "vitest --no-watch",
3273
+ "test:no-parallel": "vitest --no-watch --config=vitest.no-parallel.config.mts",
3274
+ lint: "eslint .",
3275
+ build: "tsup"
3276
+ },
3277
+ main: "./dist/index.cjs",
3278
+ module: "./dist/index.js",
3279
+ types: "./dist/index.d.ts",
3280
+ exports: {
3281
+ ".": {
3282
+ types: "./dist/index.d.ts",
3283
+ import: "./dist/index.js",
3284
+ require: "./dist/index.cjs"
3285
+ },
3286
+ "./plugins": {
3287
+ types: "./dist/plugins/index.d.ts",
3288
+ import: "./dist/plugins/index.js",
3289
+ require: "./dist/plugins/index.cjs"
3290
+ },
3291
+ "./internal": {
3292
+ types: "./dist/internal.d.ts",
3293
+ import: "./dist/internal.js",
3294
+ require: "./dist/internal.cjs"
3295
+ },
3296
+ "./bridge-entry": "./src/bridge-entry.ts",
3297
+ "./bridge-meta": {
3298
+ types: "./dist/bridge-meta.d.ts",
3299
+ default: "./dist/bridge-meta.js"
3300
+ },
3301
+ "./jest": {
3302
+ types: "./dist/jest/index.d.ts",
3303
+ import: "./dist/jest/index.js",
3304
+ require: "./dist/jest/index.cjs"
3305
+ },
3306
+ "./package.json": "./package.json"
3307
+ },
3308
+ files: [
3309
+ "dist/**/*",
3310
+ "src/bridge-entry.ts",
3311
+ "src/async-bridges.ts",
3312
+ "src/constant-bridges.ts",
3313
+ "src/event-bridges.ts",
3314
+ "hermesc/**/*",
3315
+ "plugins.d.ts",
3316
+ "jest.d.ts"
3317
+ ],
3318
+ bin: {
3319
+ ait: "./bin/ait.js"
3320
+ },
3321
+ dependencies: {
3322
+ "@apps-in-toss/analytics": "workspace:*",
3323
+ "@apps-in-toss/cli": "workspace:*",
3324
+ "@apps-in-toss/native-modules": "workspace:*",
3325
+ "@apps-in-toss/plugins": "workspace:*",
3326
+ "@apps-in-toss/types": "workspace:*",
3327
+ "@apps-in-toss/user-scripts": "workspace:^",
3328
+ "es-hangul": "^2.3.2"
3329
+ },
3330
+ devDependencies: {
3331
+ "@apps-in-toss/ait-format": "1.0.0",
3332
+ "@babel/runtime": "^7",
3333
+ "@granite-js/mpack": "catalog:granite-js",
3334
+ "@granite-js/native": "catalog:granite-js",
3335
+ "@granite-js/plugin-core": "catalog:granite-js",
3336
+ "@granite-js/react-native": "catalog:granite-js",
3337
+ "@granite-js/utils": "catalog:granite-js",
3338
+ "@toss/tds-react-native": "catalog:react-native",
3339
+ "@types/kill-port": "2.0.1",
3340
+ "@types/react": "catalog:react-native",
3341
+ "brick-module": "catalog:brick-module",
3342
+ "es-toolkit": "^1.34.1",
3343
+ eslint: "^9.7.0",
3344
+ execa: "catalog:tooling",
3345
+ jsdom: "^25.0.1",
3346
+ "kill-port": "2.0.1",
3347
+ react: "catalog:react-native",
3348
+ "react-native": "catalog:react-native",
3349
+ tsup: "^8.3.5",
3350
+ typescript: "5.8.3",
3351
+ vitest: "^3.0.3",
3352
+ "workspace-tools": "^0.38.2"
3353
+ },
3354
+ peerDependencies: {
3355
+ "@granite-js/native": "*",
3356
+ "@granite-js/react-native": "*",
3357
+ "@toss/tds-react-native": ">=2.0.0",
3358
+ "@types/react": "*",
3359
+ "brick-module": "*",
3360
+ react: "*",
3361
+ "react-native": "*"
3362
+ }
3363
+ };
3364
+
3365
+ // src/ads/sdkVersion.ts
3366
+ var SDK_VERSION = package_default.version;
3367
+
3162
3368
  // src/ads/inlineAd/loadAd.ts
3163
3369
  function createError(code, message) {
3164
3370
  return {
@@ -3185,6 +3391,28 @@ function fetchTossAdPromise(options) {
3185
3391
  });
3186
3392
  });
3187
3393
  }
3394
+ function requestAd(adGroupId) {
3395
+ if (fetchAppsInTossAd.isSupported()) {
3396
+ const body = {
3397
+ specVersion: APPS_IN_TOSS_AD_SPEC_VERSION,
3398
+ platform: "RN",
3399
+ spaceUnitId: adGroupId,
3400
+ sdkVersion: SDK_VERSION,
3401
+ availableStyleIds: AVAILABLE_STYLE_IDS,
3402
+ // device는 매크로키만 보내고 native가 실제 device로 치환한다.
3403
+ device: FETCH_APPS_IN_TOSS_AD_DEVICE_MACRO,
3404
+ app: {
3405
+ version: getTossAppVersion3(),
3406
+ bundle: resolveTossAppBundleId(getPlatformOS3()),
3407
+ subBundle: global.__granite?.app?.name ?? ""
3408
+ }
3409
+ };
3410
+ return new Promise((resolve, reject) => {
3411
+ fetchAppsInTossAd({ body, onEvent: resolve, onError: reject });
3412
+ });
3413
+ }
3414
+ return fetchTossAdPromise({ adGroupId, sdkId: SDK_ID, availableStyleIds: AVAILABLE_STYLE_IDS });
3415
+ }
3188
3416
  function isApiResponse(payload) {
3189
3417
  return Boolean(payload && typeof payload === "object" && "resultType" in payload);
3190
3418
  }
@@ -3198,6 +3426,7 @@ function normalizeAdResponse(adResponse) {
3198
3426
  })).filter((ad) => AVAILABLE_STYLE_IDS.includes(String(ad.styleId))) : [];
3199
3427
  return {
3200
3428
  requestId: adResponse.requestId ?? "",
3429
+ eventContextToken: adResponse.eventContextToken ?? "",
3201
3430
  status: adResponse.status ?? "OK",
3202
3431
  ads,
3203
3432
  ext: adResponse.ext
@@ -3238,7 +3467,7 @@ async function loadAd(adGroupId) {
3238
3467
  error: createError(ERROR_CODES.INVALID_SPACE, INVALID_AD_GROUP_ID_ERROR_MESSAGE)
3239
3468
  };
3240
3469
  }
3241
- if (!fetchTossAd.isSupported()) {
3470
+ if (!fetchAppsInTossAd.isSupported() && !fetchTossAd.isSupported()) {
3242
3471
  return {
3243
3472
  type: "error",
3244
3473
  error: createError(ERROR_CODES.SDK_NOT_INITIALIZED, "This feature is not supported in the current environment")
@@ -3246,11 +3475,7 @@ async function loadAd(adGroupId) {
3246
3475
  }
3247
3476
  let response;
3248
3477
  try {
3249
- const raw = await fetchTossAdPromise({
3250
- adGroupId: normalizedAdGroupId,
3251
- sdkId: SDK_ID,
3252
- availableStyleIds: AVAILABLE_STYLE_IDS
3253
- });
3478
+ const raw = await requestAd(normalizedAdGroupId);
3254
3479
  response = normalizeApiResponse(raw);
3255
3480
  } catch (error) {
3256
3481
  if (isAdError(error)) {
@@ -3352,6 +3577,162 @@ function supertossWeb(uri) {
3352
3577
  return `supertoss://web?url=${encodeURIComponent(uri)}&external=true`;
3353
3578
  }
3354
3579
 
3580
+ // src/ads/inlineAd/renderConfig.ts
3581
+ var listBannerPalette = {
3582
+ "1": {
3583
+ light: {
3584
+ title: "#4e5968",
3585
+ subtitle: "#6b7684",
3586
+ adClearance: "#b0b8c1",
3587
+ iconBg: "rgba(2,32,71,0.05)",
3588
+ iconBorder: "rgba(2,32,71,0.05)"
3589
+ },
3590
+ dark: {
3591
+ title: "rgba(253,253,255,0.75)",
3592
+ subtitle: "rgba(248,248,255,0.6)",
3593
+ adClearance: "rgba(242,242,255,0.47)",
3594
+ iconBg: "#ffffff",
3595
+ iconBorder: "rgba(217,217,255,0.11)"
3596
+ }
3597
+ },
3598
+ "2": {
3599
+ light: {
3600
+ title: "#4e5968",
3601
+ subtitle: "#6b7684",
3602
+ adClearance: "#b0b8c1",
3603
+ iconBg: "rgba(2,32,71,0.05)",
3604
+ iconBorder: "rgba(2,32,71,0.05)"
3605
+ },
3606
+ dark: {
3607
+ title: "rgba(253,253,255,0.75)",
3608
+ subtitle: "rgba(248,248,255,0.6)",
3609
+ adClearance: "rgba(242,242,255,0.47)",
3610
+ iconBg: "rgba(217,217,255,0.11)",
3611
+ iconBorder: "rgba(217,217,255,0.11)"
3612
+ }
3613
+ }
3614
+ };
3615
+ var feedBannerPalette = {
3616
+ "1": {
3617
+ light: {
3618
+ brandLogoBg: "rgba(2,32,71,0.05)",
3619
+ brandLogoBorder: "rgba(2,32,71,0.05)",
3620
+ brandName: "#6b7684",
3621
+ adBadge: "#8b95a1",
3622
+ title: "#333d4b",
3623
+ subtitle: "#4e5968",
3624
+ adClearance: "#8b95a1",
3625
+ imageOverlayBorder: "rgba(2,32,71,0.05)"
3626
+ },
3627
+ dark: {
3628
+ brandLogoBg: "#ffffff",
3629
+ brandLogoBorder: "rgba(217,217,255,0.11)",
3630
+ brandName: "#9e9ea4",
3631
+ adBadge: "#7e7e87",
3632
+ title: "#e4e4e5",
3633
+ subtitle: "#c3c3c6",
3634
+ adClearance: "#7e7e87",
3635
+ imageOverlayBorder: "rgba(217,217,255,0.11)"
3636
+ }
3637
+ },
3638
+ "2": {
3639
+ light: {
3640
+ brandLogoBg: "rgba(2,32,71,0.05)",
3641
+ brandLogoBorder: "rgba(2,32,71,0.05)",
3642
+ brandName: "#6b7684",
3643
+ adBadge: "#8b95a1",
3644
+ title: "#333d4b",
3645
+ subtitle: "#4e5968",
3646
+ adClearance: "#8b95a1",
3647
+ imageOverlayBorder: "rgba(2,32,71,0.05)"
3648
+ },
3649
+ dark: {
3650
+ brandLogoBg: "rgba(217,217,255,0.11)",
3651
+ brandLogoBorder: "rgba(217,217,255,0.11)",
3652
+ brandName: "#9e9ea4",
3653
+ adBadge: "#7e7e87",
3654
+ title: "#e4e4e5",
3655
+ subtitle: "#c3c3c6",
3656
+ adClearance: "#7e7e87",
3657
+ imageOverlayBorder: "rgba(217,217,255,0.11)"
3658
+ }
3659
+ }
3660
+ };
3661
+ function resolveCreativeVersion(creativeVersion) {
3662
+ return String(creativeVersion) === "2" ? "2" : "1";
3663
+ }
3664
+ function resolveListBannerRenderConfig(creativeVersion, theme) {
3665
+ const version = resolveCreativeVersion(creativeVersion);
3666
+ const isV2 = version === "2";
3667
+ return {
3668
+ colors: listBannerPalette[version][theme],
3669
+ defaultPaddingValue: DEFAULT_INLINE_AD_PADDING_BANNER,
3670
+ titleSlotId: isV2 ? "1001" : "101",
3671
+ subtitleSlotId: isV2 ? "1002" : "102",
3672
+ iconImageSlotId: isV2 ? "2505" : "202",
3673
+ adClearancePaddingRight: isV2 ? 24 : void 0
3674
+ };
3675
+ }
3676
+ function resolveFeedBannerRenderConfig(creativeVersion, theme) {
3677
+ const version = resolveCreativeVersion(creativeVersion);
3678
+ const isV2 = version === "2";
3679
+ return {
3680
+ colors: feedBannerPalette[version][theme],
3681
+ defaultPaddingValue: isV2 ? DEFAULT_INLINE_AD_PADDING_BANNER : DEFAULT_INLINE_AD_PADDING_NATIVE_IMAGE,
3682
+ brandImageSlotId: isV2 ? "2500" : "202",
3683
+ brandNameSlotId: isV2 ? "1004" : "103",
3684
+ titleSlotId: isV2 ? "1000" : "101",
3685
+ subtitleSlotId: isV2 ? "1002" : "102",
3686
+ mainImageSlotId: isV2 ? "2005" : "201",
3687
+ ctaButtonSlotId: "0",
3688
+ adBadgeText: isV2 ? "AD" : "\uAD11\uACE0",
3689
+ showTextArea: !isV2,
3690
+ adBadgePaddingLeft: isV2 ? 1 : void 0,
3691
+ imageButtonBackgroundColor: isV2 ? "#000000" : void 0,
3692
+ cardOverlayBorderWidth: isV2 ? 1.5 : void 0
3693
+ };
3694
+ }
3695
+
3696
+ // src/ads/inlineAd/resultTracking.ts
3697
+ async function fireResultTracking(result, adGroupId, ctx) {
3698
+ if (result.type !== "success") {
3699
+ return;
3700
+ }
3701
+ if (ctx.resultEndpoint == null || ctx.mediationId == null) {
3702
+ return;
3703
+ }
3704
+ const body = {
3705
+ mediationId: ctx.mediationId,
3706
+ spaceUnitId: adGroupId,
3707
+ requestId: result.response?.requestId ?? "",
3708
+ eventContextToken: ctx.eventContextToken,
3709
+ winnerSource: "TOSS",
3710
+ content: null,
3711
+ adUnitId: ctx.adUnitId ?? null,
3712
+ placementId: ctx.placementId ?? null,
3713
+ tossFailed: null
3714
+ };
3715
+ try {
3716
+ const res = await fetch(ctx.resultEndpoint, {
3717
+ method: "POST",
3718
+ headers: { "Content-Type": "application/json" },
3719
+ body: JSON.stringify(body)
3720
+ });
3721
+ if (!res.ok) {
3722
+ throw new Error(`HTTP ${res.status}`);
3723
+ }
3724
+ } catch (error) {
3725
+ trackBannerError({
3726
+ errorCode: ERROR_CODES.NETWORK_ERROR,
3727
+ errorMessage: `RESULT_TRACKING failed: ${error instanceof Error ? error.message : String(error)}`,
3728
+ adGroupId,
3729
+ mediationId: ctx.mediationId,
3730
+ eventContextToken: ctx.eventContextToken,
3731
+ endpointError: ctx.errorEndpoint
3732
+ });
3733
+ }
3734
+ }
3735
+
3355
3736
  // src/ads/inlineAd/tracking.ts
3356
3737
  var GlobalEventDeduplicator = class _GlobalEventDeduplicator {
3357
3738
  static MAX_EVENTS = 1e4;
@@ -3374,12 +3755,13 @@ var GlobalEventDeduplicator = class _GlobalEventDeduplicator {
3374
3755
  };
3375
3756
  var globalEventDeduplicator = new GlobalEventDeduplicator();
3376
3757
  var EventTracker = class {
3377
- constructor(eventTrackingUrls = [], eventTypes = [], eventPayload = "", requestId, creativeId, requestHeaders) {
3758
+ constructor(eventTrackingUrls = [], eventTypes = [], eventPayload = "", requestId, creativeId, requestHeaders, onTrackingError) {
3378
3759
  this.eventTrackingUrls = eventTrackingUrls;
3379
3760
  this.eventPayload = eventPayload;
3380
3761
  this.requestId = requestId;
3381
3762
  this.creativeId = creativeId;
3382
3763
  this.requestHeaders = requestHeaders;
3764
+ this.onTrackingError = onTrackingError;
3383
3765
  this.eventTypes = new Set(eventTypes);
3384
3766
  this.repeatableEvents = /* @__PURE__ */ new Set(["VIEW_MUTE", "VIEW_UNMUTE"]);
3385
3767
  }
@@ -3403,7 +3785,13 @@ var EventTracker = class {
3403
3785
  type: eventType,
3404
3786
  data: this.eventPayload
3405
3787
  };
3406
- await Promise.allSettled(this.eventTrackingUrls.map((url) => this.sendTrackingRequest(url, payload)));
3788
+ const results = await Promise.allSettled(
3789
+ this.eventTrackingUrls.map((url) => this.sendTrackingRequest(url, payload))
3790
+ );
3791
+ const failedUrls = this.eventTrackingUrls.filter((_, index) => results[index]?.status === "rejected");
3792
+ if (failedUrls.length > 0) {
3793
+ this.onTrackingError?.(failedUrls);
3794
+ }
3407
3795
  if (!this.repeatableEvents.has(eventType) && this.requestId && this.creativeId) {
3408
3796
  globalEventDeduplicator.markTracked(this.requestId, this.creativeId, eventType);
3409
3797
  }
@@ -3416,14 +3804,33 @@ var EventTracker = class {
3416
3804
  if (this.requestId) {
3417
3805
  headers["X-Toss-RequestId"] = this.requestId;
3418
3806
  }
3419
- await fetch(url, {
3807
+ const response = await fetch(url, {
3420
3808
  method: "POST",
3421
3809
  headers,
3422
3810
  body: JSON.stringify(payload)
3423
3811
  });
3812
+ if (!response.ok) {
3813
+ throw new Error(`HTTP ${response.status}`);
3814
+ }
3424
3815
  }
3425
3816
  };
3426
3817
 
3818
+ // src/ads/inlineAd/trackingContext.ts
3819
+ function nonEmptyString(value) {
3820
+ return typeof value === "string" && value.length > 0 ? value : void 0;
3821
+ }
3822
+ function extractAdTrackingContext(response) {
3823
+ const mediation = response?.ext?.mediation;
3824
+ return {
3825
+ mediationId: nonEmptyString(mediation?.mediationId),
3826
+ eventContextToken: nonEmptyString(response?.eventContextToken),
3827
+ resultEndpoint: nonEmptyString(mediation?.endpoint?.result),
3828
+ errorEndpoint: nonEmptyString(mediation?.endpoint?.error),
3829
+ adUnitId: nonEmptyString(mediation?.admob?.adUnitId),
3830
+ placementId: typeof mediation?.admob?.placementId === "number" ? mediation.admob.placementId : void 0
3831
+ };
3832
+ }
3833
+
3427
3834
  // src/ads/inlineAd/ui/FeedBannerAdView.tsx
3428
3835
  import { Path, Svg } from "@granite-js/native/react-native-svg";
3429
3836
  import { useRef as useRef6 } from "react";
@@ -3441,6 +3848,12 @@ var ARROW_PATH = "m7.5 20.4c-.5-.5-.5-1.2 0-1.7l6.7-6.7-6.8-6.7c-.5-.5-.5-1.2 0-
3441
3848
  function FeedBannerAdView({
3442
3849
  brandName,
3443
3850
  brandLogoUri,
3851
+ brandImageSlotId,
3852
+ brandNameSlotId,
3853
+ titleSlotId,
3854
+ subtitleSlotId,
3855
+ mainImageSlotId,
3856
+ ctaButtonSlotId,
3444
3857
  title,
3445
3858
  subtitle,
3446
3859
  mainImageUri,
@@ -3448,6 +3861,11 @@ function FeedBannerAdView({
3448
3861
  ctaTextColor,
3449
3862
  ctaBackgroundColor,
3450
3863
  adClearanceText,
3864
+ adBadgeText,
3865
+ showTextArea,
3866
+ adBadgePaddingLeft,
3867
+ imageButtonBackgroundColor,
3868
+ cardOverlayBorderWidth,
3451
3869
  colors: colors4,
3452
3870
  isAdBadgeEnabled,
3453
3871
  paddingStyle,
@@ -3485,7 +3903,7 @@ function FeedBannerAdView({
3485
3903
  Pressable2,
3486
3904
  {
3487
3905
  accessibilityRole: "button",
3488
- onPress: () => onPress("202"),
3906
+ onPress: () => onPress(brandImageSlotId),
3489
3907
  onPressIn: handlePressIn,
3490
3908
  onPressOut: handlePressOut,
3491
3909
  style: styles.logoContainer,
@@ -3500,7 +3918,7 @@ function FeedBannerAdView({
3500
3918
  Pressable2,
3501
3919
  {
3502
3920
  accessibilityRole: "button",
3503
- onPress: () => onPress("103"),
3921
+ onPress: () => onPress(brandNameSlotId),
3504
3922
  onPressIn: handlePressIn,
3505
3923
  onPressOut: handlePressOut,
3506
3924
  children: /* @__PURE__ */ jsx25(
@@ -3514,15 +3932,23 @@ function FeedBannerAdView({
3514
3932
  )
3515
3933
  }
3516
3934
  ),
3517
- isAdBadgeEnabled ? /* @__PURE__ */ jsx25(Text2, { allowFontScaling: false, numberOfLines: 1, style: [styles.adBadge, { color: colors4.adBadge }], children: "\uAD11\uACE0" }) : null
3935
+ isAdBadgeEnabled ? /* @__PURE__ */ jsx25(
3936
+ Text2,
3937
+ {
3938
+ allowFontScaling: false,
3939
+ numberOfLines: 1,
3940
+ style: [styles.adBadge, { color: colors4.adBadge, paddingLeft: adBadgePaddingLeft }],
3941
+ children: adBadgeText
3942
+ }
3943
+ ) : null
3518
3944
  ] })
3519
3945
  ] }),
3520
- /* @__PURE__ */ jsxs11(View7, { style: styles.textArea, children: [
3946
+ showTextArea ? /* @__PURE__ */ jsxs11(View7, { style: styles.textArea, children: [
3521
3947
  /* @__PURE__ */ jsx25(
3522
3948
  Pressable2,
3523
3949
  {
3524
3950
  accessibilityRole: "button",
3525
- onPress: () => onPress("101"),
3951
+ onPress: () => onPress(titleSlotId),
3526
3952
  onPressIn: handlePressIn,
3527
3953
  onPressOut: handlePressOut,
3528
3954
  children: /* @__PURE__ */ jsx25(Text2, { allowFontScaling: false, style: [styles.title, { color: colors4.title }], children: title })
@@ -3532,23 +3958,26 @@ function FeedBannerAdView({
3532
3958
  Pressable2,
3533
3959
  {
3534
3960
  accessibilityRole: "button",
3535
- onPress: () => onPress("102"),
3961
+ onPress: () => onPress(subtitleSlotId),
3536
3962
  onPressIn: handlePressIn,
3537
3963
  onPressOut: handlePressOut,
3538
3964
  children: /* @__PURE__ */ jsx25(Text2, { allowFontScaling: false, style: [styles.subtitle, { color: colors4.subtitle }], children: subtitle })
3539
3965
  }
3540
3966
  )
3541
- ] })
3967
+ ] }) : null
3542
3968
  ] }),
3543
3969
  /* @__PURE__ */ jsxs11(View7, { style: styles.card, children: [
3544
3970
  /* @__PURE__ */ jsx25(
3545
3971
  Pressable2,
3546
3972
  {
3547
3973
  accessibilityRole: "button",
3548
- onPress: () => onPress("201"),
3974
+ onPress: () => onPress(mainImageSlotId),
3549
3975
  onPressIn: handlePressIn,
3550
3976
  onPressOut: handlePressOut,
3551
- style: styles.imageButton,
3977
+ style: [
3978
+ styles.imageButton,
3979
+ imageButtonBackgroundColor ? { backgroundColor: imageButtonBackgroundColor } : null
3980
+ ],
3552
3981
  children: /* @__PURE__ */ jsx25(View7, { style: styles.imageContainer, children: mainImageUri ? /* @__PURE__ */ jsx25(Image2, { source: { uri: mainImageUri }, style: styles.mainImage, resizeMode: "cover" }) : null })
3553
3982
  }
3554
3983
  ),
@@ -3556,7 +3985,7 @@ function FeedBannerAdView({
3556
3985
  Pressable2,
3557
3986
  {
3558
3987
  accessibilityRole: "button",
3559
- onPress: () => onPress("0"),
3988
+ onPress: () => onPress(ctaButtonSlotId),
3560
3989
  onPressIn: handlePressIn,
3561
3990
  onPressOut: handlePressOut,
3562
3991
  style: [styles.cta, { backgroundColor: resolvedCtaBackground }],
@@ -3566,7 +3995,18 @@ function FeedBannerAdView({
3566
3995
  ]
3567
3996
  }
3568
3997
  ),
3569
- /* @__PURE__ */ jsx25(View7, { style: [styles.cardOverlay, { borderColor: colors4.imageOverlayBorder }] })
3998
+ /* @__PURE__ */ jsx25(
3999
+ View7,
4000
+ {
4001
+ style: [
4002
+ styles.cardOverlay,
4003
+ {
4004
+ borderColor: colors4.imageOverlayBorder,
4005
+ borderWidth: cardOverlayBorderWidth ?? styles.cardOverlay.borderWidth
4006
+ }
4007
+ ]
4008
+ }
4009
+ )
3570
4010
  ] }),
3571
4011
  adClearanceText ? /* @__PURE__ */ jsx25(Text2, { allowFontScaling: false, style: [styles.adClearance, { color: colors4.adClearance }], children: adClearanceText }) : null
3572
4012
  ] })
@@ -3696,8 +4136,12 @@ var SQUIRCLE_PATH = "M0 17.352C0 3.564 3.564 0 17.352 0H18.648C32.436 0 36 3.564
3696
4136
  function ListBannerAdView({
3697
4137
  title,
3698
4138
  subtitle,
4139
+ titleSlotId,
4140
+ subtitleSlotId,
4141
+ iconImageSlotId,
3699
4142
  adClearanceText,
3700
4143
  adClearanceFontSize,
4144
+ adClearancePaddingRight,
3701
4145
  imageUri,
3702
4146
  paddingStyle,
3703
4147
  colors: colors4,
@@ -3733,7 +4177,7 @@ function ListBannerAdView({
3733
4177
  Pressable3,
3734
4178
  {
3735
4179
  accessibilityRole: "button",
3736
- onPress: () => onPress("202"),
4180
+ onPress: () => onPress(iconImageSlotId),
3737
4181
  onPressIn: handlePressIn,
3738
4182
  onPressOut: handlePressOut,
3739
4183
  style: styles2.iconWrapper,
@@ -3768,7 +4212,7 @@ function ListBannerAdView({
3768
4212
  Pressable3,
3769
4213
  {
3770
4214
  accessibilityRole: "button",
3771
- onPress: () => onPress("101"),
4215
+ onPress: () => onPress(titleSlotId),
3772
4216
  onPressIn: handlePressIn,
3773
4217
  onPressOut: handlePressOut,
3774
4218
  children: /* @__PURE__ */ jsx26(Text3, { allowFontScaling: false, style: [styles2.title, { color: colors4.title }], children: title })
@@ -3778,7 +4222,7 @@ function ListBannerAdView({
3778
4222
  Pressable3,
3779
4223
  {
3780
4224
  accessibilityRole: "button",
3781
- onPress: () => onPress("102"),
4225
+ onPress: () => onPress(subtitleSlotId),
3782
4226
  onPressIn: handlePressIn,
3783
4227
  onPressOut: handlePressOut,
3784
4228
  children: /* @__PURE__ */ jsx26(Text3, { allowFontScaling: false, style: [styles2.subtitle, { color: colors4.subtitle }], children: subtitle })
@@ -3795,7 +4239,8 @@ function ListBannerAdView({
3795
4239
  {
3796
4240
  color: colors4.adClearance,
3797
4241
  fontSize: adClearanceFontSize,
3798
- lineHeight: adClearanceFontSize * 1.2
4242
+ lineHeight: adClearanceFontSize * 1.2,
4243
+ paddingRight: adClearancePaddingRight
3799
4244
  }
3800
4245
  ],
3801
4246
  children: adClearanceText
@@ -3907,12 +4352,12 @@ function buildBannerEventPayload(slotId, adGroupId, ad) {
3907
4352
  }
3908
4353
  };
3909
4354
  }
3910
- function buildBannerErrorPayload(slotId, adGroupId, error) {
4355
+ function buildBannerErrorPayload(slotId, adGroupId, error, mediationId) {
3911
4356
  return {
3912
4357
  slotId,
3913
4358
  adGroupId,
3914
4359
  adMetadata: {},
3915
- error
4360
+ error: mediationId ? { ...error, mediationId } : error
3916
4361
  };
3917
4362
  }
3918
4363
  function buildNoFillPayload(slotId, adGroupId) {
@@ -3925,44 +4370,6 @@ function buildNoFillPayload(slotId, adGroupId) {
3925
4370
 
3926
4371
  // src/ads/inlineAd/InlineAd.tsx
3927
4372
  import { jsx as jsx27, jsxs as jsxs13 } from "react/jsx-runtime";
3928
- var themePalette = {
3929
- light: {
3930
- title: "#4e5968",
3931
- subtitle: "#6b7684",
3932
- adClearance: "#b0b8c1",
3933
- iconBg: "rgba(2,32,71,0.05)",
3934
- iconBorder: "rgba(2,32,71,0.05)"
3935
- },
3936
- dark: {
3937
- title: "rgba(253,253,255,0.75)",
3938
- subtitle: "rgba(248,248,255,0.6)",
3939
- adClearance: "rgba(242,242,255,0.47)",
3940
- iconBg: "#ffffff",
3941
- iconBorder: "rgba(217,217,255,0.11)"
3942
- }
3943
- };
3944
- var feedThemePalette = {
3945
- light: {
3946
- brandLogoBg: "rgba(2,32,71,0.05)",
3947
- brandLogoBorder: "rgba(2,32,71,0.05)",
3948
- brandName: "#6b7684",
3949
- adBadge: "#8b95a1",
3950
- title: "#333d4b",
3951
- subtitle: "#4e5968",
3952
- adClearance: "#8b95a1",
3953
- imageOverlayBorder: "rgba(2,32,71,0.05)"
3954
- },
3955
- dark: {
3956
- brandLogoBg: "#ffffff",
3957
- brandLogoBorder: "rgba(217,217,255,0.11)",
3958
- brandName: "#9e9ea4",
3959
- adBadge: "#7e7e87",
3960
- title: "#e4e4e5",
3961
- subtitle: "#c3c3c6",
3962
- adClearance: "#7e7e87",
3963
- imageOverlayBorder: "rgba(217,217,255,0.11)"
3964
- }
3965
- };
3966
4373
  function createError2(code, message) {
3967
4374
  return {
3968
4375
  code,
@@ -4040,8 +4447,6 @@ function InlineAd(props) {
4040
4447
  const resolvedTheme = selectedTheme === "auto" ? colorScheme === "dark" ? "dark" : "light" : selectedTheme;
4041
4448
  const resolvedTone = tone ?? DEFAULT_INLINE_AD_TONE;
4042
4449
  const resolvedVariant = variant ?? DEFAULT_INLINE_AD_VARIANT;
4043
- const colors4 = themePalette[resolvedTheme];
4044
- const feedColors = feedThemePalette[resolvedTheme];
4045
4450
  const backgroundColor = resolvedTone === "grey" ? resolvedTheme === "dark" ? "#101013" : "#f2f4f7" : resolvedTheme === "dark" ? "#17171c" : "#ffffff";
4046
4451
  callbacksRef.current = {
4047
4452
  onAdRendered,
@@ -4063,35 +4468,43 @@ function InlineAd(props) {
4063
4468
  }, []);
4064
4469
  useEffect14(() => {
4065
4470
  const normalizedAdGroupId = normalizeAdGroupId(adGroupId);
4471
+ const emitFailure = (error, responseContext) => {
4472
+ callbacksRef.current.onAdFailedToRender?.(
4473
+ buildBannerErrorPayload(slotIdRef.current, normalizedAdGroupId, error, responseContext?.mediationId)
4474
+ );
4475
+ trackBannerError({
4476
+ errorCode: error.code,
4477
+ errorMessage: error.message,
4478
+ adGroupId: normalizedAdGroupId,
4479
+ mediationId: responseContext?.mediationId,
4480
+ eventContextToken: responseContext?.eventContextToken,
4481
+ endpointError: responseContext?.errorEndpoint
4482
+ });
4483
+ };
4066
4484
  const loadAdRequest = () => {
4067
4485
  if (loadingRef.current) {
4068
4486
  return;
4069
4487
  }
4070
4488
  if (normalizedAdGroupId.length === 0) {
4071
- const error = createError2(ERROR_CODES.INVALID_SPACE, INVALID_AD_GROUP_ID_ERROR_MESSAGE);
4072
- callbacksRef.current.onAdFailedToRender?.(
4073
- buildBannerErrorPayload(slotIdRef.current, normalizedAdGroupId, error)
4074
- );
4489
+ emitFailure(createError2(ERROR_CODES.INVALID_SPACE, INVALID_AD_GROUP_ID_ERROR_MESSAGE));
4075
4490
  return;
4076
4491
  }
4077
4492
  loadingRef.current = true;
4078
4493
  loadAd(normalizedAdGroupId).then((result) => {
4079
4494
  if (!isMountedRef.current) return;
4495
+ const responseContext = extractAdTrackingContext(result.response);
4496
+ void fireResultTracking(result, normalizedAdGroupId, responseContext);
4080
4497
  if (result.type === "noFill") {
4081
4498
  callbacksRef.current.onNoFill?.(buildNoFillPayload(slotIdRef.current, normalizedAdGroupId));
4082
4499
  return;
4083
4500
  }
4084
4501
  if (result.type === "error") {
4085
- callbacksRef.current.onAdFailedToRender?.(
4086
- buildBannerErrorPayload(slotIdRef.current, normalizedAdGroupId, result.error)
4087
- );
4502
+ emitFailure(result.error, responseContext);
4088
4503
  return;
4089
4504
  }
4090
4505
  if (!isValidCreative(result.ad)) {
4091
4506
  const invalidError = createError2(ERROR_CODES.INTERNAL_ERROR, "Invalid creative payload");
4092
- callbacksRef.current.onAdFailedToRender?.(
4093
- buildBannerErrorPayload(slotIdRef.current, normalizedAdGroupId, invalidError)
4094
- );
4507
+ emitFailure(invalidError, responseContext);
4095
4508
  return;
4096
4509
  }
4097
4510
  if (result.responseExt?.refetchSeconds !== void 0) {
@@ -4108,21 +4521,29 @@ function InlineAd(props) {
4108
4521
  }
4109
4522
  const payload = buildBannerEventPayload(slotIdRef.current, normalizedAdGroupId, result.ad);
4110
4523
  eventPayloadRef.current = payload;
4524
+ const reportEventTrackingFailure = (failedUrls) => trackBannerError({
4525
+ errorCode: ERROR_CODES.NETWORK_ERROR,
4526
+ errorMessage: `eventTracking delivery failed (${failedUrls.length})`,
4527
+ adGroupId: normalizedAdGroupId,
4528
+ mediationId: responseContext.mediationId,
4529
+ eventContextToken: responseContext.eventContextToken,
4530
+ endpointError: responseContext.errorEndpoint
4531
+ });
4111
4532
  eventTrackerRef.current = new EventTracker(
4112
4533
  result.ad.eventTrackingUrls ?? [],
4113
4534
  result.ad.eventTypes ?? [],
4114
4535
  result.ad.eventPayload ?? "",
4115
4536
  result.requestId,
4116
- result.ad.creative?.id
4537
+ result.ad.creative?.id,
4538
+ void 0,
4539
+ reportEventTrackingFailure
4117
4540
  );
4118
4541
  setIsAdBadgeEnabled(result.responseExt?.isAdBadgeEnabled !== false);
4119
4542
  setAd(result.ad);
4120
4543
  }).catch((error) => {
4121
4544
  if (!isMountedRef.current) return;
4122
4545
  const adError = error instanceof Error ? createError2(ERROR_CODES.INTERNAL_ERROR, error.message) : createError2(ERROR_CODES.INTERNAL_ERROR, "Unknown error");
4123
- callbacksRef.current.onAdFailedToRender?.(
4124
- buildBannerErrorPayload(slotIdRef.current, normalizedAdGroupId, adError)
4125
- );
4546
+ emitFailure(adError);
4126
4547
  }).finally(() => {
4127
4548
  loadingRef.current = false;
4128
4549
  });
@@ -4161,7 +4582,9 @@ function InlineAd(props) {
4161
4582
  }
4162
4583
  const impressionKey = `${ad.requestId ?? "request"}:${ad.creative?.id ?? "creative"}`;
4163
4584
  const resolvedStyleId = ad.styleId || LIST_BANNER_STYLE_ID;
4164
- const defaultPaddingValue = resolvedStyleId === LIST_BANNER_STYLE_ID ? DEFAULT_INLINE_AD_PADDING_BANNER : DEFAULT_INLINE_AD_PADDING_NATIVE_IMAGE;
4585
+ const listBannerConfig = resolveListBannerRenderConfig(ad.creativeVersion, resolvedTheme);
4586
+ const feedBannerConfig = resolveFeedBannerRenderConfig(ad.creativeVersion, resolvedTheme);
4587
+ const defaultPaddingValue = resolvedStyleId === LIST_BANNER_STYLE_ID ? listBannerConfig.defaultPaddingValue : feedBannerConfig.defaultPaddingValue;
4165
4588
  const paddingStyle = resolvePaddingStyle(defaultPaddingValue);
4166
4589
  const isListBanner = String(resolvedStyleId) === LIST_BANNER_STYLE_ID;
4167
4590
  const isFeedBanner = String(resolvedStyleId) === FEED_BANNER_STYLE_ID;
@@ -4257,11 +4680,15 @@ function InlineAd(props) {
4257
4680
  {
4258
4681
  title: listCreative.title,
4259
4682
  subtitle: subtitleText,
4683
+ titleSlotId: listBannerConfig.titleSlotId,
4684
+ subtitleSlotId: listBannerConfig.subtitleSlotId,
4685
+ iconImageSlotId: listBannerConfig.iconImageSlotId,
4260
4686
  adClearanceText,
4261
4687
  adClearanceFontSize,
4688
+ adClearancePaddingRight: listBannerConfig.adClearancePaddingRight,
4262
4689
  imageUri,
4263
4690
  paddingStyle,
4264
- colors: colors4,
4691
+ colors: listBannerConfig.colors,
4265
4692
  onPress: handleClick
4266
4693
  }
4267
4694
  ) : null,
@@ -4270,6 +4697,12 @@ function InlineAd(props) {
4270
4697
  {
4271
4698
  brandName: feedCreative.brandName,
4272
4699
  brandLogoUri,
4700
+ brandImageSlotId: feedBannerConfig.brandImageSlotId,
4701
+ brandNameSlotId: feedBannerConfig.brandNameSlotId,
4702
+ titleSlotId: feedBannerConfig.titleSlotId,
4703
+ subtitleSlotId: feedBannerConfig.subtitleSlotId,
4704
+ mainImageSlotId: feedBannerConfig.mainImageSlotId,
4705
+ ctaButtonSlotId: feedBannerConfig.ctaButtonSlotId,
4273
4706
  title: feedCreative.title,
4274
4707
  subtitle: feedCreative.subTitle,
4275
4708
  mainImageUri,
@@ -4277,7 +4710,12 @@ function InlineAd(props) {
4277
4710
  ctaTextColor: feedCreative.ctaTextColor,
4278
4711
  ctaBackgroundColor: feedCreative.ctaBackgroundColor,
4279
4712
  adClearanceText,
4280
- colors: feedColors,
4713
+ adBadgeText: feedBannerConfig.adBadgeText,
4714
+ showTextArea: feedBannerConfig.showTextArea,
4715
+ adBadgePaddingLeft: feedBannerConfig.adBadgePaddingLeft,
4716
+ imageButtonBackgroundColor: feedBannerConfig.imageButtonBackgroundColor,
4717
+ cardOverlayBorderWidth: feedBannerConfig.cardOverlayBorderWidth,
4718
+ colors: feedBannerConfig.colors,
4281
4719
  isAdBadgeEnabled,
4282
4720
  paddingStyle,
4283
4721
  onPress: handleClick