mini-interactions-linked-roles 0.1.0
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/index.d.ts +90 -0
- package/dist/index.js +243 -0
- package/dist/index.js.map +1 -0
- package/package.json +23 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
declare enum ApplicationRoleConnectionMetadataType {
|
|
2
|
+
IntegerLessThanOrEqual = 1,
|
|
3
|
+
IntegerGreaterThanOrEqual = 2,
|
|
4
|
+
IntegerEqual = 3,
|
|
5
|
+
IntegerNotEqual = 4,
|
|
6
|
+
DatetimeLessThanOrEqual = 5,
|
|
7
|
+
DatetimeGreaterThanOrEqual = 6,
|
|
8
|
+
BooleanEqual = 7,
|
|
9
|
+
BooleanNotEqual = 8
|
|
10
|
+
}
|
|
11
|
+
interface ApplicationRoleConnectionMetadata {
|
|
12
|
+
type: ApplicationRoleConnectionMetadataType;
|
|
13
|
+
key: string;
|
|
14
|
+
name: string;
|
|
15
|
+
name_localizations?: Readonly<Record<string, string>>;
|
|
16
|
+
description: string;
|
|
17
|
+
description_localizations?: Readonly<Record<string, string>>;
|
|
18
|
+
}
|
|
19
|
+
interface JsonBuilder<T> {
|
|
20
|
+
toJSON(): T;
|
|
21
|
+
}
|
|
22
|
+
declare class RoleConnectionMetadataBuilder implements JsonBuilder<ApplicationRoleConnectionMetadata> {
|
|
23
|
+
#private;
|
|
24
|
+
setType(type: ApplicationRoleConnectionMetadataType): this;
|
|
25
|
+
setKey(key: string): this;
|
|
26
|
+
setName(name: string): this;
|
|
27
|
+
setNameLocalization(locale: string, name: string): this;
|
|
28
|
+
setDescription(description: string): this;
|
|
29
|
+
setDescriptionLocalization(locale: string, description: string): this;
|
|
30
|
+
toJSON(): ApplicationRoleConnectionMetadata;
|
|
31
|
+
}
|
|
32
|
+
type RoleConnectionMetadataValue = string | number | boolean | Date;
|
|
33
|
+
type RoleConnectionMetadataValues = Readonly<Record<string, RoleConnectionMetadataValue>>;
|
|
34
|
+
declare function serializeRoleConnectionMetadata(metadata: RoleConnectionMetadataValues): Readonly<Record<string, string>>;
|
|
35
|
+
interface ApplicationRoleConnection {
|
|
36
|
+
platform_name: string | null;
|
|
37
|
+
platform_username?: string | null;
|
|
38
|
+
metadata: Readonly<Record<string, string>>;
|
|
39
|
+
}
|
|
40
|
+
interface UpdateRoleConnectionOptions {
|
|
41
|
+
platformName?: string;
|
|
42
|
+
platformUsername?: string;
|
|
43
|
+
metadata?: RoleConnectionMetadataValues;
|
|
44
|
+
}
|
|
45
|
+
interface DiscordOAuthTokenResponse {
|
|
46
|
+
access_token: string;
|
|
47
|
+
token_type: string;
|
|
48
|
+
expires_in: number;
|
|
49
|
+
refresh_token: string;
|
|
50
|
+
scope: string;
|
|
51
|
+
}
|
|
52
|
+
interface LinkedRolesAuthorizationOptions {
|
|
53
|
+
state?: string;
|
|
54
|
+
scopes?: readonly string[];
|
|
55
|
+
prompt?: "consent" | "none";
|
|
56
|
+
}
|
|
57
|
+
interface LinkedRolesClientOptions {
|
|
58
|
+
applicationId: string;
|
|
59
|
+
botToken?: string;
|
|
60
|
+
clientSecret?: string;
|
|
61
|
+
redirectUri?: string;
|
|
62
|
+
apiBaseUrl?: string;
|
|
63
|
+
authorizationBaseUrl?: string;
|
|
64
|
+
fetchImplementation?: typeof fetch;
|
|
65
|
+
}
|
|
66
|
+
interface LinkedRolesApplication {
|
|
67
|
+
id?: string;
|
|
68
|
+
role_connections_verification_url: string | null;
|
|
69
|
+
[key: string]: unknown;
|
|
70
|
+
}
|
|
71
|
+
declare class LinkedRolesClient {
|
|
72
|
+
#private;
|
|
73
|
+
readonly applicationId: string;
|
|
74
|
+
constructor(options: LinkedRolesClientOptions);
|
|
75
|
+
buildAuthorizationURL(options?: LinkedRolesAuthorizationOptions): string;
|
|
76
|
+
exchangeCode(code: string): Promise<DiscordOAuthTokenResponse>;
|
|
77
|
+
refreshToken(refreshToken: string): Promise<DiscordOAuthTokenResponse>;
|
|
78
|
+
getMetadataRecords(): Promise<ApplicationRoleConnectionMetadata[]>;
|
|
79
|
+
updateVerificationURL(verificationURL: string | null): Promise<LinkedRolesApplication>;
|
|
80
|
+
updateMetadataRecords(records: readonly (ApplicationRoleConnectionMetadata | JsonBuilder<ApplicationRoleConnectionMetadata>)[]): Promise<ApplicationRoleConnectionMetadata[]>;
|
|
81
|
+
getRoleConnection(accessToken: string): Promise<ApplicationRoleConnection>;
|
|
82
|
+
updateRoleConnection(accessToken: string, options: UpdateRoleConnectionOptions): Promise<ApplicationRoleConnection>;
|
|
83
|
+
deleteRoleConnection(accessToken: string): Promise<void>;
|
|
84
|
+
private requireBotAuthorization;
|
|
85
|
+
private bearerAuthorization;
|
|
86
|
+
private requestToken;
|
|
87
|
+
private request;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { type ApplicationRoleConnection, type ApplicationRoleConnectionMetadata, ApplicationRoleConnectionMetadataType, type DiscordOAuthTokenResponse, type JsonBuilder, type LinkedRolesApplication, type LinkedRolesAuthorizationOptions, LinkedRolesClient, type LinkedRolesClientOptions, RoleConnectionMetadataBuilder, type RoleConnectionMetadataValue, type RoleConnectionMetadataValues, type UpdateRoleConnectionOptions, serializeRoleConnectionMetadata };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var ApplicationRoleConnectionMetadataType = /* @__PURE__ */ ((ApplicationRoleConnectionMetadataType2) => {
|
|
3
|
+
ApplicationRoleConnectionMetadataType2[ApplicationRoleConnectionMetadataType2["IntegerLessThanOrEqual"] = 1] = "IntegerLessThanOrEqual";
|
|
4
|
+
ApplicationRoleConnectionMetadataType2[ApplicationRoleConnectionMetadataType2["IntegerGreaterThanOrEqual"] = 2] = "IntegerGreaterThanOrEqual";
|
|
5
|
+
ApplicationRoleConnectionMetadataType2[ApplicationRoleConnectionMetadataType2["IntegerEqual"] = 3] = "IntegerEqual";
|
|
6
|
+
ApplicationRoleConnectionMetadataType2[ApplicationRoleConnectionMetadataType2["IntegerNotEqual"] = 4] = "IntegerNotEqual";
|
|
7
|
+
ApplicationRoleConnectionMetadataType2[ApplicationRoleConnectionMetadataType2["DatetimeLessThanOrEqual"] = 5] = "DatetimeLessThanOrEqual";
|
|
8
|
+
ApplicationRoleConnectionMetadataType2[ApplicationRoleConnectionMetadataType2["DatetimeGreaterThanOrEqual"] = 6] = "DatetimeGreaterThanOrEqual";
|
|
9
|
+
ApplicationRoleConnectionMetadataType2[ApplicationRoleConnectionMetadataType2["BooleanEqual"] = 7] = "BooleanEqual";
|
|
10
|
+
ApplicationRoleConnectionMetadataType2[ApplicationRoleConnectionMetadataType2["BooleanNotEqual"] = 8] = "BooleanNotEqual";
|
|
11
|
+
return ApplicationRoleConnectionMetadataType2;
|
|
12
|
+
})(ApplicationRoleConnectionMetadataType || {});
|
|
13
|
+
function assertString(value, field, maxLength) {
|
|
14
|
+
if (value.trim().length === 0) throw new TypeError(`${field} must not be empty`);
|
|
15
|
+
if (value.length > maxLength) throw new RangeError(`${field} must be at most ${maxLength} characters`);
|
|
16
|
+
}
|
|
17
|
+
function jsonOf(value) {
|
|
18
|
+
return typeof value === "object" && value !== null && "toJSON" in value ? value.toJSON() : value;
|
|
19
|
+
}
|
|
20
|
+
var RoleConnectionMetadataBuilder = class {
|
|
21
|
+
#data = {};
|
|
22
|
+
#nameLocalizations = {};
|
|
23
|
+
#descriptionLocalizations = {};
|
|
24
|
+
setType(type) {
|
|
25
|
+
if (!Number.isInteger(type) || type < 1 || type > 8) throw new RangeError("type must be a valid metadata type");
|
|
26
|
+
this.#data.type = type;
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
setKey(key) {
|
|
30
|
+
if (!/^[a-z0-9_]{1,50}$/.test(key)) {
|
|
31
|
+
throw new TypeError("key must contain 1-50 lowercase letters, numbers, or underscores");
|
|
32
|
+
}
|
|
33
|
+
this.#data.key = key;
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
setName(name) {
|
|
37
|
+
assertString(name, "name", 100);
|
|
38
|
+
this.#data.name = name;
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
setNameLocalization(locale, name) {
|
|
42
|
+
assertString(locale, "locale", 20);
|
|
43
|
+
assertString(name, "name localization", 100);
|
|
44
|
+
this.#nameLocalizations[locale] = name;
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
setDescription(description) {
|
|
48
|
+
assertString(description, "description", 200);
|
|
49
|
+
this.#data.description = description;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
setDescriptionLocalization(locale, description) {
|
|
53
|
+
assertString(locale, "locale", 20);
|
|
54
|
+
assertString(description, "description localization", 200);
|
|
55
|
+
this.#descriptionLocalizations[locale] = description;
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
toJSON() {
|
|
59
|
+
if (this.#data.type === void 0) throw new TypeError("type must be set");
|
|
60
|
+
if (this.#data.key === void 0) throw new TypeError("key must be set");
|
|
61
|
+
if (this.#data.name === void 0) throw new TypeError("name must be set");
|
|
62
|
+
if (this.#data.description === void 0) throw new TypeError("description must be set");
|
|
63
|
+
return Object.freeze({
|
|
64
|
+
...this.#data,
|
|
65
|
+
...Object.keys(this.#nameLocalizations).length === 0 ? {} : { name_localizations: Object.freeze({ ...this.#nameLocalizations }) },
|
|
66
|
+
...Object.keys(this.#descriptionLocalizations).length === 0 ? {} : { description_localizations: Object.freeze({ ...this.#descriptionLocalizations }) }
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
function serializeRoleConnectionMetadata(metadata) {
|
|
71
|
+
const serialized = {};
|
|
72
|
+
for (const [key, rawValue] of Object.entries(metadata)) {
|
|
73
|
+
if (!/^[a-z0-9_]{1,50}$/.test(key)) {
|
|
74
|
+
throw new TypeError(`invalid metadata key: ${key}`);
|
|
75
|
+
}
|
|
76
|
+
let value;
|
|
77
|
+
if (rawValue instanceof Date) {
|
|
78
|
+
if (Number.isNaN(rawValue.getTime())) throw new TypeError(`${key} must be a valid date`);
|
|
79
|
+
value = rawValue.toISOString();
|
|
80
|
+
} else if (typeof rawValue === "boolean") {
|
|
81
|
+
value = rawValue ? "1" : "0";
|
|
82
|
+
} else if (typeof rawValue === "number") {
|
|
83
|
+
if (!Number.isFinite(rawValue) || !Number.isInteger(rawValue)) {
|
|
84
|
+
throw new TypeError(`${key} must be a finite integer`);
|
|
85
|
+
}
|
|
86
|
+
value = String(rawValue);
|
|
87
|
+
} else {
|
|
88
|
+
value = rawValue;
|
|
89
|
+
}
|
|
90
|
+
if (value.length > 100) throw new RangeError(`${key} must serialize to at most 100 characters`);
|
|
91
|
+
serialized[key] = value;
|
|
92
|
+
}
|
|
93
|
+
return Object.freeze(serialized);
|
|
94
|
+
}
|
|
95
|
+
var LinkedRolesClient = class {
|
|
96
|
+
#botToken;
|
|
97
|
+
#clientSecret;
|
|
98
|
+
#redirectUri;
|
|
99
|
+
#apiBaseUrl;
|
|
100
|
+
#authorizationBaseUrl;
|
|
101
|
+
#fetch;
|
|
102
|
+
applicationId;
|
|
103
|
+
constructor(options) {
|
|
104
|
+
assertString(options.applicationId, "applicationId", 32);
|
|
105
|
+
if (options.botToken !== void 0) assertString(options.botToken, "botToken", 256);
|
|
106
|
+
if (options.clientSecret !== void 0) assertString(options.clientSecret, "clientSecret", 256);
|
|
107
|
+
if (options.redirectUri !== void 0) {
|
|
108
|
+
assertString(options.redirectUri, "redirectUri", 2048);
|
|
109
|
+
new URL(options.redirectUri);
|
|
110
|
+
}
|
|
111
|
+
this.applicationId = options.applicationId;
|
|
112
|
+
this.#botToken = options.botToken;
|
|
113
|
+
this.#clientSecret = options.clientSecret;
|
|
114
|
+
this.#redirectUri = options.redirectUri;
|
|
115
|
+
this.#apiBaseUrl = (options.apiBaseUrl ?? "https://discord.com/api/v10").replace(/\/$/, "");
|
|
116
|
+
this.#authorizationBaseUrl = options.authorizationBaseUrl ?? "https://discord.com/oauth2/authorize";
|
|
117
|
+
this.#fetch = options.fetchImplementation ?? globalThis.fetch;
|
|
118
|
+
if (typeof this.#fetch !== "function") throw new TypeError("fetch implementation must be provided");
|
|
119
|
+
}
|
|
120
|
+
buildAuthorizationURL(options = {}) {
|
|
121
|
+
if (this.#redirectUri === void 0) throw new TypeError("redirectUri must be configured");
|
|
122
|
+
const url = new URL(this.#authorizationBaseUrl);
|
|
123
|
+
url.searchParams.set("client_id", this.applicationId);
|
|
124
|
+
url.searchParams.set("redirect_uri", this.#redirectUri);
|
|
125
|
+
url.searchParams.set("response_type", "code");
|
|
126
|
+
url.searchParams.set("scope", (options.scopes ?? ["identify", "role_connections.write"]).join(" "));
|
|
127
|
+
if (options.state !== void 0) {
|
|
128
|
+
assertString(options.state, "state", 1024);
|
|
129
|
+
url.searchParams.set("state", options.state);
|
|
130
|
+
}
|
|
131
|
+
if (options.prompt !== void 0) url.searchParams.set("prompt", options.prompt);
|
|
132
|
+
return url.toString();
|
|
133
|
+
}
|
|
134
|
+
async exchangeCode(code) {
|
|
135
|
+
assertString(code, "code", 2048);
|
|
136
|
+
return this.requestToken({ grant_type: "authorization_code", code });
|
|
137
|
+
}
|
|
138
|
+
async refreshToken(refreshToken) {
|
|
139
|
+
assertString(refreshToken, "refreshToken", 2048);
|
|
140
|
+
return this.requestToken({ grant_type: "refresh_token", refresh_token: refreshToken });
|
|
141
|
+
}
|
|
142
|
+
async getMetadataRecords() {
|
|
143
|
+
return this.request(
|
|
144
|
+
`/applications/${this.applicationId}/role-connections/metadata`,
|
|
145
|
+
{ method: "GET" },
|
|
146
|
+
this.requireBotAuthorization()
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
async updateVerificationURL(verificationURL) {
|
|
150
|
+
if (verificationURL !== null) {
|
|
151
|
+
assertString(verificationURL, "verificationURL", 2048);
|
|
152
|
+
new URL(verificationURL);
|
|
153
|
+
}
|
|
154
|
+
return this.request(
|
|
155
|
+
"/applications/@me",
|
|
156
|
+
{ method: "PATCH", body: JSON.stringify({ role_connections_verification_url: verificationURL }) },
|
|
157
|
+
this.requireBotAuthorization()
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
async updateMetadataRecords(records) {
|
|
161
|
+
if (records.length > 5) throw new RangeError("Discord supports at most 5 linked role metadata records");
|
|
162
|
+
const data = records.map((record) => jsonOf(record));
|
|
163
|
+
if (new Set(data.map((record) => record.key)).size !== data.length) {
|
|
164
|
+
throw new TypeError("linked role metadata keys must be unique");
|
|
165
|
+
}
|
|
166
|
+
return this.request(
|
|
167
|
+
`/applications/${this.applicationId}/role-connections/metadata`,
|
|
168
|
+
{ method: "PUT", body: JSON.stringify(data) },
|
|
169
|
+
this.requireBotAuthorization()
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
async getRoleConnection(accessToken) {
|
|
173
|
+
return this.request(
|
|
174
|
+
`/users/@me/applications/${this.applicationId}/role-connection`,
|
|
175
|
+
{ method: "GET" },
|
|
176
|
+
this.bearerAuthorization(accessToken)
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
async updateRoleConnection(accessToken, options) {
|
|
180
|
+
if (options.platformName !== void 0) assertString(options.platformName, "platformName", 50);
|
|
181
|
+
if (options.platformUsername !== void 0) assertString(options.platformUsername, "platformUsername", 100);
|
|
182
|
+
const body = {
|
|
183
|
+
...options.platformName === void 0 ? {} : { platform_name: options.platformName },
|
|
184
|
+
...options.platformUsername === void 0 ? {} : { platform_username: options.platformUsername },
|
|
185
|
+
...options.metadata === void 0 ? {} : { metadata: serializeRoleConnectionMetadata(options.metadata) }
|
|
186
|
+
};
|
|
187
|
+
return this.request(
|
|
188
|
+
`/users/@me/applications/${this.applicationId}/role-connection`,
|
|
189
|
+
{ method: "PUT", body: JSON.stringify(body) },
|
|
190
|
+
this.bearerAuthorization(accessToken)
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
async deleteRoleConnection(accessToken) {
|
|
194
|
+
await this.request(
|
|
195
|
+
`/users/@me/applications/${this.applicationId}/role-connection`,
|
|
196
|
+
{ method: "DELETE" },
|
|
197
|
+
this.bearerAuthorization(accessToken)
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
requireBotAuthorization() {
|
|
201
|
+
if (this.#botToken === void 0) throw new TypeError("botToken must be configured for metadata operations");
|
|
202
|
+
return `Bot ${this.#botToken}`;
|
|
203
|
+
}
|
|
204
|
+
bearerAuthorization(accessToken) {
|
|
205
|
+
assertString(accessToken, "accessToken", 2048);
|
|
206
|
+
return `Bearer ${accessToken}`;
|
|
207
|
+
}
|
|
208
|
+
async requestToken(parameters) {
|
|
209
|
+
if (this.#clientSecret === void 0) throw new TypeError("clientSecret must be configured");
|
|
210
|
+
if (this.#redirectUri === void 0) throw new TypeError("redirectUri must be configured");
|
|
211
|
+
const body = new URLSearchParams({
|
|
212
|
+
...parameters,
|
|
213
|
+
client_id: this.applicationId,
|
|
214
|
+
client_secret: this.#clientSecret,
|
|
215
|
+
...parameters.grant_type === "authorization_code" ? { redirect_uri: this.#redirectUri } : {}
|
|
216
|
+
});
|
|
217
|
+
return this.request("/oauth2/token", {
|
|
218
|
+
method: "POST",
|
|
219
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
220
|
+
body
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
async request(path, init, authorization) {
|
|
224
|
+
const headers = new Headers(init.headers);
|
|
225
|
+
if (authorization !== void 0) headers.set("Authorization", authorization);
|
|
226
|
+
if (init.body !== void 0 && init.body !== null && !headers.has("Content-Type")) {
|
|
227
|
+
headers.set("Content-Type", "application/json");
|
|
228
|
+
}
|
|
229
|
+
const response = await this.#fetch(`${this.#apiBaseUrl}/${path.replace(/^\//, "")}`, { ...init, headers });
|
|
230
|
+
if (!response.ok) {
|
|
231
|
+
const details = await response.text();
|
|
232
|
+
throw new Error(
|
|
233
|
+
`Discord API request failed (${response.status} ${response.statusText})${details ? `: ${details}` : ""}`
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
if (response.status === 204) return void 0;
|
|
237
|
+
return await response.json();
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export { ApplicationRoleConnectionMetadataType, LinkedRolesClient, RoleConnectionMetadataBuilder, serializeRoleConnectionMetadata };
|
|
242
|
+
//# sourceMappingURL=index.js.map
|
|
243
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["ApplicationRoleConnectionMetadataType"],"mappings":"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","file":"index.js","sourcesContent":["export enum ApplicationRoleConnectionMetadataType {\n IntegerLessThanOrEqual = 1,\n IntegerGreaterThanOrEqual = 2,\n IntegerEqual = 3,\n IntegerNotEqual = 4,\n DatetimeLessThanOrEqual = 5,\n DatetimeGreaterThanOrEqual = 6,\n BooleanEqual = 7,\n BooleanNotEqual = 8,\n}\n\nexport interface ApplicationRoleConnectionMetadata {\n type: ApplicationRoleConnectionMetadataType;\n key: string;\n name: string;\n name_localizations?: Readonly<Record<string, string>>;\n description: string;\n description_localizations?: Readonly<Record<string, string>>;\n}\n\nexport interface JsonBuilder<T> {\n toJSON(): T;\n}\n\nfunction assertString(value: string, field: string, maxLength: number): void {\n if (value.trim().length === 0) throw new TypeError(`${field} must not be empty`);\n if (value.length > maxLength) throw new RangeError(`${field} must be at most ${maxLength} characters`);\n}\n\nfunction jsonOf<T>(value: T | JsonBuilder<T>): T {\n return typeof value === \"object\" && value !== null && \"toJSON\" in value\n ? (value as JsonBuilder<T>).toJSON()\n : value;\n}\n\nexport class RoleConnectionMetadataBuilder implements JsonBuilder<ApplicationRoleConnectionMetadata> {\n readonly #data: Partial<Omit<ApplicationRoleConnectionMetadata, \"name_localizations\" | \"description_localizations\">> = {};\n readonly #nameLocalizations: Record<string, string> = {};\n readonly #descriptionLocalizations: Record<string, string> = {};\n\n public setType(type: ApplicationRoleConnectionMetadataType): this {\n if (!Number.isInteger(type) || type < 1 || type > 8) throw new RangeError(\"type must be a valid metadata type\");\n this.#data.type = type;\n return this;\n }\n\n public setKey(key: string): this {\n if (!/^[a-z0-9_]{1,50}$/.test(key)) {\n throw new TypeError(\"key must contain 1-50 lowercase letters, numbers, or underscores\");\n }\n this.#data.key = key;\n return this;\n }\n\n public setName(name: string): this {\n assertString(name, \"name\", 100);\n this.#data.name = name;\n return this;\n }\n\n public setNameLocalization(locale: string, name: string): this {\n assertString(locale, \"locale\", 20);\n assertString(name, \"name localization\", 100);\n this.#nameLocalizations[locale] = name;\n return this;\n }\n\n public setDescription(description: string): this {\n assertString(description, \"description\", 200);\n this.#data.description = description;\n return this;\n }\n\n public setDescriptionLocalization(locale: string, description: string): this {\n assertString(locale, \"locale\", 20);\n assertString(description, \"description localization\", 200);\n this.#descriptionLocalizations[locale] = description;\n return this;\n }\n\n public toJSON(): ApplicationRoleConnectionMetadata {\n if (this.#data.type === undefined) throw new TypeError(\"type must be set\");\n if (this.#data.key === undefined) throw new TypeError(\"key must be set\");\n if (this.#data.name === undefined) throw new TypeError(\"name must be set\");\n if (this.#data.description === undefined) throw new TypeError(\"description must be set\");\n return Object.freeze({\n ...this.#data,\n ...(Object.keys(this.#nameLocalizations).length === 0\n ? {}\n : { name_localizations: Object.freeze({ ...this.#nameLocalizations }) }),\n ...(Object.keys(this.#descriptionLocalizations).length === 0\n ? {}\n : { description_localizations: Object.freeze({ ...this.#descriptionLocalizations }) }),\n } as ApplicationRoleConnectionMetadata);\n }\n}\n\nexport type RoleConnectionMetadataValue = string | number | boolean | Date;\nexport type RoleConnectionMetadataValues = Readonly<Record<string, RoleConnectionMetadataValue>>;\n\nexport function serializeRoleConnectionMetadata(\n metadata: RoleConnectionMetadataValues,\n): Readonly<Record<string, string>> {\n const serialized: Record<string, string> = {};\n for (const [key, rawValue] of Object.entries(metadata)) {\n if (!/^[a-z0-9_]{1,50}$/.test(key)) {\n throw new TypeError(`invalid metadata key: ${key}`);\n }\n let value: string;\n if (rawValue instanceof Date) {\n if (Number.isNaN(rawValue.getTime())) throw new TypeError(`${key} must be a valid date`);\n value = rawValue.toISOString();\n } else if (typeof rawValue === \"boolean\") {\n value = rawValue ? \"1\" : \"0\";\n } else if (typeof rawValue === \"number\") {\n if (!Number.isFinite(rawValue) || !Number.isInteger(rawValue)) {\n throw new TypeError(`${key} must be a finite integer`);\n }\n value = String(rawValue);\n } else {\n value = rawValue;\n }\n if (value.length > 100) throw new RangeError(`${key} must serialize to at most 100 characters`);\n serialized[key] = value;\n }\n return Object.freeze(serialized);\n}\n\nexport interface ApplicationRoleConnection {\n platform_name: string | null;\n platform_username?: string | null;\n metadata: Readonly<Record<string, string>>;\n}\n\nexport interface UpdateRoleConnectionOptions {\n platformName?: string;\n platformUsername?: string;\n metadata?: RoleConnectionMetadataValues;\n}\n\nexport interface DiscordOAuthTokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token: string;\n scope: string;\n}\n\nexport interface LinkedRolesAuthorizationOptions {\n state?: string;\n scopes?: readonly string[];\n prompt?: \"consent\" | \"none\";\n}\n\nexport interface LinkedRolesClientOptions {\n applicationId: string;\n botToken?: string;\n clientSecret?: string;\n redirectUri?: string;\n apiBaseUrl?: string;\n authorizationBaseUrl?: string;\n fetchImplementation?: typeof fetch;\n}\n\nexport interface LinkedRolesApplication {\n id?: string;\n role_connections_verification_url: string | null;\n [key: string]: unknown;\n}\n\nexport class LinkedRolesClient {\n readonly #botToken: string | undefined;\n readonly #clientSecret: string | undefined;\n readonly #redirectUri: string | undefined;\n readonly #apiBaseUrl: string;\n readonly #authorizationBaseUrl: string;\n readonly #fetch: typeof fetch;\n public readonly applicationId: string;\n\n public constructor(options: LinkedRolesClientOptions) {\n assertString(options.applicationId, \"applicationId\", 32);\n if (options.botToken !== undefined) assertString(options.botToken, \"botToken\", 256);\n if (options.clientSecret !== undefined) assertString(options.clientSecret, \"clientSecret\", 256);\n if (options.redirectUri !== undefined) {\n assertString(options.redirectUri, \"redirectUri\", 2048);\n new URL(options.redirectUri);\n }\n this.applicationId = options.applicationId;\n this.#botToken = options.botToken;\n this.#clientSecret = options.clientSecret;\n this.#redirectUri = options.redirectUri;\n this.#apiBaseUrl = (options.apiBaseUrl ?? \"https://discord.com/api/v10\").replace(/\\/$/, \"\");\n this.#authorizationBaseUrl = options.authorizationBaseUrl ?? \"https://discord.com/oauth2/authorize\";\n this.#fetch = options.fetchImplementation ?? globalThis.fetch;\n if (typeof this.#fetch !== \"function\") throw new TypeError(\"fetch implementation must be provided\");\n }\n\n public buildAuthorizationURL(options: LinkedRolesAuthorizationOptions = {}): string {\n if (this.#redirectUri === undefined) throw new TypeError(\"redirectUri must be configured\");\n const url = new URL(this.#authorizationBaseUrl);\n url.searchParams.set(\"client_id\", this.applicationId);\n url.searchParams.set(\"redirect_uri\", this.#redirectUri);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"scope\", (options.scopes ?? [\"identify\", \"role_connections.write\"]).join(\" \"));\n if (options.state !== undefined) {\n assertString(options.state, \"state\", 1024);\n url.searchParams.set(\"state\", options.state);\n }\n if (options.prompt !== undefined) url.searchParams.set(\"prompt\", options.prompt);\n return url.toString();\n }\n\n public async exchangeCode(code: string): Promise<DiscordOAuthTokenResponse> {\n assertString(code, \"code\", 2048);\n return this.requestToken({ grant_type: \"authorization_code\", code });\n }\n\n public async refreshToken(refreshToken: string): Promise<DiscordOAuthTokenResponse> {\n assertString(refreshToken, \"refreshToken\", 2048);\n return this.requestToken({ grant_type: \"refresh_token\", refresh_token: refreshToken });\n }\n\n public async getMetadataRecords(): Promise<ApplicationRoleConnectionMetadata[]> {\n return this.request<ApplicationRoleConnectionMetadata[]>(\n `/applications/${this.applicationId}/role-connections/metadata`,\n { method: \"GET\" },\n this.requireBotAuthorization(),\n );\n }\n\n public async updateVerificationURL(verificationURL: string | null): Promise<LinkedRolesApplication> {\n if (verificationURL !== null) {\n assertString(verificationURL, \"verificationURL\", 2048);\n new URL(verificationURL);\n }\n return this.request<LinkedRolesApplication>(\n \"/applications/@me\",\n { method: \"PATCH\", body: JSON.stringify({ role_connections_verification_url: verificationURL }) },\n this.requireBotAuthorization(),\n );\n }\n\n public async updateMetadataRecords(\n records: readonly (ApplicationRoleConnectionMetadata | JsonBuilder<ApplicationRoleConnectionMetadata>)[],\n ): Promise<ApplicationRoleConnectionMetadata[]> {\n if (records.length > 5) throw new RangeError(\"Discord supports at most 5 linked role metadata records\");\n const data = records.map((record) => jsonOf(record));\n if (new Set(data.map((record) => record.key)).size !== data.length) {\n throw new TypeError(\"linked role metadata keys must be unique\");\n }\n return this.request<ApplicationRoleConnectionMetadata[]>(\n `/applications/${this.applicationId}/role-connections/metadata`,\n { method: \"PUT\", body: JSON.stringify(data) },\n this.requireBotAuthorization(),\n );\n }\n\n public async getRoleConnection(accessToken: string): Promise<ApplicationRoleConnection> {\n return this.request<ApplicationRoleConnection>(\n `/users/@me/applications/${this.applicationId}/role-connection`,\n { method: \"GET\" },\n this.bearerAuthorization(accessToken),\n );\n }\n\n public async updateRoleConnection(\n accessToken: string,\n options: UpdateRoleConnectionOptions,\n ): Promise<ApplicationRoleConnection> {\n if (options.platformName !== undefined) assertString(options.platformName, \"platformName\", 50);\n if (options.platformUsername !== undefined) assertString(options.platformUsername, \"platformUsername\", 100);\n const body = {\n ...(options.platformName === undefined ? {} : { platform_name: options.platformName }),\n ...(options.platformUsername === undefined ? {} : { platform_username: options.platformUsername }),\n ...(options.metadata === undefined ? {} : { metadata: serializeRoleConnectionMetadata(options.metadata) }),\n };\n return this.request<ApplicationRoleConnection>(\n `/users/@me/applications/${this.applicationId}/role-connection`,\n { method: \"PUT\", body: JSON.stringify(body) },\n this.bearerAuthorization(accessToken),\n );\n }\n\n public async deleteRoleConnection(accessToken: string): Promise<void> {\n await this.request<void>(\n `/users/@me/applications/${this.applicationId}/role-connection`,\n { method: \"DELETE\" },\n this.bearerAuthorization(accessToken),\n );\n }\n\n private requireBotAuthorization(): string {\n if (this.#botToken === undefined) throw new TypeError(\"botToken must be configured for metadata operations\");\n return `Bot ${this.#botToken}`;\n }\n\n private bearerAuthorization(accessToken: string): string {\n assertString(accessToken, \"accessToken\", 2048);\n return `Bearer ${accessToken}`;\n }\n\n private async requestToken(parameters: Record<string, string>): Promise<DiscordOAuthTokenResponse> {\n if (this.#clientSecret === undefined) throw new TypeError(\"clientSecret must be configured\");\n if (this.#redirectUri === undefined) throw new TypeError(\"redirectUri must be configured\");\n const body = new URLSearchParams({\n ...parameters,\n client_id: this.applicationId,\n client_secret: this.#clientSecret,\n ...(parameters.grant_type === \"authorization_code\" ? { redirect_uri: this.#redirectUri } : {}),\n });\n return this.request<DiscordOAuthTokenResponse>(\"/oauth2/token\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n }\n\n private async request<T>(path: string, init: RequestInit, authorization?: string): Promise<T> {\n const headers = new Headers(init.headers);\n if (authorization !== undefined) headers.set(\"Authorization\", authorization);\n if (init.body !== undefined && init.body !== null && !headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n const response = await this.#fetch(`${this.#apiBaseUrl}/${path.replace(/^\\//, \"\")}`, { ...init, headers });\n if (!response.ok) {\n const details = await response.text();\n throw new Error(\n `Discord API request failed (${response.status} ${response.statusText})${details ? `: ${details}` : \"\"}`,\n );\n }\n if (response.status === 204) return undefined as T;\n return await response.json() as T;\n }\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mini-interactions-linked-roles",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup",
|
|
18
|
+
"dev": "tsup --watch",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"clean": "rm -rf dist"
|
|
22
|
+
}
|
|
23
|
+
}
|