@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
@@ -0,0 +1,51 @@
1
+ import type { Middleware, MiddlewareAPI, UnknownAction } from '@reduxjs/toolkit';
2
+ import { type ApiError } from '../errors/extractApiError';
3
+ /**
4
+ * Toasts every rejected thunk and every failed RTK Query call, so no screen has to remember
5
+ * to surface a failure and none words it differently. Identical source in web-core and
6
+ * mobile-core; the toast itself comes in through `showToast`, so there is no UI dependency.
7
+ *
8
+ * Opt out with `silent: true` (decision 42), wherever the caller can put it:
9
+ * - a thunk: `rejectWithValue(extractApiError(e), { silent: true })`, or `{ silent: true }`
10
+ * in the thunk's object argument;
11
+ * - an RTK Query call: `{ silent: true }` in the call's argument object;
12
+ * - an RTK Query endpoint: `extraOptions: { silent: true }`, which the base query copies
13
+ * onto its meta.
14
+ *
15
+ * Never toasted: an aborted thunk or a cancelled request (a screen unmounting), an RTK Query
16
+ * condition skip (the data is already cached), a 401 by default (the auth layer owns a dead
17
+ * session). Identical messages are de-duplicated for `dedupeMs`, because a screen that fires
18
+ * four fetches and loses the network would otherwise stack four copies of one sentence.
19
+ *
20
+ * `onRejected` is the product's say over one rejection, run before the default rules:
21
+ * `'toast'` shows it even where `ignoreCodes` or `ignoreStatuses` would not (a 401 that names a
22
+ * code is a refused sign-in, not a dead session), `'silent'` drops it, and nothing at all leaves
23
+ * the default rules to decide. It runs for silent rejections too, so a side effect (a
24
+ * read-only workspace notice, a profile refetch) fires whichever screen asked; `silent: true`
25
+ * still keeps the default toast off, because the screen said it answers the failure itself.
26
+ */
27
+ export type ShowErrorToast = (message: string, error: ApiError) => void;
28
+ /** What `onRejected` decides for one rejection: `'toast'`, `'silent'`, or nothing for the default rules. */
29
+ export type RejectionDecision = 'toast' | 'silent' | undefined;
30
+ /**
31
+ * The product's hook into every rejection the middleware sees. `api` is the store's
32
+ * `dispatch` and `getState`, for a side effect that reads or updates state.
33
+ */
34
+ export type OnRejected = (action: UnknownAction, error: ApiError, api: MiddlewareAPI) => RejectionDecision;
35
+ export interface ErrorToastOptions {
36
+ showToast: ShowErrorToast;
37
+ /** Server `code` values a screen answers in its own way (a paywall, a terms gate). */
38
+ ignoreCodes?: readonly string[];
39
+ /** HTTP statuses never toasted. Default `[401]`. */
40
+ ignoreStatuses?: readonly number[];
41
+ /** Window in which an identical message is shown once. Default 4000 ms; 0 disables. */
42
+ dedupeMs?: number;
43
+ /** Decides one rejection before the default rules; see the module comment. */
44
+ onRejected?: OnRejected;
45
+ }
46
+ type Dict = Record<string, unknown>;
47
+ /** Is this a rejected createAsyncThunk or RTK Query action that asked not to be toasted? */
48
+ export declare const isSilentRejection: (meta: Dict) => boolean;
49
+ export declare function errorToastMiddleware(options: ErrorToastOptions): Middleware;
50
+ export {};
51
+ //# sourceMappingURL=errorToastMiddleware.d.ts.map
@@ -0,0 +1,6 @@
1
+ export type { ErrorToastOptions, OnRejected, RejectionDecision, ShowErrorToast } from './errorToastMiddleware';
2
+ export { errorToastMiddleware, isSilentRejection } from './errorToastMiddleware';
3
+ export type { RootReducerOptions } from './rootReducer';
4
+ export { createRootReducer, resetState } from './rootReducer';
5
+ export { SERIALIZABLE_IGNORED_ACTION_PATHS } from './serializableCheck';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,19 @@
1
+ import { type ActionFromReducersMapObject, type Reducer, type ReducersMapObject, type StateFromReducersMapObject } from '@reduxjs/toolkit';
2
+ /**
3
+ * Clears every slice, the RTK Query cache included, in one dispatch. Dispatch it on logout
4
+ * (decision 22). Not a tidy-up: a slice left behind paints the previous user's data on the
5
+ * next sign-in before fresh fetches land, which on a shared device is a data leak.
6
+ */
7
+ export declare const resetState: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"app/resetState">;
8
+ export interface RootReducerOptions<K extends string> {
9
+ /** Slices that survive a reset because they belong to the device, not the user (theme, onboarding seen). */
10
+ preserve?: readonly K[];
11
+ }
12
+ /**
13
+ * `combineReducers(reducers)` that answers `resetState` by handing every slice `undefined`,
14
+ * so each returns its initial state. The RTK Query api reducer is in `reducers`, so its
15
+ * cache empties too, and a request still in flight is dropped when it lands because its
16
+ * cache entry no longer exists.
17
+ */
18
+ export declare function createRootReducer<M extends ReducersMapObject>(reducers: M, options?: RootReducerOptions<Extract<keyof M, string>>): Reducer<StateFromReducersMapObject<M>, ActionFromReducersMapObject<M>>;
19
+ //# sourceMappingURL=rootReducer.d.ts.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Action paths the serializable check skips in every Webority store (decision 22: the check
3
+ * stays on and ignores named paths only). Setting `ignoredActionPaths` replaces Redux
4
+ * Toolkit's default list, so an app spreads this constant and appends its own paths, each
5
+ * with a one-line reason:
6
+ *
7
+ * serializableCheck: { ignoredActionPaths: [...SERIALIZABLE_IGNORED_ACTION_PATHS, 'payload.at'] }
8
+ *
9
+ * `meta.arg`: a thunk's or RTK Query call's own argument, which may hold a File, a Blob or
10
+ * an AbortSignal and is never stored. `meta.baseQueryMeta`: the base query's request and
11
+ * response metadata, never stored. `ApiError` itself is plain data and needs no exemption.
12
+ */
13
+ export declare const SERIALIZABLE_IGNORED_ACTION_PATHS: readonly string[];
14
+ //# sourceMappingURL=serializableCheck.d.ts.map
@@ -0,0 +1,25 @@
1
+ export interface SecureScreenOptions {
2
+ /**
3
+ * Whether the screen is the one on show. Pass React Navigation's
4
+ * `useIsFocused()`, so a secure screen left underneath a pushed screen stops
5
+ * blocking. Default `true`: block for as long as the component is mounted.
6
+ */
7
+ focused?: boolean;
8
+ }
9
+ /**
10
+ * Blocks capture while the calling screen is focused and releases it on blur
11
+ * or unmount. Each call holds its own claim, so two secure screens on the stack
12
+ * never release each other's protection.
13
+ *
14
+ * ```tsx
15
+ * import { useIsFocused } from '@react-navigation/native';
16
+ * import { useSecureScreen } from '@webority/mobile-core/secureScreen';
17
+ *
18
+ * const SignInScreen = () => {
19
+ * useSecureScreen({ focused: useIsFocused() });
20
+ * // ...
21
+ * };
22
+ * ```
23
+ */
24
+ export declare const useSecureScreen: (options?: SecureScreenOptions) => void;
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Build-number arithmetic for the server-driven update check, shared word for
3
+ * word by web-core and mobile-core.
4
+ *
5
+ * The API's `X-Min-App-Version` is the lowest internal build number it still
6
+ * supports for the calling client kind, and the app's own build number is an
7
+ * integer too (`VERSION_INTERNAL` on mobile, `appBuild` on web). The comparison
8
+ * is integer against integer, never semver against semver.
9
+ */
10
+ /** A non-negative integer from a config or native value, or `null` when it is not one. */
11
+ export declare const parseBuildNumber: (value: string | number | null | undefined) => number | null;
12
+ /** True only when a minimum is known and the build is strictly below it. */
13
+ export declare const isBuildBelowMinimum: (build: number, minimum: number | null) => boolean;
14
+ //# sourceMappingURL=buildNumber.d.ts.map
@@ -2,31 +2,39 @@ import { type Environment } from '../config';
2
2
  /**
3
3
  * Minimal device-info shape we depend on.
4
4
  *
5
- * This is a LAST RESORT, not the primary path. `Platform.OS` already gives the
6
- * platform, and every Webority app carries its own store id and version in
7
- * `appsettings.Compiled.json` — so `setConfig({ appId, appVersion })` covers
8
- * both remaining values without a native module. The injector below exists for
9
- * apps that would rather hand us a `react-native-device-info` instance than
10
- * wire two config keys.
5
+ * This is a LAST RESORT, not the primary path. Every Webority app carries its
6
+ * store id and build number in `appsettings.Compiled.json`, so
7
+ * `setConfig({ appId, appBuild })` covers both without a native module, and
8
+ * expo-application covers an app that wires neither. `getBuildNumber` is
9
+ * optional so an injector written before the server-driven check still fits;
10
+ * without it the build number comes from expo-application.
11
11
  */
12
12
  interface DeviceInfoLike {
13
13
  getBundleId: () => string;
14
14
  getVersion: () => string;
15
+ getBuildNumber?: () => string;
15
16
  }
16
17
  /**
17
18
  * Supply the app identity from a native module instead of config.
18
- * Prefer `setConfig({ appId, appVersion })` — it needs no native dependency.
19
+ * Prefer `setConfig({ appId, appBuild })` — it needs no native dependency.
19
20
  * Pass `null` to clear.
20
21
  */
21
22
  export declare const setDeviceInfoImplementation: (impl: DeviceInfoLike | null) => void;
22
23
  export type Platform = 'ios' | 'android' | string;
24
+ /**
25
+ * A required update always reports `'major'`: the server states a minimum
26
+ * build, not the size of the change, and `'major'` is the value consumers
27
+ * already treat as "must update".
28
+ */
23
29
  export type UpdateType = 'major' | 'minor' | 'patch' | 'prerelease' | null;
30
+ /** @deprecated Store versions are no longer parsed; the minimum is a build number. */
24
31
  export interface ParsedVersion {
25
32
  major: number;
26
33
  minor: number;
27
34
  patch: number;
28
35
  prerelease: string;
29
36
  }
37
+ /** @deprecated The store is no longer read; the minimum comes from `X-Min-App-Version`. */
30
38
  export interface VersionData {
31
39
  version: string | null;
32
40
  released?: string | null;
@@ -36,6 +44,7 @@ export interface VersionData {
36
44
  country?: string;
37
45
  lastChecked: string;
38
46
  }
47
+ /** @deprecated The store is no longer read; the minimum comes from `X-Min-App-Version`. */
39
48
  export interface VersionComparison {
40
49
  needsUpdate: boolean;
41
50
  updateType: UpdateType;
@@ -52,29 +61,31 @@ export interface UpdateInfo {
52
61
  }
53
62
  export interface VersionCheckType {
54
63
  /**
55
- * Check if a new version is available.
56
- * Includes retry logic and proper error handling.
64
+ * Whether this build is below the minimum the API last sent in
65
+ * `X-Min-App-Version`. Resolves "no update" until a reply carried one, and
66
+ * rejects only when the app's build number is unknown.
57
67
  */
58
68
  isNewVersionAvailable: () => Promise<VersionCheckResult>;
59
69
  /**
60
70
  * Opens the appropriate store URL to update the app.
61
- * Uses the provided URL or falls back to direct store URLs.
71
+ * Uses the provided URL or falls back to the direct store URL.
62
72
  */
63
73
  openUpdateUrl: (url?: string | null) => Promise<boolean>;
64
- /**
65
- * Get the fallback store URL.
66
- * Useful when URL from version check fails.
67
- */
74
+ /** The store URL for this app on this platform. */
68
75
  getFallbackStoreUrl: () => string;
69
76
  }
70
77
  export declare const VersionCheck: VersionCheckType;
71
78
  /**
72
- * Custom hook to check for required app updates.
79
+ * Whether this build must update, from the minimum the API sends in
80
+ * `X-Min-App-Version`. Re-renders the moment a reply raises the minimum, so a
81
+ * minimum raised mid-session opens the ForceUpdateDialog without a restart.
73
82
  *
74
- * @param isAppReady - Whether the app is ready to perform the check
75
- * @param environment - The app environment (defaults to the one in config)
83
+ * @param isAppReady - Whether the app is ready to show the prompt
84
+ * @param environment - The app environment (defaults to the one in config); the
85
+ * check runs in `'Production'` only
76
86
  */
77
87
  export declare const useVersionCheck: (isAppReady: boolean, environment?: Environment) => UpdateInfo;
78
88
  export default VersionCheck;
89
+ export { isBuildBelowMinimum, parseBuildNumber } from './buildNumber';
79
90
  export type { DeviceInfoLike };
80
91
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,25 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ export declare const CLIENT_BUILD_HEADER = "X-Client-Build";
3
+ export declare const CLIENT_KIND_HEADER = "X-Client-Kind";
4
+ export declare const ACCOUNT_ID_HEADER = "X-Account-Id";
5
+ /** The server picks session rules and the minimum version per kind; the names match its enum. */
6
+ export type ClientKind = 'Browser' | 'MobileApp';
7
+ export declare const CLIENT_KIND: ClientKind;
8
+ /** `<appVersion>+<commit>`, `<appVersion>` when no commit was stamped, `null` before init. */
9
+ export declare const getClientBuild: () => string | null;
10
+ /**
11
+ * Stamps X-Client-Kind and X-Client-Build on every request. A value the app
12
+ * already set (a default header, or a per-request one) wins, so an app that
13
+ * wired them by hand keeps working unchanged.
14
+ */
15
+ export declare const applyClientHeaders: (client: AxiosInstance) => void;
16
+ export type AccountIdProvider = () => string | null | undefined | Promise<string | null | undefined>;
17
+ /**
18
+ * Sets X-Account-Id from the app's provider on every send, overwriting, so a
19
+ * request replayed after a refresh or an account switch carries the current
20
+ * account rather than the one it first went out with. `null` sends none.
21
+ */
22
+ export declare const applyAccountIdHeader: (headers: {
23
+ set: (name: string, value: string) => unknown;
24
+ }, provider: AccountIdProvider | undefined) => Promise<void>;
25
+ //# sourceMappingURL=clientHeaders.d.ts.map
@@ -0,0 +1,24 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ /**
3
+ * The lowest internal build number (the integer `VERSION_INTERNAL`) the API
4
+ * still serves for this client kind. The API sends it on every response,
5
+ * errors included; cross-origin it is readable only when the API lists it in
6
+ * `Access-Control-Expose-Headers`.
7
+ */
8
+ export declare const MIN_APP_VERSION_HEADER = "X-Min-App-Version";
9
+ export type MinAppVersionListener = (minAppVersion: number) => void;
10
+ /** The floor the API last named, or `null` before any response carried one. */
11
+ export declare const getMinAppVersion: () => number | null;
12
+ /**
13
+ * Called with the floor whenever it changes, and at once with the known floor
14
+ * when one has already arrived, so a late subscriber misses nothing. Returns
15
+ * the unsubscribe function. The versionCheck module is the one subscriber an
16
+ * app normally needs.
17
+ */
18
+ export declare const addMinAppVersionListener: (listener: MinAppVersionListener) => (() => void);
19
+ /**
20
+ * Reads the floor off every response the client receives, a rejected one too:
21
+ * a 426 Upgrade Required is exactly the case the floor exists for.
22
+ */
23
+ export declare const readMinAppVersion: (client: AxiosInstance) => void;
24
+ //# sourceMappingURL=minAppVersion.d.ts.map
@@ -0,0 +1,21 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ /**
3
+ * A fresh v4 uuid. `crypto.randomUUID` exists only in a secure context (HTTPS or localhost) and
4
+ * not at all on Hermes, so the id falls back to `getRandomValues`, then to `Math.random`. A
5
+ * correlation id only has to be unique enough to find one request in the logs; it is never a secret.
6
+ */
7
+ export declare const newCorrelationId: () => string;
8
+ /**
9
+ * Applies the configured timeout and the correlation id per request, read on every send so a
10
+ * value set after import still applies (the same reason `applyConfiguredBaseUrl` exists).
11
+ * - `timeoutMs`: used when the request carries no timeout of its own; a request's own axios
12
+ * `timeout` wins. 0, either way, means no timeout (axios's own meaning).
13
+ * - `correlationIdHeader`: a fresh uuid unless the request already carries one. A retry
14
+ * resends the same config, so it keeps the id the first attempt went out with.
15
+ *
16
+ * axios fills a missing `timeout` with its own default of 0, which would make "this request
17
+ * set none" and "this request asked for none" look alike. The client's default is therefore
18
+ * cleared, so an unset timeout reaches the interceptor as undefined.
19
+ */
20
+ export declare const applyRequestDefaults: (client: AxiosInstance) => void;
21
+ //# sourceMappingURL=requestDefaults.d.ts.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * A failed response's body as log text. A JSON error body is an object, which a
3
+ * template string prints as "[object Object]"; binary bodies are named by size.
4
+ */
5
+ export declare const responseBodyText: (body: unknown, fallback: string) => string;
6
+ //# sourceMappingURL=responseBodyText.d.ts.map
@@ -1,4 +1,4 @@
1
- import type { AxiosError, AxiosInstance } from 'axios';
1
+ import { type AxiosError, type AxiosInstance } from 'axios';
2
2
  export interface RetryPolicy {
3
3
  retries?: number;
4
4
  /** `attempt` is 1-based: 1 is the first retry, not the original request. */
@@ -13,15 +13,29 @@ declare module 'axios' {
13
13
  }
14
14
  }
15
15
  /**
16
- * Status-based ONLY, deliberately: a bare network error (no `error.response`)
17
- * is never retryable. Both clients carry non-idempotent requests, login and OTP
18
- * on the public one and every write on the user one, and a broken connection
19
- * says nothing about whether the request reached the server. Retrying can
20
- * therefore create a second session, or a duplicate record, that the user never
21
- * sees. A generic network-error retry rule is not a substitute: it decides on
22
- * the transport alone and never looks at the HTTP method, so it retries POSTs
23
- * as readily as GETs.
16
+ * A write carrying this header asserts that the API deduplicates it, which is
17
+ * the only thing that makes a POST or PATCH safe to send twice.
24
18
  */
19
+ export declare const IDEMPOTENCY_KEY_HEADER = "Idempotency-Key";
25
20
  export declare const isRetryableStatus: (status: number | undefined) => boolean;
21
+ export declare const isNeverSentError: (error: AxiosError) => boolean;
22
+ /**
23
+ * The wait a refusal named, in milliseconds: the `Retry-After` header (seconds)
24
+ * or a `retryAfterSeconds` body field. `null` when it named none. Cross-origin,
25
+ * the header is readable only when the API lists it in `Access-Control-Expose-Headers`.
26
+ */
27
+ export declare const retryAfterMs: (error: AxiosError) => number | null;
28
+ /**
29
+ * The one retry rule both platforms share:
30
+ * - a request that provably never reached the server is resent, whatever its method;
31
+ * - GET, HEAD, OPTIONS, PUT and DELETE are resent on 429, any 5xx, a timeout or a
32
+ * dropped connection, because a second one leaves the server as one would;
33
+ * - POST and PATCH are resent only on 429 or 503 (the server refused before
34
+ * doing the work) AND only when they carry an `Idempotency-Key`; otherwise never;
35
+ * - a refusal that names a wait longer than 30 seconds is final;
36
+ * - a cancelled request is never resent.
37
+ * A request that knows better passes its own `shouldRetry`.
38
+ */
39
+ export declare const isRetryableFailure: (error: AxiosError) => boolean;
26
40
  export declare const attachRetry: (client: AxiosInstance, policy?: RetryPolicy) => void;
27
41
  //# sourceMappingURL=retry.d.ts.map
@@ -1,3 +1,4 @@
1
+ import { type SessionEndReason } from '../auth/authStore.js';
1
2
  import type { UserAuthOptions } from '../initUserAuth.js';
2
3
  /**
3
4
  * The one token-refresh flow in the library, run by userClient's interceptors.
@@ -27,17 +28,28 @@ export declare const injectUserAuth: (options: UserAuthOptions) => void;
27
28
  */
28
29
  export declare const resetRefreshState: () => void;
29
30
  export declare const getErrorMessage: (error: unknown) => string;
31
+ /** The app's account-id provider, once initUserAuth has run with one. */
32
+ export declare const getAccountIdProvider: () => UserAuthOptions["accountId"];
30
33
  /** The refresh endpoint's path, once initUserAuth has run. */
31
34
  export declare const getRefreshPath: () => string | undefined;
32
35
  export declare const dispatchLogout: () => Promise<void>;
36
+ export declare const SIGN_OUT_REASON_HEADER = "X-Sign-Out-Reason";
37
+ /** The server's sign-out reason from response headers (AxiosHeaders or a plain object), or null. */
38
+ export declare const readSignOutReason: (headers: unknown) => string | null;
39
+ /**
40
+ * The session is over: clear it (tokens and session user removed, listeners told why, with
41
+ * the server's reason), then dispatch the app's logout.
42
+ */
43
+ export declare const endSessionAndLogout: (reason: SessionEndReason, signOutReason: string | null) => Promise<void>;
33
44
  export declare const isRefreshInFlight: () => boolean;
34
45
  /** Wait for the in-flight refresh without joining it: resolved or rejected by processQueue. */
35
46
  export declare const queueBehindRefresh: () => Promise<string>;
36
47
  /**
37
48
  * Refresh the access token, joining a refresh already in flight rather than
38
49
  * starting a second one. Every request queued behind it is replayed on success
39
- * and rejected on failure. Logs out only when the failure proves the session
40
- * is over; a network error, timeout or 5xx keeps it and rejects.
50
+ * and rejected on failure. Ends the session (`clearSession('rejected')`, then
51
+ * logout) only when the failure proves it is over; a network error, timeout or
52
+ * 5xx keeps it and rejects.
41
53
  */
42
54
  export declare const refreshAccessToken: () => Promise<string>;
43
55
  //# sourceMappingURL=tokenRefresh.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import { type AxiosInstance } from 'axios';
2
2
  import '../types/axios.js';
3
3
  export type { RefreshableStore } from './tokenRefresh.js';
4
- export { injectStore, injectUserAuth, resetRefreshState } from './tokenRefresh.js';
4
+ export { injectStore, injectUserAuth, resetRefreshState, SIGN_OUT_REASON_HEADER } from './tokenRefresh.js';
5
5
  /**
6
6
  * Thrown by the request interceptor when the device is offline, before the
7
7
  * request ever reaches the adapter (and therefore the network). Distinct from
@@ -10,10 +10,56 @@
10
10
  */
11
11
  export declare const ACCESS_TOKEN_KEY = "accessToken";
12
12
  export declare const REFRESH_TOKEN_KEY = "refreshToken";
13
+ /**
14
+ * Where the signed-in user's profile snapshot is kept between launches. It is
15
+ * not a secret, and a profile can outgrow what the keychain takes comfortably,
16
+ * so it lives in `Storage`, not the secure store.
17
+ */
18
+ export declare const SESSION_USER_KEY = "sessionUser";
13
19
  export interface StoredToken {
14
20
  token: string;
15
21
  expiry: string;
16
22
  }
23
+ /**
24
+ * Why a session ended, handed to every `addSessionEndedListener` listener.
25
+ * - `signedOut`: the app ended it (the default for `clearSession`).
26
+ * - `rejected`: the refresh endpoint refused the refresh token.
27
+ * - `terminated`: the API reported the session dead (security stamp, admin).
28
+ * - `corrupt`: a stored token could not be read back as a token.
29
+ * - `otherTab`: web only. Another tab signed out of the shared session; never
30
+ * emitted here, declared so both platforms share one type.
31
+ */
32
+ export type SessionEndReason = 'signedOut' | 'rejected' | 'terminated' | 'corrupt' | 'otherTab';
33
+ /** What else is known about a session end, beside its reason. */
34
+ export interface SessionEndDetail {
35
+ /**
36
+ * The server's own name for why it ended the session, from the sign-out-reason response
37
+ * header (`X-Sign-Out-Reason` by default, `initUserAuth({ signOutReasonHeader })`), on a
38
+ * terminated session or a refused refresh. `null` when the server named none, and always
39
+ * `null` for `signedOut` and `corrupt` unless the app passes one.
40
+ */
41
+ signOutReason: string | null;
42
+ }
43
+ export type SessionEndedListener = (reason: SessionEndReason, detail: SessionEndDetail) => void;
44
+ /**
45
+ * The keys an app stored its session under before it adopted this library. `initUserAuth`
46
+ * takes them as `legacyKeys`; the first token read that finds the library's keys empty moves a
47
+ * session found there (see `getToken`). On mobile the token keys are secure-store services and
48
+ * `sessionUser` is a `Storage` key. Each token may be the bare string or the library's own
49
+ * `{ token, expiry }` JSON.
50
+ */
51
+ export interface LegacyTokenKeys {
52
+ accessToken: string;
53
+ refreshToken: string;
54
+ /** The old key of the signed-in user's profile snapshot, if the app kept one. */
55
+ sessionUser?: string;
56
+ }
57
+ /**
58
+ * The expiry given to a migrated refresh token whose expiry the old store never kept and which
59
+ * is not a JWT. The server stays the judge: a refresh token it no longer honours is refused at
60
+ * the first refresh, which ends the session exactly as it would have ended before.
61
+ */
62
+ export declare const LEGACY_REFRESH_TOKEN_LIFETIME_MS: number;
17
63
  /**
18
64
  * The shape this module speaks to its store through. expo-secure-store is
19
65
  * adapted to it below; an app or a test can supply anything else of this shape
@@ -75,5 +121,35 @@ export declare const getToken: (key: string) => Promise<StoredToken | null>;
75
121
  * Remove token by key.
76
122
  */
77
123
  export declare const removeToken: (key: string) => Promise<void>;
124
+ /**
125
+ * Keep the signed-in user's profile snapshot so the app can paint the signed-in
126
+ * shell at launch before the profile fetch returns. Rejects when the write
127
+ * fails, like `storeToken`.
128
+ */
129
+ export declare const storeSessionUser: <T>(user: T) => Promise<void>;
130
+ /**
131
+ * The stored user, or null. An unreadable snapshot is removed and reported,
132
+ * but does not end the session: it is a cache the next profile fetch refills.
133
+ */
134
+ export declare const getSessionUser: <T>() => Promise<T | null>;
135
+ export declare const removeSessionUser: () => Promise<void>;
136
+ /** Set by `initUserAuth({ legacyKeys })`; `null` turns the migration off. */
137
+ export declare const setLegacyTokenKeys: (keys: LegacyTokenKeys | null) => void;
138
+ /**
139
+ * Be told when the session ends, with the reason. Returns the unsubscribe.
140
+ * Fires once per session end, whichever path ended it; the app reacts here
141
+ * (clear its state, route to sign-in, show why) instead of each caller doing it.
142
+ */
143
+ export declare const addSessionEndedListener: (listener: SessionEndedListener) => (() => void);
144
+ /**
145
+ * End the session: remove both tokens and the session user, then tell every
146
+ * `addSessionEndedListener` listener why. Safe to call more than once: the
147
+ * listeners hear only the call that found a session to end, so the refresh
148
+ * flow and the app's own sign-out can both call it without a double event.
149
+ * The library calls it itself with `rejected` when the refresh endpoint refuses
150
+ * the refresh token and `terminated` when the API reports the session dead,
151
+ * with the server's sign-out reason in `detail`.
152
+ */
153
+ export declare const clearSession: (reason?: SessionEndReason, detail?: Partial<SessionEndDetail>) => Promise<void>;
78
154
  export type { KeychainLike, SecureCredentials };
79
155
  //# sourceMappingURL=authStore.d.ts.map
@@ -1,5 +1,5 @@
1
- export type { StoredToken } from './authStore.js';
2
- export { getToken, removeToken, storeToken } from './authStore.js';
1
+ export type { LegacyTokenKeys, SessionEndDetail, SessionEndedListener, SessionEndReason, StoredToken } from './authStore.js';
2
+ export { ACCESS_TOKEN_KEY, addSessionEndedListener, clearSession, getSessionUser, getToken, LEGACY_REFRESH_TOKEN_LIFETIME_MS, REFRESH_TOKEN_KEY, removeSessionUser, removeToken, SESSION_USER_KEY, setLegacyTokenKeys, storeSessionUser, storeToken } from './authStore.js';
3
3
  export type { JwtClaims } from './jwt.js';
4
4
  export { decodeJWT, getJWTExpiry, isJWTExpired } from './jwt.js';
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -2,7 +2,7 @@
2
2
  * Configuration management for Webority packages
3
3
  * Provides a flexible way to inject configuration without hard dependencies
4
4
  */
5
- export type LogLevel = 'info' | 'warn' | 'error';
5
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
6
6
  export type Environment = 'Development' | 'Production' | 'Staging';
7
7
  export interface Config {
8
8
  /** API base URL (required before making API calls) */
@@ -15,7 +15,7 @@ export interface Config {
15
15
  environment: Environment;
16
16
  /**
17
17
  * ISO 3166-1 alpha-2 country code (lowercase) used by the version-check
18
- * module to scope App Store / Play Store lookups. Defaults to `'in'`.
18
+ * module to build the App Store / Play Store link. Defaults to `'in'`.
19
19
  */
20
20
  country: string;
21
21
  /**
@@ -27,12 +27,38 @@ export interface Config {
27
27
  appId: string | null;
28
28
  /** The app's user-visible version string, e.g. `'1.4.2'`. Same rationale as `appId`. */
29
29
  appVersion: string | null;
30
+ /** The short git sha stamped into the build; with `appVersion` it makes the X-Client-Build header. */
31
+ commit: string | null;
32
+ /**
33
+ * The app's internal build number (`VERSION_INTERNAL`: Android versionCode,
34
+ * iOS CFBundleVersion). The version check compares it with the API's
35
+ * `X-Min-App-Version`. Falls back to expo-application when unset.
36
+ */
37
+ appBuild: number | null;
38
+ /**
39
+ * The numeric Apple App Store id (the digits after `id` in the store link).
40
+ * The App Store does not resolve a bundle id, so the iOS update button needs it.
41
+ */
42
+ appStoreId: string | null;
30
43
  /**
31
44
  * Log a copy-pasteable curl command for every API request. Credentials are
32
45
  * redacted either way, but this is still request-level noise, so it stays off
33
46
  * unless an app asks for it while debugging.
34
47
  */
35
48
  logCurl: boolean;
49
+ /**
50
+ * Request timeout for both clients, in milliseconds. A request overrides it with its own
51
+ * axios `timeout`. Default 30000.
52
+ */
53
+ timeoutMs: number;
54
+ /** How many times a failed request is resent under the retry rule. 0 turns retrying off. Default 3. */
55
+ retries: number;
56
+ /**
57
+ * Header that carries a fresh id (a uuid) on every request, for tracing one request across
58
+ * the app, the API and its logs. A retry keeps the id it first went out with. `null`
59
+ * sends none. Default `'X-Correlation-Id'`.
60
+ */
61
+ correlationIdHeader: string | null;
36
62
  }
37
63
  /**
38
64
  * Info lines (each token refresh, each unauthorised URL) reach the device log
@@ -40,6 +66,9 @@ export interface Config {
40
66
  * errors only.
41
67
  */
42
68
  export declare const DEFAULT_LOG_LEVEL: LogLevel;
69
+ export declare const DEFAULT_TIMEOUT_MS = 30000;
70
+ export declare const DEFAULT_RETRIES = 3;
71
+ export declare const DEFAULT_CORRELATION_ID_HEADER = "X-Correlation-Id";
43
72
  /**
44
73
  * Set global configuration for all Webority packages
45
74
  */