@absolutejs/dispatch

中文文档
0.9.1发布于 2026/10/22BSL-1.1TypeScriptES Module构建来源已验证近 30 天下载 2389

提供不可知的电子邮件、载体和丰富的信息发送器,并在绝对JS生态系统中推动通知.

中文使用文档
文档目录17 节
  1. 安装
  2. 使用量
  3. API 密码
  4. createDispatcher(options)
  5. dispatcher.email(message) 编号 : .messaging(message) 编号 : .pu…
  6. 生产推力生命周期
  7. 送出前授权政策
  8. dispatcher.metrics()
  9. 底片图案
  10. 打开几何
  11. 审计排放
  12. 套装适配器
  13. memoryEmailAdapter({ max?, idGenerator? })
  14. memoryMessagingAdapter({ max? }) 编号 : memoryPushAdapter({ m…
  15. consoleEmailAdapter({ stream? }) 编号 : consoleMessagingAdapt…
  16. 此软件包没有做什么
  17. 许可证

@absolutejs/发送

绝对JS 的提供者不可识别输出消息发送器 生态系统.

文档 : 绝对js.com/文档/发送

何等为相. 1个工厂createDispatcher) 返回a Dispatcher 有三个频道(email 编号 : messaging 编号 : push) (中文(简体) ). 适配器 插入每个频道。 适配器周围的底物——度量衡, OTel,审计排放,错误处理——是统一的.

它能解决什么. 每个需要发送交易包 信件目前带给自己的SMTP / SMS / 推取客户端 . @absolutejs/auth魔力链接路由假设主机的电子邮件为 符号 . @absolutejs/sync-pack-digest 明确说: "提供的主机 电子邮件发送者。 包不拥有运输" .. 控制飞机 需要发票失效/配额警告电子邮件。 集中到一个 调度员是指每个消费者插头进入一个地方.

安装

bun add @absolutejs/dispatch
# Plus one or more adapter siblings:
bun add @absolutejs/dispatch-resend       # Resend (email)
bun add @absolutejs/dispatch-postmark     # Postmark (email)
bun add @absolutejs/dispatch-twilio       # Twilio messaging
bun add @absolutejs/dispatch-telnyx       # Telnyx messaging
# ...etc

使用量

import { createDispatcher } from "@absolutejs/dispatch";
import { createResendAdapter } from "@absolutejs/dispatch-resend";
import { Resend } from "resend";

const resend = new Resend(process.env.RESEND_KEY!);

const dispatcher = createDispatcher({
  email: createResendAdapter({ client: resend }),
  defaultFrom: { email: "[email protected]" },
});

await dispatcher.email({
  to: "[email protected]",
  subject: "Welcome to Acme",
  text: "Hi Alice, click here to verify: ...",
  tenant: "tenant-A", // optional — propagates to OTel + audit
});

API 密码

createDispatcher(options)

type DispatcherOptions = {
  email?: EmailAdapter;
  messaging?: MessagingAdapter;
  push?: PushAdapter;
  policies?: readonly DispatchPolicy[];
  defaultFrom?: { email?: string; messaging?: MessagingEndpoint };
  onError?: (error: unknown, channel: DispatchChannel, message) => void;
  tracerProvider?: TracerProvider; // OTel
  audit?: AuditLike; // @absolutejs/audit instance
};

回返 { email, messaging, push, metrics }调用一个没有 适配器抛出 DispatchUnsupportedError。 。 。 .

dispatcher.email(message) 编号 : .messaging(message) 编号 : .push(message)

type EmailMessage = {
  to: string | ReadonlyArray<string>;
  from?: string;
  subject: string;
  text?: string;
  html?: string;
  replyTo?: string;
  cc?: string | ReadonlyArray<string>;
  bcc?: string | ReadonlyArray<string>;
  headers?: Record<string, string>;
  tenant?: string;
  metadata?: Record<string, unknown>; // adapter-specific extras
};

type MessagingMessage = {
  to: { address: string; transport: "sms" | "mms" | "rcs" | "whatsapp" };
  from?: { address: string; transport: "sms" | "mms" | "rcs" | "whatsapp" };
  content:
    | { kind: "text"; text: string }
    | {
        kind: "media";
        mediaUrls: readonly string[];
        text?: string;
        subject?: string;
      }
    | {
        kind: "template";
        id: string;
        variables?: Readonly<Record<string, string>>;
      }
    | {
        kind: "rich";
        text: string;
        title?: string;
        mediaUrl?: string;
        actions?: readonly MessagingAction[];
      };
  fallbacks?: readonly {
    transport: "sms" | "mms" | "whatsapp";
    from?: MessagingEndpoint;
    content?: MessagingContent;
  }[];
  sendAt?: string;
  idempotencyKey?: string;
  privacy?: {
    addressRetention?: "obfuscate" | "retain";
    contentRetention?: "discard" | "retain";
  };
  consent?: {
    programId: string;
    purpose: string;
  };
  extensions?: Readonly<Record<string, unknown>>;
  tenant?: string;
  metadata?: Record<string, unknown>;
};

type PushMessage = {
  to: string; // device token OR topic
  title?: string;
  body: string;
  idempotencyKey?: string;
  actions?: ReadonlyArray<{ id: string; label: string; deepLink?: string }>;
  badge?: number;
  deepLink?: string;
  sound?: string;
  data?: Record<string, unknown>;
  tenant?: string;
  metadata?: Record<string, unknown>;
};

生产推力生命周期

createPushLifecycle() 拥有APN上方的提供者中性设备层, FCM,和Web Push: 租户同化登记,用户/设备/专题定位,定界 货币,回扣,无效退休, 和一能的幻想。 决定 每一订阅的适配器,以支持特定租户的证书.

import { createPushLifecycle } from "@absolutejs/dispatch";
import {
  createPostgresPushFanoutClaimStore,
  createPostgresPushSubscriptionStore,
} from "@absolutejs/dispatch-push-postgres";

const push = createPushLifecycle({
  adapterFor: ({ platform, tenant }) => adapters.forTenant(tenant, platform),
  claimStore: createPostgresPushFanoutClaimStore(idempotentOperations),
  store: createPostgresPushSubscriptionStore(transactionRunner),
});

await push.register({
  deviceId: "iphone-15",
  platform: "apns",
  tenant: "acme",
  token,
  topics: ["incidents"],
  userId: "user-42",
});

// Authenticated apps use server-issued installation identities. Pass this
// lifecycle directly as Auth's push registrar; ownership is checked on every
// native-token or browser-subscription rotation and removal.
const installation = await push.registerInstallation({
  platform: "apns",
  tenant: "acme",
  token,
  topics: ["incidents"],
  userId: "user-42",
});

await push.registerInstallation({
  platform: "webpush",
  subscription: {
    endpoint: "https://push.example/subscription-id",
    keys: { auth: "browser-auth-key", p256dh: "browser-public-key" },
  },
  tenant: "acme",
  topics: ["incidents"],
  userId: "user-42",
});

await push.send(
  { tenant: "acme", topic: "incidents" },
  {
    body: "Database latency is elevated",
    deepLink: "absolute://incidents/42",
    idempotencyKey: "incident-42:opened",
    sound: "default",
    title: "Production alert",
  },
);

模糊的提供者故障记录为 indeterminate 而不是成为 租赁期满后默默复试. 这可以防止一个坠毁的工人 双重发送通知,其提供者的确认被丢失.

回返 MessagingDispatchResult { id?, provider, at, delivery }编辑 delivery 记录载有所要求和实际运输量外加正常运输量 初级/后退尝试。 丢入适配器 失败; onError 在重投前开火.

送出前授权政策

政策在适配方或供应商收到信息之前运行,并可能 进行持久的同步检查. @absolutejs/compliance 用品a 消息同意政策.

const dispatcher = createDispatcher({
  policies: [messagingConsentPolicy],
  messaging,
});

await dispatcher.messaging({
  content: { kind: "text", text: "Database latency is elevated" },
  consent: { programId: "acme-alerts", purpose: "incident-alerts" },
  to: { address: "+12025550100", transport: "sms" },
});

dispatcher.metrics()

{
  sent: number;
  failed: number;
  byChannel: {
    email: {
      sent, failed;
    }
    messaging: {
      sent, failed;
    }
    push: {
      sent, failed;
    }
  }
}

底片图案

打开几何

何时 tracerProvider 设定,每个发送 dispatch.<channel>.send 间距( n)dispatch.email.send页:1

  • abs.tenant (当 message.tenant 已提供)
  • dispatch.channel (单位:千美元)email 编号 : messaging 编号 : push(中文(简体) )
  • dispatch.provider (适配器名称,成功后更新到结果提供者)
  • dispatch.recipient_count (地址被故意排除在跨度之外)
  • dispatch.message_id (当适配器返回一个)

从结果中更新提供者使适配器成为中介/委托 观察时不会泄露其路径执行.

状态 OK 关于成功; ERROR + 键 recordException 失败.

审计排放

何时 audit 提供(任何) @absolutejs/audit Audit 实例), 每一次发送 dispatch.<channel>.<outcome> 事件:

  • kind数字 : dispatch.email.sent 编号 : dispatch.email.failed (中文(简体) )
  • actor数字 : message.tenant (设定时),其他 'system'
  • target: 收件人
  • metadata数字 : { channel, provider, messageId?, error? }

审计排放是火灾和遗忘——如果你的审计汇失败 发送仍然成功。 审计失败记入 console.warn。 。 。 .

审计司是 选项 —— 说 @absolutejs/audit 是一个同位素 peerDependenciesMeta.optional: true所以消费者没有它 刚刚安装通过 audit: undefined。 。 。 .

套装适配器

这些在核心的飞船用于测试 + dev. 生产部署使用 姐妹卖家适配器.

memoryEmailAdapter({ max?, idGenerator? })

正在处理的FIFO尾. inspect() 返回最古老的已抓取的信息 - 首先是:; clear() 虚空相. 我们发邮件给爱丽丝 在没有真正的SMTP服务器的测试中.

memoryMessagingAdapter({ max? }) 编号 : memoryPushAdapter({ max? })

形状相同,用法相同.

consoleEmailAdapter({ stream? }) 编号 : consoleMessagingAdapter 编号 : consolePushAdapter

JSON-每行为stdout(或作stderr). 用于 bun --watch 说到做到 您可以在不燃烧提供者的情况下看到所发送的精确信息 学分.

此软件包没有做什么

  • 模板渲染. 消息被预发. 与 @react-email, (中文(简体) ), mjml, (中文(简体) ), handlebars或者你喜欢的.
  • 受收人率受限. 编曲: @absolutejs/rate-limit 每小时5个魔法链接 g.
  • 弹出/投诉处理. 每个供应商的SDK曝光 网络呼喊这些.
  • 排队/排队. 对于延迟发送使用 @absolutejs/queue 有个接线员打电话 dispatcher.email(...)。 。 。 .

许可证

BSL-1.1 (英语) 带有一级例外: 你不能使用此选项 操作主机信件发送/ 交易邮件/ 短消息/ 推 与主办方相竞争的SaaS(Resend, Postmark, SendGrid, 邮件枪、AWS SES管理、Twilio、Vonage、Pushwoush、OneSignal、FCM 管理,敲门。 你可以把它当作你自己的应用程序的一部分 (包括你自己的SaaS). 2030-05-30自动转换为Apache 2.0.

版本与发布记录

@absolutejs/dispatch 共发布 22 个版本,首次发布于 2026/05/31;过去 12 个月发布了 22 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.9.1latest2026/10/2216 天前
0.9.02026/08/272 个月前
0.8.02026/08/272 个月前
0.7.22026/08/073 个月前
0.7.12026/08/023 个月前
0.7.02026/08/023 个月前

关于 @absolutejs/dispatch 的常见问题

@absolutejs/dispatch 是什么?

提供不可知的电子邮件、载体和丰富的信息发送器,并在绝对JS生态系统中推动通知.

如何安装 @absolutejs/dispatch?

在项目目录运行 npm install @absolutejs/dispatch,或使用 pnpm add / yarn add / bun add。

@absolutejs/dispatch 支持 TypeScript 吗?

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

@absolutejs/dispatch 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@absolutejs/dispatch 可以商用吗?

@absolutejs/dispatch 使用 BSL-1.1 许可。声明的许可为 BSL-1.1,请阅读许可原文确认使用条件。以上为概括,不构成法律意见,请以许可原文为准。

@absolutejs/dispatch 的下载量有多少?

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

@absolutejs/dispatch 还在维护吗?

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