@webority-technologies/mobile-core 0.0.5 → 0.0.7

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.
Files changed (72) hide show
  1. package/android/build.gradle +65 -0
  2. package/android/src/newarch/java/com/webority/mobilecore/smsretriever/AppSignatureHelper.kt +57 -0
  3. package/android/src/newarch/java/com/webority/mobilecore/smsretriever/SmsRetrieverModule.kt +20 -0
  4. package/android/src/newarch/java/com/webority/mobilecore/smsretriever/SmsRetrieverModuleImpl.kt +146 -0
  5. package/android/src/newarch/java/com/webority/mobilecore/smsretriever/SmsRetrieverPackage.kt +33 -0
  6. package/lib/commonjs/formatters/dateMath.js +19 -1
  7. package/lib/commonjs/formatters/index.js +6 -0
  8. package/lib/commonjs/formatters/windowsToIanaTable.js +164 -0
  9. package/lib/commonjs/geolocation/index.js +1 -1
  10. package/lib/commonjs/index.js +6 -0
  11. package/lib/commonjs/permissions/index.js +128 -129
  12. package/lib/commonjs/smsRetriever/index.js +91 -0
  13. package/lib/commonjs/specs/NativeSmsRetriever.js +15 -0
  14. package/lib/commonjs/sqlite/index.js +12 -30
  15. package/lib/module/formatters/dateMath.js +17 -0
  16. package/lib/module/formatters/index.js +1 -1
  17. package/lib/module/formatters/windowsToIanaTable.js +160 -0
  18. package/lib/module/geolocation/index.js +1 -1
  19. package/lib/module/index.js +4 -3
  20. package/lib/module/permissions/index.js +129 -130
  21. package/lib/module/smsRetriever/index.js +86 -0
  22. package/lib/module/specs/NativeSmsRetriever.js +13 -0
  23. package/lib/module/sqlite/index.js +12 -30
  24. package/lib/typescript/commonjs/formatters/dateMath.d.ts +9 -0
  25. package/lib/typescript/commonjs/formatters/index.d.ts +1 -1
  26. package/lib/typescript/commonjs/formatters/windowsToIanaTable.d.ts +18 -0
  27. package/lib/typescript/commonjs/index.d.ts +4 -3
  28. package/lib/typescript/commonjs/permissions/index.d.ts +14 -36
  29. package/lib/typescript/commonjs/smsRetriever/index.d.ts +30 -0
  30. package/lib/typescript/commonjs/specs/NativeSmsRetriever.d.ts +15 -0
  31. package/lib/typescript/commonjs/sqlite/index.d.ts +10 -18
  32. package/lib/typescript/module/formatters/dateMath.d.ts +9 -0
  33. package/lib/typescript/module/formatters/index.d.ts +1 -1
  34. package/lib/typescript/module/formatters/windowsToIanaTable.d.ts +18 -0
  35. package/lib/typescript/module/index.d.ts +4 -3
  36. package/lib/typescript/module/permissions/index.d.ts +14 -36
  37. package/lib/typescript/module/smsRetriever/index.d.ts +30 -0
  38. package/lib/typescript/module/specs/NativeSmsRetriever.d.ts +15 -0
  39. package/lib/typescript/module/sqlite/index.d.ts +10 -18
  40. package/package.json +30 -47
  41. package/lib/commonjs/sqlite/adapters/op.js +0 -43
  42. package/lib/commonjs/sqlite/adapters/rows.js +0 -33
  43. package/lib/commonjs/sqlite/adapters/storage.js +0 -50
  44. package/lib/commonjs/sqlite/adapters/sync.js +0 -45
  45. package/lib/commonjs/sqlite/nitro.js +0 -17
  46. package/lib/commonjs/sqlite/op.js +0 -18
  47. package/lib/commonjs/sqlite/quick.js +0 -14
  48. package/lib/commonjs/sqlite/storage.js +0 -14
  49. package/lib/module/sqlite/adapters/op.js +0 -38
  50. package/lib/module/sqlite/adapters/rows.js +0 -28
  51. package/lib/module/sqlite/adapters/storage.js +0 -46
  52. package/lib/module/sqlite/adapters/sync.js +0 -41
  53. package/lib/module/sqlite/nitro.js +0 -12
  54. package/lib/module/sqlite/op.js +0 -13
  55. package/lib/module/sqlite/quick.js +0 -9
  56. package/lib/module/sqlite/storage.js +0 -9
  57. package/lib/typescript/commonjs/sqlite/adapters/op.d.ts +0 -27
  58. package/lib/typescript/commonjs/sqlite/adapters/rows.d.ts +0 -7
  59. package/lib/typescript/commonjs/sqlite/adapters/storage.d.ts +0 -30
  60. package/lib/typescript/commonjs/sqlite/adapters/sync.d.ts +0 -31
  61. package/lib/typescript/commonjs/sqlite/nitro.d.ts +0 -7
  62. package/lib/typescript/commonjs/sqlite/op.d.ts +0 -8
  63. package/lib/typescript/commonjs/sqlite/quick.d.ts +0 -4
  64. package/lib/typescript/commonjs/sqlite/storage.d.ts +0 -4
  65. package/lib/typescript/module/sqlite/adapters/op.d.ts +0 -27
  66. package/lib/typescript/module/sqlite/adapters/rows.d.ts +0 -7
  67. package/lib/typescript/module/sqlite/adapters/storage.d.ts +0 -30
  68. package/lib/typescript/module/sqlite/adapters/sync.d.ts +0 -31
  69. package/lib/typescript/module/sqlite/nitro.d.ts +0 -7
  70. package/lib/typescript/module/sqlite/op.d.ts +0 -8
  71. package/lib/typescript/module/sqlite/quick.d.ts +0 -4
  72. package/lib/typescript/module/sqlite/storage.d.ts +0 -4
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * .NET-style Windows time zone ID → IANA time zone name, one entry per
5
+ * Windows zone, generated from CLDR's `windowsZones.xml` (the same
6
+ * upstream source the retired `windows-iana` npm package derived its own
7
+ * table from). Only the `territory="001"` (world-default) row is kept per
8
+ * Windows zone — `formatTimeInWindowsZone` only ever reads the first IANA
9
+ * candidate, and CLDR's `001` row is exactly that default candidate, so
10
+ * per-country territory variants (`US`, `CA`, `ZZ`, …) carry no information
11
+ * this table's one caller uses.
12
+ *
13
+ * Regenerate with `node packages/core/scripts/generate-windows-to-iana-table.mjs
14
+ * <path-to-windowsZones.xml>` (CLDR: `common/supplemental/windowsZones.xml` in
15
+ * https://github.com/unicode-org/cldr) whenever CLDR adds/renames a zone —
16
+ * this is a committed, static table; nothing fetches CLDR at build or test
17
+ * time.
18
+ */
19
+ export const WINDOWS_TO_IANA = {
20
+ 'AUS Central Standard Time': 'Australia/Darwin',
21
+ 'AUS Eastern Standard Time': 'Australia/Sydney',
22
+ 'Afghanistan Standard Time': 'Asia/Kabul',
23
+ 'Alaskan Standard Time': 'America/Anchorage',
24
+ 'Aleutian Standard Time': 'America/Adak',
25
+ 'Altai Standard Time': 'Asia/Barnaul',
26
+ 'Arab Standard Time': 'Asia/Riyadh',
27
+ 'Arabian Standard Time': 'Asia/Dubai',
28
+ 'Arabic Standard Time': 'Asia/Baghdad',
29
+ 'Argentina Standard Time': 'America/Buenos_Aires',
30
+ 'Astrakhan Standard Time': 'Europe/Astrakhan',
31
+ 'Atlantic Standard Time': 'America/Halifax',
32
+ 'Aus Central W. Standard Time': 'Australia/Eucla',
33
+ 'Azerbaijan Standard Time': 'Asia/Baku',
34
+ 'Azores Standard Time': 'Atlantic/Azores',
35
+ 'Bahia Standard Time': 'America/Bahia',
36
+ 'Bangladesh Standard Time': 'Asia/Dhaka',
37
+ 'Belarus Standard Time': 'Europe/Minsk',
38
+ 'Bougainville Standard Time': 'Pacific/Bougainville',
39
+ 'Canada Central Standard Time': 'America/Regina',
40
+ 'Cape Verde Standard Time': 'Atlantic/Cape_Verde',
41
+ 'Caucasus Standard Time': 'Asia/Yerevan',
42
+ 'Cen. Australia Standard Time': 'Australia/Adelaide',
43
+ 'Central America Standard Time': 'America/Guatemala',
44
+ 'Central Asia Standard Time': 'Asia/Almaty',
45
+ 'Central Brazilian Standard Time': 'America/Cuiaba',
46
+ 'Central Europe Standard Time': 'Europe/Budapest',
47
+ 'Central European Standard Time': 'Europe/Warsaw',
48
+ 'Central Pacific Standard Time': 'Pacific/Guadalcanal',
49
+ 'Central Standard Time': 'America/Chicago',
50
+ 'Central Standard Time (Mexico)': 'America/Mexico_City',
51
+ 'Chatham Islands Standard Time': 'Pacific/Chatham',
52
+ 'China Standard Time': 'Asia/Shanghai',
53
+ 'Cuba Standard Time': 'America/Havana',
54
+ 'Dateline Standard Time': 'Etc/GMT+12',
55
+ 'E. Africa Standard Time': 'Africa/Nairobi',
56
+ 'E. Australia Standard Time': 'Australia/Brisbane',
57
+ 'E. Europe Standard Time': 'Europe/Chisinau',
58
+ 'E. South America Standard Time': 'America/Sao_Paulo',
59
+ 'Easter Island Standard Time': 'Pacific/Easter',
60
+ 'Eastern Standard Time': 'America/New_York',
61
+ 'Eastern Standard Time (Mexico)': 'America/Cancun',
62
+ 'Egypt Standard Time': 'Africa/Cairo',
63
+ 'Ekaterinburg Standard Time': 'Asia/Yekaterinburg',
64
+ 'FLE Standard Time': 'Europe/Kiev',
65
+ 'Fiji Standard Time': 'Pacific/Fiji',
66
+ 'GMT Standard Time': 'Europe/London',
67
+ 'GTB Standard Time': 'Europe/Bucharest',
68
+ 'Georgian Standard Time': 'Asia/Tbilisi',
69
+ 'Greenland Standard Time': 'America/Godthab',
70
+ 'Greenwich Standard Time': 'Atlantic/Reykjavik',
71
+ 'Haiti Standard Time': 'America/Port-au-Prince',
72
+ 'Hawaiian Standard Time': 'Pacific/Honolulu',
73
+ 'India Standard Time': 'Asia/Calcutta',
74
+ 'Iran Standard Time': 'Asia/Tehran',
75
+ 'Israel Standard Time': 'Asia/Jerusalem',
76
+ 'Jordan Standard Time': 'Asia/Amman',
77
+ 'Kaliningrad Standard Time': 'Europe/Kaliningrad',
78
+ 'Korea Standard Time': 'Asia/Seoul',
79
+ 'Libya Standard Time': 'Africa/Tripoli',
80
+ 'Line Islands Standard Time': 'Pacific/Kiritimati',
81
+ 'Lord Howe Standard Time': 'Australia/Lord_Howe',
82
+ 'Magadan Standard Time': 'Asia/Magadan',
83
+ 'Magallanes Standard Time': 'America/Punta_Arenas',
84
+ 'Marquesas Standard Time': 'Pacific/Marquesas',
85
+ 'Mauritius Standard Time': 'Indian/Mauritius',
86
+ 'Middle East Standard Time': 'Asia/Beirut',
87
+ 'Montevideo Standard Time': 'America/Montevideo',
88
+ 'Morocco Standard Time': 'Africa/Casablanca',
89
+ 'Mountain Standard Time': 'America/Denver',
90
+ 'Mountain Standard Time (Mexico)': 'America/Chihuahua',
91
+ 'Myanmar Standard Time': 'Asia/Rangoon',
92
+ 'N. Central Asia Standard Time': 'Asia/Novosibirsk',
93
+ 'Namibia Standard Time': 'Africa/Windhoek',
94
+ 'Nepal Standard Time': 'Asia/Katmandu',
95
+ 'New Zealand Standard Time': 'Pacific/Auckland',
96
+ 'Newfoundland Standard Time': 'America/St_Johns',
97
+ 'Norfolk Standard Time': 'Pacific/Norfolk',
98
+ 'North Asia East Standard Time': 'Asia/Irkutsk',
99
+ 'North Asia Standard Time': 'Asia/Krasnoyarsk',
100
+ 'North Korea Standard Time': 'Asia/Pyongyang',
101
+ 'Omsk Standard Time': 'Asia/Omsk',
102
+ 'Pacific SA Standard Time': 'America/Santiago',
103
+ 'Pacific Standard Time': 'America/Los_Angeles',
104
+ 'Pacific Standard Time (Mexico)': 'America/Tijuana',
105
+ 'Pakistan Standard Time': 'Asia/Karachi',
106
+ 'Paraguay Standard Time': 'America/Asuncion',
107
+ 'Qyzylorda Standard Time': 'Asia/Qyzylorda',
108
+ 'Romance Standard Time': 'Europe/Paris',
109
+ 'Russia Time Zone 10': 'Asia/Srednekolymsk',
110
+ 'Russia Time Zone 11': 'Asia/Kamchatka',
111
+ 'Russia Time Zone 3': 'Europe/Samara',
112
+ 'Russian Standard Time': 'Europe/Moscow',
113
+ 'SA Eastern Standard Time': 'America/Cayenne',
114
+ 'SA Pacific Standard Time': 'America/Bogota',
115
+ 'SA Western Standard Time': 'America/La_Paz',
116
+ 'SE Asia Standard Time': 'Asia/Bangkok',
117
+ 'Saint Pierre Standard Time': 'America/Miquelon',
118
+ 'Sakhalin Standard Time': 'Asia/Sakhalin',
119
+ 'Samoa Standard Time': 'Pacific/Apia',
120
+ 'Sao Tome Standard Time': 'Africa/Sao_Tome',
121
+ 'Saratov Standard Time': 'Europe/Saratov',
122
+ 'Singapore Standard Time': 'Asia/Singapore',
123
+ 'South Africa Standard Time': 'Africa/Johannesburg',
124
+ 'South Sudan Standard Time': 'Africa/Juba',
125
+ 'Sri Lanka Standard Time': 'Asia/Colombo',
126
+ 'Sudan Standard Time': 'Africa/Khartoum',
127
+ 'Syria Standard Time': 'Asia/Damascus',
128
+ 'Taipei Standard Time': 'Asia/Taipei',
129
+ 'Tasmania Standard Time': 'Australia/Hobart',
130
+ 'Tocantins Standard Time': 'America/Araguaina',
131
+ 'Tokyo Standard Time': 'Asia/Tokyo',
132
+ 'Tomsk Standard Time': 'Asia/Tomsk',
133
+ 'Tonga Standard Time': 'Pacific/Tongatapu',
134
+ 'Transbaikal Standard Time': 'Asia/Chita',
135
+ 'Turkey Standard Time': 'Europe/Istanbul',
136
+ 'Turks And Caicos Standard Time': 'America/Grand_Turk',
137
+ 'US Eastern Standard Time': 'America/Indianapolis',
138
+ 'US Mountain Standard Time': 'America/Phoenix',
139
+ UTC: 'Etc/UTC',
140
+ 'UTC+12': 'Etc/GMT-12',
141
+ 'UTC+13': 'Etc/GMT-13',
142
+ 'UTC-02': 'Etc/GMT+2',
143
+ 'UTC-08': 'Etc/GMT+8',
144
+ 'UTC-09': 'Etc/GMT+9',
145
+ 'UTC-11': 'Etc/GMT+11',
146
+ 'Ulaanbaatar Standard Time': 'Asia/Ulaanbaatar',
147
+ 'Venezuela Standard Time': 'America/Caracas',
148
+ 'Vladivostok Standard Time': 'Asia/Vladivostok',
149
+ 'Volgograd Standard Time': 'Europe/Volgograd',
150
+ 'W. Australia Standard Time': 'Australia/Perth',
151
+ 'W. Central Africa Standard Time': 'Africa/Lagos',
152
+ 'W. Europe Standard Time': 'Europe/Berlin',
153
+ 'W. Mongolia Standard Time': 'Asia/Hovd',
154
+ 'West Asia Standard Time': 'Asia/Tashkent',
155
+ 'West Bank Standard Time': 'Asia/Hebron',
156
+ 'West Pacific Standard Time': 'Pacific/Port_Moresby',
157
+ 'Yakutsk Standard Time': 'Asia/Yakutsk',
158
+ 'Yukon Standard Time': 'America/Whitehorse'
159
+ };
160
+ //# sourceMappingURL=windowsToIanaTable.js.map
@@ -131,7 +131,7 @@ const ensureLocationPermission = async () => {
131
131
  return;
132
132
  }
133
133
  if (status === 'unavailable') {
134
- Logger.warn(`${PREFIX} Location permission status is unavailable (react-native-permissions is not ` + 'installed, or this platform has no mapping); attempting the location request anyway.');
134
+ Logger.warn(`${PREFIX} Location permission status is unavailable (expo-location is not installed, ` + 'or the check failed); attempting the location request anyway.');
135
135
  return;
136
136
  }
137
137
  throw new GeolocationError('permission-denied', `${PREFIX} Location permission is "${status}". Grant it before requesting a position` + (status === 'blocked' ? ', or call Permissions.openSettings() to let the user fix it.' : '.'));
@@ -7,11 +7,12 @@
7
7
  * for anyone importing anything at all. Those live behind their own import
8
8
  * paths instead:
9
9
  *
10
- * @webority-technologies/mobile-core/permissions react-native-permissions
10
+ * @webority-technologies/mobile-core/permissions per kind, its own Expo module
11
11
  * @webority-technologies/mobile-core/compressor react-native-compressor
12
12
  * @webority-technologies/mobile-core/geolocation a geolocation provider
13
- * @webority-technologies/mobile-core/sqlite a SQLite driver
13
+ * @webority-technologies/mobile-core/sqlite expo-sqlite
14
14
  * @webority-technologies/mobile-core/download a filesystem module
15
+ * @webority-technologies/mobile-core/smsRetriever Android only, own TurboModule
15
16
  *
16
17
  * react-native-keychain is the exception and is a REQUIRED peer: the HTTP client
17
18
  * reads the bearer token, so it is reachable from the main barrel by design.
@@ -29,7 +30,7 @@ export { getConfig, getConfigValue, resetConfig, setConfig } from "./config/inde
29
30
  // Deep links
30
31
  export { DeepLink, parseDeepLink, useDeepLink } from "./deepLink/index.js";
31
32
  // Formatters
32
- export { addDays, detectPhoneCountry, diffMs, formatCompactNumber, formatCurrency, formatDate, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatDateTime, formatNumber, formatPercent, formatPhone, formatRelativeTime, formatTime, formatTime12h, formatTimeInZone, getInitials, isDateAfter, isDateBefore, isSameDay, isValidPhoneNumber, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString, startOfDay } from "./formatters/index.js";
33
+ export { addDays, detectPhoneCountry, diffMs, formatCompactNumber, formatCurrency, formatDate, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatDateTime, formatNumber, formatPercent, formatPhone, formatRelativeTime, formatTime, formatTime12h, formatTimeInWindowsZone, formatTimeInZone, getInitials, isDateAfter, isDateBefore, isSameDay, isValidPhoneNumber, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString, startOfDay } from "./formatters/index.js";
33
34
  // Initialization
34
35
  export { initWebority } from "./initSDK.js";
35
36
  export { initUserAuth } from "./initUserAuth.js";
@@ -1,202 +1,201 @@
1
1
  "use strict";
2
2
 
3
- import { Linking, Platform } from 'react-native';
3
+ import { Linking } from 'react-native';
4
4
  import { Logger } from "../logger/index.js";
5
5
 
6
6
  // Android only — legacy WRITE_EXTERNAL_STORAGE
7
7
 
8
- let permsModule = null;
9
- let resolved = false;
10
- const resolveModule = () => {
11
- if (resolved) {
12
- return permsModule;
13
- }
14
- resolved = true;
15
- try {
16
- const mod = require('react-native-permissions');
17
- permsModule = mod.default ?? mod;
18
- } catch {
19
- Logger.warn('[permissions] react-native-permissions is not installed; ' + 'permission checks will report "unavailable".');
20
- permsModule = null;
21
- }
22
- return permsModule;
23
- };
8
+ /** The shared response shape every Expo permission function returns. */
24
9
 
25
10
  /**
26
- * Inject a custom permissions implementation at runtime.
27
- * Pass `null` to reset to the default lazily-resolved native module.
11
+ * Every permission-bearing kind resolves through its own Expo module — no
12
+ * single "permissions package" exists, so each kind names the one Expo module
13
+ * that owns it and is required lazily, the same discipline every other Expo
14
+ * surface in this library follows (an app that never asks for a permission
15
+ * never names its package to Metro). `bluetooth` and `storage` have no Expo
16
+ * module at all; they resolve through `setPermissionsImplementation` only,
17
+ * same as the test/showcase injection seam every other surface has.
28
18
  *
29
- * `resolved` goes FALSE on null, never true. Marking it resolved with a null
30
- * backend would permanently disable permissions: the resolver short-circuits and the
31
- * real module is never loaded again, which contradicts this function's own
32
- * documented contract. That exact bug shipped once, in the storage seam.
19
+ */
20
+ let backend = null;
21
+
22
+ /**
23
+ * Inject a custom permissions backend at runtime. Pass `null` to reset to the
24
+ * default per-kind Expo resolution.
33
25
  *
34
- * THIS MODULE IS THE EXPO-FIRST EXCEPTION, and deliberately keeps the old
35
- * shape. Expo ships no permissions package: each module carries its own
36
- * (expo-location's requestForegroundPermissionsAsync, expo-image-picker's, and
37
- * so on), so there is no single object to adapt and the library must not guess
38
- * which Expo modules an app installed. react-native-permissions stays, behind
39
- * this module's own import path so an app that never asks for permissions
40
- * never names the package to Metro.
26
+ * Two legitimate reasons to call this: tests/the showcase reaching a denied,
27
+ * blocked or unavailable path a healthy device never takes; and an app that
28
+ * genuinely needs `bluetooth` or `storage`, which no Expo module covers.
41
29
  */
42
30
  export const setPermissionsImplementation = impl => {
43
- permsModule = impl;
44
- resolved = impl !== null;
31
+ backend = impl;
45
32
  };
46
- const mapToNative = kind => {
47
- const m = resolveModule();
48
- if (!m) {
49
- return null;
50
- }
51
- const {
52
- IOS,
53
- ANDROID
54
- } = m.PERMISSIONS;
55
- if (Platform.OS === 'ios') {
33
+ const resolveExpoModule = kind => {
34
+ try {
56
35
  switch (kind) {
57
36
  case 'camera':
58
- return IOS.CAMERA ?? null;
37
+ {
38
+ const m = require('expo-camera');
39
+ return {
40
+ check: m.getCameraPermissionsAsync,
41
+ request: m.requestCameraPermissionsAsync
42
+ };
43
+ }
59
44
  case 'microphone':
60
- return IOS.MICROPHONE ?? null;
45
+ {
46
+ const m = require('expo-camera');
47
+ return {
48
+ check: m.getMicrophonePermissionsAsync,
49
+ request: m.requestMicrophonePermissionsAsync
50
+ };
51
+ }
61
52
  case 'photos':
62
- return IOS.PHOTO_LIBRARY ?? null;
53
+ {
54
+ const m = require('expo-image-picker');
55
+ return {
56
+ check: () => m.getMediaLibraryPermissionsAsync(false),
57
+ request: () => m.requestMediaLibraryPermissionsAsync(false)
58
+ };
59
+ }
63
60
  case 'photosAdd':
64
- return IOS.PHOTO_LIBRARY_ADD_ONLY ?? null;
61
+ {
62
+ const m = require('expo-image-picker');
63
+ return {
64
+ check: () => m.getMediaLibraryPermissionsAsync(true),
65
+ request: () => m.requestMediaLibraryPermissionsAsync(true)
66
+ };
67
+ }
65
68
  case 'mediaLibrary':
66
- return IOS.MEDIA_LIBRARY ?? null;
69
+ {
70
+ const m = require('expo-media-library');
71
+ return {
72
+ check: m.getPermissionsAsync,
73
+ request: m.requestPermissionsAsync
74
+ };
75
+ }
67
76
  case 'location':
68
- return IOS.LOCATION_WHEN_IN_USE ?? null;
77
+ {
78
+ const m = require('expo-location');
79
+ return {
80
+ check: m.getForegroundPermissionsAsync,
81
+ request: m.requestForegroundPermissionsAsync
82
+ };
83
+ }
69
84
  case 'locationAlways':
70
- return IOS.LOCATION_ALWAYS ?? null;
85
+ {
86
+ const m = require('expo-location');
87
+ return {
88
+ check: m.getBackgroundPermissionsAsync,
89
+ request: m.requestBackgroundPermissionsAsync
90
+ };
91
+ }
71
92
  case 'contacts':
72
- return IOS.CONTACTS ?? null;
93
+ {
94
+ const m = require('expo-contacts');
95
+ return {
96
+ check: m.getPermissionsAsync,
97
+ request: m.requestPermissionsAsync
98
+ };
99
+ }
73
100
  case 'calendar':
74
- return IOS.CALENDARS ?? null;
101
+ {
102
+ const m = require('expo-calendar');
103
+ return {
104
+ check: m.getCalendarPermissionsAsync,
105
+ request: m.requestCalendarPermissionsAsync
106
+ };
107
+ }
75
108
  case 'reminders':
76
- return IOS.REMINDERS ?? null;
109
+ {
110
+ const m = require('expo-calendar');
111
+ return {
112
+ check: m.getRemindersPermissionsAsync,
113
+ request: m.requestRemindersPermissionsAsync
114
+ };
115
+ }
77
116
  case 'notifications':
78
- return null;
79
- // handled separately on iOS
117
+ {
118
+ const m = require('expo-notifications');
119
+ return {
120
+ check: m.getPermissionsAsync,
121
+ request: m.requestPermissionsAsync
122
+ };
123
+ }
80
124
  case 'bluetooth':
81
- return IOS.BLUETOOTH ?? null;
82
125
  case 'storage':
126
+ // No Expo module covers either — the injected backend is the only path.
83
127
  return null;
84
128
  default:
85
129
  return null;
86
130
  }
87
- }
88
- switch (kind) {
89
- case 'camera':
90
- return ANDROID.CAMERA ?? null;
91
- case 'microphone':
92
- return ANDROID.RECORD_AUDIO ?? null;
93
- case 'photos':
94
- case 'mediaLibrary':
95
- return ANDROID.READ_MEDIA_IMAGES ?? ANDROID.READ_EXTERNAL_STORAGE ?? null;
96
- case 'photosAdd':
97
- return ANDROID.READ_MEDIA_IMAGES ?? null;
98
- case 'location':
99
- case 'locationAlways':
100
- return ANDROID.ACCESS_FINE_LOCATION ?? null;
101
- case 'contacts':
102
- return ANDROID.READ_CONTACTS ?? null;
103
- case 'calendar':
104
- return ANDROID.READ_CALENDAR ?? null;
105
- case 'reminders':
106
- return null;
107
- case 'notifications':
108
- return ANDROID.POST_NOTIFICATIONS ?? null;
109
- case 'bluetooth':
110
- return ANDROID.BLUETOOTH_CONNECT ?? null;
111
- case 'storage':
112
- return ANDROID.WRITE_EXTERNAL_STORAGE ?? null;
113
- default:
114
- return null;
131
+ } catch {
132
+ return null;
115
133
  }
116
134
  };
117
- const mapResult = raw => {
118
- const m = resolveModule();
119
- if (!m || !raw) {
135
+ const toStatus = response => {
136
+ if (!response) {
120
137
  return 'unavailable';
121
138
  }
122
- const {
123
- RESULTS
124
- } = m;
125
- if (raw === RESULTS.GRANTED) {
126
- return 'granted';
127
- }
128
- if (raw === RESULTS.DENIED) {
129
- return 'denied';
130
- }
131
- if (raw === RESULTS.LIMITED) {
139
+ if (response.accessPrivileges === 'limited') {
132
140
  return 'limited';
133
141
  }
134
- if (raw === RESULTS.BLOCKED) {
135
- return 'blocked';
142
+ if (response.status === 'granted') {
143
+ return 'granted';
144
+ }
145
+ if (response.status === 'denied') {
146
+ return response.canAskAgain ? 'denied' : 'blocked';
136
147
  }
137
- return 'unavailable';
148
+ // 'undetermined' — never asked yet. Treated as 'denied' so callers using
149
+ // Permissions.ensure() correctly trigger a request() rather than stalling.
150
+ return 'denied';
138
151
  };
139
152
  const checkPermission = async kind => {
140
- const m = resolveModule();
141
- if (!m) {
142
- return 'unavailable';
153
+ if (backend) {
154
+ return backend.check(kind);
143
155
  }
144
- const native = mapToNative(kind);
145
- if (!native) {
156
+ const fns = resolveExpoModule(kind);
157
+ if (!fns) {
146
158
  return 'unavailable';
147
159
  }
148
160
  try {
149
- const raw = await m.check(native);
150
- return mapResult(raw);
161
+ return toStatus(await fns.check());
151
162
  } catch (error) {
152
163
  Logger.error(`[permissions] check(${kind}) failed`, error);
153
164
  return 'unavailable';
154
165
  }
155
166
  };
156
167
  const requestPermission = async kind => {
157
- const m = resolveModule();
158
- if (!m) {
159
- return 'unavailable';
168
+ if (backend) {
169
+ return backend.request(kind);
160
170
  }
161
- const native = mapToNative(kind);
162
- if (!native) {
171
+ const fns = resolveExpoModule(kind);
172
+ if (!fns) {
163
173
  return 'unavailable';
164
174
  }
165
175
  try {
166
- const raw = await m.request(native);
167
- return mapResult(raw);
176
+ return toStatus(await fns.request());
168
177
  } catch (error) {
169
178
  Logger.error(`[permissions] request(${kind}) failed`, error);
170
179
  return 'unavailable';
171
180
  }
172
181
  };
173
182
  const openAppSettings = async () => {
174
- const m = resolveModule();
175
- if (!m) {
176
- try {
177
- await Linking.openSettings();
178
- return true;
179
- } catch (error) {
180
- Logger.error('[permissions] openAppSettings fallback failed', error);
181
- return false;
182
- }
183
- }
184
183
  try {
185
- await m.openSettings();
184
+ await Linking.openSettings();
186
185
  return true;
187
186
  } catch (error) {
188
- Logger.error('[permissions] openSettings failed', error);
187
+ Logger.error('[permissions] openAppSettings failed', error);
189
188
  return false;
190
189
  }
191
190
  };
192
191
 
193
192
  /**
194
193
  * Cross-platform permissions wrapper. Maps an abstract `PermissionKind`
195
- * (camera, photos, location, notifications, …) to the right
196
- * iOS / Android permission string under the hood.
197
- *
198
- * Requires `react-native-permissions` as an optional peer dependency;
199
- * when missing, every check/request resolves to `'unavailable'`.
194
+ * (camera, photos, location, notifications, …) to the Expo module that owns
195
+ * it under the hood expo-camera, expo-image-picker, expo-location,
196
+ * expo-contacts, expo-calendar, expo-notifications, expo-media-library. Every
197
+ * one is an optional peer, required lazily; an app installs only the modules
198
+ * whose kinds it actually asks for.
200
199
  */
201
200
  export const Permissions = {
202
201
  check: checkPermission,
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+
3
+ import { DeviceEventEmitter, Platform } from 'react-native';
4
+ import { Logger } from "../logger/index.js";
5
+ const OTP_EVENT = 'WeborityMobileCoreSmsRetrieved';
6
+ const ERROR_EVENT = 'WeborityMobileCoreSmsRetrieverError';
7
+ let backend = null;
8
+
9
+ /** Test-only injection point. Pass `null` to reset to the native module. */
10
+ export const setSmsRetrieverImplementation = impl => {
11
+ backend = impl;
12
+ };
13
+ let nativeModule;
14
+ const resolveNativeModule = () => {
15
+ if (nativeModule !== undefined) {
16
+ return nativeModule;
17
+ }
18
+ if (Platform.OS !== 'android') {
19
+ nativeModule = null;
20
+ return null;
21
+ }
22
+ try {
23
+ nativeModule = require('../specs/NativeSmsRetriever').default ?? null;
24
+ } catch (error) {
25
+ Logger.warn('[smsRetriever] native module not available', error);
26
+ nativeModule = null;
27
+ }
28
+ return nativeModule ?? null;
29
+ };
30
+ const defaultBackend = {
31
+ getAppHash: async () => {
32
+ const m = resolveNativeModule();
33
+ if (!m) {
34
+ throw new Error('[smsRetriever] getAppHash: native module unavailable (Android only).');
35
+ }
36
+ return m.getAppHash();
37
+ },
38
+ startListening: (onMessage, onError) => {
39
+ const m = resolveNativeModule();
40
+ if (!m) {
41
+ onError?.({
42
+ type: 'SERVICE_UNAVAILABLE',
43
+ message: 'SMS Retriever is Android-only, or the native module is not linked.'
44
+ });
45
+ return {
46
+ remove: () => undefined
47
+ };
48
+ }
49
+ const messageSub = DeviceEventEmitter.addListener(OTP_EVENT, payload => onMessage(payload.message));
50
+ const errorSub = onError ? DeviceEventEmitter.addListener(ERROR_EVENT, payload => onError(payload)) : null;
51
+ try {
52
+ m.startSMSListener();
53
+ } catch (error) {
54
+ Logger.error('[smsRetriever] startSMSListener failed', error);
55
+ }
56
+ return {
57
+ remove: () => {
58
+ messageSub.remove();
59
+ errorSub?.remove();
60
+ try {
61
+ m.stopSMSListener();
62
+ } catch (error) {
63
+ Logger.error('[smsRetriever] stopSMSListener failed', error);
64
+ }
65
+ }
66
+ };
67
+ }
68
+ };
69
+
70
+ /**
71
+ * The Play Services SMS Retriever API — auto-reads an incoming OTP SMS with
72
+ * no SMS permission, matched by an 11-character app-signature hash
73
+ * (`getAppHash`) the backend appends to the message. Android only; every
74
+ * method is safe to call on iOS and resolves/reports unavailable rather than
75
+ * throwing, so a caller doesn't need a platform check at every call site.
76
+ *
77
+ * OTP extraction is left to the caller — `onMessage` receives the raw SMS
78
+ * text, since the expected OTP format (digit count, prefix) is a backend
79
+ * concern, not this module's.
80
+ */
81
+ export const SmsRetriever = {
82
+ isAvailable: () => resolveNativeModule() !== null,
83
+ getAppHash: () => (backend ?? defaultBackend).getAppHash(),
84
+ startListening: (onMessage, onError) => (backend ?? defaultBackend).startListening(onMessage, onError)
85
+ };
86
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ import { TurboModuleRegistry } from 'react-native';
4
+
5
+ /**
6
+ * Android-only — the Play Services SMS Retriever API has no iOS equivalent.
7
+ * The JS wrapper in `smsRetriever/index.ts` never touches this module on
8
+ * iOS, so `getEnforcing` only ever runs on Android, where autolinking has
9
+ * registered `SmsRetrieverPackage`.
10
+ */
11
+
12
+ export default TurboModuleRegistry.getEnforcing('WeborityMobileCoreSmsRetriever');
13
+ //# sourceMappingURL=NativeSmsRetriever.js.map