@ait-co/devtools 0.0.3 → 0.1.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/mock/index.d.ts +464 -464
- package/dist/mock/index.d.ts.map +1 -1
- package/dist/mock/index.js +452 -451
- package/dist/mock/index.js.map +1 -1
- package/dist/panel/index.d.ts.map +1 -1
- package/dist/panel/index.js +325 -324
- package/dist/panel/index.js.map +1 -1
- package/dist/unplugin/index.cjs.map +1 -1
- package/dist/unplugin/index.d.cts +9945 -1211
- package/dist/unplugin/index.d.cts.map +1 -1
- package/dist/unplugin/index.d.ts +9945 -1211
- package/dist/unplugin/index.d.ts.map +1 -1
- package/dist/unplugin/index.js.map +1 -1
- package/package.json +8 -2
package/dist/mock/index.js
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
//#region src/mock/proxy.ts
|
|
2
|
+
/**
|
|
3
|
+
* 미구현 API용 Proxy 트립와이어.
|
|
4
|
+
*
|
|
5
|
+
* 미구현 프로퍼티에 접근하면 throw한다. 이는 "devtools에서는 멀쩡히 돌지만
|
|
6
|
+
* 실 SDK에선 실제로 동작하는" 시나리오를 차단하기 위한 의도적 선택이다.
|
|
7
|
+
* mock이 미구현인 API는 실 SDK에서는 존재할 수 있고, 사용자가 이를 인지하지
|
|
8
|
+
* 못한 채 개발을 이어가면 배포 시점에 놀라게 된다. 에러 메시지에 이슈 URL을
|
|
9
|
+
* 포함해 사용자가 mock 누락을 제보할 수 있게 한다.
|
|
10
|
+
*/
|
|
11
|
+
const ISSUES_URL = "https://github.com/apps-in-toss-community/devtools/issues";
|
|
12
|
+
function createMockProxy(moduleName, implementations) {
|
|
13
|
+
return new Proxy(implementations, { get(target, prop) {
|
|
14
|
+
if (typeof prop === "symbol") return void 0;
|
|
15
|
+
if (prop in target) return target[prop];
|
|
16
|
+
throw new Error(`[@ait-co/devtools] ${moduleName}.${prop} is not mocked. This API may exist in @apps-in-toss/web-framework, but devtools' mock does not cover it yet. Please file an issue: ${ISSUES_URL}`);
|
|
17
|
+
} });
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
1
20
|
//#region src/mock/state.ts
|
|
2
21
|
const DEFAULT_STATE = {
|
|
3
22
|
platform: "ios",
|
|
@@ -109,7 +128,7 @@ var AitStateManager = class {
|
|
|
109
128
|
try {
|
|
110
129
|
this._state.deviceId = generateDeviceId();
|
|
111
130
|
} catch {
|
|
112
|
-
this._state.deviceId =
|
|
131
|
+
this._state.deviceId = `mock-device-${Math.random().toString(36).slice(2)}`;
|
|
113
132
|
}
|
|
114
133
|
}
|
|
115
134
|
get state() {
|
|
@@ -172,6 +191,133 @@ var AitStateManager = class {
|
|
|
172
191
|
const aitState = new AitStateManager();
|
|
173
192
|
if (typeof window !== "undefined") window.__ait = aitState;
|
|
174
193
|
//#endregion
|
|
194
|
+
//#region src/mock/ads/index.ts
|
|
195
|
+
/**
|
|
196
|
+
* 광고 mock (GoogleAdMob, TossAds, FullScreenAd)
|
|
197
|
+
*/
|
|
198
|
+
function withIsSupported(fn) {
|
|
199
|
+
fn.isSupported = () => true;
|
|
200
|
+
return fn;
|
|
201
|
+
}
|
|
202
|
+
const GoogleAdMob = createMockProxy("GoogleAdMob", {
|
|
203
|
+
loadAppsInTossAdMob: withIsSupported((args) => {
|
|
204
|
+
setTimeout(() => {
|
|
205
|
+
aitState.patch("ads", { isLoaded: true });
|
|
206
|
+
args.onEvent({
|
|
207
|
+
type: "loaded",
|
|
208
|
+
data: { adGroupId: args.options?.adGroupId }
|
|
209
|
+
});
|
|
210
|
+
}, 200);
|
|
211
|
+
return () => {};
|
|
212
|
+
}),
|
|
213
|
+
showAppsInTossAdMob: withIsSupported((args) => {
|
|
214
|
+
if (!aitState.state.ads.isLoaded) {
|
|
215
|
+
args.onError(/* @__PURE__ */ new Error("Ad not loaded"));
|
|
216
|
+
return () => {};
|
|
217
|
+
}
|
|
218
|
+
setTimeout(() => args.onEvent({ type: "requested" }), 50);
|
|
219
|
+
setTimeout(() => args.onEvent({ type: "show" }), 100);
|
|
220
|
+
setTimeout(() => args.onEvent({ type: "impression" }), 150);
|
|
221
|
+
setTimeout(() => {
|
|
222
|
+
args.onEvent({
|
|
223
|
+
type: "userEarnedReward",
|
|
224
|
+
data: {
|
|
225
|
+
unitType: "coins",
|
|
226
|
+
unitAmount: 10
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}, 1e3);
|
|
230
|
+
setTimeout(() => {
|
|
231
|
+
args.onEvent({ type: "dismissed" });
|
|
232
|
+
aitState.patch("ads", { isLoaded: false });
|
|
233
|
+
}, 1500);
|
|
234
|
+
return () => {};
|
|
235
|
+
}),
|
|
236
|
+
isAppsInTossAdMobLoaded: withIsSupported(async (_options) => aitState.state.ads.isLoaded)
|
|
237
|
+
});
|
|
238
|
+
const TossAds = createMockProxy("TossAds", {
|
|
239
|
+
initialize: withIsSupported((_options) => {
|
|
240
|
+
console.log("[@ait-co/devtools] TossAds.initialize (mock)");
|
|
241
|
+
}),
|
|
242
|
+
attach: withIsSupported((_adGroupId, target, _options) => {
|
|
243
|
+
const el = typeof target === "string" ? document.querySelector(target) : target;
|
|
244
|
+
if (el) {
|
|
245
|
+
const placeholder = document.createElement("div");
|
|
246
|
+
placeholder.style.cssText = "background:#f0f0f0;border:1px dashed #999;padding:16px;text-align:center;color:#666;font-size:14px;";
|
|
247
|
+
placeholder.textContent = "[@ait-co/devtools] TossAds Placeholder";
|
|
248
|
+
el.appendChild(placeholder);
|
|
249
|
+
}
|
|
250
|
+
}),
|
|
251
|
+
attachBanner: withIsSupported((_adGroupId, target, _options) => {
|
|
252
|
+
const el = typeof target === "string" ? document.querySelector(target) : target;
|
|
253
|
+
if (el) {
|
|
254
|
+
const placeholder = document.createElement("div");
|
|
255
|
+
placeholder.style.cssText = "background:#f0f0f0;border:1px dashed #999;padding:12px;text-align:center;color:#666;font-size:12px;";
|
|
256
|
+
placeholder.textContent = "[@ait-co/devtools] Banner Ad Placeholder";
|
|
257
|
+
el.appendChild(placeholder);
|
|
258
|
+
}
|
|
259
|
+
return { destroy: () => {} };
|
|
260
|
+
}),
|
|
261
|
+
destroy: withIsSupported((_slotId) => {}),
|
|
262
|
+
destroyAll: withIsSupported(() => {})
|
|
263
|
+
});
|
|
264
|
+
const loadFullScreenAd = withIsSupported((args) => {
|
|
265
|
+
setTimeout(() => {
|
|
266
|
+
aitState.patch("ads", { isLoaded: true });
|
|
267
|
+
args.onEvent({
|
|
268
|
+
type: "loaded",
|
|
269
|
+
data: { adGroupId: args.options?.adGroupId }
|
|
270
|
+
});
|
|
271
|
+
}, 200);
|
|
272
|
+
return () => {};
|
|
273
|
+
});
|
|
274
|
+
const showFullScreenAd = withIsSupported((args) => {
|
|
275
|
+
if (!aitState.state.ads.isLoaded) {
|
|
276
|
+
args.onError(/* @__PURE__ */ new Error("Ad not loaded"));
|
|
277
|
+
return () => {};
|
|
278
|
+
}
|
|
279
|
+
setTimeout(() => args.onEvent({ type: "show" }), 100);
|
|
280
|
+
setTimeout(() => args.onEvent({ type: "dismissed" }), 1500);
|
|
281
|
+
return () => {};
|
|
282
|
+
});
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/mock/analytics/index.ts
|
|
285
|
+
/**
|
|
286
|
+
* Analytics mock
|
|
287
|
+
*/
|
|
288
|
+
const Analytics = {
|
|
289
|
+
screen: (params) => {
|
|
290
|
+
aitState.logAnalytics({
|
|
291
|
+
type: "screen",
|
|
292
|
+
params: params ?? {}
|
|
293
|
+
});
|
|
294
|
+
return Promise.resolve();
|
|
295
|
+
},
|
|
296
|
+
impression: (params) => {
|
|
297
|
+
aitState.logAnalytics({
|
|
298
|
+
type: "impression",
|
|
299
|
+
params: params ?? {}
|
|
300
|
+
});
|
|
301
|
+
return Promise.resolve();
|
|
302
|
+
},
|
|
303
|
+
click: (params) => {
|
|
304
|
+
aitState.logAnalytics({
|
|
305
|
+
type: "click",
|
|
306
|
+
params: params ?? {}
|
|
307
|
+
});
|
|
308
|
+
return Promise.resolve();
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
async function eventLog(params) {
|
|
312
|
+
aitState.logAnalytics({
|
|
313
|
+
type: params.log_type,
|
|
314
|
+
params: {
|
|
315
|
+
log_name: params.log_name,
|
|
316
|
+
...params.params
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
//#endregion
|
|
175
321
|
//#region src/mock/auth/index.ts
|
|
176
322
|
/**
|
|
177
323
|
* 인증/로그인 mock
|
|
@@ -207,7 +353,7 @@ function generatePlaceholderImage(width, height, text, color) {
|
|
|
207
353
|
const ctx = canvas.getContext("2d");
|
|
208
354
|
if (!ctx) {
|
|
209
355
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}"><rect fill="${color}" width="${width}" height="${height}"/><text x="50%" y="50%" fill="white" font-size="16" text-anchor="middle" dominant-baseline="middle">${text}</text></svg>`;
|
|
210
|
-
return
|
|
356
|
+
return `data:image/svg+xml;base64,${btoa(svg)}`;
|
|
211
357
|
}
|
|
212
358
|
ctx.fillStyle = color;
|
|
213
359
|
ctx.fillRect(0, 0, width, height);
|
|
@@ -247,7 +393,7 @@ const PROMPT_TIMEOUT_MS = 3e4;
|
|
|
247
393
|
/** @internal device 모듈 내부 전용 */
|
|
248
394
|
function waitForPromptResponse(type) {
|
|
249
395
|
return new Promise((resolve, reject) => {
|
|
250
|
-
const eventName =
|
|
396
|
+
const eventName = `__ait:prompt-response:${type}`;
|
|
251
397
|
const cancelName = "__ait:prompt-cancel";
|
|
252
398
|
function cleanup() {
|
|
253
399
|
clearTimeout(timer);
|
|
@@ -273,45 +419,6 @@ function waitForPromptResponse(type) {
|
|
|
273
419
|
});
|
|
274
420
|
}
|
|
275
421
|
//#endregion
|
|
276
|
-
//#region src/mock/proxy.ts
|
|
277
|
-
/**
|
|
278
|
-
* 미구현 API용 Proxy 트립와이어.
|
|
279
|
-
*
|
|
280
|
-
* 미구현 프로퍼티에 접근하면 throw한다. 이는 "devtools에서는 멀쩡히 돌지만
|
|
281
|
-
* 실 SDK에선 실제로 동작하는" 시나리오를 차단하기 위한 의도적 선택이다.
|
|
282
|
-
* mock이 미구현인 API는 실 SDK에서는 존재할 수 있고, 사용자가 이를 인지하지
|
|
283
|
-
* 못한 채 개발을 이어가면 배포 시점에 놀라게 된다. 에러 메시지에 이슈 URL을
|
|
284
|
-
* 포함해 사용자가 mock 누락을 제보할 수 있게 한다.
|
|
285
|
-
*/
|
|
286
|
-
const ISSUES_URL = "https://github.com/apps-in-toss-community/devtools/issues";
|
|
287
|
-
function createMockProxy(moduleName, implementations) {
|
|
288
|
-
return new Proxy(implementations, { get(target, prop) {
|
|
289
|
-
if (typeof prop === "symbol") return void 0;
|
|
290
|
-
if (prop in target) return target[prop];
|
|
291
|
-
throw new Error(`[@ait-co/devtools] ${moduleName}.${prop} is not mocked. This API may exist in @apps-in-toss/web-framework, but devtools' mock does not cover it yet. Please file an issue: ${ISSUES_URL}`);
|
|
292
|
-
} });
|
|
293
|
-
}
|
|
294
|
-
//#endregion
|
|
295
|
-
//#region src/mock/device/storage.ts
|
|
296
|
-
/**
|
|
297
|
-
* Storage mock
|
|
298
|
-
* localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리
|
|
299
|
-
*/
|
|
300
|
-
const Storage = createMockProxy("Storage", {
|
|
301
|
-
getItem: async (key) => {
|
|
302
|
-
return localStorage.getItem(`__ait_storage:${key}`);
|
|
303
|
-
},
|
|
304
|
-
setItem: async (key, value) => {
|
|
305
|
-
localStorage.setItem(`__ait_storage:${key}`, value);
|
|
306
|
-
},
|
|
307
|
-
removeItem: async (key) => {
|
|
308
|
-
localStorage.removeItem(`__ait_storage:${key}`);
|
|
309
|
-
},
|
|
310
|
-
clearItems: async () => {
|
|
311
|
-
Object.keys(localStorage).filter((k) => k.startsWith("__ait_storage:")).forEach((k) => localStorage.removeItem(k));
|
|
312
|
-
}
|
|
313
|
-
});
|
|
314
|
-
//#endregion
|
|
315
422
|
//#region src/mock/permissions.ts
|
|
316
423
|
/**
|
|
317
424
|
* 권한 시스템 mock
|
|
@@ -340,147 +447,36 @@ function checkPermission(name, fnName) {
|
|
|
340
447
|
if (aitState.state.permissions[name] === "denied") throw new Error(`[@ait-co/devtools] ${fnName}: Permission "${name}" is denied. Change it in the DevTools panel.`);
|
|
341
448
|
}
|
|
342
449
|
//#endregion
|
|
343
|
-
//#region src/mock/device/
|
|
450
|
+
//#region src/mock/device/camera.ts
|
|
344
451
|
/**
|
|
345
|
-
*
|
|
452
|
+
* Camera & Album Photos mock
|
|
346
453
|
* mock/web/prompt 모드 지원
|
|
347
454
|
*/
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
Accuracy[Accuracy["Low"] = 2] = "Low";
|
|
351
|
-
Accuracy[Accuracy["Balanced"] = 3] = "Balanced";
|
|
352
|
-
Accuracy[Accuracy["High"] = 4] = "High";
|
|
353
|
-
Accuracy[Accuracy["Highest"] = 5] = "Highest";
|
|
354
|
-
Accuracy[Accuracy["BestForNavigation"] = 6] = "BestForNavigation";
|
|
355
|
-
return Accuracy;
|
|
356
|
-
}(Accuracy || {});
|
|
357
|
-
function buildLocation() {
|
|
455
|
+
async function openCameraMock() {
|
|
456
|
+
const images = getMockImages();
|
|
358
457
|
return {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
accessLocation: aitState.state.location.accessLocation
|
|
458
|
+
id: crypto.randomUUID(),
|
|
459
|
+
dataUri: images[0]
|
|
362
460
|
};
|
|
363
461
|
}
|
|
364
|
-
async function
|
|
365
|
-
return
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
heading: pos.coords.heading ?? 0
|
|
383
|
-
},
|
|
384
|
-
timestamp: pos.timestamp,
|
|
385
|
-
accessLocation: "FINE"
|
|
386
|
-
});
|
|
387
|
-
}, () => {
|
|
388
|
-
console.warn("[@ait-co/devtools] Geolocation failed, falling back to mock");
|
|
389
|
-
resolve(buildLocation());
|
|
390
|
-
});
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
async function getCurrentLocationPrompt() {
|
|
394
|
-
return waitForPromptResponse("location");
|
|
395
|
-
}
|
|
396
|
-
const _getCurrentLocation = async (_options) => {
|
|
397
|
-
checkPermission("geolocation", "getCurrentLocation");
|
|
398
|
-
const mode = aitState.state.deviceModes.location;
|
|
399
|
-
if (mode === "web") return getCurrentLocationWeb();
|
|
400
|
-
if (mode === "prompt") return getCurrentLocationPrompt();
|
|
401
|
-
return getCurrentLocationMock();
|
|
402
|
-
};
|
|
403
|
-
const getCurrentLocation = withPermission(_getCurrentLocation, "geolocation");
|
|
404
|
-
function startUpdateLocationMock(eventParams) {
|
|
405
|
-
const { onEvent, options } = eventParams;
|
|
406
|
-
const interval = Math.max(options.timeInterval, 500);
|
|
407
|
-
const id = setInterval(() => {
|
|
408
|
-
const loc = buildLocation();
|
|
409
|
-
loc.coords.latitude += (Math.random() - .5) * 1e-4;
|
|
410
|
-
loc.coords.longitude += (Math.random() - .5) * 1e-4;
|
|
411
|
-
onEvent(loc);
|
|
412
|
-
}, interval);
|
|
413
|
-
return () => clearInterval(id);
|
|
414
|
-
}
|
|
415
|
-
function startUpdateLocationWeb(eventParams) {
|
|
416
|
-
const { onEvent, onError } = eventParams;
|
|
417
|
-
if (!navigator.geolocation) {
|
|
418
|
-
console.warn("[@ait-co/devtools] Geolocation API not available, falling back to mock");
|
|
419
|
-
return startUpdateLocationMock(eventParams);
|
|
420
|
-
}
|
|
421
|
-
const watchId = navigator.geolocation.watchPosition((pos) => {
|
|
422
|
-
onEvent({
|
|
423
|
-
coords: {
|
|
424
|
-
latitude: pos.coords.latitude,
|
|
425
|
-
longitude: pos.coords.longitude,
|
|
426
|
-
altitude: pos.coords.altitude ?? 0,
|
|
427
|
-
accuracy: pos.coords.accuracy,
|
|
428
|
-
altitudeAccuracy: pos.coords.altitudeAccuracy ?? 0,
|
|
429
|
-
heading: pos.coords.heading ?? 0
|
|
430
|
-
},
|
|
431
|
-
timestamp: pos.timestamp,
|
|
432
|
-
accessLocation: "FINE"
|
|
433
|
-
});
|
|
434
|
-
}, (err) => onError(err));
|
|
435
|
-
return () => navigator.geolocation.clearWatch(watchId);
|
|
436
|
-
}
|
|
437
|
-
function startUpdateLocationPrompt(eventParams) {
|
|
438
|
-
const { onEvent } = eventParams;
|
|
439
|
-
const handler = (e) => {
|
|
440
|
-
onEvent(e.detail);
|
|
441
|
-
};
|
|
442
|
-
window.addEventListener("__ait:prompt-response:location-update", handler);
|
|
443
|
-
window.dispatchEvent(new CustomEvent("__ait:prompt-request", { detail: { type: "location-update" } }));
|
|
444
|
-
return () => window.removeEventListener("__ait:prompt-response:location-update", handler);
|
|
445
|
-
}
|
|
446
|
-
const _startUpdateLocation = (eventParams) => {
|
|
447
|
-
const mode = aitState.state.deviceModes.location;
|
|
448
|
-
if (mode === "web") return startUpdateLocationWeb(eventParams);
|
|
449
|
-
if (mode === "prompt") return startUpdateLocationPrompt(eventParams);
|
|
450
|
-
return startUpdateLocationMock(eventParams);
|
|
451
|
-
};
|
|
452
|
-
const startUpdateLocation = withPermission(_startUpdateLocation, "geolocation");
|
|
453
|
-
//#endregion
|
|
454
|
-
//#region src/mock/device/camera.ts
|
|
455
|
-
/**
|
|
456
|
-
* Camera & Album Photos mock
|
|
457
|
-
* mock/web/prompt 모드 지원
|
|
458
|
-
*/
|
|
459
|
-
async function openCameraMock() {
|
|
460
|
-
const images = getMockImages();
|
|
461
|
-
return {
|
|
462
|
-
id: crypto.randomUUID(),
|
|
463
|
-
dataUri: images[0]
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
async function openCameraWeb() {
|
|
467
|
-
return new Promise((resolve, reject) => {
|
|
468
|
-
const input = document.createElement("input");
|
|
469
|
-
input.type = "file";
|
|
470
|
-
input.accept = "image/*";
|
|
471
|
-
input.capture = "environment";
|
|
472
|
-
let settled = false;
|
|
473
|
-
input.onchange = () => {
|
|
474
|
-
settled = true;
|
|
475
|
-
const file = input.files?.[0];
|
|
476
|
-
if (!file) {
|
|
477
|
-
reject(/* @__PURE__ */ new Error("No file selected"));
|
|
478
|
-
return;
|
|
479
|
-
}
|
|
480
|
-
const reader = new FileReader();
|
|
481
|
-
reader.onload = () => resolve({
|
|
482
|
-
id: crypto.randomUUID(),
|
|
483
|
-
dataUri: reader.result
|
|
462
|
+
async function openCameraWeb() {
|
|
463
|
+
return new Promise((resolve, reject) => {
|
|
464
|
+
const input = document.createElement("input");
|
|
465
|
+
input.type = "file";
|
|
466
|
+
input.accept = "image/*";
|
|
467
|
+
input.capture = "environment";
|
|
468
|
+
let settled = false;
|
|
469
|
+
input.onchange = () => {
|
|
470
|
+
settled = true;
|
|
471
|
+
const file = input.files?.[0];
|
|
472
|
+
if (!file) {
|
|
473
|
+
reject(/* @__PURE__ */ new Error("No file selected"));
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
const reader = new FileReader();
|
|
477
|
+
reader.onload = () => resolve({
|
|
478
|
+
id: crypto.randomUUID(),
|
|
479
|
+
dataUri: reader.result
|
|
484
480
|
});
|
|
485
481
|
reader.onerror = () => reject(/* @__PURE__ */ new Error("Failed to read file"));
|
|
486
482
|
reader.readAsDataURL(file);
|
|
@@ -630,6 +626,117 @@ async function saveBase64Data(params) {
|
|
|
630
626
|
a.click();
|
|
631
627
|
}
|
|
632
628
|
//#endregion
|
|
629
|
+
//#region src/mock/device/location.ts
|
|
630
|
+
/**
|
|
631
|
+
* Location mock (getCurrentLocation, startUpdateLocation)
|
|
632
|
+
* mock/web/prompt 모드 지원
|
|
633
|
+
*/
|
|
634
|
+
var Accuracy = /* @__PURE__ */ function(Accuracy) {
|
|
635
|
+
Accuracy[Accuracy["Lowest"] = 1] = "Lowest";
|
|
636
|
+
Accuracy[Accuracy["Low"] = 2] = "Low";
|
|
637
|
+
Accuracy[Accuracy["Balanced"] = 3] = "Balanced";
|
|
638
|
+
Accuracy[Accuracy["High"] = 4] = "High";
|
|
639
|
+
Accuracy[Accuracy["Highest"] = 5] = "Highest";
|
|
640
|
+
Accuracy[Accuracy["BestForNavigation"] = 6] = "BestForNavigation";
|
|
641
|
+
return Accuracy;
|
|
642
|
+
}(Accuracy || {});
|
|
643
|
+
function buildLocation() {
|
|
644
|
+
return {
|
|
645
|
+
coords: { ...aitState.state.location.coords },
|
|
646
|
+
timestamp: Date.now(),
|
|
647
|
+
accessLocation: aitState.state.location.accessLocation
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
async function getCurrentLocationMock() {
|
|
651
|
+
return buildLocation();
|
|
652
|
+
}
|
|
653
|
+
async function getCurrentLocationWeb() {
|
|
654
|
+
return new Promise((resolve) => {
|
|
655
|
+
if (!navigator.geolocation) {
|
|
656
|
+
console.warn("[@ait-co/devtools] Geolocation API not available, falling back to mock");
|
|
657
|
+
resolve(buildLocation());
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
navigator.geolocation.getCurrentPosition((pos) => {
|
|
661
|
+
resolve({
|
|
662
|
+
coords: {
|
|
663
|
+
latitude: pos.coords.latitude,
|
|
664
|
+
longitude: pos.coords.longitude,
|
|
665
|
+
altitude: pos.coords.altitude ?? 0,
|
|
666
|
+
accuracy: pos.coords.accuracy,
|
|
667
|
+
altitudeAccuracy: pos.coords.altitudeAccuracy ?? 0,
|
|
668
|
+
heading: pos.coords.heading ?? 0
|
|
669
|
+
},
|
|
670
|
+
timestamp: pos.timestamp,
|
|
671
|
+
accessLocation: "FINE"
|
|
672
|
+
});
|
|
673
|
+
}, () => {
|
|
674
|
+
console.warn("[@ait-co/devtools] Geolocation failed, falling back to mock");
|
|
675
|
+
resolve(buildLocation());
|
|
676
|
+
});
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
async function getCurrentLocationPrompt() {
|
|
680
|
+
return waitForPromptResponse("location");
|
|
681
|
+
}
|
|
682
|
+
const _getCurrentLocation = async (_options) => {
|
|
683
|
+
checkPermission("geolocation", "getCurrentLocation");
|
|
684
|
+
const mode = aitState.state.deviceModes.location;
|
|
685
|
+
if (mode === "web") return getCurrentLocationWeb();
|
|
686
|
+
if (mode === "prompt") return getCurrentLocationPrompt();
|
|
687
|
+
return getCurrentLocationMock();
|
|
688
|
+
};
|
|
689
|
+
const getCurrentLocation = withPermission(_getCurrentLocation, "geolocation");
|
|
690
|
+
function startUpdateLocationMock(eventParams) {
|
|
691
|
+
const { onEvent, options } = eventParams;
|
|
692
|
+
const interval = Math.max(options.timeInterval, 500);
|
|
693
|
+
const id = setInterval(() => {
|
|
694
|
+
const loc = buildLocation();
|
|
695
|
+
loc.coords.latitude += (Math.random() - .5) * 1e-4;
|
|
696
|
+
loc.coords.longitude += (Math.random() - .5) * 1e-4;
|
|
697
|
+
onEvent(loc);
|
|
698
|
+
}, interval);
|
|
699
|
+
return () => clearInterval(id);
|
|
700
|
+
}
|
|
701
|
+
function startUpdateLocationWeb(eventParams) {
|
|
702
|
+
const { onEvent, onError } = eventParams;
|
|
703
|
+
if (!navigator.geolocation) {
|
|
704
|
+
console.warn("[@ait-co/devtools] Geolocation API not available, falling back to mock");
|
|
705
|
+
return startUpdateLocationMock(eventParams);
|
|
706
|
+
}
|
|
707
|
+
const watchId = navigator.geolocation.watchPosition((pos) => {
|
|
708
|
+
onEvent({
|
|
709
|
+
coords: {
|
|
710
|
+
latitude: pos.coords.latitude,
|
|
711
|
+
longitude: pos.coords.longitude,
|
|
712
|
+
altitude: pos.coords.altitude ?? 0,
|
|
713
|
+
accuracy: pos.coords.accuracy,
|
|
714
|
+
altitudeAccuracy: pos.coords.altitudeAccuracy ?? 0,
|
|
715
|
+
heading: pos.coords.heading ?? 0
|
|
716
|
+
},
|
|
717
|
+
timestamp: pos.timestamp,
|
|
718
|
+
accessLocation: "FINE"
|
|
719
|
+
});
|
|
720
|
+
}, (err) => onError(err));
|
|
721
|
+
return () => navigator.geolocation.clearWatch(watchId);
|
|
722
|
+
}
|
|
723
|
+
function startUpdateLocationPrompt(eventParams) {
|
|
724
|
+
const { onEvent } = eventParams;
|
|
725
|
+
const handler = (e) => {
|
|
726
|
+
onEvent(e.detail);
|
|
727
|
+
};
|
|
728
|
+
window.addEventListener("__ait:prompt-response:location-update", handler);
|
|
729
|
+
window.dispatchEvent(new CustomEvent("__ait:prompt-request", { detail: { type: "location-update" } }));
|
|
730
|
+
return () => window.removeEventListener("__ait:prompt-response:location-update", handler);
|
|
731
|
+
}
|
|
732
|
+
const _startUpdateLocation = (eventParams) => {
|
|
733
|
+
const mode = aitState.state.deviceModes.location;
|
|
734
|
+
if (mode === "web") return startUpdateLocationWeb(eventParams);
|
|
735
|
+
if (mode === "prompt") return startUpdateLocationPrompt(eventParams);
|
|
736
|
+
return startUpdateLocationMock(eventParams);
|
|
737
|
+
};
|
|
738
|
+
const startUpdateLocation = withPermission(_startUpdateLocation, "geolocation");
|
|
739
|
+
//#endregion
|
|
633
740
|
//#region src/mock/device/network.ts
|
|
634
741
|
/**
|
|
635
742
|
* Network Status mock (mode-aware helper)
|
|
@@ -657,133 +764,69 @@ function getNetworkStatusByMode() {
|
|
|
657
764
|
return null;
|
|
658
765
|
}
|
|
659
766
|
//#endregion
|
|
660
|
-
//#region src/mock/
|
|
767
|
+
//#region src/mock/device/storage.ts
|
|
661
768
|
/**
|
|
662
|
-
*
|
|
769
|
+
* Storage mock
|
|
770
|
+
* localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리
|
|
663
771
|
*/
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
}
|
|
668
|
-
async
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
772
|
+
const Storage = createMockProxy("Storage", {
|
|
773
|
+
getItem: async (key) => {
|
|
774
|
+
return localStorage.getItem(`__ait_storage:${key}`);
|
|
775
|
+
},
|
|
776
|
+
setItem: async (key, value) => {
|
|
777
|
+
localStorage.setItem(`__ait_storage:${key}`, value);
|
|
778
|
+
},
|
|
779
|
+
removeItem: async (key) => {
|
|
780
|
+
localStorage.removeItem(`__ait_storage:${key}`);
|
|
781
|
+
},
|
|
782
|
+
clearItems: async () => {
|
|
783
|
+
const keys = Object.keys(localStorage).filter((k) => k.startsWith("__ait_storage:"));
|
|
784
|
+
for (const k of keys) localStorage.removeItem(k);
|
|
676
785
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
786
|
+
});
|
|
787
|
+
//#endregion
|
|
788
|
+
//#region src/mock/game/index.ts
|
|
789
|
+
/**
|
|
790
|
+
* 게임/프로모션 mock
|
|
791
|
+
*/
|
|
792
|
+
async function grantPromotionReward(params) {
|
|
793
|
+
console.log("[@ait-co/devtools] grantPromotionReward:", params.params);
|
|
794
|
+
return { key: `mock-reward-${Date.now()}` };
|
|
684
795
|
}
|
|
685
|
-
async function
|
|
686
|
-
console.log("[@ait-co/devtools]
|
|
796
|
+
async function grantPromotionRewardForGame(params) {
|
|
797
|
+
console.log("[@ait-co/devtools] grantPromotionRewardForGame:", params.params);
|
|
798
|
+
return { key: `mock-reward-${Date.now()}` };
|
|
687
799
|
}
|
|
688
|
-
async function
|
|
689
|
-
|
|
690
|
-
|
|
800
|
+
async function submitGameCenterLeaderBoardScore(params) {
|
|
801
|
+
aitState.patch("game", { leaderboardScores: [...aitState.state.game.leaderboardScores, {
|
|
802
|
+
score: params.score,
|
|
803
|
+
timestamp: Date.now()
|
|
804
|
+
}] });
|
|
805
|
+
return { statusCode: "SUCCESS" };
|
|
691
806
|
}
|
|
692
|
-
async function
|
|
693
|
-
|
|
694
|
-
return {
|
|
695
|
-
}
|
|
696
|
-
async function requestReview() {
|
|
697
|
-
console.log("[@ait-co/devtools] requestReview called");
|
|
698
|
-
}
|
|
699
|
-
requestReview.isSupported = () => true;
|
|
700
|
-
function getPlatformOS() {
|
|
701
|
-
return aitState.state.platform;
|
|
702
|
-
}
|
|
703
|
-
function getOperationalEnvironment() {
|
|
704
|
-
return aitState.state.environment;
|
|
705
|
-
}
|
|
706
|
-
function getTossAppVersion() {
|
|
707
|
-
return aitState.state.appVersion;
|
|
708
|
-
}
|
|
709
|
-
function isMinVersionSupported(minVersions) {
|
|
710
|
-
const required = aitState.state.platform === "ios" ? minVersions.ios : minVersions.android;
|
|
711
|
-
if (required === "always") return true;
|
|
712
|
-
if (required === "never") return false;
|
|
713
|
-
const current = aitState.state.appVersion.split(".").map(Number);
|
|
714
|
-
const min = required.split(".").map(Number);
|
|
715
|
-
for (let i = 0; i < 3; i++) {
|
|
716
|
-
if ((current[i] ?? 0) > (min[i] ?? 0)) return true;
|
|
717
|
-
if ((current[i] ?? 0) < (min[i] ?? 0)) return false;
|
|
718
|
-
}
|
|
719
|
-
return true;
|
|
720
|
-
}
|
|
721
|
-
function getSchemeUri() {
|
|
722
|
-
return aitState.state.schemeUri || window.location.pathname;
|
|
723
|
-
}
|
|
724
|
-
function getLocale() {
|
|
725
|
-
return aitState.state.locale;
|
|
726
|
-
}
|
|
727
|
-
function getDeviceId() {
|
|
728
|
-
return aitState.state.deviceId;
|
|
729
|
-
}
|
|
730
|
-
function getGroupId() {
|
|
731
|
-
return aitState.state.groupId;
|
|
732
|
-
}
|
|
733
|
-
async function getNetworkStatus() {
|
|
734
|
-
const modeResult = getNetworkStatusByMode();
|
|
735
|
-
if (modeResult) return modeResult;
|
|
736
|
-
return aitState.state.networkStatus;
|
|
737
|
-
}
|
|
738
|
-
async function getServerTime() {
|
|
739
|
-
return Date.now();
|
|
740
|
-
}
|
|
741
|
-
getServerTime.isSupported = () => true;
|
|
742
|
-
const graniteEvent = { addEventListener(event, { onEvent, onError }) {
|
|
743
|
-
const handler = () => {
|
|
744
|
-
try {
|
|
745
|
-
onEvent();
|
|
746
|
-
} catch (e) {
|
|
747
|
-
onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
748
|
-
}
|
|
749
|
-
};
|
|
750
|
-
window.addEventListener(`__ait:${event}`, handler);
|
|
751
|
-
return () => window.removeEventListener(`__ait:${event}`, handler);
|
|
752
|
-
} };
|
|
753
|
-
const appsInTossEvent = { addEventListener(_event, _handlers) {
|
|
754
|
-
return () => {};
|
|
755
|
-
} };
|
|
756
|
-
const tdsEvent = { addEventListener(event, { onEvent }) {
|
|
757
|
-
const handler = (e) => {
|
|
758
|
-
const detail = e.detail;
|
|
759
|
-
onEvent(detail);
|
|
760
|
-
};
|
|
761
|
-
window.addEventListener(`__ait:${event}`, handler);
|
|
762
|
-
return () => window.removeEventListener(`__ait:${event}`, handler);
|
|
763
|
-
} };
|
|
764
|
-
function onVisibilityChangedByTransparentServiceWeb(eventParams) {
|
|
765
|
-
const handler = () => eventParams.onEvent(!document.hidden);
|
|
766
|
-
document.addEventListener("visibilitychange", handler);
|
|
767
|
-
return () => document.removeEventListener("visibilitychange", handler);
|
|
768
|
-
}
|
|
769
|
-
const env = { getDeploymentId: () => aitState.state.deploymentId };
|
|
770
|
-
function getAppsInTossGlobals() {
|
|
807
|
+
async function getGameCenterGameProfile() {
|
|
808
|
+
const profile = aitState.state.game.profile;
|
|
809
|
+
if (!profile) return { statusCode: "PROFILE_NOT_FOUND" };
|
|
771
810
|
return {
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
brandPrimaryColor: aitState.state.brand.primaryColor
|
|
811
|
+
statusCode: "SUCCESS",
|
|
812
|
+
nickname: profile.nickname,
|
|
813
|
+
profileImageUri: profile.profileImageUri
|
|
776
814
|
};
|
|
777
815
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
816
|
+
async function openGameCenterLeaderboard() {
|
|
817
|
+
console.log("[@ait-co/devtools] openGameCenterLeaderboard (no-op in browser)");
|
|
818
|
+
}
|
|
819
|
+
function contactsViral(params) {
|
|
820
|
+
setTimeout(() => {
|
|
821
|
+
params.onEvent({
|
|
822
|
+
type: "close",
|
|
823
|
+
data: {
|
|
824
|
+
closeReason: "noReward",
|
|
825
|
+
sentRewardsCount: 0
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
}, 500);
|
|
829
|
+
return () => {};
|
|
787
830
|
}
|
|
788
831
|
//#endregion
|
|
789
832
|
//#region src/mock/iap/index.ts
|
|
@@ -900,175 +943,133 @@ async function checkoutPayment(options) {
|
|
|
900
943
|
};
|
|
901
944
|
}
|
|
902
945
|
//#endregion
|
|
903
|
-
//#region src/mock/
|
|
946
|
+
//#region src/mock/navigation/index.ts
|
|
904
947
|
/**
|
|
905
|
-
*
|
|
948
|
+
* 화면/네비게이션/이벤트 mock
|
|
906
949
|
*/
|
|
907
|
-
function
|
|
908
|
-
|
|
909
|
-
|
|
950
|
+
async function closeView() {
|
|
951
|
+
console.log("[@ait-co/devtools] closeView called");
|
|
952
|
+
window.history.back();
|
|
910
953
|
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
}, 200);
|
|
920
|
-
return () => {};
|
|
921
|
-
}),
|
|
922
|
-
showAppsInTossAdMob: withIsSupported((args) => {
|
|
923
|
-
if (!aitState.state.ads.isLoaded) {
|
|
924
|
-
args.onError(/* @__PURE__ */ new Error("Ad not loaded"));
|
|
925
|
-
return () => {};
|
|
926
|
-
}
|
|
927
|
-
setTimeout(() => args.onEvent({ type: "requested" }), 50);
|
|
928
|
-
setTimeout(() => args.onEvent({ type: "show" }), 100);
|
|
929
|
-
setTimeout(() => args.onEvent({ type: "impression" }), 150);
|
|
930
|
-
setTimeout(() => {
|
|
931
|
-
args.onEvent({
|
|
932
|
-
type: "userEarnedReward",
|
|
933
|
-
data: {
|
|
934
|
-
unitType: "coins",
|
|
935
|
-
unitAmount: 10
|
|
936
|
-
}
|
|
937
|
-
});
|
|
938
|
-
}, 1e3);
|
|
939
|
-
setTimeout(() => {
|
|
940
|
-
args.onEvent({ type: "dismissed" });
|
|
941
|
-
aitState.patch("ads", { isLoaded: false });
|
|
942
|
-
}, 1500);
|
|
943
|
-
return () => {};
|
|
944
|
-
}),
|
|
945
|
-
isAppsInTossAdMobLoaded: withIsSupported(async (_options) => aitState.state.ads.isLoaded)
|
|
946
|
-
});
|
|
947
|
-
const TossAds = createMockProxy("TossAds", {
|
|
948
|
-
initialize: withIsSupported((_options) => {
|
|
949
|
-
console.log("[@ait-co/devtools] TossAds.initialize (mock)");
|
|
950
|
-
}),
|
|
951
|
-
attach: withIsSupported((_adGroupId, target, _options) => {
|
|
952
|
-
const el = typeof target === "string" ? document.querySelector(target) : target;
|
|
953
|
-
if (el) {
|
|
954
|
-
const placeholder = document.createElement("div");
|
|
955
|
-
placeholder.style.cssText = "background:#f0f0f0;border:1px dashed #999;padding:16px;text-align:center;color:#666;font-size:14px;";
|
|
956
|
-
placeholder.textContent = "[@ait-co/devtools] TossAds Placeholder";
|
|
957
|
-
el.appendChild(placeholder);
|
|
958
|
-
}
|
|
959
|
-
}),
|
|
960
|
-
attachBanner: withIsSupported((_adGroupId, target, _options) => {
|
|
961
|
-
const el = typeof target === "string" ? document.querySelector(target) : target;
|
|
962
|
-
if (el) {
|
|
963
|
-
const placeholder = document.createElement("div");
|
|
964
|
-
placeholder.style.cssText = "background:#f0f0f0;border:1px dashed #999;padding:12px;text-align:center;color:#666;font-size:12px;";
|
|
965
|
-
placeholder.textContent = "[@ait-co/devtools] Banner Ad Placeholder";
|
|
966
|
-
el.appendChild(placeholder);
|
|
967
|
-
}
|
|
968
|
-
return { destroy: () => {} };
|
|
969
|
-
}),
|
|
970
|
-
destroy: withIsSupported((_slotId) => {}),
|
|
971
|
-
destroyAll: withIsSupported(() => {})
|
|
972
|
-
});
|
|
973
|
-
const loadFullScreenAd = withIsSupported((args) => {
|
|
974
|
-
setTimeout(() => {
|
|
975
|
-
aitState.patch("ads", { isLoaded: true });
|
|
976
|
-
args.onEvent({
|
|
977
|
-
type: "loaded",
|
|
978
|
-
data: { adGroupId: args.options?.adGroupId }
|
|
979
|
-
});
|
|
980
|
-
}, 200);
|
|
981
|
-
return () => {};
|
|
982
|
-
});
|
|
983
|
-
const showFullScreenAd = withIsSupported((args) => {
|
|
984
|
-
if (!aitState.state.ads.isLoaded) {
|
|
985
|
-
args.onError(/* @__PURE__ */ new Error("Ad not loaded"));
|
|
986
|
-
return () => {};
|
|
954
|
+
async function openURL(url) {
|
|
955
|
+
console.log("[@ait-co/devtools] openURL:", url);
|
|
956
|
+
window.open(url, "_blank");
|
|
957
|
+
}
|
|
958
|
+
async function share(message) {
|
|
959
|
+
if (navigator.share) {
|
|
960
|
+
await navigator.share({ text: message.message });
|
|
961
|
+
return;
|
|
987
962
|
}
|
|
988
|
-
|
|
989
|
-
setTimeout(() => args.onEvent({ type: "dismissed" }), 1500);
|
|
990
|
-
return () => {};
|
|
991
|
-
});
|
|
992
|
-
//#endregion
|
|
993
|
-
//#region src/mock/game/index.ts
|
|
994
|
-
/**
|
|
995
|
-
* 게임/프로모션 mock
|
|
996
|
-
*/
|
|
997
|
-
async function grantPromotionReward(params) {
|
|
998
|
-
console.log("[@ait-co/devtools] grantPromotionReward:", params.params);
|
|
999
|
-
return { key: `mock-reward-${Date.now()}` };
|
|
963
|
+
console.log("[@ait-co/devtools] share:", message.message);
|
|
1000
964
|
}
|
|
1001
|
-
async function
|
|
1002
|
-
|
|
1003
|
-
return { key: `mock-reward-${Date.now()}` };
|
|
965
|
+
async function getTossShareLink(path, _ogImageUrl) {
|
|
966
|
+
return `https://toss.im/share/mock${path}`;
|
|
1004
967
|
}
|
|
1005
|
-
async function
|
|
1006
|
-
|
|
1007
|
-
score: params.score,
|
|
1008
|
-
timestamp: Date.now()
|
|
1009
|
-
}] });
|
|
1010
|
-
return { statusCode: "SUCCESS" };
|
|
968
|
+
async function setIosSwipeGestureEnabled(_options) {
|
|
969
|
+
console.log("[@ait-co/devtools] setIosSwipeGestureEnabled:", _options.isEnabled);
|
|
1011
970
|
}
|
|
1012
|
-
async function
|
|
1013
|
-
|
|
1014
|
-
if (!profile) return { statusCode: "PROFILE_NOT_FOUND" };
|
|
1015
|
-
return {
|
|
1016
|
-
statusCode: "SUCCESS",
|
|
1017
|
-
nickname: profile.nickname,
|
|
1018
|
-
profileImageUri: profile.profileImageUri
|
|
1019
|
-
};
|
|
971
|
+
async function setDeviceOrientation(_options) {
|
|
972
|
+
console.log("[@ait-co/devtools] setDeviceOrientation:", _options.type);
|
|
1020
973
|
}
|
|
1021
|
-
async function
|
|
1022
|
-
console.log("[@ait-co/devtools]
|
|
974
|
+
async function setScreenAwakeMode(options) {
|
|
975
|
+
console.log("[@ait-co/devtools] setScreenAwakeMode:", options.enabled);
|
|
976
|
+
return { enabled: options.enabled };
|
|
1023
977
|
}
|
|
1024
|
-
function
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
978
|
+
async function setSecureScreen(options) {
|
|
979
|
+
console.log("[@ait-co/devtools] setSecureScreen:", options.enabled);
|
|
980
|
+
return { enabled: options.enabled };
|
|
981
|
+
}
|
|
982
|
+
async function requestReview() {
|
|
983
|
+
console.log("[@ait-co/devtools] requestReview called");
|
|
984
|
+
}
|
|
985
|
+
requestReview.isSupported = () => true;
|
|
986
|
+
function getPlatformOS() {
|
|
987
|
+
return aitState.state.platform;
|
|
988
|
+
}
|
|
989
|
+
function getOperationalEnvironment() {
|
|
990
|
+
return aitState.state.environment;
|
|
991
|
+
}
|
|
992
|
+
function getTossAppVersion() {
|
|
993
|
+
return aitState.state.appVersion;
|
|
994
|
+
}
|
|
995
|
+
function isMinVersionSupported(minVersions) {
|
|
996
|
+
const required = aitState.state.platform === "ios" ? minVersions.ios : minVersions.android;
|
|
997
|
+
if (required === "always") return true;
|
|
998
|
+
if (required === "never") return false;
|
|
999
|
+
const current = aitState.state.appVersion.split(".").map(Number);
|
|
1000
|
+
const min = required.split(".").map(Number);
|
|
1001
|
+
for (let i = 0; i < 3; i++) {
|
|
1002
|
+
if ((current[i] ?? 0) > (min[i] ?? 0)) return true;
|
|
1003
|
+
if ((current[i] ?? 0) < (min[i] ?? 0)) return false;
|
|
1004
|
+
}
|
|
1005
|
+
return true;
|
|
1006
|
+
}
|
|
1007
|
+
function getSchemeUri() {
|
|
1008
|
+
return aitState.state.schemeUri || window.location.pathname;
|
|
1009
|
+
}
|
|
1010
|
+
function getLocale() {
|
|
1011
|
+
return aitState.state.locale;
|
|
1012
|
+
}
|
|
1013
|
+
function getDeviceId() {
|
|
1014
|
+
return aitState.state.deviceId;
|
|
1015
|
+
}
|
|
1016
|
+
function getGroupId() {
|
|
1017
|
+
return aitState.state.groupId;
|
|
1018
|
+
}
|
|
1019
|
+
async function getNetworkStatus() {
|
|
1020
|
+
const modeResult = getNetworkStatusByMode();
|
|
1021
|
+
if (modeResult) return modeResult;
|
|
1022
|
+
return aitState.state.networkStatus;
|
|
1023
|
+
}
|
|
1024
|
+
async function getServerTime() {
|
|
1025
|
+
return Date.now();
|
|
1026
|
+
}
|
|
1027
|
+
getServerTime.isSupported = () => true;
|
|
1028
|
+
const graniteEvent = { addEventListener(event, { onEvent, onError }) {
|
|
1029
|
+
const handler = () => {
|
|
1030
|
+
try {
|
|
1031
|
+
onEvent();
|
|
1032
|
+
} catch (e) {
|
|
1033
|
+
onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
window.addEventListener(`__ait:${event}`, handler);
|
|
1037
|
+
return () => window.removeEventListener(`__ait:${event}`, handler);
|
|
1038
|
+
} };
|
|
1039
|
+
const appsInTossEvent = { addEventListener(_event, _handlers) {
|
|
1034
1040
|
return () => {};
|
|
1041
|
+
} };
|
|
1042
|
+
const tdsEvent = { addEventListener(event, { onEvent }) {
|
|
1043
|
+
const handler = (e) => {
|
|
1044
|
+
const detail = e.detail;
|
|
1045
|
+
onEvent(detail);
|
|
1046
|
+
};
|
|
1047
|
+
window.addEventListener(`__ait:${event}`, handler);
|
|
1048
|
+
return () => window.removeEventListener(`__ait:${event}`, handler);
|
|
1049
|
+
} };
|
|
1050
|
+
function onVisibilityChangedByTransparentServiceWeb(eventParams) {
|
|
1051
|
+
const handler = () => eventParams.onEvent(!document.hidden);
|
|
1052
|
+
document.addEventListener("visibilitychange", handler);
|
|
1053
|
+
return () => document.removeEventListener("visibilitychange", handler);
|
|
1035
1054
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
impression: (params) => {
|
|
1050
|
-
aitState.logAnalytics({
|
|
1051
|
-
type: "impression",
|
|
1052
|
-
params: params ?? {}
|
|
1053
|
-
});
|
|
1054
|
-
return Promise.resolve();
|
|
1055
|
-
},
|
|
1056
|
-
click: (params) => {
|
|
1057
|
-
aitState.logAnalytics({
|
|
1058
|
-
type: "click",
|
|
1059
|
-
params: params ?? {}
|
|
1060
|
-
});
|
|
1061
|
-
return Promise.resolve();
|
|
1055
|
+
const env = { getDeploymentId: () => aitState.state.deploymentId };
|
|
1056
|
+
function getAppsInTossGlobals() {
|
|
1057
|
+
return {
|
|
1058
|
+
deploymentId: aitState.state.deploymentId,
|
|
1059
|
+
brandDisplayName: aitState.state.brand.displayName,
|
|
1060
|
+
brandIcon: aitState.state.brand.icon,
|
|
1061
|
+
brandPrimaryColor: aitState.state.brand.primaryColor
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
const SafeAreaInsets = {
|
|
1065
|
+
get: () => ({ ...aitState.state.safeAreaInsets }),
|
|
1066
|
+
subscribe: ({ onEvent }) => {
|
|
1067
|
+
return aitState.subscribe(() => onEvent({ ...aitState.state.safeAreaInsets }));
|
|
1062
1068
|
}
|
|
1063
1069
|
};
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
params: {
|
|
1068
|
-
log_name: params.log_name,
|
|
1069
|
-
...params.params
|
|
1070
|
-
}
|
|
1071
|
-
});
|
|
1070
|
+
/** @deprecated */
|
|
1071
|
+
function getSafeAreaInsets() {
|
|
1072
|
+
return aitState.state.safeAreaInsets.top;
|
|
1072
1073
|
}
|
|
1073
1074
|
//#endregion
|
|
1074
1075
|
//#region src/mock/partner/index.ts
|