You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase Functions中admin.firestore.Timestamp.fromDate未定义报错求助

解决Firebase Functions中OTP过期时间设置的"Cannot read properties of undefined (reading 'fromDate')"错误

问题原因

你遇到的错误是因为Firebase Admin SDK v9+版本中,Timestamp不再挂载在admin.firestore对象下,而是需要从firebase-admin/firestore模块单独导入。你代码中注释了Timestamp的导入语句,导致尝试访问admin.firestore.Timestamp时返回undefined,进而调用fromDate方法时触发报错。

解决方案

  1. 取消注释Timestamp的导入语句
  2. 将代码中所有admin.firestore.Timestamp替换为导入的Timestamp对象

修改后的完整代码

import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import twilio from "twilio";
import * as dotenv from "dotenv";
import { Timestamp } from "firebase-admin/firestore"; // 启用Timestamp的单独导入

dotenv.config();
admin.initializeApp();

const twilioClient = twilio(
  process.env.TWILIO_ACCOUNT_SID,
  process.env.TWILIO_AUTH_TOKEN
);

const generateOtp = (): string => {
  return Math.floor(100000 + Math.random() * 900000).toString();
};

// Send OTP via SMS
export const sendOtpSms = functions.https.onRequest(async (req, res) => {
  const {phoneNumber} = req.body;

  if (!phoneNumber) {
    res.status(400).json({error: "Phone number is required"});
    return;
  }

  const otp = generateOtp();

  try {
    await twilioClient.messages.create({
      body: `Your OTP is ${otp}`,
      from: process.env.TWILIO_PHONE,
      to: phoneNumber,
    });

    // 使用导入的Timestamp创建过期时间
    const expiresAt = Timestamp.fromDate(
      new Date(Date.now() + 5 * 60000)
    );
    await admin.firestore().collection("otps").doc(phoneNumber).set({
      otp,
      expiresAt,
    });
    console.log(`Generated OTP: ${otp}, Expires At: ${expiresAt.toDate()}`);

    res.status(200).json({message: "OTP sent successfully"});
  } catch (error) {
    console.error("Error sending OTP:", error);
    res.status(500).json({error: "Failed to send OTP"});
  }
});

// Verify Otp
export const verifyOtp = functions.https.onRequest(async (req, res) => {
  const {phoneNumber, otp} = req.body;

  if (!phoneNumber || !otp) {
    res.status(400).json({error: "Phone number and OTP are required"});
    return;
  }

  try {
    const otpDoc = await admin
      .firestore()
      .collection("otps")
      .doc(phoneNumber)
      .get();
    if (!otpDoc.exists) {
      res.status(404).json({error: "OTP not found"});
      return;
    }

    const otpData = otpDoc.data();

    if (!otpData || !otpData.expiresAt) {
      res.status(400).json({error: "OTP data is incomplete"});
      return;
    }

    // 从Firestore读取的expiresAt本身是Timestamp类型,可直接调用toDate()
    const isExpired = otpData.expiresAt.toDate() < new Date();

    if (isExpired) {
      res.status(400).json({error: "OTP has expired"});
      return;
    }

    if (otp !== otpData.otp) {
      res.status(400).json({error: "Invalid OTP"});
      return;
    }

    res.status(200).json({message: "OTP verified successfully"});
  } catch (error) {
    console.error("Error verifying OTP:", error);
    res.status(500).json({error: "Failed to verify OTP"});
  }
});

额外优化建议

  • 移除原代码中判断admin.firestore.Timestamp.fromDate是否存在的冗余逻辑,导入正确的Timestamp后该方法必然可用
  • 验证OTP成功后,建议删除对应的OTP文档,避免被重复使用
  • 确认package.json中firebase-admin依赖为最新稳定版,避免版本兼容问题

内容的提问来源于stack exchange,提问作者Abiodun Bankole

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 13:46:01