@logto/connector-feishu-web 1.2.1 → 1.3.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 +208 -190
- package/lib/index.js.map +1 -0
- package/package.json +10 -15
- package/lib/constant.d.ts +0 -5
- package/lib/index.d.ts +0 -13
- package/lib/mock.d.ts +0 -10
- package/lib/types.d.ts +0 -100
package/lib/index.js
CHANGED
|
@@ -1,213 +1,231 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { assert, conditional } from "@silverhand/essentials";
|
|
3
|
+
import { got, HTTPError } from "got";
|
|
4
|
+
import {
|
|
5
|
+
ConnectorError,
|
|
6
|
+
ConnectorErrorCodes,
|
|
7
|
+
ConnectorPlatform as ConnectorPlatform2,
|
|
8
|
+
ConnectorType,
|
|
9
|
+
jsonGuard,
|
|
10
|
+
validateConfig
|
|
11
|
+
} from "@logto/connector-kit";
|
|
4
12
|
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const userInfoEndpoint = 'https://passport.feishu.cn/suite/passport/oauth/userinfo';
|
|
33
|
-
const defaultMetadata = {
|
|
34
|
-
id: 'feishu-web',
|
|
35
|
-
target: 'feishu',
|
|
36
|
-
platform: ConnectorPlatform.Web,
|
|
37
|
-
name: {
|
|
38
|
-
en: 'Feishu',
|
|
39
|
-
'zh-CN': '飞书',
|
|
13
|
+
// src/constant.ts
|
|
14
|
+
import { ConnectorConfigFormItemType, ConnectorPlatform } from "@logto/connector-kit";
|
|
15
|
+
var codeEndpoint = "https://passport.feishu.cn/suite/passport/oauth/authorize";
|
|
16
|
+
var accessTokenEndpoint = "https://passport.feishu.cn/suite/passport/oauth/token";
|
|
17
|
+
var userInfoEndpoint = "https://passport.feishu.cn/suite/passport/oauth/userinfo";
|
|
18
|
+
var defaultMetadata = {
|
|
19
|
+
id: "feishu-web",
|
|
20
|
+
target: "feishu",
|
|
21
|
+
platform: ConnectorPlatform.Web,
|
|
22
|
+
name: {
|
|
23
|
+
en: "Feishu",
|
|
24
|
+
"zh-CN": "\u98DE\u4E66"
|
|
25
|
+
},
|
|
26
|
+
logo: "./logo.svg",
|
|
27
|
+
logoDark: null,
|
|
28
|
+
description: {
|
|
29
|
+
"zh-CN": "\u98DE\u4E66\u662F\u4E00\u4E2A\u7531\u5B57\u8282\u8DF3\u52A8\u5F00\u53D1\u7684\u4F01\u4E1A\u534F\u4F5C\u4E0E\u7BA1\u7406\u5E73\u53F0",
|
|
30
|
+
en: "Feishu is an enterprise collaboration platform developed by ByteDance"
|
|
31
|
+
},
|
|
32
|
+
readme: "./README.md",
|
|
33
|
+
formItems: [
|
|
34
|
+
{
|
|
35
|
+
key: "appId",
|
|
36
|
+
label: "App ID",
|
|
37
|
+
type: ConnectorConfigFormItemType.Text,
|
|
38
|
+
required: true,
|
|
39
|
+
placeholder: "<app-id>"
|
|
40
40
|
},
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{
|
|
50
|
-
key: 'appId',
|
|
51
|
-
label: 'App ID',
|
|
52
|
-
type: ConnectorConfigFormItemType.Text,
|
|
53
|
-
required: true,
|
|
54
|
-
placeholder: '<app-id>',
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
key: 'appSecret',
|
|
58
|
-
label: 'App Secret',
|
|
59
|
-
type: ConnectorConfigFormItemType.Text,
|
|
60
|
-
required: true,
|
|
61
|
-
placeholder: '<app-secret>',
|
|
62
|
-
},
|
|
63
|
-
],
|
|
41
|
+
{
|
|
42
|
+
key: "appSecret",
|
|
43
|
+
label: "App Secret",
|
|
44
|
+
type: ConnectorConfigFormItemType.Text,
|
|
45
|
+
required: true,
|
|
46
|
+
placeholder: "<app-secret>"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
64
49
|
};
|
|
65
50
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
51
|
+
// src/types.ts
|
|
52
|
+
import { z } from "zod";
|
|
53
|
+
var feishuConfigGuard = z.object({
|
|
54
|
+
appId: z.string(),
|
|
55
|
+
appSecret: z.string()
|
|
69
56
|
});
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
57
|
+
var feishuAuthCodeGuard = z.object({
|
|
58
|
+
code: z.string(),
|
|
59
|
+
redirectUri: z.string()
|
|
73
60
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
61
|
+
var feishuErrorResponse = z.object({
|
|
62
|
+
error: z.string(),
|
|
63
|
+
error_description: z.string().optional()
|
|
77
64
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
65
|
+
var feishuAccessTokenResponse = z.object({
|
|
66
|
+
access_token: z.string(),
|
|
67
|
+
token_type: z.string(),
|
|
68
|
+
expires_in: z.number(),
|
|
69
|
+
refresh_token: z.string().optional(),
|
|
70
|
+
refresh_expires_in: z.number().optional()
|
|
84
71
|
});
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
72
|
+
var feishuUserInfoResponse = z.object({
|
|
73
|
+
sub: z.string(),
|
|
74
|
+
name: z.string(),
|
|
75
|
+
picture: z.string(),
|
|
76
|
+
open_id: z.string(),
|
|
77
|
+
union_id: z.string(),
|
|
78
|
+
en_name: z.string(),
|
|
79
|
+
tenant_key: z.string(),
|
|
80
|
+
avatar_url: z.string(),
|
|
81
|
+
avatar_thumb: z.string(),
|
|
82
|
+
avatar_middle: z.string(),
|
|
83
|
+
avatar_big: z.string(),
|
|
84
|
+
email: z.string().nullish(),
|
|
85
|
+
user_id: z.string().nullish(),
|
|
86
|
+
employee_no: z.string().nullish(),
|
|
87
|
+
mobile: z.string().nullish()
|
|
101
88
|
});
|
|
102
89
|
|
|
90
|
+
// src/index.ts
|
|
103
91
|
function buildAuthorizationUri(clientId, redirectUri, state) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
92
|
+
const queryParameters = new URLSearchParams({
|
|
93
|
+
client_id: clientId,
|
|
94
|
+
redirect_uri: encodeURI(redirectUri),
|
|
95
|
+
response_type: "code",
|
|
96
|
+
state
|
|
97
|
+
});
|
|
98
|
+
return `${codeEndpoint}?${queryParameters.toString()}`;
|
|
111
99
|
}
|
|
112
100
|
function getAuthorizationUri(getConfig) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
101
|
+
return async function({ state, redirectUri }) {
|
|
102
|
+
const config = await getConfig(defaultMetadata.id);
|
|
103
|
+
validateConfig(config, feishuConfigGuard);
|
|
104
|
+
const { appId } = config;
|
|
105
|
+
return buildAuthorizationUri(appId, redirectUri, state);
|
|
106
|
+
};
|
|
119
107
|
}
|
|
120
108
|
async function authorizationCallbackHandler(data) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
109
|
+
const result = feishuAuthCodeGuard.safeParse(data);
|
|
110
|
+
assert(
|
|
111
|
+
result.success,
|
|
112
|
+
new ConnectorError(ConnectorErrorCodes.InvalidResponse, JSON.stringify(data))
|
|
113
|
+
);
|
|
114
|
+
return result.data;
|
|
124
115
|
}
|
|
125
116
|
async function getAccessToken(code, appId, appSecret, redirectUri) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
117
|
+
try {
|
|
118
|
+
const response = await got.post(accessTokenEndpoint, {
|
|
119
|
+
headers: {
|
|
120
|
+
contentType: "application/www-form-urlencoded"
|
|
121
|
+
},
|
|
122
|
+
form: {
|
|
123
|
+
grant_type: "authorization_code",
|
|
124
|
+
code,
|
|
125
|
+
client_id: appId,
|
|
126
|
+
client_secret: appSecret,
|
|
127
|
+
redirect_uri: redirectUri
|
|
128
|
+
},
|
|
129
|
+
responseType: "json"
|
|
130
|
+
});
|
|
131
|
+
const result = feishuAccessTokenResponse.safeParse(response.body);
|
|
132
|
+
assert(
|
|
133
|
+
result.success,
|
|
134
|
+
new ConnectorError(ConnectorErrorCodes.InvalidResponse, JSON.stringify(response.body))
|
|
135
|
+
);
|
|
136
|
+
if (result.data.access_token.length === 0) {
|
|
137
|
+
throw new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid, "access_token is empty");
|
|
138
|
+
}
|
|
139
|
+
return { accessToken: result.data.access_token };
|
|
140
|
+
} catch (error) {
|
|
141
|
+
if (error instanceof ConnectorError) {
|
|
142
|
+
throw error;
|
|
146
143
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
errorDescription: 'Failed to get access token',
|
|
158
|
-
});
|
|
144
|
+
if (error instanceof HTTPError) {
|
|
145
|
+
const result = feishuErrorResponse.safeParse(error.response.body);
|
|
146
|
+
assert(
|
|
147
|
+
result.success,
|
|
148
|
+
new ConnectorError(ConnectorErrorCodes.InvalidResponse, JSON.stringify(error.response.body))
|
|
149
|
+
);
|
|
150
|
+
throw new ConnectorError(
|
|
151
|
+
ConnectorErrorCodes.SocialAuthCodeInvalid,
|
|
152
|
+
result.data.error_description
|
|
153
|
+
);
|
|
159
154
|
}
|
|
155
|
+
throw new ConnectorError(ConnectorErrorCodes.General, {
|
|
156
|
+
errorDescription: "Failed to get access token"
|
|
157
|
+
});
|
|
158
|
+
}
|
|
160
159
|
}
|
|
161
160
|
function getUserInfo(getConfig) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
161
|
+
return async function(data) {
|
|
162
|
+
const { code, redirectUri } = await authorizationCallbackHandler(data);
|
|
163
|
+
const config = await getConfig(defaultMetadata.id);
|
|
164
|
+
validateConfig(config, feishuConfigGuard);
|
|
165
|
+
const { accessToken } = await getAccessToken(code, config.appId, config.appSecret, redirectUri);
|
|
166
|
+
try {
|
|
167
|
+
const response = await got.get(userInfoEndpoint, {
|
|
168
|
+
headers: {
|
|
169
|
+
Authorization: `Bearer ${accessToken}`
|
|
170
|
+
},
|
|
171
|
+
responseType: "json"
|
|
172
|
+
});
|
|
173
|
+
const result = feishuUserInfoResponse.safeParse(response.body);
|
|
174
|
+
assert(
|
|
175
|
+
result.success,
|
|
176
|
+
new ConnectorError(ConnectorErrorCodes.InvalidResponse, `invalid user response`)
|
|
177
|
+
);
|
|
178
|
+
const { sub, user_id, name, email, avatar_url: avatar, mobile } = result.data;
|
|
179
|
+
return {
|
|
180
|
+
id: sub,
|
|
181
|
+
name,
|
|
182
|
+
avatar,
|
|
183
|
+
email: conditional(email),
|
|
184
|
+
userId: conditional(user_id),
|
|
185
|
+
phone: conditional(mobile?.replace("+", "")),
|
|
186
|
+
rawData: jsonGuard.parse(response.body)
|
|
187
|
+
};
|
|
188
|
+
} catch (error) {
|
|
189
|
+
if (error instanceof ConnectorError) {
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
if (error instanceof HTTPError) {
|
|
193
|
+
const result = feishuErrorResponse.safeParse(error.response.body);
|
|
194
|
+
assert(
|
|
195
|
+
result.success,
|
|
196
|
+
new ConnectorError(
|
|
197
|
+
ConnectorErrorCodes.InvalidResponse,
|
|
198
|
+
JSON.stringify(error.response.body)
|
|
199
|
+
)
|
|
200
|
+
);
|
|
201
|
+
throw new ConnectorError(
|
|
202
|
+
ConnectorErrorCodes.SocialAccessTokenInvalid,
|
|
203
|
+
result.data.error_description
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
throw new ConnectorError(ConnectorErrorCodes.General, {
|
|
207
|
+
errorDescription: "Failed to get user info"
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
};
|
|
201
211
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
212
|
+
var createFeishuConnector = async ({ getConfig }) => {
|
|
213
|
+
return {
|
|
214
|
+
metadata: defaultMetadata,
|
|
215
|
+
type: ConnectorType.Social,
|
|
216
|
+
platform: ConnectorPlatform2.Web,
|
|
217
|
+
configGuard: feishuConfigGuard,
|
|
218
|
+
getAuthorizationUri: getAuthorizationUri(getConfig),
|
|
219
|
+
getUserInfo: getUserInfo(getConfig)
|
|
220
|
+
};
|
|
211
221
|
};
|
|
212
|
-
|
|
213
|
-
export {
|
|
222
|
+
var src_default = createFeishuConnector;
|
|
223
|
+
export {
|
|
224
|
+
authorizationCallbackHandler,
|
|
225
|
+
buildAuthorizationUri,
|
|
226
|
+
src_default as default,
|
|
227
|
+
getAccessToken,
|
|
228
|
+
getAuthorizationUri,
|
|
229
|
+
getUserInfo
|
|
230
|
+
};
|
|
231
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constant.ts","../src/types.ts"],"sourcesContent":["import { assert, conditional } from '@silverhand/essentials';\nimport { got, HTTPError } from 'got';\n\nimport type {\n CreateConnector,\n GetAuthorizationUri,\n GetConnectorConfig,\n GetUserInfo,\n SocialConnector,\n} from '@logto/connector-kit';\nimport {\n ConnectorError,\n ConnectorErrorCodes,\n ConnectorPlatform,\n ConnectorType,\n jsonGuard,\n validateConfig,\n} from '@logto/connector-kit';\n\nimport {\n accessTokenEndpoint,\n codeEndpoint,\n defaultMetadata,\n userInfoEndpoint,\n} from './constant.js';\nimport {\n feishuAccessTokenResponse,\n feishuAuthCodeGuard,\n feishuConfigGuard,\n feishuErrorResponse,\n feishuUserInfoResponse,\n} from './types.js';\n\nexport function buildAuthorizationUri(\n clientId: string,\n redirectUri: string,\n state: string\n): string {\n const queryParameters = new URLSearchParams({\n client_id: clientId,\n redirect_uri: encodeURI(redirectUri),\n response_type: 'code',\n state,\n });\n\n return `${codeEndpoint}?${queryParameters.toString()}`;\n}\n\nexport function getAuthorizationUri(getConfig: GetConnectorConfig): GetAuthorizationUri {\n return async function ({ state, redirectUri }) {\n const config = await getConfig(defaultMetadata.id);\n validateConfig(config, feishuConfigGuard);\n\n const { appId } = config;\n\n return buildAuthorizationUri(appId, redirectUri, state);\n };\n}\n\nexport async function authorizationCallbackHandler(data: unknown) {\n const result = feishuAuthCodeGuard.safeParse(data);\n assert(\n result.success,\n new ConnectorError(ConnectorErrorCodes.InvalidResponse, JSON.stringify(data))\n );\n\n return result.data;\n}\n\nexport async function getAccessToken(\n code: string,\n appId: string,\n appSecret: string,\n redirectUri: string\n) {\n try {\n const response = await got.post(accessTokenEndpoint, {\n headers: {\n contentType: 'application/www-form-urlencoded',\n },\n form: {\n grant_type: 'authorization_code',\n code,\n client_id: appId,\n client_secret: appSecret,\n redirect_uri: redirectUri,\n },\n responseType: 'json',\n });\n\n const result = feishuAccessTokenResponse.safeParse(response.body);\n assert(\n result.success,\n new ConnectorError(ConnectorErrorCodes.InvalidResponse, JSON.stringify(response.body))\n );\n\n if (result.data.access_token.length === 0) {\n throw new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid, 'access_token is empty');\n }\n\n return { accessToken: result.data.access_token };\n } catch (error: unknown) {\n if (error instanceof ConnectorError) {\n throw error;\n }\n\n if (error instanceof HTTPError) {\n const result = feishuErrorResponse.safeParse(error.response.body);\n assert(\n result.success,\n new ConnectorError(ConnectorErrorCodes.InvalidResponse, JSON.stringify(error.response.body))\n );\n\n throw new ConnectorError(\n ConnectorErrorCodes.SocialAuthCodeInvalid,\n result.data.error_description\n );\n }\n\n throw new ConnectorError(ConnectorErrorCodes.General, {\n errorDescription: 'Failed to get access token',\n });\n }\n}\n\nexport function getUserInfo(getConfig: GetConnectorConfig): GetUserInfo {\n return async function (data) {\n const { code, redirectUri } = await authorizationCallbackHandler(data);\n const config = await getConfig(defaultMetadata.id);\n validateConfig(config, feishuConfigGuard);\n\n const { accessToken } = await getAccessToken(code, config.appId, config.appSecret, redirectUri);\n\n try {\n const response = await got.get(userInfoEndpoint, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n responseType: 'json',\n });\n\n const result = feishuUserInfoResponse.safeParse(response.body);\n assert(\n result.success,\n new ConnectorError(ConnectorErrorCodes.InvalidResponse, `invalid user response`)\n );\n\n const { sub, user_id, name, email, avatar_url: avatar, mobile } = result.data;\n\n return {\n id: sub,\n name,\n avatar,\n email: conditional(email),\n userId: conditional(user_id),\n phone: conditional(mobile?.replace('+', '')),\n rawData: jsonGuard.parse(response.body),\n };\n } catch (error: unknown) {\n if (error instanceof ConnectorError) {\n throw error;\n }\n\n if (error instanceof HTTPError) {\n const result = feishuErrorResponse.safeParse(error.response.body);\n\n assert(\n result.success,\n new ConnectorError(\n ConnectorErrorCodes.InvalidResponse,\n JSON.stringify(error.response.body)\n )\n );\n\n throw new ConnectorError(\n ConnectorErrorCodes.SocialAccessTokenInvalid,\n result.data.error_description\n );\n }\n\n throw new ConnectorError(ConnectorErrorCodes.General, {\n errorDescription: 'Failed to get user info',\n });\n }\n };\n}\n\nconst createFeishuConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {\n return {\n metadata: defaultMetadata,\n type: ConnectorType.Social,\n platform: ConnectorPlatform.Web,\n configGuard: feishuConfigGuard,\n getAuthorizationUri: getAuthorizationUri(getConfig),\n getUserInfo: getUserInfo(getConfig),\n };\n};\n\nexport default createFeishuConnector;\n","import type { ConnectorMetadata } from '@logto/connector-kit';\nimport { ConnectorConfigFormItemType, ConnectorPlatform } from '@logto/connector-kit';\n\nexport const codeEndpoint = 'https://passport.feishu.cn/suite/passport/oauth/authorize';\n\nexport const accessTokenEndpoint = 'https://passport.feishu.cn/suite/passport/oauth/token';\n\nexport const userInfoEndpoint = 'https://passport.feishu.cn/suite/passport/oauth/userinfo';\n\nexport const defaultMetadata: ConnectorMetadata = {\n id: 'feishu-web',\n target: 'feishu',\n platform: ConnectorPlatform.Web,\n name: {\n en: 'Feishu',\n 'zh-CN': '飞书',\n },\n logo: './logo.svg',\n logoDark: null,\n description: {\n 'zh-CN': '飞书是一个由字节跳动开发的企业协作与管理平台',\n en: 'Feishu is an enterprise collaboration platform developed by ByteDance',\n },\n readme: './README.md',\n formItems: [\n {\n key: 'appId',\n label: 'App ID',\n type: ConnectorConfigFormItemType.Text,\n required: true,\n placeholder: '<app-id>',\n },\n {\n key: 'appSecret',\n label: 'App Secret',\n type: ConnectorConfigFormItemType.Text,\n required: true,\n placeholder: '<app-secret>',\n },\n ],\n};\n","import { z } from 'zod';\n\nexport const feishuConfigGuard = z.object({\n appId: z.string(),\n appSecret: z.string(),\n});\n\nexport type FeishuConfig = z.infer<typeof feishuConfigGuard>;\n\nexport const feishuAuthCodeGuard = z.object({\n code: z.string(),\n redirectUri: z.string(),\n});\n\nexport const feishuErrorResponse = z.object({\n error: z.string(),\n error_description: z.string().optional(),\n});\n\nexport const feishuAccessTokenResponse = z.object({\n access_token: z.string(),\n token_type: z.string(),\n expires_in: z.number(),\n refresh_token: z.string().optional(),\n refresh_expires_in: z.number().optional(),\n});\n\nexport const feishuUserInfoResponse = z.object({\n sub: z.string(),\n name: z.string(),\n picture: z.string(),\n open_id: z.string(),\n union_id: z.string(),\n en_name: z.string(),\n tenant_key: z.string(),\n avatar_url: z.string(),\n avatar_thumb: z.string(),\n avatar_middle: z.string(),\n avatar_big: z.string(),\n email: z.string().nullish(),\n user_id: z.string().nullish(),\n employee_no: z.string().nullish(),\n mobile: z.string().nullish(),\n});\n"],"mappings":"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","names":["ConnectorPlatform","ConnectorPlatform"]}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/connector-feishu-web",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Feishu web connector.",
|
|
5
5
|
"author": "Silverhand Inc. <contact@silverhand.io>",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@logto/connector-kit": "^4.0.0",
|
|
8
8
|
"@silverhand/essentials": "^2.9.1",
|
|
9
9
|
"got": "^14.0.0",
|
|
10
|
-
"snakecase-keys": "^8.0.
|
|
11
|
-
"zod": "^3.
|
|
10
|
+
"snakecase-keys": "^8.0.1",
|
|
11
|
+
"zod": "^3.23.8"
|
|
12
12
|
},
|
|
13
13
|
"main": "./lib/index.js",
|
|
14
14
|
"module": "./lib/index.js",
|
|
@@ -41,30 +41,25 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@rollup/plugin-commonjs": "^26.0.0",
|
|
45
|
-
"@rollup/plugin-json": "^6.1.0",
|
|
46
|
-
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
47
|
-
"@rollup/plugin-typescript": "^11.1.6",
|
|
48
44
|
"@silverhand/eslint-config": "6.0.1",
|
|
49
45
|
"@silverhand/ts-config": "6.0.0",
|
|
50
46
|
"@types/node": "^20.11.20",
|
|
51
47
|
"@types/supertest": "^6.0.2",
|
|
52
|
-
"@vitest/coverage-v8": "^
|
|
48
|
+
"@vitest/coverage-v8": "^2.0.0",
|
|
53
49
|
"eslint": "^8.56.0",
|
|
54
50
|
"lint-staged": "^15.0.2",
|
|
55
51
|
"nock": "^13.3.1",
|
|
56
52
|
"prettier": "^3.0.0",
|
|
57
|
-
"rollup": "^4.12.0",
|
|
58
|
-
"rollup-plugin-output-size": "^1.3.0",
|
|
59
53
|
"supertest": "^7.0.0",
|
|
60
|
-
"
|
|
61
|
-
"
|
|
54
|
+
"tsup": "^8.1.0",
|
|
55
|
+
"typescript": "^5.5.3",
|
|
56
|
+
"vitest": "^2.0.0"
|
|
62
57
|
},
|
|
63
58
|
"scripts": {
|
|
64
59
|
"precommit": "lint-staged",
|
|
65
|
-
"
|
|
66
|
-
"build": "
|
|
67
|
-
"dev": "
|
|
60
|
+
"check": "tsc --noEmit",
|
|
61
|
+
"build": "tsup",
|
|
62
|
+
"dev": "tsup --watch",
|
|
68
63
|
"lint": "eslint --ext .ts src",
|
|
69
64
|
"lint:report": "pnpm lint --format json --output-file report.json",
|
|
70
65
|
"test": "vitest src",
|
package/lib/constant.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { ConnectorMetadata } from '@logto/connector-kit';
|
|
2
|
-
export declare const codeEndpoint = "https://passport.feishu.cn/suite/passport/oauth/authorize";
|
|
3
|
-
export declare const accessTokenEndpoint = "https://passport.feishu.cn/suite/passport/oauth/token";
|
|
4
|
-
export declare const userInfoEndpoint = "https://passport.feishu.cn/suite/passport/oauth/userinfo";
|
|
5
|
-
export declare const defaultMetadata: ConnectorMetadata;
|
package/lib/index.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { CreateConnector, GetAuthorizationUri, GetConnectorConfig, GetUserInfo, SocialConnector } from '@logto/connector-kit';
|
|
2
|
-
export declare function buildAuthorizationUri(clientId: string, redirectUri: string, state: string): string;
|
|
3
|
-
export declare function getAuthorizationUri(getConfig: GetConnectorConfig): GetAuthorizationUri;
|
|
4
|
-
export declare function authorizationCallbackHandler(data: unknown): Promise<{
|
|
5
|
-
code: string;
|
|
6
|
-
redirectUri: string;
|
|
7
|
-
}>;
|
|
8
|
-
export declare function getAccessToken(code: string, appId: string, appSecret: string, redirectUri: string): Promise<{
|
|
9
|
-
accessToken: string;
|
|
10
|
-
}>;
|
|
11
|
-
export declare function getUserInfo(getConfig: GetConnectorConfig): GetUserInfo;
|
|
12
|
-
declare const createFeishuConnector: CreateConnector<SocialConnector>;
|
|
13
|
-
export default createFeishuConnector;
|
package/lib/mock.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { FeishuConfig } from './types.js';
|
|
2
|
-
export declare const mockedTimestamp = "2022-02-22 22:22:22";
|
|
3
|
-
export declare const mockedFeishuConfig: FeishuConfig;
|
|
4
|
-
export declare const mockedFeishuPublicParameters: {
|
|
5
|
-
format: string;
|
|
6
|
-
grantType: string;
|
|
7
|
-
timestamp: string;
|
|
8
|
-
version: string;
|
|
9
|
-
method: string;
|
|
10
|
-
};
|
package/lib/types.d.ts
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
export declare const feishuConfigGuard: z.ZodObject<{
|
|
3
|
-
appId: z.ZodString;
|
|
4
|
-
appSecret: z.ZodString;
|
|
5
|
-
}, "strip", z.ZodTypeAny, {
|
|
6
|
-
appId: string;
|
|
7
|
-
appSecret: string;
|
|
8
|
-
}, {
|
|
9
|
-
appId: string;
|
|
10
|
-
appSecret: string;
|
|
11
|
-
}>;
|
|
12
|
-
export type FeishuConfig = z.infer<typeof feishuConfigGuard>;
|
|
13
|
-
export declare const feishuAuthCodeGuard: z.ZodObject<{
|
|
14
|
-
code: z.ZodString;
|
|
15
|
-
redirectUri: z.ZodString;
|
|
16
|
-
}, "strip", z.ZodTypeAny, {
|
|
17
|
-
code: string;
|
|
18
|
-
redirectUri: string;
|
|
19
|
-
}, {
|
|
20
|
-
code: string;
|
|
21
|
-
redirectUri: string;
|
|
22
|
-
}>;
|
|
23
|
-
export declare const feishuErrorResponse: z.ZodObject<{
|
|
24
|
-
error: z.ZodString;
|
|
25
|
-
error_description: z.ZodOptional<z.ZodString>;
|
|
26
|
-
}, "strip", z.ZodTypeAny, {
|
|
27
|
-
error: string;
|
|
28
|
-
error_description?: string | undefined;
|
|
29
|
-
}, {
|
|
30
|
-
error: string;
|
|
31
|
-
error_description?: string | undefined;
|
|
32
|
-
}>;
|
|
33
|
-
export declare const feishuAccessTokenResponse: z.ZodObject<{
|
|
34
|
-
access_token: z.ZodString;
|
|
35
|
-
token_type: z.ZodString;
|
|
36
|
-
expires_in: z.ZodNumber;
|
|
37
|
-
refresh_token: z.ZodOptional<z.ZodString>;
|
|
38
|
-
refresh_expires_in: z.ZodOptional<z.ZodNumber>;
|
|
39
|
-
}, "strip", z.ZodTypeAny, {
|
|
40
|
-
access_token: string;
|
|
41
|
-
token_type: string;
|
|
42
|
-
expires_in: number;
|
|
43
|
-
refresh_token?: string | undefined;
|
|
44
|
-
refresh_expires_in?: number | undefined;
|
|
45
|
-
}, {
|
|
46
|
-
access_token: string;
|
|
47
|
-
token_type: string;
|
|
48
|
-
expires_in: number;
|
|
49
|
-
refresh_token?: string | undefined;
|
|
50
|
-
refresh_expires_in?: number | undefined;
|
|
51
|
-
}>;
|
|
52
|
-
export declare const feishuUserInfoResponse: z.ZodObject<{
|
|
53
|
-
sub: z.ZodString;
|
|
54
|
-
name: z.ZodString;
|
|
55
|
-
picture: z.ZodString;
|
|
56
|
-
open_id: z.ZodString;
|
|
57
|
-
union_id: z.ZodString;
|
|
58
|
-
en_name: z.ZodString;
|
|
59
|
-
tenant_key: z.ZodString;
|
|
60
|
-
avatar_url: z.ZodString;
|
|
61
|
-
avatar_thumb: z.ZodString;
|
|
62
|
-
avatar_middle: z.ZodString;
|
|
63
|
-
avatar_big: z.ZodString;
|
|
64
|
-
email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
65
|
-
user_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
66
|
-
employee_no: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
67
|
-
mobile: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
68
|
-
}, "strip", z.ZodTypeAny, {
|
|
69
|
-
sub: string;
|
|
70
|
-
name: string;
|
|
71
|
-
picture: string;
|
|
72
|
-
open_id: string;
|
|
73
|
-
union_id: string;
|
|
74
|
-
en_name: string;
|
|
75
|
-
tenant_key: string;
|
|
76
|
-
avatar_url: string;
|
|
77
|
-
avatar_thumb: string;
|
|
78
|
-
avatar_middle: string;
|
|
79
|
-
avatar_big: string;
|
|
80
|
-
email?: string | null | undefined;
|
|
81
|
-
user_id?: string | null | undefined;
|
|
82
|
-
employee_no?: string | null | undefined;
|
|
83
|
-
mobile?: string | null | undefined;
|
|
84
|
-
}, {
|
|
85
|
-
sub: string;
|
|
86
|
-
name: string;
|
|
87
|
-
picture: string;
|
|
88
|
-
open_id: string;
|
|
89
|
-
union_id: string;
|
|
90
|
-
en_name: string;
|
|
91
|
-
tenant_key: string;
|
|
92
|
-
avatar_url: string;
|
|
93
|
-
avatar_thumb: string;
|
|
94
|
-
avatar_middle: string;
|
|
95
|
-
avatar_big: string;
|
|
96
|
-
email?: string | null | undefined;
|
|
97
|
-
user_id?: string | null | undefined;
|
|
98
|
-
employee_no?: string | null | undefined;
|
|
99
|
-
mobile?: string | null | undefined;
|
|
100
|
-
}>;
|