@dofe/sso-contracts
v0.1.50
Published
SSO API contracts and schemas for DofeAI platform
Readme
@repo/contracts - API 契约
使用 ts-rest 实现的前后端类型安全 API 契约。
安装
{
"dependencies": {
"@repo/contracts": "workspace:*"
}
}使用
前端使用
import { teamContract } from '@repo/contracts/api';
import { initClient } from '@ts-rest/core';
const client = initClient(teamContract, {
baseUrl: '/api',
});
const { data } = await client.getInfo({ params: { teamId: '123' } });后端使用
import { teamContract } from '@repo/contracts/api';
import { TsRestHandler, tsRestHandler } from '@ts-rest/nest';
import { success } from '@/common/ts-rest';
@Controller()
export class TeamController {
@TsRestHandler(teamContract.getInfo)
async getInfo() {
return tsRestHandler(teamContract.getInfo, async ({ params }) => {
const team = await this.teamService.getInfo(params.teamId);
return success(team);
});
}
}错误码系统
错误码按业务域组织,从 @repo/contracts/errors 导出。
错误码域
| 域 | 前缀 | 导入 |
| ------- | ------- | ------------------ |
| Team | 1xx | TeamErrorCode |
| User | 2xx | UserErrorCode |
| Space | 3xx | SpaceErrorCode |
| Folder | 4xx | FolderErrorCode |
| File | 5xx | FileErrorCode |
| Comment | 56x-57x | CommentErrorCode |
| Payment | 7xx | PaymentErrorCode |
| Common | 9xx | CommonErrorCode |
后端错误处理
import { TeamErrorCode, apiError } from '@repo/contracts/errors';
import { ApiExceptionV2 } from '@/filter/exception/api-exception-v2';
// 简单错误
throw apiError(TeamErrorCode.TeamNotFound);
// 带数据的错误
throw apiError(TeamErrorCode.TeamNotFound, { teamId: '123' });
// 直接使用 ApiExceptionV2
throw ApiExceptionV2.fromCode(TeamErrorCode.TeamNotFound);前端错误处理
import { TeamErrorCode, handleApiError, createErrorHandler } from '@repo/contracts/errors';
// 创建类型安全的错误处理器
const teamErrorHandler = createErrorHandler({
[TeamErrorCode.TeamNotFound]: {
message: '团队不存在',
action: () => router.push('/teams'),
},
[TeamErrorCode.TeamOpNoPermission]: {
message: '您没有权限执行此操作',
},
});
// 处理 API 响应
const handleTeamError = (errorCode: number) => {
const result = teamErrorHandler(errorCode);
if (result) {
toast.error(result.message);
result.action?.();
}
};契约中的类型化错误响应
import { TeamErrorCode } from '../errors/domains/team.errors';
import { createTypedErrorResponse } from '../errors/error-response';
export const teamContract = c.router({
getInfo: {
method: 'GET',
path: '/:teamId',
responses: {
200: createApiResponse(TeamInfoSchema),
400: createTypedErrorResponse([
TeamErrorCode.TeamNotFound,
TeamErrorCode.TeamMemberViewNoPermission,
] as const),
},
},
});验证 Schema
import { TeamNameSchema, PaginationQuerySchema } from '@repo/contracts/schemas';
// 在表单中使用
const teamForm = useForm({
resolver: zodResolver(
z.object({
name: TeamNameSchema,
}),
),
});
// 在 API 查询中使用
const query = PaginationQuerySchema.parse(searchParams);目录结构
src/
├── api/ # API 契约
│ ├── team.contract.ts
│ ├── user.contract.ts
│ ├── space.contract.ts
│ └── index.ts
├── errors/ # 错误码系统
│ ├── domains/ # 域错误定义
│ │ ├── team.errors.ts
│ │ ├── user.errors.ts
│ │ └── ...
│ ├── codes.ts # 统一错误码
│ ├── error-response.ts # 类型化错误响应辅助函数
│ └── index.ts
├── schemas/ # Zod Schema
│ ├── team.schema.ts
│ ├── user.schema.ts
│ └── ...
├── base.ts # 基础 Schema (createApiResponse 等)
└── index.ts # 主导出构建
pnpm --filter @repo/contracts build迁移
从旧错误系统迁移请参阅:
错误码系统状态
✅ 已完成:
- 所有错误码已迁移到
@packages/contracts/src/errors - 错误码枚举已改为字符串格式(避免打包类型问题)
- i18n 错误消息已迁移到
errors.json - 过期文件已清理
✅ 已完成:
- 所有文件已迁移到新系统或桥接文件
code.enum.ts已无任何直接引用(可安全删除)
📊 实施进度:100% ✅
NPM 发布流程
发布说明
本包在 workspace 内使用名称 @repo/contracts,发布到 npmjs 时使用名称 @dofe/sso-contracts。
发布脚本会自动处理名称转换:
prepack- 发布前将名称改为@dofe/sso-contractspostpack- 发布后恢复为@repo/contracts
发布命令
从根目录发布(推荐)
# 在 sso.dofe.ai 根目录执行
# 发布单个包
pnpm release:contracts # 发布 @dofe/sso-contracts
pnpm release:contracts:otp # 带 OTP 发布
# 批量发布所有包
pnpm release:all # 发布 contracts、hooks、ui
pnpm release:all:otp # 带 OTP 批量发布从包目录发布
# 进入 contracts 目录
cd sso.dofe.ai/packages/contracts
# 手动发布流程
pnpm build
node scripts/prepack.mjs
npm publish --access public --ignore-scripts --otp=<你的OTP码>
node scripts/postpack.mjs从根目录发布流程详解
pnpm release:contracts:otp执行步骤:
- 进入
packages/contracts目录 - 运行
prepack修改 package.json(名称改为@dofe/sso-contracts) - 执行
npm publish --access public --ignore-scripts --otp - 运行
postpack恢复 package.json 原始状态
前置条件
npm 账户登录:
npm login验证登录状态:
npm whoami
其他项目引用
发布后,agents.dofe.ai、models.dofe.ai 等项目可通过以下方式引用:
{
"dependencies": {
"@dofe/sso-contracts": "^0.1.0"
}
}import { InternalTenantSchema, TeamMemberRoleSchema } from '@dofe/sso-contracts';
import { internalContract } from '@dofe/sso-contracts/api';可用导出
| 导出路径 | 内容 |
| -------------------------------------- | ---------------------------------- |
| @dofe/sso-contracts | 所有 schemas、contracts、errors |
| @dofe/sso-contracts/api | API contracts |
| @dofe/sso-contracts/schemas | Zod schemas |
| @dofe/sso-contracts/schemas/internal | Internal API schemas (Tenant/Team) |
| @dofe/sso-contracts/errors | Error codes |
| @dofe/sso-contracts/base | Base utilities (createApiResponse) |
常见问题
Q: 发布失败 "You do not have permission"
A: 确保 npm 账户有权限发布 @dofe scope 包。需要先在 npmjs 创建或加入 @dofe organization。
Q: 发布失败 "Package already exists"
A: 版本号已存在,需要升级版本:
pnpm release:patchQ: 本地安装失败 "Cannot resolve @repo/contracts"
A: 这是因为 workspace 依赖问题。确保在 sso.dofe.ai 项目根目录运行 pnpm install。
