@tool-bridge/server 0.21.1 → 0.22.1
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/admin.js +170 -0
- package/dist/airtable-ML2GIGCH.js +790 -0
- package/dist/{alt_text_generator_ai-W7O34SNG.js → alt_text_generator_ai-FGYQAF2A.js} +12 -11
- package/dist/{amap-VOX4T2AW.js → amap-G7V65NGK.js} +221 -220
- package/dist/anthropic-6ZK24TBB.js +203 -0
- package/dist/apify-VDGYHP6W.js +248 -0
- package/dist/brave_search-TAATLZOS.js +302 -0
- package/dist/chunk-2IAI3XQM.js +302 -0
- package/dist/chunk-7ISGFRC6.js +161 -0
- package/dist/{chunk-E6JCVKW6.js → chunk-BNMLA2RC.js} +3 -3
- package/dist/chunk-HA4BGL6C.js +8429 -0
- package/dist/{chunk-KMTT3I6D.js → chunk-RMAWSG7E.js} +19172 -25717
- package/dist/{chunk-XYBU3WZH.js → chunk-RTW5VRTK.js} +3 -3
- package/dist/chunk-U7PTOA3U.js +7320 -0
- package/dist/chunk-UY6ANCOY.js +378 -0
- package/dist/{chunk-ATK45BXV.js → chunk-X7ZUTKHR.js} +4 -2
- package/dist/circleci-BQ2UWXL2.js +389 -0
- package/dist/clerk-2JYWQNOI.js +1019 -0
- package/dist/cohere-6MI7AQM4.js +185 -0
- package/dist/{confluence-B3EWPZVE.js → confluence-6Y6GDETF.js} +105 -104
- package/dist/{convertapi-EUWSQYPF.js → convertapi-HBZCSWOX.js} +32 -31
- package/dist/{currencyapi-KVTIK3GL.js → currencyapi-337U5TGI.js} +71 -71
- package/dist/deepseek-OSPASO7O.js +210 -0
- package/dist/docker_hub-3ATQOY5L.js +933 -0
- package/dist/dropbox-LSA4GM2Y.js +1305 -0
- package/dist/dub-VZPJSPI6.js +680 -0
- package/dist/e2b-6SDYQZL2.js +278 -0
- package/dist/exa-B6EUYDVP.js +332 -0
- package/dist/{fal_ai-23E7JPNT.js → fal_ai-K4Q27IME.js} +81 -80
- package/dist/{feishu-7QRIDUV6.js → feishu-4TKXG4SU.js} +528 -572
- package/dist/{feishu_custom_bot-TJ4K7QNJ.js → feishu_custom_bot-7CTEAKRB.js} +57 -53
- package/dist/figma-OUKSZLD5.js +777 -0
- package/dist/firehydrant-7MOYL7QH.js +563 -0
- package/dist/{fixer-BWON27UO.js → fixer-H2BV2NO4.js} +34 -33
- package/dist/fly-PXKY6PNH.js +469 -0
- package/dist/{front-QCGXYEDJ.js → front-UZYIV5DW.js} +104 -104
- package/dist/geocodio-NSYO7TFP.js +213 -0
- package/dist/ghost-QBKKQQMF.js +338 -0
- package/dist/github-ENLSJ4CL.js +5421 -0
- package/dist/gmail-KQSDEB47.js +1887 -0
- package/dist/googlecalendar-5YCX4SZF.js +2524 -0
- package/dist/{googledocs-BUHL4J2H.js → googledocs-SSWIVFKA.js} +341 -340
- package/dist/{grafana-GLU2DWF2.js → grafana-TF2LXDQA.js} +221 -220
- package/dist/graphhopper-CURBVHYK.js +325 -0
- package/dist/index.d.ts +1132 -332
- package/dist/index.js +31 -14
- package/dist/{ip2proxy-EZ64Y4ZH.js → ip2proxy-YNVMTZEM.js} +28 -27
- package/dist/ipgeolocation_io-NAU7VJ4J.js +315 -0
- package/dist/ipqualityscore-OT63L4TI.js +279 -0
- package/dist/{jina_ai-EFBHTBXL.js → jina_ai-6WBMBGWM.js} +23 -23
- package/dist/{jira-HQSHAA5K.js → jira-DVDVTHNO.js} +118 -117
- package/dist/langsmith-IM5N4YAU.js +593 -0
- package/dist/lemlist-277SHUQF.js +289 -0
- package/dist/{linear-K7RYFYAD.js → linear-AEPH7B5V.js} +327 -326
- package/dist/logsnag-VEWRAGBG.js +150 -0
- package/dist/main.js +57 -280
- package/dist/{mattermost-S2BRCWLQ.js → mattermost-Q3A2BIZA.js} +59 -58
- package/dist/mem0-AXS7GZGI.js +544 -0
- package/dist/memos-7TXG4ZTU.js +744 -0
- package/dist/{metabase-MMSEPCOF.js → metabase-NSVACWQM.js} +90 -89
- package/dist/mistral_ai-YZ52RGD4.js +1196 -0
- package/dist/{mother_duck-H7PCQNZ2.js → mother_duck-XLLL6FVL.js} +94 -93
- package/dist/ngrok-4O4W3WZW.js +356 -0
- package/dist/{notes-PFMKRO33.js → notes-YTB3TJOO.js} +11 -9
- package/dist/notion-4W4O7J7V.js +940 -0
- package/dist/open_exchange_rates-23QJXVO5.js +215 -0
- package/dist/openai-ZS7GLSLH.js +800 -0
- package/dist/opengraph_io-PMVH7OYI.js +362 -0
- package/dist/openrouter-ONRGFNB6.js +441 -0
- package/dist/outline-UCUYZZ7J.js +599 -0
- package/dist/paddle-35HTKTUL.js +454 -0
- package/dist/perplexity-NVOBYN24.js +220 -0
- package/dist/pinecone-55CJY73C.js +571 -0
- package/dist/{pipedrive-Y2O7QGFF.js → pipedrive-WMCAKS72.js} +99 -98
- package/dist/polar-SM4ZM53B.js +395 -0
- package/dist/posthog-NWCXVXNJ.js +3464 -0
- package/dist/postmark-QJV5PHUQ.js +427 -0
- package/dist/{prerender-MENYM2TY.js → prerender-2W7UT4SC.js} +31 -30
- package/dist/{pubmed-GOXUVVH5.js → pubmed-VVV7XYLU.js} +239 -238
- package/dist/{railway-V2SID4WV.js → railway-KGI57S3O.js} +118 -117
- package/dist/readwise-AGHTQB42.js +470 -0
- package/dist/render-O4HBROCK.js +461 -0
- package/dist/{replicate-756MXPYX.js → replicate-KWBOMX7D.js} +81 -80
- package/dist/{resend-ZKH3BTBI.js → resend-DRH6Y6I4.js} +20 -16
- package/dist/rootly-XGCUDW6X.js +336 -0
- package/dist/{scrapfly-NSRHFDIQ.js → scrapfly-OIQ3OY6L.js} +62 -61
- package/dist/{scrapingbee-OQHLAVEY.js → scrapingbee-OCZO4FHX.js} +56 -56
- package/dist/{screenshot_fyi-DVWG3AXC.js → screenshot_fyi-CUNGFZOC.js} +16 -16
- package/dist/semantic_scholar-3UJRLKES.js +611 -0
- package/dist/{sentry-546MNDJG.js → sentry-5BWVZFJV.js} +208 -207
- package/dist/{shodan-C3OON3Z3.js → shodan-HI37CTEW.js} +62 -61
- package/dist/shopify-LJ2EV2HH.js +610 -0
- package/dist/stripe-3LHMV55K.js +585 -0
- package/dist/{supabase-U2SL4D63.js → supabase-H2KPX3Q2.js} +245 -244
- package/dist/tavily-FBEWGH3Z.js +326 -0
- package/dist/telegram-MYYO3JND.js +1767 -0
- package/dist/{telnyx-CXQ4EZUX.js → telnyx-H4ALEGAX.js} +57 -56
- package/dist/todoist-OBWICA5Q.js +664 -0
- package/dist/trello-GUFUJRWO.js +1080 -0
- package/dist/turso-NIAK4UMS.js +416 -0
- package/dist/{twilio-4PDBJKWX.js → twilio-K6SLK2CX.js} +70 -69
- package/dist/umami-42RS2EPS.js +389 -0
- package/dist/unsplash-V7TOTETT.js +351 -0
- package/dist/{upstash_redis-G4LQBYHA.js → upstash_redis-AWQMB6Y3.js} +51 -50
- package/dist/uptimerobot-AZC2DHOT.js +483 -0
- package/dist/v2ex-4TVRNMLS.js +667 -0
- package/dist/vercel-DPHTJ3XR.js +1076 -0
- package/dist/{wolfram_alpha_api-3G4PUJWB.js → wolfram_alpha_api-XAG7IXBW.js} +36 -35
- package/dist/wordpress-KMPKVGUX.js +812 -0
- package/dist/workos-PKB2YR7S.js +664 -0
- package/dist/zhihu-Y4H4XYPB.js +254 -0
- package/package.json +18 -9
- package/dist/airtable-LLZDFN7M.js +0 -789
- package/dist/anthropic-G23NN3X5.js +0 -202
- package/dist/apify-Y3SS734K.js +0 -247
- package/dist/brave_search-ZC7OAPSZ.js +0 -301
- package/dist/chunk-R6P4XAE5.js +0 -248
- package/dist/chunk-U7B6DS2O.js +0 -977
- package/dist/chunk-UZM2RXZH.js +0 -23436
- package/dist/circleci-3BAX5FCG.js +0 -388
- package/dist/clerk-6LEM6TNU.js +0 -1019
- package/dist/cloudflare_dns-KINYTJUD.js +0 -588
- package/dist/cohere-XCJ5AJ6B.js +0 -185
- package/dist/deepseek-PC5YGNC5.js +0 -209
- package/dist/docker_hub-C3MA5FU6.js +0 -932
- package/dist/dropbox-XBV7Z2IR.js +0 -1304
- package/dist/dub-LDOFG3HC.js +0 -679
- package/dist/e2b-JMCPSVBW.js +0 -277
- package/dist/exa-RAK7O7RD.js +0 -331
- package/dist/figma-E6IX5DTH.js +0 -773
- package/dist/firehydrant-ZBLPQREE.js +0 -562
- package/dist/fly-ZH3HFCZJ.js +0 -468
- package/dist/geocodio-YGNI7DA4.js +0 -212
- package/dist/ghost-EVSGKH2Q.js +0 -337
- package/dist/github-MA2BGRCJ.js +0 -5420
- package/dist/gmail-E5E6AADE.js +0 -1886
- package/dist/googlecalendar-BTLFPXTD.js +0 -2523
- package/dist/graphhopper-WSMB3TCD.js +0 -324
- package/dist/ipgeolocation_io-AA7HAS22.js +0 -315
- package/dist/ipqualityscore-BHJXVTJT.js +0 -277
- package/dist/langsmith-5W6SCT6F.js +0 -592
- package/dist/lemlist-HJWH6UMK.js +0 -288
- package/dist/logsnag-4KFOHL37.js +0 -150
- package/dist/mem0-CAW43CIC.js +0 -543
- package/dist/memos-TWEGPKFM.js +0 -740
- package/dist/mistral_ai-64BGZQHP.js +0 -1195
- package/dist/ngrok-GQCUGZKJ.js +0 -356
- package/dist/notion-DQWZWP4N.js +0 -936
- package/dist/open_exchange_rates-QMMD735E.js +0 -214
- package/dist/openai-W6PX32NZ.js +0 -799
- package/dist/opengraph_io-HNDBXYNW.js +0 -361
- package/dist/openrouter-JJYMEAUL.js +0 -437
- package/dist/outline-MCBNQZYY.js +0 -595
- package/dist/paddle-D2SKLUDN.js +0 -453
- package/dist/perplexity-XIFMKUAE.js +0 -219
- package/dist/pinecone-HUFTALV2.js +0 -570
- package/dist/polar-TYTOMOSR.js +0 -394
- package/dist/posthog-43JAR3VW.js +0 -3463
- package/dist/postmark-KL2QJYSG.js +0 -426
- package/dist/readwise-CI4GIMMJ.js +0 -469
- package/dist/render-SUBJ6YRZ.js +0 -460
- package/dist/rootly-CD2LJHPI.js +0 -336
- package/dist/semantic_scholar-T4A252KW.js +0 -610
- package/dist/shopify-Y2HN2MCQ.js +0 -609
- package/dist/stripe-VE3CD3AY.js +0 -584
- package/dist/tavily-KCZHK6HE.js +0 -326
- package/dist/telegram-3URFBCMY.js +0 -1766
- package/dist/todoist-HNPWNYTD.js +0 -663
- package/dist/trello-3W2MIXRP.js +0 -1079
- package/dist/turso-2EQF7C2Z.js +0 -415
- package/dist/umami-5REN7TGP.js +0 -388
- package/dist/unsplash-EIXL424F.js +0 -350
- package/dist/uptimerobot-KNJ3EYLY.js +0 -482
- package/dist/v2ex-RHJ234PZ.js +0 -666
- package/dist/vercel-AS6NCIC7.js +0 -1075
- package/dist/wordpress-KNDAAUV7.js +0 -811
- package/dist/workos-R6UITSJ7.js +0 -663
- package/dist/zhihu-AGK4HILK.js +0 -253
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAuthedClient
|
|
3
|
+
} from "./chunk-RTW5VRTK.js";
|
|
4
|
+
import "./chunk-BNMLA2RC.js";
|
|
5
|
+
import {
|
|
6
|
+
asJsonObject,
|
|
7
|
+
trimmedText
|
|
8
|
+
} from "./chunk-JXHMDBAY.js";
|
|
9
|
+
import {
|
|
10
|
+
createProviderPlugin,
|
|
11
|
+
requireApiKey,
|
|
12
|
+
upstreamError
|
|
13
|
+
} from "./chunk-X7ZUTKHR.js";
|
|
14
|
+
import "./chunk-7ISGFRC6.js";
|
|
15
|
+
import "./chunk-UY6ANCOY.js";
|
|
16
|
+
import {
|
|
17
|
+
TBError
|
|
18
|
+
} from "./chunk-HA4BGL6C.js";
|
|
19
|
+
import "./chunk-U67V476Y.js";
|
|
20
|
+
|
|
21
|
+
// ../plugins/src/v2ex/api.ts
|
|
22
|
+
var SERVICE = "v2ex";
|
|
23
|
+
var API_BASE = "https://www.v2ex.com/api/v2";
|
|
24
|
+
var LEGACY_API_BASE = "https://www.v2ex.com/api";
|
|
25
|
+
var REQUEST_TIMEOUT_MS = 3e4;
|
|
26
|
+
function invalidResponse(message) {
|
|
27
|
+
return new TBError("unavailable", message, { retryable: true });
|
|
28
|
+
}
|
|
29
|
+
function requireRecord(value, label) {
|
|
30
|
+
const result = asJsonObject(value);
|
|
31
|
+
if (result === void 0) throw invalidResponse(`${label} must be an object`);
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
function errorMessage(payload) {
|
|
35
|
+
if (typeof payload === "string") return trimmedText(payload);
|
|
36
|
+
const body = asJsonObject(payload);
|
|
37
|
+
if (body === void 0) return void 0;
|
|
38
|
+
const direct = trimmedText(body.message) ?? trimmedText(body.error);
|
|
39
|
+
if (direct !== void 0) return direct;
|
|
40
|
+
if (Array.isArray(body.errors)) {
|
|
41
|
+
for (const item of body.errors) {
|
|
42
|
+
const detail = trimmedText(asJsonObject(item)?.detail) ?? trimmedText(asJsonObject(item)?.message);
|
|
43
|
+
if (detail !== void 0) return detail;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return void 0;
|
|
47
|
+
}
|
|
48
|
+
function envelopeError(payload) {
|
|
49
|
+
return new TBError("invalid_argument", errorMessage(payload) ?? "V2EX request failed");
|
|
50
|
+
}
|
|
51
|
+
var v2Http = createAuthedClient({
|
|
52
|
+
baseUrl: `${API_BASE}/`,
|
|
53
|
+
service: SERVICE,
|
|
54
|
+
auth: { kind: "bearer" },
|
|
55
|
+
headers: { accept: "application/json" },
|
|
56
|
+
mapError: ({ data, status }) => upstreamError(status, errorMessage(data) ?? "V2EX request failed")
|
|
57
|
+
});
|
|
58
|
+
var legacyHttp = createAuthedClient({
|
|
59
|
+
baseUrl: `${LEGACY_API_BASE}/`,
|
|
60
|
+
service: SERVICE,
|
|
61
|
+
// legacy API **不带 Authorization** —— 上游这条路径压根不调 `buildV2exHeaders`,加上 Bearer
|
|
62
|
+
// 也没用。但仍然先 `requireApiKey`:上游整个 provider 的 authType 是 `api_key`,没配凭证时
|
|
63
|
+
// 连 context 都建不起来,这两个 action 一样调不通。这里保留那道闸 —— 否则"配了才能用"
|
|
64
|
+
// 会因为迁移悄悄变成"这两个不用配",挂载语义就不一致了。
|
|
65
|
+
auth: {
|
|
66
|
+
kind: "custom",
|
|
67
|
+
headers: (ctx) => {
|
|
68
|
+
requireApiKey(ctx, SERVICE);
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
headers: { accept: "application/json" },
|
|
73
|
+
mapError: ({ data, status }) => upstreamError(status, errorMessage(data) ?? "V2EX request failed")
|
|
74
|
+
});
|
|
75
|
+
async function send(client, ctx, request2, label) {
|
|
76
|
+
const response = await client.request(ctx, {
|
|
77
|
+
...request2,
|
|
78
|
+
timeoutMs: REQUEST_TIMEOUT_MS,
|
|
79
|
+
invalidJson: "text",
|
|
80
|
+
mapTransportError: ({ kind, message }) => kind === "timeout" ? upstreamError(504, `${label} request timed out after ${REQUEST_TIMEOUT_MS / 1e3} seconds`) : upstreamError(502, message === void 0 ? `${label} request failed` : `${label} request failed: ${message}`)
|
|
81
|
+
});
|
|
82
|
+
return response.bodyKind === "empty" ? null : response.data;
|
|
83
|
+
}
|
|
84
|
+
async function request(ctx, options) {
|
|
85
|
+
return send(v2Http, ctx, {
|
|
86
|
+
method: options.method,
|
|
87
|
+
path: options.path,
|
|
88
|
+
// 上游连**空串**也当作"没给",不只是 undefined/null。
|
|
89
|
+
query: Object.entries(options.query ?? {}).filter(([, value]) => value !== void 0 && value !== ""),
|
|
90
|
+
...options.body === void 0 ? {} : { json: options.body }
|
|
91
|
+
}, `V2EX ${options.path}`);
|
|
92
|
+
}
|
|
93
|
+
async function legacyRequest(ctx, path) {
|
|
94
|
+
const payload = await send(
|
|
95
|
+
legacyHttp,
|
|
96
|
+
ctx,
|
|
97
|
+
{ method: "GET", path },
|
|
98
|
+
`V2EX legacy ${path}`
|
|
99
|
+
);
|
|
100
|
+
if (!Array.isArray(payload)) {
|
|
101
|
+
throw invalidResponse(`V2EX legacy ${path} response must be an array`);
|
|
102
|
+
}
|
|
103
|
+
return payload;
|
|
104
|
+
}
|
|
105
|
+
function unwrapEnvelope(payload, label) {
|
|
106
|
+
const envelope = requireRecord(payload, `V2EX ${label} response`);
|
|
107
|
+
if (envelope.success === false) throw envelopeError(envelope);
|
|
108
|
+
if (!("result" in envelope)) {
|
|
109
|
+
throw invalidResponse(`V2EX ${label} response missing result`);
|
|
110
|
+
}
|
|
111
|
+
return { message: trimmedText(envelope.message), result: envelope.result };
|
|
112
|
+
}
|
|
113
|
+
function ensureAccepted(payload, label) {
|
|
114
|
+
if (payload === null) return;
|
|
115
|
+
const envelope = requireRecord(payload, `V2EX ${label} response`);
|
|
116
|
+
if (envelope.success === false) throw envelopeError(envelope);
|
|
117
|
+
if (envelope.success === true) return;
|
|
118
|
+
throw invalidResponse(`V2EX ${label} response missing success=true`);
|
|
119
|
+
}
|
|
120
|
+
function objectResult(envelope, label) {
|
|
121
|
+
return requireRecord(envelope.result, `V2EX ${label} result`);
|
|
122
|
+
}
|
|
123
|
+
function arrayResult(envelope, label) {
|
|
124
|
+
if (!Array.isArray(envelope.result)) {
|
|
125
|
+
throw invalidResponse(`V2EX ${label} result must be an array`);
|
|
126
|
+
}
|
|
127
|
+
return envelope.result;
|
|
128
|
+
}
|
|
129
|
+
function parseTotal(message, result) {
|
|
130
|
+
if (message !== void 0) {
|
|
131
|
+
const slashIndex = message.indexOf("/");
|
|
132
|
+
if (slashIndex >= 0) {
|
|
133
|
+
const parsed = Number.parseInt(message.slice(slashIndex + 1), 10);
|
|
134
|
+
if (Number.isInteger(parsed) && parsed >= 0) return parsed;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return Array.isArray(result) ? result.length : 0;
|
|
138
|
+
}
|
|
139
|
+
async function listNotifications(input, ctx) {
|
|
140
|
+
const envelope = unwrapEnvelope(
|
|
141
|
+
await request(ctx, { method: "GET", path: "/notifications", query: { p: input.p } }),
|
|
142
|
+
"notifications"
|
|
143
|
+
);
|
|
144
|
+
return {
|
|
145
|
+
notifications: arrayResult(envelope, "notifications"),
|
|
146
|
+
total: parseTotal(envelope.message, envelope.result)
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
async function deleteNotification(input, ctx) {
|
|
150
|
+
const payload = await request(ctx, {
|
|
151
|
+
method: "DELETE",
|
|
152
|
+
path: `/notifications/${input.notification_id}`
|
|
153
|
+
});
|
|
154
|
+
ensureAccepted(payload, "notification deletion");
|
|
155
|
+
return { success: true };
|
|
156
|
+
}
|
|
157
|
+
async function listHotTopics(_input, ctx) {
|
|
158
|
+
return { topics: await legacyRequest(ctx, "/topics/hot.json") };
|
|
159
|
+
}
|
|
160
|
+
async function listLatestTopics(_input, ctx) {
|
|
161
|
+
return { topics: await legacyRequest(ctx, "/topics/latest.json") };
|
|
162
|
+
}
|
|
163
|
+
async function getCurrentMember(_input, ctx) {
|
|
164
|
+
const envelope = unwrapEnvelope(await request(ctx, { method: "GET", path: "/member" }), "member");
|
|
165
|
+
return { member: objectResult(envelope, "member") };
|
|
166
|
+
}
|
|
167
|
+
async function getCurrentToken(_input, ctx) {
|
|
168
|
+
const envelope = unwrapEnvelope(await request(ctx, { method: "GET", path: "/token" }), "token");
|
|
169
|
+
return { token: objectResult(envelope, "token") };
|
|
170
|
+
}
|
|
171
|
+
async function createToken(input, ctx) {
|
|
172
|
+
const envelope = unwrapEnvelope(
|
|
173
|
+
await request(ctx, {
|
|
174
|
+
method: "POST",
|
|
175
|
+
path: "/tokens",
|
|
176
|
+
body: { scope: input.scope, expiration: input.expiration }
|
|
177
|
+
}),
|
|
178
|
+
"token creation"
|
|
179
|
+
);
|
|
180
|
+
const token = trimmedText(objectResult(envelope, "token creation").token);
|
|
181
|
+
if (token === void 0) {
|
|
182
|
+
throw invalidResponse("V2EX token creation response missing token");
|
|
183
|
+
}
|
|
184
|
+
return { token };
|
|
185
|
+
}
|
|
186
|
+
async function getNode(input, ctx) {
|
|
187
|
+
const envelope = unwrapEnvelope(
|
|
188
|
+
await request(ctx, { method: "GET", path: `/nodes/${encodeURIComponent(input.node_name)}` }),
|
|
189
|
+
"node"
|
|
190
|
+
);
|
|
191
|
+
return { node: objectResult(envelope, "node") };
|
|
192
|
+
}
|
|
193
|
+
async function listNodeTopics(input, ctx) {
|
|
194
|
+
const envelope = unwrapEnvelope(
|
|
195
|
+
await request(ctx, {
|
|
196
|
+
method: "GET",
|
|
197
|
+
path: `/nodes/${encodeURIComponent(input.node_name)}/topics`,
|
|
198
|
+
query: { p: input.p }
|
|
199
|
+
}),
|
|
200
|
+
"topics"
|
|
201
|
+
);
|
|
202
|
+
return { topics: arrayResult(envelope, "topics") };
|
|
203
|
+
}
|
|
204
|
+
async function getTopic(input, ctx) {
|
|
205
|
+
const envelope = unwrapEnvelope(
|
|
206
|
+
await request(ctx, { method: "GET", path: `/topics/${input.topic_id}` }),
|
|
207
|
+
"topic"
|
|
208
|
+
);
|
|
209
|
+
return { topic: objectResult(envelope, "topic") };
|
|
210
|
+
}
|
|
211
|
+
async function listTopicReplies(input, ctx) {
|
|
212
|
+
const envelope = unwrapEnvelope(
|
|
213
|
+
await request(ctx, {
|
|
214
|
+
method: "GET",
|
|
215
|
+
path: `/topics/${input.topic_id}/replies`,
|
|
216
|
+
query: { p: input.p }
|
|
217
|
+
}),
|
|
218
|
+
"replies"
|
|
219
|
+
);
|
|
220
|
+
return { replies: arrayResult(envelope, "replies") };
|
|
221
|
+
}
|
|
222
|
+
async function setTopicSticky(input, ctx) {
|
|
223
|
+
const payload = await request(ctx, {
|
|
224
|
+
method: "POST",
|
|
225
|
+
path: `/topics/${input.topic_id}/set-sticky`,
|
|
226
|
+
query: { duration: input.duration }
|
|
227
|
+
});
|
|
228
|
+
ensureAccepted(payload, "topic sticky");
|
|
229
|
+
return { success: true };
|
|
230
|
+
}
|
|
231
|
+
async function boostTopic(input, ctx) {
|
|
232
|
+
const payload = await request(ctx, { method: "POST", path: `/topics/${input.topic_id}/boost` });
|
|
233
|
+
ensureAccepted(payload, "topic boost");
|
|
234
|
+
return { success: true };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ../plugins/src/v2ex/schema.ts
|
|
238
|
+
import { z } from "zod/v4";
|
|
239
|
+
var listNotificationsInput = z.strictObject({
|
|
240
|
+
p: z.int().min(1).describe("Optional page number to request. Defaults to 1.").optional()
|
|
241
|
+
}).describe("Input parameters for fetching V2EX notifications.");
|
|
242
|
+
var listNotificationsOutput = z.strictObject({
|
|
243
|
+
notifications: z.array(z.looseObject({
|
|
244
|
+
id: z.int().describe("The V2EX notification identifier.").optional(),
|
|
245
|
+
member_id: z.int().describe("The member identifier that triggered the notification.").optional(),
|
|
246
|
+
for_member_id: z.int().describe("The member identifier that received the notification.").optional(),
|
|
247
|
+
text: z.string().describe("The notification text.").optional(),
|
|
248
|
+
payload: z.string().describe("The notification payload string.").nullable().optional(),
|
|
249
|
+
payload_rendered: z.string().describe("The rendered notification payload.").optional(),
|
|
250
|
+
created: z.int().describe("The Unix timestamp when the notification was created.").optional(),
|
|
251
|
+
member: z.looseObject({}).describe("The member object associated with the notification.").optional()
|
|
252
|
+
}).describe("A V2EX notification object.")).describe("The notifications returned for this page."),
|
|
253
|
+
total: z.int().describe("The total notification count parsed from the V2EX pagination message.")
|
|
254
|
+
}).describe("The V2EX notifications response.");
|
|
255
|
+
var deleteNotificationInput = z.strictObject({
|
|
256
|
+
notification_id: z.int().min(1).describe("The V2EX numeric identifier.")
|
|
257
|
+
}).describe("Input parameters for deleting a V2EX notification.");
|
|
258
|
+
var deleteNotificationOutput = z.strictObject({
|
|
259
|
+
success: z.boolean().describe("Whether the V2EX request was accepted.")
|
|
260
|
+
}).describe("The empty response returned after V2EX accepts the request.");
|
|
261
|
+
var listHotTopicsInput = z.strictObject({}).describe("Input parameters for fetching V2EX legacy hot topics.");
|
|
262
|
+
var listHotTopicsOutput = z.strictObject({
|
|
263
|
+
topics: z.array(z.looseObject({
|
|
264
|
+
id: z.int().describe("The V2EX topic identifier.").optional(),
|
|
265
|
+
title: z.string().describe("The topic title.").optional(),
|
|
266
|
+
content: z.string().describe("The raw topic content.").optional(),
|
|
267
|
+
content_rendered: z.string().describe("The rendered topic content.").optional(),
|
|
268
|
+
url: z.url().describe("The V2EX URL for the topic.").optional(),
|
|
269
|
+
replies: z.int().describe("The number of replies on the topic.").optional(),
|
|
270
|
+
deleted: z.int().describe("Whether the topic has been deleted as returned by V2EX.").optional(),
|
|
271
|
+
last_reply_by: z.string().describe("The username of the latest reply author, or empty string.").optional(),
|
|
272
|
+
created: z.int().describe("The Unix timestamp when the topic was created.").optional(),
|
|
273
|
+
last_modified: z.int().describe("The Unix timestamp when the topic was last modified.").optional(),
|
|
274
|
+
last_touched: z.int().describe("The Unix timestamp when the topic was last touched.").optional(),
|
|
275
|
+
member: z.looseObject({
|
|
276
|
+
id: z.int().describe("The V2EX member identifier.").optional(),
|
|
277
|
+
username: z.string().describe("The V2EX username.").optional(),
|
|
278
|
+
url: z.url().describe("The V2EX URL for the member profile.").optional(),
|
|
279
|
+
website: z.string().describe("The member website URL, empty string, or null.").nullable().optional(),
|
|
280
|
+
twitter: z.string().describe("The member Twitter handle, empty string, or null.").nullable().optional(),
|
|
281
|
+
psn: z.string().describe("The member PlayStation Network handle, empty string, or null.").nullable().optional(),
|
|
282
|
+
github: z.string().describe("The member GitHub username, profile value, empty string, or null.").nullable().optional(),
|
|
283
|
+
btc: z.string().describe("The member Bitcoin address, empty string, or null.").nullable().optional(),
|
|
284
|
+
location: z.string().describe("The member location, empty string, or null.").nullable().optional(),
|
|
285
|
+
tagline: z.string().describe("The member tagline, empty string, or null.").nullable().optional(),
|
|
286
|
+
bio: z.string().describe("The member biography text, empty string, or null.").nullable().optional(),
|
|
287
|
+
avatar_mini: z.url().describe("The mini avatar URL.").optional(),
|
|
288
|
+
avatar_normal: z.url().describe("The normal avatar URL.").optional(),
|
|
289
|
+
avatar_large: z.url().describe("The large avatar URL.").optional(),
|
|
290
|
+
avatar_xlarge: z.url().describe("The extra-large avatar URL.").optional(),
|
|
291
|
+
avatar_xxlarge: z.url().describe("The double extra-large avatar URL.").optional(),
|
|
292
|
+
avatar_xxxlarge: z.url().describe("The triple extra-large avatar URL.").optional(),
|
|
293
|
+
created: z.int().describe("The Unix timestamp when the member account was created.").optional(),
|
|
294
|
+
last_modified: z.int().describe("The Unix timestamp when the member profile was last modified.").optional(),
|
|
295
|
+
pro: z.int().describe("Whether the member has V2EX Pro status as returned by V2EX.").optional()
|
|
296
|
+
}).describe("A member object returned by the V2EX legacy public API.").optional(),
|
|
297
|
+
node: z.looseObject({
|
|
298
|
+
id: z.int().describe("The V2EX node identifier.").optional(),
|
|
299
|
+
name: z.string().describe("The V2EX node name.").optional(),
|
|
300
|
+
url: z.url().describe("The V2EX URL for the node.").optional(),
|
|
301
|
+
title: z.string().describe("The human-readable node title.").optional(),
|
|
302
|
+
title_alternative: z.string().describe("The alternative node title.").optional(),
|
|
303
|
+
header: z.string().describe("The node header text.").optional(),
|
|
304
|
+
footer: z.string().describe("The node footer text.").optional(),
|
|
305
|
+
topics: z.int().describe("The number of topics in the node.").optional(),
|
|
306
|
+
avatar_mini: z.url().describe("The mini node avatar URL.").optional(),
|
|
307
|
+
avatar_normal: z.url().describe("The normal node avatar URL.").optional(),
|
|
308
|
+
avatar_large: z.url().describe("The large node avatar URL.").optional(),
|
|
309
|
+
stars: z.int().describe("The number of stars on the node.").optional(),
|
|
310
|
+
founder_id: z.int().describe("The member identifier of the node founder.").optional(),
|
|
311
|
+
aliases: z.array(z.string().describe("One node alias.")).describe("Alternative names for the node.").optional(),
|
|
312
|
+
root: z.boolean().describe("Whether this node is a root node.").optional(),
|
|
313
|
+
parent_node_name: z.string().describe("The parent node name, empty string, or null.").nullable().optional()
|
|
314
|
+
}).describe("A node object returned by the V2EX legacy public API.").optional()
|
|
315
|
+
}).describe("A topic object returned by the V2EX legacy public API.")).describe("The public topics returned by the V2EX legacy endpoint.")
|
|
316
|
+
}).describe("The V2EX legacy public topic list response.");
|
|
317
|
+
var listLatestTopicsInput = z.strictObject({}).describe("Input parameters for fetching V2EX legacy latest topics.");
|
|
318
|
+
var listLatestTopicsOutput = z.strictObject({
|
|
319
|
+
topics: z.array(z.looseObject({
|
|
320
|
+
id: z.int().describe("The V2EX topic identifier.").optional(),
|
|
321
|
+
title: z.string().describe("The topic title.").optional(),
|
|
322
|
+
content: z.string().describe("The raw topic content.").optional(),
|
|
323
|
+
content_rendered: z.string().describe("The rendered topic content.").optional(),
|
|
324
|
+
url: z.url().describe("The V2EX URL for the topic.").optional(),
|
|
325
|
+
replies: z.int().describe("The number of replies on the topic.").optional(),
|
|
326
|
+
deleted: z.int().describe("Whether the topic has been deleted as returned by V2EX.").optional(),
|
|
327
|
+
last_reply_by: z.string().describe("The username of the latest reply author, or empty string.").optional(),
|
|
328
|
+
created: z.int().describe("The Unix timestamp when the topic was created.").optional(),
|
|
329
|
+
last_modified: z.int().describe("The Unix timestamp when the topic was last modified.").optional(),
|
|
330
|
+
last_touched: z.int().describe("The Unix timestamp when the topic was last touched.").optional(),
|
|
331
|
+
member: z.looseObject({
|
|
332
|
+
id: z.int().describe("The V2EX member identifier.").optional(),
|
|
333
|
+
username: z.string().describe("The V2EX username.").optional(),
|
|
334
|
+
url: z.url().describe("The V2EX URL for the member profile.").optional(),
|
|
335
|
+
website: z.string().describe("The member website URL, empty string, or null.").nullable().optional(),
|
|
336
|
+
twitter: z.string().describe("The member Twitter handle, empty string, or null.").nullable().optional(),
|
|
337
|
+
psn: z.string().describe("The member PlayStation Network handle, empty string, or null.").nullable().optional(),
|
|
338
|
+
github: z.string().describe("The member GitHub username, profile value, empty string, or null.").nullable().optional(),
|
|
339
|
+
btc: z.string().describe("The member Bitcoin address, empty string, or null.").nullable().optional(),
|
|
340
|
+
location: z.string().describe("The member location, empty string, or null.").nullable().optional(),
|
|
341
|
+
tagline: z.string().describe("The member tagline, empty string, or null.").nullable().optional(),
|
|
342
|
+
bio: z.string().describe("The member biography text, empty string, or null.").nullable().optional(),
|
|
343
|
+
avatar_mini: z.url().describe("The mini avatar URL.").optional(),
|
|
344
|
+
avatar_normal: z.url().describe("The normal avatar URL.").optional(),
|
|
345
|
+
avatar_large: z.url().describe("The large avatar URL.").optional(),
|
|
346
|
+
avatar_xlarge: z.url().describe("The extra-large avatar URL.").optional(),
|
|
347
|
+
avatar_xxlarge: z.url().describe("The double extra-large avatar URL.").optional(),
|
|
348
|
+
avatar_xxxlarge: z.url().describe("The triple extra-large avatar URL.").optional(),
|
|
349
|
+
created: z.int().describe("The Unix timestamp when the member account was created.").optional(),
|
|
350
|
+
last_modified: z.int().describe("The Unix timestamp when the member profile was last modified.").optional(),
|
|
351
|
+
pro: z.int().describe("Whether the member has V2EX Pro status as returned by V2EX.").optional()
|
|
352
|
+
}).describe("A member object returned by the V2EX legacy public API.").optional(),
|
|
353
|
+
node: z.looseObject({
|
|
354
|
+
id: z.int().describe("The V2EX node identifier.").optional(),
|
|
355
|
+
name: z.string().describe("The V2EX node name.").optional(),
|
|
356
|
+
url: z.url().describe("The V2EX URL for the node.").optional(),
|
|
357
|
+
title: z.string().describe("The human-readable node title.").optional(),
|
|
358
|
+
title_alternative: z.string().describe("The alternative node title.").optional(),
|
|
359
|
+
header: z.string().describe("The node header text.").optional(),
|
|
360
|
+
footer: z.string().describe("The node footer text.").optional(),
|
|
361
|
+
topics: z.int().describe("The number of topics in the node.").optional(),
|
|
362
|
+
avatar_mini: z.url().describe("The mini node avatar URL.").optional(),
|
|
363
|
+
avatar_normal: z.url().describe("The normal node avatar URL.").optional(),
|
|
364
|
+
avatar_large: z.url().describe("The large node avatar URL.").optional(),
|
|
365
|
+
stars: z.int().describe("The number of stars on the node.").optional(),
|
|
366
|
+
founder_id: z.int().describe("The member identifier of the node founder.").optional(),
|
|
367
|
+
aliases: z.array(z.string().describe("One node alias.")).describe("Alternative names for the node.").optional(),
|
|
368
|
+
root: z.boolean().describe("Whether this node is a root node.").optional(),
|
|
369
|
+
parent_node_name: z.string().describe("The parent node name, empty string, or null.").nullable().optional()
|
|
370
|
+
}).describe("A node object returned by the V2EX legacy public API.").optional()
|
|
371
|
+
}).describe("A topic object returned by the V2EX legacy public API.")).describe("The public topics returned by the V2EX legacy endpoint.")
|
|
372
|
+
}).describe("The V2EX legacy public topic list response.");
|
|
373
|
+
var getCurrentMemberInput = z.strictObject({}).describe("Input parameters for fetching the authenticated V2EX member.");
|
|
374
|
+
var getCurrentMemberOutput = z.strictObject({
|
|
375
|
+
member: z.looseObject({
|
|
376
|
+
id: z.int().describe("The V2EX member identifier.").optional(),
|
|
377
|
+
username: z.string().describe("The V2EX username.").optional(),
|
|
378
|
+
url: z.url().describe("The V2EX URL for the member profile.").optional(),
|
|
379
|
+
website: z.string().describe("The member website URL or empty string.").optional(),
|
|
380
|
+
twitter: z.string().describe("The member Twitter handle or empty string.").optional(),
|
|
381
|
+
psn: z.string().describe("The member PlayStation Network handle or empty string.").optional(),
|
|
382
|
+
github: z.string().describe("The member GitHub username or profile value.").optional(),
|
|
383
|
+
btc: z.string().describe("The member Bitcoin address or empty string.").optional(),
|
|
384
|
+
location: z.string().describe("The member location or empty string.").optional(),
|
|
385
|
+
tagline: z.string().describe("The member tagline or empty string.").optional(),
|
|
386
|
+
bio: z.string().describe("The member biography text.").optional(),
|
|
387
|
+
avatar_mini: z.url().describe("The mini avatar URL.").optional(),
|
|
388
|
+
avatar_normal: z.url().describe("The normal avatar URL.").optional(),
|
|
389
|
+
avatar_large: z.url().describe("The large avatar URL.").optional(),
|
|
390
|
+
created: z.int().describe("The Unix timestamp when the member account was created.").optional(),
|
|
391
|
+
last_modified: z.int().describe("The Unix timestamp when the profile was last modified.").optional(),
|
|
392
|
+
pro: z.int().describe("Whether the member has V2EX Pro status as returned by V2EX.").optional()
|
|
393
|
+
}).describe("The authenticated V2EX member profile.")
|
|
394
|
+
}).describe("The V2EX member profile response.");
|
|
395
|
+
var getCurrentTokenInput = z.strictObject({}).describe("Input parameters for fetching current V2EX token metadata.");
|
|
396
|
+
var getCurrentTokenOutput = z.strictObject({
|
|
397
|
+
token: z.looseObject({
|
|
398
|
+
token: z.string().describe("The token value as returned by V2EX. It may be masked after creation.").optional(),
|
|
399
|
+
scope: z.enum(["everything", "regular"]).describe("The token scope.").optional(),
|
|
400
|
+
expiration: z.int().describe("The token lifetime in seconds.").optional(),
|
|
401
|
+
good_for_days: z.int().describe("The remaining token lifetime in days.").optional(),
|
|
402
|
+
total_used: z.int().describe("The total number of times the token has been used.").optional(),
|
|
403
|
+
last_used: z.int().describe("The Unix timestamp when the token was last used.").optional(),
|
|
404
|
+
created: z.int().describe("The Unix timestamp when the token was created.").optional()
|
|
405
|
+
}).describe("Metadata for a V2EX Personal Access Token.")
|
|
406
|
+
}).describe("The V2EX token metadata response.");
|
|
407
|
+
var createTokenInput = z.strictObject({
|
|
408
|
+
scope: z.enum(["everything", "regular"]).describe("The access scope for the new V2EX token."),
|
|
409
|
+
expiration: z.union([z.literal(2592e3).describe("A 30-day token lifetime in seconds."), z.literal(5184e3).describe("A 60-day token lifetime in seconds."), z.literal(7776e3).describe("A 90-day token lifetime in seconds."), z.literal(15552e3).describe("A 180-day token lifetime in seconds.")]).describe("The token lifetime in seconds.")
|
|
410
|
+
}).describe("Input parameters for creating a V2EX Personal Access Token.");
|
|
411
|
+
var createTokenOutput = z.strictObject({
|
|
412
|
+
token: z.string().describe("The newly created Personal Access Token value.")
|
|
413
|
+
}).describe("The V2EX token creation response.");
|
|
414
|
+
var getNodeInput = z.strictObject({
|
|
415
|
+
node_name: z.string().min(1).describe("The V2EX node name, such as `python`.")
|
|
416
|
+
}).describe("Input parameters for fetching a V2EX node.");
|
|
417
|
+
var getNodeOutput = z.strictObject({
|
|
418
|
+
node: z.looseObject({
|
|
419
|
+
id: z.int().describe("The V2EX node identifier.").optional(),
|
|
420
|
+
founder_id: z.int().describe("The member identifier of the node founder.").optional(),
|
|
421
|
+
url: z.url().describe("The V2EX URL for the node.").optional(),
|
|
422
|
+
name: z.string().describe("The V2EX node name.").optional(),
|
|
423
|
+
title: z.string().describe("The human-readable node title.").optional(),
|
|
424
|
+
header: z.string().describe("The node header text.").optional(),
|
|
425
|
+
footer: z.string().describe("The node footer text.").optional(),
|
|
426
|
+
avatar: z.url().describe("The node avatar URL.").optional(),
|
|
427
|
+
topics: z.int().describe("The number of topics in the node.").optional(),
|
|
428
|
+
created: z.int().describe("The Unix timestamp when the node was created.").optional(),
|
|
429
|
+
last_modified: z.int().describe("The Unix timestamp when the node was last modified.").optional()
|
|
430
|
+
}).describe("A V2EX node object.")
|
|
431
|
+
}).describe("The V2EX node response.");
|
|
432
|
+
var listNodeTopicsInput = z.strictObject({
|
|
433
|
+
node_name: z.string().min(1).describe("The V2EX node name, such as `python`."),
|
|
434
|
+
p: z.int().min(1).describe("Optional page number to request. Defaults to 1.").optional()
|
|
435
|
+
}).describe("Input parameters for fetching topics from a V2EX node.");
|
|
436
|
+
var listNodeTopicsOutput = z.strictObject({
|
|
437
|
+
topics: z.array(z.looseObject({
|
|
438
|
+
id: z.int().describe("The V2EX topic identifier.").optional(),
|
|
439
|
+
title: z.string().describe("The topic title.").optional(),
|
|
440
|
+
content: z.string().describe("The raw topic content.").optional(),
|
|
441
|
+
content_rendered: z.string().describe("The rendered topic content.").optional(),
|
|
442
|
+
syntax: z.int().describe("The content syntax mode returned by V2EX.").optional(),
|
|
443
|
+
url: z.url().describe("The V2EX URL for the topic.").optional(),
|
|
444
|
+
replies: z.int().describe("The number of replies on the topic.").optional(),
|
|
445
|
+
stars: z.int().describe("The number of stars on the topic.").optional(),
|
|
446
|
+
thanks: z.int().describe("The number of thanks on the topic.").optional(),
|
|
447
|
+
last_reply_by: z.string().describe("The username of the latest reply author, or empty string.").optional(),
|
|
448
|
+
created: z.int().describe("The Unix timestamp when the topic was created.").optional(),
|
|
449
|
+
last_modified: z.int().describe("The Unix timestamp when the topic was last modified.").optional(),
|
|
450
|
+
last_touched: z.int().describe("The Unix timestamp when the topic was last touched.").optional(),
|
|
451
|
+
member: z.looseObject({
|
|
452
|
+
id: z.int().describe("The V2EX member identifier.").optional(),
|
|
453
|
+
username: z.string().describe("The V2EX username.").optional(),
|
|
454
|
+
bio: z.string().describe("The member biography text.").optional(),
|
|
455
|
+
website: z.string().describe("The member website URL or empty string.").optional(),
|
|
456
|
+
github: z.string().describe("The member GitHub username or profile value.").optional(),
|
|
457
|
+
url: z.url().describe("The V2EX URL for the member profile.").optional(),
|
|
458
|
+
avatar: z.url().describe("The member avatar URL.").optional(),
|
|
459
|
+
created: z.int().describe("The Unix timestamp when the member account was created.").optional(),
|
|
460
|
+
pro: z.int().describe("Whether the member has V2EX Pro status as returned by V2EX.").optional()
|
|
461
|
+
}).describe("A compact V2EX member object.").optional(),
|
|
462
|
+
node: z.looseObject({
|
|
463
|
+
id: z.int().describe("The V2EX node identifier.").optional(),
|
|
464
|
+
founder_id: z.int().describe("The member identifier of the node founder.").optional(),
|
|
465
|
+
url: z.url().describe("The V2EX URL for the node.").optional(),
|
|
466
|
+
name: z.string().describe("The V2EX node name.").optional(),
|
|
467
|
+
title: z.string().describe("The human-readable node title.").optional(),
|
|
468
|
+
header: z.string().describe("The node header text.").optional(),
|
|
469
|
+
footer: z.string().describe("The node footer text.").optional(),
|
|
470
|
+
avatar: z.url().describe("The node avatar URL.").optional(),
|
|
471
|
+
topics: z.int().describe("The number of topics in the node.").optional(),
|
|
472
|
+
created: z.int().describe("The Unix timestamp when the node was created.").optional(),
|
|
473
|
+
last_modified: z.int().describe("The Unix timestamp when the node was last modified.").optional()
|
|
474
|
+
}).describe("A V2EX node object.").optional(),
|
|
475
|
+
supplements: z.array(z.unknown().describe("One supplement.")).describe("Supplement objects attached to the topic.").optional()
|
|
476
|
+
}).describe("A V2EX topic object.")).describe("The topics returned for this node page.")
|
|
477
|
+
}).describe("The V2EX node topics response.");
|
|
478
|
+
var getTopicInput = z.strictObject({
|
|
479
|
+
topic_id: z.int().min(1).describe("The V2EX numeric identifier.")
|
|
480
|
+
}).describe("Input parameters for fetching a V2EX topic.");
|
|
481
|
+
var getTopicOutput = z.strictObject({
|
|
482
|
+
topic: z.looseObject({
|
|
483
|
+
id: z.int().describe("The V2EX topic identifier.").optional(),
|
|
484
|
+
title: z.string().describe("The topic title.").optional(),
|
|
485
|
+
content: z.string().describe("The raw topic content.").optional(),
|
|
486
|
+
content_rendered: z.string().describe("The rendered topic content.").optional(),
|
|
487
|
+
syntax: z.int().describe("The content syntax mode returned by V2EX.").optional(),
|
|
488
|
+
url: z.url().describe("The V2EX URL for the topic.").optional(),
|
|
489
|
+
replies: z.int().describe("The number of replies on the topic.").optional(),
|
|
490
|
+
stars: z.int().describe("The number of stars on the topic.").optional(),
|
|
491
|
+
thanks: z.int().describe("The number of thanks on the topic.").optional(),
|
|
492
|
+
last_reply_by: z.string().describe("The username of the latest reply author, or empty string.").optional(),
|
|
493
|
+
created: z.int().describe("The Unix timestamp when the topic was created.").optional(),
|
|
494
|
+
last_modified: z.int().describe("The Unix timestamp when the topic was last modified.").optional(),
|
|
495
|
+
last_touched: z.int().describe("The Unix timestamp when the topic was last touched.").optional(),
|
|
496
|
+
member: z.looseObject({
|
|
497
|
+
id: z.int().describe("The V2EX member identifier.").optional(),
|
|
498
|
+
username: z.string().describe("The V2EX username.").optional(),
|
|
499
|
+
bio: z.string().describe("The member biography text.").optional(),
|
|
500
|
+
website: z.string().describe("The member website URL or empty string.").optional(),
|
|
501
|
+
github: z.string().describe("The member GitHub username or profile value.").optional(),
|
|
502
|
+
url: z.url().describe("The V2EX URL for the member profile.").optional(),
|
|
503
|
+
avatar: z.url().describe("The member avatar URL.").optional(),
|
|
504
|
+
created: z.int().describe("The Unix timestamp when the member account was created.").optional(),
|
|
505
|
+
pro: z.int().describe("Whether the member has V2EX Pro status as returned by V2EX.").optional()
|
|
506
|
+
}).describe("A compact V2EX member object.").optional(),
|
|
507
|
+
node: z.looseObject({
|
|
508
|
+
id: z.int().describe("The V2EX node identifier.").optional(),
|
|
509
|
+
founder_id: z.int().describe("The member identifier of the node founder.").optional(),
|
|
510
|
+
url: z.url().describe("The V2EX URL for the node.").optional(),
|
|
511
|
+
name: z.string().describe("The V2EX node name.").optional(),
|
|
512
|
+
title: z.string().describe("The human-readable node title.").optional(),
|
|
513
|
+
header: z.string().describe("The node header text.").optional(),
|
|
514
|
+
footer: z.string().describe("The node footer text.").optional(),
|
|
515
|
+
avatar: z.url().describe("The node avatar URL.").optional(),
|
|
516
|
+
topics: z.int().describe("The number of topics in the node.").optional(),
|
|
517
|
+
created: z.int().describe("The Unix timestamp when the node was created.").optional(),
|
|
518
|
+
last_modified: z.int().describe("The Unix timestamp when the node was last modified.").optional()
|
|
519
|
+
}).describe("A V2EX node object.").optional(),
|
|
520
|
+
supplements: z.array(z.unknown().describe("One supplement.")).describe("Supplement objects attached to the topic.").optional()
|
|
521
|
+
}).describe("A V2EX topic object.")
|
|
522
|
+
}).describe("The V2EX topic response.");
|
|
523
|
+
var listTopicRepliesInput = z.strictObject({
|
|
524
|
+
topic_id: z.int().min(1).describe("The V2EX numeric identifier."),
|
|
525
|
+
p: z.int().min(1).describe("Optional page number to request. Defaults to 1.").optional()
|
|
526
|
+
}).describe("Input parameters for fetching replies for a V2EX topic.");
|
|
527
|
+
var listTopicRepliesOutput = z.strictObject({
|
|
528
|
+
replies: z.array(z.looseObject({
|
|
529
|
+
id: z.int().describe("The V2EX reply identifier.").optional(),
|
|
530
|
+
content: z.string().describe("The raw reply content.").optional(),
|
|
531
|
+
content_rendered: z.string().describe("The rendered reply content.").optional(),
|
|
532
|
+
created: z.int().describe("The Unix timestamp when the reply was created.").optional(),
|
|
533
|
+
member: z.looseObject({
|
|
534
|
+
id: z.int().describe("The V2EX member identifier.").optional(),
|
|
535
|
+
username: z.string().describe("The V2EX username.").optional(),
|
|
536
|
+
bio: z.string().describe("The member biography text.").optional(),
|
|
537
|
+
website: z.string().describe("The member website URL or empty string.").optional(),
|
|
538
|
+
github: z.string().describe("The member GitHub username or profile value.").optional(),
|
|
539
|
+
url: z.url().describe("The V2EX URL for the member profile.").optional(),
|
|
540
|
+
avatar: z.url().describe("The member avatar URL.").optional(),
|
|
541
|
+
created: z.int().describe("The Unix timestamp when the member account was created.").optional(),
|
|
542
|
+
pro: z.int().describe("Whether the member has V2EX Pro status as returned by V2EX.").optional()
|
|
543
|
+
}).describe("A compact V2EX member object.").optional()
|
|
544
|
+
}).describe("A V2EX topic reply object.")).describe("The replies returned for this topic page.")
|
|
545
|
+
}).describe("The V2EX topic replies response.");
|
|
546
|
+
var setTopicStickyInput = z.strictObject({
|
|
547
|
+
topic_id: z.int().min(1).describe("The V2EX numeric identifier."),
|
|
548
|
+
duration: z.enum(["15min", "1hr", "8hr"]).describe("Optional sticky duration. Defaults to 15min.").optional()
|
|
549
|
+
}).describe("Input parameters for setting a V2EX topic as sticky.");
|
|
550
|
+
var setTopicStickyOutput = z.strictObject({
|
|
551
|
+
success: z.boolean().describe("Whether the V2EX request was accepted.")
|
|
552
|
+
}).describe("The empty response returned after V2EX accepts the request.");
|
|
553
|
+
var boostTopicInput = z.strictObject({
|
|
554
|
+
topic_id: z.int().min(1).describe("The V2EX numeric identifier.")
|
|
555
|
+
}).describe("Input parameters for boosting a V2EX topic.");
|
|
556
|
+
var boostTopicOutput = z.strictObject({
|
|
557
|
+
success: z.boolean().describe("Whether the V2EX request was accepted.")
|
|
558
|
+
}).describe("The empty response returned after V2EX accepts the request.");
|
|
559
|
+
var v2exActions = {
|
|
560
|
+
list_notifications: {
|
|
561
|
+
description: "Fetch the latest V2EX notifications for the authenticated member.",
|
|
562
|
+
effect: "read",
|
|
563
|
+
inputSchema: listNotificationsInput,
|
|
564
|
+
outputSchema: z.toJSONSchema(listNotificationsOutput, { io: "output", unrepresentable: "any" })
|
|
565
|
+
},
|
|
566
|
+
delete_notification: {
|
|
567
|
+
description: "Delete one V2EX notification by its numeric identifier.",
|
|
568
|
+
effect: "destructive",
|
|
569
|
+
inputSchema: deleteNotificationInput,
|
|
570
|
+
outputSchema: z.toJSONSchema(deleteNotificationOutput, { io: "output", unrepresentable: "any" })
|
|
571
|
+
},
|
|
572
|
+
list_hot_topics: {
|
|
573
|
+
description: "Fetch public hot topics from the V2EX legacy JSON API.",
|
|
574
|
+
effect: "read",
|
|
575
|
+
inputSchema: listHotTopicsInput,
|
|
576
|
+
outputSchema: z.toJSONSchema(listHotTopicsOutput, { io: "output", unrepresentable: "any" })
|
|
577
|
+
},
|
|
578
|
+
list_latest_topics: {
|
|
579
|
+
description: "Fetch public latest topics from the V2EX legacy JSON API.",
|
|
580
|
+
effect: "read",
|
|
581
|
+
inputSchema: listLatestTopicsInput,
|
|
582
|
+
outputSchema: z.toJSONSchema(listLatestTopicsOutput, { io: "output", unrepresentable: "any" })
|
|
583
|
+
},
|
|
584
|
+
get_current_member: {
|
|
585
|
+
description: "Fetch the authenticated V2EX member profile.",
|
|
586
|
+
effect: "read",
|
|
587
|
+
inputSchema: getCurrentMemberInput,
|
|
588
|
+
outputSchema: z.toJSONSchema(getCurrentMemberOutput, { io: "output", unrepresentable: "any" })
|
|
589
|
+
},
|
|
590
|
+
get_current_token: {
|
|
591
|
+
description: "Fetch metadata for the V2EX Personal Access Token used by this connection.",
|
|
592
|
+
effect: "read",
|
|
593
|
+
inputSchema: getCurrentTokenInput,
|
|
594
|
+
outputSchema: z.toJSONSchema(getCurrentTokenOutput, { io: "output", unrepresentable: "any" })
|
|
595
|
+
},
|
|
596
|
+
create_token: {
|
|
597
|
+
description: "Create a new V2EX Personal Access Token from an existing token.",
|
|
598
|
+
effect: "write",
|
|
599
|
+
inputSchema: createTokenInput,
|
|
600
|
+
outputSchema: z.toJSONSchema(createTokenOutput, { io: "output", unrepresentable: "any" })
|
|
601
|
+
},
|
|
602
|
+
get_node: {
|
|
603
|
+
description: "Fetch a V2EX node by node name.",
|
|
604
|
+
effect: "read",
|
|
605
|
+
inputSchema: getNodeInput,
|
|
606
|
+
outputSchema: z.toJSONSchema(getNodeOutput, { io: "output", unrepresentable: "any" })
|
|
607
|
+
},
|
|
608
|
+
list_node_topics: {
|
|
609
|
+
description: "Fetch topics from a V2EX node.",
|
|
610
|
+
effect: "read",
|
|
611
|
+
inputSchema: listNodeTopicsInput,
|
|
612
|
+
outputSchema: z.toJSONSchema(listNodeTopicsOutput, { io: "output", unrepresentable: "any" })
|
|
613
|
+
},
|
|
614
|
+
get_topic: {
|
|
615
|
+
description: "Fetch a V2EX topic by numeric identifier.",
|
|
616
|
+
effect: "read",
|
|
617
|
+
inputSchema: getTopicInput,
|
|
618
|
+
outputSchema: z.toJSONSchema(getTopicOutput, { io: "output", unrepresentable: "any" })
|
|
619
|
+
},
|
|
620
|
+
list_topic_replies: {
|
|
621
|
+
description: "Fetch replies for a V2EX topic.",
|
|
622
|
+
effect: "read",
|
|
623
|
+
inputSchema: listTopicRepliesInput,
|
|
624
|
+
outputSchema: z.toJSONSchema(listTopicRepliesOutput, { io: "output", unrepresentable: "any" })
|
|
625
|
+
},
|
|
626
|
+
set_topic_sticky: {
|
|
627
|
+
description: "Set one of the authenticated member's V2EX topics as sticky.",
|
|
628
|
+
effect: "write",
|
|
629
|
+
inputSchema: setTopicStickyInput,
|
|
630
|
+
outputSchema: z.toJSONSchema(setTopicStickyOutput, { io: "output", unrepresentable: "any" })
|
|
631
|
+
},
|
|
632
|
+
boost_topic: {
|
|
633
|
+
description: "Boost one of the authenticated member's V2EX topics to the homepage.",
|
|
634
|
+
effect: "write",
|
|
635
|
+
inputSchema: boostTopicInput,
|
|
636
|
+
outputSchema: z.toJSONSchema(boostTopicOutput, { io: "output", unrepresentable: "any" })
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
// ../plugins/src/v2ex/index.ts
|
|
641
|
+
function createV2exPlugin() {
|
|
642
|
+
return createProviderPlugin({
|
|
643
|
+
description: "V2EX",
|
|
644
|
+
credentialProbe: "get_current_member",
|
|
645
|
+
actions: v2exActions,
|
|
646
|
+
handlers: {
|
|
647
|
+
list_notifications: listNotifications,
|
|
648
|
+
delete_notification: deleteNotification,
|
|
649
|
+
list_hot_topics: listHotTopics,
|
|
650
|
+
list_latest_topics: listLatestTopics,
|
|
651
|
+
get_current_member: getCurrentMember,
|
|
652
|
+
get_current_token: getCurrentToken,
|
|
653
|
+
create_token: createToken,
|
|
654
|
+
get_node: getNode,
|
|
655
|
+
list_node_topics: listNodeTopics,
|
|
656
|
+
get_topic: getTopic,
|
|
657
|
+
list_topic_replies: listTopicReplies,
|
|
658
|
+
set_topic_sticky: setTopicSticky,
|
|
659
|
+
boost_topic: boostTopic
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
var v2ex_default = createV2exPlugin();
|
|
664
|
+
export {
|
|
665
|
+
createV2exPlugin,
|
|
666
|
+
v2ex_default as default
|
|
667
|
+
};
|