@blade47/saga-ts

中文文档
1.0.4发布于 2025/12/09MITTypeScriptCommonJS零依赖近 30 天下载 4894

对 TypeScript 的轻量级、 类型安全并带有自动回滚支持的 saga 模式执行

中文使用文档
文档目录23 节
  1. 特征
  2. 安装
  3. 快速启动
  4. API 参考
  5. createSaga()
  6. .step(name, input, execute, rollback?)
  7. .run()
  8. 实例
  9. 用回滚处理付款
  10. 复杂的用户登入
  11. 如何运作
  12. 类型安全
  13. 处理最佳做法出错
  14. 已知的限制
  15. 仅顺序执行
  16. 无内建重试逻辑
  17. 有限回滚可观察性
  18. 只有记忆
  19. 无条件逻辑
  20. 没有超时或取消
  21. 何时使用 Sagas
  22. 许可证
  23. 捐款

萨加

为TypeScript执行轻量级,型号安全的saga模式,并自动回滚支持.

特征

  • 类型安全: 完整的类型脚本支持,并带有智能类型推论
  • 自动回滚: 失败的步骤按倒序自动触发补偿
  • 零依赖关系:轻量级和生产准备
  • 简单 API: 用于定义 sagas 的直观构建器模式
  • 弹性: 任何同步操作的工程(数据库、API呼叫等)

安装

npm install saga-ts

快速启动

import { createSaga } from 'saga-ts';

const result = await createSaga()
  .step(
    'createUser',
    { email: '[email protected]', name: 'John' },
    async (input, ctx) => {
      const user = await db.users.create(input);
      return { userId: user.id, email: input.email };
    },
    async (output) => {
      // Rollback: delete the user if something fails later
      await db.users.delete(output.userId);
    }
  )
  .step(
    'sendEmail',
    { template: 'welcome' },
    async (input, ctx) => {
      // Access previous step results with full type safety
      const { email } = ctx.results.createUser;

      const emailId = await emailService.send({
        to: email,
        template: input.template,
      });
      return { emailId, sentAt: new Date() };
    },
    async (output) => {
      await emailService.cancel(output.emailId);
    }
  )
  .run();

if (result.status === 'success') {
  console.log('User created:', result.results.createUser.userId);
  console.log('Email sent:', result.results.sendEmail.emailId);
} else {
  console.error('Failed at step:', result.failedAt);
  console.error('Error:', result.error);
}

API 参考

createSaga()

创建新的 saga 构建实例 .

.step(name, input, execute, rollback?)

加一相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相.

  • 名称: 该步骤的独特标识符(用于获取结果)
  • 投入: 步骤输入数据
  • 执行: 执行步骤动作的自动同步函数
    • 接收 input 财务报告和审定财务报表 ctx (包含以往步骤的结果)
    • 必须返回步骤的输出
  • 倒滚 (可选) : 取消步骤动作的自动同步函数
    • 接收步骤的输出
    • 如果后一步失败, 则自动调用

.run()

执行"萨加",并随结果返回承诺.

成功结果:

{
  status: 'success',
  data: TLastOutput,      // Output of the last step
  results: TResults       // All step results by name
}

失败结果 :

{
  status: 'failed',
  error: Error,           // The error that occurred
  failedAt: string        // Name of the step that failed
}

实例

用回滚处理付款

const result = await createSaga()
  .step(
    'validateCard',
    { cardToken: 'tok_visa' },
    async (input) => {
      const card = await stripe.tokens.retrieve(input.cardToken);
      return { cardId: card.id, last4: card.card.last4 };
    }
  )
  .step(
    'calculateTotal',
    { items: [{ id: '1', price: 100 }, { id: '2', price: 50 }] },
    async (input) => {
      const total = input.items.reduce((sum, item) => sum + item.price, 0);
      return { total, items: input.items };
    }
  )
  .step(
    'createCharge',
    { currency: 'usd' },
    async (input, ctx) => {
      const charge = await stripe.charges.create({
        amount: ctx.results.calculateTotal.total,
        currency: input.currency,
        source: ctx.results.validateCard.cardId,
      });
      return { chargeId: charge.id };
    },
    async (output) => {
      // Rollback: refund the charge
      await stripe.refunds.create({ charge: output.chargeId });
    }
  )
  .step(
    'sendReceipt',
    { recipientEmail: '[email protected]' },
    async (input, ctx) => {
      await emailService.send({
        to: input.recipientEmail,
        template: 'receipt',
        data: {
          chargeId: ctx.results.createCharge.chargeId,
          amount: ctx.results.calculateTotal.total,
        },
      });
      return { sent: true };
    }
  )
  .run();

// If sendReceipt fails, the charge will be automatically refunded

复杂的用户登入

const result = await createSaga()
  .step(
    'createAccount',
    { email: '[email protected]', password: 'secure123' },
    async (input) => {
      const account = await db.accounts.create(input);
      return { accountId: account.id };
    },
    async (output) => {
      await db.accounts.delete(output.accountId);
    }
  )
  .step(
    'createProfile',
    { name: 'John Doe', avatar: 'default.png' },
    async (input, ctx) => {
      const profile = await db.profiles.create({
        ...input,
        accountId: ctx.results.createAccount.accountId,
      });
      return { profileId: profile.id };
    },
    async (output) => {
      await db.profiles.delete(output.profileId);
    }
  )
  .step(
    'assignRole',
    { role: 'user' },
    async (input, ctx) => {
      await db.roles.assign({
        accountId: ctx.results.createAccount.accountId,
        role: input.role,
      });
      return { role: input.role };
    },
    async (output, ctx) => {
      await db.roles.revoke({
        accountId: ctx.results.createAccount.accountId,
        role: output.role,
      });
    }
  )
  .step(
    'sendWelcomeEmail',
    { template: 'onboarding' },
    async (input, ctx) => {
      const emailId = await emailService.send({
        to: ctx.results.createAccount.email,
        template: input.template,
      });
      return { emailId };
    }
  )
  .run();

如何运作

  1. 步骤执行:步骤按定义顺序顺序执行
  2. 背景宣传:每个步骤从以往的所有步骤得到结果,直至 ctx.results
  3. 类型安全: TypeScript 自动推断并验证步骤输入和输出的类型
  4. 处理错误: 如果任何步骤出现出错, 立即停止执行
  5. 自动回滚: 所有成功执行步骤的补偿功能按倒序调用
  6. 后退复原力: 如果回滚失败, 错误会被记录, 但其它回滚继续

类型安全

saga-ts提供完整的类型推断:

const result = await createSaga()
  .step('step1', { value: 10 }, async (input) => {
    return { doubled: input.value * 2 };
  })
  .step('step2', { multiplier: 3 }, async (input, ctx) => {
    // TypeScript knows ctx.results.step1.doubled is a number
    const result = ctx.results.step1.doubled * input.multiplier;
    return { final: result };
  })
  .run();

if (result.status === 'success') {
  // TypeScript knows the exact shape of results
  const doubled: number = result.results.step1.doubled;
  const final: number = result.results.step2.final;
}

处理最佳做法出错

  1. 总是提供回滚函数 用于修改状态的步骤
  2. 保持回滚自制 - 他们可能多次被调用
  3. 日志倒滚失败 - 图书馆记录下来,但继续
  4. 测试回滚逻辑 确保补偿工作正确

已知的限制

这个库是为了简单和类型安全而设计的. 对于更为复杂的组织需要,请考虑这些局限性:

仅顺序执行

步骤一次执行一个顺序 。 如果你有独立的步骤 可以平行运行, 他们仍然会等待对方完成.

// These steps run sequentially even though they're independent
.step('fetchUserProfile', {}, async () => { /* ... */ })
.step('fetchUserPreferences', {}, async () => { /* ... */ })

工作周边: 同时使用独立 sagas 运行 Promise.all()。 。 。 .

无内建重试逻辑

如果一个步骤因瞬态问题(网络超时,速率限制)而失败,则整个saga会失败并回滚. 指数回放没有自动重试.

工作周边: 执行步骤函数中的重试逻辑,或在重试处理器中将 saga 执行包起来.

有限回滚可观察性

当回滚函数失败时,错误会被记录到 console.error 但不包含在saga结果中. 你不会知道赔偿是不是部分失败的.

工作周边: 如果您需要详细的报酬审计记录, 请在回滚函数内执行自己的错误跟踪 .

只有记忆

所有步骤结果在执行期间被存储在内存中. 对于能回放出大有效载荷的长期活塞或步骤,这可能造成内存问题. 无相相相相相相相相相相相相相相相相相.

影响:如果您的进程崩溃了中相,就无法恢复. 对于关键的工作流程,考虑工作流程引擎如Temperor或Porder.

无条件逻辑

除非前一步失败,否则每一步都会运行. 你不能根据条件跳过台阶.

// Can't do: "if user is premium, skip payment step"

工作周边: 使用条件性逻辑内步函数来提前返回,或被分拆为单独的 sagas.

没有超时或取消

步骤可以无限地运行。 没有内置的超时机制或中止Signal支持.

工作周边: 使用 Promise.race() 或终止控制器.

何时使用 Sagas

萨加斯是理想的:

  • 需要原子化的多步骤业务流程
  • 服务间分配交易
  • 具有补偿逻辑的复杂工作流程
  • 需要保持失败一致性的业务

许可证

麻省理工学院

捐款

欢迎捐款! 请随意提交拉力请求.

版本与发布记录

@blade47/saga-ts 共发布 5 个版本,首次发布于 2025/11/18;过去 12 个月发布了 5 个版本。

版本发布日期距今
1.0.4latest2025/12/0910 个月前
1.0.32025/11/1811 个月前
1.0.22025/11/1811 个月前
1.0.12025/11/1811 个月前
1.0.02025/11/1811 个月前

关于 @blade47/saga-ts 的常见问题

@blade47/saga-ts 是什么?

对 TypeScript 的轻量级、 类型安全并带有自动回滚支持的 saga 模式执行

如何安装 @blade47/saga-ts?

在项目目录运行 npm install @blade47/saga-ts,或使用 pnpm add / yarn add / bun add。

@blade47/saga-ts 支持 TypeScript 吗?

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

@blade47/saga-ts 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@blade47/saga-ts 需要什么版本的 Node.js?

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

@blade47/saga-ts 可以商用吗?

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

@blade47/saga-ts 的下载量有多少?

根据 npm 官方下载统计,@blade47/saga-ts 在 2026/10/09 – 2026/11/07 这 30 天内被下载 4,894 次,日均约 163 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@blade47/saga-ts 还在维护吗?

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