@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
@@ -8,199 +8,198 @@ var _reactNative = require("react-native");
8
8
  var _index = require("../logger/index.js");
9
9
  // Android only — legacy WRITE_EXTERNAL_STORAGE
10
10
 
11
- let permsModule = null;
12
- let resolved = false;
13
- const resolveModule = () => {
14
- if (resolved) {
15
- return permsModule;
16
- }
17
- resolved = true;
18
- try {
19
- const mod = require('react-native-permissions');
20
- permsModule = mod.default ?? mod;
21
- } catch {
22
- _index.Logger.warn('[permissions] react-native-permissions is not installed; ' + 'permission checks will report "unavailable".');
23
- permsModule = null;
24
- }
25
- return permsModule;
26
- };
11
+ /** The shared response shape every Expo permission function returns. */
27
12
 
28
13
  /**
29
- * Inject a custom permissions implementation at runtime.
30
- * Pass `null` to reset to the default lazily-resolved native module.
14
+ * Every permission-bearing kind resolves through its own Expo module — no
15
+ * single "permissions package" exists, so each kind names the one Expo module
16
+ * that owns it and is required lazily, the same discipline every other Expo
17
+ * surface in this library follows (an app that never asks for a permission
18
+ * never names its package to Metro). `bluetooth` and `storage` have no Expo
19
+ * module at all; they resolve through `setPermissionsImplementation` only,
20
+ * same as the test/showcase injection seam every other surface has.
31
21
  *
32
- * `resolved` goes FALSE on null, never true. Marking it resolved with a null
33
- * backend would permanently disable permissions: the resolver short-circuits and the
34
- * real module is never loaded again, which contradicts this function's own
35
- * documented contract. That exact bug shipped once, in the storage seam.
22
+ */
23
+ let backend = null;
24
+
25
+ /**
26
+ * Inject a custom permissions backend at runtime. Pass `null` to reset to the
27
+ * default per-kind Expo resolution.
36
28
  *
37
- * THIS MODULE IS THE EXPO-FIRST EXCEPTION, and deliberately keeps the old
38
- * shape. Expo ships no permissions package: each module carries its own
39
- * (expo-location's requestForegroundPermissionsAsync, expo-image-picker's, and
40
- * so on), so there is no single object to adapt and the library must not guess
41
- * which Expo modules an app installed. react-native-permissions stays, behind
42
- * this module's own import path so an app that never asks for permissions
43
- * never names the package to Metro.
29
+ * Two legitimate reasons to call this: tests/the showcase reaching a denied,
30
+ * blocked or unavailable path a healthy device never takes; and an app that
31
+ * genuinely needs `bluetooth` or `storage`, which no Expo module covers.
44
32
  */
45
33
  const setPermissionsImplementation = impl => {
46
- permsModule = impl;
47
- resolved = impl !== null;
34
+ backend = impl;
48
35
  };
49
36
  exports.setPermissionsImplementation = setPermissionsImplementation;
50
- const mapToNative = kind => {
51
- const m = resolveModule();
52
- if (!m) {
53
- return null;
54
- }
55
- const {
56
- IOS,
57
- ANDROID
58
- } = m.PERMISSIONS;
59
- if (_reactNative.Platform.OS === 'ios') {
37
+ const resolveExpoModule = kind => {
38
+ try {
60
39
  switch (kind) {
61
40
  case 'camera':
62
- return IOS.CAMERA ?? null;
41
+ {
42
+ const m = require('expo-camera');
43
+ return {
44
+ check: m.getCameraPermissionsAsync,
45
+ request: m.requestCameraPermissionsAsync
46
+ };
47
+ }
63
48
  case 'microphone':
64
- return IOS.MICROPHONE ?? null;
49
+ {
50
+ const m = require('expo-camera');
51
+ return {
52
+ check: m.getMicrophonePermissionsAsync,
53
+ request: m.requestMicrophonePermissionsAsync
54
+ };
55
+ }
65
56
  case 'photos':
66
- return IOS.PHOTO_LIBRARY ?? null;
57
+ {
58
+ const m = require('expo-image-picker');
59
+ return {
60
+ check: () => m.getMediaLibraryPermissionsAsync(false),
61
+ request: () => m.requestMediaLibraryPermissionsAsync(false)
62
+ };
63
+ }
67
64
  case 'photosAdd':
68
- return IOS.PHOTO_LIBRARY_ADD_ONLY ?? null;
65
+ {
66
+ const m = require('expo-image-picker');
67
+ return {
68
+ check: () => m.getMediaLibraryPermissionsAsync(true),
69
+ request: () => m.requestMediaLibraryPermissionsAsync(true)
70
+ };
71
+ }
69
72
  case 'mediaLibrary':
70
- return IOS.MEDIA_LIBRARY ?? null;
73
+ {
74
+ const m = require('expo-media-library');
75
+ return {
76
+ check: m.getPermissionsAsync,
77
+ request: m.requestPermissionsAsync
78
+ };
79
+ }
71
80
  case 'location':
72
- return IOS.LOCATION_WHEN_IN_USE ?? null;
81
+ {
82
+ const m = require('expo-location');
83
+ return {
84
+ check: m.getForegroundPermissionsAsync,
85
+ request: m.requestForegroundPermissionsAsync
86
+ };
87
+ }
73
88
  case 'locationAlways':
74
- return IOS.LOCATION_ALWAYS ?? null;
89
+ {
90
+ const m = require('expo-location');
91
+ return {
92
+ check: m.getBackgroundPermissionsAsync,
93
+ request: m.requestBackgroundPermissionsAsync
94
+ };
95
+ }
75
96
  case 'contacts':
76
- return IOS.CONTACTS ?? null;
97
+ {
98
+ const m = require('expo-contacts');
99
+ return {
100
+ check: m.getPermissionsAsync,
101
+ request: m.requestPermissionsAsync
102
+ };
103
+ }
77
104
  case 'calendar':
78
- return IOS.CALENDARS ?? null;
105
+ {
106
+ const m = require('expo-calendar');
107
+ return {
108
+ check: m.getCalendarPermissionsAsync,
109
+ request: m.requestCalendarPermissionsAsync
110
+ };
111
+ }
79
112
  case 'reminders':
80
- return IOS.REMINDERS ?? null;
113
+ {
114
+ const m = require('expo-calendar');
115
+ return {
116
+ check: m.getRemindersPermissionsAsync,
117
+ request: m.requestRemindersPermissionsAsync
118
+ };
119
+ }
81
120
  case 'notifications':
82
- return null;
83
- // handled separately on iOS
121
+ {
122
+ const m = require('expo-notifications');
123
+ return {
124
+ check: m.getPermissionsAsync,
125
+ request: m.requestPermissionsAsync
126
+ };
127
+ }
84
128
  case 'bluetooth':
85
- return IOS.BLUETOOTH ?? null;
86
129
  case 'storage':
130
+ // No Expo module covers either — the injected backend is the only path.
87
131
  return null;
88
132
  default:
89
133
  return null;
90
134
  }
91
- }
92
- switch (kind) {
93
- case 'camera':
94
- return ANDROID.CAMERA ?? null;
95
- case 'microphone':
96
- return ANDROID.RECORD_AUDIO ?? null;
97
- case 'photos':
98
- case 'mediaLibrary':
99
- return ANDROID.READ_MEDIA_IMAGES ?? ANDROID.READ_EXTERNAL_STORAGE ?? null;
100
- case 'photosAdd':
101
- return ANDROID.READ_MEDIA_IMAGES ?? null;
102
- case 'location':
103
- case 'locationAlways':
104
- return ANDROID.ACCESS_FINE_LOCATION ?? null;
105
- case 'contacts':
106
- return ANDROID.READ_CONTACTS ?? null;
107
- case 'calendar':
108
- return ANDROID.READ_CALENDAR ?? null;
109
- case 'reminders':
110
- return null;
111
- case 'notifications':
112
- return ANDROID.POST_NOTIFICATIONS ?? null;
113
- case 'bluetooth':
114
- return ANDROID.BLUETOOTH_CONNECT ?? null;
115
- case 'storage':
116
- return ANDROID.WRITE_EXTERNAL_STORAGE ?? null;
117
- default:
118
- return null;
135
+ } catch {
136
+ return null;
119
137
  }
120
138
  };
121
- const mapResult = raw => {
122
- const m = resolveModule();
123
- if (!m || !raw) {
139
+ const toStatus = response => {
140
+ if (!response) {
124
141
  return 'unavailable';
125
142
  }
126
- const {
127
- RESULTS
128
- } = m;
129
- if (raw === RESULTS.GRANTED) {
130
- return 'granted';
131
- }
132
- if (raw === RESULTS.DENIED) {
133
- return 'denied';
134
- }
135
- if (raw === RESULTS.LIMITED) {
143
+ if (response.accessPrivileges === 'limited') {
136
144
  return 'limited';
137
145
  }
138
- if (raw === RESULTS.BLOCKED) {
139
- return 'blocked';
146
+ if (response.status === 'granted') {
147
+ return 'granted';
148
+ }
149
+ if (response.status === 'denied') {
150
+ return response.canAskAgain ? 'denied' : 'blocked';
140
151
  }
141
- return 'unavailable';
152
+ // 'undetermined' — never asked yet. Treated as 'denied' so callers using
153
+ // Permissions.ensure() correctly trigger a request() rather than stalling.
154
+ return 'denied';
142
155
  };
143
156
  const checkPermission = async kind => {
144
- const m = resolveModule();
145
- if (!m) {
146
- return 'unavailable';
157
+ if (backend) {
158
+ return backend.check(kind);
147
159
  }
148
- const native = mapToNative(kind);
149
- if (!native) {
160
+ const fns = resolveExpoModule(kind);
161
+ if (!fns) {
150
162
  return 'unavailable';
151
163
  }
152
164
  try {
153
- const raw = await m.check(native);
154
- return mapResult(raw);
165
+ return toStatus(await fns.check());
155
166
  } catch (error) {
156
167
  _index.Logger.error(`[permissions] check(${kind}) failed`, error);
157
168
  return 'unavailable';
158
169
  }
159
170
  };
160
171
  const requestPermission = async kind => {
161
- const m = resolveModule();
162
- if (!m) {
163
- return 'unavailable';
172
+ if (backend) {
173
+ return backend.request(kind);
164
174
  }
165
- const native = mapToNative(kind);
166
- if (!native) {
175
+ const fns = resolveExpoModule(kind);
176
+ if (!fns) {
167
177
  return 'unavailable';
168
178
  }
169
179
  try {
170
- const raw = await m.request(native);
171
- return mapResult(raw);
180
+ return toStatus(await fns.request());
172
181
  } catch (error) {
173
182
  _index.Logger.error(`[permissions] request(${kind}) failed`, error);
174
183
  return 'unavailable';
175
184
  }
176
185
  };
177
186
  const openAppSettings = async () => {
178
- const m = resolveModule();
179
- if (!m) {
180
- try {
181
- await _reactNative.Linking.openSettings();
182
- return true;
183
- } catch (error) {
184
- _index.Logger.error('[permissions] openAppSettings fallback failed', error);
185
- return false;
186
- }
187
- }
188
187
  try {
189
- await m.openSettings();
188
+ await _reactNative.Linking.openSettings();
190
189
  return true;
191
190
  } catch (error) {
192
- _index.Logger.error('[permissions] openSettings failed', error);
191
+ _index.Logger.error('[permissions] openAppSettings failed', error);
193
192
  return false;
194
193
  }
195
194
  };
196
195
 
197
196
  /**
198
197
  * Cross-platform permissions wrapper. Maps an abstract `PermissionKind`
199
- * (camera, photos, location, notifications, …) to the right
200
- * iOS / Android permission string under the hood.
201
- *
202
- * Requires `react-native-permissions` as an optional peer dependency;
203
- * when missing, every check/request resolves to `'unavailable'`.
198
+ * (camera, photos, location, notifications, …) to the Expo module that owns
199
+ * it under the hood expo-camera, expo-image-picker, expo-location,
200
+ * expo-contacts, expo-calendar, expo-notifications, expo-media-library. Every
201
+ * one is an optional peer, required lazily; an app installs only the modules
202
+ * whose kinds it actually asks for.
204
203
  */
205
204
  const Permissions = exports.Permissions = {
206
205
  check: checkPermission,
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.setSmsRetrieverImplementation = exports.SmsRetriever = void 0;
7
+ var _reactNative = require("react-native");
8
+ var _index = require("../logger/index.js");
9
+ const OTP_EVENT = 'WeborityMobileCoreSmsRetrieved';
10
+ const ERROR_EVENT = 'WeborityMobileCoreSmsRetrieverError';
11
+ let backend = null;
12
+
13
+ /** Test-only injection point. Pass `null` to reset to the native module. */
14
+ const setSmsRetrieverImplementation = impl => {
15
+ backend = impl;
16
+ };
17
+ exports.setSmsRetrieverImplementation = setSmsRetrieverImplementation;
18
+ let nativeModule;
19
+ const resolveNativeModule = () => {
20
+ if (nativeModule !== undefined) {
21
+ return nativeModule;
22
+ }
23
+ if (_reactNative.Platform.OS !== 'android') {
24
+ nativeModule = null;
25
+ return null;
26
+ }
27
+ try {
28
+ nativeModule = require('../specs/NativeSmsRetriever').default ?? null;
29
+ } catch (error) {
30
+ _index.Logger.warn('[smsRetriever] native module not available', error);
31
+ nativeModule = null;
32
+ }
33
+ return nativeModule ?? null;
34
+ };
35
+ const defaultBackend = {
36
+ getAppHash: async () => {
37
+ const m = resolveNativeModule();
38
+ if (!m) {
39
+ throw new Error('[smsRetriever] getAppHash: native module unavailable (Android only).');
40
+ }
41
+ return m.getAppHash();
42
+ },
43
+ startListening: (onMessage, onError) => {
44
+ const m = resolveNativeModule();
45
+ if (!m) {
46
+ onError?.({
47
+ type: 'SERVICE_UNAVAILABLE',
48
+ message: 'SMS Retriever is Android-only, or the native module is not linked.'
49
+ });
50
+ return {
51
+ remove: () => undefined
52
+ };
53
+ }
54
+ const messageSub = _reactNative.DeviceEventEmitter.addListener(OTP_EVENT, payload => onMessage(payload.message));
55
+ const errorSub = onError ? _reactNative.DeviceEventEmitter.addListener(ERROR_EVENT, payload => onError(payload)) : null;
56
+ try {
57
+ m.startSMSListener();
58
+ } catch (error) {
59
+ _index.Logger.error('[smsRetriever] startSMSListener failed', error);
60
+ }
61
+ return {
62
+ remove: () => {
63
+ messageSub.remove();
64
+ errorSub?.remove();
65
+ try {
66
+ m.stopSMSListener();
67
+ } catch (error) {
68
+ _index.Logger.error('[smsRetriever] stopSMSListener failed', error);
69
+ }
70
+ }
71
+ };
72
+ }
73
+ };
74
+
75
+ /**
76
+ * The Play Services SMS Retriever API — auto-reads an incoming OTP SMS with
77
+ * no SMS permission, matched by an 11-character app-signature hash
78
+ * (`getAppHash`) the backend appends to the message. Android only; every
79
+ * method is safe to call on iOS and resolves/reports unavailable rather than
80
+ * throwing, so a caller doesn't need a platform check at every call site.
81
+ *
82
+ * OTP extraction is left to the caller — `onMessage` receives the raw SMS
83
+ * text, since the expected OTP format (digit count, prefix) is a backend
84
+ * concern, not this module's.
85
+ */
86
+ const SmsRetriever = exports.SmsRetriever = {
87
+ isAvailable: () => resolveNativeModule() !== null,
88
+ getAppHash: () => (backend ?? defaultBackend).getAppHash(),
89
+ startListening: (onMessage, onError) => (backend ?? defaultBackend).startListening(onMessage, onError)
90
+ };
91
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _reactNative = require("react-native");
8
+ /**
9
+ * Android-only — the Play Services SMS Retriever API has no iOS equivalent.
10
+ * The JS wrapper in `smsRetriever/index.ts` never touches this module on
11
+ * iOS, so `getEnforcing` only ever runs on Android, where autolinking has
12
+ * registered `SmsRetrieverPackage`.
13
+ */
14
+ var _default = exports.default = _reactNative.TurboModuleRegistry.getEnforcing('WeborityMobileCoreSmsRetriever');
15
+ //# sourceMappingURL=NativeSmsRetriever.js.map
@@ -9,40 +9,25 @@ var _index = require("../logger/index.js");
9
9
  var _expo = require("./adapters/expo.js");
10
10
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
11
11
  /**
12
- * This module names NO native package. Metro resolves requires statically, so a
13
- * driver named here would be bundled by every consumer and would have to be
14
- * installed by every app, whichever driver it actually chose. Each driver lives
15
- * behind its own import path, and the app wires one at startup:
16
- *
17
- * import { setSqliteImplementation } from '@webority-technologies/mobile-core/sqlite';
18
- * import { opSqliteDriver } from '@webority-technologies/mobile-core/sqlite/op';
19
- * setSqliteImplementation(opSqliteDriver());
20
- *
21
- * Supported entry points: /sqlite/op, /sqlite/nitro, /sqlite/quick,
22
- * /sqlite/storage. Any object matching SqliteDriver also works.
12
+ * expo-sqlite is the fleet's only sanctioned SQLite driver (react-native.md:
13
+ * "we will always use expo-sqlite, what Expo gives, we don't look elsewhere
14
+ * ever") this module resolves it automatically, with no app-side wiring.
15
+ * `setSqliteImplementation` still exists, narrowed to tests and the showcase:
16
+ * it injects a denying/failing backend to reach error paths a healthy device
17
+ * never takes, the same pattern every other injectable surface in this
18
+ * library follows. It is not a way to pick an alternate real driver.
23
19
  */
24
20
 
25
21
  /** Only what a test or an app injected; null means use expo-sqlite. */
26
22
  let backend = null;
27
23
 
28
- /**
29
- * expo-sqlite, adapted once and memoised.
30
- *
31
- * Unlike the other surfaces this one keeps a real reason to inject: an app with
32
- * an existing database on another driver (op-sqlite, nitro, quick,
33
- * sqlite-storage) can hand it over, and those entry points stay published for
34
- * exactly that. expo-sqlite is simply what happens when nobody does.
35
- */
24
+ /** expo-sqlite, adapted once and memoised. The only driver this module resolves. */
36
25
  let expoDriver;
37
26
 
38
27
  /**
39
- * Inject the SQLite driver. Pass `null` to clear it.
40
- *
41
- * `@webority-technologies/mobile-core` ships no database: it is pure JavaScript
42
- * and defines only this interface. Wire a driver once at startup:
43
- *
44
- * import { opSqliteDriver } from '@webority-technologies/mobile-core/sqlite/op';
45
- * setSqliteImplementation(opSqliteDriver());
28
+ * Test/showcase-only injection point — see the module header. Not a way to
29
+ * pick an alternate real driver; `@webority-technologies/mobile-core` always
30
+ * resolves expo-sqlite when nothing is injected. Pass `null` to clear it.
46
31
  */
47
32
  const setSqliteImplementation = impl => {
48
33
  backend = impl;
@@ -62,10 +47,7 @@ exports.isSqliteAvailable = isSqliteAvailable;
62
47
  const requireBackend = op => {
63
48
  const b = resolveDriver();
64
49
  if (!b) {
65
- // Naming the SETTER and an import path, not just packages to install:
66
- // installing a driver alone does nothing here, and the previous wording
67
- // ("Install one of ...") sent people to fix a thing that was not broken.
68
- const err = new Error(`[@webority-technologies/mobile-core] No SQLite driver injected; cannot ${op}. ` + 'Install a driver and wire it once at startup, e.g. ' + "`import { opSqliteDriver } from '@webority-technologies/mobile-core/sqlite/op'` " + 'then `setSqliteImplementation(opSqliteDriver())`. Drivers: @op-engineering/op-sqlite ' + '(recommended), expo-sqlite, react-native-nitro-sqlite, react-native-quick-sqlite, ' + 'react-native-sqlite-storage.');
50
+ const err = new Error(`[@webority-technologies/mobile-core] No SQLite driver available; cannot ${op}. ` + 'Install expo-sqlite (the only sanctioned driver) in the consuming app.');
69
51
  _index.Logger.error(err.message);
70
52
  throw err;
71
53
  }
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
 
3
+ import { WINDOWS_TO_IANA } from "./windowsToIanaTable.js";
3
4
  const toDate = value => {
4
5
  if (value instanceof Date) {
5
6
  return Number.isNaN(value.getTime()) ? null : value;
@@ -274,4 +275,20 @@ export const formatTimeInZone = (value, ianaTimeZone) => {
274
275
  const period = get('dayPeriod').toLowerCase();
275
276
  return `${PAD(hour)}:${minute} ${period}`;
276
277
  };
278
+
279
+ /**
280
+ * Same as {@link formatTimeInZone}, but for a .NET-style Windows timezone ID
281
+ * (e.g. `"India Standard Time"`) rather than an IANA one. .NET's own
282
+ * `TimeZoneInfo` API only knows Windows IDs, so a backend built on it hands
283
+ * these to clients directly — `Intl`, by contrast, only recognises IANA
284
+ * names, so the ID has to be translated before it can be used here. Throws
285
+ * if `windowsTimeZoneId` has no known IANA mapping.
286
+ */
287
+ export const formatTimeInWindowsZone = (value, windowsTimeZoneId) => {
288
+ const ianaTimeZone = WINDOWS_TO_IANA[windowsTimeZoneId];
289
+ if (!ianaTimeZone) {
290
+ throw new Error(`Mapping for Windows time zone '${windowsTimeZoneId}' not found.`);
291
+ }
292
+ return formatTimeInZone(value, ianaTimeZone);
293
+ };
277
294
  //# sourceMappingURL=dateMath.js.map
@@ -2,7 +2,7 @@
2
2
 
3
3
  export { formatCurrency } from "./currency.js";
4
4
  export { formatDate, formatDateTime, formatRelativeTime, formatTime } from "./date.js";
5
- export { addDays, diffMs, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatTime12h, formatTimeInZone, isDateAfter, isDateBefore, isSameDay, startOfDay } from "./dateMath.js";
5
+ export { addDays, diffMs, formatDateDDMMMYYYY, formatDateISO, formatDatePattern, formatTime12h, formatTimeInWindowsZone, formatTimeInZone, isDateAfter, isDateBefore, isSameDay, startOfDay } from "./dateMath.js";
6
6
  export { getInitials } from "./initials.js";
7
7
  export { formatCompactNumber, formatNumber, formatPercent } from "./number.js";
8
8
  export { detectPhoneCountry, formatPhone, isValidPhoneNumber, normalizePhone, parsePhoneNumber, parsePhoneNumberFromString } from "./phone.js";