@nextclaw/channel-plugin-feishu 0.2.29-beta.0 → 0.2.29-beta.2
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/dist/index.d.ts +23 -0
- package/dist/index.js +45 -0
- package/dist/src/accounts.js +141 -0
- package/dist/src/app-scope-checker.js +36 -0
- package/dist/src/async.js +34 -0
- package/dist/src/auth-errors.js +72 -0
- package/dist/src/bitable.js +495 -0
- package/dist/src/bot.d.ts +35 -0
- package/dist/src/bot.js +941 -0
- package/dist/src/calendar-calendar.js +54 -0
- package/dist/src/calendar-event-attendee.js +98 -0
- package/dist/src/calendar-event.js +193 -0
- package/dist/src/calendar-freebusy.js +40 -0
- package/dist/src/calendar-shared.js +23 -0
- package/dist/src/calendar.js +16 -0
- package/dist/src/card-action.js +49 -0
- package/dist/src/channel.d.ts +7 -0
- package/dist/src/channel.js +413 -0
- package/dist/src/chat-schema.js +25 -0
- package/dist/src/chat.js +87 -0
- package/dist/src/client.d.ts +16 -0
- package/dist/src/client.js +112 -0
- package/dist/src/config-schema.d.ts +357 -0
- package/dist/src/dedup.js +126 -0
- package/dist/src/device-flow.js +109 -0
- package/dist/src/directory.js +101 -0
- package/dist/src/doc-schema.js +148 -0
- package/dist/src/docx-batch-insert.js +104 -0
- package/dist/src/docx-color-text.js +80 -0
- package/dist/src/docx-table-ops.js +197 -0
- package/dist/src/docx.js +858 -0
- package/dist/src/domains.js +14 -0
- package/dist/src/drive-schema.js +41 -0
- package/dist/src/drive.js +126 -0
- package/dist/src/dynamic-agent.js +93 -0
- package/dist/src/external-keys.js +13 -0
- package/dist/src/feishu-fetch.js +12 -0
- package/dist/src/identity.js +92 -0
- package/dist/src/lark-ticket.js +11 -0
- package/dist/src/media.d.ts +75 -0
- package/dist/src/media.js +304 -0
- package/dist/src/mention.d.ts +52 -0
- package/dist/src/mention.js +82 -0
- package/dist/src/monitor.account.d.ts +1 -0
- package/dist/src/monitor.account.js +393 -0
- package/dist/src/monitor.d.ts +11 -0
- package/dist/src/monitor.js +58 -0
- package/dist/src/monitor.startup.js +24 -0
- package/dist/src/monitor.state.d.ts +1 -0
- package/dist/src/monitor.state.js +80 -0
- package/dist/src/monitor.transport.js +167 -0
- package/dist/src/nextclaw-sdk/account-id.js +15 -0
- package/dist/src/nextclaw-sdk/core-channel.js +150 -0
- package/dist/src/nextclaw-sdk/core-pairing.js +151 -0
- package/dist/src/nextclaw-sdk/dedupe.js +164 -0
- package/dist/src/nextclaw-sdk/feishu.d.ts +1 -0
- package/dist/src/nextclaw-sdk/feishu.js +14 -0
- package/dist/src/nextclaw-sdk/history.js +69 -0
- package/dist/src/nextclaw-sdk/network-body.js +180 -0
- package/dist/src/nextclaw-sdk/network-fetch.js +63 -0
- package/dist/src/nextclaw-sdk/network-webhook.js +126 -0
- package/dist/src/nextclaw-sdk/network.js +4 -0
- package/dist/src/nextclaw-sdk/runtime-store.js +21 -0
- package/dist/src/nextclaw-sdk/secrets-config.js +65 -0
- package/dist/src/nextclaw-sdk/secrets-core.d.ts +1 -0
- package/dist/src/nextclaw-sdk/secrets-core.js +68 -0
- package/dist/src/nextclaw-sdk/secrets-prompt.js +193 -0
- package/dist/src/nextclaw-sdk/secrets.d.ts +1 -0
- package/dist/src/nextclaw-sdk/secrets.js +4 -0
- package/dist/src/nextclaw-sdk/types.d.ts +242 -0
- package/dist/src/oauth.js +171 -0
- package/dist/src/onboarding.js +381 -0
- package/dist/src/outbound.js +150 -0
- package/dist/src/perm-schema.js +49 -0
- package/dist/src/perm.js +90 -0
- package/dist/src/policy.js +61 -0
- package/dist/src/post.js +160 -0
- package/dist/src/probe.d.ts +11 -0
- package/dist/src/probe.js +85 -0
- package/dist/src/raw-request.js +24 -0
- package/dist/src/reactions.d.ts +67 -0
- package/dist/src/reactions.js +91 -0
- package/dist/src/reply-dispatcher.js +250 -0
- package/dist/src/runtime.js +5 -0
- package/dist/src/secret-input.js +3 -0
- package/dist/src/send-result.js +12 -0
- package/dist/src/send-target.js +22 -0
- package/dist/src/send.d.ts +51 -0
- package/dist/src/send.js +265 -0
- package/dist/src/sheets-shared.js +193 -0
- package/dist/src/sheets.js +95 -0
- package/dist/src/streaming-card.js +263 -0
- package/dist/src/targets.js +39 -0
- package/dist/src/task-comment.js +76 -0
- package/dist/src/task-shared.js +13 -0
- package/dist/src/task-subtask.js +79 -0
- package/dist/src/task-task.js +144 -0
- package/dist/src/task-tasklist.js +136 -0
- package/dist/src/task.js +16 -0
- package/dist/src/token-store.js +154 -0
- package/dist/src/tool-account.js +65 -0
- package/dist/src/tool-result.js +18 -0
- package/dist/src/tool-scopes.js +62 -0
- package/dist/src/tools-config.js +30 -0
- package/dist/src/types.d.ts +43 -0
- package/dist/src/typing.js +145 -0
- package/dist/src/uat-client.js +102 -0
- package/dist/src/user-tool-client.js +132 -0
- package/dist/src/user-tool-helpers.js +110 -0
- package/dist/src/user-tool-result.js +10 -0
- package/dist/src/wiki-schema.js +45 -0
- package/dist/src/wiki.js +144 -0
- package/package.json +8 -4
- package/index.ts +0 -75
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { OpenClawPluginApi } from "./src/nextclaw-sdk/types.js";
|
|
2
|
+
import { MentionTarget, buildMentionedCardContent, buildMentionedMessage, extractMentionTargets, extractMessageBody, formatMentionAllForCard, formatMentionAllForText, formatMentionForCard, formatMentionForText, isMentionForwardRequest } from "./src/mention.js";
|
|
3
|
+
import { editMessageFeishu, getMessageFeishu, sendCardFeishu, sendMessageFeishu, updateCardFeishu } from "./src/send.js";
|
|
4
|
+
import { monitorFeishuProvider } from "./src/monitor.js";
|
|
5
|
+
import { sendFileFeishu, sendImageFeishu, sendMediaFeishu, uploadFileFeishu, uploadImageFeishu } from "./src/media.js";
|
|
6
|
+
import { probeFeishu } from "./src/probe.js";
|
|
7
|
+
import { FeishuEmoji, addReactionFeishu, listReactionsFeishu, removeReactionFeishu } from "./src/reactions.js";
|
|
8
|
+
import { feishuPlugin } from "./src/channel.js";
|
|
9
|
+
|
|
10
|
+
//#region index.d.ts
|
|
11
|
+
declare const plugin: {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
configSchema: {
|
|
16
|
+
type: "object";
|
|
17
|
+
additionalProperties: false;
|
|
18
|
+
properties: Record<string, unknown>;
|
|
19
|
+
};
|
|
20
|
+
register(api: OpenClawPluginApi): void;
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { FeishuEmoji, type MentionTarget, addReactionFeishu, buildMentionedCardContent, buildMentionedMessage, plugin as default, editMessageFeishu, extractMentionTargets, extractMessageBody, feishuPlugin, formatMentionAllForCard, formatMentionAllForText, formatMentionForCard, formatMentionForText, getMessageFeishu, isMentionForwardRequest, listReactionsFeishu, monitorFeishuProvider, probeFeishu, removeReactionFeishu, sendCardFeishu, sendFileFeishu, sendImageFeishu, sendMediaFeishu, sendMessageFeishu, updateCardFeishu, uploadFileFeishu, uploadImageFeishu };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { emptyPluginConfigSchema } from "./src/nextclaw-sdk/core-channel.js";
|
|
2
|
+
import "./src/nextclaw-sdk/feishu.js";
|
|
3
|
+
import { registerFeishuCalendarTools } from "./src/calendar.js";
|
|
4
|
+
import { registerFeishuBitableTools } from "./src/bitable.js";
|
|
5
|
+
import { probeFeishu } from "./src/probe.js";
|
|
6
|
+
import { setFeishuRuntime } from "./src/runtime.js";
|
|
7
|
+
import { sendFileFeishu, sendImageFeishu, sendMediaFeishu, uploadFileFeishu, uploadImageFeishu } from "./src/media.js";
|
|
8
|
+
import { buildMentionedCardContent, buildMentionedMessage, extractMentionTargets, extractMessageBody, formatMentionAllForCard, formatMentionAllForText, formatMentionForCard, formatMentionForText, isMentionForwardRequest } from "./src/mention.js";
|
|
9
|
+
import { editMessageFeishu, getMessageFeishu, sendCardFeishu, sendMessageFeishu, updateCardFeishu } from "./src/send.js";
|
|
10
|
+
import { feishuPlugin } from "./src/channel.js";
|
|
11
|
+
import { registerFeishuChatTools } from "./src/chat.js";
|
|
12
|
+
import { registerFeishuDocTools } from "./src/docx.js";
|
|
13
|
+
import { registerFeishuDriveTools } from "./src/drive.js";
|
|
14
|
+
import { registerFeishuIdentityTools } from "./src/identity.js";
|
|
15
|
+
import { registerFeishuOAuthTool } from "./src/oauth.js";
|
|
16
|
+
import { registerFeishuPermTools } from "./src/perm.js";
|
|
17
|
+
import { registerFeishuSheetsTools } from "./src/sheets.js";
|
|
18
|
+
import { registerFeishuTaskTools } from "./src/task.js";
|
|
19
|
+
import { registerFeishuWikiTools } from "./src/wiki.js";
|
|
20
|
+
import { monitorFeishuProvider } from "./src/monitor.js";
|
|
21
|
+
import { FeishuEmoji, addReactionFeishu, listReactionsFeishu, removeReactionFeishu } from "./src/reactions.js";
|
|
22
|
+
//#region index.ts
|
|
23
|
+
const plugin = {
|
|
24
|
+
id: "feishu",
|
|
25
|
+
name: "Feishu",
|
|
26
|
+
description: "Feishu/Lark channel plugin",
|
|
27
|
+
configSchema: emptyPluginConfigSchema(),
|
|
28
|
+
register(api) {
|
|
29
|
+
setFeishuRuntime(api.runtime);
|
|
30
|
+
api.registerChannel({ plugin: feishuPlugin });
|
|
31
|
+
registerFeishuDocTools(api);
|
|
32
|
+
registerFeishuChatTools(api);
|
|
33
|
+
registerFeishuWikiTools(api);
|
|
34
|
+
registerFeishuDriveTools(api);
|
|
35
|
+
registerFeishuPermTools(api);
|
|
36
|
+
registerFeishuBitableTools(api);
|
|
37
|
+
registerFeishuCalendarTools(api);
|
|
38
|
+
registerFeishuTaskTools(api);
|
|
39
|
+
registerFeishuSheetsTools(api);
|
|
40
|
+
registerFeishuIdentityTools(api);
|
|
41
|
+
registerFeishuOAuthTool(api);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { FeishuEmoji, addReactionFeishu, buildMentionedCardContent, buildMentionedMessage, plugin as default, editMessageFeishu, extractMentionTargets, extractMessageBody, feishuPlugin, formatMentionAllForCard, formatMentionAllForText, formatMentionForCard, formatMentionForText, getMessageFeishu, isMentionForwardRequest, listReactionsFeishu, monitorFeishuProvider, probeFeishu, removeReactionFeishu, sendCardFeishu, sendFileFeishu, sendImageFeishu, sendMediaFeishu, sendMessageFeishu, updateCardFeishu, uploadFileFeishu, uploadImageFeishu };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "./nextclaw-sdk/account-id.js";
|
|
2
|
+
import { normalizeResolvedSecretInputString, normalizeSecretInputString } from "./nextclaw-sdk/secrets-core.js";
|
|
3
|
+
import "./secret-input.js";
|
|
4
|
+
//#region src/accounts.ts
|
|
5
|
+
/**
|
|
6
|
+
* List all configured account IDs from the accounts field.
|
|
7
|
+
*/
|
|
8
|
+
function listConfiguredAccountIds(cfg) {
|
|
9
|
+
const accounts = (cfg?.channels?.feishu)?.accounts;
|
|
10
|
+
if (!accounts || typeof accounts !== "object") return [];
|
|
11
|
+
return Object.keys(accounts).filter(Boolean);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* List all Feishu account IDs.
|
|
15
|
+
* If no accounts are configured, returns [DEFAULT_ACCOUNT_ID] for backward compatibility.
|
|
16
|
+
*/
|
|
17
|
+
function listFeishuAccountIds(cfg) {
|
|
18
|
+
const ids = listConfiguredAccountIds(cfg);
|
|
19
|
+
if (ids.length === 0) return [DEFAULT_ACCOUNT_ID];
|
|
20
|
+
return [...ids].toSorted((a, b) => a.localeCompare(b));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the default account selection and its source.
|
|
24
|
+
*/
|
|
25
|
+
function resolveDefaultFeishuAccountSelection(cfg) {
|
|
26
|
+
const preferredRaw = (cfg?.channels?.feishu)?.defaultAccount?.trim();
|
|
27
|
+
const preferred = preferredRaw ? normalizeAccountId(preferredRaw) : void 0;
|
|
28
|
+
if (preferred) return {
|
|
29
|
+
accountId: preferred,
|
|
30
|
+
source: "explicit-default"
|
|
31
|
+
};
|
|
32
|
+
const ids = listFeishuAccountIds(cfg);
|
|
33
|
+
if (ids.includes("default")) return {
|
|
34
|
+
accountId: DEFAULT_ACCOUNT_ID,
|
|
35
|
+
source: "mapped-default"
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
accountId: ids[0] ?? "default",
|
|
39
|
+
source: "fallback"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolve the default account ID.
|
|
44
|
+
*/
|
|
45
|
+
function resolveDefaultFeishuAccountId(cfg) {
|
|
46
|
+
return resolveDefaultFeishuAccountSelection(cfg).accountId;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the raw account-specific config.
|
|
50
|
+
*/
|
|
51
|
+
function resolveAccountConfig(cfg, accountId) {
|
|
52
|
+
const accounts = (cfg?.channels?.feishu)?.accounts;
|
|
53
|
+
if (!accounts || typeof accounts !== "object") return;
|
|
54
|
+
return accounts[accountId];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Merge top-level config with account-specific config.
|
|
58
|
+
* Account-specific fields override top-level fields.
|
|
59
|
+
*/
|
|
60
|
+
function mergeFeishuAccountConfig(cfg, accountId) {
|
|
61
|
+
const { accounts: _ignored, defaultAccount: _ignoredDefaultAccount, ...base } = cfg?.channels?.feishu ?? {};
|
|
62
|
+
const account = resolveAccountConfig(cfg, accountId) ?? {};
|
|
63
|
+
return {
|
|
64
|
+
...base,
|
|
65
|
+
...account
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function resolveFeishuCredentials(cfg, options) {
|
|
69
|
+
const normalizeString = (value) => {
|
|
70
|
+
if (typeof value !== "string") return;
|
|
71
|
+
const trimmed = value.trim();
|
|
72
|
+
return trimmed ? trimmed : void 0;
|
|
73
|
+
};
|
|
74
|
+
const resolveSecretLike = (value, path) => {
|
|
75
|
+
const asString = normalizeString(value);
|
|
76
|
+
if (asString) return asString;
|
|
77
|
+
if (options?.allowUnresolvedSecretRef && typeof value === "object" && value !== null) {
|
|
78
|
+
const rec = value;
|
|
79
|
+
const source = normalizeString(rec.source)?.toLowerCase();
|
|
80
|
+
const id = normalizeString(rec.id);
|
|
81
|
+
if (source === "env" && id) {
|
|
82
|
+
const envValue = normalizeString(process.env[id]);
|
|
83
|
+
if (envValue) return envValue;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (options?.allowUnresolvedSecretRef) return normalizeSecretInputString(value);
|
|
87
|
+
return normalizeResolvedSecretInputString({
|
|
88
|
+
value,
|
|
89
|
+
path
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
const appId = resolveSecretLike(cfg?.appId, "channels.feishu.appId");
|
|
93
|
+
const appSecret = resolveSecretLike(cfg?.appSecret, "channels.feishu.appSecret");
|
|
94
|
+
if (!appId || !appSecret) return null;
|
|
95
|
+
return {
|
|
96
|
+
appId,
|
|
97
|
+
appSecret,
|
|
98
|
+
encryptKey: (cfg?.connectionMode ?? "websocket") === "webhook" ? resolveSecretLike(cfg?.encryptKey, "channels.feishu.encryptKey") : normalizeString(cfg?.encryptKey),
|
|
99
|
+
verificationToken: resolveSecretLike(cfg?.verificationToken, "channels.feishu.verificationToken"),
|
|
100
|
+
domain: cfg?.domain ?? "feishu"
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Resolve a complete Feishu account with merged config.
|
|
105
|
+
*/
|
|
106
|
+
function resolveFeishuAccount(params) {
|
|
107
|
+
const hasExplicitAccountId = typeof params.accountId === "string" && params.accountId.trim() !== "";
|
|
108
|
+
const defaultSelection = hasExplicitAccountId ? null : resolveDefaultFeishuAccountSelection(params.cfg);
|
|
109
|
+
const accountId = hasExplicitAccountId ? normalizeAccountId(params.accountId) : defaultSelection?.accountId ?? "default";
|
|
110
|
+
const selectionSource = hasExplicitAccountId ? "explicit" : defaultSelection?.source ?? "fallback";
|
|
111
|
+
const baseEnabled = (params.cfg.channels?.feishu)?.enabled !== false;
|
|
112
|
+
const merged = mergeFeishuAccountConfig(params.cfg, accountId);
|
|
113
|
+
const accountEnabled = merged.enabled !== false;
|
|
114
|
+
const enabled = baseEnabled && accountEnabled;
|
|
115
|
+
const creds = resolveFeishuCredentials(merged);
|
|
116
|
+
const accountName = merged.name;
|
|
117
|
+
return {
|
|
118
|
+
accountId,
|
|
119
|
+
selectionSource,
|
|
120
|
+
enabled,
|
|
121
|
+
configured: Boolean(creds),
|
|
122
|
+
name: typeof accountName === "string" ? accountName.trim() || void 0 : void 0,
|
|
123
|
+
appId: creds?.appId,
|
|
124
|
+
appSecret: creds?.appSecret,
|
|
125
|
+
encryptKey: creds?.encryptKey,
|
|
126
|
+
verificationToken: creds?.verificationToken,
|
|
127
|
+
domain: creds?.domain ?? "feishu",
|
|
128
|
+
config: merged
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* List all enabled and configured accounts.
|
|
133
|
+
*/
|
|
134
|
+
function listEnabledFeishuAccounts(cfg) {
|
|
135
|
+
return listFeishuAccountIds(cfg).map((accountId) => resolveFeishuAccount({
|
|
136
|
+
cfg,
|
|
137
|
+
accountId
|
|
138
|
+
})).filter((account) => account.enabled && account.configured);
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
141
|
+
export { listEnabledFeishuAccounts, listFeishuAccountIds, resolveDefaultFeishuAccountId, resolveFeishuAccount, resolveFeishuCredentials };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { AppScopeCheckFailedError } from "./auth-errors.js";
|
|
2
|
+
//#region src/app-scope-checker.ts
|
|
3
|
+
const cache = /* @__PURE__ */ new Map();
|
|
4
|
+
const CACHE_TTL_MS = 30 * 1e3;
|
|
5
|
+
function invalidateAppScopeCache(appId) {
|
|
6
|
+
cache.delete(appId);
|
|
7
|
+
}
|
|
8
|
+
async function getAppGrantedScopes(sdk, appId, tokenType) {
|
|
9
|
+
const cached = cache.get(appId);
|
|
10
|
+
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) return cached.rawScopes.filter((scope) => !tokenType || !scope.token_types || scope.token_types.includes(tokenType)).map((scope) => scope.scope);
|
|
11
|
+
try {
|
|
12
|
+
const response = await sdk.request({
|
|
13
|
+
method: "GET",
|
|
14
|
+
url: `/open-apis/application/v6/applications/${appId}`,
|
|
15
|
+
params: { lang: "zh_cn" }
|
|
16
|
+
});
|
|
17
|
+
if (response.code !== 0) throw new AppScopeCheckFailedError(appId);
|
|
18
|
+
const rawScopes = response.data?.app?.scopes?.filter((scope) => typeof scope.scope === "string" && scope.scope.length > 0) ?? [];
|
|
19
|
+
cache.set(appId, {
|
|
20
|
+
rawScopes,
|
|
21
|
+
fetchedAt: Date.now()
|
|
22
|
+
});
|
|
23
|
+
return rawScopes.filter((scope) => !tokenType || !scope.token_types || scope.token_types.includes(tokenType)).map((scope) => scope.scope);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (error instanceof AppScopeCheckFailedError) throw error;
|
|
26
|
+
const statusCode = error.response?.status ?? error.status ?? error.statusCode;
|
|
27
|
+
if (statusCode === 400 || statusCode === 403) throw new AppScopeCheckFailedError(appId);
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function missingScopes(appGranted, apiRequired) {
|
|
32
|
+
const granted = new Set(appGranted);
|
|
33
|
+
return apiRequired.filter((scope) => !granted.has(scope));
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { getAppGrantedScopes, invalidateAppScopeCache, missingScopes };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/async.ts
|
|
2
|
+
const RACE_TIMEOUT = Symbol("race-timeout");
|
|
3
|
+
const RACE_ABORT = Symbol("race-abort");
|
|
4
|
+
async function raceWithTimeoutAndAbort(promise, options = {}) {
|
|
5
|
+
if (options.abortSignal?.aborted) return { status: "aborted" };
|
|
6
|
+
if (options.timeoutMs === void 0 && !options.abortSignal) return {
|
|
7
|
+
status: "resolved",
|
|
8
|
+
value: await promise
|
|
9
|
+
};
|
|
10
|
+
let timeoutHandle;
|
|
11
|
+
let abortHandler;
|
|
12
|
+
const contenders = [promise];
|
|
13
|
+
if (options.timeoutMs !== void 0) contenders.push(new Promise((resolve) => {
|
|
14
|
+
timeoutHandle = setTimeout(() => resolve(RACE_TIMEOUT), options.timeoutMs);
|
|
15
|
+
}));
|
|
16
|
+
if (options.abortSignal) contenders.push(new Promise((resolve) => {
|
|
17
|
+
abortHandler = () => resolve(RACE_ABORT);
|
|
18
|
+
options.abortSignal?.addEventListener("abort", abortHandler, { once: true });
|
|
19
|
+
}));
|
|
20
|
+
try {
|
|
21
|
+
const result = await Promise.race(contenders);
|
|
22
|
+
if (result === RACE_TIMEOUT) return { status: "timeout" };
|
|
23
|
+
if (result === RACE_ABORT) return { status: "aborted" };
|
|
24
|
+
return {
|
|
25
|
+
status: "resolved",
|
|
26
|
+
value: result
|
|
27
|
+
};
|
|
28
|
+
} finally {
|
|
29
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
30
|
+
if (abortHandler) options.abortSignal?.removeEventListener("abort", abortHandler);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { raceWithTimeoutAndAbort };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
//#region src/auth-errors.ts
|
|
2
|
+
const LARK_ERROR = {
|
|
3
|
+
APP_SCOPE_MISSING: 99991672,
|
|
4
|
+
USER_SCOPE_INSUFFICIENT: 99991679,
|
|
5
|
+
TOKEN_INVALID: 99991668,
|
|
6
|
+
TOKEN_EXPIRED: 99991677,
|
|
7
|
+
REFRESH_TOKEN_INVALID: 20026,
|
|
8
|
+
REFRESH_TOKEN_EXPIRED: 20037,
|
|
9
|
+
REFRESH_TOKEN_REVOKED: 20064,
|
|
10
|
+
REFRESH_TOKEN_ALREADY_USED: 20073,
|
|
11
|
+
REFRESH_SERVER_ERROR: 20050
|
|
12
|
+
};
|
|
13
|
+
const REFRESH_TOKEN_RETRYABLE = new Set([LARK_ERROR.REFRESH_SERVER_ERROR]);
|
|
14
|
+
const TOKEN_RETRY_CODES = new Set([LARK_ERROR.TOKEN_INVALID, LARK_ERROR.TOKEN_EXPIRED]);
|
|
15
|
+
var NeedAuthorizationError = class extends Error {
|
|
16
|
+
userOpenId;
|
|
17
|
+
constructor(userOpenId) {
|
|
18
|
+
super("need_user_authorization");
|
|
19
|
+
this.name = "NeedAuthorizationError";
|
|
20
|
+
this.userOpenId = userOpenId;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
var AppScopeCheckFailedError = class extends Error {
|
|
24
|
+
appId;
|
|
25
|
+
constructor(appId) {
|
|
26
|
+
super("应用缺少 application:application:self_manage 权限,无法查询应用权限配置。");
|
|
27
|
+
this.name = "AppScopeCheckFailedError";
|
|
28
|
+
this.appId = appId;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var AppScopeMissingError = class extends Error {
|
|
32
|
+
apiName;
|
|
33
|
+
missingScopes;
|
|
34
|
+
appId;
|
|
35
|
+
constructor(info) {
|
|
36
|
+
super(`应用缺少权限 [${info.scopes.join(", ")}],请管理员在飞书开放平台开通。`);
|
|
37
|
+
this.name = "AppScopeMissingError";
|
|
38
|
+
this.apiName = info.apiName;
|
|
39
|
+
this.missingScopes = info.scopes;
|
|
40
|
+
this.appId = info.appId;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var UserAuthRequiredError = class extends Error {
|
|
44
|
+
userOpenId;
|
|
45
|
+
apiName;
|
|
46
|
+
requiredScopes;
|
|
47
|
+
appScopeVerified;
|
|
48
|
+
appId;
|
|
49
|
+
constructor(userOpenId, info) {
|
|
50
|
+
super("need_user_authorization");
|
|
51
|
+
this.name = "UserAuthRequiredError";
|
|
52
|
+
this.userOpenId = userOpenId;
|
|
53
|
+
this.apiName = info.apiName;
|
|
54
|
+
this.requiredScopes = info.scopes;
|
|
55
|
+
this.appScopeVerified = info.appScopeVerified ?? true;
|
|
56
|
+
this.appId = info.appId;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var UserScopeInsufficientError = class extends Error {
|
|
60
|
+
userOpenId;
|
|
61
|
+
apiName;
|
|
62
|
+
missingScopes;
|
|
63
|
+
constructor(userOpenId, info) {
|
|
64
|
+
super("user_scope_insufficient");
|
|
65
|
+
this.name = "UserScopeInsufficientError";
|
|
66
|
+
this.userOpenId = userOpenId;
|
|
67
|
+
this.apiName = info.apiName;
|
|
68
|
+
this.missingScopes = info.scopes;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
//#endregion
|
|
72
|
+
export { AppScopeCheckFailedError, AppScopeMissingError, LARK_ERROR, NeedAuthorizationError, REFRESH_TOKEN_RETRYABLE, TOKEN_RETRY_CODES, UserAuthRequiredError, UserScopeInsufficientError };
|