@wowlabtech/mini-app-adapter 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -216,6 +216,21 @@ interface MiniAppAdapter {
216
216
  * Resolves with true if permission was granted.
217
217
  */
218
218
  requestNotificationsPermission?(): Promise<boolean>;
219
+ /**
220
+ * Prompts user to add the mini app to the home screen if supported.
221
+ * Resolves with true when the prompt succeeded.
222
+ */
223
+ addToHomeScreen?(): Promise<boolean>;
224
+ /**
225
+ * Checks whether the mini app is already added to the home screen, if supported.
226
+ * Returns platform-specific status or 'unknown' when not available.
227
+ */
228
+ checkHomeScreenStatus?(): Promise<'added' | 'not_added' | 'unknown' | string>;
229
+ /**
230
+ * Revokes/denies push notifications if supported by the platform.
231
+ * Resolves with true if notifications were disabled.
232
+ */
233
+ denyNotifications?(): Promise<boolean>;
219
234
  /**
220
235
  * Subscribes to push token updates delivered by native shells.
221
236
  */
@@ -311,6 +326,9 @@ declare abstract class BaseMiniAppAdapter implements MiniAppAdapter {
311
326
  scanQRCode(_options?: MiniAppQrScanOptions): Promise<string | null>;
312
327
  requestPhone(): Promise<string | null>;
313
328
  requestNotificationsPermission(): Promise<boolean>;
329
+ addToHomeScreen(): Promise<boolean>;
330
+ checkHomeScreenStatus(): Promise<'added' | 'not_added' | 'unknown' | string>;
331
+ denyNotifications(): Promise<boolean>;
314
332
  enableVerticalSwipes(): void;
315
333
  disableVerticalSwipes(): void;
316
334
  protected notifyEnvironmentChanged(): void;
@@ -393,6 +411,8 @@ declare class TelegramMiniAppAdapter extends BaseMiniAppAdapter {
393
411
  shareUrl(url: string, text?: string): void;
394
412
  downloadFile(url: string, filename: string): Promise<void>;
395
413
  shareStory(mediaUrl: string, options?: MiniAppShareStoryOptions): Promise<void>;
414
+ addToHomeScreen(): Promise<boolean>;
415
+ checkHomeScreenStatus(): Promise<'added' | 'not_added' | 'unknown' | string>;
396
416
  requestPhone(): Promise<string | null>;
397
417
  private setupAppearanceWatcher;
398
418
  private notifyAppearance;
@@ -430,10 +450,14 @@ declare class VKMiniAppAdapter extends BaseMiniAppAdapter {
430
450
  supports(capability: MiniAppCapability): Promise<boolean>;
431
451
  requestPhone(): Promise<string | null>;
432
452
  requestNotificationsPermission(): Promise<boolean>;
453
+ addToHomeScreen(): Promise<boolean>;
454
+ denyNotifications(): Promise<boolean>;
433
455
  scanQRCode(options?: MiniAppQrScanOptions): Promise<string | null>;
434
456
  onViewHide(callback: () => void): () => void;
435
457
  onViewRestore(callback: () => void): () => void;
436
458
  shareStory(mediaUrl: string, _options?: MiniAppShareStoryOptions): Promise<void>;
459
+ shareUrl(url: string, text?: string): void;
460
+ private shareUrlInternal;
437
461
  downloadFile(url: string, filename: string): Promise<void>;
438
462
  trackConversionEvent(event: string, payload?: Record<string, unknown>): void;
439
463
  trackPixelEvent(event: string, payload?: Record<string, unknown>): void;
@@ -461,9 +485,13 @@ declare class VKMiniAppAdapter extends BaseMiniAppAdapter {
461
485
  }
462
486
 
463
487
  declare class WebMiniAppAdapter extends BaseMiniAppAdapter {
488
+ private deferredPrompt;
464
489
  constructor();
465
490
  downloadFile(url: string, filename: string): Promise<void>;
466
491
  scanQRCode(_options?: MiniAppQrScanOptions): Promise<string | null>;
492
+ shareUrl(url: string, text: string): void;
493
+ addToHomeScreen(): Promise<boolean>;
494
+ checkHomeScreenStatus(): Promise<'added' | 'not_added' | 'unknown' | string>;
467
495
  }
468
496
 
469
497
  interface CreateAdapterOptions {
package/dist/index.d.ts CHANGED
@@ -216,6 +216,21 @@ interface MiniAppAdapter {
216
216
  * Resolves with true if permission was granted.
217
217
  */
218
218
  requestNotificationsPermission?(): Promise<boolean>;
219
+ /**
220
+ * Prompts user to add the mini app to the home screen if supported.
221
+ * Resolves with true when the prompt succeeded.
222
+ */
223
+ addToHomeScreen?(): Promise<boolean>;
224
+ /**
225
+ * Checks whether the mini app is already added to the home screen, if supported.
226
+ * Returns platform-specific status or 'unknown' when not available.
227
+ */
228
+ checkHomeScreenStatus?(): Promise<'added' | 'not_added' | 'unknown' | string>;
229
+ /**
230
+ * Revokes/denies push notifications if supported by the platform.
231
+ * Resolves with true if notifications were disabled.
232
+ */
233
+ denyNotifications?(): Promise<boolean>;
219
234
  /**
220
235
  * Subscribes to push token updates delivered by native shells.
221
236
  */
@@ -311,6 +326,9 @@ declare abstract class BaseMiniAppAdapter implements MiniAppAdapter {
311
326
  scanQRCode(_options?: MiniAppQrScanOptions): Promise<string | null>;
312
327
  requestPhone(): Promise<string | null>;
313
328
  requestNotificationsPermission(): Promise<boolean>;
329
+ addToHomeScreen(): Promise<boolean>;
330
+ checkHomeScreenStatus(): Promise<'added' | 'not_added' | 'unknown' | string>;
331
+ denyNotifications(): Promise<boolean>;
314
332
  enableVerticalSwipes(): void;
315
333
  disableVerticalSwipes(): void;
316
334
  protected notifyEnvironmentChanged(): void;
@@ -393,6 +411,8 @@ declare class TelegramMiniAppAdapter extends BaseMiniAppAdapter {
393
411
  shareUrl(url: string, text?: string): void;
394
412
  downloadFile(url: string, filename: string): Promise<void>;
395
413
  shareStory(mediaUrl: string, options?: MiniAppShareStoryOptions): Promise<void>;
414
+ addToHomeScreen(): Promise<boolean>;
415
+ checkHomeScreenStatus(): Promise<'added' | 'not_added' | 'unknown' | string>;
396
416
  requestPhone(): Promise<string | null>;
397
417
  private setupAppearanceWatcher;
398
418
  private notifyAppearance;
@@ -430,10 +450,14 @@ declare class VKMiniAppAdapter extends BaseMiniAppAdapter {
430
450
  supports(capability: MiniAppCapability): Promise<boolean>;
431
451
  requestPhone(): Promise<string | null>;
432
452
  requestNotificationsPermission(): Promise<boolean>;
453
+ addToHomeScreen(): Promise<boolean>;
454
+ denyNotifications(): Promise<boolean>;
433
455
  scanQRCode(options?: MiniAppQrScanOptions): Promise<string | null>;
434
456
  onViewHide(callback: () => void): () => void;
435
457
  onViewRestore(callback: () => void): () => void;
436
458
  shareStory(mediaUrl: string, _options?: MiniAppShareStoryOptions): Promise<void>;
459
+ shareUrl(url: string, text?: string): void;
460
+ private shareUrlInternal;
437
461
  downloadFile(url: string, filename: string): Promise<void>;
438
462
  trackConversionEvent(event: string, payload?: Record<string, unknown>): void;
439
463
  trackPixelEvent(event: string, payload?: Record<string, unknown>): void;
@@ -461,9 +485,13 @@ declare class VKMiniAppAdapter extends BaseMiniAppAdapter {
461
485
  }
462
486
 
463
487
  declare class WebMiniAppAdapter extends BaseMiniAppAdapter {
488
+ private deferredPrompt;
464
489
  constructor();
465
490
  downloadFile(url: string, filename: string): Promise<void>;
466
491
  scanQRCode(_options?: MiniAppQrScanOptions): Promise<string | null>;
492
+ shareUrl(url: string, text: string): void;
493
+ addToHomeScreen(): Promise<boolean>;
494
+ checkHomeScreenStatus(): Promise<'added' | 'not_added' | 'unknown' | string>;
467
495
  }
468
496
 
469
497
  interface CreateAdapterOptions {
package/dist/index.js CHANGED
@@ -681,6 +681,25 @@ var BaseMiniAppAdapter = class {
681
681
  return null;
682
682
  }
683
683
  async requestNotificationsPermission() {
684
+ if (typeof Notification === "undefined" || typeof Notification.requestPermission !== "function") {
685
+ return false;
686
+ }
687
+ try {
688
+ const permission = await Notification.requestPermission();
689
+ return permission === "granted";
690
+ } catch (error) {
691
+ console.warn("[tvm-app-adapter] requestNotificationsPermission fallback failed:", error);
692
+ return false;
693
+ }
694
+ }
695
+ async addToHomeScreen() {
696
+ return false;
697
+ }
698
+ async checkHomeScreenStatus() {
699
+ return "unknown";
700
+ }
701
+ async denyNotifications() {
702
+ console.warn("[tvm-app-adapter] denyNotifications fallback is not supported in this environment.");
684
703
  return false;
685
704
  }
686
705
  enableVerticalSwipes() {
@@ -1010,7 +1029,11 @@ import {
1010
1029
  shareURL as shareURLSdk,
1011
1030
  copyTextToClipboard as copyTextToClipboardSdk,
1012
1031
  downloadFile as downloadFileSdk,
1013
- shareStory as shareStorySdk
1032
+ shareStory as shareStorySdk,
1033
+ addToHomeScreen as addToHomeScreenSdk,
1034
+ checkHomeScreenStatus as checkHomeScreenStatusSdk,
1035
+ on,
1036
+ off
1014
1037
  } from "@tma.js/sdk";
1015
1038
 
1016
1039
  // src/lib/features.ts
@@ -1433,6 +1456,50 @@ var TelegramMiniAppAdapter = class extends BaseMiniAppAdapter {
1433
1456
  async shareStory(mediaUrl, options) {
1434
1457
  shareStorySdk(mediaUrl, options);
1435
1458
  }
1459
+ async addToHomeScreen() {
1460
+ const isAvailable = typeof addToHomeScreenSdk?.isAvailable === "function" ? addToHomeScreenSdk.isAvailable() : true;
1461
+ if (!isAvailable) {
1462
+ return super.addToHomeScreen();
1463
+ }
1464
+ return new Promise((resolve) => {
1465
+ const cleanup = () => {
1466
+ off("home_screen_added", handleSuccess);
1467
+ off("home_screen_failed", handleFail);
1468
+ };
1469
+ const handleSuccess = () => {
1470
+ cleanup();
1471
+ resolve(true);
1472
+ };
1473
+ const handleFail = () => {
1474
+ cleanup();
1475
+ resolve(false);
1476
+ };
1477
+ on("home_screen_added", handleSuccess);
1478
+ on("home_screen_failed", handleFail);
1479
+ try {
1480
+ addToHomeScreenSdk();
1481
+ } catch (error) {
1482
+ cleanup();
1483
+ console.warn("[tvm-app-adapter] Telegram addToHomeScreen failed:", error);
1484
+ resolve(false);
1485
+ }
1486
+ });
1487
+ }
1488
+ async checkHomeScreenStatus() {
1489
+ try {
1490
+ const status = await checkHomeScreenStatusSdk();
1491
+ if (typeof status === "string") {
1492
+ return status;
1493
+ }
1494
+ if (typeof status === "boolean") {
1495
+ return status ? "added" : "not_added";
1496
+ }
1497
+ return "unknown";
1498
+ } catch (error) {
1499
+ console.warn("[tvm-app-adapter] Telegram checkHomeScreenStatus failed:", error);
1500
+ return "unknown";
1501
+ }
1502
+ }
1436
1503
  async requestPhone() {
1437
1504
  const contactFeature = ensureFeature(requestContact);
1438
1505
  if (!contactFeature.ok) {
@@ -1774,6 +1841,39 @@ var VKMiniAppAdapter = class extends BaseMiniAppAdapter {
1774
1841
  return false;
1775
1842
  }
1776
1843
  }
1844
+ async addToHomeScreen() {
1845
+ const supported = await this.supportsBridgeMethod("VKWebAppAddToHomeScreen");
1846
+ if (!supported) {
1847
+ console.warn("[tvm-app-adapter] VK addToHomeScreen not supported");
1848
+ return super.addToHomeScreen();
1849
+ }
1850
+ try {
1851
+ const response = await bridge.send("VKWebAppAddToHomeScreen");
1852
+ if (response && typeof response === "object" && "result" in response) {
1853
+ return Boolean(response.result);
1854
+ }
1855
+ return true;
1856
+ } catch (error) {
1857
+ console.warn("[tvm-app-adapter] VK addToHomeScreen failed:", error);
1858
+ return false;
1859
+ }
1860
+ }
1861
+ async denyNotifications() {
1862
+ const supported = await this.supportsBridgeMethod("VKWebAppDenyNotifications");
1863
+ if (!supported) {
1864
+ return super.denyNotifications();
1865
+ }
1866
+ try {
1867
+ const response = await bridge.send("VKWebAppDenyNotifications");
1868
+ if (response && typeof response === "object" && "result" in response) {
1869
+ return Boolean(response.result);
1870
+ }
1871
+ return true;
1872
+ } catch (error) {
1873
+ console.warn("[tvm-app-adapter] VK deny notifications failed:", error);
1874
+ return false;
1875
+ }
1876
+ }
1777
1877
  async scanQRCode(options) {
1778
1878
  const supportsQrScanner = await this.supportsBridgeMethod("VKWebAppOpenCodeReader");
1779
1879
  if (!supportsQrScanner) {
@@ -1809,6 +1909,25 @@ var VKMiniAppAdapter = class extends BaseMiniAppAdapter {
1809
1909
  };
1810
1910
  await bridge.send("VKWebAppShowStoryBox", bridgeOptions);
1811
1911
  }
1912
+ shareUrl(url, text) {
1913
+ void this.shareUrlInternal(url, text);
1914
+ }
1915
+ async shareUrlInternal(url, text) {
1916
+ const supported = await this.supportsBridgeMethod("VKWebAppShare");
1917
+ if (!supported) {
1918
+ super.shareUrl(url, text ?? "");
1919
+ return;
1920
+ }
1921
+ try {
1922
+ await bridge.send("VKWebAppShare", {
1923
+ link: url,
1924
+ ...text ? { text } : {}
1925
+ });
1926
+ } catch (error) {
1927
+ console.warn("[tvm-app-adapter] VK shareUrl failed:", error);
1928
+ super.shareUrl(url, text ?? "");
1929
+ }
1930
+ }
1812
1931
  async downloadFile(url, filename) {
1813
1932
  const supported = await this.supportsBridgeMethod("VKWebAppDownloadFile");
1814
1933
  if (!supported) {
@@ -2167,6 +2286,13 @@ var WebMiniAppAdapter = class extends BaseMiniAppAdapter {
2167
2286
  languageCode: navigator.language,
2168
2287
  isWebView: false
2169
2288
  });
2289
+ __publicField(this, "deferredPrompt", null);
2290
+ if (typeof window !== "undefined") {
2291
+ window.addEventListener("beforeinstallprompt", (event) => {
2292
+ event.preventDefault();
2293
+ this.deferredPrompt = event;
2294
+ });
2295
+ }
2170
2296
  }
2171
2297
  async downloadFile(url, filename) {
2172
2298
  try {
@@ -2315,6 +2441,49 @@ var WebMiniAppAdapter = class extends BaseMiniAppAdapter {
2315
2441
  }
2316
2442
  });
2317
2443
  }
2444
+ shareUrl(url, text) {
2445
+ if (navigator.share) {
2446
+ try {
2447
+ navigator.share({ title: text, text, url });
2448
+ return;
2449
+ } catch (err) {
2450
+ console.warn("Share cancelled or failed:", err);
2451
+ }
2452
+ }
2453
+ const payload = text ? `${text}
2454
+ ${url}` : url;
2455
+ this.copyTextToClipboard(payload).catch((err) => {
2456
+ console.warn("Share fallback (clipboard) failed:", err);
2457
+ });
2458
+ }
2459
+ async addToHomeScreen() {
2460
+ const isAndroid = /android/i.test(navigator.userAgent);
2461
+ if (!isAndroid || !this.deferredPrompt) {
2462
+ return super.addToHomeScreen();
2463
+ }
2464
+ try {
2465
+ this.deferredPrompt.prompt();
2466
+ const choice = await this.deferredPrompt.userChoice;
2467
+ this.deferredPrompt = null;
2468
+ return choice?.outcome === "accepted";
2469
+ } catch (error) {
2470
+ console.warn("[tvm-app-adapter] Web addToHomeScreen failed:", error);
2471
+ this.deferredPrompt = null;
2472
+ return false;
2473
+ }
2474
+ }
2475
+ async checkHomeScreenStatus() {
2476
+ try {
2477
+ const isStandalone = typeof window !== "undefined" && window.matchMedia?.("(display-mode: standalone)").matches || // iOS Safari specific flag
2478
+ typeof navigator !== "undefined" && navigator.standalone === true;
2479
+ if (isStandalone) {
2480
+ return "added";
2481
+ }
2482
+ return "unknown";
2483
+ } catch {
2484
+ return "unknown";
2485
+ }
2486
+ }
2318
2487
  };
2319
2488
 
2320
2489
  // src/adapters/index.ts