nativine 1.0.2

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,1954 @@
1
+ /**
2
+ * Nativine Platform Detection
3
+ *
4
+ * Detects whether the web page is running inside a Nativine-powered native app
5
+ * and identifies the platform (Android, iOS, or Web).
6
+ */
7
+ /**
8
+ * Detects the current platform by checking for native bridge objects
9
+ * injected by the Nativine native shell.
10
+ */
11
+ function detectPlatform() {
12
+ if (typeof window === 'undefined')
13
+ return 'web';
14
+ // Android: The Kotlin WebView injects `window.nativine` via addJavascriptInterface
15
+ if (window.nativine && typeof window.nativine.vibrate === 'function') {
16
+ return 'android';
17
+ }
18
+ // Android fallback: check for NativineAndroid bridge
19
+ if (window.NativineAndroid && typeof window.NativineAndroid.postMessage === 'function') {
20
+ return 'android';
21
+ }
22
+ // iOS: WebKit message handlers are injected via WKScriptMessageHandler
23
+ if (window.webkit &&
24
+ window.webkit.messageHandlers &&
25
+ window.webkit.messageHandlers.nativine) {
26
+ return 'ios';
27
+ }
28
+ return 'web';
29
+ }
30
+ /** The detected platform: `'android'`, `'ios'`, or `'web'` */
31
+ const platform = detectPlatform();
32
+ /** `true` if the page is running inside a Nativine native app (Android or iOS) */
33
+ const isNativeApp = platform !== 'web';
34
+ /** `true` if the page is running inside a Nativine Android app */
35
+ const isAndroid = platform === 'android';
36
+ /** `true` if the page is running inside a Nativine iOS app */
37
+ const isIos = platform === 'ios';
38
+
39
+ /**
40
+ * Nativine Bridge Dispatcher
41
+ *
42
+ * Low-level bridge call mechanism that provides a unified, Promise-based interface
43
+ * for communicating with the native Android/iOS app shell.
44
+ *
45
+ * Architecture:
46
+ * - Android: Calls `window.nativine.<method>(args, callbackId)` via @JavascriptInterface
47
+ * - iOS: Calls `window.webkit.messageHandlers.nativine.postMessage({ method, args, callbackId })`
48
+ * - Web: Returns rejected promises or no-ops gracefully
49
+ *
50
+ * The native side resolves the Promise by calling: `window[callbackId](jsonResult)`
51
+ */
52
+ /** Counter for generating unique callback IDs */
53
+ let _callbackCounter = 0;
54
+ /** Default timeout for bridge calls (10 seconds) */
55
+ const DEFAULT_TIMEOUT_MS = 10000;
56
+ /**
57
+ * Error thrown when a bridge method is called outside a native app context.
58
+ */
59
+ class NativineNotAvailableError extends Error {
60
+ constructor(method) {
61
+ super(`nativine.${method}() is not available — page is not running inside a Nativine app.`);
62
+ this.name = 'NativineNotAvailableError';
63
+ }
64
+ }
65
+ /**
66
+ * Error thrown when a bridge call times out waiting for native response.
67
+ */
68
+ class NativineTimeoutError extends Error {
69
+ constructor(method, timeoutMs) {
70
+ super(`nativine.${method}() timed out after ${timeoutMs}ms waiting for native response.`);
71
+ this.name = 'NativineTimeoutError';
72
+ }
73
+ }
74
+ /**
75
+ * Makes an async call to the native bridge and returns a Promise that resolves
76
+ * when the native side responds via the callback.
77
+ *
78
+ * @param method - The native method name to call (e.g., 'getDeviceInfo')
79
+ * @param args - Optional arguments to pass to the native method (serialized as JSON string)
80
+ * @param timeoutMs - Timeout in milliseconds (default: 10s)
81
+ * @returns Promise that resolves with the parsed native response
82
+ */
83
+ function callNativeAsync(method, args, timeoutMs = DEFAULT_TIMEOUT_MS) {
84
+ return new Promise((resolve, reject) => {
85
+ if (!isNativeApp) {
86
+ reject(new NativineNotAvailableError(method));
87
+ return;
88
+ }
89
+ const callbackId = `__nativine_cb_${++_callbackCounter}_${Date.now()}`;
90
+ let settled = false;
91
+ // Timeout guard
92
+ const timer = setTimeout(() => {
93
+ if (!settled) {
94
+ settled = true;
95
+ cleanup();
96
+ reject(new NativineTimeoutError(method, timeoutMs));
97
+ }
98
+ }, timeoutMs);
99
+ const cleanup = () => {
100
+ delete window[callbackId];
101
+ delete window[`${callbackId}_error`];
102
+ clearTimeout(timer);
103
+ };
104
+ // Register success callback
105
+ window[callbackId] = (result) => {
106
+ if (settled)
107
+ return;
108
+ settled = true;
109
+ cleanup();
110
+ try {
111
+ const parsed = typeof result === 'string' ? JSON.parse(result) : result;
112
+ resolve(parsed);
113
+ }
114
+ catch (_a) {
115
+ // If it's not JSON, return raw string
116
+ resolve(result);
117
+ }
118
+ };
119
+ // Register error callback
120
+ window[`${callbackId}_error`] = (error) => {
121
+ if (settled)
122
+ return;
123
+ settled = true;
124
+ cleanup();
125
+ reject(new Error(error || `Native method '${method}' failed`));
126
+ };
127
+ // Dispatch the call to the appropriate native bridge
128
+ try {
129
+ const argsString = args ? JSON.stringify(args) : '';
130
+ if (isAndroid) {
131
+ const bridge = window.nativine;
132
+ if (bridge && typeof bridge[method] === 'function') {
133
+ bridge[method](argsString, callbackId);
134
+ }
135
+ else {
136
+ // Fallback: use NativineAndroid.postMessage for methods handled there
137
+ const androidBridge = window.NativineAndroid;
138
+ if (androidBridge && typeof androidBridge.postMessage === 'function') {
139
+ androidBridge.postMessage(JSON.stringify({
140
+ action: method,
141
+ payload: args || {},
142
+ callbackId,
143
+ }));
144
+ }
145
+ else {
146
+ settled = true;
147
+ cleanup();
148
+ reject(new Error(`Native method '${method}' not found on bridge`));
149
+ }
150
+ }
151
+ }
152
+ else if (isIos) {
153
+ window.webkit.messageHandlers.nativine.postMessage({
154
+ method,
155
+ args: args || {},
156
+ callbackId,
157
+ });
158
+ }
159
+ }
160
+ catch (e) {
161
+ if (!settled) {
162
+ settled = true;
163
+ cleanup();
164
+ reject(e);
165
+ }
166
+ }
167
+ });
168
+ }
169
+ /**
170
+ * Makes a synchronous (fire-and-forget) call to the native bridge.
171
+ * Used for methods that don't need a return value (e.g., vibrate, statusBar).
172
+ *
173
+ * @param method - The native method name to call
174
+ * @param args - Optional arguments
175
+ */
176
+ function callNativeSync(method, args) {
177
+ if (!isNativeApp)
178
+ return; // Silent no-op on web
179
+ try {
180
+ const argsString = args ? JSON.stringify(args) : '';
181
+ if (isAndroid) {
182
+ const bridge = window.nativine;
183
+ if (bridge && typeof bridge[method] === 'function') {
184
+ bridge[method](argsString);
185
+ }
186
+ else {
187
+ // Fallback: postMessage for actions handled in the message handler
188
+ const androidBridge = window.NativineAndroid;
189
+ if (androidBridge && typeof androidBridge.postMessage === 'function') {
190
+ androidBridge.postMessage(JSON.stringify({
191
+ action: method,
192
+ payload: args || {},
193
+ }));
194
+ }
195
+ }
196
+ }
197
+ else if (isIos) {
198
+ window.webkit.messageHandlers.nativine.postMessage({
199
+ method,
200
+ args: args || {},
201
+ });
202
+ }
203
+ }
204
+ catch (e) {
205
+ // Silent fail on web or if bridge is unavailable
206
+ if (typeof console !== 'undefined') {
207
+ console.warn(`[nativine] Failed to call native method '${method}':`, e);
208
+ }
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Device Module
214
+ *
215
+ * Access device hardware/software information, safe area insets,
216
+ * app version, and anonymous device identifiers.
217
+ */
218
+ /**
219
+ * Get comprehensive device information.
220
+ *
221
+ * @example
222
+ * ```js
223
+ * const info = await nativine.device.getInfo();
224
+ * console.log(info.model); // "Pixel 8"
225
+ * console.log(info.appVersion); // "1.2.0"
226
+ * ```
227
+ */
228
+ async function getInfo() {
229
+ if (!isNativeApp) {
230
+ return {
231
+ model: navigator.userAgent,
232
+ manufacturer: 'unknown',
233
+ osVersion: 'unknown',
234
+ appVersion: '0.0.0',
235
+ appVersionCode: 0,
236
+ packageName: 'web',
237
+ locale: navigator.language || 'en',
238
+ screenWidth: window.innerWidth,
239
+ screenHeight: window.innerHeight,
240
+ density: window.devicePixelRatio || 1,
241
+ platform,
242
+ };
243
+ }
244
+ return callNativeAsync('getDeviceInfo');
245
+ }
246
+ /**
247
+ * Get the current safe area insets.
248
+ * Useful for positioning UI elements to avoid notches and system bars.
249
+ *
250
+ * @example
251
+ * ```js
252
+ * const insets = await nativine.device.getSafeAreaInsets();
253
+ * element.style.paddingTop = `${insets.top}px`;
254
+ * ```
255
+ */
256
+ async function getSafeAreaInsets() {
257
+ if (!isNativeApp) {
258
+ return { top: 0, bottom: 0, left: 0, right: 0 };
259
+ }
260
+ return callNativeAsync('getSafeAreaInsets');
261
+ }
262
+ /**
263
+ * Get the app's version name string (e.g., "1.2.0").
264
+ *
265
+ * @example
266
+ * ```js
267
+ * const version = await nativine.device.getAppVersion();
268
+ * // "1.2.0"
269
+ * ```
270
+ */
271
+ async function getAppVersion() {
272
+ if (!isNativeApp)
273
+ return '0.0.0';
274
+ const info = await callNativeAsync('getDeviceInfo');
275
+ return info.appVersion;
276
+ }
277
+ /**
278
+ * Get an anonymous, persistent device identifier.
279
+ * This ID is unique per app installation (not a hardware ID).
280
+ * Resets when the app is reinstalled.
281
+ *
282
+ * @example
283
+ * ```js
284
+ * const id = await nativine.device.getDeviceId();
285
+ * // "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
286
+ * ```
287
+ */
288
+ async function getDeviceId() {
289
+ if (!isNativeApp)
290
+ return 'web-' + Math.random().toString(36).slice(2);
291
+ return callNativeAsync('getDeviceId');
292
+ }
293
+
294
+ var device = /*#__PURE__*/Object.freeze({
295
+ __proto__: null,
296
+ getAppVersion: getAppVersion,
297
+ getDeviceId: getDeviceId,
298
+ getInfo: getInfo,
299
+ getSafeAreaInsets: getSafeAreaInsets
300
+ });
301
+
302
+ /**
303
+ * UI Module
304
+ *
305
+ * Control native UI elements: status bar, navigation bar, splash screen,
306
+ * screen orientation, and native component visibility.
307
+ */
308
+ /**
309
+ * Configure the native status bar appearance.
310
+ *
311
+ * @example
312
+ * ```js
313
+ * nativine.ui.statusBar({ color: '#1a1a2e', style: 'light' });
314
+ * ```
315
+ */
316
+ function statusBar(options) {
317
+ callNativeSync('setStatusBar', options);
318
+ }
319
+ /**
320
+ * Configure the native navigation bar appearance (Android only).
321
+ *
322
+ * @example
323
+ * ```js
324
+ * nativine.ui.navigationBar({ color: '#16213e' });
325
+ * ```
326
+ */
327
+ function navigationBar(options) {
328
+ callNativeSync('setNavigationBar', options);
329
+ }
330
+ /**
331
+ * Programmatically hide the splash screen.
332
+ * Useful when your web app needs time to load data before revealing the UI.
333
+ *
334
+ * @example
335
+ * ```js
336
+ * await fetchInitialData();
337
+ * nativine.ui.hideSplashScreen();
338
+ * ```
339
+ */
340
+ function hideSplashScreen() {
341
+ callNativeSync('hideSplashScreen');
342
+ }
343
+ /**
344
+ * Lock the screen to a specific orientation.
345
+ *
346
+ * @param mode - 'portrait' | 'landscape' | 'auto'
347
+ *
348
+ * @example
349
+ * ```js
350
+ * // Lock to landscape for a video player
351
+ * nativine.ui.setOrientation('landscape');
352
+ *
353
+ * // Unlock when done
354
+ * nativine.ui.setOrientation('auto');
355
+ * ```
356
+ */
357
+ function setOrientation(mode) {
358
+ callNativeSync('setOrientation', { mode });
359
+ }
360
+ /**
361
+ * Show native UI components (header, bottom nav, floating button).
362
+ * Reverses the effect of `hideNativeComponents()`.
363
+ *
364
+ * @example
365
+ * ```js
366
+ * nativine.ui.showNativeComponents();
367
+ * ```
368
+ */
369
+ function showNativeComponents() {
370
+ callNativeSync('showNativeComponents');
371
+ }
372
+ /**
373
+ * Hide all native UI components (header, bottom nav, floating button).
374
+ * Useful for fullscreen content like videos or immersive experiences.
375
+ *
376
+ * @example
377
+ * ```js
378
+ * // Enter fullscreen mode
379
+ * nativine.ui.hideNativeComponents();
380
+ * ```
381
+ */
382
+ function hideNativeComponents() {
383
+ callNativeSync('hideNativeComponents');
384
+ }
385
+ /**
386
+ * Toggle pull-to-refresh behavior.
387
+ *
388
+ * @param enabled - Whether pull-to-refresh should be enabled
389
+ *
390
+ * @example
391
+ * ```js
392
+ * // Disable on a page with custom scroll behavior
393
+ * nativine.ui.setPullToRefresh(false);
394
+ * ```
395
+ */
396
+ function setPullToRefresh(enabled) {
397
+ callNativeSync('setPullToRefresh', { enabled });
398
+ }
399
+ /**
400
+ * Toggle pinch-to-zoom behavior.
401
+ *
402
+ * @param enabled - Whether pinch-to-zoom should be enabled
403
+ *
404
+ * @example
405
+ * ```js
406
+ * // Enable for an image gallery
407
+ * nativine.ui.setPinchToZoom(true);
408
+ * ```
409
+ */
410
+ function setPinchToZoom(enabled) {
411
+ callNativeSync('setPinchToZoom', { enabled });
412
+ }
413
+
414
+ var ui = /*#__PURE__*/Object.freeze({
415
+ __proto__: null,
416
+ hideNativeComponents: hideNativeComponents,
417
+ hideSplashScreen: hideSplashScreen,
418
+ navigationBar: navigationBar,
419
+ setOrientation: setOrientation,
420
+ setPinchToZoom: setPinchToZoom,
421
+ setPullToRefresh: setPullToRefresh,
422
+ showNativeComponents: showNativeComponents,
423
+ statusBar: statusBar
424
+ });
425
+
426
+ /**
427
+ * Navigation Module
428
+ *
429
+ * Control in-app navigation: go back, go forward, navigate to URLs,
430
+ * open external browser, and close the app.
431
+ */
432
+ /**
433
+ * Navigate the WebView back one page in history.
434
+ * No-op if there's no back history.
435
+ *
436
+ * @example
437
+ * ```js
438
+ * nativine.navigation.goBack();
439
+ * ```
440
+ */
441
+ function goBack() {
442
+ if (!isNativeApp) {
443
+ window.history.back();
444
+ return;
445
+ }
446
+ callNativeSync('goBack');
447
+ }
448
+ /**
449
+ * Navigate the WebView forward one page in history.
450
+ * No-op if there's no forward history.
451
+ *
452
+ * @example
453
+ * ```js
454
+ * nativine.navigation.goForward();
455
+ * ```
456
+ */
457
+ function goForward() {
458
+ if (!isNativeApp) {
459
+ window.history.forward();
460
+ return;
461
+ }
462
+ callNativeSync('goForward');
463
+ }
464
+ /**
465
+ * Navigate the WebView to a specific URL.
466
+ * Supports both absolute URLs and relative paths.
467
+ *
468
+ * @param url - The URL or path to navigate to
469
+ *
470
+ * @example
471
+ * ```js
472
+ * nativine.navigation.navigate('/products');
473
+ * nativine.navigation.navigate('https://example.com/page');
474
+ * ```
475
+ */
476
+ function navigate(url) {
477
+ if (!isNativeApp) {
478
+ window.location.href = url;
479
+ return;
480
+ }
481
+ callNativeSync('navigate', { url });
482
+ }
483
+ /**
484
+ * Open a URL in the device's default external browser.
485
+ * The user leaves the app temporarily.
486
+ *
487
+ * @param url - The URL to open externally
488
+ *
489
+ * @example
490
+ * ```js
491
+ * nativine.navigation.openInBrowser('https://docs.nativine.com');
492
+ * ```
493
+ */
494
+ function openInBrowser(url) {
495
+ if (!isNativeApp) {
496
+ window.open(url, '_blank');
497
+ return;
498
+ }
499
+ callNativeSync('openInBrowser', { url });
500
+ }
501
+ /**
502
+ * Close the app. On Android, this finishes the Activity.
503
+ *
504
+ * @example
505
+ * ```js
506
+ * nativine.navigation.closeApp();
507
+ * ```
508
+ */
509
+ function closeApp() {
510
+ callNativeSync('closeApp');
511
+ }
512
+
513
+ var navigation = /*#__PURE__*/Object.freeze({
514
+ __proto__: null,
515
+ closeApp: closeApp,
516
+ goBack: goBack,
517
+ goForward: goForward,
518
+ navigate: navigate,
519
+ openInBrowser: openInBrowser
520
+ });
521
+
522
+ /**
523
+ * Haptics Module
524
+ *
525
+ * Trigger device vibrations and haptic feedback patterns.
526
+ */
527
+ /**
528
+ * Vibrate the device for a specified duration.
529
+ *
530
+ * @param durationMs - Duration in milliseconds (default: 100ms)
531
+ *
532
+ * @example
533
+ * ```js
534
+ * nativine.haptics.vibrate(200);
535
+ * ```
536
+ */
537
+ function vibrate(durationMs = 100) {
538
+ if (!isNativeApp) {
539
+ // Web Vibration API fallback
540
+ if (typeof navigator !== 'undefined' && navigator.vibrate) {
541
+ navigator.vibrate(durationMs);
542
+ }
543
+ return;
544
+ }
545
+ callNativeSync('vibrate', { duration: durationMs });
546
+ }
547
+ /**
548
+ * Trigger a predefined haptic feedback pattern.
549
+ *
550
+ * @param type - The type of haptic feedback
551
+ *
552
+ * Feedback types:
553
+ * - `'light'` — Subtle tap (e.g., toggle switch)
554
+ * - `'medium'` — Standard tap (e.g., button press)
555
+ * - `'heavy'` — Strong tap (e.g., action confirmation)
556
+ * - `'success'` — Success pattern (double tap)
557
+ * - `'error'` — Error pattern (triple tap)
558
+ * - `'warning'` — Warning pattern
559
+ * - `'selection'` — Selection change (lightest)
560
+ *
561
+ * @example
562
+ * ```js
563
+ * // On button click
564
+ * nativine.haptics.feedback('medium');
565
+ *
566
+ * // On form validation error
567
+ * nativine.haptics.feedback('error');
568
+ *
569
+ * // On successful payment
570
+ * nativine.haptics.feedback('success');
571
+ * ```
572
+ */
573
+ function feedback(type = 'medium') {
574
+ if (!isNativeApp) {
575
+ // Web fallback: simple vibration pattern
576
+ if (typeof navigator !== 'undefined' && navigator.vibrate) {
577
+ const patterns = {
578
+ light: 10,
579
+ medium: 30,
580
+ heavy: 50,
581
+ success: [30, 50, 30],
582
+ error: [30, 30, 30, 30, 30],
583
+ warning: [30, 50, 50],
584
+ selection: 5,
585
+ };
586
+ navigator.vibrate(patterns[type] || 30);
587
+ }
588
+ return;
589
+ }
590
+ callNativeSync('hapticFeedback', { type });
591
+ }
592
+
593
+ var haptics = /*#__PURE__*/Object.freeze({
594
+ __proto__: null,
595
+ feedback: feedback,
596
+ vibrate: vibrate
597
+ });
598
+
599
+ /**
600
+ * Storage Module
601
+ *
602
+ * Persistent key-value storage that survives WebView cache clears.
603
+ * Data is stored in Android SharedPreferences / iOS UserDefaults,
604
+ * not in the WebView's localStorage.
605
+ */
606
+ /**
607
+ * Store a value persistently in native storage.
608
+ * This data persists even when the WebView cache is cleared.
609
+ *
610
+ * @param key - The storage key
611
+ * @param value - The value to store (will be serialized to string)
612
+ *
613
+ * @example
614
+ * ```js
615
+ * await nativine.storage.set('auth_token', 'abc123');
616
+ * await nativine.storage.set('user', JSON.stringify({ name: 'John' }));
617
+ * ```
618
+ */
619
+ function set(key, value) {
620
+ if (!isNativeApp) {
621
+ try {
622
+ localStorage.setItem(`nativine_${key}`, value);
623
+ }
624
+ catch (e) { /* quota exceeded */ }
625
+ return;
626
+ }
627
+ if (isAndroid) {
628
+ // Direct call — AppJsBridge.setLocalData() is synchronous
629
+ const bridge = window.nativine;
630
+ if (bridge && typeof bridge.setLocalData === 'function') {
631
+ bridge.setLocalData(key, value);
632
+ return;
633
+ }
634
+ }
635
+ callNativeSync('setLocalData', { key, value });
636
+ }
637
+ /**
638
+ * Retrieve a value from native persistent storage.
639
+ *
640
+ * @param key - The storage key
641
+ * @param defaultValue - Value to return if key doesn't exist (default: '')
642
+ * @returns The stored value, or defaultValue if not found
643
+ *
644
+ * @example
645
+ * ```js
646
+ * const token = nativine.storage.get('auth_token');
647
+ * const user = JSON.parse(nativine.storage.get('user', '{}'));
648
+ * ```
649
+ */
650
+ function get(key, defaultValue = '') {
651
+ if (!isNativeApp) {
652
+ try {
653
+ return localStorage.getItem(`nativine_${key}`) || defaultValue;
654
+ }
655
+ catch (_a) {
656
+ return defaultValue;
657
+ }
658
+ }
659
+ if (isAndroid) {
660
+ // Direct synchronous return via @JavascriptInterface
661
+ const bridge = window.nativine;
662
+ if (bridge && typeof bridge.getLocalData === 'function') {
663
+ return bridge.getLocalData(key, defaultValue);
664
+ }
665
+ }
666
+ return defaultValue;
667
+ }
668
+ /**
669
+ * Remove a specific key from native persistent storage.
670
+ *
671
+ * @param key - The storage key to remove
672
+ *
673
+ * @example
674
+ * ```js
675
+ * nativine.storage.remove('auth_token');
676
+ * ```
677
+ */
678
+ function remove(key) {
679
+ if (!isNativeApp) {
680
+ try {
681
+ localStorage.removeItem(`nativine_${key}`);
682
+ }
683
+ catch ( /* ignore */_a) { /* ignore */ }
684
+ return;
685
+ }
686
+ if (isAndroid) {
687
+ const bridge = window.nativine;
688
+ if (bridge && typeof bridge.removeLocalData === 'function') {
689
+ bridge.removeLocalData(key);
690
+ return;
691
+ }
692
+ }
693
+ callNativeSync('removeLocalData', { key });
694
+ }
695
+ /**
696
+ * Clear all data from native persistent storage.
697
+ *
698
+ * @example
699
+ * ```js
700
+ * // On logout
701
+ * nativine.storage.clear();
702
+ * ```
703
+ */
704
+ function clear$1() {
705
+ if (!isNativeApp) {
706
+ try {
707
+ const keys = Object.keys(localStorage).filter(k => k.startsWith('nativine_'));
708
+ keys.forEach(k => localStorage.removeItem(k));
709
+ }
710
+ catch ( /* ignore */_a) { /* ignore */ }
711
+ return;
712
+ }
713
+ if (isAndroid) {
714
+ const bridge = window.nativine;
715
+ if (bridge && typeof bridge.clearLocalData === 'function') {
716
+ bridge.clearLocalData();
717
+ return;
718
+ }
719
+ }
720
+ callNativeSync('clearLocalData');
721
+ }
722
+
723
+ var storage = /*#__PURE__*/Object.freeze({
724
+ __proto__: null,
725
+ clear: clear$1,
726
+ get: get,
727
+ remove: remove,
728
+ set: set
729
+ });
730
+
731
+ /**
732
+ * Share Module
733
+ *
734
+ * Trigger the native share sheet to share text, URLs, and files.
735
+ */
736
+ /**
737
+ * Open the native share sheet with the specified content.
738
+ *
739
+ * @example
740
+ * ```js
741
+ * nativine.share.share({
742
+ * title: 'Check this out',
743
+ * text: 'Amazing app!',
744
+ * url: 'https://example.com'
745
+ * });
746
+ * ```
747
+ */
748
+ function share(options) {
749
+ if (!isNativeApp) {
750
+ // Web Share API fallback
751
+ if (typeof navigator !== 'undefined' && navigator.share) {
752
+ navigator.share(options).catch(() => { });
753
+ }
754
+ return;
755
+ }
756
+ callNativeSync('share', options);
757
+ }
758
+ /**
759
+ * Share a file using the native share sheet.
760
+ *
761
+ * @example
762
+ * ```js
763
+ * nativine.share.shareFile({
764
+ * filePath: '/storage/emulated/0/Download/report.pdf',
765
+ * mimeType: 'application/pdf'
766
+ * });
767
+ * ```
768
+ */
769
+ function shareFile(options) {
770
+ callNativeSync('shareFile', options);
771
+ }
772
+
773
+ /**
774
+ * Auth Module
775
+ *
776
+ * Native Google Sign-In integration. Triggers the native Google Sign-In flow
777
+ * and returns user credentials to your web app.
778
+ */
779
+ /**
780
+ * Trigger the native Google Sign-In flow.
781
+ * Returns user credentials when the user completes sign-in.
782
+ *
783
+ * @returns Promise resolving with Google user credentials
784
+ *
785
+ * @example
786
+ * ```js
787
+ * try {
788
+ * const user = await nativine.auth.googleSignIn();
789
+ * console.log(user.email); // "john@gmail.com"
790
+ * console.log(user.idToken); // Send to your backend for verification
791
+ * } catch (err) {
792
+ * console.log('Sign-in cancelled or failed');
793
+ * }
794
+ * ```
795
+ */
796
+ async function googleSignIn() {
797
+ if (!isNativeApp) {
798
+ throw new Error('nativine.auth.googleSignIn() is only available inside a Nativine app.');
799
+ }
800
+ return callNativeAsync('googleSignIn');
801
+ }
802
+ /**
803
+ * Sign out of the current Google account.
804
+ *
805
+ * @example
806
+ * ```js
807
+ * await nativine.auth.googleSignOut();
808
+ * ```
809
+ */
810
+ function googleSignOut() {
811
+ if (!isNativeApp)
812
+ return;
813
+ if (isAndroid) {
814
+ const bridge = window.NativineAndroid;
815
+ if (bridge && typeof bridge.postMessage === 'function') {
816
+ bridge.postMessage(JSON.stringify({ action: 'google_signout' }));
817
+ return;
818
+ }
819
+ }
820
+ callNativeSync('googleSignOut');
821
+ }
822
+
823
+ var auth = /*#__PURE__*/Object.freeze({
824
+ __proto__: null,
825
+ googleSignIn: googleSignIn,
826
+ googleSignOut: googleSignOut
827
+ });
828
+
829
+ /**
830
+ * Biometrics Module
831
+ *
832
+ * Trigger native biometric authentication (fingerprint, face recognition, iris scan).
833
+ */
834
+ /**
835
+ * Check if biometric authentication is available on this device.
836
+ *
837
+ * @returns Promise resolving with availability info
838
+ *
839
+ * @example
840
+ * ```js
841
+ * const { available, biometryType } = await nativine.biometrics.isAvailable();
842
+ * if (available) {
843
+ * console.log(`Biometric type: ${biometryType}`); // "fingerprint"
844
+ * }
845
+ * ```
846
+ */
847
+ async function isAvailable$1() {
848
+ if (!isNativeApp) {
849
+ return { available: false, biometryType: 'none' };
850
+ }
851
+ return callNativeAsync('isBiometricAvailable');
852
+ }
853
+ /**
854
+ * Trigger biometric authentication.
855
+ *
856
+ * @param options - Configuration for the authentication prompt
857
+ * @returns Promise resolving with the authentication result
858
+ *
859
+ * @example
860
+ * ```js
861
+ * const result = await nativine.biometrics.authenticate({
862
+ * reason: 'Verify your identity to access settings',
863
+ * allowFallback: true
864
+ * });
865
+ *
866
+ * if (result.success) {
867
+ * // User authenticated
868
+ * showSensitiveContent();
869
+ * }
870
+ * ```
871
+ */
872
+ async function authenticate(options = {}) {
873
+ if (!isNativeApp) {
874
+ throw new Error('nativine.biometrics.authenticate() is only available inside a Nativine app.');
875
+ }
876
+ return callNativeAsync('authenticateBiometric', options);
877
+ }
878
+
879
+ var biometrics = /*#__PURE__*/Object.freeze({
880
+ __proto__: null,
881
+ authenticate: authenticate,
882
+ isAvailable: isAvailable$1
883
+ });
884
+
885
+ /**
886
+ * Contacts Module
887
+ *
888
+ * Access the device's native contact list (requires user permission).
889
+ */
890
+ /**
891
+ * Retrieve the user's contacts from the native contact book.
892
+ * Prompts for permission if not already granted.
893
+ *
894
+ * @returns Promise resolving with an array of contacts
895
+ *
896
+ * @example
897
+ * ```js
898
+ * const contacts = await nativine.contacts.getAll();
899
+ * contacts.forEach(c => {
900
+ * console.log(`${c.name}: ${c.phone}`);
901
+ * });
902
+ * ```
903
+ */
904
+ async function getAll() {
905
+ if (!isNativeApp) {
906
+ // Web Contacts API fallback (if available)
907
+ if ('contacts' in navigator && 'ContactsManager' in window) {
908
+ try {
909
+ const props = ['name', 'tel', 'email'];
910
+ const contacts = await navigator.contacts.select(props, { multiple: true });
911
+ return contacts.map((c) => {
912
+ var _a, _b, _c;
913
+ return ({
914
+ name: ((_a = c.name) === null || _a === void 0 ? void 0 : _a[0]) || '',
915
+ phone: ((_b = c.tel) === null || _b === void 0 ? void 0 : _b[0]) || '',
916
+ email: ((_c = c.email) === null || _c === void 0 ? void 0 : _c[0]) || '',
917
+ });
918
+ });
919
+ }
920
+ catch (_a) {
921
+ return [];
922
+ }
923
+ }
924
+ return [];
925
+ }
926
+ return callNativeAsync('getContacts');
927
+ }
928
+
929
+ var contacts = /*#__PURE__*/Object.freeze({
930
+ __proto__: null,
931
+ getAll: getAll
932
+ });
933
+
934
+ /**
935
+ * Clipboard Module
936
+ *
937
+ * Read from and write to the device clipboard.
938
+ */
939
+ /**
940
+ * Copy text to the device clipboard.
941
+ *
942
+ * @param text - The text to copy
943
+ *
944
+ * @example
945
+ * ```js
946
+ * await nativine.clipboard.copy('https://example.com/share/abc123');
947
+ * ```
948
+ */
949
+ async function copy(text) {
950
+ if (!isNativeApp) {
951
+ // Web Clipboard API fallback
952
+ if (navigator.clipboard && navigator.clipboard.writeText) {
953
+ await navigator.clipboard.writeText(text);
954
+ }
955
+ else {
956
+ // Legacy fallback
957
+ const textarea = document.createElement('textarea');
958
+ textarea.value = text;
959
+ textarea.style.position = 'fixed';
960
+ textarea.style.opacity = '0';
961
+ document.body.appendChild(textarea);
962
+ textarea.select();
963
+ document.execCommand('copy');
964
+ document.body.removeChild(textarea);
965
+ }
966
+ return;
967
+ }
968
+ callNativeSync('copyToClipboard', { text });
969
+ }
970
+ /**
971
+ * Read text from the device clipboard.
972
+ *
973
+ * @returns Promise resolving with the clipboard text content
974
+ *
975
+ * @example
976
+ * ```js
977
+ * const text = await nativine.clipboard.read();
978
+ * console.log('Clipboard:', text);
979
+ * ```
980
+ */
981
+ async function read() {
982
+ if (!isNativeApp) {
983
+ // Web Clipboard API fallback
984
+ if (navigator.clipboard && navigator.clipboard.readText) {
985
+ return navigator.clipboard.readText();
986
+ }
987
+ return '';
988
+ }
989
+ return callNativeAsync('readClipboard');
990
+ }
991
+
992
+ var clipboard = /*#__PURE__*/Object.freeze({
993
+ __proto__: null,
994
+ copy: copy,
995
+ read: read
996
+ });
997
+
998
+ /**
999
+ * Downloads Module
1000
+ *
1001
+ * Trigger native file downloads using the device's download manager.
1002
+ */
1003
+ /**
1004
+ * Download a file using the native download manager.
1005
+ * Shows a notification with download progress on Android.
1006
+ *
1007
+ * @param options - Download configuration
1008
+ *
1009
+ * @example
1010
+ * ```js
1011
+ * nativine.downloads.downloadFile({
1012
+ * url: 'https://example.com/report.pdf',
1013
+ * filename: 'monthly-report.pdf',
1014
+ * openAfterDownload: true
1015
+ * });
1016
+ * ```
1017
+ */
1018
+ function downloadFile(options) {
1019
+ if (!isNativeApp) {
1020
+ // Web fallback: trigger download via anchor tag
1021
+ const a = document.createElement('a');
1022
+ a.href = options.url;
1023
+ a.download = options.filename || '';
1024
+ a.target = '_blank';
1025
+ document.body.appendChild(a);
1026
+ a.click();
1027
+ document.body.removeChild(a);
1028
+ return;
1029
+ }
1030
+ callNativeSync('downloadFile', options);
1031
+ }
1032
+
1033
+ var downloads = /*#__PURE__*/Object.freeze({
1034
+ __proto__: null,
1035
+ downloadFile: downloadFile
1036
+ });
1037
+
1038
+ /**
1039
+ * Camera / Scanner Module
1040
+ *
1041
+ * Access the device camera for barcode and QR code scanning.
1042
+ */
1043
+ /**
1044
+ * Open the native barcode/QR code scanner.
1045
+ *
1046
+ * @param options - Scanner configuration
1047
+ * @returns Promise resolving with the scanned code data
1048
+ *
1049
+ * @example
1050
+ * ```js
1051
+ * try {
1052
+ * const result = await nativine.scanner.scan();
1053
+ * console.log(result.value); // "https://example.com"
1054
+ * console.log(result.format); // "QR_CODE"
1055
+ * } catch (err) {
1056
+ * console.log('Scan cancelled');
1057
+ * }
1058
+ * ```
1059
+ */
1060
+ async function scan(options = {}) {
1061
+ if (!isNativeApp) {
1062
+ throw new Error('nativine.scanner.scan() is only available inside a Nativine app.');
1063
+ }
1064
+ return callNativeAsync('scanBarcode', options);
1065
+ }
1066
+
1067
+ var camera = /*#__PURE__*/Object.freeze({
1068
+ __proto__: null,
1069
+ scan: scan
1070
+ });
1071
+
1072
+ /**
1073
+ * Location Module
1074
+ *
1075
+ * Access the device's GPS location.
1076
+ */
1077
+ /**
1078
+ * Get the device's current GPS location.
1079
+ * Prompts for location permission if not already granted.
1080
+ *
1081
+ * @returns Promise resolving with location coordinates
1082
+ *
1083
+ * @example
1084
+ * ```js
1085
+ * const loc = await nativine.location.getCurrent();
1086
+ * console.log(`Lat: ${loc.latitude}, Lng: ${loc.longitude}`);
1087
+ * console.log(`Accuracy: ${loc.accuracy}m`);
1088
+ * ```
1089
+ */
1090
+ async function getCurrent() {
1091
+ if (!isNativeApp) {
1092
+ // Web Geolocation API fallback
1093
+ return new Promise((resolve, reject) => {
1094
+ if (!navigator.geolocation) {
1095
+ reject(new Error('Geolocation not supported in this browser'));
1096
+ return;
1097
+ }
1098
+ navigator.geolocation.getCurrentPosition((pos) => resolve({
1099
+ latitude: pos.coords.latitude,
1100
+ longitude: pos.coords.longitude,
1101
+ accuracy: pos.coords.accuracy,
1102
+ altitude: pos.coords.altitude || undefined,
1103
+ speed: pos.coords.speed || undefined,
1104
+ }), (err) => reject(new Error(err.message)), { enableHighAccuracy: true, timeout: 15000, maximumAge: 0 });
1105
+ });
1106
+ }
1107
+ return callNativeAsync('getCurrentLocation');
1108
+ }
1109
+
1110
+ var location = /*#__PURE__*/Object.freeze({
1111
+ __proto__: null,
1112
+ getCurrent: getCurrent
1113
+ });
1114
+
1115
+ /**
1116
+ * Network Module
1117
+ *
1118
+ * Check connectivity status and listen for network changes.
1119
+ */
1120
+ const _listeners = [];
1121
+ /**
1122
+ * Check if the device currently has network connectivity.
1123
+ *
1124
+ * @returns Promise resolving with connectivity status
1125
+ *
1126
+ * @example
1127
+ * ```js
1128
+ * const status = await nativine.network.isOnline();
1129
+ * if (!status.online) {
1130
+ * showOfflineBanner();
1131
+ * }
1132
+ * ```
1133
+ */
1134
+ async function isOnline() {
1135
+ if (!isNativeApp) {
1136
+ return {
1137
+ online: typeof navigator !== 'undefined' ? navigator.onLine : true,
1138
+ type: 'unknown',
1139
+ };
1140
+ }
1141
+ return callNativeAsync('getConnectivityStatus');
1142
+ }
1143
+ /**
1144
+ * Listen for network connectivity changes.
1145
+ *
1146
+ * @param callback - Function called when connectivity changes
1147
+ * @returns Unsubscribe function to stop listening
1148
+ *
1149
+ * @example
1150
+ * ```js
1151
+ * const unsubscribe = nativine.network.onConnectivityChange((status) => {
1152
+ * if (!status.online) {
1153
+ * showOfflineBanner();
1154
+ * } else {
1155
+ * hideOfflineBanner();
1156
+ * }
1157
+ * });
1158
+ *
1159
+ * // Later: stop listening
1160
+ * unsubscribe();
1161
+ * ```
1162
+ */
1163
+ function onConnectivityChange(callback) {
1164
+ _listeners.push(callback);
1165
+ // Set up web fallback listener
1166
+ if (!isNativeApp) {
1167
+ const onlineHandler = () => callback({ online: true, type: 'unknown' });
1168
+ const offlineHandler = () => callback({ online: false, type: 'none' });
1169
+ window.addEventListener('online', onlineHandler);
1170
+ window.addEventListener('offline', offlineHandler);
1171
+ return () => {
1172
+ const idx = _listeners.indexOf(callback);
1173
+ if (idx !== -1)
1174
+ _listeners.splice(idx, 1);
1175
+ window.removeEventListener('online', onlineHandler);
1176
+ window.removeEventListener('offline', offlineHandler);
1177
+ };
1178
+ }
1179
+ // Register native listener
1180
+ callNativeSync('registerConnectivityListener');
1181
+ return () => {
1182
+ const idx = _listeners.indexOf(callback);
1183
+ if (idx !== -1)
1184
+ _listeners.splice(idx, 1);
1185
+ if (_listeners.length === 0) {
1186
+ callNativeSync('unregisterConnectivityListener');
1187
+ }
1188
+ };
1189
+ }
1190
+ /**
1191
+ * Internal: Called by the native side when connectivity changes.
1192
+ * Dispatches to all registered listeners.
1193
+ * @internal
1194
+ */
1195
+ function _onConnectivityChanged(status) {
1196
+ _listeners.forEach(cb => {
1197
+ try {
1198
+ cb(status);
1199
+ }
1200
+ catch (e) {
1201
+ console.error('[nativine] Connectivity listener error:', e);
1202
+ }
1203
+ });
1204
+ }
1205
+ // Register global handler for native callbacks
1206
+ if (typeof window !== 'undefined') {
1207
+ window.__nativine_onConnectivityChanged = (json) => {
1208
+ try {
1209
+ const status = typeof json === 'string' ? JSON.parse(json) : json;
1210
+ _onConnectivityChanged(status);
1211
+ }
1212
+ catch (e) { /* ignore */ }
1213
+ };
1214
+ }
1215
+
1216
+ var network = /*#__PURE__*/Object.freeze({
1217
+ __proto__: null,
1218
+ _onConnectivityChanged: _onConnectivityChanged,
1219
+ isOnline: isOnline,
1220
+ onConnectivityChange: onConnectivityChange
1221
+ });
1222
+
1223
+ /**
1224
+ * Cache Module
1225
+ *
1226
+ * Clear WebView cache and cookies.
1227
+ */
1228
+ /**
1229
+ * Clear the WebView cache (CSS, JS, images, etc.).
1230
+ * Shows a confirmation dialog to the user.
1231
+ *
1232
+ * @example
1233
+ * ```js
1234
+ * nativine.cache.clear();
1235
+ * ```
1236
+ */
1237
+ function clear() {
1238
+ if (!isNativeApp)
1239
+ return;
1240
+ callNativeSync('clear_cache');
1241
+ }
1242
+ /**
1243
+ * Clear all WebView cookies.
1244
+ * Useful for logout flows to ensure session data is wiped.
1245
+ *
1246
+ * @example
1247
+ * ```js
1248
+ * nativine.cache.clearCookies();
1249
+ * ```
1250
+ */
1251
+ function clearCookies() {
1252
+ if (!isNativeApp) {
1253
+ // Web fallback: clear cookies via document.cookie
1254
+ document.cookie.split(';').forEach(cookie => {
1255
+ const name = cookie.split('=')[0].trim();
1256
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
1257
+ });
1258
+ return;
1259
+ }
1260
+ callNativeSync('clearCookies');
1261
+ }
1262
+
1263
+ var cache = /*#__PURE__*/Object.freeze({
1264
+ __proto__: null,
1265
+ clear: clear,
1266
+ clearCookies: clearCookies
1267
+ });
1268
+
1269
+ /**
1270
+ * Print Module
1271
+ *
1272
+ * Trigger native print dialog for the current page.
1273
+ */
1274
+ /**
1275
+ * Open the native print dialog for the current WebView content.
1276
+ *
1277
+ * @example
1278
+ * ```js
1279
+ * nativine.print();
1280
+ * ```
1281
+ */
1282
+ function printPage() {
1283
+ if (!isNativeApp) {
1284
+ window.print();
1285
+ return;
1286
+ }
1287
+ callNativeSync('printPage');
1288
+ }
1289
+
1290
+ /**
1291
+ * Screenshot Module
1292
+ *
1293
+ * Control screenshot protection (prevent screenshots of sensitive screens).
1294
+ */
1295
+ /**
1296
+ * Enable or disable screenshot/screen recording protection.
1297
+ * When enabled, the app content appears black in screenshots and screen recordings.
1298
+ *
1299
+ * @param enabled - Whether to enable screenshot protection
1300
+ *
1301
+ * @example
1302
+ * ```js
1303
+ * // Protect a banking page
1304
+ * nativine.screenshot.setProtection(true);
1305
+ *
1306
+ * // Remove protection when leaving
1307
+ * nativine.screenshot.setProtection(false);
1308
+ * ```
1309
+ */
1310
+ function setProtection(enabled) {
1311
+ if (!isNativeApp)
1312
+ return;
1313
+ callNativeSync('setScreenshotProtection', { enabled });
1314
+ }
1315
+
1316
+ var screenshot = /*#__PURE__*/Object.freeze({
1317
+ __proto__: null,
1318
+ setProtection: setProtection
1319
+ });
1320
+
1321
+ /**
1322
+ * Reviews Module
1323
+ *
1324
+ * Trigger the native in-app review dialog (Google Play / App Store).
1325
+ */
1326
+ /**
1327
+ * Request an in-app review from the user.
1328
+ * Uses Google Play In-App Review API (Android) or StoreKit (iOS).
1329
+ *
1330
+ * Note: The system may not show the dialog if the user has already reviewed
1331
+ * or if the request is too frequent. This is controlled by the platform.
1332
+ *
1333
+ * @example
1334
+ * ```js
1335
+ * // After a positive user interaction
1336
+ * nativine.reviews.request();
1337
+ * ```
1338
+ */
1339
+ function request() {
1340
+ if (!isNativeApp)
1341
+ return;
1342
+ callNativeSync('requestAppReview');
1343
+ }
1344
+
1345
+ var reviews = /*#__PURE__*/Object.freeze({
1346
+ __proto__: null,
1347
+ request: request
1348
+ });
1349
+
1350
+ /**
1351
+ * Updates Module
1352
+ *
1353
+ * Check for and trigger in-app updates (Android only).
1354
+ */
1355
+ /**
1356
+ * Check for available app updates using the Android In-App Update API.
1357
+ * If an update is available, a native update UI will be shown.
1358
+ *
1359
+ * @example
1360
+ * ```js
1361
+ * nativine.updates.check();
1362
+ * ```
1363
+ */
1364
+ function check() {
1365
+ if (!isNativeApp)
1366
+ return;
1367
+ callNativeSync('checkForUpdates');
1368
+ }
1369
+
1370
+ var updates = /*#__PURE__*/Object.freeze({
1371
+ __proto__: null,
1372
+ check: check
1373
+ });
1374
+
1375
+ /**
1376
+ * Ads Module
1377
+ *
1378
+ * Control AdMob interstitial and rewarded ad display from your web app.
1379
+ */
1380
+ /**
1381
+ * Show a fullscreen interstitial ad.
1382
+ * The ad must be pre-loaded by the native app.
1383
+ *
1384
+ * @example
1385
+ * ```js
1386
+ * // Show an ad between content transitions
1387
+ * nativine.ads.showInterstitial();
1388
+ * ```
1389
+ */
1390
+ function showInterstitial() {
1391
+ if (!isNativeApp)
1392
+ return;
1393
+ callNativeSync('showInterstitialAd');
1394
+ }
1395
+ /**
1396
+ * Show a rewarded video ad.
1397
+ * Returns a Promise that resolves when the user finishes watching.
1398
+ *
1399
+ * @returns Promise resolving with the reward result
1400
+ *
1401
+ * @example
1402
+ * ```js
1403
+ * const result = await nativine.ads.showRewarded();
1404
+ * if (result.rewarded) {
1405
+ * // Grant premium access for 24 hours
1406
+ * unlockPremiumContent();
1407
+ * }
1408
+ * ```
1409
+ */
1410
+ async function showRewarded() {
1411
+ if (!isNativeApp) {
1412
+ return { rewarded: false };
1413
+ }
1414
+ return callNativeAsync('showRewardedAd');
1415
+ }
1416
+
1417
+ var ads = /*#__PURE__*/Object.freeze({
1418
+ __proto__: null,
1419
+ showInterstitial: showInterstitial,
1420
+ showRewarded: showRewarded
1421
+ });
1422
+
1423
+ /**
1424
+ * OneSignal Module
1425
+ *
1426
+ * Interact with OneSignal push notification service from your web app.
1427
+ * Requires the OneSignal addon to be enabled in your Nativine app.
1428
+ */
1429
+ /**
1430
+ * Set the OneSignal external user ID.
1431
+ * Links the device's push subscription to your backend user ID.
1432
+ *
1433
+ * @param userId - Your app's user identifier
1434
+ *
1435
+ * @example
1436
+ * ```js
1437
+ * // After user logs in
1438
+ * nativine.onesignal.setExternalUserId('user_12345');
1439
+ * ```
1440
+ */
1441
+ function setExternalUserId(userId) {
1442
+ if (!isNativeApp)
1443
+ return;
1444
+ callNativeSync('onesignalSetExternalUserId', { userId });
1445
+ }
1446
+ /**
1447
+ * Send a tag (key-value pair) to OneSignal for audience segmentation.
1448
+ *
1449
+ * @param key - Tag key
1450
+ * @param value - Tag value
1451
+ *
1452
+ * @example
1453
+ * ```js
1454
+ * nativine.onesignal.sendTag('plan', 'premium');
1455
+ * nativine.onesignal.sendTag('language', 'en');
1456
+ * ```
1457
+ */
1458
+ function sendTag(key, value) {
1459
+ if (!isNativeApp)
1460
+ return;
1461
+ callNativeSync('onesignalSendTag', { key, value });
1462
+ }
1463
+ /**
1464
+ * Send multiple tags at once to OneSignal.
1465
+ *
1466
+ * @param tags - Object with tag key-value pairs
1467
+ *
1468
+ * @example
1469
+ * ```js
1470
+ * nativine.onesignal.sendTags({
1471
+ * plan: 'premium',
1472
+ * language: 'en',
1473
+ * onboarded: 'true'
1474
+ * });
1475
+ * ```
1476
+ */
1477
+ function sendTags(tags) {
1478
+ if (!isNativeApp)
1479
+ return;
1480
+ callNativeSync('onesignalSendTags', { tags });
1481
+ }
1482
+ /**
1483
+ * Get the OneSignal Player ID (push subscription ID) for this device.
1484
+ *
1485
+ * @returns Promise resolving with the player ID string
1486
+ *
1487
+ * @example
1488
+ * ```js
1489
+ * const playerId = await nativine.onesignal.getPlayerId();
1490
+ * // Send to your backend for targeted push notifications
1491
+ * ```
1492
+ */
1493
+ async function getPlayerId() {
1494
+ if (!isNativeApp)
1495
+ return '';
1496
+ return callNativeAsync('onesignalGetPlayerId');
1497
+ }
1498
+ /**
1499
+ * Remove the external user ID association.
1500
+ * Call this when the user logs out.
1501
+ *
1502
+ * @example
1503
+ * ```js
1504
+ * // On logout
1505
+ * nativine.onesignal.removeExternalUserId();
1506
+ * ```
1507
+ */
1508
+ function removeExternalUserId() {
1509
+ if (!isNativeApp)
1510
+ return;
1511
+ callNativeSync('onesignalRemoveExternalUserId');
1512
+ }
1513
+
1514
+ var onesignal = /*#__PURE__*/Object.freeze({
1515
+ __proto__: null,
1516
+ getPlayerId: getPlayerId,
1517
+ removeExternalUserId: removeExternalUserId,
1518
+ sendTag: sendTag,
1519
+ sendTags: sendTags,
1520
+ setExternalUserId: setExternalUserId
1521
+ });
1522
+
1523
+ /**
1524
+ * Toast Module
1525
+ *
1526
+ * Show native Android toast messages.
1527
+ */
1528
+ /**
1529
+ * Show a native toast message.
1530
+ *
1531
+ * @param message - The text to display
1532
+ * @param duration - 'short' (~2s) or 'long' (~3.5s)
1533
+ *
1534
+ * @example
1535
+ * ```js
1536
+ * nativine.toast('Item added to cart!');
1537
+ * nativine.toast('Processing payment...', 'long');
1538
+ * ```
1539
+ */
1540
+ function showToast(message, duration = 'short') {
1541
+ if (!isNativeApp) {
1542
+ // Web fallback: show a temporary notification-style element
1543
+ const el = document.createElement('div');
1544
+ el.textContent = message;
1545
+ Object.assign(el.style, {
1546
+ position: 'fixed',
1547
+ bottom: '80px',
1548
+ left: '50%',
1549
+ transform: 'translateX(-50%)',
1550
+ background: 'rgba(0,0,0,0.8)',
1551
+ color: '#fff',
1552
+ padding: '10px 24px',
1553
+ borderRadius: '24px',
1554
+ fontSize: '14px',
1555
+ zIndex: '999999',
1556
+ pointerEvents: 'none',
1557
+ transition: 'opacity 0.3s ease',
1558
+ opacity: '0',
1559
+ fontFamily: '-apple-system, BlinkMacSystemFont, sans-serif',
1560
+ });
1561
+ document.body.appendChild(el);
1562
+ // Fade in
1563
+ requestAnimationFrame(() => { el.style.opacity = '1'; });
1564
+ // Remove after duration
1565
+ const ms = duration === 'long' ? 3500 : 2000;
1566
+ setTimeout(() => {
1567
+ el.style.opacity = '0';
1568
+ setTimeout(() => {
1569
+ if (el.parentNode)
1570
+ el.parentNode.removeChild(el);
1571
+ }, 300);
1572
+ }, ms);
1573
+ return;
1574
+ }
1575
+ callNativeSync('showToast', { message, duration });
1576
+ }
1577
+
1578
+ /**
1579
+ * Pedometer / Step Counter Module
1580
+ *
1581
+ * Access the device's built-in step counter sensor to track steps.
1582
+ * Uses Android's TYPE_STEP_COUNTER hardware sensor.
1583
+ * Requires ACTIVITY_RECOGNITION permission on Android 10+.
1584
+ */
1585
+ /**
1586
+ * Check if the device has a step counter sensor.
1587
+ *
1588
+ * @returns Promise resolving with availability info
1589
+ *
1590
+ * @example
1591
+ * ```js
1592
+ * const { available } = await nativine.pedometer.isAvailable();
1593
+ * if (available) {
1594
+ * nativine.pedometer.startTracking();
1595
+ * }
1596
+ * ```
1597
+ */
1598
+ async function isAvailable() {
1599
+ if (!isNativeApp) {
1600
+ return { available: false };
1601
+ }
1602
+ return callNativeAsync('isPedometerAvailable');
1603
+ }
1604
+ /**
1605
+ * Get the current step count since tracking started.
1606
+ * Returns 0 if tracking hasn't been started yet.
1607
+ *
1608
+ * @returns Promise resolving with the step count
1609
+ *
1610
+ * @example
1611
+ * ```js
1612
+ * const { steps } = await nativine.pedometer.getStepCount();
1613
+ * console.log(`You've taken ${steps} steps`);
1614
+ * ```
1615
+ */
1616
+ async function getStepCount() {
1617
+ if (!isNativeApp) {
1618
+ return { steps: 0 };
1619
+ }
1620
+ return callNativeAsync('getStepCount');
1621
+ }
1622
+ /**
1623
+ * Start tracking steps. The step count resets to 0 when tracking begins.
1624
+ * Step updates are dispatched as 'stepUpdate' events via `nativine.on()`.
1625
+ *
1626
+ * @example
1627
+ * ```js
1628
+ * nativine.pedometer.startTracking();
1629
+ *
1630
+ * // Listen for real-time step updates
1631
+ * nativine.on('stepUpdate', ({ steps }) => {
1632
+ * document.getElementById('step-count').textContent = steps;
1633
+ * });
1634
+ * ```
1635
+ */
1636
+ function startTracking() {
1637
+ if (!isNativeApp)
1638
+ return;
1639
+ callNativeSync('startStepTracking');
1640
+ }
1641
+ /**
1642
+ * Stop tracking steps. The sensor listener is unregistered to save battery.
1643
+ *
1644
+ * @example
1645
+ * ```js
1646
+ * nativine.pedometer.stopTracking();
1647
+ * ```
1648
+ */
1649
+ function stopTracking() {
1650
+ if (!isNativeApp)
1651
+ return;
1652
+ callNativeSync('stopStepTracking');
1653
+ }
1654
+
1655
+ var pedometer = /*#__PURE__*/Object.freeze({
1656
+ __proto__: null,
1657
+ getStepCount: getStepCount,
1658
+ isAvailable: isAvailable,
1659
+ startTracking: startTracking,
1660
+ stopTracking: stopTracking
1661
+ });
1662
+
1663
+ /**
1664
+ * Events Module
1665
+ *
1666
+ * Subscribe to native app lifecycle events.
1667
+ * The native side dispatches events by calling global handler functions.
1668
+ */
1669
+ const _eventListeners = new Map();
1670
+ /**
1671
+ * Subscribe to a native app lifecycle event.
1672
+ *
1673
+ * Available events:
1674
+ * - `'appResume'` — App returned to foreground
1675
+ * - `'appPause'` — App went to background
1676
+ * - `'pageReady'` — Bridge is fully initialized and ready
1677
+ * - `'keyboardShow'` — Software keyboard appeared (with height data)
1678
+ * - `'keyboardHide'` — Software keyboard dismissed
1679
+ *
1680
+ * @param event - The event name to listen for
1681
+ * @param callback - Function called when the event fires
1682
+ * @returns Unsubscribe function
1683
+ *
1684
+ * @example
1685
+ * ```js
1686
+ * // Refresh data when user returns to app
1687
+ * const unsubscribe = nativine.on('appResume', () => {
1688
+ * fetchLatestData();
1689
+ * });
1690
+ *
1691
+ * // Listen for keyboard visibility
1692
+ * nativine.on('keyboardShow', ({ height }) => {
1693
+ * adjustLayoutForKeyboard(height);
1694
+ * });
1695
+ *
1696
+ * // Cleanup
1697
+ * unsubscribe();
1698
+ * ```
1699
+ */
1700
+ function on(event, callback) {
1701
+ if (!_eventListeners.has(event)) {
1702
+ _eventListeners.set(event, []);
1703
+ }
1704
+ _eventListeners.get(event).push(callback);
1705
+ return () => {
1706
+ const listeners = _eventListeners.get(event);
1707
+ if (listeners) {
1708
+ const idx = listeners.indexOf(callback);
1709
+ if (idx !== -1)
1710
+ listeners.splice(idx, 1);
1711
+ }
1712
+ };
1713
+ }
1714
+ /**
1715
+ * Unsubscribe all listeners for a specific event, or all events.
1716
+ *
1717
+ * @param event - The event to clear listeners for (or omit to clear all)
1718
+ *
1719
+ * @example
1720
+ * ```js
1721
+ * // Remove all appResume listeners
1722
+ * nativine.off('appResume');
1723
+ *
1724
+ * // Remove ALL event listeners
1725
+ * nativine.off();
1726
+ * ```
1727
+ */
1728
+ function off(event) {
1729
+ if (event) {
1730
+ _eventListeners.delete(event);
1731
+ }
1732
+ else {
1733
+ _eventListeners.clear();
1734
+ }
1735
+ }
1736
+ /**
1737
+ * Internal: Dispatch an event to all registered listeners.
1738
+ * Called by the native side via global window functions.
1739
+ * @internal
1740
+ */
1741
+ function _dispatchEvent(event, data) {
1742
+ const listeners = _eventListeners.get(event);
1743
+ if (listeners) {
1744
+ listeners.forEach(cb => {
1745
+ try {
1746
+ cb(data);
1747
+ }
1748
+ catch (e) {
1749
+ console.error(`[nativine] Event '${event}' listener error:`, e);
1750
+ }
1751
+ });
1752
+ }
1753
+ }
1754
+ // Register global handlers for native-side event dispatching
1755
+ if (typeof window !== 'undefined') {
1756
+ window.__nativine_event = (eventName, jsonData) => {
1757
+ try {
1758
+ const data = jsonData ? (typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData) : undefined;
1759
+ _dispatchEvent(eventName, data);
1760
+ }
1761
+ catch (e) { /* ignore parse errors */ }
1762
+ };
1763
+ // Convenience aliases for common events
1764
+ window.__nativine_onAppResume = () => _dispatchEvent('appResume');
1765
+ window.__nativine_onAppPause = () => _dispatchEvent('appPause');
1766
+ window.__nativine_onKeyboardShow = (json) => {
1767
+ try {
1768
+ _dispatchEvent('keyboardShow', JSON.parse(json));
1769
+ }
1770
+ catch (_a) {
1771
+ _dispatchEvent('keyboardShow');
1772
+ }
1773
+ };
1774
+ window.__nativine_onKeyboardHide = () => _dispatchEvent('keyboardHide');
1775
+ // Fire 'pageReady' event after bridge initialization
1776
+ if (document.readyState === 'complete') {
1777
+ setTimeout(() => _dispatchEvent('pageReady'), 0);
1778
+ }
1779
+ else {
1780
+ window.addEventListener('load', () => {
1781
+ setTimeout(() => _dispatchEvent('pageReady'), 0);
1782
+ });
1783
+ }
1784
+ }
1785
+
1786
+ /**
1787
+ * Nativine JavaScript Bridge
1788
+ *
1789
+ * Enterprise-grade bridge for communicating between web apps and Nativine native shells.
1790
+ * Provides 50+ APIs across 12 namespaces with full TypeScript support, Promise-based
1791
+ * async methods, and graceful web fallbacks.
1792
+ *
1793
+ * @example ESM (recommended)
1794
+ * ```js
1795
+ * import nativine from 'nativine';
1796
+ *
1797
+ * if (nativine.isNativeApp) {
1798
+ * const info = await nativine.device.getInfo();
1799
+ * nativine.haptics.vibrate(200);
1800
+ * }
1801
+ * ```
1802
+ *
1803
+ * @example CDN / Script tag
1804
+ * ```html
1805
+ * <script src="https://cdn.jsdelivr.net/npm/nativine@latest/dist/nativine.umd.js"></script>
1806
+ * <script>
1807
+ * if (Nativine.isNativeApp) {
1808
+ * Nativine.haptics.vibrate(200);
1809
+ * }
1810
+ * </script>
1811
+ * ```
1812
+ *
1813
+ * @packageDocumentation
1814
+ */
1815
+ // ─── Core ────────────────────────────────────────────────────
1816
+ // ─── Bridge API ──────────────────────────────────────────────
1817
+ const nativine = {
1818
+ // ── Detection ──────────────────────────────────
1819
+ /** The detected platform: `'android'`, `'ios'`, or `'web'` */
1820
+ platform,
1821
+ /** `true` if running inside a Nativine native app */
1822
+ isNativeApp,
1823
+ /** `true` if running inside a Nativine Android app */
1824
+ isAndroid,
1825
+ /** `true` if running inside a Nativine iOS app */
1826
+ isIos,
1827
+ // ── SDK Version ────────────────────────────────
1828
+ /** The version of this SDK */
1829
+ version: '1.0.0',
1830
+ // ── Device ─────────────────────────────────────
1831
+ device: {
1832
+ getInfo: getInfo,
1833
+ getSafeAreaInsets: getSafeAreaInsets,
1834
+ getAppVersion: getAppVersion,
1835
+ getDeviceId: getDeviceId,
1836
+ },
1837
+ // ── UI ──────────────────────────────────────────
1838
+ ui: {
1839
+ statusBar: statusBar,
1840
+ navigationBar: navigationBar,
1841
+ hideSplashScreen: hideSplashScreen,
1842
+ setOrientation: setOrientation,
1843
+ showNativeComponents: showNativeComponents,
1844
+ hideNativeComponents: hideNativeComponents,
1845
+ setPullToRefresh: setPullToRefresh,
1846
+ setPinchToZoom: setPinchToZoom,
1847
+ },
1848
+ // ── Navigation ──────────────────────────────────
1849
+ navigation: {
1850
+ goBack: goBack,
1851
+ goForward: goForward,
1852
+ navigate: navigate,
1853
+ openInBrowser: openInBrowser,
1854
+ closeApp: closeApp,
1855
+ },
1856
+ // ── Haptics ─────────────────────────────────────
1857
+ haptics: {
1858
+ vibrate: vibrate,
1859
+ feedback: feedback,
1860
+ },
1861
+ // ── Storage ─────────────────────────────────────
1862
+ storage: {
1863
+ set: set,
1864
+ get: get,
1865
+ remove: remove,
1866
+ clear: clear$1,
1867
+ },
1868
+ // ── Share ───────────────────────────────────────
1869
+ share: share,
1870
+ shareFile: shareFile,
1871
+ // ── Auth ────────────────────────────────────────
1872
+ auth: {
1873
+ googleSignIn: googleSignIn,
1874
+ googleSignOut: googleSignOut,
1875
+ },
1876
+ // ── Biometrics ──────────────────────────────────
1877
+ biometrics: {
1878
+ isAvailable: isAvailable$1,
1879
+ authenticate: authenticate,
1880
+ },
1881
+ // ── Contacts ────────────────────────────────────
1882
+ contacts: {
1883
+ getAll: getAll,
1884
+ },
1885
+ // ── Clipboard ───────────────────────────────────
1886
+ clipboard: {
1887
+ copy: copy,
1888
+ read: read,
1889
+ },
1890
+ // ── Downloads ───────────────────────────────────
1891
+ downloads: {
1892
+ downloadFile: downloadFile,
1893
+ },
1894
+ // ── Scanner ─────────────────────────────────────
1895
+ scanner: {
1896
+ scan: scan,
1897
+ },
1898
+ // ── Location ────────────────────────────────────
1899
+ location: {
1900
+ getCurrent: getCurrent,
1901
+ },
1902
+ // ── Network ─────────────────────────────────────
1903
+ network: {
1904
+ isOnline: isOnline,
1905
+ onConnectivityChange: onConnectivityChange,
1906
+ },
1907
+ // ── Cache ───────────────────────────────────────
1908
+ cache: {
1909
+ clear: clear,
1910
+ clearCookies: clearCookies,
1911
+ },
1912
+ // ── Print ───────────────────────────────────────
1913
+ print: printPage,
1914
+ // ── Screenshot ──────────────────────────────────
1915
+ screenshot: {
1916
+ setProtection: setProtection,
1917
+ },
1918
+ // ── Reviews ─────────────────────────────────────
1919
+ reviews: {
1920
+ request: request,
1921
+ },
1922
+ // ── Updates ─────────────────────────────────────
1923
+ updates: {
1924
+ check: check,
1925
+ },
1926
+ // ── Ads ─────────────────────────────────────────
1927
+ ads: {
1928
+ showInterstitial: showInterstitial,
1929
+ showRewarded: showRewarded,
1930
+ },
1931
+ // ── OneSignal ───────────────────────────────────
1932
+ onesignal: {
1933
+ setExternalUserId: setExternalUserId,
1934
+ removeExternalUserId: removeExternalUserId,
1935
+ sendTag: sendTag,
1936
+ sendTags: sendTags,
1937
+ getPlayerId: getPlayerId,
1938
+ },
1939
+ // ── Toast ───────────────────────────────────────
1940
+ toast: showToast,
1941
+ // ── Pedometer / Step Counter ────────────────
1942
+ pedometer: {
1943
+ isAvailable: isAvailable,
1944
+ getStepCount: getStepCount,
1945
+ startTracking: startTracking,
1946
+ stopTracking: stopTracking,
1947
+ },
1948
+ // ── Events ──────────────────────────────────────
1949
+ on,
1950
+ off,
1951
+ };
1952
+
1953
+ export { ads, auth, biometrics, cache, clipboard, contacts, nativine as default, device, downloads, haptics, isAndroid, isIos, isNativeApp, location, navigation, network, off, on, onesignal, pedometer, platform, reviews, camera as scanner, screenshot, storage, ui, updates };
1954
+ //# sourceMappingURL=nativine.esm.js.map