@webority/mobile-core 0.1.0 → 0.2.1
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.
- package/README.md +32 -0
- package/lib/commonjs/api/clientHeaders.js +1 -0
- package/lib/commonjs/api/minAppVersion.js +1 -0
- package/lib/commonjs/api/publicClient.js +1 -1
- package/lib/commonjs/api/requestDefaults.js +1 -0
- package/lib/commonjs/api/retry.js +1 -1
- package/lib/commonjs/api/tokenRefresh.js +1 -1
- package/lib/commonjs/api/userClient.js +1 -1
- package/lib/commonjs/auth/authStore.js +1 -1
- package/lib/commonjs/auth/index.js +1 -1
- package/lib/commonjs/config/index.js +1 -1
- package/lib/commonjs/errors/extractApiError.js +1 -0
- package/lib/commonjs/errors/index.js +1 -0
- package/lib/commonjs/formatters/currency.js +1 -1
- package/lib/commonjs/formatters/date.js +1 -1
- package/lib/commonjs/formatters/dateMath.js +1 -1
- package/lib/commonjs/formatters/formatConfig.js +1 -0
- package/lib/commonjs/formatters/house.js +1 -0
- package/lib/commonjs/formatters/index.js +1 -1
- package/lib/commonjs/formatters/number.js +1 -1
- package/lib/commonjs/index.js +1 -1
- package/lib/commonjs/initSDK.js +1 -1
- package/lib/commonjs/initUserAuth.js +1 -1
- package/lib/commonjs/logger/index.js +1 -1
- package/lib/commonjs/query/apiBaseQuery.js +1 -0
- package/lib/commonjs/query/createAppApi.js +1 -0
- package/lib/commonjs/query/index.js +1 -0
- package/lib/commonjs/query/listeners.js +1 -0
- package/lib/commonjs/query/paging.js +1 -0
- package/lib/commonjs/query/tags.js +1 -0
- package/lib/commonjs/redux/errorToastMiddleware.js +1 -0
- package/lib/commonjs/redux/index.js +1 -0
- package/lib/commonjs/redux/rootReducer.js +1 -0
- package/lib/commonjs/redux/serializableCheck.js +1 -0
- package/lib/commonjs/versionCheck/buildNumber.js +1 -0
- package/lib/commonjs/versionCheck/index.js +1 -1
- package/lib/module/api/baseUrl.js +1 -1
- package/lib/module/api/clientHeaders.js +1 -0
- package/lib/module/api/curl.js +1 -1
- package/lib/module/api/minAppVersion.js +1 -0
- package/lib/module/api/multipart.js +1 -1
- package/lib/module/api/publicClient.js +1 -1
- package/lib/module/api/requestDefaults.js +1 -0
- package/lib/module/api/responseBodyText.js +1 -1
- package/lib/module/api/retry.js +1 -1
- package/lib/module/api/tokenRefresh.js +1 -1
- package/lib/module/api/userClient.js +1 -1
- package/lib/module/auth/authStore.js +1 -1
- package/lib/module/auth/index.js +1 -1
- package/lib/module/auth/jwt.js +1 -1
- package/lib/module/config/index.js +1 -1
- package/lib/module/deepLink/index.js +1 -1
- package/lib/module/download/adapters/expoFs.js +1 -1
- package/lib/module/download/adapters/shared.js +1 -1
- package/lib/module/download/index.js +1 -1
- package/lib/module/errors/extractApiError.js +1 -0
- package/lib/module/errors/index.js +1 -0
- package/lib/module/formatters/currency.js +1 -1
- package/lib/module/formatters/date.js +1 -1
- package/lib/module/formatters/dateMath.js +1 -1
- package/lib/module/formatters/formatConfig.js +1 -0
- package/lib/module/formatters/house.js +1 -0
- package/lib/module/formatters/index.js +1 -1
- package/lib/module/formatters/initials.js +1 -1
- package/lib/module/formatters/intlCache.js +1 -1
- package/lib/module/formatters/number.js +1 -1
- package/lib/module/formatters/phone.js +1 -1
- package/lib/module/formatters/windowsToIanaTable.js +1 -1
- package/lib/module/geolocation/adapters/expoLocation.js +1 -1
- package/lib/module/geolocation/index.js +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/initSDK.js +1 -1
- package/lib/module/initUserAuth.js +1 -1
- package/lib/module/logger/crashlytics.js +1 -1
- package/lib/module/logger/index.js +1 -1
- package/lib/module/logger/redact.js +1 -1
- package/lib/module/network/index.js +1 -1
- package/lib/module/network/networkStatus.js +1 -1
- package/lib/module/permissions/calendar.js +1 -1
- package/lib/module/permissions/camera.js +1 -1
- package/lib/module/permissions/contacts.js +1 -1
- package/lib/module/permissions/index.js +1 -1
- package/lib/module/permissions/location.js +1 -1
- package/lib/module/permissions/mediaLibrary.js +1 -1
- package/lib/module/permissions/notifications.js +1 -1
- package/lib/module/permissions/photos.js +1 -1
- package/lib/module/phone/countries.js +1 -1
- package/lib/module/push/index.js +1 -1
- package/lib/module/push/push.js +1 -1
- package/lib/module/push/status.js +1 -1
- package/lib/module/push/task.js +1 -1
- package/lib/module/query/apiBaseQuery.js +1 -0
- package/lib/module/query/createAppApi.js +1 -0
- package/lib/module/query/index.js +1 -0
- package/lib/module/query/listeners.js +1 -0
- package/lib/module/query/paging.js +1 -0
- package/lib/module/query/tags.js +1 -0
- package/lib/module/redux/errorToastMiddleware.js +1 -0
- package/lib/module/redux/index.js +1 -0
- package/lib/module/redux/rootReducer.js +1 -0
- package/lib/module/redux/serializableCheck.js +1 -0
- package/lib/module/secureScreen/index.js +1 -1
- package/lib/module/share/index.js +1 -1
- package/lib/module/smsRetriever/index.js +1 -1
- package/lib/module/specs/NativeSmsRetriever.js +1 -1
- package/lib/module/sqlite/adapters/expo.js +1 -1
- package/lib/module/sqlite/index.js +1 -1
- package/lib/module/storage/index.js +1 -1
- package/lib/module/types/axios.js +1 -1
- package/lib/module/types/globals.d.js +1 -1
- package/lib/module/utils/base64.js +1 -1
- package/lib/module/utils/imageCompression.js +1 -1
- package/lib/module/utils/index.js +1 -1
- package/lib/module/validators/index.js +1 -1
- package/lib/module/versionCheck/buildNumber.js +1 -0
- package/lib/module/versionCheck/index.js +1 -1
- package/lib/typescript/commonjs/api/clientHeaders.d.ts +25 -0
- package/lib/typescript/commonjs/api/minAppVersion.d.ts +24 -0
- package/lib/typescript/commonjs/api/requestDefaults.d.ts +21 -0
- package/lib/typescript/commonjs/api/retry.d.ts +23 -9
- package/lib/typescript/commonjs/api/tokenRefresh.d.ts +14 -2
- package/lib/typescript/commonjs/api/userClient.d.ts +1 -1
- package/lib/typescript/commonjs/auth/authStore.d.ts +76 -0
- package/lib/typescript/commonjs/auth/index.d.ts +2 -2
- package/lib/typescript/commonjs/config/index.d.ts +31 -2
- package/lib/typescript/commonjs/errors/extractApiError.d.ts +69 -0
- package/lib/typescript/commonjs/errors/index.d.ts +3 -0
- package/lib/typescript/commonjs/formatters/currency.d.ts +22 -7
- package/lib/typescript/commonjs/formatters/date.d.ts +13 -13
- package/lib/typescript/commonjs/formatters/dateMath.d.ts +4 -2
- package/lib/typescript/commonjs/formatters/formatConfig.d.ts +48 -0
- package/lib/typescript/commonjs/formatters/house.d.ts +143 -0
- package/lib/typescript/commonjs/formatters/index.d.ts +4 -0
- package/lib/typescript/commonjs/formatters/number.d.ts +15 -5
- package/lib/typescript/commonjs/index.d.ts +21 -8
- package/lib/typescript/commonjs/initSDK.d.ts +18 -6
- package/lib/typescript/commonjs/initUserAuth.d.ts +29 -0
- package/lib/typescript/commonjs/logger/index.d.ts +17 -0
- package/lib/typescript/commonjs/query/apiBaseQuery.d.ts +55 -0
- package/lib/typescript/commonjs/query/createAppApi.d.ts +21 -0
- package/lib/typescript/commonjs/query/index.d.ts +9 -0
- package/lib/typescript/commonjs/query/listeners.d.ts +11 -0
- package/lib/typescript/commonjs/query/paging.d.ts +42 -0
- package/lib/typescript/commonjs/query/tags.d.ts +31 -0
- package/lib/typescript/commonjs/redux/errorToastMiddleware.d.ts +51 -0
- package/lib/typescript/commonjs/redux/index.d.ts +6 -0
- package/lib/typescript/commonjs/redux/rootReducer.d.ts +19 -0
- package/lib/typescript/commonjs/redux/serializableCheck.d.ts +14 -0
- package/lib/typescript/commonjs/versionCheck/buildNumber.d.ts +14 -0
- package/lib/typescript/commonjs/versionCheck/index.d.ts +28 -17
- package/lib/typescript/module/api/clientHeaders.d.ts +25 -0
- package/lib/typescript/module/api/minAppVersion.d.ts +24 -0
- package/lib/typescript/module/api/requestDefaults.d.ts +21 -0
- package/lib/typescript/module/api/retry.d.ts +23 -9
- package/lib/typescript/module/api/tokenRefresh.d.ts +14 -2
- package/lib/typescript/module/api/userClient.d.ts +1 -1
- package/lib/typescript/module/auth/authStore.d.ts +76 -0
- package/lib/typescript/module/auth/index.d.ts +2 -2
- package/lib/typescript/module/config/index.d.ts +31 -2
- package/lib/typescript/module/errors/extractApiError.d.ts +69 -0
- package/lib/typescript/module/errors/index.d.ts +3 -0
- package/lib/typescript/module/formatters/currency.d.ts +22 -7
- package/lib/typescript/module/formatters/date.d.ts +13 -13
- package/lib/typescript/module/formatters/dateMath.d.ts +4 -2
- package/lib/typescript/module/formatters/formatConfig.d.ts +48 -0
- package/lib/typescript/module/formatters/house.d.ts +143 -0
- package/lib/typescript/module/formatters/index.d.ts +4 -0
- package/lib/typescript/module/formatters/number.d.ts +15 -5
- package/lib/typescript/module/index.d.ts +21 -8
- package/lib/typescript/module/initSDK.d.ts +18 -6
- package/lib/typescript/module/initUserAuth.d.ts +29 -0
- package/lib/typescript/module/logger/index.d.ts +17 -0
- package/lib/typescript/module/query/apiBaseQuery.d.ts +55 -0
- package/lib/typescript/module/query/createAppApi.d.ts +21 -0
- package/lib/typescript/module/query/index.d.ts +9 -0
- package/lib/typescript/module/query/listeners.d.ts +11 -0
- package/lib/typescript/module/query/paging.d.ts +42 -0
- package/lib/typescript/module/query/tags.d.ts +31 -0
- package/lib/typescript/module/redux/errorToastMiddleware.d.ts +51 -0
- package/lib/typescript/module/redux/index.d.ts +6 -0
- package/lib/typescript/module/redux/rootReducer.d.ts +19 -0
- package/lib/typescript/module/redux/serializableCheck.d.ts +14 -0
- package/lib/typescript/module/versionCheck/buildNumber.d.ts +14 -0
- package/lib/typescript/module/versionCheck/index.d.ts +28 -17
- package/package.json +30 -2
|
@@ -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,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.
|
|
6
|
-
*
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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,
|
|
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
|
-
*
|
|
56
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
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
|
-
*
|
|
17
|
-
*
|
|
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.
|
|
40
|
-
* is over; a network error, timeout or
|
|
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
|
|
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
|
*/
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes any failure a thunk, a service or the RTK Query base query can see into one
|
|
3
|
+
* `ApiError`. Identical source in @webority/web-core and @webority/mobile-core.
|
|
4
|
+
*
|
|
5
|
+
* Bodies read, newest first: the fleet body `{ code, message, traceId, errors }` (D-077),
|
|
6
|
+
* where `errors` is a ModelState dictionary (`{ Field: ["msg"] }`) or a list of
|
|
7
|
+
* `{ field, message, reference }` (a refusal that names its fields),
|
|
8
|
+
* ProblemDetails `{ title, detail, errors }` from APIs not yet moved, legacy `{ error }` and
|
|
9
|
+
* `{ message }`, and a plain-text body.
|
|
10
|
+
*
|
|
11
|
+
* Message precedence is fixed (react.md): first field error, then `message`, `detail`, a
|
|
12
|
+
* legacy `error`, `title`, then `Request failed (<status>)`. `title` is last because it is
|
|
13
|
+
* the ProblemDetails category ("Bad Request"), not the curated sentence.
|
|
14
|
+
*
|
|
15
|
+
* Two things never become `message`: a 5xx body (our failure, nothing the user can act on)
|
|
16
|
+
* and anything that reads like an exception dump. The server's text goes on `detail` for
|
|
17
|
+
* the logger instead.
|
|
18
|
+
*/
|
|
19
|
+
export interface ApiError {
|
|
20
|
+
/** Stable snake_case branch key from the server (`not_found`, `validation_failed`). Branch on it, never render it. */
|
|
21
|
+
code: string | null;
|
|
22
|
+
/** The only user-facing string. */
|
|
23
|
+
message: string;
|
|
24
|
+
/** camelCase field path to its first message, ready for react-hook-form `setError`. */
|
|
25
|
+
fieldErrors: Record<string, string>;
|
|
26
|
+
/** HTTP status, or 0 when no response arrived. */
|
|
27
|
+
status: number;
|
|
28
|
+
/** True when no answer arrived (offline, network drop, timeout): a retry is worth offering. */
|
|
29
|
+
offline: boolean;
|
|
30
|
+
/** The server's trace id, for a support reference. */
|
|
31
|
+
traceId: string | null;
|
|
32
|
+
/** What the server or runtime actually said. For the logger, never for the screen. */
|
|
33
|
+
detail: string | null;
|
|
34
|
+
}
|
|
35
|
+
export declare const SERVER_FAILURE_MESSAGE = "Something went wrong on our side. Please try again in a moment.";
|
|
36
|
+
export declare const OFFLINE_MESSAGE = "You appear to be offline. Check your connection and try again.";
|
|
37
|
+
export declare const TIMEOUT_MESSAGE = "That took too long to respond. Check your connection and try again.";
|
|
38
|
+
export declare const UNEXPECTED_MESSAGE = "Something went wrong. Please try again.";
|
|
39
|
+
/** `code` for a request the caller cancelled (axios `CanceledError`). Never toasted. */
|
|
40
|
+
export declare const REQUEST_CANCELED_CODE = "request_canceled";
|
|
41
|
+
/** `code` for a response that failed schema validation at the service boundary. */
|
|
42
|
+
export declare const CONTRACT_ERROR_CODE = "contract_error";
|
|
43
|
+
/** `code` for a request that got no answer in time (axios `ECONNABORTED` / `ETIMEDOUT`). `offline` is true. */
|
|
44
|
+
export declare const TIMEOUT_CODE = "timeout";
|
|
45
|
+
/** `code` for a request that never reached the server (offline, DNS, CORS, a dropped connection). `offline` is true. */
|
|
46
|
+
export declare const NETWORK_CODE = "network";
|
|
47
|
+
/** `Items[0].UnitPrice` -> `items[0].unitPrice`; `$.email` (System.Text.Json path) -> `email`. */
|
|
48
|
+
export declare const toFieldPath: (key: string) => string;
|
|
49
|
+
export declare const isApiError: (value: unknown) => value is ApiError;
|
|
50
|
+
export declare function extractApiError(error: unknown): ApiError;
|
|
51
|
+
/**
|
|
52
|
+
* True when no answer arrived (offline, a dropped connection, a timeout), so the caller cannot
|
|
53
|
+
* tell what the server did. The same as `extractApiError(error).offline`.
|
|
54
|
+
*/
|
|
55
|
+
export declare const isNoResponse: (error: unknown) => boolean;
|
|
56
|
+
/**
|
|
57
|
+
* The sentence a screen shows for a failure: the server's own curated message when it sent one,
|
|
58
|
+
* otherwise the screen's `fallback` ("We couldn't save the project."), otherwise the library's
|
|
59
|
+
* generic sentence. A lost answer always reads as the connection message, because "check your
|
|
60
|
+
* connection" is more accurate than any screen's fallback. A 5xx, a cancelled request and a body
|
|
61
|
+
* with no usable sentence count as "the server said nothing usable".
|
|
62
|
+
*
|
|
63
|
+
* `fallback: null` is the "say nothing" mode, for a screen that shows only what the server
|
|
64
|
+
* curated (a live panel that keeps its last result): it returns null when the server said
|
|
65
|
+
* nothing usable, and still the connection message for a lost answer.
|
|
66
|
+
*/
|
|
67
|
+
export declare function apiErrorMessage(error: unknown, fallback?: string): string;
|
|
68
|
+
export declare function apiErrorMessage(error: unknown, fallback: string | null): string | null;
|
|
69
|
+
//# sourceMappingURL=extractApiError.d.ts.map
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { ApiError } from './extractApiError.js';
|
|
2
|
+
export { apiErrorMessage, CONTRACT_ERROR_CODE, extractApiError, isApiError, isNoResponse, NETWORK_CODE, OFFLINE_MESSAGE, REQUEST_CANCELED_CODE, SERVER_FAILURE_MESSAGE, TIMEOUT_CODE, TIMEOUT_MESSAGE, toFieldPath, UNEXPECTED_MESSAGE } from './extractApiError.js';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,24 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The currency keys plus any other `Intl.NumberFormatOptions` (`currencyDisplay`, `notation`,
|
|
3
|
+
* `signDisplay`, ...), passed through to Intl.NumberFormat.
|
|
4
|
+
*/
|
|
5
|
+
export interface FormatCurrencyOptions extends Omit<Intl.NumberFormatOptions, 'style' | 'currency'> {
|
|
2
6
|
/** ISO 4217 currency code. Defaults to `'INR'`. */
|
|
3
7
|
currency?: string;
|
|
4
|
-
/** BCP-47 locale tag. Defaults to `'en-IN'` (Indian numbering system). */
|
|
8
|
+
/** BCP-47 locale tag. Defaults to the configured locale, else `'en-IN'` (Indian numbering system). */
|
|
5
9
|
locale?: string;
|
|
6
|
-
/** Minimum fraction digits. Defaults to 0 for whole amounts, 2
|
|
10
|
+
/** Minimum fraction digits. Defaults to 0 for whole amounts, else the currency's own (2 for INR, 0 for JPY). */
|
|
7
11
|
minimumFractionDigits?: number;
|
|
8
|
-
/** Maximum fraction digits. Defaults to
|
|
12
|
+
/** Maximum fraction digits. Defaults to the currency's own. */
|
|
9
13
|
maximumFractionDigits?: number;
|
|
10
14
|
/** Strip the currency symbol — useful when the symbol is rendered separately. */
|
|
11
15
|
stripSymbol?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* What a missing amount prints. Defaults to the configured placeholder once the app has
|
|
18
|
+
* configured a locale or an `empty` (`configureFormatters`), else `''`.
|
|
19
|
+
*/
|
|
20
|
+
empty?: string;
|
|
12
21
|
}
|
|
13
22
|
/**
|
|
14
23
|
* Format an amount as currency. Defaults to **INR** with Indian numbering (`en-IN`),
|
|
15
|
-
* which matches the standard convention across Webority projects.
|
|
24
|
+
* which matches the standard convention across Webority projects. Called with no
|
|
25
|
+
* options: "₹1,50,000" for 150000, "₹1,234.50" for 1234.5, and `''` for a missing amount.
|
|
26
|
+
* Once the app configures a locale (`configureFormatters({ locale })`), the amount is
|
|
27
|
+
* written in that locale and a missing amount prints the configured placeholder ("-").
|
|
28
|
+
* A numeric string reads as its number. For money the API carries in minor units (paise),
|
|
29
|
+
* use `formatMinor`.
|
|
16
30
|
*
|
|
17
31
|
* @example
|
|
18
32
|
* formatCurrency(150000) // ₹1,50,000
|
|
19
33
|
* formatCurrency(1234.5) // ₹1,234.50
|
|
20
|
-
* formatCurrency(99, { currency: 'USD', locale: 'en-US' }) // $99
|
|
34
|
+
* formatCurrency(99, { currency: 'USD', locale: 'en-US' }) // $99
|
|
21
35
|
* formatCurrency(150000, { stripSymbol: true }) // 1,50,000
|
|
36
|
+
* formatCurrency(1500000, { notation: 'compact' }) // ₹15L
|
|
22
37
|
*/
|
|
23
|
-
export declare const formatCurrency: (amount: number | null | undefined, options?: FormatCurrencyOptions) => string;
|
|
38
|
+
export declare const formatCurrency: (amount: number | string | null | undefined, options?: FormatCurrencyOptions) => string;
|
|
24
39
|
//# sourceMappingURL=currency.d.ts.map
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
+
import { type DateValue, type FormatDateOptions, type FormatDateTimeOptions, type FormatTimeOptions } from './house.js';
|
|
1
2
|
export type DateInput = Date | string | number;
|
|
2
3
|
export type DateStyle = 'short' | 'medium' | 'long' | 'full';
|
|
3
4
|
export type TimeStyle = 'short' | 'medium' | 'long';
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export declare const formatDateTime: (value: DateInput, dateStyle?: DateStyle, timeStyle?: TimeStyle, locale?: string) => string;
|
|
5
|
+
/** "08-Apr-2026" in the configured zone; a bare calendar date stays that day. */
|
|
6
|
+
export declare function formatDate(value: DateValue, options?: FormatDateOptions): string;
|
|
7
|
+
/** Intl `dateStyle` output, `'en-IN'` by default. */
|
|
8
|
+
export declare function formatDate(value: DateInput, style: DateStyle, locale?: string): string;
|
|
9
|
+
/** "8:05 PM" in IST, labelled in any other zone. */
|
|
10
|
+
export declare function formatTime(value: DateValue, options?: FormatTimeOptions): string;
|
|
11
|
+
/** Intl `timeStyle` output (24-hour fallback when Intl is unavailable). */
|
|
12
|
+
export declare function formatTime(value: DateInput, style: TimeStyle, locale?: string): string;
|
|
13
|
+
/** "08-Apr-2026, 8:05 PM" in IST, labelled in any other zone. */
|
|
14
|
+
export declare function formatDateTime(value: DateValue, options?: FormatDateTimeOptions): string;
|
|
15
|
+
/** Intl `dateStyle` + `timeStyle` output. */
|
|
16
|
+
export declare function formatDateTime(value: DateInput, dateStyle: DateStyle, timeStyle?: TimeStyle, locale?: string): string;
|
|
17
17
|
/**
|
|
18
18
|
* Returns a humanized relative-time string (e.g. "5 minutes ago", "in 3 days").
|
|
19
19
|
* Uses `Intl.RelativeTimeFormat` when available; otherwise a sensible English fallback.
|