@apps-in-toss/devtools 3.1.1 → 3.2.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/CHANGELOG.md +6 -0
- package/dist/mock/2x.d.ts +0 -10
- package/dist/mock/2x.js +5 -4
- package/dist/mock/3x.d.ts +1 -18
- package/dist/mock/3x.js +95 -73
- package/dist/mock/index.d.ts +1 -18
- package/dist/mock/index.js +95 -73
- package/dist/panel/index.js +18 -5
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
package/dist/mock/2x.d.ts
CHANGED
|
@@ -479,16 +479,6 @@ declare const openPDFViewer: ((params: OpenPDFViewerParams) => Promise<OpenPDFVi
|
|
|
479
479
|
};
|
|
480
480
|
//#endregion
|
|
481
481
|
//#region src/mock/device/storage.d.ts
|
|
482
|
-
/**
|
|
483
|
-
* Storage mock
|
|
484
|
-
* localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리
|
|
485
|
-
*
|
|
486
|
-
* 실기기(2.x×iOS) capture는 `setItem`/`removeItem`/`clearItems` 세 메서드가
|
|
487
|
-
* `undefined`가 아니라 `null`로 resolve됨을 보였다(devtools#770). 원본 SDK 타입
|
|
488
|
-
* 선언은 여전히 `Promise<void>`이므로 시그니처는 그대로 두고, 런타임 반환값만
|
|
489
|
-
* `null`로 캐스트해 실측과 동치시킨다 — Analytics·setClipboardText와 같은 처리(#775).
|
|
490
|
-
* `getItem`은 이미 `string | null`이라 실측과 일치하므로 손대지 않는다.
|
|
491
|
-
*/
|
|
492
482
|
declare const Storage: {
|
|
493
483
|
getItem: (key: string) => Promise<string | null>;
|
|
494
484
|
setItem: (key: string, value: string) => Promise<void>;
|
package/dist/mock/2x.js
CHANGED
|
@@ -1578,20 +1578,21 @@ const openPDFViewer = Object.assign(_openPDFViewerImpl, { isSupported: () => tru
|
|
|
1578
1578
|
* `null`로 캐스트해 실측과 동치시킨다 — Analytics·setClipboardText와 같은 처리(#775).
|
|
1579
1579
|
* `getItem`은 이미 `string | null`이라 실측과 일치하므로 손대지 않는다.
|
|
1580
1580
|
*/
|
|
1581
|
+
const STORAGE_PREFIX = "__ait_storage:";
|
|
1581
1582
|
const Storage = createMockProxy("Storage", {
|
|
1582
1583
|
getItem: async (key) => {
|
|
1583
|
-
return localStorage.getItem(
|
|
1584
|
+
return localStorage.getItem(`${STORAGE_PREFIX}${key}`);
|
|
1584
1585
|
},
|
|
1585
1586
|
setItem: async (key, value) => {
|
|
1586
|
-
localStorage.setItem(
|
|
1587
|
+
localStorage.setItem(`${STORAGE_PREFIX}${key}`, value);
|
|
1587
1588
|
return null;
|
|
1588
1589
|
},
|
|
1589
1590
|
removeItem: async (key) => {
|
|
1590
|
-
localStorage.removeItem(
|
|
1591
|
+
localStorage.removeItem(`${STORAGE_PREFIX}${key}`);
|
|
1591
1592
|
return null;
|
|
1592
1593
|
},
|
|
1593
1594
|
clearItems: async () => {
|
|
1594
|
-
const keys = Object.keys(localStorage).filter((k) => k.startsWith(
|
|
1595
|
+
const keys = Object.keys(localStorage).filter((k) => k.startsWith(STORAGE_PREFIX));
|
|
1595
1596
|
for (const k of keys) localStorage.removeItem(k);
|
|
1596
1597
|
return null;
|
|
1597
1598
|
}
|
package/dist/mock/3x.d.ts
CHANGED
|
@@ -193,6 +193,7 @@ declare const Review: typeof SDK.Review;
|
|
|
193
193
|
declare const SafeArea: typeof SDK.SafeArea;
|
|
194
194
|
declare const Screen: typeof SDK.Screen;
|
|
195
195
|
declare const Share: typeof SDK.Share;
|
|
196
|
+
declare const Storage: typeof SDK.Storage;
|
|
196
197
|
declare const TossAuth: typeof SDK.TossAuth;
|
|
197
198
|
declare const TossPay: typeof SDK.TossPay;
|
|
198
199
|
declare const User: typeof SDK.User;
|
|
@@ -556,24 +557,6 @@ declare const startUpdateLocation: ((eventParams: StartUpdateLocationEventParams
|
|
|
556
557
|
openPermissionDialog: () => Promise<"allowed" | "denied">;
|
|
557
558
|
};
|
|
558
559
|
//#endregion
|
|
559
|
-
//#region src/mock/device/storage.d.ts
|
|
560
|
-
/**
|
|
561
|
-
* Storage mock
|
|
562
|
-
* localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리
|
|
563
|
-
*
|
|
564
|
-
* 실기기(2.x×iOS) capture는 `setItem`/`removeItem`/`clearItems` 세 메서드가
|
|
565
|
-
* `undefined`가 아니라 `null`로 resolve됨을 보였다(devtools#770). 원본 SDK 타입
|
|
566
|
-
* 선언은 여전히 `Promise<void>`이므로 시그니처는 그대로 두고, 런타임 반환값만
|
|
567
|
-
* `null`로 캐스트해 실측과 동치시킨다 — Analytics·setClipboardText와 같은 처리(#775).
|
|
568
|
-
* `getItem`은 이미 `string | null`이라 실측과 일치하므로 손대지 않는다.
|
|
569
|
-
*/
|
|
570
|
-
declare const Storage: {
|
|
571
|
-
getItem: (key: string) => Promise<string | null>;
|
|
572
|
-
setItem: (key: string, value: string) => Promise<void>;
|
|
573
|
-
removeItem: (key: string) => Promise<void>;
|
|
574
|
-
clearItems: () => Promise<void>;
|
|
575
|
-
};
|
|
576
|
-
//#endregion
|
|
577
560
|
//#region src/mock/iap/index.d.ts
|
|
578
561
|
declare function checkoutPayment(options: {
|
|
579
562
|
params: {
|
package/dist/mock/3x.js
CHANGED
|
@@ -328,6 +328,86 @@ if (!globalRef[SINGLETON_KEY]) globalRef[SINGLETON_KEY] = new AitStateManager();
|
|
|
328
328
|
const aitState = globalRef[SINGLETON_KEY];
|
|
329
329
|
if (typeof window !== "undefined") window.__ait = aitState;
|
|
330
330
|
//#endregion
|
|
331
|
+
//#region src/mock/proxy.ts
|
|
332
|
+
/**
|
|
333
|
+
* 미구현 API용 Proxy 트립와이어.
|
|
334
|
+
*
|
|
335
|
+
* 미구현 프로퍼티에 접근하면 throw한다. 이는 "devtools에서는 멀쩡히 돌지만
|
|
336
|
+
* 실 SDK에선 실제로 동작하는" 시나리오를 차단하기 위한 의도적 선택이다.
|
|
337
|
+
* mock이 미구현인 API는 실 SDK에서는 존재할 수 있고, 사용자가 이를 인지하지
|
|
338
|
+
* 못한 채 개발을 이어가면 배포 시점에 놀라게 된다. 에러 메시지에 이슈 URL을
|
|
339
|
+
* 포함해 사용자가 mock 누락을 제보할 수 있게 한다.
|
|
340
|
+
*
|
|
341
|
+
* ## KNOWN_UNIMPLEMENTED 정책
|
|
342
|
+
* SDK에 존재하는 것으로 알려져 있으나 현재 mock이 없는 API 이름만 이 집합에 둔다.
|
|
343
|
+
* 이 경우에만 throw 대신 🔴 inert no-op을 반환하고 sdkCallLog에 기록한다.
|
|
344
|
+
* 완전히 미지의 이름은 여전히 throw — "잘 되는 척" 방지.
|
|
345
|
+
*/
|
|
346
|
+
const ISSUES_URL = "https://github.com/apps-in-toss-community/devtools/issues";
|
|
347
|
+
/**
|
|
348
|
+
* SDK에 존재하나 mock이 아직 없는 것으로 확인된 이름 목록.
|
|
349
|
+
* 새 API가 SDK에 추가되면 여기에 추가하고 별도 PR에서 mock 구현으로 이동한다.
|
|
350
|
+
* 확인되지 않은 이름은 절대 여기에 추가하지 않는다 — throw가 더 안전하다.
|
|
351
|
+
*/
|
|
352
|
+
const KNOWN_UNIMPLEMENTED = /* @__PURE__ */ new Set([]);
|
|
353
|
+
function createMockProxy(moduleName, implementations) {
|
|
354
|
+
return new Proxy(implementations, { get(target, prop) {
|
|
355
|
+
if (typeof prop === "symbol") return void 0;
|
|
356
|
+
if (prop in target) return target[prop];
|
|
357
|
+
const name = String(prop);
|
|
358
|
+
if (KNOWN_UNIMPLEMENTED.has(name)) return (...args) => {
|
|
359
|
+
console.warn(`[@apps-in-toss/devtools] ${moduleName}.${name} is known-unimplemented (🔴 inert). Returning undefined. Please file or upvote an issue: ${ISSUES_URL}`);
|
|
360
|
+
aitState.logSdkCall({
|
|
361
|
+
method: `${moduleName}.${name}`,
|
|
362
|
+
args,
|
|
363
|
+
timestamp: Date.now(),
|
|
364
|
+
status: "resolved",
|
|
365
|
+
result: void 0,
|
|
366
|
+
fidelity: "inert"
|
|
367
|
+
});
|
|
368
|
+
};
|
|
369
|
+
throw new Error(`[@apps-in-toss/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}`);
|
|
370
|
+
} });
|
|
371
|
+
}
|
|
372
|
+
//#endregion
|
|
373
|
+
//#region src/mock/device/storage.ts
|
|
374
|
+
/**
|
|
375
|
+
* Storage mock
|
|
376
|
+
* localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리
|
|
377
|
+
*
|
|
378
|
+
* 실기기(2.x×iOS) capture는 `setItem`/`removeItem`/`clearItems` 세 메서드가
|
|
379
|
+
* `undefined`가 아니라 `null`로 resolve됨을 보였다(devtools#770). 원본 SDK 타입
|
|
380
|
+
* 선언은 여전히 `Promise<void>`이므로 시그니처는 그대로 두고, 런타임 반환값만
|
|
381
|
+
* `null`로 캐스트해 실측과 동치시킨다 — Analytics·setClipboardText와 같은 처리(#775).
|
|
382
|
+
* `getItem`은 이미 `string | null`이라 실측과 일치하므로 손대지 않는다.
|
|
383
|
+
*/
|
|
384
|
+
const STORAGE_PREFIX = "__ait_storage:";
|
|
385
|
+
async function getItems(keys) {
|
|
386
|
+
return Object.fromEntries(keys.map((key) => [key, localStorage.getItem(`${STORAGE_PREFIX}${key}`)]));
|
|
387
|
+
}
|
|
388
|
+
async function setItems(items) {
|
|
389
|
+
for (const [key, value] of Object.entries(items)) localStorage.setItem(`${STORAGE_PREFIX}${key}`, value);
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
const Storage$1 = createMockProxy("Storage", {
|
|
393
|
+
getItem: async (key) => {
|
|
394
|
+
return localStorage.getItem(`${STORAGE_PREFIX}${key}`);
|
|
395
|
+
},
|
|
396
|
+
setItem: async (key, value) => {
|
|
397
|
+
localStorage.setItem(`${STORAGE_PREFIX}${key}`, value);
|
|
398
|
+
return null;
|
|
399
|
+
},
|
|
400
|
+
removeItem: async (key) => {
|
|
401
|
+
localStorage.removeItem(`${STORAGE_PREFIX}${key}`);
|
|
402
|
+
return null;
|
|
403
|
+
},
|
|
404
|
+
clearItems: async () => {
|
|
405
|
+
const keys = Object.keys(localStorage).filter((k) => k.startsWith(STORAGE_PREFIX));
|
|
406
|
+
for (const k of keys) localStorage.removeItem(k);
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
//#endregion
|
|
331
411
|
//#region src/mock/native-error.ts
|
|
332
412
|
/**
|
|
333
413
|
* 실패-모드 다이얼 — 네이티브 에러 envelope 조립 (devtools#770).
|
|
@@ -499,48 +579,6 @@ function safeSerialize(value) {
|
|
|
499
579
|
}
|
|
500
580
|
}
|
|
501
581
|
//#endregion
|
|
502
|
-
//#region src/mock/proxy.ts
|
|
503
|
-
/**
|
|
504
|
-
* 미구현 API용 Proxy 트립와이어.
|
|
505
|
-
*
|
|
506
|
-
* 미구현 프로퍼티에 접근하면 throw한다. 이는 "devtools에서는 멀쩡히 돌지만
|
|
507
|
-
* 실 SDK에선 실제로 동작하는" 시나리오를 차단하기 위한 의도적 선택이다.
|
|
508
|
-
* mock이 미구현인 API는 실 SDK에서는 존재할 수 있고, 사용자가 이를 인지하지
|
|
509
|
-
* 못한 채 개발을 이어가면 배포 시점에 놀라게 된다. 에러 메시지에 이슈 URL을
|
|
510
|
-
* 포함해 사용자가 mock 누락을 제보할 수 있게 한다.
|
|
511
|
-
*
|
|
512
|
-
* ## KNOWN_UNIMPLEMENTED 정책
|
|
513
|
-
* SDK에 존재하는 것으로 알려져 있으나 현재 mock이 없는 API 이름만 이 집합에 둔다.
|
|
514
|
-
* 이 경우에만 throw 대신 🔴 inert no-op을 반환하고 sdkCallLog에 기록한다.
|
|
515
|
-
* 완전히 미지의 이름은 여전히 throw — "잘 되는 척" 방지.
|
|
516
|
-
*/
|
|
517
|
-
const ISSUES_URL = "https://github.com/apps-in-toss-community/devtools/issues";
|
|
518
|
-
/**
|
|
519
|
-
* SDK에 존재하나 mock이 아직 없는 것으로 확인된 이름 목록.
|
|
520
|
-
* 새 API가 SDK에 추가되면 여기에 추가하고 별도 PR에서 mock 구현으로 이동한다.
|
|
521
|
-
* 확인되지 않은 이름은 절대 여기에 추가하지 않는다 — throw가 더 안전하다.
|
|
522
|
-
*/
|
|
523
|
-
const KNOWN_UNIMPLEMENTED = /* @__PURE__ */ new Set([]);
|
|
524
|
-
function createMockProxy(moduleName, implementations) {
|
|
525
|
-
return new Proxy(implementations, { get(target, prop) {
|
|
526
|
-
if (typeof prop === "symbol") return void 0;
|
|
527
|
-
if (prop in target) return target[prop];
|
|
528
|
-
const name = String(prop);
|
|
529
|
-
if (KNOWN_UNIMPLEMENTED.has(name)) return (...args) => {
|
|
530
|
-
console.warn(`[@apps-in-toss/devtools] ${moduleName}.${name} is known-unimplemented (🔴 inert). Returning undefined. Please file or upvote an issue: ${ISSUES_URL}`);
|
|
531
|
-
aitState.logSdkCall({
|
|
532
|
-
method: `${moduleName}.${name}`,
|
|
533
|
-
args,
|
|
534
|
-
timestamp: Date.now(),
|
|
535
|
-
status: "resolved",
|
|
536
|
-
result: void 0,
|
|
537
|
-
fidelity: "inert"
|
|
538
|
-
});
|
|
539
|
-
};
|
|
540
|
-
throw new Error(`[@apps-in-toss/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}`);
|
|
541
|
-
} });
|
|
542
|
-
}
|
|
543
|
-
//#endregion
|
|
544
582
|
//#region src/mock/throttle.ts
|
|
545
583
|
/**
|
|
546
584
|
* THROTTLED 시뮬레이션 (devtools#834 — #770 §3 분리).
|
|
@@ -1567,36 +1605,6 @@ const _openPDFViewerImpl = async (_params) => {
|
|
|
1567
1605
|
};
|
|
1568
1606
|
const openPDFViewer$1 = Object.assign(_openPDFViewerImpl, { isSupported: () => true });
|
|
1569
1607
|
//#endregion
|
|
1570
|
-
//#region src/mock/device/storage.ts
|
|
1571
|
-
/**
|
|
1572
|
-
* Storage mock
|
|
1573
|
-
* localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리
|
|
1574
|
-
*
|
|
1575
|
-
* 실기기(2.x×iOS) capture는 `setItem`/`removeItem`/`clearItems` 세 메서드가
|
|
1576
|
-
* `undefined`가 아니라 `null`로 resolve됨을 보였다(devtools#770). 원본 SDK 타입
|
|
1577
|
-
* 선언은 여전히 `Promise<void>`이므로 시그니처는 그대로 두고, 런타임 반환값만
|
|
1578
|
-
* `null`로 캐스트해 실측과 동치시킨다 — Analytics·setClipboardText와 같은 처리(#775).
|
|
1579
|
-
* `getItem`은 이미 `string | null`이라 실측과 일치하므로 손대지 않는다.
|
|
1580
|
-
*/
|
|
1581
|
-
const Storage = createMockProxy("Storage", {
|
|
1582
|
-
getItem: async (key) => {
|
|
1583
|
-
return localStorage.getItem(`__ait_storage:${key}`);
|
|
1584
|
-
},
|
|
1585
|
-
setItem: async (key, value) => {
|
|
1586
|
-
localStorage.setItem(`__ait_storage:${key}`, value);
|
|
1587
|
-
return null;
|
|
1588
|
-
},
|
|
1589
|
-
removeItem: async (key) => {
|
|
1590
|
-
localStorage.removeItem(`__ait_storage:${key}`);
|
|
1591
|
-
return null;
|
|
1592
|
-
},
|
|
1593
|
-
clearItems: async () => {
|
|
1594
|
-
const keys = Object.keys(localStorage).filter((k) => k.startsWith("__ait_storage:"));
|
|
1595
|
-
for (const k of keys) localStorage.removeItem(k);
|
|
1596
|
-
return null;
|
|
1597
|
-
}
|
|
1598
|
-
});
|
|
1599
|
-
//#endregion
|
|
1600
1608
|
//#region src/mock/iap/index.ts
|
|
1601
1609
|
let orderCounter = 0;
|
|
1602
1610
|
function generateOrderId() {
|
|
@@ -2394,6 +2402,10 @@ const V = {
|
|
|
2394
2402
|
android: "5.233.0",
|
|
2395
2403
|
ios: "5.233.0"
|
|
2396
2404
|
},
|
|
2405
|
+
storageBatch: {
|
|
2406
|
+
android: "5.270.0",
|
|
2407
|
+
ios: "5.270.0"
|
|
2408
|
+
},
|
|
2397
2409
|
tossLogin: {
|
|
2398
2410
|
android: "5.237.0",
|
|
2399
2411
|
ios: "5.237.0"
|
|
@@ -2533,10 +2545,15 @@ const File = {
|
|
|
2533
2545
|
saveBase64: saveBase64Data,
|
|
2534
2546
|
openPDFViewer
|
|
2535
2547
|
};
|
|
2548
|
+
const subscribeInfoOverlayHidden = ({ onEvent }) => {
|
|
2549
|
+
const timeoutId = window.setTimeout(onEvent, 0);
|
|
2550
|
+
return () => window.clearTimeout(timeoutId);
|
|
2551
|
+
};
|
|
2536
2552
|
const Game = {
|
|
2537
2553
|
openLeaderboard: openGameCenterLeaderboard,
|
|
2538
2554
|
setLeaderboardScore: submitGameCenterLeaderBoardScore,
|
|
2539
|
-
getUserProfile: getGameCenterGameProfile
|
|
2555
|
+
getUserProfile: getGameCenterGameProfile,
|
|
2556
|
+
subscribeInfoOverlayHidden
|
|
2540
2557
|
};
|
|
2541
2558
|
const Migration = { getOriginStorage: async () => {
|
|
2542
2559
|
const createEmptyDump = () => ({
|
|
@@ -2572,6 +2589,11 @@ const Share = {
|
|
|
2572
2589
|
createLink: ({ path, ogImageUrl }) => getTossShareLink(path, ogImageUrl),
|
|
2573
2590
|
sendMessage: share
|
|
2574
2591
|
};
|
|
2592
|
+
const Storage = {
|
|
2593
|
+
...Storage$1,
|
|
2594
|
+
getItems: supported(getItems, V.storageBatch),
|
|
2595
|
+
setItems: supported(setItems, V.storageBatch)
|
|
2596
|
+
};
|
|
2575
2597
|
const TossAuth = {
|
|
2576
2598
|
login: appLogin,
|
|
2577
2599
|
isIntegrated: getIsTossLoginIntegratedService,
|
package/dist/mock/index.d.ts
CHANGED
|
@@ -193,6 +193,7 @@ declare const Review: typeof SDK.Review;
|
|
|
193
193
|
declare const SafeArea: typeof SDK.SafeArea;
|
|
194
194
|
declare const Screen: typeof SDK.Screen;
|
|
195
195
|
declare const Share: typeof SDK.Share;
|
|
196
|
+
declare const Storage: typeof SDK.Storage;
|
|
196
197
|
declare const TossAuth: typeof SDK.TossAuth;
|
|
197
198
|
declare const TossPay: typeof SDK.TossPay;
|
|
198
199
|
declare const User: typeof SDK.User;
|
|
@@ -556,24 +557,6 @@ declare const startUpdateLocation: ((eventParams: StartUpdateLocationEventParams
|
|
|
556
557
|
openPermissionDialog: () => Promise<"allowed" | "denied">;
|
|
557
558
|
};
|
|
558
559
|
//#endregion
|
|
559
|
-
//#region src/mock/device/storage.d.ts
|
|
560
|
-
/**
|
|
561
|
-
* Storage mock
|
|
562
|
-
* localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리
|
|
563
|
-
*
|
|
564
|
-
* 실기기(2.x×iOS) capture는 `setItem`/`removeItem`/`clearItems` 세 메서드가
|
|
565
|
-
* `undefined`가 아니라 `null`로 resolve됨을 보였다(devtools#770). 원본 SDK 타입
|
|
566
|
-
* 선언은 여전히 `Promise<void>`이므로 시그니처는 그대로 두고, 런타임 반환값만
|
|
567
|
-
* `null`로 캐스트해 실측과 동치시킨다 — Analytics·setClipboardText와 같은 처리(#775).
|
|
568
|
-
* `getItem`은 이미 `string | null`이라 실측과 일치하므로 손대지 않는다.
|
|
569
|
-
*/
|
|
570
|
-
declare const Storage: {
|
|
571
|
-
getItem: (key: string) => Promise<string | null>;
|
|
572
|
-
setItem: (key: string, value: string) => Promise<void>;
|
|
573
|
-
removeItem: (key: string) => Promise<void>;
|
|
574
|
-
clearItems: () => Promise<void>;
|
|
575
|
-
};
|
|
576
|
-
//#endregion
|
|
577
560
|
//#region src/mock/iap/index.d.ts
|
|
578
561
|
declare function checkoutPayment(options: {
|
|
579
562
|
params: {
|
package/dist/mock/index.js
CHANGED
|
@@ -328,6 +328,86 @@ if (!globalRef[SINGLETON_KEY]) globalRef[SINGLETON_KEY] = new AitStateManager();
|
|
|
328
328
|
const aitState = globalRef[SINGLETON_KEY];
|
|
329
329
|
if (typeof window !== "undefined") window.__ait = aitState;
|
|
330
330
|
//#endregion
|
|
331
|
+
//#region src/mock/proxy.ts
|
|
332
|
+
/**
|
|
333
|
+
* 미구현 API용 Proxy 트립와이어.
|
|
334
|
+
*
|
|
335
|
+
* 미구현 프로퍼티에 접근하면 throw한다. 이는 "devtools에서는 멀쩡히 돌지만
|
|
336
|
+
* 실 SDK에선 실제로 동작하는" 시나리오를 차단하기 위한 의도적 선택이다.
|
|
337
|
+
* mock이 미구현인 API는 실 SDK에서는 존재할 수 있고, 사용자가 이를 인지하지
|
|
338
|
+
* 못한 채 개발을 이어가면 배포 시점에 놀라게 된다. 에러 메시지에 이슈 URL을
|
|
339
|
+
* 포함해 사용자가 mock 누락을 제보할 수 있게 한다.
|
|
340
|
+
*
|
|
341
|
+
* ## KNOWN_UNIMPLEMENTED 정책
|
|
342
|
+
* SDK에 존재하는 것으로 알려져 있으나 현재 mock이 없는 API 이름만 이 집합에 둔다.
|
|
343
|
+
* 이 경우에만 throw 대신 🔴 inert no-op을 반환하고 sdkCallLog에 기록한다.
|
|
344
|
+
* 완전히 미지의 이름은 여전히 throw — "잘 되는 척" 방지.
|
|
345
|
+
*/
|
|
346
|
+
const ISSUES_URL = "https://github.com/apps-in-toss-community/devtools/issues";
|
|
347
|
+
/**
|
|
348
|
+
* SDK에 존재하나 mock이 아직 없는 것으로 확인된 이름 목록.
|
|
349
|
+
* 새 API가 SDK에 추가되면 여기에 추가하고 별도 PR에서 mock 구현으로 이동한다.
|
|
350
|
+
* 확인되지 않은 이름은 절대 여기에 추가하지 않는다 — throw가 더 안전하다.
|
|
351
|
+
*/
|
|
352
|
+
const KNOWN_UNIMPLEMENTED = /* @__PURE__ */ new Set([]);
|
|
353
|
+
function createMockProxy(moduleName, implementations) {
|
|
354
|
+
return new Proxy(implementations, { get(target, prop) {
|
|
355
|
+
if (typeof prop === "symbol") return void 0;
|
|
356
|
+
if (prop in target) return target[prop];
|
|
357
|
+
const name = String(prop);
|
|
358
|
+
if (KNOWN_UNIMPLEMENTED.has(name)) return (...args) => {
|
|
359
|
+
console.warn(`[@apps-in-toss/devtools] ${moduleName}.${name} is known-unimplemented (🔴 inert). Returning undefined. Please file or upvote an issue: ${ISSUES_URL}`);
|
|
360
|
+
aitState.logSdkCall({
|
|
361
|
+
method: `${moduleName}.${name}`,
|
|
362
|
+
args,
|
|
363
|
+
timestamp: Date.now(),
|
|
364
|
+
status: "resolved",
|
|
365
|
+
result: void 0,
|
|
366
|
+
fidelity: "inert"
|
|
367
|
+
});
|
|
368
|
+
};
|
|
369
|
+
throw new Error(`[@apps-in-toss/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}`);
|
|
370
|
+
} });
|
|
371
|
+
}
|
|
372
|
+
//#endregion
|
|
373
|
+
//#region src/mock/device/storage.ts
|
|
374
|
+
/**
|
|
375
|
+
* Storage mock
|
|
376
|
+
* localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리
|
|
377
|
+
*
|
|
378
|
+
* 실기기(2.x×iOS) capture는 `setItem`/`removeItem`/`clearItems` 세 메서드가
|
|
379
|
+
* `undefined`가 아니라 `null`로 resolve됨을 보였다(devtools#770). 원본 SDK 타입
|
|
380
|
+
* 선언은 여전히 `Promise<void>`이므로 시그니처는 그대로 두고, 런타임 반환값만
|
|
381
|
+
* `null`로 캐스트해 실측과 동치시킨다 — Analytics·setClipboardText와 같은 처리(#775).
|
|
382
|
+
* `getItem`은 이미 `string | null`이라 실측과 일치하므로 손대지 않는다.
|
|
383
|
+
*/
|
|
384
|
+
const STORAGE_PREFIX = "__ait_storage:";
|
|
385
|
+
async function getItems(keys) {
|
|
386
|
+
return Object.fromEntries(keys.map((key) => [key, localStorage.getItem(`${STORAGE_PREFIX}${key}`)]));
|
|
387
|
+
}
|
|
388
|
+
async function setItems(items) {
|
|
389
|
+
for (const [key, value] of Object.entries(items)) localStorage.setItem(`${STORAGE_PREFIX}${key}`, value);
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
const Storage$1 = createMockProxy("Storage", {
|
|
393
|
+
getItem: async (key) => {
|
|
394
|
+
return localStorage.getItem(`${STORAGE_PREFIX}${key}`);
|
|
395
|
+
},
|
|
396
|
+
setItem: async (key, value) => {
|
|
397
|
+
localStorage.setItem(`${STORAGE_PREFIX}${key}`, value);
|
|
398
|
+
return null;
|
|
399
|
+
},
|
|
400
|
+
removeItem: async (key) => {
|
|
401
|
+
localStorage.removeItem(`${STORAGE_PREFIX}${key}`);
|
|
402
|
+
return null;
|
|
403
|
+
},
|
|
404
|
+
clearItems: async () => {
|
|
405
|
+
const keys = Object.keys(localStorage).filter((k) => k.startsWith(STORAGE_PREFIX));
|
|
406
|
+
for (const k of keys) localStorage.removeItem(k);
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
//#endregion
|
|
331
411
|
//#region src/mock/native-error.ts
|
|
332
412
|
/**
|
|
333
413
|
* 실패-모드 다이얼 — 네이티브 에러 envelope 조립 (devtools#770).
|
|
@@ -499,48 +579,6 @@ function safeSerialize(value) {
|
|
|
499
579
|
}
|
|
500
580
|
}
|
|
501
581
|
//#endregion
|
|
502
|
-
//#region src/mock/proxy.ts
|
|
503
|
-
/**
|
|
504
|
-
* 미구현 API용 Proxy 트립와이어.
|
|
505
|
-
*
|
|
506
|
-
* 미구현 프로퍼티에 접근하면 throw한다. 이는 "devtools에서는 멀쩡히 돌지만
|
|
507
|
-
* 실 SDK에선 실제로 동작하는" 시나리오를 차단하기 위한 의도적 선택이다.
|
|
508
|
-
* mock이 미구현인 API는 실 SDK에서는 존재할 수 있고, 사용자가 이를 인지하지
|
|
509
|
-
* 못한 채 개발을 이어가면 배포 시점에 놀라게 된다. 에러 메시지에 이슈 URL을
|
|
510
|
-
* 포함해 사용자가 mock 누락을 제보할 수 있게 한다.
|
|
511
|
-
*
|
|
512
|
-
* ## KNOWN_UNIMPLEMENTED 정책
|
|
513
|
-
* SDK에 존재하는 것으로 알려져 있으나 현재 mock이 없는 API 이름만 이 집합에 둔다.
|
|
514
|
-
* 이 경우에만 throw 대신 🔴 inert no-op을 반환하고 sdkCallLog에 기록한다.
|
|
515
|
-
* 완전히 미지의 이름은 여전히 throw — "잘 되는 척" 방지.
|
|
516
|
-
*/
|
|
517
|
-
const ISSUES_URL = "https://github.com/apps-in-toss-community/devtools/issues";
|
|
518
|
-
/**
|
|
519
|
-
* SDK에 존재하나 mock이 아직 없는 것으로 확인된 이름 목록.
|
|
520
|
-
* 새 API가 SDK에 추가되면 여기에 추가하고 별도 PR에서 mock 구현으로 이동한다.
|
|
521
|
-
* 확인되지 않은 이름은 절대 여기에 추가하지 않는다 — throw가 더 안전하다.
|
|
522
|
-
*/
|
|
523
|
-
const KNOWN_UNIMPLEMENTED = /* @__PURE__ */ new Set([]);
|
|
524
|
-
function createMockProxy(moduleName, implementations) {
|
|
525
|
-
return new Proxy(implementations, { get(target, prop) {
|
|
526
|
-
if (typeof prop === "symbol") return void 0;
|
|
527
|
-
if (prop in target) return target[prop];
|
|
528
|
-
const name = String(prop);
|
|
529
|
-
if (KNOWN_UNIMPLEMENTED.has(name)) return (...args) => {
|
|
530
|
-
console.warn(`[@apps-in-toss/devtools] ${moduleName}.${name} is known-unimplemented (🔴 inert). Returning undefined. Please file or upvote an issue: ${ISSUES_URL}`);
|
|
531
|
-
aitState.logSdkCall({
|
|
532
|
-
method: `${moduleName}.${name}`,
|
|
533
|
-
args,
|
|
534
|
-
timestamp: Date.now(),
|
|
535
|
-
status: "resolved",
|
|
536
|
-
result: void 0,
|
|
537
|
-
fidelity: "inert"
|
|
538
|
-
});
|
|
539
|
-
};
|
|
540
|
-
throw new Error(`[@apps-in-toss/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}`);
|
|
541
|
-
} });
|
|
542
|
-
}
|
|
543
|
-
//#endregion
|
|
544
582
|
//#region src/mock/throttle.ts
|
|
545
583
|
/**
|
|
546
584
|
* THROTTLED 시뮬레이션 (devtools#834 — #770 §3 분리).
|
|
@@ -1567,36 +1605,6 @@ const _openPDFViewerImpl = async (_params) => {
|
|
|
1567
1605
|
};
|
|
1568
1606
|
const openPDFViewer$1 = Object.assign(_openPDFViewerImpl, { isSupported: () => true });
|
|
1569
1607
|
//#endregion
|
|
1570
|
-
//#region src/mock/device/storage.ts
|
|
1571
|
-
/**
|
|
1572
|
-
* Storage mock
|
|
1573
|
-
* localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리
|
|
1574
|
-
*
|
|
1575
|
-
* 실기기(2.x×iOS) capture는 `setItem`/`removeItem`/`clearItems` 세 메서드가
|
|
1576
|
-
* `undefined`가 아니라 `null`로 resolve됨을 보였다(devtools#770). 원본 SDK 타입
|
|
1577
|
-
* 선언은 여전히 `Promise<void>`이므로 시그니처는 그대로 두고, 런타임 반환값만
|
|
1578
|
-
* `null`로 캐스트해 실측과 동치시킨다 — Analytics·setClipboardText와 같은 처리(#775).
|
|
1579
|
-
* `getItem`은 이미 `string | null`이라 실측과 일치하므로 손대지 않는다.
|
|
1580
|
-
*/
|
|
1581
|
-
const Storage = createMockProxy("Storage", {
|
|
1582
|
-
getItem: async (key) => {
|
|
1583
|
-
return localStorage.getItem(`__ait_storage:${key}`);
|
|
1584
|
-
},
|
|
1585
|
-
setItem: async (key, value) => {
|
|
1586
|
-
localStorage.setItem(`__ait_storage:${key}`, value);
|
|
1587
|
-
return null;
|
|
1588
|
-
},
|
|
1589
|
-
removeItem: async (key) => {
|
|
1590
|
-
localStorage.removeItem(`__ait_storage:${key}`);
|
|
1591
|
-
return null;
|
|
1592
|
-
},
|
|
1593
|
-
clearItems: async () => {
|
|
1594
|
-
const keys = Object.keys(localStorage).filter((k) => k.startsWith("__ait_storage:"));
|
|
1595
|
-
for (const k of keys) localStorage.removeItem(k);
|
|
1596
|
-
return null;
|
|
1597
|
-
}
|
|
1598
|
-
});
|
|
1599
|
-
//#endregion
|
|
1600
1608
|
//#region src/mock/iap/index.ts
|
|
1601
1609
|
let orderCounter = 0;
|
|
1602
1610
|
function generateOrderId() {
|
|
@@ -2394,6 +2402,10 @@ const V = {
|
|
|
2394
2402
|
android: "5.233.0",
|
|
2395
2403
|
ios: "5.233.0"
|
|
2396
2404
|
},
|
|
2405
|
+
storageBatch: {
|
|
2406
|
+
android: "5.270.0",
|
|
2407
|
+
ios: "5.270.0"
|
|
2408
|
+
},
|
|
2397
2409
|
tossLogin: {
|
|
2398
2410
|
android: "5.237.0",
|
|
2399
2411
|
ios: "5.237.0"
|
|
@@ -2533,10 +2545,15 @@ const File = {
|
|
|
2533
2545
|
saveBase64: saveBase64Data,
|
|
2534
2546
|
openPDFViewer
|
|
2535
2547
|
};
|
|
2548
|
+
const subscribeInfoOverlayHidden = ({ onEvent }) => {
|
|
2549
|
+
const timeoutId = window.setTimeout(onEvent, 0);
|
|
2550
|
+
return () => window.clearTimeout(timeoutId);
|
|
2551
|
+
};
|
|
2536
2552
|
const Game = {
|
|
2537
2553
|
openLeaderboard: openGameCenterLeaderboard,
|
|
2538
2554
|
setLeaderboardScore: submitGameCenterLeaderBoardScore,
|
|
2539
|
-
getUserProfile: getGameCenterGameProfile
|
|
2555
|
+
getUserProfile: getGameCenterGameProfile,
|
|
2556
|
+
subscribeInfoOverlayHidden
|
|
2540
2557
|
};
|
|
2541
2558
|
const Migration = { getOriginStorage: async () => {
|
|
2542
2559
|
const createEmptyDump = () => ({
|
|
@@ -2572,6 +2589,11 @@ const Share = {
|
|
|
2572
2589
|
createLink: ({ path, ogImageUrl }) => getTossShareLink(path, ogImageUrl),
|
|
2573
2590
|
sendMessage: share
|
|
2574
2591
|
};
|
|
2592
|
+
const Storage = {
|
|
2593
|
+
...Storage$1,
|
|
2594
|
+
getItems: supported(getItems, V.storageBatch),
|
|
2595
|
+
setItems: supported(setItems, V.storageBatch)
|
|
2596
|
+
};
|
|
2575
2597
|
const TossAuth = {
|
|
2576
2598
|
login: appLogin,
|
|
2577
2599
|
isIntegrated: getIsTossLoginIntegratedService,
|
package/dist/panel/index.js
CHANGED
|
@@ -27325,20 +27325,33 @@ function createMockProxy(moduleName, implementations) {
|
|
|
27325
27325
|
throw new Error(`[@apps-in-toss/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}`);
|
|
27326
27326
|
} });
|
|
27327
27327
|
}
|
|
27328
|
+
//#endregion
|
|
27329
|
+
//#region src/mock/device/storage.ts
|
|
27330
|
+
/**
|
|
27331
|
+
* Storage mock
|
|
27332
|
+
* localStorage에 `__ait_storage:` prefix로 저장하여 앱 자체 localStorage와 분리
|
|
27333
|
+
*
|
|
27334
|
+
* 실기기(2.x×iOS) capture는 `setItem`/`removeItem`/`clearItems` 세 메서드가
|
|
27335
|
+
* `undefined`가 아니라 `null`로 resolve됨을 보였다(devtools#770). 원본 SDK 타입
|
|
27336
|
+
* 선언은 여전히 `Promise<void>`이므로 시그니처는 그대로 두고, 런타임 반환값만
|
|
27337
|
+
* `null`로 캐스트해 실측과 동치시킨다 — Analytics·setClipboardText와 같은 처리(#775).
|
|
27338
|
+
* `getItem`은 이미 `string | null`이라 실측과 일치하므로 손대지 않는다.
|
|
27339
|
+
*/
|
|
27340
|
+
const STORAGE_PREFIX = "__ait_storage:";
|
|
27328
27341
|
createMockProxy("Storage", {
|
|
27329
27342
|
getItem: async (key) => {
|
|
27330
|
-
return localStorage.getItem(
|
|
27343
|
+
return localStorage.getItem(`${STORAGE_PREFIX}${key}`);
|
|
27331
27344
|
},
|
|
27332
27345
|
setItem: async (key, value) => {
|
|
27333
|
-
localStorage.setItem(
|
|
27346
|
+
localStorage.setItem(`${STORAGE_PREFIX}${key}`, value);
|
|
27334
27347
|
return null;
|
|
27335
27348
|
},
|
|
27336
27349
|
removeItem: async (key) => {
|
|
27337
|
-
localStorage.removeItem(
|
|
27350
|
+
localStorage.removeItem(`${STORAGE_PREFIX}${key}`);
|
|
27338
27351
|
return null;
|
|
27339
27352
|
},
|
|
27340
27353
|
clearItems: async () => {
|
|
27341
|
-
const keys = Object.keys(localStorage).filter((k) => k.startsWith(
|
|
27354
|
+
const keys = Object.keys(localStorage).filter((k) => k.startsWith(STORAGE_PREFIX));
|
|
27342
27355
|
for (const k of keys) localStorage.removeItem(k);
|
|
27343
27356
|
return null;
|
|
27344
27357
|
}
|
|
@@ -30601,7 +30614,7 @@ function Panel() {
|
|
|
30601
30614
|
color: "#666",
|
|
30602
30615
|
fontWeight: 400
|
|
30603
30616
|
},
|
|
30604
|
-
children: ["v", "3.
|
|
30617
|
+
children: ["v", "3.2.0"]
|
|
30605
30618
|
}),
|
|
30606
30619
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
30607
30620
|
type: "button",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apps-in-toss/devtools",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Browser development tools for Apps in Toss mini-apps — mock SDK, floating devtools panel, and universal bundler plugin. devDependency only; contributes nothing to a production bundle",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"apps-in-toss",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"unplugin": "^3.2.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@apps-in-toss/web-framework": "^3.
|
|
70
|
+
"@apps-in-toss/web-framework": "^3.2.0",
|
|
71
71
|
"@apps-in-toss/web-framework-2x": "npm:@apps-in-toss/web-framework@2.10.8",
|
|
72
72
|
"@testing-library/dom": "10.4.1",
|
|
73
73
|
"@testing-library/react": "16.3.2",
|