@larksuiteoapi/node-sdk 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Lark Technologies Pte. Ltd.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice, shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,452 @@
1
+ # Feishu open interface SDK
2
+
3
+ [中文](https://github.com/larksuite/node-sdk/blob/main/README.zh.md)
4
+ ## Overview
5
+ [Feishu Open Platform](https://open.feishu.cn/document/ukTMukTMukTM/uITNz4iM1MjLyUzM) provides a series of atomic APIs on the server side to realize diversified functions, but the actual coding process is not very smooth: when using these APIs to complete operation, a lot of extra work needs to be considered, such as token acquisition and maintenance, data encryption and decryption, request signature verification, etc.; in the actual coding process, the semantics of function calls are missing, cause mental burden.
6
+
7
+ All of these make the overall development experience poor. In order to make the open capability easy to use, we have written this SDK, which integrates all the verbose logic into built-in processing, provides a complete type hints, and provides external semantics. Programming interface to improve coding experience.
8
+
9
+ ## Concept
10
+ - Development documentation: A reference to the open interface of the open platform, ** a must-see for developers, you can use the search function to query documents efficiently**. [More introduction instructions](https://open.feishu.cn/document/) .
11
+
12
+ - Developer background: The management background of the developer's development application, [more introduction](https://open.feishu.cn/app/).
13
+
14
+ - Enterprise self-built Application: The application can only be installed and used within the enterprise, [more introduction](https://open.feishu.cn/document/uQjL04CN/ukzM04SOzQjL5MDN).
15
+
16
+ - ISV Application: The app will be listed in the [ISV Application](https://app.feishu.cn/?lang=zh-CN)
17
+ Display, each enterprise can choose to install, [more introduction instructions](https://open.feishu.cn/document/uQjL04CN/ugTO5UjL4kTO14CO5kTN).
18
+
19
+ ## Installation
20
+ npm
21
+ ```shell script
22
+ npm install @larksuiteoapi/node-sdk
23
+ ````
24
+ yarn
25
+ ````
26
+ yarn add @larksuiteoapi/node-sdk
27
+ ````
28
+
29
+ ## How to use
30
+ Provides two versions of ECMAScript and CommonJS, and supports the use of native Javascript and Typescript. The examples are all taking Typescript as an example.
31
+
32
+ Typescript
33
+ ```typescript
34
+ import * as lark from '@larksuiteoapi/node-sdk';
35
+ ````
36
+ CommonJS
37
+ ````javascript
38
+ const lark = require('@larksuiteoapi/node-sdk');
39
+ ````
40
+ ECMAScript
41
+ ````javascript
42
+ import * as lark from '@larksuiteoapi/node-sdk';
43
+ ````
44
+ ### API Call
45
+ The list of all APIs on Feishu Open Platform: [click here](https://open.feishu.cn/document/ukTMukTMukTM/uYTM5UjL2ETO14iNxkTN/server-api-list).
46
+
47
+ The SDK provides a semantic calling method. You only need to construct a client instance according to the relevant parameters, and then use the semantic method (*client.business domain.resource.method*) on it to complete the API call, the calling process and the calling result. There are complete types for prompting, such as sending a message to a group chat:
48
+ ```typescript
49
+ import * as lark from '@larksuiteoapi/node-sdk';
50
+
51
+ const client = new lark. Client({
52
+ appId: 'app id',
53
+ appSecret: 'app secret',
54
+ appType: lark.AppType.SelfBuild,
55
+ domain: lark.Domain.Feishu,
56
+ });
57
+
58
+ const res = await client.im.message.create({
59
+ params: {
60
+ receive_id_type: 'chat_id',
61
+ },
62
+ data: {
63
+ receive_id: 'receive_id',
64
+ content: 'hello world',
65
+ msg_type: 'text',
66
+ },
67
+ });
68
+ ````
69
+ > Note: The SDK has made a complete type declaration for the call result of the API. In development, most of our focus is on the call result itself, but there are still a few scenarios where we need to pay attention to the details of the API call. The SDK puts this part of the content in the result’s prototype of the call, and if you need to get this part of the information, you can use `res.request` to get it.
70
+
71
+ > tips: If you want to debug an API, you can click the link in the comment to enter the API debugging platform for debugging:
72
+ ![](doc/debugger-tip.png)
73
+
74
+ #### Create Client
75
+ For self-built applications, you can use the following code to create a client:
76
+
77
+ ```typescript
78
+ import * as lark from '@larksuiteoapi/node-sdk';
79
+
80
+ const client = new lark. Client({
81
+ appId: 'app id',
82
+ appSecret: 'app secret'
83
+ });
84
+ ````
85
+
86
+ For store apps, the specified appType that needs to be displayed is lark.AppType.ISV:
87
+ ```typescript
88
+ import * as lark from '@larksuiteoapi/node-sdk';
89
+
90
+ const client = new lark. Client({
91
+ appId: 'app id',
92
+ appSecret: 'app secret',
93
+ appType: lark.AppType.ISV,
94
+ });
95
+ ````
96
+ **When using the client of the created store application to initiate an API call, you need to manually pass the [tenant_key](https://open.feishu.cn/document/ukTMukTMukTM/ukDNz4SO0MjL5QzM/g#d15ab5d)**, you can Use lark.withTenantKey to do it:
97
+ ```typescript
98
+ client.im.message.create({
99
+ params: {
100
+ receive_id_type: 'chat_id',
101
+ },
102
+ data: {
103
+ receive_id: 'chat_id',
104
+ content: 'hello world',
105
+ msg_type: 'text'
106
+ },
107
+ }, lark.withTenantKey('tenant key'));
108
+ ````
109
+
110
+ #### `Client` construction parameters:
111
+ | Parameter | Description | Type | Required | Default |
112
+ | ---- | ---- | ---- | ---- | ---- |
113
+ | appId | app id | string | yes | - |
114
+ | appSecret | app secret | string | yes | - |
115
+ | domain | The domain of the application, divided into Feishu (https://open.feishu.cn), lark (https://open.larksuite.com), others (the complete domain name needs to be passed) | Domain | string | no | Domain.Feishu |
116
+ | loggerLevel | Log Level | LoggerLevel | No | info |
117
+ | logger | - | Logger | No | - |
118
+ | cache | Cache | Cache | No | - |
119
+ | disableTokenCache | Whether to disable the cache, if disabled, the token will not be cached, and it will be re-pulled every time it needs to be used | boolean | No | false |
120
+ | appType | The type of application, divided into store application or self-built application | AppType | No | AppType.SelfBuild |
121
+ | helpDeskId | helpdesk id | string | no | - |
122
+ | helpDeskToken | helpdesk token | string | no | - |
123
+
124
+ #### Pagination
125
+ For the interface whose return value is presented in the form of pagination, it provides iterator encapsulation (the method name suffix is ​​WithIterator), which improves the usability and eliminates the tedious operation of repeatedly obtaining data according to page_token, such as obtaining the user list:
126
+ ``` typescript
127
+ // Process 20 pieces of data each time
128
+ for await (const items of await client.contact.user.listWithIterator({
129
+ params: {
130
+ department_id: '0',
131
+ page_size: 20,
132
+ },
133
+ })) {
134
+ console.log(items);
135
+ }
136
+
137
+ // You can also use next to manually control the iteration, fetching 20 pieces of data each time
138
+ const listIterator = await SDKClient.contact.user.listWithIterator({
139
+ params: {
140
+ department_id: '0',
141
+ page_size: 20,
142
+ },
143
+ });
144
+ const { value } = await listIterator[Symbol.asyncIterator]().next();
145
+ console.log(value);
146
+ ````
147
+ * Of course, you can also use the version without iterator encapsulation. In this case, you need to manually perform paging calls each time according to the returned page_token. *
148
+ #### File upload
149
+ In the same way as calling ordinary API, you can pass the parameters according to the type prompt, and the processing of file upload is encapsulated inside, such as:
150
+ ```typescript
151
+ const res = await client.im.file.create({
152
+ data: {
153
+ file_type: 'mp4',
154
+ file_name: 'test.mp4',
155
+ file: fs.readFileSync('file path'),
156
+ },
157
+ });
158
+ ````
159
+ #### File download
160
+ The returned binary stream is encapsulated, eliminating the processing of the stream itself, just call the writeFile method to write the data to the file, such as:
161
+ ```typescript
162
+ const resp = await client.im.file.get({
163
+ path: {
164
+ file_key: 'file key',
165
+ },
166
+ });
167
+ await resp.writeFile(`filepath.suffix`);
168
+ ````
169
+
170
+ #### Normal call
171
+ Some old versions of the open interface cannot generate corresponding semantic calling methods, and you need to use the request method on the client to make manual calls:
172
+ ```typescript
173
+ import * as lark from '@larksuiteoapi/node-sdk';
174
+
175
+ const client = new lark. Client({
176
+ appId: 'app id',
177
+ appSecret: 'app secret',
178
+ appType: lark.AppType.SelfBuild,
179
+ domain: lark.Domain.Feishu,
180
+ });
181
+
182
+ const res = await client. request({
183
+ method: 'POST',
184
+ url: 'xxx',
185
+ data: {},
186
+ params: {},
187
+ });
188
+ ````
189
+
190
+ #### Configure request options
191
+ If you want to modify the parameters of the request during the API call, such as carrying some headers, custom tenantToken, etc., you can use the second parameter of the request method to modify:
192
+ ```typescript
193
+ await client.im.message.create({
194
+ params: {
195
+ receive_id_type: 'chat_id',
196
+ },
197
+ data: {
198
+ receive_id: 'receive_id',
199
+ content: 'hello world',
200
+ msg_type: 'text',
201
+ },
202
+ }, {
203
+ headers: {
204
+ customizedHeaderKey: 'customizedHeaderValue'
205
+ }
206
+ });
207
+ ````
208
+ The SDK also encapsulates commonly used modification operations into methods, which can be used:
209
+
210
+ | Method | Description |
211
+ | ---- | ---- |
212
+ | withTenantKey | Set tenant key |
213
+ | withTenantToken | Set tenant token |
214
+ | withHelpDeskCredential | Whether to bring in the [Service Desk token](https://open.feishu.cn/document/ukTMukTMukTM/ugDOyYjL4gjM24CO4IjN) |
215
+ | withUserAccessToken | Set access token |
216
+ | withAll | Combines the results of the above methods |
217
+
218
+ ```typescript
219
+ await client.im.message.create({
220
+ params: {
221
+ receive_id_type: 'chat_id',
222
+ },
223
+ data: {
224
+ receive_id: 'receive_id',
225
+ content: 'hello world',
226
+ msg_type: 'text',
227
+ },
228
+ }, lark.withTenantToken('tenant token'));
229
+
230
+ await client.im.message.create({
231
+ params: {
232
+ receive_id_type: 'chat_id',
233
+ },
234
+ data: {
235
+ receive_id: 'receive_id',
236
+ content: 'hello world',
237
+ msg_type: 'text',
238
+ },
239
+ }, lark.withAll([
240
+ lark.withTenantToken('tenant token'),
241
+ lark.withTenantKey('tenant key')
242
+ ]));
243
+ ````
244
+
245
+ ### Events handling
246
+ For a list of all events opened on Feishu Open Platform, please click [here](https://open.feishu.cn/document/ukTMukTMukTM/uYDNxYjL2QTM24iN0EjN/event-list).
247
+
248
+ For the event processing scenario, we care about is only what kind of events to listen for, and what we do after the event occurs. other work such as data decryption we don't want to care about. The SDK provides an intuitive way to describe this part of the logic:
249
+ 1. Construct an instance of the event handler `EventDispatcher`;
250
+ 2. Register the events to be monitored and their handler functions on the instance;
251
+ 3. Bind the instance to the service;
252
+
253
+ `EventDispatcher` will perform operations such as data decryption internally. If no relevant parameters are passed, it will be automatically ignored.
254
+ ```typescript
255
+ import http from 'http';
256
+ import * as lark from '@larksuiteoapi/node-sdk';
257
+
258
+ const eventDispatcher = new lark.EventDispatcher({
259
+ encryptKey: 'encrypt key'
260
+ }).register({
261
+ 'im.message.receive_v1': async (data) => {
262
+ const chatId = data.message.chat_id;
263
+
264
+ const res = await client.im.message.create({
265
+ params: {
266
+ receive_id_type: 'chat_id',
267
+ },
268
+ data: {
269
+ receive_id: chatId,
270
+ content: 'hello world',
271
+ msg_type: 'text'
272
+ },
273
+ });
274
+ return res;
275
+ }
276
+ });
277
+
278
+ const server = http.createServer();
279
+ server.on('request', lark.adaptDefault('/webhook/event', eventDispatcher));
280
+ server.listen(3000);
281
+ ````
282
+
283
+ #### `EventDispatcher` constructor parameters
284
+
285
+ | Parameter | Description | Type | Required | Default |
286
+ | ---- | ---- | ---- | ---- | ---- |
287
+ | [encryptKey](https://open.feishu.cn/document/ukTMukTMukTM/uYDNxYjL2QTM24iN0EjN/event-subscription-configure-/encrypt-key-encryption-configuration-case) | Push data encryption key, required when enabling encrypted push use for data decryption | string | no | - |
288
+ | loggerLevel | log level | LoggerLevel | no | lark.LoggerLevel.info |
289
+ | logger | - | Logger | No | - |
290
+ | cache | Cache | Cache | No | - |
291
+
292
+ > Note: Some events are v1.0 version and are no longer maintained. The SDK retains support for them. It is strongly recommended to use new versions of events that are consistent with their functions. Move the mouse to the corresponding event subscription function to see the relevant documents:
293
+ ![](doc/deprecated.png)
294
+
295
+ #### Combined with express
296
+ The SDK provides an adapter for experss to convert eventDispatcher into express middleware, which can be seamlessly combined with services written using express (*The use of bodyParser in the example is not necessary, but the community mostly uses it to format body data*):
297
+ ```typescript
298
+ import * as lark from '@larksuiteoapi/node-sdk';
299
+ import express from 'express';
300
+ import bodyParser from 'body-parser';
301
+
302
+ const server = express();
303
+ server.use(bodyParser.json());
304
+
305
+ const eventDispatcher = new lark.EventDispatcher({
306
+ encryptKey: 'encryptKey',
307
+ }).register({
308
+ 'im.message.receive_v1': async (data) => {
309
+ const chatId = data.message.chat_id;
310
+
311
+ const res = await client.im.message.create({
312
+ params: {
313
+ receive_id_type: 'chat_id',
314
+ },
315
+ data: {
316
+ receive_id: chatId,
317
+ content: 'hello world',
318
+ msg_type: 'text'
319
+ },
320
+ });
321
+ return res;
322
+ }
323
+ });
324
+
325
+ server.use('/webhook/event', lark.adaptExpress(eventDispatcher));
326
+ server.listen(3000);
327
+ ````
328
+ #### Combined with Koa
329
+ The SDK provides an adapter for Koa to convert eventDispatcher into Koa middleware, which can be seamlessly combined with services written using Koa (*The use of koa-body in the example is not necessary, but the community mostly uses it to format body data*):
330
+ ```typescript
331
+ import * as lark from '@larksuiteoapi/node-sdk';
332
+ import Koa from 'koa';
333
+ import koaBody from 'koa-body';
334
+
335
+ const server = new Koa();
336
+ server.use(koaBody());
337
+
338
+ const eventDispatcher = new lark.EventDispatcher({
339
+ encryptKey: 'encryptKey',
340
+ }).register({
341
+ 'im.message.receive_v1': async (data) => {
342
+ const open_chat_id = data.message.chat_id;
343
+
344
+ const res = await client.im.message.create({
345
+ params: {
346
+ receive_id_type: 'chat_id',
347
+ },
348
+ data: {
349
+ receive_id: open_chat_id,
350
+ content: 'hello world',
351
+ msg_type: 'text'
352
+ },
353
+ });
354
+
355
+ return res;
356
+ },
357
+ });
358
+
359
+ server.use(nodeSdk.adaptKoa('/webhook/event', eventDispatcher));
360
+ server.listen(3000);
361
+ ````
362
+ #### Combined with koa-router
363
+ When using Koa to write services, in most cases, koa-router is used to process routing, so the SDK also provides adaptations for this situation:
364
+ ```typescript
365
+ import * as nodeSdk from '@larksuiteoapi/node-sdk';
366
+ import Koa from 'koa';
367
+ import Router from '@koa/router';
368
+ import koaBody from 'koa-body';
369
+
370
+ const server = new Koa();
371
+ const router = new Router();
372
+ server.use(koaBody());
373
+
374
+ onst eventDispatcher = new lark.EventDispatcher({
375
+ encryptKey: 'encryptKey',
376
+ }).register({
377
+ 'im.message.receive_v1': async (data) => {
378
+ const open_chat_id = data.message.chat_id;
379
+
380
+ const res = await client.im.message.create({
381
+ params: {
382
+ receive_id_type: 'chat_id',
383
+ },
384
+ data: {
385
+ receive_id: open_chat_id,
386
+ content: 'hello world',
387
+ msg_type: 'text'
388
+ },
389
+ });
390
+
391
+ return res;
392
+ },
393
+ });
394
+
395
+ router.post('/webhook/event', lark.adaptKoaRouter(eventDispatcher));
396
+ server.use(router.routes());
397
+ server.listen(3000);
398
+ ````
399
+ #### Custom adapter
400
+ If you want to adapt to services written by other libraries, you currently need to encapsulate the corresponding adapter yourself. Pass the received event data to the invoke method of the instantiated `eventDispatcher` for event processing:
401
+
402
+ ```typescript
403
+ const data = server.getData();
404
+ const resule = await dispatcher.invoke(data);
405
+ server.sendResult(result);
406
+ ````
407
+
408
+ ### [Message Card](https://open.feishu.cn/document/ukTMukTMukTM/uczM3QjL3MzN04yNzcDN)
409
+ The processing of the Message Card is also a kind of Event processing. The only difference between the two is that the processor of the Message Card is used to respond to the events generated by the interaction between the user and the Message Card. If the processor has a return value (*the value structure should be in line with the structure defined by [Message Card Structure](https://open.feishu.cn/document/ukTMukTMukTM/uEjNwUjLxYDM14SM2ATN)*), then the return value is used to update the responded message card:
410
+
411
+ ```typescript
412
+ import http from 'http';
413
+ import * as lark from '@larksuiteoapi/node-sdk';
414
+
415
+ const cardDispatcher = new lark.CardActionHandler(
416
+ {
417
+ encryptKey: 'encrypt key',
418
+ verificationToken: 'verification token'
419
+ },
420
+ async(data) => {
421
+ console.log(data);
422
+ return newCard;
423
+ }
424
+ );
425
+
426
+ const server = http.createServer();
427
+ server.on('request', lark.adaptDefault('/webhook/card', cardDispatcher));
428
+ server.listen(3000);
429
+ ````
430
+ #### `CardActionHandler` construction parameters
431
+
432
+ | Parameter | Description | Type | Required | Default |
433
+ | ---- | ---- | ---- | ---- | ---- |
434
+ | [encryptKey](https://open.feishu.cn/document/ukTMukTMukTM/uYDNxYjL2QTM24iN0EjN/event-subscription-configure-/encrypt-key-encryption-configuration-case) | Push data encryption key, required when enabling encrypted push use for data decryption | string | no | - |
435
+ | [verificationToken](https://open.feishu.cn/document/ukTMukTMukTM/uYzMxEjL2MTMx4iNzETM) | Security verification, it needs to be used when enabling message security verification | string | No | - |
436
+ | loggerLevel | Log Level | LoggerLevel | No | LoggerLevel.info |
437
+ | logger | - | Logger | No | - |
438
+ | cache | Cache | Cache | No | - |
439
+
440
+ ### Tool method
441
+ #### AESCipher
442
+ Decrypt. If [Encrypted Push](https://open.feishu.cn/document/ukTMukTMukTM/uYDNxYjL2QTM24iN0EjN/event-subscription-configure-/encrypt-key-encryption-configuration-case) is configured, the open platform will push encrypted data, At this time, the data needs to be decrypted, and this method can be called for convenient decryption. (In general, the decryption logic is built into the SDK, and no manual processing is required).
443
+ ```typescript
444
+ import * as lark from '@larksuiteoapi/node-sdk';
445
+
446
+ new lark.AESCipher('encrypt key').decrypt('content');
447
+ ````
448
+ ## LICENSE
449
+ MIT
450
+
451
+ ## Contact Us
452
+ Click [Server SDK](https://open.feishu.cn/document/ukTMukTMukTM/uETO1YjLxkTN24SM5UjN) in the upper right corner of the page [Is this document helpful to you? 】Submit feedback