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

td-feature-node

v0.0.2

Published

ThinkingData server-side experimentation SDK for Node.js

Readme

TD Feature Node.js SDK

ThinkingData 实验平台的 Node.js 服务端 SDK,分阶段实现一期远端分流。

当前版本:0.0.2。远端分流、曝光、完整服务 Demo、HTTPS、资源压力及发布检查已补齐;自动曝光默认关闭。0.0.2 待发布,0.0.1 已发布;未实现本地分流。真实项目与跨操作系统验收范围另行列明。

分阶段交付

| 阶段 | SDK | Demo | 状态 | | --- | --- | --- | --- | | S1 | npm 包、类型声明、初始化与关闭 | 初始化示例 | 已完成 | | S2 | RCC 请求、签名、响应解码、Feature 取值 | Mock RCC / 真实 RCC 两种运行方式 | 已完成本地验收 | | S3 | 单次超时、可选重试、有界并发/排队、结果缓存 | 重试恢复、缓存、过载和超时场景 | 已完成本地验收 | | S4 | Java 对齐的手动/自动曝光、去重、队列、采集适配器 | 实际使用结果后曝光 | 已完成本地验收 | | S5 | 完整兼容矩阵、负载、内部候选包验收 | 完整 API、进程关闭、显式业务回退 | 本机自动化验收;外部项保留 |

详见 接入指南、任务清单、Java 对齐基准、兼容性记录、发布验收与保留项。

使用

当前待发布版本为 [email protected]。npm 安装包只包含 dist/、README、包信息和纯生产依赖发布锁;完整文档与 Demo 保留在源码仓库,不随安装包分发。本文的构建、Demo 和验收命令均在源码仓库根目录执行。

先构建并验证本地包:

npm ci
npm test
npm run verify:package

0.0.2 发布后,在消费项目从 registry 安装;默认安装无需 TypeScript、Prettier 或开发依赖:

npm install [email protected]
const { createClient, SplitMode } = require('td-feature-node');
const client = createClient({
  splitMode: SplitMode.REMOTE,
  appId: 'your_app_id',
  serverUrl: 'https://your-rcc-server.example.com',
  timeout: 1000,
  retryTimes: 0,
  maxConcurrentRequests: 20,
  maxQueueSize: 0,
  enableCache: false,
  autoExposure: false
});

client.fetch({
  accountId: 'user_123',
  distinctId: 'device_456',
  featureKeys: ['checkout_button'],
  customParams: { country: 'CN' }
}).then(function (config) {
  const feature = config.features['checkout_button'];
  const text = feature ? feature.asString('购买') : '购买';
  console.log(text, feature && feature.experiment && feature.experiment.experimentId);
  if (feature) client.expose(feature, { scene: 'checkout' }); // 在实际使用值后曝光。
}, function (error) {
  // 网络或协议错误由业务显式处理,不会伪装成成功的空配置。
  console.error(error.code, error.message);
}).then(function () {
  return client.close(); // 单次脚本示例;服务端应复用 Client,在进程退出时关闭。
}, function (error) {
  console.error(error.code, error.message);
  return client.close();
});

createClient() 不访问网络。splitMode 默认 SplitMode.REMOTE,也可直接传 'REMOTE'。SplitMode.LOCAL 仅作后续扩展预留,当前传入会同步抛出 INVALID_CONFIG。fetch() 在缓存未命中时请求 RCC,默认不排队、不自动重试;需要时可显式开启。身份必须至少包含一个非空字符串。不指定 Feature 列表或列表为空时请求全部 Feature。customParams 只接受 JSON 数据,保留身份、语言和 Feature 字段由 SDK 覆盖;使用原生 JSON.stringify,对象和数组中的 null 均保留,未提供的账号/设备字段省略。

配置

| 配置 | 默认值 | 说明 | | --- | --- | --- | | appId | 必填 | 平台项目 ID | | serverUrl | 必填 | 远端决策与采集共用的 HTTP(S) 基础地址 | | splitMode | SplitMode.REMOTE | 初始化时选择分流模式;当前仅实现 REMOTE,LOCAL 为预留值且会报错 | | timeout | 5000 ms | 单次 HTTP 阶段超时,含连接池等待、连接和响应读取;到期中止请求 | | maxHttpConnections | 20 | 同一 RCC 的连接池最大连接数 | | maxConcurrentRequests | 与 maxHttpConnections 相同 | 活跃 fetch 上限,不能大于连接数;解码和退避期间保留槽位 | | maxQueueSize | 0 | 默认不排队;可设 0–1000000,并发及等待位置满时返回 QUEUE_FULL | | retryTimes | 0 | 默认不自动重试;首次请求后的最大重试次数,范围 0–10 | | retryInterval | 500 ms | 首次退避间隔;允许 0 | | retryStrategy | EXPONENTIAL_BACKOFF | 可选 FIXED_INTERVAL | | retryJitter | true | 在退避区间内作 full jitter 随机延迟 | | maxRetryInterval | 30000 ms | 重试等待上限;Retry-After 超过此值时停止重试,返回原 HTTP 错误 | | enableCache | false | 显式启用成功结果缓存 | | cacheExpireTime | 86400 秒 | RCC TTL 非正数时的回退;正数 RCC TTL 优先 | | maxCacheSize | 10000 | LRU 缓存条目上限;0 不存储 | | maxDecompressedResponseBytes | 10 MiB | data 字段 Base64/GZIP 解压后的上限,与 Java 默认值一致 | | autoExposure | false | 开启后首次读取原始/类型化值时自动曝光 | | exposureDedupMaxSize | 100000 | 曝光去重条目上限,独立于结果缓存 | | exposureDedupExpireSeconds | 86400 秒 | 去重 TTL,读取不续期 | | exposureQueueCapacity | 10000 | 等待曝光容量,范围 1–1000000;另有一个活跃任务 | | exposureBatchSize | 100 | 自建采集器每批事件数,范围 1–10000 | | exposureFlushIntervalMillis | 1000 ms | 自建采集器不足一批时的最长缓冲时间 | | exposureFlushTimeoutMillis | 5000 ms | flush/close 等待预算;自建采集请求的单次 I/O 预算 | | tdAnalytics | 未指定 | 复用业务已有 Node 采集实例,外部实例由业务关闭 | | exposureAdapter | 未指定 | 自定义异步采集适配器,与 tdAnalytics 互斥,外部实例由业务关闭 | | tlsCa | 运行时默认信任根 | 显式 PEM CA 字符串/数组会替换默认 CA 列表,作用于 RCC/自建采集 HTTPS,仍检查主机名 |

timeout 只控制每次 HTTP 尝试,重试会重新计时;排队、重试等待和 RCC 字段解码不计入该 HTTP 超时。整次 fetch 的耗时会随尝试次数与退避等待增加,可用 AbortSignal 提前取消。完整语义和示例见 S3 请求可靠性与缓存。

默认最多 20 个活跃 fetch,没有等待队列,失败只尝试一次。显式开启排队或重试后,整次 fetch 仍没有 SDK 内置的总期限;有业务截止时间时传入带期限的 signal。较早版本默认重试 3 次、排队 1000 项,接入升级时需留意默认行为变化。

serverUrl 不接受认证信息、查询参数或 fragment,末尾 / 会归一化。未知或未实现的配置会报错,当前不能设置本地模式。

Feature 读取

fetch() 返回只读的普通对象:

{
  features: { checkout_button: feature },
  ttl: 60 // RCC 原始 TTL,单位秒,不是缓存剩余寿命
}

通过 result.features[key] 查找,缺失时为 undefined;Object.keys(result.features) 枚举 Feature。字典没有原型,__proto__、constructor 等服务端 Key 也能安全读取,experiment_detail 不进入字典。

Feature 提供 key、value、accountId、distinctId、experiment 和 hasValue 属性;转换方法为 asString(fallback)、asNumber(fallback)、asBoolean(fallback)、asJson(fallback)。省略 fallback 时默认为 null;false、0、空字符串不会被业务默认值覆盖。

JSON 数字使用原生 number:asString() 按 String(number) 输出,对象和数组按 JSON.stringify 输出。例如 1.0 读取为 1、字符串为 "1",1e23 的字符串为 "1e+23"。超出安全整数范围的数字遵循 JS 精度规则,9007199254740993 会读取为 9007199254740992;需要精确保留的长 ID 应由服务端作为字符串返回。

asNumber() 接受数字或非空数字字符串,按 Number() 解析;例如 "0x10" 为 16,"1f"、"0x1.8p1"、NaN、空白字符串和其他类型返回 fallback。asBoolean() 接受布尔值或大小写不限的 "true" / "false" 字符串。asJson() 接受对象或解析为对象的 JSON 字符串;空字符串、"null"、数组和无效 JSON 返回 fallback。

experiment 为 null 或只读实验信息对象;实验 ID、分组、控制组和自定义分桶直接从对象读取。不再提供重复元数据 getter,也不为远端模式构造版本/分流来源占位值。

读取 value 或调用转换方法会触发可选自动曝光;读取元数据和 hasValue 不会。自动曝光默认关闭。展开、序列化 Feature 也会读取 value,调试元数据时只选取所需字段。

未发布 API 在 rc.2 直接调整,不提供旧构造器或 getter 别名。旧候选迁移及维护约定见 Node API 与编码约定。

曝光

client.expose(feature, properties?) 同步返回是否入队;未匹配、重复、队列满或已关闭返回 false。返回 true 不是入库确认。入队前复制属性,所有 # 开头的自定义属性被忽略。远端曝光只发送 Java 已提供的元数据,不从结果的 Feature Key 推造远端元数据。

自动曝光默认关闭;显式开启后,value 和所有类型化读取首次触发,包括返回业务默认值的情况。元数据读取与 hasValue 不触发;每次 fetch(包括缓存命中)的结果各自有一次触发状态,再经过 Client 级去重。队列拒绝或提交失败撤销去重标记,新结果或手动曝光可重试,同一个自动结果不会再次触发。

默认采集器按 100 条一批发送,不足一批最多缓冲 1 秒;同一批共用一次 GZIP/HTTP 请求。一个批次发送期间,后续曝光留在有容量限制的队列中。client.flush() 立即刷新余量,client.close() 在关闭预算内排空。复用外部采集实例时,保留该实例的批量和定时配置;官方 track() 同步返回,不逐条等待网络回调或触发 flush。

默认自建采集器直接依赖官方 npm 包 [email protected],首次曝光时惰性加载;也可通过 tdAnalytics 复用已有官方实例。SDK 只为自建实例配置传输资源、TLS、超时与关闭,不修改官方包源码。依赖与适配边界见 曝光与采集说明。

错误与关闭

fetch(request, options?) 对参数、网络和协议错误均返回 Promise rejection。FeatureError.code 区分 INVALID_CONFIG、INVALID_REQUEST、NETWORK_ERROR、HTTP_ERROR、REMOTE_ERROR、INVALID_RESPONSE、RESPONSE_TOO_LARGE、TIMEOUT、ABORTED、QUEUE_FULL、CLIENT_CLOSED、EXPOSURE_ERROR。

HTTP 错误附 httpStatus;RCC 业务错误附原始 remoteCode 和 Java 映射后的 errorCode。未知 RCC code 映射到 5000,但保留原始 code。符合 Java 兼容契约的空数据/缺失模板仍是成功的空配置,也可缓存。

clearCache() 只清结果缓存,不清曝光去重。曝光入队后由 SDK 后台发送,业务请求无需调用或等待 flush();它是测试、批处理等需要等待此前曝光处理完成时使用的可选接口。超时或适配器 flush 失败分别拒绝为 TIMEOUT、EXPOSURE_ERROR。单个曝光提交失败会撤销去重标记。

close() 停收、取消 fetch 和退避,有限等待曝光排空并关闭自建采集实例;超时丢弃待处理曝光并取消自有连接,外部采集实例仍由业务管理。方法可重复调用,关闭后不能再次 fetch。没有本地规则轮询或采集周期定时器。flush 控制槽和关闭的具体边界见 曝光说明。

Demo 与兼容验证

npm run demo
npm run demo:s3
npm run demo:s4
npm run demo:s5
npm run demo:service
npm run verify:package -- /path/to/node-v12.0.0/bin/node /path/to/another/node
npm run verify:production-install -- /path/to/node-v12.0.0/bin/node

基础 Demo 展示缓存,S3 展示可靠性,S4 展示曝光;S5 自动跑 API→RCC→缓存取值→曝光→采集→回退→关闭,service 提供常驻本机 API 和 SIGTERM 关闭。默认都只使用本机 Mock。完整接入和真实模式见 指南、Demo 说明。真实 RCC、曝光入库及四进程生命周期的执行结果见 真实联调和 PM2 验收,记录保留实际验收时的版本号。

验收从同一 tarball 安装 SDK,执行支持版本矩阵、最低 Node 版本的 engine-strict 生产安装、JS/TS/ESM 消费、八个压力场景及官方采集实例验证。测试和 Demo 从仓库运行,通过 TD_FEATURE_SDK_PATH 指向已安装的 SDK,生成绑定 SHA-256 的报告。命令、指标边界和公网发布保留项见 压力验收、发布验收。没有自动发布步骤。

当前版本为 0.0.2,最低 Node.js 12.0.0,发布 ES2019 CommonJS 与 .d.ts。[email protected] 保留为生产依赖;仓库使用完整的 package-lock.json 安装开发工具;打包时自动生成只含生产依赖的 npm-shrinkwrap.json,固定支持 Node 12 的依赖树,包括 [email protected]、@dabh/[email protected]、[email protected]、[email protected] 和 [email protected]。打包结束会移除临时发布锁,保留正常的仓库 npm ci 流程。仓库和发布包均不使用 overrides,不包含 vendor 或修改过的官方源码。构建工具属于开发依赖,维护构建使用现代 Node;TLS 功能测试另需 OpenSSL CLI,消费 SDK 无需该命令。Node 12.0–12.16 的 ESM 导入需启用 --experimental-modules,CommonJS 无需该参数。

Java 固定样本已纳入测试;维护者可用 npm run fixtures:java 从同级 Java SDK 当前源码重新生成。该命令需要 JDK 17+、Python 3 和脚本列出的本地 Maven 缓存依赖,不修改 Java 项目,不访问真实 RCC。