• Joined on 2026-07-21

@bpos/activity-contract (8.0.0)

Published 2026-09-20 10:55:06 +08:00 by ChaiHao

Installation

@bpos:registry=https://gitea.akhr-ai.com/api/packages/ChaiHao/npm/
npm install @bpos/activity-contract@8.0.0
"@bpos/activity-contract": "8.0.0"

About this package

脚手架契约 —— 活动 ↔ 系统那条线上的全部消息形状(zod + 类型)。

@bpos/activity-contract —— 脚手架契约

系统给活动的只有一样东西:这份契约。 契约以内是系统;契约以外、活动包以内的一切归活动。 那就是黑盒线的准确位置。

形状全部是 zod,不是 TS 接口:每次跨界调用双向 safeParse —— 系统不信任活动交来的, 活动侧的 SDK 也校验系统答的,装不装 SDK 都拦得住。

规范在《操作系统系统设计》:§6.1(清单)· §3(操作表单)· §6.2(活动进程)· §6.4(能力面的名词表)· §6.5(事件表)· §4.2(工单那一组)· §2.8(业务数据)· §7.3(交出的两条路)· §12(令牌只对本任务节点有效)。

三样东西

在哪 是什么
线材 src/index.ts 递入信封 · 事件表 · 名词表 · 交出与错误信封
清单与操作表单 src/manifest.ts bpos-activity.json 的形状(manifestSchema,含 declares.tables[] 的表声明)与工单定义那三段,加机检用的几把尺子(manifestGaps / outputIssues / orderIssues / tableIssues / artifactIssues / commitIssues / chartIssues / archiveIssues),以及件上 ref 那一格的值形状(refValueSchema / refIsEmpty / refKeyOf)与主键串的编解码(encodeRefKey / decodeRefKey)
不在这里的 — 实践的图(graphSchema 那一组)——图归实践、在系统侧编排,活动不知道有边

清单在这里而不在工作台契约里,是因为它是活动交付物的形状:包一搬出这个仓, 手写 bpos-activity.json 的人得拿得到那把尺子。构建时 manifestSchema.parse(自己的清单), 写坏了停在人改得动的地方,不必等装包那一刻由服务端说。

引用方向只许一边:本包不引 web/api/contracts;工作台契约单向引本包的清单形状, 再原样导出(接缝只有 web/api/contracts/plugin/manifest.ts 一处)。两向各有一条用例钉着: 本包的 tests/boundary.test.ts 钉禁止的那一向,server 的 tests/boundaries.test.ts R8 钉许可的那一向。

两个方向,两条线材

方向 线材 形状
系统 → 活动 POST http://127.0.0.1:<BPOS_EVENT_PORT>/events eventEnvelopeSchema;进程答 eventAckSchema 即确认
活动 → 系统 POST <BPOS_CAPABILITY_BASE>/call capabilityCallSchema → capabilityResultSchema
活动 → 系统 POST <BPOS_CAPABILITY_BASE>/handoff handoffSchema → handoffOutcomeSchema

信封(环境变量)见 ACTIVITY_ENV:taskId · nodeRunId · nodeId · token · base · eventPort。 一个任务节点一个进程:进程知道自己是哪一单的哪一步,不知道图长什么样、别的步是谁。

事件

enter · work-order-reply · work-order-saved · work-order-mail · human-say · timer · control · handoff-refused(现算一份在 SYSTEM_EVENTS)。

每条带 id、按本任务节点内的先后顺序投、至少送到一次——活动用自己的实例状态去重, 系统不重放(§6.2)。每种事件的来处见 SYSTEM_EVENT_SOURCE:发出去的每一个口对着一条回来的路。

名词

工单 4(create · read · write · void)· 对话 2(say · input)· 模型 1 · 业务数据 1(table.read,只读)· 工作持久 4(state · memory 各两个)· 文件 4(get · text · put · info)· 定时 1 · 本步读数 1 · 留痕 1(现算一份在 CAPABILITIES)。

写业务库不在里面(7.0):落业务库只有工单提交一个入口——活动把要落的东西摆进工单的 数据对象、在数据表单的 commit 里声明落到哪,人提交、系统在那一个事务里落定并盖章。 归档同理随落定走(件上标了 archive 的文件格),所以没有单独的归档动作。

发卡也不在里面:对话区没有卡——要人拿个主意、补几格信息,派一张一两格的执行工单; 对象的新建同样只从工单落定来,系统不替活动建对象。 审批不在里面:活动不声明审批、不知道审批、收不到裁决。 邮箱也不在里面:信箱只服务系统的事件规则;沟通工单上的信由人在件下发出、由系统按信头 收回那张单上——活动既不发信、也不收信,只读得到那条往来。

什么改动要升大版本

往 CAPABILITIES / SYSTEM_EVENTS / CAPABILITY_ERRORS 这几个封闭集里减一个值, 对已经打好的活动包是破坏性的——那些包把旧的枚举内联进了 dist/activity.mjs。加一个值 破不破,看这个值从哪一头来:系统答出去的(一种事件、一个拒绝码)加了就破——老包拒收并报 「系统答的形状不对」,而毛病在系统;活动发出来的(一个能力名词)加了不破——老包不认识它, 也永远不会收到它。破坏性的走大版本,其余走小版本。 往事件载荷里加一个字段同样不破(zod 对象默认非严格,多的字段被忽略),走小版本。 分界线不是「改没改契约」,是「老包会不会收到一个它解不出来的东西」——看的是活动包内联的那一份。

清单那一侧收窄不按这条走:清单不在活动包内联校验的那条线上(manifestSchema 是系统在装包那一刻用的尺子), 所以判据换成一条:收窄之后从前跑得起来的包会不会跑不起来。会 → 大版本; 只是把一个本来就用不成的值提前拦下来(拦点从下游挪到机检,并说得更清楚)→ 小版本。 icon 收进图标调色板走的就是后者:调色板外的值从前装得进、机检还全绿,可它建不出活动类型来(建类型 422), 从来没有一个包靠它跑起来过。

5.5.0:enter 载荷加 extraContext(恒有,没填是空串)——往开放的对象里加字段,按上面的判据走小版本;活动清单的 ^5.x 范围都满足。

5.6.0:能力名词加 ledger.reverse(冲销一行台账:打废弃标记、记理由与本步,数字一个不动)、table.read 多一格 retired(不给就是在用行);清单的表声明与列声明多几样注解(表的 text / time / refs,列的 text / measure)。 名词是活动发出来的那一头、注解是清单那一侧只放宽不收窄,两样都不破老包,走小版本。

5.7.0:工单封闭集加第四种 collaborate(协同工单:人带着自己的 AI 做出一份交付物, 执行工单偏人独立完成;同一副表单、同一枚「提交」,分界在谁来干);工单定义加一格可选的 deliverable(只协同有、且必有,指数据结构里一个 file 字段——放行时那一格非空是系统那一道 的固定规则,机检第七查拦漏写 / 错写)。清单那一侧是放宽:从前跑得起来的三种单一个字都不用改; work-order-reply 的结果集一个值都没加(协同与执行同一枚 submitted),所以老包也收不到 任何它解不出来的东西。两条判据都指向小版本。

5.8.0:表单字段的封闭集加第九种 chart(件上一格只读的展示),字段多一格 chart ({ kind, unit?, from? }:画法封闭五种 bar / hbar / line / pie / donut)。两条数据驱动的路: 显式值由活动写(order.create 的初值、order.write 的补丁),值是图表数据 { labels, series: [{ name?, values }] }(每条系列与 labels 等长);派生图写 chart.from, 值从本件那张表格此刻的行现算、数据对象里不存这一格。图表恒为只读(accessOf 对它恒答 read), 不进 rows、不作 decision / deliverable,机检第七查逐条拦(chartIssues 一处判两侧用)。 表的列类型 COLUMN_TYPES 与产出字段 CONTRACT_FIELD_TYPES 一个字都没加——图表不是列、也不是产出。 清单那一侧是放宽:从前跑得起来的八种字段一个字都不用改;活动发出来的那一头没减东西, 老包也收不到任何它解不出来的东西。两条判据都指向小版本。

6.0.0:制品从工单来 + 六格补齐。六条改动,头两条各自就够得上大版本——

  1. 撤制品卡(产品设计 §1.5、附录 B 31)。chat.card 的卡族去 artifact(只剩 decision · elicitation),card-reply.kind 跟着去一个值,artifactArchivePayload 去 kind 与 cardId (只归资料;那一份收严成 strictObject,老包照旧递 kind: 'artifact' 时当场被指名, 而不是把那一格默默丢掉、照 type 归出一份资料来)。两个封闭集各减一个值:卡族是活动 发出来的那一头(减一个破),card-reply.kind 是系统答出去的那一头(加减都破)。 要人认一版草稿的改派验收工单,要人做出一份文件的改派协同工单。
  2. ref 值的形状进契约(收窄)。refValueSchema / refIsEmpty / refKeyOf 从工作台契约 搬进这里(那一侧经 plugin/manifest.ts 那一处接缝再导出),checkValue 多一支 ref: 主键串或 { key, label? },老写法 { 列: 值 } 当场拒并指名。从前它落在 default 分支上, 活动经 order.create / order.write 写老写法一路无声——从前跑得起来的包会跑不起来。
  3. needs.tables 分读写(收窄)。一条可以写成 { address, write?: true };字符串写法恒为 只读。机检第五查核「write 只许标在 master.* 上」(标在自己声明的表或别的域上都 fail), 能力面对没标 write 的外域表拒写并指名。从前靠约定,一次手滑就能让方案侧的包改掉全域 共用的那一行——清单侧的判据同样指向大版本。
  4. 文件格的 archive(加格)。工单定义里 file 字段多一格 archive,指本清单 declares.documents[] 里一个文档类型的代号:放行成立的那个事务里按那个类型归档, 种类随类型。第七查三条(archiveIssues 一处判两侧用):代号要在本清单声明里、 协同单的 deliverable 那一格必须标了 archive 且那一类是制品、非文件格不许标。 CAPABILITY_ERRORS 加 suspended(挂起中调能力面收它,与「这一步已收场」的 node-closed 分开)——系统答出去的封闭集加一个值,本身就是大版本。
  5. measure.unitFrom(加格):度量四选一,单位可按行取自另一列(数量列的单位随料走)。
  6. 列 default(加格):declares.tables[].columns[].default,与主数据那一层的列规格同一格, 落到库上是 DEFAULT、落到屏上是新建弹窗的预填;形不合这一列的由机检第五查当场指名。

活动包要跟的:清单 contract 范围改 ^6.0.0;制品卡那一段改成验收单 / 协同单加一格标了 archive 的文件格;写 master.* 的登记类活动把那张表标上 write: true;ref 那几格改成 主键串或 { key, label }。

6.1.0:协同工单 = 制品卡的替代。6.0 落的是「制品从工单来」的前一半(文件格标 archive、 放行即归档),这一版补另一半——复杂制品不再由活动自己做完请人认,而是派一张协同单、 让执行人带着自己的 MCP host 做出来(产品设计 §1.4 / §1.5 / §3.5、系统设计 §3.1 / §3.4、附录 B 43 / 44)。 活动要把这一步交代清楚,所以多两格、多两条机检;加格与加机检,一个封闭集都没减——小版本:

  1. text.prompt(加格):给 AI 的提示词——执行人的 host 做这一步时喂给它的模型的那段话。 协同单该有(缺了机检警示,不拦激活);别的类型写了也警示(它不上屏、不进取单答复)。
  2. text.references[](加格):制品参照与模版 { field, role: 'example' | 'template' }[]。 field 必须是数据结构里 access: read 的 file 字段(机检拦:不是文件格的话 host 拿不到可读的字节,人能改的话活动给的那一版会被当成待填的格改掉);值由活动在 order.create 时给(文件库里的一份引用)。
  3. 交付物那一格不许写 multiple(加机检):只有一个槽,再交即覆盖(件上换一份、 host 里 desk.deliver_artifact 再交一次都是覆盖,旧的那份留一行工作日志、字节不删)。 多份的话「这一张单的产出是哪一份」在屏上、在 host 里、在放行那一道都答不出来。
  4. 交付物归到的那个文档类型,formats 要落在 DELIVERABLE_FORMATS 之内(加机检): html / markdown / pdf——工作区那一列里渲得开的那三种(产品设计 §3.5「交付物的规格」、 系统设计 §13)。不写 formats(不限)也拦:不限意味着 Word / Excel 也收得下。 这个常量住契约包,机检、服务端(件上传与 desk.deliver_artifact 同一把尺)、前端三处同源。
  5. 活动可在 order.create 时预填交付物槽(自己起的一版草稿当起点):checkValue 对 file 值照旧判形状,没有新的口子。

活动包要跟的:清单 contract 范围改 ^6.1.0(^6.0.0 照样满足,不改也跑得起来); 协同单补 text.prompt,要给参照 / 模版的补 text.references[] 并把那几格标成 access: read; 交付物那一格去掉 multiple、它归到的那个文档类型的 formats 收进三种之内。

6.2.0:引用进输入与表格列 · datetime · 主键串的编解码。第六阶段第一个活动 端到端跑通之后撞出来的几格;全是放宽,一个封闭集都没减——小版本:

  1. 输入 / 产出字段收 ref(CONTRACT_FIELD_TYPES 加一个值):一步的输入常常就是 「哪一条对象」。写成 text 的时候起单弹窗摆的是一个空输入框,人得自己把主键串背出来, 抄错一个字照样收得下——活动拿它读不到行,屏上是「这一步空跑了一趟」而没有一处说得出为什么。 值的形状与件上那一格同一份(refValueSchema);字段上写 ref 指定对象表地址, 那个地址要在 needs.tables 里且是对象表(机检第五查拦)。
  2. 表格的内联列收 ref(新封闭集 FORM_COLUMN_TYPES = 列类型 + ref):一张报价行里的 「哪一颗料」就是这一格。从前只能摊成两列文本自己拼回去,拼不回去一个字也不报错。 人保存与放行按 refValueSchema 判(tableRowGaps 一把尺);列上那个地址归机检第七查。
  3. 列类型加 datetime(COLUMN_TYPES 加一个值):落库 timestamptz,契约里的值是 ISO 8601 带时区的串(checkValue 拒光一个 YYYY-MM-DD、也拒不带时区的时刻)。 date 只写得出哪一天;只有它的时候,一件「几点发生的」只剩两条路——截成一天, 或塞进文本列(从此排不了序、比不了大小、数仓认不出它是时间),两条路都不报错。 台账的业务时间 time 指得到它(一刻本来就含着一天);屏上按业务时区渲。
  4. encodeRefKey / decodeRefKey(加两个函数):主键串 col=val;col=val 的编解码搬进契约包。 从前它只在工作台契约里、活动够不着,于是每个要写引用格的活动自己拼一遍——值里带了 ; = % 的那一条拼出来拆回去就不是原来那一条,而两头都不报错。工作台契约的 encodeRecordKey / decodeRecordKey 改成从这里单向再导出(接缝只此一处,用例钉)。

活动包要跟的:清单 contract 范围改 ^6.2.0(^6.0.0 / ^6.1.0 照样满足,不改也跑得起来); 把“哪一条对象”那几格输入从 text 改成 ref 并补上地址;摸成几列文本的引用列合回一格 ref; 要记「哪一刻」的列从 text 改成 datetime;自己拼主键串的改调 encodeRefKey。

6.3.0:输入契约的文本字段可标 multiline。一步要收的常常是一段话——一封邮件的正文、 一段客户口述、一份要人贴进来的原文。件上那一格(declares.orders[].data.fields)早就有这一格, 输入契约(declares.input.fields[])只有单行那一档:触发弹窗摆的是一个 <input>,人往里贴一段 带换行的正文,框里只看得见最后一行,而换行还在不在值里屏上答不出来。换一个要人贴一段正文起单的 活动都会撞到,所以它是系统的一格。

inputFieldSchema 多一格可选的 multiline(只 text 有,写在别的类型上机检当场指名, 措辞与件上那一格逐字一样——refineMultiline 一把尺两处用);两处触发弹窗(单活动节点的、实践的) 对标了这一格的文本字段渲多行框,值仍是字符串。

放宽,走小版本:清单那一侧多一格可选属性,从前跑得起来的包一个字都不用改;活动发出来的 那几张封闭集(CAPABILITIES / SYSTEM_EVENTS / CAPABILITY_ERRORS)一个值都没动,老包收不到 任何它解不出来的东西。活动包要跟的:清单 contract 范围改 ^6.3.0(^6.x 的老范围照样满足, 不改也跑得起来);要人贴一段正文的那几格输入补上 "multiline": true。

6.4.0:声明的表可以标人读名列 nameColumn。屏上一律印人读名、不印键(产品设计 §7.3): 引到别的表的列、台账的挂靠列,印的是目标那一行的名字(「华芯智能」「人民币」),键降成小字。 哪一列是名只有表的定义者答得出,所以它是声明里的一格:declares.tables[].nameColumn 指本表 columns 里的一列,且是文本或枚举列(一个数字、一个日期当不了「这一行叫什么」)。 台账不必标——一笔账的身份是「哪一天、哪几个键」,没有「它叫什么」。 主数据那一层的人读名列由系统清单给(master.party 是 name、master.part 是 mpn……), 活动引用它们时什么都不用做。

放宽,走小版本:清单那一侧多一格可选属性,从前跑得起来的包一个字都不用改——对象表没标只提示 不拦(机检 warn),只是引到它的列在屏上退回印键。活动包要跟的:清单 contract 范围改 ^6.4.0 (^6.x 的老范围照样满足,不改也跑得起来);每张对象表标上 "nameColumn": "<哪一列是名>"。

7.0.0:工单落定——落业务库只有工单提交一个入口(产品设计 §1.4 / §1.5、系统设计 §2.8 / §3 / §4.5、附录 B 6 / 45 / 47 / 49)。一句话:业务库的写从能力面挪进了工单定义的 commit。 几条改动里任何一条单独就够得上大版本——

  1. 业务数据名词只剩读(封闭集减四个值):撤 ledger.append · ledger.reverse · object.upsert · artifact.archive。活动对业务库只读;要落的东西摆进工单的数据对象、在数据 表单的 commit 里声明落到哪,人提交、系统在同一个事务里落账、办结、冻结、归档并盖章 (任务、节点、工单、提交人、时刻)。归档同理随落定走(文件格的 archive),没有单独的归档动作。
  2. 对话区没有卡(封闭集再减):撤 chat.card 与两张卡的形状、撤事件 card-reply。 要人拿个主意、补几格信息,派一张一两格的执行工单——它有表单、有复核、有冻结、记得到人。 对象的新建同理只从工单落定来,所以 NODE_RUN_STATES 也去掉了 awaiting-object。
  3. 事件加两种(系统答出去的封闭集加值,同样破):work-order-saved(表单声明了 recheckOnSave 的单被人保存了一次,请活动复核一遍)、work-order-mail(沟通工单收到一封回信)。
  4. work-order-reply 多两格:landing(落账摘要,恒有;不写业务库的单与「重做」是 { items: [] })与 by(提交人 { id, name })。活动交出时要带回去的需求号、客户代号从 摘要里取——回头去库里捞一遍的话,捞到的可能是别人同时落下的那一行。
  5. 工单定义 = 数据表单四段 + 一块类型拓展(清单侧收窄):data · interaction · commit · text 四段讲的都是数据对象,四种单共用;这一种单特有的东西写在以类型命名的 那个键下——执行 guide · 验收 acceptance · 协同 artifact(必有)· 沟通 communication (必有)。顶层的 deliverable 挪进 artifact.slot,text 里的 guide / standard / criteria / matters / prompt / references 与 interaction.decision 各归各位, text 只剩 brief · sections · fields。写了不属于本类型的那一块、一份定义写了两块,机检 fail。
  6. interaction 加两格:requiredWhen(带条件的必填——「结论选了退回则原因必填」)与 recheckOnSave。
  7. 两侧共用的纯函数进契约:evalCondition · accessAt / missingOf · planCommit / summarizePlan · formatSerial · mailDraftOf / mailDraftIssues。件上、宿主、服务端三处要 同一个答案,各写一遍必然有一天不一样——而那一天,人是照着预告点的提交。
  8. 顺带:table.read 的 orderBy 收数组(至多四列);chat.say 可带一张本步派过的工单 (屏上多一枚「打开工单」);order.read 的 done 收成有形状的办结段(带 landing),沟通单 另带 mails;导出 FORMAT_EXTENSIONS / formatOfFileName(档次与扩展名一把尺)。

活动包要跟的:清单 contract 范围改 ^7.0.0;每一处 cap.append / cap.upsert / cap.reverse / cap.archive 都改成一条 commit 落账项(值先摆进件上一格只读的格,人看得见); 发卡的那几处改派轻工单;text 里那六格与 deliverable 挪进各自的类型拓展;读 work-order-reply 的地方改从 landing 里取键。SDK 同版(@bpos/activity-sdk 7.0.0),信封多一格业务时区 (Envelope.timezone,缺席答 'UTC',配一个 dayIn(zone, at))。

7.1.0:落账项落得进「同域的表」 —— 机检那一句放宽到设计的口径(系统设计 §8.2、§3.8; 附录 B 27)。从前这一道要求落账项的 table 在本清单 declares.tables 里,而落定那一道 (server/src/modules/desk/landing.ts::writableAt)判的是域相同:一个活动拆成两包时, 第二包写的正是第一包建的那张表——两包在同一个域里、本来就是同一件事的两段。两句话不一样的代价是 装得上、机检全绿的包在人按下提交的那一刻被拒,而那时候人已经把一张单填完了。 写得了的从此是:同域的表(本清单声明的,或同域别的活动建的)与在 needs.tables 里标了 write: true 的主数据表;别的域的表永远只读,一个字都没放松。域从本清单声明的表推 (清单里没有子系统代号),一张表都不声明的活动因此只剩主数据那一档。

放宽,走小版本:机检少拦一种清单,从前跑得起来的包一个字都不用改,一条新 warn 也没有; 封闭集、载荷、答复形状一律没动,老包收不到任何它解不出来的东西。活动包要跟的:没有——要用这一档 (落账到同域别的活动建的表)的包,清单 contract 范围写 ^7.1.0。

8.0.0:业务库四层——对象 · 单据 · 台账 · 文档(产品设计 §1.4;系统设计 §3.8 / §6.1 / §8.2; 附录 B 53 · 54 · 56)。从前叫 ledger 的「只增不改的事实行」整体改叫 voucher(单据), ledger 换成新语义 「按主键一行的状态」。八条改动,头两条各自就够得上大版本:

  1. TABLE_KINDS 三个值(object · voucher · ledger):一个封闭集改了一个值的含义—— 照 7.x 写的包声明 kind: 'ledger' 的表在 8.0 里是另一种东西,数仓按 kind = 'ledger' 建事实表 会建错。这一条单独就是大版本。
  2. COMMIT_ACTIONS 五个值:加 post(过账:按主键找到那一行,没有就建;set 置值、 add / sub 增减,一句里原子地做)。动作配得上种类三分:对象 create / update、 单据 append / reverse、台账 post——7.x 的「append / reverse 落到 ledger 上」 在 8.0 里是一条 fail。
  3. 落账项加 add / sub(只在 post 项里;同一列在 set / add / sub 里至多一次; 目标是数值列、来源是数值),并加一条 无单据不过账:有 post 的表单至少有一项 append 或 reverse。
  4. set 改成可缺:落账只写例外,没写的列按同名直落解(§3.8)——7.x 那句「至少写一格」 逼着作者把一个本来解得出来的列再抄一遍,而抄错一个字就是一条静静落错的列。
  5. 声明多三格:单据的 source: { kind, no }(源单那两列,都是本表的文本列)、台账数值列上的 nonNegative,以及挂靠 attachedTo 的三种情形——单体挂单头(必填)· 单头挂一张对象表(可不挂)· 台账挂一张对象表或单据表(必挂);谁都不许挂到台账上。time 与 source 只属于单据, nonNegative 只属于台账的数值列,nameColumn 对象表该写 · 单据表可写可不写 · 台账不许写 (6.4.0 那句「台账不必标」在 8.0 里成了一条 fail)。
  6. 引用的目标放宽到单据表:件上的 ref、输入 / 产出的 ref、表格内联的 ref 列都指得到 对象表与单据表(挑一条对象,或挑一张源单);台账仍不作引用与挂靠的目标——一行状态不是身份。 表上的 refs 注解没放宽:它的目标只有对象表,单据之间靠 source 连。
  7. ref 来源的 column 改成可缺:不带就是整把主键串(记源单号那一列用的就是它); 它是一串字,所以只落得进文本列。
  8. 顺带:parseAddresses 认全角的分号与逗号(中文输入法下打出来的就是它们;不认的话整串 当成一个地址,屏上那一句「这几个不成形」指着人打对了的那一串)。

破坏性,走大版本:一个封闭集换了一个值的含义、另一个封闭集加了值且动作与种类的对应收紧、 两条新 fail(台账标 nameColumn、台账写 time)——7.x 里声明了表的包装进 8.0 的系统会被机检点名。 活动包要跟的:清单 contract 范围改 ^8.0.0;把当事实行用的 kind: 'ledger' 改成 'voucher'; 台账上的 nameColumn 与 time 撤掉;要过账的表单补 post 项与 add / sub,并确保同一张单里 记了单据。SDK 同版(@bpos/activity-sdk 8.0.0)。

机检加一条 warn 也算改了清单侧的尺子:包的 build.ts 要求 0 warn(一份自己都不干净的清单不该打成包), 所以一条新 warn 会让一个字都没改的包当场红——6.4.0 的 nameColumn 就这样撞红过 A1 1.1.0。 升版的那条车道因此要把仓里已有的包各 build 一遍(活动仓 BPOS-Activity/ 的与本仓 activities/ 的), 撞红的那几个包一并改到:这是升版自己的尾,收不掉就别升。

拒绝

业务上的拒绝用 HTTP 200 承载(ok: false + error + message + hint)——它不是传输错误, 是系统对这次调用的回答,活动要读得到才知道下一步做什么。真正的 4xx 只有两种: 令牌不对 401、这一步已交出或这一单已挂起 409。码是封闭集,见 CAPABILITY_ERRORS。

Dependencies

Dependencies

ID Version
zod 4.4.3

Development Dependencies

ID Version
@types/node ^24.0.0
tsx ^4.19.0
typescript ^5.6.0
Details
npm
2026-09-20 10:55:06 +08:00
0
UNLICENSED
123 KiB
Assets (1)
Versions (36) View all
13.13.0 2026-10-25
13.10.0 2026-10-23
13.9.0 2026-10-21
13.8.0 2026-10-20
13.7.0 2026-10-20