@notidotbot/noti-api-client 1.9.39 → 1.9.40

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.
@@ -1,357 +1,45 @@
1
- import { GuildClipForwardCreateSchema, GuildClipForwardZod } from '../other/prisma';
1
+ import { GuildClipForward, GuildClipForwardCreateSchema, GuildClipForwardZod } from '../other/prisma';
2
2
  import { CancelOutWebResponses, DeepPartial } from '../types';
3
3
  import { WebDataManager } from '../core/manager';
4
+ /** The platforms clip forwarding supports. Caps, addons and rows are all counted per platform. */
5
+ export type ClipForwardPlatform = 'kick' | 'twitch';
6
+ /** One platform's allowance: tier default + purchased addon, and how much of it is used. */
7
+ export type ClipForwardCap = {
8
+ currentTotal: number;
9
+ maxLimit: number;
10
+ };
11
+ export type GuildClipForwardsData = {
12
+ forwards: GuildClipForward[];
13
+ /**
14
+ * PER PLATFORM, because the allowance is. `defaultKickClips` and `defaultTwitchClips` are separate
15
+ * tier numbers with separate addons (`additionalKickClips` / `additionalTwitchClips`), so a single
16
+ * pair would be wrong for whichever platform you were rendering.
17
+ *
18
+ * The server computes this with the same helper the create route enforces with, so a UI that
19
+ * believes there is room will not be refused - render the Add control off `currentTotal < maxLimit`
20
+ * rather than counting `forwards` yourself.
21
+ */
22
+ limits: Record<ClipForwardPlatform, ClipForwardCap>;
23
+ /** Which tier the allowance came from, so an upsell can name it. */
24
+ premium: {
25
+ tierId: string;
26
+ tierName: string;
27
+ };
28
+ };
4
29
  export declare class APIGuildClipForward {
5
30
  private web;
6
31
  constructor(web: WebDataManager);
7
- getGuildClipForwards({ auth, guildId }: GuildClipForwardFunctionsInput['getGuildClipForwards']): Promise<import("../types").WebResponse<({
8
- customMessages: ({
9
- clipForward: {
10
- dbId: string;
11
- guildId: string;
12
- platform: import("@prisma/client").$Enums.PlatformEnum;
13
- channelId: string | null;
14
- streamerUserName: string;
15
- usePerStreamerEmbeds: boolean | null;
16
- showNotifyButton: boolean | null;
17
- pingRoleId: string | null;
18
- clipForwardId: string;
19
- minViews: number | null;
20
- minDuration: number | null;
21
- maxPerCycle: number | null;
22
- allowMature: boolean | null;
23
- includeOffline: boolean | null;
24
- whitelistClippers: string[];
25
- blacklistClippers: string[];
26
- whitelistCategories: string[];
27
- blacklistCategories: string[];
28
- lastClipAt: Date | null;
29
- lastClipId: string | null;
30
- } | null;
31
- webhook: ({
32
- cfCustomMessage: ({
33
- clipForward: {
34
- dbId: string;
35
- guildId: string;
36
- platform: import("@prisma/client").$Enums.PlatformEnum;
37
- channelId: string | null;
38
- streamerUserName: string;
39
- usePerStreamerEmbeds: boolean | null;
40
- showNotifyButton: boolean | null;
41
- pingRoleId: string | null;
42
- clipForwardId: string;
43
- minViews: number | null;
44
- minDuration: number | null;
45
- maxPerCycle: number | null;
46
- allowMature: boolean | null;
47
- includeOffline: boolean | null;
48
- whitelistClippers: string[];
49
- blacklistClippers: string[];
50
- whitelistCategories: string[];
51
- blacklistCategories: string[];
52
- lastClipAt: Date | null;
53
- lastClipId: string | null;
54
- } | null;
55
- embed: ({
56
- fields: ({
57
- cfMessageEmbed: {
58
- dbId: string;
59
- title: string | null;
60
- description: string;
61
- url: string | null;
62
- color: string | null;
63
- footer: string | null;
64
- footerIcon: string | null;
65
- image: string | null;
66
- thumbnail: string | null;
67
- author: string | null;
68
- authorIcon: string | null;
69
- cfCustomMessageId: string;
70
- } | null;
71
- } & {
72
- name: string;
73
- dbId: string;
74
- value: string | null;
75
- inline: boolean | null;
76
- cfMessageEmbedId: string;
77
- })[];
78
- } & {
79
- dbId: string;
80
- title: string | null;
81
- description: string;
82
- url: string | null;
83
- color: string | null;
84
- footer: string | null;
85
- footerIcon: string | null;
86
- image: string | null;
87
- thumbnail: string | null;
88
- author: string | null;
89
- authorIcon: string | null;
90
- cfCustomMessageId: string;
91
- }) | null;
92
- buttons: {
93
- dbId: string;
94
- title: string;
95
- url: string | null;
96
- emojiUnicodeOrId: string | null;
97
- cfCustomMessageId: string;
98
- }[];
99
- } & {
100
- dbId: string;
101
- type: import("@prisma/client").$Enums.StreamerMessageTypeEnum;
102
- content: string | null;
103
- showInviteButton: boolean | null;
104
- showWatchButton: boolean | null;
105
- clipForwardId: string;
106
- }) | null;
107
- } & {
108
- dbId: string;
109
- enabled: boolean | null;
110
- username: string | null;
111
- avatarUrl: string | null;
112
- cfCustomMessageId: string;
113
- }) | null;
114
- embed: ({
115
- fields: ({
116
- cfMessageEmbed: ({
117
- cfCustomMessage: ({
118
- clipForward: {
119
- dbId: string;
120
- guildId: string;
121
- platform: import("@prisma/client").$Enums.PlatformEnum;
122
- channelId: string | null;
123
- streamerUserName: string;
124
- usePerStreamerEmbeds: boolean | null;
125
- showNotifyButton: boolean | null;
126
- pingRoleId: string | null;
127
- clipForwardId: string;
128
- minViews: number | null;
129
- minDuration: number | null;
130
- maxPerCycle: number | null;
131
- allowMature: boolean | null;
132
- includeOffline: boolean | null;
133
- whitelistClippers: string[];
134
- blacklistClippers: string[];
135
- whitelistCategories: string[];
136
- blacklistCategories: string[];
137
- lastClipAt: Date | null;
138
- lastClipId: string | null;
139
- } | null;
140
- webhook: {
141
- dbId: string;
142
- enabled: boolean | null;
143
- username: string | null;
144
- avatarUrl: string | null;
145
- cfCustomMessageId: string;
146
- } | null;
147
- buttons: {
148
- dbId: string;
149
- title: string;
150
- url: string | null;
151
- emojiUnicodeOrId: string | null;
152
- cfCustomMessageId: string;
153
- }[];
154
- } & {
155
- dbId: string;
156
- type: import("@prisma/client").$Enums.StreamerMessageTypeEnum;
157
- content: string | null;
158
- showInviteButton: boolean | null;
159
- showWatchButton: boolean | null;
160
- clipForwardId: string;
161
- }) | null;
162
- } & {
163
- dbId: string;
164
- title: string | null;
165
- description: string;
166
- url: string | null;
167
- color: string | null;
168
- footer: string | null;
169
- footerIcon: string | null;
170
- image: string | null;
171
- thumbnail: string | null;
172
- author: string | null;
173
- authorIcon: string | null;
174
- cfCustomMessageId: string;
175
- }) | null;
176
- } & {
177
- name: string;
178
- dbId: string;
179
- value: string | null;
180
- inline: boolean | null;
181
- cfMessageEmbedId: string;
182
- })[];
183
- cfCustomMessage: ({
184
- clipForward: {
185
- dbId: string;
186
- guildId: string;
187
- platform: import("@prisma/client").$Enums.PlatformEnum;
188
- channelId: string | null;
189
- streamerUserName: string;
190
- usePerStreamerEmbeds: boolean | null;
191
- showNotifyButton: boolean | null;
192
- pingRoleId: string | null;
193
- clipForwardId: string;
194
- minViews: number | null;
195
- minDuration: number | null;
196
- maxPerCycle: number | null;
197
- allowMature: boolean | null;
198
- includeOffline: boolean | null;
199
- whitelistClippers: string[];
200
- blacklistClippers: string[];
201
- whitelistCategories: string[];
202
- blacklistCategories: string[];
203
- lastClipAt: Date | null;
204
- lastClipId: string | null;
205
- } | null;
206
- webhook: {
207
- dbId: string;
208
- enabled: boolean | null;
209
- username: string | null;
210
- avatarUrl: string | null;
211
- cfCustomMessageId: string;
212
- } | null;
213
- buttons: {
214
- dbId: string;
215
- title: string;
216
- url: string | null;
217
- emojiUnicodeOrId: string | null;
218
- cfCustomMessageId: string;
219
- }[];
220
- } & {
221
- dbId: string;
222
- type: import("@prisma/client").$Enums.StreamerMessageTypeEnum;
223
- content: string | null;
224
- showInviteButton: boolean | null;
225
- showWatchButton: boolean | null;
226
- clipForwardId: string;
227
- }) | null;
228
- } & {
229
- dbId: string;
230
- title: string | null;
231
- description: string;
232
- url: string | null;
233
- color: string | null;
234
- footer: string | null;
235
- footerIcon: string | null;
236
- image: string | null;
237
- thumbnail: string | null;
238
- author: string | null;
239
- authorIcon: string | null;
240
- cfCustomMessageId: string;
241
- }) | null;
242
- buttons: ({
243
- cfCustomMessage: ({
244
- clipForward: {
245
- dbId: string;
246
- guildId: string;
247
- platform: import("@prisma/client").$Enums.PlatformEnum;
248
- channelId: string | null;
249
- streamerUserName: string;
250
- usePerStreamerEmbeds: boolean | null;
251
- showNotifyButton: boolean | null;
252
- pingRoleId: string | null;
253
- clipForwardId: string;
254
- minViews: number | null;
255
- minDuration: number | null;
256
- maxPerCycle: number | null;
257
- allowMature: boolean | null;
258
- includeOffline: boolean | null;
259
- whitelistClippers: string[];
260
- blacklistClippers: string[];
261
- whitelistCategories: string[];
262
- blacklistCategories: string[];
263
- lastClipAt: Date | null;
264
- lastClipId: string | null;
265
- } | null;
266
- webhook: {
267
- dbId: string;
268
- enabled: boolean | null;
269
- username: string | null;
270
- avatarUrl: string | null;
271
- cfCustomMessageId: string;
272
- } | null;
273
- embed: ({
274
- fields: ({
275
- cfMessageEmbed: {
276
- dbId: string;
277
- title: string | null;
278
- description: string;
279
- url: string | null;
280
- color: string | null;
281
- footer: string | null;
282
- footerIcon: string | null;
283
- image: string | null;
284
- thumbnail: string | null;
285
- author: string | null;
286
- authorIcon: string | null;
287
- cfCustomMessageId: string;
288
- } | null;
289
- } & {
290
- name: string;
291
- dbId: string;
292
- value: string | null;
293
- inline: boolean | null;
294
- cfMessageEmbedId: string;
295
- })[];
296
- } & {
297
- dbId: string;
298
- title: string | null;
299
- description: string;
300
- url: string | null;
301
- color: string | null;
302
- footer: string | null;
303
- footerIcon: string | null;
304
- image: string | null;
305
- thumbnail: string | null;
306
- author: string | null;
307
- authorIcon: string | null;
308
- cfCustomMessageId: string;
309
- }) | null;
310
- } & {
311
- dbId: string;
312
- type: import("@prisma/client").$Enums.StreamerMessageTypeEnum;
313
- content: string | null;
314
- showInviteButton: boolean | null;
315
- showWatchButton: boolean | null;
316
- clipForwardId: string;
317
- }) | null;
318
- } & {
319
- dbId: string;
320
- title: string;
321
- url: string | null;
322
- emojiUnicodeOrId: string | null;
323
- cfCustomMessageId: string;
324
- })[];
325
- } & {
326
- dbId: string;
327
- type: import("@prisma/client").$Enums.StreamerMessageTypeEnum;
328
- content: string | null;
329
- showInviteButton: boolean | null;
330
- showWatchButton: boolean | null;
331
- clipForwardId: string;
332
- })[];
333
- } & {
334
- dbId: string;
335
- guildId: string;
336
- platform: import("@prisma/client").$Enums.PlatformEnum;
337
- channelId: string | null;
338
- streamerUserName: string;
339
- usePerStreamerEmbeds: boolean | null;
340
- showNotifyButton: boolean | null;
341
- pingRoleId: string | null;
342
- clipForwardId: string;
343
- minViews: number | null;
344
- minDuration: number | null;
345
- maxPerCycle: number | null;
346
- allowMature: boolean | null;
347
- includeOffline: boolean | null;
348
- whitelistClippers: string[];
349
- blacklistClippers: string[];
350
- whitelistCategories: string[];
351
- blacklistCategories: string[];
352
- lastClipAt: Date | null;
353
- lastClipId: string | null;
354
- })[]>>;
32
+ /**
33
+ * Every clip-forward rule for this guild, with the per-platform allowance.
34
+ *
35
+ * **BREAKING in 1.9.40**: this returned `GuildClipForward[]` directly. The rows moved to
36
+ * `data.forwards` so the allowance could travel with them - `WebResponse` is exactly
37
+ * `{ status, data }`, so there is no room for a sibling field and an array has nowhere to put one.
38
+ *
39
+ * The caps were always enforced on create; they were simply never reported, which made a capped
40
+ * feature indistinguishable from an uncapped one until the create failed.
41
+ */
42
+ getGuildClipForwards({ auth, guildId }: GuildClipForwardFunctionsInput['getGuildClipForwards']): Promise<import("../types").WebResponse<GuildClipForwardsData>>;
355
43
  getGuildClipForward({ auth, guildId, clipForwardId }: GuildClipForwardFunctionsInput['getGuildClipForward']): Promise<import("../types").WebResponse<{
356
44
  customMessages: ({
357
45
  clipForward: {
@@ -8,6 +8,16 @@ class APIGuildClipForward {
8
8
  this.web = web;
9
9
  }
10
10
  // Methods.
11
+ /**
12
+ * Every clip-forward rule for this guild, with the per-platform allowance.
13
+ *
14
+ * **BREAKING in 1.9.40**: this returned `GuildClipForward[]` directly. The rows moved to
15
+ * `data.forwards` so the allowance could travel with them - `WebResponse` is exactly
16
+ * `{ status, data }`, so there is no room for a sibling field and an array has nowhere to put one.
17
+ *
18
+ * The caps were always enforced on create; they were simply never reported, which made a capped
19
+ * feature indistinguishable from an uncapped one until the create failed.
20
+ */
11
21
  async getGuildClipForwards({ auth, guildId }) {
12
22
  return await this.web.request({
13
23
  method: 'GET', auth,
@@ -10,6 +10,15 @@ import { WebDataManager } from '../core/manager';
10
10
  export type StatChannelPlatform = 'kick' | 'twitch' | 'youtube' | 'tiktok' | 'rumble' | 'whatnot' | 'twitter';
11
11
  /** Only Kick has a follower counter. Every other model has `isLive` alone. */
12
12
  export type StatChannelKind = 'isLive' | 'followers';
13
+ /**
14
+ * What `createStatChannels` accepts, which is NOT `StatChannelKind`.
15
+ *
16
+ * `liveUpdates` is the same counter `StatChannelKind` calls `isLive`. The create body has said
17
+ * `liveUpdates` since counters were made from `POST /panel`, and the rest of the stat-channel surface
18
+ * says `isLive`; the server keeps both rather than breaking existing callers, and its RESPONSE always
19
+ * speaks `StatChannelKind`. So you send `liveUpdates` and read `isLive` back, deliberately.
20
+ */
21
+ export type StatChannelCreateType = 'liveUpdates' | 'followers';
13
22
  /**
14
23
  * Why a counter is or is not updating.
15
24
  *
@@ -50,6 +59,17 @@ export type StatChannelsData = {
50
59
  * `cluster-unreachable` and none of them says anything about the channels themselves.
51
60
  */
52
61
  inspected: boolean;
62
+ /**
63
+ * Platforms a counter can be CREATED for, which is narrower than the platforms that can hold one.
64
+ *
65
+ * Creating a counter needs the bot to resolve the creator's live state first, and only some
66
+ * platforms have a check for that - so YouTube, X and Whatnot can carry a counter that already
67
+ * exists while refusing a new one. Read this instead of hard-coding the list: it is served from the
68
+ * single constant the server also gates the create route on, and it widened once already.
69
+ *
70
+ * Absent on an API older than 1.9.40, so treat `undefined` as "Kick only".
71
+ */
72
+ canCreate?: StatChannelPlatform[];
53
73
  channels: StatChannel[];
54
74
  };
55
75
  export type UpdatedStatChannel = {
@@ -71,6 +91,17 @@ export type DeletedStatChannels = {
71
91
  /** Always false. Unlinking stops the counter; the Discord channel stays theirs to remove. */
72
92
  channelDeleted: boolean;
73
93
  };
94
+ export type CreatedStatChannels = {
95
+ platform: StatChannelPlatform;
96
+ username: string;
97
+ /**
98
+ * One entry per counter created, in `updateStatChannel`'s shape.
99
+ *
100
+ * Read back from the database after creation rather than echoing the request, so the ids are the
101
+ * ones that actually landed. A caller does not need to re-`getStatChannels` to learn them.
102
+ */
103
+ channels: UpdatedStatChannel[];
104
+ };
74
105
  export type RetriedStatChannel = {
75
106
  platform: StatChannelPlatform;
76
107
  username: string;
@@ -87,6 +118,22 @@ export declare class APIGuildStatChannels {
87
118
  constructor(web: WebDataManager);
88
119
  /** Every counter this guild has configured, with why each is or is not updating. */
89
120
  getStatChannels({ auth, guildId }: GuildStatChannelsFunctionsInput['getStatChannels']): Promise<WebResponse<StatChannelsData>>;
121
+ /**
122
+ * Create the counter channels themselves, and link them.
123
+ *
124
+ * Use this rather than making a voice channel and pointing `updateStatChannel` at it - the bot
125
+ * names the new channel from the server's own `statChannelLive` / `statFollowers` template and sets
126
+ * its permissions.
127
+ *
128
+ * **Check `canCreate` from `getStatChannels` first.** Creating needs the bot to read the creator's
129
+ * live state, and the platforms that support that are narrower than the ones that can hold a
130
+ * counter - a platform outside that list is a 400, not a silent no-op.
131
+ *
132
+ * `followers` is Kick-only; asking for it anywhere else is a 400 naming the platform. 404 when the
133
+ * creator is not tracked in this guild, 400 when the live or follower read failed, in which case
134
+ * nothing was created.
135
+ */
136
+ createStatChannels({ auth, guildId, platform, username, types }: GuildStatChannelsFunctionsInput['createStatChannels']): Promise<WebResponse<CreatedStatChannels>>;
90
137
  /**
91
138
  * Point a counter at a channel, creating it if the creator had none.
92
139
  *
@@ -114,6 +161,13 @@ export type GuildStatChannelsFunctionsInput = {
114
161
  auth: string;
115
162
  guildId: string;
116
163
  };
164
+ 'createStatChannels': {
165
+ auth: string;
166
+ guildId: string;
167
+ platform: StatChannelPlatform;
168
+ username: string;
169
+ types: StatChannelCreateType[];
170
+ };
117
171
  'updateStatChannel': {
118
172
  auth: string;
119
173
  guildId: string;
@@ -140,6 +194,8 @@ export type GuildStatChannelsFunctionsInput = {
140
194
  export type GuildStatChannelsReturnTypes = {
141
195
  'getStatChannelsRaw': Awaited<ReturnType<APIGuildStatChannels['getStatChannels']>>;
142
196
  'getStatChannelsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildStatChannels['getStatChannels']>>>;
197
+ 'createStatChannelsRaw': Awaited<ReturnType<APIGuildStatChannels['createStatChannels']>>;
198
+ 'createStatChannelsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildStatChannels['createStatChannels']>>>;
143
199
  'updateStatChannelRaw': Awaited<ReturnType<APIGuildStatChannels['updateStatChannel']>>;
144
200
  'updateStatChannelSuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildStatChannels['updateStatChannel']>>>;
145
201
  'deleteStatChannelsRaw': Awaited<ReturnType<APIGuildStatChannels['deleteStatChannels']>>;
@@ -15,6 +15,28 @@ class APIGuildStatChannels {
15
15
  endpoint: this.web.qp(`/data/guild/${guildId}/stat-channels`),
16
16
  });
17
17
  }
18
+ /**
19
+ * Create the counter channels themselves, and link them.
20
+ *
21
+ * Use this rather than making a voice channel and pointing `updateStatChannel` at it - the bot
22
+ * names the new channel from the server's own `statChannelLive` / `statFollowers` template and sets
23
+ * its permissions.
24
+ *
25
+ * **Check `canCreate` from `getStatChannels` first.** Creating needs the bot to read the creator's
26
+ * live state, and the platforms that support that are narrower than the ones that can hold a
27
+ * counter - a platform outside that list is a 400, not a silent no-op.
28
+ *
29
+ * `followers` is Kick-only; asking for it anywhere else is a 400 naming the platform. 404 when the
30
+ * creator is not tracked in this guild, 400 when the live or follower read failed, in which case
31
+ * nothing was created.
32
+ */
33
+ async createStatChannels({ auth, guildId, platform, username, types }) {
34
+ return await this.web.request({
35
+ method: 'POST', auth,
36
+ endpoint: this.web.qp(`/data/guild/${guildId}/stat-channels/${platform}/${username}`),
37
+ body: { types },
38
+ });
39
+ }
18
40
  /**
19
41
  * Point a counter at a channel, creating it if the creator had none.
20
42
  *