@apps-in-toss/framework 2.9.3 → 2.10.0

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
@@ -1777,7 +1777,7 @@ function convertIntentURL(url) {
1777
1777
  return `${scheme}://${url.hostname}${url.pathname}${url.search}`;
1778
1778
  }
1779
1779
 
1780
- // src/ads/fetchTossAd.ts
1780
+ // src/ads/fetchAppsInTossAd.ts
1781
1781
  import {
1782
1782
  getOperationalEnvironment as getOperationalEnvironment6,
1783
1783
  INTERNAL__appBridgeHandler as INTERNAL__appBridgeHandler3,
@@ -1809,14 +1809,54 @@ function generateSessionId() {
1809
1809
  // src/ads/constants.ts
1810
1810
  var sessionId = generateSessionId();
1811
1811
 
1812
+ // src/ads/fetchAppsInTossAd.ts
1813
+ var ANDROID_SUPPORTED_VERSION = "5.264.0";
1814
+ var IOS_SUPPORTED_VERSION = "5.264.0";
1815
+ var APP_BRIDGE_METHOD_NAME2 = "fetchAppsInTossAd";
1816
+ var UNSUPPORTED_ERROR_MESSAGE = "This feature is not supported in the current environment";
1817
+ function fetchAppsInTossAd(params) {
1818
+ const { body, onEvent, onError } = params;
1819
+ if (!fetchAppsInTossAd.isSupported()) {
1820
+ onError(new Error(UNSUPPORTED_ERROR_MESSAGE));
1821
+ return noop;
1822
+ }
1823
+ const spaceUnitId = normalizeAdGroupId(body.spaceUnitId);
1824
+ if (spaceUnitId.length === 0) {
1825
+ onError(createInvalidAdGroupIdError());
1826
+ return noop;
1827
+ }
1828
+ return INTERNAL__appBridgeHandler3.invokeAppBridgeMethod(
1829
+ APP_BRIDGE_METHOD_NAME2,
1830
+ { ...body, spaceUnitId, sessionId: body.sessionId ?? sessionId },
1831
+ {
1832
+ onSuccess: onEvent,
1833
+ onError
1834
+ }
1835
+ );
1836
+ }
1837
+ fetchAppsInTossAd.isSupported = () => {
1838
+ if (getOperationalEnvironment6() !== "toss") {
1839
+ return false;
1840
+ }
1841
+ return isMinVersionSupported4({
1842
+ android: ANDROID_SUPPORTED_VERSION,
1843
+ ios: IOS_SUPPORTED_VERSION
1844
+ });
1845
+ };
1846
+
1812
1847
  // src/ads/fetchTossAd.ts
1848
+ import {
1849
+ getOperationalEnvironment as getOperationalEnvironment7,
1850
+ INTERNAL__appBridgeHandler as INTERNAL__appBridgeHandler4,
1851
+ isMinVersionSupported as isMinVersionSupported5
1852
+ } from "@apps-in-toss/native-modules";
1813
1853
  var ANDROID_FETCH_TOSS_AD_SUPPORTED_VERSION = "5.241.0";
1814
1854
  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();
1855
+ var UNSUPPORTED_ERROR_MESSAGE2 = "This feature is not supported in the current environment";
1856
+ var ENVIRONMENT = getOperationalEnvironment7();
1817
1857
  function fetchTossAd(params) {
1818
1858
  if (!fetchTossAd.isSupported()) {
1819
- params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE));
1859
+ params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE2));
1820
1860
  return noop;
1821
1861
  }
1822
1862
  const { onEvent, onError, options } = params;
@@ -1826,7 +1866,7 @@ function fetchTossAd(params) {
1826
1866
  return noop;
1827
1867
  }
1828
1868
  const wireHeaders = options.headers;
1829
- const unregisterCallbacks = INTERNAL__appBridgeHandler3.invokeAppBridgeMethod(
1869
+ const unregisterCallbacks = INTERNAL__appBridgeHandler4.invokeAppBridgeMethod(
1830
1870
  "fetchTossAd",
1831
1871
  {
1832
1872
  spaceUnitId: adGroupId,
@@ -1850,14 +1890,14 @@ fetchTossAd.isSupported = () => {
1850
1890
  if (ENVIRONMENT !== "toss") {
1851
1891
  return false;
1852
1892
  }
1853
- return isMinVersionSupported4({
1893
+ return isMinVersionSupported5({
1854
1894
  android: ANDROID_FETCH_TOSS_AD_SUPPORTED_VERSION,
1855
1895
  ios: IOS_FETCH_TOSS_AD_SUPPORTED_VERSION
1856
1896
  });
1857
1897
  };
1858
1898
 
1859
1899
  // src/ads/integratedAd.ts
1860
- import { GoogleAdMob, INTERNAL__appBridgeHandler as INTERNAL__appBridgeHandler4, isMinVersionSupported as isMinVersionSupported5 } from "@apps-in-toss/native-modules";
1900
+ import { GoogleAdMob, INTERNAL__appBridgeHandler as INTERNAL__appBridgeHandler5, isMinVersionSupported as isMinVersionSupported6 } from "@apps-in-toss/native-modules";
1861
1901
 
1862
1902
  // src/ads/generateRequestId.ts
1863
1903
  function generateRequestId() {
@@ -1877,7 +1917,7 @@ function getReferrer() {
1877
1917
  }
1878
1918
 
1879
1919
  // src/ads/remotes.ts
1880
- import { getOperationalEnvironment as getOperationalEnvironment7, getPlatformOS, getTossAppVersion } from "@apps-in-toss/native-modules";
1920
+ import { getOperationalEnvironment as getOperationalEnvironment8, getPlatformOS, getTossAppVersion } from "@apps-in-toss/native-modules";
1881
1921
 
1882
1922
  // src/ads/getIsDev.ts
1883
1923
  import { getSchemeUri as getSchemeUri7 } from "@granite-js/react-native";
@@ -1890,7 +1930,7 @@ function getIsDev() {
1890
1930
  }
1891
1931
 
1892
1932
  // src/ads/remotes.ts
1893
- var OPERATIONAL_ENVIRONMENT = getOperationalEnvironment7();
1933
+ var OPERATIONAL_ENVIRONMENT = getOperationalEnvironment8();
1894
1934
  var OS = getPlatformOS();
1895
1935
  var APP_VER = getTossAppVersion();
1896
1936
  var ALPHA_EVENT_TRACKER_HTTP_ENDPOINT = "https://alpha-trillion.toss.im/trk/sdk-mediation/event";
@@ -1924,10 +1964,10 @@ function postEventTracking(params) {
1924
1964
  var INTEGRATED_AD_SDK_VERSION = "0.0.0";
1925
1965
  var ANDROID_INTEGRATED_AD_SUPPORTED_VERSION = "5.247.0";
1926
1966
  var IOS_INTEGRATED_AD_SUPPORTED_VERSION = "5.247.0";
1927
- var UNSUPPORTED_ERROR_MESSAGE2 = "This feature is not supported in the current environment";
1967
+ var UNSUPPORTED_ERROR_MESSAGE3 = "This feature is not supported in the current environment";
1928
1968
  var INTG_AD_ADM_FALLBACK_RID_MAP = {};
1929
1969
  function integratedAdIsSupported() {
1930
- return isMinVersionSupported5({
1970
+ return isMinVersionSupported6({
1931
1971
  android: ANDROID_INTEGRATED_AD_SUPPORTED_VERSION,
1932
1972
  ios: IOS_INTEGRATED_AD_SUPPORTED_VERSION
1933
1973
  });
@@ -1935,7 +1975,7 @@ function integratedAdIsSupported() {
1935
1975
  function generateLoadFullScreenAd(sdkId) {
1936
1976
  const fn = (params) => {
1937
1977
  if (!GoogleAdMob.loadAppsInTossAdMob.isSupported()) {
1938
- params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE2));
1978
+ params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE3));
1939
1979
  return noop;
1940
1980
  }
1941
1981
  const normalizedAdGroupId = normalizeAdGroupId(params.options.adGroupId);
@@ -1993,7 +2033,7 @@ function generateLoadFullScreenAd(sdkId) {
1993
2033
  const { adGroupId } = options;
1994
2034
  const referrer = getReferrer();
1995
2035
  const wireHeaders = options.headers;
1996
- const unregisterCallbacks = INTERNAL__appBridgeHandler4.invokeAppBridgeMethod(
2036
+ const unregisterCallbacks = INTERNAL__appBridgeHandler5.invokeAppBridgeMethod(
1997
2037
  "loadTossAdOrAdmob",
1998
2038
  {
1999
2039
  spaceUnitId: adGroupId,
@@ -2020,7 +2060,7 @@ var loadFullScreenAd = generateLoadFullScreenAd("107");
2020
2060
  var loadFullScreenAdForWeb = generateLoadFullScreenAd("107");
2021
2061
  function showFullScreenAd(params) {
2022
2062
  if (!GoogleAdMob.showAppsInTossAdMob.isSupported()) {
2023
- params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE2));
2063
+ params.onError(new Error(UNSUPPORTED_ERROR_MESSAGE3));
2024
2064
  return noop;
2025
2065
  }
2026
2066
  const normalizedAdGroupId = normalizeAdGroupId(params.options.adGroupId);
@@ -2135,7 +2175,7 @@ function showFullScreenAd(params) {
2135
2175
  const { onEvent, onError, options } = normalizedParams;
2136
2176
  const { adGroupId } = options;
2137
2177
  const referrer = getReferrer();
2138
- const unregisterCallbacks = INTERNAL__appBridgeHandler4.invokeAppBridgeMethod(
2178
+ const unregisterCallbacks = INTERNAL__appBridgeHandler5.invokeAppBridgeMethod(
2139
2179
  "showTossAdOrAdmob",
2140
2180
  { spaceUnitId: adGroupId, referrer, sessionId },
2141
2181
  {
@@ -2701,7 +2741,7 @@ function useTopNavigation() {
2701
2741
  }
2702
2742
 
2703
2743
  // src/hooks/useWebViewMemoryDebug.tsx
2704
- import { getOperationalEnvironment as getOperationalEnvironment8 } from "@apps-in-toss/native-modules";
2744
+ import { getOperationalEnvironment as getOperationalEnvironment9 } from "@apps-in-toss/native-modules";
2705
2745
  import { Granite as Granite8 } from "@granite-js/react-native";
2706
2746
  import { useToast } from "@toss/tds-react-native";
2707
2747
  function useHandleWebViewProcessDidTerminate(webViewRef) {
@@ -2729,7 +2769,7 @@ function webViewDebugLog(logName, params) {
2729
2769
  deployment_id: global2.deploymentId
2730
2770
  }
2731
2771
  };
2732
- if (getOperationalEnvironment8() === "toss") {
2772
+ if (getOperationalEnvironment9() === "toss") {
2733
2773
  sendLog(event, { pipelines: ["core"] });
2734
2774
  } else {
2735
2775
  console.log("[webViewDebugLog]", event);
@@ -2875,6 +2915,8 @@ function WebView({ type, local, onMessage, ...props }) {
2875
2915
  showFullScreenAd,
2876
2916
  /** TossAd */
2877
2917
  fetchTossAd,
2918
+ // v1.4 배너: web 이벤트 브릿지는 payload를 options로 전달하지만 fetchAppsInTossAd는 body로 받으므로 어댑팅한다.
2919
+ fetchAppsInTossAd: ({ onEvent, onError, options }) => fetchAppsInTossAd({ body: options, onEvent, onError }),
2878
2920
  /** IAP */
2879
2921
  iapCreateOneTimePurchaseOrder: IAP.createOneTimePurchaseOrder,
2880
2922
  requestSubscriptionPurchase,
@@ -2896,6 +2938,7 @@ function WebView({ type, local, onMessage, ...props }) {
2896
2938
  showFullScreenAd_isSupported: showFullScreenAd.isSupported,
2897
2939
  /** TossAd */
2898
2940
  fetchTossAd_isSupported: fetchTossAd.isSupported,
2941
+ fetchAppsInTossAd_isSupported: fetchAppsInTossAd.isSupported,
2899
2942
  /** env */
2900
2943
  getDeploymentId: env.getDeploymentId,
2901
2944
  getWebViewType: env.getWebViewType,
@@ -3159,6 +3202,159 @@ var AD_STATUS_ERROR_MAP = {
3159
3202
  }
3160
3203
  };
3161
3204
 
3205
+ // src/ads/inlineAd/errorTracking.ts
3206
+ var BANNER_ERROR_LOG_NAME = "display_ads_all::error__banner";
3207
+ var MAX_STACK_TRACE_LENGTH = 255;
3208
+ function logBannerErrorToAppLog(info) {
3209
+ void tossAdEventLog({
3210
+ log_name: BANNER_ERROR_LOG_NAME,
3211
+ log_type: "debug",
3212
+ params: {
3213
+ error_code: info.errorCode,
3214
+ error_message: info.errorMessage,
3215
+ ad_group_id: info.adGroupId,
3216
+ mediation_id: info.mediationId,
3217
+ event_context_token: info.eventContextToken
3218
+ }
3219
+ }).catch(noop);
3220
+ }
3221
+ function trackBannerError(info) {
3222
+ if (info.endpointError) {
3223
+ void fetch(info.endpointError, {
3224
+ method: "POST",
3225
+ headers: { "Content-Type": "application/json" },
3226
+ body: JSON.stringify({
3227
+ eventContextToken: info.eventContextToken,
3228
+ mediationId: info.mediationId,
3229
+ errorCode: info.errorCode,
3230
+ errorMessage: info.errorMessage,
3231
+ stackTrace: info.stackTrace?.slice(0, MAX_STACK_TRACE_LENGTH)
3232
+ })
3233
+ // POST 실패(CORS·네트워크) → 앱로그 fallback (endpoint와 같은 채널이라 함께 막히는 경우 대비).
3234
+ }).catch(() => logBannerErrorToAppLog(info));
3235
+ return;
3236
+ }
3237
+ logBannerErrorToAppLog(info);
3238
+ }
3239
+
3240
+ // src/ads/inlineAd/loadAd.ts
3241
+ import { getPlatformOS as getPlatformOS3, getTossAppVersion as getTossAppVersion3 } from "@apps-in-toss/native-modules";
3242
+
3243
+ // src/ads/fetchAppsInTossAdSchema.ts
3244
+ var APPS_IN_TOSS_AD_SPEC_VERSION = "1.4.1";
3245
+ var FETCH_APPS_IN_TOSS_AD_DEVICE_MACRO = "{{device}}";
3246
+ var TOSS_APP_BUNDLE_IDS = {
3247
+ ios: "com.vivarepublica.cash",
3248
+ android: "viva.republica.toss"
3249
+ };
3250
+ function resolveTossAppBundleId(os) {
3251
+ return TOSS_APP_BUNDLE_IDS[os];
3252
+ }
3253
+
3254
+ // package.json
3255
+ var package_default = {
3256
+ name: "@apps-in-toss/framework",
3257
+ type: "module",
3258
+ version: "2.10.0",
3259
+ description: "The framework for Apps In Toss",
3260
+ scripts: {
3261
+ typecheck: "tsc --noEmit",
3262
+ test: "vitest --no-watch",
3263
+ "test:no-parallel": "vitest --no-watch --config=vitest.no-parallel.config.mts",
3264
+ lint: "eslint .",
3265
+ build: "tsup"
3266
+ },
3267
+ main: "./dist/index.cjs",
3268
+ module: "./dist/index.js",
3269
+ types: "./dist/index.d.ts",
3270
+ exports: {
3271
+ ".": {
3272
+ types: "./dist/index.d.ts",
3273
+ import: "./dist/index.js",
3274
+ require: "./dist/index.cjs"
3275
+ },
3276
+ "./plugins": {
3277
+ types: "./dist/plugins/index.d.ts",
3278
+ import: "./dist/plugins/index.js",
3279
+ require: "./dist/plugins/index.cjs"
3280
+ },
3281
+ "./internal": {
3282
+ types: "./dist/internal.d.ts",
3283
+ import: "./dist/internal.js",
3284
+ require: "./dist/internal.cjs"
3285
+ },
3286
+ "./bridge-entry": "./src/bridge-entry.ts",
3287
+ "./bridge-meta": {
3288
+ types: "./dist/bridge-meta.d.ts",
3289
+ default: "./dist/bridge-meta.js"
3290
+ },
3291
+ "./jest": {
3292
+ types: "./dist/jest/index.d.ts",
3293
+ import: "./dist/jest/index.js",
3294
+ require: "./dist/jest/index.cjs"
3295
+ },
3296
+ "./package.json": "./package.json"
3297
+ },
3298
+ files: [
3299
+ "dist/**/*",
3300
+ "src/bridge-entry.ts",
3301
+ "src/async-bridges.ts",
3302
+ "src/constant-bridges.ts",
3303
+ "src/event-bridges.ts",
3304
+ "hermesc/**/*",
3305
+ "plugins.d.ts",
3306
+ "jest.d.ts"
3307
+ ],
3308
+ bin: {
3309
+ ait: "./bin/ait.js"
3310
+ },
3311
+ dependencies: {
3312
+ "@apps-in-toss/analytics": "workspace:*",
3313
+ "@apps-in-toss/cli": "workspace:*",
3314
+ "@apps-in-toss/native-modules": "workspace:*",
3315
+ "@apps-in-toss/plugins": "workspace:*",
3316
+ "@apps-in-toss/types": "workspace:*",
3317
+ "@apps-in-toss/user-scripts": "workspace:^",
3318
+ "es-hangul": "^2.3.2"
3319
+ },
3320
+ devDependencies: {
3321
+ "@apps-in-toss/ait-format": "1.0.0",
3322
+ "@babel/runtime": "^7",
3323
+ "@granite-js/mpack": "catalog:granite-js",
3324
+ "@granite-js/native": "catalog:granite-js",
3325
+ "@granite-js/plugin-core": "catalog:granite-js",
3326
+ "@granite-js/react-native": "catalog:granite-js",
3327
+ "@granite-js/utils": "catalog:granite-js",
3328
+ "@toss/tds-react-native": "catalog:react-native",
3329
+ "@types/kill-port": "2.0.1",
3330
+ "@types/react": "catalog:react-native",
3331
+ "brick-module": "catalog:brick-module",
3332
+ "es-toolkit": "^1.34.1",
3333
+ eslint: "^9.7.0",
3334
+ execa: "catalog:tooling",
3335
+ jsdom: "^25.0.1",
3336
+ "kill-port": "2.0.1",
3337
+ react: "catalog:react-native",
3338
+ "react-native": "catalog:react-native",
3339
+ tsup: "^8.3.5",
3340
+ typescript: "5.8.3",
3341
+ vitest: "^3.0.3",
3342
+ "workspace-tools": "^0.38.2"
3343
+ },
3344
+ peerDependencies: {
3345
+ "@granite-js/native": "*",
3346
+ "@granite-js/react-native": "*",
3347
+ "@toss/tds-react-native": ">=2.0.0",
3348
+ "@types/react": "*",
3349
+ "brick-module": "*",
3350
+ react: "*",
3351
+ "react-native": "*"
3352
+ }
3353
+ };
3354
+
3355
+ // src/ads/sdkVersion.ts
3356
+ var SDK_VERSION = package_default.version;
3357
+
3162
3358
  // src/ads/inlineAd/loadAd.ts
3163
3359
  function createError(code, message) {
3164
3360
  return {
@@ -3185,6 +3381,28 @@ function fetchTossAdPromise(options) {
3185
3381
  });
3186
3382
  });
3187
3383
  }
3384
+ function requestAd(adGroupId) {
3385
+ if (fetchAppsInTossAd.isSupported()) {
3386
+ const body = {
3387
+ specVersion: APPS_IN_TOSS_AD_SPEC_VERSION,
3388
+ platform: "RN",
3389
+ spaceUnitId: adGroupId,
3390
+ sdkVersion: SDK_VERSION,
3391
+ availableStyleIds: AVAILABLE_STYLE_IDS,
3392
+ // device는 매크로키만 보내고 native가 실제 device로 치환한다.
3393
+ device: FETCH_APPS_IN_TOSS_AD_DEVICE_MACRO,
3394
+ app: {
3395
+ version: getTossAppVersion3(),
3396
+ bundle: resolveTossAppBundleId(getPlatformOS3()),
3397
+ subBundle: global.__granite?.app?.name ?? ""
3398
+ }
3399
+ };
3400
+ return new Promise((resolve, reject) => {
3401
+ fetchAppsInTossAd({ body, onEvent: resolve, onError: reject });
3402
+ });
3403
+ }
3404
+ return fetchTossAdPromise({ adGroupId, sdkId: SDK_ID, availableStyleIds: AVAILABLE_STYLE_IDS });
3405
+ }
3188
3406
  function isApiResponse(payload) {
3189
3407
  return Boolean(payload && typeof payload === "object" && "resultType" in payload);
3190
3408
  }
@@ -3198,6 +3416,7 @@ function normalizeAdResponse(adResponse) {
3198
3416
  })).filter((ad) => AVAILABLE_STYLE_IDS.includes(String(ad.styleId))) : [];
3199
3417
  return {
3200
3418
  requestId: adResponse.requestId ?? "",
3419
+ eventContextToken: adResponse.eventContextToken ?? "",
3201
3420
  status: adResponse.status ?? "OK",
3202
3421
  ads,
3203
3422
  ext: adResponse.ext
@@ -3238,7 +3457,7 @@ async function loadAd(adGroupId) {
3238
3457
  error: createError(ERROR_CODES.INVALID_SPACE, INVALID_AD_GROUP_ID_ERROR_MESSAGE)
3239
3458
  };
3240
3459
  }
3241
- if (!fetchTossAd.isSupported()) {
3460
+ if (!fetchAppsInTossAd.isSupported() && !fetchTossAd.isSupported()) {
3242
3461
  return {
3243
3462
  type: "error",
3244
3463
  error: createError(ERROR_CODES.SDK_NOT_INITIALIZED, "This feature is not supported in the current environment")
@@ -3246,11 +3465,7 @@ async function loadAd(adGroupId) {
3246
3465
  }
3247
3466
  let response;
3248
3467
  try {
3249
- const raw = await fetchTossAdPromise({
3250
- adGroupId: normalizedAdGroupId,
3251
- sdkId: SDK_ID,
3252
- availableStyleIds: AVAILABLE_STYLE_IDS
3253
- });
3468
+ const raw = await requestAd(normalizedAdGroupId);
3254
3469
  response = normalizeApiResponse(raw);
3255
3470
  } catch (error) {
3256
3471
  if (isAdError(error)) {
@@ -3352,6 +3567,162 @@ function supertossWeb(uri) {
3352
3567
  return `supertoss://web?url=${encodeURIComponent(uri)}&external=true`;
3353
3568
  }
3354
3569
 
3570
+ // src/ads/inlineAd/renderConfig.ts
3571
+ var listBannerPalette = {
3572
+ "1": {
3573
+ light: {
3574
+ title: "#4e5968",
3575
+ subtitle: "#6b7684",
3576
+ adClearance: "#b0b8c1",
3577
+ iconBg: "rgba(2,32,71,0.05)",
3578
+ iconBorder: "rgba(2,32,71,0.05)"
3579
+ },
3580
+ dark: {
3581
+ title: "rgba(253,253,255,0.75)",
3582
+ subtitle: "rgba(248,248,255,0.6)",
3583
+ adClearance: "rgba(242,242,255,0.47)",
3584
+ iconBg: "#ffffff",
3585
+ iconBorder: "rgba(217,217,255,0.11)"
3586
+ }
3587
+ },
3588
+ "2": {
3589
+ light: {
3590
+ title: "#4e5968",
3591
+ subtitle: "#6b7684",
3592
+ adClearance: "#b0b8c1",
3593
+ iconBg: "rgba(2,32,71,0.05)",
3594
+ iconBorder: "rgba(2,32,71,0.05)"
3595
+ },
3596
+ dark: {
3597
+ title: "rgba(253,253,255,0.75)",
3598
+ subtitle: "rgba(248,248,255,0.6)",
3599
+ adClearance: "rgba(242,242,255,0.47)",
3600
+ iconBg: "rgba(217,217,255,0.11)",
3601
+ iconBorder: "rgba(217,217,255,0.11)"
3602
+ }
3603
+ }
3604
+ };
3605
+ var feedBannerPalette = {
3606
+ "1": {
3607
+ light: {
3608
+ brandLogoBg: "rgba(2,32,71,0.05)",
3609
+ brandLogoBorder: "rgba(2,32,71,0.05)",
3610
+ brandName: "#6b7684",
3611
+ adBadge: "#8b95a1",
3612
+ title: "#333d4b",
3613
+ subtitle: "#4e5968",
3614
+ adClearance: "#8b95a1",
3615
+ imageOverlayBorder: "rgba(2,32,71,0.05)"
3616
+ },
3617
+ dark: {
3618
+ brandLogoBg: "#ffffff",
3619
+ brandLogoBorder: "rgba(217,217,255,0.11)",
3620
+ brandName: "#9e9ea4",
3621
+ adBadge: "#7e7e87",
3622
+ title: "#e4e4e5",
3623
+ subtitle: "#c3c3c6",
3624
+ adClearance: "#7e7e87",
3625
+ imageOverlayBorder: "rgba(217,217,255,0.11)"
3626
+ }
3627
+ },
3628
+ "2": {
3629
+ light: {
3630
+ brandLogoBg: "rgba(2,32,71,0.05)",
3631
+ brandLogoBorder: "rgba(2,32,71,0.05)",
3632
+ brandName: "#6b7684",
3633
+ adBadge: "#8b95a1",
3634
+ title: "#333d4b",
3635
+ subtitle: "#4e5968",
3636
+ adClearance: "#8b95a1",
3637
+ imageOverlayBorder: "rgba(2,32,71,0.05)"
3638
+ },
3639
+ dark: {
3640
+ brandLogoBg: "rgba(217,217,255,0.11)",
3641
+ brandLogoBorder: "rgba(217,217,255,0.11)",
3642
+ brandName: "#9e9ea4",
3643
+ adBadge: "#7e7e87",
3644
+ title: "#e4e4e5",
3645
+ subtitle: "#c3c3c6",
3646
+ adClearance: "#7e7e87",
3647
+ imageOverlayBorder: "rgba(217,217,255,0.11)"
3648
+ }
3649
+ }
3650
+ };
3651
+ function resolveCreativeVersion(creativeVersion) {
3652
+ return String(creativeVersion) === "2" ? "2" : "1";
3653
+ }
3654
+ function resolveListBannerRenderConfig(creativeVersion, theme) {
3655
+ const version = resolveCreativeVersion(creativeVersion);
3656
+ const isV2 = version === "2";
3657
+ return {
3658
+ colors: listBannerPalette[version][theme],
3659
+ defaultPaddingValue: DEFAULT_INLINE_AD_PADDING_BANNER,
3660
+ titleSlotId: isV2 ? "1001" : "101",
3661
+ subtitleSlotId: isV2 ? "1002" : "102",
3662
+ iconImageSlotId: isV2 ? "2505" : "202",
3663
+ adClearancePaddingRight: isV2 ? 24 : void 0
3664
+ };
3665
+ }
3666
+ function resolveFeedBannerRenderConfig(creativeVersion, theme) {
3667
+ const version = resolveCreativeVersion(creativeVersion);
3668
+ const isV2 = version === "2";
3669
+ return {
3670
+ colors: feedBannerPalette[version][theme],
3671
+ defaultPaddingValue: isV2 ? DEFAULT_INLINE_AD_PADDING_BANNER : DEFAULT_INLINE_AD_PADDING_NATIVE_IMAGE,
3672
+ brandImageSlotId: isV2 ? "2500" : "202",
3673
+ brandNameSlotId: isV2 ? "1004" : "103",
3674
+ titleSlotId: isV2 ? "1000" : "101",
3675
+ subtitleSlotId: isV2 ? "1002" : "102",
3676
+ mainImageSlotId: isV2 ? "2005" : "201",
3677
+ ctaButtonSlotId: "0",
3678
+ adBadgeText: isV2 ? "AD" : "\uAD11\uACE0",
3679
+ showTextArea: !isV2,
3680
+ adBadgePaddingLeft: isV2 ? 1 : void 0,
3681
+ imageButtonBackgroundColor: isV2 ? "#000000" : void 0,
3682
+ cardOverlayBorderWidth: isV2 ? 1.5 : void 0
3683
+ };
3684
+ }
3685
+
3686
+ // src/ads/inlineAd/resultTracking.ts
3687
+ async function fireResultTracking(result, adGroupId, ctx) {
3688
+ if (result.type !== "success") {
3689
+ return;
3690
+ }
3691
+ if (ctx.resultEndpoint == null || ctx.mediationId == null) {
3692
+ return;
3693
+ }
3694
+ const body = {
3695
+ mediationId: ctx.mediationId,
3696
+ spaceUnitId: adGroupId,
3697
+ requestId: result.response?.requestId ?? "",
3698
+ eventContextToken: ctx.eventContextToken,
3699
+ winnerSource: "TOSS",
3700
+ content: null,
3701
+ adUnitId: ctx.adUnitId ?? null,
3702
+ placementId: ctx.placementId ?? null,
3703
+ tossFailed: null
3704
+ };
3705
+ try {
3706
+ const res = await fetch(ctx.resultEndpoint, {
3707
+ method: "POST",
3708
+ headers: { "Content-Type": "application/json" },
3709
+ body: JSON.stringify(body)
3710
+ });
3711
+ if (!res.ok) {
3712
+ throw new Error(`HTTP ${res.status}`);
3713
+ }
3714
+ } catch (error) {
3715
+ trackBannerError({
3716
+ errorCode: ERROR_CODES.NETWORK_ERROR,
3717
+ errorMessage: `RESULT_TRACKING failed: ${error instanceof Error ? error.message : String(error)}`,
3718
+ adGroupId,
3719
+ mediationId: ctx.mediationId,
3720
+ eventContextToken: ctx.eventContextToken,
3721
+ endpointError: ctx.errorEndpoint
3722
+ });
3723
+ }
3724
+ }
3725
+
3355
3726
  // src/ads/inlineAd/tracking.ts
3356
3727
  var GlobalEventDeduplicator = class _GlobalEventDeduplicator {
3357
3728
  static MAX_EVENTS = 1e4;
@@ -3374,12 +3745,13 @@ var GlobalEventDeduplicator = class _GlobalEventDeduplicator {
3374
3745
  };
3375
3746
  var globalEventDeduplicator = new GlobalEventDeduplicator();
3376
3747
  var EventTracker = class {
3377
- constructor(eventTrackingUrls = [], eventTypes = [], eventPayload = "", requestId, creativeId, requestHeaders) {
3748
+ constructor(eventTrackingUrls = [], eventTypes = [], eventPayload = "", requestId, creativeId, requestHeaders, onTrackingError) {
3378
3749
  this.eventTrackingUrls = eventTrackingUrls;
3379
3750
  this.eventPayload = eventPayload;
3380
3751
  this.requestId = requestId;
3381
3752
  this.creativeId = creativeId;
3382
3753
  this.requestHeaders = requestHeaders;
3754
+ this.onTrackingError = onTrackingError;
3383
3755
  this.eventTypes = new Set(eventTypes);
3384
3756
  this.repeatableEvents = /* @__PURE__ */ new Set(["VIEW_MUTE", "VIEW_UNMUTE"]);
3385
3757
  }
@@ -3403,7 +3775,13 @@ var EventTracker = class {
3403
3775
  type: eventType,
3404
3776
  data: this.eventPayload
3405
3777
  };
3406
- await Promise.allSettled(this.eventTrackingUrls.map((url) => this.sendTrackingRequest(url, payload)));
3778
+ const results = await Promise.allSettled(
3779
+ this.eventTrackingUrls.map((url) => this.sendTrackingRequest(url, payload))
3780
+ );
3781
+ const failedUrls = this.eventTrackingUrls.filter((_, index) => results[index]?.status === "rejected");
3782
+ if (failedUrls.length > 0) {
3783
+ this.onTrackingError?.(failedUrls);
3784
+ }
3407
3785
  if (!this.repeatableEvents.has(eventType) && this.requestId && this.creativeId) {
3408
3786
  globalEventDeduplicator.markTracked(this.requestId, this.creativeId, eventType);
3409
3787
  }
@@ -3416,14 +3794,33 @@ var EventTracker = class {
3416
3794
  if (this.requestId) {
3417
3795
  headers["X-Toss-RequestId"] = this.requestId;
3418
3796
  }
3419
- await fetch(url, {
3797
+ const response = await fetch(url, {
3420
3798
  method: "POST",
3421
3799
  headers,
3422
3800
  body: JSON.stringify(payload)
3423
3801
  });
3802
+ if (!response.ok) {
3803
+ throw new Error(`HTTP ${response.status}`);
3804
+ }
3424
3805
  }
3425
3806
  };
3426
3807
 
3808
+ // src/ads/inlineAd/trackingContext.ts
3809
+ function nonEmptyString(value) {
3810
+ return typeof value === "string" && value.length > 0 ? value : void 0;
3811
+ }
3812
+ function extractAdTrackingContext(response) {
3813
+ const mediation = response?.ext?.mediation;
3814
+ return {
3815
+ mediationId: nonEmptyString(mediation?.mediationId),
3816
+ eventContextToken: nonEmptyString(response?.eventContextToken),
3817
+ resultEndpoint: nonEmptyString(mediation?.endpoint?.result),
3818
+ errorEndpoint: nonEmptyString(mediation?.endpoint?.error),
3819
+ adUnitId: nonEmptyString(mediation?.admob?.adUnitId),
3820
+ placementId: typeof mediation?.admob?.placementId === "number" ? mediation.admob.placementId : void 0
3821
+ };
3822
+ }
3823
+
3427
3824
  // src/ads/inlineAd/ui/FeedBannerAdView.tsx
3428
3825
  import { Path, Svg } from "@granite-js/native/react-native-svg";
3429
3826
  import { useRef as useRef6 } from "react";
@@ -3441,6 +3838,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
3838
  function FeedBannerAdView({
3442
3839
  brandName,
3443
3840
  brandLogoUri,
3841
+ brandImageSlotId,
3842
+ brandNameSlotId,
3843
+ titleSlotId,
3844
+ subtitleSlotId,
3845
+ mainImageSlotId,
3846
+ ctaButtonSlotId,
3444
3847
  title,
3445
3848
  subtitle,
3446
3849
  mainImageUri,
@@ -3448,6 +3851,11 @@ function FeedBannerAdView({
3448
3851
  ctaTextColor,
3449
3852
  ctaBackgroundColor,
3450
3853
  adClearanceText,
3854
+ adBadgeText,
3855
+ showTextArea,
3856
+ adBadgePaddingLeft,
3857
+ imageButtonBackgroundColor,
3858
+ cardOverlayBorderWidth,
3451
3859
  colors: colors4,
3452
3860
  isAdBadgeEnabled,
3453
3861
  paddingStyle,
@@ -3485,7 +3893,7 @@ function FeedBannerAdView({
3485
3893
  Pressable2,
3486
3894
  {
3487
3895
  accessibilityRole: "button",
3488
- onPress: () => onPress("202"),
3896
+ onPress: () => onPress(brandImageSlotId),
3489
3897
  onPressIn: handlePressIn,
3490
3898
  onPressOut: handlePressOut,
3491
3899
  style: styles.logoContainer,
@@ -3500,7 +3908,7 @@ function FeedBannerAdView({
3500
3908
  Pressable2,
3501
3909
  {
3502
3910
  accessibilityRole: "button",
3503
- onPress: () => onPress("103"),
3911
+ onPress: () => onPress(brandNameSlotId),
3504
3912
  onPressIn: handlePressIn,
3505
3913
  onPressOut: handlePressOut,
3506
3914
  children: /* @__PURE__ */ jsx25(
@@ -3514,15 +3922,23 @@ function FeedBannerAdView({
3514
3922
  )
3515
3923
  }
3516
3924
  ),
3517
- isAdBadgeEnabled ? /* @__PURE__ */ jsx25(Text2, { allowFontScaling: false, numberOfLines: 1, style: [styles.adBadge, { color: colors4.adBadge }], children: "\uAD11\uACE0" }) : null
3925
+ isAdBadgeEnabled ? /* @__PURE__ */ jsx25(
3926
+ Text2,
3927
+ {
3928
+ allowFontScaling: false,
3929
+ numberOfLines: 1,
3930
+ style: [styles.adBadge, { color: colors4.adBadge, paddingLeft: adBadgePaddingLeft }],
3931
+ children: adBadgeText
3932
+ }
3933
+ ) : null
3518
3934
  ] })
3519
3935
  ] }),
3520
- /* @__PURE__ */ jsxs11(View7, { style: styles.textArea, children: [
3936
+ showTextArea ? /* @__PURE__ */ jsxs11(View7, { style: styles.textArea, children: [
3521
3937
  /* @__PURE__ */ jsx25(
3522
3938
  Pressable2,
3523
3939
  {
3524
3940
  accessibilityRole: "button",
3525
- onPress: () => onPress("101"),
3941
+ onPress: () => onPress(titleSlotId),
3526
3942
  onPressIn: handlePressIn,
3527
3943
  onPressOut: handlePressOut,
3528
3944
  children: /* @__PURE__ */ jsx25(Text2, { allowFontScaling: false, style: [styles.title, { color: colors4.title }], children: title })
@@ -3532,23 +3948,26 @@ function FeedBannerAdView({
3532
3948
  Pressable2,
3533
3949
  {
3534
3950
  accessibilityRole: "button",
3535
- onPress: () => onPress("102"),
3951
+ onPress: () => onPress(subtitleSlotId),
3536
3952
  onPressIn: handlePressIn,
3537
3953
  onPressOut: handlePressOut,
3538
3954
  children: /* @__PURE__ */ jsx25(Text2, { allowFontScaling: false, style: [styles.subtitle, { color: colors4.subtitle }], children: subtitle })
3539
3955
  }
3540
3956
  )
3541
- ] })
3957
+ ] }) : null
3542
3958
  ] }),
3543
3959
  /* @__PURE__ */ jsxs11(View7, { style: styles.card, children: [
3544
3960
  /* @__PURE__ */ jsx25(
3545
3961
  Pressable2,
3546
3962
  {
3547
3963
  accessibilityRole: "button",
3548
- onPress: () => onPress("201"),
3964
+ onPress: () => onPress(mainImageSlotId),
3549
3965
  onPressIn: handlePressIn,
3550
3966
  onPressOut: handlePressOut,
3551
- style: styles.imageButton,
3967
+ style: [
3968
+ styles.imageButton,
3969
+ imageButtonBackgroundColor ? { backgroundColor: imageButtonBackgroundColor } : null
3970
+ ],
3552
3971
  children: /* @__PURE__ */ jsx25(View7, { style: styles.imageContainer, children: mainImageUri ? /* @__PURE__ */ jsx25(Image2, { source: { uri: mainImageUri }, style: styles.mainImage, resizeMode: "cover" }) : null })
3553
3972
  }
3554
3973
  ),
@@ -3556,7 +3975,7 @@ function FeedBannerAdView({
3556
3975
  Pressable2,
3557
3976
  {
3558
3977
  accessibilityRole: "button",
3559
- onPress: () => onPress("0"),
3978
+ onPress: () => onPress(ctaButtonSlotId),
3560
3979
  onPressIn: handlePressIn,
3561
3980
  onPressOut: handlePressOut,
3562
3981
  style: [styles.cta, { backgroundColor: resolvedCtaBackground }],
@@ -3566,7 +3985,18 @@ function FeedBannerAdView({
3566
3985
  ]
3567
3986
  }
3568
3987
  ),
3569
- /* @__PURE__ */ jsx25(View7, { style: [styles.cardOverlay, { borderColor: colors4.imageOverlayBorder }] })
3988
+ /* @__PURE__ */ jsx25(
3989
+ View7,
3990
+ {
3991
+ style: [
3992
+ styles.cardOverlay,
3993
+ {
3994
+ borderColor: colors4.imageOverlayBorder,
3995
+ borderWidth: cardOverlayBorderWidth ?? styles.cardOverlay.borderWidth
3996
+ }
3997
+ ]
3998
+ }
3999
+ )
3570
4000
  ] }),
3571
4001
  adClearanceText ? /* @__PURE__ */ jsx25(Text2, { allowFontScaling: false, style: [styles.adClearance, { color: colors4.adClearance }], children: adClearanceText }) : null
3572
4002
  ] })
@@ -3696,8 +4126,12 @@ var SQUIRCLE_PATH = "M0 17.352C0 3.564 3.564 0 17.352 0H18.648C32.436 0 36 3.564
3696
4126
  function ListBannerAdView({
3697
4127
  title,
3698
4128
  subtitle,
4129
+ titleSlotId,
4130
+ subtitleSlotId,
4131
+ iconImageSlotId,
3699
4132
  adClearanceText,
3700
4133
  adClearanceFontSize,
4134
+ adClearancePaddingRight,
3701
4135
  imageUri,
3702
4136
  paddingStyle,
3703
4137
  colors: colors4,
@@ -3733,7 +4167,7 @@ function ListBannerAdView({
3733
4167
  Pressable3,
3734
4168
  {
3735
4169
  accessibilityRole: "button",
3736
- onPress: () => onPress("202"),
4170
+ onPress: () => onPress(iconImageSlotId),
3737
4171
  onPressIn: handlePressIn,
3738
4172
  onPressOut: handlePressOut,
3739
4173
  style: styles2.iconWrapper,
@@ -3768,7 +4202,7 @@ function ListBannerAdView({
3768
4202
  Pressable3,
3769
4203
  {
3770
4204
  accessibilityRole: "button",
3771
- onPress: () => onPress("101"),
4205
+ onPress: () => onPress(titleSlotId),
3772
4206
  onPressIn: handlePressIn,
3773
4207
  onPressOut: handlePressOut,
3774
4208
  children: /* @__PURE__ */ jsx26(Text3, { allowFontScaling: false, style: [styles2.title, { color: colors4.title }], children: title })
@@ -3778,7 +4212,7 @@ function ListBannerAdView({
3778
4212
  Pressable3,
3779
4213
  {
3780
4214
  accessibilityRole: "button",
3781
- onPress: () => onPress("102"),
4215
+ onPress: () => onPress(subtitleSlotId),
3782
4216
  onPressIn: handlePressIn,
3783
4217
  onPressOut: handlePressOut,
3784
4218
  children: /* @__PURE__ */ jsx26(Text3, { allowFontScaling: false, style: [styles2.subtitle, { color: colors4.subtitle }], children: subtitle })
@@ -3795,7 +4229,8 @@ function ListBannerAdView({
3795
4229
  {
3796
4230
  color: colors4.adClearance,
3797
4231
  fontSize: adClearanceFontSize,
3798
- lineHeight: adClearanceFontSize * 1.2
4232
+ lineHeight: adClearanceFontSize * 1.2,
4233
+ paddingRight: adClearancePaddingRight
3799
4234
  }
3800
4235
  ],
3801
4236
  children: adClearanceText
@@ -3907,12 +4342,12 @@ function buildBannerEventPayload(slotId, adGroupId, ad) {
3907
4342
  }
3908
4343
  };
3909
4344
  }
3910
- function buildBannerErrorPayload(slotId, adGroupId, error) {
4345
+ function buildBannerErrorPayload(slotId, adGroupId, error, mediationId) {
3911
4346
  return {
3912
4347
  slotId,
3913
4348
  adGroupId,
3914
4349
  adMetadata: {},
3915
- error
4350
+ error: mediationId ? { ...error, mediationId } : error
3916
4351
  };
3917
4352
  }
3918
4353
  function buildNoFillPayload(slotId, adGroupId) {
@@ -3925,44 +4360,6 @@ function buildNoFillPayload(slotId, adGroupId) {
3925
4360
 
3926
4361
  // src/ads/inlineAd/InlineAd.tsx
3927
4362
  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
4363
  function createError2(code, message) {
3967
4364
  return {
3968
4365
  code,
@@ -4040,8 +4437,6 @@ function InlineAd(props) {
4040
4437
  const resolvedTheme = selectedTheme === "auto" ? colorScheme === "dark" ? "dark" : "light" : selectedTheme;
4041
4438
  const resolvedTone = tone ?? DEFAULT_INLINE_AD_TONE;
4042
4439
  const resolvedVariant = variant ?? DEFAULT_INLINE_AD_VARIANT;
4043
- const colors4 = themePalette[resolvedTheme];
4044
- const feedColors = feedThemePalette[resolvedTheme];
4045
4440
  const backgroundColor = resolvedTone === "grey" ? resolvedTheme === "dark" ? "#101013" : "#f2f4f7" : resolvedTheme === "dark" ? "#17171c" : "#ffffff";
4046
4441
  callbacksRef.current = {
4047
4442
  onAdRendered,
@@ -4063,35 +4458,43 @@ function InlineAd(props) {
4063
4458
  }, []);
4064
4459
  useEffect14(() => {
4065
4460
  const normalizedAdGroupId = normalizeAdGroupId(adGroupId);
4461
+ const emitFailure = (error, responseContext) => {
4462
+ callbacksRef.current.onAdFailedToRender?.(
4463
+ buildBannerErrorPayload(slotIdRef.current, normalizedAdGroupId, error, responseContext?.mediationId)
4464
+ );
4465
+ trackBannerError({
4466
+ errorCode: error.code,
4467
+ errorMessage: error.message,
4468
+ adGroupId: normalizedAdGroupId,
4469
+ mediationId: responseContext?.mediationId,
4470
+ eventContextToken: responseContext?.eventContextToken,
4471
+ endpointError: responseContext?.errorEndpoint
4472
+ });
4473
+ };
4066
4474
  const loadAdRequest = () => {
4067
4475
  if (loadingRef.current) {
4068
4476
  return;
4069
4477
  }
4070
4478
  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
- );
4479
+ emitFailure(createError2(ERROR_CODES.INVALID_SPACE, INVALID_AD_GROUP_ID_ERROR_MESSAGE));
4075
4480
  return;
4076
4481
  }
4077
4482
  loadingRef.current = true;
4078
4483
  loadAd(normalizedAdGroupId).then((result) => {
4079
4484
  if (!isMountedRef.current) return;
4485
+ const responseContext = extractAdTrackingContext(result.response);
4486
+ void fireResultTracking(result, normalizedAdGroupId, responseContext);
4080
4487
  if (result.type === "noFill") {
4081
4488
  callbacksRef.current.onNoFill?.(buildNoFillPayload(slotIdRef.current, normalizedAdGroupId));
4082
4489
  return;
4083
4490
  }
4084
4491
  if (result.type === "error") {
4085
- callbacksRef.current.onAdFailedToRender?.(
4086
- buildBannerErrorPayload(slotIdRef.current, normalizedAdGroupId, result.error)
4087
- );
4492
+ emitFailure(result.error, responseContext);
4088
4493
  return;
4089
4494
  }
4090
4495
  if (!isValidCreative(result.ad)) {
4091
4496
  const invalidError = createError2(ERROR_CODES.INTERNAL_ERROR, "Invalid creative payload");
4092
- callbacksRef.current.onAdFailedToRender?.(
4093
- buildBannerErrorPayload(slotIdRef.current, normalizedAdGroupId, invalidError)
4094
- );
4497
+ emitFailure(invalidError, responseContext);
4095
4498
  return;
4096
4499
  }
4097
4500
  if (result.responseExt?.refetchSeconds !== void 0) {
@@ -4108,21 +4511,29 @@ function InlineAd(props) {
4108
4511
  }
4109
4512
  const payload = buildBannerEventPayload(slotIdRef.current, normalizedAdGroupId, result.ad);
4110
4513
  eventPayloadRef.current = payload;
4514
+ const reportEventTrackingFailure = (failedUrls) => trackBannerError({
4515
+ errorCode: ERROR_CODES.NETWORK_ERROR,
4516
+ errorMessage: `eventTracking delivery failed (${failedUrls.length})`,
4517
+ adGroupId: normalizedAdGroupId,
4518
+ mediationId: responseContext.mediationId,
4519
+ eventContextToken: responseContext.eventContextToken,
4520
+ endpointError: responseContext.errorEndpoint
4521
+ });
4111
4522
  eventTrackerRef.current = new EventTracker(
4112
4523
  result.ad.eventTrackingUrls ?? [],
4113
4524
  result.ad.eventTypes ?? [],
4114
4525
  result.ad.eventPayload ?? "",
4115
4526
  result.requestId,
4116
- result.ad.creative?.id
4527
+ result.ad.creative?.id,
4528
+ void 0,
4529
+ reportEventTrackingFailure
4117
4530
  );
4118
4531
  setIsAdBadgeEnabled(result.responseExt?.isAdBadgeEnabled !== false);
4119
4532
  setAd(result.ad);
4120
4533
  }).catch((error) => {
4121
4534
  if (!isMountedRef.current) return;
4122
4535
  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
- );
4536
+ emitFailure(adError);
4126
4537
  }).finally(() => {
4127
4538
  loadingRef.current = false;
4128
4539
  });
@@ -4161,7 +4572,9 @@ function InlineAd(props) {
4161
4572
  }
4162
4573
  const impressionKey = `${ad.requestId ?? "request"}:${ad.creative?.id ?? "creative"}`;
4163
4574
  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;
4575
+ const listBannerConfig = resolveListBannerRenderConfig(ad.creativeVersion, resolvedTheme);
4576
+ const feedBannerConfig = resolveFeedBannerRenderConfig(ad.creativeVersion, resolvedTheme);
4577
+ const defaultPaddingValue = resolvedStyleId === LIST_BANNER_STYLE_ID ? listBannerConfig.defaultPaddingValue : feedBannerConfig.defaultPaddingValue;
4165
4578
  const paddingStyle = resolvePaddingStyle(defaultPaddingValue);
4166
4579
  const isListBanner = String(resolvedStyleId) === LIST_BANNER_STYLE_ID;
4167
4580
  const isFeedBanner = String(resolvedStyleId) === FEED_BANNER_STYLE_ID;
@@ -4257,11 +4670,15 @@ function InlineAd(props) {
4257
4670
  {
4258
4671
  title: listCreative.title,
4259
4672
  subtitle: subtitleText,
4673
+ titleSlotId: listBannerConfig.titleSlotId,
4674
+ subtitleSlotId: listBannerConfig.subtitleSlotId,
4675
+ iconImageSlotId: listBannerConfig.iconImageSlotId,
4260
4676
  adClearanceText,
4261
4677
  adClearanceFontSize,
4678
+ adClearancePaddingRight: listBannerConfig.adClearancePaddingRight,
4262
4679
  imageUri,
4263
4680
  paddingStyle,
4264
- colors: colors4,
4681
+ colors: listBannerConfig.colors,
4265
4682
  onPress: handleClick
4266
4683
  }
4267
4684
  ) : null,
@@ -4270,6 +4687,12 @@ function InlineAd(props) {
4270
4687
  {
4271
4688
  brandName: feedCreative.brandName,
4272
4689
  brandLogoUri,
4690
+ brandImageSlotId: feedBannerConfig.brandImageSlotId,
4691
+ brandNameSlotId: feedBannerConfig.brandNameSlotId,
4692
+ titleSlotId: feedBannerConfig.titleSlotId,
4693
+ subtitleSlotId: feedBannerConfig.subtitleSlotId,
4694
+ mainImageSlotId: feedBannerConfig.mainImageSlotId,
4695
+ ctaButtonSlotId: feedBannerConfig.ctaButtonSlotId,
4273
4696
  title: feedCreative.title,
4274
4697
  subtitle: feedCreative.subTitle,
4275
4698
  mainImageUri,
@@ -4277,7 +4700,12 @@ function InlineAd(props) {
4277
4700
  ctaTextColor: feedCreative.ctaTextColor,
4278
4701
  ctaBackgroundColor: feedCreative.ctaBackgroundColor,
4279
4702
  adClearanceText,
4280
- colors: feedColors,
4703
+ adBadgeText: feedBannerConfig.adBadgeText,
4704
+ showTextArea: feedBannerConfig.showTextArea,
4705
+ adBadgePaddingLeft: feedBannerConfig.adBadgePaddingLeft,
4706
+ imageButtonBackgroundColor: feedBannerConfig.imageButtonBackgroundColor,
4707
+ cardOverlayBorderWidth: feedBannerConfig.cardOverlayBorderWidth,
4708
+ colors: feedBannerConfig.colors,
4281
4709
  isAdBadgeEnabled,
4282
4710
  paddingStyle,
4283
4711
  onPress: handleClick