@notidotbot/noti-api-client 1.9.61 → 1.9.63
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/classes/guildBadges.d.ts +18 -0
- package/dist/classes/guildBadges.js +16 -0
- package/dist/classes/guildDrops.d.ts +29 -0
- package/dist/classes/guildDrops.js +20 -0
- package/dist/classes/guildGiveaway.d.ts +28 -1
- package/dist/classes/guildGiveaway.js +14 -0
- package/dist/classes/publicDrops.d.ts +147 -0
- package/dist/classes/publicDrops.js +54 -0
- package/dist/classes/publicGiveaways.d.ts +152 -0
- package/dist/classes/publicGiveaways.js +80 -0
- package/dist/core/manager.d.ts +4 -0
- package/dist/core/manager.js +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +10 -1
- package/dist/other/bitfields.d.ts +8 -2
- package/dist/other/bitfields.js +6 -0
- package/dist/other/features.d.ts +1 -1
- package/dist/other/features.js +3 -0
- package/dist/other/giveawayClaims.d.ts +23 -0
- package/dist/other/giveawayClaims.js +33 -0
- package/dist/other/zod/giveaways.zod.d.ts +19 -0
- package/dist/other/zod/giveaways.zod.js +12 -0
- package/dist/other/zod/guild.zod.d.ts +2 -0
- package/dist/other/zod/guild.zod.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/prisma/generated/ts-prisma.d.ts +303 -58
- package/prisma/schema/models/giveaways.prisma +43 -0
- package/prisma/schema/models/guild.prisma +3 -0
- package/prisma/schema/schema.prisma +6 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { WebDataManager } from '../core/manager';
|
|
2
2
|
import { CancelOutWebResponses, WebResponse } from '../types';
|
|
3
|
+
import type { MissingSendData } from './guildDrops';
|
|
3
4
|
/**
|
|
4
5
|
* Badge Notifications - a server is pinged, once per badge, when a Kick or Twitch drops campaign offers
|
|
5
6
|
* a chat badge. Separate from Drops: every badge on an enabled platform, with an optional game filter,
|
|
@@ -49,6 +50,16 @@ export declare class APIGuildBadges {
|
|
|
49
50
|
* shape the API's catch-all guild routes cannot claim.
|
|
50
51
|
*/
|
|
51
52
|
sendTestBadgeNotification({ auth, guildId, platform, gameId }: GuildBadgesFunctionsInput['sendTestBadgeNotification']): Promise<WebResponse<string>>;
|
|
53
|
+
/**
|
|
54
|
+
* "Force Missing Badges": sends, now, every badge still live that this server is set up for and has not
|
|
55
|
+
* been sent, rather than at the next 5-minute check. Never re-sends one already sent.
|
|
56
|
+
*
|
|
57
|
+
* 400 when badges are not set up or the platform is switched off; 403 for the launch flag; 429 within
|
|
58
|
+
* 5 minutes of the last press for this server and platform (`error.code === 'rate_limited'`, count down
|
|
59
|
+
* from `error.retryAfterSeconds`); 503 in the first minutes after the bot starts, before its first badge
|
|
60
|
+
* check (that press does not start the cooldown). `data.message` is ready to show.
|
|
61
|
+
*/
|
|
62
|
+
sendMissingBadges({ auth, guildId, platform }: GuildBadgesFunctionsInput['sendMissingBadges']): Promise<WebResponse<MissingSendData>>;
|
|
52
63
|
/**
|
|
53
64
|
* The badge game picker's list: every game of the platform, ONE ROW PER GAME - duplicate entries for one
|
|
54
65
|
* game are merged, every id in `ids`. Any game can offer a badge later, so it is not limited to games that
|
|
@@ -188,6 +199,11 @@ export type GuildBadgesFunctionsInput = {
|
|
|
188
199
|
offset?: number;
|
|
189
200
|
configuredGameIds?: string[];
|
|
190
201
|
};
|
|
202
|
+
'sendMissingBadges': {
|
|
203
|
+
auth: string;
|
|
204
|
+
guildId: string;
|
|
205
|
+
platform: 'kick' | 'twitch';
|
|
206
|
+
};
|
|
191
207
|
};
|
|
192
208
|
export type GuildBadgesReturnTypes = {
|
|
193
209
|
'getGuildBadgesRaw': Awaited<ReturnType<APIGuildBadges['getGuildBadges']>>;
|
|
@@ -198,4 +214,6 @@ export type GuildBadgesReturnTypes = {
|
|
|
198
214
|
'sendTestBadgeNotificationSuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildBadges['sendTestBadgeNotification']>>>;
|
|
199
215
|
'getBadgeGamesRaw': Awaited<ReturnType<APIGuildBadges['getBadgeGames']>>;
|
|
200
216
|
'getBadgeGamesSuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildBadges['getBadgeGames']>>>;
|
|
217
|
+
'sendMissingBadgesRaw': Awaited<ReturnType<APIGuildBadges['sendMissingBadges']>>;
|
|
218
|
+
'sendMissingBadgesSuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildBadges['sendMissingBadges']>>>;
|
|
201
219
|
};
|
|
@@ -69,6 +69,22 @@ class APIGuildBadges {
|
|
|
69
69
|
body: { platform, gameId },
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* "Force Missing Badges": sends, now, every badge still live that this server is set up for and has not
|
|
74
|
+
* been sent, rather than at the next 5-minute check. Never re-sends one already sent.
|
|
75
|
+
*
|
|
76
|
+
* 400 when badges are not set up or the platform is switched off; 403 for the launch flag; 429 within
|
|
77
|
+
* 5 minutes of the last press for this server and platform (`error.code === 'rate_limited'`, count down
|
|
78
|
+
* from `error.retryAfterSeconds`); 503 in the first minutes after the bot starts, before its first badge
|
|
79
|
+
* check (that press does not start the cooldown). `data.message` is ready to show.
|
|
80
|
+
*/
|
|
81
|
+
async sendMissingBadges({ auth, guildId, platform }) {
|
|
82
|
+
return await this.web.request({
|
|
83
|
+
method: 'POST', auth,
|
|
84
|
+
endpoint: this.web.qp(`/data/guild/${guildId}/missing-badges`),
|
|
85
|
+
body: { platform },
|
|
86
|
+
});
|
|
87
|
+
}
|
|
72
88
|
/**
|
|
73
89
|
* The badge game picker's list: every game of the platform, ONE ROW PER GAME - duplicate entries for one
|
|
74
90
|
* game are merged, every id in `ids`. Any game can offer a badge later, so it is not limited to games that
|
|
@@ -19,7 +19,29 @@ export declare class APIGuildDrops {
|
|
|
19
19
|
* with "Invalid platform.". One segment is the only shape they cannot claim.
|
|
20
20
|
*/
|
|
21
21
|
sendTestDropNotification({ auth, guildId, platform, variant, dontPing }: GuildDropsFunctionsInput['sendTestDropNotification']): Promise<WebResponse<string>>;
|
|
22
|
+
/**
|
|
23
|
+
* "Force Missing Drops": sends, now, every drop still running that this server should have and has not
|
|
24
|
+
* been sent - for a server that enabled mid-campaign and does not want to wait for the next 5-minute
|
|
25
|
+
* check, or one that thinks a drop was missed. Never re-sends one already sent. Ignores the server's
|
|
26
|
+
* delivery window ("force" means now).
|
|
27
|
+
*
|
|
28
|
+
* 400 when drops are not set up or the platform is switched off; 429 within 5 minutes of the last press
|
|
29
|
+
* for this server and platform (`error.code === 'rate_limited'`, count down from `error.retryAfterSeconds`);
|
|
30
|
+
* 503 while the bot is starting. `data.sent` is how many drops were handed to the server; `data.message`
|
|
31
|
+
* is ready to show.
|
|
32
|
+
*
|
|
33
|
+
* One segment (`/missing-drops`) for the reason in `sendTestDropNotification`.
|
|
34
|
+
*/
|
|
35
|
+
sendMissingDrops({ auth, guildId, platform }: GuildDropsFunctionsInput['sendMissingDrops']): Promise<WebResponse<MissingSendData>>;
|
|
22
36
|
}
|
|
37
|
+
/** What a "send missing drops / badges" press did. */
|
|
38
|
+
export type MissingSendData = {
|
|
39
|
+
platform: 'kick' | 'twitch';
|
|
40
|
+
/** How many were handed to the server to post. 0 = nothing was missing. */
|
|
41
|
+
sent: number;
|
|
42
|
+
/** Ready to show: "Sending 3 missing Twitch drops now." or "Nothing missing - ...". */
|
|
43
|
+
message: string;
|
|
44
|
+
};
|
|
23
45
|
/** Which drops feed to sample: an ordinary campaign, or the exclusive/go-live variant. */
|
|
24
46
|
export type DropTestVariant = 'campaign' | 'live';
|
|
25
47
|
export type GuildDropsFunctionsInput = {
|
|
@@ -27,6 +49,11 @@ export type GuildDropsFunctionsInput = {
|
|
|
27
49
|
auth: string;
|
|
28
50
|
guildId: string;
|
|
29
51
|
};
|
|
52
|
+
'sendMissingDrops': {
|
|
53
|
+
auth: string;
|
|
54
|
+
guildId: string;
|
|
55
|
+
platform: 'kick' | 'twitch';
|
|
56
|
+
};
|
|
30
57
|
'sendTestDropNotification': {
|
|
31
58
|
auth: string;
|
|
32
59
|
guildId: string;
|
|
@@ -102,6 +129,8 @@ export type GuildDropsReturnTypes = {
|
|
|
102
129
|
'updateGuildDropsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildDrops['updateGuildDrops']>>>;
|
|
103
130
|
'sendTestDropNotificationRaw': Awaited<ReturnType<APIGuildDrops['sendTestDropNotification']>>;
|
|
104
131
|
'sendTestDropNotificationSuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildDrops['sendTestDropNotification']>>>;
|
|
132
|
+
'sendMissingDropsRaw': Awaited<ReturnType<APIGuildDrops['sendMissingDrops']>>;
|
|
133
|
+
'sendMissingDropsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildDrops['sendMissingDrops']>>>;
|
|
105
134
|
};
|
|
106
135
|
export type WebhookConfig = {
|
|
107
136
|
avatarUrl: string | null;
|
|
@@ -70,5 +70,25 @@ class APIGuildDrops {
|
|
|
70
70
|
body: { platform, variant },
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* "Force Missing Drops": sends, now, every drop still running that this server should have and has not
|
|
75
|
+
* been sent - for a server that enabled mid-campaign and does not want to wait for the next 5-minute
|
|
76
|
+
* check, or one that thinks a drop was missed. Never re-sends one already sent. Ignores the server's
|
|
77
|
+
* delivery window ("force" means now).
|
|
78
|
+
*
|
|
79
|
+
* 400 when drops are not set up or the platform is switched off; 429 within 5 minutes of the last press
|
|
80
|
+
* for this server and platform (`error.code === 'rate_limited'`, count down from `error.retryAfterSeconds`);
|
|
81
|
+
* 503 while the bot is starting. `data.sent` is how many drops were handed to the server; `data.message`
|
|
82
|
+
* is ready to show.
|
|
83
|
+
*
|
|
84
|
+
* One segment (`/missing-drops`) for the reason in `sendTestDropNotification`.
|
|
85
|
+
*/
|
|
86
|
+
async sendMissingDrops({ auth, guildId, platform }) {
|
|
87
|
+
return await this.web.request({
|
|
88
|
+
method: 'POST', auth,
|
|
89
|
+
endpoint: this.web.qp(`/data/guild/${guildId}/missing-drops`),
|
|
90
|
+
body: { platform },
|
|
91
|
+
});
|
|
92
|
+
}
|
|
73
93
|
}
|
|
74
94
|
exports.APIGuildDrops = APIGuildDrops;
|
|
@@ -18,6 +18,10 @@ export declare class APIGuildGiveaway {
|
|
|
18
18
|
resendGiveawayMessage({ auth, guildId, giveawayId }: GuildGiveawayFunctionsInput['resendGiveawayMessage']): Promise<import("../types").WebResponse<string>>;
|
|
19
19
|
startScheduledGiveaway({ auth, guildId, giveawayId }: GuildGiveawayFunctionsInput['startScheduledGiveaway']): Promise<import("../types").WebResponse<string>>;
|
|
20
20
|
endGiveaway({ auth, guildId, giveawayId }: GuildGiveawayFunctionsInput['endGiveaway']): Promise<import("../types").WebResponse<string>>;
|
|
21
|
+
/** The server's public giveaways switches. 403 while the `publicGiveaways` flag is hidden for the caller. */
|
|
22
|
+
getPublicGiveawaySettings({ auth, guildId }: GuildGiveawayFunctionsInput['getPublicGiveawaySettings']): Promise<import("../types").WebResponse<PublicGiveawaySettings>>;
|
|
23
|
+
/** Change either switch, field by field (booleans only). Answers with both. */
|
|
24
|
+
updatePublicGiveawaySettings({ auth, guildId, ...body }: GuildGiveawayFunctionsInput['updatePublicGiveawaySettings']): Promise<import("../types").WebResponse<PublicGiveawaySettings>>;
|
|
21
25
|
rerollGiveaway({ auth, guildId, giveawayId }: GuildGiveawayFunctionsInput['rerollGiveaway']): Promise<import("../types").WebResponse<string>>;
|
|
22
26
|
deleteGiveaway({ auth, guildId, giveawayId, type }: GuildGiveawayFunctionsInput['deleteGiveaway']): Promise<import("../types").WebResponse<string>>;
|
|
23
27
|
}
|
|
@@ -53,8 +57,16 @@ export type GuildGiveawayFunctionsInput<T extends WhenCreate = never> = {
|
|
|
53
57
|
auth: string;
|
|
54
58
|
guildId: string;
|
|
55
59
|
giveawayId: string;
|
|
56
|
-
body: Pick<DeepPartial<GuildGiveawayZod>, 'winnerCount' | 'durationMinutes' | 'name'>;
|
|
60
|
+
body: Pick<DeepPartial<GuildGiveawayZod>, 'winnerCount' | 'durationMinutes' | 'name' | 'publicListing'>;
|
|
57
61
|
};
|
|
62
|
+
'getPublicGiveawaySettings': {
|
|
63
|
+
auth: string;
|
|
64
|
+
guildId: string;
|
|
65
|
+
};
|
|
66
|
+
'updatePublicGiveawaySettings': {
|
|
67
|
+
auth: string;
|
|
68
|
+
guildId: string;
|
|
69
|
+
} & Partial<PublicGiveawaySettings>;
|
|
58
70
|
'resendGiveawayMessage': {
|
|
59
71
|
auth: string;
|
|
60
72
|
guildId: string;
|
|
@@ -96,9 +108,18 @@ export type GuildGiveawayReturnTypes = {
|
|
|
96
108
|
'deleteGiveawaySuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildGiveaway['deleteGiveaway']>>>;
|
|
97
109
|
'endGiveawayRaw': Awaited<ReturnType<APIGuildGiveaway['endGiveaway']>>;
|
|
98
110
|
'endGiveawaySuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildGiveaway['endGiveaway']>>>;
|
|
111
|
+
'getPublicGiveawaySettingsRaw': Awaited<ReturnType<APIGuildGiveaway['getPublicGiveawaySettings']>>;
|
|
112
|
+
'getPublicGiveawaySettingsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildGiveaway['getPublicGiveawaySettings']>>>;
|
|
113
|
+
'updatePublicGiveawaySettingsRaw': Awaited<ReturnType<APIGuildGiveaway['updatePublicGiveawaySettings']>>;
|
|
114
|
+
'updatePublicGiveawaySettingsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildGiveaway['updatePublicGiveawaySettings']>>>;
|
|
99
115
|
'rerollGiveawayRaw': Awaited<ReturnType<APIGuildGiveaway['rerollGiveaway']>>;
|
|
100
116
|
'rerollGiveawaySuccess': CancelOutWebResponses<Awaited<ReturnType<APIGuildGiveaway['rerollGiveaway']>>>;
|
|
101
117
|
};
|
|
118
|
+
/** `publicGiveaways`: list this server's giveaways on noti.bot (default on). `giveawayJoinLinks`: let people join from there (default off). */
|
|
119
|
+
export type PublicGiveawaySettings = {
|
|
120
|
+
publicGiveaways: boolean;
|
|
121
|
+
giveawayJoinLinks: boolean;
|
|
122
|
+
};
|
|
102
123
|
export type WhenCreate = 'now' | 'later';
|
|
103
124
|
export type StateType = 'live' | 'scheduled';
|
|
104
125
|
export type GuildGiveawaysType = {
|
|
@@ -124,6 +145,12 @@ export type GuildGiveawaysType = {
|
|
|
124
145
|
canBonusEntries: boolean;
|
|
125
146
|
canRequirements: boolean;
|
|
126
147
|
canModifyWhileRunning: boolean;
|
|
148
|
+
/** Claim to win (Premium Plus). Gate the claim window control on this. */
|
|
149
|
+
canClaim: boolean;
|
|
150
|
+
/** Winner role (Premium). Gate the winner role and its removal days on this. */
|
|
151
|
+
canWinnerRole: boolean;
|
|
152
|
+
/** The claim windows the server accepts, in minutes. Same list as `GIVEAWAY_CLAIM_WINDOWS`. */
|
|
153
|
+
claimWindowChoices: number[];
|
|
127
154
|
};
|
|
128
155
|
/** Which tier those caps came from, so the UI can name the plan in a limit message. */
|
|
129
156
|
premium: {
|
|
@@ -58,6 +58,20 @@ class APIGuildGiveaway {
|
|
|
58
58
|
endpoint: this.web.qp('/data/giveaways/' + guildId + '/' + giveawayId + '/end'),
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
|
+
/** The server's public giveaways switches. 403 while the `publicGiveaways` flag is hidden for the caller. */
|
|
62
|
+
async getPublicGiveawaySettings({ auth, guildId }) {
|
|
63
|
+
return await this.web.request({
|
|
64
|
+
method: 'GET', auth,
|
|
65
|
+
endpoint: this.web.qp('/data/guild/' + guildId + '/public-giveaways'),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/** Change either switch, field by field (booleans only). Answers with both. */
|
|
69
|
+
async updatePublicGiveawaySettings({ auth, guildId, ...body }) {
|
|
70
|
+
return await this.web.request({
|
|
71
|
+
method: 'PATCH', auth, body,
|
|
72
|
+
endpoint: this.web.qp('/data/guild/' + guildId + '/public-giveaways'),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
61
75
|
async rerollGiveaway({ auth, guildId, giveawayId }) {
|
|
62
76
|
return await this.web.request({
|
|
63
77
|
method: 'POST', auth,
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { CancelOutWebResponses } from '../types';
|
|
2
|
+
import { WebDataManager } from '../core/manager';
|
|
3
|
+
/**
|
|
4
|
+
* The PUBLIC drops and badges pages - current and upcoming Kick and Twitch drops campaigns, and the chat
|
|
5
|
+
* badges they reward.
|
|
6
|
+
*
|
|
7
|
+
* ── WHO SEES WHAT ──────────────────────────────────────────────────────────
|
|
8
|
+
* `listPublicDrops` / `listPublicBadges` need no session: the first 12. The `*All*` methods page the rest for
|
|
9
|
+
* any logged-in user (no server permission), so pass `auth`.
|
|
10
|
+
*
|
|
11
|
+
* ── SOURCES ────────────────────────────────────────────────────────────────
|
|
12
|
+
* Every response carries `sources`: whether the Kick or Twitch drops source is failing right now. An empty list
|
|
13
|
+
* with a failing source means "unavailable", not "no drops" - show it that way.
|
|
14
|
+
*
|
|
15
|
+
* Behind the `publicDrops` launch flag: while it is hidden for the caller the lists are EMPTY (not 403).
|
|
16
|
+
* Built from the bot's last successful sync (every 5 minutes), so a new campaign can take that long to appear.
|
|
17
|
+
*/
|
|
18
|
+
export declare class APIPublicDrops {
|
|
19
|
+
private web;
|
|
20
|
+
constructor(web: WebDataManager);
|
|
21
|
+
/** The first 12 drops campaigns, live (ending soonest) then upcoming. No session. */
|
|
22
|
+
listPublicDrops({ platform }?: PublicDropsFunctionsInput['listPublicDrops']): Promise<import("../types").WebResponse<PublicDropList>>;
|
|
23
|
+
/** Every drops campaign, 24 per page. Pass the previous page's `nextCursor`; null = last page. */
|
|
24
|
+
listAllPublicDrops({ auth, platform, cursor }: PublicDropsFunctionsInput['listAllPublicDrops']): Promise<import("../types").WebResponse<PublicDropPage>>;
|
|
25
|
+
/** The first 12 chat badges from drops, live then upcoming. No session. */
|
|
26
|
+
listPublicBadges({ platform }?: PublicDropsFunctionsInput['listPublicBadges']): Promise<import("../types").WebResponse<PublicBadgeList>>;
|
|
27
|
+
/** Every chat badge, 24 per page. */
|
|
28
|
+
listAllPublicBadges({ auth, platform, cursor }: PublicDropsFunctionsInput['listAllPublicBadges']): Promise<import("../types").WebResponse<PublicBadgePage>>;
|
|
29
|
+
}
|
|
30
|
+
/** `all` (or omitted) = both platforms. */
|
|
31
|
+
export type PublicDropsPlatformFilter = 'kick' | 'twitch' | 'all';
|
|
32
|
+
export type PublicDropsFunctionsInput = {
|
|
33
|
+
'listPublicDrops': {
|
|
34
|
+
platform?: PublicDropsPlatformFilter;
|
|
35
|
+
};
|
|
36
|
+
'listAllPublicDrops': {
|
|
37
|
+
auth: string;
|
|
38
|
+
platform?: PublicDropsPlatformFilter;
|
|
39
|
+
cursor?: string | null;
|
|
40
|
+
};
|
|
41
|
+
'listPublicBadges': {
|
|
42
|
+
platform?: PublicDropsPlatformFilter;
|
|
43
|
+
};
|
|
44
|
+
'listAllPublicBadges': {
|
|
45
|
+
auth: string;
|
|
46
|
+
platform?: PublicDropsPlatformFilter;
|
|
47
|
+
cursor?: string | null;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export type PublicDropsGetReturnTypes = {
|
|
51
|
+
'listPublicDropsRaw': Awaited<ReturnType<APIPublicDrops['listPublicDrops']>>;
|
|
52
|
+
'listPublicDropsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIPublicDrops['listPublicDrops']>>>;
|
|
53
|
+
'listAllPublicDropsRaw': Awaited<ReturnType<APIPublicDrops['listAllPublicDrops']>>;
|
|
54
|
+
'listAllPublicDropsSuccess': CancelOutWebResponses<Awaited<ReturnType<APIPublicDrops['listAllPublicDrops']>>>;
|
|
55
|
+
'listPublicBadgesRaw': Awaited<ReturnType<APIPublicDrops['listPublicBadges']>>;
|
|
56
|
+
'listPublicBadgesSuccess': CancelOutWebResponses<Awaited<ReturnType<APIPublicDrops['listPublicBadges']>>>;
|
|
57
|
+
'listAllPublicBadgesRaw': Awaited<ReturnType<APIPublicDrops['listAllPublicBadges']>>;
|
|
58
|
+
'listAllPublicBadgesSuccess': CancelOutWebResponses<Awaited<ReturnType<APIPublicDrops['listAllPublicBadges']>>>;
|
|
59
|
+
};
|
|
60
|
+
/** Is each drops source failing right now. `since` is ISO, set while failing. */
|
|
61
|
+
export type PublicDropsSources = {
|
|
62
|
+
kick: {
|
|
63
|
+
ok: boolean;
|
|
64
|
+
since: string | null;
|
|
65
|
+
};
|
|
66
|
+
twitch: {
|
|
67
|
+
ok: boolean;
|
|
68
|
+
since: string | null;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
export type PublicDropReward = {
|
|
72
|
+
name: string;
|
|
73
|
+
imageUrl: string | null;
|
|
74
|
+
requiredMinutes: number | null;
|
|
75
|
+
/** Subscriptions the reward needs (Twitch only); null when none. */
|
|
76
|
+
requiredSubs: number | null;
|
|
77
|
+
isBadge: boolean;
|
|
78
|
+
};
|
|
79
|
+
/** One campaign. Mirrors `PublicDropCard` in Noti-v3's `src/modules/publicDrops.ts`. */
|
|
80
|
+
export type PublicDropCard = {
|
|
81
|
+
/** `<platform>:<campaignId>`. */
|
|
82
|
+
id: string;
|
|
83
|
+
platform: 'kick' | 'twitch';
|
|
84
|
+
name: string;
|
|
85
|
+
game: {
|
|
86
|
+
name: string;
|
|
87
|
+
imageUrl: string | null;
|
|
88
|
+
};
|
|
89
|
+
/** Kick only. */
|
|
90
|
+
organization: string | null;
|
|
91
|
+
/** ISO. */
|
|
92
|
+
startsAt: string;
|
|
93
|
+
/** ISO. */
|
|
94
|
+
endsAt: string;
|
|
95
|
+
status: 'live' | 'upcoming';
|
|
96
|
+
/** Where to watch: the Kick category page, or the Twitch campaign page. */
|
|
97
|
+
url: string | null;
|
|
98
|
+
rewards: PublicDropReward[];
|
|
99
|
+
/** Kick drops earned only by watching these streamers; null for everyone else. */
|
|
100
|
+
exclusive: {
|
|
101
|
+
streamers: {
|
|
102
|
+
username: string;
|
|
103
|
+
url: string;
|
|
104
|
+
}[];
|
|
105
|
+
} | null;
|
|
106
|
+
};
|
|
107
|
+
/** One chat badge. Mirrors `PublicBadgeCard` in Noti-v3. */
|
|
108
|
+
export type PublicBadgeCard = {
|
|
109
|
+
/** `<platform>:<rewardId>`. */
|
|
110
|
+
key: string;
|
|
111
|
+
platform: 'kick' | 'twitch';
|
|
112
|
+
name: string;
|
|
113
|
+
imageUrl: string | null;
|
|
114
|
+
game: string;
|
|
115
|
+
campaign: string;
|
|
116
|
+
/** ISO. */
|
|
117
|
+
startsAt: string;
|
|
118
|
+
/** ISO. */
|
|
119
|
+
endsAt: string;
|
|
120
|
+
/** Claimable right now. */
|
|
121
|
+
active: boolean;
|
|
122
|
+
url: string | null;
|
|
123
|
+
requiredMinutes: number | null;
|
|
124
|
+
requiredSubs: number | null;
|
|
125
|
+
};
|
|
126
|
+
export type PublicDropList = {
|
|
127
|
+
drops: PublicDropCard[];
|
|
128
|
+
total: number;
|
|
129
|
+
sources: PublicDropsSources;
|
|
130
|
+
};
|
|
131
|
+
export type PublicDropPage = {
|
|
132
|
+
drops: PublicDropCard[];
|
|
133
|
+
nextCursor: string | null;
|
|
134
|
+
total: number;
|
|
135
|
+
sources: PublicDropsSources;
|
|
136
|
+
};
|
|
137
|
+
export type PublicBadgeList = {
|
|
138
|
+
badges: PublicBadgeCard[];
|
|
139
|
+
total: number;
|
|
140
|
+
sources: PublicDropsSources;
|
|
141
|
+
};
|
|
142
|
+
export type PublicBadgePage = {
|
|
143
|
+
badges: PublicBadgeCard[];
|
|
144
|
+
nextCursor: string | null;
|
|
145
|
+
total: number;
|
|
146
|
+
sources: PublicDropsSources;
|
|
147
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.APIPublicDrops = void 0;
|
|
4
|
+
// Data.
|
|
5
|
+
/**
|
|
6
|
+
* The PUBLIC drops and badges pages - current and upcoming Kick and Twitch drops campaigns, and the chat
|
|
7
|
+
* badges they reward.
|
|
8
|
+
*
|
|
9
|
+
* ── WHO SEES WHAT ──────────────────────────────────────────────────────────
|
|
10
|
+
* `listPublicDrops` / `listPublicBadges` need no session: the first 12. The `*All*` methods page the rest for
|
|
11
|
+
* any logged-in user (no server permission), so pass `auth`.
|
|
12
|
+
*
|
|
13
|
+
* ── SOURCES ────────────────────────────────────────────────────────────────
|
|
14
|
+
* Every response carries `sources`: whether the Kick or Twitch drops source is failing right now. An empty list
|
|
15
|
+
* with a failing source means "unavailable", not "no drops" - show it that way.
|
|
16
|
+
*
|
|
17
|
+
* Behind the `publicDrops` launch flag: while it is hidden for the caller the lists are EMPTY (not 403).
|
|
18
|
+
* Built from the bot's last successful sync (every 5 minutes), so a new campaign can take that long to appear.
|
|
19
|
+
*/
|
|
20
|
+
class APIPublicDrops {
|
|
21
|
+
web;
|
|
22
|
+
constructor(web) {
|
|
23
|
+
this.web = web;
|
|
24
|
+
}
|
|
25
|
+
/** The first 12 drops campaigns, live (ending soonest) then upcoming. No session. */
|
|
26
|
+
async listPublicDrops({ platform } = {}) {
|
|
27
|
+
return await this.web.request({
|
|
28
|
+
method: 'GET',
|
|
29
|
+
endpoint: this.web.qp('/public/drops', platform ? { platform } : {}),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** Every drops campaign, 24 per page. Pass the previous page's `nextCursor`; null = last page. */
|
|
33
|
+
async listAllPublicDrops({ auth, platform, cursor }) {
|
|
34
|
+
return await this.web.request({
|
|
35
|
+
method: 'GET', auth,
|
|
36
|
+
endpoint: this.web.qp('/public/drops/all', { ...(platform ? { platform } : {}), ...(cursor ? { cursor } : {}) }),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/** The first 12 chat badges from drops, live then upcoming. No session. */
|
|
40
|
+
async listPublicBadges({ platform } = {}) {
|
|
41
|
+
return await this.web.request({
|
|
42
|
+
method: 'GET',
|
|
43
|
+
endpoint: this.web.qp('/public/badges', platform ? { platform } : {}),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/** Every chat badge, 24 per page. */
|
|
47
|
+
async listAllPublicBadges({ auth, platform, cursor }) {
|
|
48
|
+
return await this.web.request({
|
|
49
|
+
method: 'GET', auth,
|
|
50
|
+
endpoint: this.web.qp('/public/badges/all', { ...(platform ? { platform } : {}), ...(cursor ? { cursor } : {}) }),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.APIPublicDrops = APIPublicDrops;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { CancelOutWebResponses } from '../types';
|
|
2
|
+
import { WebDataManager } from '../core/manager';
|
|
3
|
+
/**
|
|
4
|
+
* The PUBLIC giveaways page - running giveaways from every server that lists them on noti.bot.
|
|
5
|
+
*
|
|
6
|
+
* ── WHO SEES WHAT ──────────────────────────────────────────────────────────
|
|
7
|
+
* `listPublicGiveaways` needs no session: the latest 10. Everything else needs a logged-in user (any
|
|
8
|
+
* Discord account - no server permission), so pass `auth`.
|
|
9
|
+
*
|
|
10
|
+
* ── LISTED BY DEFAULT ──────────────────────────────────────────────────────
|
|
11
|
+
* A server's giveaways are listed unless it switched them off (`guildGiveaway.updatePublicGiveawaySettings`),
|
|
12
|
+
* and each giveaway can override that (`publicListing`). Behind the `publicGiveaways` launch flag: while it
|
|
13
|
+
* is hidden for the caller the lists are EMPTY (not 403) and single lookups 404.
|
|
14
|
+
*
|
|
15
|
+
* ── WHAT A CARD NEVER CARRIES ──────────────────────────────────────────────
|
|
16
|
+
* No host, winners, entrants or internal ids. Roles are names, dates are ISO strings, and a role deleted
|
|
17
|
+
* since the giveaway was made reads "deleted role" rather than disappearing.
|
|
18
|
+
*
|
|
19
|
+
* The lists are cached on the server for up to a minute, so an entry count can trail by that much.
|
|
20
|
+
*/
|
|
21
|
+
export declare class APIPublicGiveaways {
|
|
22
|
+
private web;
|
|
23
|
+
constructor(web: WebDataManager);
|
|
24
|
+
/** The latest 10 listed giveaways and how many are listed in all. No session. */
|
|
25
|
+
listPublicGiveaways(): Promise<import("../types").WebResponse<PublicGiveawayList>>;
|
|
26
|
+
/** Every listed giveaway, 24 per page, newest first. Pass the previous page's `nextCursor`; null = last page. */
|
|
27
|
+
listAllPublicGiveaways({ auth, cursor }: PublicGiveawaysFunctionsInput['listAllPublicGiveaways']): Promise<import("../types").WebResponse<PublicGiveawayPage>>;
|
|
28
|
+
/** One listed giveaway, plus where the logged-in user stands on it. 404 when it is not listed (or ended). */
|
|
29
|
+
getPublicGiveaway({ auth, giveawayId }: PublicGiveawaysFunctionsInput['getPublicGiveaway']): Promise<import("../types").WebResponse<PublicGiveawayWithViewer>>;
|
|
30
|
+
/**
|
|
31
|
+
* Enter a listed giveaway as the logged-in user - the same rules as the Discord button. A refusal is
|
|
32
|
+
* `{ status: 400 | 404 | 429, error: { code } }` with `code` from `PUBLIC_ENTRY_REFUSALS`; word it on the
|
|
33
|
+
* page (the card's `requirements` say what is required). 10 attempts per user per minute.
|
|
34
|
+
*/
|
|
35
|
+
createPublicGiveawayEntry({ auth, giveawayId }: PublicGiveawaysFunctionsInput['createPublicGiveawayEntry']): Promise<import("../types").WebResponse<PublicGiveawayEntryResult>>;
|
|
36
|
+
/**
|
|
37
|
+
* A link to join the giveaway's server - only when the card's `canJoin` is true. 404 when the server does
|
|
38
|
+
* not allow it or no invite could be made. The same link is reused; do not call it per render.
|
|
39
|
+
*/
|
|
40
|
+
getPublicGiveawayJoinLink({ auth, giveawayId }: PublicGiveawaysFunctionsInput['getPublicGiveawayJoinLink']): Promise<import("../types").WebResponse<{
|
|
41
|
+
url: string;
|
|
42
|
+
}>>;
|
|
43
|
+
}
|
|
44
|
+
export type PublicGiveawaysFunctionsInput = {
|
|
45
|
+
'listAllPublicGiveaways': {
|
|
46
|
+
auth: string;
|
|
47
|
+
cursor?: string | null;
|
|
48
|
+
};
|
|
49
|
+
'getPublicGiveaway': {
|
|
50
|
+
auth: string;
|
|
51
|
+
giveawayId: string;
|
|
52
|
+
};
|
|
53
|
+
'createPublicGiveawayEntry': {
|
|
54
|
+
auth: string;
|
|
55
|
+
giveawayId: string;
|
|
56
|
+
};
|
|
57
|
+
'getPublicGiveawayJoinLink': {
|
|
58
|
+
auth: string;
|
|
59
|
+
giveawayId: string;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
export type PublicGiveawaysGetReturnTypes = {
|
|
63
|
+
'listPublicGiveawaysRaw': Awaited<ReturnType<APIPublicGiveaways['listPublicGiveaways']>>;
|
|
64
|
+
'listPublicGiveawaysSuccess': CancelOutWebResponses<Awaited<ReturnType<APIPublicGiveaways['listPublicGiveaways']>>>;
|
|
65
|
+
'listAllPublicGiveawaysRaw': Awaited<ReturnType<APIPublicGiveaways['listAllPublicGiveaways']>>;
|
|
66
|
+
'listAllPublicGiveawaysSuccess': CancelOutWebResponses<Awaited<ReturnType<APIPublicGiveaways['listAllPublicGiveaways']>>>;
|
|
67
|
+
'getPublicGiveawayRaw': Awaited<ReturnType<APIPublicGiveaways['getPublicGiveaway']>>;
|
|
68
|
+
'getPublicGiveawaySuccess': CancelOutWebResponses<Awaited<ReturnType<APIPublicGiveaways['getPublicGiveaway']>>>;
|
|
69
|
+
'createPublicGiveawayEntryRaw': Awaited<ReturnType<APIPublicGiveaways['createPublicGiveawayEntry']>>;
|
|
70
|
+
'createPublicGiveawayEntrySuccess': CancelOutWebResponses<Awaited<ReturnType<APIPublicGiveaways['createPublicGiveawayEntry']>>>;
|
|
71
|
+
'getPublicGiveawayJoinLinkRaw': Awaited<ReturnType<APIPublicGiveaways['getPublicGiveawayJoinLink']>>;
|
|
72
|
+
'getPublicGiveawayJoinLinkSuccess': CancelOutWebResponses<Awaited<ReturnType<APIPublicGiveaways['getPublicGiveawayJoinLink']>>>;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Every reason an entry can be refused. Mirrors `PUBLIC_ENTRY_REFUSALS` in Noti-v3's
|
|
76
|
+
* `src/modules/publicGiveaways.ts`; the eligibility ones match the card's `requirements` / `entryFilter`.
|
|
77
|
+
*/
|
|
78
|
+
export declare const PUBLIC_ENTRY_REFUSALS: readonly ["not_listed", "ended", "full", "not_member", "already_entered", "rate_limited", "role_whitelist", "role_blacklist", "joined_server_before", "account_created_before", "min_account_age", "boosting_server", "roles", "message_count"];
|
|
79
|
+
export type PublicEntryRefusal = typeof PUBLIC_ENTRY_REFUSALS[number];
|
|
80
|
+
export type PublicGiveawayRole = {
|
|
81
|
+
id: string;
|
|
82
|
+
name: string;
|
|
83
|
+
};
|
|
84
|
+
/** One giveaway as the public page shows it. Mirrors `PublicGiveawayCard` in Noti-v3. */
|
|
85
|
+
export type PublicGiveawayCard = {
|
|
86
|
+
giveawayId: string;
|
|
87
|
+
name: string;
|
|
88
|
+
emoji: string | null;
|
|
89
|
+
/** ISO. */
|
|
90
|
+
endsAt: string;
|
|
91
|
+
winnerCount: number;
|
|
92
|
+
maxEntries: number | null;
|
|
93
|
+
entryCount: number;
|
|
94
|
+
/** Minutes winners have to press Claim; null when the giveaway does not need claiming. */
|
|
95
|
+
claimWindowMinutes: number | null;
|
|
96
|
+
/** Voting for Noti counts as a second entry. */
|
|
97
|
+
doubleVoteEntry: boolean;
|
|
98
|
+
requirements: {
|
|
99
|
+
/** ISO. */
|
|
100
|
+
joinedServerBefore: string | null;
|
|
101
|
+
/** ISO. */
|
|
102
|
+
accountCreatedBefore: string | null;
|
|
103
|
+
minAccountAgeDays: number | null;
|
|
104
|
+
boostingServer: boolean;
|
|
105
|
+
messageCount: number | null;
|
|
106
|
+
roles: PublicGiveawayRole[];
|
|
107
|
+
} | null;
|
|
108
|
+
entryFilter: {
|
|
109
|
+
mode: 'whitelist' | 'blacklist';
|
|
110
|
+
roles: PublicGiveawayRole[];
|
|
111
|
+
} | null;
|
|
112
|
+
/** `stacks: false` = only the member's highest bonus role counts. */
|
|
113
|
+
bonusRoles: {
|
|
114
|
+
roles: PublicGiveawayRole[];
|
|
115
|
+
additionalEntries: number;
|
|
116
|
+
stacks: boolean;
|
|
117
|
+
}[];
|
|
118
|
+
guild: {
|
|
119
|
+
id: string;
|
|
120
|
+
name: string;
|
|
121
|
+
icon: string | null;
|
|
122
|
+
memberCount: number;
|
|
123
|
+
};
|
|
124
|
+
/** The giveaway message in Discord. */
|
|
125
|
+
messageUrl: string;
|
|
126
|
+
/** The server lets people join from noti.bot - offer `getPublicGiveawayJoinLink`. */
|
|
127
|
+
canJoin: boolean;
|
|
128
|
+
};
|
|
129
|
+
export type PublicGiveawayViewer = {
|
|
130
|
+
entered: boolean;
|
|
131
|
+
isMember: boolean;
|
|
132
|
+
eligible: boolean;
|
|
133
|
+
/** Why not, when `eligible` is false. */
|
|
134
|
+
reason: PublicEntryRefusal | null;
|
|
135
|
+
};
|
|
136
|
+
export type PublicGiveawayList = {
|
|
137
|
+
giveaways: PublicGiveawayCard[];
|
|
138
|
+
total: number;
|
|
139
|
+
};
|
|
140
|
+
export type PublicGiveawayPage = {
|
|
141
|
+
giveaways: PublicGiveawayCard[];
|
|
142
|
+
nextCursor: string | null;
|
|
143
|
+
total: number;
|
|
144
|
+
};
|
|
145
|
+
export type PublicGiveawayWithViewer = {
|
|
146
|
+
giveaway: PublicGiveawayCard;
|
|
147
|
+
viewer: PublicGiveawayViewer;
|
|
148
|
+
};
|
|
149
|
+
export type PublicGiveawayEntryResult = {
|
|
150
|
+
entered: true;
|
|
151
|
+
entries: number;
|
|
152
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PUBLIC_ENTRY_REFUSALS = exports.APIPublicGiveaways = void 0;
|
|
4
|
+
// Data.
|
|
5
|
+
/**
|
|
6
|
+
* The PUBLIC giveaways page - running giveaways from every server that lists them on noti.bot.
|
|
7
|
+
*
|
|
8
|
+
* ── WHO SEES WHAT ──────────────────────────────────────────────────────────
|
|
9
|
+
* `listPublicGiveaways` needs no session: the latest 10. Everything else needs a logged-in user (any
|
|
10
|
+
* Discord account - no server permission), so pass `auth`.
|
|
11
|
+
*
|
|
12
|
+
* ── LISTED BY DEFAULT ──────────────────────────────────────────────────────
|
|
13
|
+
* A server's giveaways are listed unless it switched them off (`guildGiveaway.updatePublicGiveawaySettings`),
|
|
14
|
+
* and each giveaway can override that (`publicListing`). Behind the `publicGiveaways` launch flag: while it
|
|
15
|
+
* is hidden for the caller the lists are EMPTY (not 403) and single lookups 404.
|
|
16
|
+
*
|
|
17
|
+
* ── WHAT A CARD NEVER CARRIES ──────────────────────────────────────────────
|
|
18
|
+
* No host, winners, entrants or internal ids. Roles are names, dates are ISO strings, and a role deleted
|
|
19
|
+
* since the giveaway was made reads "deleted role" rather than disappearing.
|
|
20
|
+
*
|
|
21
|
+
* The lists are cached on the server for up to a minute, so an entry count can trail by that much.
|
|
22
|
+
*/
|
|
23
|
+
class APIPublicGiveaways {
|
|
24
|
+
web;
|
|
25
|
+
constructor(web) {
|
|
26
|
+
this.web = web;
|
|
27
|
+
}
|
|
28
|
+
/** The latest 10 listed giveaways and how many are listed in all. No session. */
|
|
29
|
+
async listPublicGiveaways() {
|
|
30
|
+
return await this.web.request({
|
|
31
|
+
method: 'GET',
|
|
32
|
+
endpoint: this.web.qp('/public/giveaways'),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/** Every listed giveaway, 24 per page, newest first. Pass the previous page's `nextCursor`; null = last page. */
|
|
36
|
+
async listAllPublicGiveaways({ auth, cursor }) {
|
|
37
|
+
return await this.web.request({
|
|
38
|
+
method: 'GET', auth,
|
|
39
|
+
endpoint: this.web.qp('/public/giveaways/all', cursor ? { cursor } : {}),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** One listed giveaway, plus where the logged-in user stands on it. 404 when it is not listed (or ended). */
|
|
43
|
+
async getPublicGiveaway({ auth, giveawayId }) {
|
|
44
|
+
return await this.web.request({
|
|
45
|
+
method: 'GET', auth,
|
|
46
|
+
endpoint: this.web.qp('/public/giveaways/' + giveawayId),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Enter a listed giveaway as the logged-in user - the same rules as the Discord button. A refusal is
|
|
51
|
+
* `{ status: 400 | 404 | 429, error: { code } }` with `code` from `PUBLIC_ENTRY_REFUSALS`; word it on the
|
|
52
|
+
* page (the card's `requirements` say what is required). 10 attempts per user per minute.
|
|
53
|
+
*/
|
|
54
|
+
async createPublicGiveawayEntry({ auth, giveawayId }) {
|
|
55
|
+
return await this.web.request({
|
|
56
|
+
method: 'POST', auth,
|
|
57
|
+
endpoint: this.web.qp('/public/giveaways/' + giveawayId + '/entries'),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A link to join the giveaway's server - only when the card's `canJoin` is true. 404 when the server does
|
|
62
|
+
* not allow it or no invite could be made. The same link is reused; do not call it per render.
|
|
63
|
+
*/
|
|
64
|
+
async getPublicGiveawayJoinLink({ auth, giveawayId }) {
|
|
65
|
+
return await this.web.request({
|
|
66
|
+
method: 'GET', auth,
|
|
67
|
+
endpoint: this.web.qp('/public/giveaways/' + giveawayId + '/join'),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.APIPublicGiveaways = APIPublicGiveaways;
|
|
72
|
+
/**
|
|
73
|
+
* Every reason an entry can be refused. Mirrors `PUBLIC_ENTRY_REFUSALS` in Noti-v3's
|
|
74
|
+
* `src/modules/publicGiveaways.ts`; the eligibility ones match the card's `requirements` / `entryFilter`.
|
|
75
|
+
*/
|
|
76
|
+
exports.PUBLIC_ENTRY_REFUSALS = [
|
|
77
|
+
'not_listed', 'ended', 'full', 'not_member', 'already_entered', 'rate_limited',
|
|
78
|
+
'role_whitelist', 'role_blacklist', 'joined_server_before', 'account_created_before', 'min_account_age',
|
|
79
|
+
'boosting_server', 'roles', 'message_count',
|
|
80
|
+
];
|