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

@trustbaseai/shop

v0.1.0

Published

TrustBase 最小商域模型:商品与多规格、本地购物车、订单状态机(与链上一致)、订单草稿,以及跨侧硬契约的下单意愿 canonical JSON + sha256 + tb-auth memo

Readme

@trustbaseai/shop

TrustBase 的最小商域模型:商品与多规格、本地购物车、订单状态机(与链上一致)、订单草稿, 以及下单意愿(canonical JSON + sha256 + tb-auth: memo)的同构实现。

  • 纯逻辑:无 UI、无 DOM、无存储、无网络、不签名、不持私钥。
  • 同构:浏览器与 Node 跑同一份代码;src/ 零 Node 内建依赖(测试扫着)。
  • 唯一运行时依赖:@noble/hashes(算意愿的 sha256)。
  • 状态:已实现并测试通过(116 个用例);未验证/未做的清单见 §7。

1. 为什么这个包存在(以及它不是什么)

买家不装节点、浏览器不持私钥 —— 所以 v3.9.4 起 MsgCreateOrder 的 signer 是卖家, "这一单是买家要的"由 tx memo 承载:memo = "tb-auth:<sha256(意愿原文)>"。 意愿原文的序列化口径是跨侧契约:卖家后端算一遍、买家浏览器算一遍、争议时仲裁方再算一遍, 三次必须得到同一个 hash。任何一方口径不一致 = 静默失败(链上只校验 64 位小写 hex, 不会告诉你"你的原文排序错了")。

本包就是那条口径的 SDK 侧实现,出处是链侧真源:

| 契约 | 链侧出处 | |---|---| | 意愿序列化 + sha256 + memo | trustbase-seller-backend/core/order-intent.js | | MsgCreateOrder signer = seller / buyer 非空且 ≠ seller | trustchain-relmerge/proto/trustchain/order/v1/tx.proto:40-63、x/order/keeper/msg_server.go:37- | | 订单状态与迁移 | proto/trustchain/order/v1/params.proto:11-19 + x/order/keeper/msg_server.go(守卫行号见 src/order.ts 顶部表) | | tct1 地址形态校验 | trustbase-seller-backend/core/address.js |

不是什么:不是链客户端(不发交易、不签名 —— 那是 @trustbase/chain-client 与商户守护进程), 不是 UI(见 @trustbaseai/shop-ui),不是索引器(查询面见 @trustbase/index-client)。

2. 下单意愿:硬契约

import { buildOrderIntentHash } from '@trustbaseai/shop';

const { intent, canonical, hash, memo } = buildOrderIntentHash(
  [{ sku_id: 'sku-tea-250g', quantity: 2, price_per_unit: '19900000' }],
  { buyer, seller, order_ref: 'tb-mf8k2p-3b1x9q', timestamp_ms: 1758500000000, session_ref: 'sess-abc' }
);
// canonical: 键递归升序的紧凑 JSON(被哈希的字符串,留证用)
// hash:      64 位小写 hex
// memo:      "tb-auth:<hash>"  ← 直接塞进 tx memo

口径要点(与链侧逐条对齐):

| # | 规则 | |---|---| | 1 | 对象键递归升序、数组保序(items 顺序即业务顺序 → 顺序影响 hash) | | 2 | quantity / price_per_unit 归一成字符串(2 与 "2" 同 hash) | | 3 | 顶层固定 8 字段:kind, v, buyer, seller, order_ref, timestamp_ms, session_ref, items | | 4 | 缺字段抛错,不补空串/0(否则两批不同订单会撞同一个 hash) | | 5 | session_ref 是唯一例外:入参缺省 → ""(链侧 c.session_ref ?? "",有固定向量锁着) | | 6 | memo 只接受 64 位小写 hex;非 tb-auth: 前缀的 memo 链上不校验(isValidAuthMemo 返回 true) |

比链侧更严的三处(只影响"更早报错",不影响合法输入的 hash):严格形状(多/少键即拒)、 金额必须是规范十进制整数字符串(小数直接拒)、buyer === seller 直接拒。

证据:与链侧同 hash(固定向量)

test-vectors/order-intent.golden.json 由 链侧真实现跑出来,不是手写的:

node tools/gen-intent-vectors.cjs ../trustbase-seller-backend   # 或传绝对路径

test/order-intent.test.ts 对每条向量断言 intent / canonical / hash / memo 逐字节相同, 另含两条链侧自算的交叉验证:normalization_cross_check(number 与 string 同 hash)、 key_order_cross_check(键插入顺序打乱后 hash 不变)。

该脚本不在 npm test 里:链侧仓库不在本仓库,CI 跑不了不是 bug (与 @trustbase/protocol 的 tools/check-proto-citations.cjs 同一取舍)。 链侧口径变了就重跑一次 —— diff 出现在 review 里才是纪律。

3. 订单状态机(与链上一致,不是我们拍的)

PENDING ──confirm_payment──► PAID ──ship──► SHIPPED ──confirm──► CONFIRMED
   │                                          │                    │
   └──cancel──► CANCELLED                     └────dispute────► DISPUTED ◄──dispute──┘

| SDK 状态 | 链上枚举 | 值 | |---|---|---| | PENDING | ORDER_STATUS_PENDING | 0 | | PAID | ORDER_STATUS_PAID | 7 | | SHIPPED | ORDER_STATUS_SHIPPED | 1 | | CONFIRMED | ORDER_STATUS_CONFIRMED | 2 | | DISPUTED | ORDER_STATUS_DISPUTED | 3 | | CANCELLED | ORDER_STATUS_CANCELLED | 5 |

链上还有 RESOLVED(4) / REFUNDED(6) 与 SettleOrder(CONFIRMED 后过争议窗口结算,不改状态)—— 属于争议/结算工作包,本包不做(写在这里是为了让"为什么没有"有据可查)。

canTransition / assertTransition / canApplyAction / applyAction:前两个是状态对状态, 后两个是"动作 + 前置状态"(界面据此决定按钮可点)。

4. 商品与多规格

父商品 + N 个规格(SKU);链上仍是单 SKU 粒度(MsgCreateOrder.sku_id 是单个字符串), 所以"一个父商品 → N 条 MsgCreateOrder"这条路是通的。

  • 上限是可配置参数:ShopLimits.maxSkusPerGoods(默认 20)、maxLinesPerOrder(默认 20)。 边界语义:等于上限通过、超 1 即拒(limit_exceeded)。
  • 金额一律 microTCT 十进制整数字符串(不是 TCT、不是浮点);formatTctAmount 负责显示(永远带单位)。
const goods = buildGoods({ goods_id, seller, title, skus: [{ sku_id, title, price_per_unit: '19900000', stock: 3, spec: { 规格: '250g' } }] });
defaultSku(goods);   // 有货且最便宜
priceRange(goods);   // { min, max }

5. 购物车(本地)

纯函数、不可变、不碰任何存储 API(存哪儿是宿主的决定):

let cart = emptyCart();
cart = addToCart(cart, { goods, sku_id, quantity: 2 });   // 同 sku 合并;超库存抛 out_of_stock
cart = setLineQuantity(cart, sku_id, 0);                   // 0 = 删行
cartTotalMicroTct(cart);                                   // 合计(整数串)
serializeCart(cart); / parseCart(raw)                      // 落盘/读盘(坏数据 → ok:false,不白屏)
cartToOrderLines(cart);                                    // → 意愿 items(结算桥)

6. 公开 API

| 模块 | 出口 | |---|---| | 意愿 | buildOrderIntentHash buildOrderIntent hashOrderIntent canonicalize(内部) buildAuthMemo isValidAuthMemo assertOrderIntent normalizeTimestampMs validateBuyerAddress + 常量 INTENT_KIND INTENT_SCHEMA AUTH_MEMO_PREFIX | | 订单 | ORDER_STATUS ORDER_ACTIONS CHAIN_ORDER_STATUS ALLOWED_TRANSITIONS canTransition assertTransition canApplyAction applyAction isTerminalStatus buildOrderDraft orderDraftIntentItems orderDraftIntentContext createOrderRef | | 商品 | buildGoods validateGoods resolveShopLimits skuById requireSku defaultSku priceRange totalStock specAxisNames skuLabel GOODS_STATUS + 上限常量 | | 购物车 | emptyCart EMPTY_CART addToCart setLineQuantity removeFromCart clearCart cartLineCount cartTotalQuantity lineAmount cartTotalMicroTct cartToOrderLines serializeCart parseCart | | 金额 | normalizeDecimalInteger normalizeCount isDecimalIntegerString addAmounts multiplyAmount formatTctAmount parseTctAmount MICRO_TCT_PER_TCT | | 地址/错误 | isTctAddress TCT_ADDRESS_RE shortenTctAddress ShopError ShopErrorCode Validation<T> valid invalid |

错误分两类(与 @trustbase/protocol 同一套纪律):外部数据不合规 → validateXxx 返回 Validation<T>(不抛); 契约被破坏 → 抛 ShopError(code 机器可读,测试按 code 断言)。

7. 未验证 / 未做(诚实清单)

  • 未验证:本包的意愿实现与链侧真机联调尚未做过(只有固定向量 + 代码口径对齐)。 等 WP0 升级窗口落地后,用真实卖家后端跑一单,比对两边 hash —— 那是最终验收。
  • 未验证:真实链上多规格方案未定(链是单 SKU 粒度,本包只是"父商品 + N 规格"的模型)。
  • 未做:RESOLVED / REFUNDED 状态与 SettleOrder(结算)、退款式;
  • 未做:优惠券、多仓、库存并发预占、订单超时自动取消(链上有 auto_confirm_timeout,SDK 侧未接);
  • 未做:收货信息的加密与 shipping_address_hash —— 由商户守护进程做(浏览器不碰加密契约);
  • 未做:shop 与 @trustbase/index-client 的对接(索引器返回的 CatalogItem → Goods 的映射,属 WP5)。

8. 开发

npm run build      # CJS → dist/ ;ESM → dist/esm/(浏览器可直接 import)
npm test           # jest(116 用例)
npm run typecheck  # tsc --noEmit

src/ 的相对导入写 ESM 形态(带 .js 后缀)——这样 dist/esm/ 不需要打包器就能被浏览器加载; jest 侧用 moduleNameMapper 摘掉后缀(见 jest.config.js)。

9. 约束(会拒绝的写法)

  • src/ 里出现 node: / process. / Buffer / __dirname → 同构测试失败(构建配置也把 types 设为空,编译期就报);
  • 签名、私钥、助记词相关标识符 → 同构测试失败(本包不持私钥);
  • 改意愿口径(排序、字段、归一)必须同时改链侧并 re-bump INTENT_SCHEMA + 重跑向量脚本。