@apps-in-toss/web-bridge 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/bridge.d.ts +1 -0
- package/dist/bridge.js +1 -1
- package/dist/getDeclaredAgeRange.d.ts +17 -0
- package/dist/index.cjs +358 -48
- package/dist/index.d.cts +46 -1
- package/dist/index.d.ts +46 -1
- package/dist/index.js +357 -48
- package/package.json +4 -4
package/dist/bridge.d.ts
CHANGED
|
@@ -36,6 +36,7 @@ export * from './getIsTossLoginIntegratedService';
|
|
|
36
36
|
export * from './getServerTime';
|
|
37
37
|
export * from './getConsentedUserData';
|
|
38
38
|
export * from './requestReview';
|
|
39
|
+
export * from './getDeclaredAgeRange';
|
|
39
40
|
export * from './getLocale';
|
|
40
41
|
export * from './getSchemeUri';
|
|
41
42
|
export * from './getPlatformOS';
|
package/dist/bridge.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createAsyncBridge,createConstantBridge,createEventBridge}from"@apps-in-toss/bridge-core";var createEvents=function(){return{emit:function emit(event,args){for(var callbacks=this.events[event]||[],i=0,length=callbacks.length;i<length;i++){callbacks[i](args)}},events:{},on:function on(event,cb){var _this=this;var _this_events,_event;((_this_events=this.events)[_event=event]||(_this_events[_event]=[])).push(cb);return function(){var _this_events_event;_this.events[event]=(_this_events_event=_this.events[event])===null||_this_events_event===void 0?void 0:_this_events_event.filter(function(i){return cb!==i})}}}};if(typeof window!=="undefined"){window.__GRANITE_NATIVE_EMITTER=createEvents()}export var closeView=createAsyncBridge("closeView");export var generateHapticFeedback=createAsyncBridge("generateHapticFeedback");export var share=createAsyncBridge("share");export var setSecureScreen=createAsyncBridge("setSecureScreen");export var setScreenAwakeMode=createAsyncBridge("setScreenAwakeMode");export var getNetworkStatus=createAsyncBridge("getNetworkStatus");export var setIosSwipeGestureEnabled=createAsyncBridge("setIosSwipeGestureEnabled");export var openURL=createAsyncBridge("openURL");export var openPermissionDialog=createAsyncBridge("openPermissionDialog");export var getPermission=createAsyncBridge("getPermission");export var requestPermission=createAsyncBridge("requestPermission");export var setClipboardText=createConstantBridge("setClipboardText");export var getClipboardText=createConstantBridge("getClipboardText");export var fetchContacts=createConstantBridge("fetchContacts");export var fetchAlbumPhotos=createConstantBridge("fetchAlbumPhotos");export var getCurrentLocation=createConstantBridge("getCurrentLocation");export var openCamera=createConstantBridge("openCamera");export var appLogin=createAsyncBridge("appLogin");export var getAnonymousKey=createAsyncBridge("getAnonymousKey");export var eventLog=createAsyncBridge("eventLog");export var getTossShareLink=createAsyncBridge("getTossShareLink");export var setDeviceOrientation=createAsyncBridge("setDeviceOrientation");export var checkoutPayment=createAsyncBridge("checkoutPayment");export var requestTossPayPaysBilling=createAsyncBridge("requestTossPayPaysBilling");export var saveBase64Data=createAsyncBridge("saveBase64Data");export var openPDFViewer=createAsyncBridge("openPDFViewer");export var fetchAlbumItems=createAsyncBridge("fetchAlbumItems");export var appsInTossSignTossCert=createAsyncBridge("appsInTossSignTossCert");export var getGameCenterGameProfile=createAsyncBridge("getGameCenterGameProfile");export var openGameCenterLeaderboard=createAsyncBridge("openGameCenterLeaderboard");export var submitGameCenterLeaderBoardScore=createAsyncBridge("submitGameCenterLeaderBoardScore");export var getUserKeyForGame=createAsyncBridge("getUserKeyForGame");export var grantPromotionReward=createAsyncBridge("grantPromotionReward");export var grantPromotionRewardForGame=createAsyncBridge("grantPromotionRewardForGame");export var getIsTossLoginIntegratedService=createAsyncBridge("getIsTossLoginIntegratedService");export var getServerTime=createAsyncBridge("getServerTime");export var getConsentedUserData=createAsyncBridge("getConsentedUserData");export var requestReview=createAsyncBridge("requestReview");export var getLocale=createConstantBridge("getLocale");export var getSchemeUri=createConstantBridge("getSchemeUri");export var getPlatformOS=createConstantBridge("getPlatformOS");export var getOperationalEnvironment=createConstantBridge("getOperationalEnvironment");export var getTossAppVersion=createConstantBridge("getTossAppVersion");export var getDeviceId=createConstantBridge("getDeviceId");export var getGroupId=createConstantBridge("getGroupId");export var contactsViral=createEventBridge("contactsViral");export var startUpdateLocation=createEventBridge("startUpdateLocation");export var onVisibilityChangedByTransparentServiceWeb=createEventBridge("onVisibilityChangedByTransparentServiceWeb");
|
|
1
|
+
import{createAsyncBridge,createConstantBridge,createEventBridge}from"@apps-in-toss/bridge-core";var createEvents=function(){return{emit:function emit(event,args){for(var callbacks=this.events[event]||[],i=0,length=callbacks.length;i<length;i++){callbacks[i](args)}},events:{},on:function on(event,cb){var _this=this;var _this_events,_event;((_this_events=this.events)[_event=event]||(_this_events[_event]=[])).push(cb);return function(){var _this_events_event;_this.events[event]=(_this_events_event=_this.events[event])===null||_this_events_event===void 0?void 0:_this_events_event.filter(function(i){return cb!==i})}}}};if(typeof window!=="undefined"){window.__GRANITE_NATIVE_EMITTER=createEvents()}export var closeView=createAsyncBridge("closeView");export var generateHapticFeedback=createAsyncBridge("generateHapticFeedback");export var share=createAsyncBridge("share");export var setSecureScreen=createAsyncBridge("setSecureScreen");export var setScreenAwakeMode=createAsyncBridge("setScreenAwakeMode");export var getNetworkStatus=createAsyncBridge("getNetworkStatus");export var setIosSwipeGestureEnabled=createAsyncBridge("setIosSwipeGestureEnabled");export var openURL=createAsyncBridge("openURL");export var openPermissionDialog=createAsyncBridge("openPermissionDialog");export var getPermission=createAsyncBridge("getPermission");export var requestPermission=createAsyncBridge("requestPermission");export var setClipboardText=createConstantBridge("setClipboardText");export var getClipboardText=createConstantBridge("getClipboardText");export var fetchContacts=createConstantBridge("fetchContacts");export var fetchAlbumPhotos=createConstantBridge("fetchAlbumPhotos");export var getCurrentLocation=createConstantBridge("getCurrentLocation");export var openCamera=createConstantBridge("openCamera");export var appLogin=createAsyncBridge("appLogin");export var getAnonymousKey=createAsyncBridge("getAnonymousKey");export var eventLog=createAsyncBridge("eventLog");export var getTossShareLink=createAsyncBridge("getTossShareLink");export var setDeviceOrientation=createAsyncBridge("setDeviceOrientation");export var checkoutPayment=createAsyncBridge("checkoutPayment");export var requestTossPayPaysBilling=createAsyncBridge("requestTossPayPaysBilling");export var saveBase64Data=createAsyncBridge("saveBase64Data");export var openPDFViewer=createAsyncBridge("openPDFViewer");export var fetchAlbumItems=createAsyncBridge("fetchAlbumItems");export var appsInTossSignTossCert=createAsyncBridge("appsInTossSignTossCert");export var getGameCenterGameProfile=createAsyncBridge("getGameCenterGameProfile");export var openGameCenterLeaderboard=createAsyncBridge("openGameCenterLeaderboard");export var submitGameCenterLeaderBoardScore=createAsyncBridge("submitGameCenterLeaderBoardScore");export var getUserKeyForGame=createAsyncBridge("getUserKeyForGame");export var grantPromotionReward=createAsyncBridge("grantPromotionReward");export var grantPromotionRewardForGame=createAsyncBridge("grantPromotionRewardForGame");export var getIsTossLoginIntegratedService=createAsyncBridge("getIsTossLoginIntegratedService");export var getServerTime=createAsyncBridge("getServerTime");export var getConsentedUserData=createAsyncBridge("getConsentedUserData");export var requestReview=createAsyncBridge("requestReview");export var getDeclaredAgeRange=createAsyncBridge("getDeclaredAgeRange");export var getLocale=createConstantBridge("getLocale");export var getSchemeUri=createConstantBridge("getSchemeUri");export var getPlatformOS=createConstantBridge("getPlatformOS");export var getOperationalEnvironment=createConstantBridge("getOperationalEnvironment");export var getTossAppVersion=createConstantBridge("getTossAppVersion");export var getDeviceId=createConstantBridge("getDeviceId");export var getGroupId=createConstantBridge("getGroupId");export var contactsViral=createEventBridge("contactsViral");export var startUpdateLocation=createEventBridge("startUpdateLocation");export var onVisibilityChangedByTransparentServiceWeb=createEventBridge("onVisibilityChangedByTransparentServiceWeb");
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface DeclaredAgeRange {
|
|
2
|
+
status: "SHARING" | "DECLINED_SHARING" | "UNSUPPORTED_OS" | "NOT_AVAILABLE" | "INVALID_REQUEST" | "FAILED";
|
|
3
|
+
lowerBound?: number;
|
|
4
|
+
upperBound?: number;
|
|
5
|
+
ageRangeDeclaration?: string;
|
|
6
|
+
activeParentalControls: string[];
|
|
7
|
+
isEligibleForAgeFeatures?: boolean;
|
|
8
|
+
errorCode?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function getDeclaredAgeRange(params: {
|
|
11
|
+
ageGates: number[];
|
|
12
|
+
}): Promise<DeclaredAgeRange>;
|
|
13
|
+
export declare namespace getDeclaredAgeRange {
|
|
14
|
+
var isSupported: () => boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export {};
|
package/dist/index.cjs
CHANGED
|
@@ -37,6 +37,7 @@ __export(index_exports, {
|
|
|
37
37
|
getAppsInTossGlobals: () => getAppsInTossGlobals,
|
|
38
38
|
getClipboardText: () => getClipboardText,
|
|
39
39
|
getCurrentLocation: () => getCurrentLocation,
|
|
40
|
+
getDeclaredAgeRange: () => getDeclaredAgeRange,
|
|
40
41
|
getSafeAreaInsets: () => getSafeAreaInsets,
|
|
41
42
|
getServerTime: () => getServerTime,
|
|
42
43
|
graniteEvent: () => graniteEvent,
|
|
@@ -1035,6 +1036,197 @@ function resetAttachedBannerRegistry() {
|
|
|
1035
1036
|
attachedBannerRegistry = /* @__PURE__ */ new WeakMap();
|
|
1036
1037
|
}
|
|
1037
1038
|
|
|
1039
|
+
// src/toss-ad/constants.ts
|
|
1040
|
+
var ERROR_CODES = {
|
|
1041
|
+
NETWORK_ERROR: 1001,
|
|
1042
|
+
INVALID_REQUEST: 1002,
|
|
1043
|
+
NO_AD: 1003,
|
|
1044
|
+
ERROR: 1004,
|
|
1045
|
+
INVALID_SPACE: 1005,
|
|
1046
|
+
SDK_NOT_INITIALIZED: 1007,
|
|
1047
|
+
HTTP_TIMEOUT: 1008,
|
|
1048
|
+
EXECUTION_FAIL: 1009,
|
|
1049
|
+
INTERRUPTED: 1010,
|
|
1050
|
+
FAIL: 1011,
|
|
1051
|
+
BLOCKED: 1012,
|
|
1052
|
+
TIMEOUT: 1013,
|
|
1053
|
+
LIMITED_AD: 1014,
|
|
1054
|
+
CONSENT_REQUIRED: 1015,
|
|
1055
|
+
TEST_MODE: 1016,
|
|
1056
|
+
INTERNAL_ERROR: 1017
|
|
1057
|
+
};
|
|
1058
|
+
var NON_ERROR_STATUSES = /* @__PURE__ */ new Set(["OK", "TEST_MODE", "NO_AD"]);
|
|
1059
|
+
var API_RESULT_ERROR_CODE_MAP = {
|
|
1060
|
+
HTTP_TIMEOUT: ERROR_CODES.HTTP_TIMEOUT,
|
|
1061
|
+
NETWORK_ERROR: ERROR_CODES.NETWORK_ERROR,
|
|
1062
|
+
EXECUTION_FAIL: ERROR_CODES.EXECUTION_FAIL,
|
|
1063
|
+
INTERRUPTED: ERROR_CODES.INTERRUPTED,
|
|
1064
|
+
INTERNAL_ERROR: ERROR_CODES.ERROR,
|
|
1065
|
+
FAIL: ERROR_CODES.FAIL
|
|
1066
|
+
};
|
|
1067
|
+
var AD_STATUS_ERROR_CODE_MAP = {
|
|
1068
|
+
BLOCKED: ERROR_CODES.BLOCKED,
|
|
1069
|
+
ERROR: ERROR_CODES.ERROR,
|
|
1070
|
+
TIMEOUT: ERROR_CODES.TIMEOUT,
|
|
1071
|
+
INVALID_SPACE: ERROR_CODES.INVALID_SPACE,
|
|
1072
|
+
INVALID_REQUEST: ERROR_CODES.INVALID_REQUEST,
|
|
1073
|
+
LIMITED_AD: ERROR_CODES.LIMITED_AD,
|
|
1074
|
+
CONSENT_REQUIRED: ERROR_CODES.CONSENT_REQUIRED
|
|
1075
|
+
};
|
|
1076
|
+
|
|
1077
|
+
// src/toss-ad/tossAdEventLog.ts
|
|
1078
|
+
var tossAdEventLog = createAsyncBridge("tossAdEventLog");
|
|
1079
|
+
|
|
1080
|
+
// src/toss-ad/errorTracking.ts
|
|
1081
|
+
var BANNER_ERROR_LOG_NAME = "display_ads_all::error__banner";
|
|
1082
|
+
function logBannerErrorToAppLog(info) {
|
|
1083
|
+
void tossAdEventLog({
|
|
1084
|
+
log_name: BANNER_ERROR_LOG_NAME,
|
|
1085
|
+
log_type: "debug",
|
|
1086
|
+
params: {
|
|
1087
|
+
error_code: info.errorCode,
|
|
1088
|
+
error_message: info.errorMessage,
|
|
1089
|
+
ad_group_id: info.adGroupId,
|
|
1090
|
+
mediation_id: info.mediationId,
|
|
1091
|
+
event_context_token: info.eventContextToken
|
|
1092
|
+
}
|
|
1093
|
+
}).catch(() => {
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
function trackBannerError(info) {
|
|
1097
|
+
if (info.endpointError) {
|
|
1098
|
+
void fetch(info.endpointError, {
|
|
1099
|
+
method: "POST",
|
|
1100
|
+
headers: { "Content-Type": "application/json" },
|
|
1101
|
+
body: JSON.stringify({
|
|
1102
|
+
eventContextToken: info.eventContextToken,
|
|
1103
|
+
mediationId: info.mediationId,
|
|
1104
|
+
errorCode: info.errorCode,
|
|
1105
|
+
errorMessage: info.errorMessage
|
|
1106
|
+
})
|
|
1107
|
+
// POST 실패(CORS·네트워크) → 앱로그 fallback (endpoint와 같은 채널이라 함께 막히는 경우 대비).
|
|
1108
|
+
}).catch(() => logBannerErrorToAppLog(info));
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
logBannerErrorToAppLog(info);
|
|
1112
|
+
}
|
|
1113
|
+
function trackResponseError(response, adGroupId, context) {
|
|
1114
|
+
if (response.resultType !== "SUCCESS") {
|
|
1115
|
+
trackBannerError({
|
|
1116
|
+
adGroupId,
|
|
1117
|
+
errorCode: API_RESULT_ERROR_CODE_MAP[response.resultType] ?? ERROR_CODES.INTERNAL_ERROR,
|
|
1118
|
+
errorMessage: response.error?.reason ?? response.resultType
|
|
1119
|
+
});
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
const success = response.success;
|
|
1123
|
+
if (!success || NON_ERROR_STATUSES.has(String(success.status))) {
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
trackBannerError({
|
|
1127
|
+
adGroupId,
|
|
1128
|
+
errorCode: AD_STATUS_ERROR_CODE_MAP[String(success.status)] ?? ERROR_CODES.INTERNAL_ERROR,
|
|
1129
|
+
mediationId: context.mediationId,
|
|
1130
|
+
eventContextToken: context.eventContextToken,
|
|
1131
|
+
errorMessage: `Ad response status: ${success.status}`,
|
|
1132
|
+
endpointError: context.errorEndpoint
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// src/toss-ad/eventTracking.ts
|
|
1137
|
+
async function handleTrackingRequest(request) {
|
|
1138
|
+
if (request.type === "EVENT_TRACKING") {
|
|
1139
|
+
await sendEventTracking(request);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
async function sendEventTracking(request) {
|
|
1143
|
+
if (request.urls.length === 0) {
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
const body = JSON.stringify({ type: request.eventName, data: request.eventPayload });
|
|
1147
|
+
const headers = { "Content-Type": "application/json" };
|
|
1148
|
+
if (request.requestId) {
|
|
1149
|
+
headers["X-Toss-RequestId"] = request.requestId;
|
|
1150
|
+
}
|
|
1151
|
+
const settled = await Promise.allSettled(
|
|
1152
|
+
request.urls.map(
|
|
1153
|
+
(url) => fetch(url, { method: "POST", headers, body }).then((response) => {
|
|
1154
|
+
if (!response.ok) {
|
|
1155
|
+
throw new Error(`HTTP ${response.status}`);
|
|
1156
|
+
}
|
|
1157
|
+
})
|
|
1158
|
+
)
|
|
1159
|
+
);
|
|
1160
|
+
const failedCount = settled.filter((result) => result.status === "rejected").length;
|
|
1161
|
+
if (failedCount === 0) {
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
trackBannerError({
|
|
1165
|
+
adGroupId: request.adGroupId,
|
|
1166
|
+
errorCode: ERROR_CODES.NETWORK_ERROR,
|
|
1167
|
+
errorMessage: `EVENT_TRACKING failed: ${request.eventName} (${failedCount}/${request.urls.length})`,
|
|
1168
|
+
mediationId: request.mediationId || void 0,
|
|
1169
|
+
eventContextToken: request.eventContextToken || void 0,
|
|
1170
|
+
endpointError: request.errorEndpoint
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
// src/toss-ad/fetchAppsInTossAdSchema.ts
|
|
1175
|
+
var APPS_IN_TOSS_AD_SPEC_VERSION = "1.4.1";
|
|
1176
|
+
var FETCH_APPS_IN_TOSS_AD_DEVICE_MACRO = "{{device}}";
|
|
1177
|
+
var TOSS_APP_BUNDLE_IDS = {
|
|
1178
|
+
ios: "com.vivarepublica.cash",
|
|
1179
|
+
android: "viva.republica.toss"
|
|
1180
|
+
};
|
|
1181
|
+
function resolveTossAppBundleId(os) {
|
|
1182
|
+
return TOSS_APP_BUNDLE_IDS[os];
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// src/toss-ad/normalize.ts
|
|
1186
|
+
var LIST_BANNER_STYLE_ID = "1";
|
|
1187
|
+
var NATIVE_IMAGE_STYLE_ID = "2";
|
|
1188
|
+
var AVAILABLE_STYLE_IDS = [LIST_BANNER_STYLE_ID, NATIVE_IMAGE_STYLE_ID];
|
|
1189
|
+
var SUPPORTED_STYLE_IDS = new Set(AVAILABLE_STYLE_IDS);
|
|
1190
|
+
function normalizeAdResponse(adResponse) {
|
|
1191
|
+
const ads = Array.isArray(adResponse.ads) ? adResponse.ads.filter((ad) => SUPPORTED_STYLE_IDS.has(String(ad.styleId))) : [];
|
|
1192
|
+
return {
|
|
1193
|
+
requestId: adResponse.requestId ?? "",
|
|
1194
|
+
// SDK가 event 트래킹 위임(onTrackingRequest) 시 응답 top-level에서 읽어 실어 보낸다.
|
|
1195
|
+
// 떼어내면 SDK가 토큰을 못 보고, event 트래킹 실패 시 endpoint.error에서 토큰이 빠진다.
|
|
1196
|
+
eventContextToken: adResponse.eventContextToken,
|
|
1197
|
+
status: adResponse.status ?? "OK",
|
|
1198
|
+
ads,
|
|
1199
|
+
ext: adResponse.ext
|
|
1200
|
+
};
|
|
1201
|
+
}
|
|
1202
|
+
function normalizeApiResponse(raw) {
|
|
1203
|
+
if (isApiResponse(raw)) {
|
|
1204
|
+
if (raw.resultType !== "SUCCESS") {
|
|
1205
|
+
return raw;
|
|
1206
|
+
}
|
|
1207
|
+
if (!raw.success) {
|
|
1208
|
+
return {
|
|
1209
|
+
resultType: "FAIL",
|
|
1210
|
+
error: { reason: "fetchTossAd returned SUCCESS without payload" }
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
return { ...raw, success: normalizeAdResponse(raw.success) };
|
|
1214
|
+
}
|
|
1215
|
+
if (isAdResponse(raw)) {
|
|
1216
|
+
return {
|
|
1217
|
+
resultType: "SUCCESS",
|
|
1218
|
+
success: normalizeAdResponse(raw)
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
return { resultType: "FAIL", error: { reason: "Invalid response from fetchTossAd" } };
|
|
1222
|
+
}
|
|
1223
|
+
function isApiResponse(payload) {
|
|
1224
|
+
return Boolean(payload && typeof payload === "object" && "resultType" in payload);
|
|
1225
|
+
}
|
|
1226
|
+
function isAdResponse(payload) {
|
|
1227
|
+
return Boolean(payload && typeof payload === "object" && "ads" in payload);
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1038
1230
|
// src/toss-ad/opener.ts
|
|
1039
1231
|
var openURL = createAsyncBridge("openURL");
|
|
1040
1232
|
function openUrlOpener(url) {
|
|
@@ -1049,8 +1241,49 @@ function supertossWeb(uri) {
|
|
|
1049
1241
|
return `supertoss://web?url=${encodeURIComponent(uri)}&external=true`;
|
|
1050
1242
|
}
|
|
1051
1243
|
|
|
1244
|
+
// src/toss-ad/resultTracking.ts
|
|
1245
|
+
async function fireResultTracking(response, adGroupId, ctx) {
|
|
1246
|
+
const status = response.success?.status;
|
|
1247
|
+
if (response.resultType !== "SUCCESS" || status !== "OK" && status !== "TEST_MODE") {
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
if (ctx.resultEndpoint == null || ctx.mediationId == null) {
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
const body = {
|
|
1254
|
+
mediationId: ctx.mediationId,
|
|
1255
|
+
spaceUnitId: adGroupId,
|
|
1256
|
+
requestId: response.success?.requestId ?? "",
|
|
1257
|
+
eventContextToken: ctx.eventContextToken,
|
|
1258
|
+
winnerSource: "TOSS",
|
|
1259
|
+
content: null,
|
|
1260
|
+
adUnitId: ctx.adUnitId ?? null,
|
|
1261
|
+
placementId: ctx.placementId ?? null,
|
|
1262
|
+
tossFailed: null
|
|
1263
|
+
};
|
|
1264
|
+
try {
|
|
1265
|
+
const res = await fetch(ctx.resultEndpoint, {
|
|
1266
|
+
method: "POST",
|
|
1267
|
+
headers: { "Content-Type": "application/json" },
|
|
1268
|
+
body: JSON.stringify(body)
|
|
1269
|
+
});
|
|
1270
|
+
if (!res.ok) {
|
|
1271
|
+
throw new Error(`HTTP ${res.status}`);
|
|
1272
|
+
}
|
|
1273
|
+
} catch (error) {
|
|
1274
|
+
trackBannerError({
|
|
1275
|
+
adGroupId,
|
|
1276
|
+
errorCode: ERROR_CODES.NETWORK_ERROR,
|
|
1277
|
+
errorMessage: `RESULT_TRACKING failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
1278
|
+
mediationId: ctx.mediationId,
|
|
1279
|
+
eventContextToken: ctx.eventContextToken,
|
|
1280
|
+
endpointError: ctx.errorEndpoint
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1052
1285
|
// src/toss-ad/scriptLoader.ts
|
|
1053
|
-
var DEFAULT_SDK_URL = "https://static.toss.im/ads/sdk/toss-ads-space-kit-1.
|
|
1286
|
+
var DEFAULT_SDK_URL = "https://static.toss.im/ads/sdk/toss-ads-space-kit-3.1.0.js";
|
|
1054
1287
|
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
1055
1288
|
var pendingLoad = null;
|
|
1056
1289
|
function getAdsSdk() {
|
|
@@ -1106,12 +1339,79 @@ function loadAdsSdk() {
|
|
|
1106
1339
|
return promise;
|
|
1107
1340
|
}
|
|
1108
1341
|
|
|
1342
|
+
// package.json
|
|
1343
|
+
var package_default = {
|
|
1344
|
+
name: "@apps-in-toss/web-bridge",
|
|
1345
|
+
type: "module",
|
|
1346
|
+
version: "2.10.1",
|
|
1347
|
+
description: "Web Bridge for Apps In Toss",
|
|
1348
|
+
scripts: {
|
|
1349
|
+
typecheck: "tsc --noEmit",
|
|
1350
|
+
lint: "eslint .",
|
|
1351
|
+
build: "tsup"
|
|
1352
|
+
},
|
|
1353
|
+
main: "./dist/index.cjs",
|
|
1354
|
+
module: "./dist/index.js",
|
|
1355
|
+
types: "./dist/index.d.ts",
|
|
1356
|
+
exports: {
|
|
1357
|
+
".": {
|
|
1358
|
+
import: {
|
|
1359
|
+
types: "./dist/index.d.ts",
|
|
1360
|
+
default: "./dist/index.js"
|
|
1361
|
+
},
|
|
1362
|
+
require: {
|
|
1363
|
+
types: "./dist/index.d.cts",
|
|
1364
|
+
default: "./dist/index.cjs"
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
},
|
|
1368
|
+
files: [
|
|
1369
|
+
"dist"
|
|
1370
|
+
],
|
|
1371
|
+
dependencies: {
|
|
1372
|
+
"@apps-in-toss/types": "workspace:*"
|
|
1373
|
+
},
|
|
1374
|
+
devDependencies: {
|
|
1375
|
+
"@apps-in-toss/bridge-core": "workspace:*",
|
|
1376
|
+
"@apps-in-toss/native-modules": "workspace:^",
|
|
1377
|
+
"@swc/core": "^1.12.7",
|
|
1378
|
+
picocolors: "^1.1.1",
|
|
1379
|
+
"ts-morph": "^26.0.0",
|
|
1380
|
+
tsup: "^8.5.0",
|
|
1381
|
+
typescript: "5.8.3",
|
|
1382
|
+
vitest: "^3.1.2"
|
|
1383
|
+
}
|
|
1384
|
+
};
|
|
1385
|
+
|
|
1386
|
+
// src/toss-ad/sdkVersion.ts
|
|
1387
|
+
var SDK_VERSION = package_default.version;
|
|
1388
|
+
|
|
1389
|
+
// src/toss-ad/trackingContext.ts
|
|
1390
|
+
function nonEmptyString(value) {
|
|
1391
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1392
|
+
}
|
|
1393
|
+
function extractAdTrackingContext(response) {
|
|
1394
|
+
const mediation = response?.ext?.mediation;
|
|
1395
|
+
return {
|
|
1396
|
+
mediationId: nonEmptyString(mediation?.mediationId),
|
|
1397
|
+
eventContextToken: nonEmptyString(response?.eventContextToken),
|
|
1398
|
+
resultEndpoint: nonEmptyString(mediation?.endpoint?.result),
|
|
1399
|
+
errorEndpoint: nonEmptyString(mediation?.endpoint?.error),
|
|
1400
|
+
adUnitId: nonEmptyString(mediation?.admob?.adUnitId),
|
|
1401
|
+
placementId: typeof mediation?.admob?.placementId === "number" ? mediation.admob.placementId : void 0
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1109
1405
|
// src/toss-ad/index.ts
|
|
1110
1406
|
var fetchTossAd = Object.assign(createEventBridge("fetchTossAd"), {
|
|
1111
1407
|
isSupported: createConstantBridge("fetchTossAd_isSupported")
|
|
1112
1408
|
});
|
|
1113
|
-
var
|
|
1114
|
-
|
|
1409
|
+
var fetchAppsInTossAd = Object.assign(createEventBridge("fetchAppsInTossAd"), {
|
|
1410
|
+
isSupported: createConstantBridge("fetchAppsInTossAd_isSupported")
|
|
1411
|
+
});
|
|
1412
|
+
var getPlatformOS = createConstantBridge("getPlatformOS");
|
|
1413
|
+
var getTossAppVersion = createConstantBridge("getTossAppVersion");
|
|
1414
|
+
var WEB_SDK_ID = "108";
|
|
1115
1415
|
var INVALID_AD_GROUP_ID_ERROR_MESSAGE = "\uC798\uBABB\uB41C \uC694\uCCAD\uC774\uC5D0\uC694. \uD544\uC694\uD55C \uAC12\uC774 \uBE44\uC5B4 \uC788\uC5B4\uC694.";
|
|
1116
1416
|
function normalizeAdGroupId(adGroupId) {
|
|
1117
1417
|
return adGroupId.trim();
|
|
@@ -1148,62 +1448,56 @@ function fetchTossAdPromise(options) {
|
|
|
1148
1448
|
});
|
|
1149
1449
|
});
|
|
1150
1450
|
}
|
|
1151
|
-
function
|
|
1152
|
-
|
|
1153
|
-
return {
|
|
1154
|
-
requestId: adResponse.requestId ?? "",
|
|
1155
|
-
status: adResponse.status ?? "OK",
|
|
1156
|
-
ads,
|
|
1157
|
-
ext: adResponse.ext
|
|
1158
|
-
};
|
|
1451
|
+
function getSubBundle() {
|
|
1452
|
+
return globalThis.__granite?.app?.name ?? "";
|
|
1159
1453
|
}
|
|
1160
|
-
function
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1454
|
+
function fetchAppsInTossAdPromise(spaceUnitId) {
|
|
1455
|
+
const platformOS = getPlatformOS();
|
|
1456
|
+
const tossAppVersion = getTossAppVersion();
|
|
1457
|
+
const body = {
|
|
1458
|
+
specVersion: APPS_IN_TOSS_AD_SPEC_VERSION,
|
|
1459
|
+
platform: "WEB",
|
|
1460
|
+
spaceUnitId,
|
|
1461
|
+
sdkVersion: SDK_VERSION,
|
|
1462
|
+
availableStyleIds: AVAILABLE_STYLE_IDS,
|
|
1463
|
+
// device는 매크로키만 보내고 native가 실제 device로 치환한다.
|
|
1464
|
+
device: FETCH_APPS_IN_TOSS_AD_DEVICE_MACRO,
|
|
1465
|
+
app: {
|
|
1466
|
+
version: tossAppVersion,
|
|
1467
|
+
bundle: resolveTossAppBundleId(platformOS),
|
|
1468
|
+
subBundle: getSubBundle()
|
|
1170
1469
|
}
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
resultType: "SUCCESS",
|
|
1176
|
-
success: normalizeAdResponse(raw)
|
|
1177
|
-
};
|
|
1178
|
-
}
|
|
1179
|
-
return { resultType: "FAIL", error: { reason: "Invalid response from fetchTossAd" } };
|
|
1180
|
-
}
|
|
1181
|
-
function isApiResponse(payload) {
|
|
1182
|
-
return Boolean(payload && typeof payload === "object" && "resultType" in payload);
|
|
1183
|
-
}
|
|
1184
|
-
function isAdResponse(payload) {
|
|
1185
|
-
return Boolean(payload && typeof payload === "object" && "ads" in payload);
|
|
1470
|
+
};
|
|
1471
|
+
return new Promise((resolve, reject) => {
|
|
1472
|
+
fetchAppsInTossAd({ options: body, onEvent: resolve, onError: reject });
|
|
1473
|
+
});
|
|
1186
1474
|
}
|
|
1187
1475
|
function createCustomAdFetcher() {
|
|
1188
1476
|
return async (_endpoint, request) => {
|
|
1189
1477
|
const spaceUnitId = normalizeAdGroupId(request.spaceUnitId);
|
|
1190
1478
|
if (spaceUnitId.length === 0) {
|
|
1479
|
+
trackBannerError({
|
|
1480
|
+
adGroupId: spaceUnitId,
|
|
1481
|
+
errorCode: ERROR_CODES.INVALID_SPACE,
|
|
1482
|
+
errorMessage: INVALID_AD_GROUP_ID_ERROR_MESSAGE
|
|
1483
|
+
});
|
|
1191
1484
|
return createInvalidAdGroupIdResponse();
|
|
1192
1485
|
}
|
|
1193
1486
|
try {
|
|
1194
|
-
const raw = await fetchTossAdPromise({
|
|
1487
|
+
const raw = fetchAppsInTossAd.isSupported() ? await fetchAppsInTossAdPromise(spaceUnitId) : await fetchTossAdPromise({
|
|
1195
1488
|
adGroupId: spaceUnitId,
|
|
1196
|
-
sdkId:
|
|
1197
|
-
availableStyleIds:
|
|
1489
|
+
sdkId: WEB_SDK_ID,
|
|
1490
|
+
availableStyleIds: AVAILABLE_STYLE_IDS
|
|
1198
1491
|
});
|
|
1199
|
-
|
|
1492
|
+
const response = normalizeApiResponse(raw);
|
|
1493
|
+
const trackingContext = extractAdTrackingContext(response.success);
|
|
1494
|
+
trackResponseError(response, spaceUnitId, trackingContext);
|
|
1495
|
+
void fireResultTracking(response, spaceUnitId, trackingContext);
|
|
1496
|
+
return response;
|
|
1200
1497
|
} catch (error) {
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
reason: error instanceof Error ? error.message : "Unknown fetchTossAd error"
|
|
1205
|
-
}
|
|
1206
|
-
};
|
|
1498
|
+
const reason = error instanceof Error ? error.message : "Unknown fetchTossAd error";
|
|
1499
|
+
trackBannerError({ adGroupId: spaceUnitId, errorCode: ERROR_CODES.NETWORK_ERROR, errorMessage: reason });
|
|
1500
|
+
return { resultType: "FAIL", error: { reason } };
|
|
1207
1501
|
}
|
|
1208
1502
|
};
|
|
1209
1503
|
}
|
|
@@ -1229,7 +1523,12 @@ function initialize(options) {
|
|
|
1229
1523
|
return;
|
|
1230
1524
|
}
|
|
1231
1525
|
const customAdFetcher = createCustomAdFetcher();
|
|
1232
|
-
const config = {
|
|
1526
|
+
const config = {
|
|
1527
|
+
environment: "live",
|
|
1528
|
+
customAdFetcher,
|
|
1529
|
+
opener: openUrlOpener,
|
|
1530
|
+
onTrackingRequest: handleTrackingRequest
|
|
1531
|
+
};
|
|
1233
1532
|
sdk.init(config);
|
|
1234
1533
|
});
|
|
1235
1534
|
pendingLoad2 = initPromise;
|
|
@@ -1406,7 +1705,7 @@ function attachBanner(adGroupId, target, options = {}) {
|
|
|
1406
1705
|
autoLoad: true,
|
|
1407
1706
|
theme: theme === "auto" ? void 0 : theme,
|
|
1408
1707
|
renderPadding: (styleId) => {
|
|
1409
|
-
if (styleId ===
|
|
1708
|
+
if (styleId === LIST_BANNER_STYLE_ID) {
|
|
1410
1709
|
return DEFAULT_ATTACH_PADDING_BANNER;
|
|
1411
1710
|
}
|
|
1412
1711
|
return DEFAULT_ATTACH_PADDING_NATIVE_IMAGE;
|
|
@@ -1479,6 +1778,8 @@ function wrapCallbacks(adGroupId, callbacks) {
|
|
|
1479
1778
|
});
|
|
1480
1779
|
callbacks.onAdImpression?.(mapEvent(payload));
|
|
1481
1780
|
},
|
|
1781
|
+
// 에러 트래킹은 응답을 소유한 createCustomAdFetcher가 담당한다. 콜백은 publisher 전달만.
|
|
1782
|
+
// 응답 수신 후 에러의 mediationId는 SDK(ads-sdk/web)가 error에 실어주므로 그대로 전달한다.
|
|
1482
1783
|
onAdFailedToRender: (payload) => callbacks.onAdFailedToRender?.({
|
|
1483
1784
|
...mapEvent(payload),
|
|
1484
1785
|
error: payload?.error ?? { code: 0, message: "UNKNOWN" }
|
|
@@ -1532,6 +1833,14 @@ function requestNotificationAgreement(params) {
|
|
|
1532
1833
|
return unregisterCallbacks;
|
|
1533
1834
|
}
|
|
1534
1835
|
|
|
1836
|
+
// src/getDeclaredAgeRange.ts
|
|
1837
|
+
var getDeclaredAgeRange = Object.assign(
|
|
1838
|
+
createAsyncBridge("getDeclaredAgeRange"),
|
|
1839
|
+
{
|
|
1840
|
+
isSupported: createConstantBridge("getDeclaredAgeRange_isSupported")
|
|
1841
|
+
}
|
|
1842
|
+
);
|
|
1843
|
+
|
|
1535
1844
|
// src/index.ts
|
|
1536
1845
|
__reExport(index_exports, require("@apps-in-toss/types"), module.exports);
|
|
1537
1846
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1551,6 +1860,7 @@ __reExport(index_exports, require("@apps-in-toss/types"), module.exports);
|
|
|
1551
1860
|
getAppsInTossGlobals,
|
|
1552
1861
|
getClipboardText,
|
|
1553
1862
|
getCurrentLocation,
|
|
1863
|
+
getDeclaredAgeRange,
|
|
1554
1864
|
getSafeAreaInsets,
|
|
1555
1865
|
getServerTime,
|
|
1556
1866
|
graniteEvent,
|
package/dist/index.d.cts
CHANGED
|
@@ -3,6 +3,7 @@ export * from '@apps-in-toss/bridge-core';
|
|
|
3
3
|
import * as _apps_in_toss_types from '@apps-in-toss/types';
|
|
4
4
|
import { LoadAdMobEvent, LoadAdMobOptions, ShowAdMobEvent, ShowAdMobOptions, IsAdMobLoadedOptions, FetchAlbumPhotos, FetchContacts, GetCurrentLocation, OpenCamera, SetClipboardText, GetClipboardText, StartUpdateLocationEventParams, LoadFullScreenAdEvent, LoadFullScreenAdOptions, ShowFullScreenAdEvent, ShowFullScreenAdOptions } from '@apps-in-toss/types';
|
|
5
5
|
export * from '@apps-in-toss/types';
|
|
6
|
+
import { DeclaredAgeRange } from '@apps-in-toss/native-modules/async-bridges';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* @public
|
|
@@ -885,6 +886,22 @@ interface RuntimeInfo {
|
|
|
885
886
|
safeAreaInsets?: SafeAreaInsets;
|
|
886
887
|
}
|
|
887
888
|
type AdOpener = (url: string, target?: string, features?: string) => void;
|
|
889
|
+
/** SDK가 `onTrackingRequest`로 위임하는 트래킹 요청. ads-sdk/web의 동형 계약. */
|
|
890
|
+
interface TrackingRequestBase {
|
|
891
|
+
adGroupId: string;
|
|
892
|
+
requestId?: string;
|
|
893
|
+
creativeId?: string;
|
|
894
|
+
mediationId?: string;
|
|
895
|
+
eventContextToken?: string;
|
|
896
|
+
errorEndpoint?: string;
|
|
897
|
+
}
|
|
898
|
+
interface EventTrackingRequest extends TrackingRequestBase {
|
|
899
|
+
type: 'EVENT_TRACKING';
|
|
900
|
+
eventName: string;
|
|
901
|
+
urls: string[];
|
|
902
|
+
eventPayload: string;
|
|
903
|
+
}
|
|
904
|
+
type TrackingRequest = EventTrackingRequest;
|
|
888
905
|
interface AdConfig {
|
|
889
906
|
environment: Environment;
|
|
890
907
|
apiEndpoint?: string;
|
|
@@ -893,6 +910,11 @@ interface AdConfig {
|
|
|
893
910
|
runtimeInfo?: RuntimeInfo;
|
|
894
911
|
opener?: AdOpener;
|
|
895
912
|
customAdFetcher?: CustomAdFetcher;
|
|
913
|
+
/**
|
|
914
|
+
* 트래킹 전송 위임(SDK 3.1.0+). 지정 시 SDK는 직접 전송하지 않고 이 콜백에 위임한다.
|
|
915
|
+
* fire-and-forget이며 실패 관측은 사용측 책임. 현재 위임 대상은 EVENT_TRACKING이다.
|
|
916
|
+
*/
|
|
917
|
+
onTrackingRequest?: (request: TrackingRequest) => void | Promise<void>;
|
|
896
918
|
}
|
|
897
919
|
interface AdRequest {
|
|
898
920
|
spaceUnitId: string;
|
|
@@ -907,6 +929,7 @@ interface AdRequest {
|
|
|
907
929
|
type AdResponseStatus = 'OK' | 'NO_AD' | 'BLOCKED' | 'ERROR' | 'TIMEOUT' | 'INVALID_SPACE' | 'INVALID_REQUEST' | 'LIMITED_AD' | 'CONSENT_REQUIRED' | 'TEST_MODE';
|
|
908
930
|
interface AdResponse {
|
|
909
931
|
requestId?: string;
|
|
932
|
+
eventContextToken?: string;
|
|
910
933
|
status?: AdResponseStatus;
|
|
911
934
|
ads: Ad[];
|
|
912
935
|
ext?: AdResponseExt;
|
|
@@ -919,6 +942,19 @@ interface Ad {
|
|
|
919
942
|
eventPayload?: string;
|
|
920
943
|
requestId?: string;
|
|
921
944
|
}
|
|
945
|
+
interface TossAdsMediation {
|
|
946
|
+
mediationId: string;
|
|
947
|
+
priority: Array<'TOSS' | 'ADMOB'>;
|
|
948
|
+
admob: {
|
|
949
|
+
adUnitId: string;
|
|
950
|
+
placementId: number;
|
|
951
|
+
} | null;
|
|
952
|
+
endpoint?: {
|
|
953
|
+
result?: string;
|
|
954
|
+
exposure?: string;
|
|
955
|
+
error?: string;
|
|
956
|
+
};
|
|
957
|
+
}
|
|
922
958
|
interface AdResponseExt {
|
|
923
959
|
skippableOffsetSeconds?: number;
|
|
924
960
|
reward?: {
|
|
@@ -927,6 +963,7 @@ interface AdResponseExt {
|
|
|
927
963
|
};
|
|
928
964
|
isAdBadgeEnabled?: boolean;
|
|
929
965
|
refetchSeconds?: number | null;
|
|
966
|
+
mediation?: TossAdsMediation;
|
|
930
967
|
}
|
|
931
968
|
interface ApiResponse<T> {
|
|
932
969
|
resultType: 'SUCCESS' | 'HTTP_TIMEOUT' | 'NETWORK_ERROR' | 'EXECUTION_FAIL' | 'INTERRUPTED' | 'INTERNAL_ERROR' | 'FAIL';
|
|
@@ -958,10 +995,12 @@ interface BannerSlotErrorPayload {
|
|
|
958
995
|
slotId: string;
|
|
959
996
|
adGroupId: string;
|
|
960
997
|
adMetadata: Record<string, never>;
|
|
998
|
+
/** `mediationId`는 `/api-web/v3/benefit-ads/display-ad/ads` 응답 수신 후 발생한 에러에만 포함된다. */
|
|
961
999
|
error: {
|
|
962
1000
|
code: number;
|
|
963
1001
|
message: string;
|
|
964
1002
|
domain?: string;
|
|
1003
|
+
mediationId?: string;
|
|
965
1004
|
};
|
|
966
1005
|
}
|
|
967
1006
|
interface BannerSlotCallbacks {
|
|
@@ -1095,4 +1134,10 @@ interface RequestNotificationAgreementOptions {
|
|
|
1095
1134
|
*/
|
|
1096
1135
|
declare function requestNotificationAgreement(params: RequestNotificationAgreementOptions): () => void;
|
|
1097
1136
|
|
|
1098
|
-
|
|
1137
|
+
declare const getDeclaredAgeRange: ((args_0: {
|
|
1138
|
+
ageGates: number[];
|
|
1139
|
+
}) => Promise<DeclaredAgeRange>) & {
|
|
1140
|
+
isSupported: () => boolean;
|
|
1141
|
+
};
|
|
1142
|
+
|
|
1143
|
+
export { type AddAccessoryButtonOptions, type AppsInTossEvent, type AppsInTossGlobals, type CompletedOrRefundedOrdersResult, type ConsumableProductListItem, type CreateSubscriptionPurchaseOrderOptions, GoogleAdMob, type GraniteEvent, IAP, type IapCreateOneTimePurchaseOrderOptions, type IapProductListItem, type IapSubscriptionInfoResponse, type IapSubscriptionInfoResult, type NonConsumableProductListItem, type NotificationAgreementResult, type RequestNotificationAgreementOptions, SafeAreaInsets$1 as SafeAreaInsets, Storage, type SubscriptionProductListItem, type TdsEvent, TossAds, type AttachBannerOptions as TossAdsAttachBannerOptions, type AttachBannerResult as TossAdsAttachBannerResult, type AttachOptions as TossAdsAttachOptions, type BannerSlotCallbacks as TossAdsBannerSlotCallbacks, type BannerSlotErrorPayload as TossAdsBannerSlotErrorPayload, type BannerSlotEventPayload as TossAdsBannerSlotEventPayload, type InitializeOptions as TossAdsInitializeOptions, appsInTossEvent, env, fetchAlbumPhotos, fetchContacts, getAppsInTossGlobals, getClipboardText, getCurrentLocation, getDeclaredAgeRange, getSafeAreaInsets, getServerTime, graniteEvent, isMinVersionSupported, loadFullScreenAd, openCamera, partner, requestNotificationAgreement, requestReview, setClipboardText, showFullScreenAd, startUpdateLocation, tdsEvent };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from '@apps-in-toss/bridge-core';
|
|
|
3
3
|
import * as _apps_in_toss_types from '@apps-in-toss/types';
|
|
4
4
|
import { LoadAdMobEvent, LoadAdMobOptions, ShowAdMobEvent, ShowAdMobOptions, IsAdMobLoadedOptions, FetchAlbumPhotos, FetchContacts, GetCurrentLocation, OpenCamera, SetClipboardText, GetClipboardText, StartUpdateLocationEventParams, LoadFullScreenAdEvent, LoadFullScreenAdOptions, ShowFullScreenAdEvent, ShowFullScreenAdOptions } from '@apps-in-toss/types';
|
|
5
5
|
export * from '@apps-in-toss/types';
|
|
6
|
+
import { DeclaredAgeRange } from '@apps-in-toss/native-modules/async-bridges';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* @public
|
|
@@ -885,6 +886,22 @@ interface RuntimeInfo {
|
|
|
885
886
|
safeAreaInsets?: SafeAreaInsets;
|
|
886
887
|
}
|
|
887
888
|
type AdOpener = (url: string, target?: string, features?: string) => void;
|
|
889
|
+
/** SDK가 `onTrackingRequest`로 위임하는 트래킹 요청. ads-sdk/web의 동형 계약. */
|
|
890
|
+
interface TrackingRequestBase {
|
|
891
|
+
adGroupId: string;
|
|
892
|
+
requestId?: string;
|
|
893
|
+
creativeId?: string;
|
|
894
|
+
mediationId?: string;
|
|
895
|
+
eventContextToken?: string;
|
|
896
|
+
errorEndpoint?: string;
|
|
897
|
+
}
|
|
898
|
+
interface EventTrackingRequest extends TrackingRequestBase {
|
|
899
|
+
type: 'EVENT_TRACKING';
|
|
900
|
+
eventName: string;
|
|
901
|
+
urls: string[];
|
|
902
|
+
eventPayload: string;
|
|
903
|
+
}
|
|
904
|
+
type TrackingRequest = EventTrackingRequest;
|
|
888
905
|
interface AdConfig {
|
|
889
906
|
environment: Environment;
|
|
890
907
|
apiEndpoint?: string;
|
|
@@ -893,6 +910,11 @@ interface AdConfig {
|
|
|
893
910
|
runtimeInfo?: RuntimeInfo;
|
|
894
911
|
opener?: AdOpener;
|
|
895
912
|
customAdFetcher?: CustomAdFetcher;
|
|
913
|
+
/**
|
|
914
|
+
* 트래킹 전송 위임(SDK 3.1.0+). 지정 시 SDK는 직접 전송하지 않고 이 콜백에 위임한다.
|
|
915
|
+
* fire-and-forget이며 실패 관측은 사용측 책임. 현재 위임 대상은 EVENT_TRACKING이다.
|
|
916
|
+
*/
|
|
917
|
+
onTrackingRequest?: (request: TrackingRequest) => void | Promise<void>;
|
|
896
918
|
}
|
|
897
919
|
interface AdRequest {
|
|
898
920
|
spaceUnitId: string;
|
|
@@ -907,6 +929,7 @@ interface AdRequest {
|
|
|
907
929
|
type AdResponseStatus = 'OK' | 'NO_AD' | 'BLOCKED' | 'ERROR' | 'TIMEOUT' | 'INVALID_SPACE' | 'INVALID_REQUEST' | 'LIMITED_AD' | 'CONSENT_REQUIRED' | 'TEST_MODE';
|
|
908
930
|
interface AdResponse {
|
|
909
931
|
requestId?: string;
|
|
932
|
+
eventContextToken?: string;
|
|
910
933
|
status?: AdResponseStatus;
|
|
911
934
|
ads: Ad[];
|
|
912
935
|
ext?: AdResponseExt;
|
|
@@ -919,6 +942,19 @@ interface Ad {
|
|
|
919
942
|
eventPayload?: string;
|
|
920
943
|
requestId?: string;
|
|
921
944
|
}
|
|
945
|
+
interface TossAdsMediation {
|
|
946
|
+
mediationId: string;
|
|
947
|
+
priority: Array<'TOSS' | 'ADMOB'>;
|
|
948
|
+
admob: {
|
|
949
|
+
adUnitId: string;
|
|
950
|
+
placementId: number;
|
|
951
|
+
} | null;
|
|
952
|
+
endpoint?: {
|
|
953
|
+
result?: string;
|
|
954
|
+
exposure?: string;
|
|
955
|
+
error?: string;
|
|
956
|
+
};
|
|
957
|
+
}
|
|
922
958
|
interface AdResponseExt {
|
|
923
959
|
skippableOffsetSeconds?: number;
|
|
924
960
|
reward?: {
|
|
@@ -927,6 +963,7 @@ interface AdResponseExt {
|
|
|
927
963
|
};
|
|
928
964
|
isAdBadgeEnabled?: boolean;
|
|
929
965
|
refetchSeconds?: number | null;
|
|
966
|
+
mediation?: TossAdsMediation;
|
|
930
967
|
}
|
|
931
968
|
interface ApiResponse<T> {
|
|
932
969
|
resultType: 'SUCCESS' | 'HTTP_TIMEOUT' | 'NETWORK_ERROR' | 'EXECUTION_FAIL' | 'INTERRUPTED' | 'INTERNAL_ERROR' | 'FAIL';
|
|
@@ -958,10 +995,12 @@ interface BannerSlotErrorPayload {
|
|
|
958
995
|
slotId: string;
|
|
959
996
|
adGroupId: string;
|
|
960
997
|
adMetadata: Record<string, never>;
|
|
998
|
+
/** `mediationId`는 `/api-web/v3/benefit-ads/display-ad/ads` 응답 수신 후 발생한 에러에만 포함된다. */
|
|
961
999
|
error: {
|
|
962
1000
|
code: number;
|
|
963
1001
|
message: string;
|
|
964
1002
|
domain?: string;
|
|
1003
|
+
mediationId?: string;
|
|
965
1004
|
};
|
|
966
1005
|
}
|
|
967
1006
|
interface BannerSlotCallbacks {
|
|
@@ -1095,4 +1134,10 @@ interface RequestNotificationAgreementOptions {
|
|
|
1095
1134
|
*/
|
|
1096
1135
|
declare function requestNotificationAgreement(params: RequestNotificationAgreementOptions): () => void;
|
|
1097
1136
|
|
|
1098
|
-
|
|
1137
|
+
declare const getDeclaredAgeRange: ((args_0: {
|
|
1138
|
+
ageGates: number[];
|
|
1139
|
+
}) => Promise<DeclaredAgeRange>) & {
|
|
1140
|
+
isSupported: () => boolean;
|
|
1141
|
+
};
|
|
1142
|
+
|
|
1143
|
+
export { type AddAccessoryButtonOptions, type AppsInTossEvent, type AppsInTossGlobals, type CompletedOrRefundedOrdersResult, type ConsumableProductListItem, type CreateSubscriptionPurchaseOrderOptions, GoogleAdMob, type GraniteEvent, IAP, type IapCreateOneTimePurchaseOrderOptions, type IapProductListItem, type IapSubscriptionInfoResponse, type IapSubscriptionInfoResult, type NonConsumableProductListItem, type NotificationAgreementResult, type RequestNotificationAgreementOptions, SafeAreaInsets$1 as SafeAreaInsets, Storage, type SubscriptionProductListItem, type TdsEvent, TossAds, type AttachBannerOptions as TossAdsAttachBannerOptions, type AttachBannerResult as TossAdsAttachBannerResult, type AttachOptions as TossAdsAttachOptions, type BannerSlotCallbacks as TossAdsBannerSlotCallbacks, type BannerSlotErrorPayload as TossAdsBannerSlotErrorPayload, type BannerSlotEventPayload as TossAdsBannerSlotEventPayload, type InitializeOptions as TossAdsInitializeOptions, appsInTossEvent, env, fetchAlbumPhotos, fetchContacts, getAppsInTossGlobals, getClipboardText, getCurrentLocation, getDeclaredAgeRange, getSafeAreaInsets, getServerTime, graniteEvent, isMinVersionSupported, loadFullScreenAd, openCamera, partner, requestNotificationAgreement, requestReview, setClipboardText, showFullScreenAd, startUpdateLocation, tdsEvent };
|
package/dist/index.js
CHANGED
|
@@ -986,6 +986,197 @@ function resetAttachedBannerRegistry() {
|
|
|
986
986
|
attachedBannerRegistry = /* @__PURE__ */ new WeakMap();
|
|
987
987
|
}
|
|
988
988
|
|
|
989
|
+
// src/toss-ad/constants.ts
|
|
990
|
+
var ERROR_CODES = {
|
|
991
|
+
NETWORK_ERROR: 1001,
|
|
992
|
+
INVALID_REQUEST: 1002,
|
|
993
|
+
NO_AD: 1003,
|
|
994
|
+
ERROR: 1004,
|
|
995
|
+
INVALID_SPACE: 1005,
|
|
996
|
+
SDK_NOT_INITIALIZED: 1007,
|
|
997
|
+
HTTP_TIMEOUT: 1008,
|
|
998
|
+
EXECUTION_FAIL: 1009,
|
|
999
|
+
INTERRUPTED: 1010,
|
|
1000
|
+
FAIL: 1011,
|
|
1001
|
+
BLOCKED: 1012,
|
|
1002
|
+
TIMEOUT: 1013,
|
|
1003
|
+
LIMITED_AD: 1014,
|
|
1004
|
+
CONSENT_REQUIRED: 1015,
|
|
1005
|
+
TEST_MODE: 1016,
|
|
1006
|
+
INTERNAL_ERROR: 1017
|
|
1007
|
+
};
|
|
1008
|
+
var NON_ERROR_STATUSES = /* @__PURE__ */ new Set(["OK", "TEST_MODE", "NO_AD"]);
|
|
1009
|
+
var API_RESULT_ERROR_CODE_MAP = {
|
|
1010
|
+
HTTP_TIMEOUT: ERROR_CODES.HTTP_TIMEOUT,
|
|
1011
|
+
NETWORK_ERROR: ERROR_CODES.NETWORK_ERROR,
|
|
1012
|
+
EXECUTION_FAIL: ERROR_CODES.EXECUTION_FAIL,
|
|
1013
|
+
INTERRUPTED: ERROR_CODES.INTERRUPTED,
|
|
1014
|
+
INTERNAL_ERROR: ERROR_CODES.ERROR,
|
|
1015
|
+
FAIL: ERROR_CODES.FAIL
|
|
1016
|
+
};
|
|
1017
|
+
var AD_STATUS_ERROR_CODE_MAP = {
|
|
1018
|
+
BLOCKED: ERROR_CODES.BLOCKED,
|
|
1019
|
+
ERROR: ERROR_CODES.ERROR,
|
|
1020
|
+
TIMEOUT: ERROR_CODES.TIMEOUT,
|
|
1021
|
+
INVALID_SPACE: ERROR_CODES.INVALID_SPACE,
|
|
1022
|
+
INVALID_REQUEST: ERROR_CODES.INVALID_REQUEST,
|
|
1023
|
+
LIMITED_AD: ERROR_CODES.LIMITED_AD,
|
|
1024
|
+
CONSENT_REQUIRED: ERROR_CODES.CONSENT_REQUIRED
|
|
1025
|
+
};
|
|
1026
|
+
|
|
1027
|
+
// src/toss-ad/tossAdEventLog.ts
|
|
1028
|
+
var tossAdEventLog = createAsyncBridge("tossAdEventLog");
|
|
1029
|
+
|
|
1030
|
+
// src/toss-ad/errorTracking.ts
|
|
1031
|
+
var BANNER_ERROR_LOG_NAME = "display_ads_all::error__banner";
|
|
1032
|
+
function logBannerErrorToAppLog(info) {
|
|
1033
|
+
void tossAdEventLog({
|
|
1034
|
+
log_name: BANNER_ERROR_LOG_NAME,
|
|
1035
|
+
log_type: "debug",
|
|
1036
|
+
params: {
|
|
1037
|
+
error_code: info.errorCode,
|
|
1038
|
+
error_message: info.errorMessage,
|
|
1039
|
+
ad_group_id: info.adGroupId,
|
|
1040
|
+
mediation_id: info.mediationId,
|
|
1041
|
+
event_context_token: info.eventContextToken
|
|
1042
|
+
}
|
|
1043
|
+
}).catch(() => {
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
function trackBannerError(info) {
|
|
1047
|
+
if (info.endpointError) {
|
|
1048
|
+
void fetch(info.endpointError, {
|
|
1049
|
+
method: "POST",
|
|
1050
|
+
headers: { "Content-Type": "application/json" },
|
|
1051
|
+
body: JSON.stringify({
|
|
1052
|
+
eventContextToken: info.eventContextToken,
|
|
1053
|
+
mediationId: info.mediationId,
|
|
1054
|
+
errorCode: info.errorCode,
|
|
1055
|
+
errorMessage: info.errorMessage
|
|
1056
|
+
})
|
|
1057
|
+
// POST 실패(CORS·네트워크) → 앱로그 fallback (endpoint와 같은 채널이라 함께 막히는 경우 대비).
|
|
1058
|
+
}).catch(() => logBannerErrorToAppLog(info));
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
logBannerErrorToAppLog(info);
|
|
1062
|
+
}
|
|
1063
|
+
function trackResponseError(response, adGroupId, context) {
|
|
1064
|
+
if (response.resultType !== "SUCCESS") {
|
|
1065
|
+
trackBannerError({
|
|
1066
|
+
adGroupId,
|
|
1067
|
+
errorCode: API_RESULT_ERROR_CODE_MAP[response.resultType] ?? ERROR_CODES.INTERNAL_ERROR,
|
|
1068
|
+
errorMessage: response.error?.reason ?? response.resultType
|
|
1069
|
+
});
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
const success = response.success;
|
|
1073
|
+
if (!success || NON_ERROR_STATUSES.has(String(success.status))) {
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
trackBannerError({
|
|
1077
|
+
adGroupId,
|
|
1078
|
+
errorCode: AD_STATUS_ERROR_CODE_MAP[String(success.status)] ?? ERROR_CODES.INTERNAL_ERROR,
|
|
1079
|
+
mediationId: context.mediationId,
|
|
1080
|
+
eventContextToken: context.eventContextToken,
|
|
1081
|
+
errorMessage: `Ad response status: ${success.status}`,
|
|
1082
|
+
endpointError: context.errorEndpoint
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// src/toss-ad/eventTracking.ts
|
|
1087
|
+
async function handleTrackingRequest(request) {
|
|
1088
|
+
if (request.type === "EVENT_TRACKING") {
|
|
1089
|
+
await sendEventTracking(request);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
async function sendEventTracking(request) {
|
|
1093
|
+
if (request.urls.length === 0) {
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
const body = JSON.stringify({ type: request.eventName, data: request.eventPayload });
|
|
1097
|
+
const headers = { "Content-Type": "application/json" };
|
|
1098
|
+
if (request.requestId) {
|
|
1099
|
+
headers["X-Toss-RequestId"] = request.requestId;
|
|
1100
|
+
}
|
|
1101
|
+
const settled = await Promise.allSettled(
|
|
1102
|
+
request.urls.map(
|
|
1103
|
+
(url) => fetch(url, { method: "POST", headers, body }).then((response) => {
|
|
1104
|
+
if (!response.ok) {
|
|
1105
|
+
throw new Error(`HTTP ${response.status}`);
|
|
1106
|
+
}
|
|
1107
|
+
})
|
|
1108
|
+
)
|
|
1109
|
+
);
|
|
1110
|
+
const failedCount = settled.filter((result) => result.status === "rejected").length;
|
|
1111
|
+
if (failedCount === 0) {
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
trackBannerError({
|
|
1115
|
+
adGroupId: request.adGroupId,
|
|
1116
|
+
errorCode: ERROR_CODES.NETWORK_ERROR,
|
|
1117
|
+
errorMessage: `EVENT_TRACKING failed: ${request.eventName} (${failedCount}/${request.urls.length})`,
|
|
1118
|
+
mediationId: request.mediationId || void 0,
|
|
1119
|
+
eventContextToken: request.eventContextToken || void 0,
|
|
1120
|
+
endpointError: request.errorEndpoint
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// src/toss-ad/fetchAppsInTossAdSchema.ts
|
|
1125
|
+
var APPS_IN_TOSS_AD_SPEC_VERSION = "1.4.1";
|
|
1126
|
+
var FETCH_APPS_IN_TOSS_AD_DEVICE_MACRO = "{{device}}";
|
|
1127
|
+
var TOSS_APP_BUNDLE_IDS = {
|
|
1128
|
+
ios: "com.vivarepublica.cash",
|
|
1129
|
+
android: "viva.republica.toss"
|
|
1130
|
+
};
|
|
1131
|
+
function resolveTossAppBundleId(os) {
|
|
1132
|
+
return TOSS_APP_BUNDLE_IDS[os];
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
// src/toss-ad/normalize.ts
|
|
1136
|
+
var LIST_BANNER_STYLE_ID = "1";
|
|
1137
|
+
var NATIVE_IMAGE_STYLE_ID = "2";
|
|
1138
|
+
var AVAILABLE_STYLE_IDS = [LIST_BANNER_STYLE_ID, NATIVE_IMAGE_STYLE_ID];
|
|
1139
|
+
var SUPPORTED_STYLE_IDS = new Set(AVAILABLE_STYLE_IDS);
|
|
1140
|
+
function normalizeAdResponse(adResponse) {
|
|
1141
|
+
const ads = Array.isArray(adResponse.ads) ? adResponse.ads.filter((ad) => SUPPORTED_STYLE_IDS.has(String(ad.styleId))) : [];
|
|
1142
|
+
return {
|
|
1143
|
+
requestId: adResponse.requestId ?? "",
|
|
1144
|
+
// SDK가 event 트래킹 위임(onTrackingRequest) 시 응답 top-level에서 읽어 실어 보낸다.
|
|
1145
|
+
// 떼어내면 SDK가 토큰을 못 보고, event 트래킹 실패 시 endpoint.error에서 토큰이 빠진다.
|
|
1146
|
+
eventContextToken: adResponse.eventContextToken,
|
|
1147
|
+
status: adResponse.status ?? "OK",
|
|
1148
|
+
ads,
|
|
1149
|
+
ext: adResponse.ext
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
function normalizeApiResponse(raw) {
|
|
1153
|
+
if (isApiResponse(raw)) {
|
|
1154
|
+
if (raw.resultType !== "SUCCESS") {
|
|
1155
|
+
return raw;
|
|
1156
|
+
}
|
|
1157
|
+
if (!raw.success) {
|
|
1158
|
+
return {
|
|
1159
|
+
resultType: "FAIL",
|
|
1160
|
+
error: { reason: "fetchTossAd returned SUCCESS without payload" }
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
return { ...raw, success: normalizeAdResponse(raw.success) };
|
|
1164
|
+
}
|
|
1165
|
+
if (isAdResponse(raw)) {
|
|
1166
|
+
return {
|
|
1167
|
+
resultType: "SUCCESS",
|
|
1168
|
+
success: normalizeAdResponse(raw)
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
return { resultType: "FAIL", error: { reason: "Invalid response from fetchTossAd" } };
|
|
1172
|
+
}
|
|
1173
|
+
function isApiResponse(payload) {
|
|
1174
|
+
return Boolean(payload && typeof payload === "object" && "resultType" in payload);
|
|
1175
|
+
}
|
|
1176
|
+
function isAdResponse(payload) {
|
|
1177
|
+
return Boolean(payload && typeof payload === "object" && "ads" in payload);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
989
1180
|
// src/toss-ad/opener.ts
|
|
990
1181
|
var openURL = createAsyncBridge("openURL");
|
|
991
1182
|
function openUrlOpener(url) {
|
|
@@ -1000,8 +1191,49 @@ function supertossWeb(uri) {
|
|
|
1000
1191
|
return `supertoss://web?url=${encodeURIComponent(uri)}&external=true`;
|
|
1001
1192
|
}
|
|
1002
1193
|
|
|
1194
|
+
// src/toss-ad/resultTracking.ts
|
|
1195
|
+
async function fireResultTracking(response, adGroupId, ctx) {
|
|
1196
|
+
const status = response.success?.status;
|
|
1197
|
+
if (response.resultType !== "SUCCESS" || status !== "OK" && status !== "TEST_MODE") {
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
if (ctx.resultEndpoint == null || ctx.mediationId == null) {
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
const body = {
|
|
1204
|
+
mediationId: ctx.mediationId,
|
|
1205
|
+
spaceUnitId: adGroupId,
|
|
1206
|
+
requestId: response.success?.requestId ?? "",
|
|
1207
|
+
eventContextToken: ctx.eventContextToken,
|
|
1208
|
+
winnerSource: "TOSS",
|
|
1209
|
+
content: null,
|
|
1210
|
+
adUnitId: ctx.adUnitId ?? null,
|
|
1211
|
+
placementId: ctx.placementId ?? null,
|
|
1212
|
+
tossFailed: null
|
|
1213
|
+
};
|
|
1214
|
+
try {
|
|
1215
|
+
const res = await fetch(ctx.resultEndpoint, {
|
|
1216
|
+
method: "POST",
|
|
1217
|
+
headers: { "Content-Type": "application/json" },
|
|
1218
|
+
body: JSON.stringify(body)
|
|
1219
|
+
});
|
|
1220
|
+
if (!res.ok) {
|
|
1221
|
+
throw new Error(`HTTP ${res.status}`);
|
|
1222
|
+
}
|
|
1223
|
+
} catch (error) {
|
|
1224
|
+
trackBannerError({
|
|
1225
|
+
adGroupId,
|
|
1226
|
+
errorCode: ERROR_CODES.NETWORK_ERROR,
|
|
1227
|
+
errorMessage: `RESULT_TRACKING failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
1228
|
+
mediationId: ctx.mediationId,
|
|
1229
|
+
eventContextToken: ctx.eventContextToken,
|
|
1230
|
+
endpointError: ctx.errorEndpoint
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1003
1235
|
// src/toss-ad/scriptLoader.ts
|
|
1004
|
-
var DEFAULT_SDK_URL = "https://static.toss.im/ads/sdk/toss-ads-space-kit-1.
|
|
1236
|
+
var DEFAULT_SDK_URL = "https://static.toss.im/ads/sdk/toss-ads-space-kit-3.1.0.js";
|
|
1005
1237
|
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
1006
1238
|
var pendingLoad = null;
|
|
1007
1239
|
function getAdsSdk() {
|
|
@@ -1057,12 +1289,79 @@ function loadAdsSdk() {
|
|
|
1057
1289
|
return promise;
|
|
1058
1290
|
}
|
|
1059
1291
|
|
|
1292
|
+
// package.json
|
|
1293
|
+
var package_default = {
|
|
1294
|
+
name: "@apps-in-toss/web-bridge",
|
|
1295
|
+
type: "module",
|
|
1296
|
+
version: "2.10.1",
|
|
1297
|
+
description: "Web Bridge for Apps In Toss",
|
|
1298
|
+
scripts: {
|
|
1299
|
+
typecheck: "tsc --noEmit",
|
|
1300
|
+
lint: "eslint .",
|
|
1301
|
+
build: "tsup"
|
|
1302
|
+
},
|
|
1303
|
+
main: "./dist/index.cjs",
|
|
1304
|
+
module: "./dist/index.js",
|
|
1305
|
+
types: "./dist/index.d.ts",
|
|
1306
|
+
exports: {
|
|
1307
|
+
".": {
|
|
1308
|
+
import: {
|
|
1309
|
+
types: "./dist/index.d.ts",
|
|
1310
|
+
default: "./dist/index.js"
|
|
1311
|
+
},
|
|
1312
|
+
require: {
|
|
1313
|
+
types: "./dist/index.d.cts",
|
|
1314
|
+
default: "./dist/index.cjs"
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
},
|
|
1318
|
+
files: [
|
|
1319
|
+
"dist"
|
|
1320
|
+
],
|
|
1321
|
+
dependencies: {
|
|
1322
|
+
"@apps-in-toss/types": "workspace:*"
|
|
1323
|
+
},
|
|
1324
|
+
devDependencies: {
|
|
1325
|
+
"@apps-in-toss/bridge-core": "workspace:*",
|
|
1326
|
+
"@apps-in-toss/native-modules": "workspace:^",
|
|
1327
|
+
"@swc/core": "^1.12.7",
|
|
1328
|
+
picocolors: "^1.1.1",
|
|
1329
|
+
"ts-morph": "^26.0.0",
|
|
1330
|
+
tsup: "^8.5.0",
|
|
1331
|
+
typescript: "5.8.3",
|
|
1332
|
+
vitest: "^3.1.2"
|
|
1333
|
+
}
|
|
1334
|
+
};
|
|
1335
|
+
|
|
1336
|
+
// src/toss-ad/sdkVersion.ts
|
|
1337
|
+
var SDK_VERSION = package_default.version;
|
|
1338
|
+
|
|
1339
|
+
// src/toss-ad/trackingContext.ts
|
|
1340
|
+
function nonEmptyString(value) {
|
|
1341
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1342
|
+
}
|
|
1343
|
+
function extractAdTrackingContext(response) {
|
|
1344
|
+
const mediation = response?.ext?.mediation;
|
|
1345
|
+
return {
|
|
1346
|
+
mediationId: nonEmptyString(mediation?.mediationId),
|
|
1347
|
+
eventContextToken: nonEmptyString(response?.eventContextToken),
|
|
1348
|
+
resultEndpoint: nonEmptyString(mediation?.endpoint?.result),
|
|
1349
|
+
errorEndpoint: nonEmptyString(mediation?.endpoint?.error),
|
|
1350
|
+
adUnitId: nonEmptyString(mediation?.admob?.adUnitId),
|
|
1351
|
+
placementId: typeof mediation?.admob?.placementId === "number" ? mediation.admob.placementId : void 0
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1060
1355
|
// src/toss-ad/index.ts
|
|
1061
1356
|
var fetchTossAd = Object.assign(createEventBridge("fetchTossAd"), {
|
|
1062
1357
|
isSupported: createConstantBridge("fetchTossAd_isSupported")
|
|
1063
1358
|
});
|
|
1064
|
-
var
|
|
1065
|
-
|
|
1359
|
+
var fetchAppsInTossAd = Object.assign(createEventBridge("fetchAppsInTossAd"), {
|
|
1360
|
+
isSupported: createConstantBridge("fetchAppsInTossAd_isSupported")
|
|
1361
|
+
});
|
|
1362
|
+
var getPlatformOS = createConstantBridge("getPlatformOS");
|
|
1363
|
+
var getTossAppVersion = createConstantBridge("getTossAppVersion");
|
|
1364
|
+
var WEB_SDK_ID = "108";
|
|
1066
1365
|
var INVALID_AD_GROUP_ID_ERROR_MESSAGE = "\uC798\uBABB\uB41C \uC694\uCCAD\uC774\uC5D0\uC694. \uD544\uC694\uD55C \uAC12\uC774 \uBE44\uC5B4 \uC788\uC5B4\uC694.";
|
|
1067
1366
|
function normalizeAdGroupId(adGroupId) {
|
|
1068
1367
|
return adGroupId.trim();
|
|
@@ -1099,62 +1398,56 @@ function fetchTossAdPromise(options) {
|
|
|
1099
1398
|
});
|
|
1100
1399
|
});
|
|
1101
1400
|
}
|
|
1102
|
-
function
|
|
1103
|
-
|
|
1104
|
-
return {
|
|
1105
|
-
requestId: adResponse.requestId ?? "",
|
|
1106
|
-
status: adResponse.status ?? "OK",
|
|
1107
|
-
ads,
|
|
1108
|
-
ext: adResponse.ext
|
|
1109
|
-
};
|
|
1401
|
+
function getSubBundle() {
|
|
1402
|
+
return globalThis.__granite?.app?.name ?? "";
|
|
1110
1403
|
}
|
|
1111
|
-
function
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1404
|
+
function fetchAppsInTossAdPromise(spaceUnitId) {
|
|
1405
|
+
const platformOS = getPlatformOS();
|
|
1406
|
+
const tossAppVersion = getTossAppVersion();
|
|
1407
|
+
const body = {
|
|
1408
|
+
specVersion: APPS_IN_TOSS_AD_SPEC_VERSION,
|
|
1409
|
+
platform: "WEB",
|
|
1410
|
+
spaceUnitId,
|
|
1411
|
+
sdkVersion: SDK_VERSION,
|
|
1412
|
+
availableStyleIds: AVAILABLE_STYLE_IDS,
|
|
1413
|
+
// device는 매크로키만 보내고 native가 실제 device로 치환한다.
|
|
1414
|
+
device: FETCH_APPS_IN_TOSS_AD_DEVICE_MACRO,
|
|
1415
|
+
app: {
|
|
1416
|
+
version: tossAppVersion,
|
|
1417
|
+
bundle: resolveTossAppBundleId(platformOS),
|
|
1418
|
+
subBundle: getSubBundle()
|
|
1121
1419
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
resultType: "SUCCESS",
|
|
1127
|
-
success: normalizeAdResponse(raw)
|
|
1128
|
-
};
|
|
1129
|
-
}
|
|
1130
|
-
return { resultType: "FAIL", error: { reason: "Invalid response from fetchTossAd" } };
|
|
1131
|
-
}
|
|
1132
|
-
function isApiResponse(payload) {
|
|
1133
|
-
return Boolean(payload && typeof payload === "object" && "resultType" in payload);
|
|
1134
|
-
}
|
|
1135
|
-
function isAdResponse(payload) {
|
|
1136
|
-
return Boolean(payload && typeof payload === "object" && "ads" in payload);
|
|
1420
|
+
};
|
|
1421
|
+
return new Promise((resolve, reject) => {
|
|
1422
|
+
fetchAppsInTossAd({ options: body, onEvent: resolve, onError: reject });
|
|
1423
|
+
});
|
|
1137
1424
|
}
|
|
1138
1425
|
function createCustomAdFetcher() {
|
|
1139
1426
|
return async (_endpoint, request) => {
|
|
1140
1427
|
const spaceUnitId = normalizeAdGroupId(request.spaceUnitId);
|
|
1141
1428
|
if (spaceUnitId.length === 0) {
|
|
1429
|
+
trackBannerError({
|
|
1430
|
+
adGroupId: spaceUnitId,
|
|
1431
|
+
errorCode: ERROR_CODES.INVALID_SPACE,
|
|
1432
|
+
errorMessage: INVALID_AD_GROUP_ID_ERROR_MESSAGE
|
|
1433
|
+
});
|
|
1142
1434
|
return createInvalidAdGroupIdResponse();
|
|
1143
1435
|
}
|
|
1144
1436
|
try {
|
|
1145
|
-
const raw = await fetchTossAdPromise({
|
|
1437
|
+
const raw = fetchAppsInTossAd.isSupported() ? await fetchAppsInTossAdPromise(spaceUnitId) : await fetchTossAdPromise({
|
|
1146
1438
|
adGroupId: spaceUnitId,
|
|
1147
|
-
sdkId:
|
|
1148
|
-
availableStyleIds:
|
|
1439
|
+
sdkId: WEB_SDK_ID,
|
|
1440
|
+
availableStyleIds: AVAILABLE_STYLE_IDS
|
|
1149
1441
|
});
|
|
1150
|
-
|
|
1442
|
+
const response = normalizeApiResponse(raw);
|
|
1443
|
+
const trackingContext = extractAdTrackingContext(response.success);
|
|
1444
|
+
trackResponseError(response, spaceUnitId, trackingContext);
|
|
1445
|
+
void fireResultTracking(response, spaceUnitId, trackingContext);
|
|
1446
|
+
return response;
|
|
1151
1447
|
} catch (error) {
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
reason: error instanceof Error ? error.message : "Unknown fetchTossAd error"
|
|
1156
|
-
}
|
|
1157
|
-
};
|
|
1448
|
+
const reason = error instanceof Error ? error.message : "Unknown fetchTossAd error";
|
|
1449
|
+
trackBannerError({ adGroupId: spaceUnitId, errorCode: ERROR_CODES.NETWORK_ERROR, errorMessage: reason });
|
|
1450
|
+
return { resultType: "FAIL", error: { reason } };
|
|
1158
1451
|
}
|
|
1159
1452
|
};
|
|
1160
1453
|
}
|
|
@@ -1180,7 +1473,12 @@ function initialize(options) {
|
|
|
1180
1473
|
return;
|
|
1181
1474
|
}
|
|
1182
1475
|
const customAdFetcher = createCustomAdFetcher();
|
|
1183
|
-
const config = {
|
|
1476
|
+
const config = {
|
|
1477
|
+
environment: "live",
|
|
1478
|
+
customAdFetcher,
|
|
1479
|
+
opener: openUrlOpener,
|
|
1480
|
+
onTrackingRequest: handleTrackingRequest
|
|
1481
|
+
};
|
|
1184
1482
|
sdk.init(config);
|
|
1185
1483
|
});
|
|
1186
1484
|
pendingLoad2 = initPromise;
|
|
@@ -1357,7 +1655,7 @@ function attachBanner(adGroupId, target, options = {}) {
|
|
|
1357
1655
|
autoLoad: true,
|
|
1358
1656
|
theme: theme === "auto" ? void 0 : theme,
|
|
1359
1657
|
renderPadding: (styleId) => {
|
|
1360
|
-
if (styleId ===
|
|
1658
|
+
if (styleId === LIST_BANNER_STYLE_ID) {
|
|
1361
1659
|
return DEFAULT_ATTACH_PADDING_BANNER;
|
|
1362
1660
|
}
|
|
1363
1661
|
return DEFAULT_ATTACH_PADDING_NATIVE_IMAGE;
|
|
@@ -1430,6 +1728,8 @@ function wrapCallbacks(adGroupId, callbacks) {
|
|
|
1430
1728
|
});
|
|
1431
1729
|
callbacks.onAdImpression?.(mapEvent(payload));
|
|
1432
1730
|
},
|
|
1731
|
+
// 에러 트래킹은 응답을 소유한 createCustomAdFetcher가 담당한다. 콜백은 publisher 전달만.
|
|
1732
|
+
// 응답 수신 후 에러의 mediationId는 SDK(ads-sdk/web)가 error에 실어주므로 그대로 전달한다.
|
|
1433
1733
|
onAdFailedToRender: (payload) => callbacks.onAdFailedToRender?.({
|
|
1434
1734
|
...mapEvent(payload),
|
|
1435
1735
|
error: payload?.error ?? { code: 0, message: "UNKNOWN" }
|
|
@@ -1483,6 +1783,14 @@ function requestNotificationAgreement(params) {
|
|
|
1483
1783
|
return unregisterCallbacks;
|
|
1484
1784
|
}
|
|
1485
1785
|
|
|
1786
|
+
// src/getDeclaredAgeRange.ts
|
|
1787
|
+
var getDeclaredAgeRange = Object.assign(
|
|
1788
|
+
createAsyncBridge("getDeclaredAgeRange"),
|
|
1789
|
+
{
|
|
1790
|
+
isSupported: createConstantBridge("getDeclaredAgeRange_isSupported")
|
|
1791
|
+
}
|
|
1792
|
+
);
|
|
1793
|
+
|
|
1486
1794
|
// src/index.ts
|
|
1487
1795
|
export * from "@apps-in-toss/types";
|
|
1488
1796
|
export {
|
|
@@ -1501,6 +1809,7 @@ export {
|
|
|
1501
1809
|
getAppsInTossGlobals,
|
|
1502
1810
|
getClipboardText,
|
|
1503
1811
|
getCurrentLocation,
|
|
1812
|
+
getDeclaredAgeRange,
|
|
1504
1813
|
getSafeAreaInsets,
|
|
1505
1814
|
getServerTime,
|
|
1506
1815
|
graniteEvent,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apps-in-toss/web-bridge",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.10.1",
|
|
5
5
|
"description": "Web Bridge for Apps In Toss",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"typecheck": "tsc --noEmit",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"dist"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@apps-in-toss/types": "2.
|
|
30
|
+
"@apps-in-toss/types": "2.10.1"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@apps-in-toss/bridge-core": "2.
|
|
34
|
-
"@apps-in-toss/native-modules": "^2.
|
|
33
|
+
"@apps-in-toss/bridge-core": "2.10.1",
|
|
34
|
+
"@apps-in-toss/native-modules": "^2.10.1",
|
|
35
35
|
"@swc/core": "^1.12.7",
|
|
36
36
|
"picocolors": "^1.1.1",
|
|
37
37
|
"ts-morph": "^26.0.0",
|