-1

I created a custom npm package for SMS verification. It's a PIN code input that automatically fills out if you receive the PIN via SMS. It works great on its own. The problem occurs when I upload the npm package to Azure Artifacts and try to use it in another project.

After configuring .npmrc to

registry=https://pkgs.dev.azure.com/<url>/npm/registry/ 
                        
always-auth=true

I start a new React Native project with npx react-native init SMSTest and install the package with npm install in the new project.

When I try to use the component I get an error TypeError: null is not an object (evaluating 'RNOtpVerify.getOtp') and the app doesn't work. The error goes away if I run npm i react-native-otp-verify.

The interesting part is that all dependencies are already present in node_modules even before the second time I install them via npm.

Any ideas what could be the problem and how to fix it?

App.tsx

import React from 'react';
import {StyleSheet, View} from 'react-native';
import GiSmsVerificationInput from '<company-name>/GiSmsVerificationInput';

interface AppProps {}

const App: React.FC<AppProps> = props => {
  return (
    <GiSmsVerificationInput
      onFulfill={code => console.log(code)}></GiSmsVerificationInput>
  );
};

const styles = StyleSheet.create({});

export default App;

GiSmsVerificationInput.tsx

import React, { useState, useEffect } from 'react';
import { StyleSheet, View } from 'react-native';
import SmoothPinCodeInput from 'react-native-smooth-pincode-input';
import RNOtpVerify from 'react-native-otp-verify';

/**
 * @param pinInput (Optional) Properties you want to pass to SmoothPinCodeInput
 * @param onFulfill Handler for when the user fills out pin
 * @param extractOTP (Optional) Extraction function for the OTP in the SMS
 */
interface SmsVerificationInputProps {
  /**
   * (Optional) Properties you want to pass to SmoothPinCodeInput
   */
  pinInputProps?: any;
  /**
   * Handler for when the user fills out pin
   * @param code PIN code entered
   */
  onFulfill: (code: string) => any;
  /**
   * (Optional) Extraction function for the OTP in the SMS
   * @param message Full SMS message received
   */
  extractOTP?: (message: string) => string;
}

/**
 * Verification PIN input component. Listens to SMS and fills out automatically if the right sms is sent.
 */
const SmsVerificationInput: React.FC<SmsVerificationInputProps> = (props) => {
  const [code, setCode] = useState('');
  /**
   * Function to get the hash that has to be appended to the message for the SMS listener to work.
   * Eg. SMS: This is your code: 1234 Uo4J1jaLso7
   */
  const getHash = () => {
    RNOtpVerify.getHash()
      .then((res) => console.log('Use Hash:', res[0]))
      .catch((err) => console.log(err));
  };

  /**
   * Start listening for SMS with the hash appended. Not triggered on an received SMS without the hash.
   * */
  const startListeningForOtp = () => {
    RNOtpVerify.getOtp()
      .then((p) => {
        RNOtpVerify.addListener((message) => {
          otpHandler(message);
        });
      })
      .catch((p) => console.log(p));
  };

  /**
   * Handle the received SMS with hash. Restarts listener for any subsequent messages the user might request.
   * @param message Full SMS message
   */
  const otpHandler = (message: string) => {
    if (message && !message.includes('Error')) {
      console.log('otpHandler', message);
      console.log('set pin to:', extractOTP(message));
      setCode(extractOTP(message));
    }
    RNOtpVerify.removeListener();
    startListeningForOtp();
  };

  /**
   * Extract code from your SMS message.
   * @param message Full SMS message
   */
  const extractOTP = (message: string) => {
    if (props.extractOTP) {
      return props.extractOTP(message);
    }
    return /(\d{4})/g.exec(message)[1];
  };

  /**
   * Start listening for OTP on first render. Remove listener when component is destroyed.
   */
  useEffect(() => {
    getHash();
    startListeningForOtp();
    return RNOtpVerify.removeListener();
  }, []);

  const DefaultMask = <View style={styles.mask} />;

  return (
    <SmoothPinCodeInput
      value={code}
      onTextChange={(code: string) => setCode(code)}
      onFulfill={(code: string) => props.onFulfill(code)}
      cellStyle={styles.cell}
      autoFocus={true}
      cellStyleFocused={null}
      cellSize={50}
      codeLength={4}
      cellSpacing={5}
      keyboardType={'number-pad'}
      maskDelay={500}
      password={true}
      mask={DefaultMask}
      textStyle={styles.text}
      {...props.pinInputProps}
    />
  );
};

const styles = StyleSheet.create({
  cell: {},
  text: {},
  mask: {},
});

export default SmsVerificationInput;

package.json

  "name": "",
  "version": "",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": ""
  },
  "keywords": [
  ],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@types/react-native": "^0.63.34",
    "react": "16.13.1",
    "react-native": "^0.63.3",
    "react-native-otp-verify": "^1.0.3",
    "react-native-smooth-pincode-input": "^1.0.9",
    "react-native-sms-retriever": "^1.1.1"
  }
}

Entalist
  • 13
  • 4

1 Answers1

0

You can try removing entire node_modules folder, and deleting the package-lock.json file. And then run npm install again.

If deletion of node_modules and package-lock.json doesnot work. You can try explicitly adding the react-native-otp-verify dependency to the package.json file of your project SMSTest.

You can aslo try adding "preinstall": "npm install react-native-otp-verify" to scripts section in package.json file of your project.

Check out this thread for more information.

Levi Lu-MSFT
  • 18,505
  • 1
  • 12
  • 19