mcpField
S
seam-access-grants

seam-access-grants

github.com/seamapi安全244 次安装26 周前更新
代码仓库

关于 seam-access-grants

指导开发者在现有代码库中集成 Seam Access Grants,包括围绕预订创建、更新和删除访问授权。重点是按房间映射设备,并保存授权 ID 以供后续操作。

主要功能

  1. 01在现有处理程序中加入 Seam 调用
  2. 02按预订时间段创建授权
  3. 03将每个房间映射到对应设备 ID
  4. 04使用已存 ID 更新或删除授权
  5. 05添加访问事件 Webhook 端点

适用场景

  1. 01在创建预订时授予门锁访问权限
  2. 02预订变更后调整访问时间
  3. 03取消预订时撤销访问权限

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/seamapi/seam-plugin --skill seam-access-grants

安装后在 Claude Code 中输入/seam-access-grants确认已加载。

附带文件references/production-checklist.mdreferences/troubleshooting.md

详细介绍

Seam 访问授权

你是一名经验丰富的 Seam 集成工程师。直接在开发者现有的代码库中编写集成代码。

实施方法

  1. 快速推进。 搜索关键文件(预订/预约处理程序、路由、模型),阅读后立即开始编写代码。
  2. 在现有文件中编写代码。 直接在现有服务/处理程序函数中添加 Seam 调用。不要创建包装服务。
  3. 尽量减少改动。 仅修改需要调用 Seam 的文件和 webhook 路由。安装 SDK,添加导入,并添加调用。

Access Grants 的工作原理

创建访问授权时,需要指定用户身份、目标设备、请求的访问方式(PIN、手机钥匙)和时间范围。Seam 会在门锁上配置凭证。你必须存储 access_grant_id,以便之后更新或删除该授权。

1. 安装 SDK 并初始化

不要固定到特定版本。

npm install seam        # Node.js
pip install seam        # Python
bundle add seam         # Ruby

Next.js 的重要注意事项: 在模块作用域中使用 new Seam() 会导致 next build 失败。请使用惰性 getter:

import { Seam } from "seam";
let _seam: Seam;
function getSeam() {
  if (!_seam) _seam = new Seam({ apiKey: process.env.SEAM_API_KEY! });
  return _seam;
}

对于 Express / 标准 Node.js:

import { Seam } from "seam";
const seam = new Seam({ apiKey: process.env.SEAM_API_KEY });
from seam import Seam
seam = Seam(api_key=os.environ["SEAM_API_KEY"])

2. 获取设备 ID

Access Grants 的目标是由 device_id 指定的特定设备。每个房间/门都必须映射到自己的设备 ID,不要对所有房间使用同一个全局设备。

查找设备 ID 的位置:

  • 每个房间对应的环境变量:SEAM_DEVICE_ROOM_101、SEAM_DEVICE_ID_ROOM_A1 等。
  • 应用的数据模型(例如 room.seamDeviceId、unit.deviceId)

如果缺少映射,则操作失败,不要回退到全局设备。将访问权限授予错误的门,比操作失败更糟。

3. 创建预订时创建访问授权

直接在创建函数中添加。在预订对象上存储 access_grant_id。

// Inside createBooking(), after saving the booking:
const deviceId = getDeviceIdForRoom(room);  // Must resolve per-room
if (!deviceId) {
  throw new Error(`No Seam device configured for room ${room.id}`);
}
try {
  const accessGrant = await seam.accessGrants.create({
    user_identity: {
      full_name: guest.name,
      email_address: guest.email
    },
    device_ids: [deviceId],
    requested_access_methods: [
      { mode: "code" }           // PIN code
      // { mode: "mobile_key" }  // Add for mobile key + Instant Key
    ],
    starts_at: booking.checkIn,
    ends_at: booking.checkOut
  });
  booking.seamAccessGrantId = accessGrant.access_grant_id;
} catch (err) {
  console.error("Seam access grant failed:", err);
  // Consider: should this fail the booking? If access is required, throw.
}
# Inside create_booking(), after saving:
device_id = get_device_id_for_room(room)  # Must resolve per-room
if not device_id:
    raise ValueError(f"No Seam device configured for room {room.id}")
try:
    access_grant = seam.access_grants.create(
        user_identity={"full_name": guest.name, "email_address": guest.email},
        device_ids=[device_id],
        requested_access_methods=[{"mode": "code"}],
        starts_at=booking.check_in,
        ends_at=booking.check_out
    )
    booking.seam_access_grant_id = access_grant.access_grant_id
except Exception as e:
    print(f"Seam access grant failed: {e}")
    # Consider: should this fail the booking? If access is required, raise.

注意事项

  • 存储 access_grant_id——更新和删除时需要用到它。如果它是 null/undefined,则授权失败,需要重试。若预订模型中没有该字段,请添加。
  • 绝不要回退到全局设备——每个房间都必须映射到自己的特定设备。授权进入错误的房间,比无法进入更糟。
  • user_identity 接受 full_name 和 email_address,而不是 name 和 email。
  • device_ids 是一个数组——一次调用即可授予多个门的访问权限。
  • requested_access_methods——PIN 使用 "code",手机钥匙和 Instant Key 使用 "mobile_key"。
  • 确定失败处理方式:如果预订必须具备访问权限(例如酒店房间),则 Seam 调用失败时抛出错误,避免在没有可用密码的情况下确认预订。如果访问权限可选(例如健身房),则记录日志并继续。

4. 预订变更时更新访问授权

if (booking.seamAccessGrantId) {
  await seam.accessGrants.update({
    access_grant_id: booking.seamAccessGrantId,
    starts_at: booking.checkIn,
    ends_at: booking.checkOut
  });
}

5. 取消预订时删除访问授权

if (booking.seamAccessGrantId) {
  await seam.accessGrants.delete({
    access_grant_id: booking.seamAccessGrantId
  });
}
if booking.seam_access_grant_id:
    seam.access_grants.delete(
        access_grant_id=booking.seam_access_grant_id
    )

6. 添加 webhook 端点

遵循代码库中现有的 webhook 模式:

router.post("/seam", (req, res) => {
  const { event_type, ...data } = req.body;
  switch (event_type) {
    case "access_code.set_on_device":
      console.log("PIN set on lock:", data.access_code_id);
      break;
    case "access_code.failed_to_set_on_device":
      console.log("PIN failed:", data.access_code_id);
      break;
    case "device.disconnected":
      console.log("Lock offline:", data.device_id);
      break;
  }
  res.json({ received: true });
});

7. 将函数改为异步

将服务函数改为异步,并更新调用方以使用 await。

如果出现问题,请阅读 references/troubleshooting.md。如需做好生产环境准备,请阅读 references/production-checklist.md。

评论

支持 Markdown