@logto/connector-discord 1.4.1 → 1.6.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/lib/index.js CHANGED
@@ -50,11 +50,11 @@ var defaultMetadata = {
50
50
  },
51
51
  {
52
52
  key: "scope",
53
- type: ConnectorConfigFormItemType.Text,
53
+ type: ConnectorConfigFormItemType.MultilineText,
54
54
  required: false,
55
55
  label: "Scope",
56
- placeholder: "<scope>",
57
- description: "The `scope` determines permissions granted by the user's authorization. If you are not sure what to enter, do not worry, just leave it blank."
56
+ placeholder: "Enter the scopes (separated by a space)",
57
+ description: "The `scope` determines permissions granted by the user's authorization. "
58
58
  }
59
59
  ]
60
60
  };
@@ -93,14 +93,14 @@ var authorizationCallbackErrorGuard = z.object({
93
93
  var authResponseGuard = z.object({ code: z.string(), redirectUri: z.string() });
94
94
 
95
95
  // src/index.ts
96
- var getAuthorizationUri = (getConfig) => async ({ state, redirectUri }) => {
96
+ var getAuthorizationUri = (getConfig) => async ({ state, redirectUri, scope: scope2 }) => {
97
97
  const config = await getConfig(defaultMetadata.id);
98
98
  validateConfig(config, discordConfigGuard);
99
99
  const queryParameters = new URLSearchParams({
100
100
  client_id: config.clientId,
101
101
  redirect_uri: redirectUri,
102
102
  response_type: "code",
103
- scope: config.scope ?? scope,
103
+ scope: scope2 ?? config.scope ?? scope,
104
104
  state
105
105
  });
106
106
  return `${authorizationEndpoint}?${queryParameters.toString()}`;
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/constant.ts","../src/types.ts"],"sourcesContent":["/**\n * Discord OAuth2 Connector\n * https://discord.com/developers/docs/topics/oauth2\n */\n\nimport { assert, conditional } from '@silverhand/essentials';\nimport { got, HTTPError } from 'got';\n\nimport type {\n GetConnectorConfig,\n GetAuthorizationUri,\n GetUserInfo,\n CreateConnector,\n SocialConnector,\n} from '@logto/connector-kit';\nimport {\n socialUserInfoGuard,\n validateConfig,\n ConnectorError,\n ConnectorErrorCodes,\n ConnectorType,\n parseJson,\n} from '@logto/connector-kit';\n\nimport {\n defaultMetadata,\n scope as defaultScope,\n authorizationEndpoint,\n accessTokenEndpoint,\n defaultTimeout,\n userInfoEndpoint,\n} from './constant.js';\nimport type { DiscordConfig } from './types.js';\nimport {\n discordConfigGuard,\n authResponseGuard,\n accessTokenResponseGuard,\n userInfoResponseGuard,\n} from './types.js';\n\nconst getAuthorizationUri =\n (getConfig: GetConnectorConfig): GetAuthorizationUri =>\n async ({ state, redirectUri }) => {\n const config = await getConfig(defaultMetadata.id);\n validateConfig(config, discordConfigGuard);\n\n const queryParameters = new URLSearchParams({\n client_id: config.clientId,\n redirect_uri: redirectUri,\n response_type: 'code',\n scope: config.scope ?? defaultScope,\n state,\n });\n\n return `${authorizationEndpoint}?${queryParameters.toString()}`;\n };\n\nexport const getAccessToken = async (\n config: DiscordConfig,\n codeObject: { code: string; redirectUri: string }\n) => {\n const { code, redirectUri } = codeObject;\n\n const { clientId: client_id, clientSecret: client_secret } = config;\n\n const httpResponse = await got.post(accessTokenEndpoint, {\n form: {\n client_id,\n client_secret,\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n },\n timeout: { request: defaultTimeout },\n });\n\n const result = accessTokenResponseGuard.safeParse(parseJson(httpResponse.body));\n\n if (!result.success) {\n throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, result.error);\n }\n\n const { access_token: accessToken } = result.data;\n\n assert(accessToken, new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid));\n\n return { accessToken };\n};\n\nconst getUserInfo =\n (getConfig: GetConnectorConfig): GetUserInfo =>\n async (data) => {\n const { code, redirectUri } = await authorizationCallbackHandler(data);\n const config = await getConfig(defaultMetadata.id);\n validateConfig(config, discordConfigGuard);\n const { accessToken } = await getAccessToken(config, { code, redirectUri });\n\n try {\n const httpResponse = await got.get(userInfoEndpoint, {\n headers: {\n authorization: `Bearer ${accessToken}`,\n },\n timeout: { request: defaultTimeout },\n });\n const rawData = parseJson(httpResponse.body);\n const result = userInfoResponseGuard.safeParse(rawData);\n\n if (!result.success) {\n throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, result.error);\n }\n\n const { id, username: name, avatar, email, verified } = result.data;\n\n const rawUserInfo = {\n id,\n name,\n avatar: conditional(avatar && `https://cdn.discordapp.com/avatars/${id}/${avatar}`),\n email: conditional(verified && email),\n };\n\n const userInfoResult = socialUserInfoGuard.safeParse(rawUserInfo);\n\n if (!userInfoResult.success) {\n throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, userInfoResult.error);\n }\n\n return { ...userInfoResult.data, rawData };\n } catch (error: unknown) {\n if (error instanceof HTTPError) {\n const { statusCode, body: rawBody } = error.response;\n\n if (statusCode === 401) {\n throw new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid);\n }\n\n throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(rawBody));\n }\n\n throw error;\n }\n };\n\nconst authorizationCallbackHandler = async (parameterObject: unknown) => {\n const result = authResponseGuard.safeParse(parameterObject);\n\n if (!result.success) {\n throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(parameterObject));\n }\n\n return result.data;\n};\n\nconst createDiscordConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {\n return {\n metadata: defaultMetadata,\n type: ConnectorType.Social,\n configGuard: discordConfigGuard,\n getAuthorizationUri: getAuthorizationUri(getConfig),\n getUserInfo: getUserInfo(getConfig),\n };\n};\n\nexport default createDiscordConnector;\n","import type { ConnectorMetadata } from '@logto/connector-kit';\nimport { ConnectorConfigFormItemType, ConnectorPlatform } from '@logto/connector-kit';\n\n/**\n * Base authorization URL.\n * https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-urls\n */\nexport const authorizationEndpoint = 'https://discord.com/oauth2/authorize';\n\n/**\n * Discord exposes different versions of the API, You should specify which version to use by including it in your requests.\n * https://discord.com/developers/docs/reference#api-reference\n */\nexport const accessTokenEndpoint = 'https://discord.com/api/v10/oauth2/token';\nexport const userInfoEndpoint = 'https://discord.com/api/v10/users/@me';\n\n/**\n * OAuth2 Scopes\n * https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes\n */\nexport const scope = 'identify email';\n\nexport const defaultMetadata: ConnectorMetadata = {\n id: 'discord-universal',\n target: 'discord',\n platform: ConnectorPlatform.Universal,\n name: {\n en: 'Discord',\n },\n logo: './logo.svg',\n logoDark: null,\n description: {\n en: 'Discord is the easiest way to talk over voice, video, and text.',\n 'pt-PT': 'Discord é a forma mais fácil de comunicar por voz, vídeo e texto.',\n 'zh-CN': 'Discord 是一款专为社群设计的免费网络实时通话软件与数字发行平台。',\n 'tr-TR': 'Discord, sesli, görüntülü ve metin üzerinden konuşmanın en kolay yoludur.',\n ko: 'Discord는 음성, 비디오 및 텍스트로 대화하는 가장 쉬운 방법입니다.',\n },\n readme: './README.md',\n formItems: [\n {\n key: 'clientId',\n type: ConnectorConfigFormItemType.Text,\n required: true,\n label: 'Client ID',\n placeholder: '<client-id>',\n },\n {\n key: 'clientSecret',\n type: ConnectorConfigFormItemType.Text,\n required: true,\n label: 'Client Secret',\n placeholder: '<client-secret>',\n },\n {\n key: 'scope',\n type: ConnectorConfigFormItemType.Text,\n required: false,\n label: 'Scope',\n placeholder: '<scope>',\n description:\n \"The `scope` determines permissions granted by the user's authorization. If you are not sure what to enter, do not worry, just leave it blank.\",\n },\n ],\n};\n\nexport const defaultTimeout = 5000;\n","import type { Nullable, Optional } from '@silverhand/essentials';\nimport { z } from 'zod';\n\nconst nullishToUndefined = <T = unknown>(input: Nullable<T>): Optional<T> => {\n if (!input) {\n return;\n }\n\n return input;\n};\n\nexport const discordConfigGuard = z.object({\n clientId: z.string(),\n clientSecret: z.string(),\n scope: z.string().optional(),\n});\n\nexport type DiscordConfig = z.infer<typeof discordConfigGuard>;\n\nexport const accessTokenResponseGuard = z.object({\n access_token: z.string(),\n token_type: z.string(),\n expires_in: z.number(),\n scope: z.string(),\n});\n\nexport type AccessTokenResponse = z.infer<typeof accessTokenResponseGuard>;\n\nexport const userInfoResponseGuard = z.object({\n id: z.string(),\n username: z.string().nullish().transform(nullishToUndefined),\n avatar: z.string().nullish().transform(nullishToUndefined),\n email: z.string().nullish().transform(nullishToUndefined),\n verified: z.boolean().nullish().transform(nullishToUndefined),\n});\n\nexport type UserInfoResponse = z.infer<typeof userInfoResponseGuard>;\n\nexport const authorizationCallbackErrorGuard = z.object({\n error: z.string(),\n error_description: z.string(),\n});\n\nexport const authResponseGuard = z.object({ code: z.string(), redirectUri: z.string() });\n"],"mappings":";AAKA,SAAS,QAAQ,mBAAmB;AACpC,SAAS,KAAK,iBAAiB;AAS/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACrBP,SAAS,6BAA6B,yBAAyB;AAMxD,IAAM,wBAAwB;AAM9B,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB;AAMzB,IAAM,QAAQ;AAEd,IAAM,kBAAqC;AAAA,EAChD,IAAI;AAAA,EACJ,QAAQ;AAAA,EACR,UAAU,kBAAkB;AAAA,EAC5B,MAAM;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aAAa;AAAA,IACX,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,IAAI;AAAA,EACN;AAAA,EACA,QAAQ;AAAA,EACR,WAAW;AAAA,IACT;AAAA,MACE,KAAK;AAAA,MACL,MAAM,4BAA4B;AAAA,MAClC,UAAU;AAAA,MACV,OAAO;AAAA,MACP,aAAa;AAAA,IACf;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM,4BAA4B;AAAA,MAClC,UAAU;AAAA,MACV,OAAO;AAAA,MACP,aAAa;AAAA,IACf;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM,4BAA4B;AAAA,MAClC,UAAU;AAAA,MACV,OAAO;AAAA,MACP,aAAa;AAAA,MACb,aACE;AAAA,IACJ;AAAA,EACF;AACF;AAEO,IAAM,iBAAiB;;;ACjE9B,SAAS,SAAS;AAElB,IAAM,qBAAqB,CAAc,UAAoC;AAC3E,MAAI,CAAC,OAAO;AACV;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,qBAAqB,EAAE,OAAO;AAAA,EACzC,UAAU,EAAE,OAAO;AAAA,EACnB,cAAc,EAAE,OAAO;AAAA,EACvB,OAAO,EAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAIM,IAAM,2BAA2B,EAAE,OAAO;AAAA,EAC/C,cAAc,EAAE,OAAO;AAAA,EACvB,YAAY,EAAE,OAAO;AAAA,EACrB,YAAY,EAAE,OAAO;AAAA,EACrB,OAAO,EAAE,OAAO;AAClB,CAAC;AAIM,IAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,IAAI,EAAE,OAAO;AAAA,EACb,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,kBAAkB;AAAA,EAC3D,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,kBAAkB;AAAA,EACzD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,kBAAkB;AAAA,EACxD,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,kBAAkB;AAC9D,CAAC;AAIM,IAAM,kCAAkC,EAAE,OAAO;AAAA,EACtD,OAAO,EAAE,OAAO;AAAA,EAChB,mBAAmB,EAAE,OAAO;AAC9B,CAAC;AAEM,IAAM,oBAAoB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,aAAa,EAAE,OAAO,EAAE,CAAC;;;AFHvF,IAAM,sBACJ,CAAC,cACD,OAAO,EAAE,OAAO,YAAY,MAAM;AAChC,QAAM,SAAS,MAAM,UAAU,gBAAgB,EAAE;AACjD,iBAAe,QAAQ,kBAAkB;AAEzC,QAAM,kBAAkB,IAAI,gBAAgB;AAAA,IAC1C,WAAW,OAAO;AAAA,IAClB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,OAAO,OAAO,SAAS;AAAA,IACvB;AAAA,EACF,CAAC;AAED,SAAO,GAAG,qBAAqB,IAAI,gBAAgB,SAAS,CAAC;AAC/D;AAEK,IAAM,iBAAiB,OAC5B,QACA,eACG;AACH,QAAM,EAAE,MAAM,YAAY,IAAI;AAE9B,QAAM,EAAE,UAAU,WAAW,cAAc,cAAc,IAAI;AAE7D,QAAM,eAAe,MAAM,IAAI,KAAK,qBAAqB;AAAA,IACvD,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,IACA,SAAS,EAAE,SAAS,eAAe;AAAA,EACrC,CAAC;AAED,QAAM,SAAS,yBAAyB,UAAU,UAAU,aAAa,IAAI,CAAC;AAE9E,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,eAAe,oBAAoB,iBAAiB,OAAO,KAAK;AAAA,EAC5E;AAEA,QAAM,EAAE,cAAc,YAAY,IAAI,OAAO;AAE7C,SAAO,aAAa,IAAI,eAAe,oBAAoB,qBAAqB,CAAC;AAEjF,SAAO,EAAE,YAAY;AACvB;AAEA,IAAM,cACJ,CAAC,cACD,OAAO,SAAS;AACd,QAAM,EAAE,MAAM,YAAY,IAAI,MAAM,6BAA6B,IAAI;AACrE,QAAM,SAAS,MAAM,UAAU,gBAAgB,EAAE;AACjD,iBAAe,QAAQ,kBAAkB;AACzC,QAAM,EAAE,YAAY,IAAI,MAAM,eAAe,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE1E,MAAI;AACF,UAAM,eAAe,MAAM,IAAI,IAAI,kBAAkB;AAAA,MACnD,SAAS;AAAA,QACP,eAAe,UAAU,WAAW;AAAA,MACtC;AAAA,MACA,SAAS,EAAE,SAAS,eAAe;AAAA,IACrC,CAAC;AACD,UAAM,UAAU,UAAU,aAAa,IAAI;AAC3C,UAAM,SAAS,sBAAsB,UAAU,OAAO;AAEtD,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI,eAAe,oBAAoB,iBAAiB,OAAO,KAAK;AAAA,IAC5E;AAEA,UAAM,EAAE,IAAI,UAAU,MAAM,QAAQ,OAAO,SAAS,IAAI,OAAO;AAE/D,UAAM,cAAc;AAAA,MAClB;AAAA,MACA;AAAA,MACA,QAAQ,YAAY,UAAU,sCAAsC,EAAE,IAAI,MAAM,EAAE;AAAA,MAClF,OAAO,YAAY,YAAY,KAAK;AAAA,IACtC;AAEA,UAAM,iBAAiB,oBAAoB,UAAU,WAAW;AAEhE,QAAI,CAAC,eAAe,SAAS;AAC3B,YAAM,IAAI,eAAe,oBAAoB,iBAAiB,eAAe,KAAK;AAAA,IACpF;AAEA,WAAO,EAAE,GAAG,eAAe,MAAM,QAAQ;AAAA,EAC3C,SAAS,OAAgB;AACvB,QAAI,iBAAiB,WAAW;AAC9B,YAAM,EAAE,YAAY,MAAM,QAAQ,IAAI,MAAM;AAE5C,UAAI,eAAe,KAAK;AACtB,cAAM,IAAI,eAAe,oBAAoB,wBAAwB;AAAA,MACvE;AAEA,YAAM,IAAI,eAAe,oBAAoB,SAAS,KAAK,UAAU,OAAO,CAAC;AAAA,IAC/E;AAEA,UAAM;AAAA,EACR;AACF;AAEF,IAAM,+BAA+B,OAAO,oBAA6B;AACvE,QAAM,SAAS,kBAAkB,UAAU,eAAe;AAE1D,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,eAAe,oBAAoB,SAAS,KAAK,UAAU,eAAe,CAAC;AAAA,EACvF;AAEA,SAAO,OAAO;AAChB;AAEA,IAAM,yBAA2D,OAAO,EAAE,UAAU,MAAM;AACxF,SAAO;AAAA,IACL,UAAU;AAAA,IACV,MAAM,cAAc;AAAA,IACpB,aAAa;AAAA,IACb,qBAAqB,oBAAoB,SAAS;AAAA,IAClD,aAAa,YAAY,SAAS;AAAA,EACpC;AACF;AAEA,IAAO,gBAAQ;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/constant.ts","../src/types.ts"],"sourcesContent":["/**\n * Discord OAuth2 Connector\n * https://discord.com/developers/docs/topics/oauth2\n */\n\nimport { assert, conditional } from '@silverhand/essentials';\nimport { got, HTTPError } from 'got';\n\nimport type {\n GetConnectorConfig,\n GetAuthorizationUri,\n GetUserInfo,\n CreateConnector,\n SocialConnector,\n} from '@logto/connector-kit';\nimport {\n socialUserInfoGuard,\n validateConfig,\n ConnectorError,\n ConnectorErrorCodes,\n ConnectorType,\n parseJson,\n} from '@logto/connector-kit';\n\nimport {\n defaultMetadata,\n scope as defaultScope,\n authorizationEndpoint,\n accessTokenEndpoint,\n defaultTimeout,\n userInfoEndpoint,\n} from './constant.js';\nimport type { DiscordConfig } from './types.js';\nimport {\n discordConfigGuard,\n authResponseGuard,\n accessTokenResponseGuard,\n userInfoResponseGuard,\n} from './types.js';\n\nconst getAuthorizationUri =\n (getConfig: GetConnectorConfig): GetAuthorizationUri =>\n async ({ state, redirectUri, scope }) => {\n const config = await getConfig(defaultMetadata.id);\n validateConfig(config, discordConfigGuard);\n\n const queryParameters = new URLSearchParams({\n client_id: config.clientId,\n redirect_uri: redirectUri,\n response_type: 'code',\n scope: scope ?? config.scope ?? defaultScope,\n state,\n });\n\n return `${authorizationEndpoint}?${queryParameters.toString()}`;\n };\n\nexport const getAccessToken = async (\n config: DiscordConfig,\n codeObject: { code: string; redirectUri: string }\n) => {\n const { code, redirectUri } = codeObject;\n\n const { clientId: client_id, clientSecret: client_secret } = config;\n\n const httpResponse = await got.post(accessTokenEndpoint, {\n form: {\n client_id,\n client_secret,\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n },\n timeout: { request: defaultTimeout },\n });\n\n const result = accessTokenResponseGuard.safeParse(parseJson(httpResponse.body));\n\n if (!result.success) {\n throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, result.error);\n }\n\n const { access_token: accessToken } = result.data;\n\n assert(accessToken, new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid));\n\n return { accessToken };\n};\n\nconst getUserInfo =\n (getConfig: GetConnectorConfig): GetUserInfo =>\n async (data) => {\n const { code, redirectUri } = await authorizationCallbackHandler(data);\n const config = await getConfig(defaultMetadata.id);\n validateConfig(config, discordConfigGuard);\n const { accessToken } = await getAccessToken(config, { code, redirectUri });\n\n try {\n const httpResponse = await got.get(userInfoEndpoint, {\n headers: {\n authorization: `Bearer ${accessToken}`,\n },\n timeout: { request: defaultTimeout },\n });\n const rawData = parseJson(httpResponse.body);\n const result = userInfoResponseGuard.safeParse(rawData);\n\n if (!result.success) {\n throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, result.error);\n }\n\n const { id, username: name, avatar, email, verified } = result.data;\n\n const rawUserInfo = {\n id,\n name,\n avatar: conditional(avatar && `https://cdn.discordapp.com/avatars/${id}/${avatar}`),\n email: conditional(verified && email),\n };\n\n const userInfoResult = socialUserInfoGuard.safeParse(rawUserInfo);\n\n if (!userInfoResult.success) {\n throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, userInfoResult.error);\n }\n\n return { ...userInfoResult.data, rawData };\n } catch (error: unknown) {\n if (error instanceof HTTPError) {\n const { statusCode, body: rawBody } = error.response;\n\n if (statusCode === 401) {\n throw new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid);\n }\n\n throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(rawBody));\n }\n\n throw error;\n }\n };\n\nconst authorizationCallbackHandler = async (parameterObject: unknown) => {\n const result = authResponseGuard.safeParse(parameterObject);\n\n if (!result.success) {\n throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(parameterObject));\n }\n\n return result.data;\n};\n\nconst createDiscordConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {\n return {\n metadata: defaultMetadata,\n type: ConnectorType.Social,\n configGuard: discordConfigGuard,\n getAuthorizationUri: getAuthorizationUri(getConfig),\n getUserInfo: getUserInfo(getConfig),\n };\n};\n\nexport default createDiscordConnector;\n","import type { ConnectorMetadata } from '@logto/connector-kit';\nimport { ConnectorConfigFormItemType, ConnectorPlatform } from '@logto/connector-kit';\n\n/**\n * Base authorization URL.\n * https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-urls\n */\nexport const authorizationEndpoint = 'https://discord.com/oauth2/authorize';\n\n/**\n * Discord exposes different versions of the API, You should specify which version to use by including it in your requests.\n * https://discord.com/developers/docs/reference#api-reference\n */\nexport const accessTokenEndpoint = 'https://discord.com/api/v10/oauth2/token';\nexport const userInfoEndpoint = 'https://discord.com/api/v10/users/@me';\n\n/**\n * OAuth2 Scopes\n * https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes\n */\nexport const scope = 'identify email';\n\nexport const defaultMetadata: ConnectorMetadata = {\n id: 'discord-universal',\n target: 'discord',\n platform: ConnectorPlatform.Universal,\n name: {\n en: 'Discord',\n },\n logo: './logo.svg',\n logoDark: null,\n description: {\n en: 'Discord is the easiest way to talk over voice, video, and text.',\n 'pt-PT': 'Discord é a forma mais fácil de comunicar por voz, vídeo e texto.',\n 'zh-CN': 'Discord 是一款专为社群设计的免费网络实时通话软件与数字发行平台。',\n 'tr-TR': 'Discord, sesli, görüntülü ve metin üzerinden konuşmanın en kolay yoludur.',\n ko: 'Discord는 음성, 비디오 및 텍스트로 대화하는 가장 쉬운 방법입니다.',\n },\n readme: './README.md',\n formItems: [\n {\n key: 'clientId',\n type: ConnectorConfigFormItemType.Text,\n required: true,\n label: 'Client ID',\n placeholder: '<client-id>',\n },\n {\n key: 'clientSecret',\n type: ConnectorConfigFormItemType.Text,\n required: true,\n label: 'Client Secret',\n placeholder: '<client-secret>',\n },\n {\n key: 'scope',\n type: ConnectorConfigFormItemType.MultilineText,\n required: false,\n label: 'Scope',\n placeholder: 'Enter the scopes (separated by a space)',\n description: \"The `scope` determines permissions granted by the user's authorization. \",\n },\n ],\n};\n\nexport const defaultTimeout = 5000;\n","import type { Nullable, Optional } from '@silverhand/essentials';\nimport { z } from 'zod';\n\nconst nullishToUndefined = <T = unknown>(input: Nullable<T>): Optional<T> => {\n if (!input) {\n return;\n }\n\n return input;\n};\n\nexport const discordConfigGuard = z.object({\n clientId: z.string(),\n clientSecret: z.string(),\n scope: z.string().optional(),\n});\n\nexport type DiscordConfig = z.infer<typeof discordConfigGuard>;\n\nexport const accessTokenResponseGuard = z.object({\n access_token: z.string(),\n token_type: z.string(),\n expires_in: z.number(),\n scope: z.string(),\n});\n\nexport type AccessTokenResponse = z.infer<typeof accessTokenResponseGuard>;\n\nexport const userInfoResponseGuard = z.object({\n id: z.string(),\n username: z.string().nullish().transform(nullishToUndefined),\n avatar: z.string().nullish().transform(nullishToUndefined),\n email: z.string().nullish().transform(nullishToUndefined),\n verified: z.boolean().nullish().transform(nullishToUndefined),\n});\n\nexport type UserInfoResponse = z.infer<typeof userInfoResponseGuard>;\n\nexport const authorizationCallbackErrorGuard = z.object({\n error: z.string(),\n error_description: z.string(),\n});\n\nexport const authResponseGuard = z.object({ code: z.string(), redirectUri: z.string() });\n"],"mappings":"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","names":["scope"]}
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@logto/connector-discord",
3
- "version": "1.4.1",
3
+ "version": "1.6.0",
4
4
  "description": "Discord connector implementation.",
5
5
  "author": "ZR3SYSTEMS. <https://github.com/FlurryNight>",
6
6
  "dependencies": {
7
- "@logto/connector-kit": "^4.1.1",
8
7
  "@silverhand/essentials": "^2.9.1",
9
8
  "got": "^14.0.0",
10
9
  "snakecase-keys": "^8.0.1",
11
- "zod": "^3.23.8"
10
+ "zod": "3.24.3",
11
+ "@logto/connector-kit": "^4.4.0"
12
12
  },
13
13
  "main": "./lib/index.js",
14
14
  "module": "./lib/index.js",
@@ -22,7 +22,7 @@
22
22
  "logo-dark.svg"
23
23
  ],
24
24
  "engines": {
25
- "node": "^20.9.0"
25
+ "node": "^22.14.0"
26
26
  },
27
27
  "eslintConfig": {
28
28
  "extends": "@silverhand",
@@ -43,17 +43,17 @@
43
43
  "devDependencies": {
44
44
  "@silverhand/eslint-config": "6.0.1",
45
45
  "@silverhand/ts-config": "6.0.0",
46
- "@types/node": "^20.11.20",
46
+ "@types/node": "^22.14.0",
47
47
  "@types/supertest": "^6.0.2",
48
- "@vitest/coverage-v8": "^2.1.9",
48
+ "@vitest/coverage-v8": "^3.1.1",
49
49
  "eslint": "^8.56.0",
50
50
  "lint-staged": "^15.0.2",
51
- "nock": "^13.3.1",
52
- "prettier": "^3.0.0",
51
+ "nock": "^14.0.3",
52
+ "prettier": "^3.5.3",
53
53
  "supertest": "^7.0.0",
54
- "tsup": "^8.3.0",
54
+ "tsup": "^8.5.0",
55
55
  "typescript": "^5.5.3",
56
- "vitest": "^2.1.9"
56
+ "vitest": "^3.1.1"
57
57
  },
58
58
  "scripts": {
59
59
  "precommit": "lint-staged",