安装本地包
从仓库根目录执行:
npm --prefix sdk/typescript ci
npm --prefix sdk/typescript run build
cd sdk/typescript
npm pack
在你的项目里安装生成的 tarball:
npm install /absolute/path/to/sdk/typescript/pushnow-sdk-0.1.1.tgz
包名是 pushnow-sdk。发布后可使用 npm install pushnow-sdk,本地开发也可以安装 tarball。包格式是 ESM,并包含 TypeScript declarations;没有 CommonJS 入口。
如果在不打包的浏览器里使用,把构建后的 dist/browser.js 作为 ES module 从你的应用里提供。它已经包含 HPKE 依赖。运行环境需要 HTTPS 或 loopback HTTP,并支持 WebCrypto、fetch、AbortController 和 structuredClone。
使用一个带权限的 Authorization Key
服务端集成和 webhook 式发送可以直接使用 Dashboard API token,并只授予需要的 scopes。
import { getAccount, listSources, sendMessage } from 'pushnow-sdk';
const auth = {
api_url: 'https://api.pushnow.dev',
authorization_key: process.env.PUSHNOW_API_KEY!,
};
const me = await getAccount(auth);
const sources = await listSources(auth);
const sent = await sendMessage(auth, {
title: 'Build complete',
body: 'The report is ready.',
inboxOnly: true,
});
sendMessage 需要 send:write,调用 /v2/messages。后端会使用已登录 Web 或 App 保存的同账号 sender key 加密。
getAccount 需要 account:read,listSources 需要 sources:read。
需要 v2 端到端加密内容和加密附件时,使用下面的 encrypted sender flow。
使用账号 Token 授权一次,用于 E2EE
使用已登录 PushNow App 或可信 Dashboard 会话里的账号 access token,创建账号绑定 sender 授权。
import { beginAccountLogin, finishAccountLogin } from 'pushnow-sdk';
const pending = await beginAccountLogin(
'https://api.pushnow.dev',
accountAccessToken,
'My integration',
);
// 展示这些公开值,并在已登录 App 中批准 sender。
console.log(pending.authorization.user_code);
console.log(pending.fingerprint);
const config = await finishAccountLogin(pending);
token 只用于访问 /v2/account-authorizations 创建授权。scoped API token 可以按权限调用 HTTP API,但没有返回的 sender config 就不能加密 v2 消息。
config 含有私密凭证。浏览器场景只建议保存在当前会话内;服务端场景应放入安全的 secret store。不要把它写进公开 JavaScript、URL、日志或明文浏览器存储。接入 Dashboard 时,应确认 config.user_id 等于当前登录账号,config.api_url 等于预期 API origin,然后调用 recipientsV2(config) 校验设备目录。用户退出登录或切换账号时清理配置。
发送文字和文件
import { sendNotification } from 'pushnow-sdk';
const result = await sendNotification(config, {
title: 'Build complete',
body: 'The report is ready.',
links: ['https://example.com/reports/latest'],
files: [{
data: new Blob(['Build passed']),
name: 'build.txt',
mime: 'text/plain',
}],
}, {
inboxOnly: true,
});
console.log(result.message_id, result.deduplicated);
去掉 inboxOnly 会通知所有可接收设备。发送到指定设备时使用 deviceIds: [selectedDeviceID],不要和 inboxOnly: true 同时使用。scheduledAt 和 expiresAt 放在第三个参数的 options 里。
image 或 icon 可以作为 content 字段传入,格式同样是 {data,name,mime},SDK 会上传并引用图片。文件数据可以是 Blob、Uint8Array 或 ArrayBuffer。
声音参数在第三个参数中传入:
await sendNotification(config, { title: 'Quiet update', body: 'Ready to review.' }, {
sound: 'silent',
});
MessageOptions.sound 支持 'default' | 'silent' | 'chime'。省略时保持默认行为。声音是公开路由元数据;消息正文和文件仍然加密。不支持任意音频文件名、音频上传或 critical alert。
Prepare 和重试
import { recipientsV2, prepareMessageV2, submitMessageV2 } from 'pushnow-sdk';
const directory = await recipientsV2(config);
const prepared = await prepareMessageV2(config, directory, {
title: 'Report ready', body: 'Open the app to review.',
}, { inboxOnly: true });
const result = await submitMessageV2(config, prepared);
// 如果网络结果不确定,重试 submitMessageV2(config, prepared)。
必须保留原始 prepared 对象。SDK 会把它和账号/source 在内存中绑定;JSON 序列化、clone 或重新导入会丢失绑定并被拒绝。当前版本不提供持久化 outbox 导入。需要进程重启后仍可重试时,请使用 CLI 或其他绑定的 durable outbox 流程。
脱敏请求事件
await sendNotification(config, { title: 'Ready', body: 'Done' }, {
onRequest(event) {
console.log(event.method, event.path, event.status, event.durationMs, event.outcome);
},
});
事件不包含 headers、tokens、明文或原始响应体。路径使用 template,不输出具体 ID。自定义 fetcher 会收到凭证和密文请求体,它必须是可信代码;它不是脱敏日志钩子。
HTTP 错误会暴露 APIError.status。请求会拒绝 redirect 并带超时。可以传入 AbortSignal 取消请求;取消不证明服务端没有收到提交。