@larksuiteoapi/node-sdk 1.60.0 → 1.61.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/README.md +62 -0
- package/README.zh.md +62 -0
- package/es/index.js +149 -1
- package/lib/index.js +149 -0
- package/package.json +1 -1
- package/types/index.d.ts +29 -1
package/README.md
CHANGED
|
@@ -627,6 +627,68 @@ server.listen(3000);
|
|
|
627
627
|
| logger | - | Logger | No | - |
|
|
628
628
|
| cache | Cache | Cache | No | - |
|
|
629
629
|
|
|
630
|
+
### App Registration
|
|
631
|
+
The SDK provides a `registerApp` method for one-click app creation based on the OAuth 2.0 Device Authorization Grant (RFC 8628) protocol. It returns a verification URL that users can open in Feishu/Lark to authorize and automatically register an app, obtaining credentials without manually creating one on the developer console.
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
import * as lark from '@larksuiteoapi/node-sdk';
|
|
635
|
+
|
|
636
|
+
try {
|
|
637
|
+
const result = await lark.registerApp({
|
|
638
|
+
onQRCodeReady(info) {
|
|
639
|
+
console.log(`Scan the QR code: ${info.url}`);
|
|
640
|
+
console.log(`Link expires in ${info.expireIn} seconds`);
|
|
641
|
+
},
|
|
642
|
+
onStatusChange(info) {
|
|
643
|
+
// Handle status changes: 'polling' | 'slow_down' | 'domain_switched'
|
|
644
|
+
},
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
console.log('App ID:', result.client_id);
|
|
648
|
+
console.log('App Secret:', result.client_secret);
|
|
649
|
+
|
|
650
|
+
// Use the credentials to initialize a Client
|
|
651
|
+
const client = new lark.Client({
|
|
652
|
+
appId: result.client_id,
|
|
653
|
+
appSecret: result.client_secret,
|
|
654
|
+
});
|
|
655
|
+
} catch (e) {
|
|
656
|
+
// e.code: 'access_denied' | 'expired_token' | 'abort' | ...
|
|
657
|
+
// e.description: error description
|
|
658
|
+
console.error(e.code, e.description);
|
|
659
|
+
}
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
#### `registerApp` parameters
|
|
663
|
+
|
|
664
|
+
| Parameter | Description | Type | Required | Default |
|
|
665
|
+
| ---- | ---- | ---- | ---- | ---- |
|
|
666
|
+
| domain | Custom accounts domain (host only) | string | No | `accounts.feishu.cn` |
|
|
667
|
+
| larkDomain | Custom Lark accounts domain (host only), used when tenant brand is detected as Lark | string | No | `accounts.larksuite.com` |
|
|
668
|
+
| source | Source identifier, appended to the QR code URL `from` parameter as `node-sdk/{source}` | string | No | - |
|
|
669
|
+
| signal | `AbortSignal` to cancel the polling | AbortSignal | No | - |
|
|
670
|
+
| onQRCodeReady | Callback when the verification URL is ready. Receives `{ url, expireIn }`. You can render the URL as a QR code for users to scan, or display it as a link | function | Yes | - |
|
|
671
|
+
| onStatusChange | Callback on polling status changes. Receives `{ status, interval? }`. Status values: `polling`, `slow_down`, `domain_switched` | function | No | - |
|
|
672
|
+
|
|
673
|
+
#### Return value
|
|
674
|
+
|
|
675
|
+
| Field | Type | Description |
|
|
676
|
+
| ---- | ---- | ---- |
|
|
677
|
+
| client_id | string | App ID |
|
|
678
|
+
| client_secret | string | App Secret |
|
|
679
|
+
| user_info | object (optional) | Scanning user info |
|
|
680
|
+
| user_info.open_id | string (optional) | User's open_id |
|
|
681
|
+
| user_info.tenant_brand | string (optional) | `"feishu"` or `"lark"` |
|
|
682
|
+
|
|
683
|
+
#### Error handling
|
|
684
|
+
The thrown error object contains `code` and `description` fields:
|
|
685
|
+
|
|
686
|
+
| code | Description |
|
|
687
|
+
| ---- | ---- |
|
|
688
|
+
| `access_denied` | User denied the authorization |
|
|
689
|
+
| `expired_token` | QR code expired or polling timed out |
|
|
690
|
+
| `abort` | Cancelled via AbortSignal |
|
|
691
|
+
|
|
630
692
|
### Tool method
|
|
631
693
|
#### AESCipher
|
|
632
694
|
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).
|
package/README.zh.md
CHANGED
|
@@ -627,6 +627,68 @@ server.listen(3000);
|
|
|
627
627
|
| logger | - | Logger | 否 | - |
|
|
628
628
|
| cache | 缓存器 | Cache | 否 | - |
|
|
629
629
|
|
|
630
|
+
### 一键创建应用
|
|
631
|
+
SDK提供了`registerApp`方法,基于 OAuth 2.0 Device Authorization Grant(RFC 8628)协议实现一键创建应用。该方法会返回一个验证链接,用户在飞书/Lark中打开该链接完成授权后,即可自动注册应用并获取凭据,无需手动到开发者后台创建。
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
import * as lark from '@larksuiteoapi/node-sdk';
|
|
635
|
+
|
|
636
|
+
try {
|
|
637
|
+
const result = await lark.registerApp({
|
|
638
|
+
onQRCodeReady(info) {
|
|
639
|
+
console.log(`请扫码: ${info.url}`);
|
|
640
|
+
console.log(`链接将在 ${info.expireIn} 秒后过期`);
|
|
641
|
+
},
|
|
642
|
+
onStatusChange(info) {
|
|
643
|
+
// 处理状态变化:'polling' | 'slow_down' | 'domain_switched'
|
|
644
|
+
},
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
console.log('App ID:', result.client_id);
|
|
648
|
+
console.log('App Secret:', result.client_secret);
|
|
649
|
+
|
|
650
|
+
// 用获取到的凭据初始化 Client
|
|
651
|
+
const client = new lark.Client({
|
|
652
|
+
appId: result.client_id,
|
|
653
|
+
appSecret: result.client_secret,
|
|
654
|
+
});
|
|
655
|
+
} catch (e) {
|
|
656
|
+
// e.code: 'access_denied' | 'expired_token' | 'abort' | ...
|
|
657
|
+
// e.description: 错误描述
|
|
658
|
+
console.error(e.code, e.description);
|
|
659
|
+
}
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
#### `registerApp`参数
|
|
663
|
+
|
|
664
|
+
| 参数 | 描述 | 类型 | 必须 | 默认 |
|
|
665
|
+
| ---- | ---- | ---- | ---- | ---- |
|
|
666
|
+
| domain | 自定义认证域名(仅 host 部分) | string | 否 | `accounts.feishu.cn` |
|
|
667
|
+
| larkDomain | 自定义 Lark 认证域名(仅 host 部分),检测到 Lark 租户时自动切换 | string | 否 | `accounts.larksuite.com` |
|
|
668
|
+
| source | 来源标识,拼入二维码 URL 的 `from` 参数,格式为 `node-sdk/{source}` | string | 否 | - |
|
|
669
|
+
| signal | 用于取消轮询的 `AbortSignal` | AbortSignal | 否 | - |
|
|
670
|
+
| onQRCodeReady | 验证链接就绪时的回调,参数为 `{ url, expireIn }`。可将 URL 渲染为二维码供用户扫码,或直接作为链接展示 | function | 是 | - |
|
|
671
|
+
| onStatusChange | 轮询状态变化时的回调,参数为 `{ status, interval? }`。status 取值:`polling`、`slow_down`、`domain_switched` | function | 否 | - |
|
|
672
|
+
|
|
673
|
+
#### 返回值
|
|
674
|
+
|
|
675
|
+
| 字段 | 类型 | 描述 |
|
|
676
|
+
| ---- | ---- | ---- |
|
|
677
|
+
| client_id | string | App ID |
|
|
678
|
+
| client_secret | string | App Secret |
|
|
679
|
+
| user_info | object(可选) | 扫码用户信息 |
|
|
680
|
+
| user_info.open_id | string(可选) | 扫码用户的 open_id |
|
|
681
|
+
| user_info.tenant_brand | string(可选) | `"feishu"` 或 `"lark"` |
|
|
682
|
+
|
|
683
|
+
#### 错误处理
|
|
684
|
+
抛出的错误对象包含 `code` 和 `description` 字段:
|
|
685
|
+
|
|
686
|
+
| code | 描述 |
|
|
687
|
+
| ---- | ---- |
|
|
688
|
+
| `access_denied` | 用户拒绝了授权 |
|
|
689
|
+
| `expired_token` | 二维码过期或轮询超时 |
|
|
690
|
+
| `abort` | 通过 AbortSignal 取消 |
|
|
691
|
+
|
|
630
692
|
### 工具方法
|
|
631
693
|
#### AESCipher
|
|
632
694
|
解密。如果配置了[加密推送](https://open.feishu.cn/document/ukTMukTMukTM/uYDNxYjL2QTM24iN0EjN/event-subscription-configure-/encrypt-key-encryption-configuration-case),开放平台会推送加密的数据,这时候需要对数据进行解密处理,调用此方法可以便捷的进行解密。(一般情况下,SDK中内置了解密逻辑,不需要手动进行处理)。
|
package/es/index.js
CHANGED
|
@@ -85895,4 +85895,152 @@ class Aily {
|
|
|
85895
85895
|
}
|
|
85896
85896
|
}
|
|
85897
85897
|
|
|
85898
|
-
|
|
85898
|
+
function createError(code, description) {
|
|
85899
|
+
return { code, description };
|
|
85900
|
+
}
|
|
85901
|
+
|
|
85902
|
+
const SDK_NAME = 'node-sdk';
|
|
85903
|
+
const DEFAULT_FEISHU_DOMAIN = 'accounts.feishu.cn';
|
|
85904
|
+
const DEFAULT_LARK_DOMAIN = 'accounts.larksuite.com';
|
|
85905
|
+
const ENDPOINT = '/oauth/v1/app/registration';
|
|
85906
|
+
function requestRegistration(baseUrl, params) {
|
|
85907
|
+
var _a;
|
|
85908
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
85909
|
+
try {
|
|
85910
|
+
const resp = yield defaultHttpInstance.post(`${baseUrl}${ENDPOINT}`, new URLSearchParams(params).toString(), {
|
|
85911
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
85912
|
+
});
|
|
85913
|
+
return resp;
|
|
85914
|
+
}
|
|
85915
|
+
catch (e) {
|
|
85916
|
+
// RFC 8628: authorization_pending, slow_down etc. are returned with HTTP 400
|
|
85917
|
+
if (e instanceof AxiosError && ((_a = e.response) === null || _a === void 0 ? void 0 : _a.data)) {
|
|
85918
|
+
return e.response.data;
|
|
85919
|
+
}
|
|
85920
|
+
throw e;
|
|
85921
|
+
}
|
|
85922
|
+
});
|
|
85923
|
+
}
|
|
85924
|
+
function begin(baseUrl) {
|
|
85925
|
+
return requestRegistration(baseUrl, {
|
|
85926
|
+
action: 'begin',
|
|
85927
|
+
archetype: 'PersonalAgent',
|
|
85928
|
+
auth_method: 'client_secret',
|
|
85929
|
+
request_user_info: 'open_id',
|
|
85930
|
+
});
|
|
85931
|
+
}
|
|
85932
|
+
function startPolling(ctx) {
|
|
85933
|
+
return new Promise((resolve, reject) => {
|
|
85934
|
+
var _a, _b;
|
|
85935
|
+
let { baseUrl, interval } = ctx;
|
|
85936
|
+
let domainSwitched = false;
|
|
85937
|
+
let pollTimer = null;
|
|
85938
|
+
let expireTimer = null;
|
|
85939
|
+
const cleanup = () => {
|
|
85940
|
+
var _a;
|
|
85941
|
+
if (pollTimer !== null) {
|
|
85942
|
+
clearTimeout(pollTimer);
|
|
85943
|
+
pollTimer = null;
|
|
85944
|
+
}
|
|
85945
|
+
if (expireTimer !== null) {
|
|
85946
|
+
clearTimeout(expireTimer);
|
|
85947
|
+
expireTimer = null;
|
|
85948
|
+
}
|
|
85949
|
+
(_a = ctx.signal) === null || _a === void 0 ? void 0 : _a.removeEventListener('abort', onAbort);
|
|
85950
|
+
};
|
|
85951
|
+
const onAbort = () => {
|
|
85952
|
+
cleanup();
|
|
85953
|
+
reject(createError('abort', 'Registration was aborted'));
|
|
85954
|
+
};
|
|
85955
|
+
if ((_a = ctx.signal) === null || _a === void 0 ? void 0 : _a.aborted) {
|
|
85956
|
+
return reject(createError('abort', 'Registration was aborted'));
|
|
85957
|
+
}
|
|
85958
|
+
(_b = ctx.signal) === null || _b === void 0 ? void 0 : _b.addEventListener('abort', onAbort, { once: true });
|
|
85959
|
+
expireTimer = setTimeout(() => {
|
|
85960
|
+
cleanup();
|
|
85961
|
+
reject(createError('expired_token', 'Polling timed out'));
|
|
85962
|
+
}, ctx.expireIn);
|
|
85963
|
+
const poll = () => __awaiter(this, void 0, void 0, function* () {
|
|
85964
|
+
var _c, _d, _e, _f, _g, _h;
|
|
85965
|
+
try {
|
|
85966
|
+
const pollRes = yield requestRegistration(baseUrl, {
|
|
85967
|
+
action: 'poll',
|
|
85968
|
+
device_code: ctx.deviceCode,
|
|
85969
|
+
});
|
|
85970
|
+
// Lark domain switch (once only)
|
|
85971
|
+
if (((_c = pollRes.user_info) === null || _c === void 0 ? void 0 : _c.tenant_brand) === 'lark' && !domainSwitched) {
|
|
85972
|
+
baseUrl = ctx.larkBaseUrl;
|
|
85973
|
+
domainSwitched = true;
|
|
85974
|
+
(_d = ctx.onStatusChange) === null || _d === void 0 ? void 0 : _d.call(ctx, { status: 'domain_switched' });
|
|
85975
|
+
poll();
|
|
85976
|
+
return;
|
|
85977
|
+
}
|
|
85978
|
+
// Success
|
|
85979
|
+
if (pollRes.client_id && pollRes.client_secret) {
|
|
85980
|
+
cleanup();
|
|
85981
|
+
resolve({
|
|
85982
|
+
client_id: pollRes.client_id,
|
|
85983
|
+
client_secret: pollRes.client_secret,
|
|
85984
|
+
user_info: pollRes.user_info,
|
|
85985
|
+
});
|
|
85986
|
+
return;
|
|
85987
|
+
}
|
|
85988
|
+
// Handle errors
|
|
85989
|
+
switch (pollRes.error) {
|
|
85990
|
+
case 'authorization_pending':
|
|
85991
|
+
(_e = ctx.onStatusChange) === null || _e === void 0 ? void 0 : _e.call(ctx, { status: 'polling' });
|
|
85992
|
+
break;
|
|
85993
|
+
case 'slow_down':
|
|
85994
|
+
interval += 5000;
|
|
85995
|
+
(_f = ctx.onStatusChange) === null || _f === void 0 ? void 0 : _f.call(ctx, { status: 'slow_down', interval: interval / 1000 });
|
|
85996
|
+
break;
|
|
85997
|
+
case 'access_denied':
|
|
85998
|
+
case 'expired_token':
|
|
85999
|
+
cleanup();
|
|
86000
|
+
reject(createError(pollRes.error, (_g = pollRes.error_description) !== null && _g !== void 0 ? _g : 'Unknown error'));
|
|
86001
|
+
return;
|
|
86002
|
+
default:
|
|
86003
|
+
if (pollRes.error) {
|
|
86004
|
+
cleanup();
|
|
86005
|
+
reject(createError(pollRes.error, (_h = pollRes.error_description) !== null && _h !== void 0 ? _h : 'Unknown error'));
|
|
86006
|
+
return;
|
|
86007
|
+
}
|
|
86008
|
+
break;
|
|
86009
|
+
}
|
|
86010
|
+
pollTimer = setTimeout(poll, interval);
|
|
86011
|
+
}
|
|
86012
|
+
catch (e) {
|
|
86013
|
+
cleanup();
|
|
86014
|
+
reject(e);
|
|
86015
|
+
}
|
|
86016
|
+
});
|
|
86017
|
+
poll();
|
|
86018
|
+
});
|
|
86019
|
+
}
|
|
86020
|
+
function registerApp(options) {
|
|
86021
|
+
var _a, _b, _c, _d;
|
|
86022
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
86023
|
+
const { domain, source, signal, onQRCodeReady, onStatusChange } = options;
|
|
86024
|
+
const baseUrl = `https://${domain !== null && domain !== void 0 ? domain : DEFAULT_FEISHU_DOMAIN}`;
|
|
86025
|
+
const beginRes = yield begin(baseUrl);
|
|
86026
|
+
const qrCodeUrl = new URL(beginRes.verification_uri_complete);
|
|
86027
|
+
qrCodeUrl.searchParams.set('from', 'sdk');
|
|
86028
|
+
qrCodeUrl.searchParams.set('source', source ? `${SDK_NAME}/${source}` : SDK_NAME);
|
|
86029
|
+
qrCodeUrl.searchParams.set('tp', 'sdk');
|
|
86030
|
+
onQRCodeReady({
|
|
86031
|
+
url: qrCodeUrl.toString(),
|
|
86032
|
+
expireIn: (_a = beginRes.expire_in) !== null && _a !== void 0 ? _a : 600,
|
|
86033
|
+
});
|
|
86034
|
+
return startPolling({
|
|
86035
|
+
baseUrl,
|
|
86036
|
+
deviceCode: beginRes.device_code,
|
|
86037
|
+
interval: ((_b = beginRes.interval) !== null && _b !== void 0 ? _b : 5) * 1000,
|
|
86038
|
+
expireIn: ((_c = beginRes.expire_in) !== null && _c !== void 0 ? _c : 600) * 1000,
|
|
86039
|
+
larkBaseUrl: `https://${(_d = options.larkDomain) !== null && _d !== void 0 ? _d : DEFAULT_LARK_DOMAIN}`,
|
|
86040
|
+
signal,
|
|
86041
|
+
onStatusChange,
|
|
86042
|
+
});
|
|
86043
|
+
});
|
|
86044
|
+
}
|
|
86045
|
+
|
|
86046
|
+
export { AESCipher, Aily, AppType, CAppTicket, CTenantAccessToken, CardActionHandler, Client, Domain, EventDispatcher, LoggerLevel, WSClient, adaptDefault, adaptExpress, adaptKoa, adaptKoaRouter, defaultHttpInstance, generateChallenge, messageCard, registerApp, withAll, withHelpDeskCredential, withTenantKey, withTenantToken, withUserAccessToken };
|
package/lib/index.js
CHANGED
|
@@ -85910,6 +85910,154 @@ class Aily {
|
|
|
85910
85910
|
}
|
|
85911
85911
|
}
|
|
85912
85912
|
|
|
85913
|
+
function createError(code, description) {
|
|
85914
|
+
return { code, description };
|
|
85915
|
+
}
|
|
85916
|
+
|
|
85917
|
+
const SDK_NAME = 'node-sdk';
|
|
85918
|
+
const DEFAULT_FEISHU_DOMAIN = 'accounts.feishu.cn';
|
|
85919
|
+
const DEFAULT_LARK_DOMAIN = 'accounts.larksuite.com';
|
|
85920
|
+
const ENDPOINT = '/oauth/v1/app/registration';
|
|
85921
|
+
function requestRegistration(baseUrl, params) {
|
|
85922
|
+
var _a;
|
|
85923
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
85924
|
+
try {
|
|
85925
|
+
const resp = yield defaultHttpInstance.post(`${baseUrl}${ENDPOINT}`, new URLSearchParams(params).toString(), {
|
|
85926
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
85927
|
+
});
|
|
85928
|
+
return resp;
|
|
85929
|
+
}
|
|
85930
|
+
catch (e) {
|
|
85931
|
+
// RFC 8628: authorization_pending, slow_down etc. are returned with HTTP 400
|
|
85932
|
+
if (e instanceof axios.AxiosError && ((_a = e.response) === null || _a === void 0 ? void 0 : _a.data)) {
|
|
85933
|
+
return e.response.data;
|
|
85934
|
+
}
|
|
85935
|
+
throw e;
|
|
85936
|
+
}
|
|
85937
|
+
});
|
|
85938
|
+
}
|
|
85939
|
+
function begin(baseUrl) {
|
|
85940
|
+
return requestRegistration(baseUrl, {
|
|
85941
|
+
action: 'begin',
|
|
85942
|
+
archetype: 'PersonalAgent',
|
|
85943
|
+
auth_method: 'client_secret',
|
|
85944
|
+
request_user_info: 'open_id',
|
|
85945
|
+
});
|
|
85946
|
+
}
|
|
85947
|
+
function startPolling(ctx) {
|
|
85948
|
+
return new Promise((resolve, reject) => {
|
|
85949
|
+
var _a, _b;
|
|
85950
|
+
let { baseUrl, interval } = ctx;
|
|
85951
|
+
let domainSwitched = false;
|
|
85952
|
+
let pollTimer = null;
|
|
85953
|
+
let expireTimer = null;
|
|
85954
|
+
const cleanup = () => {
|
|
85955
|
+
var _a;
|
|
85956
|
+
if (pollTimer !== null) {
|
|
85957
|
+
clearTimeout(pollTimer);
|
|
85958
|
+
pollTimer = null;
|
|
85959
|
+
}
|
|
85960
|
+
if (expireTimer !== null) {
|
|
85961
|
+
clearTimeout(expireTimer);
|
|
85962
|
+
expireTimer = null;
|
|
85963
|
+
}
|
|
85964
|
+
(_a = ctx.signal) === null || _a === void 0 ? void 0 : _a.removeEventListener('abort', onAbort);
|
|
85965
|
+
};
|
|
85966
|
+
const onAbort = () => {
|
|
85967
|
+
cleanup();
|
|
85968
|
+
reject(createError('abort', 'Registration was aborted'));
|
|
85969
|
+
};
|
|
85970
|
+
if ((_a = ctx.signal) === null || _a === void 0 ? void 0 : _a.aborted) {
|
|
85971
|
+
return reject(createError('abort', 'Registration was aborted'));
|
|
85972
|
+
}
|
|
85973
|
+
(_b = ctx.signal) === null || _b === void 0 ? void 0 : _b.addEventListener('abort', onAbort, { once: true });
|
|
85974
|
+
expireTimer = setTimeout(() => {
|
|
85975
|
+
cleanup();
|
|
85976
|
+
reject(createError('expired_token', 'Polling timed out'));
|
|
85977
|
+
}, ctx.expireIn);
|
|
85978
|
+
const poll = () => __awaiter(this, void 0, void 0, function* () {
|
|
85979
|
+
var _c, _d, _e, _f, _g, _h;
|
|
85980
|
+
try {
|
|
85981
|
+
const pollRes = yield requestRegistration(baseUrl, {
|
|
85982
|
+
action: 'poll',
|
|
85983
|
+
device_code: ctx.deviceCode,
|
|
85984
|
+
});
|
|
85985
|
+
// Lark domain switch (once only)
|
|
85986
|
+
if (((_c = pollRes.user_info) === null || _c === void 0 ? void 0 : _c.tenant_brand) === 'lark' && !domainSwitched) {
|
|
85987
|
+
baseUrl = ctx.larkBaseUrl;
|
|
85988
|
+
domainSwitched = true;
|
|
85989
|
+
(_d = ctx.onStatusChange) === null || _d === void 0 ? void 0 : _d.call(ctx, { status: 'domain_switched' });
|
|
85990
|
+
poll();
|
|
85991
|
+
return;
|
|
85992
|
+
}
|
|
85993
|
+
// Success
|
|
85994
|
+
if (pollRes.client_id && pollRes.client_secret) {
|
|
85995
|
+
cleanup();
|
|
85996
|
+
resolve({
|
|
85997
|
+
client_id: pollRes.client_id,
|
|
85998
|
+
client_secret: pollRes.client_secret,
|
|
85999
|
+
user_info: pollRes.user_info,
|
|
86000
|
+
});
|
|
86001
|
+
return;
|
|
86002
|
+
}
|
|
86003
|
+
// Handle errors
|
|
86004
|
+
switch (pollRes.error) {
|
|
86005
|
+
case 'authorization_pending':
|
|
86006
|
+
(_e = ctx.onStatusChange) === null || _e === void 0 ? void 0 : _e.call(ctx, { status: 'polling' });
|
|
86007
|
+
break;
|
|
86008
|
+
case 'slow_down':
|
|
86009
|
+
interval += 5000;
|
|
86010
|
+
(_f = ctx.onStatusChange) === null || _f === void 0 ? void 0 : _f.call(ctx, { status: 'slow_down', interval: interval / 1000 });
|
|
86011
|
+
break;
|
|
86012
|
+
case 'access_denied':
|
|
86013
|
+
case 'expired_token':
|
|
86014
|
+
cleanup();
|
|
86015
|
+
reject(createError(pollRes.error, (_g = pollRes.error_description) !== null && _g !== void 0 ? _g : 'Unknown error'));
|
|
86016
|
+
return;
|
|
86017
|
+
default:
|
|
86018
|
+
if (pollRes.error) {
|
|
86019
|
+
cleanup();
|
|
86020
|
+
reject(createError(pollRes.error, (_h = pollRes.error_description) !== null && _h !== void 0 ? _h : 'Unknown error'));
|
|
86021
|
+
return;
|
|
86022
|
+
}
|
|
86023
|
+
break;
|
|
86024
|
+
}
|
|
86025
|
+
pollTimer = setTimeout(poll, interval);
|
|
86026
|
+
}
|
|
86027
|
+
catch (e) {
|
|
86028
|
+
cleanup();
|
|
86029
|
+
reject(e);
|
|
86030
|
+
}
|
|
86031
|
+
});
|
|
86032
|
+
poll();
|
|
86033
|
+
});
|
|
86034
|
+
}
|
|
86035
|
+
function registerApp(options) {
|
|
86036
|
+
var _a, _b, _c, _d;
|
|
86037
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
86038
|
+
const { domain, source, signal, onQRCodeReady, onStatusChange } = options;
|
|
86039
|
+
const baseUrl = `https://${domain !== null && domain !== void 0 ? domain : DEFAULT_FEISHU_DOMAIN}`;
|
|
86040
|
+
const beginRes = yield begin(baseUrl);
|
|
86041
|
+
const qrCodeUrl = new URL(beginRes.verification_uri_complete);
|
|
86042
|
+
qrCodeUrl.searchParams.set('from', 'sdk');
|
|
86043
|
+
qrCodeUrl.searchParams.set('source', source ? `${SDK_NAME}/${source}` : SDK_NAME);
|
|
86044
|
+
qrCodeUrl.searchParams.set('tp', 'sdk');
|
|
86045
|
+
onQRCodeReady({
|
|
86046
|
+
url: qrCodeUrl.toString(),
|
|
86047
|
+
expireIn: (_a = beginRes.expire_in) !== null && _a !== void 0 ? _a : 600,
|
|
86048
|
+
});
|
|
86049
|
+
return startPolling({
|
|
86050
|
+
baseUrl,
|
|
86051
|
+
deviceCode: beginRes.device_code,
|
|
86052
|
+
interval: ((_b = beginRes.interval) !== null && _b !== void 0 ? _b : 5) * 1000,
|
|
86053
|
+
expireIn: ((_c = beginRes.expire_in) !== null && _c !== void 0 ? _c : 600) * 1000,
|
|
86054
|
+
larkBaseUrl: `https://${(_d = options.larkDomain) !== null && _d !== void 0 ? _d : DEFAULT_LARK_DOMAIN}`,
|
|
86055
|
+
signal,
|
|
86056
|
+
onStatusChange,
|
|
86057
|
+
});
|
|
86058
|
+
});
|
|
86059
|
+
}
|
|
86060
|
+
|
|
85913
86061
|
exports.AESCipher = AESCipher;
|
|
85914
86062
|
exports.Aily = Aily;
|
|
85915
86063
|
exports.CAppTicket = CAppTicket;
|
|
@@ -85925,6 +86073,7 @@ exports.adaptKoaRouter = adaptKoaRouter;
|
|
|
85925
86073
|
exports.defaultHttpInstance = defaultHttpInstance;
|
|
85926
86074
|
exports.generateChallenge = generateChallenge;
|
|
85927
86075
|
exports.messageCard = messageCard;
|
|
86076
|
+
exports.registerApp = registerApp;
|
|
85928
86077
|
exports.withAll = withAll;
|
|
85929
86078
|
exports.withHelpDeskCredential = withHelpDeskCredential;
|
|
85930
86079
|
exports.withTenantKey = withTenantKey;
|
package/package.json
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -293196,4 +293196,32 @@ declare class Aily {
|
|
|
293196
293196
|
};
|
|
293197
293197
|
}
|
|
293198
293198
|
|
|
293199
|
-
|
|
293199
|
+
interface QRCodeInfo {
|
|
293200
|
+
url: string;
|
|
293201
|
+
expireIn: number;
|
|
293202
|
+
}
|
|
293203
|
+
interface StatusChangeInfo {
|
|
293204
|
+
status: 'polling' | 'slow_down' | 'domain_switched';
|
|
293205
|
+
interval?: number;
|
|
293206
|
+
}
|
|
293207
|
+
interface RegisterAppOptions {
|
|
293208
|
+
domain?: string;
|
|
293209
|
+
larkDomain?: string;
|
|
293210
|
+
source?: string;
|
|
293211
|
+
signal?: AbortSignal;
|
|
293212
|
+
onQRCodeReady: (info: QRCodeInfo) => void;
|
|
293213
|
+
onStatusChange?: (info: StatusChangeInfo) => void;
|
|
293214
|
+
}
|
|
293215
|
+
interface UserInfo {
|
|
293216
|
+
open_id?: string;
|
|
293217
|
+
tenant_brand?: 'feishu' | 'lark';
|
|
293218
|
+
}
|
|
293219
|
+
interface RegisterAppResult {
|
|
293220
|
+
client_id: string;
|
|
293221
|
+
client_secret: string;
|
|
293222
|
+
user_info?: UserInfo;
|
|
293223
|
+
}
|
|
293224
|
+
|
|
293225
|
+
declare function registerApp(options: RegisterAppOptions): Promise<RegisterAppResult>;
|
|
293226
|
+
|
|
293227
|
+
export { AESCipher, Aily, AppType, CAppTicket, CTenantAccessToken, Cache, CardActionHandler, Client, Domain, EventDispatcher, IHandles as EventHandles, HttpInstance, HttpRequestOptions, InteractiveCard, InteractiveCardActionEvent, InteractiveCardActionItem, InteractiveCardButtonActionItem, InteractiveCardDatePickerActionItem, InteractiveCardDivElement, InteractiveCardDividerElement, InteractiveCardElement, InteractiveCardField, InteractiveCardImageElement, InteractiveCardImageItem, InteractiveCardLarkMdItem, InteractiveCardMarkdownElement, InteractiveCardNoteElement, InteractiveCardOverflowActionItem, InteractiveCardPlainTextItem, InteractiveCardSelectMenuActionItem, InteractiveCardTextItem, InteractiveCardTitle, InteractiveCardUrlItem, InterfaceCardActionElement, LoggerLevel, WSClient, adaptDefault, adaptExpress, adaptKoa, adaptKoaRouter, defaultHttpInstance, generateChallenge, messageCard, registerApp, withAll, withHelpDeskCredential, withTenantKey, withTenantToken, withUserAccessToken };
|