@symbiote-native/local-auth 0.0.1 → 0.3.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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +252 -24
  3. package/build/angular/index.d.ts +1 -0
  4. package/build/angular/index.js +4 -0
  5. package/build/core/index.d.ts +2 -0
  6. package/build/core/index.js +2 -0
  7. package/build/core/local-authentication.d.ts +33 -0
  8. package/build/core/local-authentication.js +75 -0
  9. package/build/core/native-module.d.ts +13 -0
  10. package/build/core/native-module.js +3 -0
  11. package/build/core/types.d.ts +83 -0
  12. package/build/core/types.js +55 -0
  13. package/build/react/index.d.ts +1 -0
  14. package/build/react/index.js +6 -0
  15. package/build/svelte/index.d.ts +1 -0
  16. package/build/svelte/index.js +6 -0
  17. package/build/vue/index.d.ts +1 -0
  18. package/build/vue/index.js +4 -0
  19. package/build-ngc/angular/index.d.ts +1 -0
  20. package/build-ngc/angular/index.js +5 -0
  21. package/build-ngc/angular/index.js.map +1 -0
  22. package/build-ngc/core/index.d.ts +2 -0
  23. package/build-ngc/core/index.js +3 -0
  24. package/build-ngc/core/index.js.map +1 -0
  25. package/build-ngc/core/local-authentication.d.ts +33 -0
  26. package/build-ngc/core/local-authentication.js +76 -0
  27. package/build-ngc/core/local-authentication.js.map +1 -0
  28. package/build-ngc/core/native-module.d.ts +13 -0
  29. package/build-ngc/core/native-module.js +4 -0
  30. package/build-ngc/core/native-module.js.map +1 -0
  31. package/build-ngc/core/types.d.ts +83 -0
  32. package/build-ngc/core/types.js +56 -0
  33. package/build-ngc/core/types.js.map +1 -0
  34. package/native-link.json +17 -0
  35. package/package.json +110 -3
  36. package/src/angular/index.ts +4 -0
  37. package/src/core/index.ts +16 -0
  38. package/src/core/local-authentication.ts +96 -0
  39. package/src/core/native-module.ts +27 -0
  40. package/src/core/types.ts +130 -0
  41. package/src/react/index.ts +6 -0
  42. package/src/svelte/index.ts +6 -0
  43. package/src/vue/index.ts +4 -0
@@ -0,0 +1,3 @@
1
+ export { hasHardwareAsync, supportedAuthenticationTypesAsync, isEnrolledAsync, getEnrolledLevelAsync, authenticateAsync, cancelAuthenticate, } from './local-authentication';
2
+ export { AuthenticationType, SecurityLevel, } from './types';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,iCAAiC,EACjC,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,kBAAkB,EAClB,aAAa,GAKd,MAAM,SAAS,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { AuthenticationType, ILocalAuthenticationOptions, ILocalAuthenticationResult, SecurityLevel } from './types';
2
+ /**
3
+ * Determine whether a face or fingerprint scanner is available on the device.
4
+ */
5
+ export declare function hasHardwareAsync(): Promise<boolean>;
6
+ /**
7
+ * Determine what kinds of authentications are available on the device. Devices can support
8
+ * multiple authentication methods — e.g. `[FINGERPRINT, FACIAL_RECOGNITION]` means the device
9
+ * supports both. Returns an empty array if none are supported.
10
+ */
11
+ export declare function supportedAuthenticationTypesAsync(): Promise<AuthenticationType[]>;
12
+ /**
13
+ * Determine whether the device has saved fingerprints or facial data to use for authentication.
14
+ */
15
+ export declare function isEnrolledAsync(): Promise<boolean>;
16
+ /**
17
+ * Determine what kind of authentication is enrolled on the device.
18
+ * > On Android devices prior to M, `SECRET` can be returned if only the SIM lock has been
19
+ * enrolled, which is not the method `authenticateAsync` prompts.
20
+ */
21
+ export declare function getEnrolledLevelAsync(): Promise<SecurityLevel>;
22
+ /**
23
+ * Attempts to authenticate via Fingerprint/TouchID (or FaceID if available on the device).
24
+ * > Apple requires apps which use FaceID to provide a description of why they use this API
25
+ * (`NSFaceIDUsageDescription` in `Info.plist`). Without it, the module authenticates using the
26
+ * device passcode instead.
27
+ */
28
+ export declare function authenticateAsync(options?: ILocalAuthenticationOptions): Promise<ILocalAuthenticationResult>;
29
+ /**
30
+ * Cancels the authentication flow.
31
+ * @platform android
32
+ */
33
+ export declare function cancelAuthenticate(): Promise<void>;
@@ -0,0 +1,76 @@
1
+ import { UnavailabilityError } from 'expo-modules-core';
2
+ import invariant from 'invariant';
3
+ import { expoLocalAuthentication } from './native-module';
4
+ const NATIVE_MODULE_NAME = 'expo-local-authentication';
5
+ const DEFAULT_PROMPT_MESSAGE = 'Authenticate';
6
+ const DEFAULT_CANCEL_LABEL = 'Cancel';
7
+ /**
8
+ * Determine whether a face or fingerprint scanner is available on the device.
9
+ */
10
+ export async function hasHardwareAsync() {
11
+ if (!expoLocalAuthentication.hasHardwareAsync) {
12
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'hasHardwareAsync');
13
+ }
14
+ return expoLocalAuthentication.hasHardwareAsync();
15
+ }
16
+ /**
17
+ * Determine what kinds of authentications are available on the device. Devices can support
18
+ * multiple authentication methods — e.g. `[FINGERPRINT, FACIAL_RECOGNITION]` means the device
19
+ * supports both. Returns an empty array if none are supported.
20
+ */
21
+ export async function supportedAuthenticationTypesAsync() {
22
+ if (!expoLocalAuthentication.supportedAuthenticationTypesAsync) {
23
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'supportedAuthenticationTypesAsync');
24
+ }
25
+ return expoLocalAuthentication.supportedAuthenticationTypesAsync();
26
+ }
27
+ /**
28
+ * Determine whether the device has saved fingerprints or facial data to use for authentication.
29
+ */
30
+ export async function isEnrolledAsync() {
31
+ if (!expoLocalAuthentication.isEnrolledAsync) {
32
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'isEnrolledAsync');
33
+ }
34
+ return expoLocalAuthentication.isEnrolledAsync();
35
+ }
36
+ /**
37
+ * Determine what kind of authentication is enrolled on the device.
38
+ * > On Android devices prior to M, `SECRET` can be returned if only the SIM lock has been
39
+ * enrolled, which is not the method `authenticateAsync` prompts.
40
+ */
41
+ export async function getEnrolledLevelAsync() {
42
+ if (!expoLocalAuthentication.getEnrolledLevelAsync) {
43
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getEnrolledLevelAsync');
44
+ }
45
+ return expoLocalAuthentication.getEnrolledLevelAsync();
46
+ }
47
+ /**
48
+ * Attempts to authenticate via Fingerprint/TouchID (or FaceID if available on the device).
49
+ * > Apple requires apps which use FaceID to provide a description of why they use this API
50
+ * (`NSFaceIDUsageDescription` in `Info.plist`). Without it, the module authenticates using the
51
+ * device passcode instead.
52
+ */
53
+ export async function authenticateAsync(options = {}) {
54
+ if (!expoLocalAuthentication.authenticateAsync) {
55
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'authenticateAsync');
56
+ }
57
+ if (options.promptMessage !== undefined) {
58
+ invariant(typeof options.promptMessage === 'string' && options.promptMessage.length > 0, 'LocalAuthentication.authenticateAsync: `options.promptMessage` must be a non-empty string.');
59
+ }
60
+ return expoLocalAuthentication.authenticateAsync({
61
+ ...options,
62
+ promptMessage: options.promptMessage || DEFAULT_PROMPT_MESSAGE,
63
+ cancelLabel: options.cancelLabel || DEFAULT_CANCEL_LABEL,
64
+ });
65
+ }
66
+ /**
67
+ * Cancels the authentication flow.
68
+ * @platform android
69
+ */
70
+ export async function cancelAuthenticate() {
71
+ if (!expoLocalAuthentication.cancelAuthenticate) {
72
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'cancelAuthenticate');
73
+ }
74
+ await expoLocalAuthentication.cancelAuthenticate();
75
+ }
76
+ //# sourceMappingURL=local-authentication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-authentication.js","sourceRoot":"","sources":["../../src/core/local-authentication.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,SAAS,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAQ1D,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;AACvD,MAAM,sBAAsB,GAAG,cAAc,CAAC;AAC9C,MAAM,oBAAoB,GAAG,QAAQ,CAAC;AAEtC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC,uBAAuB,CAAC,gBAAgB,EAAE,CAAC;QAC9C,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,uBAAuB,CAAC,gBAAgB,EAAE,CAAC;AACpD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iCAAiC;IACrD,IAAI,CAAC,uBAAuB,CAAC,iCAAiC,EAAE,CAAC;QAC/D,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,mCAAmC,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,uBAAuB,CAAC,iCAAiC,EAAE,CAAC;AACrE,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,CAAC,uBAAuB,CAAC,eAAe,EAAE,CAAC;QAC7C,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,iBAAiB,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,uBAAuB,CAAC,eAAe,EAAE,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,IAAI,CAAC,uBAAuB,CAAC,qBAAqB,EAAE,CAAC;QACnD,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,uBAAuB,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,uBAAuB,CAAC,qBAAqB,EAAE,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,UAAuC,EAAE;IAEzC,IAAI,CAAC,uBAAuB,CAAC,iBAAiB,EAAE,CAAC;QAC/C,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACxC,SAAS,CACP,OAAO,OAAO,CAAC,aAAa,KAAK,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAC7E,4FAA4F,CAC7F,CAAC;IACJ,CAAC;IAED,OAAO,uBAAuB,CAAC,iBAAiB,CAAC;QAC/C,GAAG,OAAO;QACV,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,sBAAsB;QAC9D,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,oBAAoB;KACzD,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,IAAI,CAAC,uBAAuB,CAAC,kBAAkB,EAAE,CAAC;QAChD,MAAM,IAAI,mBAAmB,CAAC,kBAAkB,EAAE,oBAAoB,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,uBAAuB,CAAC,kBAAkB,EAAE,CAAC;AACrD,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { AuthenticationType, ILocalAuthenticationOptions, ILocalAuthenticationResult, SecurityLevel } from './types';
2
+ export type INativeLocalAuthenticationModule = {
3
+ hasHardwareAsync?(): Promise<boolean>;
4
+ supportedAuthenticationTypesAsync?(): Promise<AuthenticationType[]>;
5
+ isEnrolledAsync?(): Promise<boolean>;
6
+ getEnrolledLevelAsync?(): Promise<SecurityLevel>;
7
+ authenticateAsync?(options: ILocalAuthenticationOptions & {
8
+ promptMessage: string;
9
+ cancelLabel: string;
10
+ }): Promise<ILocalAuthenticationResult>;
11
+ cancelAuthenticate?(): Promise<void>;
12
+ };
13
+ export declare const expoLocalAuthentication: INativeLocalAuthenticationModule;
@@ -0,0 +1,4 @@
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ const EXPO_LOCAL_AUTHENTICATION_MODULE_NAME = 'ExpoLocalAuthentication';
3
+ export const expoLocalAuthentication = requireNativeModule(EXPO_LOCAL_AUTHENTICATION_MODULE_NAME);
4
+ //# sourceMappingURL=native-module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAQxD,MAAM,qCAAqC,GAAG,yBAAyB,CAAC;AAgBxE,MAAM,CAAC,MAAM,uBAAuB,GAAG,mBAAmB,CACxD,qCAAqC,CACtC,CAAC"}
@@ -0,0 +1,83 @@
1
+ export type ILocalAuthenticationResult = {
2
+ success: true;
3
+ } | {
4
+ success: false;
5
+ error: ILocalAuthenticationError;
6
+ warning?: string;
7
+ };
8
+ export declare enum AuthenticationType {
9
+ /** Indicates fingerprint support. */
10
+ FINGERPRINT = 1,
11
+ /** Indicates facial recognition support. */
12
+ FACIAL_RECOGNITION = 2,
13
+ /**
14
+ * Indicates iris recognition support.
15
+ * @platform android
16
+ */
17
+ IRIS = 3
18
+ }
19
+ export declare enum SecurityLevel {
20
+ /** Indicates no enrolled authentication. */
21
+ NONE = 0,
22
+ /** Indicates non-biometric authentication (e.g. PIN, Pattern). */
23
+ SECRET = 1,
24
+ /**
25
+ * Indicates biometric authentication.
26
+ * @deprecated please use `BIOMETRIC_STRONG` or `BIOMETRIC_WEAK` instead.
27
+ * @hidden
28
+ */
29
+ BIOMETRIC,
30
+ /**
31
+ * Indicates weak biometric authentication. For example, a 2D image-based face unlock. There
32
+ * are currently no weak biometric authentication options on iOS.
33
+ */
34
+ BIOMETRIC_WEAK = 2,
35
+ /** Indicates strong biometric authentication. For example, a fingerprint scan or 3D face unlock. */
36
+ BIOMETRIC_STRONG = 3
37
+ }
38
+ /**
39
+ * Security level of the biometric authentication to allow.
40
+ * @platform android
41
+ */
42
+ export type IBiometricsSecurityLevel = 'weak' | 'strong';
43
+ export type ILocalAuthenticationOptions = {
44
+ /** A message that is shown alongside the TouchID or FaceID prompt. */
45
+ promptMessage?: string;
46
+ /**
47
+ * A subtitle displayed below the prompt message in the authentication prompt.
48
+ * @platform android
49
+ */
50
+ promptSubtitle?: string;
51
+ /**
52
+ * A description displayed in the middle of the authentication prompt.
53
+ * @platform android
54
+ */
55
+ promptDescription?: string;
56
+ /** Allows customizing the default `Cancel` label shown. */
57
+ cancelLabel?: string;
58
+ /**
59
+ * After several failed attempts, the system falls back to the device passcode. This setting
60
+ * allows you to disable this option and instead handle the fallback yourself. Defaults to `false`.
61
+ */
62
+ disableDeviceFallback?: boolean;
63
+ /**
64
+ * Sets a hint to the system for whether to require user confirmation after authentication.
65
+ * Defaults to `true`.
66
+ * @platform android
67
+ */
68
+ requireConfirmation?: boolean;
69
+ /**
70
+ * Sets the security class of biometric authentication to allow. `strong` allows only Android
71
+ * Class 3 biometrics; `weak` allows both Class 3 and Class 2.
72
+ * @platform android
73
+ * @default 'weak'
74
+ */
75
+ biometricsSecurityLevel?: IBiometricsSecurityLevel;
76
+ /**
77
+ * Allows customizing the default `Use Passcode` label shown after several failed attempts. An
78
+ * empty string disables the button.
79
+ * @platform ios
80
+ */
81
+ fallbackLabel?: string;
82
+ };
83
+ export type ILocalAuthenticationError = 'not_enrolled' | 'user_cancel' | 'app_cancel' | 'not_available' | 'lockout' | 'no_space' | 'timeout' | 'unable_to_process' | 'unknown' | 'system_cancel' | 'user_fallback' | 'invalid_context' | 'passcode_not_set' | 'authentication_failed';
@@ -0,0 +1,56 @@
1
+ // expo-local-authentication's own types file imports Platform from the `expo` meta-package. We
2
+ // never depend on `expo` itself (it drags in a second Metro/babel pipeline — see the
3
+ // symbiote-expo-native-module skill) so this pulls Platform straight from expo-modules-core,
4
+ // which is where `expo` re-exports it from — same source device-sensor.ts (packages/sensors)
5
+ // uses for the same reason.
6
+ import { Platform } from 'expo-modules-core';
7
+ export var AuthenticationType;
8
+ (function (AuthenticationType) {
9
+ /** Indicates fingerprint support. */
10
+ AuthenticationType[AuthenticationType["FINGERPRINT"] = 1] = "FINGERPRINT";
11
+ /** Indicates facial recognition support. */
12
+ AuthenticationType[AuthenticationType["FACIAL_RECOGNITION"] = 2] = "FACIAL_RECOGNITION";
13
+ /**
14
+ * Indicates iris recognition support.
15
+ * @platform android
16
+ */
17
+ AuthenticationType[AuthenticationType["IRIS"] = 3] = "IRIS";
18
+ })(AuthenticationType || (AuthenticationType = {}));
19
+ export var SecurityLevel;
20
+ (function (SecurityLevel) {
21
+ /** Indicates no enrolled authentication. */
22
+ SecurityLevel[SecurityLevel["NONE"] = 0] = "NONE";
23
+ /** Indicates non-biometric authentication (e.g. PIN, Pattern). */
24
+ SecurityLevel[SecurityLevel["SECRET"] = 1] = "SECRET";
25
+ /**
26
+ * Indicates biometric authentication.
27
+ * @deprecated please use `BIOMETRIC_STRONG` or `BIOMETRIC_WEAK` instead.
28
+ * @hidden
29
+ */
30
+ SecurityLevel[SecurityLevel["BIOMETRIC"] = Platform.OS === 'android'
31
+ ? SecurityLevel.BIOMETRIC_WEAK
32
+ : SecurityLevel.BIOMETRIC_STRONG] = "BIOMETRIC";
33
+ /**
34
+ * Indicates weak biometric authentication. For example, a 2D image-based face unlock. There
35
+ * are currently no weak biometric authentication options on iOS.
36
+ */
37
+ SecurityLevel[SecurityLevel["BIOMETRIC_WEAK"] = 2] = "BIOMETRIC_WEAK";
38
+ /** Indicates strong biometric authentication. For example, a fingerprint scan or 3D face unlock. */
39
+ SecurityLevel[SecurityLevel["BIOMETRIC_STRONG"] = 3] = "BIOMETRIC_STRONG";
40
+ })(SecurityLevel || (SecurityLevel = {}));
41
+ // Upstream deprecation shim: SecurityLevel.BIOMETRIC used to be a real enum member; it's now a
42
+ // getter aliasing to the platform-correct strong/weak member, so old call sites still resolve
43
+ // but see a console warning steering them to the non-deprecated name.
44
+ Object.defineProperty(SecurityLevel, 'BIOMETRIC', {
45
+ get() {
46
+ const additionalMessage = Platform.OS === 'android'
47
+ ? '. `SecurityLevel.BIOMETRIC` is currently an alias for `SecurityLevel.BIOMETRIC_WEAK` on Android, which might lead to unexpected behaviour.'
48
+ : '';
49
+ console.warn('`SecurityLevel.BIOMETRIC` has been deprecated. Use `SecurityLevel.BIOMETRIC_WEAK` or `SecurityLevel.BIOMETRIC_STRONG` instead' +
50
+ additionalMessage);
51
+ return Platform.OS === 'android'
52
+ ? SecurityLevel.BIOMETRIC_WEAK
53
+ : SecurityLevel.BIOMETRIC_STRONG;
54
+ },
55
+ });
56
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,qFAAqF;AACrF,6FAA6F;AAC7F,6FAA6F;AAC7F,4BAA4B;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAU7C,MAAM,CAAN,IAAY,kBAUX;AAVD,WAAY,kBAAkB;IAC5B,qCAAqC;IACrC,yEAAe,CAAA;IACf,4CAA4C;IAC5C,uFAAsB,CAAA;IACtB;;;OAGG;IACH,2DAAQ,CAAA;AACV,CAAC,EAVW,kBAAkB,KAAlB,kBAAkB,QAU7B;AAED,MAAM,CAAN,IAAY,aAoBX;AApBD,WAAY,aAAa;IACvB,4CAA4C;IAC5C,iDAAQ,CAAA;IACR,kEAAkE;IAClE,qDAAU,CAAA;IACV;;;;OAIG;IACH,2CAAY,QAAQ,CAAC,EAAE,KAAK,SAAS;QACnC,CAAC,CAAC,aAAa,CAAC,cAAc;QAC9B,CAAC,CAAC,aAAa,CAAC,gBAAgB,eAAA,CAAA;IAClC;;;OAGG;IACH,qEAAkB,CAAA;IAClB,oGAAoG;IACpG,yEAAoB,CAAA;AACtB,CAAC,EApBW,aAAa,KAAb,aAAa,QAoBxB;AAED,+FAA+F;AAC/F,8FAA8F;AAC9F,sEAAsE;AACtE,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,WAAW,EAAE;IAChD,GAAG;QACD,MAAM,iBAAiB,GACrB,QAAQ,CAAC,EAAE,KAAK,SAAS;YACvB,CAAC,CAAC,4IAA4I;YAC9I,CAAC,CAAC,EAAE,CAAC;QACT,OAAO,CAAC,IAAI,CACV,+HAA+H;YAC7H,iBAAiB,CACpB,CAAC;QACF,OAAO,QAAQ,CAAC,EAAE,KAAK,SAAS;YAC9B,CAAC,CAAC,aAAa,CAAC,cAAc;YAC9B,CAAC,CAAC,aAAa,CAAC,gBAAgB,CAAC;IACrC,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ {
2
+ "android": {
3
+ "gradleProjectName": "expo-local-authentication",
4
+ "modules": [
5
+ {
6
+ "importPath": "expo.modules.localauthentication.LocalAuthenticationModule",
7
+ "className": "LocalAuthenticationModule",
8
+ "nativeName": "ExpoLocalAuthentication"
9
+ }
10
+ ]
11
+ },
12
+ "ios": {
13
+ "infoPlistKeys": {
14
+ "NSFaceIDUsageDescription": "This app uses Face ID to authenticate you."
15
+ }
16
+ }
17
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@symbiote-native/local-auth",
3
- "version": "0.0.1",
4
- "description": "expo-local-authentication wrapped for SymbioteNative — planned: one framework-agnostic core, reachable from the React, Vue, and Angular adapters. FaceID/TouchID (iOS) and the Fingerprint/Biometric API (Android). Skeleton only — no implementation yet, see README.",
3
+ "version": "0.3.0",
4
+ "description": "expo-local-authentication wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, and Angular adapters. FaceID/TouchID on iOS, the Fingerprint/Biometric API on Android.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -13,7 +13,114 @@
13
13
  "url": "https://github.com/OneEyed1366/symbiote-native/issues"
14
14
  },
15
15
  "author": "Andrey Prokopenko <psevdoproger@gmail.com>",
16
+ "type": "module",
17
+ "main": "./build/core/index.js",
18
+ "module": "./build/core/index.js",
19
+ "types": "./build/core/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./build/core/index.d.ts",
23
+ "default": "./build/core/index.js"
24
+ },
25
+ "./vue": {
26
+ "types": "./build/vue/index.d.ts",
27
+ "default": "./build/vue/index.js"
28
+ },
29
+ "./react": {
30
+ "types": "./build/react/index.d.ts",
31
+ "default": "./build/react/index.js"
32
+ },
33
+ "./svelte": {
34
+ "types": "./build/svelte/index.d.ts",
35
+ "default": "./build/svelte/index.js"
36
+ },
37
+ "./angular": {
38
+ "types": "./build-ngc/angular/index.d.ts",
39
+ "react-native": "./build-ngc/angular/index.js",
40
+ "default": "./src/angular/index.ts"
41
+ }
42
+ },
43
+ "files": [
44
+ "src",
45
+ "build",
46
+ "build-ngc",
47
+ "native-link.json",
48
+ "!src/**/*.test.*",
49
+ "!src/**/*.spec.*",
50
+ "!src/**/*.detox.*"
51
+ ],
16
52
  "publishConfig": {
17
53
  "access": "public"
54
+ },
55
+ "dependencies": {
56
+ "expo-local-authentication": "57.0.2",
57
+ "expo-modules-core": "57.0.5",
58
+ "invariant": "^2.2.4"
59
+ },
60
+ "peerDependencies": {
61
+ "@symbiote-native/angular": ">=0.6.2",
62
+ "@symbiote-native/engine": ">=0.1.7",
63
+ "@symbiote-native/react": ">=0.2.8",
64
+ "@symbiote-native/svelte": ">=0.1.0",
65
+ "@symbiote-native/vue": ">=0.3.8",
66
+ "@angular/core": ">=20",
67
+ "@vue/runtime-core": "^3.5.13",
68
+ "react": ">=19.0.0",
69
+ "react-native": ">=0.86",
70
+ "svelte": ">=5.56.0",
71
+ "vue": ">=3.5.0"
72
+ },
73
+ "peerDependenciesMeta": {
74
+ "@symbiote-native/angular": {
75
+ "optional": true
76
+ },
77
+ "@symbiote-native/react": {
78
+ "optional": true
79
+ },
80
+ "@symbiote-native/svelte": {
81
+ "optional": true
82
+ },
83
+ "@symbiote-native/vue": {
84
+ "optional": true
85
+ },
86
+ "@angular/core": {
87
+ "optional": true
88
+ },
89
+ "@vue/runtime-core": {
90
+ "optional": true
91
+ },
92
+ "react": {
93
+ "optional": true
94
+ },
95
+ "svelte": {
96
+ "optional": true
97
+ },
98
+ "vue": {
99
+ "optional": true
100
+ }
101
+ },
102
+ "devDependencies": {
103
+ "@angular/compiler": "~22.0.8",
104
+ "@angular/compiler-cli": "~22.0.8",
105
+ "@angular/core": "~22.0.8",
106
+ "@types/invariant": "^2.2.37",
107
+ "@types/node": "^26.0.0",
108
+ "@types/react": "^19.2.0",
109
+ "@vue/runtime-core": "^3.5.13",
110
+ "react": "19.2.3",
111
+ "svelte": "^5.56.0",
112
+ "typescript": "~6.0.0",
113
+ "@symbiote-native/angular": "0.7.0",
114
+ "@symbiote-native/engine": "0.2.0",
115
+ "@symbiote-native/react": "0.3.0",
116
+ "@symbiote-native/svelte": "0.2.0",
117
+ "@symbiote-native/test-utils": "0.1.6",
118
+ "@symbiote-native/vue": "0.4.0"
119
+ },
120
+ "scripts": {
121
+ "typecheck": "tsc --build",
122
+ "clean": "rm -rf build-ngc",
123
+ "ng:build": "pnpm run clean && ngc -p tsconfig.angular.json",
124
+ "format": "prettier --write \"src/**/*.{ts,tsx}\""
18
125
  }
19
- }
126
+ }
@@ -0,0 +1,4 @@
1
+ // @symbiote-native/local-auth/angular: the Angular entry over the framework-agnostic core. Same
2
+ // reasoning as the React/Vue entries — no per-instance state or event stream to wrap in a
3
+ // service, so this is a plain re-export.
4
+ export * from '../core';
@@ -0,0 +1,16 @@
1
+ export {
2
+ hasHardwareAsync,
3
+ supportedAuthenticationTypesAsync,
4
+ isEnrolledAsync,
5
+ getEnrolledLevelAsync,
6
+ authenticateAsync,
7
+ cancelAuthenticate,
8
+ } from './local-authentication';
9
+ export {
10
+ AuthenticationType,
11
+ SecurityLevel,
12
+ type IBiometricsSecurityLevel,
13
+ type ILocalAuthenticationOptions,
14
+ type ILocalAuthenticationResult,
15
+ type ILocalAuthenticationError,
16
+ } from './types';
@@ -0,0 +1,96 @@
1
+ import { UnavailabilityError } from 'expo-modules-core';
2
+ import invariant from 'invariant';
3
+
4
+ import { expoLocalAuthentication } from './native-module';
5
+ import type {
6
+ AuthenticationType,
7
+ ILocalAuthenticationOptions,
8
+ ILocalAuthenticationResult,
9
+ SecurityLevel,
10
+ } from './types';
11
+
12
+ const NATIVE_MODULE_NAME = 'expo-local-authentication';
13
+ const DEFAULT_PROMPT_MESSAGE = 'Authenticate';
14
+ const DEFAULT_CANCEL_LABEL = 'Cancel';
15
+
16
+ /**
17
+ * Determine whether a face or fingerprint scanner is available on the device.
18
+ */
19
+ export async function hasHardwareAsync(): Promise<boolean> {
20
+ if (!expoLocalAuthentication.hasHardwareAsync) {
21
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'hasHardwareAsync');
22
+ }
23
+ return expoLocalAuthentication.hasHardwareAsync();
24
+ }
25
+
26
+ /**
27
+ * Determine what kinds of authentications are available on the device. Devices can support
28
+ * multiple authentication methods — e.g. `[FINGERPRINT, FACIAL_RECOGNITION]` means the device
29
+ * supports both. Returns an empty array if none are supported.
30
+ */
31
+ export async function supportedAuthenticationTypesAsync(): Promise<AuthenticationType[]> {
32
+ if (!expoLocalAuthentication.supportedAuthenticationTypesAsync) {
33
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'supportedAuthenticationTypesAsync');
34
+ }
35
+ return expoLocalAuthentication.supportedAuthenticationTypesAsync();
36
+ }
37
+
38
+ /**
39
+ * Determine whether the device has saved fingerprints or facial data to use for authentication.
40
+ */
41
+ export async function isEnrolledAsync(): Promise<boolean> {
42
+ if (!expoLocalAuthentication.isEnrolledAsync) {
43
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'isEnrolledAsync');
44
+ }
45
+ return expoLocalAuthentication.isEnrolledAsync();
46
+ }
47
+
48
+ /**
49
+ * Determine what kind of authentication is enrolled on the device.
50
+ * > On Android devices prior to M, `SECRET` can be returned if only the SIM lock has been
51
+ * enrolled, which is not the method `authenticateAsync` prompts.
52
+ */
53
+ export async function getEnrolledLevelAsync(): Promise<SecurityLevel> {
54
+ if (!expoLocalAuthentication.getEnrolledLevelAsync) {
55
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getEnrolledLevelAsync');
56
+ }
57
+ return expoLocalAuthentication.getEnrolledLevelAsync();
58
+ }
59
+
60
+ /**
61
+ * Attempts to authenticate via Fingerprint/TouchID (or FaceID if available on the device).
62
+ * > Apple requires apps which use FaceID to provide a description of why they use this API
63
+ * (`NSFaceIDUsageDescription` in `Info.plist`). Without it, the module authenticates using the
64
+ * device passcode instead.
65
+ */
66
+ export async function authenticateAsync(
67
+ options: ILocalAuthenticationOptions = {},
68
+ ): Promise<ILocalAuthenticationResult> {
69
+ if (!expoLocalAuthentication.authenticateAsync) {
70
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'authenticateAsync');
71
+ }
72
+
73
+ if (options.promptMessage !== undefined) {
74
+ invariant(
75
+ typeof options.promptMessage === 'string' && options.promptMessage.length > 0,
76
+ 'LocalAuthentication.authenticateAsync: `options.promptMessage` must be a non-empty string.',
77
+ );
78
+ }
79
+
80
+ return expoLocalAuthentication.authenticateAsync({
81
+ ...options,
82
+ promptMessage: options.promptMessage || DEFAULT_PROMPT_MESSAGE,
83
+ cancelLabel: options.cancelLabel || DEFAULT_CANCEL_LABEL,
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Cancels the authentication flow.
89
+ * @platform android
90
+ */
91
+ export async function cancelAuthenticate(): Promise<void> {
92
+ if (!expoLocalAuthentication.cancelAuthenticate) {
93
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'cancelAuthenticate');
94
+ }
95
+ await expoLocalAuthentication.cancelAuthenticate();
96
+ }
@@ -0,0 +1,27 @@
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ import type {
3
+ AuthenticationType,
4
+ ILocalAuthenticationOptions,
5
+ ILocalAuthenticationResult,
6
+ SecurityLevel,
7
+ } from './types';
8
+
9
+ const EXPO_LOCAL_AUTHENTICATION_MODULE_NAME = 'ExpoLocalAuthentication';
10
+
11
+ // Every method is optional — each call site checks for its presence before calling through and
12
+ // throws an UnavailabilityError itself, matching upstream's own per-platform capability checks
13
+ // rather than assuming the native module implements the whole surface.
14
+ export type INativeLocalAuthenticationModule = {
15
+ hasHardwareAsync?(): Promise<boolean>;
16
+ supportedAuthenticationTypesAsync?(): Promise<AuthenticationType[]>;
17
+ isEnrolledAsync?(): Promise<boolean>;
18
+ getEnrolledLevelAsync?(): Promise<SecurityLevel>;
19
+ authenticateAsync?(
20
+ options: ILocalAuthenticationOptions & { promptMessage: string; cancelLabel: string },
21
+ ): Promise<ILocalAuthenticationResult>;
22
+ cancelAuthenticate?(): Promise<void>;
23
+ };
24
+
25
+ export const expoLocalAuthentication = requireNativeModule<INativeLocalAuthenticationModule>(
26
+ EXPO_LOCAL_AUTHENTICATION_MODULE_NAME,
27
+ );