@logto/connector-github 1.5.0 → 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 +2 -2
- package/lib/index.js.map +1 -1
- package/package.json +10 -10
package/lib/index.js
CHANGED
|
@@ -204,9 +204,9 @@ var createGithubConnector = async ({ getConfig }) => {
|
|
|
204
204
|
getUserInfo: getUserInfo(getConfig)
|
|
205
205
|
};
|
|
206
206
|
};
|
|
207
|
-
var
|
|
207
|
+
var index_default = createGithubConnector;
|
|
208
208
|
export {
|
|
209
|
-
|
|
209
|
+
index_default as default,
|
|
210
210
|
getAccessToken
|
|
211
211
|
};
|
|
212
212
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/constant.ts","../src/types.ts"],"sourcesContent":["import { assert, conditional, trySafe } from '@silverhand/essentials';\n\nimport {\n ConnectorError,\n ConnectorErrorCodes,\n validateConfig,\n ConnectorType,\n jsonGuard,\n} from '@logto/connector-kit';\nimport type {\n GetAuthorizationUri,\n GetUserInfo,\n SocialConnector,\n CreateConnector,\n GetConnectorConfig,\n} from '@logto/connector-kit';\nimport ky, { HTTPError } from 'ky';\n\nimport {\n authorizationEndpoint,\n accessTokenEndpoint,\n scope as defaultScope,\n userInfoEndpoint,\n userEmailsEndpoint,\n defaultMetadata,\n defaultTimeout,\n} from './constant.js';\nimport type { GithubConfig } from './types.js';\nimport {\n authorizationCallbackErrorGuard,\n githubConfigGuard,\n emailAddressGuard,\n accessTokenResponseGuard,\n userInfoResponseGuard,\n authResponseGuard,\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, githubConfigGuard);\n const queryParameters = new URLSearchParams({\n client_id: config.clientId,\n redirect_uri: redirectUri,\n state,\n scope: config.scope ?? defaultScope,\n });\n\n return `${authorizationEndpoint}?${queryParameters.toString()}`;\n };\n\nconst authorizationCallbackHandler = async (parameterObject: unknown) => {\n const result = authResponseGuard.safeParse(parameterObject);\n\n if (result.success) {\n return result.data;\n }\n\n const parsedError = authorizationCallbackErrorGuard.safeParse(parameterObject);\n\n if (!parsedError.success) {\n throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(parameterObject));\n }\n\n const { error, error_description, error_uri } = parsedError.data;\n\n if (error === 'access_denied') {\n throw new ConnectorError(ConnectorErrorCodes.AuthorizationFailed, error_description);\n }\n\n throw new ConnectorError(ConnectorErrorCodes.General, {\n error,\n errorDescription: error_description,\n error_uri,\n });\n};\n\nexport const getAccessToken = async (config: GithubConfig, codeObject: { code: string }) => {\n const { code } = codeObject;\n const { clientId: client_id, clientSecret: client_secret } = config;\n\n const httpResponse = await ky\n .post(accessTokenEndpoint, {\n body: new URLSearchParams({\n client_id,\n client_secret,\n code,\n }),\n timeout: defaultTimeout,\n })\n .json();\n\n const result = accessTokenResponseGuard.safeParse(httpResponse);\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 } = await authorizationCallbackHandler(data);\n const config = await getConfig(defaultMetadata.id);\n validateConfig(config, githubConfigGuard);\n const { accessToken } = await getAccessToken(config, { code });\n\n const authedApi = ky.create({\n timeout: defaultTimeout,\n hooks: {\n beforeRequest: [\n (request) => {\n request.headers.set('Authorization', `Bearer ${accessToken}`);\n },\n ],\n },\n });\n\n try {\n /**\n * If user(s) is using GitHub Apps (instead of OAuth Apps), they can customize\n * \"Account permissions\" and restrict the \"email addresses\" visibility, and GitHub\n * hence throws error instead of returning an empty array.\n *\n * We try catch the error and return an empty array instead.\n */\n const [userInfo, userEmails = []] = await Promise.all([\n authedApi.get(userInfoEndpoint).json(),\n trySafe(authedApi.get(userEmailsEndpoint).json()),\n ]);\n\n const userInfoResult = userInfoResponseGuard.safeParse(userInfo);\n const userEmailsResult = emailAddressGuard.array().safeParse(userEmails);\n\n if (!userInfoResult.success) {\n throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, userInfoResult.error);\n }\n\n if (!userEmailsResult.success) {\n throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, userEmailsResult.error);\n }\n\n const { id, avatar_url: avatar, email: publicEmail, name } = userInfoResult.data;\n\n return {\n id: String(id),\n avatar: conditional(avatar),\n email: conditional(\n publicEmail ??\n userEmailsResult.data.find(({ verified, primary }) => verified && primary)?.email\n ),\n name: conditional(name),\n rawData: jsonGuard.parse({\n userInfo,\n userEmails,\n }),\n };\n } catch (error: unknown) {\n if (error instanceof HTTPError) {\n const { status, body: rawBody } = error.response;\n\n if (status === 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 createGithubConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {\n return {\n metadata: defaultMetadata,\n type: ConnectorType.Social,\n configGuard: githubConfigGuard,\n getAuthorizationUri: getAuthorizationUri(getConfig),\n getUserInfo: getUserInfo(getConfig),\n };\n};\n\nexport default createGithubConnector;\n","import type { ConnectorMetadata } from '@logto/connector-kit';\nimport { ConnectorPlatform, ConnectorConfigFormItemType } from '@logto/connector-kit';\n\nexport const authorizationEndpoint = 'https://github.com/login/oauth/authorize';\n/**\n * `read:user` read user profile data; `user:email` read user email addresses (including private email addresses).\n * Ref: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps\n */\nexport const scope = 'read:user user:email';\nexport const accessTokenEndpoint = 'https://github.com/login/oauth/access_token';\nexport const userInfoEndpoint = 'https://api.github.com/user';\n// Ref: https://docs.github.com/en/rest/users/emails?apiVersion=2022-11-28#list-email-addresses-for-the-authenticated-user\nexport const userEmailsEndpoint = 'https://api.github.com/user/emails';\n\nexport const defaultMetadata: ConnectorMetadata = {\n id: 'github-universal',\n target: 'github',\n platform: ConnectorPlatform.Universal,\n name: {\n en: 'GitHub',\n 'zh-CN': 'GitHub',\n 'tr-TR': 'GitHub',\n ko: 'GitHub',\n },\n logo: './logo.svg',\n logoDark: './logo-dark.svg',\n description: {\n en: 'GitHub is an online community for software development and version control.',\n 'zh-CN': 'GitHub 是极受欢迎的代码托管仓库。',\n 'tr-TR': 'GitHub, yazılım geliştirme ve sürüm kontrolü için çevrimiçi bir topluluktur.',\n ko: 'GitHub는 소프트웨어 개발과 버전 관리를 위한 온라인 커뮤니티입니다.',\n },\n readme: './README.md',\n formItems: [\n {\n key: 'clientId',\n type: ConnectorConfigFormItemType.Text,\n label: 'Client ID',\n required: true,\n placeholder: '<client-id>',\n },\n {\n key: 'clientSecret',\n type: ConnectorConfigFormItemType.Text,\n label: 'Client Secret',\n required: true,\n placeholder: '<client-secret>',\n },\n {\n key: 'scope',\n type: ConnectorConfigFormItemType.Text,\n label: 'Scope',\n required: false,\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 { z } from 'zod';\n\nexport const githubConfigGuard = z.object({\n clientId: z.string(),\n clientSecret: z.string(),\n scope: z.string().optional(),\n});\n\nexport type GithubConfig = z.infer<typeof githubConfigGuard>;\n\n/**\n * This guard is used to validate the response from the GitHub API when requesting the user's email addresses.\n * Ref: https://docs.github.com/en/rest/users/emails?apiVersion=2022-11-28#list-email-addresses-for-the-authenticated-user\n */\nexport const emailAddressGuard = z.object({\n email: z.string(),\n primary: z.boolean(),\n verified: z.boolean(),\n visibility: z.string().nullable(),\n});\n\nexport const accessTokenResponseGuard = z.object({\n access_token: z.string(),\n scope: z.string(),\n token_type: z.string(),\n});\n\nexport type AccessTokenResponse = z.infer<typeof accessTokenResponseGuard>;\n\nexport const userInfoResponseGuard = z.object({\n id: z.number(),\n avatar_url: z.string().optional().nullable(),\n email: z.string().optional().nullable(),\n name: z.string().optional().nullable(),\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 error_uri: z.string(),\n});\n\nexport const authResponseGuard = z.object({ code: z.string() });\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constant.ts","../src/types.ts"],"sourcesContent":["import { assert, conditional, trySafe } from '@silverhand/essentials';\n\nimport {\n ConnectorError,\n ConnectorErrorCodes,\n validateConfig,\n ConnectorType,\n jsonGuard,\n} from '@logto/connector-kit';\nimport type {\n GetAuthorizationUri,\n GetUserInfo,\n SocialConnector,\n CreateConnector,\n GetConnectorConfig,\n} from '@logto/connector-kit';\nimport ky, { HTTPError } from 'ky';\n\nimport {\n authorizationEndpoint,\n accessTokenEndpoint,\n scope as defaultScope,\n userInfoEndpoint,\n userEmailsEndpoint,\n defaultMetadata,\n defaultTimeout,\n} from './constant.js';\nimport type { GithubConfig } from './types.js';\nimport {\n authorizationCallbackErrorGuard,\n githubConfigGuard,\n emailAddressGuard,\n accessTokenResponseGuard,\n userInfoResponseGuard,\n authResponseGuard,\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, githubConfigGuard);\n const queryParameters = new URLSearchParams({\n client_id: config.clientId,\n redirect_uri: redirectUri,\n state,\n scope: config.scope ?? defaultScope,\n });\n\n return `${authorizationEndpoint}?${queryParameters.toString()}`;\n };\n\nconst authorizationCallbackHandler = async (parameterObject: unknown) => {\n const result = authResponseGuard.safeParse(parameterObject);\n\n if (result.success) {\n return result.data;\n }\n\n const parsedError = authorizationCallbackErrorGuard.safeParse(parameterObject);\n\n if (!parsedError.success) {\n throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(parameterObject));\n }\n\n const { error, error_description, error_uri } = parsedError.data;\n\n if (error === 'access_denied') {\n throw new ConnectorError(ConnectorErrorCodes.AuthorizationFailed, error_description);\n }\n\n throw new ConnectorError(ConnectorErrorCodes.General, {\n error,\n errorDescription: error_description,\n error_uri,\n });\n};\n\nexport const getAccessToken = async (config: GithubConfig, codeObject: { code: string }) => {\n const { code } = codeObject;\n const { clientId: client_id, clientSecret: client_secret } = config;\n\n const httpResponse = await ky\n .post(accessTokenEndpoint, {\n body: new URLSearchParams({\n client_id,\n client_secret,\n code,\n }),\n timeout: defaultTimeout,\n })\n .json();\n\n const result = accessTokenResponseGuard.safeParse(httpResponse);\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 } = await authorizationCallbackHandler(data);\n const config = await getConfig(defaultMetadata.id);\n validateConfig(config, githubConfigGuard);\n const { accessToken } = await getAccessToken(config, { code });\n\n const authedApi = ky.create({\n timeout: defaultTimeout,\n hooks: {\n beforeRequest: [\n (request) => {\n request.headers.set('Authorization', `Bearer ${accessToken}`);\n },\n ],\n },\n });\n\n try {\n /**\n * If user(s) is using GitHub Apps (instead of OAuth Apps), they can customize\n * \"Account permissions\" and restrict the \"email addresses\" visibility, and GitHub\n * hence throws error instead of returning an empty array.\n *\n * We try catch the error and return an empty array instead.\n */\n const [userInfo, userEmails = []] = await Promise.all([\n authedApi.get(userInfoEndpoint).json(),\n trySafe(authedApi.get(userEmailsEndpoint).json()),\n ]);\n\n const userInfoResult = userInfoResponseGuard.safeParse(userInfo);\n const userEmailsResult = emailAddressGuard.array().safeParse(userEmails);\n\n if (!userInfoResult.success) {\n throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, userInfoResult.error);\n }\n\n if (!userEmailsResult.success) {\n throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, userEmailsResult.error);\n }\n\n const { id, avatar_url: avatar, email: publicEmail, name } = userInfoResult.data;\n\n return {\n id: String(id),\n avatar: conditional(avatar),\n email: conditional(\n publicEmail ??\n userEmailsResult.data.find(({ verified, primary }) => verified && primary)?.email\n ),\n name: conditional(name),\n rawData: jsonGuard.parse({\n userInfo,\n userEmails,\n }),\n };\n } catch (error: unknown) {\n if (error instanceof HTTPError) {\n const { status, body: rawBody } = error.response;\n\n if (status === 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 createGithubConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {\n return {\n metadata: defaultMetadata,\n type: ConnectorType.Social,\n configGuard: githubConfigGuard,\n getAuthorizationUri: getAuthorizationUri(getConfig),\n getUserInfo: getUserInfo(getConfig),\n };\n};\n\nexport default createGithubConnector;\n","import type { ConnectorMetadata } from '@logto/connector-kit';\nimport { ConnectorPlatform, ConnectorConfigFormItemType } from '@logto/connector-kit';\n\nexport const authorizationEndpoint = 'https://github.com/login/oauth/authorize';\n/**\n * `read:user` read user profile data; `user:email` read user email addresses (including private email addresses).\n * Ref: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps\n */\nexport const scope = 'read:user user:email';\nexport const accessTokenEndpoint = 'https://github.com/login/oauth/access_token';\nexport const userInfoEndpoint = 'https://api.github.com/user';\n// Ref: https://docs.github.com/en/rest/users/emails?apiVersion=2022-11-28#list-email-addresses-for-the-authenticated-user\nexport const userEmailsEndpoint = 'https://api.github.com/user/emails';\n\nexport const defaultMetadata: ConnectorMetadata = {\n id: 'github-universal',\n target: 'github',\n platform: ConnectorPlatform.Universal,\n name: {\n en: 'GitHub',\n 'zh-CN': 'GitHub',\n 'tr-TR': 'GitHub',\n ko: 'GitHub',\n },\n logo: './logo.svg',\n logoDark: './logo-dark.svg',\n description: {\n en: 'GitHub is an online community for software development and version control.',\n 'zh-CN': 'GitHub 是极受欢迎的代码托管仓库。',\n 'tr-TR': 'GitHub, yazılım geliştirme ve sürüm kontrolü için çevrimiçi bir topluluktur.',\n ko: 'GitHub는 소프트웨어 개발과 버전 관리를 위한 온라인 커뮤니티입니다.',\n },\n readme: './README.md',\n formItems: [\n {\n key: 'clientId',\n type: ConnectorConfigFormItemType.Text,\n label: 'Client ID',\n required: true,\n placeholder: '<client-id>',\n },\n {\n key: 'clientSecret',\n type: ConnectorConfigFormItemType.Text,\n label: 'Client Secret',\n required: true,\n placeholder: '<client-secret>',\n },\n {\n key: 'scope',\n type: ConnectorConfigFormItemType.Text,\n label: 'Scope',\n required: false,\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 { z } from 'zod';\n\nexport const githubConfigGuard = z.object({\n clientId: z.string(),\n clientSecret: z.string(),\n scope: z.string().optional(),\n});\n\nexport type GithubConfig = z.infer<typeof githubConfigGuard>;\n\n/**\n * This guard is used to validate the response from the GitHub API when requesting the user's email addresses.\n * Ref: https://docs.github.com/en/rest/users/emails?apiVersion=2022-11-28#list-email-addresses-for-the-authenticated-user\n */\nexport const emailAddressGuard = z.object({\n email: z.string(),\n primary: z.boolean(),\n verified: z.boolean(),\n visibility: z.string().nullable(),\n});\n\nexport const accessTokenResponseGuard = z.object({\n access_token: z.string(),\n scope: z.string(),\n token_type: z.string(),\n});\n\nexport type AccessTokenResponse = z.infer<typeof accessTokenResponseGuard>;\n\nexport const userInfoResponseGuard = z.object({\n id: z.number(),\n avatar_url: z.string().optional().nullable(),\n email: z.string().optional().nullable(),\n name: z.string().optional().nullable(),\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 error_uri: z.string(),\n});\n\nexport const authResponseGuard = z.object({ code: z.string() });\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/connector-github",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Github web connector implementation.",
|
|
5
5
|
"author": "Silverhand Inc. <contact@silverhand.io>",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@logto/connector-kit": "^4.
|
|
7
|
+
"@logto/connector-kit": "^4.3.0",
|
|
8
8
|
"@silverhand/essentials": "^2.9.1",
|
|
9
9
|
"ky": "^1.2.3",
|
|
10
10
|
"query-string": "^9.0.0",
|
|
11
11
|
"snakecase-keys": "^8.0.1",
|
|
12
|
-
"zod": "^3.
|
|
12
|
+
"zod": "^3.24.2"
|
|
13
13
|
},
|
|
14
14
|
"main": "./lib/index.js",
|
|
15
15
|
"module": "./lib/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"logo-dark.svg"
|
|
24
24
|
],
|
|
25
25
|
"engines": {
|
|
26
|
-
"node": "^
|
|
26
|
+
"node": "^22.14.0"
|
|
27
27
|
},
|
|
28
28
|
"eslintConfig": {
|
|
29
29
|
"extends": "@silverhand",
|
|
@@ -44,17 +44,17 @@
|
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@silverhand/eslint-config": "6.0.1",
|
|
46
46
|
"@silverhand/ts-config": "6.0.0",
|
|
47
|
-
"@types/node": "^
|
|
47
|
+
"@types/node": "^22.14.0",
|
|
48
48
|
"@types/supertest": "^6.0.2",
|
|
49
|
-
"@vitest/coverage-v8": "^
|
|
49
|
+
"@vitest/coverage-v8": "^3.1.1",
|
|
50
50
|
"eslint": "^8.56.0",
|
|
51
51
|
"lint-staged": "^15.0.2",
|
|
52
|
-
"nock": "14.0.
|
|
53
|
-
"prettier": "^3.
|
|
52
|
+
"nock": "^14.0.3",
|
|
53
|
+
"prettier": "^3.5.3",
|
|
54
54
|
"supertest": "^7.0.0",
|
|
55
|
-
"tsup": "^8.
|
|
55
|
+
"tsup": "^8.3.0",
|
|
56
56
|
"typescript": "^5.5.3",
|
|
57
|
-
"vitest": "^
|
|
57
|
+
"vitest": "^3.1.1"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"precommit": "lint-staged",
|