@tool-bridge/server 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/airtable-V6446SVY.js +792 -0
- package/dist/alt_text_generator_ai-HV7JZPDT.js +72 -0
- package/dist/amap-TTTVB6WS.js +755 -0
- package/dist/anthropic-JH3RA363.js +224 -0
- package/dist/apify-ETNN7ITU.js +262 -0
- package/dist/brave_search-3DDR2MMB.js +322 -0
- package/dist/chunk-CSJEZHQO.js +252 -0
- package/dist/chunk-JLTYA2B3.js +20121 -0
- package/dist/chunk-K7FVSFUX.js +333 -0
- package/dist/{chunk-6SMIQ6QU.js → chunk-KGYJEEBI.js} +2770 -21574
- package/dist/circleci-MX3TX3HC.js +409 -0
- package/dist/clerk-MRPORVF4.js +1036 -0
- package/dist/cloudflare_dns-OWP7DD7L.js +605 -0
- package/dist/cohere-GPECP66S.js +197 -0
- package/dist/confluence-BN7LZ6BC.js +436 -0
- package/dist/convertapi-SBEOFOFQ.js +161 -0
- package/dist/currencyapi-P2YY7Y7P.js +306 -0
- package/dist/deepseek-MWB3NYIN.js +205 -0
- package/dist/docker_hub-3JSCIGQ3.js +946 -0
- package/dist/dropbox-RFIBDAXO.js +1308 -0
- package/dist/dub-YVP57ELQ.js +706 -0
- package/dist/e2b-NFSUHTZR.js +305 -0
- package/dist/exa-KTDY6IV3.js +360 -0
- package/dist/fal_ai-OCUENLNQ.js +405 -0
- package/dist/feishu-5CWBQ7E5.js +225 -0
- package/dist/feishu_custom_bot-ZJR22OK6.js +240 -0
- package/dist/figma-YULGANSA.js +798 -0
- package/dist/firehydrant-2V6YSYAP.js +573 -0
- package/dist/fixer-LTCDB3CJ.js +171 -0
- package/dist/fly-IXPKMAML.js +478 -0
- package/dist/front-KRFB4M5X.js +379 -0
- package/dist/geocodio-VVURKYHQ.js +236 -0
- package/dist/ghost-6J2RIOUB.js +341 -0
- package/dist/github-5Z6KQRYH.js +5410 -0
- package/dist/gmail-KU4NZ7VA.js +1894 -0
- package/dist/googlecalendar-X44DFFXG.js +2539 -0
- package/dist/googledocs-WSGLPKSF.js +1322 -0
- package/dist/grafana-4PKSSDXY.js +817 -0
- package/dist/graphhopper-DF65ZNGK.js +336 -0
- package/dist/index.d.ts +181 -2
- package/dist/index.js +2 -1
- package/dist/ip2proxy-UCAQ5P2J.js +118 -0
- package/dist/ipgeolocation_io-UX6FCA2S.js +333 -0
- package/dist/ipqualityscore-MKTRXIZJ.js +287 -0
- package/dist/jina_ai-MRHPCSV5.js +119 -0
- package/dist/jira-EG7ZPOIW.js +627 -0
- package/dist/langsmith-FNO3RCOZ.js +597 -0
- package/dist/lemlist-SN6BJHSG.js +298 -0
- package/dist/linear-H3VU4PSD.js +2163 -0
- package/dist/logsnag-OY2JJT2H.js +167 -0
- package/dist/main.js +246 -2
- package/dist/mattermost-C5SQ7PGD.js +320 -0
- package/dist/mem0-LMLE5BFC.js +567 -0
- package/dist/memos-UWFAMBZC.js +781 -0
- package/dist/metabase-SRYDSDJ6.js +365 -0
- package/dist/mistral_ai-YNIJ7VDM.js +1195 -0
- package/dist/mother_duck-CPGOFEXE.js +322 -0
- package/dist/ngrok-CDJFBSOM.js +375 -0
- package/dist/notes-DIVFH3P3.js +109 -0
- package/dist/notion-HGDKS4HK.js +945 -0
- package/dist/open_exchange_rates-COHHYJDD.js +216 -0
- package/dist/openai-4TRT66GW.js +795 -0
- package/dist/opengraph_io-YKVW4PXI.js +377 -0
- package/dist/openrouter-6CV7B7V5.js +444 -0
- package/dist/outline-YWDUK5F7.js +604 -0
- package/dist/paddle-MEU7HWDZ.js +464 -0
- package/dist/perplexity-MRQUDBIC.js +238 -0
- package/dist/pinecone-JI7X2TAF.js +599 -0
- package/dist/pipedrive-6JQPAW23.js +453 -0
- package/dist/polar-7BF56CMC.js +400 -0
- package/dist/posthog-YPU5ADEN.js +3462 -0
- package/dist/postmark-BEU5OFKU.js +441 -0
- package/dist/prerender-UT5GOOZH.js +180 -0
- package/dist/pubmed-3SGOE24Q.js +1052 -0
- package/dist/railway-CEK4GLRQ.js +452 -0
- package/dist/readwise-DXQUQU67.js +482 -0
- package/dist/render-7TGAU5AW.js +473 -0
- package/dist/replicate-VICFSQ5A.js +347 -0
- package/dist/resend-3E76WK3O.js +100 -0
- package/dist/rootly-36GY46BY.js +345 -0
- package/dist/scrapfly-VDVUYAHX.js +289 -0
- package/dist/scrapingbee-3KTPMAVY.js +247 -0
- package/dist/screenshot_fyi-LKG62C3J.js +116 -0
- package/dist/semantic_scholar-4WREECYO.js +626 -0
- package/dist/sentry-HUQTGXOV.js +1139 -0
- package/dist/shodan-SGRKU4KS.js +303 -0
- package/dist/shopify-YCZ4L5HT.js +620 -0
- package/dist/stripe-OEBKMELB.js +583 -0
- package/dist/supabase-I3DBY7L4.js +937 -0
- package/dist/tavily-B2YHCNRD.js +349 -0
- package/dist/telegram-2VYJELZX.js +1773 -0
- package/dist/telnyx-HHXD3CXL.js +237 -0
- package/dist/todoist-PHFDEEIS.js +672 -0
- package/dist/trello-WUSAK6YN.js +1091 -0
- package/dist/turso-FW56U2B3.js +432 -0
- package/dist/twilio-M5JI7XHA.js +321 -0
- package/dist/umami-HAYODRC4.js +411 -0
- package/dist/unsplash-EDPTNEHJ.js +364 -0
- package/dist/upstash_redis-GC2CLIWD.js +299 -0
- package/dist/uptimerobot-XMSNYLIT.js +481 -0
- package/dist/v2ex-KU4ECD65.js +672 -0
- package/dist/vercel-THPCEFHW.js +1096 -0
- package/dist/wolfram_alpha_api-WHHTH4GU.js +212 -0
- package/dist/wordpress-O6TQEQNF.js +822 -0
- package/dist/workos-A3VHHWI3.js +681 -0
- package/dist/zhihu-BJAI64YJ.js +273 -0
- package/package.json +5 -4
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertPublicHttpUrl,
|
|
3
|
+
createProviderPlugin,
|
|
4
|
+
guardedFetch,
|
|
5
|
+
requireCredential,
|
|
6
|
+
upstreamError
|
|
7
|
+
} from "./chunk-CSJEZHQO.js";
|
|
8
|
+
import "./chunk-K7FVSFUX.js";
|
|
9
|
+
import {
|
|
10
|
+
TBError,
|
|
11
|
+
external_exports
|
|
12
|
+
} from "./chunk-JLTYA2B3.js";
|
|
13
|
+
import "./chunk-MLKGABMK.js";
|
|
14
|
+
|
|
15
|
+
// ../plugins/src/jira/api.ts
|
|
16
|
+
var SERVICE = "jira";
|
|
17
|
+
var DEFAULT_LIMIT = 50;
|
|
18
|
+
var DEFAULT_ISSUE_FIELD_IDS = [
|
|
19
|
+
"summary",
|
|
20
|
+
"description",
|
|
21
|
+
"status",
|
|
22
|
+
"issuetype",
|
|
23
|
+
"project",
|
|
24
|
+
"assignee",
|
|
25
|
+
"reporter",
|
|
26
|
+
"priority",
|
|
27
|
+
"labels",
|
|
28
|
+
"created",
|
|
29
|
+
"updated",
|
|
30
|
+
"duedate"
|
|
31
|
+
];
|
|
32
|
+
function text(value) {
|
|
33
|
+
if (typeof value !== "string") return void 0;
|
|
34
|
+
const trimmed = value.trim();
|
|
35
|
+
return trimmed === "" ? void 0 : trimmed;
|
|
36
|
+
}
|
|
37
|
+
function record(value) {
|
|
38
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
39
|
+
}
|
|
40
|
+
function integer(value) {
|
|
41
|
+
return typeof value === "number" && Number.isInteger(value) ? value : void 0;
|
|
42
|
+
}
|
|
43
|
+
function boolean(value) {
|
|
44
|
+
return typeof value === "boolean" ? value : void 0;
|
|
45
|
+
}
|
|
46
|
+
function compact(input) {
|
|
47
|
+
return Object.fromEntries(
|
|
48
|
+
Object.entries(input).filter(([, value]) => value !== void 0)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
function stringArray(value) {
|
|
52
|
+
if (!Array.isArray(value)) return [];
|
|
53
|
+
return value.map((item) => text(item)).filter((item) => item !== void 0);
|
|
54
|
+
}
|
|
55
|
+
function recordArray(value) {
|
|
56
|
+
if (!Array.isArray(value)) return [];
|
|
57
|
+
return value.map((item) => record(item)).filter((item) => item !== void 0);
|
|
58
|
+
}
|
|
59
|
+
function joinOptionalList(values) {
|
|
60
|
+
return values.length > 0 ? values.join(",") : void 0;
|
|
61
|
+
}
|
|
62
|
+
function optionalStringList(values) {
|
|
63
|
+
return values.length > 0 ? values : void 0;
|
|
64
|
+
}
|
|
65
|
+
function mergeUniqueFieldIds(base, extra) {
|
|
66
|
+
const merged = [...base];
|
|
67
|
+
for (const field of extra) {
|
|
68
|
+
if (!merged.includes(field)) merged.push(field);
|
|
69
|
+
}
|
|
70
|
+
return merged;
|
|
71
|
+
}
|
|
72
|
+
function isAbsoluteUrl(value) {
|
|
73
|
+
return value.startsWith("https://") || value.startsWith("http://");
|
|
74
|
+
}
|
|
75
|
+
function apiBaseUrl(ctx) {
|
|
76
|
+
const raw = requireCredential(ctx, SERVICE, "baseUrl");
|
|
77
|
+
let url;
|
|
78
|
+
try {
|
|
79
|
+
url = assertPublicHttpUrl(raw);
|
|
80
|
+
} catch {
|
|
81
|
+
throw new TBError(
|
|
82
|
+
"invalid_argument",
|
|
83
|
+
"Jira \u51ED\u8BC1\u91CC\u7684 baseUrl \u4E0D\u662F\u53EF\u51FA\u7AD9\u7684\u516C\u7F51 http(s) \u5730\u5740 \u2014\u2014 \u63D2\u4EF6\u4F1A\u62E6\u4E0B\u79C1\u6709\u7F51\u6BB5\u3001\u56DE\u73AF\u4E0E\u4E91\u5143\u6570\u636E\u5730\u5740(\u9632 SSRF)\u3002\u8BF7\u628A\u8FD9\u4E2A Jira \u5B9E\u4F8B\u7684\u516C\u7F51\u5730\u5740\u586B\u8FDB\u51ED\u8BC1\u7684 baseUrl \u5B57\u6BB5"
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (url.username !== "" || url.password !== "") {
|
|
87
|
+
throw new TBError("invalid_argument", "Jira \u51ED\u8BC1\u91CC\u7684 baseUrl \u4E0D\u80FD\u5185\u5D4C\u7528\u6237\u540D\u6216\u5BC6\u7801");
|
|
88
|
+
}
|
|
89
|
+
url.hash = "";
|
|
90
|
+
url.search = "";
|
|
91
|
+
const path = url.pathname.replace(/\/+$/, "").replace(/\/rest\/api\/(?:2|3|latest)$/, "");
|
|
92
|
+
url.pathname = `${path}/rest/api/2`;
|
|
93
|
+
return url.toString().replace(/\/$/, "");
|
|
94
|
+
}
|
|
95
|
+
function buildUrl(base, pathOrUrl, query) {
|
|
96
|
+
const target = isAbsoluteUrl(pathOrUrl) ? new URL(pathOrUrl) : new URL(pathOrUrl.replace(/^\/+/, ""), `${base}/`);
|
|
97
|
+
const baseUrl = new URL(base);
|
|
98
|
+
if (target.origin !== baseUrl.origin || !target.pathname.startsWith(`${baseUrl.pathname}/`)) {
|
|
99
|
+
throw new TBError("invalid_argument", `jira requests must target ${base}`);
|
|
100
|
+
}
|
|
101
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
102
|
+
if (value === void 0 || value === "") continue;
|
|
103
|
+
target.searchParams.set(key, value);
|
|
104
|
+
}
|
|
105
|
+
return target.toString();
|
|
106
|
+
}
|
|
107
|
+
function errorMessage(payload) {
|
|
108
|
+
const body = record(payload);
|
|
109
|
+
if (body === void 0) return "jira request failed";
|
|
110
|
+
const messages = stringArray(body.errorMessages);
|
|
111
|
+
if (messages.length > 0) return messages.join("; ");
|
|
112
|
+
const fieldErrors = record(body.errors);
|
|
113
|
+
if (fieldErrors !== void 0) {
|
|
114
|
+
const parts = [];
|
|
115
|
+
for (const [key, value] of Object.entries(fieldErrors)) {
|
|
116
|
+
const message = text(value);
|
|
117
|
+
if (message !== void 0) parts.push(`${key}: ${message}`);
|
|
118
|
+
}
|
|
119
|
+
if (parts.length > 0) return parts.join("; ");
|
|
120
|
+
}
|
|
121
|
+
return text(body.message) ?? "jira request failed";
|
|
122
|
+
}
|
|
123
|
+
async function readPayload(response) {
|
|
124
|
+
const raw = await response.text().catch(() => "");
|
|
125
|
+
if (raw === "") return {};
|
|
126
|
+
try {
|
|
127
|
+
return JSON.parse(raw);
|
|
128
|
+
} catch {
|
|
129
|
+
return { message: raw };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function requestValue(ctx, options) {
|
|
133
|
+
const headers = {
|
|
134
|
+
accept: "application/json",
|
|
135
|
+
authorization: `Bearer ${requireCredential(ctx, SERVICE, "personalAccessToken")}`
|
|
136
|
+
};
|
|
137
|
+
if (options.body !== void 0) headers["content-type"] = "application/json";
|
|
138
|
+
const response = await guardedFetch(buildUrl(apiBaseUrl(ctx), options.path, options.query), {
|
|
139
|
+
method: options.method ?? (options.body === void 0 ? "GET" : "POST"),
|
|
140
|
+
headers,
|
|
141
|
+
...options.body === void 0 ? {} : { body: JSON.stringify(options.body) }
|
|
142
|
+
});
|
|
143
|
+
const payload = await readPayload(response);
|
|
144
|
+
if (!response.ok) throw upstreamError(response.status, errorMessage(payload));
|
|
145
|
+
return payload;
|
|
146
|
+
}
|
|
147
|
+
async function requestObject(ctx, options) {
|
|
148
|
+
const payload = await requestValue(ctx, options);
|
|
149
|
+
const body = record(payload);
|
|
150
|
+
if (body === void 0) throw upstreamError(502, "jira response payload must be a JSON object");
|
|
151
|
+
return body;
|
|
152
|
+
}
|
|
153
|
+
function parseCursor(value) {
|
|
154
|
+
const cursor = text(value);
|
|
155
|
+
if (cursor === void 0) return 0;
|
|
156
|
+
const parsed = Number(cursor);
|
|
157
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
158
|
+
throw new TBError("invalid_argument", "cursor must be a non-negative integer string");
|
|
159
|
+
}
|
|
160
|
+
return parsed;
|
|
161
|
+
}
|
|
162
|
+
function nextNumericCursor(startAt, itemCount, total, isLast) {
|
|
163
|
+
if (itemCount === 0) return null;
|
|
164
|
+
if (isLast === true) return null;
|
|
165
|
+
if (typeof total === "number" && startAt + itemCount >= total) return null;
|
|
166
|
+
return String(startAt + itemCount);
|
|
167
|
+
}
|
|
168
|
+
function requireText(value, field) {
|
|
169
|
+
const result = text(value);
|
|
170
|
+
if (result === void 0) throw new TBError("invalid_argument", `${field} is required`);
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
function normalizeUser(value) {
|
|
174
|
+
const user = record(value);
|
|
175
|
+
if (user === void 0) return void 0;
|
|
176
|
+
return compact({
|
|
177
|
+
accountId: text(user.accountId),
|
|
178
|
+
accountType: text(user.accountType),
|
|
179
|
+
// DC 用 name/key 标识用户,而不是 Cloud 的 accountId。
|
|
180
|
+
name: text(user.name),
|
|
181
|
+
key: text(user.key),
|
|
182
|
+
displayName: text(user.displayName),
|
|
183
|
+
emailAddress: text(user.emailAddress),
|
|
184
|
+
active: boolean(user.active),
|
|
185
|
+
self: text(user.self),
|
|
186
|
+
timeZone: text(user.timeZone)
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
function normalizeNamedReference(value) {
|
|
190
|
+
const reference = record(value);
|
|
191
|
+
if (reference === void 0) return void 0;
|
|
192
|
+
return compact({
|
|
193
|
+
id: text(reference.id),
|
|
194
|
+
name: text(reference.name),
|
|
195
|
+
key: text(reference.key),
|
|
196
|
+
self: text(reference.self),
|
|
197
|
+
description: text(reference.description)
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
function normalizeProject(project) {
|
|
201
|
+
return compact({
|
|
202
|
+
id: text(project.id),
|
|
203
|
+
key: text(project.key),
|
|
204
|
+
name: text(project.name),
|
|
205
|
+
self: text(project.self),
|
|
206
|
+
description: text(project.description),
|
|
207
|
+
projectTypeKey: text(project.projectTypeKey),
|
|
208
|
+
simplified: boolean(project.simplified),
|
|
209
|
+
style: text(project.style),
|
|
210
|
+
url: text(project.url),
|
|
211
|
+
lead: normalizeUser(project.lead),
|
|
212
|
+
projectCategory: normalizeNamedReference(project.projectCategory),
|
|
213
|
+
avatarUrls: record(project.avatarUrls),
|
|
214
|
+
raw: project
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
function normalizeIssue(issue) {
|
|
218
|
+
const fields = record(issue.fields) ?? {};
|
|
219
|
+
return compact({
|
|
220
|
+
id: text(issue.id),
|
|
221
|
+
key: text(issue.key),
|
|
222
|
+
self: text(issue.self),
|
|
223
|
+
summary: text(fields.summary),
|
|
224
|
+
description: fields.description,
|
|
225
|
+
status: normalizeNamedReference(fields.status),
|
|
226
|
+
issueType: normalizeNamedReference(fields.issuetype),
|
|
227
|
+
project: record(fields.project) === void 0 ? void 0 : normalizeProject(record(fields.project)),
|
|
228
|
+
assignee: normalizeUser(fields.assignee),
|
|
229
|
+
reporter: normalizeUser(fields.reporter),
|
|
230
|
+
priority: normalizeNamedReference(fields.priority),
|
|
231
|
+
labels: stringArray(fields.labels),
|
|
232
|
+
created: text(fields.created),
|
|
233
|
+
updated: text(fields.updated),
|
|
234
|
+
dueDate: text(fields.duedate),
|
|
235
|
+
fields,
|
|
236
|
+
raw: issue
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function normalizeComment(comment) {
|
|
240
|
+
return compact({
|
|
241
|
+
id: text(comment.id),
|
|
242
|
+
self: text(comment.self),
|
|
243
|
+
body: comment.body,
|
|
244
|
+
author: normalizeUser(comment.author),
|
|
245
|
+
updateAuthor: normalizeUser(comment.updateAuthor),
|
|
246
|
+
created: text(comment.created),
|
|
247
|
+
updated: text(comment.updated),
|
|
248
|
+
jsdPublic: boolean(comment.jsdPublic),
|
|
249
|
+
raw: comment
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
function rawText(value) {
|
|
253
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
254
|
+
}
|
|
255
|
+
function appendAdfText(value, parts) {
|
|
256
|
+
const node = record(value);
|
|
257
|
+
if (node === void 0) return;
|
|
258
|
+
const type = text(node.type);
|
|
259
|
+
if (type === "text") {
|
|
260
|
+
const content = rawText(node.text);
|
|
261
|
+
if (content !== void 0) parts.push(content);
|
|
262
|
+
} else if (type === "hardBreak") {
|
|
263
|
+
parts.push("\n");
|
|
264
|
+
} else if (type === "mention" || type === "emoji" || type === "date" || type === "status") {
|
|
265
|
+
const content = rawText(record(node.attrs)?.text);
|
|
266
|
+
if (content !== void 0) parts.push(content);
|
|
267
|
+
} else if (type === "inlineCard") {
|
|
268
|
+
const url = rawText(record(node.attrs)?.url);
|
|
269
|
+
if (url !== void 0) parts.push(url);
|
|
270
|
+
}
|
|
271
|
+
const children = Array.isArray(node.content) ? node.content : [];
|
|
272
|
+
for (const child of children) appendAdfText(child, parts);
|
|
273
|
+
if (children.length > 0 && (type === "paragraph" || type === "heading" || type === "listItem")) {
|
|
274
|
+
parts.push("\n");
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function adfToPlainText(value) {
|
|
278
|
+
const parts = [];
|
|
279
|
+
appendAdfText(value, parts);
|
|
280
|
+
return parts.join("").replace(/\n{3,}/g, "\n\n").trim();
|
|
281
|
+
}
|
|
282
|
+
async function listProjects(input, ctx) {
|
|
283
|
+
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
284
|
+
const startAt = parseCursor(input.cursor);
|
|
285
|
+
const payload = await requestValue(ctx, {
|
|
286
|
+
path: "/project",
|
|
287
|
+
query: compact({ expand: joinOptionalList(stringArray(input.expand)) })
|
|
288
|
+
});
|
|
289
|
+
const projects = recordArray(payload).map((project) => normalizeProject(project));
|
|
290
|
+
const page = projects.slice(startAt, startAt + limit);
|
|
291
|
+
return {
|
|
292
|
+
projects: page,
|
|
293
|
+
pagination: {
|
|
294
|
+
nextCursor: startAt + page.length < projects.length ? String(startAt + page.length) : null
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
async function getProject(input, ctx) {
|
|
299
|
+
const payload = await requestObject(ctx, {
|
|
300
|
+
path: `/project/${encodeURIComponent(requireText(input.projectIdOrKey, "projectIdOrKey"))}`,
|
|
301
|
+
query: compact({ expand: joinOptionalList(stringArray(input.expand)) })
|
|
302
|
+
});
|
|
303
|
+
return { project: normalizeProject(payload) };
|
|
304
|
+
}
|
|
305
|
+
async function searchIssues(input, ctx) {
|
|
306
|
+
const startAt = parseCursor(input.cursor);
|
|
307
|
+
const payload = await requestObject(ctx, {
|
|
308
|
+
path: "/search",
|
|
309
|
+
method: "POST",
|
|
310
|
+
body: compact({
|
|
311
|
+
jql: requireText(input.jql, "jql"),
|
|
312
|
+
maxResults: input.limit ?? DEFAULT_LIMIT,
|
|
313
|
+
// DC 的 POST /rest/api/2/search 绑的是 SearchRequestBean,fields 与 expand 都收**数组**;
|
|
314
|
+
// Cloud 的增强端点收逗号串 —— 两边形状不同,写反了要么 400 要么静默全字段。
|
|
315
|
+
fields: mergeUniqueFieldIds(DEFAULT_ISSUE_FIELD_IDS, stringArray(input.includeFields)),
|
|
316
|
+
startAt,
|
|
317
|
+
expand: optionalStringList(stringArray(input.expand))
|
|
318
|
+
})
|
|
319
|
+
});
|
|
320
|
+
const issues = recordArray(payload.issues);
|
|
321
|
+
return {
|
|
322
|
+
issues: issues.map((issue) => normalizeIssue(issue)),
|
|
323
|
+
pagination: {
|
|
324
|
+
nextCursor: nextNumericCursor(startAt, issues.length, integer(payload.total))
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
async function getIssue(input, ctx) {
|
|
329
|
+
const payload = await requestObject(ctx, {
|
|
330
|
+
path: `/issue/${encodeURIComponent(requireText(input.issueIdOrKey, "issueIdOrKey"))}`,
|
|
331
|
+
query: compact({
|
|
332
|
+
// 这个端点上 fields 是**逗号串**,不是数组。
|
|
333
|
+
fields: joinOptionalList(mergeUniqueFieldIds(DEFAULT_ISSUE_FIELD_IDS, stringArray(input.includeFields))),
|
|
334
|
+
expand: joinOptionalList(stringArray(input.expand))
|
|
335
|
+
})
|
|
336
|
+
});
|
|
337
|
+
return { issue: normalizeIssue(payload) };
|
|
338
|
+
}
|
|
339
|
+
function projectReference(input) {
|
|
340
|
+
const projectId = text(input.projectId);
|
|
341
|
+
if (projectId !== void 0) return { id: projectId };
|
|
342
|
+
const projectKey = text(input.projectKey);
|
|
343
|
+
if (projectKey !== void 0) return { key: projectKey };
|
|
344
|
+
throw new TBError("invalid_argument", "projectKey or projectId is required");
|
|
345
|
+
}
|
|
346
|
+
function issueTypeReference(input) {
|
|
347
|
+
const issueTypeId = text(input.issueTypeId);
|
|
348
|
+
if (issueTypeId !== void 0) return { id: issueTypeId };
|
|
349
|
+
const issueTypeName = text(input.issueTypeName);
|
|
350
|
+
if (issueTypeName !== void 0) return { name: issueTypeName };
|
|
351
|
+
throw new TBError("invalid_argument", "issueTypeId or issueTypeName is required");
|
|
352
|
+
}
|
|
353
|
+
async function createIssue(input, ctx) {
|
|
354
|
+
const description = record(input.description);
|
|
355
|
+
const explicitFields = compact({
|
|
356
|
+
project: projectReference(input),
|
|
357
|
+
issuetype: issueTypeReference(input),
|
|
358
|
+
summary: requireText(input.summary, "summary"),
|
|
359
|
+
// DC 的 description 是纯文本:给了 ADF 就拍平,只给了 descriptionText 就直接用。
|
|
360
|
+
description: description !== void 0 ? adfToPlainText(description) : text(input.descriptionText),
|
|
361
|
+
// 上游这里用的是 `readStringArray`,没给 labels 时得到的是 `[]` 而非 undefined,于是
|
|
362
|
+
// 创建请求总会带上 `labels: []`。保留这个行为(创建时本就没有标签,发空数组无副作用)。
|
|
363
|
+
labels: stringArray(input.labels),
|
|
364
|
+
assignee: text(input.assigneeAccountId) === void 0 ? void 0 : { name: text(input.assigneeAccountId) },
|
|
365
|
+
priority: text(input.priorityId) === void 0 ? void 0 : { id: text(input.priorityId) },
|
|
366
|
+
duedate: text(input.dueDate),
|
|
367
|
+
parent: text(input.parentIssueKey) === void 0 ? void 0 : { key: text(input.parentIssueKey) }
|
|
368
|
+
});
|
|
369
|
+
const created = await requestObject(ctx, {
|
|
370
|
+
path: "/issue",
|
|
371
|
+
method: "POST",
|
|
372
|
+
// extraFields 在前:同名键由显式入参覆盖,免得裸传的 extraFields 悄悄改掉 summary 之类。
|
|
373
|
+
body: { fields: { ...record(input.extraFields) ?? {}, ...explicitFields } }
|
|
374
|
+
});
|
|
375
|
+
const createdRef = text(created.key) ?? text(created.id) ?? text(created.self);
|
|
376
|
+
if (createdRef === void 0) throw upstreamError(502, "missing jira created issue self");
|
|
377
|
+
const issue = await requestObject(ctx, {
|
|
378
|
+
// self 是绝对地址,`buildUrl` 会验它仍落在 base URL 之内。
|
|
379
|
+
path: isAbsoluteUrl(createdRef) ? createdRef : `/issue/${encodeURIComponent(createdRef)}`,
|
|
380
|
+
query: { fields: joinOptionalList(DEFAULT_ISSUE_FIELD_IDS) }
|
|
381
|
+
});
|
|
382
|
+
return { issue: normalizeIssue(issue) };
|
|
383
|
+
}
|
|
384
|
+
async function listIssueComments(input, ctx) {
|
|
385
|
+
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
386
|
+
const startAt = parseCursor(input.cursor);
|
|
387
|
+
const payload = await requestObject(ctx, {
|
|
388
|
+
path: `/issue/${encodeURIComponent(requireText(input.issueIdOrKey, "issueIdOrKey"))}/comment`,
|
|
389
|
+
query: compact({
|
|
390
|
+
maxResults: String(limit),
|
|
391
|
+
startAt: String(startAt),
|
|
392
|
+
expand: joinOptionalList(stringArray(input.expand))
|
|
393
|
+
})
|
|
394
|
+
});
|
|
395
|
+
const comments = recordArray(payload.comments).map((comment) => normalizeComment(comment));
|
|
396
|
+
return {
|
|
397
|
+
comments,
|
|
398
|
+
pagination: { nextCursor: nextNumericCursor(startAt, comments.length, integer(payload.total)) }
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
async function addComment(input, ctx) {
|
|
402
|
+
const document = record(input.body);
|
|
403
|
+
const body = document !== void 0 ? adfToPlainText(document) : text(input.bodyText);
|
|
404
|
+
if (body === void 0 || body === "") {
|
|
405
|
+
throw new TBError("invalid_argument", "comment body or bodyText is required");
|
|
406
|
+
}
|
|
407
|
+
const payload = await requestObject(ctx, {
|
|
408
|
+
path: `/issue/${encodeURIComponent(requireText(input.issueIdOrKey, "issueIdOrKey"))}/comment`,
|
|
409
|
+
method: "POST",
|
|
410
|
+
body: { body }
|
|
411
|
+
});
|
|
412
|
+
return { comment: normalizeComment(payload) };
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// ../plugins/src/jira/schema.ts
|
|
416
|
+
var listProjectsInput = external_exports.strictObject({
|
|
417
|
+
limit: external_exports.int().min(1).max(100).describe("Maximum items to return in one Jira page.").optional(),
|
|
418
|
+
cursor: external_exports.string().regex(new RegExp("^\\d+$")).describe("StartAt pagination cursor as a non-negative integer string.").optional(),
|
|
419
|
+
expand: external_exports.array(external_exports.string().min(1).describe("Jira expand token.")).min(1).describe("Additional Jira expand tokens.").optional()
|
|
420
|
+
}).describe("The input payload for this action.");
|
|
421
|
+
var listProjectsOutput = external_exports.strictObject({
|
|
422
|
+
projects: external_exports.array(external_exports.looseObject({
|
|
423
|
+
id: external_exports.string().describe("Jira project ID.").optional(),
|
|
424
|
+
key: external_exports.string().describe("Jira project key.").optional(),
|
|
425
|
+
name: external_exports.string().describe("Jira project name.").optional(),
|
|
426
|
+
raw: external_exports.looseObject({}).describe("Jira API object.").optional()
|
|
427
|
+
}).describe("Jira project.")),
|
|
428
|
+
pagination: external_exports.strictObject({
|
|
429
|
+
nextCursor: external_exports.string().describe("Cursor for the next page.").nullable()
|
|
430
|
+
}).describe("Jira pagination metadata.")
|
|
431
|
+
}).describe("Jira action output.");
|
|
432
|
+
var getProjectInput = external_exports.strictObject({
|
|
433
|
+
projectIdOrKey: external_exports.string().min(1).describe("Jira project ID or key."),
|
|
434
|
+
expand: external_exports.array(external_exports.string().min(1).describe("Jira expand token.")).min(1).describe("Additional Jira expand tokens.").optional()
|
|
435
|
+
}).describe("The input payload for this action.");
|
|
436
|
+
var getProjectOutput = external_exports.strictObject({
|
|
437
|
+
project: external_exports.looseObject({
|
|
438
|
+
id: external_exports.string().describe("Jira project ID.").optional(),
|
|
439
|
+
key: external_exports.string().describe("Jira project key.").optional(),
|
|
440
|
+
name: external_exports.string().describe("Jira project name.").optional(),
|
|
441
|
+
raw: external_exports.looseObject({}).describe("Jira API object.").optional()
|
|
442
|
+
}).describe("Jira project.")
|
|
443
|
+
}).describe("Jira action output.");
|
|
444
|
+
var searchIssuesInput = external_exports.strictObject({
|
|
445
|
+
jql: external_exports.string().min(1).describe("Jira Query Language string."),
|
|
446
|
+
limit: external_exports.int().min(1).max(100).describe("Maximum items to return in one Jira page.").optional(),
|
|
447
|
+
cursor: external_exports.string().min(1).describe("Opaque pagination cursor returned by Jira.").optional(),
|
|
448
|
+
includeFields: external_exports.array(external_exports.string().min(1).describe("Jira field ID or name.")).min(1).describe("Additional Jira issue fields.").optional(),
|
|
449
|
+
expand: external_exports.array(external_exports.string().min(1).describe("Jira expand token.")).min(1).describe("Additional Jira expand tokens.").optional()
|
|
450
|
+
}).describe("The input payload for this action.");
|
|
451
|
+
var searchIssuesOutput = external_exports.strictObject({
|
|
452
|
+
issues: external_exports.array(external_exports.looseObject({
|
|
453
|
+
id: external_exports.string().describe("Jira issue ID.").optional(),
|
|
454
|
+
key: external_exports.string().describe("Jira issue key.").optional(),
|
|
455
|
+
summary: external_exports.string().describe("Jira issue summary.").optional(),
|
|
456
|
+
fields: external_exports.looseObject({}).describe("Jira API object.").optional(),
|
|
457
|
+
raw: external_exports.looseObject({}).describe("Jira API object.").optional()
|
|
458
|
+
}).describe("Jira issue.")),
|
|
459
|
+
pagination: external_exports.strictObject({
|
|
460
|
+
nextCursor: external_exports.string().describe("Cursor for the next page.").nullable()
|
|
461
|
+
}).describe("Jira pagination metadata.")
|
|
462
|
+
}).describe("Jira action output.");
|
|
463
|
+
var getIssueInput = external_exports.strictObject({
|
|
464
|
+
issueIdOrKey: external_exports.string().min(1).describe("Jira issue ID or key."),
|
|
465
|
+
includeFields: external_exports.array(external_exports.string().min(1).describe("Jira field ID or name.")).min(1).describe("Additional Jira issue fields.").optional(),
|
|
466
|
+
expand: external_exports.array(external_exports.string().min(1).describe("Jira expand token.")).min(1).describe("Additional Jira expand tokens.").optional()
|
|
467
|
+
}).describe("The input payload for this action.");
|
|
468
|
+
var getIssueOutput = external_exports.strictObject({
|
|
469
|
+
issue: external_exports.looseObject({
|
|
470
|
+
id: external_exports.string().describe("Jira issue ID.").optional(),
|
|
471
|
+
key: external_exports.string().describe("Jira issue key.").optional(),
|
|
472
|
+
summary: external_exports.string().describe("Jira issue summary.").optional(),
|
|
473
|
+
fields: external_exports.looseObject({}).describe("Jira API object.").optional(),
|
|
474
|
+
raw: external_exports.looseObject({}).describe("Jira API object.").optional()
|
|
475
|
+
}).describe("Jira issue.")
|
|
476
|
+
}).describe("Jira action output.");
|
|
477
|
+
var createIssueInput = external_exports.strictObject({
|
|
478
|
+
projectKey: external_exports.string().min(1).describe("Jira project key.").optional(),
|
|
479
|
+
projectId: external_exports.string().min(1).describe("Jira project ID.").optional(),
|
|
480
|
+
issueTypeId: external_exports.string().min(1).describe("Jira issue type ID.").optional(),
|
|
481
|
+
issueTypeName: external_exports.string().min(1).describe("Jira issue type name.").optional(),
|
|
482
|
+
summary: external_exports.string().min(1).describe("Jira issue summary."),
|
|
483
|
+
descriptionText: external_exports.string().min(1).describe("Plain text description converted to the connected deployment's document format.").optional(),
|
|
484
|
+
description: external_exports.looseObject({
|
|
485
|
+
type: external_exports.literal("doc").describe("ADF root node type."),
|
|
486
|
+
version: external_exports.int().describe("ADF document version."),
|
|
487
|
+
content: external_exports.array(external_exports.unknown().describe("ADF top-level node.")).describe("ADF content nodes.")
|
|
488
|
+
}).describe("Atlassian Document Format document.").optional(),
|
|
489
|
+
labels: external_exports.array(external_exports.string().min(1)).min(1).describe("Jira labels.").optional(),
|
|
490
|
+
assigneeAccountId: external_exports.string().min(1).describe("Assignee account ID for Jira Cloud or username for Jira Data Center/Server.").optional(),
|
|
491
|
+
priorityId: external_exports.string().min(1).describe("Jira priority ID.").optional(),
|
|
492
|
+
dueDate: external_exports.iso.date().describe("Jira due date in YYYY-MM-DD format.").optional(),
|
|
493
|
+
parentIssueKey: external_exports.string().min(1).describe("Parent issue key for subtasks.").optional(),
|
|
494
|
+
extraFields: external_exports.looseObject({}).describe("Jira API object.").optional()
|
|
495
|
+
}).describe("The input payload for this action.");
|
|
496
|
+
var createIssueOutput = external_exports.strictObject({
|
|
497
|
+
issue: external_exports.looseObject({
|
|
498
|
+
id: external_exports.string().describe("Jira issue ID.").optional(),
|
|
499
|
+
key: external_exports.string().describe("Jira issue key.").optional(),
|
|
500
|
+
summary: external_exports.string().describe("Jira issue summary.").optional(),
|
|
501
|
+
fields: external_exports.looseObject({}).describe("Jira API object.").optional(),
|
|
502
|
+
raw: external_exports.looseObject({}).describe("Jira API object.").optional()
|
|
503
|
+
}).describe("Jira issue.")
|
|
504
|
+
}).describe("Jira action output.");
|
|
505
|
+
var listIssueCommentsInput = external_exports.strictObject({
|
|
506
|
+
issueIdOrKey: external_exports.string().min(1).describe("Jira issue ID or key."),
|
|
507
|
+
limit: external_exports.int().min(1).max(100).describe("Maximum items to return in one Jira page.").optional(),
|
|
508
|
+
cursor: external_exports.string().regex(new RegExp("^\\d+$")).describe("StartAt pagination cursor as a non-negative integer string.").optional(),
|
|
509
|
+
expand: external_exports.array(external_exports.string().min(1).describe("Jira expand token.")).min(1).describe("Additional Jira expand tokens.").optional()
|
|
510
|
+
}).describe("The input payload for this action.");
|
|
511
|
+
var listIssueCommentsOutput = external_exports.strictObject({
|
|
512
|
+
comments: external_exports.array(external_exports.looseObject({
|
|
513
|
+
id: external_exports.string().describe("Jira comment ID.").optional(),
|
|
514
|
+
body: external_exports.union([external_exports.looseObject({
|
|
515
|
+
type: external_exports.literal("doc").describe("ADF root node type."),
|
|
516
|
+
version: external_exports.int().describe("ADF document version."),
|
|
517
|
+
content: external_exports.array(external_exports.unknown().describe("ADF top-level node.")).describe("ADF content nodes.")
|
|
518
|
+
}).describe("Atlassian Document Format document."), external_exports.string().describe("Plain text comment body (Jira Server/Data Center).")]).describe("Jira comment body: an ADF document (Cloud) or plain text (Server/Data Center).").optional(),
|
|
519
|
+
raw: external_exports.looseObject({}).describe("Jira API object.").optional()
|
|
520
|
+
}).describe("Jira comment.")),
|
|
521
|
+
pagination: external_exports.strictObject({
|
|
522
|
+
nextCursor: external_exports.string().describe("Cursor for the next page.").nullable()
|
|
523
|
+
}).describe("Jira pagination metadata.")
|
|
524
|
+
}).describe("Jira action output.");
|
|
525
|
+
var addCommentInput = external_exports.strictObject({
|
|
526
|
+
issueIdOrKey: external_exports.string().min(1).describe("Jira issue ID or key."),
|
|
527
|
+
bodyText: external_exports.string().min(1).describe("Plain text comment body converted to the connected deployment's document format.").optional(),
|
|
528
|
+
body: external_exports.looseObject({
|
|
529
|
+
type: external_exports.literal("doc").describe("ADF root node type."),
|
|
530
|
+
version: external_exports.int().describe("ADF document version."),
|
|
531
|
+
content: external_exports.array(external_exports.unknown().describe("ADF top-level node.")).describe("ADF content nodes.")
|
|
532
|
+
}).describe("Atlassian Document Format document.").optional()
|
|
533
|
+
}).describe("The input payload for this action.");
|
|
534
|
+
var addCommentOutput = external_exports.strictObject({
|
|
535
|
+
comment: external_exports.looseObject({
|
|
536
|
+
id: external_exports.string().describe("Jira comment ID.").optional(),
|
|
537
|
+
body: external_exports.union([external_exports.looseObject({
|
|
538
|
+
type: external_exports.literal("doc").describe("ADF root node type."),
|
|
539
|
+
version: external_exports.int().describe("ADF document version."),
|
|
540
|
+
content: external_exports.array(external_exports.unknown().describe("ADF top-level node.")).describe("ADF content nodes.")
|
|
541
|
+
}).describe("Atlassian Document Format document."), external_exports.string().describe("Plain text comment body (Jira Server/Data Center).")]).describe("Jira comment body: an ADF document (Cloud) or plain text (Server/Data Center).").optional(),
|
|
542
|
+
raw: external_exports.looseObject({}).describe("Jira API object.").optional()
|
|
543
|
+
}).describe("Jira comment.")
|
|
544
|
+
}).describe("Jira action output.");
|
|
545
|
+
var jiraActions = {
|
|
546
|
+
list_projects: {
|
|
547
|
+
description: "List Jira projects available to the connected Jira site.",
|
|
548
|
+
effect: "read",
|
|
549
|
+
inputSchema: listProjectsInput,
|
|
550
|
+
outputSchema: external_exports.toJSONSchema(listProjectsOutput, { io: "output", unrepresentable: "any" })
|
|
551
|
+
},
|
|
552
|
+
get_project: {
|
|
553
|
+
description: "Get one Jira project by project ID or key.",
|
|
554
|
+
effect: "read",
|
|
555
|
+
inputSchema: getProjectInput,
|
|
556
|
+
outputSchema: external_exports.toJSONSchema(getProjectOutput, { io: "output", unrepresentable: "any" })
|
|
557
|
+
},
|
|
558
|
+
search_issues: {
|
|
559
|
+
description: "Search Jira issues with JQL on the connected Jira site.",
|
|
560
|
+
effect: "read",
|
|
561
|
+
inputSchema: searchIssuesInput,
|
|
562
|
+
outputSchema: external_exports.toJSONSchema(searchIssuesOutput, { io: "output", unrepresentable: "any" })
|
|
563
|
+
},
|
|
564
|
+
get_issue: {
|
|
565
|
+
description: "Get one Jira issue by issue ID or key.",
|
|
566
|
+
effect: "read",
|
|
567
|
+
inputSchema: getIssueInput,
|
|
568
|
+
outputSchema: external_exports.toJSONSchema(getIssueOutput, { io: "output", unrepresentable: "any" })
|
|
569
|
+
},
|
|
570
|
+
create_issue: {
|
|
571
|
+
description: "Create a Jira issue and return the normalized issue detail.",
|
|
572
|
+
effect: "write",
|
|
573
|
+
inputSchema: createIssueInput,
|
|
574
|
+
outputSchema: external_exports.toJSONSchema(createIssueOutput, { io: "output", unrepresentable: "any" })
|
|
575
|
+
},
|
|
576
|
+
list_issue_comments: {
|
|
577
|
+
description: "List comments for one Jira issue.",
|
|
578
|
+
effect: "read",
|
|
579
|
+
inputSchema: listIssueCommentsInput,
|
|
580
|
+
outputSchema: external_exports.toJSONSchema(listIssueCommentsOutput, { io: "output", unrepresentable: "any" })
|
|
581
|
+
},
|
|
582
|
+
add_comment: {
|
|
583
|
+
description: "Add a comment to one Jira issue.",
|
|
584
|
+
effect: "write",
|
|
585
|
+
inputSchema: addCommentInput,
|
|
586
|
+
outputSchema: external_exports.toJSONSchema(addCommentOutput, { io: "output", unrepresentable: "any" })
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
// ../plugins/src/jira/index.ts
|
|
591
|
+
function createJiraPlugin() {
|
|
592
|
+
return createProviderPlugin({
|
|
593
|
+
description: "Jira (Data Center / Server)",
|
|
594
|
+
credentialFields: [
|
|
595
|
+
{
|
|
596
|
+
key: "baseUrl",
|
|
597
|
+
label: "Instance URL",
|
|
598
|
+
required: true,
|
|
599
|
+
secret: false,
|
|
600
|
+
description: "Jira Data Center / Server \u5B9E\u4F8B\u7684\u6839\u5730\u5740(https://jira.example.com,\u5E26\u90E8\u7F72\u4E0A\u4E0B\u6587\u8DEF\u5F84\u4E5F\u53EF\u4EE5),\u4E0D\u8981\u5E26 API \u8DEF\u5F84;\u5FC5\u987B\u662F\u516C\u7F51\u53EF\u8FBE\u5730\u5740,\u79C1\u6709\u7F51\u6BB5\u4F1A\u88AB\u51FA\u7AD9\u7B56\u7565\u62E6\u4E0B"
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
key: "personalAccessToken",
|
|
604
|
+
label: "Personal access token",
|
|
605
|
+
required: true,
|
|
606
|
+
secret: true,
|
|
607
|
+
description: "Jira Data Center / Server \u7684\u4E2A\u4EBA\u8BBF\u95EE\u4EE4\u724C,\u4EE5 Bearer \u53D1\u9001"
|
|
608
|
+
}
|
|
609
|
+
],
|
|
610
|
+
credentialProbe: "list_projects",
|
|
611
|
+
actions: jiraActions,
|
|
612
|
+
handlers: {
|
|
613
|
+
list_projects: listProjects,
|
|
614
|
+
get_project: getProject,
|
|
615
|
+
search_issues: searchIssues,
|
|
616
|
+
get_issue: getIssue,
|
|
617
|
+
create_issue: createIssue,
|
|
618
|
+
list_issue_comments: listIssueComments,
|
|
619
|
+
add_comment: addComment
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
var jira_default = createJiraPlugin();
|
|
624
|
+
export {
|
|
625
|
+
createJiraPlugin,
|
|
626
|
+
jira_default as default
|
|
627
|
+
};
|