ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Corsair Jira 插件接入指南:32 个类型化接口、本地数据同步与 Webhook 事件

Corsair Jira 插件接入指南:32 个类型化接口、本地数据同步与 Webhook 事件 Corsair Jira 插件接入指南32 个类型化接口、本地数据同步与 Webhook 事件【免费下载链接】corsairConnect your users to their apps项目地址: https://gitcode.com/GitHub_Trending/corsa/corsair导读corsair-dev/jira是 Corsair 生态中的 Jira 官方插件它把 Jira Cloud 的 REST API v3 与 Agile REST API v1.0 封装成 32 个类型安全的jira.api.*操作、6 张本地同步数据表与 3 种入站 Webhook 事件让 AI Agent 可以直接通过一个客户端完成查问题、改状态、建项目、排迭代、回评论等完整工作流。读完本文你将掌握该插件的安装、认证、端点调用、本地数据查询与 Webhook 接入的全套实战方法并理解其底层 HTTP 客户端与错误处理机制。插件概览一个 Jira 连接层corsair-dev/jira位于仓库 packages/jira 目录是 Corsair 标准插件形态的参考实现之一。从源码结构看插件由四层组成见 packages/jira/index.ts端点层endpoints/目录按业务域拆分为 issues.ts、comments.ts、projects.ts、sprints.ts、users.ts覆盖问题、评论、项目、迭代、用户与用户组六大域客户端层client.ts 封装 Jira REST API v3 与 Agile API v1.0 两类请求通道以及附件上传数据模型层schema/database.ts 定义了 6 个可本地同步的实体boards、comments、issues、projects、sprints、usersWebhook 层webhooks/ 提供 3 种事件的匹配、HMAC 签名校验与多租户识别。所有端点的输入/输出均通过 Zod 模式定义于 endpoints/types.ts并在插件注册时暴露为endpointSchemas这是类型安全的来源——调用方与响应方共用同一套模式非法字段在编译期即被拦截。安装与环境要求根据 packages/jira/README.md使用 pnpm 安装pnpm add corsair-dev/jira也可以使用你习惯的包管理器npm / yarn / bun同时安装corsair与插件本体npm install corsair corsair-dev/jira插件在 packages/jira/package.json 中声明了两个 peer 依赖依赖版本要求用途corsair0.1.0提供插件运行时、HTTP 请求、数据库与 Webhook 基础设施zod^4.1.13端点输入/输出与 Webhook 负载的模式校验当前仓库中该插件版本为0.1.5类型入口为./dist/index.d.ts产物为 ESM 格式。快速接入注册插件与连接租户在 docs/plugins/jira/overview.mdx 中给出了标准的接入流程。首先创建一个corsair.ts并注册插件import Database from better-sqlite3; import { createCorsair } from corsair; import { jira } from corsair-dev/jira; export const corsair createCorsair({ plugins: [ jira(), ], database: new Database(corsair.db), kek: process.env.CORSAIR_KEK!, hub: { projectApiKey: process.env.CORSAIR_API_KEY!, signingSecret: process.env.CORSAIR_SIGNING_SECRET!, }, });Corsair 默认支持多租户multi-tenancy用corsair.withTenant(id)隔离不同用户/Jira 站点的凭据与数据。接入方通过 Hub 生成 connect 链接让租户在浏览器中完成授权并把结果回传给应用const { connectUrl } await corsair.manage.connect.createLink({ plugin: jira, tenantId: acme, }); // redirect the users browser to connectUrl首次调用时Corsair 会提示租户提供 API Key详见下文认证章节。关于 KEK、Hub 密钥与租户隔离的细节可分别参考 docs/getting-started/set-up-with-your-agent.mdx 与 docs/concepts/multi-tenancy.mdx。插件工厂选项jira()工厂函数接受 JiraPluginOptions 配置选项类型说明authTypeapi_key认证方式默认为api_keykeystring全局 API Key优先级高于数据库中的租户凭据webhookSecretstring全局 Webhook 签名密钥也可由租户单独存储cloudUrlstringJira Cloud 地址如https://your-domain.atlassian.net所有 API 调用必需hooksobject端点执行前/后的生命周期钩子webhookHooksobjectWebhook 处理前/后的钩子errorHandlersCorsairErrorHandler自定义错误处理器覆盖插件默认行为permissionsPluginPermissionsConfig权限配置使用 Jira 端点树的点分路径非法路径会在编译期报错认证API Key 与租户凭据packages/jira/README.md 明确Auth: API keyCorsair 会在租户首次使用时提示输入凭据。Jira Cloud 使用 Basic Auth即邮箱 API Token的组合email:apiToken客户端会将其 Base64 编码后放入Authorization头见 client.ts。获取并存储凭据根据 docs/plugins/jira/get-credentials.mdx登录 Atlassian 账号进入Security → API tokens页面点击Create API token命名如 Corsair Integration后创建立即复制 Token只显示一次妥善保存。随后通过 Corsair CLI 存储为租户凭据pnpm corsair setup --pluginjira api_keyyour-api-tokenJira Cloud URL如https://yourcompany.atlassian.net会作为独立账号字段cloud_url存储。这一点在 index.ts 的jiraAuthConfig中有专门设计——它在基础api_key配置上扩展了account: [cloud_url]字段使云端地址可以通过corsair auth动态设置而无需硬编码在插件选项里。keyBuilder 的取 key 优先级从 index.ts 的keyBuilder实现可以梳理出凭据解析顺序Webhook 来源优先使用options.webhookSecret否则从ctx.keys.get_webhook_signature()读取租户的webhook_signature缺失则抛出[auth-missing:jira:webhook_signature]错误端点来源优先使用options.key全局配置否则从ctx.keys.get_api_key()读取租户api_key缺失则抛出AuthMissingError(jira, api_key)。每个端点处理器还会通过ctx.keys.get_cloud_url()获取目标站点地址二者共同构成一次完整调用的认证上下文。OAuth 配置说明尽管文档推荐并使用 API Key源码中的oauthConfig仍内置了 Atlassian OAuth 端点与授权范围read:jira-work、write:jira-work、read:jira-user、offline_accessaudience 为api.atlassian.com。可以推断这是为未来或自托管场景预留的 OAuth 能力当前默认与文档化认证方式以 API Key 为准。端点总览32 个类型化操作下表完整列出了插件暴露的全部操作来自 packages/jira/README.md同时与 index.ts 中的jiraEndpointsNested、jiraEndpointMeta一致。操作 ID 为jira.api.operation的完整路径风险级别分为read、write、destructive三档OperationOperation IDRiskDescriptioncomments.addjira.api.comments.addwriteAdd a comment to a Jira issuecomments.deletejira.api.comments.deletedestructiveDelete a comment from a Jira issue [DESTRUCTIVE]comments.getjira.api.comments.getreadGet a specific comment on a Jira issuecomments.listjira.api.comments.listreadList all comments on a Jira issuecomments.updatejira.api.comments.updatewriteUpdate a comment on a Jira issuegroups.createjira.api.groups.createwriteCreate a new Jira groupgroups.getAlljira.api.groups.getAllreadGet all Jira groupsissues.addAttachmentjira.api.issues.addAttachmentwriteAdd an attachment to a Jira issueissues.addWatcherjira.api.issues.addWatcherwriteAdd a watcher to a Jira issueissues.assignjira.api.issues.assignwriteAssign a Jira issue to a userissues.bulkCreatejira.api.issues.bulkCreatewriteBulk create multiple Jira issuesissues.bulkFetchjira.api.issues.bulkFetchreadBulk fetch multiple Jira issues by ID or keyissues.createjira.api.issues.createwriteCreate a new Jira issueissues.deletejira.api.issues.deletedestructiveDelete a Jira issue [DESTRUCTIVE]issues.editjira.api.issues.editwriteEdit an existing Jira issueissues.getjira.api.issues.getreadGet a Jira issue by ID or keyissues.getTransitionsjira.api.issues.getTransitionsreadGet available transitions for a Jira issueissues.linkIssuesjira.api.issues.linkIssueswriteLink two Jira issues togetherissues.removeWatcherjira.api.issues.removeWatcherwriteRemove a watcher from a Jira issueissues.searchjira.api.issues.searchreadSearch issues using JQLissues.transitionjira.api.issues.transitionwriteTransition a Jira issue to a new statusprojects.createjira.api.projects.createwriteCreate a new Jira projectprojects.getjira.api.projects.getreadGet a Jira project by ID or keyprojects.getRolesjira.api.projects.getRolesreadGet project roles for a Jira projectprojects.listjira.api.projects.listreadList Jira projectssprints.createjira.api.sprints.createwriteCreate a new sprint on a Jira boardsprints.listjira.api.sprints.listreadList sprints for a Jira boardsprints.listBoardsjira.api.sprints.listBoardsreadList Jira boardssprints.moveIssuesjira.api.sprints.moveIssueswriteMove issues to a sprintusers.findjira.api.users.findreadSearch for Jira usersusers.getAlljira.api.users.getAllreadGet all Jira usersusers.getCurrentjira.api.users.getCurrentreadGet the currently authenticated Jira user每个操作的完整输入/输出字段、类型与必填性均可在 docs/plugins/jira/api.mdx 中查阅该页由插件 Zod 模式生成。核心操作实战以下示例均基于corsair.withTenant(acme)获取的租户实例调用参数采用 Zod 模式中的snake_case命名见 endpoints/types.ts。问题Issues域创建问题——最小参数为project_key与summary其余可选const tenant corsair.withTenant(acme); await tenant.jira.api.issues.create({ project_key: DEMO, summary: Fix login redirect bug, issue_type: Task, // 默认为 Task description: Users are redirected to /home instead of /dashboard, assignee: 712020:abc123, // accountId priority: High, labels: [frontend, auth], due_date: 2026-09-30, });从 issues.ts 的实现可见插件会把输入映射为 Jira REST v3 的fields结构其中description会通过makeAdf()自动包装为 Atlassian Document FormatADF即{ version: 1, type: doc, content: [{ type: paragraph, content: [{ type: text, text }] }] }——你无需关心 ADF 细节传普通字符串即可。查询与搜索// 按 ID 或 Key 获取 await tenant.jira.api.issues.get({ issue_id_or_key: DEMO-42, fields: summary,status,assignee, expand: renderedFields, }); // JQL 搜索 await tenant.jira.api.issues.search({ jql: project DEMO AND status In Progress ORDER BY updated DESC, start_at: 0, max_results: 50, });状态流转——通常先取可用流转再执行const { transitions } await tenant.jira.api.issues.getTransitions({ issue_id_or_key: DEMO-42, }); await tenant.jira.api.issues.transition({ issue_id_or_key: DEMO-42, transition_id: transitions![0].id!, comment: Moving to Done per sprint review, });transition支持附带评论插件会将其同样包装为 ADF 追加到变更记录中。批量操作await tenant.jira.api.issues.bulkCreate({ issues: [ { project_key: DEMO, summary: Issue A, issue_type: Task }, { project_key: DEMO, summary: Issue B, priority: High }, ], }); await tenant.jira.api.issues.bulkFetch({ issue_ids_or_keys: [DEMO-1, DEMO-2], fields: [summary, status], });附件上传——两种方式二选一file_contentBase64 内容或file_url远程地址Zod 模式通过refine强制至少提供其一// 方式一Base64 内容 await tenant.jira.api.issues.addAttachment({ issue_id_or_key: DEMO-42, file_name: screenshot.png, file_content: iVBORw0KGgoAAAANSUhEUg..., mime_type: image/png, }); // 方式二远程 URL await tenant.jira.api.issues.addAttachment({ issue_id_or_key: DEMO-42, file_name: design.pdf, file_url: https://cdn.example.com/design.pdf, });评论Comments域// 添加评论支持 visibility 限制到角色/群组 await tenant.jira.api.comments.add({ issue_id_or_key: DEMO-42, comment: Fixed in build #1201, please verify, visibility_type: role, visibility_value: Developers, }); // 分页列出评论 await tenant.jira.api.comments.list({ issue_id_or_key: DEMO-42, start_at: 0, max_results: 20, order_by: -created, });项目、迭代、用户与用户组// 创建项目默认 software 类型、UNASSIGNED 指派策略 await tenant.jira.api.projects.create({ key: DEMO, name: Demo Project, project_type_key: software, description: Demo project for the AI assistant, }); // 列出项目 / 获取角色 await tenant.jira.api.projects.list({ query: demo, max_results: 10 }); await tenant.jira.api.projects.getRoles({ project_id_or_key: DEMO }); // 迭代域走 Agile API v1.0 const { values: boards } await tenant.jira.api.sprints.listBoards({ project_key_or_id: DEMO, }); await tenant.jira.api.sprints.create({ origin_board_id: boards![0]!.id!, name: Sprint 24, goal: Ship onboarding v2, }); await tenant.jira.api.sprints.moveIssues({ sprint_id: 124, issue_keys: [DEMO-42, DEMO-43], }); // 用户域 await tenant.jira.api.users.getCurrent({}); await tenant.jira.api.users.find({ query: alice, max_results: 5 }); // 用户组域 await tenant.jira.api.groups.getAll({}); await tenant.jira.api.groups.create({ name: support-team });注意项目、迭代、用户等端点同样会在成功后把返回实体写入本地数据库详见本地数据同步章节实现远端操作 本地可查询的双通道一致性。源码级原理HTTP 客户端与错误处理双 API 通道client.ts 提供了两个请求入口makeJiraRequest基础路径为${cloudUrl}/rest/api/3服务所有非迭代端点makeJiraAgileRequest基础路径为${cloudUrl}/rest/agile/1.0服务看板/迭代端点sprints.*。两者统一采用 Basic AuthBasic base64(email:apiToken)cloudUrl会先经过sanitizeCloudUrl去除尾部斜杠再拼接。GET/DELETE 支持 query 参数POST/PUT/PATCH 携带 JSON body。限流与重试插件内置了 Jira 限流配置JIRA_RATE_LIMIT_CONFIG启用限流、最多重试 3 次、初始退避 1 秒、退避倍率 2并读取Retry-After响应头。当请求经过corsair/http的request()时该配置会被传入以驱动自动重试。附件上传的特殊处理uploadJiraAttachment不使用 JSON而是构造multipart/form-data若提供file_url先fetch拉取内容mime 类型从响应头自动识别否则把file_contentBase64解码为 Buffer请求携带X-Atlassian-Token: no-check头Jira 附件接口的防 CSRF 要求且故意不设置 Content-Type由 fetch 自动生成 multipart boundary。分层错误处理error-handlers.ts 定义了四个错误处理器与corsair/http的ApiError协同处理器匹配条件行为RATE_LIMIT_ERRORHTTP 429 或消息含rate_limit/ratelimited/429最多重试 5 次尊重Retry-AfterAUTH_ERRORHTTP 401 或unauthorized/authentication failed/invalid_auth不重试提示检查email:apiToken格式PERMISSION_ERRORHTTP 403 或permission_denied/forbidden/access_denied不重试记录告警DEFAULT兜底记录错误不重试你可以在jira({ errorHandlers: ... })中覆盖或扩展这些默认行为index.ts中通过{ ...errorHandlers, ...options.errorHandlers }合并。本地数据同步6 个可搜索实体插件会把调用结果与 Webhook 事件持续同步到本地数据库。6 个实体及其 Zod 模型定义在 schema/database.ts实体主要字段boardsid(number)、name、type、projectId、projectKey、projectNamecommentsid、issueKey、body、authorAccountId、authorDisplayName、created、updatedissuesid、key、summary、description、status、assignee*、reporter*、priority、issueType、projectKey、projectId、labelsprojectsid、key、name、description、projectTypeKey、leadAccountId、leadDisplayNamesprintsid(number)、name、state、goal、startDate、endDate、originBoardIdusersaccountId、displayName、emailAddress、active、timeZone、locale同步写入通过ctx.db.entity.upsertByEntityId(...)完成例如 issues.ts 在create、get、search、bulkCreate、bulkFetch成功后都会落库Webhook 处理器也会在收到事件时更新对应行见 webhooks/new-issue.ts。edit、assign等只持有issue_id_or_key可能是 Key 而非数字 ID的操作会刻意跳过落库交由下一次issues.get刷新数据——源码注释中明确记录了这一设计取舍。查询本地数据const rows await corsair.jira.db.issues.search({ data: { status: In Progress, projectKey: DEMO }, limit: 100, offset: 0, });每个实体的可过滤字段与操作符各不相同docs/plugins/jira/database.mdx 给出了完整矩阵规律如下字符串字段支持equals、contains、startsWith、endsWith、in数字字段如boards.id、sprints.id、sprints.originBoardId支持equals、gt、gte、lt、lte、increatedAt日期字段支持equals、before、after、betweenusers.active布尔字段仅支持equals。所有.search()均接受limit与offset做分页。Webhook3 种事件与签名验证packages/jira/README.md 说明插件处理 3 种 Webhook 事件映射关系见 index.ts 的jiraWebhooksNested事件路径Webhook Event 值触发时机issues.newIssuejira:issue_created新建问题issues.updatedIssuejira:issue_updated问题被更新含 changelog 变更明细projects.newProjectproject_created新建项目接收 Webhook 的 HTTP Handler把 Jira 的订阅 URL 指向你的 Corsair HTTP 处理端点Next.js 路由示例来自 docs/plugins/jira/webhooks.mdximport { processWebhook } from corsair; import { corsair } from /server/corsair; export async function POST(request: Request) { const headers Object.fromEntries(request.headers); const body await request.json(); const result await processWebhook(corsair, headers, body); return result.response; }匹配与签名验证事件匹配createJiraMatch(webhookEvent)webhooks/types.ts解析请求体并比对webhookEvent字段插件级匹配器则检查请求头中是否含x-atlassian-webhook-identifierindex.ts 的pluginWebhookMatcher。签名验证verifyJiraWebhookSignature使用 HMAC-SHA256 校验x-hub-signature头格式为sha256hash并用crypto.timingSafeEqual做常数时间比较防止时序攻击。签名密钥来自options.webhookSecret或租户的webhook_signature。验证失败时返回 HTTP 401。多租户识别tenant-matcher.ts 从负载的issue.self、issue.fields.project.self、project.self、user.self中提取站点 host得到cloud_url后按此维度路由到对应租户。使用 webhookHooks 处理事件jira({ webhookHooks: { issues: { newIssue: { before(ctx, args) { // 事件处理前记录、鉴权、去重 return { ctx, args }; }, after(ctx, response) { // 事件处理后通知、审计 }, }, updatedIssue: { before(ctx, args) { return { ctx, args }; }, after(ctx, response) {}, }, }, projects: { newProject: { before(ctx, args) { return { ctx, args }; }, after(ctx, response) {}, }, }, }, })各事件的完整负载结构issue、user、changelog、project的嵌套类型可在 docs/plugins/jira/webhooks.mdx 查阅Zod 模式定义见 webhooks/types.ts。收到事件后插件默认行为是同步对应实体到本地数据库如newIssue会 upsert 问题与用户行随后触发after钩子。权限配置限制 Agent 能做什么JiraPluginOptions.permissions用于控制 AI Agent 允许执行的操作采用点分路径引用端点树如issues.delete、comments.delete路径非法时会产生编译期类型错误jira({ permissions: { issues.delete: false, // 禁止删除问题 issues.transition: true, // 允许状态流转 comments.add: true, // 允许添加评论 }, })该机制与 docs/concepts/permissions.mdx 中的权限模型一致配合端点元数据中的riskLevelread/write/destructive可对不同风险等级的操作做精细化放行。测试与验证插件自带两套测试可作为验证行为与理解调用链的参考api.test.ts针对真实 Jira Cloud 的集成型类型测试通过环境变量JIRA_API_KEY、JIRA_CLOUD_URL驱动覆盖users、projects、issues、comments等域每个响应都会用JiraEndpointOutputSchemas.*.parse()做运行时校验client.test.ts 与 webhooks/types.test.ts客户端与 Webhook 类型层面的测试。本地运行测试与构建pnpm --filter corsair-dev/jira test pnpm --filter corsair-dev/jira build # tsc --build --force tsup许可与参考插件以Apache-2.0许可发布见 packages/jira/README.md 与 packages/jira/package.json。更完整的参考文档含每个端点的输入/输出类型、数据库过滤操作符、Webhook 负载示例位于 docs/plugins/jira 目录overview.mdx接入总览与快速开始api.mdx全部jira.api.*操作与类型参考database.mdx同步实体与搜索过滤操作符webhooks.mdx事件路径、负载与webhookHooks示例get-credentials.mdxAPI Token 与 Webhook 密钥获取步骤若要将这些操作暴露给 AI 助手调用可参考 docs/mcp-adapters/mcp-adapters.mdx 的 MCP 适配方案把插件能力直接映射为 MCP 工具。【免费下载链接】corsairConnect your users to their apps项目地址: https://gitcode.com/GitHub_Trending/corsa/corsair创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表