@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,265 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = exports.SESSION_TERMINATION_CODES = exports.SESSION_INVALID_HEADER = exports.RequestOfflineError = void 0;
7
- Object.defineProperty(exports, "injectStore", {
8
- enumerable: true,
9
- get: function () {
10
- return _tokenRefresh.injectStore;
11
- }
12
- });
13
- Object.defineProperty(exports, "injectUserAuth", {
14
- enumerable: true,
15
- get: function () {
16
- return _tokenRefresh.injectUserAuth;
17
- }
18
- });
19
- Object.defineProperty(exports, "resetRefreshState", {
20
- enumerable: true,
21
- get: function () {
22
- return _tokenRefresh.resetRefreshState;
23
- }
24
- });
25
- var _axios = _interopRequireWildcard(require("axios"));
26
- var _authStore = require("../auth/authStore.js");
27
- var _index = require("../config/index.js");
28
- var _index2 = require("../logger/index.js");
29
- var _networkStatus = require("../network/networkStatus.js");
30
- require("../types/axios.js");
31
- var _baseUrl = require("./baseUrl.js");
32
- var _curl = require("./curl.js");
33
- var _multipart = require("./multipart.js");
34
- var _retry = require("./retry.js");
35
- var _tokenRefresh = require("./tokenRefresh.js");
36
- 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); }
37
- // Define timeout for requests
38
- const REQUEST_TIMEOUT = 30000; // 30 seconds
39
-
40
- /**
41
- * Thrown by the request interceptor when the device is offline, before the
42
- * request ever reaches the adapter (and therefore the network). Distinct from
43
- * an AxiosError so callers can show an offline message instead of a generic
44
- * request failure.
45
- */
46
- class RequestOfflineError extends Error {
47
- constructor(message = 'Request blocked: device is offline') {
48
- super(message);
49
- this.name = 'RequestOfflineError';
50
- // Babel's class transform can drop the prototype link, which makes
51
- // `instanceof RequestOfflineError` false in the transpiled build.
52
- Object.setPrototypeOf(this, RequestOfflineError.prototype);
53
- }
54
- }
55
-
56
- /**
57
- * Sub-codes a 401 response body carries when the session itself is dead
58
- * (terminated by an admin, or expired server-side) rather than merely
59
- * out-of-date. These never warrant a refresh attempt — only logout.
60
- */
61
- exports.RequestOfflineError = RequestOfflineError;
62
- const SESSION_TERMINATION_CODES = exports.SESSION_TERMINATION_CODES = {
63
- TERMINATED: 'SESSION_TERMINATED',
64
- EXPIRED: 'SESSION_EXPIRED'
65
- };
66
- const TERMINATION_CODES = new Set(Object.values(SESSION_TERMINATION_CODES));
67
-
68
- /**
69
- * The header is the AUTHORITATIVE signal, verified against the backend:
70
- * `WeborityJwtMiddleware.ReturnUnauthorized` answers an invalidated session with
71
- * `401` + `X-Security-Stamp-Invalid: true` and a body of
72
- * `{ error: 'Unauthorized', message: '...' }` — no code field at all, and
73
- * `error` is a string rather than an object. An earlier version of this checked
74
- * only body fields and would therefore never have fired against a real server.
75
- *
76
- * The body codes below are kept as a secondary path for any head that does send
77
- * an explicit sub-code; they match on exact strings, so looking is free.
78
- */
79
- const SESSION_INVALID_HEADER = exports.SESSION_INVALID_HEADER = 'x-security-stamp-invalid';
80
- const hasSessionInvalidHeader = headers => {
81
- if (!headers || typeof headers !== 'object') {
82
- return false;
83
- }
84
- const get = headers.get;
85
- const raw = typeof get === 'function' ? get.call(headers, SESSION_INVALID_HEADER) : headers[SESSION_INVALID_HEADER];
86
- return String(raw).toLowerCase() === 'true';
87
- };
88
- const getSessionTerminationCode = data => {
89
- if (!data || typeof data !== 'object') {
90
- return undefined;
91
- }
92
- const body = data;
93
- const nested = body.error;
94
- const candidates = [body.code, body.errorCode, nested && typeof nested === 'object' ? nested.code : undefined];
95
- for (const candidate of candidates) {
96
- if (typeof candidate === 'string' && TERMINATION_CODES.has(candidate)) {
97
- return candidate;
98
- }
99
- }
100
- return undefined;
101
- };
102
-
103
- /**
104
- * Internal extension of axios request config to track retry attempts.
105
- */
106
-
107
- const userClient = _axios.default.create({
108
- headers: {
109
- 'Content-Type': 'application/json',
110
- 'Accept-Encoding': 'gzip, deflate, br'
111
- },
112
- timeout: REQUEST_TIMEOUT // Set timeout for all requests
113
- });
114
-
115
- // Registered before the auth interceptors below, so a retryable 5xx is retried
116
- // before anything else sees it while a 401 still falls through to the refresh
117
- // flow. Policy and reasoning live in ./retry.
118
- (0, _retry.attachRetry)(userClient);
119
- const setAuthHeader = (config, token) => {
120
- if (config.headers instanceof _axios.AxiosHeaders) {
121
- config.headers.set('Authorization', `Bearer ${token}`);
122
- } else {
123
- // Fallback in case headers were provided as a plain object.
124
- config.headers = _axios.AxiosHeaders.from({
125
- ...config.headers,
126
- Authorization: `Bearer ${token}`
127
- });
128
- }
129
- };
130
- const isRefreshTokenRequest = url => {
131
- const path = (0, _tokenRefresh.getRefreshPath)();
132
- return !!path && !!url?.includes(path);
133
- };
134
-
135
- /**
136
- * Attach Authorization Token Before Requests
137
- */
138
- // Registered after the curl logger and before the auth interceptor, so that it
139
- // RUNS between them: axios unshifts its request chain, making the first
140
- // registered run last. The curl line therefore describes a request that already
141
- // has both its baseURL and its Authorization header.
142
- (0, _baseUrl.applyConfiguredBaseUrl)(userClient);
143
- (0, _multipart.sendFormDataAsMultipart)(userClient);
144
-
145
- // Registered BEFORE the auth interceptor below deliberately. Axios builds its
146
- // request chain by unshifting, so the FIRST-registered request interceptor runs
147
- // LAST — closest to dispatch. This one therefore observes the final config,
148
- // with the Authorization header already attached, which is the whole point of
149
- // a curl line. Registering it after would log the request before it is signed.
150
- userClient.interceptors.request.use(config => {
151
- if ((0, _index.getConfigValue)('logCurl')) {
152
- (0, _curl.logCurl)(config);
153
- }
154
- return config;
155
- });
156
- userClient.interceptors.request.use(async config => {
157
- // Reject before any network call when the device is known to be offline.
158
- // Unknown connectivity (netinfo not installed, or undetermined) is treated
159
- // as online — never block a request on an unavailable probe.
160
- const network = await (0, _networkStatus.getLastKnownNetworkStatus)();
161
- if (network.isConnected === false) {
162
- _index2.Logger.warn(`Request blocked: device is offline. URL: ${config.url}`);
163
- return Promise.reject(new RequestOfflineError());
164
- }
165
- try {
166
- // Skip token check for refresh token endpoint to prevent infinite loop
167
- if (isRefreshTokenRequest(config.url)) {
168
- return config;
169
- }
170
- const token = await (0, _authStore.getToken)(_authStore.ACCESS_TOKEN_KEY);
171
-
172
- // Check if token exists
173
- if (!token?.token) {
174
- throw new Error('No access token available');
175
- }
176
-
177
- // Check if token is expired
178
- const currentTime = Date.now();
179
- const tokenExpiry = Date.parse(token.expiry);
180
- const bufferTime = 30 * 1000; // 30 seconds buffer
181
-
182
- // If token is expired or about to expire, try to refresh it first
183
- if (tokenExpiry <= currentTime + bufferTime) {
184
- _index2.Logger.info('Access token expired or about to expire, refreshing before request');
185
-
186
- // Joins a refresh already in flight rather than starting a second one.
187
- const newToken = await (0, _tokenRefresh.refreshAccessToken)();
188
- setAuthHeader(config, newToken);
189
- return config;
190
- }
191
-
192
- // Token is valid, proceed with request
193
- setAuthHeader(config, token.token);
194
- return config;
195
- } catch (error) {
196
- _index2.Logger.error('Failed to attach token:', (0, _tokenRefresh.getErrorMessage)(error));
197
- return Promise.reject(error);
198
- }
199
- }, error => {
200
- _index2.Logger.error('Request error:', (0, _tokenRefresh.getErrorMessage)(error));
201
- return Promise.reject(error);
202
- });
203
-
204
- /**
205
- * Handle Response & Token Refresh
206
- */
207
- userClient.interceptors.response.use(response => response, async error => {
208
- if (!_axios.default.isAxiosError(error)) {
209
- _index2.Logger.error(`Non-axios error in response interceptor: ${(0, _tokenRefresh.getErrorMessage)(error)}`);
210
- return Promise.reject(error);
211
- }
212
- const axiosError = error;
213
- const originalRequest = axiosError.config;
214
- if (!axiosError.response) {
215
- if (!originalRequest?.skipErrorLog) {
216
- _index2.Logger.error(`Network error or no response from server: ${axiosError.message}, URL: ${originalRequest?.url}`);
217
- }
218
- return Promise.reject(error);
219
- }
220
- if (axiosError.response.status === 401 && originalRequest && !originalRequest._retry) {
221
- // The refresh call goes through this client. A 401 on it must not queue behind
222
- // refreshTokenPromise: that promise is the call itself, so queueing deadlocks it
223
- // and every later 401 waits forever.
224
- if (isRefreshTokenRequest(originalRequest.url)) {
225
- return Promise.reject(error);
226
- }
227
- const terminationCode = getSessionTerminationCode(axiosError.response.data) ?? (hasSessionInvalidHeader(axiosError.response.headers) ? SESSION_TERMINATION_CODES.TERMINATED : undefined);
228
- if (terminationCode) {
229
- // The session is dead server-side — a refresh would only burn a
230
- // pointless round-trip, so go straight to logout.
231
- _index2.Logger.warn(`Session ${terminationCode}, logging out without refresh. URL: ${originalRequest.url}`);
232
- (0, _tokenRefresh.resetRefreshState)();
233
- await (0, _tokenRefresh.dispatchLogout)();
234
- return Promise.reject(error);
235
- }
236
- _index2.Logger.warn(`Unauthorized URL: ${originalRequest.url}`);
237
- originalRequest._retry = true;
238
-
239
- // If we already have a refresh in progress, queue this request
240
- if ((0, _tokenRefresh.isRefreshInFlight)()) {
241
- return (0, _tokenRefresh.queueBehindRefresh)().then(token => {
242
- _index2.Logger.info('Retrying request after token refresh:', originalRequest.url);
243
- setAuthHeader(originalRequest, token);
244
- return userClient(originalRequest);
245
- }).catch(err => {
246
- _index2.Logger.error('Failed to retry request after token refresh:', (0, _tokenRefresh.getErrorMessage)(err));
247
- return Promise.reject(err);
248
- });
249
- }
250
- try {
251
- // Start a new token refresh process and wait for it to complete
252
- const newToken = await (0, _tokenRefresh.refreshAccessToken)();
253
- setAuthHeader(originalRequest, newToken);
254
- return userClient(originalRequest);
255
- } catch (err) {
256
- return Promise.reject(err);
257
- }
258
- }
259
- if (!originalRequest?.skipErrorLog) {
260
- _index2.Logger.error(`Response error: ${axiosError.response?.data ?? axiosError.message}, URL: ${originalRequest?.url}, Status: ${axiosError.response.status}`);
261
- }
262
- return Promise.reject(error);
263
- });
264
- var _default = exports.default = userClient;
265
- //# sourceMappingURL=userClient.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.SESSION_TERMINATION_CODES=exports.SESSION_INVALID_HEADER=exports.RequestOfflineError=void 0,Object.defineProperty(exports,"SIGN_OUT_REASON_HEADER",{enumerable:!0,get:function(){return _tokenRefresh.SIGN_OUT_REASON_HEADER}}),exports.default=void 0,Object.defineProperty(exports,"injectStore",{enumerable:!0,get:function(){return _tokenRefresh.injectStore}}),Object.defineProperty(exports,"injectUserAuth",{enumerable:!0,get:function(){return _tokenRefresh.injectUserAuth}}),Object.defineProperty(exports,"resetRefreshState",{enumerable:!0,get:function(){return _tokenRefresh.resetRefreshState}});var _axios=_interopRequireWildcard(require("axios")),_authStore=require("../auth/authStore.js"),_index=require("../config/index.js"),_index2=require("../logger/index.js"),_networkStatus=require("../network/networkStatus.js");require("../types/axios.js");var _baseUrl=require("./baseUrl.js"),_clientHeaders=require("./clientHeaders.js"),_curl=require("./curl.js"),_minAppVersion=require("./minAppVersion.js"),_multipart=require("./multipart.js"),_requestDefaults=require("./requestDefaults.js"),_responseBodyText=require("./responseBodyText.js"),_retry=require("./retry.js"),_tokenRefresh=require("./tokenRefresh.js");function _interopRequireWildcard(e,r){if("function"==typeof WeakMap)var t=new WeakMap,s=new WeakMap;return(_interopRequireWildcard=function(e,r){if(!r&&e&&e.__esModule)return e;var o,n,i={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return i;if(o=r?s:t){if(o.has(e))return o.get(e);o.set(e,i)}for(const r in e)"default"!==r&&{}.hasOwnProperty.call(e,r)&&((n=(o=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,r))&&(n.get||n.set)?o(i,r,n):i[r]=e[r]);return i})(e,r)}class RequestOfflineError extends Error{constructor(e="Request blocked: device is offline"){super(e),this.name="RequestOfflineError",Object.setPrototypeOf(this,RequestOfflineError.prototype)}}exports.RequestOfflineError=RequestOfflineError;const SESSION_TERMINATION_CODES=exports.SESSION_TERMINATION_CODES={TERMINATED:"SESSION_TERMINATED",EXPIRED:"SESSION_EXPIRED"},TERMINATION_CODES=new Set(Object.values(SESSION_TERMINATION_CODES)),SESSION_INVALID_HEADER=exports.SESSION_INVALID_HEADER="x-security-stamp-invalid",hasSessionInvalidHeader=e=>{if(!e||"object"!=typeof e)return!1;const r=e.get,t="function"==typeof r?r.call(e,SESSION_INVALID_HEADER):e[SESSION_INVALID_HEADER];return"true"===String(t).toLowerCase()},getSessionTerminationCode=e=>{if(!e||"object"!=typeof e)return;const r=e,t=r.error,s=[r.code,r.errorCode,t&&"object"==typeof t?t.code:void 0];for(const e of s)if("string"==typeof e&&TERMINATION_CODES.has(e))return e},userClient=_axios.default.create({headers:{"Content-Type":"application/json"}});(0,_minAppVersion.readMinAppVersion)(userClient),(0,_retry.attachRetry)(userClient);const setAuthHeader=(e,r)=>{e.headers instanceof _axios.AxiosHeaders?e.headers.set("Authorization",`Bearer ${r}`):e.headers=_axios.AxiosHeaders.from({...e.headers,Authorization:`Bearer ${r}`})},isRefreshTokenRequest=e=>{const r=(0,_tokenRefresh.getRefreshPath)();return!!r&&!!e?.includes(r)};(0,_baseUrl.applyConfiguredBaseUrl)(userClient),(0,_requestDefaults.applyRequestDefaults)(userClient),(0,_multipart.sendFormDataAsMultipart)(userClient),userClient.interceptors.request.use(e=>((0,_index.getConfigValue)("logCurl")&&(0,_curl.logCurl)(e),e)),(0,_clientHeaders.applyClientHeaders)(userClient),userClient.interceptors.request.use(async e=>{if(!1===(await(0,_networkStatus.getLastKnownNetworkStatus)()).isConnected)return _index2.Logger.warn(`Request blocked: device is offline. URL: ${e.url}`),Promise.reject(new RequestOfflineError);try{if(isRefreshTokenRequest(e.url))return e;const r=await(0,_authStore.getToken)(_authStore.ACCESS_TOKEN_KEY);if(!r?.token)throw new Error("No access token available");const t=Date.now(),s=Date.parse(r.expiry);if(s<=t+3e4){_index2.Logger.info("Access token expired or about to expire, refreshing before request");const r=await(0,_tokenRefresh.refreshAccessToken)();return setAuthHeader(e,r),await(0,_clientHeaders.applyAccountIdHeader)(e.headers,(0,_tokenRefresh.getAccountIdProvider)()),e}return setAuthHeader(e,r.token),await(0,_clientHeaders.applyAccountIdHeader)(e.headers,(0,_tokenRefresh.getAccountIdProvider)()),e}catch(e){return _index2.Logger.error("Failed to attach token:",(0,_tokenRefresh.getErrorMessage)(e)),Promise.reject(e)}},e=>(_index2.Logger.error("Request error:",(0,_tokenRefresh.getErrorMessage)(e)),Promise.reject(e))),userClient.interceptors.response.use(e=>e,async e=>{if(!_axios.default.isAxiosError(e))return _index2.Logger.error(`Non-axios error in response interceptor: ${(0,_tokenRefresh.getErrorMessage)(e)}`),Promise.reject(e);const r=e,t=r.config;if(!r.response)return t?.skipErrorLog||_index2.Logger.error(`Network error or no response from server: ${r.message}, URL: ${t?.url}`),Promise.reject(e);if(401===r.response.status&&t&&!t._retry){if(isRefreshTokenRequest(t.url))return Promise.reject(e);const s=(0,_tokenRefresh.readSignOutReason)(r.response.headers),o=getSessionTerminationCode(r.response.data)??(hasSessionInvalidHeader(r.response.headers)||null!==s?SESSION_TERMINATION_CODES.TERMINATED:void 0);if(o)return _index2.Logger.warn(`Session ${o}, logging out without refresh. URL: ${t.url}`),(0,_tokenRefresh.resetRefreshState)(),await(0,_tokenRefresh.endSessionAndLogout)("terminated",s),Promise.reject(e);if(_index2.Logger.warn(`Unauthorized URL: ${t.url}`),t._retry=!0,(0,_tokenRefresh.isRefreshInFlight)())return(0,_tokenRefresh.queueBehindRefresh)().then(e=>(_index2.Logger.info("Retrying request after token refresh:",t.url),setAuthHeader(t,e),userClient(t))).catch(e=>(_index2.Logger.error("Failed to retry request after token refresh:",(0,_tokenRefresh.getErrorMessage)(e)),Promise.reject(e)));try{const e=await(0,_tokenRefresh.refreshAccessToken)();return setAuthHeader(t,e),userClient(t)}catch(e){return Promise.reject(e)}}return t?.skipErrorLog||_index2.Logger.error(`Response error: ${(0,_responseBodyText.responseBodyText)(r.response?.data,r.message)}, URL: ${t?.url}, Status: ${r.response.status}`),Promise.reject(e)});var _default=exports.default=userClient;
@@ -1,265 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.storeToken = exports.setKeychainImplementation = exports.removeToken = exports.getToken = exports.REFRESH_TOKEN_KEY = exports.ACCESS_TOKEN_KEY = void 0;
7
- var SecureStore = _interopRequireWildcard(require("expo-secure-store"));
8
- var _index = require("../logger/index.js");
9
- 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); }
10
- /**
11
- * Token data persisted in the keychain.
12
- */
13
- /**
14
- * The two keys the library itself reads. Everything in the library that needs
15
- * the bearer token, the HTTP client and the authenticated image cache,
16
- * resolves it through these rather than repeating the literal, so
17
- * one of them cannot silently drift and start reading a key nothing writes.
18
- * Apps are free to store their own tokens under any other key.
19
- */
20
- const ACCESS_TOKEN_KEY = exports.ACCESS_TOKEN_KEY = 'accessToken';
21
- const REFRESH_TOKEN_KEY = exports.REFRESH_TOKEN_KEY = 'refreshToken';
22
-
23
- /**
24
- * The shape this module speaks to its store through. expo-secure-store is
25
- * adapted to it below; an app or a test can supply anything else of this shape
26
- * through `setKeychainImplementation`.
27
- */
28
- /**
29
- * The GENERIC password API, not the internet-credentials one.
30
- *
31
- * `kSecClassInternetPassword` exists for credentials bound to a server, protocol
32
- * and port, and it integrates with Safari and AutoFill. A bearer token keyed by
33
- * a name like "accessToken" is none of those things, and the library was only
34
- * satisfying that API's required `server` argument by passing the key twice,
35
- * once as the server and once as the service. That is misuse of the class.
36
- *
37
- * `kSecClassGenericPassword` is the class for app-local secrets, which is what a
38
- * token is. It is what expo-secure-store uses underneath, and what the consumer
39
- * app being migrated had already chosen for itself.
40
- */
41
- /**
42
- * The credential shape the seam reads back, declared here rather than imported
43
- * from whichever package a consumer's backend comes from. A type-only import of
44
- * a package this library does not declare survives into the published `.d.ts`,
45
- * where a consumer that has not installed it either fails to typecheck or,
46
- * under the RN template's `skipLibCheck: true`, loses all checking on these
47
- * members with no signal. Any credential object with these three members
48
- * satisfies it structurally.
49
- */
50
-
51
- // Only what a test or the showcase injected; null means use expo-secure-store.
52
- let backend = null;
53
-
54
- /**
55
- * expo-secure-store, adapted to the generic-password shape this module speaks.
56
- *
57
- * It is a flat key/value store, so the credential shape is reconstructed around
58
- * it. The key is sanitised because expo rejects anything outside
59
- * [A-Za-z0-9._-] at runtime, which would otherwise surface as a throw from deep
60
- * inside the store rather than as a bad key.
61
- */
62
- const keyFor = service => (service ?? 'default').replace(/[^A-Za-z0-9._-]/g, '_');
63
- const expoSecureStoreBackend = {
64
- setGenericPassword: async (username, password, options) => {
65
- await SecureStore.setItemAsync(keyFor(options?.service), JSON.stringify({
66
- username,
67
- password
68
- }));
69
- return true;
70
- },
71
- getGenericPassword: async options => {
72
- const service = options?.service;
73
- const raw = await SecureStore.getItemAsync(keyFor(service));
74
- if (raw === null) {
75
- return false;
76
- }
77
- const parsed = JSON.parse(raw);
78
- return {
79
- username: parsed.username,
80
- password: parsed.password,
81
- service: service ?? 'default'
82
- };
83
- },
84
- resetGenericPassword: async options => {
85
- await SecureStore.deleteItemAsync(keyFor(options?.service));
86
- return true;
87
- }
88
- };
89
- const resolveBackend = () => backend ?? expoSecureStoreBackend;
90
-
91
- /**
92
- * Every request reads the access token, and a secure-store read is a native
93
- * keychain/keystore decrypt. Reads are therefore served from memory, written
94
- * through by `storeToken` and dropped by `removeToken`. `generation` moves on
95
- * every write, removal and backend swap, so a read that started before one of
96
- * those cannot cache the value it saw.
97
- */
98
- const memo = new Map();
99
- let generation = 0;
100
- const forget = key => {
101
- generation += 1;
102
- if (key === undefined) {
103
- memo.clear();
104
- } else {
105
- memo.delete(key);
106
- }
107
- };
108
- const requireBackend = op => {
109
- const b = resolveBackend();
110
- if (!b) {
111
- const err = new Error(`[authStore] no secure-store backend available; cannot ${op}.`);
112
- _index.Logger.error(err.message);
113
- throw err;
114
- }
115
- return b;
116
- };
117
-
118
- /**
119
- * Replace the secure-store backend. Intended for TESTS and for the showcase,
120
- * which injects a failing store to demo the write-failure path; it is not how
121
- * an app configures the library. Pass `null` to restore expo-secure-store.
122
- */
123
- const setKeychainImplementation = impl => {
124
- backend = impl;
125
- forget();
126
- };
127
-
128
- /**
129
- * Store token with expiry.
130
- */
131
- exports.setKeychainImplementation = setKeychainImplementation;
132
- const storeToken = async (key, token, expiry) => {
133
- // Never log the token or expiry values: Logger forwards to whatever remote
134
- // sink the app wired (Crashlytics/Sentry), so a token here leaves the device.
135
- _index.Logger.info(`Storing token for key: ${key}`);
136
- forget(key);
137
- try {
138
- const data = JSON.stringify({
139
- token,
140
- expiry
141
- });
142
- await requireBackend('store a token').setGenericPassword('token', data, {
143
- service: key
144
- });
145
- forget(key);
146
- memo.set(key, {
147
- token,
148
- expiry
149
- });
150
- _index.Logger.info(`Token stored successfully for key: ${key}`);
151
- } catch (error) {
152
- forget(key);
153
- // Log AND rethrow. Swallowing this told the caller the token was persisted
154
- // when it was not, so an app would show a signed-in user holding a token
155
- // that never reached the keychain — the session then dies at the next
156
- // cold start with no failure anyone could have seen.
157
- _index.Logger.error(`Error storing token for key: ${key}`, error);
158
- throw error;
159
- }
160
- };
161
-
162
- /**
163
- * Parse token data from credentials.
164
- */
165
- exports.storeToken = storeToken;
166
- const parseTokenData = credentials => {
167
- if (!credentials) {
168
- return null;
169
- }
170
- const {
171
- password
172
- } = credentials;
173
- try {
174
- const parsed = JSON.parse(password);
175
- if (parsed && typeof parsed === 'object' && 'token' in parsed && 'expiry' in parsed && typeof parsed.token === 'string' && typeof parsed.expiry === 'string') {
176
- return parsed;
177
- }
178
- return null;
179
- } catch {
180
- // The single report for "stored, but not a token" belongs to getToken, which
181
- // knows whether anything was stored at all. Logging here too made one event
182
- // arrive twice, at two different levels.
183
- return null;
184
- }
185
- };
186
-
187
- /**
188
- * Retrieve token and check if expired.
189
- */
190
- const getToken = async key => {
191
- if (memo.has(key)) {
192
- return memo.get(key) ?? null;
193
- }
194
- const seen = generation;
195
- try {
196
- const credentials = await requireBackend('read a token').getGenericPassword({
197
- service: key
198
- });
199
- // Nothing stored is an ORDINARY state, not a fault: a signed-out user has no
200
- // token, and every authenticated request, image and download asks for one.
201
- // Warning here put three info lines and a warning into the log, and into the
202
- // remote crash sink, on every one of those calls.
203
- let value = null;
204
- if (credentials) {
205
- const parsedData = parseTokenData(credentials);
206
- if (parsedData) {
207
- value = {
208
- token: parsedData.token,
209
- expiry: parsedData.expiry
210
- };
211
- } else {
212
- // Something IS stored and it is not a token. That is corruption worth
213
- // hearing about, and it is a different event from having no token.
214
- _index.Logger.warn(`Stored credentials for key "${key}" are not a valid token; ignoring them.`);
215
- }
216
- }
217
- if (seen === generation) {
218
- memo.set(key, value);
219
- }
220
- return value;
221
- } catch (error) {
222
- const message = error instanceof Error ? error.message : String(error);
223
- // Both spellings matter. Android throws "Key permanently invalidated" when
224
- // the biometric enrolment changes; iOS throws "Secret invalidated" for the
225
- // equivalent. Either way the stored value can never be decrypted again, so
226
- // clearing it is the only way out: leaving it makes every later read fail
227
- // identically, and the user is stuck with no route back to a login. A
228
- // consumer app handled the iOS spelling and the library did not.
229
- if (message.includes('Key permanently invalidated') || message.includes('Secret invalidated')) {
230
- _index.Logger.error(`Stored token for key "${key}" can no longer be decrypted; clearing it.`);
231
- await removeToken(key);
232
- return null;
233
- }
234
- _index.Logger.error(`Error retrieving token for key: ${key}`, error);
235
- return null;
236
- }
237
- };
238
-
239
- /**
240
- * Remove token by key.
241
- */
242
- exports.getToken = getToken;
243
- const removeToken = async key => {
244
- forget(key);
245
- try {
246
- await requireBackend('remove a token').resetGenericPassword({
247
- service: key
248
- });
249
- _index.Logger.info(`Token removed successfully for key: ${key}`);
250
- } catch (error) {
251
- // Clearing a key that was never written is the ordinary logout path, not a
252
- // failure: only one of the two tokens may ever have been stored. Logging it
253
- // as an error puts routine traffic in the channel people watch for real
254
- // problems, which is how an error channel stops being watched.
255
- if (error instanceof Error && error.message.includes('Item not found')) {
256
- _index.Logger.info(`No token found to remove for key: ${key}`);
257
- return;
258
- }
259
- _index.Logger.error(`Failed to remove token for key: ${key}`, error);
260
- } finally {
261
- forget(key);
262
- }
263
- };
264
- exports.removeToken = removeToken;
265
- //# sourceMappingURL=authStore.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.storeToken=exports.storeSessionUser=exports.setLegacyTokenKeys=exports.setKeychainImplementation=exports.removeToken=exports.removeSessionUser=exports.getToken=exports.getSessionUser=exports.clearSession=exports.addSessionEndedListener=exports.SESSION_USER_KEY=exports.REFRESH_TOKEN_KEY=exports.LEGACY_REFRESH_TOKEN_LIFETIME_MS=exports.ACCESS_TOKEN_KEY=void 0;var SecureStore=_interopRequireWildcard(require("expo-secure-store")),_index=require("../logger/index.js"),_index2=require("../storage/index.js"),_jwt=require("./jwt.js");function _interopRequireWildcard(e,r){if("function"==typeof WeakMap)var n=new WeakMap,t=new WeakMap;return(_interopRequireWildcard=function(e,r){if(!r&&e&&e.__esModule)return e;var o,s,i={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return i;if(o=r?t:n){if(o.has(e))return o.get(e);o.set(e,i)}for(const r in e)"default"!==r&&{}.hasOwnProperty.call(e,r)&&((s=(o=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,r))&&(s.get||s.set)?o(i,r,s):i[r]=e[r]);return i})(e,r)}const ACCESS_TOKEN_KEY=exports.ACCESS_TOKEN_KEY="accessToken",REFRESH_TOKEN_KEY=exports.REFRESH_TOKEN_KEY="refreshToken",SESSION_USER_KEY=exports.SESSION_USER_KEY="sessionUser",LEGACY_REFRESH_TOKEN_LIFETIME_MS=exports.LEGACY_REFRESH_TOKEN_LIFETIME_MS=2592e6;let backend=null;const keyFor=e=>(e??"default").replace(/[^A-Za-z0-9._-]/g,"_"),expoSecureStoreBackend={setGenericPassword:async(e,r,n)=>(await SecureStore.setItemAsync(keyFor(n?.service),JSON.stringify({username:e,password:r})),!0),getGenericPassword:async e=>{const r=e?.service,n=await SecureStore.getItemAsync(keyFor(r));if(null===n)return!1;const t=JSON.parse(n);return{username:t.username,password:t.password,service:r??"default"}},resetGenericPassword:async e=>(await SecureStore.deleteItemAsync(keyFor(e?.service)),!0)},resolveBackend=()=>backend??expoSecureStoreBackend,memo=new Map;let generation=0;const forget=e=>{generation+=1,void 0===e?memo.clear():memo.delete(e)},requireBackend=e=>{const r=resolveBackend();if(!r){const r=new Error(`[authStore] no secure-store backend available; cannot ${e}.`);throw _index.Logger.error(r.message),r}return r},setKeychainImplementation=e=>{backend=e,forget()};exports.setKeychainImplementation=setKeychainImplementation;const storeToken=async(e,r,n)=>{_index.Logger.info(`Storing token for key: ${e}`),forget(e);try{const t=JSON.stringify({token:r,expiry:n});await requireBackend("store a token").setGenericPassword("token",t,{service:e}),forget(e),memo.set(e,{token:r,expiry:n}),_index.Logger.info(`Token stored successfully for key: ${e}`)}catch(r){throw forget(e),_index.Logger.error(`Error storing token for key: ${e}`,r),r}};exports.storeToken=storeToken;const parseTokenData=e=>{if(!e)return null;const{password:r}=e;try{const e=JSON.parse(r);return e&&"object"==typeof e&&"token"in e&&"expiry"in e&&"string"==typeof e.token&&"string"==typeof e.expiry?e:null}catch{return null}},getToken=async e=>{if(isSessionKey(e)&&legacyKeys&&await migrateLegacySession(),memo.has(e))return memo.get(e)??null;const r=generation;try{const n=await requireBackend("read a token").getGenericPassword({service:e});let t=null;if(n){const r=parseTokenData(n);if(r)t={token:r.token,expiry:r.expiry};else if(_index.Logger.warn(`Stored credentials for key "${e}" are not a valid token; ignoring them.`),isSessionKey(e))return await endSession("corrupt",!0),null}return r===generation&&memo.set(e,t),t}catch(r){const n=r instanceof Error?r.message:String(r);return n.includes("Key permanently invalidated")||n.includes("Secret invalidated")?(_index.Logger.error(`Stored token for key "${e}" can no longer be decrypted; clearing it.`),isSessionKey(e)?await endSession("corrupt",!0):await removeToken(e),null):(_index.Logger.error(`Error retrieving token for key: ${e}`,r),null)}};exports.getToken=getToken;const removeToken=async e=>{forget(e);try{await requireBackend("remove a token").resetGenericPassword({service:e}),_index.Logger.info(`Token removed successfully for key: ${e}`)}catch(r){if(r instanceof Error&&r.message.includes("Item not found"))return void _index.Logger.info(`No token found to remove for key: ${e}`);_index.Logger.error(`Failed to remove token for key: ${e}`,r)}finally{forget(e)}};exports.removeToken=removeToken;const isSessionKey=e=>e===ACCESS_TOKEN_KEY||e===REFRESH_TOKEN_KEY,storeSessionUser=async e=>{if(!await _index2.Storage.setItem(SESSION_USER_KEY,JSON.stringify(e)))throw new Error("[authStore] could not store the session user.")};exports.storeSessionUser=storeSessionUser;const getSessionUser=async()=>{const e=await _index2.Storage.getItem(SESSION_USER_KEY);if(null===e)return null;try{return JSON.parse(e)}catch{return _index.Logger.warn("The stored session user is not valid JSON; clearing it."),await removeSessionUser(),null}};exports.getSessionUser=getSessionUser;const removeSessionUser=async()=>{await _index2.Storage.removeItem(SESSION_USER_KEY)};exports.removeSessionUser=removeSessionUser;let legacyKeys=null,legacyCheck=null;const setLegacyTokenKeys=e=>{legacyKeys=e,legacyCheck=null};exports.setLegacyTokenKeys=setLegacyTokenKeys;const readLegacyToken=e=>{try{const r=JSON.parse(e);if("string"==typeof r)return""===r.trim()?null:{token:r,expiry:null};if(r&&"object"==typeof r&&"string"==typeof r.token&&"string"==typeof r.expiry)return r}catch{}return""===e.trim()?null:{token:e,expiry:null}},expiryOf=e=>3===e.split(".").length?(0,_jwt.getJWTExpiry)(e)?.toISOString()??null:null,readLegacyRaw=async e=>{const r=await resolveBackend().getGenericPassword({service:e});return r?r.password:null},migrateLegacySession=()=>{if(!legacyKeys)return Promise.resolve();if(legacyCheck)return legacyCheck;const e=legacyKeys;return legacyCheck=(async()=>{try{const r=resolveBackend(),n=!await r.getGenericPassword({service:ACCESS_TOKEN_KEY})&&!await r.getGenericPassword({service:REFRESH_TOKEN_KEY}),t=await readLegacyRaw(e.accessToken),o=await readLegacyRaw(e.refreshToken);if(n&&(null!==t||null!==o)){const n=null===t?null:readLegacyToken(t),s=null===o?null:readLegacyToken(o);if(n){const e=n.expiry??expiryOf(n.token)??(new Date).toISOString();await r.setGenericPassword("token",JSON.stringify({token:n.token,expiry:e}),{service:ACCESS_TOKEN_KEY})}if(s){const e=s.expiry??expiryOf(s.token)??new Date(Date.now()+LEGACY_REFRESH_TOKEN_LIFETIME_MS).toISOString();await r.setGenericPassword("token",JSON.stringify({token:s.token,expiry:e}),{service:REFRESH_TOKEN_KEY})}if(e.sessionUser){const r=await _index2.Storage.getItem(e.sessionUser);null!==r&&await _index2.Storage.setItem(SESSION_USER_KEY,r)}null===n&&null===s||(forget(),_index.Logger.breadcrumb("[authStore] moved a session from the legacy token keys"))}for(const n of[e.accessToken,e.refreshToken])await r.resetGenericPassword({service:n}).catch(()=>{});e.sessionUser&&await _index2.Storage.removeItem(e.sessionUser)}catch(e){_index.Logger.error("[authStore] could not move the session from the legacy token keys",e)}})(),legacyCheck},listeners=new Set,emitSessionEnded=(e,r)=>{for(const n of[...listeners])try{n(e,r)}catch(e){_index.Logger.error("[authStore] a session-ended listener threw",e)}},addSessionEndedListener=e=>(listeners.add(e),()=>{listeners.delete(e)});exports.addSessionEndedListener=addSessionEndedListener;const endSession=async(e,r,n=null)=>{const t=r||null!==await getToken(ACCESS_TOKEN_KEY)||null!==await getToken(REFRESH_TOKEN_KEY);await removeToken(ACCESS_TOKEN_KEY),await removeToken(REFRESH_TOKEN_KEY),await removeSessionUser(),t&&emitSessionEnded(e,{signOutReason:n})},clearSession=async(e="signedOut",r={})=>endSession(e,!1,r.signOutReason??null);exports.clearSession=clearSession;
@@ -1,44 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "decodeJWT", {
7
- enumerable: true,
8
- get: function () {
9
- return _jwt.decodeJWT;
10
- }
11
- });
12
- Object.defineProperty(exports, "getJWTExpiry", {
13
- enumerable: true,
14
- get: function () {
15
- return _jwt.getJWTExpiry;
16
- }
17
- });
18
- Object.defineProperty(exports, "getToken", {
19
- enumerable: true,
20
- get: function () {
21
- return _authStore.getToken;
22
- }
23
- });
24
- Object.defineProperty(exports, "isJWTExpired", {
25
- enumerable: true,
26
- get: function () {
27
- return _jwt.isJWTExpired;
28
- }
29
- });
30
- Object.defineProperty(exports, "removeToken", {
31
- enumerable: true,
32
- get: function () {
33
- return _authStore.removeToken;
34
- }
35
- });
36
- Object.defineProperty(exports, "storeToken", {
37
- enumerable: true,
38
- get: function () {
39
- return _authStore.storeToken;
40
- }
41
- });
42
- var _authStore = require("./authStore.js");
43
- var _jwt = require("./jwt.js");
44
- //# sourceMappingURL=index.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"ACCESS_TOKEN_KEY",{enumerable:!0,get:function(){return _authStore.ACCESS_TOKEN_KEY}}),Object.defineProperty(exports,"LEGACY_REFRESH_TOKEN_LIFETIME_MS",{enumerable:!0,get:function(){return _authStore.LEGACY_REFRESH_TOKEN_LIFETIME_MS}}),Object.defineProperty(exports,"REFRESH_TOKEN_KEY",{enumerable:!0,get:function(){return _authStore.REFRESH_TOKEN_KEY}}),Object.defineProperty(exports,"SESSION_USER_KEY",{enumerable:!0,get:function(){return _authStore.SESSION_USER_KEY}}),Object.defineProperty(exports,"addSessionEndedListener",{enumerable:!0,get:function(){return _authStore.addSessionEndedListener}}),Object.defineProperty(exports,"clearSession",{enumerable:!0,get:function(){return _authStore.clearSession}}),Object.defineProperty(exports,"decodeJWT",{enumerable:!0,get:function(){return _jwt.decodeJWT}}),Object.defineProperty(exports,"getJWTExpiry",{enumerable:!0,get:function(){return _jwt.getJWTExpiry}}),Object.defineProperty(exports,"getSessionUser",{enumerable:!0,get:function(){return _authStore.getSessionUser}}),Object.defineProperty(exports,"getToken",{enumerable:!0,get:function(){return _authStore.getToken}}),Object.defineProperty(exports,"isJWTExpired",{enumerable:!0,get:function(){return _jwt.isJWTExpired}}),Object.defineProperty(exports,"removeSessionUser",{enumerable:!0,get:function(){return _authStore.removeSessionUser}}),Object.defineProperty(exports,"removeToken",{enumerable:!0,get:function(){return _authStore.removeToken}}),Object.defineProperty(exports,"setLegacyTokenKeys",{enumerable:!0,get:function(){return _authStore.setLegacyTokenKeys}}),Object.defineProperty(exports,"storeSessionUser",{enumerable:!0,get:function(){return _authStore.storeSessionUser}}),Object.defineProperty(exports,"storeToken",{enumerable:!0,get:function(){return _authStore.storeToken}});var _authStore=require("./authStore.js"),_jwt=require("./jwt.js");