{"_id":"@byfire-dev/publication-bridge-contract","_rev":"3-b41505bc09876924cf336bb6092ab91a","name":"@byfire-dev/publication-bridge-contract","dist-tags":{"latest":"3.2.0"},"versions":{"3.0.0":{"name":"@byfire-dev/publication-bridge-contract","version":"3.0.0","license":"MIT","_id":"@byfire-dev/publication-bridge-contract@3.0.0","maintainers":[{"name":"sanqianyuejia","email":"lixm@byfire.ai"}],"homepage":"https://github.com/byfire-dev/vibe-market#readme","bugs":{"url":"https://github.com/byfire-dev/vibe-market/issues"},"dist":{"shasum":"c9bdfac3b797cbf78e143183840e1d004180be72","tarball":"https://registry.npmjs.org/@byfire-dev/publication-bridge-contract/-/publication-bridge-contract-3.0.0.tgz","fileCount":116,"integrity":"sha512-4RbDoi3i0mUI/AItUTnIqLa595NWDwn25tV1xpdngTTSFxjfKS+uLGjwxPGT4V9m99xAz+R9bn/i+lOeL602Sw==","signatures":[{"sig":"MEUCIEdI9R5Q/YAQR1iBCWgqO9ACL9h/vgtI/j+gKhpt6BbfAiEArPmeOyWVgT4mu/WZjRXLYV071I/0Vl5SY1hU3B6+7fg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5345012},"main":"./dist/cjs/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./v3":{"import":{"types":"./dist/v3/index.d.ts","default":"./dist/v3/index.js"},"require":{"types":"./dist/cjs/v3/index.d.ts","default":"./dist/cjs/v3/index.js"}},"./v3/testing":{"import":{"types":"./dist/v3/testing.d.ts","default":"./dist/v3/testing.js"},"require":{"types":"./dist/cjs/v3/testing.d.ts","default":"./dist/cjs/v3/testing.js"}},"./package.json":"./package.json"},"gitHead":"5435d1d3a126e558c10354b3198d988f96f888e7","private":false,"scripts":{"lint":"eslint src --max-warnings 0","test":"vitest run","build":"node scripts/build.mjs","prepack":"npm run build","typecheck":"tsc --noEmit","pack:check":"pnpm build && node scripts/pack-smoke.mjs","publish:check":"npm run typecheck && npm run lint && npm test && npm run pack:check","prepublishOnly":"npm run publish:check"},"_npmUser":{"name":"sanqianyuejia","email":"lixm@byfire.ai"},"repository":{"url":"git+https://github.com/byfire-dev/vibe-market.git","type":"git","directory":"packages/publication-bridge-contract"},"_npmVersion":"10.9.2","description":"Versioned, runtime-validated publication Bridge contract shared by VibeMarket and Wechatsync.","directories":{},"sideEffects":false,"_nodeVersion":"22.17.0","dependencies":{"zod":"^3.25.76"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.7","typescript":"^5.7.3","@types/node":"^22.10.5"},"_npmOperationalInternal":{"tmp":"tmp/publication-bridge-contract_3.0.0_1785646172726_0.5137272177661838","host":"s3://npm-registry-packages-npm-production"}},"3.1.0":{"name":"@byfire-dev/publication-bridge-contract","version":"3.1.0","license":"MIT","_id":"@byfire-dev/publication-bridge-contract@3.1.0","maintainers":[{"name":"sanqianyuejia","email":"lixm@byfire.ai"}],"homepage":"https://github.com/byfire-dev/vibe-market#readme","bugs":{"url":"https://github.com/byfire-dev/vibe-market/issues"},"dist":{"shasum":"73f3b0d88885a2fdb699d3edb90dc51b2e13cc1e","tarball":"https://registry.npmjs.org/@byfire-dev/publication-bridge-contract/-/publication-bridge-contract-3.1.0.tgz","fileCount":116,"integrity":"sha512-fC2Ogp2jgGnLNU+pd2KEWDKDtGDlRIFonWRNbr0A6bDW+rzPjjhZrhCtzrQySmPI/W886NkPr3Z03KFnVLM8sQ==","signatures":[{"sig":"MEUCIAsiNzmah+RtZrKVDlf5oTrdVzdjO0H8acEXbCRpXclAAiEA6VIToBd9ikI31rHHmp8HBbjLrx90wjUmFmnMGJsQG5A=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":5765042},"main":"./dist/cjs/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./v3":{"import":{"types":"./dist/v3/index.d.ts","default":"./dist/v3/index.js"},"require":{"types":"./dist/cjs/v3/index.d.ts","default":"./dist/cjs/v3/index.js"}},"./v3/testing":{"import":{"types":"./dist/v3/testing.d.ts","default":"./dist/v3/testing.js"},"require":{"types":"./dist/cjs/v3/testing.d.ts","default":"./dist/cjs/v3/testing.js"}},"./package.json":"./package.json"},"gitHead":"c1da8fa7f26e2678c8634c80bdbdcc95b668ca9c","private":false,"scripts":{"lint":"eslint src --max-warnings 0","test":"vitest run","build":"node scripts/build.mjs","prepack":"npm run build","typecheck":"tsc --noEmit","pack:check":"pnpm build && node scripts/pack-smoke.mjs","publish:check":"npm run typecheck && npm run lint && npm test && npm run pack:check","prepublishOnly":"npm run publish:check"},"_npmUser":{"name":"sanqianyuejia","email":"lixm@byfire.ai"},"repository":{"url":"git+https://github.com/byfire-dev/vibe-market.git","type":"git","directory":"packages/publication-bridge-contract"},"_npmVersion":"10.9.2","description":"Versioned, runtime-validated publication Bridge contract shared by VibeMarket and Wechatsync.","directories":{},"sideEffects":false,"_nodeVersion":"22.17.0","dependencies":{"zod":"^3.25.76"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.7","typescript":"^5.7.3","@types/node":"^22.10.5"},"_npmOperationalInternal":{"tmp":"tmp/publication-bridge-contract_3.1.0_1785845414532_0.9786744732370931","host":"s3://npm-registry-packages-npm-production"}},"3.2.0":{"name":"@byfire-dev/publication-bridge-contract","version":"3.2.0","description":"Versioned, runtime-validated publication Bridge contract shared by VibeMarket and Wechatsync.","private":false,"license":"MIT","repository":{"type":"git","url":"git+https://github.com/byfire-dev/vibe-market.git","directory":"packages/publication-bridge-contract"},"type":"module","sideEffects":false,"engines":{"node":">=20.0.0"},"main":"./dist/cjs/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./v3":{"import":{"types":"./dist/v3/index.d.ts","default":"./dist/v3/index.js"},"require":{"types":"./dist/cjs/v3/index.d.ts","default":"./dist/cjs/v3/index.js"}},"./v3/testing":{"import":{"types":"./dist/v3/testing.d.ts","default":"./dist/v3/testing.js"},"require":{"types":"./dist/cjs/v3/testing.d.ts","default":"./dist/cjs/v3/testing.js"}},"./package.json":"./package.json"},"scripts":{"build":"node scripts/build.mjs","typecheck":"tsc --noEmit","lint":"eslint src --max-warnings 0","test":"vitest run","pack:check":"pnpm build && node scripts/pack-smoke.mjs","publish:check":"npm run typecheck && npm run lint && npm test && npm run pack:check","prepublishOnly":"npm run publish:check","prepack":"npm run build"},"dependencies":{"zod":"^3.25.76"},"devDependencies":{"@types/node":"^22.10.5","typescript":"^5.7.3","vitest":"^4.1.7"},"_id":"@byfire-dev/publication-bridge-contract@3.2.0","gitHead":"8f1a8e07311835cab9f5ac2e23d8778b19c8c616","bugs":{"url":"https://github.com/byfire-dev/vibe-market/issues"},"homepage":"https://github.com/byfire-dev/vibe-market#readme","_nodeVersion":"22.17.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-7MZVPR8ubZxW8C+ny8fy+2Gexmzpazwy4GTVXRSUNPn4OUkRZ6W++JTvvhMoSvQcVPwznOOQBt0oaiJEM28TFQ==","shasum":"e6431dee0f92b3f29a840a273e8fab30d74bd9c7","tarball":"https://registry.npmjs.org/@byfire-dev/publication-bridge-contract/-/publication-bridge-contract-3.2.0.tgz","fileCount":124,"unpackedSize":6532956,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDNHdw0kSvpPCG8WwkyRaJTJa8IQfxf9p5xSSstn3+wLAiEAmW91oVrsjyOJ38wy6b0hEOVLL8hISfgLqme6e1BKolQ="}]},"_npmUser":{"name":"sanqianyuejia","email":"lixm@byfire.ai"},"directories":{},"maintainers":[{"name":"sanqianyuejia","email":"lixm@byfire.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/publication-bridge-contract_3.2.0_1786360831551_0.9408768389760889"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-02T04:49:32.614Z","modified":"2026-08-10T11:20:32.125Z","3.0.0":"2026-08-02T04:49:32.886Z","3.1.0":"2026-08-04T12:10:14.729Z","3.2.0":"2026-08-10T11:20:31.706Z"},"bugs":{"url":"https://github.com/byfire-dev/vibe-market/issues"},"license":"MIT","homepage":"https://github.com/byfire-dev/vibe-market#readme","repository":{"type":"git","url":"git+https://github.com/byfire-dev/vibe-market.git","directory":"packages/publication-bridge-contract"},"description":"Versioned, runtime-validated publication Bridge contract shared by VibeMarket and Wechatsync.","maintainers":[{"name":"sanqianyuejia","email":"lixm@byfire.ai"}],"readme":"# `@byfire-dev/publication-bridge-contract`\n\nVibeMarket 与 Wechatsync 共享的发布 Bridge 契约包。它提供带运行时校验的 Zod Schema、由 Schema 推导的 TypeScript 类型、协议版本常量以及跨仓契约测试 fixture。npm 产物同时提供 ESM、CommonJS 及各自可消费的声明文件。\n\n包版本是 `3.2.0`，最新 Bridge v3 wire `contractVersion` 是 `3.2`，并精确兼容 `3.0` 与 `3.1`。两者相关但不相等：包版本变化不应迫使 wire 协议版本变化。\n\n本包以 public access 发布到 npmjs，供不同仓库和开发设备消费。`prepublishOnly` 会在发布前强制执行类型检查、lint、测试和 tarball 消费验证；`publishConfig` 将目标固定为 npmjs public registry，避免 scoped package 首发时误用 restricted access。\n\n## 安装与导入\n\n建议在生产消费者中固定精确包版本，确保 VibeMarket 与 Wechatsync 使用同一份 wire Schema：\n\n```powershell\npnpm add --save-exact @byfire-dev/publication-bridge-contract@3.2.0\n```\n\n```ts\nimport { PUBLICATION_BRIDGE_CONTRACT_VERSION } from '@byfire-dev/publication-bridge-contract';\nimport {\n  PublicationBridgeV3RequestSchema,\n  type PublicationBridgeV3Request,\n} from '@byfire-dev/publication-bridge-contract/v3';\n```\n\n`/v3/testing` 只提供跨仓契约测试 fixture，不是生产数据入口。\n\n## 契约范围\n\n本包只提供独立、版本化的契约单一真源，不接入浏览器运行时，也不替换现有 Bridge v2：\n\n- 不声明或注入 `window.$syncer`；\n- 不实现 callback transport、超时、重试或会话管理；\n- 不接入发布 reducer、服务端持久化、Placement、引用归因或绩效；\n- 不实现平台网络 I/O、URL 归一化或消费者侧业务投影；\n- 不删除或修改 Bridge v2。\n\nv3 上线期间，v2 feature detection、fallback、遥测和最终退场条件均由消费者运行时负责。v3 协商或调用失败不得由契约包隐式降级，也不得被转换成业务成功、`NOT_FOUND` 或可安全重发。\n\nv3 固定以下 command 集合：`bridge.negotiate`、`bridge.cancel`、`accounts.resolve`、`publication.publishDraft`、`publication.getOperation`、`publication.inspect`、`publication.openDraft`。`PUBLICATION_BRIDGE_V3_COMMAND_POLICIES` 是 command、所需 Bridge capability、副作用级别和重放规则的机器可读单一真源。\n\n## 五种版本概念\n\n以下版本必须独立演进，不得相互冒充：\n\n1. **package version**：本包的内部版本，例如 `3.2.0`。遵循 SemVer，描述包产物兼容性。\n2. **wire `contractVersion`**：跨 Bridge 传输的协议版本，当前支持 `3.0`、`3.1` 与 `3.2`，协商时选择双方支持的最高精确版本。只有 wire 兼容边界变化时才升级。\n3. **`extensionVersion`**：当前 Wechatsync 扩展构建版本，用于诊断与采用率遥测，不代表协议兼容性。\n4. **producer `adapterVersion`**：扩展中实际执行平台 I/O 的平台适配器版本，与该适配器声明的 capability 快照绑定。\n5. **consumer VibeMarket `adapterVersion`**：VibeMarket 中负责信任校验和业务投影的平台适配器版本；它不进入 Bridge wire、不由扩展声明，也不能用 producer `adapterVersion` 替代。消费者应自行持久化对应的 consumer adapter snapshot。\n\ncapability snapshot 是一次协商或操作发生时的能力事实，而不是额外的版本号。全局 Bridge capability 只描述当前 negotiated wire 上可调用的方法；平台 capability 来自实际注册的 producer adapter。空 capability 或 adapter 集合用于真实表达“已协商 v3，但当前没有启用命令或注册平台”，不得用伪造能力填充。消费者最终可用能力仍须取服务端 rollout、Bridge 声明和 consumer adapter 能力的交集。wire `3.2` 的 runtime 必须声明 `bridge.request.cancel`，wire `3.0` 与 `3.1` 的 runtime 必须不声明该 capability，避免版本声称与可调用方法互相矛盾。\n\n`selectPublicationBridgeContractVersion()` 只会从本包实际支持的 wire 版本中选择双方精确交集。双方都声称支持但本包 Schema 尚未实现的版本不会被选中。\n\n`publication.inspect` 在 wire `3.1` 中可携带可选的 `publicationWindow`：`publishedNotBefore` 必须是带时区的 ISO datetime，`basis` 固定为 `DISPATCH_STARTED_AT`。成功 result 必须完整回显该窗口。wire `3.0` 严格拒绝这一字段。\n\nwire `3.2` 要求每个 `publication.inspect` request 在 envelope 顶层携带 `deadlineAt`，其值必须是带时区的 ISO datetime。`3.0` 与 `3.1` 严格拒绝该字段。每个执行层从绝对 deadline 重新计算剩余预算，不在 wire 中传递可被逐层重置的 `timeoutMs`。\n\nwire `3.2` 增加 `bridge.cancel` 与 `bridge.request.cancel` capability。取消 request 自身的 `operationId` 必须使用目标 inspection 的 operation id；payload 用 `targetRequestId`、固定的 `targetCommand: 'publication.inspect'` 和 `CALLER_ABORTED | DEADLINE_EXCEEDED` reason 精确定位目标。成功 result 完整回显目标和 reason，并返回 `CANCELLED | ALREADY_CANCELLED | ALREADY_TERMINAL` disposition。跨端契约测试必须使用 `PublicationBridgeV3InspectionCancellationExchangeSchema` 同时校验目标 inspect request、cancel request 和 cancel response；该 Schema 会复用完整 command request 约束，目标 `3.2` inspect 缺少 `deadlineAt` 时同样拒绝，不能只校验基础 inspect shape 或后两个 envelope。消费端 transport 对 `3.2` inspect 必须返回可取消 handle；handle 只有在同步发出上述关联 `bridge.cancel` 后才可报告成功，缺失 handle 或未发出取消都必须按 transport failure 终结，不能退化为仅在页面本地停止等待。取消是幂等的，只适用于只读 inspection，不得用于推断发布写操作已经停止或可以安全重试。`3.0` 与 `3.1` 严格拒绝 `bridge.cancel`，也不得声明 `bridge.request.cancel`。\n\n## 单一真源\n\n- 所有跨仓 wire payload 都必须由本包的 Zod Schema 定义；导出的 TypeScript 类型必须通过 `z.infer` 推导。\n- VibeMarket 和 Wechatsync 不得再次手写同名 Schema、枚举或响应联合。\n- 两端必须使用 `@byfire-dev/publication-bridge-contract/v3/testing` 提供的相同 fixture 执行契约测试。\n- 消费者可以在 Schema 校验之后施加更严格的账号、URL、平台身份和业务投影校验，但不得放宽 wire 契约。\n- 根入口只提供稳定公共 API；版本化 API 从 `./v3` 导出，测试数据从 `./v3/testing` 导出。\n\n跨仓消费者必须固定到同一已发布版本，不能复制 Schema 或维护平行定义。包升级与 wire 协议升级必须分别评估并显式验证兼容性。\n\n## 安全边界\n\nBridge 返回值始终是不可信输入。契约 Schema 应遵循以下规则：\n\n- 边界对象使用严格对象，拒绝未知字段；\n- 每个外层消息都携带固定 `namespace: 'byfire.publication-bridge'` 和 `direction: REQUEST | RESPONSE | EVENT`，避免与页面中的其他 `postMessage` 混淆；\n- 所有文本、数组、URL 和错误信息都有显式上限；\n- 标题、摘要、键和值域文本拒绝控制字符，正文允许换行但拒绝 NUL，保证边界数据可安全持久化；\n- URL 只允许无凭证、无控制字符的 HTTP/HTTPS 地址；\n- `draftReference` 与 `platformPostId` 只能使用受限的 opaque identifier 字符集，不能携带编辑器 URL、查询参数或认证 token；\n- 成功与失败使用判别联合，失败不得伪装成空成功；\n- `contractVersion`、`operationId`、`requestId`、平台、账号和 adapter snapshot 必须在请求与响应之间一致；\n- 每个协商后的成功、失败响应或事件都携带实际执行时的 producer runtime/adapter/capability snapshot；发布 operation 内的 `runtime` 是首次执行时的不可变历史，result/event 顶层 `runtime` 是本次查询、幂等重放或事件投递的当前执行环境，二者不得混作能力授权；同一 negotiated session 的事件流不得中途更换 runtime，能力或 adapter 变化后必须重新协商 session；\n- 包内运行时代码只依赖 `zod` 和本地纯模块，不得导入 `node:*`、Prisma、React、Next.js、Sentry 或任何仓库私有运行时包。\n\ncapability 使用受限的 namespaced string，以便扩展能声明未来能力；未知 capability 只允许安全传输，消费者必须忽略它，并且只对本包导出的 known capability 与服务端 rollout、消费侧 adapter 能力取交集。未知值绝不能自动启用功能。\n\n`accounts.resolve` 以平台和可选 `expectedExternalAccountId` 为目标。`ACCOUNT_MISMATCH` 必须由一个不同的预期账号锚定；`UNAVAILABLE` 可以明确表示尚无对应 adapter，不能为了满足 Schema 伪造 adapter snapshot。\n\n公开地址不是文章身份。`publication.inspect` 中的 `publicUrl` 只作为访问提示，必须伴随由平台规则归一化得到的 `publicIdentityKey`；result 必须回显完整请求 locator，每条 observation 还必须用 `matchedLocator` 锚定请求中的一个稳定 locator，所有显式返回的 post、draft 或 public identity 也必须与该关联一致。公开观察和在线访问证据回传同一身份键。这样 `https://www.sohu.com/a/...` 与 `https://m.sohu.com/a/...` 可以在原始 URL 不相等时证明为同一篇文章，同时请求文章 A 不能用文章 B 的发布、待审、拒绝或删除结果冒充。Schema 只负责携带和关联身份键；两端仍须使用平台描述符的同一归一化算法从 URL 重新计算，不能盲信对端回传值。\n\n`PUBLISHED + CONFIRMED` 只能来自公开页面证据；公开访问受阻时，`PUBLISHED + BLOCKED_BY_PLATFORM` 必须另有 authenticated page 或 published list 证明。403、反爬页或登录墙本身不构成“已发布”的公开证据。\n\n`tsconfig.json` 显式清空 Node 类型并只启用 Web 标准库，使 `process`、`Buffer` 等 Node 全局在契约源码中无法通过类型检查。\n\n## 标识与重放规则\n\n- `operationId` 标识一次用户级操作，用于丢弃上一代异步回调；\n- `requestId` 标识一次具体 Bridge 调用，用于请求与响应关联；\n- `idempotencyKey` 只用于可能产生平台写入的发布请求；同一键与相同规范化 payload 返回既有 operation snapshot，同一键与不同 payload 返回 `publication.idempotency-conflict`；\n- `payloadDigest` 是 `sha256:` 加 64 位小写十六进制摘要。双方必须对 `canonicalizePublicationBridgeV3PublishPayload()` 返回的 UTF-8 字符串重新计算并比对，不能只信任来包中的摘要；\n- 幂等重放请求可以使用新的调用方 `operationId`，response envelope 回显新的 `operationId` 以关联本次调用，但 `REPLAYED` result 保留首次写入的原始 operation snapshot；当前 responder runtime 单独返回，扩展升级不得篡改历史 snapshot；\n- 只读查询可以在同一 `operationId` 下使用新的 `requestId` 重新发起，但不能把 `requestId` 或 `operationId` 当作发布幂等键；\n- 发布等可能产生外部写入的操作，一旦进入 dispatched 或结果未知状态，不得自动再次提交；\n- `ACCEPTED` operation 的全部 target 必须仍处于 `QUEUED + NOT_DISPATCHED`；一旦开始派发即进入 `RUNNING`；\n- `FAILED + DISPATCHED` 只表示 adapter 已取得明确平台失败终态；`TIMEOUT`、`TRANSPORT`、`UNKNOWN` 等派发后不确定性必须进入 `OUTCOME_UNKNOWN`；\n- `publication.publishDraft` 的失败 envelope 只允许表示 `NOT_DISPATCHED`；一旦可能已写入平台，必须返回 operation snapshot 中的 `OUTCOME_UNKNOWN`，不能用普通失败 envelope 隐去不确定性；\n- `OUTCOME_UNKNOWN` 必须进入人工核对或安全结算路径，不能转换为可重试失败；\n- capability 缺失、版本不兼容或响应校验失败时必须 fail closed。\n\n## 构建与验证\n\n```powershell\npnpm --filter @byfire-dev/publication-bridge-contract typecheck\npnpm --filter @byfire-dev/publication-bridge-contract lint\npnpm --filter @byfire-dev/publication-bridge-contract test\npnpm --filter @byfire-dev/publication-bridge-contract build\npnpm --filter @byfire-dev/publication-bridge-contract pack:check\npnpm --filter @byfire-dev/publication-bridge-contract publish:check\n```\n\n发布产物只包含 `dist/`、本 README、MIT `LICENSE` 与 npm 自动包含的 `package.json`；烟测结束后会删除临时 tarball。本包依据 MIT License 开放使用、修改和再分发，分发时须保留许可证与版权声明。\n","readmeFilename":"README.md"}