# Credential

## Description

Credential 模块用于提供围绕凭据（credential）进行生成、签发、解析、校验、脱敏与比较的基础建模能力，用于把 API key、JSON Web Token（JWT）与密码散列这类可被系统接受为验证依据的材料组织成稳定公共边界。

它关注的是“系统凭什么接受一个调用方”，而不是“一个对象是谁”，也不是完整登录流程、权限判定或传输协议接入本身。

## For Understanding

理解 Credential 模块时，应先把它与 Identifier、Random 和 Request 区分开。

- 与 Identifier 的区别在于：Identifier 关注的是身份或标识如何被稳定表达；Credential 关注的是调用方凭什么被信任、被验证或被放行。
- 与 Random 的区别在于：Credential 中虽然可能会使用随机源，但这里的重点不是通用随机文本生成，而是带有安全前提与凭据语义的结果格式。
- 与 Request 的区别在于：Credential 负责凭据本身的建模，不负责把凭据如何塞进 HTTP header、cookie 或具体请求链路中。

当前这个模块适合承载以下几类稳定语义：

- 不透明凭据的生成与格式约束，例如 API key。
- 凭据载体字符串的格式化与提取，例如 Bearer credential。
- 可签发、可验证的令牌凭据，例如 JWT。
- 可生成、可比较的密码散列材料，例如带盐密码散列。

同时也要守住几个边界：

- 这里不负责完整认证流程，例如登录、刷新流程编排或会话管理。
- 这里不负责授权（authorization）与权限决策，例如角色、权限、策略判断。
- 这里不负责完整密码学工具箱；只有当某个密码学能力直接服务于凭据建模时，才适合作为内部实现或局部公共能力存在。

## For Using

当你需要在系统边界生成、签发、验证或展示凭据，而又希望这些能力以稳定、可复用的公共 API 形式存在时，可以使用这个模块。

从使用角度看，当前公共能力大致可以分为四类：

- API key 能力：用于生成默认或自定义格式的 key，并在日志或界面中按同一份格式约束做安全遮罩。
- Bearer 能力：用于把非空原始 token 表达为 Bearer 凭据字符串，或从 Bearer 凭据字符串中提取原始 token。
- JWT 能力：用于基于共享密钥签发与解析原始 token，并从 token 中恢复稳定业务载荷。
- 密码能力：用于生成盐值、产出带盐散列，以及比较用户输入与既有散列。

更合理的接入方式通常是：在靠近应用边界的位置生成或验证这些凭据，再把结果作为普通输入传入更内层的业务模型。这样做可以避免让内层逻辑直接依赖随机源、签名库或散列细节。

其中 API key 能力允许调用方覆写前缀、字符集与主体长度；一旦使用了自定义格式，后续做脱敏展示时也应继续沿用同一份格式约束，否则“这个字符串是否是合法 API key”就会在生成与遮罩两个动作之间出现分叉。

其中 Bearer 能力只负责凭据字符串本身的格式化与提取，不负责与请求对象、header 容器或具体框架适配层直接耦合。格式化时应把“可被发送的 Bearer 凭据字符串”视为目标，因此空白输入应被视为无效 token，而不是被格式化成一个外形接近但语义上无效的结果。若你的需求已经开始偏向协议接入，例如把 Bearer 写入某个具体请求对象、处理 cookie 写入、OAuth 回调或会话刷新编排，那么更合适的做法通常是在更外层再建立专门模块，而不是直接扩张 Credential 顶层边界。

## For Contributing

贡献 Credential 模块时，应优先判断新增内容表达的是“凭据本身的稳定语义”，还是“某个接入场景下的临时便利代码”。只有前者才适合进入这个模块。

在扩展时，应优先遵守以下边界：

- 公共能力应围绕凭据的生成、签发、解析、校验、脱敏、比较、格式化与失效语义展开。
- 不要把 HTTP、cookie、框架中间件或数据库存储策略直接提升为顶层公共 API。
- 不要把角色、权限、授权规则或完整会话编排混入这里。
- 如果某项能力的重点已经变成通用密码学原语，而不是凭据模型，应考虑在更明确的问题域中单独建模。

### JSDoc 注释格式要求

- 每个公开导出的目标（类型、函数、变量、类等）都应包含 JSDoc 注释，让人在不跳转实现的情况下就能理解用途。
- JSDoc 注释第一行应为清晰且简洁的描述，该描述优先使用中文（英文也可以）。
- 如果描述后还有其他内容，应在描述后加一个空行。
- 如果有示例，应使用 `@example` 标签，后接三重反引号代码块（不带语言标识）。
- 如果有示例，应包含多个场景，展示不同用法，尤其要覆盖常见组合方式或边界输入。
- 如果有示例，应使用注释格式说明每个场景：`// Expect: <result>`。
- 如果有示例，应将结果赋值给 `example1`、`example2` 之类的变量，以保持示例易读。
- 如果有示例，`// Expect: <result>` 应该位于 `example1`、`example2` 之前，以保持示例的逻辑清晰。
- 如果有示例，应优先使用确定性示例；避免断言精确的随机输出。
- 如果函数返回结构化字符串，应展示其预期格式特征。
- 如果有参考资料，应将 `@see` 放在 `@example` 代码块之后，并用一个空行分隔。

### 实现规范要求

- 不同程序元素之间使用一个空行分隔，保持结构清楚。这里的程序元素，通常指函数、类型、常量，以及直接服务于它们的辅助元素。
- 某程序元素独占的辅助元素与该程序元素本身视为一个整体，不要在它们之间添加空行。
- 程序元素的辅助元素应该放置在该程序元素的上方，以保持阅读时的逻辑顺序。
- 若辅助元素被多个程序元素共享，则应将其视为独立的程序元素，放在这些程序元素中第一个相关目标的上方，并与后续程序元素之间保留一个空行。
- 辅助元素也应该像其它程序元素一样，保持清晰的命名和适当的注释，以便在需要阅读实现细节时能够快速理解它们的作用和使用方式。
- 辅助元素的命名必须以前缀 `internal` 开头（或 `Internal`，大小写不敏感）。
- 辅助元素永远不要公开导出。
- 被模块内多个不同文件中的程序元素共享的辅助元素，应该放在一个单独的文件中，例如 `./src/credential/internal.ts`。
- 模块内可以包含子模块。只有当某个子目录表达一个稳定、可单独理解、且可能被父模块重导出的子问题域时，才应将其视为子模块。
- 子模块包含多个文件时，应该为其单独创建子文件夹，并为其创建单独的 Barrel 文件；父模块的 Barrel 文件再重导出子模块的 Barrel 文件。
- 子模块不需要有自己的 `README.md`。
- 子模块可以有自己的 `internal.ts` 文件，多个子模块共享的辅助元素应该放在父模块的 `internal.ts` 文件中，单个子模块共享的辅助元素应该放在该子模块的 `internal.ts` 文件中。
- 对模块依赖关系的要求（通常是不循环依赖或不反向依赖）与对 DRY 的要求可能产生冲突。此时，若复用的代码数量不大，可以适当牺牲 DRY，复制粘贴并保留必要的注释说明；若复用的代码数量较大，则可以将其抽象到新的文件或子模块中，如 `common.ts`，并在需要的地方导入使用。
- 与凭据相关的实现应优先围绕格式约束、签发语义、校验语义、脱敏语义与比较语义组织，避免把协议接入或业务流程细节直接提升为公共 API。

### 导出策略要求

- 保持内部辅助项和内部符号为私有，不要让外部接入依赖临时性的内部结构。
- 每个模块都应有一个用于重导出所有公共 API 的 Barrel 文件。
- Barrel 文件应命名为 `index.ts`，放在模块目录根部，并且所有公共 API 都应从该文件导出。
- 新增公共能力时，应优先检查它是否表达稳定、清楚且值得长期维护的凭据语义，而不是某段实现细节的便捷暴露；仅在确认需要长期对外承诺时再加入 Barrel 导出。

### 测试要求

- 若程序元素是函数，则只为该函数编写一个测试，如果该函数需要测试多个用例，应放在同一个测试中。
- 若程序元素是类，则至少要为该类的每一个方法编写一个测试，如果该方法需要测试多个用例，应放在同一个测试中。
- 若程序元素是类，除了为该类的每一个方法编写至少一个测试之外，还可以为该类编写任意多个测试，以覆盖该类的不同使用场景或边界情况。
- 若编写测试时需要用到辅助元素（Mock 或 Spy 等），可以在测试文件中直接定义这些辅助元素。若辅助元素较为简单，则可以直接放在每一个测试内部，优先保证每个测试的独立性，而不是追求极致 DRY；若辅助元素较为复杂或需要在多个测试中复用，则可以放在测试文件顶部，供该测试文件中的所有测试使用。
- 测试顺序应与源文件中被测试目标的原始顺序保持一致。
- 若该模块不需要测试，必须在说明文件中明确说明该模块不需要测试，并说明理由。一般来说，只有在该模块没有可执行的公共函数、只承载类型层表达，或其语义已被上层模块的测试完整覆盖且重复测试几乎不再带来额外价值时，才适合这样处理。
- 模块的单元测试文件目录是 `./tests/unit/credential`，若模块包含子模块，则子模块的单元测试文件目录为 `./tests/unit/credential/<sub-module-name>`。
- 对这个模块来说，测试应优先覆盖 API key 的格式与遮罩、Bearer 凭据的格式化与提取、JWT 的签发与解析、密码盐值的结果特征、带盐散列的一致性，以及密码比较在匹配与不匹配场景下的稳定行为。
- 若 API key 支持可配置格式，测试应同时覆盖默认格式与至少一种自定义格式，并验证生成、校验与遮罩对“合法 key”的理解保持一致。
- Bearer 能力的测试除正常格式化与提取外，还应覆盖空白输入被拒绝的情况，避免格式化函数产出一个校验函数本身都不会接受的结果。
