@notidotbot/noti-api-client 1.9.86 → 1.9.88

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.
@@ -0,0 +1,336 @@
1
+ import { CancelOutWebResponses } from '../types';
2
+ import { WebDataManager } from '../core/manager';
3
+ import type { FeedbackAudience, FeedbackPost, FeedbackStatus, FeedbackThread } from './feedback';
4
+ /**
5
+ * The feedback board - the staff side. Post moderation, tags and bans are staff + developers; boards (and
6
+ * rewriting a post's `title` / `body`) are developers only (403 otherwise). None is behind the `feedback`
7
+ * flag, so boards can be set up before launch. Every change is written to the audit log (`getFeedbackAudits`).
8
+ */
9
+ export declare class APIAdminFeedback {
10
+ private web;
11
+ constructor(web: WebDataManager);
12
+ /** Every post incl. hidden / private. `deleted: true` lists deleted ones instead; `merged: true` includes merged ones. */
13
+ getAdminFeedbackPosts({ auth, ...query }: AdminFeedbackFunctionsInput['getAdminFeedbackPosts']): Promise<import("../types").WebResponse<{
14
+ posts: AdminFeedbackPost[];
15
+ total: number;
16
+ offset: number;
17
+ limit: number;
18
+ }>>;
19
+ /** One post with who wants it: votes by plan, voters' server reach, share from accounts under 30 days. */
20
+ getAdminFeedbackPost({ auth, number }: AdminFeedbackFunctionsInput['getAdminFeedbackPost']): Promise<import("../types").WebResponse<{
21
+ post: AdminFeedbackPost;
22
+ breakdown: FeedbackVoteBreakdown;
23
+ }>>;
24
+ /**
25
+ * Moderate a post; send only what changes. `status: 'done'` sets `shippedAt`. `audienceOverride` may only
26
+ * narrow the board (`audience_widens_board`). `featured` puts it on the main page (until `featuredUntil`).
27
+ * `deleted` soft-deletes / restores. `title` / `body` are developers only.
28
+ */
29
+ updateAdminFeedbackPost({ auth, number, post }: AdminFeedbackFunctionsInput['updateAdminFeedbackPost']): Promise<import("../types").WebResponse<{
30
+ post: AdminFeedbackPost | null;
31
+ }>>;
32
+ deleteAdminFeedbackPost({ auth, number }: AdminFeedbackFunctionsInput['deleteAdminFeedbackPost']): Promise<import("../types").WebResponse<{
33
+ post: AdminFeedbackPost | null;
34
+ }>>;
35
+ /**
36
+ * Merge post `number` into `intoNumber`: votes move (one per user), comments and follows move, the old
37
+ * number redirects. There is no unmerge. Refusals: `same_post`, `not_found`, `already_merged`,
38
+ * `target_merged`, `deleted`, `busy`.
39
+ */
40
+ createFeedbackMerge({ auth, number, intoNumber }: AdminFeedbackFunctionsInput['createFeedbackMerge']): Promise<import("../types").WebResponse<{
41
+ post: AdminFeedbackPost | null;
42
+ movedVotes: number;
43
+ }>>;
44
+ getAdminFeedbackBoards({ auth }: AdminFeedbackFunctionsInput['getAdminFeedbackBoards']): Promise<import("../types").WebResponse<{
45
+ boards: AdminFeedbackBoard[];
46
+ }>>;
47
+ /** Developers only. `minTierId` needs `audience: 'premium'` and a paid guild plan. */
48
+ createFeedbackBoard({ auth, board }: AdminFeedbackFunctionsInput['createFeedbackBoard']): Promise<import("../types").WebResponse<{
49
+ boardId: string;
50
+ }>>;
51
+ updateFeedbackBoard({ auth, boardId, board }: AdminFeedbackFunctionsInput['updateFeedbackBoard']): Promise<import("../types").WebResponse<{
52
+ boardId: string;
53
+ }>>;
54
+ /** Only an empty board (`board_has_posts` otherwise - archive it instead). */
55
+ deleteFeedbackBoard({ auth, boardId }: AdminFeedbackFunctionsInput['deleteFeedbackBoard']): Promise<import("../types").WebResponse<{
56
+ deleted: true;
57
+ }>>;
58
+ /** Every tag, hidden ones included. */
59
+ getAdminFeedbackTags({ auth }: AdminFeedbackFunctionsInput['getAdminFeedbackTags']): Promise<import("../types").WebResponse<{
60
+ tags: Array<{
61
+ tagId: string;
62
+ slug: string;
63
+ name: string;
64
+ color: string;
65
+ hidden: boolean;
66
+ }>;
67
+ }>>;
68
+ createFeedbackTag({ auth, tag }: AdminFeedbackFunctionsInput['createFeedbackTag']): Promise<import("../types").WebResponse<{
69
+ tagId: string;
70
+ }>>;
71
+ /** Tags are hidden, never deleted. */
72
+ updateFeedbackTag({ auth, tagId, tag }: AdminFeedbackFunctionsInput['updateFeedbackTag']): Promise<import("../types").WebResponse<{
73
+ tagId: string;
74
+ }>>;
75
+ /** Active bans (`all: true` includes expired), optionally for one `userId`. */
76
+ getFeedbackBans({ auth, ...query }: AdminFeedbackFunctionsInput['getFeedbackBans']): Promise<import("../types").WebResponse<{
77
+ bans: FeedbackBan[];
78
+ }>>;
79
+ /** Ban a user from posting, commenting (and reacting), voting, or all of it. Survives their data deletion. */
80
+ createFeedbackBan({ auth, ban }: AdminFeedbackFunctionsInput['createFeedbackBan']): Promise<import("../types").WebResponse<{
81
+ banId: string;
82
+ }>>;
83
+ deleteFeedbackBan({ auth, banId }: AdminFeedbackFunctionsInput['deleteFeedbackBan']): Promise<import("../types").WebResponse<{
84
+ deleted: true;
85
+ }>>;
86
+ /**
87
+ * Comment as staff: `internal` for a staff-only note (a reply under a note is a note too), `official` for the
88
+ * pinned answer (replaces the current one; never a note, never a reply). Returns the full thread incl. notes.
89
+ */
90
+ createAdminFeedbackComment({ auth, number, comment }: AdminFeedbackFunctionsInput['createAdminFeedbackComment']): Promise<import("../types").WebResponse<FeedbackThread>>;
91
+ /** Hide / unhide a comment, or make it (or stop it being) the official answer. */
92
+ updateAdminFeedbackComment({ auth, commentId, comment }: AdminFeedbackFunctionsInput['updateAdminFeedbackComment']): Promise<import("../types").WebResponse<FeedbackThread>>;
93
+ /** The staff action log, newest first. `target` filters, e.g. `post:42`, `board:<id>`, `user:<discordId>`. */
94
+ getFeedbackAudits({ auth, ...query }: AdminFeedbackFunctionsInput['getFeedbackAudits']): Promise<import("../types").WebResponse<{
95
+ audits: FeedbackAudit[];
96
+ offset: number;
97
+ limit: number;
98
+ }>>;
99
+ }
100
+ export type AdminFeedbackFunctionsInput = {
101
+ 'getAdminFeedbackPosts': {
102
+ auth: string;
103
+ status?: FeedbackStatus;
104
+ boardId?: string;
105
+ q?: string;
106
+ hidden?: boolean;
107
+ deleted?: boolean;
108
+ merged?: boolean;
109
+ sort?: 'new' | 'top';
110
+ offset?: number;
111
+ limit?: number;
112
+ };
113
+ 'getAdminFeedbackPost': {
114
+ auth: string;
115
+ number: number;
116
+ };
117
+ 'updateAdminFeedbackPost': {
118
+ auth: string;
119
+ number: number;
120
+ post: AdminFeedbackPostUpdate;
121
+ };
122
+ 'deleteAdminFeedbackPost': {
123
+ auth: string;
124
+ number: number;
125
+ };
126
+ 'createFeedbackMerge': {
127
+ auth: string;
128
+ number: number;
129
+ intoNumber: number;
130
+ };
131
+ 'getAdminFeedbackBoards': {
132
+ auth: string;
133
+ };
134
+ 'createFeedbackBoard': {
135
+ auth: string;
136
+ board: FeedbackBoardInput;
137
+ };
138
+ 'updateFeedbackBoard': {
139
+ auth: string;
140
+ boardId: string;
141
+ board: Partial<FeedbackBoardInput>;
142
+ };
143
+ 'deleteFeedbackBoard': {
144
+ auth: string;
145
+ boardId: string;
146
+ };
147
+ 'getAdminFeedbackTags': {
148
+ auth: string;
149
+ };
150
+ 'createFeedbackTag': {
151
+ auth: string;
152
+ tag: {
153
+ slug: string;
154
+ name: string;
155
+ color: string;
156
+ hidden?: boolean;
157
+ };
158
+ };
159
+ 'updateFeedbackTag': {
160
+ auth: string;
161
+ tagId: string;
162
+ tag: {
163
+ slug?: string;
164
+ name?: string;
165
+ color?: string;
166
+ hidden?: boolean;
167
+ };
168
+ };
169
+ 'getFeedbackBans': {
170
+ auth: string;
171
+ userId?: string;
172
+ all?: boolean;
173
+ };
174
+ 'createFeedbackBan': {
175
+ auth: string;
176
+ ban: {
177
+ userId: string;
178
+ scope: FeedbackBanScope;
179
+ reason: string;
180
+ until?: string | null;
181
+ };
182
+ };
183
+ 'deleteFeedbackBan': {
184
+ auth: string;
185
+ banId: string;
186
+ };
187
+ 'getFeedbackAudits': {
188
+ auth: string;
189
+ target?: string;
190
+ offset?: number;
191
+ limit?: number;
192
+ };
193
+ 'createAdminFeedbackComment': {
194
+ auth: string;
195
+ number: number;
196
+ comment: {
197
+ body: string;
198
+ parentId?: string;
199
+ uploadIds?: string[];
200
+ internal?: boolean;
201
+ official?: boolean;
202
+ };
203
+ };
204
+ 'updateAdminFeedbackComment': {
205
+ auth: string;
206
+ commentId: string;
207
+ comment: {
208
+ hidden?: boolean;
209
+ official?: boolean;
210
+ };
211
+ };
212
+ };
213
+ export type AdminFeedbackGetReturnTypes = {
214
+ 'getAdminFeedbackPostsRaw': Awaited<ReturnType<APIAdminFeedback['getAdminFeedbackPosts']>>;
215
+ 'getAdminFeedbackPostsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['getAdminFeedbackPosts']>>>;
216
+ 'getAdminFeedbackPostRaw': Awaited<ReturnType<APIAdminFeedback['getAdminFeedbackPost']>>;
217
+ 'getAdminFeedbackPostSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['getAdminFeedbackPost']>>>;
218
+ 'updateAdminFeedbackPostRaw': Awaited<ReturnType<APIAdminFeedback['updateAdminFeedbackPost']>>;
219
+ 'updateAdminFeedbackPostSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['updateAdminFeedbackPost']>>>;
220
+ 'deleteAdminFeedbackPostRaw': Awaited<ReturnType<APIAdminFeedback['deleteAdminFeedbackPost']>>;
221
+ 'deleteAdminFeedbackPostSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['deleteAdminFeedbackPost']>>>;
222
+ 'createFeedbackMergeRaw': Awaited<ReturnType<APIAdminFeedback['createFeedbackMerge']>>;
223
+ 'createFeedbackMergeSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['createFeedbackMerge']>>>;
224
+ 'getAdminFeedbackBoardsRaw': Awaited<ReturnType<APIAdminFeedback['getAdminFeedbackBoards']>>;
225
+ 'getAdminFeedbackBoardsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['getAdminFeedbackBoards']>>>;
226
+ 'createFeedbackBoardRaw': Awaited<ReturnType<APIAdminFeedback['createFeedbackBoard']>>;
227
+ 'createFeedbackBoardSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['createFeedbackBoard']>>>;
228
+ 'updateFeedbackBoardRaw': Awaited<ReturnType<APIAdminFeedback['updateFeedbackBoard']>>;
229
+ 'updateFeedbackBoardSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['updateFeedbackBoard']>>>;
230
+ 'deleteFeedbackBoardRaw': Awaited<ReturnType<APIAdminFeedback['deleteFeedbackBoard']>>;
231
+ 'deleteFeedbackBoardSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['deleteFeedbackBoard']>>>;
232
+ 'getAdminFeedbackTagsRaw': Awaited<ReturnType<APIAdminFeedback['getAdminFeedbackTags']>>;
233
+ 'getAdminFeedbackTagsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['getAdminFeedbackTags']>>>;
234
+ 'createFeedbackTagRaw': Awaited<ReturnType<APIAdminFeedback['createFeedbackTag']>>;
235
+ 'createFeedbackTagSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['createFeedbackTag']>>>;
236
+ 'updateFeedbackTagRaw': Awaited<ReturnType<APIAdminFeedback['updateFeedbackTag']>>;
237
+ 'updateFeedbackTagSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['updateFeedbackTag']>>>;
238
+ 'getFeedbackBansRaw': Awaited<ReturnType<APIAdminFeedback['getFeedbackBans']>>;
239
+ 'getFeedbackBansSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['getFeedbackBans']>>>;
240
+ 'createFeedbackBanRaw': Awaited<ReturnType<APIAdminFeedback['createFeedbackBan']>>;
241
+ 'createFeedbackBanSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['createFeedbackBan']>>>;
242
+ 'deleteFeedbackBanRaw': Awaited<ReturnType<APIAdminFeedback['deleteFeedbackBan']>>;
243
+ 'deleteFeedbackBanSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['deleteFeedbackBan']>>>;
244
+ 'getFeedbackAuditsRaw': Awaited<ReturnType<APIAdminFeedback['getFeedbackAudits']>>;
245
+ 'getFeedbackAuditsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['getFeedbackAudits']>>>;
246
+ 'createAdminFeedbackCommentRaw': Awaited<ReturnType<APIAdminFeedback['createAdminFeedbackComment']>>;
247
+ 'createAdminFeedbackCommentSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['createAdminFeedbackComment']>>>;
248
+ 'updateAdminFeedbackCommentRaw': Awaited<ReturnType<APIAdminFeedback['updateAdminFeedbackComment']>>;
249
+ 'updateAdminFeedbackCommentSuccess': CancelOutWebResponses<Awaited<ReturnType<APIAdminFeedback['updateAdminFeedbackComment']>>>;
250
+ };
251
+ /** Mirrors `FeedbackBanScopeEnum`. `comment` also covers reactions. */
252
+ export declare const FEEDBACK_BAN_SCOPES: readonly ["post", "comment", "vote", "all"];
253
+ export type FeedbackBanScope = typeof FEEDBACK_BAN_SCOPES[number];
254
+ export type AdminFeedbackPost = FeedbackPost & {
255
+ /** Discord id of the author; null for imported / deleted-user posts. */
256
+ authorId: string | null;
257
+ audienceOverride: FeedbackAudience | null;
258
+ featuredAt: string | null;
259
+ featuredOrder: number | null;
260
+ featuredUntil: string | null;
261
+ deletedAt: string | null;
262
+ };
263
+ export type AdminFeedbackPostUpdate = {
264
+ status?: FeedbackStatus;
265
+ declinedReason?: string | null;
266
+ eta?: string | null;
267
+ tagIds?: string[];
268
+ boardId?: string;
269
+ audienceOverride?: FeedbackAudience | null;
270
+ pinned?: boolean;
271
+ hidden?: boolean;
272
+ hiddenReason?: string | null;
273
+ featured?: boolean;
274
+ featuredOrder?: number | null;
275
+ /** ISO, or null for no end. */
276
+ featuredUntil?: string | null;
277
+ votingLocked?: boolean;
278
+ commentsLocked?: boolean;
279
+ deleted?: boolean;
280
+ /** A changelog entry (its dbId) this shipped in; shown on the timeline once that changelog is public. `invalid_changelog` if unknown. */
281
+ changelogId?: string | null;
282
+ /** Developers only. */
283
+ title?: string;
284
+ /** Developers only. */
285
+ body?: string;
286
+ };
287
+ export type FeedbackVoteBreakdown = {
288
+ votes: number;
289
+ /** Plan name -> votes, e.g. `{ Free: 30, 'Server Premium': 4 }`. */
290
+ byTier: Record<string, number>;
291
+ /** Sum of member counts of the voters' premium servers at vote time. */
292
+ memberReach: number;
293
+ newAccounts: number;
294
+ /** 0..1 - a high share from accounts under 30 days old is worth a second look. */
295
+ newAccountShare: number;
296
+ };
297
+ export type FeedbackBoardInput = {
298
+ slug: string;
299
+ name: string;
300
+ description?: string | null;
301
+ audience?: FeedbackAudience;
302
+ /** A paid guild plan's tierId; needs audience 'premium'. Null = any paid plan. */
303
+ minTierId?: string | null;
304
+ position?: number;
305
+ hidden?: boolean;
306
+ archived?: boolean;
307
+ postingOpen?: boolean;
308
+ /** What new posts in this board default to, e.g. 'authorAndStaff' for a bug board. Must narrow `audience`. */
309
+ defaultPostAudience?: FeedbackAudience | null;
310
+ };
311
+ export type AdminFeedbackBoard = Required<Omit<FeedbackBoardInput, 'description' | 'minTierId' | 'defaultPostAudience'>> & {
312
+ boardId: string;
313
+ description: string | null;
314
+ minTierId: string | null;
315
+ defaultPostAudience: FeedbackAudience | null;
316
+ createdAt: string;
317
+ updatedAt: string;
318
+ };
319
+ export type FeedbackBan = {
320
+ banId: string;
321
+ userId: string;
322
+ scope: FeedbackBanScope;
323
+ reason: string;
324
+ until: string | null;
325
+ createdBy: string;
326
+ createdAt: string;
327
+ };
328
+ export type FeedbackAudit = {
329
+ auditId: string;
330
+ actorId: string;
331
+ action: string;
332
+ target: string;
333
+ before: unknown;
334
+ after: unknown;
335
+ createdAt: string;
336
+ };
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FEEDBACK_BAN_SCOPES = exports.APIAdminFeedback = void 0;
4
+ // Data.
5
+ /**
6
+ * The feedback board - the staff side. Post moderation, tags and bans are staff + developers; boards (and
7
+ * rewriting a post's `title` / `body`) are developers only (403 otherwise). None is behind the `feedback`
8
+ * flag, so boards can be set up before launch. Every change is written to the audit log (`getFeedbackAudits`).
9
+ */
10
+ class APIAdminFeedback {
11
+ web;
12
+ constructor(web) {
13
+ this.web = web;
14
+ }
15
+ /** Every post incl. hidden / private. `deleted: true` lists deleted ones instead; `merged: true` includes merged ones. */
16
+ async getAdminFeedbackPosts({ auth, ...query }) {
17
+ return await this.web.request({
18
+ method: 'GET', auth,
19
+ endpoint: this.web.qp('/admin/feedback/posts', query),
20
+ });
21
+ }
22
+ /** One post with who wants it: votes by plan, voters' server reach, share from accounts under 30 days. */
23
+ async getAdminFeedbackPost({ auth, number }) {
24
+ return await this.web.request({
25
+ method: 'GET', auth,
26
+ endpoint: this.web.qp('/admin/feedback/posts/' + number),
27
+ });
28
+ }
29
+ /**
30
+ * Moderate a post; send only what changes. `status: 'done'` sets `shippedAt`. `audienceOverride` may only
31
+ * narrow the board (`audience_widens_board`). `featured` puts it on the main page (until `featuredUntil`).
32
+ * `deleted` soft-deletes / restores. `title` / `body` are developers only.
33
+ */
34
+ async updateAdminFeedbackPost({ auth, number, post }) {
35
+ return await this.web.request({
36
+ method: 'PATCH', auth,
37
+ endpoint: this.web.qp('/admin/feedback/posts/' + number),
38
+ body: post,
39
+ });
40
+ }
41
+ async deleteAdminFeedbackPost({ auth, number }) {
42
+ return await this.web.request({
43
+ method: 'DELETE', auth,
44
+ endpoint: this.web.qp('/admin/feedback/posts/' + number),
45
+ });
46
+ }
47
+ /**
48
+ * Merge post `number` into `intoNumber`: votes move (one per user), comments and follows move, the old
49
+ * number redirects. There is no unmerge. Refusals: `same_post`, `not_found`, `already_merged`,
50
+ * `target_merged`, `deleted`, `busy`.
51
+ */
52
+ async createFeedbackMerge({ auth, number, intoNumber }) {
53
+ return await this.web.request({
54
+ method: 'POST', auth,
55
+ endpoint: this.web.qp('/admin/feedback/posts/' + number + '/merges'),
56
+ body: { intoNumber },
57
+ });
58
+ }
59
+ async getAdminFeedbackBoards({ auth }) {
60
+ return await this.web.request({
61
+ method: 'GET', auth,
62
+ endpoint: this.web.qp('/admin/feedback/boards'),
63
+ });
64
+ }
65
+ /** Developers only. `minTierId` needs `audience: 'premium'` and a paid guild plan. */
66
+ async createFeedbackBoard({ auth, board }) {
67
+ return await this.web.request({
68
+ method: 'POST', auth,
69
+ endpoint: this.web.qp('/admin/feedback/boards'),
70
+ body: board,
71
+ });
72
+ }
73
+ async updateFeedbackBoard({ auth, boardId, board }) {
74
+ return await this.web.request({
75
+ method: 'PATCH', auth,
76
+ endpoint: this.web.qp('/admin/feedback/boards/' + boardId),
77
+ body: board,
78
+ });
79
+ }
80
+ /** Only an empty board (`board_has_posts` otherwise - archive it instead). */
81
+ async deleteFeedbackBoard({ auth, boardId }) {
82
+ return await this.web.request({
83
+ method: 'DELETE', auth,
84
+ endpoint: this.web.qp('/admin/feedback/boards/' + boardId),
85
+ });
86
+ }
87
+ /** Every tag, hidden ones included. */
88
+ async getAdminFeedbackTags({ auth }) {
89
+ return await this.web.request({
90
+ method: 'GET', auth,
91
+ endpoint: this.web.qp('/admin/feedback/tags'),
92
+ });
93
+ }
94
+ async createFeedbackTag({ auth, tag }) {
95
+ return await this.web.request({
96
+ method: 'POST', auth,
97
+ endpoint: this.web.qp('/admin/feedback/tags'),
98
+ body: tag,
99
+ });
100
+ }
101
+ /** Tags are hidden, never deleted. */
102
+ async updateFeedbackTag({ auth, tagId, tag }) {
103
+ return await this.web.request({
104
+ method: 'PATCH', auth,
105
+ endpoint: this.web.qp('/admin/feedback/tags/' + tagId),
106
+ body: tag,
107
+ });
108
+ }
109
+ /** Active bans (`all: true` includes expired), optionally for one `userId`. */
110
+ async getFeedbackBans({ auth, ...query }) {
111
+ return await this.web.request({
112
+ method: 'GET', auth,
113
+ endpoint: this.web.qp('/admin/feedback/bans', query),
114
+ });
115
+ }
116
+ /** Ban a user from posting, commenting (and reacting), voting, or all of it. Survives their data deletion. */
117
+ async createFeedbackBan({ auth, ban }) {
118
+ return await this.web.request({
119
+ method: 'POST', auth,
120
+ endpoint: this.web.qp('/admin/feedback/bans'),
121
+ body: ban,
122
+ });
123
+ }
124
+ async deleteFeedbackBan({ auth, banId }) {
125
+ return await this.web.request({
126
+ method: 'DELETE', auth,
127
+ endpoint: this.web.qp('/admin/feedback/bans/' + banId),
128
+ });
129
+ }
130
+ /**
131
+ * Comment as staff: `internal` for a staff-only note (a reply under a note is a note too), `official` for the
132
+ * pinned answer (replaces the current one; never a note, never a reply). Returns the full thread incl. notes.
133
+ */
134
+ async createAdminFeedbackComment({ auth, number, comment }) {
135
+ return await this.web.request({
136
+ method: 'POST', auth,
137
+ endpoint: this.web.qp('/admin/feedback/posts/' + number + '/comments'),
138
+ body: comment,
139
+ });
140
+ }
141
+ /** Hide / unhide a comment, or make it (or stop it being) the official answer. */
142
+ async updateAdminFeedbackComment({ auth, commentId, comment }) {
143
+ return await this.web.request({
144
+ method: 'PATCH', auth,
145
+ endpoint: this.web.qp('/admin/feedback/comments/' + commentId),
146
+ body: comment,
147
+ });
148
+ }
149
+ /** The staff action log, newest first. `target` filters, e.g. `post:42`, `board:<id>`, `user:<discordId>`. */
150
+ async getFeedbackAudits({ auth, ...query }) {
151
+ return await this.web.request({
152
+ method: 'GET', auth,
153
+ endpoint: this.web.qp('/admin/feedback/audits', query),
154
+ });
155
+ }
156
+ }
157
+ exports.APIAdminFeedback = APIAdminFeedback;
158
+ /** Mirrors `FeedbackBanScopeEnum`. `comment` also covers reactions. */
159
+ exports.FEEDBACK_BAN_SCOPES = ['post', 'comment', 'vote', 'all'];
@@ -94,17 +94,21 @@ export type SitePollCreateInput = {
94
94
  closesAt?: Date | string | null;
95
95
  /** Default false. */
96
96
  postToDiscord?: boolean;
97
+ /** `feedbackPostNumber` links the option to a PUBLIC feedback post (`{ code: 'post_not_public', number }` otherwise). */
97
98
  options: Array<{
98
99
  label: string;
99
100
  description?: string | null;
101
+ feedbackPostNumber?: number | null;
100
102
  }>;
101
103
  };
102
104
  /** Mirrors `SitePollUpdateSchema` in Noti-v3. */
103
105
  export type SitePollUpdateInput = Partial<Omit<SitePollCreateInput, 'options'>> & {
106
+ /** Replaces the list - an option sent without `feedbackPostNumber` is unlinked. */
104
107
  options?: Array<{
105
108
  optionId?: string;
106
109
  label: string;
107
110
  description?: string | null;
111
+ feedbackPostNumber?: number | null;
108
112
  }>;
109
113
  /** Allow removing options that have votes (their votes are deleted). */
110
114
  force?: boolean;