npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@indexyz/worker-ai-base

v0.4.0

Published

Privacy-conscious AI usage analytics and OpenTelemetry tracing for Cloudflare Workers

Readme

@indexyz/worker-ai-base

Cloudflare Workers 的 AI 遥测公共包,提供统一的 usage analytics 与分布式 tracing;不依赖具体业务环境、路由、D1 或套餐枚举。

  • Analytics:Anthropic Messages JSON/SSE usage → Analytics Engine,每次上游调用最多写一条。
  • Tracing:真正的 OpenTelemetry SERVER/CLIENT spans、W3C traceparent / tracestate、显式父子 context;不是仅记录 request ID。
  • 安全默认:不自动采集 URL、headers、正文、异常 message/stack;模型名仅记录到用量数据,不加入 tracing;遥测故障不改变业务结果。
  • 工具链:Vite 8(Oxc/Rolldown)、oxfmt、oxlint recommended correctness + type-aware/type-check、严格 TypeScript、Vitest + workerd E2E。

安装与接入

npm install @indexyz/worker-ai-base @opentelemetry/api

包为 ESM,包含声明文件,无 Node.js 运行时依赖。构建/测试环境使用 Node.js 22.12+,推荐 Node.js 24。

import { createTelemetry } from "@indexyz/worker-ai-base";
import type { AnalyticsDataset } from "@indexyz/worker-ai-base";

interface Env {
  USAGE?: AnalyticsDataset;
  USAGE_ENABLED: string;
}

export default {
  fetch(request: Request, env: Env, ctx: ExecutionContext) {
    const telemetry = createTelemetry({
      analytics: {
        enabled: env.USAGE_ENABLED === "true",
        ...(env.USAGE ? { dataset: env.USAGE } : {}),
      },
      // tracing 可独立启用,见下一节。
    });

    // 鉴权、参数校验、解析模型别名之后再进入;不要将 API key 当作 keyId。
    return telemetry.handle(
      request,
      {
        operation: "POST /v1/messages", // 静态路由模板,不能是实际 URL
        keyId: "internal-key-id",
        model: "resolved-model-id", // 包内 SHA-256,原文不进入 telemetry
        mode: "personal_plan", // 应用定义的静态 provider/plan 标签
      },
      async (scope) => {
        return scope.fetch("https://provider.example/v1/messages", {
          method: "POST",
          headers: { "content-type": "application/json" },
          body: JSON.stringify({ model: "resolved-model-id", messages: [] }),
          signal: request.signal,
        });
      },
      ctx,
    );
  },
};

使用 scope.fetch 而不是全局 fetch 记录 AI 调用;包不会包装全局 fetch。一次 handler 可以发起多个上游调用,每个调用独立记录,使用同一 request.id 关联。非 AI 请求不要通过 scope.fetch。

handle 为返回的 HTTP 响应设置新生成的 x-request-id,忽略入站同名 header。上游 CLIENT span 持续至其响应体 EOF/错误/取消;SERVER span 持续至最终响应体终止。必须返回、消费或取消每个上游 body,否则不会产生完整遥测。无 body 的响应立即结束。不支持 WebSocket upgrade。

原始 fetch/handler/流异常保留身份并向调用方传播,不生成业务错误响应;需要安全错误响应时由应用处理。没有内置重试或超时策略,使用 RequestInit.signal(例如 AbortSignal.timeout),以及显式取消响应体。

OpenTelemetry

传入应用已有的 SDK tracer 和 provider 的 flush:

const telemetry = createTelemetry({
  tracing: {
    tracer: provider.getTracer("my-worker"),
    flush: () => provider.forceFlush(),
    acceptRemoteParent: false, // 公网入口推荐;可信内部入口可设 true
  },
});

provider 是应用创建的 OpenTelemetry SDK provider,例如 @opentelemetry/sdk-trace-base 的 BasicTracerProvider,配置应用选择的 SpanProcessor / Workers-compatible SpanExporter。包不创建全局 provider/context manager,不绑定供应商或 OTLP endpoint,也不自动开启 Cloudflare fetch/D1 instrumentation。没有 SDK tracer 时只启用 analytics;只有 API 的 no-op tracer 不会导出 spans。

生产使用供应商提供的 Workers exporter,或经 workerd 验证、使用 fetch 的 OTLP exporter;不要直接使用依赖 Node HTTP、XHR 或 DOM 的 exporter。采样、认证、批量上限、重试、出口脱敏均由 SDK/exporter 管理。通过每次 invocation 的 ctx.waitUntil 调度 flush,拒绝不会变成 unhandled rejection;未传 ctx 时只能 best-effort,不能保证响应结束后的导出。

入站默认提取 W3C trace context(可用 acceptRemoteParent: false 禁用);不提取 baggage。出站默认不自动注入,仅对明确可信且支持 tracing 的上游启用:

const response = await scope.fetch(url, init, { propagateTrace: true });

启用注入时强制 redirect: "manual",避免通过重定向把 trace context 带到其他域。应用自行提供的 headers 不会被清洗;不要复制未经审查的入站 headers。可用 tracing.propagator 替换传播协议,但自定义 propagator 的隐私策略由调用方负责。

其他业务 span 显式传 scope.context:

const span = tracer.startSpan("business.operation", {}, scope.context);
try {
  // ...
} finally {
  span.end();
}

包创建的 span 只携带 request.id、http.response.status_code,使用静态名称和 ERROR status;不调用 recordException。自动结束和去重,且不使用 ambient context,避免并发 invocation 串联。SDK 自行添加的 resource/attributes 不在包的隐私保证范围内。

Analytics Engine

{
  "analytics_engine_datasets": [{ "binding": "USAGE", "dataset": "my_worker_usage_v1" }],
  "vars": { "USAGE_ENABLED": "true" },
}

缺失 binding、未启用或同步写入抛错均 fail-open,不重试、不写 D1,也不需要为 writeDataPoint 调用 waitUntil。

固定 v1 列

v1 使用固定列顺序;不要修改已存在 dataset 的列语义。

| 列 | 含义 | | --------- | ----------------------------------------------------------------------------------------------------------------------- | | index1 | 内部 API key ID(不是 key/prefix/hash;须符合 AE 的 96-byte index 限制) | | blob1 | v1 | | blob2 | 本地生成的 request ID | | blob3 | 兼容旧版的模型哈希;新接入不计算哈希,此列为 omitted | | blob4 | 应用定义的静态 mode | | blob5 | json / sse / unknown | | blob6 | completed / http_error / upstream_error / incomplete / cancelled / timeout / read_error / network_error | | blob7 | complete / partial / missing | | double1 | 上游 status,无 headers 为 0 | | double2–5 | input、output、cache creation、cache read tokens | | double6 | 上游调用至本地终止的毫秒数(受消费速度影响) | | double7 | 首个非空响应 chunk 等待毫秒数,无数据为 -1 | | double8 | 已知字段 bitmask:input=1、output=2、creation=4、read=8 |

SSE message_delta 是累计值,不逐 chunk 相加。拒绝负值、非安全整数和倒退计数;零与未知通过 bitmask 区分。complete 要求 input/output 已知、正常 EOF、无协议错误;SSE 还要求 start、带 output 的 delta 和 stop。取消/错误仅保留已观察到的 partial。

JSON 观察最多 1 MiB;SSE 每行/事件最多 64 Ki UTF-16 字符。明确的 content/tool 事件不影响 usage 完整性。无 tee/clone,无主动排空,无更改响应字节;保留背压及取消传播。目前仅理解 Anthropic Messages,不是 OpenAI Responses/Chat Completions usage 适配器。未知协议仍记录请求结果,但 usage 为 missing。

Analytics Engine 会采样,不是计费账本;查询必须用 _sample_interval:

SELECT index1 AS key_id,
       SUM(_sample_interval) AS estimated_requests,
       SUM(IF(blob7 = 'complete', double2 * _sample_interval, 0)) AS input_tokens,
       SUM(IF(blob7 = 'complete', double3 * _sample_interval, 0)) AS output_tokens
FROM my_worker_usage_v1
WHERE timestamp >= NOW() - INTERVAL '1' DAY
GROUP BY key_id

自 0.3.0 起,blob8 保存模型名(最多 256 字符,不含控制字符;无效值为 omitted)。旧版没有此列,无法从历史哈希恢复原名。新接入向 writer 传入 model,不再计算哈希;前七个 blob 和所有 double 保持兼容。模型名不加入 tracing 属性。

高级接入可以独立使用 MessageUsage、createUsageWriter;每个上游调用新建 observer/writer,observer 依序 feed 后只 finish 一次。writer 的输入为受信任的已验证数据;它在首次写入尝试后关闭,不因失败重试。

隐私和运行时边界

operation、mode、keyId 是调用方维护的静态/内部元数据,不是任意客户端输入。这里只保证包自身的 telemetry 不采集敏感内容;无法脱敏 Cloudflare 平台附加元数据、SDK 自动 instrumentation 或原始异常被应用重新抛出后的平台日志。特别是 provider URL 路径可能含 key,勿直接开启自动 fetch spans。

平台强制终止、未消费 body、网络或采样均可能丢记录。analytics 与 tracing 可独立启停。库不会改变任何远程配置,不保证 Cloudflare 的实际日志保留或数据送达。

开发与验证

npm ci
npm run check
npm pack --dry-run
  • npm run lint:oxlint 默认 recommended correctness 规则、type-aware、--type-check,警告失败;额外启用 Promise 正确性规则。
  • npm run typecheck:TypeScript strict、unchecked index、exact optional、unused、isolated/verbatim modules。
  • npm test:先构建 ESM/声明,Vite 打包真实的包消费者,在 Miniflare/workerd 运行 Vitest E2E。
  • artifacts/vitest.json:机器可读测试结果;artifacts/telemetry.json:实际采集的 AE points 和 SDK 导出的 spans;artifacts/worker/worker.js:运行过的 Worker bundle。

测试包含 JSON/SSE、累计计数、截断/超限/错误、取消/背压、并发 context、W3C 父子关系、可选/失败的遥测、敏感字段不进入 telemetry。AE 使用内存 binding adapter,tracing 使用真实 SDK 的 InMemorySpanExporter;不写远程 dataset,也不证明生产 OTLP collector 可达。

Miniflare 固定为 5.20260921.0-alpha(仅开发依赖),使用其官方 v4 配置转换器;旧 v4 的传递依赖存在已知安全公告。锁文件固定全部依赖版本。发布仅包含 dist/、本说明和 package metadata,不包含业务代码、测试或测试产物。