插件后端工具与封装文档

本文档只整理 Chatbuddy AI 插件/扩展后端可以直接使用的工具与封装。示例参考
templates/extension-starter/src/api

导入总览

类型导入方式用途
基础 Controller/Service@chatbuddy-ai/base日志、分页结果、CRUD、事务、分页查询
插件 Controller/Entity 装饰器@chatbuddy-ai/core/decorators插件前台接口、控制台接口、插件实体
通用装饰器@chatbuddy-ai/decorators/...公开接口、当前用户、文件 URL、响应转换
DTO@chatbuddy-ai/dto分页查询 DTO
Pipe@chatbuddy-ai/pipe/param-validate.pipeUUID 参数校验
错误封装@chatbuddy-ai/errors统一业务错误
数据库@chatbuddy-ai/db/@nestjs/typeorm@chatbuddy-ai/db/typeormTypeORM Module、Repository、装饰器、查询操作符
平台实体@chatbuddy-ai/db/entities使用平台已有实体,如User
插件 SDK@chatbuddy-ai/extension-sdk平台用户、AI、计费、tsup 构建配置
工具函数@chatbuddy-ai/utilswhere 构造、路径、类型转换、版本、文件、安全等

插件 Controller 装饰器

ExtensionWebController

导入:
import { ExtensionWebController } from "@chatbuddy-ai/core/decorators";
用途:声明插件前台 API Controller。
import { BaseController } from "@chatbuddy-ai/base";
import { ExtensionWebController } from "@chatbuddy-ai/core/decorators";
import { Public } from "@chatbuddy-ai/decorators/public.decorator";
import { UUIDValidationPipe } from "@chatbuddy-ai/pipe/param-validate.pipe";
import { Get, Param, Query } from "@nestjs/common"; @ExtensionWebController("article")
export class ArticleWebController extends BaseController { constructor(private readonly articleService: ArticleService) { super; } @Get @Public async findAll(@Query query: QueryArticleDto) { return this.articleService.list(query); } @Get(":id") @Public async findOne(@Param("id", UUIDValidationPipe) id: string) { return this.articleService.findOneById(id); }
}
可用参数:
写法介绍
@ExtensionWebController("article")配置 Controller path
@ExtensionWebController({ path: "article" })对象写法
@ExtensionWebController({ path: "article", skipAuth: true })整个 Controller 跳过鉴权
内置能力:
能力介绍
插件路由前缀默认/{extensionIdentifier}/api/{path}
环境前缀如果存在VITE_APP_WEB_API_PREFIX,使用该前缀
插件 metadata配置插件包名和 Web Controller 标记
鉴权控制skipAuth会配置公开 metadata
path 校验path 不能包含/:

ExtensionConsoleController

导入:
import { ExtensionConsoleController } from "@chatbuddy-ai/core/decorators";
用途:声明插件控制台 API Controller。
import { BaseController } from "@chatbuddy-ai/base";
import { ExtensionConsoleController } from "@chatbuddy-ai/core/decorators";
import { Playground } from "@chatbuddy-ai/decorators/playground.decorator";
import { type UserPlayground } from "@chatbuddy-ai/db";
import { UUIDValidationPipe } from "@chatbuddy-ai/pipe/param-validate.pipe";
import { Body, Delete, Get, Param, Post, Query } from "@nestjs/common"; @ExtensionConsoleController("article", "文章管理")
export class ArticleController extends BaseController { constructor(private readonly articleService: ArticleService) { super; } @Post async create(@Body dto: CreateArticleDto, @Playground user: UserPlayground) { return this.articleService.createArticle(dto, user.id); } @Get async findAll(@Query query: QueryArticleDto) { return this.articleService.list(query); } @Delete(":id") async remove(@Param("id", UUIDValidationPipe) id: string) { await this.articleService.delete(id); return { success: true }; }
}
可用参数:
写法介绍
@ExtensionConsoleController("article", "文章管理")配置 path 和权限组名称
@ExtensionConsoleController({ path: "article" }, "文章管理")对象写法
@ExtensionConsoleController({ path: "article", skipAuth: true }, "文章管理")跳过鉴权
内置能力:
能力介绍
插件路由前缀默认/{extensionIdentifier}/consoleapi/{path}
环境前缀如果存在VITE_APP_CONSOLE_API_PREFIX,使用该前缀
插件 metadata配置插件包名和 Console Controller 标记
权限组 metadata自动配置code: "${extensionIdentifier}@${path}"name: groupName
path 校验path 不能包含/:

插件 Entity

ExtensionEntity

导入:
import { ExtensionEntity } from "@chatbuddy-ai/core/decorators";
用途:声明插件实体并自动归入插件 schema。
import { ExtensionEntity } from "@chatbuddy-ai/core/decorators";
import { Column, CreateDateColumn, PrimaryGeneratedColumn, UpdateDateColumn,
} from "@chatbuddy-ai/db/typeorm"; @ExtensionEntity
export class Article { @PrimaryGeneratedColumn("uuid") id: string; @Column({ length: 200, comment: "文章标题" }) title: string; @Column({ type: "text", nullable: true, comment: "摘要" }) summary?: string; @CreateDateColumn createdAt: Date; @UpdateDateColumn updatedAt: Date;
}
可用写法:
写法介绍
@ExtensionEntity表名默认用类名转 snake_case
@ExtensionEntity("article")指定表名
@ExtensionEntity({ name: "article" })使用 TypeORMEntityOptions
内置能力:
能力介绍
插件 schema根据插件安装目录推导 schema
表名处理支持默认表名和自定义表名
TypeORM Entity内部应用 TypeORMEntity装饰器

基础 Controller

BaseController

导入:
import { BaseController } from "@chatbuddy-ai/base";
可用能力:
能力介绍
logger自动创建 Nest Logger,context 为子类名
paginationResult组装标准分页响应
import { BaseController } from "@chatbuddy-ai/base"; export class ArticleController extends BaseController { async list(dto: QueryArticleDto) { this.logger.log("query article list"); return this.articleService.list(dto); }
}
分页响应格式:
{ items: T[]; total: number; page: number; pageSize: number; totalPages: number;
}

基础 Service

BaseService

导入:
import { BaseService } from "@chatbuddy-ai/base";
用法:
import { BaseService } from "@chatbuddy-ai/base";
import { InjectRepository } from "@chatbuddy-ai/db/@nestjs/typeorm";
import { Repository } from "@chatbuddy-ai/db/typeorm";
import { HttpErrorFactory } from "@chatbuddy-ai/errors";
import { Injectable } from "@nestjs/common"; import { Article } from "../../../db/entities/article.entity";
import { CreateArticleDto, QueryArticleDto } from "../dto"; @Injectable
export class ArticleService extends BaseService<Article> { constructor( @InjectRepository(Article) private readonly articleRepository: Repository<Article>, ) { super(articleRepository); } async createArticle(dto: CreateArticleDto) { return this.create(dto); } async list(query: QueryArticleDto) { const where = query.title ? this.ilike("title", query.title) : {}; return this.paginate(query, { where, order: { createdAt: "DESC" }, }); } async publish(id: string) { const article = await this.findOneById(id); if (!article) { throw HttpErrorFactory.notFound("文章不存在"); } return this.updateById(id, { status: "published" }); }
}
可用方法:
方法介绍
create创建单条记录
createMany批量创建
updateById按 id 更新
update按条件更新
findOneById按 id 查询
findOne按条件查询单条
findAll查询列表
count计数
delete移除
deleteMany批量移除
restore恢复软移除记录
paginateRepository 分页
paginateQueryBuilderQueryBuilder 分页
createTransaction创建事务
withTransaction在事务中执行
withRetry重试执行
applyLockToFindOptions查询锁配置
查询辅助方法:
方法介绍
ilike(field, value)PostgreSQL 不区分大小写模糊搜索
textSearch(field, value)PostgreSQL 全文搜索
jsonQuery(field, path, value)JSON 字段查询
arrayContains(field, values)数组包含查询
字段过滤:
选项介绍
includeFields只返回指定字段,支持author.nickname
excludeFields排除指定字段,支持嵌套字段
return this.findOneById(id, { relations: ["author"], includeFields: ["id", "title", "author.id", "author.nickname"] as const,
});

DTO 和 Pipe

PaginationDto

导入:
import { PaginationDto } from "@chatbuddy-ai/dto";
可用字段:
字段默认值介绍
page1当前页
pageSize15每页数量
import { PaginationDto } from "@chatbuddy-ai/dto";
import { IsOptional, IsString, IsUUID } from "class-validator"; export class QueryArticleDto extends PaginationDto { @IsOptional @IsString title?: string; @IsOptional @IsUUID categoryId?: string;
}

UUIDValidationPipe

导入:
import { UUIDValidationPipe } from "@chatbuddy-ai/pipe/param-validate.pipe";
import { Get, Param } from "@nestjs/common"; @Get(":id")
async findOne(@Param("id", UUIDValidationPipe) id: string) { return this.articleService.findOneById(id);
}

通用装饰器

Public

导入:
import { Public } from "@chatbuddy-ai/decorators/public.decorator";
用途:标记公开接口。
@Get("published")
@Public
async getPublished { return this.articleService.getPublishedArticles;
}

Playground

导入:
import { Playground } from "@chatbuddy-ai/decorators/playground.decorator";
用途:获取当前登录用户上下文。
import { type UserPlayground } from "@chatbuddy-ai/db"; @Post
async create(@Body dto: CreateArticleDto, @Playground user: UserPlayground) { return this.articleService.createArticle(dto, user.id);
}
支持获取指定属性:
async create(@Playground("id") userId: string) { return userId;
}

BuildFileUrl

导入:
import { BuildFileUrl } from "@chatbuddy-ai/decorators";
用途:把文件字段转换为完整可访问 URL。
@Get(":id")
@BuildFileUrl(["cover", "author.avatar", "items.*.thumbnail"])
async findOne(@Param("id", UUIDValidationPipe) id: string) { return this.articleService.findOneById(id);
}
可用写法:
写法介绍
"cover"普通字段
"author.avatar"嵌套字段
"items.*.thumbnail"数组通配字段
{ field: "images", isArray: true }数组字段

SkipTransform

导入:
import { SkipTransform } from "@chatbuddy-ai/decorators";
用途:跳过统一响应转换。
@Get("raw")
@SkipTransform
async raw { return "plain text";
}

错误封装

HttpErrorFactory

导入:
import { HttpErrorFactory } from "@chatbuddy-ai/errors";
可用方法:
方法介绍
badRequest(message)参数或业务状态错误
unauthorized(message)未登录或认证失败
forbidden(message)无权限
notFound(message)资源不存在
internal(message)服务内部错误
if (!article) { throw HttpErrorFactory.notFound("文章不存在");
} if (!category) { throw HttpErrorFactory.badRequest("栏目不存在");
}
其他导出:
import { ApplicationError, HttpError, HttpStatus } from "@chatbuddy-ai/errors";

数据库工具

TypeORM Module 和 Repository

导入:
import { InjectRepository, TypeOrmModule } from "@chatbuddy-ai/db/@nestjs/typeorm";
import { Repository } from "@chatbuddy-ai/db/typeorm";
模块注册:
import { TypeOrmModule } from "@chatbuddy-ai/db/@nestjs/typeorm";
import { Module } from "@nestjs/common"; import { Article } from "../../db/entities/article.entity";
import { ArticleController } from "./controllers/console/article.controller";
import { ArticleWebController } from "./controllers/web/article.web.controller";
import { ArticleService } from "./services/article.service"; @Module({ imports: [TypeOrmModule.forFeature([Article])], controllers: [ArticleController, ArticleWebController], providers: [ArticleService], exports: [ArticleService],
})
export class ArticleModule {}
Repository 注入:
constructor( @InjectRepository(Article) private readonly articleRepository: Repository<Article>,
) {}

TypeORM 装饰器和操作符

导入:
import { Column, CreateDateColumn, In, Like, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn,
} from "@chatbuddy-ai/db/typeorm";
常用导出:
类型介绍
Column字段
PrimaryGeneratedColumn主键
CreateDateColumn创建时间
UpdateDateColumn更新时间
ManyToOneOneToManyJoinColumn关联
InLikeILikeRaw查询操作符
RepositoryTypeORM Repository
FindOptionsWhere查询条件类型

平台实体

导入:
import { User } from "@chatbuddy-ai/db/entities";
可用于插件实体关联平台用户:
import { User } from "@chatbuddy-ai/db/entities";
import { JoinColumn, ManyToOne } from "@chatbuddy-ai/db/typeorm"; @ManyToOne( => User, { nullable: true })
@JoinColumn({ name: "authorId" })
author?: User;

插件 SDK

PublicUserService

导入:
import { PublicUserService } from "@chatbuddy-ai/extension-sdk";
用途:读取平台用户信息。
constructor(private readonly userService: PublicUserService) {} async attachAuthor(authorId: string) { const author = await this.userService.findUserById(authorId); if (!author) { throw HttpErrorFactory.notFound("作者不存在"); } return author;
}

AiPublicModule 和 PublicAiModelService

导入:
import { AiPublicModule, PublicAiModelService } from "@chatbuddy-ai/extension-sdk";
模块使用:
import { AiPublicModule } from "@chatbuddy-ai/extension-sdk";
import { Module } from "@nestjs/common"; @Module({ imports: [AiPublicModule], providers: [GenerateService], exports: [GenerateService],
})
export class GenerateModule {}
Service 注入:
import { PublicAiModelService } from "@chatbuddy-ai/extension-sdk"; constructor(private readonly aiModelService: PublicAiModelService) {}

ExtensionBillingModule 和 ExtensionBillingService

导入:
import { ExtensionBillingModule, ExtensionBillingService } from "@chatbuddy-ai/extension-sdk";
模块使用:
import { ExtensionBillingModule } from "@chatbuddy-ai/extension-sdk";
import { Module } from "@nestjs/common"; @Module({ imports: [ExtensionBillingModule], providers: [GenerateService], exports: [GenerateService],
})
export class GenerateModule {}
Service 注入:
import { ExtensionBillingService } from "@chatbuddy-ai/extension-sdk"; constructor(private readonly billingService: ExtensionBillingService) {}
导出类型:
import type { ExtensionPowerDeductionOptions } from "@chatbuddy-ai/extension-sdk";

工具函数

buildWhere

导入:
import { buildWhere } from "@chatbuddy-ai/utils";
用途:过滤掉undefined条件,构造 TypeORM where。
import { Like } from "@chatbuddy-ai/db/typeorm";
import { buildWhere } from "@chatbuddy-ai/utils"; const where = buildWhere<Article>({ title: query.title ? Like(`%${query.title}%`) : undefined, categoryId: query.categoryId, status: query.status,
}); return this.paginate(query, { where });

类型转换工具

导入:
import { asArray, asBoolean, asDate, asDefined, asError, asJson, asNumber, asObject, asString,
} from "@chatbuddy-ai/utils";
工具介绍
asArray转数组
asString转字符串
asNumber转数字
asBoolean转布尔
asObject转对象
asDate转日期
asJson解析 JSON
asDefined过滤空值
asError转 Error

路径工具

导入:
import { joinPaths, joinRouterPaths, validatePath } from "@chatbuddy-ai/utils";
工具介绍
joinPaths拼接普通路径
joinRouterPaths拼接路由路径
validatePath校验路径片段

插件标识工具

导入:
import { parseExtensionIdentifier, parsePackageName } from "@chatbuddy-ai/utils";
工具介绍
parseExtensionIdentifier解析插件标识
parsePackageName解析包名

安全和版本工具

导入:
import { checkVersionCompatibility, decryptValue, maskSensitiveValue } from "@chatbuddy-ai/utils";
工具介绍
maskSensitiveValue脱敏字符串
decryptValue解密值
checkVersionCompatibility检查版本兼容

Promise 和流工具

导入:
import { createResolvablePromise, DelayedPromise, StreamUtils } from "@chatbuddy-ai/utils";
工具介绍
createResolvablePromise创建可外部 resolve/reject 的 Promise
DelayedPromise延迟 Promise 工具
StreamUtils流处理工具

消息内容工具

导入:
import { extractFilesFromMessageContent, extractTextFromMessageContent } from "@chatbuddy-ai/utils";
工具介绍
extractTextFromMessageContent从消息内容中提取文本
extractFilesFromMessageContent从消息内容中提取文件

Nest 常用导入

插件后端 Controller 和 Module 可以直接使用 Nest 标准装饰器:
import { Body, Delete, Get, Param, Patch, Post, Query } from "@nestjs/common";
import { Injectable, Module } from "@nestjs/common";
常用装饰器:
装饰器场景
@Module声明模块
@Injectable声明 Service
@GetGET 接口
@PostPOST 接口
@PatchPATCH 接口
@DeleteDELETE 接口
@Body求体
@Query查询参数
@Param路径参数

319 篇文档 · 内容同步自官方帮助中心