@webority/mobile-core 0.112.3 → 0.114.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.
- package/README.md +17 -0
- package/lib/commonjs/api/clientHeaders.js +1 -1
- package/lib/commonjs/appLock/index.js +1 -1
- package/lib/module/api/clientHeaders.js +1 -1
- package/lib/module/appLock/index.js +1 -1
- package/lib/typescript/commonjs/api/clientHeaders.d.ts +3 -1
- package/lib/typescript/commonjs/appLock/index.d.ts +4 -0
- package/lib/typescript/module/api/clientHeaders.d.ts +3 -1
- package/lib/typescript/module/appLock/index.d.ts +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -208,6 +208,9 @@ and answers an older build with 426 `client_update_required`. The number comes f
|
|
|
208
208
|
`nativeBuildVersion`. Without a whole number the header is left off, and the server never refuses a
|
|
209
209
|
request without it. `Client-Build` (`<appVersion>+<commit>`) is unchanged.
|
|
210
210
|
|
|
211
|
+
Both HTTP clients also send `Client-App: <appId>` when the config has an app id (`initWebority({ appId })`).
|
|
212
|
+
It is the app's store identifier, so the API can tell apps of the same client kind apart.
|
|
213
|
+
|
|
211
214
|
The version floor comes only from the `Min-App-Version` response header. When a reply carries it,
|
|
212
215
|
`useVersionCheck` turns `isUpdateRequired` on for a build below it. A 426 `client_update_required`
|
|
213
216
|
does not move the floor, so a 426 without that header leaves the floor where it is. A 426 is never
|
|
@@ -233,6 +236,20 @@ JWT-shaped strings, and the values of keys named `token`, `accessToken`, `refres
|
|
|
233
236
|
|
|
234
237
|
`configureLogger({ redactKeys })` adds app keys to the built-in masked list and never removes one. `Logger.getBreadcrumbs()` returns the last 50 breadcrumbs, oldest first, already redacted; `configureLogger({ breadcrumbLimit })` changes the cap. `initWebority` takes a required `remoteLogger`: the sink, or `null` for a build without crash reporting. It also takes a required `appId`, the compiled settings' app id, and refuses to start when it differs from the installed app's id: a bundle prebuilt for another environment stops at start-up with the prebuild step to run.
|
|
235
238
|
|
|
239
|
+
## App lock
|
|
240
|
+
|
|
241
|
+
`@webority/mobile-core/appLock` locks the app when a signed-in person returns after the lock delay (five minutes by default). `useAppLock` returns what a settings screen and the lock screen need:
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
import { useAppLock } from '@webority/mobile-core/appLock';
|
|
245
|
+
|
|
246
|
+
const { locked, enabled, biometricAvailable, availabilityKnown, setEnabled, unlock } = useAppLock({ active: isSignedIn });
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
- `availabilityKnown` is false until the first biometric check settles. Until then `biometricAvailable` is not an answer yet, so a screen should wait before it shows the lock as unavailable or disables its switch.
|
|
250
|
+
- `setEnabled(next)` and `unlock(reason)` return an `AppLockResult`: `{ ok: true }`, or `{ ok: false, reason }` with the reason `cancelled`, `lockout`, `not-enrolled`, `not-available` or `failed`.
|
|
251
|
+
- `policy` overrides the delay and the two storage keys; the defaults are used for any key left out.
|
|
252
|
+
|
|
236
253
|
## Metro bridge
|
|
237
254
|
|
|
238
255
|
`@webority/mobile-core/metro` builds the development bridge that a Metro dev tool reads as
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.stampAccountId=exports.readAccountId=exports.getClientBuild=exports.applyClientHeaders=exports.CLIENT_KIND_HEADER=exports.CLIENT_KIND=exports.CLIENT_BUILD_HEADER=exports.APP_BUILD_HEADER=exports.ACCOUNT_ID_HEADER=void 0;var _index=require("../config/index.js"),_appBuild=require("../versionCheck/appBuild.js");const CLIENT_BUILD_HEADER=exports.CLIENT_BUILD_HEADER="Client-Build",APP_BUILD_HEADER=exports.APP_BUILD_HEADER="App-Build",CLIENT_KIND_HEADER=exports.CLIENT_KIND_HEADER="Client-Kind",ACCOUNT_ID_HEADER=exports.ACCOUNT_ID_HEADER="Account-Id",CLIENT_KIND=exports.CLIENT_KIND="MobileApp",getClientBuild=()=>{const e=(0,_index.getConfigValue)("appVersion");if(!e)return null;const t=(0,_index.getConfigValue)("commit");return t?`${e}+${t}`:e};exports.getClientBuild=getClientBuild;const setIfAbsent=(e,t,s)=>{s&&!e.has(t)&&e.set(t,s)},applyClientHeaders=e=>{e.interceptors.request.use(e=>{setIfAbsent(e.headers,CLIENT_KIND_HEADER,CLIENT_KIND),setIfAbsent(e.headers,CLIENT_BUILD_HEADER,getClientBuild());const t=(0,_appBuild.readAppBuild)();return setIfAbsent(e.headers,APP_BUILD_HEADER,null===t?null:String(t)),e})};exports.applyClientHeaders=applyClientHeaders;const readAccountId=async e=>e&&await e()||null;exports.readAccountId=readAccountId;const stampAccountId=async(e,t)=>{if(void 0!==e._accountId)return void(e._accountId&&e.headers.set(ACCOUNT_ID_HEADER,e._accountId));const s=e.headers.get(ACCOUNT_ID_HEADER);if("string"==typeof s&&""!==s)return void(e._accountId=s);const n=await readAccountId(t);e._accountId=n,n&&e.headers.set(ACCOUNT_ID_HEADER,n)};exports.stampAccountId=stampAccountId;
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.stampAccountId=exports.readAccountId=exports.getClientBuild=exports.applyClientHeaders=exports.CLIENT_KIND_HEADER=exports.CLIENT_KIND=exports.CLIENT_BUILD_HEADER=exports.CLIENT_APP_HEADER=exports.APP_BUILD_HEADER=exports.ACCOUNT_ID_HEADER=void 0;var _index=require("../config/index.js"),_appBuild=require("../versionCheck/appBuild.js");const CLIENT_BUILD_HEADER=exports.CLIENT_BUILD_HEADER="Client-Build",APP_BUILD_HEADER=exports.APP_BUILD_HEADER="App-Build",CLIENT_KIND_HEADER=exports.CLIENT_KIND_HEADER="Client-Kind",CLIENT_APP_HEADER=exports.CLIENT_APP_HEADER="Client-App",ACCOUNT_ID_HEADER=exports.ACCOUNT_ID_HEADER="Account-Id",CLIENT_KIND=exports.CLIENT_KIND="MobileApp",getClientBuild=()=>{const e=(0,_index.getConfigValue)("appVersion");if(!e)return null;const t=(0,_index.getConfigValue)("commit");return t?`${e}+${t}`:e};exports.getClientBuild=getClientBuild;const setIfAbsent=(e,t,s)=>{s&&!e.has(t)&&e.set(t,s)},applyClientHeaders=e=>{e.interceptors.request.use(e=>{setIfAbsent(e.headers,CLIENT_KIND_HEADER,CLIENT_KIND),setIfAbsent(e.headers,CLIENT_APP_HEADER,(0,_index.getConfigValue)("appId")),setIfAbsent(e.headers,CLIENT_BUILD_HEADER,getClientBuild());const t=(0,_appBuild.readAppBuild)();return setIfAbsent(e.headers,APP_BUILD_HEADER,null===t?null:String(t)),e})};exports.applyClientHeaders=applyClientHeaders;const readAccountId=async e=>e&&await e()||null;exports.readAccountId=readAccountId;const stampAccountId=async(e,t)=>{if(void 0!==e._accountId)return void(e._accountId&&e.headers.set(ACCOUNT_ID_HEADER,e._accountId));const s=e.headers.get(ACCOUNT_ID_HEADER);if("string"==typeof s&&""!==s)return void(e._accountId=s);const n=await readAccountId(t);e._accountId=n,n&&e.headers.set(ACCOUNT_ID_HEADER,n)};exports.stampAccountId=stampAccountId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.authenticateBiometric=authenticateBiometric,exports.isBiometricAvailable=isBiometricAvailable,exports.useAppLock=useAppLock;var cache,LocalAuthentication=_interopRequireWildcard(require("expo-local-authentication")),_react=require("react"),_reactNative=require("react-native"),_index=require("../logger/index.js"),_index2=require("../storage/index.js");function _interopRequireWildcard(e,t){if(!t&&e&&e.__esModule)return e;var a,r,c=Object.defineProperty,n={__proto__:null,default:e};if(Object(e)!==e)return n;if(cache||"function"!=typeof WeakMap||(cache=new WeakMap),cache){if(cache.has(e))return cache.get(e);cache.set(e,n)}for(r in e)"default"!==r&&{}.hasOwnProperty.call(e,r)&&((a=c&&Object.getOwnPropertyDescriptor(e,r))&&(a.get||a.set)?c(n,r,a):n[r]=e[r]);return n}const DEFAULT_POLICY={lockAfterMs:3e5,enabledKey:"appLockEnabled",backgroundedAtKey:"appLockBackgroundedAt"};let pendingPrompt=null;async function isBiometricAvailable(){try{const[e,t]=await Promise.all([LocalAuthentication.hasHardwareAsync(),LocalAuthentication.isEnrolledAsync()]);return e&&t}catch(e){return _index.Logger.error("[AppLock] biometric availability check failed:",e),!1}}const failureFor=e=>{switch(e){case"user_cancel":case"app_cancel":case"system_cancel":case"user_fallback":return"cancelled";case"lockout":return"lockout";case"not_enrolled":case"passcode_not_set":return"not-enrolled";case"not_available":return"not-available";default:return"failed"}},prompt=async e=>{try{if(await LocalAuthentication.getEnrolledLevelAsync()===LocalAuthentication.SecurityLevel.NONE)return{ok:!1,reason:"not-enrolled"};const t=await LocalAuthentication.authenticateAsync({promptMessage:e,cancelLabel:"Cancel",fallbackLabel:"Use passcode",disableDeviceFallback:!1});return t.success?{ok:!0}:(_index.Logger.warn("[AppLock] check not passed:",t.error),{ok:!1,reason:failureFor(t.error)})}catch(e){return _index.Logger.error("[AppLock] check failed:",e),{ok:!1,reason:"failed"}}};function authenticateBiometric(e){return pendingPrompt||(pendingPrompt=prompt(e).finally(()=>{pendingPrompt=null})),pendingPrompt}function useAppLock({active:e,policy:t}){const a=t?.lockAfterMs??DEFAULT_POLICY.lockAfterMs,r=t?.enabledKey??DEFAULT_POLICY.enabledKey,c=t?.backgroundedAtKey??DEFAULT_POLICY.backgroundedAtKey,[n,o]=(0,_react.useState)(!1),[i,l]=(0,_react.useState)(!1),[s,u]=(0,_react.useState)(!1),d=(0,_react.useCallback)(async()=>{const e=await _index2.Storage.getItem(r);return"true"===e||"false"===e?"true"===e:isBiometricAvailable()},[r]),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.authenticateBiometric=authenticateBiometric,exports.isBiometricAvailable=isBiometricAvailable,exports.useAppLock=useAppLock;var cache,LocalAuthentication=_interopRequireWildcard(require("expo-local-authentication")),_react=require("react"),_reactNative=require("react-native"),_index=require("../logger/index.js"),_index2=require("../storage/index.js");function _interopRequireWildcard(e,t){if(!t&&e&&e.__esModule)return e;var a,r,c=Object.defineProperty,n={__proto__:null,default:e};if(Object(e)!==e)return n;if(cache||"function"!=typeof WeakMap||(cache=new WeakMap),cache){if(cache.has(e))return cache.get(e);cache.set(e,n)}for(r in e)"default"!==r&&{}.hasOwnProperty.call(e,r)&&((a=c&&Object.getOwnPropertyDescriptor(e,r))&&(a.get||a.set)?c(n,r,a):n[r]=e[r]);return n}const DEFAULT_POLICY={lockAfterMs:3e5,enabledKey:"appLockEnabled",backgroundedAtKey:"appLockBackgroundedAt"};let pendingPrompt=null;async function isBiometricAvailable(){try{const[e,t]=await Promise.all([LocalAuthentication.hasHardwareAsync(),LocalAuthentication.isEnrolledAsync()]);return e&&t}catch(e){return _index.Logger.error("[AppLock] biometric availability check failed:",e),!1}}const failureFor=e=>{switch(e){case"user_cancel":case"app_cancel":case"system_cancel":case"user_fallback":return"cancelled";case"lockout":return"lockout";case"not_enrolled":case"passcode_not_set":return"not-enrolled";case"not_available":return"not-available";default:return"failed"}},prompt=async e=>{try{if(await LocalAuthentication.getEnrolledLevelAsync()===LocalAuthentication.SecurityLevel.NONE)return{ok:!1,reason:"not-enrolled"};const t=await LocalAuthentication.authenticateAsync({promptMessage:e,cancelLabel:"Cancel",fallbackLabel:"Use passcode",disableDeviceFallback:!1});return t.success?{ok:!0}:(_index.Logger.warn("[AppLock] check not passed:",t.error),{ok:!1,reason:failureFor(t.error)})}catch(e){return _index.Logger.error("[AppLock] check failed:",e),{ok:!1,reason:"failed"}}};function authenticateBiometric(e){return pendingPrompt||(pendingPrompt=prompt(e).finally(()=>{pendingPrompt=null})),pendingPrompt}function useAppLock({active:e,policy:t}){const a=t?.lockAfterMs??DEFAULT_POLICY.lockAfterMs,r=t?.enabledKey??DEFAULT_POLICY.enabledKey,c=t?.backgroundedAtKey??DEFAULT_POLICY.backgroundedAtKey,[n,o]=(0,_react.useState)(!1),[i,l]=(0,_react.useState)(!1),[s,u]=(0,_react.useState)(!1),[d,p]=(0,_react.useState)(!1),_=(0,_react.useCallback)(async()=>{const e=await _index2.Storage.getItem(r);return"true"===e||"false"===e?"true"===e:isBiometricAvailable()},[r]),k=(0,_react.useCallback)(async()=>{const t=await _index2.Storage.getItem(c);null!==t&&(await _index2.Storage.removeItem(c),e&&Date.now()-Number(t)>=a&&await _()&&o(!0))},[e,c,a,_]);(0,_react.useEffect)(()=>{e||o(!1),k()},[e,k]),(0,_react.useEffect)(()=>{const t=_reactNative.AppState.addEventListener("change",t=>{"background"===t&&e?_index2.Storage.setItem(c,String(Date.now())):"active"===t&&k()});return()=>t.remove()},[e,c,k]),(0,_react.useEffect)(()=>{let e=!1;return isBiometricAvailable().then(t=>{e||(u(t),p(!0))}),_().then(t=>{e||l(t)}),()=>{e=!0}},[_]);return{locked:n,enabled:i,biometricAvailable:s,availabilityKnown:d,setEnabled:(0,_react.useCallback)(async e=>await _index2.Storage.setItem(r,e?"true":"false")?(l(e),{ok:!0}):{ok:!1,reason:"failed"},[r]),unlock:(0,_react.useCallback)(async e=>{const t=await authenticateBiometric(e);return t.ok&&o(!1),t},[])}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{getConfigValue}from"../config/index.js";import{readAppBuild}from"../versionCheck/appBuild.js";export const CLIENT_BUILD_HEADER="Client-Build";export const APP_BUILD_HEADER="App-Build";export const CLIENT_KIND_HEADER="Client-Kind";export const ACCOUNT_ID_HEADER="Account-Id";export const CLIENT_KIND="MobileApp";export const getClientBuild=()=>{const t=getConfigValue("appVersion");if(!t)return null;const e=getConfigValue("commit");return e?`${t}+${e}`:t};const setIfAbsent=(t,e,n)=>{n&&!t.has(e)&&t.set(e,n)};export const applyClientHeaders=t=>{t.interceptors.request.use(t=>{setIfAbsent(t.headers,"Client-Kind","MobileApp"),setIfAbsent(t.headers,"Client-Build",getClientBuild());const e=readAppBuild();return setIfAbsent(t.headers,"App-Build",null===e?null:String(e)),t})};export const readAccountId=async t=>t&&await t()||null;export const stampAccountId=async(t,e)=>{if(void 0!==t._accountId)return void(t._accountId&&t.headers.set("Account-Id",t._accountId));const n=t.headers.get("Account-Id");if("string"==typeof n&&""!==n)return void(t._accountId=n);const o=await readAccountId(e);t._accountId=o,o&&t.headers.set("Account-Id",o)};
|
|
1
|
+
"use strict";import{getConfigValue}from"../config/index.js";import{readAppBuild}from"../versionCheck/appBuild.js";export const CLIENT_BUILD_HEADER="Client-Build";export const APP_BUILD_HEADER="App-Build";export const CLIENT_KIND_HEADER="Client-Kind";export const CLIENT_APP_HEADER="Client-App";export const ACCOUNT_ID_HEADER="Account-Id";export const CLIENT_KIND="MobileApp";export const getClientBuild=()=>{const t=getConfigValue("appVersion");if(!t)return null;const e=getConfigValue("commit");return e?`${t}+${e}`:t};const setIfAbsent=(t,e,n)=>{n&&!t.has(e)&&t.set(e,n)};export const applyClientHeaders=t=>{t.interceptors.request.use(t=>{setIfAbsent(t.headers,"Client-Kind","MobileApp"),setIfAbsent(t.headers,"Client-App",getConfigValue("appId")),setIfAbsent(t.headers,"Client-Build",getClientBuild());const e=readAppBuild();return setIfAbsent(t.headers,"App-Build",null===e?null:String(e)),t})};export const readAccountId=async t=>t&&await t()||null;export const stampAccountId=async(t,e)=>{if(void 0!==t._accountId)return void(t._accountId&&t.headers.set("Account-Id",t._accountId));const n=t.headers.get("Account-Id");if("string"==typeof n&&""!==n)return void(t._accountId=n);const o=await readAccountId(e);t._accountId=o,o&&t.headers.set("Account-Id",o)};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import*as LocalAuthentication from"expo-local-authentication";import{useCallback,useEffect,useState}from"react";import{AppState}from"react-native";import{Logger}from"../logger/index.js";import{Storage}from"../storage/index.js";const DEFAULT_POLICY={lockAfterMs:3e5,enabledKey:"appLockEnabled",backgroundedAtKey:"appLockBackgroundedAt"};let pendingPrompt=null;export async function isBiometricAvailable(){try{const[e,t]=await Promise.all([LocalAuthentication.hasHardwareAsync(),LocalAuthentication.isEnrolledAsync()]);return e&&t}catch(e){return Logger.error("[AppLock] biometric availability check failed:",e),!1}}const failureFor=e=>{switch(e){case"user_cancel":case"app_cancel":case"system_cancel":case"user_fallback":return"cancelled";case"lockout":return"lockout";case"not_enrolled":case"passcode_not_set":return"not-enrolled";case"not_available":return"not-available";default:return"failed"}},prompt=async e=>{try{if(await LocalAuthentication.getEnrolledLevelAsync()===LocalAuthentication.SecurityLevel.NONE)return{ok:!1,reason:"not-enrolled"};const t=await LocalAuthentication.authenticateAsync({promptMessage:e,cancelLabel:"Cancel",fallbackLabel:"Use passcode",disableDeviceFallback:!1});return t.success?{ok:!0}:(Logger.warn("[AppLock] check not passed:",t.error),{ok:!1,reason:failureFor(t.error)})}catch(e){return Logger.error("[AppLock] check failed:",e),{ok:!1,reason:"failed"}}};export function authenticateBiometric(e){return pendingPrompt||(pendingPrompt=prompt(e).finally(()=>{pendingPrompt=null})),pendingPrompt}export function useAppLock({active:e,policy:t}){const a=t?.lockAfterMs??DEFAULT_POLICY.lockAfterMs,
|
|
1
|
+
"use strict";import*as LocalAuthentication from"expo-local-authentication";import{useCallback,useEffect,useState}from"react";import{AppState}from"react-native";import{Logger}from"../logger/index.js";import{Storage}from"../storage/index.js";const DEFAULT_POLICY={lockAfterMs:3e5,enabledKey:"appLockEnabled",backgroundedAtKey:"appLockBackgroundedAt"};let pendingPrompt=null;export async function isBiometricAvailable(){try{const[e,t]=await Promise.all([LocalAuthentication.hasHardwareAsync(),LocalAuthentication.isEnrolledAsync()]);return e&&t}catch(e){return Logger.error("[AppLock] biometric availability check failed:",e),!1}}const failureFor=e=>{switch(e){case"user_cancel":case"app_cancel":case"system_cancel":case"user_fallback":return"cancelled";case"lockout":return"lockout";case"not_enrolled":case"passcode_not_set":return"not-enrolled";case"not_available":return"not-available";default:return"failed"}},prompt=async e=>{try{if(await LocalAuthentication.getEnrolledLevelAsync()===LocalAuthentication.SecurityLevel.NONE)return{ok:!1,reason:"not-enrolled"};const t=await LocalAuthentication.authenticateAsync({promptMessage:e,cancelLabel:"Cancel",fallbackLabel:"Use passcode",disableDeviceFallback:!1});return t.success?{ok:!0}:(Logger.warn("[AppLock] check not passed:",t.error),{ok:!1,reason:failureFor(t.error)})}catch(e){return Logger.error("[AppLock] check failed:",e),{ok:!1,reason:"failed"}}};export function authenticateBiometric(e){return pendingPrompt||(pendingPrompt=prompt(e).finally(()=>{pendingPrompt=null})),pendingPrompt}export function useAppLock({active:e,policy:t}){const a=t?.lockAfterMs??DEFAULT_POLICY.lockAfterMs,o=t?.enabledKey??DEFAULT_POLICY.enabledKey,r=t?.backgroundedAtKey??DEFAULT_POLICY.backgroundedAtKey,[n,c]=useState(!1),[l,i]=useState(!1),[s,u]=useState(!1),[p,d]=useState(!1),k=useCallback(async()=>{const e=await Storage.getItem(o);return"true"===e||"false"===e?"true"===e:isBiometricAvailable()},[o]),m=useCallback(async()=>{const t=await Storage.getItem(r);null!==t&&(await Storage.removeItem(r),e&&Date.now()-Number(t)>=a&&await k()&&c(!0))},[e,r,a,k]);useEffect(()=>{e||c(!1),m()},[e,m]),useEffect(()=>{const t=AppState.addEventListener("change",t=>{"background"===t&&e?Storage.setItem(r,String(Date.now())):"active"===t&&m()});return()=>t.remove()},[e,r,m]),useEffect(()=>{let e=!1;return isBiometricAvailable().then(t=>{e||(u(t),d(!0))}),k().then(t=>{e||i(t)}),()=>{e=!0}},[k]);return{locked:n,enabled:l,biometricAvailable:s,availabilityKnown:p,setEnabled:useCallback(async e=>await Storage.setItem(o,e?"true":"false")?(i(e),{ok:!0}):{ok:!1,reason:"failed"},[o]),unlock:useCallback(async e=>{const t=await authenticateBiometric(e);return t.ok&&c(!1),t},[])}}
|
|
@@ -2,6 +2,7 @@ import type { AxiosInstance } from "axios";
|
|
|
2
2
|
export declare const CLIENT_BUILD_HEADER = "Client-Build";
|
|
3
3
|
export declare const APP_BUILD_HEADER = "App-Build";
|
|
4
4
|
export declare const CLIENT_KIND_HEADER = "Client-Kind";
|
|
5
|
+
export declare const CLIENT_APP_HEADER = "Client-App";
|
|
5
6
|
export declare const ACCOUNT_ID_HEADER = "Account-Id";
|
|
6
7
|
/** The server picks session rules and the minimum version per kind; the names match its enum. */
|
|
7
8
|
export type ClientKind = "Browser" | "MobileApp";
|
|
@@ -9,7 +10,8 @@ export declare const CLIENT_KIND: ClientKind;
|
|
|
9
10
|
/** `<appVersion>+<commit>`, `<appVersion>` when no commit was stamped, `null` before init. */
|
|
10
11
|
export declare const getClientBuild: () => string | null;
|
|
11
12
|
/**
|
|
12
|
-
* Stamps Client-Kind, Client-Build and App-Build on every request
|
|
13
|
+
* Stamps Client-Kind, Client-Build and App-Build on every request, and Client-App with the
|
|
14
|
+
* config's app id when one is set, so the server can tell the apps of one kind apart.
|
|
13
15
|
* App-Build is the whole build number the server compares with its minimum;
|
|
14
16
|
* it is left off when the build is unknown, because the server never refuses a
|
|
15
17
|
* request without it and a guessed number could strand a current build. A value the app
|
|
@@ -14,6 +14,8 @@ export interface AppLockState {
|
|
|
14
14
|
locked: boolean;
|
|
15
15
|
enabled: boolean;
|
|
16
16
|
biometricAvailable: boolean;
|
|
17
|
+
/** False until the first biometric availability check settles, so `biometricAvailable` is not yet a real answer. */
|
|
18
|
+
availabilityKnown: boolean;
|
|
17
19
|
setEnabled: (enabled: boolean) => Promise<AppLockResult>;
|
|
18
20
|
unlock: (reason: string) => Promise<AppLockResult>;
|
|
19
21
|
}
|
|
@@ -25,6 +27,8 @@ export declare function authenticateBiometric(reason: string): Promise<AppLockRe
|
|
|
25
27
|
* The time it left the screen is saved, not held in memory, so a phone that closed the app in the background still
|
|
26
28
|
* locks on the next launch. Only "background" counts as away: iOS reports "inactive" while the Face ID prompt is up.
|
|
27
29
|
* The person's choice is stored under `enabledKey`; with none saved it is on when the phone has a fingerprint or face enrolled.
|
|
30
|
+
* `availabilityKnown` stays false until the first availability check settles, so a screen can wait before it reads
|
|
31
|
+
* `biometricAvailable` as "this phone has no biometrics".
|
|
28
32
|
*/
|
|
29
33
|
export declare function useAppLock({ active, policy }: {
|
|
30
34
|
active: boolean;
|
|
@@ -2,6 +2,7 @@ import type { AxiosInstance } from "axios";
|
|
|
2
2
|
export declare const CLIENT_BUILD_HEADER = "Client-Build";
|
|
3
3
|
export declare const APP_BUILD_HEADER = "App-Build";
|
|
4
4
|
export declare const CLIENT_KIND_HEADER = "Client-Kind";
|
|
5
|
+
export declare const CLIENT_APP_HEADER = "Client-App";
|
|
5
6
|
export declare const ACCOUNT_ID_HEADER = "Account-Id";
|
|
6
7
|
/** The server picks session rules and the minimum version per kind; the names match its enum. */
|
|
7
8
|
export type ClientKind = "Browser" | "MobileApp";
|
|
@@ -9,7 +10,8 @@ export declare const CLIENT_KIND: ClientKind;
|
|
|
9
10
|
/** `<appVersion>+<commit>`, `<appVersion>` when no commit was stamped, `null` before init. */
|
|
10
11
|
export declare const getClientBuild: () => string | null;
|
|
11
12
|
/**
|
|
12
|
-
* Stamps Client-Kind, Client-Build and App-Build on every request
|
|
13
|
+
* Stamps Client-Kind, Client-Build and App-Build on every request, and Client-App with the
|
|
14
|
+
* config's app id when one is set, so the server can tell the apps of one kind apart.
|
|
13
15
|
* App-Build is the whole build number the server compares with its minimum;
|
|
14
16
|
* it is left off when the build is unknown, because the server never refuses a
|
|
15
17
|
* request without it and a guessed number could strand a current build. A value the app
|
|
@@ -14,6 +14,8 @@ export interface AppLockState {
|
|
|
14
14
|
locked: boolean;
|
|
15
15
|
enabled: boolean;
|
|
16
16
|
biometricAvailable: boolean;
|
|
17
|
+
/** False until the first biometric availability check settles, so `biometricAvailable` is not yet a real answer. */
|
|
18
|
+
availabilityKnown: boolean;
|
|
17
19
|
setEnabled: (enabled: boolean) => Promise<AppLockResult>;
|
|
18
20
|
unlock: (reason: string) => Promise<AppLockResult>;
|
|
19
21
|
}
|
|
@@ -25,6 +27,8 @@ export declare function authenticateBiometric(reason: string): Promise<AppLockRe
|
|
|
25
27
|
* The time it left the screen is saved, not held in memory, so a phone that closed the app in the background still
|
|
26
28
|
* locks on the next launch. Only "background" counts as away: iOS reports "inactive" while the Face ID prompt is up.
|
|
27
29
|
* The person's choice is stored under `enabledKey`; with none saved it is on when the phone has a fingerprint or face enrolled.
|
|
30
|
+
* `availabilityKnown` stays false until the first availability check settles, so a screen can wait before it reads
|
|
31
|
+
* `biometricAvailable` as "this phone has no biometrics".
|
|
28
32
|
*/
|
|
29
33
|
export declare function useAppLock({ active, policy }: {
|
|
30
34
|
active: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority/mobile-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.114.0",
|
|
4
4
|
"description": "Platform layer for Webority React Native apps: HTTP clients, auth/token storage, config, logging, formatters, validators, network status, permissions, storage, version checks and over-the-air updates. No UI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|