@webority/mobile-core 0.0.29 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/README.md +32 -0
  2. package/lib/commonjs/api/baseUrl.js +1 -34
  3. package/lib/commonjs/api/clientHeaders.js +1 -0
  4. package/lib/commonjs/api/curl.js +1 -109
  5. package/lib/commonjs/api/minAppVersion.js +1 -0
  6. package/lib/commonjs/api/multipart.js +1 -21
  7. package/lib/commonjs/api/publicClient.js +1 -79
  8. package/lib/commonjs/api/requestDefaults.js +1 -0
  9. package/lib/commonjs/api/responseBodyText.js +1 -0
  10. package/lib/commonjs/api/retry.js +1 -91
  11. package/lib/commonjs/api/tokenRefresh.js +1 -205
  12. package/lib/commonjs/api/userClient.js +1 -265
  13. package/lib/commonjs/auth/authStore.js +1 -265
  14. package/lib/commonjs/auth/index.js +1 -44
  15. package/lib/commonjs/auth/jwt.js +1 -112
  16. package/lib/commonjs/config/index.js +1 -72
  17. package/lib/commonjs/deepLink/index.js +1 -286
  18. package/lib/commonjs/download/adapters/expoFs.js +1 -69
  19. package/lib/commonjs/download/adapters/shared.js +1 -13
  20. package/lib/commonjs/download/index.js +1 -250
  21. package/lib/commonjs/errors/extractApiError.js +1 -0
  22. package/lib/commonjs/errors/index.js +1 -0
  23. package/lib/commonjs/formatters/currency.js +1 -70
  24. package/lib/commonjs/formatters/date.js +1 -167
  25. package/lib/commonjs/formatters/dateMath.js +1 -311
  26. package/lib/commonjs/formatters/formatConfig.js +1 -0
  27. package/lib/commonjs/formatters/house.js +1 -0
  28. package/lib/commonjs/formatters/index.js +1 -246
  29. package/lib/commonjs/formatters/initials.js +1 -32
  30. package/lib/commonjs/formatters/intlCache.js +1 -37
  31. package/lib/commonjs/formatters/number.js +1 -89
  32. package/lib/commonjs/formatters/phone.js +1 -369
  33. package/lib/commonjs/formatters/windowsToIanaTable.js +1 -164
  34. package/lib/commonjs/geolocation/adapters/expoLocation.js +1 -126
  35. package/lib/commonjs/geolocation/index.js +1 -355
  36. package/lib/commonjs/index.js +1 -644
  37. package/lib/commonjs/initSDK.js +1 -66
  38. package/lib/commonjs/initUserAuth.js +1 -37
  39. package/lib/commonjs/logger/crashlytics.js +1 -0
  40. package/lib/commonjs/logger/index.js +1 -301
  41. package/lib/commonjs/logger/redact.js +1 -50
  42. package/lib/commonjs/network/index.js +1 -31
  43. package/lib/commonjs/network/networkStatus.js +1 -171
  44. package/lib/commonjs/permissions/calendar.js +1 -14
  45. package/lib/commonjs/permissions/camera.js +1 -14
  46. package/lib/commonjs/permissions/contacts.js +1 -10
  47. package/lib/commonjs/permissions/index.js +1 -133
  48. package/lib/commonjs/permissions/location.js +1 -14
  49. package/lib/commonjs/permissions/mediaLibrary.js +1 -10
  50. package/lib/commonjs/permissions/notifications.js +1 -10
  51. package/lib/commonjs/permissions/photos.js +1 -14
  52. package/lib/commonjs/phone/countries.js +1 -265
  53. package/lib/commonjs/push/index.js +1 -61
  54. package/lib/commonjs/push/push.js +1 -468
  55. package/lib/commonjs/push/status.js +1 -0
  56. package/lib/commonjs/push/task.js +1 -43
  57. package/lib/commonjs/query/apiBaseQuery.js +1 -0
  58. package/lib/commonjs/query/createAppApi.js +1 -0
  59. package/lib/commonjs/query/index.js +1 -0
  60. package/lib/commonjs/query/listeners.js +1 -0
  61. package/lib/commonjs/query/paging.js +1 -0
  62. package/lib/commonjs/query/tags.js +1 -0
  63. package/lib/commonjs/redux/errorToastMiddleware.js +1 -0
  64. package/lib/commonjs/redux/index.js +1 -0
  65. package/lib/commonjs/redux/rootReducer.js +1 -0
  66. package/lib/commonjs/redux/serializableCheck.js +1 -0
  67. package/lib/commonjs/secureScreen/index.js +1 -0
  68. package/lib/commonjs/share/index.js +1 -70
  69. package/lib/commonjs/smsRetriever/index.js +1 -91
  70. package/lib/commonjs/specs/NativeSmsRetriever.js +1 -15
  71. package/lib/commonjs/sqlite/adapters/expo.js +1 -53
  72. package/lib/commonjs/sqlite/index.js +1 -604
  73. package/lib/commonjs/storage/index.js +1 -214
  74. package/lib/commonjs/types/axios.js +1 -4
  75. package/lib/commonjs/types/globals.d.js +1 -6
  76. package/lib/commonjs/utils/base64.js +1 -24
  77. package/lib/commonjs/utils/imageCompression.js +1 -389
  78. package/lib/commonjs/utils/index.js +1 -19
  79. package/lib/commonjs/validators/index.js +1 -227
  80. package/lib/commonjs/versionCheck/buildNumber.js +1 -0
  81. package/lib/commonjs/versionCheck/index.js +1 -419
  82. package/lib/module/api/baseUrl.js +1 -30
  83. package/lib/module/api/clientHeaders.js +1 -0
  84. package/lib/module/api/curl.js +1 -104
  85. package/lib/module/api/minAppVersion.js +1 -0
  86. package/lib/module/api/multipart.js +1 -16
  87. package/lib/module/api/publicClient.js +1 -75
  88. package/lib/module/api/requestDefaults.js +1 -0
  89. package/lib/module/api/responseBodyText.js +1 -0
  90. package/lib/module/api/retry.js +1 -85
  91. package/lib/module/api/tokenRefresh.js +1 -192
  92. package/lib/module/api/userClient.js +1 -243
  93. package/lib/module/auth/authStore.js +1 -257
  94. package/lib/module/auth/index.js +1 -5
  95. package/lib/module/auth/jwt.js +1 -106
  96. package/lib/module/config/index.js +1 -64
  97. package/lib/module/deepLink/index.js +1 -280
  98. package/lib/module/download/adapters/expoFs.js +1 -64
  99. package/lib/module/download/adapters/shared.js +1 -8
  100. package/lib/module/download/index.js +1 -242
  101. package/lib/module/errors/extractApiError.js +1 -0
  102. package/lib/module/errors/index.js +1 -0
  103. package/lib/module/formatters/currency.js +1 -65
  104. package/lib/module/formatters/date.js +1 -159
  105. package/lib/module/formatters/dateMath.js +1 -295
  106. package/lib/module/formatters/formatConfig.js +1 -0
  107. package/lib/module/formatters/house.js +1 -0
  108. package/lib/module/formatters/index.js +1 -9
  109. package/lib/module/formatters/initials.js +1 -27
  110. package/lib/module/formatters/intlCache.js +1 -30
  111. package/lib/module/formatters/number.js +1 -82
  112. package/lib/module/formatters/phone.js +1 -302
  113. package/lib/module/formatters/windowsToIanaTable.js +1 -160
  114. package/lib/module/geolocation/adapters/expoLocation.js +1 -121
  115. package/lib/module/geolocation/index.js +1 -347
  116. package/lib/module/index.js +1 -57
  117. package/lib/module/initSDK.js +1 -61
  118. package/lib/module/initUserAuth.js +1 -33
  119. package/lib/module/logger/crashlytics.js +1 -0
  120. package/lib/module/logger/index.js +1 -295
  121. package/lib/module/logger/redact.js +1 -44
  122. package/lib/module/network/index.js +1 -4
  123. package/lib/module/network/networkStatus.js +1 -161
  124. package/lib/module/permissions/calendar.js +1 -15
  125. package/lib/module/permissions/camera.js +1 -15
  126. package/lib/module/permissions/contacts.js +1 -11
  127. package/lib/module/permissions/index.js +1 -128
  128. package/lib/module/permissions/location.js +1 -15
  129. package/lib/module/permissions/mediaLibrary.js +1 -11
  130. package/lib/module/permissions/notifications.js +1 -11
  131. package/lib/module/permissions/photos.js +1 -15
  132. package/lib/module/phone/countries.js +1 -261
  133. package/lib/module/push/index.js +1 -4
  134. package/lib/module/push/push.js +1 -452
  135. package/lib/module/push/status.js +1 -0
  136. package/lib/module/push/task.js +1 -38
  137. package/lib/module/query/apiBaseQuery.js +1 -0
  138. package/lib/module/query/createAppApi.js +1 -0
  139. package/lib/module/query/index.js +1 -0
  140. package/lib/module/query/listeners.js +1 -0
  141. package/lib/module/query/paging.js +1 -0
  142. package/lib/module/query/tags.js +1 -0
  143. package/lib/module/redux/errorToastMiddleware.js +1 -0
  144. package/lib/module/redux/index.js +1 -0
  145. package/lib/module/redux/rootReducer.js +1 -0
  146. package/lib/module/redux/serializableCheck.js +1 -0
  147. package/lib/module/secureScreen/index.js +1 -0
  148. package/lib/module/share/index.js +1 -64
  149. package/lib/module/smsRetriever/index.js +1 -86
  150. package/lib/module/specs/NativeSmsRetriever.js +1 -13
  151. package/lib/module/sqlite/adapters/expo.js +1 -48
  152. package/lib/module/sqlite/index.js +1 -594
  153. package/lib/module/storage/index.js +1 -208
  154. package/lib/module/types/axios.js +1 -4
  155. package/lib/module/types/globals.d.js +1 -10
  156. package/lib/module/utils/base64.js +1 -19
  157. package/lib/module/utils/imageCompression.js +1 -383
  158. package/lib/module/utils/index.js +1 -4
  159. package/lib/module/validators/index.js +1 -205
  160. package/lib/module/versionCheck/buildNumber.js +1 -0
  161. package/lib/module/versionCheck/index.js +1 -413
  162. package/lib/typescript/commonjs/api/clientHeaders.d.ts +25 -0
  163. package/lib/typescript/commonjs/api/minAppVersion.d.ts +24 -0
  164. package/lib/typescript/commonjs/api/requestDefaults.d.ts +21 -0
  165. package/lib/typescript/commonjs/api/responseBodyText.d.ts +6 -0
  166. package/lib/typescript/commonjs/api/retry.d.ts +23 -9
  167. package/lib/typescript/commonjs/api/tokenRefresh.d.ts +14 -2
  168. package/lib/typescript/commonjs/api/userClient.d.ts +1 -1
  169. package/lib/typescript/commonjs/auth/authStore.d.ts +76 -0
  170. package/lib/typescript/commonjs/auth/index.d.ts +2 -2
  171. package/lib/typescript/commonjs/config/index.d.ts +31 -2
  172. package/lib/typescript/commonjs/errors/extractApiError.d.ts +69 -0
  173. package/lib/typescript/commonjs/errors/index.d.ts +3 -0
  174. package/lib/typescript/commonjs/formatters/currency.d.ts +22 -7
  175. package/lib/typescript/commonjs/formatters/date.d.ts +13 -13
  176. package/lib/typescript/commonjs/formatters/dateMath.d.ts +4 -2
  177. package/lib/typescript/commonjs/formatters/formatConfig.d.ts +48 -0
  178. package/lib/typescript/commonjs/formatters/house.d.ts +143 -0
  179. package/lib/typescript/commonjs/formatters/index.d.ts +4 -0
  180. package/lib/typescript/commonjs/formatters/number.d.ts +15 -5
  181. package/lib/typescript/commonjs/index.d.ts +26 -8
  182. package/lib/typescript/commonjs/initSDK.d.ts +18 -6
  183. package/lib/typescript/commonjs/initUserAuth.d.ts +29 -0
  184. package/lib/typescript/commonjs/logger/crashlytics.d.ts +31 -0
  185. package/lib/typescript/commonjs/logger/index.d.ts +17 -0
  186. package/lib/typescript/commonjs/push/index.d.ts +3 -1
  187. package/lib/typescript/commonjs/push/push.d.ts +1 -1
  188. package/lib/typescript/commonjs/push/status.d.ts +9 -0
  189. package/lib/typescript/commonjs/query/apiBaseQuery.d.ts +55 -0
  190. package/lib/typescript/commonjs/query/createAppApi.d.ts +21 -0
  191. package/lib/typescript/commonjs/query/index.d.ts +9 -0
  192. package/lib/typescript/commonjs/query/listeners.d.ts +11 -0
  193. package/lib/typescript/commonjs/query/paging.d.ts +42 -0
  194. package/lib/typescript/commonjs/query/tags.d.ts +31 -0
  195. package/lib/typescript/commonjs/redux/errorToastMiddleware.d.ts +51 -0
  196. package/lib/typescript/commonjs/redux/index.d.ts +6 -0
  197. package/lib/typescript/commonjs/redux/rootReducer.d.ts +19 -0
  198. package/lib/typescript/commonjs/redux/serializableCheck.d.ts +14 -0
  199. package/lib/typescript/commonjs/secureScreen/index.d.ts +25 -0
  200. package/lib/typescript/commonjs/versionCheck/buildNumber.d.ts +14 -0
  201. package/lib/typescript/commonjs/versionCheck/index.d.ts +28 -17
  202. package/lib/typescript/module/api/clientHeaders.d.ts +25 -0
  203. package/lib/typescript/module/api/minAppVersion.d.ts +24 -0
  204. package/lib/typescript/module/api/requestDefaults.d.ts +21 -0
  205. package/lib/typescript/module/api/responseBodyText.d.ts +6 -0
  206. package/lib/typescript/module/api/retry.d.ts +23 -9
  207. package/lib/typescript/module/api/tokenRefresh.d.ts +14 -2
  208. package/lib/typescript/module/api/userClient.d.ts +1 -1
  209. package/lib/typescript/module/auth/authStore.d.ts +76 -0
  210. package/lib/typescript/module/auth/index.d.ts +2 -2
  211. package/lib/typescript/module/config/index.d.ts +31 -2
  212. package/lib/typescript/module/errors/extractApiError.d.ts +69 -0
  213. package/lib/typescript/module/errors/index.d.ts +3 -0
  214. package/lib/typescript/module/formatters/currency.d.ts +22 -7
  215. package/lib/typescript/module/formatters/date.d.ts +13 -13
  216. package/lib/typescript/module/formatters/dateMath.d.ts +4 -2
  217. package/lib/typescript/module/formatters/formatConfig.d.ts +48 -0
  218. package/lib/typescript/module/formatters/house.d.ts +143 -0
  219. package/lib/typescript/module/formatters/index.d.ts +4 -0
  220. package/lib/typescript/module/formatters/number.d.ts +15 -5
  221. package/lib/typescript/module/index.d.ts +26 -8
  222. package/lib/typescript/module/initSDK.d.ts +18 -6
  223. package/lib/typescript/module/initUserAuth.d.ts +29 -0
  224. package/lib/typescript/module/logger/crashlytics.d.ts +31 -0
  225. package/lib/typescript/module/logger/index.d.ts +17 -0
  226. package/lib/typescript/module/push/index.d.ts +3 -1
  227. package/lib/typescript/module/push/push.d.ts +1 -1
  228. package/lib/typescript/module/push/status.d.ts +9 -0
  229. package/lib/typescript/module/query/apiBaseQuery.d.ts +55 -0
  230. package/lib/typescript/module/query/createAppApi.d.ts +21 -0
  231. package/lib/typescript/module/query/index.d.ts +9 -0
  232. package/lib/typescript/module/query/listeners.d.ts +11 -0
  233. package/lib/typescript/module/query/paging.d.ts +42 -0
  234. package/lib/typescript/module/query/tags.d.ts +31 -0
  235. package/lib/typescript/module/redux/errorToastMiddleware.d.ts +51 -0
  236. package/lib/typescript/module/redux/index.d.ts +6 -0
  237. package/lib/typescript/module/redux/rootReducer.d.ts +19 -0
  238. package/lib/typescript/module/redux/serializableCheck.d.ts +14 -0
  239. package/lib/typescript/module/secureScreen/index.d.ts +25 -0
  240. package/lib/typescript/module/versionCheck/buildNumber.d.ts +14 -0
  241. package/lib/typescript/module/versionCheck/index.d.ts +28 -17
  242. package/package.json +52 -5
@@ -1,250 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.setFileSystemImplementation = exports.downloadFile = exports.DownloadError = void 0;
7
- var ExpoFileSystem = _interopRequireWildcard(require("expo-file-system"));
8
- var _reactNative = require("react-native");
9
- var _index = require("../logger/index.js");
10
- var _index2 = require("../permissions/index.js");
11
- var _expoFs = require("./adapters/expoFs.js");
12
- var _shared = require("./adapters/shared.js");
13
- 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); }
14
- const PREFIX = '[@webority/mobile-core]';
15
-
16
- /** Android stopped requiring a storage permission for a Downloads write at API 29. */
17
- const SCOPED_STORAGE_API_LEVEL = 29;
18
-
19
- /** A file can take far longer than the 30 s the fleet's JSON clients allow. */
20
- const DOWNLOAD_TIMEOUT_MS = 300000;
21
-
22
- /**
23
- * The slice of a filesystem module this module actually uses. expo-file-system
24
- * is adapted onto it, and a test or the showcase can inject its own with
25
- * `setFileSystemImplementation`.
26
- */
27
-
28
- /**
29
- * The slice of an HTTP client a download needs. The app's axios instance
30
- * (mobile-core's `userClient` or `publicClient`, or its own) satisfies it as is,
31
- * so whatever that client adds to a request (bearer token, tenant header, refresh
32
- * and retry on 401) applies to the download too. Declared structurally, as
33
- * mobile-support's client is, so no axios type leaks into the declarations.
34
- */
35
-
36
- class DownloadError extends Error {
37
- constructor(code, message, status) {
38
- super(`${PREFIX} ${message}`);
39
- this.name = 'DownloadError';
40
- this.code = code;
41
- this.status = status;
42
- // Babel's class transform can drop the prototype link, which makes
43
- // `instanceof DownloadError` false in the transpiled build.
44
- Object.setPrototypeOf(this, DownloadError.prototype);
45
- }
46
- }
47
- exports.DownloadError = DownloadError;
48
- const describe = error => error instanceof Error ? error.message : String(error);
49
-
50
- /** Only what a test or the showcase injected; null means use expo-file-system. */
51
- let backend = null;
52
-
53
- /**
54
- * expo-file-system, adapted once and memoised. The adapter is shape-checked, so
55
- * a build where the native module did not link returns null and the guided
56
- * error below still fires rather than a confusing property access.
57
- */
58
- let expoBackend;
59
- const resolveBackend = () => {
60
- if (backend) {
61
- return backend;
62
- }
63
- if (expoBackend === undefined) {
64
- expoBackend = (0, _expoFs.adaptExpoFileSystem)(ExpoFileSystem);
65
- }
66
- return expoBackend;
67
- };
68
-
69
- /**
70
- * Replace the filesystem backend. Intended for TESTS and for the showcase,
71
- * which injects a denying backend to demo the permission error; an app gets
72
- * expo-file-system without wiring anything. Pass `null` to restore it.
73
- */
74
- const setFileSystemImplementation = impl => {
75
- backend = impl;
76
- };
77
- exports.setFileSystemImplementation = setFileSystemImplementation;
78
- const requireBackend = () => {
79
- const fs = resolveBackend();
80
- if (!fs) {
81
- throw new DownloadError('unsupported', 'No filesystem module is available, so files cannot be downloaded. ' + 'expo-file-system did not load, which on a real build means the native module ' + 'was not linked.');
82
- }
83
- return fs;
84
- };
85
- const stripControlChars = value => Array.from(value).filter(char => (char.codePointAt(0) ?? 0) > 0x1f).join('');
86
- const lastSegment = raw => {
87
- const segments = raw.split(/[/\\]/);
88
- return stripControlChars(segments[segments.length - 1] ?? '').trim();
89
- };
90
-
91
- /**
92
- * Reduce a caller- or server-supplied name to a single path segment: `../../evil.pdf`
93
- * must land inside the destination directory as `evil.pdf` rather than escaping it.
94
- */
95
- const sanitiseFileName = raw => {
96
- const base = lastSegment(raw);
97
- if (base === '' || base === '.' || base === '..') {
98
- throw new DownloadError('write-failed', `"${raw}" does not contain a usable file name. Pass an explicit fileName.`);
99
- }
100
- return base;
101
- };
102
- const fileNameFromUrl = url => {
103
- const withoutQuery = url.split('#')[0]?.split('?')[0] ?? '';
104
- const last = withoutQuery.split('/').pop() ?? '';
105
- let decoded = last;
106
- try {
107
- decoded = decodeURIComponent(last);
108
- } catch {
109
- // A malformed escape sequence is not a reason to fail the download.
110
- }
111
- const base = lastSegment(decoded);
112
- return base === '' || base === '.' || base === '..' ? 'download' : base;
113
- };
114
- const androidApiLevel = () => typeof _reactNative.Platform.Version === 'number' ? _reactNative.Platform.Version : Number.parseInt(String(_reactNative.Platform.Version), 10);
115
- const ensureStoragePermission = async destination => {
116
- if (_reactNative.Platform.OS !== 'android' || destination !== 'downloads') {
117
- return;
118
- }
119
- if (androidApiLevel() >= SCOPED_STORAGE_API_LEVEL) {
120
- return;
121
- }
122
- const status = await _index2.Permissions.ensure('storage');
123
- if (status === 'granted' || status === 'limited') {
124
- return;
125
- }
126
- throw new DownloadError('permission-denied', `Storage permission is "${status}", so nothing can be written to the Downloads folder ` + 'on this Android version. Ask the user to grant it (Permissions.openSettings()), or ' + 'download to the "documents" destination instead.');
127
- };
128
- const emptyFile = url => new DownloadError('empty-file', `The download of ${url} produced an empty file, so nothing was saved. ` + 'Check that the URL is correct and that the request carried the credentials the ' + 'server expects.');
129
- const requestFailed = (error, options, fileName) => {
130
- if (options.signal?.aborted) {
131
- return new DownloadError('aborted', `The download of ${fileName} was aborted.`);
132
- }
133
- const e = error ?? {};
134
- // By name, not instanceof: a second copy of mobile-core would fail instanceof.
135
- if (e.name === 'RequestOfflineError') {
136
- return new DownloadError('network', `The device is offline, so ${options.url} was not downloaded.`);
137
- }
138
- const status = e.response?.status;
139
- if (typeof status === 'number') {
140
- return new DownloadError('http-error', `The server answered ${status} for ${options.url}, so no file was saved.`, status);
141
- }
142
- return new DownloadError('network', `The download of ${options.url} failed: ${describe(error)}`);
143
- };
144
- const discardPartial = async (fs, path) => {
145
- try {
146
- if (await fs.exists(path)) {
147
- await fs.unlink(path);
148
- }
149
- } catch (error) {
150
- _index.Logger.warn(`${PREFIX} Failed to remove the partial download at ${path}`, error);
151
- }
152
- };
153
-
154
- /**
155
- * Download a file to the device through the app's own HTTP client, so it is
156
- * authenticated exactly as the app's other calls are. The whole file is held
157
- * in memory before it is written, which suits documents and reports rather
158
- * than large media.
159
- *
160
- * A finished download is always verified to be non-empty: a 0-byte file looks
161
- * like a success to every caller and then wedges whatever consumes it, so it is
162
- * reported as `empty-file` and nothing is kept.
163
- */
164
- const downloadFile = async options => {
165
- const fs = requireBackend();
166
- const destination = options.destination ?? 'documents';
167
- const fileName = options.fileName ? sanitiseFileName(options.fileName) : fileNameFromUrl(options.url);
168
- await ensureStoragePermission(destination);
169
- const directory = fs.dirs[destination];
170
- const path = `${directory}/${fileName}`;
171
- if (options.signal?.aborted) {
172
- throw new DownloadError('aborted', `The download of ${fileName} was aborted before it started.`);
173
- }
174
- let reuseExisting = false;
175
- try {
176
- await fs.mkdir(directory);
177
- const exists = await fs.exists(path);
178
- if (exists && options.overwrite === false) {
179
- reuseExisting = true;
180
- } else if (exists) {
181
- await fs.unlink(path);
182
- }
183
- } catch (error) {
184
- throw new DownloadError('write-failed', `Could not prepare ${path} for writing: ${describe(error)}`);
185
- }
186
- if (reuseExisting) {
187
- const stat = await fs.stat(path);
188
- return {
189
- path,
190
- bytes: (0, _shared.asNumber)(stat?.size),
191
- mimeType: options.mimeType,
192
- fromCache: true
193
- };
194
- }
195
- const {
196
- onProgress
197
- } = options;
198
- let data;
199
- try {
200
- ({
201
- data
202
- } = await options.client.get(options.url, {
203
- headers: {
204
- Accept: '*/*',
205
- ...options.headers
206
- },
207
- responseType: 'arraybuffer',
208
- timeout: DOWNLOAD_TIMEOUT_MS,
209
- signal: options.signal,
210
- onDownloadProgress: onProgress ? ({
211
- loaded,
212
- total = 0
213
- }) => onProgress(loaded, total, total > 0 ? loaded / total : 0) : undefined
214
- }));
215
- } catch (error) {
216
- throw requestFailed(error, options, fileName);
217
- }
218
- if (options.signal?.aborted) {
219
- throw new DownloadError('aborted', `The download of ${fileName} was aborted.`);
220
- }
221
- const received = new Uint8Array(data ?? new ArrayBuffer(0));
222
- if (received.byteLength === 0) {
223
- throw emptyFile(options.url);
224
- }
225
- try {
226
- await fs.write(path, received);
227
- } catch (error) {
228
- await discardPartial(fs, path);
229
- throw new DownloadError('write-failed', `Could not write ${path}: ${describe(error)}`);
230
- }
231
- let bytes = 0;
232
- try {
233
- bytes = (await fs.exists(path)) ? (0, _shared.asNumber)((await fs.stat(path)).size) : 0;
234
- } catch (error) {
235
- await discardPartial(fs, path);
236
- throw new DownloadError('write-failed', `The download of ${fileName} finished but ${path} could not be read back: ${describe(error)}`);
237
- }
238
- if (bytes <= 0) {
239
- await discardPartial(fs, path);
240
- throw emptyFile(options.url);
241
- }
242
- return {
243
- path,
244
- bytes,
245
- mimeType: options.mimeType,
246
- fromCache: false
247
- };
248
- };
249
- exports.downloadFile = downloadFile;
250
- //# sourceMappingURL=index.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.setFileSystemImplementation=exports.downloadFile=exports.DownloadError=void 0;var ExpoFileSystem=_interopRequireWildcard(require("expo-file-system")),_reactNative=require("react-native"),_index=require("../logger/index.js"),_index2=require("../permissions/index.js"),_expoFs=require("./adapters/expoFs.js"),_shared=require("./adapters/shared.js");function _interopRequireWildcard(e,r){if("function"==typeof WeakMap)var t=new WeakMap,o=new WeakMap;return(_interopRequireWildcard=function(e,r){if(!r&&e&&e.__esModule)return e;var a,n,i={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return i;if(a=r?o:t){if(a.has(e))return a.get(e);a.set(e,i)}for(const r in e)"default"!==r&&{}.hasOwnProperty.call(e,r)&&((n=(a=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,r))&&(n.get||n.set)?a(i,r,n):i[r]=e[r]);return i})(e,r)}const PREFIX="[@webority/mobile-core]",SCOPED_STORAGE_API_LEVEL=29,DOWNLOAD_TIMEOUT_MS=3e5;class DownloadError extends Error{constructor(e,r,t){super(`${PREFIX} ${r}`),this.name="DownloadError",this.code=e,this.status=t,Object.setPrototypeOf(this,DownloadError.prototype)}}exports.DownloadError=DownloadError;const describe=e=>e instanceof Error?e.message:String(e);let expoBackend,backend=null;const resolveBackend=()=>backend||(void 0===expoBackend&&(expoBackend=(0,_expoFs.adaptExpoFileSystem)(ExpoFileSystem)),expoBackend),setFileSystemImplementation=e=>{backend=e};exports.setFileSystemImplementation=setFileSystemImplementation;const requireBackend=()=>{const e=resolveBackend();if(!e)throw new DownloadError("unsupported","No filesystem module is available, so files cannot be downloaded. expo-file-system did not load, which on a real build means the native module was not linked.");return e},stripControlChars=e=>Array.from(e).filter(e=>(e.codePointAt(0)??0)>31).join(""),lastSegment=e=>{const r=e.split(/[/\\]/);return stripControlChars(r[r.length-1]??"").trim()},sanitiseFileName=e=>{const r=lastSegment(e);if(""===r||"."===r||".."===r)throw new DownloadError("write-failed",`"${e}" does not contain a usable file name. Pass an explicit fileName.`);return r},fileNameFromUrl=e=>{const r=(e.split("#")[0]?.split("?")[0]??"").split("/").pop()??"";let t=r;try{t=decodeURIComponent(r)}catch{}const o=lastSegment(t);return""===o||"."===o||".."===o?"download":o},androidApiLevel=()=>"number"==typeof _reactNative.Platform.Version?_reactNative.Platform.Version:Number.parseInt(String(_reactNative.Platform.Version),10),ensureStoragePermission=async e=>{if("android"!==_reactNative.Platform.OS||"downloads"!==e)return;if(androidApiLevel()>=29)return;const r=await _index2.Permissions.ensure("storage");if("granted"!==r&&"limited"!==r)throw new DownloadError("permission-denied",`Storage permission is "${r}", so nothing can be written to the Downloads folder on this Android version. Ask the user to grant it (Permissions.openSettings()), or download to the "documents" destination instead.`)},emptyFile=e=>new DownloadError("empty-file",`The download of ${e} produced an empty file, so nothing was saved. Check that the URL is correct and that the request carried the credentials the server expects.`),requestFailed=(e,r,t)=>{if(r.signal?.aborted)return new DownloadError("aborted",`The download of ${t} was aborted.`);const o=e??{};if("RequestOfflineError"===o.name)return new DownloadError("network",`The device is offline, so ${r.url} was not downloaded.`);const a=o.response?.status;return"number"==typeof a?new DownloadError("http-error",`The server answered ${a} for ${r.url}, so no file was saved.`,a):new DownloadError("network",`The download of ${r.url} failed: ${describe(e)}`)},discardPartial=async(e,r)=>{try{await e.exists(r)&&await e.unlink(r)}catch(e){_index.Logger.warn(`${PREFIX} Failed to remove the partial download at ${r}`,e)}},downloadFile=async e=>{const r=requireBackend(),t=e.destination??"documents",o=e.fileName?sanitiseFileName(e.fileName):fileNameFromUrl(e.url);await ensureStoragePermission(t);const a=r.dirs[t],n=`${a}/${o}`;if(e.signal?.aborted)throw new DownloadError("aborted",`The download of ${o} was aborted before it started.`);let i=!1;try{await r.mkdir(a);const t=await r.exists(n);t&&!1===e.overwrite?i=!0:t&&await r.unlink(n)}catch(e){throw new DownloadError("write-failed",`Could not prepare ${n} for writing: ${describe(e)}`)}if(i){const t=await r.stat(n);return{path:n,bytes:(0,_shared.asNumber)(t?.size),mimeType:e.mimeType,fromCache:!0}}const{onProgress:s}=e;let d;try{({data:d}=await e.client.get(e.url,{headers:{Accept:"*/*",...e.headers},responseType:"arraybuffer",timeout:3e5,signal:e.signal,onDownloadProgress:s?({loaded:e,total:r=0})=>s(e,r,r>0?e/r:0):void 0}))}catch(r){throw requestFailed(r,e,o)}if(e.signal?.aborted)throw new DownloadError("aborted",`The download of ${o} was aborted.`);const l=new Uint8Array(d??new ArrayBuffer(0));if(0===l.byteLength)throw emptyFile(e.url);try{await r.write(n,l)}catch(e){throw await discardPartial(r,n),new DownloadError("write-failed",`Could not write ${n}: ${describe(e)}`)}let c=0;try{c=await r.exists(n)?(0,_shared.asNumber)((await r.stat(n)).size):0}catch(e){throw await discardPartial(r,n),new DownloadError("write-failed",`The download of ${o} finished but ${n} could not be read back: ${describe(e)}`)}if(c<=0)throw await discardPartial(r,n),emptyFile(e.url);return{path:n,bytes:c,mimeType:e.mimeType,fromCache:!1}};exports.downloadFile=downloadFile;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.UNEXPECTED_MESSAGE=exports.TIMEOUT_MESSAGE=exports.TIMEOUT_CODE=exports.SERVER_FAILURE_MESSAGE=exports.REQUEST_CANCELED_CODE=exports.OFFLINE_MESSAGE=exports.NETWORK_CODE=exports.CONTRACT_ERROR_CODE=void 0,exports.apiErrorMessage=apiErrorMessage,exports.extractApiError=extractApiError,exports.toFieldPath=exports.isNoResponse=exports.isApiError=void 0;const SERVER_FAILURE_MESSAGE=exports.SERVER_FAILURE_MESSAGE="Something went wrong on our side. Please try again in a moment.",OFFLINE_MESSAGE=exports.OFFLINE_MESSAGE="You appear to be offline. Check your connection and try again.",TIMEOUT_MESSAGE=exports.TIMEOUT_MESSAGE="That took too long to respond. Check your connection and try again.",UNEXPECTED_MESSAGE=exports.UNEXPECTED_MESSAGE="Something went wrong. Please try again.",REQUEST_CANCELED_CODE=exports.REQUEST_CANCELED_CODE="request_canceled",CONTRACT_ERROR_CODE=exports.CONTRACT_ERROR_CODE="contract_error",TIMEOUT_CODE=exports.TIMEOUT_CODE="timeout",NETWORK_CODE=exports.NETWORK_CODE="network",MAX_MESSAGE_LENGTH=300,requestFailedMessage=e=>`Request failed (${e})`,isDict=e=>"object"==typeof e&&null!==e&&!Array.isArray(e),nonEmptyString=e=>"string"==typeof e&&e.trim().length>0?e:null,looksLikeDiagnostics=e=>e.length>300||/^\s*</.test(e)||e.includes("\n at ")||/\b(Exception|StackTrace):/.test(e)||/\b(System|Microsoft)\.[A-Za-z]+\.[A-Za-z]/.test(e),userSafe=e=>{const r=nonEmptyString(e);return null===r||looksLikeDiagnostics(r)?null:r},toFieldPath=e=>e.replace(/^\$\.?/,"").split(".").map(e=>e.charAt(0).toLowerCase()+e.slice(1)).join(".");exports.toFieldPath=toFieldPath;const firstMessage=e=>{if(Array.isArray(e)){for(const r of e){const e=nonEmptyString(r);if(null!==e)return e}return null}return nonEmptyString(e)},addError=(e,r,t)=>{const s=toFieldPath(r);""===s?e.form??=t:s in e.fields||(e.fields[s]=t)},readErrors=e=>{const r={fields:{},form:null};if(Array.isArray(e)){for(const t of e){if(!isDict(t))continue;const e=nonEmptyString(t.message);null!==e&&addError(r,"string"==typeof t.field?t.field:"",e)}return r}if(!isDict(e))return r;for(const[t,s]of Object.entries(e)){const e=firstMessage(s);null!==e&&addError(r,t,e)}return r},readLegacyError=e=>{const r=e.error;return isDict(r)?nonEmptyString(r.message):nonEmptyString(r)},isApiError=e=>isDict(e)&&"string"==typeof e.message&&"number"==typeof e.status&&"boolean"==typeof e.offline&&isDict(e.fieldErrors);exports.isApiError=isApiError;const build=e=>({code:null,fieldErrors:{},status:0,offline:!1,traceId:null,detail:null,...e}),fromNoResponse=e=>{const r=nonEmptyString(e.code),t=nonEmptyString(e.name),s=nonEmptyString(e.message);return build("CanceledError"===t||"ERR_CANCELED"===r?{code:REQUEST_CANCELED_CODE,message:UNEXPECTED_MESSAGE,detail:s}:"ECONNABORTED"===r||"ETIMEDOUT"===r?{code:TIMEOUT_CODE,message:TIMEOUT_MESSAGE,offline:!0,detail:s}:"RequestOfflineError"===t||"ERR_NETWORK"===r||"Network Error"===s?{code:NETWORK_CODE,message:OFFLINE_MESSAGE,offline:!0,detail:s}:{message:UNEXPECTED_MESSAGE,detail:s})};function extractApiError(e){if(isApiError(e))return e;if("string"==typeof e)return build({message:userSafe(e)??UNEXPECTED_MESSAGE,detail:e||null});if(!isDict(e))return build({message:UNEXPECTED_MESSAGE,detail:null==e?null:String(e)});if(!0===e.isContractError)return build({code:CONTRACT_ERROR_CODE,message:userSafe(e.message)??UNEXPECTED_MESSAGE,detail:nonEmptyString(e.message)});const r=isDict(e.response)?e.response:null,t="number"==typeof r?.status?r.status:"number"==typeof e.status?e.status:0,s=r?r.data:e.body;if(0===t&&null==s)return fromNoResponse(e);const E=isDict(s)?s:null,{fields:o,form:n}=readErrors(E?.errors),i=nonEmptyString(E?.code),a=nonEmptyString(E?.traceId),l=nonEmptyString(E?.message)??nonEmptyString(E?.detail)??(E?readLegacyError(E):null)??nonEmptyString(E?.title)??nonEmptyString(s)??nonEmptyString(e.message);let S;return S=t>=500?SERVER_FAILURE_MESSAGE:userSafe(Object.values(o)[0])??userSafe(n)??userSafe(E?.message)??userSafe(E?.detail)??(E?userSafe(readLegacyError(E)):null)??userSafe(E?.title)??userSafe(s)??(t?requestFailedMessage(t):UNEXPECTED_MESSAGE),build({code:i,message:S,fieldErrors:o,status:t,traceId:a,detail:l})}const isNoResponse=e=>extractApiError(e).offline;function apiErrorMessage(e,r){const t=extractApiError(e);if(t.offline||null!==r&&!r)return t.message;return t.status>=500||t.code===REQUEST_CANCELED_CODE||t.message===UNEXPECTED_MESSAGE||t.message===requestFailedMessage(t.status)?r??null:t.message}exports.isNoResponse=isNoResponse;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"CONTRACT_ERROR_CODE",{enumerable:!0,get:function(){return _extractApiError.CONTRACT_ERROR_CODE}}),Object.defineProperty(exports,"NETWORK_CODE",{enumerable:!0,get:function(){return _extractApiError.NETWORK_CODE}}),Object.defineProperty(exports,"OFFLINE_MESSAGE",{enumerable:!0,get:function(){return _extractApiError.OFFLINE_MESSAGE}}),Object.defineProperty(exports,"REQUEST_CANCELED_CODE",{enumerable:!0,get:function(){return _extractApiError.REQUEST_CANCELED_CODE}}),Object.defineProperty(exports,"SERVER_FAILURE_MESSAGE",{enumerable:!0,get:function(){return _extractApiError.SERVER_FAILURE_MESSAGE}}),Object.defineProperty(exports,"TIMEOUT_CODE",{enumerable:!0,get:function(){return _extractApiError.TIMEOUT_CODE}}),Object.defineProperty(exports,"TIMEOUT_MESSAGE",{enumerable:!0,get:function(){return _extractApiError.TIMEOUT_MESSAGE}}),Object.defineProperty(exports,"UNEXPECTED_MESSAGE",{enumerable:!0,get:function(){return _extractApiError.UNEXPECTED_MESSAGE}}),Object.defineProperty(exports,"apiErrorMessage",{enumerable:!0,get:function(){return _extractApiError.apiErrorMessage}}),Object.defineProperty(exports,"extractApiError",{enumerable:!0,get:function(){return _extractApiError.extractApiError}}),Object.defineProperty(exports,"isApiError",{enumerable:!0,get:function(){return _extractApiError.isApiError}}),Object.defineProperty(exports,"isNoResponse",{enumerable:!0,get:function(){return _extractApiError.isNoResponse}}),Object.defineProperty(exports,"toFieldPath",{enumerable:!0,get:function(){return _extractApiError.toFieldPath}});var _extractApiError=require("./extractApiError.js");
@@ -1,70 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.formatCurrency = void 0;
7
- var _intlCache = require("./intlCache.js");
8
- const hasIntlNumber = () => typeof Intl !== 'undefined' && typeof Intl.NumberFormat === 'function';
9
- const indianGroupingFallback = (n, fractionDigits) => {
10
- // Indian numbering: 1,23,45,678.90 (last 3 digits, then groups of 2).
11
- const sign = n < 0 ? '-' : '';
12
- const abs = Math.abs(n);
13
- const fixed = abs.toFixed(fractionDigits);
14
- const [intPart, decPart] = fixed.split('.');
15
- const last3 = intPart.length > 3 ? intPart.slice(-3) : intPart;
16
- const rest = intPart.length > 3 ? intPart.slice(0, -3) : '';
17
- const grouped = rest ? rest.replace(/\B(?=(\d{2})+(?!\d))/g, ',') + ',' + last3 : last3;
18
- return sign + grouped + (decPart ? `.${decPart}` : '');
19
- };
20
-
21
- /**
22
- * Format an amount as currency. Defaults to **INR** with Indian numbering (`en-IN`),
23
- * which matches the standard convention across Webority projects.
24
- *
25
- * @example
26
- * formatCurrency(150000) // ₹1,50,000
27
- * formatCurrency(1234.5) // ₹1,234.50
28
- * formatCurrency(99, { currency: 'USD', locale: 'en-US' }) // $99.00
29
- * formatCurrency(150000, { stripSymbol: true }) // 1,50,000
30
- */
31
- const formatCurrency = (amount, options = {}) => {
32
- if (amount == null || Number.isNaN(amount)) {
33
- return '';
34
- }
35
- const {
36
- currency = 'INR',
37
- locale = 'en-IN',
38
- minimumFractionDigits,
39
- maximumFractionDigits = 2,
40
- stripSymbol = false
41
- } = options;
42
- const minFrac = minimumFractionDigits ?? (Number.isInteger(amount) ? 0 : 2);
43
- if (hasIntlNumber()) {
44
- try {
45
- const formatted = (0, _intlCache.numberFormat)(locale, {
46
- style: 'currency',
47
- currency,
48
- minimumFractionDigits: minFrac,
49
- maximumFractionDigits
50
- }).format(amount);
51
- if (!stripSymbol) {
52
- return formatted;
53
- }
54
- // Strip currency code/symbol while keeping digits, separators and sign.
55
- return formatted.replace(/[^\d,.\s\-+]/g, '').trim();
56
- } catch {
57
- /* fall through to fallback */
58
- }
59
- }
60
- const numeric = indianGroupingFallback(amount, minFrac);
61
- if (stripSymbol) {
62
- return numeric;
63
- }
64
- if (currency === 'INR') {
65
- return `₹${numeric}`;
66
- }
67
- return `${currency} ${numeric}`;
68
- };
69
- exports.formatCurrency = formatCurrency;
70
- //# sourceMappingURL=currency.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.formatCurrency=void 0;var _formatConfig=require("./formatConfig.js"),_intlCache=require("./intlCache.js");const hasIntlNumber=()=>"undefined"!=typeof Intl&&"function"==typeof Intl.NumberFormat,indianGroupingFallback=(r,t)=>{const e=r<0?"-":"",n=Math.abs(r).toFixed(t),[i,o]=n.split("."),m=i.length>3?i.slice(-3):i,u=i.length>3?i.slice(0,-3):"";return e+(u?u.replace(/\B(?=(\d{2})+(?!\d))/g,",")+","+m:m)+(o?`.${o}`:"")},toAmount=r=>{if(null==r||"string"==typeof r&&""===r.trim())return null;const t="number"==typeof r?r:Number(r);return Number.isFinite(t)?t:null},currencyDigits=(r,t)=>(0,_intlCache.numberFormat)(r,{style:"currency",currency:t}).resolvedOptions().maximumFractionDigits??2,formatCurrency=(r,t={})=>{const{currency:e="INR",locale:n=(0,_formatConfig.configuredLocale)()??"en-IN",minimumFractionDigits:i,maximumFractionDigits:o,stripSymbol:m=!1,empty:u=((0,_formatConfig.isFormatterConfigured)("locale")||(0,_formatConfig.isFormatterConfigured)("empty")?(0,_formatConfig.getFormatterConfig)().empty:""),...a}=t,c=toAmount(r);if(null===c)return u;if(hasIntlNumber())try{const r=o??currencyDigits(n,e),t=i??(Number.isInteger(c)?0:r),u=(0,_intlCache.numberFormat)(n,{...a,style:"currency",currency:e,minimumFractionDigits:t,maximumFractionDigits:Math.max(t,r)}).format(c);return m?u.replace(/[^\d,.\s\-+]/g,"").trim():u}catch{}const s=indianGroupingFallback(c,i??(Number.isInteger(c)?0:2));return m?s:"INR"===e?`₹${s}`:`${e} ${s}`};exports.formatCurrency=formatCurrency;
@@ -1,167 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.formatTime = exports.formatRelativeTime = exports.formatDateTime = exports.formatDate = void 0;
7
- var _intlCache = require("./intlCache.js");
8
- const toDate = value => {
9
- if (value instanceof Date) {
10
- return Number.isNaN(value.getTime()) ? null : value;
11
- }
12
- const d = new Date(value);
13
- return Number.isNaN(d.getTime()) ? null : d;
14
- };
15
- const hasIntl = () => typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat === 'function';
16
- const PAD = n => n < 10 ? `0${n}` : `${n}`;
17
- const fallbackDate = (d, style) => {
18
- const day = PAD(d.getDate());
19
- const monthShort = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][d.getMonth()];
20
- const monthLong = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][d.getMonth()];
21
- const year = d.getFullYear();
22
- const weekdayLong = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][d.getDay()];
23
- switch (style) {
24
- case 'short':
25
- return `${day}/${PAD(d.getMonth() + 1)}/${year}`;
26
- case 'long':
27
- return `${day} ${monthLong} ${year}`;
28
- case 'full':
29
- return `${weekdayLong}, ${day} ${monthLong} ${year}`;
30
- case 'medium':
31
- default:
32
- return `${day} ${monthShort} ${year}`;
33
- }
34
- };
35
- const fallbackTime = (d, style) => {
36
- const hh = PAD(d.getHours());
37
- const mm = PAD(d.getMinutes());
38
- if (style === 'short') {
39
- return `${hh}:${mm}`;
40
- }
41
- const ss = PAD(d.getSeconds());
42
- return `${hh}:${mm}:${ss}`;
43
- };
44
-
45
- /**
46
- * Locale-aware date formatter. Defaults to `'medium'` style and `'en-IN'` locale,
47
- * matching the Indian-locale convention used across Webority apps.
48
- */
49
- const formatDate = (value, style = 'medium', locale = 'en-IN') => {
50
- const d = toDate(value);
51
- if (!d) {
52
- return '';
53
- }
54
- if (hasIntl()) {
55
- try {
56
- return (0, _intlCache.dateTimeFormat)(locale, {
57
- dateStyle: style
58
- }).format(d);
59
- } catch {
60
- /* fall through to fallback */
61
- }
62
- }
63
- return fallbackDate(d, style);
64
- };
65
-
66
- /**
67
- * Locale-aware time formatter (24-hour fallback when Intl is unavailable).
68
- */
69
- exports.formatDate = formatDate;
70
- const formatTime = (value, style = 'short', locale = 'en-IN') => {
71
- const d = toDate(value);
72
- if (!d) {
73
- return '';
74
- }
75
- if (hasIntl()) {
76
- try {
77
- return (0, _intlCache.dateTimeFormat)(locale, {
78
- timeStyle: style
79
- }).format(d);
80
- } catch {
81
- /* fall through */
82
- }
83
- }
84
- return fallbackTime(d, style);
85
- };
86
-
87
- /**
88
- * Combined date + time formatter.
89
- */
90
- exports.formatTime = formatTime;
91
- const formatDateTime = (value, dateStyle = 'medium', timeStyle = 'short', locale = 'en-IN') => {
92
- const d = toDate(value);
93
- if (!d) {
94
- return '';
95
- }
96
- if (hasIntl()) {
97
- try {
98
- return (0, _intlCache.dateTimeFormat)(locale, {
99
- dateStyle,
100
- timeStyle
101
- }).format(d);
102
- } catch {
103
- /* fall through */
104
- }
105
- }
106
- return `${fallbackDate(d, dateStyle)}, ${fallbackTime(d, timeStyle)}`;
107
- };
108
- exports.formatDateTime = formatDateTime;
109
- const SECOND = 1000;
110
- const MINUTE = 60 * SECOND;
111
- const HOUR = 60 * MINUTE;
112
- const DAY = 24 * HOUR;
113
- const WEEK = 7 * DAY;
114
- const MONTH = 30 * DAY;
115
- const YEAR = 365 * DAY;
116
-
117
- /**
118
- * Returns a humanized relative-time string (e.g. "5 minutes ago", "in 3 days").
119
- * Uses `Intl.RelativeTimeFormat` when available; otherwise a sensible English fallback.
120
- */
121
- const formatRelativeTime = (value, base = new Date(), locale = 'en-IN') => {
122
- const target = toDate(value);
123
- const now = toDate(base);
124
- if (!target || !now) {
125
- return '';
126
- }
127
- const diffMs = target.getTime() - now.getTime();
128
- const abs = Math.abs(diffMs);
129
- let unit;
130
- let amount;
131
- if (abs < MINUTE) {
132
- unit = 'second';
133
- amount = Math.round(diffMs / SECOND);
134
- } else if (abs < HOUR) {
135
- unit = 'minute';
136
- amount = Math.round(diffMs / MINUTE);
137
- } else if (abs < DAY) {
138
- unit = 'hour';
139
- amount = Math.round(diffMs / HOUR);
140
- } else if (abs < WEEK) {
141
- unit = 'day';
142
- amount = Math.round(diffMs / DAY);
143
- } else if (abs < MONTH) {
144
- unit = 'week';
145
- amount = Math.round(diffMs / WEEK);
146
- } else if (abs < YEAR) {
147
- unit = 'month';
148
- amount = Math.round(diffMs / MONTH);
149
- } else {
150
- unit = 'year';
151
- amount = Math.round(diffMs / YEAR);
152
- }
153
- const Rtf = hasIntl() ? Intl.RelativeTimeFormat : undefined;
154
- if (typeof Rtf === 'function') {
155
- try {
156
- return (0, _intlCache.relativeTimeFormat)(Rtf, locale).format(amount, unit);
157
- } catch {
158
- /* fall through */
159
- }
160
- }
161
- const past = amount < 0;
162
- const n = Math.abs(amount);
163
- const u = n === 1 ? unit : `${unit}s`;
164
- return past ? `${n} ${u} ago` : `in ${n} ${u}`;
165
- };
166
- exports.formatRelativeTime = formatRelativeTime;
167
- //# sourceMappingURL=date.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.formatDate=formatDate,exports.formatDateTime=formatDateTime,exports.formatRelativeTime=void 0,exports.formatTime=formatTime;var _house=require("./house.js"),_intlCache=require("./intlCache.js");const toDate=t=>{if(t instanceof Date)return Number.isNaN(t.getTime())?null:t;const e=new Date(t);return Number.isNaN(e.getTime())?null:e},hasIntl=()=>"undefined"!=typeof Intl&&"function"==typeof Intl.DateTimeFormat,PAD=t=>t<10?`0${t}`:`${t}`,fallbackDate=(t,e)=>{const a=PAD(t.getDate()),r=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][t.getMonth()],n=["January","February","March","April","May","June","July","August","September","October","November","December"][t.getMonth()],o=t.getFullYear(),i=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"][t.getDay()];switch(e){case"short":return`${a}/${PAD(t.getMonth()+1)}/${o}`;case"long":return`${a} ${n} ${o}`;case"full":return`${i}, ${a} ${n} ${o}`;default:return`${a} ${r} ${o}`}},fallbackTime=(t,e)=>{const a=PAD(t.getHours()),r=PAD(t.getMinutes());if("short"===e)return`${a}:${r}`;return`${a}:${r}:${PAD(t.getSeconds())}`},isStyle=t=>"string"==typeof t;function formatDate(t,e,a="en-IN"){if(!isStyle(e))return(0,_house.formatDate)(t,e);const r=e,n=toDate(t);if(!n)return"";if(hasIntl())try{return(0,_intlCache.dateTimeFormat)(a,{dateStyle:r}).format(n)}catch{}return fallbackDate(n,r)}function formatTime(t,e,a="en-IN"){if(!isStyle(e))return(0,_house.formatTime)(t,e);const r=e,n=toDate(t);if(!n)return"";if(hasIntl())try{return(0,_intlCache.dateTimeFormat)(a,{timeStyle:r}).format(n)}catch{}return fallbackTime(n,r)}function formatDateTime(t,e,a="short",r="en-IN"){if(!isStyle(e))return(0,_house.formatDateTime)(t,e);const n=e,o=toDate(t);if(!o)return"";if(hasIntl())try{return(0,_intlCache.dateTimeFormat)(r,{dateStyle:n,timeStyle:a}).format(o)}catch{}return`${fallbackDate(o,n)}, ${fallbackTime(o,a)}`}const SECOND=1e3,MINUTE=6e4,HOUR=36e5,DAY=24*HOUR,WEEK=7*DAY,MONTH=30*DAY,YEAR=365*DAY,formatRelativeTime=(t,e=new Date,a="en-IN")=>{const r=toDate(t),n=toDate(e);if(!r||!n)return"";const o=r.getTime()-n.getTime(),i=Math.abs(o);let u,m;i<6e4?(u="second",m=Math.round(o/1e3)):i<HOUR?(u="minute",m=Math.round(o/6e4)):i<DAY?(u="hour",m=Math.round(o/HOUR)):i<WEEK?(u="day",m=Math.round(o/DAY)):i<MONTH?(u="week",m=Math.round(o/WEEK)):i<YEAR?(u="month",m=Math.round(o/MONTH)):(u="year",m=Math.round(o/YEAR));const s=hasIntl()?Intl.RelativeTimeFormat:void 0;if("function"==typeof s)try{return(0,_intlCache.relativeTimeFormat)(s,a).format(m,u)}catch{}const l=m<0,f=Math.abs(m),c=1===f?u:`${u}s`;return l?`${f} ${c} ago`:`in ${f} ${c}`};exports.formatRelativeTime=formatRelativeTime;