@mi-pase/sdk

中文文档
0.2.3发布于 2026/11/02MITTypeScriptESM + CJS零依赖构建来源已验证

mi-pase API(项目、注册、奖励、模板和验证器)的官方Node.js / TypeScript SDK。

中文使用文档
文档目录14 节
  1. 安装
  2. 快速启动
  3. 客户的选择
  4. API版本控制
  5. 资源
  6. 项目
  7. 入学
  8. 奖励
  9. 模板
  10. 验证器
  11. 通知
  12. 健康
  13. 错误处理
  14. 要求

@mi-pase / sdk

的官方Node.js / TypeScript SDK mi-pase API -管理项目,注册,奖励,传递模板和验证器从您的后端。

  • 零运行时依赖,构建在本机上 fetch.
  • 每个请求和响应的完整TypeScript类型。
  • 流畅的、可链接的API: client.project(id).enrollment(id).setCustomFields(...).
  • 发布ESM和CJS版本。

安装

npm install @mi-pase/sdk

就这样——包被发布到公共npm注册表,不需要身份验证。

而是从GitHub包安装

@mi-pase/sdk 在每个版本中也会发布到GitHub Packages。要使用该注册表,请将其添加到项目的注册表中 .npmrc:

@mi-pase:registry=https://npm.pkg.github.com/

然后使用GitHub个人访问令牌对npm进行身份验证 read:packages 作用域,通过 npm login --scope=@mi-pase --registry=https://npm.pkg.github.com 或者加上 .npmrc:

//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN

快速启动

import { MiPaseClient } from "@mi-pase/sdk";

const client = new MiPaseClient({
  // A Clerk Organization API key, created from your mi-pase organization's
  // API Keys settings panel. Sent as `Authorization: Bearer <apiKey>`.
  apiKey: process.env.MI_PASE_API_KEY!,
});

const project = await client.projects.create({
  domain: "acme",
  name: "Summer Fest 2026",
});

const enrollment = await client.project(project._id).enrollments.create({
  domain: "acme",
  name: "Jane Doe",
  email: "[email protected]",
});

// Chain from a project straight into one of its enrollments:
await client
  .project(project._id)
  .enrollment(enrollment._id)
  .setCustomFields({ seat: "12A" }, { override: true });

客户的选择

new MiPaseClient({
  apiKey: "...",           // required — Clerk Organization API key
  baseUrl: "...",          // default: "https://app.mi-pase.ar"
  timeoutMs: 30_000,       // per-request timeout
  maxRetries: 2,           // retries for GET/PUT/DELETE on network/timeout/429/5xx errors
  fetch: customFetch,      // override the fetch implementation
});

POST请求永远不会自动重试(默认情况下,它们不是幂等的——例如,创建一个项目两次会创建两个项目)。通过 { idempotent: true } 作为每个调用选项,如果您知道特定的POST可以安全重试,则底层资源方法将其公开。

API版本控制

midpase API目前是 v1 只有;下面展示的每一种方法都与 v1 端点。客户端接受一个预留 apiVersion 选项("v1" 今天)等那时候 v2 端点船,这个SDK可以添加一个 v2 表面没有断裂的变化 v1 一个。

资源

项目

await client.projects.list({ domain, kind });
await client.projects.create({ domain, name, ... });

await client.project(id).get();
await client.project(id).update({ name: "New name" });
await client.project(id).delete();      // only finalized projects can be deleted
await client.project(id).duplicate();

入学

await client.enrollments.list({ project, person, domain });
await client.enrollments.create({ domain, project_id, name, email, phone, customFields });
await client.enrollments.bulkCreate({ domain, project_id, rows: [...] });
await client.enrollments.copyToProject({ sourceProjectId, targetProjectId, domain });

await client.enrollment(id).get();
await client.enrollment(id).update({ customFields });  // full replace, matches the raw API
await client.enrollment(id).delete();                  // unenrolls the person (and revokes their pass)
await client.enrollment(id).revoke();                  // revokes the issued pass; person stays enrolled
await client.enrollment(id).setCustomFields({ seat: "12A" });                     // merges with existing fields (fetches first)
await client.enrollment(id).setCustomFields({ seat: "12A" }, { override: true }); // full replace, no extra fetch

在一个项目范围内, project_id 为您填写:

await client.project(projectId).enrollments.list();
await client.project(projectId).enrollments.create({ domain, name, email });
await client.project(projectId).enrollments.bulkCreate({ domain, rows: [...] });
await client.project(projectId).enrollment(enrollmentId).setCustomFields({...});

奖励

奖励只存在于一个项目中——没有顶层 /rewards 端点。

await client.project(projectId).rewards.list();
await client.project(projectId).rewards.create({ name, description, pointsRequired });
await client.project(projectId).rewards.update(rewardId, { pointsRequired: 200 });
await client.project(projectId).rewards.delete(rewardId);

模板

await client.templates.list({ domain });
await client.templates.create({ domain, name, type: "event" });

await client.template(id).get();
await client.template(id).update({ name: "New name" });
await client.template(id).delete();
await client.template(id).duplicate();
await client.template(id).getConfig();              // Apple + Google wallet design, or undefined if unsynced
await client.template(id).saveConfig({ apple, google });

验证器

await client.validators.list({ domain });
await client.validators.create({ domain, name, project, scanMode: "both" });
await client.validators.recordsForEnrollments([enrollmentId1, enrollmentId2]);

await client.validator(id).get();
await client.validator(id).update({ scanMode: "nfc" });
await client.validator(id).delete();
await client.validator(id).scan({ scannedValue, scanMode: "camera" });
await client.validator(id).records({ limit: 50, skip: 0, search: "" });

scan() 可以返回 { matches: [...] } 当扫描值解析为多个注册时,不使用验证记录,而是使用导出的 isScanAmbiguous() 键入保护并重新扫描 enrollmentId 设置:

import { isScanAmbiguous } from "@mi-pase/sdk";

const result = await client.validator(id).scan({ scannedValue, scanMode: "camera" });
if (isScanAmbiguous(result)) {
  // prompt the operator to pick one of result.matches
} else {
  // result is a ValidationRecord
}

通知

钱包推送通知到项目的活动通道。 send 默认针对整个项目;缩小范围 enrollmentIds (特定注册)和/或 issuedFrom/issuedTo 签发日期窗口。 message 在两个钱包之间共享,可选的每个平台覆盖- googleMessage 可以携带一个单 <a href> 锚谷歌钱包呈现为一个可点击的链接(苹果推送没有链接支持)。

await client.notifications.send({
  domain,
  project: projectId,
  message: "Doors open at 7pm.",
  // optional per-platform overrides:
  appleMessage: "Doors open at 7pm.",
  googleMessage: 'Doors open at 7pm. <a href="https://acme.example/map">View map</a>',
  // optional filters:
  enrollmentIds: [enrollmentId1, enrollmentId2],
  issuedFrom: "2026-10-01",
  issuedTo: "2026-10-31",
});

await client.notifications.list({ domain });        // sent-notification history for a domain
await client.notifications.listByPasses([passId1]); // history touching specific passes
await client.notifications.preview({ domain, project: projectId, enrollmentIds }); // { count, cooldownUntil }

API上限发送点 每24小时通知一个项目在该窗口内发送将抛出 MiPaseApiError 与地位 429。呼叫 preview 首先找到潜在的目标 count 和 cooldownUntil 时间戳(ISO字符串,或 null (现在允许发送)而不消耗冷却时间。

健康

await client.health(); // { status: "ok", timestamp: "..." }

错误处理

每个非2xx响应都会抛出 MiPaseApiError:

import { MiPaseApiError } from "@mi-pase/sdk";

try {
  await client.project("does-not-exist").get();
} catch (error) {
  if (error instanceof MiPaseApiError) {
    console.error(error.status, error.message, error.body);
  }
  throw error;
}

网络故障抛出 MiPaseNetworkError;客户端超时抛出 MiPaseTimeoutError.

要求

Node.js 18或更高版本(用于全局) fetch),或者传递你自己的 fetch 实现通过 options.fetch.

版本与发布记录

@mi-pase/sdk 共发布 7 个版本,首次发布于 2026/08/27;过去 12 个月发布了 7 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.2.3latest2026/11/021 天前
0.2.22026/11/021 天前
0.2.12026/10/2113 天前
0.2.02026/10/2113 天前
0.1.32026/09/141 个月前
0.1.22026/08/272 个月前

关于 @mi-pase/sdk 的常见问题

@mi-pase/sdk 是什么?

mi-pase API(项目、注册、奖励、模板和验证器)的官方Node.js / TypeScript SDK。

如何安装 @mi-pase/sdk?

在项目目录运行 npm install @mi-pase/sdk,或使用 pnpm add / yarn add / bun add。

@mi-pase/sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@mi-pase/sdk 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@mi-pase/sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@mi-pase/sdk 可以商用吗?

@mi-pase/sdk 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@mi-pase/sdk 还在维护吗?

最新版本 0.2.3 发布于 2026/11/02(1 天前);至今共发布 7 个版本,其中过去 12 个月发布了 7 个;首次发布于 2026/08/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。