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