connectbase-client 5.12.6 → 5.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -5144,6 +5144,14 @@ interface NativeBridgeInterface {
5144
5144
  rewarded: boolean;
5145
5145
  }>;
5146
5146
  };
5147
+ /** 모바일 전용: 네이티브 인앱 브라우저 세션으로 여는 OAuth (ASWebAuthenticationSession/Custom Tabs) */
5148
+ oauth?: {
5149
+ signIn: (authUrl: string, callbackScheme: string) => Promise<{
5150
+ url: string;
5151
+ }>;
5152
+ /** 이 패키징 앱의 OAuth 콜백 URL 스킴 (`<scheme>://oauth/callback`). 동기 함수 */
5153
+ getCallbackScheme: () => string;
5154
+ };
5147
5155
  system?: {
5148
5156
  getInfo: () => Promise<SystemInfo>;
5149
5157
  getMemory: () => Promise<MemoryInfo>;
@@ -5173,6 +5181,7 @@ interface NativeBridgeInterface {
5173
5181
  readImage: () => Promise<string | null>;
5174
5182
  writeImage: (dataURL: string) => Promise<void>;
5175
5183
  clear: () => Promise<void>;
5184
+ has: (format: string) => Promise<boolean>;
5176
5185
  };
5177
5186
  shell?: {
5178
5187
  openExternal: (url: string) => Promise<{
@@ -5242,6 +5251,22 @@ interface NativeBridgeInterface {
5242
5251
  getAppDir?: () => Promise<string>;
5243
5252
  };
5244
5253
  onDeepLink?: (callback: (url: string) => void) => () => void;
5254
+ /** 모바일 전용: 앱에 연결된 Connect Base Storage 로 파일 업로드 (file_storage.type=connectbase 일 때만 존재) */
5255
+ connectbase?: {
5256
+ uploadFile: (uri: string, filename?: string, mimeType?: string) => Promise<{
5257
+ id: string;
5258
+ name: string;
5259
+ url: string;
5260
+ path: string;
5261
+ storageId: string;
5262
+ }>;
5263
+ };
5264
+ /**
5265
+ * 데스크톱 전용: 저수준 이벤트 구독 (`off` 는 해당 채널의 모든 리스너를 제거한다 — 콜백
5266
+ * 단위 해제가 아니다). `deep-link` 는 `onDeepLink` 로도 동일하게 구독할 수 있다.
5267
+ */
5268
+ on?: (channel: "deep-link" | "window-focus" | "window-blur" | "update-available" | "update-downloaded", callback: (...args: unknown[]) => void) => void;
5269
+ off?: (channel: "deep-link" | "window-focus" | "window-blur" | "update-available" | "update-downloaded") => void;
5245
5270
  }
5246
5271
  type Platform = "web" | "mobile" | "desktop";
5247
5272
  /** 패키징 앱 정보 (`cb.native.getAppInfo()`) */
@@ -5459,6 +5484,10 @@ declare class NativeAPI {
5459
5484
  * 이미지 읽기 (데스크톱 전용, Data URL 반환)
5460
5485
  */
5461
5486
  readImage: () => Promise<string | null>;
5487
+ /**
5488
+ * 클립보드에 특정 형식(MIME 타입, 예: 'text/plain', 'image/png')의 데이터가 있는지 확인 (데스크톱 전용)
5489
+ */
5490
+ has: (format: string) => Promise<boolean>;
5462
5491
  };
5463
5492
  /**
5464
5493
  * 크로스 플랫폼 파일 시스템 API
@@ -5573,6 +5602,47 @@ declare class NativeAPI {
5573
5602
  */
5574
5603
  openExternal: (url: string) => Promise<boolean>;
5575
5604
  };
5605
+ /**
5606
+ * 모바일 전용: 네이티브 인앱 브라우저 세션으로 여는 OAuth
5607
+ *
5608
+ * WebView 안에서 소셜 로그인 팝업을 열면 세션/쿠키가 격리돼 실패하는 경우가 많다.
5609
+ * 패키징 앱(RN)에서는 시스템 브라우저 세션(iOS ASWebAuthenticationSession /
5610
+ * Android Custom Tabs)으로 열고 앱 URL 스킴 콜백으로 결과를 받는다.
5611
+ * 웹/데스크톱에서는 지원하지 않는다 — 일반 팝업/리다이렉트 OAuth 플로우를 쓸 것.
5612
+ *
5613
+ * @example
5614
+ * ```typescript
5615
+ * if (cb.native.getPlatform() === 'mobile') {
5616
+ * const result = await cb.native.oauth.signIn(authorizeUrl)
5617
+ * if (result) window.location.href = result.url // 콜백 URL 로 계속 진행
5618
+ * }
5619
+ * ```
5620
+ */
5621
+ oauth: {
5622
+ /**
5623
+ * OAuth 인가 URL 을 네이티브 인앱 브라우저 세션으로 열고 콜백 URL 을 기다린다.
5624
+ * callbackScheme 을 생략하면 이 패키징 앱의 스킴(getCallbackScheme())을 사용한다.
5625
+ * 사용자가 취소했거나 미지원 플랫폼이면 null.
5626
+ */
5627
+ signIn: (authUrl: string, callbackScheme?: string) => Promise<{
5628
+ url: string;
5629
+ } | null>;
5630
+ /** 이 패키징 앱의 OAuth 콜백 URL 스킴(`<scheme>://oauth/callback`). 미지원 플랫폼은 null (동기) */
5631
+ getCallbackScheme: () => string | null;
5632
+ };
5633
+ /**
5634
+ * 모바일 전용: 패키징 앱에 연결된 Connect Base Storage 로 파일 업로드.
5635
+ * 콘솔 패키징 설정에서 "파일 저장 위치" 를 Connect Base Storage 로 선택한 경우에만 지원한다.
5636
+ */
5637
+ connectbase: {
5638
+ uploadFile: (uri: string, filename?: string, mimeType?: string) => Promise<{
5639
+ id: string;
5640
+ name: string;
5641
+ url: string;
5642
+ path: string;
5643
+ storageId: string;
5644
+ } | null>;
5645
+ };
5576
5646
  /**
5577
5647
  * 데스크톱 전용 창 제어 API
5578
5648
  */
@@ -5584,6 +5654,19 @@ declare class NativeAPI {
5584
5654
  isMaximized: () => Promise<boolean>;
5585
5655
  setTitle: (title: string) => Promise<void>;
5586
5656
  setFullScreen: (flag: boolean) => Promise<void>;
5657
+ isFullScreen: () => Promise<boolean>;
5658
+ /** 창 크기 설정 (데스크톱 전용) */
5659
+ setSize: (width: number, height: number) => Promise<void>;
5660
+ /** 창 크기 조회 (데스크톱 전용, 미지원 플랫폼은 null) */
5661
+ getSize: () => Promise<[number, number] | null>;
5662
+ /** 창 위치 설정 (데스크톱 전용) */
5663
+ setPosition: (x: number, y: number) => Promise<void>;
5664
+ /** 창 위치 조회 (데스크톱 전용, 미지원 플랫폼은 null) */
5665
+ getPosition: () => Promise<[number, number] | null>;
5666
+ /** 화면 중앙으로 이동 (데스크톱 전용) */
5667
+ center: () => Promise<void>;
5668
+ /** 항상 위에 표시 설정 (데스크톱 전용) */
5669
+ setAlwaysOnTop: (flag: boolean) => Promise<void>;
5587
5670
  };
5588
5671
  /**
5589
5672
  * 데스크톱 전용 시스템 정보 API
@@ -5591,6 +5674,7 @@ declare class NativeAPI {
5591
5674
  system: {
5592
5675
  getInfo: () => Promise<SystemInfo | null>;
5593
5676
  getMemory: () => Promise<MemoryInfo | null>;
5677
+ getCPU: () => Promise<CPUInfo | null>;
5594
5678
  };
5595
5679
  /**
5596
5680
  * 모바일 전용 생체인증 API
package/dist/index.d.ts CHANGED
@@ -5144,6 +5144,14 @@ interface NativeBridgeInterface {
5144
5144
  rewarded: boolean;
5145
5145
  }>;
5146
5146
  };
5147
+ /** 모바일 전용: 네이티브 인앱 브라우저 세션으로 여는 OAuth (ASWebAuthenticationSession/Custom Tabs) */
5148
+ oauth?: {
5149
+ signIn: (authUrl: string, callbackScheme: string) => Promise<{
5150
+ url: string;
5151
+ }>;
5152
+ /** 이 패키징 앱의 OAuth 콜백 URL 스킴 (`<scheme>://oauth/callback`). 동기 함수 */
5153
+ getCallbackScheme: () => string;
5154
+ };
5147
5155
  system?: {
5148
5156
  getInfo: () => Promise<SystemInfo>;
5149
5157
  getMemory: () => Promise<MemoryInfo>;
@@ -5173,6 +5181,7 @@ interface NativeBridgeInterface {
5173
5181
  readImage: () => Promise<string | null>;
5174
5182
  writeImage: (dataURL: string) => Promise<void>;
5175
5183
  clear: () => Promise<void>;
5184
+ has: (format: string) => Promise<boolean>;
5176
5185
  };
5177
5186
  shell?: {
5178
5187
  openExternal: (url: string) => Promise<{
@@ -5242,6 +5251,22 @@ interface NativeBridgeInterface {
5242
5251
  getAppDir?: () => Promise<string>;
5243
5252
  };
5244
5253
  onDeepLink?: (callback: (url: string) => void) => () => void;
5254
+ /** 모바일 전용: 앱에 연결된 Connect Base Storage 로 파일 업로드 (file_storage.type=connectbase 일 때만 존재) */
5255
+ connectbase?: {
5256
+ uploadFile: (uri: string, filename?: string, mimeType?: string) => Promise<{
5257
+ id: string;
5258
+ name: string;
5259
+ url: string;
5260
+ path: string;
5261
+ storageId: string;
5262
+ }>;
5263
+ };
5264
+ /**
5265
+ * 데스크톱 전용: 저수준 이벤트 구독 (`off` 는 해당 채널의 모든 리스너를 제거한다 — 콜백
5266
+ * 단위 해제가 아니다). `deep-link` 는 `onDeepLink` 로도 동일하게 구독할 수 있다.
5267
+ */
5268
+ on?: (channel: "deep-link" | "window-focus" | "window-blur" | "update-available" | "update-downloaded", callback: (...args: unknown[]) => void) => void;
5269
+ off?: (channel: "deep-link" | "window-focus" | "window-blur" | "update-available" | "update-downloaded") => void;
5245
5270
  }
5246
5271
  type Platform = "web" | "mobile" | "desktop";
5247
5272
  /** 패키징 앱 정보 (`cb.native.getAppInfo()`) */
@@ -5459,6 +5484,10 @@ declare class NativeAPI {
5459
5484
  * 이미지 읽기 (데스크톱 전용, Data URL 반환)
5460
5485
  */
5461
5486
  readImage: () => Promise<string | null>;
5487
+ /**
5488
+ * 클립보드에 특정 형식(MIME 타입, 예: 'text/plain', 'image/png')의 데이터가 있는지 확인 (데스크톱 전용)
5489
+ */
5490
+ has: (format: string) => Promise<boolean>;
5462
5491
  };
5463
5492
  /**
5464
5493
  * 크로스 플랫폼 파일 시스템 API
@@ -5573,6 +5602,47 @@ declare class NativeAPI {
5573
5602
  */
5574
5603
  openExternal: (url: string) => Promise<boolean>;
5575
5604
  };
5605
+ /**
5606
+ * 모바일 전용: 네이티브 인앱 브라우저 세션으로 여는 OAuth
5607
+ *
5608
+ * WebView 안에서 소셜 로그인 팝업을 열면 세션/쿠키가 격리돼 실패하는 경우가 많다.
5609
+ * 패키징 앱(RN)에서는 시스템 브라우저 세션(iOS ASWebAuthenticationSession /
5610
+ * Android Custom Tabs)으로 열고 앱 URL 스킴 콜백으로 결과를 받는다.
5611
+ * 웹/데스크톱에서는 지원하지 않는다 — 일반 팝업/리다이렉트 OAuth 플로우를 쓸 것.
5612
+ *
5613
+ * @example
5614
+ * ```typescript
5615
+ * if (cb.native.getPlatform() === 'mobile') {
5616
+ * const result = await cb.native.oauth.signIn(authorizeUrl)
5617
+ * if (result) window.location.href = result.url // 콜백 URL 로 계속 진행
5618
+ * }
5619
+ * ```
5620
+ */
5621
+ oauth: {
5622
+ /**
5623
+ * OAuth 인가 URL 을 네이티브 인앱 브라우저 세션으로 열고 콜백 URL 을 기다린다.
5624
+ * callbackScheme 을 생략하면 이 패키징 앱의 스킴(getCallbackScheme())을 사용한다.
5625
+ * 사용자가 취소했거나 미지원 플랫폼이면 null.
5626
+ */
5627
+ signIn: (authUrl: string, callbackScheme?: string) => Promise<{
5628
+ url: string;
5629
+ } | null>;
5630
+ /** 이 패키징 앱의 OAuth 콜백 URL 스킴(`<scheme>://oauth/callback`). 미지원 플랫폼은 null (동기) */
5631
+ getCallbackScheme: () => string | null;
5632
+ };
5633
+ /**
5634
+ * 모바일 전용: 패키징 앱에 연결된 Connect Base Storage 로 파일 업로드.
5635
+ * 콘솔 패키징 설정에서 "파일 저장 위치" 를 Connect Base Storage 로 선택한 경우에만 지원한다.
5636
+ */
5637
+ connectbase: {
5638
+ uploadFile: (uri: string, filename?: string, mimeType?: string) => Promise<{
5639
+ id: string;
5640
+ name: string;
5641
+ url: string;
5642
+ path: string;
5643
+ storageId: string;
5644
+ } | null>;
5645
+ };
5576
5646
  /**
5577
5647
  * 데스크톱 전용 창 제어 API
5578
5648
  */
@@ -5584,6 +5654,19 @@ declare class NativeAPI {
5584
5654
  isMaximized: () => Promise<boolean>;
5585
5655
  setTitle: (title: string) => Promise<void>;
5586
5656
  setFullScreen: (flag: boolean) => Promise<void>;
5657
+ isFullScreen: () => Promise<boolean>;
5658
+ /** 창 크기 설정 (데스크톱 전용) */
5659
+ setSize: (width: number, height: number) => Promise<void>;
5660
+ /** 창 크기 조회 (데스크톱 전용, 미지원 플랫폼은 null) */
5661
+ getSize: () => Promise<[number, number] | null>;
5662
+ /** 창 위치 설정 (데스크톱 전용) */
5663
+ setPosition: (x: number, y: number) => Promise<void>;
5664
+ /** 창 위치 조회 (데스크톱 전용, 미지원 플랫폼은 null) */
5665
+ getPosition: () => Promise<[number, number] | null>;
5666
+ /** 화면 중앙으로 이동 (데스크톱 전용) */
5667
+ center: () => Promise<void>;
5668
+ /** 항상 위에 표시 설정 (데스크톱 전용) */
5669
+ setAlwaysOnTop: (flag: boolean) => Promise<void>;
5587
5670
  };
5588
5671
  /**
5589
5672
  * 데스크톱 전용 시스템 정보 API
@@ -5591,6 +5674,7 @@ declare class NativeAPI {
5591
5674
  system: {
5592
5675
  getInfo: () => Promise<SystemInfo | null>;
5593
5676
  getMemory: () => Promise<MemoryInfo | null>;
5677
+ getCPU: () => Promise<CPUInfo | null>;
5594
5678
  };
5595
5679
  /**
5596
5680
  * 모바일 전용 생체인증 API
package/dist/index.js CHANGED
@@ -5355,6 +5355,15 @@ var NativeAPI = class {
5355
5355
  return window.NativeBridge.clipboard.readImage();
5356
5356
  }
5357
5357
  return null;
5358
+ },
5359
+ /**
5360
+ * 클립보드에 특정 형식(MIME 타입, 예: 'text/plain', 'image/png')의 데이터가 있는지 확인 (데스크톱 전용)
5361
+ */
5362
+ has: async (format) => {
5363
+ if (window.NativeBridge?.clipboard?.has) {
5364
+ return window.NativeBridge.clipboard.has(format);
5365
+ }
5366
+ return false;
5358
5367
  }
5359
5368
  };
5360
5369
  /**
@@ -5393,25 +5402,33 @@ var NativeAPI = class {
5393
5402
  saveFile: async (content, filename, options) => {
5394
5403
  const platform = this.getPlatform();
5395
5404
  if (platform === "desktop" && window.NativeBridge?.filesystem) {
5396
- const result = await window.NativeBridge.filesystem.showSaveDialog?.({
5397
- defaultPath: filename,
5398
- filters: options?.filters
5399
- });
5400
- if (result?.canceled || !result?.filePath) return false;
5401
- const textContent = content instanceof Blob ? await content.text() : content;
5402
- const writeResult = await window.NativeBridge.filesystem.writeFile(
5403
- result.filePath,
5404
- textContent
5405
- );
5406
- return writeResult.success;
5405
+ try {
5406
+ const result = await window.NativeBridge.filesystem.showSaveDialog?.({
5407
+ defaultPath: filename,
5408
+ filters: options?.filters
5409
+ });
5410
+ if (result?.canceled || !result?.filePath) return false;
5411
+ const textContent = content instanceof Blob ? await content.text() : content;
5412
+ const writeResult = await window.NativeBridge.filesystem.writeFile(
5413
+ result.filePath,
5414
+ textContent
5415
+ );
5416
+ return writeResult.success;
5417
+ } catch {
5418
+ return false;
5419
+ }
5407
5420
  }
5408
5421
  if (platform === "mobile" && window.NativeBridge?.filesystem) {
5409
- const textContent = content instanceof Blob ? await content.text() : content;
5410
- const result = await window.NativeBridge.filesystem.writeFile(
5411
- filename,
5412
- textContent
5413
- );
5414
- return result.success;
5422
+ try {
5423
+ const textContent = content instanceof Blob ? await content.text() : content;
5424
+ const result = await window.NativeBridge.filesystem.writeFile(
5425
+ filename,
5426
+ textContent
5427
+ );
5428
+ return result.success;
5429
+ } catch {
5430
+ return false;
5431
+ }
5415
5432
  }
5416
5433
  const blob = content instanceof Blob ? content : new Blob([content], { type: "text/plain" });
5417
5434
  const url = URL.createObjectURL(blob);
@@ -5427,8 +5444,12 @@ var NativeAPI = class {
5427
5444
  */
5428
5445
  readFile: async (path) => {
5429
5446
  if (window.NativeBridge?.filesystem?.readFile) {
5430
- const result = await window.NativeBridge.filesystem.readFile(path);
5431
- return result.success ? result.content ?? null : null;
5447
+ try {
5448
+ const result = await window.NativeBridge.filesystem.readFile(path);
5449
+ return result.success ? result.content ?? null : null;
5450
+ } catch {
5451
+ return null;
5452
+ }
5432
5453
  }
5433
5454
  return null;
5434
5455
  },
@@ -5452,7 +5473,11 @@ var NativeAPI = class {
5452
5473
  takePicture: async (options) => {
5453
5474
  const platform = this.getPlatform();
5454
5475
  if (platform === "mobile" && window.NativeBridge?.camera) {
5455
- return window.NativeBridge.camera.takePicture(options);
5476
+ try {
5477
+ return await window.NativeBridge.camera.takePicture(options);
5478
+ } catch {
5479
+ return null;
5480
+ }
5456
5481
  }
5457
5482
  return new Promise((resolve) => {
5458
5483
  const input = document.createElement("input");
@@ -5489,7 +5514,11 @@ var NativeAPI = class {
5489
5514
  pickImage: async (options) => {
5490
5515
  const platform = this.getPlatform();
5491
5516
  if (platform === "mobile" && window.NativeBridge?.camera) {
5492
- return window.NativeBridge.camera.pickImage(options);
5517
+ try {
5518
+ return await window.NativeBridge.camera.pickImage(options);
5519
+ } catch {
5520
+ return null;
5521
+ }
5493
5522
  }
5494
5523
  return new Promise((resolve) => {
5495
5524
  const input = document.createElement("input");
@@ -5632,7 +5661,11 @@ var NativeAPI = class {
5632
5661
  */
5633
5662
  getToken: async () => {
5634
5663
  if (this.getPlatform() === "mobile" && window.NativeBridge?.push) {
5635
- return window.NativeBridge.push.getToken();
5664
+ try {
5665
+ return await window.NativeBridge.push.getToken();
5666
+ } catch {
5667
+ return null;
5668
+ }
5636
5669
  }
5637
5670
  return null;
5638
5671
  },
@@ -5643,8 +5676,12 @@ var NativeAPI = class {
5643
5676
  /** 로컬 알림 예약 (패키징 앱 전용) */
5644
5677
  scheduleLocal: async (options) => {
5645
5678
  if (this.getPlatform() === "mobile" && window.NativeBridge?.push) {
5646
- const result = await window.NativeBridge.push.scheduleLocal(options);
5647
- return result.notificationId;
5679
+ try {
5680
+ const result = await window.NativeBridge.push.scheduleLocal(options);
5681
+ return result.notificationId;
5682
+ } catch {
5683
+ return null;
5684
+ }
5648
5685
  }
5649
5686
  return null;
5650
5687
  },
@@ -5652,8 +5689,12 @@ var NativeAPI = class {
5652
5689
  setBadgeCount: async (count) => {
5653
5690
  const setter = window.NativeBridge?.push?.setBadgeCount;
5654
5691
  if (!setter) return false;
5655
- const result = await setter(count);
5656
- return result.success;
5692
+ try {
5693
+ const result = await setter(count);
5694
+ return result.success;
5695
+ } catch {
5696
+ return false;
5697
+ }
5657
5698
  }
5658
5699
  };
5659
5700
  /**
@@ -5672,12 +5713,12 @@ var NativeAPI = class {
5672
5713
  if (platform === "mobile" && window.NativeBridge?.push?.scheduleLocal) {
5673
5714
  const granted = await this.notification.requestPermission();
5674
5715
  if (!granted) return false;
5675
- await window.NativeBridge.push.scheduleLocal({
5716
+ const notificationId = await this.push.scheduleLocal({
5676
5717
  title: options.title,
5677
5718
  body: options.body,
5678
5719
  trigger: null
5679
5720
  });
5680
- return true;
5721
+ return notificationId !== null;
5681
5722
  }
5682
5723
  if (!("Notification" in window)) return false;
5683
5724
  if (Notification.permission !== "granted") {
@@ -5697,8 +5738,12 @@ var NativeAPI = class {
5697
5738
  requestPermission: async () => {
5698
5739
  const platform = this.getPlatform();
5699
5740
  if (platform === "mobile" && window.NativeBridge?.push) {
5700
- const result = await window.NativeBridge.push.requestPermission();
5701
- return result.granted;
5741
+ try {
5742
+ const result = await window.NativeBridge.push.requestPermission();
5743
+ return result.granted;
5744
+ } catch {
5745
+ return false;
5746
+ }
5702
5747
  }
5703
5748
  if (!("Notification" in window)) return false;
5704
5749
  const permission = await Notification.requestPermission();
@@ -5719,13 +5764,77 @@ var NativeAPI = class {
5719
5764
  return result.success;
5720
5765
  }
5721
5766
  if (platform === "mobile" && window.NativeBridge?.browser) {
5722
- const result = await window.NativeBridge.browser.openExternal(url);
5723
- return result.success;
5767
+ try {
5768
+ const result = await window.NativeBridge.browser.openExternal(url);
5769
+ return result.success;
5770
+ } catch {
5771
+ return false;
5772
+ }
5724
5773
  }
5725
5774
  window.open(url, "_blank");
5726
5775
  return true;
5727
5776
  }
5728
5777
  };
5778
+ /**
5779
+ * 모바일 전용: 네이티브 인앱 브라우저 세션으로 여는 OAuth
5780
+ *
5781
+ * WebView 안에서 소셜 로그인 팝업을 열면 세션/쿠키가 격리돼 실패하는 경우가 많다.
5782
+ * 패키징 앱(RN)에서는 시스템 브라우저 세션(iOS ASWebAuthenticationSession /
5783
+ * Android Custom Tabs)으로 열고 앱 URL 스킴 콜백으로 결과를 받는다.
5784
+ * 웹/데스크톱에서는 지원하지 않는다 — 일반 팝업/리다이렉트 OAuth 플로우를 쓸 것.
5785
+ *
5786
+ * @example
5787
+ * ```typescript
5788
+ * if (cb.native.getPlatform() === 'mobile') {
5789
+ * const result = await cb.native.oauth.signIn(authorizeUrl)
5790
+ * if (result) window.location.href = result.url // 콜백 URL 로 계속 진행
5791
+ * }
5792
+ * ```
5793
+ */
5794
+ this.oauth = {
5795
+ /**
5796
+ * OAuth 인가 URL 을 네이티브 인앱 브라우저 세션으로 열고 콜백 URL 을 기다린다.
5797
+ * callbackScheme 을 생략하면 이 패키징 앱의 스킴(getCallbackScheme())을 사용한다.
5798
+ * 사용자가 취소했거나 미지원 플랫폼이면 null.
5799
+ */
5800
+ signIn: async (authUrl, callbackScheme) => {
5801
+ const bridge = window.NativeBridge;
5802
+ if (this.getPlatform() !== "mobile" || !bridge?.oauth) return null;
5803
+ const scheme = callbackScheme ?? bridge.oauth.getCallbackScheme();
5804
+ try {
5805
+ return await bridge.oauth.signIn(authUrl, scheme);
5806
+ } catch {
5807
+ return null;
5808
+ }
5809
+ },
5810
+ /** 이 패키징 앱의 OAuth 콜백 URL 스킴(`<scheme>://oauth/callback`). 미지원 플랫폼은 null (동기) */
5811
+ getCallbackScheme: () => {
5812
+ if (this.getPlatform() !== "mobile" || !window.NativeBridge?.oauth) {
5813
+ return null;
5814
+ }
5815
+ return window.NativeBridge.oauth.getCallbackScheme();
5816
+ }
5817
+ };
5818
+ /**
5819
+ * 모바일 전용: 패키징 앱에 연결된 Connect Base Storage 로 파일 업로드.
5820
+ * 콘솔 패키징 설정에서 "파일 저장 위치" 를 Connect Base Storage 로 선택한 경우에만 지원한다.
5821
+ */
5822
+ this.connectbase = {
5823
+ uploadFile: async (uri, filename, mimeType) => {
5824
+ if (this.getPlatform() !== "mobile" || !window.NativeBridge?.connectbase) {
5825
+ return null;
5826
+ }
5827
+ try {
5828
+ return await window.NativeBridge.connectbase.uploadFile(
5829
+ uri,
5830
+ filename,
5831
+ mimeType
5832
+ );
5833
+ } catch {
5834
+ return null;
5835
+ }
5836
+ }
5837
+ };
5729
5838
  /**
5730
5839
  * 데스크톱 전용 창 제어 API
5731
5840
  */
@@ -5762,6 +5871,36 @@ var NativeAPI = class {
5762
5871
  await document.exitFullscreen();
5763
5872
  }
5764
5873
  }
5874
+ },
5875
+ isFullScreen: async () => {
5876
+ if (window.NativeBridge?.window) {
5877
+ return await window.NativeBridge.window.isFullScreen() ?? false;
5878
+ }
5879
+ return !!document.fullscreenElement;
5880
+ },
5881
+ /** 창 크기 설정 (데스크톱 전용) */
5882
+ setSize: async (width, height) => {
5883
+ await window.NativeBridge?.window?.setSize(width, height);
5884
+ },
5885
+ /** 창 크기 조회 (데스크톱 전용, 미지원 플랫폼은 null) */
5886
+ getSize: async () => {
5887
+ return await window.NativeBridge?.window?.getSize() ?? null;
5888
+ },
5889
+ /** 창 위치 설정 (데스크톱 전용) */
5890
+ setPosition: async (x, y) => {
5891
+ await window.NativeBridge?.window?.setPosition(x, y);
5892
+ },
5893
+ /** 창 위치 조회 (데스크톱 전용, 미지원 플랫폼은 null) */
5894
+ getPosition: async () => {
5895
+ return await window.NativeBridge?.window?.getPosition() ?? null;
5896
+ },
5897
+ /** 화면 중앙으로 이동 (데스크톱 전용) */
5898
+ center: async () => {
5899
+ await window.NativeBridge?.window?.center();
5900
+ },
5901
+ /** 항상 위에 표시 설정 (데스크톱 전용) */
5902
+ setAlwaysOnTop: async (flag) => {
5903
+ await window.NativeBridge?.window?.setAlwaysOnTop(flag);
5765
5904
  }
5766
5905
  };
5767
5906
  /**
@@ -5779,6 +5918,12 @@ var NativeAPI = class {
5779
5918
  return window.NativeBridge.system.getMemory();
5780
5919
  }
5781
5920
  return null;
5921
+ },
5922
+ getCPU: async () => {
5923
+ if (window.NativeBridge?.system) {
5924
+ return window.NativeBridge.system.getCPU();
5925
+ }
5926
+ return null;
5782
5927
  }
5783
5928
  };
5784
5929
  /**
@@ -5787,13 +5932,21 @@ var NativeAPI = class {
5787
5932
  this.biometric = {
5788
5933
  isAvailable: async () => {
5789
5934
  if (window.NativeBridge?.biometric) {
5790
- return window.NativeBridge.biometric.isAvailable();
5935
+ try {
5936
+ return await window.NativeBridge.biometric.isAvailable();
5937
+ } catch {
5938
+ return null;
5939
+ }
5791
5940
  }
5792
5941
  return null;
5793
5942
  },
5794
5943
  authenticate: async (options) => {
5795
5944
  if (window.NativeBridge?.biometric) {
5796
- return window.NativeBridge.biometric.authenticate(options);
5945
+ try {
5946
+ return await window.NativeBridge.biometric.authenticate(options);
5947
+ } catch {
5948
+ return null;
5949
+ }
5797
5950
  }
5798
5951
  return null;
5799
5952
  }
@@ -5804,26 +5957,38 @@ var NativeAPI = class {
5804
5957
  this.secureStore = {
5805
5958
  setItem: async (key, value) => {
5806
5959
  if (window.NativeBridge?.secureStore) {
5807
- const result = await window.NativeBridge.secureStore.setItem(
5808
- key,
5809
- value
5810
- );
5811
- return result.success;
5960
+ try {
5961
+ const result = await window.NativeBridge.secureStore.setItem(
5962
+ key,
5963
+ value
5964
+ );
5965
+ return result.success;
5966
+ } catch {
5967
+ return false;
5968
+ }
5812
5969
  }
5813
5970
  localStorage.setItem(key, value);
5814
5971
  return true;
5815
5972
  },
5816
5973
  getItem: async (key) => {
5817
5974
  if (window.NativeBridge?.secureStore) {
5818
- const result = await window.NativeBridge.secureStore.getItem(key);
5819
- return result.value;
5975
+ try {
5976
+ const result = await window.NativeBridge.secureStore.getItem(key);
5977
+ return result.value;
5978
+ } catch {
5979
+ return null;
5980
+ }
5820
5981
  }
5821
5982
  return localStorage.getItem(key);
5822
5983
  },
5823
5984
  deleteItem: async (key) => {
5824
5985
  if (window.NativeBridge?.secureStore) {
5825
- const result = await window.NativeBridge.secureStore.deleteItem(key);
5826
- return result.success;
5986
+ try {
5987
+ const result = await window.NativeBridge.secureStore.deleteItem(key);
5988
+ return result.success;
5989
+ } catch {
5990
+ return false;
5991
+ }
5827
5992
  }
5828
5993
  localStorage.removeItem(key);
5829
5994
  return true;
@@ -5835,15 +6000,23 @@ var NativeAPI = class {
5835
6000
  this.admob = {
5836
6001
  showInterstitial: async () => {
5837
6002
  if (window.NativeBridge?.admob) {
5838
- const result = await window.NativeBridge.admob.showInterstitial();
5839
- return result.shown;
6003
+ try {
6004
+ const result = await window.NativeBridge.admob.showInterstitial();
6005
+ return result.shown;
6006
+ } catch {
6007
+ return false;
6008
+ }
5840
6009
  }
5841
6010
  return false;
5842
6011
  },
5843
6012
  showRewarded: async () => {
5844
6013
  if (window.NativeBridge?.admob) {
5845
- const result = await window.NativeBridge.admob.showRewarded();
5846
- return result.rewarded;
6014
+ try {
6015
+ const result = await window.NativeBridge.admob.showRewarded();
6016
+ return result.rewarded;
6017
+ } catch {
6018
+ return false;
6019
+ }
5847
6020
  }
5848
6021
  return false;
5849
6022
  }