koishi-plugin-crom-querier-modified 2.0.0 → 2.0.2
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/lib/index.js +47 -156
- package/lib/lib.d.ts +3 -4
- package/lib/types.d.ts +21 -51
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -79,64 +79,37 @@ var apiList = [
|
|
|
79
79
|
];
|
|
80
80
|
var branchInfo = {
|
|
81
81
|
// br
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"it": { url: "http://it-backrooms-wiki.wikidot.com" },
|
|
93
|
-
"de": { url: "http://de-backrooms-wiki.wikidot.com" },
|
|
94
|
-
// scp
|
|
95
|
-
"scp-cn": { url: "http://scp-wiki-cn.wikidot.com" },
|
|
96
|
-
"scp-cs": { url: "http://scp-cs.wikidot.com" },
|
|
97
|
-
"scp-de": { url: "http://scp-wiki-de.wikidot.com" },
|
|
98
|
-
"scp-en": { url: "http://scp-wiki.wikidot.com" },
|
|
99
|
-
"scp-es": { url: "http://lafundacionscp.wikidot.com" },
|
|
100
|
-
"scp-fr": { url: "http://fondationscp.wikidot.com" },
|
|
101
|
-
"scp-int": { url: "http://scp-int.wikidot.com" },
|
|
102
|
-
"scp-it": { url: "http://fondazionescp.wikidot.com" },
|
|
103
|
-
"scp-jp": { url: "http://scp-jp.wikidot.com" },
|
|
104
|
-
"scp-ko": { url: "http://scpko.wikidot.com" },
|
|
105
|
-
"scp-pl": { url: "http://scp-pl.wikidot.com" },
|
|
106
|
-
"scp-ptbr": { url: "http://scp-pt-br.wikidot.com" },
|
|
107
|
-
"scp-ru": { url: "http://scp-ru.wikidot.com" },
|
|
108
|
-
"scp-th": { url: "http://scp-th.wikidot.com" },
|
|
109
|
-
"scp-uk": { url: "http://scp-ukrainian.wikidot.com" },
|
|
110
|
-
"scp-vn": { url: "http://scp-vn.wikidot.com" },
|
|
111
|
-
"scp-el": { url: "http://scp-el.wikidot.com" },
|
|
112
|
-
"scp-id": { url: "http://scp-id.wikidot.com" },
|
|
113
|
-
// others
|
|
114
|
-
"na": { url: "http://nationarea.wikidot.com" },
|
|
115
|
-
"ci-cn": { url: "http://ci-cn-wiki.wikidot.com" },
|
|
116
|
-
// wl
|
|
117
|
-
"wl-en": { url: "http://wanderers-library.wikidot.com" },
|
|
118
|
-
"wl-pl": { url: "http://wanderers-library-pl.wikidot.com" },
|
|
119
|
-
"wl-jp": { url: "http://wanderers-library-jp.wikidot.com" },
|
|
120
|
-
"wl-cs": { url: "http://wanderers-library-cs.wikidot.com" },
|
|
121
|
-
"wl-ko": { url: "http://wanderers-library-ko.wikidot.com" },
|
|
122
|
-
"wl-vn": { url: "http://wanderers-library-vn.wikidot.com" }
|
|
82
|
+
"ubmh": { wiki: "ubmh" },
|
|
83
|
+
"scp-cloud": { wiki: "scp-wiki-cloud" },
|
|
84
|
+
"cloud": { wiki: "backroom-wiki-cn" },
|
|
85
|
+
"scr": { wiki: "scr-wiki" },
|
|
86
|
+
"deep": { wiki: "deep-forest-club" },
|
|
87
|
+
"rule": { wiki: "rule-wiki" },
|
|
88
|
+
"as": { wiki: "asbackroom" },
|
|
89
|
+
"lm": { wiki: "lostmedia" },
|
|
90
|
+
"if": { wiki: "if-backrooms" },
|
|
91
|
+
"rpc": { wiki: "rpc-wiki-cn" }
|
|
123
92
|
};
|
|
124
|
-
async function cromApiRequest(
|
|
93
|
+
async function cromApiRequest(param, name2, endpointIndex = 0, queryString) {
|
|
125
94
|
if (endpointIndex >= apiList.length) {
|
|
126
95
|
throw new Error("所有API端点均已尝试但均失败");
|
|
127
96
|
}
|
|
97
|
+
let variables = {};
|
|
98
|
+
const branchShortName = name2;
|
|
99
|
+
if (queryString.includes("query titleQuery")) {
|
|
100
|
+
variables = { query: param, anyBaseUrl: branchShortName ? [branchShortName] : null };
|
|
101
|
+
} else if (queryString.includes("query userQuery")) {
|
|
102
|
+
variables = { query: param, baseUrl: branchShortName };
|
|
103
|
+
} else if (queryString.includes("query userRankQuery")) {
|
|
104
|
+
variables = { baseUrl: branchShortName };
|
|
105
|
+
}
|
|
128
106
|
try {
|
|
129
107
|
const response = await fetch(apiList[endpointIndex], {
|
|
130
108
|
method: "POST",
|
|
131
109
|
headers: { "Content-Type": "application/json" },
|
|
132
110
|
body: JSON.stringify({
|
|
133
111
|
query: queryString,
|
|
134
|
-
variables
|
|
135
|
-
query: titleQuery,
|
|
136
|
-
anyBaseUrl: baseUrl !== "" ? baseUrl : null,
|
|
137
|
-
baseUrl,
|
|
138
|
-
rank: parseInt(titleQuery.replace(/#([0-9]{1,15})/, "$1")) || 0
|
|
139
|
-
}
|
|
112
|
+
variables
|
|
140
113
|
})
|
|
141
114
|
});
|
|
142
115
|
if (!response.ok) {
|
|
@@ -144,12 +117,12 @@ async function cromApiRequest(titleQuery, baseUrl, endpointIndex = 0, queryStrin
|
|
|
144
117
|
}
|
|
145
118
|
const { data, errors } = await response.json();
|
|
146
119
|
if (errors && errors.length > 0) {
|
|
147
|
-
return await cromApiRequest(
|
|
120
|
+
return await cromApiRequest(param, name2, endpointIndex + 1, queryString);
|
|
148
121
|
}
|
|
149
122
|
return data;
|
|
150
123
|
} catch (error) {
|
|
151
124
|
if (endpointIndex < apiList.length - 1) {
|
|
152
|
-
return await cromApiRequest(
|
|
125
|
+
return await cromApiRequest(param, name2, endpointIndex + 1, queryString);
|
|
153
126
|
}
|
|
154
127
|
throw error;
|
|
155
128
|
}
|
|
@@ -173,19 +146,8 @@ function apply(ctx, config) {
|
|
|
173
146
|
defaultBranch: "string(64)"
|
|
174
147
|
});
|
|
175
148
|
const normalizeUrl = /* @__PURE__ */ __name((url) => url.replace(/^https?:\/\/backrooms-wiki-cn.wikidot.com/, "https://brcn.backroomswiki.cn").replace(/^https?:\/\/scp-wiki-cn.wikidot.com/, "https://scpcn.backroomswiki.cn").replace(/^https?:\/\/([a-z]+-wiki-cn|nationarea)/, "https://$1"), "normalizeUrl");
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (Object.keys(branchInfo).includes(lastStr)) {
|
|
179
|
-
return branchInfo[lastStr].url;
|
|
180
|
-
} else if (branch && Object.keys(branchInfo).includes(branch)) {
|
|
181
|
-
return branchInfo[branch].url;
|
|
182
|
-
} else if (branchUrls.length > 0) {
|
|
183
|
-
return branchInfo[branchUrls[0].defaultBranch].url;
|
|
184
|
-
} else {
|
|
185
|
-
return branchInfo.cn.url;
|
|
186
|
-
}
|
|
187
|
-
}, "getBranchUrl");
|
|
188
|
-
ctx.command("default-branch <分部名称:string>", "设置默认分部。").alias("默认分部").alias("默认").alias("db").action(async (argv, branch) => {
|
|
149
|
+
let cmd = ctx.command("wikit");
|
|
150
|
+
cmd.subcommand("default-branch <分部名称:string>", "设置默认分部。").alias("默认分部").alias("默认").alias("db").action(async (argv, branch) => {
|
|
189
151
|
const platform = argv.session.event.platform;
|
|
190
152
|
const channelId = argv.session.event.channel.id;
|
|
191
153
|
if (!branch || !Object.keys(branchInfo).includes(branch) || branch === "all") {
|
|
@@ -194,30 +156,12 @@ function apply(ctx, config) {
|
|
|
194
156
|
ctx.database.upsert("cromQuerier", [{ channelId, platform, defaultBranch: branch }], ["platform", "channelId"]);
|
|
195
157
|
return `已将本群默认查询分部设置为: ${branch}`;
|
|
196
158
|
});
|
|
197
|
-
|
|
198
|
-
const branchUrl = await getBranchUrl(branch, argv.args.at(-1), argv.session.event);
|
|
159
|
+
cmd.subcommand("author <作者:string> [分部名称:string]", "查询作者信息。\n默认搜索后室中文站。").alias("作者").alias("作").alias("au").action(async (argv, author, branch) => {
|
|
199
160
|
const isRankQuery = /^#[0-9]{1,15}$/.test(author);
|
|
200
161
|
const queryString = isRankQuery ? queries.userRankQuery : queries.userQuery;
|
|
201
162
|
const authorName = branch && !Object.keys(branchInfo).includes(branch) || !author ? Object.keys(branchInfo).includes(argv.args.at(-1)) ? argv.args.slice(0, -1).join(" ") : argv.args.join(" ") : author;
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
return "";
|
|
205
|
-
}
|
|
206
|
-
const filteredInfos = authorInfos.filter(
|
|
207
|
-
(info) => info.authorPage.translationOf == null && !info.authorPage.url.includes("old:") && !info.authorPage.url.includes("deleted:")
|
|
208
|
-
);
|
|
209
|
-
if (filteredInfos.length === 0) return "";
|
|
210
|
-
const matchingAuthorInfos = filteredInfos.filter(
|
|
211
|
-
(info) => info.authorPage.url.includes(author2)
|
|
212
|
-
);
|
|
213
|
-
return matchingAuthorInfos.length > 0 ? matchingAuthorInfos.find((info) => info.site === branch2)?.authorPage.url ?? matchingAuthorInfos[0]?.authorPage.url : filteredInfos.find((info) => info.site === branch2)?.authorPage.url ?? filteredInfos[0]?.authorPage.url ?? "";
|
|
214
|
-
}, "authorpageOutput");
|
|
215
|
-
const User = /* @__PURE__ */ __name(({
|
|
216
|
-
object,
|
|
217
|
-
branch: branch2,
|
|
218
|
-
isRank
|
|
219
|
-
}) => {
|
|
220
|
-
const dataArray = isRank ? object.usersByRank : object.searchUsers;
|
|
163
|
+
const User = /* @__PURE__ */ __name(({ object }) => {
|
|
164
|
+
const dataArray = object.authorRanking ? object.authorRanking : object.authorWikiRank ? [object.authorWikiRank] : [];
|
|
221
165
|
if (!dataArray || dataArray.length === 0) {
|
|
222
166
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("template", { children: "未找到用户。" });
|
|
223
167
|
}
|
|
@@ -228,33 +172,20 @@ function apply(ctx, config) {
|
|
|
228
172
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("template", { children: "未找到符合条件的用户。" });
|
|
229
173
|
}
|
|
230
174
|
const user = dataArray[selectedIndex];
|
|
231
|
-
const userTotalRating = user.statistics.totalRating;
|
|
232
|
-
const userPageCount = user.statistics.pageCount;
|
|
233
|
-
const userAuthorPageUrl = normalizeUrl(authorpageOutput(user.name, user.authorInfos, branch2));
|
|
234
|
-
const averageRating = userPageCount > 0 ? (userTotalRating / userPageCount).toFixed(2) : "0.00";
|
|
235
175
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("template", { children: [
|
|
236
176
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("quote", { id: argv.session.event.message.id }),
|
|
237
177
|
user.name,
|
|
238
178
|
" (#",
|
|
239
|
-
user.
|
|
179
|
+
user.rank,
|
|
240
180
|
")",
|
|
241
181
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}),
|
|
242
182
|
"总分:",
|
|
243
|
-
|
|
244
|
-
" 总页面数:",
|
|
245
|
-
userPageCount,
|
|
246
|
-
" 平均分:",
|
|
247
|
-
averageRating,
|
|
248
|
-
userAuthorPageUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("template", { children: [
|
|
249
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}),
|
|
250
|
-
"作者页:",
|
|
251
|
-
userAuthorPageUrl
|
|
252
|
-
] })
|
|
183
|
+
user.value
|
|
253
184
|
] });
|
|
254
185
|
}, "User");
|
|
255
186
|
try {
|
|
256
|
-
const result = await cromApiRequest(authorName,
|
|
257
|
-
const response = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(User, { object: result
|
|
187
|
+
const result = await cromApiRequest(authorName, branch, 0, queryString);
|
|
188
|
+
const response = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(User, { object: result });
|
|
258
189
|
const sentMessages = await argv.session.send(response);
|
|
259
190
|
scheduleChecks(0, argv.session, sentMessages[0]);
|
|
260
191
|
return;
|
|
@@ -265,82 +196,42 @@ function apply(ctx, config) {
|
|
|
265
196
|
] });
|
|
266
197
|
}
|
|
267
198
|
});
|
|
268
|
-
|
|
269
|
-
const branchUrl = await getBranchUrl(branch, argv.args.at(-1), argv.session.event);
|
|
199
|
+
cmd.subcommand("search <标题:string> [分部名称:string]", "查询文章信息。\n默认搜索后室中文站。").alias("搜索").alias("搜").alias("sr").action(async (argv, title, branch) => {
|
|
270
200
|
const titleName = branch && !Object.keys(branchInfo).includes(branch) || !title ? Object.keys(branchInfo).includes(argv.args.at(-1)) ? argv.args.slice(0, -1).join(" ") : argv.args.join(" ") : title;
|
|
271
|
-
const Author = /* @__PURE__ */ __name(({
|
|
272
|
-
const prefix = isTranslation ? "译者:" : "作者:";
|
|
273
|
-
if (!article.attributions) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("template", { children: [
|
|
274
|
-
prefix,
|
|
275
|
-
" 未知"
|
|
276
|
-
] });
|
|
277
|
-
const authors = article.attributions.map((attr) => attr.user.name).join("、");
|
|
278
|
-
if (!isTranslation) {
|
|
279
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("template", { children: [
|
|
280
|
-
prefix,
|
|
281
|
-
authors
|
|
282
|
-
] });
|
|
283
|
-
}
|
|
284
|
-
if (!article.translationOf || !article.translationOf.attributions) {
|
|
285
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("template", { children: [
|
|
286
|
-
prefix,
|
|
287
|
-
authors,
|
|
288
|
-
" 作者:未知"
|
|
289
|
-
] });
|
|
290
|
-
}
|
|
291
|
-
const originalAuthors = article.translationOf.attributions.map((attr) => attr.user.name).join("、");
|
|
201
|
+
const Author = /* @__PURE__ */ __name(({ authorName }) => {
|
|
292
202
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("template", { children: [
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
" 作者:",
|
|
296
|
-
originalAuthors
|
|
203
|
+
"作者:",
|
|
204
|
+
authorName || "未知"
|
|
297
205
|
] });
|
|
298
206
|
}, "Author");
|
|
299
207
|
const TitleProceed = /* @__PURE__ */ __name(({ titleData }) => {
|
|
300
|
-
|
|
208
|
+
const articles = titleData?.articles?.nodes;
|
|
209
|
+
if (!articles || articles.length === 0) {
|
|
301
210
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("template", { children: "未找到文章。" });
|
|
302
211
|
}
|
|
303
|
-
const selectedIndex =
|
|
304
|
-
const isBannedTitle = config.bannedTitles.includes(article2.
|
|
305
|
-
const isBannedUser = config.bannedUsers.
|
|
306
|
-
|
|
307
|
-
);
|
|
308
|
-
const isBannedTag = config.bannedTags.some(
|
|
309
|
-
(tag) => article2.wikidotInfo.tags.includes(tag)
|
|
310
|
-
);
|
|
311
|
-
return !(isBannedTitle || isBannedUser || isBannedTag);
|
|
212
|
+
const selectedIndex = articles.findIndex((article2) => {
|
|
213
|
+
const isBannedTitle = config.bannedTitles.includes(article2.title);
|
|
214
|
+
const isBannedUser = config.bannedUsers.includes(article2.author);
|
|
215
|
+
return !(isBannedTitle || isBannedUser);
|
|
312
216
|
});
|
|
313
217
|
if (selectedIndex === -1) {
|
|
314
218
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("template", { children: "未找到符合条件的文章。" });
|
|
315
219
|
}
|
|
316
|
-
const article =
|
|
317
|
-
const { rating, voteCount } = article.wikidotInfo;
|
|
318
|
-
const positiveVotes = Math.round((voteCount + rating) / 2);
|
|
319
|
-
const negativeVotes = Math.round((voteCount - rating) / 2);
|
|
320
|
-
const alternateTitle = article.alternateTitles && article.alternateTitles.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
321
|
-
" - ",
|
|
322
|
-
article.alternateTitles[selectedIndex].title
|
|
323
|
-
] }) : null;
|
|
220
|
+
const article = articles[selectedIndex];
|
|
324
221
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("template", { children: [
|
|
325
222
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("quote", { id: argv.session.event.message.id }),
|
|
326
|
-
article.
|
|
327
|
-
alternateTitle,
|
|
223
|
+
article.title,
|
|
328
224
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}),
|
|
329
225
|
"评分:",
|
|
330
|
-
rating,
|
|
331
|
-
" (+",
|
|
332
|
-
positiveVotes,
|
|
333
|
-
", -",
|
|
334
|
-
negativeVotes,
|
|
335
|
-
")",
|
|
226
|
+
article.rating,
|
|
336
227
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}),
|
|
337
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Author, {
|
|
228
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Author, { authorName: article.author }),
|
|
338
229
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}),
|
|
339
230
|
normalizeUrl(article.url)
|
|
340
231
|
] });
|
|
341
232
|
}, "TitleProceed");
|
|
342
233
|
try {
|
|
343
|
-
const result = await cromApiRequest(titleName,
|
|
234
|
+
const result = await cromApiRequest(titleName, branch, 0, queries.titleQuery);
|
|
344
235
|
const response = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleProceed, { titleData: result });
|
|
345
236
|
const sentMessages = await argv.session.send(response);
|
|
346
237
|
scheduleChecks(0, argv.session, sentMessages[0]);
|
package/lib/lib.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TitleQueryResponse, UserQueryResponse, UserRankQueryResponse } from "./types";
|
|
2
2
|
export declare const branchInfo: Record<string, {
|
|
3
|
-
|
|
3
|
+
wiki: string;
|
|
4
4
|
}>;
|
|
5
|
-
export declare function cromApiRequest(
|
|
6
|
-
export declare function getBranchUrl(branch: string): string;
|
|
5
|
+
export declare function cromApiRequest(param: string, name: string, endpointIndex: number, queryString: string): Promise<TitleQueryResponse | UserQueryResponse | UserRankQueryResponse>;
|
package/lib/types.d.ts
CHANGED
|
@@ -1,59 +1,29 @@
|
|
|
1
|
-
export interface
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export interface Article {
|
|
2
|
+
title: string;
|
|
3
|
+
url: string;
|
|
4
|
+
author: string;
|
|
5
|
+
rating: number;
|
|
6
|
+
}
|
|
7
|
+
export interface PageInfo {
|
|
8
|
+
total: number;
|
|
9
|
+
page: number;
|
|
10
|
+
pageSize: number;
|
|
11
|
+
hasNextPage: boolean;
|
|
5
12
|
}
|
|
6
|
-
export interface
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
url: string;
|
|
11
|
-
} | null;
|
|
12
|
-
url: string;
|
|
13
|
+
export interface TitleQueryResponse {
|
|
14
|
+
articles: {
|
|
15
|
+
nodes: Article[];
|
|
16
|
+
pageInfo: PageInfo;
|
|
13
17
|
};
|
|
14
18
|
}
|
|
15
|
-
export interface
|
|
19
|
+
export interface AuthorRank {
|
|
16
20
|
rank: number;
|
|
17
|
-
totalRating: number;
|
|
18
|
-
pageCount: number;
|
|
19
|
-
}
|
|
20
|
-
export interface User {
|
|
21
21
|
name: string;
|
|
22
|
-
|
|
23
|
-
authorInfos: AuthorInfo[];
|
|
24
|
-
statistics: Statistics;
|
|
25
|
-
}
|
|
26
|
-
export interface UserQuery {
|
|
27
|
-
searchUsers: User[];
|
|
28
|
-
}
|
|
29
|
-
export interface UserRankQuery {
|
|
30
|
-
usersByRank: User[];
|
|
22
|
+
value: number;
|
|
31
23
|
}
|
|
32
|
-
export interface
|
|
33
|
-
|
|
34
|
-
name: string;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
interface TitleWikidotInfo {
|
|
38
|
-
title: string;
|
|
39
|
-
rating: number;
|
|
40
|
-
voteCount: number;
|
|
41
|
-
createdAt: Date;
|
|
42
|
-
tags: string[];
|
|
43
|
-
}
|
|
44
|
-
export interface Title {
|
|
45
|
-
url: string;
|
|
46
|
-
wikidotInfo: TitleWikidotInfo;
|
|
47
|
-
alternateTitles: {
|
|
48
|
-
title: string;
|
|
49
|
-
}[];
|
|
50
|
-
translationOf: {
|
|
51
|
-
url: string;
|
|
52
|
-
attributions: Attribution[];
|
|
53
|
-
} | null;
|
|
54
|
-
attributions: Attribution[];
|
|
24
|
+
export interface UserQueryResponse {
|
|
25
|
+
authorWikiRank: AuthorRank;
|
|
55
26
|
}
|
|
56
|
-
export interface
|
|
57
|
-
|
|
27
|
+
export interface UserRankQueryResponse {
|
|
28
|
+
authorRanking: AuthorRank[];
|
|
58
29
|
}
|
|
59
|
-
export {};
|