oasis_test_v2 2.2.113 → 2.2.115
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.js +472 -21
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -20479,7 +20479,8 @@ var init_feishu = __esm({
|
|
|
20479
20479
|
"FEISHU_REFRESH_TOKEN_EXPIRES_AT",
|
|
20480
20480
|
FEISHU_USER_OPEN_ID_VAR,
|
|
20481
20481
|
FEISHU_AUTHORIZED_BY_VAR,
|
|
20482
|
-
FEISHU_USER_AUTH_INVALID_VAR
|
|
20482
|
+
FEISHU_USER_AUTH_INVALID_VAR,
|
|
20483
|
+
"FEISHU_AUTH_PENDING_APPROVAL"
|
|
20483
20484
|
];
|
|
20484
20485
|
/** 宿主机登录态隔离,理由同 github(见接口注释):由通用装配层无条件设。 */
|
|
20485
20486
|
hostCredentialIsolationEnvKeys = ["LARKSUITE_CLI_CONFIG_DIR"];
|
|
@@ -20671,7 +20672,8 @@ async function pollFeishuDeviceToken(input) {
|
|
|
20671
20672
|
const data = await resp.json();
|
|
20672
20673
|
const errStr = data["error"];
|
|
20673
20674
|
if (errStr === "authorization_pending" || errStr === "slow_down") return { status: "pending" };
|
|
20674
|
-
if (
|
|
20675
|
+
if (errStr) throw new FeishuDeviceFlowError(errStr, String(data["error_description"] ?? errStr));
|
|
20676
|
+
if (!resp.ok) throw new Error(String(data["error_description"] ?? "login failed"));
|
|
20675
20677
|
if (!data["access_token"]) throw new Error("no access_token in response");
|
|
20676
20678
|
return { status: "ok", data };
|
|
20677
20679
|
}
|
|
@@ -20720,7 +20722,7 @@ function feishuUserAuthInvalidText(input) {
|
|
|
20720
20722
|
${input.link}` : `${head}
|
|
20721
20723
|
\u8BF7\u5230 Oasis \u8BE5 Agent \u7684\u300C\u8FDE\u63A5\u5668\u300D\u9875\u91CD\u65B0\u6388\u6743\u98DE\u4E66\u3002`;
|
|
20722
20724
|
}
|
|
20723
|
-
var FEISHU_DEVICE_AUTHORIZATION_URL, FEISHU_USER_INFO_URL, FEISHU_SEND_MESSAGE_URL, FEISHU_BATCH_GET_ID_URL;
|
|
20725
|
+
var FEISHU_DEVICE_AUTHORIZATION_URL, FEISHU_USER_INFO_URL, FEISHU_SEND_MESSAGE_URL, FEISHU_BATCH_GET_ID_URL, FeishuDeviceFlowError;
|
|
20724
20726
|
var init_user_auth = __esm({
|
|
20725
20727
|
"../connectors/src/feishu/user-auth.ts"() {
|
|
20726
20728
|
"use strict";
|
|
@@ -20729,6 +20731,81 @@ var init_user_auth = __esm({
|
|
|
20729
20731
|
FEISHU_USER_INFO_URL = "https://open.feishu.cn/open-apis/authen/v1/user_info";
|
|
20730
20732
|
FEISHU_SEND_MESSAGE_URL = "https://open.feishu.cn/open-apis/im/v1/messages";
|
|
20731
20733
|
FEISHU_BATCH_GET_ID_URL = "https://open.feishu.cn/open-apis/contact/v3/users/batch_get_id";
|
|
20734
|
+
FeishuDeviceFlowError = class extends Error {
|
|
20735
|
+
constructor(code2, message) {
|
|
20736
|
+
super(message);
|
|
20737
|
+
this.code = code2;
|
|
20738
|
+
this.name = "FeishuDeviceFlowError";
|
|
20739
|
+
}
|
|
20740
|
+
};
|
|
20741
|
+
}
|
|
20742
|
+
});
|
|
20743
|
+
|
|
20744
|
+
// ../connectors/src/feishu/pending-approval.ts
|
|
20745
|
+
function feishuPendingApprovalScopes(input) {
|
|
20746
|
+
const granted = input.granted ? new Set(input.granted) : null;
|
|
20747
|
+
const missing = input.requested.filter((s2) => s2 !== "offline_access" && !granted?.has(s2));
|
|
20748
|
+
if (!input.appScopes) return missing.filter((s2) => !AUTO_APPROVED2.has(s2));
|
|
20749
|
+
const byName = userScopeIndex(input.appScopes);
|
|
20750
|
+
return missing.filter((s2) => byName.has(s2) && !isGranted(byName.get(s2)));
|
|
20751
|
+
}
|
|
20752
|
+
function feishuPendingApprovalSettled(pending, appScopes) {
|
|
20753
|
+
const byName = userScopeIndex(appScopes);
|
|
20754
|
+
return pending.pendingScopes.every((s2) => isGranted(byName.get(s2)));
|
|
20755
|
+
}
|
|
20756
|
+
function feishuPendingApprovalModules(pending) {
|
|
20757
|
+
const waiting = new Set(pending.pendingScopes);
|
|
20758
|
+
return pending.modules.filter((m2) => (FEISHU_DOMAIN_SCOPES[m2]?.scopes ?? []).some((s2) => waiting.has(s2)));
|
|
20759
|
+
}
|
|
20760
|
+
async function readFeishuPendingApproval(store, actorId) {
|
|
20761
|
+
const raw = await store.revealVariable(FEISHU_AUTH_PENDING_APPROVAL_VAR, actorId).catch(() => null);
|
|
20762
|
+
if (!raw) return null;
|
|
20763
|
+
try {
|
|
20764
|
+
const p2 = JSON.parse(raw);
|
|
20765
|
+
return typeof p2?.at === "string" && typeof p2.appId === "string" && Array.isArray(p2.modules) && Array.isArray(p2.pendingScopes) ? p2 : null;
|
|
20766
|
+
} catch {
|
|
20767
|
+
return null;
|
|
20768
|
+
}
|
|
20769
|
+
}
|
|
20770
|
+
async function writeFeishuPendingApproval(store, actorId, pending) {
|
|
20771
|
+
await store.putVariable({
|
|
20772
|
+
key: FEISHU_AUTH_PENDING_APPROVAL_VAR,
|
|
20773
|
+
value: JSON.stringify(pending),
|
|
20774
|
+
...actorId ? { scope: "personal", actorId } : { scope: "global" },
|
|
20775
|
+
connectorId: "feishu",
|
|
20776
|
+
encrypted: false
|
|
20777
|
+
});
|
|
20778
|
+
}
|
|
20779
|
+
async function clearFeishuPendingApproval(store, actorId) {
|
|
20780
|
+
await store.deleteVariable(FEISHU_AUTH_PENDING_APPROVAL_VAR, actorId);
|
|
20781
|
+
}
|
|
20782
|
+
function feishuApprovalGrantedText(input) {
|
|
20783
|
+
const head = `\u7BA1\u7406\u5458\u5DF2\u6279\u51C6\u300C${input.agentName}\u300D\u7533\u8BF7\u7684\u98DE\u4E66\u6743\u9650\uFF08${moduleNames(input.modules)}\uFF09\u3002\u8FD8\u5DEE\u4F60\u70B9\u4E00\u6B21\u6388\u6743\uFF0C\u8FD9\u90E8\u5206\u529F\u80FD\u624D\u80FD\u4EE5\u4F60\u7684\u8EAB\u4EFD\u4F7F\u7528\u3002`;
|
|
20784
|
+
return input.link ? `${head}
|
|
20785
|
+
\u70B9\u8FD9\u4E2A\u94FE\u63A5\u8865\u4E0A\u6743\u9650\uFF08\u9700\u7528\u6536\u5230\u8FD9\u6761\u79C1\u4FE1\u7684\u98DE\u4E66\u8D26\u53F7\u767B\u5F55\uFF0C7 \u5929\u5185\u6709\u6548\uFF09\uFF1A
|
|
20786
|
+
${input.link}` : `${head}
|
|
20787
|
+
\u8BF7\u5230 Oasis \u8BE5 Agent \u7684\u300C\u8FDE\u63A5\u5668\u300D\u9875\u91CD\u65B0\u8FDE\u63A5\u98DE\u4E66\u3002`;
|
|
20788
|
+
}
|
|
20789
|
+
function feishuPendingApprovalNotice(modules) {
|
|
20790
|
+
return `${moduleNames(modules)}\u542B\u9700\u98DE\u4E66\u7BA1\u7406\u5458\u5BA1\u6279\u7684\u6743\u9650\uFF0C\u5DF2\u63D0\u4EA4\u5BA1\u6279\u3002\u6279\u51C6\u540E\u4F1A\u5728\u98DE\u4E66\u79C1\u4FE1\u901A\u77E5\u4F60\uFF0C\u70B9\u4E00\u4E0B\u5373\u53EF\u8865\u4E0A\u8FD9\u90E8\u5206\u6743\u9650\uFF1B\u5DF2\u6709\u7684\u98DE\u4E66\u80FD\u529B\u4E0D\u53D7\u5F71\u54CD\u3002`;
|
|
20791
|
+
}
|
|
20792
|
+
function feishuApprovalUnconfirmedNotice(modules, expired) {
|
|
20793
|
+
return `${expired ? "\u6388\u6743\u9875\u5DF2\u8D85\u65F6\uFF0C" : ""}\u98DE\u4E66\u8FD9\u4E00\u8F6E\u6CA1\u6709\u7ED9\u51FA\u6388\u6743\uFF0COasis \u65E0\u6CD5\u786E\u8BA4\u4F60\u662F\u5426\u5728\u6388\u6743\u9875\u5BF9${moduleNames(modules)}\u7684\u6743\u9650\u70B9\u4E86\u300C\u7533\u8BF7\u300D\u3002\u5982\u679C\u70B9\u4E86\uFF0C\u8BF7\u9009\u300C\u6211\u70B9\u4E86\u7533\u8BF7\u300D\uFF0C\u6279\u51C6\u540E\u4F1A\u5728\u98DE\u4E66\u79C1\u4FE1\u901A\u77E5\u4F60\u8865\u6388\u6743\uFF1B\u6CA1\u70B9\uFF08\u6216\u70B9\u7684\u662F\u62D2\u7EDD\uFF09\u7684\u8BDD\u91CD\u65B0\u53D1\u8D77\u6388\u6743\u5373\u53EF\u3002\u5DF2\u6709\u7684\u98DE\u4E66\u80FD\u529B\u4E0D\u53D7\u5F71\u54CD\u3002`;
|
|
20794
|
+
}
|
|
20795
|
+
var FEISHU_AUTH_PENDING_APPROVAL_VAR, FEISHU_PENDING_APPROVAL_WATCH_MS, FEISHU_APPROVED_SUPPLEMENT_KEEP_MS, AUTO_APPROVED2, userScopeIndex, isGranted, moduleNames;
|
|
20796
|
+
var init_pending_approval = __esm({
|
|
20797
|
+
"../connectors/src/feishu/pending-approval.ts"() {
|
|
20798
|
+
"use strict";
|
|
20799
|
+
init_scopes();
|
|
20800
|
+
FEISHU_AUTH_PENDING_APPROVAL_VAR = "FEISHU_AUTH_PENDING_APPROVAL";
|
|
20801
|
+
FEISHU_PENDING_APPROVAL_WATCH_MS = 30 * 24 * 36e5;
|
|
20802
|
+
FEISHU_APPROVED_SUPPLEMENT_KEEP_MS = 7 * 24 * 36e5;
|
|
20803
|
+
AUTO_APPROVED2 = new Set(FEISHU_BASIC_SCOPES);
|
|
20804
|
+
userScopeIndex = (appScopes) => new Map(
|
|
20805
|
+
appScopes.filter((s2) => s2.scope_name && (!s2.scope_type || s2.scope_type === "user")).map((s2) => [s2.scope_name, s2])
|
|
20806
|
+
);
|
|
20807
|
+
isGranted = (s2) => !!s2 && (s2.grant_status === void 0 || s2.grant_status === 1);
|
|
20808
|
+
moduleNames = (modules) => modules.map((m2) => FEISHU_MODULE_LABELS[m2] ?? m2).join("\u3001") || "\u6240\u7533\u8BF7\u7684";
|
|
20732
20809
|
}
|
|
20733
20810
|
});
|
|
20734
20811
|
|
|
@@ -24653,6 +24730,7 @@ var init_src3 = __esm({
|
|
|
24653
24730
|
init_host_isolation();
|
|
24654
24731
|
init_feishu();
|
|
24655
24732
|
init_user_auth();
|
|
24733
|
+
init_pending_approval();
|
|
24656
24734
|
init_scopes();
|
|
24657
24735
|
init_oauth();
|
|
24658
24736
|
init_scheduled_refresh();
|
|
@@ -24674,6 +24752,14 @@ var init_src3 = __esm({
|
|
|
24674
24752
|
});
|
|
24675
24753
|
|
|
24676
24754
|
// ../server/src/feishu-reauth.ts
|
|
24755
|
+
async function supplementSelection(store, actorId) {
|
|
24756
|
+
const pending = await readFeishuPendingApproval(store, actorId);
|
|
24757
|
+
if (!pending) return null;
|
|
24758
|
+
const appId = await store.revealResolvedVariable("FEISHU_APP_ID", actorId).catch(() => null);
|
|
24759
|
+
if (appId !== pending.appId) return null;
|
|
24760
|
+
const sel = normalizeFeishuAuthSelection({ modules: pending.modules, sendAsUser: pending.sendAsUser });
|
|
24761
|
+
return sel ? { sel, sendAsUser: pending.sendAsUserRequested, pending } : null;
|
|
24762
|
+
}
|
|
24677
24763
|
async function reauthSelection(store, actorId) {
|
|
24678
24764
|
const raw = await store.revealVariable(FEISHU_AUTH_SELECTION_VAR, actorId).catch(() => null);
|
|
24679
24765
|
if (raw) {
|
|
@@ -24713,20 +24799,63 @@ function createFeishuReauth(deps) {
|
|
|
24713
24799
|
message: `\u8FD9\u4E2A\u94FE\u63A5\u53EA\u80FD\u7531\u539F\u6388\u6743\u4EBA\u672C\u4EBA\u4F7F\u7528\u3002\u4F60${who.name ? `\uFF08${who.name}\uFF09` : ""}\u4E0D\u662F\u539F\u6388\u6743\u4EBA\uFF0C\u672C\u6B21\u6388\u6743\u672A\u4FDD\u5B58\uFF0C\u539F\u6388\u6743\u4FDD\u6301\u4E0D\u53D8\u3002`
|
|
24714
24800
|
};
|
|
24715
24801
|
}
|
|
24716
|
-
await withConnectorCredentialLock("feishu", claims.actorId, async () => {
|
|
24802
|
+
const supplement = await withConnectorCredentialLock("feishu", claims.actorId, async () => {
|
|
24803
|
+
const pending2 = claims.purpose === "supplement" ? await readFeishuPendingApproval(store, claims.actorId) : null;
|
|
24717
24804
|
await persistFeishuUserAuthorization(store, claims.actorId, data, now(), {
|
|
24718
24805
|
openId: who.openId,
|
|
24719
|
-
...who.name ? { userName: who.name } : {}
|
|
24806
|
+
...who.name ? { userName: who.name } : {},
|
|
24807
|
+
...pending2?.applicant ? { authorizedBy: pending2.applicant } : {}
|
|
24720
24808
|
});
|
|
24809
|
+
const record10 = feishuAuthSelectionRecord(sel, sendAsUserRequested, data);
|
|
24721
24810
|
await store.putVariable({
|
|
24722
24811
|
key: FEISHU_AUTH_SELECTION_VAR,
|
|
24723
|
-
value: JSON.stringify(
|
|
24812
|
+
value: JSON.stringify(record10),
|
|
24724
24813
|
...claims.actorId ? { scope: "personal", actorId: claims.actorId } : { scope: "global" },
|
|
24725
24814
|
connectorId: "feishu",
|
|
24726
24815
|
encrypted: false
|
|
24727
24816
|
});
|
|
24728
|
-
|
|
24729
|
-
|
|
24817
|
+
if (claims.purpose !== "supplement") return null;
|
|
24818
|
+
if (!record10.grantedScopes) return "unknown";
|
|
24819
|
+
if (!pending2) {
|
|
24820
|
+
const granted2 = new Set(record10.grantedScopes);
|
|
24821
|
+
const wanted = scopesForSelection(sel, sendAsUserRequested).filter((x2) => x2 !== "offline_access");
|
|
24822
|
+
return wanted.every((x2) => granted2.has(x2)) ? "complete" : "short";
|
|
24823
|
+
}
|
|
24824
|
+
const granted = new Set(record10.grantedScopes);
|
|
24825
|
+
const still = pending2.pendingScopes.filter((x2) => !granted.has(x2));
|
|
24826
|
+
if (still.length === 0) {
|
|
24827
|
+
await clearFeishuPendingApproval(store, claims.actorId);
|
|
24828
|
+
return "complete";
|
|
24829
|
+
}
|
|
24830
|
+
const next = { ...pending2, pendingScopes: still };
|
|
24831
|
+
delete next.approvedAt;
|
|
24832
|
+
delete next.notice;
|
|
24833
|
+
await writeFeishuPendingApproval(store, claims.actorId, next);
|
|
24834
|
+
return "partial";
|
|
24835
|
+
});
|
|
24836
|
+
const userName = who.name ? { userName: who.name } : {};
|
|
24837
|
+
if (supplement === "partial") {
|
|
24838
|
+
return {
|
|
24839
|
+
state: "incomplete",
|
|
24840
|
+
...userName,
|
|
24841
|
+
message: "\u6388\u6743\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u98DE\u4E66\u8FD9\u6B21\u6CA1\u6709\u7ED9\u9F50\u7BA1\u7406\u5458\u6279\u51C6\u7684\u6743\u9650\uFF0C\u8FD8\u5DEE\u7684\u90E8\u5206\u7EE7\u7EED\u7B49\u5F85\u5BA1\u6279\uFF1B\u6279\u51C6\u540E\u4F1A\u518D\u79C1\u4FE1\u901A\u77E5\u4F60\u3002\u5DF2\u6709\u7684\u98DE\u4E66\u80FD\u529B\u4E0D\u53D7\u5F71\u54CD\u3002"
|
|
24842
|
+
};
|
|
24843
|
+
}
|
|
24844
|
+
if (supplement === "short") {
|
|
24845
|
+
return {
|
|
24846
|
+
state: "incomplete",
|
|
24847
|
+
...userName,
|
|
24848
|
+
message: "\u6388\u6743\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u98DE\u4E66\u8FD9\u6B21\u6CA1\u6709\u7ED9\u9F50\u6240\u7533\u8BF7\u7684\u6743\u9650\u3002\u53EF\u5728 Oasis \u8FDE\u63A5\u5668\u8BE6\u60C5\u67E5\u770B\u5DF2\u5F00\u901A\u7684\u529F\u80FD\uFF0C\u9700\u8981\u65F6\u91CD\u65B0\u8FDE\u63A5\u98DE\u4E66\u3002"
|
|
24849
|
+
};
|
|
24850
|
+
}
|
|
24851
|
+
if (supplement === "unknown") {
|
|
24852
|
+
return {
|
|
24853
|
+
state: "incomplete",
|
|
24854
|
+
...userName,
|
|
24855
|
+
message: "\u6388\u6743\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u98DE\u4E66\u6CA1\u6709\u56DE\u62A5\u8FD9\u6B21\u6388\u4E88\u4E86\u54EA\u4E9B\u6743\u9650\uFF0C\u65E0\u6CD5\u786E\u8BA4\u7BA1\u7406\u5458\u6279\u51C6\u7684\u6743\u9650\u662F\u5426\u5DF2\u8865\u4E0A\u3002\u53EF\u5728 Oasis \u8FDE\u63A5\u5668\u8BE6\u60C5\u67E5\u770B\uFF1B\u4ECD\u663E\u793A\u5F85\u8865\u6388\u6743\u7684\u8BDD\uFF0C\u518D\u70B9\u4E00\u6B21\u94FE\u63A5\u5373\u53EF\u3002"
|
|
24856
|
+
};
|
|
24857
|
+
}
|
|
24858
|
+
await deps.onRestored?.(claims, { openId: who.openId, ...userName }).catch((e) => warn(`onRestored: ${String(e)}`));
|
|
24730
24859
|
return { state: "restored", ...who.name ? { userName: who.name } : {} };
|
|
24731
24860
|
};
|
|
24732
24861
|
const watch = async (deviceCode, entry, ctx) => {
|
|
@@ -24756,7 +24885,15 @@ function createFeishuReauth(deps) {
|
|
|
24756
24885
|
if (!store) return { ok: false, status: 404, message: "\u627E\u4E0D\u5230\u8FD9\u4E2A\u94FE\u63A5\u6240\u5C5E\u7684\u7EC4\u7EC7\u3002" };
|
|
24757
24886
|
const app = await appCredentials(store, claims.actorId);
|
|
24758
24887
|
if (!app) return { ok: false, status: 409, message: "\u8FD9\u540D Agent \u7684\u98DE\u4E66\u5E94\u7528\u51ED\u636E\u5DF2\u4E0D\u5B58\u5728\uFF0C\u65E0\u6CD5\u91CD\u65B0\u6388\u6743\u3002\u8BF7\u5230 Oasis \u8FDE\u63A5\u5668\u9875\u91CD\u65B0\u8FDE\u63A5\u98DE\u4E66\u3002" };
|
|
24759
|
-
|
|
24888
|
+
let picked;
|
|
24889
|
+
if (claims.purpose === "supplement") {
|
|
24890
|
+
const sup = await supplementSelection(store, claims.actorId);
|
|
24891
|
+
if (!sup) return { ok: false, status: 410, message: "\u8FD9\u6B21\u8865\u6388\u6743\u5DF2\u7ECF\u5B8C\u6210\u6216\u5DF2\u5931\u6548\u3002\u8BF7\u5230 Oasis \u8BE5 Agent \u7684\u300C\u8FDE\u63A5\u5668\u300D\u9875\u67E5\u770B\uFF0C\u9700\u8981\u65F6\u91CD\u65B0\u8FDE\u63A5\u98DE\u4E66\u3002" };
|
|
24892
|
+
picked = sup;
|
|
24893
|
+
} else {
|
|
24894
|
+
picked = await reauthSelection(store, claims.actorId);
|
|
24895
|
+
}
|
|
24896
|
+
const { sel, sendAsUser } = picked;
|
|
24760
24897
|
const auth = await (deps.start ?? startFeishuDeviceAuthorization)({
|
|
24761
24898
|
appId: app.appId,
|
|
24762
24899
|
appSecret: app.appSecret,
|
|
@@ -24771,7 +24908,7 @@ function createFeishuReauth(deps) {
|
|
|
24771
24908
|
const intervalSec = auth.interval ?? DEFAULT_POLL_INTERVAL_SEC;
|
|
24772
24909
|
void watch(auth.deviceCode, entry, { store, ...app, sel, sendAsUser, intervalSec });
|
|
24773
24910
|
const agentName = await deps.agentName?.(claims.companyId, claims.actorId).catch(() => void 0) ?? claims.actorId ?? "\u7EC4\u7EC7";
|
|
24774
|
-
return { ok: true, verificationUrl: auth.verificationUrl, deviceCode: auth.deviceCode, agentName, intervalSec };
|
|
24911
|
+
return { ok: true, verificationUrl: auth.verificationUrl, deviceCode: auth.deviceCode, agentName, intervalSec, purpose: claims.purpose };
|
|
24775
24912
|
},
|
|
24776
24913
|
/** 页面轮询结果。票与 deviceCode 必须是同一次 begin 发出来的。 */
|
|
24777
24914
|
status(token2, deviceCode) {
|
|
@@ -24788,17 +24925,18 @@ function createFeishuReauth(deps) {
|
|
|
24788
24925
|
function feishuReauthPageHtml(input) {
|
|
24789
24926
|
const head = `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>\u91CD\u65B0\u6388\u6743\u98DE\u4E66</title>
|
|
24790
24927
|
<style>body{font-family:system-ui,-apple-system,sans-serif;max-width:32rem;margin:3rem auto;padding:0 1.25rem;color:#1f2329;line-height:1.6}a.btn{display:inline-block;background:#1f2329;color:#fff;padding:.6rem 1.2rem;border-radius:.5rem;text-decoration:none}#s{margin-top:1.25rem}</style></head><body>`;
|
|
24791
|
-
if (!input.ok) return `${head}<h2>\u65E0\u6CD5\
|
|
24792
|
-
const
|
|
24793
|
-
|
|
24794
|
-
<
|
|
24928
|
+
if (!input.ok) return `${head}<h2>\u65E0\u6CD5\u5B8C\u6210\u6388\u6743</h2><p>${escapeHtml(input.message)}</p></body></html>`;
|
|
24929
|
+
const supplement = input.purpose === "supplement";
|
|
24930
|
+
const cfg = JSON.stringify({ t: input.token, d: input.deviceCode, i: Math.max(2, input.intervalSec), s: supplement }).replace(/</g, "\\u003c");
|
|
24931
|
+
return `${head}<h2>${supplement ? "\u8865\u6388\u6743\u98DE\u4E66\uFF08\u7BA1\u7406\u5458\u5DF2\u6279\u51C6\uFF09" : "\u91CD\u65B0\u6388\u6743\u98DE\u4E66"}\uFF1A${escapeHtml(input.agentName)}</h2>
|
|
24932
|
+
<p>\u8BF7\u7528<strong>${supplement ? "\u7533\u8BF7\u4EBA" : "\u539F\u6388\u6743\u4EBA"}</strong>\u7684\u98DE\u4E66\u8D26\u53F7\u5B8C\u6210\u6388\u6743\u3002\u6362\u6210\u522B\u7684\u8D26\u53F7\u6388\u6743\u4F1A\u88AB\u62D2\u7EDD\uFF0C\u539F\u6388\u6743\u4FDD\u6301\u4E0D\u53D8\u3002</p>
|
|
24795
24933
|
<p><a class="btn" href="${escapeHtml(input.verificationUrl)}" target="_blank" rel="noopener">\u53BB\u98DE\u4E66\u6388\u6743</a></p>
|
|
24796
24934
|
<p id="s">\u7B49\u5F85\u4F60\u5728\u98DE\u4E66\u70B9\u300C\u6388\u6743\u300D\u2026</p>
|
|
24797
24935
|
<script>(function(){var c=${cfg};var el=document.getElementById("s");
|
|
24798
24936
|
function tick(){fetch("reauth/status",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({t:c.t,deviceCode:c.d})})
|
|
24799
24937
|
.then(function(r){return r.json()}).then(function(b){
|
|
24800
24938
|
if(b.state==="pending"){setTimeout(tick,c.i*1000);return}
|
|
24801
|
-
if(b.state==="restored"){el.textContent="\u5DF2\u6062\u590D\uFF1A"+(b.userName?b.userName+" \u7684":"")+"\u98DE\u4E66\u7528\u6237\u6388\u6743\u91CD\u65B0\u751F\u6548\uFF0C\u53EF\u4EE5\u5173\u6389\u8FD9\u4E2A\u9875\u9762\u4E86\u3002";return}
|
|
24939
|
+
if(b.state==="restored"){el.textContent=(c.s?"\u5DF2\u8865\u4E0A\uFF1A":"\u5DF2\u6062\u590D\uFF1A")+(b.userName?b.userName+" \u7684":"")+(c.s?"\u98DE\u4E66\u7528\u6237\u6388\u6743\u5DF2\u5305\u542B\u7BA1\u7406\u5458\u6279\u51C6\u7684\u6743\u9650":"\u98DE\u4E66\u7528\u6237\u6388\u6743\u91CD\u65B0\u751F\u6548")+"\uFF0C\u53EF\u4EE5\u5173\u6389\u8FD9\u4E2A\u9875\u9762\u4E86\u3002";return}
|
|
24802
24940
|
el.textContent=b.message||"\u6388\u6743\u6CA1\u6709\u5B8C\u6210\uFF0C\u53EF\u4EE5\u91CD\u65B0\u70B9\u94FE\u63A5\u518D\u8BD5\u3002"}).catch(function(){setTimeout(tick,c.i*1000)})}
|
|
24803
24941
|
setTimeout(tick,c.i*1000)})();</script></body></html>`;
|
|
24804
24942
|
}
|
|
@@ -212190,6 +212328,35 @@ async function feishuModuleAccess(store, actorId, fetchScopes = fetchFeishuAppSc
|
|
|
212190
212328
|
...botCheckError ? { botCheckError } : {}
|
|
212191
212329
|
};
|
|
212192
212330
|
}
|
|
212331
|
+
async function saveFeishuModuleSelection(store, actorId, body2) {
|
|
212332
|
+
const read3 = (key2) => store.revealResolvedVariable(key2, actorId).catch(() => null);
|
|
212333
|
+
if (!await read3("FEISHU_APP_ID") || !await read3("FEISHU_APP_SECRET")) return { ok: false, error: "no_app" };
|
|
212334
|
+
const sel = normalizeFeishuAuthSelection({ modules: Array.isArray(body2.modules) ? body2.modules : [] });
|
|
212335
|
+
if (!sel) return { ok: false, error: "empty" };
|
|
212336
|
+
let prev = {};
|
|
212337
|
+
const raw = await read3(FEISHU_AUTH_SELECTION_VAR);
|
|
212338
|
+
try {
|
|
212339
|
+
prev = raw ? JSON.parse(raw) ?? {} : {};
|
|
212340
|
+
} catch {
|
|
212341
|
+
prev = {};
|
|
212342
|
+
}
|
|
212343
|
+
const grantedScopes = Array.isArray(prev.grantedScopes) ? prev.grantedScopes.filter((s2) => typeof s2 === "string") : void 0;
|
|
212344
|
+
const sendAsUser = prev.sendAsUser === true;
|
|
212345
|
+
const record10 = {
|
|
212346
|
+
modules: sel.modules,
|
|
212347
|
+
sendAsUser,
|
|
212348
|
+
sendAsUserRequested: sendAsUser && prev.sendAsUserRequested === true,
|
|
212349
|
+
...grantedScopes ? { grantedScopes } : {}
|
|
212350
|
+
};
|
|
212351
|
+
await store.putVariable({
|
|
212352
|
+
key: FEISHU_AUTH_SELECTION_VAR,
|
|
212353
|
+
value: JSON.stringify(record10),
|
|
212354
|
+
...actorId ? { scope: "personal", actorId } : { scope: "global" },
|
|
212355
|
+
connectorId: "feishu",
|
|
212356
|
+
encrypted: false
|
|
212357
|
+
});
|
|
212358
|
+
return { ok: true, record: record10 };
|
|
212359
|
+
}
|
|
212193
212360
|
var init_feishu_module_access = __esm({
|
|
212194
212361
|
"../server/src/feishu-module-access.ts"() {
|
|
212195
212362
|
"use strict";
|
|
@@ -212197,6 +212364,51 @@ var init_feishu_module_access = __esm({
|
|
|
212197
212364
|
}
|
|
212198
212365
|
});
|
|
212199
212366
|
|
|
212367
|
+
// ../server/src/feishu-pending-approval.ts
|
|
212368
|
+
async function recordFeishuPendingApproval(input) {
|
|
212369
|
+
const pendingScopes = await pendingApprovalScopes(input);
|
|
212370
|
+
if (pendingScopes.length === 0) {
|
|
212371
|
+
if (input.granted) {
|
|
212372
|
+
await withConnectorCredentialLock("feishu", input.actorId, () => clearFeishuPendingApproval(input.store, input.actorId));
|
|
212373
|
+
}
|
|
212374
|
+
return null;
|
|
212375
|
+
}
|
|
212376
|
+
const record10 = {
|
|
212377
|
+
at: new Date(input.now).toISOString(),
|
|
212378
|
+
appId: input.appId,
|
|
212379
|
+
...input.applicant ? { applicant: input.applicant } : {},
|
|
212380
|
+
modules: input.selection.modules,
|
|
212381
|
+
sendAsUser: input.selection.sendAsUser,
|
|
212382
|
+
sendAsUserRequested: input.sendAsUserRequested,
|
|
212383
|
+
pendingScopes
|
|
212384
|
+
};
|
|
212385
|
+
await withConnectorCredentialLock("feishu", input.actorId, () => writeFeishuPendingApproval(input.store, input.actorId, record10));
|
|
212386
|
+
const modules = feishuPendingApprovalModules(record10);
|
|
212387
|
+
return { modules, scopes: pendingScopes, notice: feishuPendingApprovalNotice(modules) };
|
|
212388
|
+
}
|
|
212389
|
+
async function pendingApprovalScopes(input) {
|
|
212390
|
+
const requested = scopesForSelection(input.selection, input.sendAsUserRequested);
|
|
212391
|
+
let appScopes = null;
|
|
212392
|
+
try {
|
|
212393
|
+
appScopes = await (input.fetchScopes ?? fetchFeishuAppScopes)(input.appId, input.appSecret);
|
|
212394
|
+
} catch (e) {
|
|
212395
|
+
(input.warn ?? ((m2) => console.warn(`[feishu-oauth] ${m2}`)))(`\u5E94\u7528\u6743\u9650\u5217\u8868\u67E5\u8BE2\u5931\u8D25\uFF0C\u5F85\u5BA1\u6279\u6309\u514D\u5BA1\u96C6\u5408\u4F30\u7B97: ${String(e)}`);
|
|
212396
|
+
}
|
|
212397
|
+
return feishuPendingApprovalScopes({ requested, granted: input.granted, appScopes });
|
|
212398
|
+
}
|
|
212399
|
+
async function assessFeishuApprovalUnconfirmed(input) {
|
|
212400
|
+
const scopes = await pendingApprovalScopes(input);
|
|
212401
|
+
if (scopes.length === 0) return null;
|
|
212402
|
+
const modules = feishuPendingApprovalModules({ modules: input.selection.modules, pendingScopes: scopes });
|
|
212403
|
+
return { modules, scopes, notice: feishuApprovalUnconfirmedNotice(modules, input.expired) };
|
|
212404
|
+
}
|
|
212405
|
+
var init_feishu_pending_approval = __esm({
|
|
212406
|
+
"../server/src/feishu-pending-approval.ts"() {
|
|
212407
|
+
"use strict";
|
|
212408
|
+
init_src3();
|
|
212409
|
+
}
|
|
212410
|
+
});
|
|
212411
|
+
|
|
212200
212412
|
// ../server/src/github-app-inventory.ts
|
|
212201
212413
|
async function collectOasisGithubApps(svc) {
|
|
212202
212414
|
const rows = (await svc.listVariables()).filter((r) => r.scope === "global" || r.scope === "personal");
|
|
@@ -218401,6 +218613,27 @@ ${composed}`;
|
|
|
218401
218613
|
}
|
|
218402
218614
|
return;
|
|
218403
218615
|
}
|
|
218616
|
+
if (url.pathname === "/api/connectors/feishu/modules" && req.method === "POST") {
|
|
218617
|
+
try {
|
|
218618
|
+
const body2 = JSON.parse(rawBody || "{}");
|
|
218619
|
+
const svc = await connectorActorsService();
|
|
218620
|
+
if (!svc) throw new Error("actors service unavailable");
|
|
218621
|
+
const denied = await connectorWriteDenied(svc, body2.actorId, "\u8C03\u6574\u98DE\u4E66\u63A5\u5165\u529F\u80FD");
|
|
218622
|
+
if (denied) {
|
|
218623
|
+
writeApiError(res, denied);
|
|
218624
|
+
return;
|
|
218625
|
+
}
|
|
218626
|
+
const saved = await saveFeishuModuleSelection(svc, body2.actorId, body2);
|
|
218627
|
+
if (!saved.ok) {
|
|
218628
|
+
res.writeHead(saved.error === "no_app" ? 409 : 400, { "content-type": "application/json" }).end(JSON.stringify({ error: saved.error === "no_app" ? "\u8FD8\u6CA1\u6709\u914D\u7F6E\u98DE\u4E66\u5E94\u7528\uFF0C\u8BF7\u5148\u5B8C\u6210\u8FDE\u63A5" : "\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u4E2A\u529F\u80FD\u6A21\u5757" }));
|
|
218629
|
+
return;
|
|
218630
|
+
}
|
|
218631
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ ok: true, modules: saved.record.modules }));
|
|
218632
|
+
} catch (e) {
|
|
218633
|
+
res.writeHead(500).end(JSON.stringify({ error: String(e) }));
|
|
218634
|
+
}
|
|
218635
|
+
return;
|
|
218636
|
+
}
|
|
218404
218637
|
if (url.pathname === "/api/connectors/feishu/login/start" && req.method === "POST") {
|
|
218405
218638
|
const startBody = JSON.parse(rawBody);
|
|
218406
218639
|
const { appId, actorId } = startBody;
|
|
@@ -218470,6 +218703,51 @@ ${composed}`;
|
|
|
218470
218703
|
}
|
|
218471
218704
|
return;
|
|
218472
218705
|
}
|
|
218706
|
+
if (url.pathname === "/api/connectors/feishu/login/confirm-application" && req.method === "POST") {
|
|
218707
|
+
const { appId, deviceCode, actorId } = JSON.parse(rawBody);
|
|
218708
|
+
if (!appId || !deviceCode) {
|
|
218709
|
+
res.writeHead(400).end(JSON.stringify({ error: "appId and deviceCode required" }));
|
|
218710
|
+
return;
|
|
218711
|
+
}
|
|
218712
|
+
try {
|
|
218713
|
+
const devicePending = opts.connectorAuthPending?.githubApp;
|
|
218714
|
+
const started = devicePending ? await devicePending.get(feishuDevicePendingKey(deviceCode), Date.now()) : { status: "missing" };
|
|
218715
|
+
if (started.status !== "found") {
|
|
218716
|
+
res.writeHead(409).end(JSON.stringify({ ok: false, restart: true, error: "\u8FD9\u6B21\u6388\u6743\u7684\u767B\u8BB0\u5DF2\u5931\u6548\uFF08\u8D85\u65F6\u6216\u670D\u52A1\u5DF2\u66F4\u65B0\uFF09\uFF0C\u8BF7\u91CD\u65B0\u53D1\u8D77\u6388\u6743" }));
|
|
218717
|
+
return;
|
|
218718
|
+
}
|
|
218719
|
+
const v2 = started.value.value;
|
|
218720
|
+
if (v2["appId"] !== appId || v2["actorId"] !== (actorId ?? "") || (started.value.companyId ?? "") !== (currentCompanyId ?? "")) {
|
|
218721
|
+
res.writeHead(400).end(JSON.stringify({ ok: false, restart: true, error: "\u8FD9\u6B21\u6388\u6743\u4E0D\u662F\u7531\u5F53\u524D\u5E94\u7528\u6216\u5458\u5DE5\u53D1\u8D77\u7684\uFF0C\u8BF7\u91CD\u65B0\u53D1\u8D77\u6388\u6743" }));
|
|
218722
|
+
return;
|
|
218723
|
+
}
|
|
218724
|
+
if (v2["ended"] !== "no_token") {
|
|
218725
|
+
res.writeHead(409).end(JSON.stringify({ ok: false, error: "\u8FD9\u6B21\u6388\u6743\u6CA1\u6709\u5904\u5728\u300C\u5F85\u786E\u8BA4\u662F\u5426\u5DF2\u7533\u8BF7\u300D\u7684\u72B6\u6001\uFF0C\u65E0\u9700\u786E\u8BA4" }));
|
|
218726
|
+
return;
|
|
218727
|
+
}
|
|
218728
|
+
const selection = normalizeFeishuAuthSelection({ modules: v2["modules"], sendAsUser: v2["sendAsUser"] });
|
|
218729
|
+
const confirmSvc = await connectorActorsService();
|
|
218730
|
+
const appSecret = confirmSvc ? await confirmSvc.revealResolvedVariable("FEISHU_APP_SECRET", actorId) : null;
|
|
218731
|
+
if (!selection || !confirmSvc || !appSecret) {
|
|
218732
|
+
res.writeHead(409).end(JSON.stringify({ ok: false, restart: true, error: "\u8FD9\u6B21\u6388\u6743\u7684\u767B\u8BB0\u5DF2\u635F\u574F\u6216\u5E94\u7528\u51ED\u636E\u5DF2\u4E0D\u5B58\u5728\uFF0C\u8BF7\u91CD\u65B0\u53D1\u8D77\u6388\u6743" }));
|
|
218733
|
+
return;
|
|
218734
|
+
}
|
|
218735
|
+
const pendingApproval = await recordFeishuPendingApproval({
|
|
218736
|
+
store: confirmSvc,
|
|
218737
|
+
actorId,
|
|
218738
|
+
appId,
|
|
218739
|
+
appSecret,
|
|
218740
|
+
selection,
|
|
218741
|
+
sendAsUserRequested: selection.sendAsUser && v2["sendAsUserRequested"] === true,
|
|
218742
|
+
...isHumanActorId(actor) ? { applicant: actor } : {},
|
|
218743
|
+
now: Date.now()
|
|
218744
|
+
});
|
|
218745
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(pendingApproval ? { ok: true, pendingApproval: { modules: pendingApproval.modules, scopes: pendingApproval.scopes }, notice: pendingApproval.notice } : { ok: false, error: "\u8FD9\u4E9B\u6743\u9650\u73B0\u5728\u5DF2\u7ECF\u53EF\u7528\uFF08\u7BA1\u7406\u5458\u53EF\u80FD\u5DF2\u6279\u51C6\uFF09\uFF0C\u8BF7\u91CD\u65B0\u53D1\u8D77\u6388\u6743\u5B8C\u6210\u8FDE\u63A5" }));
|
|
218746
|
+
} catch (e) {
|
|
218747
|
+
res.writeHead(500).end(JSON.stringify({ error: String(e) }));
|
|
218748
|
+
}
|
|
218749
|
+
return;
|
|
218750
|
+
}
|
|
218473
218751
|
if (url.pathname === "/api/connectors/feishu/login/poll" && req.method === "POST") {
|
|
218474
218752
|
const { appId, deviceCode, actorId } = JSON.parse(rawBody);
|
|
218475
218753
|
if (!appId || !deviceCode) {
|
|
@@ -218498,12 +218776,40 @@ ${composed}`;
|
|
|
218498
218776
|
const pollSvc = await connectorActorsService();
|
|
218499
218777
|
const appSecret = pollSvc ? await pollSvc.revealResolvedVariable("FEISHU_APP_SECRET", actorId) : null;
|
|
218500
218778
|
if (!appSecret) throw new Error("FEISHU_APP_SECRET not found \u2014 please complete app setup first");
|
|
218501
|
-
|
|
218779
|
+
let polled;
|
|
218780
|
+
try {
|
|
218781
|
+
polled = await pollFeishuDeviceToken({ appId, appSecret, deviceCode });
|
|
218782
|
+
} catch (e) {
|
|
218783
|
+
if (!(e instanceof FeishuDeviceFlowError) || !pollSvc) throw e;
|
|
218784
|
+
const expired = e.code === "expired_token" || e.code === "invalid_grant";
|
|
218785
|
+
const unconfirmed = await assessFeishuApprovalUnconfirmed({
|
|
218786
|
+
appId,
|
|
218787
|
+
appSecret,
|
|
218788
|
+
selection: startedSelection.selection,
|
|
218789
|
+
sendAsUserRequested: startedSelection.sendAsUserRequested,
|
|
218790
|
+
expired
|
|
218791
|
+
});
|
|
218792
|
+
if (unconfirmed && devicePending) {
|
|
218793
|
+
await devicePending.patch(feishuDevicePendingKey(deviceCode), { ended: "no_token", endedCode: e.code });
|
|
218794
|
+
}
|
|
218795
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(unconfirmed ? {
|
|
218796
|
+
ok: false,
|
|
218797
|
+
final: true,
|
|
218798
|
+
approvalUnconfirmed: { modules: unconfirmed.modules, scopes: unconfirmed.scopes },
|
|
218799
|
+
notice: unconfirmed.notice
|
|
218800
|
+
} : {
|
|
218801
|
+
ok: false,
|
|
218802
|
+
final: true,
|
|
218803
|
+
error: expired ? "\u6388\u6743\u8D85\u65F6\uFF08\u8BBE\u5907\u7801\u5DF2\u8FC7\u671F\uFF09\uFF0C\u8BF7\u91CD\u65B0\u53D1\u8D77\u6388\u6743" : `\u98DE\u4E66\u6CA1\u6709\u5B8C\u6210\u6388\u6743\uFF08${e.message.slice(0, 200)}\uFF09\uFF0C\u53EF\u4EE5\u91CD\u65B0\u53D1\u8D77\u6388\u6743`
|
|
218804
|
+
}));
|
|
218805
|
+
return;
|
|
218806
|
+
}
|
|
218502
218807
|
if (polled.status === "pending") {
|
|
218503
218808
|
res.writeHead(200).end(JSON.stringify({ ok: false, error: "authorization_pending" }));
|
|
218504
218809
|
return;
|
|
218505
218810
|
}
|
|
218506
218811
|
const data = polled.data;
|
|
218812
|
+
let pendingApproval = null;
|
|
218507
218813
|
const svc = await connectorActorsService();
|
|
218508
218814
|
if (svc) {
|
|
218509
218815
|
if (actorId) {
|
|
@@ -218528,6 +218834,23 @@ ${composed}`;
|
|
|
218528
218834
|
connectorId: "feishu",
|
|
218529
218835
|
encrypted: false
|
|
218530
218836
|
});
|
|
218837
|
+
if (record10.grantedScopes) {
|
|
218838
|
+
try {
|
|
218839
|
+
pendingApproval = await recordFeishuPendingApproval({
|
|
218840
|
+
store: svc,
|
|
218841
|
+
actorId,
|
|
218842
|
+
appId,
|
|
218843
|
+
appSecret,
|
|
218844
|
+
selection: startedSelection.selection,
|
|
218845
|
+
sendAsUserRequested: startedSelection.sendAsUserRequested,
|
|
218846
|
+
...isHumanActorId(actor) ? { applicant: actor } : {},
|
|
218847
|
+
granted: record10.grantedScopes,
|
|
218848
|
+
now: Date.now()
|
|
218849
|
+
});
|
|
218850
|
+
} catch (e) {
|
|
218851
|
+
console.error(`[feishu-oauth] \u5F85\u5BA1\u6279\u8BB0\u5F55\u5199\u5165\u5931\u8D25: ${String(e)}`);
|
|
218852
|
+
}
|
|
218853
|
+
}
|
|
218531
218854
|
if (!who.openId) console.error("[feishu-oauth] user_info \u672A\u53D6\u5230\u6388\u6743\u4EBA open_id\uFF1A\u6388\u6743\u5931\u6548\u65F6\u65E0\u6CD5\u79C1\u4FE1\u672C\u4EBA\u3001\u4E5F\u7B7E\u4E0D\u51FA\u4E00\u952E\u91CD\u65B0\u6388\u6743\u94FE\u63A5");
|
|
218532
218855
|
try {
|
|
218533
218856
|
const secret = await svc.revealResolvedVariable("FEISHU_APP_SECRET", actorId);
|
|
@@ -218552,7 +218875,12 @@ ${composed}`;
|
|
|
218552
218875
|
}
|
|
218553
218876
|
}
|
|
218554
218877
|
}
|
|
218555
|
-
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({
|
|
218878
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({
|
|
218879
|
+
ok: true,
|
|
218880
|
+
appId,
|
|
218881
|
+
stored: true,
|
|
218882
|
+
...pendingApproval ? { pendingApproval: { modules: pendingApproval.modules, scopes: pendingApproval.scopes }, notice: pendingApproval.notice } : {}
|
|
218883
|
+
}));
|
|
218556
218884
|
} catch (e) {
|
|
218557
218885
|
res.writeHead(500).end(JSON.stringify({ error: String(e) }));
|
|
218558
218886
|
}
|
|
@@ -218895,6 +219223,7 @@ var init_server3 = __esm({
|
|
|
218895
219223
|
init_child_live_turn();
|
|
218896
219224
|
init_registry_audit_sink();
|
|
218897
219225
|
init_feishu_module_access();
|
|
219226
|
+
init_feishu_pending_approval();
|
|
218898
219227
|
init_src3();
|
|
218899
219228
|
init_github_app_inventory();
|
|
218900
219229
|
init_github_app_timing();
|
|
@@ -287145,6 +287474,122 @@ function createConnectorRenewalRuntime(options) {
|
|
|
287145
287474
|
}
|
|
287146
287475
|
for (const k2 of handledThisSweep) if (JSON.parse(k2)[0] === companyId) handledThisSweep.delete(k2);
|
|
287147
287476
|
};
|
|
287477
|
+
const applicantOpenId = async (companyId, store, actorId, app, applicant) => {
|
|
287478
|
+
if (!applicant || !isHumanActorId(applicant)) return null;
|
|
287479
|
+
const by = await store.revealVariable(FEISHU_AUTHORIZED_BY_VAR, actorId).catch(() => null);
|
|
287480
|
+
const stored = by === applicant ? await store.revealVariable(FEISHU_USER_OPEN_ID_VAR, actorId).catch(() => null) : null;
|
|
287481
|
+
return stored || recoverOpenId(companyId, app, applicant);
|
|
287482
|
+
};
|
|
287483
|
+
const deliverApprovalNotice = async (companyId, store, actorId, pending, app) => {
|
|
287484
|
+
const prev = pending.notice ?? { inApp: false, dm: "pending", attempts: 0 };
|
|
287485
|
+
const state = { ...prev, attempts: prev.attempts + 1 };
|
|
287486
|
+
const who = `actor=${actorId ?? "-"} \u7B2C ${state.attempts}/${MAX_NOTICE_ATTEMPTS} \u6B21`;
|
|
287487
|
+
const name = await agentName(companyId, actorId);
|
|
287488
|
+
const modules = feishuPendingApprovalModules(pending);
|
|
287489
|
+
if (!state.inApp) {
|
|
287490
|
+
try {
|
|
287491
|
+
const ledger = await options.notifications(companyId);
|
|
287492
|
+
if (!ledger) throw new Error("\u8BE5\u516C\u53F8\u7684\u901A\u77E5\u53F0\u8D26\u4E0D\u53EF\u7528");
|
|
287493
|
+
const recipients = pending.applicant && isHumanActorId(pending.applicant) ? [pending.applicant] : (await recipientsFor(companyId, store, actorId)).recipients;
|
|
287494
|
+
if (recipients.length === 0) throw new Error("\u6CA1\u6709\u6536\u4EF6\u4EBA\uFF08\u6CA1\u8BB0\u7533\u8BF7\u4EBA\u3001\u5458\u5DE5\u4E5F\u6CA1\u6709\u7ED1\u5B9A\u771F\u4EBA\uFF09");
|
|
287495
|
+
const rows = [];
|
|
287496
|
+
for (const recipient of recipients) {
|
|
287497
|
+
rows.push(await ledger.insert({
|
|
287498
|
+
recipient,
|
|
287499
|
+
category: "connector",
|
|
287500
|
+
kind: "feishu-approval-granted",
|
|
287501
|
+
// 每次申请一条(键里带提交时刻);同一次批准补发 / 重复扫描不重发(唯一约束)。
|
|
287502
|
+
sourceKey: `connector:feishu:${actorId ?? "org"}@approved:${pending.at}`,
|
|
287503
|
+
title: `\u7BA1\u7406\u5458\u5DF2\u6279\u51C6\u300C${name}\u300D\u7533\u8BF7\u7684\u98DE\u4E66\u6743\u9650\uFF0C\u8865\u6388\u6743\u540E\u5373\u53EF\u4F7F\u7528`,
|
|
287504
|
+
...actorId ? { actorId } : {},
|
|
287505
|
+
enteredAt: pending.approvedAt ?? new Date(now()).toISOString()
|
|
287506
|
+
}));
|
|
287507
|
+
}
|
|
287508
|
+
options.onNotifications?.(companyId, rows);
|
|
287509
|
+
state.inApp = true;
|
|
287510
|
+
} catch (err) {
|
|
287511
|
+
options.warn(new Error(`\u98DE\u4E66\u6743\u9650\u6279\u51C6\u7AD9\u5185\u901A\u77E5\u672A\u5199\u5165\uFF08${who}\uFF0C\u4E0B\u4E00\u62CD\u91CD\u8BD5\uFF09: ${String(err)}`));
|
|
287512
|
+
}
|
|
287513
|
+
}
|
|
287514
|
+
if (state.dm === "pending") {
|
|
287515
|
+
try {
|
|
287516
|
+
const openId = await applicantOpenId(companyId, store, actorId, app, pending.applicant);
|
|
287517
|
+
if (!openId) {
|
|
287518
|
+
state.dm = "unavailable";
|
|
287519
|
+
console.warn(`[credential-refresh] \u98DE\u4E66\u6743\u9650\u6279\u51C6\u79C1\u4FE1\u65E0\u4ECE\u53D1\u51FA\uFF08${pending.applicant ? "\u901A\u8BAF\u5F55\u6CA1\u6309\u7533\u8BF7\u4EBA\u7684\u8D26\u53F7\u90AE\u7BB1\u627E\u5230\u4ED6" : "\u6CA1\u8BB0\u7533\u8BF7\u4EBA"}\uFF09actor=${actorId ?? "-"}\uFF1B\u53EA\u6709\u7AD9\u5185\u901A\u77E5\uFF0C\u9700\u5230\u8FDE\u63A5\u5668\u9875\u91CD\u65B0\u8FDE\u63A5`);
|
|
287520
|
+
} else {
|
|
287521
|
+
const token2 = options.links.issue({
|
|
287522
|
+
companyId,
|
|
287523
|
+
...actorId ? { actorId } : {},
|
|
287524
|
+
connectorId: "feishu",
|
|
287525
|
+
purpose: "supplement",
|
|
287526
|
+
subject: openId
|
|
287527
|
+
});
|
|
287528
|
+
const link = options.apiBase ? feishuReauthUrl(options.apiBase, token2) : void 0;
|
|
287529
|
+
await notifyFeishuUser(store, actorId, feishuApprovalGrantedText({ agentName: name, modules, ...link ? { link } : {} }), openId);
|
|
287530
|
+
state.dm = "sent";
|
|
287531
|
+
}
|
|
287532
|
+
} catch (err) {
|
|
287533
|
+
options.warn(new Error(`\u98DE\u4E66\u6743\u9650\u6279\u51C6\u79C1\u4FE1\u53D1\u9001\u5931\u8D25\uFF08${who}\uFF0C\u4E0B\u4E00\u62CD\u91CD\u8BD5\uFF09: ${String(err)}`));
|
|
287534
|
+
}
|
|
287535
|
+
}
|
|
287536
|
+
if ((!state.inApp || state.dm === "pending") && state.attempts >= MAX_NOTICE_ATTEMPTS) {
|
|
287537
|
+
options.warn(new Error(`\u98DE\u4E66\u6743\u9650\u6279\u51C6\u901A\u77E5\u8865\u53D1 ${state.attempts} \u6B21\u4ECD\u672A\u9001\u5230\uFF0C\u653E\u5F03 actor=${actorId ?? "-"} \u7AD9\u5185=${String(state.inApp)} \u79C1\u4FE1=${state.dm}`));
|
|
287538
|
+
}
|
|
287539
|
+
return state;
|
|
287540
|
+
};
|
|
287541
|
+
const savePendingApproval = async (store, actorId, at2, next) => {
|
|
287542
|
+
await withConnectorCredentialLock("feishu", actorId, async () => {
|
|
287543
|
+
const current = await readFeishuPendingApproval(store, actorId);
|
|
287544
|
+
if (current?.at !== at2) return;
|
|
287545
|
+
if (next) await writeFeishuPendingApproval(store, actorId, next);
|
|
287546
|
+
else await clearFeishuPendingApproval(store, actorId);
|
|
287547
|
+
});
|
|
287548
|
+
};
|
|
287549
|
+
const checkPendingApproval = async (companyId, store, actorId) => {
|
|
287550
|
+
const pending = await readFeishuPendingApproval(store, actorId);
|
|
287551
|
+
if (!pending) return;
|
|
287552
|
+
const t = now();
|
|
287553
|
+
const app = await appCredentials(store, actorId);
|
|
287554
|
+
if (!app || app.appId !== pending.appId) {
|
|
287555
|
+
console.warn(`[credential-refresh] \u98DE\u4E66\u5F85\u5BA1\u6279\u8BB0\u5F55\u4F5C\u5E9F\uFF08\u5E94\u7528\u51ED\u636E${app ? "\u5DF2\u6362\u6210\u522B\u7684\u5E94\u7528" : "\u4E0D\u5B58\u5728"}\uFF09actor=${actorId ?? "-"}`);
|
|
287556
|
+
await savePendingApproval(store, actorId, pending.at, null);
|
|
287557
|
+
return;
|
|
287558
|
+
}
|
|
287559
|
+
let next;
|
|
287560
|
+
if (!pending.approvedAt) {
|
|
287561
|
+
if (t - Date.parse(pending.at) > FEISHU_PENDING_APPROVAL_WATCH_MS) {
|
|
287562
|
+
options.warn(new Error(`\u98DE\u4E66\u5F85\u5BA1\u6279 ${pending.at} \u8D77 30 \u5929\u672A\u68C0\u6D4B\u5230\u6279\u51C6\uFF0C\u4E0D\u518D\u68C0\u6D4B actor=${actorId ?? "-"} \u6743\u9650=${pending.pendingScopes.join(",")}`));
|
|
287563
|
+
await savePendingApproval(store, actorId, pending.at, null);
|
|
287564
|
+
return;
|
|
287565
|
+
}
|
|
287566
|
+
const scopes = await (options.fetchAppScopes ?? fetchFeishuAppScopes)(app.appId, app.appSecret);
|
|
287567
|
+
if (!feishuPendingApprovalSettled(pending, scopes)) return;
|
|
287568
|
+
next = { ...pending, approvedAt: new Date(t).toISOString(), notice: { inApp: false, dm: "pending", attempts: 0 } };
|
|
287569
|
+
console.warn(`[credential-refresh] \u98DE\u4E66\u5F85\u5BA1\u6279\u5DF2\u6279\u51C6 actor=${actorId ?? "-"} \u6743\u9650=${pending.pendingScopes.join(",")}`);
|
|
287570
|
+
} else {
|
|
287571
|
+
if (t - Date.parse(pending.approvedAt) > FEISHU_APPROVED_SUPPLEMENT_KEEP_MS) {
|
|
287572
|
+
await savePendingApproval(store, actorId, pending.at, null);
|
|
287573
|
+
return;
|
|
287574
|
+
}
|
|
287575
|
+
const n = pending.notice;
|
|
287576
|
+
if (!n || n.inApp && n.dm !== "pending" || n.attempts >= MAX_NOTICE_ATTEMPTS) return;
|
|
287577
|
+
next = pending;
|
|
287578
|
+
}
|
|
287579
|
+
await savePendingApproval(store, actorId, pending.at, { ...next, notice: await deliverApprovalNotice(companyId, store, actorId, next, app) });
|
|
287580
|
+
};
|
|
287581
|
+
const checkPendingApprovals = async (companyId, store) => {
|
|
287582
|
+
const svc = await options.actors(companyId);
|
|
287583
|
+
if (!svc) return;
|
|
287584
|
+
const ids2 = [void 0, ...(await svc.listActors({ status: "active" })).map((a) => a.id)];
|
|
287585
|
+
for (const actorId of ids2) {
|
|
287586
|
+
try {
|
|
287587
|
+
await checkPendingApproval(companyId, store, actorId);
|
|
287588
|
+
} catch (err) {
|
|
287589
|
+
options.warn(new Error(`\u98DE\u4E66\u5F85\u5BA1\u6279\u68C0\u6D4B\u5931\u8D25\uFF08\u4E0B\u4E00\u62CD\u91CD\u8BD5\uFF09actor=${actorId ?? "-"}: ${String(err)}`));
|
|
287590
|
+
}
|
|
287591
|
+
}
|
|
287592
|
+
};
|
|
287148
287593
|
const onFeishuRenewed = async (e, store) => {
|
|
287149
287594
|
if (await store.revealVariable(FEISHU_USER_OPEN_ID_VAR, e.actorId)) return;
|
|
287150
287595
|
const accessToken = e.outcome.credentials?.["user_access_token"];
|
|
@@ -287183,7 +287628,13 @@ function createConnectorRenewalRuntime(options) {
|
|
|
287183
287628
|
onRenewed: async (e, store) => {
|
|
287184
287629
|
if (e.connector.config.slug === "feishu") await onFeishuRenewed(e, store);
|
|
287185
287630
|
},
|
|
287186
|
-
afterCompany:
|
|
287631
|
+
afterCompany: async (companyId, store) => {
|
|
287632
|
+
try {
|
|
287633
|
+
await retryPendingNotices(companyId, store);
|
|
287634
|
+
} finally {
|
|
287635
|
+
await checkPendingApprovals(companyId, store);
|
|
287636
|
+
}
|
|
287637
|
+
},
|
|
287187
287638
|
warn: options.warn,
|
|
287188
287639
|
...options.now ? { now: options.now } : {}
|
|
287189
287640
|
});
|
|
@@ -287195,7 +287646,7 @@ function createConnectorRenewalRuntime(options) {
|
|
|
287195
287646
|
const store = await options.actors(claims.companyId);
|
|
287196
287647
|
if (!store) return;
|
|
287197
287648
|
const name = await agentName(claims.companyId, claims.actorId);
|
|
287198
|
-
await notifyFeishuUser(store, claims.actorId, `\u300C${name}\u300D\u7684\u98DE\u4E66\u7528\u6237\u6388\u6743\u5DF2\u6062\u590D\u3002`).catch(() => void 0);
|
|
287649
|
+
await notifyFeishuUser(store, claims.actorId, claims.purpose === "supplement" ? `\u300C${name}\u300D\u7684\u98DE\u4E66\u6743\u9650\u5DF2\u8865\u4E0A\uFF0C\u7BA1\u7406\u5458\u6279\u51C6\u7684\u529F\u80FD\u73B0\u5728\u53EF\u4EE5\u4F7F\u7528\u4E86\u3002` : `\u300C${name}\u300D\u7684\u98DE\u4E66\u7528\u6237\u6388\u6743\u5DF2\u6062\u590D\u3002`).catch(() => void 0);
|
|
287199
287650
|
},
|
|
287200
287651
|
onRejected: async (claims, who) => {
|
|
287201
287652
|
const store = await options.actors(claims.companyId);
|
|
@@ -301084,7 +301535,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
301084
301535
|
}
|
|
301085
301536
|
}
|
|
301086
301537
|
}
|
|
301087
|
-
var CLI_VERSION = "2.2.
|
|
301538
|
+
var CLI_VERSION = "2.2.115" ? "2.2.115" : "dev";
|
|
301088
301539
|
function apiHeaders(token2, company) {
|
|
301089
301540
|
const headers = {
|
|
301090
301541
|
authorization: `Bearer ${token2}`,
|
|
@@ -305255,7 +305706,7 @@ function shimScript() {
|
|
|
305255
305706
|
}
|
|
305256
305707
|
|
|
305257
305708
|
// src/index.ts
|
|
305258
|
-
var PKG_VERSION = true ? "2.2.
|
|
305709
|
+
var PKG_VERSION = true ? "2.2.115" : "dev";
|
|
305259
305710
|
var LOCAL_BIN = localBin();
|
|
305260
305711
|
var NPM_PREFIX = npmPrefix();
|
|
305261
305712
|
var INSTANCE = DEFAULT_INSTANCE;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oasis_test_v2",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.115",
|
|
4
4
|
"description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
|
|
5
5
|
"bin": {
|
|
6
6
|
"oasis": "./dist/index.js"
|
|
@@ -26,6 +26,6 @@
|
|
|
26
26
|
"node": ">=20"
|
|
27
27
|
},
|
|
28
28
|
"oasisRelease": {
|
|
29
|
-
"sourceHead": "
|
|
29
|
+
"sourceHead": "9c025c6edd39870a4e40a29026007109bbec04cf"
|
|
30
30
|
}
|
|
31
31
|
}
|