@apps-in-toss/framework 2.9.2 → 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
  {
@@ -2155,7 +2195,8 @@ function showFullScreenAd(params) {
2155
2195
  onEvent({ type: "show" });
2156
2196
  },
2157
2197
  onUserEarnedReward: (data) => {
2158
- onEvent({ type: "userEarnedReward", data });
2198
+ const normalized = "type" in data ? { unitType: data.type, unitAmount: data.amount } : data;
2199
+ onEvent({ type: "userEarnedReward", data: normalized });
2159
2200
  },
2160
2201
  onSuccess: () => {
2161
2202
  onEvent({ type: "requested" });
@@ -2700,7 +2741,7 @@ function useTopNavigation() {
2700
2741
  }
2701
2742
 
2702
2743
  // src/hooks/useWebViewMemoryDebug.tsx
2703
- import { getOperationalEnvironment as getOperationalEnvironment8 } from "@apps-in-toss/native-modules";
2744
+ import { getOperationalEnvironment as getOperationalEnvironment9 } from "@apps-in-toss/native-modules";
2704
2745
  import { Granite as Granite8 } from "@granite-js/react-native";
2705
2746
  import { useToast } from "@toss/tds-react-native";
2706
2747
  function useHandleWebViewProcessDidTerminate(webViewRef) {
@@ -2728,7 +2769,7 @@ function webViewDebugLog(logName, params) {
2728
2769
  deployment_id: global2.deploymentId
2729
2770
  }
2730
2771
  };
2731
- if (getOperationalEnvironment8() === "toss") {
2772
+ if (getOperationalEnvironment9() === "toss") {
2732
2773
  sendLog(event, { pipelines: ["core"] });
2733
2774
  } else {
2734
2775
  console.log("[webViewDebugLog]", event);
@@ -2874,6 +2915,8 @@ function WebView({ type, local, onMessage, ...props }) {
2874
2915
  showFullScreenAd,
2875
2916
  /** TossAd */
2876
2917
  fetchTossAd,
2918
+ // v1.4 배너: web 이벤트 브릿지는 payload를 options로 전달하지만 fetchAppsInTossAd는 body로 받으므로 어댑팅한다.
2919
+ fetchAppsInTossAd: ({ onEvent, onError, options }) => fetchAppsInTossAd({ body: options, onEvent, onError }),
2877
2920
  /** IAP */
2878
2921
  iapCreateOneTimePurchaseOrder: IAP.createOneTimePurchaseOrder,
2879
2922
  requestSubscriptionPurchase,
@@ -2895,6 +2938,7 @@ function WebView({ type, local, onMessage, ...props }) {
2895
2938
  showFullScreenAd_isSupported: showFullScreenAd.isSupported,
2896
2939
  /** TossAd */
2897
2940
  fetchTossAd_isSupported: fetchTossAd.isSupported,
2941
+ fetchAppsInTossAd_isSupported: fetchAppsInTossAd.isSupported,
2898
2942
  /** env */
2899
2943
  getDeploymentId: env.getDeploymentId,
2900
2944
  getWebViewType: env.getWebViewType,
@@ -3158,6 +3202,159 @@ var AD_STATUS_ERROR_MAP = {
3158
3202
  }
3159
3203
  };
3160
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
+
3161
3358
  // src/ads/inlineAd/loadAd.ts
3162
3359
  function createError(code, message) {
3163
3360
  return {
@@ -3184,6 +3381,28 @@ function fetchTossAdPromise(options) {
3184
3381
  });
3185
3382
  });
3186
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
+ }
3187
3406
  function isApiResponse(payload) {
3188
3407
  return Boolean(payload && typeof payload === "object" && "resultType" in payload);
3189
3408
  }
@@ -3197,6 +3416,7 @@ function normalizeAdResponse(adResponse) {
3197
3416
  })).filter((ad) => AVAILABLE_STYLE_IDS.includes(String(ad.styleId))) : [];
3198
3417
  return {
3199
3418
  requestId: adResponse.requestId ?? "",
3419
+ eventContextToken: adResponse.eventContextToken ?? "",
3200
3420
  status: adResponse.status ?? "OK",
3201
3421
  ads,
3202
3422
  ext: adResponse.ext
@@ -3237,7 +3457,7 @@ async function loadAd(adGroupId) {
3237
3457
  error: createError(ERROR_CODES.INVALID_SPACE, INVALID_AD_GROUP_ID_ERROR_MESSAGE)
3238
3458
  };
3239
3459
  }
3240
- if (!fetchTossAd.isSupported()) {
3460
+ if (!fetchAppsInTossAd.isSupported() && !fetchTossAd.isSupported()) {
3241
3461
  return {
3242
3462
  type: "error",
3243
3463
  error: createError(ERROR_CODES.SDK_NOT_INITIALIZED, "This feature is not supported in the current environment")
@@ -3245,11 +3465,7 @@ async function loadAd(adGroupId) {
3245
3465
  }
3246
3466
  let response;
3247
3467
  try {
3248
- const raw = await fetchTossAdPromise({
3249
- adGroupId: normalizedAdGroupId,
3250
- sdkId: SDK_ID,
3251
- availableStyleIds: AVAILABLE_STYLE_IDS
3252
- });
3468
+ const raw = await requestAd(normalizedAdGroupId);
3253
3469
  response = normalizeApiResponse(raw);
3254
3470
  } catch (error) {
3255
3471
  if (isAdError(error)) {
@@ -3351,6 +3567,162 @@ function supertossWeb(uri) {
3351
3567
  return `supertoss://web?url=${encodeURIComponent(uri)}&external=true`;
3352
3568
  }
3353
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
+
3354
3726
  // src/ads/inlineAd/tracking.ts
3355
3727
  var GlobalEventDeduplicator = class _GlobalEventDeduplicator {
3356
3728
  static MAX_EVENTS = 1e4;
@@ -3373,12 +3745,13 @@ var GlobalEventDeduplicator = class _GlobalEventDeduplicator {
3373
3745
  };
3374
3746
  var globalEventDeduplicator = new GlobalEventDeduplicator();
3375
3747
  var EventTracker = class {
3376
- constructor(eventTrackingUrls = [], eventTypes = [], eventPayload = "", requestId, creativeId, requestHeaders) {
3748
+ constructor(eventTrackingUrls = [], eventTypes = [], eventPayload = "", requestId, creativeId, requestHeaders, onTrackingError) {
3377
3749
  this.eventTrackingUrls = eventTrackingUrls;
3378
3750
  this.eventPayload = eventPayload;
3379
3751
  this.requestId = requestId;
3380
3752
  this.creativeId = creativeId;
3381
3753
  this.requestHeaders = requestHeaders;
3754
+ this.onTrackingError = onTrackingError;
3382
3755
  this.eventTypes = new Set(eventTypes);
3383
3756
  this.repeatableEvents = /* @__PURE__ */ new Set(["VIEW_MUTE", "VIEW_UNMUTE"]);
3384
3757
  }
@@ -3402,7 +3775,13 @@ var EventTracker = class {
3402
3775
  type: eventType,
3403
3776
  data: this.eventPayload
3404
3777
  };
3405
- 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
+ }
3406
3785
  if (!this.repeatableEvents.has(eventType) && this.requestId && this.creativeId) {
3407
3786
  globalEventDeduplicator.markTracked(this.requestId, this.creativeId, eventType);
3408
3787
  }
@@ -3415,14 +3794,33 @@ var EventTracker = class {
3415
3794
  if (this.requestId) {
3416
3795
  headers["X-Toss-RequestId"] = this.requestId;
3417
3796
  }
3418
- await fetch(url, {
3797
+ const response = await fetch(url, {
3419
3798
  method: "POST",
3420
3799
  headers,
3421
3800
  body: JSON.stringify(payload)
3422
3801
  });
3802
+ if (!response.ok) {
3803
+ throw new Error(`HTTP ${response.status}`);
3804
+ }
3423
3805
  }
3424
3806
  };
3425
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
+
3426
3824
  // src/ads/inlineAd/ui/FeedBannerAdView.tsx
3427
3825
  import { Path, Svg } from "@granite-js/native/react-native-svg";
3428
3826
  import { useRef as useRef6 } from "react";
@@ -3440,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-
3440
3838
  function FeedBannerAdView({
3441
3839
  brandName,
3442
3840
  brandLogoUri,
3841
+ brandImageSlotId,
3842
+ brandNameSlotId,
3843
+ titleSlotId,
3844
+ subtitleSlotId,
3845
+ mainImageSlotId,
3846
+ ctaButtonSlotId,
3443
3847
  title,
3444
3848
  subtitle,
3445
3849
  mainImageUri,
@@ -3447,6 +3851,11 @@ function FeedBannerAdView({
3447
3851
  ctaTextColor,
3448
3852
  ctaBackgroundColor,
3449
3853
  adClearanceText,
3854
+ adBadgeText,
3855
+ showTextArea,
3856
+ adBadgePaddingLeft,
3857
+ imageButtonBackgroundColor,
3858
+ cardOverlayBorderWidth,
3450
3859
  colors: colors4,
3451
3860
  isAdBadgeEnabled,
3452
3861
  paddingStyle,
@@ -3484,7 +3893,7 @@ function FeedBannerAdView({
3484
3893
  Pressable2,
3485
3894
  {
3486
3895
  accessibilityRole: "button",
3487
- onPress: () => onPress("202"),
3896
+ onPress: () => onPress(brandImageSlotId),
3488
3897
  onPressIn: handlePressIn,
3489
3898
  onPressOut: handlePressOut,
3490
3899
  style: styles.logoContainer,
@@ -3499,7 +3908,7 @@ function FeedBannerAdView({
3499
3908
  Pressable2,
3500
3909
  {
3501
3910
  accessibilityRole: "button",
3502
- onPress: () => onPress("103"),
3911
+ onPress: () => onPress(brandNameSlotId),
3503
3912
  onPressIn: handlePressIn,
3504
3913
  onPressOut: handlePressOut,
3505
3914
  children: /* @__PURE__ */ jsx25(
@@ -3513,15 +3922,23 @@ function FeedBannerAdView({
3513
3922
  )
3514
3923
  }
3515
3924
  ),
3516
- 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
3517
3934
  ] })
3518
3935
  ] }),
3519
- /* @__PURE__ */ jsxs11(View7, { style: styles.textArea, children: [
3936
+ showTextArea ? /* @__PURE__ */ jsxs11(View7, { style: styles.textArea, children: [
3520
3937
  /* @__PURE__ */ jsx25(
3521
3938
  Pressable2,
3522
3939
  {
3523
3940
  accessibilityRole: "button",
3524
- onPress: () => onPress("101"),
3941
+ onPress: () => onPress(titleSlotId),
3525
3942
  onPressIn: handlePressIn,
3526
3943
  onPressOut: handlePressOut,
3527
3944
  children: /* @__PURE__ */ jsx25(Text2, { allowFontScaling: false, style: [styles.title, { color: colors4.title }], children: title })
@@ -3531,23 +3948,26 @@ function FeedBannerAdView({
3531
3948
  Pressable2,
3532
3949
  {
3533
3950
  accessibilityRole: "button",
3534
- onPress: () => onPress("102"),
3951
+ onPress: () => onPress(subtitleSlotId),
3535
3952
  onPressIn: handlePressIn,
3536
3953
  onPressOut: handlePressOut,
3537
3954
  children: /* @__PURE__ */ jsx25(Text2, { allowFontScaling: false, style: [styles.subtitle, { color: colors4.subtitle }], children: subtitle })
3538
3955
  }
3539
3956
  )
3540
- ] })
3957
+ ] }) : null
3541
3958
  ] }),
3542
3959
  /* @__PURE__ */ jsxs11(View7, { style: styles.card, children: [
3543
3960
  /* @__PURE__ */ jsx25(
3544
3961
  Pressable2,
3545
3962
  {
3546
3963
  accessibilityRole: "button",
3547
- onPress: () => onPress("201"),
3964
+ onPress: () => onPress(mainImageSlotId),
3548
3965
  onPressIn: handlePressIn,
3549
3966
  onPressOut: handlePressOut,
3550
- style: styles.imageButton,
3967
+ style: [
3968
+ styles.imageButton,
3969
+ imageButtonBackgroundColor ? { backgroundColor: imageButtonBackgroundColor } : null
3970
+ ],
3551
3971
  children: /* @__PURE__ */ jsx25(View7, { style: styles.imageContainer, children: mainImageUri ? /* @__PURE__ */ jsx25(Image2, { source: { uri: mainImageUri }, style: styles.mainImage, resizeMode: "cover" }) : null })
3552
3972
  }
3553
3973
  ),
@@ -3555,7 +3975,7 @@ function FeedBannerAdView({
3555
3975
  Pressable2,
3556
3976
  {
3557
3977
  accessibilityRole: "button",
3558
- onPress: () => onPress("0"),
3978
+ onPress: () => onPress(ctaButtonSlotId),
3559
3979
  onPressIn: handlePressIn,
3560
3980
  onPressOut: handlePressOut,
3561
3981
  style: [styles.cta, { backgroundColor: resolvedCtaBackground }],
@@ -3565,7 +3985,18 @@ function FeedBannerAdView({
3565
3985
  ]
3566
3986
  }
3567
3987
  ),
3568
- /* @__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
+ )
3569
4000
  ] }),
3570
4001
  adClearanceText ? /* @__PURE__ */ jsx25(Text2, { allowFontScaling: false, style: [styles.adClearance, { color: colors4.adClearance }], children: adClearanceText }) : null
3571
4002
  ] })
@@ -3695,8 +4126,12 @@ var SQUIRCLE_PATH = "M0 17.352C0 3.564 3.564 0 17.352 0H18.648C32.436 0 36 3.564
3695
4126
  function ListBannerAdView({
3696
4127
  title,
3697
4128
  subtitle,
4129
+ titleSlotId,
4130
+ subtitleSlotId,
4131
+ iconImageSlotId,
3698
4132
  adClearanceText,
3699
4133
  adClearanceFontSize,
4134
+ adClearancePaddingRight,
3700
4135
  imageUri,
3701
4136
  paddingStyle,
3702
4137
  colors: colors4,
@@ -3732,7 +4167,7 @@ function ListBannerAdView({
3732
4167
  Pressable3,
3733
4168
  {
3734
4169
  accessibilityRole: "button",
3735
- onPress: () => onPress("202"),
4170
+ onPress: () => onPress(iconImageSlotId),
3736
4171
  onPressIn: handlePressIn,
3737
4172
  onPressOut: handlePressOut,
3738
4173
  style: styles2.iconWrapper,
@@ -3767,7 +4202,7 @@ function ListBannerAdView({
3767
4202
  Pressable3,
3768
4203
  {
3769
4204
  accessibilityRole: "button",
3770
- onPress: () => onPress("101"),
4205
+ onPress: () => onPress(titleSlotId),
3771
4206
  onPressIn: handlePressIn,
3772
4207
  onPressOut: handlePressOut,
3773
4208
  children: /* @__PURE__ */ jsx26(Text3, { allowFontScaling: false, style: [styles2.title, { color: colors4.title }], children: title })
@@ -3777,7 +4212,7 @@ function ListBannerAdView({
3777
4212
  Pressable3,
3778
4213
  {
3779
4214
  accessibilityRole: "button",
3780
- onPress: () => onPress("102"),
4215
+ onPress: () => onPress(subtitleSlotId),
3781
4216
  onPressIn: handlePressIn,
3782
4217
  onPressOut: handlePressOut,
3783
4218
  children: /* @__PURE__ */ jsx26(Text3, { allowFontScaling: false, style: [styles2.subtitle, { color: colors4.subtitle }], children: subtitle })
@@ -3794,7 +4229,8 @@ function ListBannerAdView({
3794
4229
  {
3795
4230
  color: colors4.adClearance,
3796
4231
  fontSize: adClearanceFontSize,
3797
- lineHeight: adClearanceFontSize * 1.2
4232
+ lineHeight: adClearanceFontSize * 1.2,
4233
+ paddingRight: adClearancePaddingRight
3798
4234
  }
3799
4235
  ],
3800
4236
  children: adClearanceText
@@ -3906,12 +4342,12 @@ function buildBannerEventPayload(slotId, adGroupId, ad) {
3906
4342
  }
3907
4343
  };
3908
4344
  }
3909
- function buildBannerErrorPayload(slotId, adGroupId, error) {
4345
+ function buildBannerErrorPayload(slotId, adGroupId, error, mediationId) {
3910
4346
  return {
3911
4347
  slotId,
3912
4348
  adGroupId,
3913
4349
  adMetadata: {},
3914
- error
4350
+ error: mediationId ? { ...error, mediationId } : error
3915
4351
  };
3916
4352
  }
3917
4353
  function buildNoFillPayload(slotId, adGroupId) {
@@ -3924,44 +4360,6 @@ function buildNoFillPayload(slotId, adGroupId) {
3924
4360
 
3925
4361
  // src/ads/inlineAd/InlineAd.tsx
3926
4362
  import { jsx as jsx27, jsxs as jsxs13 } from "react/jsx-runtime";
3927
- var themePalette = {
3928
- light: {
3929
- title: "#4e5968",
3930
- subtitle: "#6b7684",
3931
- adClearance: "#b0b8c1",
3932
- iconBg: "rgba(2,32,71,0.05)",
3933
- iconBorder: "rgba(2,32,71,0.05)"
3934
- },
3935
- dark: {
3936
- title: "rgba(253,253,255,0.75)",
3937
- subtitle: "rgba(248,248,255,0.6)",
3938
- adClearance: "rgba(242,242,255,0.47)",
3939
- iconBg: "#ffffff",
3940
- iconBorder: "rgba(217,217,255,0.11)"
3941
- }
3942
- };
3943
- var feedThemePalette = {
3944
- light: {
3945
- brandLogoBg: "rgba(2,32,71,0.05)",
3946
- brandLogoBorder: "rgba(2,32,71,0.05)",
3947
- brandName: "#6b7684",
3948
- adBadge: "#8b95a1",
3949
- title: "#333d4b",
3950
- subtitle: "#4e5968",
3951
- adClearance: "#8b95a1",
3952
- imageOverlayBorder: "rgba(2,32,71,0.05)"
3953
- },
3954
- dark: {
3955
- brandLogoBg: "#ffffff",
3956
- brandLogoBorder: "rgba(217,217,255,0.11)",
3957
- brandName: "#9e9ea4",
3958
- adBadge: "#7e7e87",
3959
- title: "#e4e4e5",
3960
- subtitle: "#c3c3c6",
3961
- adClearance: "#7e7e87",
3962
- imageOverlayBorder: "rgba(217,217,255,0.11)"
3963
- }
3964
- };
3965
4363
  function createError2(code, message) {
3966
4364
  return {
3967
4365
  code,
@@ -4039,8 +4437,6 @@ function InlineAd(props) {
4039
4437
  const resolvedTheme = selectedTheme === "auto" ? colorScheme === "dark" ? "dark" : "light" : selectedTheme;
4040
4438
  const resolvedTone = tone ?? DEFAULT_INLINE_AD_TONE;
4041
4439
  const resolvedVariant = variant ?? DEFAULT_INLINE_AD_VARIANT;
4042
- const colors4 = themePalette[resolvedTheme];
4043
- const feedColors = feedThemePalette[resolvedTheme];
4044
4440
  const backgroundColor = resolvedTone === "grey" ? resolvedTheme === "dark" ? "#101013" : "#f2f4f7" : resolvedTheme === "dark" ? "#17171c" : "#ffffff";
4045
4441
  callbacksRef.current = {
4046
4442
  onAdRendered,
@@ -4062,35 +4458,43 @@ function InlineAd(props) {
4062
4458
  }, []);
4063
4459
  useEffect14(() => {
4064
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
+ };
4065
4474
  const loadAdRequest = () => {
4066
4475
  if (loadingRef.current) {
4067
4476
  return;
4068
4477
  }
4069
4478
  if (normalizedAdGroupId.length === 0) {
4070
- const error = createError2(ERROR_CODES.INVALID_SPACE, INVALID_AD_GROUP_ID_ERROR_MESSAGE);
4071
- callbacksRef.current.onAdFailedToRender?.(
4072
- buildBannerErrorPayload(slotIdRef.current, normalizedAdGroupId, error)
4073
- );
4479
+ emitFailure(createError2(ERROR_CODES.INVALID_SPACE, INVALID_AD_GROUP_ID_ERROR_MESSAGE));
4074
4480
  return;
4075
4481
  }
4076
4482
  loadingRef.current = true;
4077
4483
  loadAd(normalizedAdGroupId).then((result) => {
4078
4484
  if (!isMountedRef.current) return;
4485
+ const responseContext = extractAdTrackingContext(result.response);
4486
+ void fireResultTracking(result, normalizedAdGroupId, responseContext);
4079
4487
  if (result.type === "noFill") {
4080
4488
  callbacksRef.current.onNoFill?.(buildNoFillPayload(slotIdRef.current, normalizedAdGroupId));
4081
4489
  return;
4082
4490
  }
4083
4491
  if (result.type === "error") {
4084
- callbacksRef.current.onAdFailedToRender?.(
4085
- buildBannerErrorPayload(slotIdRef.current, normalizedAdGroupId, result.error)
4086
- );
4492
+ emitFailure(result.error, responseContext);
4087
4493
  return;
4088
4494
  }
4089
4495
  if (!isValidCreative(result.ad)) {
4090
4496
  const invalidError = createError2(ERROR_CODES.INTERNAL_ERROR, "Invalid creative payload");
4091
- callbacksRef.current.onAdFailedToRender?.(
4092
- buildBannerErrorPayload(slotIdRef.current, normalizedAdGroupId, invalidError)
4093
- );
4497
+ emitFailure(invalidError, responseContext);
4094
4498
  return;
4095
4499
  }
4096
4500
  if (result.responseExt?.refetchSeconds !== void 0) {
@@ -4107,21 +4511,29 @@ function InlineAd(props) {
4107
4511
  }
4108
4512
  const payload = buildBannerEventPayload(slotIdRef.current, normalizedAdGroupId, result.ad);
4109
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
+ });
4110
4522
  eventTrackerRef.current = new EventTracker(
4111
4523
  result.ad.eventTrackingUrls ?? [],
4112
4524
  result.ad.eventTypes ?? [],
4113
4525
  result.ad.eventPayload ?? "",
4114
4526
  result.requestId,
4115
- result.ad.creative?.id
4527
+ result.ad.creative?.id,
4528
+ void 0,
4529
+ reportEventTrackingFailure
4116
4530
  );
4117
4531
  setIsAdBadgeEnabled(result.responseExt?.isAdBadgeEnabled !== false);
4118
4532
  setAd(result.ad);
4119
4533
  }).catch((error) => {
4120
4534
  if (!isMountedRef.current) return;
4121
4535
  const adError = error instanceof Error ? createError2(ERROR_CODES.INTERNAL_ERROR, error.message) : createError2(ERROR_CODES.INTERNAL_ERROR, "Unknown error");
4122
- callbacksRef.current.onAdFailedToRender?.(
4123
- buildBannerErrorPayload(slotIdRef.current, normalizedAdGroupId, adError)
4124
- );
4536
+ emitFailure(adError);
4125
4537
  }).finally(() => {
4126
4538
  loadingRef.current = false;
4127
4539
  });
@@ -4160,7 +4572,9 @@ function InlineAd(props) {
4160
4572
  }
4161
4573
  const impressionKey = `${ad.requestId ?? "request"}:${ad.creative?.id ?? "creative"}`;
4162
4574
  const resolvedStyleId = ad.styleId || LIST_BANNER_STYLE_ID;
4163
- 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;
4164
4578
  const paddingStyle = resolvePaddingStyle(defaultPaddingValue);
4165
4579
  const isListBanner = String(resolvedStyleId) === LIST_BANNER_STYLE_ID;
4166
4580
  const isFeedBanner = String(resolvedStyleId) === FEED_BANNER_STYLE_ID;
@@ -4256,11 +4670,15 @@ function InlineAd(props) {
4256
4670
  {
4257
4671
  title: listCreative.title,
4258
4672
  subtitle: subtitleText,
4673
+ titleSlotId: listBannerConfig.titleSlotId,
4674
+ subtitleSlotId: listBannerConfig.subtitleSlotId,
4675
+ iconImageSlotId: listBannerConfig.iconImageSlotId,
4259
4676
  adClearanceText,
4260
4677
  adClearanceFontSize,
4678
+ adClearancePaddingRight: listBannerConfig.adClearancePaddingRight,
4261
4679
  imageUri,
4262
4680
  paddingStyle,
4263
- colors: colors4,
4681
+ colors: listBannerConfig.colors,
4264
4682
  onPress: handleClick
4265
4683
  }
4266
4684
  ) : null,
@@ -4269,6 +4687,12 @@ function InlineAd(props) {
4269
4687
  {
4270
4688
  brandName: feedCreative.brandName,
4271
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,
4272
4696
  title: feedCreative.title,
4273
4697
  subtitle: feedCreative.subTitle,
4274
4698
  mainImageUri,
@@ -4276,7 +4700,12 @@ function InlineAd(props) {
4276
4700
  ctaTextColor: feedCreative.ctaTextColor,
4277
4701
  ctaBackgroundColor: feedCreative.ctaBackgroundColor,
4278
4702
  adClearanceText,
4279
- 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,
4280
4709
  isAdBadgeEnabled,
4281
4710
  paddingStyle,
4282
4711
  onPress: handleClick