From 6cf77bc7506d1b89afc18e52645e9f010164d554 Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Mon, 19 Oct 2026 15:58:30 +0800 Subject: [PATCH 1/5] =?UTF-8?q?docs(twitter):=20=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E5=BD=92=E6=A1=A3=E6=8E=A5=E5=85=A5=E5=A5=91=E7=BA=A6=E5=B9=B6?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=20JWT=20=E5=AF=BF=E5=91=BD=E4=B8=8A=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 统一 User/Post/Media 原生信息、受管关系、旧记录过渡与媒体按需读取的跨分发语义 - 记录 x-monkey 的 JWT Cookie 连接、默认七天寿命及自动续签边界 - 将 JWT 签发默认值与协议准入分离,并更新共享契约导航 --- 20-product-tdd/cross-unit-contracts.md | 4 + .../peer-database-runtime-contract.md | 15 +-- ...emantic-retrieval-and-peer-capabilities.md | 4 +- 20-product-tdd/twitter-archive-contract.md | 92 +++++++++++++++++++ docs/index.md | 1 + 5 files changed, 106 insertions(+), 10 deletions(-) create mode 100644 20-product-tdd/twitter-archive-contract.md diff --git a/20-product-tdd/cross-unit-contracts.md b/20-product-tdd/cross-unit-contracts.md index 9b77f48..63d540e 100644 --- a/20-product-tdd/cross-unit-contracts.md +++ b/20-product-tdd/cross-unit-contracts.md @@ -33,6 +33,10 @@ Record durable data and behavior contracts that span more than one unit reposito - Registry owns hosting and executable API details; authors own site content and structure. Documentation does not become an installable Distribution or alter Host lifecycle authority. +## Twitter 归档信息与接入契约 + +[Twitter 归档信息与接入契约](twitter-archive-contract.md)拥有 `inkcre/twitter` 各 Distribution 共同使用的 User/Post/Media 原生信息、Resolver 与关系含义、旧帖子过渡,以及 x-monkey 协议的 JWT 会话和媒体按需读取边界。各 Unit 保留自己的 HTTP 注册、持久化实现、采集适配与界面代码。 + ## Info-Base Ownership Contract - Collection, organization, application, graph authority, resolver/storage composition, and diff --git a/20-product-tdd/peer-database-runtime-contract.md b/20-product-tdd/peer-database-runtime-contract.md index dca6b48..434cc4c 100644 --- a/20-product-tdd/peer-database-runtime-contract.md +++ b/20-product-tdd/peer-database-runtime-contract.md @@ -103,20 +103,21 @@ The shared browser-to-database and browser-to-runtime token contract is: - audience: required and exactly `inkcre-api`; - issued-at (`iat`): required; - expiry (`exp`): required; -- maximum lifetime: 24 hours; - signature secret: runtime-owned and at least 32 bytes. -A signer may move `iat` a small, bounded amount into the past to tolerate ordinary clock skew -between independently deployed Peers and protocol runtimes. It must derive `exp` from that adjusted -`iat`, so the allowance never increases the 24-hour maximum token lifetime. Clock-skew handling -belongs to the signing boundary; database queries and domain callers do not retry or rewrite tokens -individually. +`iat` 与 `exp` 必须是有效数值时间,`exp` 必须晚于 `iat`;接收端校验允许的未来 `iat` 时钟偏差和实际过期时间。协议不设置 `exp - iat` 的最大值,也不将某个部署的签发默认值作为准入上限。 + +签发者拥有自己的默认有效期与配置方式。服务端签发默认值由环境配置,配置值必须是正整数;默认值只影响以后签发的 JWT,降低默认值不会撤销尚未过期的既有凭据。静态客户端的默认值属于该签发者的策略,不从数据库准入合同派生。 + +签发者可以将 `iat` 向过去调整一个有界的小幅度,以容忍独立部署的 Peer 与协议运行时之间的普通时钟偏差,并从调整后的 `iat` 计算 `exp`。时钟偏差处理属于签发边界;数据库查询和业务调用者不逐个重试或改写 token。 PostgREST and native HTTP runtimes validate the same claim vectors. A missing, malformed, -expired, overlong, wrong-secret, wrong-role, wrong-issuer, or wrong-audience token is denied. +expired, wrong-secret, wrong-role, wrong-issuer, or wrong-audience token is denied. The contract does not assign secret custody to `impl-py`; each deployment supplies the same secret independently to the runtimes that validate it. +Extension 可以为同类 JWT 定义有签名保护的用途声明和续签条件,但不能据此声称缩小原有 Peer 权限。Twitter 归档连接的传输、签发默认值和自动续签见 [Twitter 归档信息与接入契约](twitter-archive-contract.md)。 + ## Artifact And Environment Contract - The core database runtime is published as an OCI image addressable by immutable digest. diff --git a/20-product-tdd/semantic-retrieval-and-peer-capabilities.md b/20-product-tdd/semantic-retrieval-and-peer-capabilities.md index 0242b53..654829f 100644 --- a/20-product-tdd/semantic-retrieval-and-peer-capabilities.md +++ b/20-product-tdd/semantic-retrieval-and-peer-capabilities.md @@ -145,9 +145,7 @@ The first admitted exact capability IDs are: ## Runtime Authentication And Advertisement -- Peer HTTP uses the shared `HS256` token contract with role `authenticated`, issuer - `inkcre-peer`, audience `inkcre-api`, required `iat`/`exp`, a 24-hour maximum lifetime, and - deployment-owned secret material of at least 32 bytes. +- Peer HTTP 使用 [Peer Database Runtime Contract](peer-database-runtime-contract.md#jwt-contract) 的共享 `HS256` JWT:role 为 `authenticated`,issuer 为 `inkcre-peer`,audience 为 `inkcre-api`,必需 `iat`/`exp`,部署持有至少 32 字节的签名秘密。签发默认有效期属于签发者配置,接收端不把它作为最大寿命。 - A capability is advertised only after its inbound is registered and routable. Withdrawal precedes runtime unmount/close. Ordinary Peer-row updates do not imply liveness. - The deployment owns each Peer identity and runtime config, including the public base URL diff --git a/20-product-tdd/twitter-archive-contract.md b/20-product-tdd/twitter-archive-contract.md new file mode 100644 index 0000000..383a45a --- /dev/null +++ b/20-product-tdd/twitter-archive-contract.md @@ -0,0 +1,92 @@ +# Twitter 归档信息与接入契约 + +本契约由 `inkcre/twitter` 拥有,约束 Python 与 Web Distribution 共同写入和解释的原生信息、关系及 x-monkey 接入语义。持久信息属于共享 info-base;采集入口或执行 Peer 停止后,信息仍可由其他具备相应能力的 Peer 使用。各 Unit 自己拥有持久化查询、事务实现、HTTP 注册、采集适配和界面实现。 + +## 原生信息与身份 + +x-monkey 兼容基线为 `v0.2.0` / `0fe02c7f291bbdc48a6376bc30d8a98f63e94136`,完整 wire 字段以该版本的 [archive/model.ts](https://github.com/steven-vvv/x-monkey/blob/0fe02c7f291bbdc48a6376bc30d8a98f63e94136/src/archive/model.ts) 为依据。三类独立实体通过 ID 引用彼此;同一种实体的原生 ID 决定合并身份,不能使用 handle、显示名或 JavaScript 数字替代。 + +| 原生实体 | Resolver | 完整记录的必需字段 | 保留的信息 | +| --- | --- | --- | --- | +| User | `extensions.twitter.user.v1` | `id`、`handle`、`name` | 作者资料、简介富文本、来源链接、账号属性,以及逐项计数和观察时间。 | +| Post | `extensions.twitter.tweet.v2` | `id`、`authorId`、`createdAt` | 正文富文本、长文结构、作者与上下文 ID、媒体顺序、卡片、投票、地点、计数和其他已捕获源事实。 | +| Media | `extensions.twitter.media.v1` | `id`、`type`、`url` | 图片或封面 URL、尺寸、alt、视频 variants、来源 ID、可用性及其他已捕获媒体元数据。 | + +每个根 Block 的 content 保存该实体的原生 JSON,而不是清洗后的阅读文本或另一个归档副本。阅读投影只使用其中部分字段时,不得删改已接纳的其他源事实。原生 ID 为正十进制字符串;正文实体区间是 Unicode 码点的半开区间 `[start, end)`;原生时间使用 UTC ISO-8601,计数观察时间保留采集响应完成时的精度。长文 Draft.js 区间继续采用源数据的单位,不擅自转换成正文区间。 + +字段缺省表示未知。合并不得把缺省变成 `null`、空数组、空正文或否定值;纯转帖可以只有必需字段和 `repostOf`。嵌套对象递归合并,已出现的数组整体替换并保留顺序。接收到明确引用的 ID、但没有完整记录时,可以建立 content 严格为 `{"id":"..."}` 的身份根;不能编造作者资料、正文或未捕获的上下文。后续完整记录补齐同一根。 + +x-monkey 与 Bookmark 是共同原生信息的两个采集入口。同一 native Post ID 补充同一根,Bookmark 不能用加工后的媒体占位文本覆盖已保存的完整正文。Provider 只交付它实际观察到的字段;作者 handle 不能充当作者 ID,conversation ID 不能充当回复父帖 ID。 + +匹配时优先使用新版根,再寻找同一原生 ID 的 `extensions.twitter.tweet.v1` 根。旧根获得足够新版事实时原地升级并保留 Block ID,使已有组织和引用继续成立;没有重新采集的 v1 记录仍由 v1 decoder 读取。若历史上已有重复,使用固定目标,不承诺本次搬迁或清理全部重复。普通 Twitter 写入入口对身份匹配、合并和受管关系使用同一串行化边界,提交失败不能留下部分批次;这不将所有 info-base 原始写入都纳入 Twitter 的身份保证。 + +## 稀疏计数与重复提交 + +User/Post 的每项计数与同名 `countsObservedAt` 成对处理,规则与基线 [mergeCapturedArchiveRecord](https://github.com/steven-vvv/x-monkey/blob/0fe02c7f291bbdc48a6376bc30d8a98f63e94136/src/archive/merge.ts) 一致: + +- 新旧值都有观察时间时,较旧观察不能覆盖较新值;相同或较新时间可以覆盖。 +- 相同计数但较新的观察时间仍需保存;不能用客户端“内容是否改变”的返回值忽略元数据写入。 +- 无时间的新计数可以更新;值改变时移除该项旧时间,避免用旧观察时间标记新值。值未改变时保留已有时间。 +- 没有对应计数的孤立观察时间不更新记录;未提交的其他计数和时间保持。 + +完整信息、补充信息与原样重放均保持同一 Block 身份。较旧的客户端捕获可能继续显示计数差异;不能为消除该界面差异回退已保存的新观察。 + +## 可导航关系 + +Post 的受管出边 content 使用以下 JSON grammar;`type` 是表中的一个实际值,只有 `media` 带从 0 开始的 `position`。 + +```json +{"schema":"extensions.twitter.reference.v1","type":"media","position":0} +``` + +| `type` | 目标 | 对应事实 | +| --- | --- | --- | +| `author` | User 根 | `authorId`。 | +| `media` | Media 根 | 依次连接 `mediaIds`、`article.coverMediaId`、`article.mediaIds`,按首次出现去重后形成的有序序列,`position` 为该序列的 0-based 下标。 | +| `reply` | Post 根 | `replyTo.postId`。 | +| `quote` | Post 根 | `quote.postId`。 | +| `repost` | Post 根 | `repostOf`。 | + +这些边由对应原生引用维护;只删除或替换本 grammar 管理的边,不改动用户组织关系、既有引用或旧 v1 `attachment` / `entities:url` 边。只知道 ID 的目标仍可导航到身份根,并明确表示未捕获内容。原生记录里的其他 ID 不因此获得一条未定义的关系类型。 + +Media 根通过既有 content 为 `content` 的关系指向普通 `core.image.v1` 或 `core.video.v1` Block。普通媒体内容 Block 使用既有 HTTP Storage 指针。原生 Media、可读取内容与实际媒体字节是不同层次的信息,不能把三者混为已保全的本地文件。 + +## 媒体读取与独立使用 + +本版本只保存原生元数据和可按需读取的 HTTP 指针,不持久化图片或视频字节,也不创建媒体下载 Job。只有符合 Twitter 媒体 HTTPS CDN 规则的地址可形成读取指针;无法形成安全指针的原生元数据仍保留。视频/GIF 使用已捕获的可用 MP4 variant,不把 HLS 播放清单当作视频本体。 + +保存、query、列表、文本投影与词法索引不得为了媒体内容读取外部字节;用户明确展开后,才使用现有 HTTP Storage 的超时、大小限制和失败反馈。源站 URL 失效时保留文字与元数据,界面明确表示媒体读取失败。`accepted`、`unchanged` 和 `found` 均不承诺媒体长期可用,连接说明必须说明未自动转存媒体,以免沿用客户端的媒体转存文案产生误解。 + +Post/User Resolver 通过既有投影与索引维护提供原帖 ID/链接、作者和已捕获正文/长文线索;阅读端展示正文、长文、出处和已捕获上下文,并安全解释结构化富文本,不执行归档中的 HTML 或脚本。关闭 x-monkey 后,这些能力仍使用共享信息。未捕获的上下文只显示其已知身份或原生不可用说明,不在阅读时额外抓取完整线程。 + +媒体本体持久化属于后续能力:先具备适合大媒体的 Storage,再由明确设置开关选择异步 Job;本版本不提供没有实现的开关、保存进度或重试界面。 + +## x-monkey 协议 + +用户配置的 Base URL 为执行该 HTTP 能力的 Core 公共基址加 `/twitter/x-monkey`,保留部署路径前缀。 + +| 相对 Base URL 的路径 | 行为 | +| --- | --- | +| `GET /api/v1/session` | 返回会话状态、期限及 `account_url`;未连接时提供连接指引。 | +| `POST /api/v1/archive/query` | 按各类 ID 批量返回 `found`、`missing` 或 `failed`。完整记录为 `found` 并返回同一份原生 JSON;严格身份根为 `missing`;损坏记录为 `failed`。 | +| `POST /api/v1/archive/submit` | 接收 User/Post/Media 原生批次,合并后返回逐项状态与对应汇总;原样重放不新增根或受管关系。 | + +一次 submit 的共同事实与受管关系原子保存;数据库失败使整个批次回滚并返回请求错误。结果中的 `accepted` 表示已保存或合并,包括只有计数观察时间变化的持久更新;`unchanged` 表示没有持久变化。不能用成功汇总掩盖失败实体,也不能因本版本有意不下载媒体而返回 `partial`。 + +协议不依赖 X OAuth;OAuth 仍只服务 Bookmark 采集。浏览器和脚本管理器适配属于 x-monkey。该接入不提供远端历史浏览、检索或恢复接口,也不补抓请求外的线程和历史。 + +## JWT 连接与续签 + +协议复用 [Peer JWT](peer-database-runtime-contract.md#jwt-contract),不新增 PAT、refresh token、签名秘密或会话表。JWT 仍具既有完整 Peer 权限;用途声明与 Cookie 路径都不构成降权或单会话撤销。 + +用户在 x-monkey 设置远端数据库地址并检测;未连接时通过 `account_url` 打开 Twitter 连接页。该页指引用户另行打开已连接同一 info-base 的 InKCre Web,在 Twitter setup 中点击“连接 x-monkey”。Web 向明确选择的 Core 部署以顶层 POST 投递新鲜 Peer JWT;Core 验证后签发会话 JWT、建立 Cookie,用户返回脚本再次检测。连接页不自动发现 Web 地址,也不接受任意回跳地址。Web 从所选 Core 的 setup 状态提供的可选 `x_monkey_base_url` 判断该入口是否可用,不以两个 Distribution 的版本数字猜测能力。 + +会话 JWT 带有签名保护的 `session_use="twitter_archive"`,其默认有效期为 7 天,由 Core 环境配置。首次连接与续签使用同一签发配置;静态 Web 不读取或复制该期限。普通 Peer JWT 只在显式连接入口证明已有权限,普通业务请求不会自动将它升级为可续签会话。 + +有效 session/query/submit 请求通过会话 JWT、用途及来源检查后,若剩余有效期不超过当前配置寿命的一半,Core 签发新的 `iat`/`exp` 并通过 `Set-Cookie` 更新 Cookie。未到窗口不重写 Cookie。过期、无效或没有该用途的 token 不能续签,其他 Core 请求不触发续签。脚本不需要 refresh endpoint 或续期定时器;停止请求后,在最后签发 JWT 的 `exp` 到期。 + +本版本没有从首次授权开始计算的绝对会话上限;活跃会话和已复制的合格 JWT 都可以持续续签。断开仅清理当前浏览器 Cookie,不撤销已复制 JWT;部署更换既有 JWT_SECRET 后按既有机制失效。较长 JWT 同时扩大被复制凭据的可用时间。 + +正式 HTTP 接入使用 HTTPS,Cookie 为 Secure、HttpOnly、SameSite=None,Path 限于保留部署前缀的 Twitter 协议路径,期限不晚于 JWT `exp`。只有这些路由读取协议 Cookie,Core 其他受保护路由继续要求既有 Bearer。无关网页不能读取协议响应或利用 Cookie 发起归档写入,明显的子资源嵌入请求不能触发续签;不能把宽松 CORS、JSON 格式或固定客户端头视为凭据。GM 后台请求可能没有网页 Origin,接收端不能据此识别所有触发无 Origin session GET 的页面。JWT 不出现在 URL 或日志中,JWT_SECRET 不发送到新连接页或脚本。 + +Python 与 Web Distribution 依靠本契约配套;其 [Native Release 独立版本](extension-release-and-installation.md),不要求版本数字相同。旧阅读端不能假定已支持新版 Resolver,部署需要选择能够解释本契约的 Distribution。 diff --git a/docs/index.md b/docs/index.md index 61c8bb6..3a4733f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,6 +8,7 @@ - [System state and authority](../20-product-tdd/system-state-and-authority.md) - [Cross-unit contracts](../20-product-tdd/cross-unit-contracts.md) - [跨 Peer 可观测性契约](../20-product-tdd/observability-contract.md) +- [Twitter 归档信息与接入契约](../20-product-tdd/twitter-archive-contract.md) - [Knowledge capability contract](../20-product-tdd/knowledge-capability-contract.md) - [Semantic retrieval and Peer capabilities](../20-product-tdd/semantic-retrieval-and-peer-capabilities.md) - [Feature retrieval and media interpretation](../20-product-tdd/feature-retrieval-and-media-interpretation.md) From 5221c88cbc88b71a2f896d4fd20774a61aa54288 Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Mon, 19 Oct 2026 17:43:12 +0800 Subject: [PATCH 2/5] =?UTF-8?q?fix(twitter):=20=E5=B0=86=E8=BF=9C=E7=AB=AF?= =?UTF-8?q?=E5=AA=92=E4=BD=93=E8=AF=BB=E5=8F=96=E4=BF=9D=E7=95=99=E5=9C=A8?= =?UTF-8?q?=E6=98=BE=E5=BC=8F=E5=B1=95=E5=BC=80=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 原生媒体不预建可被独立索引的普通内容块 - 保留通用媒体物化合同及按需读取安全边界 --- 20-product-tdd/twitter-archive-contract.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/20-product-tdd/twitter-archive-contract.md b/20-product-tdd/twitter-archive-contract.md index 383a45a..eec20ef 100644 --- a/20-product-tdd/twitter-archive-contract.md +++ b/20-product-tdd/twitter-archive-contract.md @@ -49,13 +49,15 @@ Post 的受管出边 content 使用以下 JSON grammar;`type` 是表中的一 这些边由对应原生引用维护;只删除或替换本 grammar 管理的边,不改动用户组织关系、既有引用或旧 v1 `attachment` / `entities:url` 边。只知道 ID 的目标仍可导航到身份根,并明确表示未捕获内容。原生记录里的其他 ID 不因此获得一条未定义的关系类型。 -Media 根通过既有 content 为 `content` 的关系指向普通 `core.image.v1` 或 `core.video.v1` Block。普通媒体内容 Block 使用既有 HTTP Storage 指针。原生 Media、可读取内容与实际媒体字节是不同层次的信息,不能把三者混为已保全的本地文件。 +本版本的 Media 根只保存原生元数据,不预建持久的 `core.image.v1` / `core.video.v1` 内容 Block,也不建立 Media 到这些 Block 的 `content` 关系。Post 到 Media 的受管引用保持不变,媒体身份、字段合并和 query 仍以原生 Media 根为准。 ## 媒体读取与独立使用 -本版本只保存原生元数据和可按需读取的 HTTP 指针,不持久化图片或视频字节,也不创建媒体下载 Job。只有符合 Twitter 媒体 HTTPS CDN 规则的地址可形成读取指针;无法形成安全指针的原生元数据仍保留。视频/GIF 使用已捕获的可用 MP4 variant,不把 HLS 播放清单当作视频本体。 +本版本只保存 Media 原生元数据,不持久化图片或视频字节,也不创建媒体下载 Job。用户明确展开时,Twitter Distribution 从已捕获 URL 经现有 HTTP Storage 读取字节;这次读取不创建持久媒体内容 Block。读取只接受精确匹配允许 CDN 主机的 HTTPS URL;不符合读取条件的原生元数据仍保留。视频/GIF 选择已捕获可用 MP4 variant 中码率最高的地址,不把 HLS 播放清单当作视频本体。 -保存、query、列表、文本投影与词法索引不得为了媒体内容读取外部字节;用户明确展开后,才使用现有 HTTP Storage 的超时、大小限制和失败反馈。源站 URL 失效时保留文字与元数据,界面明确表示媒体读取失败。`accepted`、`unchanged` 和 `found` 均不承诺媒体长期可用,连接说明必须说明未自动转存媒体,以免沿用客户端的媒体转存文案产生误解。 +保存、query、列表、文本投影与词法索引不得为了这些 Twitter 媒体读取外部字节;用户明确展开后,才使用现有 HTTP Storage 的超时、大小限制和失败反馈。普通媒体内容 Block 可以按其既有 [词法投影与媒体物化合同](feature-retrieval-and-media-interpretation.md#faithful-media-materialization) 被独立处理;为避免全库索引维护提前读取 Twitter 媒体,本版本不预建这类 Block,不改变通用媒体的词法物化政策。 + +源站 URL 失效时保留文字与元数据,界面明确表示媒体读取失败。`accepted`、`unchanged` 和 `found` 均不承诺媒体长期可用,连接说明必须说明未自动转存媒体,以免沿用客户端的媒体转存文案产生误解。 Post/User Resolver 通过既有投影与索引维护提供原帖 ID/链接、作者和已捕获正文/长文线索;阅读端展示正文、长文、出处和已捕获上下文,并安全解释结构化富文本,不执行归档中的 HTML 或脚本。关闭 x-monkey 后,这些能力仍使用共享信息。未捕获的上下文只显示其已知身份或原生不可用说明,不在阅读时额外抓取完整线程。 From 4cf6cf480804c2779d0ed4317c1a4a92db9e635a Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Mon, 19 Oct 2026 22:46:02 +0800 Subject: [PATCH 3/5] =?UTF-8?q?docs(twitter):=20=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E5=88=86=E5=8F=91=E7=9A=84=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 分别选择 Python 与 Web 分发版本 - 明确当前 Python 分发所需的 Core Host 兼容范围 --- website/content/en/guide/sources/twitter.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/website/content/en/guide/sources/twitter.md b/website/content/en/guide/sources/twitter.md index e2db3ac..f551d85 100644 --- a/website/content/en/guide/sources/twitter.md +++ b/website/content/en/guide/sources/twitter.md @@ -23,18 +23,19 @@ requirements. An app-only bearer token is not a substitute for authorizing your The browser-side Twitter Extension provides a visual **Setup** wizard. You do not need the OAuth script when that wizard is available with a compatible Core Extension. -Use `inkcre/twitter` version `0.4.1` with Core Host SDK `0.3.x` and a compatible Web Host. Both -Hosts use the same installed version: Core runs the Python collector, while the browser loads the -setup wizard from that release's Module Federation distribution. If browser enablement reports a -missing distribution, check the release publication and Registry configuration. Do not downgrade to -`0.3.0`: its Python package targets Core Host `0.1.x`. +The Bookmark example uses Python `inkcre/twitter` version `0.4.1` with Core Host SDK +`>=0.3.1 <0.4.0`. Select a compatible Web Module Federation distribution separately: Core runs the +Python collector, while the browser runs the setup wizard and content views. These are independently +versioned releases; equal version numbers do not establish compatibility. If browser enablement +reports a missing distribution, check its release publication, Host compatibility and Registry +configuration. Do not downgrade to `0.3.0`: its Python package targets Core Host `0.1.x`. ### 1. Open Setup 1. [Prepare the Extension](/guide/extensions) on Core with name `inkcre/twitter` and version `0.4.1`, then enable it on Core. -2. In **Extensions**, choose **Enable…** on `inkcre/twitter`, select **This browser**, confirm, and - click **Setup**. +2. Install a compatible Web Module Federation distribution for **This browser**. In **Extensions**, + choose **Enable…** on `inkcre/twitter`, select **This browser**, confirm, and click **Setup**. 3. Choose your online Core Peer in the wizard. Enable Twitter there if prompted. Core handles the callback and collection; browser enablement alone is insufficient. From 7df2e19707a4746c1d84b0a9b4937ad57ff2145a Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Tue, 20 Oct 2026 11:51:49 +0800 Subject: [PATCH 4/5] =?UTF-8?q?docs(twitter):=20=E6=98=8E=E7=A1=AE?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E4=B8=8E=20Peer=20=E5=87=AD=E6=8D=AE?= =?UTF-8?q?=E4=BA=A4=E6=8E=A5=E7=9A=84=E6=89=80=E6=9C=89=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将共同信息模型与 x-monkey 固定协议分离 - 将媒体网络读取交还通用 Storage - 定义 Host/Auth 的浏览器表单交接合同 --- .../peer-database-runtime-contract.md | 2 ++ ...emantic-retrieval-and-peer-capabilities.md | 18 ++++++++++++++++- 20-product-tdd/twitter-archive-contract.md | 20 +++++++++++-------- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/20-product-tdd/peer-database-runtime-contract.md b/20-product-tdd/peer-database-runtime-contract.md index 434cc4c..3955f1b 100644 --- a/20-product-tdd/peer-database-runtime-contract.md +++ b/20-product-tdd/peer-database-runtime-contract.md @@ -118,6 +118,8 @@ secret independently to the runtimes that validate it. Extension 可以为同类 JWT 定义有签名保护的用途声明和续签条件,但不能据此声称缩小原有 Peer 权限。Twitter 归档连接的传输、签发默认值和自动续签见 [Twitter 归档信息与接入契约](twitter-archive-contract.md)。 +需要浏览器顶层表单交接时,由 Host/Auth 按[浏览器凭据交接协议](semantic-retrieval-and-peer-capabilities.md#浏览器凭据交接协议-v1)绑定所选 Peer 与能力广告,并在内部签发这类 JWT。该通用传输不拥有接收扩展的 Cookie、会话期限或续签政策。 + ## Artifact And Environment Contract - The core database runtime is published as an OCI image addressable by immutable digest. diff --git a/20-product-tdd/semantic-retrieval-and-peer-capabilities.md b/20-product-tdd/semantic-retrieval-and-peer-capabilities.md index 654829f..42637b3 100644 --- a/20-product-tdd/semantic-retrieval-and-peer-capabilities.md +++ b/20-product-tdd/semantic-retrieval-and-peer-capabilities.md @@ -3,7 +3,7 @@ ## Purpose Define the shared semantics for semantic retrieval, the minimum focal-block organization -path that improves its granularity, and synchronous capability delegation between +path that improves its granularity, and capability delegation and browser credential handoff between heterogeneous runtime Peers. Unit repositories still own framework classes, route mounting, database queries, scheduler wiring, and provider-specific configuration. @@ -143,6 +143,22 @@ The first admitted exact capability IDs are: - `core.extension.management.v1`; - `extensions.mail.mime_part.materialize.v1`. +## 浏览器凭据交接协议 V1 + +`core.peer.protocol.browser-form.v1` 供需要浏览器顶层导航的显式凭据交接使用。业务能力拥有接收路由及后续会话语义,Host/Auth 拥有目标校验、Peer JWT 签发和表单传输。广告参数为: + +```json +{"method":"POST","path":"/business/session","credential_field":"token"} +``` + +参数对象只接受上述三个字段,`method` 固定为 `POST`。`path` 是相对于 Peer 公共基址及其路径前缀追加的路由,最长 2048 字符,各段只能包含 ASCII 字母、数字、下划线和短横线,遵守 `^(?:/[A-Za-z0-9_-]+)+$`;不接受查询、fragment、点段、双斜线或百分号编码。`credential_field` 指定表单中承载凭据的字段,遵守 `^[A-Za-z][A-Za-z0-9_-]{0,63}$`,且不能是 `action`、`enctype`、`method`、`requestSubmit`、`submit` 或 `target`,避免遮蔽浏览器表单属性。 + +调用者只提交明确选择的 Peer 与精确 capability ID。Host 按数据库时间确认该 Peer 的 live lease,并读取该能力的有效广告;不替换成其他 Peer,也不执行自动重试。Host 从该 Peer 的 `http_public_base_url` 派生目标,要求 HTTPS、无 userinfo/query/fragment,保留已有路径前缀并追加广告 path。业务 UI 不能把任意 URL 或待签 JWT 传入这条路径。 + +仅在显式调用时,Host/Auth 内部签发新鲜的现有 Peer JWT,通过 `application/x-www-form-urlencoded`、`target=_top` 的 POST 表单将其放入 `credential_field`。原始 JWT 不返回业务 UI,也不进入 URL。调用结果最多说明导航已发起,即 `initiated`;它不证明远端建立会话、Cookie 被浏览器接受或业务操作成功。业务需要通过自己的完成页面或会话检查确认后续结果。 + +这是一条导航交接合同,不使用 HTTP V1 的请求/响应 envelope。接收能力自行决定是否兑换同类会话 JWT、Cookie、有效期和续签;通用 Host 不吸收这些业务政策。 + ## Runtime Authentication And Advertisement - Peer HTTP 使用 [Peer Database Runtime Contract](peer-database-runtime-contract.md#jwt-contract) 的共享 `HS256` JWT:role 为 `authenticated`,issuer 为 `inkcre-peer`,audience 为 `inkcre-api`,必需 `iat`/`exp`,部署持有至少 32 字节的签名秘密。签发默认有效期属于签发者配置,接收端不把它作为最大寿命。 diff --git a/20-product-tdd/twitter-archive-contract.md b/20-product-tdd/twitter-archive-contract.md index eec20ef..30bd5da 100644 --- a/20-product-tdd/twitter-archive-contract.md +++ b/20-product-tdd/twitter-archive-contract.md @@ -4,7 +4,7 @@ ## 原生信息与身份 -x-monkey 兼容基线为 `v0.2.0` / `0fe02c7f291bbdc48a6376bc30d8a98f63e94136`,完整 wire 字段以该版本的 [archive/model.ts](https://github.com/steven-vvv/x-monkey/blob/0fe02c7f291bbdc48a6376bc30d8a98f63e94136/src/archive/model.ts) 为依据。三类独立实体通过 ID 引用彼此;同一种实体的原生 ID 决定合并身份,不能使用 handle、显示名或 JavaScript 数字替代。 +User、Post、Media 是 Twitter Extension 自有的共同信息模型,供采集适配器、协议适配器和各 Distribution 的 Resolver 共同使用。x-monkey 的兼容基线为 `v0.2.0` / `0fe02c7f291bbdc48a6376bc30d8a98f63e94136`;该版本的 [archive/model.ts](https://github.com/steven-vvv/x-monkey/blob/0fe02c7f291bbdc48a6376bc30d8a98f63e94136/src/archive/model.ts) 只定义这个客户端适配器的固定 DTO,不拥有共同模型的演进或合并规则。三类实体通过 ID 引用彼此;同一种实体的原生 ID 决定合并身份,不能使用 handle、显示名或 JavaScript 数字替代。 | 原生实体 | Resolver | 完整记录的必需字段 | 保留的信息 | | --- | --- | --- | --- | @@ -12,17 +12,17 @@ x-monkey 兼容基线为 `v0.2.0` / `0fe02c7f291bbdc48a6376bc30d8a98f63e94136` | Post | `extensions.twitter.tweet.v2` | `id`、`authorId`、`createdAt` | 正文富文本、长文结构、作者与上下文 ID、媒体顺序、卡片、投票、地点、计数和其他已捕获源事实。 | | Media | `extensions.twitter.media.v1` | `id`、`type`、`url` | 图片或封面 URL、尺寸、alt、视频 variants、来源 ID、可用性及其他已捕获媒体元数据。 | -每个根 Block 的 content 保存该实体的原生 JSON,而不是清洗后的阅读文本或另一个归档副本。阅读投影只使用其中部分字段时,不得删改已接纳的其他源事实。原生 ID 为正十进制字符串;正文实体区间是 Unicode 码点的半开区间 `[start, end)`;原生时间使用 UTC ISO-8601,计数观察时间保留采集响应完成时的精度。长文 Draft.js 区间继续采用源数据的单位,不擅自转换成正文区间。 +每个根 Block 的 content 保存共同模型的结构化 JSON,而不是清洗后的阅读文本或另一份协议归档。已保存字段、Resolver ID、Block ID 和引用含义保持兼容,不因适配器与共同模型分离而迁移数据。阅读投影只使用其中部分字段时,不得删改已接纳的其他源事实。原生 ID 为正十进制字符串;正文实体区间是 Unicode 码点的半开区间 `[start, end)`;原生时间使用 UTC ISO-8601,计数观察时间保留采集响应完成时的精度。长文 Draft.js 区间继续采用源数据的单位,不擅自转换成正文区间。 字段缺省表示未知。合并不得把缺省变成 `null`、空数组、空正文或否定值;纯转帖可以只有必需字段和 `repostOf`。嵌套对象递归合并,已出现的数组整体替换并保留顺序。接收到明确引用的 ID、但没有完整记录时,可以建立 content 严格为 `{"id":"..."}` 的身份根;不能编造作者资料、正文或未捕获的上下文。后续完整记录补齐同一根。 -x-monkey 与 Bookmark 是共同原生信息的两个采集入口。同一 native Post ID 补充同一根,Bookmark 不能用加工后的媒体占位文本覆盖已保存的完整正文。Provider 只交付它实际观察到的字段;作者 handle 不能充当作者 ID,conversation ID 不能充当回复父帖 ID。 +x-monkey 与 Bookmark 是共同信息的两个入口。x-monkey 在边界将固定 DTO 转为共同模型;官方 API 和 Twikit 也把实际观察到的已支持字段投影到共同模型。持久化和 Resolver 不依赖 wire DTO 或协议状态。同一 Post ID 补充同一根,Bookmark 不能用加工后的媒体占位文本覆盖已保存的完整正文;作者 handle 不能充当作者 ID,conversation ID 不能充当回复父帖 ID。当前 provider 适配器没有保存全部原始响应,未映射的未知字段不构成已保留事实。 匹配时优先使用新版根,再寻找同一原生 ID 的 `extensions.twitter.tweet.v1` 根。旧根获得足够新版事实时原地升级并保留 Block ID,使已有组织和引用继续成立;没有重新采集的 v1 记录仍由 v1 decoder 读取。若历史上已有重复,使用固定目标,不承诺本次搬迁或清理全部重复。普通 Twitter 写入入口对身份匹配、合并和受管关系使用同一串行化边界,提交失败不能留下部分批次;这不将所有 info-base 原始写入都纳入 Twitter 的身份保证。 ## 稀疏计数与重复提交 -User/Post 的每项计数与同名 `countsObservedAt` 成对处理,规则与基线 [mergeCapturedArchiveRecord](https://github.com/steven-vvv/x-monkey/blob/0fe02c7f291bbdc48a6376bc30d8a98f63e94136/src/archive/merge.ts) 一致: +User/Post 的每项计数与同名 `countsObservedAt` 成对处理。以下规则属于 Twitter 的共同模型;客户端适配器保持相应兼容行为,但不将上游实现当作合并权威。比较按毫秒时间值处理,持久记录保留输入时间字符串的精度: - 新旧值都有观察时间时,较旧观察不能覆盖较新值;相同或较新时间可以覆盖。 - 相同计数但较新的观察时间仍需保存;不能用客户端“内容是否改变”的返回值忽略元数据写入。 @@ -53,7 +53,7 @@ Post 的受管出边 content 使用以下 JSON grammar;`type` 是表中的一 ## 媒体读取与独立使用 -本版本只保存 Media 原生元数据,不持久化图片或视频字节,也不创建媒体下载 Job。用户明确展开时,Twitter Distribution 从已捕获 URL 经现有 HTTP Storage 读取字节;这次读取不创建持久媒体内容 Block。读取只接受精确匹配允许 CDN 主机的 HTTPS URL;不符合读取条件的原生元数据仍保留。视频/GIF 选择已捕获可用 MP4 variant 中码率最高的地址,不把 HLS 播放清单当作视频本体。 +本版本只保存 Media 元数据,不持久化图片或视频字节,也不创建媒体下载 Job。用户明确展开时,Twitter Distribution 选择已捕获的图片 URL,或视频/GIF 可用 MP4 variants 中码率最高的地址,交给现有 HTTP Storage 读取;这次读取不创建持久媒体内容 Block。URL 的 HTTP(S) 校验、超时、体积限制和重定向处理由通用 Storage 合同拥有。HLS 继续保留为元数据,不作为视频本体加载。 保存、query、列表、文本投影与词法索引不得为了这些 Twitter 媒体读取外部字节;用户明确展开后,才使用现有 HTTP Storage 的超时、大小限制和失败反馈。普通媒体内容 Block 可以按其既有 [词法投影与媒体物化合同](feature-retrieval-and-media-interpretation.md#faithful-media-materialization) 被独立处理;为避免全库索引维护提前读取 Twitter 媒体,本版本不预建这类 Block,不改变通用媒体的词法物化政策。 @@ -70,18 +70,22 @@ Post/User Resolver 通过既有投影与索引维护提供原帖 ID/链接、作 | 相对 Base URL 的路径 | 行为 | | --- | --- | | `GET /api/v1/session` | 返回会话状态、期限及 `account_url`;未连接时提供连接指引。 | -| `POST /api/v1/archive/query` | 按各类 ID 批量返回 `found`、`missing` 或 `failed`。完整记录为 `found` 并返回同一份原生 JSON;严格身份根为 `missing`;损坏记录为 `failed`。 | -| `POST /api/v1/archive/submit` | 接收 User/Post/Media 原生批次,合并后返回逐项状态与对应汇总;原样重放不新增根或受管关系。 | +| `POST /api/v1/archive/query` | 按各类 ID 批量返回 `found`、`missing` 或 `failed`。适配器将完整共同模型显式投影为固定协议 DTO;严格身份根为 `missing`;损坏记录为 `failed`。 | +| `POST /api/v1/archive/submit` | 接收固定 User/Post/Media DTO 批次,转为共同模型写入后,由适配器产生逐项状态与汇总;原样重放不新增根或受管关系。 | 一次 submit 的共同事实与受管关系原子保存;数据库失败使整个批次回滚并返回请求错误。结果中的 `accepted` 表示已保存或合并,包括只有计数观察时间变化的持久更新;`unchanged` 表示没有持久变化。不能用成功汇总掩盖失败实体,也不能因本版本有意不下载媒体而返回 `partial`。 +读取与写入用例只返回信息、无效记录、Block 身份和实际变化,不产生 x-monkey 状态。协议请求的条数限制与固定 DTO 校验留在适配边界,不成为共同模型的集合上限。适配器按固定 DTO 字段集递归导出响应,其中声明为自由 JSON 的文章 data 仍保留其内容;共同模型以后增加的字段不会自动泄漏到旧协议,也不会因旧协议投影而从持久记录删除。 + 协议不依赖 X OAuth;OAuth 仍只服务 Bookmark 采集。浏览器和脚本管理器适配属于 x-monkey。该接入不提供远端历史浏览、检索或恢复接口,也不补抓请求外的线程和历史。 ## JWT 连接与续签 协议复用 [Peer JWT](peer-database-runtime-contract.md#jwt-contract),不新增 PAT、refresh token、签名秘密或会话表。JWT 仍具既有完整 Peer 权限;用途声明与 Cookie 路径都不构成降权或单会话撤销。 -用户在 x-monkey 设置远端数据库地址并检测;未连接时通过 `account_url` 打开 Twitter 连接页。该页指引用户另行打开已连接同一 info-base 的 InKCre Web,在 Twitter setup 中点击“连接 x-monkey”。Web 向明确选择的 Core 部署以顶层 POST 投递新鲜 Peer JWT;Core 验证后签发会话 JWT、建立 Cookie,用户返回脚本再次检测。连接页不自动发现 Web 地址,也不接受任意回跳地址。Web 从所选 Core 的 setup 状态提供的可选 `x_monkey_base_url` 判断该入口是否可用,不以两个 Distribution 的版本数字猜测能力。 +用户在 x-monkey 设置远端数据库地址并检测;未连接时通过 `account_url` 打开 Twitter 连接页。该页指引用户另行打开已连接同一 info-base 的 InKCre Web,在 Twitter setup 中点击“连接 x-monkey”。Twitter UI 向 Host 提交所选 Peer 和 `inkcre.twitter.x-monkey.session.v1` 能力的连接意图;Host 按[浏览器凭据交接协议](semantic-retrieval-and-peer-capabilities.md#浏览器凭据交接协议-v1)发现有效广告、绑定该 Peer 的公共基址和路径前缀,再内部签发新鲜 Peer JWT 并顶层表单导航。UI 不接收原始 JWT 或指定任意目标 URL。发起导航只表示 `initiated`;Core 建立 Cookie 后,用户仍需在账户页及脚本检测中确认连接结果。 + +Twitter 在实际 session 路由就绪且配置了 HTTPS 公共基址时广告此能力,其 inbound 为 `core.peer.protocol.browser-form.v1`,参数为 `{"method":"POST","path":"/twitter/x-monkey/session","credential_field":"token"}`。停用时随路由撤回。setup 状态的 `x_monkey_base_url` 仍供用户复制服务地址;地址展示与连接按钮分别判断,按钮以所选 Peer 的精确能力广告为依据,展示字段不作为凭据投递目标的权威。连接页不自动发现 Web 地址,也不接受任意回跳地址;能力发现不依靠两个 Distribution 的版本数字相同。 会话 JWT 带有签名保护的 `session_use="twitter_archive"`,其默认有效期为 7 天,由 Core 环境配置。首次连接与续签使用同一签发配置;静态 Web 不读取或复制该期限。普通 Peer JWT 只在显式连接入口证明已有权限,普通业务请求不会自动将它升级为可续签会话。 From ff820977d011f8fb97c1656cbf48aca21606c426 Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Tue, 20 Oct 2026 14:07:17 +0800 Subject: [PATCH 5/5] =?UTF-8?q?docs(twitter):=20=E5=B0=86=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E6=95=9B=E4=B8=BA=20Core=20=E8=87=AA?= =?UTF-8?q?=E6=89=98=E7=AE=A1=E8=B4=A6=E6=88=B7=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除通用 browser-form 凭据交接合同\n- 明确本地短期 JWT 签名、同源 Cookie 建立及可信部署前提 --- .../peer-database-runtime-contract.md | 2 -- ...semantic-retrieval-and-peer-capabilities.md | 18 +----------------- 20-product-tdd/twitter-archive-contract.md | 6 +++--- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/20-product-tdd/peer-database-runtime-contract.md b/20-product-tdd/peer-database-runtime-contract.md index 3955f1b..434cc4c 100644 --- a/20-product-tdd/peer-database-runtime-contract.md +++ b/20-product-tdd/peer-database-runtime-contract.md @@ -118,8 +118,6 @@ secret independently to the runtimes that validate it. Extension 可以为同类 JWT 定义有签名保护的用途声明和续签条件,但不能据此声称缩小原有 Peer 权限。Twitter 归档连接的传输、签发默认值和自动续签见 [Twitter 归档信息与接入契约](twitter-archive-contract.md)。 -需要浏览器顶层表单交接时,由 Host/Auth 按[浏览器凭据交接协议](semantic-retrieval-and-peer-capabilities.md#浏览器凭据交接协议-v1)绑定所选 Peer 与能力广告,并在内部签发这类 JWT。该通用传输不拥有接收扩展的 Cookie、会话期限或续签政策。 - ## Artifact And Environment Contract - The core database runtime is published as an OCI image addressable by immutable digest. diff --git a/20-product-tdd/semantic-retrieval-and-peer-capabilities.md b/20-product-tdd/semantic-retrieval-and-peer-capabilities.md index 42637b3..654829f 100644 --- a/20-product-tdd/semantic-retrieval-and-peer-capabilities.md +++ b/20-product-tdd/semantic-retrieval-and-peer-capabilities.md @@ -3,7 +3,7 @@ ## Purpose Define the shared semantics for semantic retrieval, the minimum focal-block organization -path that improves its granularity, and capability delegation and browser credential handoff between +path that improves its granularity, and synchronous capability delegation between heterogeneous runtime Peers. Unit repositories still own framework classes, route mounting, database queries, scheduler wiring, and provider-specific configuration. @@ -143,22 +143,6 @@ The first admitted exact capability IDs are: - `core.extension.management.v1`; - `extensions.mail.mime_part.materialize.v1`. -## 浏览器凭据交接协议 V1 - -`core.peer.protocol.browser-form.v1` 供需要浏览器顶层导航的显式凭据交接使用。业务能力拥有接收路由及后续会话语义,Host/Auth 拥有目标校验、Peer JWT 签发和表单传输。广告参数为: - -```json -{"method":"POST","path":"/business/session","credential_field":"token"} -``` - -参数对象只接受上述三个字段,`method` 固定为 `POST`。`path` 是相对于 Peer 公共基址及其路径前缀追加的路由,最长 2048 字符,各段只能包含 ASCII 字母、数字、下划线和短横线,遵守 `^(?:/[A-Za-z0-9_-]+)+$`;不接受查询、fragment、点段、双斜线或百分号编码。`credential_field` 指定表单中承载凭据的字段,遵守 `^[A-Za-z][A-Za-z0-9_-]{0,63}$`,且不能是 `action`、`enctype`、`method`、`requestSubmit`、`submit` 或 `target`,避免遮蔽浏览器表单属性。 - -调用者只提交明确选择的 Peer 与精确 capability ID。Host 按数据库时间确认该 Peer 的 live lease,并读取该能力的有效广告;不替换成其他 Peer,也不执行自动重试。Host 从该 Peer 的 `http_public_base_url` 派生目标,要求 HTTPS、无 userinfo/query/fragment,保留已有路径前缀并追加广告 path。业务 UI 不能把任意 URL 或待签 JWT 传入这条路径。 - -仅在显式调用时,Host/Auth 内部签发新鲜的现有 Peer JWT,通过 `application/x-www-form-urlencoded`、`target=_top` 的 POST 表单将其放入 `credential_field`。原始 JWT 不返回业务 UI,也不进入 URL。调用结果最多说明导航已发起,即 `initiated`;它不证明远端建立会话、Cookie 被浏览器接受或业务操作成功。业务需要通过自己的完成页面或会话检查确认后续结果。 - -这是一条导航交接合同,不使用 HTTP V1 的请求/响应 envelope。接收能力自行决定是否兑换同类会话 JWT、Cookie、有效期和续签;通用 Host 不吸收这些业务政策。 - ## Runtime Authentication And Advertisement - Peer HTTP 使用 [Peer Database Runtime Contract](peer-database-runtime-contract.md#jwt-contract) 的共享 `HS256` JWT:role 为 `authenticated`,issuer 为 `inkcre-peer`,audience 为 `inkcre-api`,必需 `iat`/`exp`,部署持有至少 32 字节的签名秘密。签发默认有效期属于签发者配置,接收端不把它作为最大寿命。 diff --git a/20-product-tdd/twitter-archive-contract.md b/20-product-tdd/twitter-archive-contract.md index 30bd5da..e92813d 100644 --- a/20-product-tdd/twitter-archive-contract.md +++ b/20-product-tdd/twitter-archive-contract.md @@ -83,9 +83,9 @@ Post/User Resolver 通过既有投影与索引维护提供原帖 ID/链接、作 协议复用 [Peer JWT](peer-database-runtime-contract.md#jwt-contract),不新增 PAT、refresh token、签名秘密或会话表。JWT 仍具既有完整 Peer 权限;用途声明与 Cookie 路径都不构成降权或单会话撤销。 -用户在 x-monkey 设置远端数据库地址并检测;未连接时通过 `account_url` 打开 Twitter 连接页。该页指引用户另行打开已连接同一 info-base 的 InKCre Web,在 Twitter setup 中点击“连接 x-monkey”。Twitter UI 向 Host 提交所选 Peer 和 `inkcre.twitter.x-monkey.session.v1` 能力的连接意图;Host 按[浏览器凭据交接协议](semantic-retrieval-and-peer-capabilities.md#浏览器凭据交接协议-v1)发现有效广告、绑定该 Peer 的公共基址和路径前缀,再内部签发新鲜 Peer JWT 并顶层表单导航。UI 不接收原始 JWT 或指定任意目标 URL。发起导航只表示 `initiated`;Core 建立 Cookie 后,用户仍需在账户页及脚本检测中确认连接结果。 +用户在 x-monkey 设置远端数据库地址并检测;未连接时通过 `account_url` 打开同一 Core 自托管的 `/twitter/x-monkey/account`。用户确认是自己信任的 HTTPS 部署后,在账户页输入该部署现有的 `JWT_SECRET`。页面通过浏览器 WebCrypto 本地签发短期 Peer JWT,以同 Origin Bearer 请求提交到 `/twitter/x-monkey/session`;Core 复用普通 Peer JWT 认证后建立归档 Cookie。页面再通过 session 请求确认浏览器实际接受 Cookie,才显示 `Connected`、连接的 Peer 与到期时间;用户返回脚本再次检测。连接不要求安装 InKCre Web 或 Twitter Web Distribution。 -Twitter 在实际 session 路由就绪且配置了 HTTPS 公共基址时广告此能力,其 inbound 为 `core.peer.protocol.browser-form.v1`,参数为 `{"method":"POST","path":"/twitter/x-monkey/session","credential_field":"token"}`。停用时随路由撤回。setup 状态的 `x_monkey_base_url` 仍供用户复制服务地址;地址展示与连接按钮分别判断,按钮以所选 Peer 的精确能力广告为依据,展示字段不作为凭据投递目标的权威。连接页不自动发现 Web 地址,也不接受任意回跳地址;能力发现不依靠两个 Distribution 的版本数字相同。 +账户页不持久化或经网络发送 `JWT_SECRET`,不加载第三方脚本,不接受任意回跳地址;本地签名不意味着恶意或被篡改的页面安全,部署页面本身必须可信。可选的 Web Setup 保留 `x_monkey_base_url` 供用户复制,并以普通链接打开该 Core 的账户页,不处理密钥或签发 JWT。 会话 JWT 带有签名保护的 `session_use="twitter_archive"`,其默认有效期为 7 天,由 Core 环境配置。首次连接与续签使用同一签发配置;静态 Web 不读取或复制该期限。普通 Peer JWT 只在显式连接入口证明已有权限,普通业务请求不会自动将它升级为可续签会话。 @@ -93,6 +93,6 @@ Twitter 在实际 session 路由就绪且配置了 HTTPS 公共基址时广告 本版本没有从首次授权开始计算的绝对会话上限;活跃会话和已复制的合格 JWT 都可以持续续签。断开仅清理当前浏览器 Cookie,不撤销已复制 JWT;部署更换既有 JWT_SECRET 后按既有机制失效。较长 JWT 同时扩大被复制凭据的可用时间。 -正式 HTTP 接入使用 HTTPS,Cookie 为 Secure、HttpOnly、SameSite=None,Path 限于保留部署前缀的 Twitter 协议路径,期限不晚于 JWT `exp`。只有这些路由读取协议 Cookie,Core 其他受保护路由继续要求既有 Bearer。无关网页不能读取协议响应或利用 Cookie 发起归档写入,明显的子资源嵌入请求不能触发续签;不能把宽松 CORS、JSON 格式或固定客户端头视为凭据。GM 后台请求可能没有网页 Origin,接收端不能据此识别所有触发无 Origin session GET 的页面。JWT 不出现在 URL 或日志中,JWT_SECRET 不发送到新连接页或脚本。 +正式 HTTP 接入使用 HTTPS,Cookie 为 Secure、HttpOnly、SameSite=None,Path 限于保留部署前缀的 Twitter 协议路径,期限不晚于 JWT `exp`。只有这些路由读取协议 Cookie,Core 其他受保护路由继续要求既有 Bearer。无关网页不能读取协议响应或利用 Cookie 发起归档写入,明显的子资源嵌入请求不能触发续签;不能把宽松 CORS、JSON 格式或固定客户端头视为凭据。GM 后台请求可能没有网页 Origin,接收端不能据此识别所有触发无 Origin session GET 的页面。JWT 不出现在 URL 或日志中,JWT_SECRET 不经网络发送给 Core、X 或脚本。 Python 与 Web Distribution 依靠本契约配套;其 [Native Release 独立版本](extension-release-and-installation.md),不要求版本数字相同。旧阅读端不能假定已支持新版 Resolver,部署需要选择能够解释本契约的 Distribution。