@wowlabtech/mini-app-adapter 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.
@@ -0,0 +1,511 @@
1
+ import { ImpactHapticFeedbackStyle, NotificationHapticFeedbackType } from '@tma.js/bridge';
2
+ import { TapticVibrationPowerType, TapticNotificationType } from '@vkontakte/vk-bridge';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { ReactNode } from 'react';
5
+
6
+ type ShellPlatform = 'shell_ios' | 'shell_android';
7
+ interface ShellStoreTokenPayload {
8
+ token?: string;
9
+ [key: string]: unknown;
10
+ }
11
+ type PushListener = (token: string) => void;
12
+ type DeepLinkListener = (path: string) => void;
13
+ type VoidListener = () => void;
14
+ interface ShellAPI {
15
+ openNativeQR(): Promise<string>;
16
+ onPushToken(callback: PushListener): () => void;
17
+ onDeepLink(callback: DeepLinkListener): () => void;
18
+ onAppActive(callback: VoidListener): () => void;
19
+ onAppBackground(callback: VoidListener): () => void;
20
+ }
21
+ declare function isShell(platform: MiniAppPlatform): platform is ShellPlatform;
22
+ declare function isShellIOS(platform: MiniAppPlatform): platform is 'shell_ios';
23
+ declare function isShellAndroid(platform: MiniAppPlatform): platform is 'shell_android';
24
+ declare function readShellPlatform(): ShellPlatform | undefined;
25
+ type PlatformResolver = MiniAppPlatform | (() => MiniAppPlatform);
26
+ declare function createShellAPI(platform: PlatformResolver): ShellAPI;
27
+ declare const shell: ShellAPI;
28
+ declare function storeShellToken(payload?: ShellStoreTokenPayload): boolean;
29
+ declare function requestShellPushPermission(): boolean;
30
+
31
+ type MiniAppPlatform = 'telegram' | 'vk' | 'max' | 'web' | 'shell_ios' | 'shell_android';
32
+ interface MiniAppEnvironmentInfo {
33
+ platform: MiniAppPlatform;
34
+ sdkVersion?: string;
35
+ appVersion?: string;
36
+ languageCode?: string;
37
+ appearance?: string;
38
+ isWebView?: boolean;
39
+ hasNativeQR?: boolean;
40
+ hasPush?: boolean;
41
+ hasWidgets?: boolean;
42
+ safeArea?: {
43
+ top: number;
44
+ right: number;
45
+ bottom: number;
46
+ left: number;
47
+ };
48
+ }
49
+ interface MiniAppSafeAreaInsets {
50
+ top: number;
51
+ right: number;
52
+ bottom: number;
53
+ left: number;
54
+ }
55
+ interface MiniAppViewportInsets {
56
+ safeArea: MiniAppSafeAreaInsets;
57
+ contentSafeArea: MiniAppSafeAreaInsets;
58
+ }
59
+ interface MiniAppInitOptions {
60
+ /**
61
+ * Enables verbose logs for platforms that support it.
62
+ */
63
+ debug?: boolean;
64
+ /**
65
+ * Dynamically loads Eruda devtools if supported.
66
+ */
67
+ eruda?: boolean;
68
+ /**
69
+ * Allows adapters to mock vendor-specific quirks (e.g. Telegram macOS client).
70
+ */
71
+ mockForMacOS?: boolean;
72
+ }
73
+ interface MiniAppShareStoryOptions {
74
+ text?: string;
75
+ widgetLink?: {
76
+ url: string;
77
+ name?: string;
78
+ };
79
+ }
80
+ type MiniAppCapability = 'haptics' | 'popup' | 'qrScanner' | 'closeApp' | 'backButton' | 'backButtonVisibility' | 'bindCssVariables' | 'requestPhone' | 'notifications';
81
+ interface MiniAppPopupButton {
82
+ id: string;
83
+ text?: string;
84
+ type?: 'default' | 'ok' | 'destructive';
85
+ }
86
+ interface MiniAppPopupOptions {
87
+ title: string;
88
+ message: string;
89
+ buttons?: MiniAppPopupButton[];
90
+ }
91
+ interface MiniAppQrScanOptions {
92
+ /**
93
+ * Closes scanner right after the QR code was captured. Defaults to true.
94
+ */
95
+ closeOnCapture?: boolean;
96
+ }
97
+ interface MiniAppAdapter {
98
+ readonly platform: MiniAppPlatform;
99
+ readonly shell: ShellAPI;
100
+ /**
101
+ * Quick capability check before calling platform specific APIs.
102
+ */
103
+ supports(capability: MiniAppCapability): boolean | Promise<boolean>;
104
+ /**
105
+ * Initializes platform SDK. Safe to call multiple times.
106
+ */
107
+ init(options?: MiniAppInitOptions): Promise<void>;
108
+ /**
109
+ * Indicates whether init step finished successfully.
110
+ */
111
+ isReady(): boolean;
112
+ /**
113
+ * Reads environment specific data exposed by the host Mini App platform.
114
+ */
115
+ getEnvironment(): MiniAppEnvironmentInfo;
116
+ /**
117
+ * Tears down adapter listeners/resources when it is no longer used.
118
+ */
119
+ destroy?(): void;
120
+ /**
121
+ * Applies navigation / background colors if supported by the host platform.
122
+ */
123
+ setColors(colors: {
124
+ header?: string;
125
+ background?: string;
126
+ footer?: string;
127
+ }): Promise<void>;
128
+ /**
129
+ * Registers a callback for platform back button.
130
+ * Returns disposer that removes the listener.
131
+ */
132
+ onBackButton(callback: () => void): () => void;
133
+ /**
134
+ * Opens external link using platform capabilities.
135
+ */
136
+ openExternalLink(url: string): Promise<void>;
137
+ /**
138
+ * Opens internal link using platform capabilities.
139
+ */
140
+ openInternalLink(url: string): Promise<void>;
141
+ /**
142
+ * Closes the host mini app if supported.
143
+ */
144
+ closeApp(): Promise<void>;
145
+ /**
146
+ * Updates visibility of the native back button if supported.
147
+ */
148
+ setBackButtonVisibility(visible: boolean): void;
149
+ /**
150
+ * Optional hook allowing adapters to expose debug helpers.
151
+ */
152
+ enableDebug?(state: boolean): void;
153
+ /**
154
+ * Subscribes to appearance changes if supported by the platform.
155
+ */
156
+ onAppearanceChange?(callback: (appearance: 'dark' | 'light' | undefined) => void): () => void;
157
+ /**
158
+ * Provides raw init data string, if available.
159
+ */
160
+ getInitData?(): string | undefined;
161
+ /**
162
+ * Reads platform launch parameters, if available.
163
+ */
164
+ getLaunchParams?(): unknown;
165
+ /**
166
+ * Decodes platform specific start parameter.
167
+ */
168
+ decodeStartParam?(param: string): unknown;
169
+ /**
170
+ * Requests fullscreen mode if supported by the platform.
171
+ */
172
+ requestFullscreen?(): void;
173
+ /**
174
+ * Returns viewport safe area insets if supported by the platform.
175
+ */
176
+ getViewportInsets?(): MiniAppViewportInsets | undefined;
177
+ /**
178
+ * Aggregates all known safe area insets into a single value.
179
+ */
180
+ computeSafeArea(): MiniAppEnvironmentInfo['safeArea'];
181
+ /**
182
+ * Binds platform theme variables to CSS custom properties.
183
+ */
184
+ bindCssVariables(mapper?: (key: string) => string): void;
185
+ /**
186
+ * Strong/weak haptic feedback helpers.
187
+ */
188
+ vibrateImpact(style: ImpactHapticFeedbackStyle): void;
189
+ vibrateNotification(type: NotificationHapticFeedbackType): void;
190
+ vibrateSelection(): void;
191
+ /**
192
+ * Notifies when the host view goes to background/foreground (VK only).
193
+ */
194
+ onViewHide?(callback: () => void): () => void;
195
+ onViewRestore?(callback: () => void): () => void;
196
+ /**
197
+ * Enables or disables vertical swipe gestures if supported by the platform.
198
+ */
199
+ enableVerticalSwipes?(): void;
200
+ disableVerticalSwipes?(): void;
201
+ /**
202
+ * Displays native popup if available.
203
+ * Resolves with button id or null if popup was dismissed.
204
+ */
205
+ showPopup(options: MiniAppPopupOptions): Promise<string | null>;
206
+ /**
207
+ * Opens QR scanner and resolves with scanned value (if any).
208
+ */
209
+ scanQRCode(options?: MiniAppQrScanOptions): Promise<string | null>;
210
+ /**
211
+ * Requests phone number from the host platform if supported.
212
+ */
213
+ requestPhone(): Promise<string | null>;
214
+ /**
215
+ * Requests permission to send push notifications (platform-specific).
216
+ * Resolves with true if permission was granted.
217
+ */
218
+ requestNotificationsPermission?(): Promise<boolean>;
219
+ /**
220
+ * Subscribes to push token updates delivered by native shells.
221
+ */
222
+ onPushToken(listener: (token: string) => void): () => void;
223
+ /**
224
+ * Subscribes to native deep link events exposed by shell containers.
225
+ */
226
+ onDeepLink(listener: (path: string) => void): void;
227
+ /**
228
+ * Subscribes to adapter environment updates (safe area, appearance etc.).
229
+ */
230
+ subscribe?(listener: () => void): () => void;
231
+ /**
232
+ * Shares a message using platform-specific capabilities.
233
+ */
234
+ shareMessage?(message: string): Promise<void>;
235
+ /**
236
+ * Shares a URL using platform-specific capabilities.
237
+ */
238
+ shareUrl?(url: string, text: string): void;
239
+ /**
240
+ * Copies text to the clipboard if supported by the platform.
241
+ */
242
+ copyTextToClipboard?(text: string): Promise<void>;
243
+ /**
244
+ * Downloads a file using platform-specific capabilities.
245
+ */
246
+ downloadFile?(url: string, filename: string): Promise<void>;
247
+ /**
248
+ * Shares a story using platform-specific capabilities.
249
+ */
250
+ shareStory?(mediaUrl: string, options?: MiniAppShareStoryOptions): Promise<void>;
251
+ /**
252
+ * Sends analytics event to the host platform if supported.
253
+ */
254
+ trackConversionEvent(event: string, payload?: Record<string, unknown>): void;
255
+ /**
256
+ * Sends retargeting pixel event if supported.
257
+ */
258
+ trackPixelEvent(event: string, payload?: Record<string, unknown>): void;
259
+ }
260
+
261
+ type Disposable = (() => void) | {
262
+ dispose: () => void;
263
+ } | null | undefined;
264
+
265
+ declare abstract class BaseMiniAppAdapter implements MiniAppAdapter {
266
+ protected ready: boolean;
267
+ protected environment: MiniAppEnvironmentInfo;
268
+ private listeners;
269
+ private readonly disposables;
270
+ readonly shell: ShellAPI;
271
+ protected constructor(platform: MiniAppPlatform, environment?: Partial<MiniAppEnvironmentInfo>);
272
+ supports(_capability: MiniAppCapability): boolean | Promise<boolean>;
273
+ get platform(): MiniAppPlatform;
274
+ init(_options?: MiniAppInitOptions): Promise<void>;
275
+ isReady(): boolean;
276
+ getEnvironment(): MiniAppEnvironmentInfo;
277
+ destroy(): void;
278
+ subscribe(listener: () => void): () => void;
279
+ setColors(colors: {
280
+ header?: string;
281
+ background?: string;
282
+ }): Promise<void>;
283
+ onBackButton(callback: () => void): () => void;
284
+ onPushToken(callback: (token: string) => void): () => void;
285
+ onDeepLink(callback: (path: string) => void): () => void;
286
+ openExternalLink(url: string): Promise<void>;
287
+ openInternalLink(_url: string): Promise<void>;
288
+ closeApp(): Promise<void>;
289
+ setBackButtonVisibility(_visible: boolean): void;
290
+ onAppearanceChange(callback: (appearance: 'dark' | 'light' | undefined) => void): () => void;
291
+ getInitData(): string | undefined;
292
+ getLaunchParams(): unknown;
293
+ decodeStartParam(_param: string): unknown;
294
+ requestFullscreen(): void;
295
+ getViewportInsets(): MiniAppViewportInsets | undefined;
296
+ shareMessage(_message: string): Promise<void>;
297
+ shareUrl(_url: string, _text: string): void;
298
+ downloadFile(url: string, filename: string): Promise<void>;
299
+ shareStory(_mediaUrl: string, _options?: MiniAppShareStoryOptions): Promise<void>;
300
+ trackConversionEvent(_event: string, _payload?: Record<string, unknown>): void;
301
+ trackPixelEvent(_event: string, _payload?: Record<string, unknown>): void;
302
+ copyTextToClipboard(text: string): Promise<void>;
303
+ computeSafeArea(): MiniAppEnvironmentInfo['safeArea'];
304
+ bindCssVariables(_mapper?: (key: string) => string): void;
305
+ vibrateImpact(_style: ImpactHapticFeedbackStyle): void;
306
+ vibrateNotification(_type: NotificationHapticFeedbackType): void;
307
+ vibrateSelection(): void;
308
+ onViewHide(_callback: () => void): () => void;
309
+ onViewRestore(_callback: () => void): () => void;
310
+ showPopup(options: MiniAppPopupOptions): Promise<string | null>;
311
+ scanQRCode(_options?: MiniAppQrScanOptions): Promise<string | null>;
312
+ requestPhone(): Promise<string | null>;
313
+ requestNotificationsPermission(): Promise<boolean>;
314
+ enableVerticalSwipes(): void;
315
+ disableVerticalSwipes(): void;
316
+ protected notifyEnvironmentChanged(): void;
317
+ protected onDestroy(): void;
318
+ protected registerDisposable(disposable: Disposable): () => void;
319
+ private applyScrollGuards;
320
+ }
321
+
322
+ declare class MaxMiniAppAdapter extends BaseMiniAppAdapter {
323
+ private readonly backHandlers;
324
+ private initData?;
325
+ private initDataUnsafe?;
326
+ constructor();
327
+ init(_options?: MiniAppInitOptions): Promise<void>;
328
+ supports(capability: MiniAppCapability): boolean;
329
+ getInitData(): string | undefined;
330
+ getLaunchParams(): unknown;
331
+ onBackButton(callback: () => void): () => void;
332
+ setBackButtonVisibility(visible: boolean): void;
333
+ openExternalLink(url: string): Promise<void>;
334
+ closeApp(): Promise<void>;
335
+ vibrateImpact(style: ImpactHapticFeedbackStyle): void;
336
+ vibrateNotification(type: NotificationHapticFeedbackType): void;
337
+ vibrateSelection(): void;
338
+ scanQRCode(options?: MiniAppQrScanOptions): Promise<string | null>;
339
+ requestPhone(): Promise<string | null>;
340
+ showPopup(options: MiniAppPopupOptions): Promise<string | null>;
341
+ downloadFile(url: string, filename: string): Promise<void>;
342
+ private requestPhoneViaEvent;
343
+ private extractPhone;
344
+ protected onDestroy(): void;
345
+ }
346
+
347
+ declare class ShellMiniAppAdapter extends BaseMiniAppAdapter {
348
+ constructor(platform: 'shell_ios' | 'shell_android');
349
+ supports(capability: MiniAppCapability): boolean | Promise<boolean>;
350
+ scanQRCode(): Promise<string | null>;
351
+ requestNotificationsPermission(): Promise<boolean>;
352
+ }
353
+
354
+ declare class TelegramMiniAppAdapter extends BaseMiniAppAdapter {
355
+ private readonly backHandlers;
356
+ private cssVariablesBound;
357
+ private readonly appearanceListeners;
358
+ private appearanceWatcherDispose?;
359
+ private readonly viewHideListeners;
360
+ private readonly viewRestoreListeners;
361
+ private activeWatcherDispose?;
362
+ constructor();
363
+ init(options?: MiniAppInitOptions): Promise<void>;
364
+ setColors(colors: {
365
+ header?: string;
366
+ background?: string;
367
+ footer?: string;
368
+ }): Promise<void>;
369
+ copyTextToClipboard(text: string): Promise<void>;
370
+ onBackButton(callback: () => void): () => void;
371
+ openExternalLink(url: string): Promise<void>;
372
+ openInternalLink(url: string): Promise<void>;
373
+ enableDebug(state: boolean): void;
374
+ supports(capability: MiniAppCapability): boolean;
375
+ bindCssVariables(mapper?: (key: string) => string): void;
376
+ vibrateImpact(style: ImpactHapticFeedbackStyle): void;
377
+ vibrateNotification(type: NotificationHapticFeedbackType): void;
378
+ vibrateSelection(): void;
379
+ showPopup(options: MiniAppPopupOptions): Promise<string | null>;
380
+ scanQRCode(options?: MiniAppQrScanOptions): Promise<string | null>;
381
+ closeApp(): Promise<void>;
382
+ getInitData(): string | undefined;
383
+ getLaunchParams(): unknown;
384
+ decodeStartParam(param: string): unknown;
385
+ requestFullscreen(): void;
386
+ getViewportInsets(): MiniAppViewportInsets | undefined;
387
+ onAppearanceChange(callback: (appearance: 'dark' | 'light' | undefined) => void): () => void;
388
+ setBackButtonVisibility(visible: boolean): void;
389
+ enableVerticalSwipes(): void;
390
+ disableVerticalSwipes(): void;
391
+ onViewHide(callback: () => void): () => void;
392
+ onViewRestore(callback: () => void): () => void;
393
+ shareUrl(url: string, text?: string): void;
394
+ downloadFile(url: string, filename: string): Promise<void>;
395
+ shareStory(mediaUrl: string, options?: MiniAppShareStoryOptions): Promise<void>;
396
+ requestPhone(): Promise<string | null>;
397
+ private setupAppearanceWatcher;
398
+ private notifyAppearance;
399
+ private setupActiveWatcher;
400
+ private prepareViewport;
401
+ private requestFullscreenInternal;
402
+ private getViewportMountOptions;
403
+ private notifyViewHide;
404
+ private notifyViewRestore;
405
+ protected onDestroy(): void;
406
+ }
407
+
408
+ declare class VKMiniAppAdapter extends BaseMiniAppAdapter {
409
+ private configSafeArea?;
410
+ private stopViewportTracking?;
411
+ private readonly supportsAsync?;
412
+ private pixelCodeWarningShown;
413
+ computeSafeArea(): MiniAppEnvironmentInfo['safeArea'];
414
+ private unsubscribe?;
415
+ private launchParams?;
416
+ private queryParams?;
417
+ private readonly viewHideListeners;
418
+ private readonly viewRestoreListeners;
419
+ constructor();
420
+ init(_options?: MiniAppInitOptions): Promise<void>;
421
+ vibrateImpact(style: TapticVibrationPowerType): Promise<void>;
422
+ vibrateNotification(type: TapticNotificationType): Promise<void>;
423
+ vibrateSelection(): Promise<void>;
424
+ setColors(colors: {
425
+ header?: string;
426
+ background?: string;
427
+ }): Promise<void>;
428
+ getEnvironment(): MiniAppEnvironmentInfo;
429
+ getLaunchParams(): unknown;
430
+ supports(capability: MiniAppCapability): Promise<boolean>;
431
+ requestPhone(): Promise<string | null>;
432
+ requestNotificationsPermission(): Promise<boolean>;
433
+ scanQRCode(options?: MiniAppQrScanOptions): Promise<string | null>;
434
+ onViewHide(callback: () => void): () => void;
435
+ onViewRestore(callback: () => void): () => void;
436
+ shareStory(mediaUrl: string, _options?: MiniAppShareStoryOptions): Promise<void>;
437
+ downloadFile(url: string, filename: string): Promise<void>;
438
+ trackConversionEvent(event: string, payload?: Record<string, unknown>): void;
439
+ trackPixelEvent(event: string, payload?: Record<string, unknown>): void;
440
+ private dispatchAnalytics;
441
+ private emitAnalyticsFallback;
442
+ private normalizeAnalyticsEventName;
443
+ private normalizeAnalyticsPayload;
444
+ private isPlainObject;
445
+ private safeBridgeSend;
446
+ private composeEnvironment;
447
+ private handleBridgeEvent;
448
+ private updateEnvironmentFromConfig;
449
+ private applyAppearance;
450
+ private resolveStatusBarStyle;
451
+ private normalizeAppearance;
452
+ private extractSafeAreaFromConfig;
453
+ private notifyVisibilityListeners;
454
+ private computeBaseSafeArea;
455
+ private startViewportTracking;
456
+ private resolveOverlayInsets;
457
+ private isLikelyMobilePlatform;
458
+ private resolveLaunchParam;
459
+ private supportsBridgeMethod;
460
+ protected onDestroy(): void;
461
+ }
462
+
463
+ declare class WebMiniAppAdapter extends BaseMiniAppAdapter {
464
+ constructor();
465
+ downloadFile(url: string, filename: string): Promise<void>;
466
+ scanQRCode(_options?: MiniAppQrScanOptions): Promise<string | null>;
467
+ }
468
+
469
+ interface CreateAdapterOptions {
470
+ platform?: MiniAppPlatform;
471
+ vk?: {
472
+ pixelCode?: string;
473
+ };
474
+ }
475
+ declare function detectPlatform(): MiniAppPlatform;
476
+ declare function createAdapter(): MiniAppAdapter;
477
+ declare function createAdapter(platform: MiniAppPlatform): MiniAppAdapter;
478
+ declare function createAdapter(options: CreateAdapterOptions): MiniAppAdapter;
479
+
480
+ interface AdapterProviderProps {
481
+ adapter: MiniAppAdapter;
482
+ children: ReactNode;
483
+ }
484
+ declare function AdapterProvider({ adapter, children }: AdapterProviderProps): react_jsx_runtime.JSX.Element;
485
+ declare function useMiniAppAdapter(): MiniAppAdapter;
486
+
487
+ type ThemePreference = 'system' | 'light' | 'dark';
488
+ declare function useAdapterTheme(): {
489
+ readonly isDark: boolean;
490
+ readonly appearance: "dark" | "light";
491
+ readonly preference: ThemePreference;
492
+ readonly setPreference: (pref: ThemePreference) => void;
493
+ readonly toggle: () => void;
494
+ };
495
+
496
+ declare function useSafeArea(): {
497
+ top: number;
498
+ right: number;
499
+ bottom: number;
500
+ left: number;
501
+ };
502
+
503
+ declare function getActiveAdapter(): MiniAppAdapter | null;
504
+
505
+ declare function configureVkPixel(pixelCode: string): void;
506
+ declare function trackConversionEvent(event: string, payload?: Record<string, unknown>): void;
507
+ declare function trackPixelEvent(event: string, payload?: Record<string, unknown>): void;
508
+
509
+ declare function getPlatform(): MiniAppPlatform;
510
+
511
+ export { AdapterProvider, BaseMiniAppAdapter, type CreateAdapterOptions, MaxMiniAppAdapter, type MiniAppAdapter, type MiniAppCapability, type MiniAppEnvironmentInfo, type MiniAppInitOptions, type MiniAppPlatform, type MiniAppPopupOptions, type MiniAppQrScanOptions, ShellMiniAppAdapter, TelegramMiniAppAdapter, VKMiniAppAdapter, WebMiniAppAdapter, configureVkPixel, createAdapter, createShellAPI, detectPlatform, getActiveAdapter, getPlatform, isShell, isShellAndroid, isShellIOS, readShellPlatform, requestShellPushPermission, shell, storeShellToken, trackConversionEvent, trackPixelEvent, useAdapterTheme, useMiniAppAdapter, useSafeArea };