@dereekb/discord 13.33.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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -0
  3. package/index.cjs.default.js +1 -0
  4. package/index.cjs.js +817 -0
  5. package/index.cjs.mjs +2 -0
  6. package/index.d.ts +1 -0
  7. package/index.esm.js +789 -0
  8. package/nestjs/index.cjs.default.js +1 -0
  9. package/nestjs/index.cjs.js +1928 -0
  10. package/nestjs/index.cjs.mjs +2 -0
  11. package/nestjs/index.d.ts +1 -0
  12. package/nestjs/index.esm.js +1905 -0
  13. package/nestjs/package.json +26 -0
  14. package/nestjs/src/index.d.ts +1 -0
  15. package/nestjs/src/lib/discord/discord.api.d.ts +69 -0
  16. package/nestjs/src/lib/discord/discord.api.spec.client.d.ts +20 -0
  17. package/nestjs/src/lib/discord/discord.config.d.ts +58 -0
  18. package/nestjs/src/lib/discord/discord.module.d.ts +20 -0
  19. package/nestjs/src/lib/discord/discord.util.d.ts +28 -0
  20. package/nestjs/src/lib/discord/index.d.ts +4 -0
  21. package/nestjs/src/lib/index.d.ts +3 -0
  22. package/nestjs/src/lib/oauth/index.d.ts +3 -0
  23. package/nestjs/src/lib/oauth/oauth.api.d.ts +74 -0
  24. package/nestjs/src/lib/oauth/oauth.config.d.ts +55 -0
  25. package/nestjs/src/lib/oauth/oauth.module.d.ts +22 -0
  26. package/nestjs/src/lib/webhook/index.d.ts +6 -0
  27. package/nestjs/src/lib/webhook/webhook.discord.config.d.ts +22 -0
  28. package/nestjs/src/lib/webhook/webhook.discord.controller.d.ts +8 -0
  29. package/nestjs/src/lib/webhook/webhook.discord.d.ts +59 -0
  30. package/nestjs/src/lib/webhook/webhook.discord.module.d.ts +17 -0
  31. package/nestjs/src/lib/webhook/webhook.discord.service.d.ts +18 -0
  32. package/nestjs/src/lib/webhook/webhook.discord.verify.d.ts +46 -0
  33. package/package.json +33 -0
  34. package/src/index.d.ts +1 -0
  35. package/src/lib/discord.api.page.d.ts +108 -0
  36. package/src/lib/discord.config.d.ts +19 -0
  37. package/src/lib/discord.type.d.ts +41 -0
  38. package/src/lib/index.d.ts +4 -0
  39. package/src/lib/oauth/index.d.ts +6 -0
  40. package/src/lib/oauth/oauth.api.d.ts +130 -0
  41. package/src/lib/oauth/oauth.authorize.d.ts +93 -0
  42. package/src/lib/oauth/oauth.config.d.ts +56 -0
  43. package/src/lib/oauth/oauth.d.ts +42 -0
  44. package/src/lib/oauth/oauth.error.api.d.ts +65 -0
  45. package/src/lib/oauth/oauth.factory.d.ts +36 -0
package/index.esm.js ADDED
@@ -0,0 +1,789 @@
1
+ import { lastValue, MS_IN_SECOND } from '@dereekb/util';
2
+ import { fetchPageFactory, FetchResponseError, fetchJsonFunction, returnNullHandleFetchJsonParseErrorFunction, fetchApiFetchService } from '@dereekb/util/fetch';
3
+ import { BaseError } from 'make-error';
4
+
5
+ function _define_property$1(obj, key, value) {
6
+ if (key in obj) {
7
+ Object.defineProperty(obj, key, {
8
+ value: value,
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true
12
+ });
13
+ } else {
14
+ obj[key] = value;
15
+ }
16
+ return obj;
17
+ }
18
+ function _object_spread(target) {
19
+ for(var i = 1; i < arguments.length; i++){
20
+ var source = arguments[i] != null ? arguments[i] : {};
21
+ var ownKeys = Object.keys(source);
22
+ if (typeof Object.getOwnPropertySymbols === "function") {
23
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
24
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
25
+ }));
26
+ }
27
+ ownKeys.forEach(function(key) {
28
+ _define_property$1(target, key, source[key]);
29
+ });
30
+ }
31
+ return target;
32
+ }
33
+ function ownKeys(object, enumerableOnly) {
34
+ var keys = Object.keys(object);
35
+ if (Object.getOwnPropertySymbols) {
36
+ var symbols = Object.getOwnPropertySymbols(object);
37
+ keys.push.apply(keys, symbols);
38
+ }
39
+ return keys;
40
+ }
41
+ function _object_spread_props(target, source) {
42
+ source = source != null ? source : {};
43
+ if (Object.getOwnPropertyDescriptors) {
44
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
45
+ } else {
46
+ ownKeys(Object(source)).forEach(function(key) {
47
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
48
+ });
49
+ }
50
+ return target;
51
+ }
52
+ /**
53
+ * Default number of messages per page when fetching Discord channel messages.
54
+ */ var DEFAULT_DISCORD_MESSAGES_PER_PAGE = 100;
55
+ /**
56
+ * Creates a page factory that wraps a Discord message fetch function with automatic cursor-based pagination.
57
+ *
58
+ * Discord paginates via `before`/`after` snowflake IDs. This factory automatically reads the last
59
+ * message's ID from each response and sets it as the `before` cursor for the next request.
60
+ * When the number of returned messages is less than the requested limit, pagination stops.
61
+ *
62
+ * @param input - The factory input configuration.
63
+ * @returns A page factory that produces iterable page fetchers.
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * const pageFactory = discordFetchMessagePageFactory({ fetch: fetchChannelMessages });
68
+ *
69
+ * const fetchPage = pageFactory({ limit: 50 });
70
+ * const firstPage = await fetchPage.fetchNext();
71
+ *
72
+ * if (firstPage.hasNext) {
73
+ * const secondPage = await firstPage.fetchNext();
74
+ * }
75
+ * ```
76
+ */ function discordFetchMessagePageFactory(input) {
77
+ var _ref;
78
+ var fetch = input.fetch, config = input.config, defaults = input.defaults;
79
+ var readMessageId = (_ref = config === null || config === void 0 ? void 0 : config.readMessageId) !== null && _ref !== void 0 ? _ref : function(message) {
80
+ return message.id;
81
+ };
82
+ return fetchPageFactory(_object_spread_props(_object_spread({}, defaults), {
83
+ fetch: fetch,
84
+ readFetchPageResultInfo: function readFetchPageResultInfo(result) {
85
+ var count = result.data.length;
86
+ var nextCursor = count > 0 ? readMessageId(lastValue(result.data)) : undefined;
87
+ return {
88
+ hasNext: count > 0,
89
+ nextPageCursor: nextCursor
90
+ };
91
+ },
92
+ buildInputForNextPage: function buildInputForNextPage(pageResult, input, options) {
93
+ var _ref, _options_maxItemsPerPage, _ref1;
94
+ var _pageResult_result;
95
+ var nextCursor = pageResult.nextPageCursor;
96
+ var effectiveLimit = (_ref = (_options_maxItemsPerPage = options.maxItemsPerPage) !== null && _options_maxItemsPerPage !== void 0 ? _options_maxItemsPerPage : input.limit) !== null && _ref !== void 0 ? _ref : DEFAULT_DISCORD_MESSAGES_PER_PAGE;
97
+ var resultCount = (_ref1 = (_pageResult_result = pageResult.result) === null || _pageResult_result === void 0 ? void 0 : _pageResult_result.data.length) !== null && _ref1 !== void 0 ? _ref1 : 0;
98
+ var nextInput;
99
+ // Discord signals no more results when fewer items than the limit are returned
100
+ if (!nextCursor || resultCount < effectiveLimit) {
101
+ nextInput = undefined;
102
+ } else {
103
+ nextInput = _object_spread_props(_object_spread({}, input), {
104
+ before: nextCursor,
105
+ after: undefined,
106
+ around: undefined,
107
+ limit: effectiveLimit
108
+ });
109
+ }
110
+ return nextInput;
111
+ }
112
+ }));
113
+ }
114
+
115
+ /**
116
+ * The Discord REST API base, pinned to a version.
117
+ *
118
+ * Endpoint paths are appended to this base, so it intentionally carries no endpoint segment of its
119
+ * own. Discord requires an explicit version in the path; an unversioned base resolves to the oldest
120
+ * still-supported version.
121
+ */ var DISCORD_API_URL = 'https://discord.com/api/v10';
122
+
123
+ /**
124
+ * Maps a {@link DiscordOAuthTokenResponse} to a {@link DiscordAccessToken}.
125
+ *
126
+ * @param response - The token response returned by the Discord token endpoint.
127
+ * @returns The equivalent DiscordAccessToken, with `expiresAt` resolved against the current time.
128
+ *
129
+ * @__NO_SIDE_EFFECTS__
130
+ */ function discordAccessTokenFromTokenResponse(response) {
131
+ var createdAt = Date.now();
132
+ var access_token = response.access_token, refresh_token = response.refresh_token, scope = response.scope, expires_in = response.expires_in;
133
+ var accessToken = {
134
+ accessToken: access_token,
135
+ refreshToken: refresh_token,
136
+ expiresIn: expires_in,
137
+ expiresAt: new Date(createdAt + expires_in * MS_IN_SECOND),
138
+ scope: scope !== null && scope !== void 0 ? scope : ''
139
+ };
140
+ return accessToken;
141
+ }
142
+
143
+ /**
144
+ * The Discord OAuth2 authorize URL the user's browser is redirected to.
145
+ *
146
+ * Note this is NOT under `/api`: Discord serves the consent screen from the site root, while the
147
+ * token endpoint lives under {@link DISCORD_API_URL}. It is therefore a full URL rather than a path
148
+ * relative to the API base.
149
+ */ var DISCORD_OAUTH_AUTHORIZE_URL = 'https://discord.com/oauth2/authorize';
150
+ /**
151
+ * The Discord OAuth2 token endpoint path, relative to {@link DISCORD_API_URL}.
152
+ */ var DISCORD_OAUTH_TOKEN_PATH = '/oauth2/token';
153
+ /**
154
+ * The Discord OAuth2 token revocation endpoint path, relative to {@link DISCORD_API_URL}.
155
+ */ var DISCORD_OAUTH_REVOKE_PATH = '/oauth2/token/revoke';
156
+ /**
157
+ * Path of the endpoint returning the user an access token belongs to.
158
+ *
159
+ * Requires the `identify` scope.
160
+ */ var DISCORD_OAUTH_CURRENT_USER_PATH = '/users/@me';
161
+
162
+ /**
163
+ * The `Content-Type` Discord's token endpoint requires.
164
+ *
165
+ * Discord rejects a JSON body outright, unlike Cal.com, which requires one.
166
+ *
167
+ * `@dereekb/util/oidc`'s `postTokenEndpoint` is the in-workspace precedent for this form-encoded
168
+ * shape and is deliberately NOT reused: its `exchangeAuthorizationCode` requires a PKCE
169
+ * `code_verifier`, it authenticates with `client_secret_post` rather than Basic, and it is
170
+ * discovery-driven. Discord is not an OIDC provider — there is no discovery document and no
171
+ * `id_token`.
172
+ */ var DISCORD_OAUTH_TOKEN_CONTENT_TYPE = 'application/x-www-form-urlencoded';
173
+ /**
174
+ * Builds the HTTP Basic `Authorization` header value that authenticates the OAuth client.
175
+ *
176
+ * Discord accepts the client credentials as Basic auth rather than in the request body, which is why
177
+ * `client_id` / `client_secret` are absent from the exchange body below.
178
+ *
179
+ * Uses `btoa()` rather than `Buffer`, so this package stays usable outside Node — the same choice
180
+ * `@dereekb/util`'s PKCE helpers make.
181
+ *
182
+ * @param config - The client credentials to encode.
183
+ * @returns The `Authorization` header value, including the `Basic ` prefix.
184
+ *
185
+ * @__NO_SIDE_EFFECTS__
186
+ */ function discordOAuthBasicAuthorizationHeader(config) {
187
+ var credentials = "".concat(config.clientId, ":").concat(config.clientSecret);
188
+ return "Basic ".concat(btoa(credentials));
189
+ }
190
+ /**
191
+ * Exchanges an OAuth authorization code for access and refresh tokens.
192
+ *
193
+ * Discord requires `application/x-www-form-urlencoded` — a JSON body is rejected — and authenticates
194
+ * the client with HTTP Basic rather than credentials in the body. Both differ from Cal.com, which
195
+ * posts JSON with the credentials inline. The Basic header rides on the context's configured fetch.
196
+ *
197
+ * @param context - The Discord OAuth context providing the authenticated fetch.
198
+ * @returns Exchanges an authorization code for access and refresh tokens.
199
+ *
200
+ * @see https://docs.discord.com/developers/topics/oauth2
201
+ *
202
+ * @example
203
+ * ```ts
204
+ * const response = await exchangeAuthorizationCode(context)({
205
+ * code: 'auth-code-from-redirect',
206
+ * redirectUri: 'http://localhost:9901/oauth/discord/callback'
207
+ * });
208
+ * ```
209
+ */ function exchangeAuthorizationCode(context) {
210
+ return function(input) {
211
+ var body = new URLSearchParams({
212
+ grant_type: 'authorization_code',
213
+ code: input.code,
214
+ redirect_uri: input.redirectUri
215
+ });
216
+ var fetchJsonInput = {
217
+ method: 'POST',
218
+ body: body.toString()
219
+ };
220
+ return context.fetchJson(DISCORD_OAUTH_TOKEN_PATH, fetchJsonInput);
221
+ };
222
+ }
223
+ /**
224
+ * Refreshes an access token.
225
+ *
226
+ * Discord's refresh response carries a `refresh_token` of its own, so persist whatever comes back
227
+ * rather than assuming the sent one stays valid. That is correct for rotating and non-rotating
228
+ * providers alike.
229
+ *
230
+ * Reached through `DiscordUserExternalConnectionOAuthService.refreshCredentials`, which the external
231
+ * connection reader dispatches to when a user's stored Discord credentials are near expiration.
232
+ *
233
+ * @param context - The Discord OAuth context providing the authenticated fetch.
234
+ * @returns Refreshes an access token using the given refresh token.
235
+ *
236
+ * @see https://docs.discord.com/developers/topics/oauth2
237
+ */ function refreshAccessToken(context) {
238
+ return function(input) {
239
+ var body = new URLSearchParams({
240
+ grant_type: 'refresh_token',
241
+ refresh_token: input.refreshToken
242
+ });
243
+ var fetchJsonInput = {
244
+ method: 'POST',
245
+ body: body.toString()
246
+ };
247
+ return context.fetchJson(DISCORD_OAUTH_TOKEN_PATH, fetchJsonInput);
248
+ };
249
+ }
250
+ /**
251
+ * Reads the user an access token belongs to. Requires the `identify` scope.
252
+ *
253
+ * Bearer-authenticated with the USER's token, not Basic-authenticated with the client credentials, so
254
+ * the `Authorization` header is passed per-request to override the one on the context's fetch. A
255
+ * per-request header wins over the base header of the same name, which is what makes one configured
256
+ * fetch enough for both shapes.
257
+ *
258
+ * @param context - The Discord OAuth context providing the authenticated fetch.
259
+ * @returns Reads the Discord user the given access token belongs to.
260
+ *
261
+ * @see https://docs.discord.com/developers/resources/user
262
+ */ function readCurrentUser(context) {
263
+ return function(input) {
264
+ var fetchJsonInput = {
265
+ method: 'GET',
266
+ headers: {
267
+ Authorization: "Bearer ".concat(input.accessToken)
268
+ }
269
+ };
270
+ return context.fetchJson(DISCORD_OAUTH_CURRENT_USER_PATH, fetchJsonInput);
271
+ };
272
+ }
273
+
274
+ /**
275
+ * The Discord OAuth scopes this package models.
276
+ *
277
+ * A runtime list rather than a bare type union, so a configured scope can be validated instead of
278
+ * being passed through to the consent screen and refused there.
279
+ *
280
+ * Deliberately NOT Discord's full ~40-scope surface: only what a per-user account connect can
281
+ * legitimately ask for. Add a scope here when code actually uses it.
282
+ *
283
+ * @see https://docs.discord.com/developers/topics/oauth2
284
+ */ var ALL_DISCORD_OAUTH_SCOPES = [
285
+ 'identify',
286
+ 'email',
287
+ 'guilds',
288
+ 'connections'
289
+ ];
290
+ /**
291
+ * Returns whether the input is a known {@link DiscordOAuthScope}.
292
+ *
293
+ * @param value - The value to check.
294
+ * @returns True when the value is a Discord OAuth scope this package models.
295
+ */ function isDiscordOAuthScope(value) {
296
+ return ALL_DISCORD_OAUTH_SCOPES.includes(value);
297
+ }
298
+ /**
299
+ * The delimiter used to join scopes in the `scope` query parameter.
300
+ *
301
+ * OAuth2 specifies a space-delimited list and Discord follows it. `URL.searchParams.set` handles the
302
+ * percent-encoding, so this stays a literal space.
303
+ */ var DISCORD_OAUTH_SCOPE_DELIMITER = ' ';
304
+ /**
305
+ * The `response_type` used by the authorization-code flow.
306
+ */ var DISCORD_OAUTH_AUTHORIZE_RESPONSE_TYPE = 'code';
307
+ /**
308
+ * Creates a {@link DiscordOAuthAuthorizeUrlFactory} that composes the Discord authorize URL a user's
309
+ * browser is redirected to in order to begin the authorization-code flow.
310
+ *
311
+ * The client id, redirect URI, and scopes are fixed by the config, since a consumer holds those
312
+ * constant and varies only the per-request `state`.
313
+ *
314
+ * @param config - The client id, redirect URI, and scopes to request.
315
+ * @returns A factory that builds an authorize URL for the given params.
316
+ *
317
+ * @see https://docs.discord.com/developers/topics/oauth2
318
+ *
319
+ * @example
320
+ * ```ts
321
+ * const authorizeUrlFactory = discordOAuthAuthorizeUrlFactory({
322
+ * clientId: 'client-id',
323
+ * redirectUri: 'http://localhost:9901/oauth/discord/callback',
324
+ * scopes: ['identify']
325
+ * });
326
+ *
327
+ * const url = authorizeUrlFactory({ state: 'signed-state' });
328
+ * ```
329
+ *
330
+ * @__NO_SIDE_EFFECTS__
331
+ */ function discordOAuthAuthorizeUrlFactory(config) {
332
+ var clientId = config.clientId, redirectUri = config.redirectUri, scopes = config.scopes, inputAuthorizeUrl = config.authorizeUrl;
333
+ var authorizeUrl = inputAuthorizeUrl !== null && inputAuthorizeUrl !== void 0 ? inputAuthorizeUrl : DISCORD_OAUTH_AUTHORIZE_URL;
334
+ var scope = scopes.join(DISCORD_OAUTH_SCOPE_DELIMITER);
335
+ return function(params) {
336
+ var url = new URL(authorizeUrl);
337
+ var state = params === null || params === void 0 ? void 0 : params.state;
338
+ url.searchParams.set('client_id', clientId);
339
+ url.searchParams.set('redirect_uri', redirectUri);
340
+ url.searchParams.set('response_type', DISCORD_OAUTH_AUTHORIZE_RESPONSE_TYPE);
341
+ url.searchParams.set('scope', scope);
342
+ if (state != null) {
343
+ url.searchParams.set('state', state);
344
+ }
345
+ return url.toString();
346
+ };
347
+ }
348
+
349
+ function _assert_this_initialized(self) {
350
+ if (self === void 0) {
351
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
352
+ }
353
+ return self;
354
+ }
355
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
356
+ try {
357
+ var info = gen[key](arg);
358
+ var value = info.value;
359
+ } catch (error) {
360
+ reject(error);
361
+ return;
362
+ }
363
+ if (info.done) {
364
+ resolve(value);
365
+ } else {
366
+ Promise.resolve(value).then(_next, _throw);
367
+ }
368
+ }
369
+ function _async_to_generator(fn) {
370
+ return function() {
371
+ var self = this, args = arguments;
372
+ return new Promise(function(resolve, reject) {
373
+ var gen = fn.apply(self, args);
374
+ function _next(value) {
375
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
376
+ }
377
+ function _throw(err) {
378
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
379
+ }
380
+ _next(undefined);
381
+ });
382
+ };
383
+ }
384
+ function _call_super(_this, derived, args) {
385
+ derived = _get_prototype_of(derived);
386
+ return _possible_constructor_return(_this, _is_native_reflect_construct() ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) : derived.apply(_this, args));
387
+ }
388
+ function _class_call_check(instance, Constructor) {
389
+ if (!(instance instanceof Constructor)) {
390
+ throw new TypeError("Cannot call a class as a function");
391
+ }
392
+ }
393
+ function _defineProperties(target, props) {
394
+ for(var i = 0; i < props.length; i++){
395
+ var descriptor = props[i];
396
+ descriptor.enumerable = descriptor.enumerable || false;
397
+ descriptor.configurable = true;
398
+ if ("value" in descriptor) descriptor.writable = true;
399
+ Object.defineProperty(target, descriptor.key, descriptor);
400
+ }
401
+ }
402
+ function _create_class(Constructor, protoProps, staticProps) {
403
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
404
+ return Constructor;
405
+ }
406
+ function _define_property(obj, key, value) {
407
+ if (key in obj) {
408
+ Object.defineProperty(obj, key, {
409
+ value: value,
410
+ enumerable: true,
411
+ configurable: true,
412
+ writable: true
413
+ });
414
+ } else {
415
+ obj[key] = value;
416
+ }
417
+ return obj;
418
+ }
419
+ function _get_prototype_of(o) {
420
+ _get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
421
+ return o.__proto__ || Object.getPrototypeOf(o);
422
+ };
423
+ return _get_prototype_of(o);
424
+ }
425
+ function _inherits(subClass, superClass) {
426
+ if (typeof superClass !== "function" && superClass !== null) {
427
+ throw new TypeError("Super expression must either be null or a function");
428
+ }
429
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
430
+ constructor: {
431
+ value: subClass,
432
+ writable: true,
433
+ configurable: true
434
+ }
435
+ });
436
+ if (superClass) _set_prototype_of(subClass, superClass);
437
+ }
438
+ function _instanceof(left, right) {
439
+ "@swc/helpers - instanceof";
440
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
441
+ return !!right[Symbol.hasInstance](left);
442
+ } else {
443
+ return left instanceof right;
444
+ }
445
+ }
446
+ function _possible_constructor_return(self, call) {
447
+ if (call && (_type_of(call) === "object" || typeof call === "function")) {
448
+ return call;
449
+ }
450
+ return _assert_this_initialized(self);
451
+ }
452
+ function _set_prototype_of(o, p) {
453
+ _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
454
+ o.__proto__ = p;
455
+ return o;
456
+ };
457
+ return _set_prototype_of(o, p);
458
+ }
459
+ function _type_of(obj) {
460
+ "@swc/helpers - typeof";
461
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
462
+ }
463
+ function _is_native_reflect_construct() {
464
+ try {
465
+ var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
466
+ } catch (_) {}
467
+ return (_is_native_reflect_construct = function() {
468
+ return !!result;
469
+ })();
470
+ }
471
+ function _ts_generator(thisArg, body) {
472
+ var f, y, t, _ = {
473
+ label: 0,
474
+ sent: function() {
475
+ if (t[0] & 1) throw t[1];
476
+ return t[1];
477
+ },
478
+ trys: [],
479
+ ops: []
480
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
481
+ return d(g, "next", {
482
+ value: verb(0)
483
+ }), d(g, "throw", {
484
+ value: verb(1)
485
+ }), d(g, "return", {
486
+ value: verb(2)
487
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
488
+ value: function() {
489
+ return this;
490
+ }
491
+ }), g;
492
+ function verb(n) {
493
+ return function(v) {
494
+ return step([
495
+ n,
496
+ v
497
+ ]);
498
+ };
499
+ }
500
+ function step(op) {
501
+ if (f) throw new TypeError("Generator is already executing.");
502
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
503
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
504
+ if (y = 0, t) op = [
505
+ op[0] & 2,
506
+ t.value
507
+ ];
508
+ switch(op[0]){
509
+ case 0:
510
+ case 1:
511
+ t = op;
512
+ break;
513
+ case 4:
514
+ _.label++;
515
+ return {
516
+ value: op[1],
517
+ done: false
518
+ };
519
+ case 5:
520
+ _.label++;
521
+ y = op[1];
522
+ op = [
523
+ 0
524
+ ];
525
+ continue;
526
+ case 7:
527
+ op = _.ops.pop();
528
+ _.trys.pop();
529
+ continue;
530
+ default:
531
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
532
+ _ = 0;
533
+ continue;
534
+ }
535
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
536
+ _.label = op[1];
537
+ break;
538
+ }
539
+ if (op[0] === 6 && _.label < t[1]) {
540
+ _.label = t[1];
541
+ t = op;
542
+ break;
543
+ }
544
+ if (t && _.label < t[2]) {
545
+ _.label = t[2];
546
+ _.ops.push(op);
547
+ break;
548
+ }
549
+ if (t[2]) _.ops.pop();
550
+ _.trys.pop();
551
+ continue;
552
+ }
553
+ op = body.call(thisArg, _);
554
+ } catch (e) {
555
+ op = [
556
+ 6,
557
+ e
558
+ ];
559
+ y = 0;
560
+ } finally{
561
+ f = t = 0;
562
+ }
563
+ if (op[0] & 5) throw op[1];
564
+ return {
565
+ value: op[0] ? op[1] : void 0,
566
+ done: true
567
+ };
568
+ }
569
+ }
570
+ /**
571
+ * Error code returned when a code or refresh token is invalid, expired, or was already spent.
572
+ */ var DISCORD_OAUTH_INVALID_GRANT_ERROR_CODE = 'invalid_grant';
573
+ /**
574
+ * Error code returned when the requested scope set is not one the application may ask for.
575
+ */ var DISCORD_OAUTH_INVALID_SCOPE_ERROR_CODE = 'invalid_scope';
576
+ /**
577
+ * An error reported by a Discord OAuth endpoint.
578
+ */ var DiscordOAuthError = /*#__PURE__*/ function(BaseError) {
579
+ _inherits(DiscordOAuthError, BaseError);
580
+ function DiscordOAuthError(error) {
581
+ _class_call_check(this, DiscordOAuthError);
582
+ var _this;
583
+ _this = _call_super(this, DiscordOAuthError, [
584
+ error.error_description ? "".concat(error.error, ": ").concat(error.error_description) : error.error
585
+ ]), _define_property(_this, "error", void 0);
586
+ _this.error = error;
587
+ return _this;
588
+ }
589
+ _create_class(DiscordOAuthError, [
590
+ {
591
+ key: "code",
592
+ get: function get() {
593
+ return this.error.error;
594
+ }
595
+ }
596
+ ]);
597
+ return DiscordOAuthError;
598
+ }(BaseError);
599
+ /**
600
+ * A {@link DiscordOAuthError} that retains the HTTP response it was parsed from.
601
+ */ var DiscordOAuthFetchResponseError = /*#__PURE__*/ function(DiscordOAuthError) {
602
+ _inherits(DiscordOAuthFetchResponseError, DiscordOAuthError);
603
+ function DiscordOAuthFetchResponseError(data, responseError) {
604
+ _class_call_check(this, DiscordOAuthFetchResponseError);
605
+ var _this;
606
+ _this = _call_super(this, DiscordOAuthFetchResponseError, [
607
+ data
608
+ ]), _define_property(_this, "data", void 0), _define_property(_this, "responseError", void 0);
609
+ _this.data = data;
610
+ _this.responseError = responseError;
611
+ return _this;
612
+ }
613
+ return DiscordOAuthFetchResponseError;
614
+ }(DiscordOAuthError);
615
+ /**
616
+ * Creates a {@link LogDiscordOAuthErrorFunction} that logs the error to the console.
617
+ *
618
+ * @param discordApiNamePrefix - Prefix to use when logging, e.g. `DiscordOAuth`.
619
+ * @returns A log function that prefixes each logged error.
620
+ *
621
+ * @__NO_SIDE_EFFECTS__
622
+ */ function logDiscordOAuthErrorFunction(discordApiNamePrefix) {
623
+ return function(error) {
624
+ if (_instanceof(error, DiscordOAuthFetchResponseError)) {
625
+ console.log("".concat(discordApiNamePrefix, "Error(").concat(error.responseError.response.status, "): "), {
626
+ error: error,
627
+ errorData: error.data
628
+ });
629
+ } else if (_instanceof(error, DiscordOAuthError)) {
630
+ console.log("".concat(discordApiNamePrefix, "Error(code:").concat(error.code, "): "), {
631
+ error: error
632
+ });
633
+ } else {
634
+ console.log("".concat(discordApiNamePrefix, "Error(name:").concat(error.name, "): "), {
635
+ error: error
636
+ });
637
+ }
638
+ };
639
+ }
640
+ var logDiscordOAuthErrorToConsole = logDiscordOAuthErrorFunction('DiscordOAuth');
641
+ /**
642
+ * Parses a {@link FetchResponseError} from a Discord OAuth call into a typed error.
643
+ *
644
+ * @param responseError - The fetch response error to parse.
645
+ * @returns The parsed error, or undefined when the body carried no OAuth error to parse.
646
+ */ function parseDiscordOAuthError(responseError) {
647
+ return _async_to_generator(function() {
648
+ var data, result;
649
+ return _ts_generator(this, function(_state) {
650
+ switch(_state.label){
651
+ case 0:
652
+ return [
653
+ 4,
654
+ responseError.response.clone().json().catch(function() {
655
+ return undefined;
656
+ })
657
+ ];
658
+ case 1:
659
+ data = _state.sent();
660
+ if (data === null || data === void 0 ? void 0 : data.error) {
661
+ result = new DiscordOAuthFetchResponseError(data, responseError);
662
+ }
663
+ return [
664
+ 2,
665
+ result
666
+ ];
667
+ }
668
+ });
669
+ })();
670
+ }
671
+ /**
672
+ * Wraps a {@link ConfiguredFetch} so that Discord OAuth error responses surface as typed errors.
673
+ *
674
+ * @param fetch - The fetch to wrap.
675
+ * @param logError - Optional override of the error logging function.
676
+ * @returns The wrapped fetch.
677
+ *
678
+ * @__NO_SIDE_EFFECTS__
679
+ */ function handleDiscordOAuthErrorFetch(fetch) {
680
+ var logError = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : logDiscordOAuthErrorToConsole;
681
+ return function(x, y) {
682
+ return _async_to_generator(function() {
683
+ var e, error;
684
+ return _ts_generator(this, function(_state) {
685
+ switch(_state.label){
686
+ case 0:
687
+ _state.trys.push([
688
+ 0,
689
+ 2,
690
+ ,
691
+ 5
692
+ ]);
693
+ return [
694
+ 4,
695
+ fetch(x, y)
696
+ ];
697
+ case 1:
698
+ return [
699
+ 2,
700
+ _state.sent()
701
+ ]; // await to catch thrown errors
702
+ case 2:
703
+ e = _state.sent();
704
+ if (!_instanceof(e, FetchResponseError)) return [
705
+ 3,
706
+ 4
707
+ ];
708
+ return [
709
+ 4,
710
+ parseDiscordOAuthError(e)
711
+ ];
712
+ case 3:
713
+ error = _state.sent();
714
+ if (error) {
715
+ logError(error); // log before throwing
716
+ throw error;
717
+ }
718
+ _state.label = 4;
719
+ case 4:
720
+ throw e;
721
+ case 5:
722
+ return [
723
+ 2
724
+ ];
725
+ }
726
+ });
727
+ })();
728
+ };
729
+ }
730
+
731
+ /**
732
+ * Creates a {@link DiscordOAuthFactory} that produces configured Discord OAuth instances.
733
+ *
734
+ * There is no access-token cache or per-user token factory here, unlike `calcomOAuthFactory`: the
735
+ * external-connection framework stores each user's credentials itself, so the client only ever needs
736
+ * to make the calls it is asked to make.
737
+ *
738
+ * @param factoryConfig - Configuration including an optional fetch factory, fetch handler, and error logging.
739
+ * @returns A factory accepting a DiscordOAuthConfig and producing a DiscordOAuth instance.
740
+ *
741
+ * @__NO_SIDE_EFFECTS__
742
+ */ function discordOAuthFactory(factoryConfig) {
743
+ var fetchHandler = factoryConfig.fetchHandler, logDiscordOAuthErrorFunction = factoryConfig.logDiscordOAuthErrorFunction;
744
+ var _factoryConfig_fetchFactory = factoryConfig.fetchFactory, fetchFactory = _factoryConfig_fetchFactory === void 0 ? function(input) {
745
+ return fetchApiFetchService.makeFetch({
746
+ baseUrl: DISCORD_API_URL,
747
+ baseRequest: {
748
+ headers: {
749
+ // the token endpoint's shape, since it is the only endpoint that posts a body. A
750
+ // per-request header of the same name wins, which is how readCurrentUser swaps the
751
+ // client's Basic credentials for the user's Bearer token.
752
+ 'Content-Type': DISCORD_OAUTH_TOKEN_CONTENT_TYPE,
753
+ Authorization: discordOAuthBasicAuthorizationHeader(input.config)
754
+ }
755
+ },
756
+ fetchHandler: fetchHandler !== null && fetchHandler !== void 0 ? fetchHandler : undefined,
757
+ timeout: 20 * 1000,
758
+ requireOkResponse: true,
759
+ useTimeout: true // use timeout
760
+ });
761
+ } : _factoryConfig_fetchFactory;
762
+ return function(config) {
763
+ // a missing credential otherwise composes `client_id=undefined` on the authorize URL and fails at
764
+ // the consent screen rather than at startup
765
+ if (!config.clientId) {
766
+ throw new Error('DiscordOAuthConfig missing clientId.');
767
+ } else if (!config.clientSecret) {
768
+ throw new Error('DiscordOAuthConfig missing clientSecret.');
769
+ }
770
+ var baseFetch = fetchFactory({
771
+ config: config
772
+ });
773
+ var fetch = handleDiscordOAuthErrorFetch(baseFetch, logDiscordOAuthErrorFunction);
774
+ var fetchJson = fetchJsonFunction(fetch, {
775
+ handleFetchJsonParseErrorFunction: returnNullHandleFetchJsonParseErrorFunction
776
+ });
777
+ var oauthContext = {
778
+ fetch: fetch,
779
+ fetchJson: fetchJson,
780
+ config: config
781
+ };
782
+ var discordOAuth = {
783
+ oauthContext: oauthContext
784
+ };
785
+ return discordOAuth;
786
+ };
787
+ }
788
+
789
+ export { ALL_DISCORD_OAUTH_SCOPES, DEFAULT_DISCORD_MESSAGES_PER_PAGE, DISCORD_API_URL, DISCORD_OAUTH_AUTHORIZE_RESPONSE_TYPE, DISCORD_OAUTH_AUTHORIZE_URL, DISCORD_OAUTH_CURRENT_USER_PATH, DISCORD_OAUTH_INVALID_GRANT_ERROR_CODE, DISCORD_OAUTH_INVALID_SCOPE_ERROR_CODE, DISCORD_OAUTH_REVOKE_PATH, DISCORD_OAUTH_SCOPE_DELIMITER, DISCORD_OAUTH_TOKEN_CONTENT_TYPE, DISCORD_OAUTH_TOKEN_PATH, DiscordOAuthError, DiscordOAuthFetchResponseError, discordAccessTokenFromTokenResponse, discordFetchMessagePageFactory, discordOAuthAuthorizeUrlFactory, discordOAuthBasicAuthorizationHeader, discordOAuthFactory, exchangeAuthorizationCode, handleDiscordOAuthErrorFetch, isDiscordOAuthScope, logDiscordOAuthErrorFunction, logDiscordOAuthErrorToConsole, parseDiscordOAuthError, readCurrentUser, refreshAccessToken };