oasis_test_v2 2.2.113 → 2.2.114
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 +333 -18
- 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,78 @@ 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
|
+
var FEISHU_AUTH_PENDING_APPROVAL_VAR, FEISHU_PENDING_APPROVAL_WATCH_MS, FEISHU_APPROVED_SUPPLEMENT_KEEP_MS, AUTO_APPROVED2, userScopeIndex, isGranted, moduleNames;
|
|
20793
|
+
var init_pending_approval = __esm({
|
|
20794
|
+
"../connectors/src/feishu/pending-approval.ts"() {
|
|
20795
|
+
"use strict";
|
|
20796
|
+
init_scopes();
|
|
20797
|
+
FEISHU_AUTH_PENDING_APPROVAL_VAR = "FEISHU_AUTH_PENDING_APPROVAL";
|
|
20798
|
+
FEISHU_PENDING_APPROVAL_WATCH_MS = 30 * 24 * 36e5;
|
|
20799
|
+
FEISHU_APPROVED_SUPPLEMENT_KEEP_MS = 7 * 24 * 36e5;
|
|
20800
|
+
AUTO_APPROVED2 = new Set(FEISHU_BASIC_SCOPES);
|
|
20801
|
+
userScopeIndex = (appScopes) => new Map(
|
|
20802
|
+
appScopes.filter((s2) => s2.scope_name && (!s2.scope_type || s2.scope_type === "user")).map((s2) => [s2.scope_name, s2])
|
|
20803
|
+
);
|
|
20804
|
+
isGranted = (s2) => !!s2 && (s2.grant_status === void 0 || s2.grant_status === 1);
|
|
20805
|
+
moduleNames = (modules) => modules.map((m2) => FEISHU_MODULE_LABELS[m2] ?? m2).join("\u3001") || "\u6240\u7533\u8BF7\u7684";
|
|
20732
20806
|
}
|
|
20733
20807
|
});
|
|
20734
20808
|
|
|
@@ -24653,6 +24727,7 @@ var init_src3 = __esm({
|
|
|
24653
24727
|
init_host_isolation();
|
|
24654
24728
|
init_feishu();
|
|
24655
24729
|
init_user_auth();
|
|
24730
|
+
init_pending_approval();
|
|
24656
24731
|
init_scopes();
|
|
24657
24732
|
init_oauth();
|
|
24658
24733
|
init_scheduled_refresh();
|
|
@@ -24674,6 +24749,14 @@ var init_src3 = __esm({
|
|
|
24674
24749
|
});
|
|
24675
24750
|
|
|
24676
24751
|
// ../server/src/feishu-reauth.ts
|
|
24752
|
+
async function supplementSelection(store, actorId) {
|
|
24753
|
+
const pending = await readFeishuPendingApproval(store, actorId);
|
|
24754
|
+
if (!pending) return null;
|
|
24755
|
+
const appId = await store.revealResolvedVariable("FEISHU_APP_ID", actorId).catch(() => null);
|
|
24756
|
+
if (appId !== pending.appId) return null;
|
|
24757
|
+
const sel = normalizeFeishuAuthSelection({ modules: pending.modules, sendAsUser: pending.sendAsUser });
|
|
24758
|
+
return sel ? { sel, sendAsUser: pending.sendAsUserRequested, pending } : null;
|
|
24759
|
+
}
|
|
24677
24760
|
async function reauthSelection(store, actorId) {
|
|
24678
24761
|
const raw = await store.revealVariable(FEISHU_AUTH_SELECTION_VAR, actorId).catch(() => null);
|
|
24679
24762
|
if (raw) {
|
|
@@ -24714,17 +24797,31 @@ function createFeishuReauth(deps) {
|
|
|
24714
24797
|
};
|
|
24715
24798
|
}
|
|
24716
24799
|
await withConnectorCredentialLock("feishu", claims.actorId, async () => {
|
|
24800
|
+
const pending2 = claims.purpose === "supplement" ? await readFeishuPendingApproval(store, claims.actorId) : null;
|
|
24717
24801
|
await persistFeishuUserAuthorization(store, claims.actorId, data, now(), {
|
|
24718
24802
|
openId: who.openId,
|
|
24719
|
-
...who.name ? { userName: who.name } : {}
|
|
24803
|
+
...who.name ? { userName: who.name } : {},
|
|
24804
|
+
...pending2?.applicant ? { authorizedBy: pending2.applicant } : {}
|
|
24720
24805
|
});
|
|
24806
|
+
const record10 = feishuAuthSelectionRecord(sel, sendAsUserRequested, data);
|
|
24721
24807
|
await store.putVariable({
|
|
24722
24808
|
key: FEISHU_AUTH_SELECTION_VAR,
|
|
24723
|
-
value: JSON.stringify(
|
|
24809
|
+
value: JSON.stringify(record10),
|
|
24724
24810
|
...claims.actorId ? { scope: "personal", actorId: claims.actorId } : { scope: "global" },
|
|
24725
24811
|
connectorId: "feishu",
|
|
24726
24812
|
encrypted: false
|
|
24727
24813
|
});
|
|
24814
|
+
if (pending2) {
|
|
24815
|
+
const granted = record10.grantedScopes ? new Set(record10.grantedScopes) : null;
|
|
24816
|
+
const still = granted ? pending2.pendingScopes.filter((x2) => !granted.has(x2)) : [];
|
|
24817
|
+
if (still.length === 0) await clearFeishuPendingApproval(store, claims.actorId);
|
|
24818
|
+
else {
|
|
24819
|
+
const next = { ...pending2, pendingScopes: still };
|
|
24820
|
+
delete next.approvedAt;
|
|
24821
|
+
delete next.notice;
|
|
24822
|
+
await writeFeishuPendingApproval(store, claims.actorId, next);
|
|
24823
|
+
}
|
|
24824
|
+
}
|
|
24728
24825
|
});
|
|
24729
24826
|
await deps.onRestored?.(claims, { openId: who.openId, ...who.name ? { userName: who.name } : {} }).catch((e) => warn(`onRestored: ${String(e)}`));
|
|
24730
24827
|
return { state: "restored", ...who.name ? { userName: who.name } : {} };
|
|
@@ -24756,7 +24853,15 @@ function createFeishuReauth(deps) {
|
|
|
24756
24853
|
if (!store) return { ok: false, status: 404, message: "\u627E\u4E0D\u5230\u8FD9\u4E2A\u94FE\u63A5\u6240\u5C5E\u7684\u7EC4\u7EC7\u3002" };
|
|
24757
24854
|
const app = await appCredentials(store, claims.actorId);
|
|
24758
24855
|
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
|
-
|
|
24856
|
+
let picked;
|
|
24857
|
+
if (claims.purpose === "supplement") {
|
|
24858
|
+
const sup = await supplementSelection(store, claims.actorId);
|
|
24859
|
+
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" };
|
|
24860
|
+
picked = sup;
|
|
24861
|
+
} else {
|
|
24862
|
+
picked = await reauthSelection(store, claims.actorId);
|
|
24863
|
+
}
|
|
24864
|
+
const { sel, sendAsUser } = picked;
|
|
24760
24865
|
const auth = await (deps.start ?? startFeishuDeviceAuthorization)({
|
|
24761
24866
|
appId: app.appId,
|
|
24762
24867
|
appSecret: app.appSecret,
|
|
@@ -24771,7 +24876,7 @@ function createFeishuReauth(deps) {
|
|
|
24771
24876
|
const intervalSec = auth.interval ?? DEFAULT_POLL_INTERVAL_SEC;
|
|
24772
24877
|
void watch(auth.deviceCode, entry, { store, ...app, sel, sendAsUser, intervalSec });
|
|
24773
24878
|
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 };
|
|
24879
|
+
return { ok: true, verificationUrl: auth.verificationUrl, deviceCode: auth.deviceCode, agentName, intervalSec, purpose: claims.purpose };
|
|
24775
24880
|
},
|
|
24776
24881
|
/** 页面轮询结果。票与 deviceCode 必须是同一次 begin 发出来的。 */
|
|
24777
24882
|
status(token2, deviceCode) {
|
|
@@ -24788,17 +24893,18 @@ function createFeishuReauth(deps) {
|
|
|
24788
24893
|
function feishuReauthPageHtml(input) {
|
|
24789
24894
|
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
24895
|
<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
|
-
<
|
|
24896
|
+
if (!input.ok) return `${head}<h2>\u65E0\u6CD5\u5B8C\u6210\u6388\u6743</h2><p>${escapeHtml(input.message)}</p></body></html>`;
|
|
24897
|
+
const supplement = input.purpose === "supplement";
|
|
24898
|
+
const cfg = JSON.stringify({ t: input.token, d: input.deviceCode, i: Math.max(2, input.intervalSec), s: supplement }).replace(/</g, "\\u003c");
|
|
24899
|
+
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>
|
|
24900
|
+
<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
24901
|
<p><a class="btn" href="${escapeHtml(input.verificationUrl)}" target="_blank" rel="noopener">\u53BB\u98DE\u4E66\u6388\u6743</a></p>
|
|
24796
24902
|
<p id="s">\u7B49\u5F85\u4F60\u5728\u98DE\u4E66\u70B9\u300C\u6388\u6743\u300D\u2026</p>
|
|
24797
24903
|
<script>(function(){var c=${cfg};var el=document.getElementById("s");
|
|
24798
24904
|
function tick(){fetch("reauth/status",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({t:c.t,deviceCode:c.d})})
|
|
24799
24905
|
.then(function(r){return r.json()}).then(function(b){
|
|
24800
24906
|
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}
|
|
24907
|
+
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
24908
|
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
24909
|
setTimeout(tick,c.i*1000)})();</script></body></html>`;
|
|
24804
24910
|
}
|
|
@@ -212197,6 +212303,42 @@ var init_feishu_module_access = __esm({
|
|
|
212197
212303
|
}
|
|
212198
212304
|
});
|
|
212199
212305
|
|
|
212306
|
+
// ../server/src/feishu-pending-approval.ts
|
|
212307
|
+
async function recordFeishuPendingApproval(input) {
|
|
212308
|
+
const requested = scopesForSelection(input.selection, input.sendAsUserRequested);
|
|
212309
|
+
let appScopes = null;
|
|
212310
|
+
try {
|
|
212311
|
+
appScopes = await (input.fetchScopes ?? fetchFeishuAppScopes)(input.appId, input.appSecret);
|
|
212312
|
+
} catch (e) {
|
|
212313
|
+
(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)}`);
|
|
212314
|
+
}
|
|
212315
|
+
const pendingScopes = feishuPendingApprovalScopes({ requested, granted: input.granted, appScopes });
|
|
212316
|
+
if (pendingScopes.length === 0) {
|
|
212317
|
+
if (input.granted) {
|
|
212318
|
+
await withConnectorCredentialLock("feishu", input.actorId, () => clearFeishuPendingApproval(input.store, input.actorId));
|
|
212319
|
+
}
|
|
212320
|
+
return null;
|
|
212321
|
+
}
|
|
212322
|
+
const record10 = {
|
|
212323
|
+
at: new Date(input.now).toISOString(),
|
|
212324
|
+
appId: input.appId,
|
|
212325
|
+
...input.applicant ? { applicant: input.applicant } : {},
|
|
212326
|
+
modules: input.selection.modules,
|
|
212327
|
+
sendAsUser: input.selection.sendAsUser,
|
|
212328
|
+
sendAsUserRequested: input.sendAsUserRequested,
|
|
212329
|
+
pendingScopes
|
|
212330
|
+
};
|
|
212331
|
+
await withConnectorCredentialLock("feishu", input.actorId, () => writeFeishuPendingApproval(input.store, input.actorId, record10));
|
|
212332
|
+
const modules = feishuPendingApprovalModules(record10);
|
|
212333
|
+
return { modules, scopes: pendingScopes, notice: feishuPendingApprovalNotice(modules) };
|
|
212334
|
+
}
|
|
212335
|
+
var init_feishu_pending_approval = __esm({
|
|
212336
|
+
"../server/src/feishu-pending-approval.ts"() {
|
|
212337
|
+
"use strict";
|
|
212338
|
+
init_src3();
|
|
212339
|
+
}
|
|
212340
|
+
});
|
|
212341
|
+
|
|
212200
212342
|
// ../server/src/github-app-inventory.ts
|
|
212201
212343
|
async function collectOasisGithubApps(svc) {
|
|
212202
212344
|
const rows = (await svc.listVariables()).filter((r) => r.scope === "global" || r.scope === "personal");
|
|
@@ -218498,12 +218640,40 @@ ${composed}`;
|
|
|
218498
218640
|
const pollSvc = await connectorActorsService();
|
|
218499
218641
|
const appSecret = pollSvc ? await pollSvc.revealResolvedVariable("FEISHU_APP_SECRET", actorId) : null;
|
|
218500
218642
|
if (!appSecret) throw new Error("FEISHU_APP_SECRET not found \u2014 please complete app setup first");
|
|
218501
|
-
|
|
218643
|
+
let polled;
|
|
218644
|
+
try {
|
|
218645
|
+
polled = await pollFeishuDeviceToken({ appId, appSecret, deviceCode });
|
|
218646
|
+
} catch (e) {
|
|
218647
|
+
if (!(e instanceof FeishuDeviceFlowError) || !pollSvc) throw e;
|
|
218648
|
+
const pendingApproval2 = await recordFeishuPendingApproval({
|
|
218649
|
+
store: pollSvc,
|
|
218650
|
+
actorId,
|
|
218651
|
+
appId,
|
|
218652
|
+
appSecret,
|
|
218653
|
+
selection: startedSelection.selection,
|
|
218654
|
+
sendAsUserRequested: startedSelection.sendAsUserRequested,
|
|
218655
|
+
...isHumanActorId(actor) ? { applicant: actor } : {},
|
|
218656
|
+
now: Date.now()
|
|
218657
|
+
});
|
|
218658
|
+
const expired = e.code === "expired_token" || e.code === "invalid_grant";
|
|
218659
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(pendingApproval2 ? {
|
|
218660
|
+
ok: false,
|
|
218661
|
+
final: true,
|
|
218662
|
+
pendingApproval: { modules: pendingApproval2.modules, scopes: pendingApproval2.scopes },
|
|
218663
|
+
notice: expired ? `\u6388\u6743\u9875\u5DF2\u8D85\u65F6\u3002\u5982\u679C\u4F60\u5728\u6388\u6743\u9875\u70B9\u4E86\u300C\u7533\u8BF7\u300D\uFF1A${pendingApproval2.notice}\u6CA1\u70B9\u7684\u8BDD\u91CD\u65B0\u53D1\u8D77\u6388\u6743\u5373\u53EF\u3002` : pendingApproval2.notice
|
|
218664
|
+
} : {
|
|
218665
|
+
ok: false,
|
|
218666
|
+
final: true,
|
|
218667
|
+
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`
|
|
218668
|
+
}));
|
|
218669
|
+
return;
|
|
218670
|
+
}
|
|
218502
218671
|
if (polled.status === "pending") {
|
|
218503
218672
|
res.writeHead(200).end(JSON.stringify({ ok: false, error: "authorization_pending" }));
|
|
218504
218673
|
return;
|
|
218505
218674
|
}
|
|
218506
218675
|
const data = polled.data;
|
|
218676
|
+
let pendingApproval = null;
|
|
218507
218677
|
const svc = await connectorActorsService();
|
|
218508
218678
|
if (svc) {
|
|
218509
218679
|
if (actorId) {
|
|
@@ -218528,6 +218698,23 @@ ${composed}`;
|
|
|
218528
218698
|
connectorId: "feishu",
|
|
218529
218699
|
encrypted: false
|
|
218530
218700
|
});
|
|
218701
|
+
if (record10.grantedScopes) {
|
|
218702
|
+
try {
|
|
218703
|
+
pendingApproval = await recordFeishuPendingApproval({
|
|
218704
|
+
store: svc,
|
|
218705
|
+
actorId,
|
|
218706
|
+
appId,
|
|
218707
|
+
appSecret,
|
|
218708
|
+
selection: startedSelection.selection,
|
|
218709
|
+
sendAsUserRequested: startedSelection.sendAsUserRequested,
|
|
218710
|
+
...isHumanActorId(actor) ? { applicant: actor } : {},
|
|
218711
|
+
granted: record10.grantedScopes,
|
|
218712
|
+
now: Date.now()
|
|
218713
|
+
});
|
|
218714
|
+
} catch (e) {
|
|
218715
|
+
console.error(`[feishu-oauth] \u5F85\u5BA1\u6279\u8BB0\u5F55\u5199\u5165\u5931\u8D25: ${String(e)}`);
|
|
218716
|
+
}
|
|
218717
|
+
}
|
|
218531
218718
|
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
218719
|
try {
|
|
218533
218720
|
const secret = await svc.revealResolvedVariable("FEISHU_APP_SECRET", actorId);
|
|
@@ -218552,7 +218739,12 @@ ${composed}`;
|
|
|
218552
218739
|
}
|
|
218553
218740
|
}
|
|
218554
218741
|
}
|
|
218555
|
-
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({
|
|
218742
|
+
res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({
|
|
218743
|
+
ok: true,
|
|
218744
|
+
appId,
|
|
218745
|
+
stored: true,
|
|
218746
|
+
...pendingApproval ? { pendingApproval: { modules: pendingApproval.modules, scopes: pendingApproval.scopes }, notice: pendingApproval.notice } : {}
|
|
218747
|
+
}));
|
|
218556
218748
|
} catch (e) {
|
|
218557
218749
|
res.writeHead(500).end(JSON.stringify({ error: String(e) }));
|
|
218558
218750
|
}
|
|
@@ -218895,6 +219087,7 @@ var init_server3 = __esm({
|
|
|
218895
219087
|
init_child_live_turn();
|
|
218896
219088
|
init_registry_audit_sink();
|
|
218897
219089
|
init_feishu_module_access();
|
|
219090
|
+
init_feishu_pending_approval();
|
|
218898
219091
|
init_src3();
|
|
218899
219092
|
init_github_app_inventory();
|
|
218900
219093
|
init_github_app_timing();
|
|
@@ -287145,6 +287338,122 @@ function createConnectorRenewalRuntime(options) {
|
|
|
287145
287338
|
}
|
|
287146
287339
|
for (const k2 of handledThisSweep) if (JSON.parse(k2)[0] === companyId) handledThisSweep.delete(k2);
|
|
287147
287340
|
};
|
|
287341
|
+
const applicantOpenId = async (companyId, store, actorId, app, applicant) => {
|
|
287342
|
+
if (!applicant || !isHumanActorId(applicant)) return null;
|
|
287343
|
+
const by = await store.revealVariable(FEISHU_AUTHORIZED_BY_VAR, actorId).catch(() => null);
|
|
287344
|
+
const stored = by === applicant ? await store.revealVariable(FEISHU_USER_OPEN_ID_VAR, actorId).catch(() => null) : null;
|
|
287345
|
+
return stored || recoverOpenId(companyId, app, applicant);
|
|
287346
|
+
};
|
|
287347
|
+
const deliverApprovalNotice = async (companyId, store, actorId, pending, app) => {
|
|
287348
|
+
const prev = pending.notice ?? { inApp: false, dm: "pending", attempts: 0 };
|
|
287349
|
+
const state = { ...prev, attempts: prev.attempts + 1 };
|
|
287350
|
+
const who = `actor=${actorId ?? "-"} \u7B2C ${state.attempts}/${MAX_NOTICE_ATTEMPTS} \u6B21`;
|
|
287351
|
+
const name = await agentName(companyId, actorId);
|
|
287352
|
+
const modules = feishuPendingApprovalModules(pending);
|
|
287353
|
+
if (!state.inApp) {
|
|
287354
|
+
try {
|
|
287355
|
+
const ledger = await options.notifications(companyId);
|
|
287356
|
+
if (!ledger) throw new Error("\u8BE5\u516C\u53F8\u7684\u901A\u77E5\u53F0\u8D26\u4E0D\u53EF\u7528");
|
|
287357
|
+
const recipients = pending.applicant && isHumanActorId(pending.applicant) ? [pending.applicant] : (await recipientsFor(companyId, store, actorId)).recipients;
|
|
287358
|
+
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");
|
|
287359
|
+
const rows = [];
|
|
287360
|
+
for (const recipient of recipients) {
|
|
287361
|
+
rows.push(await ledger.insert({
|
|
287362
|
+
recipient,
|
|
287363
|
+
category: "connector",
|
|
287364
|
+
kind: "feishu-approval-granted",
|
|
287365
|
+
// 每次申请一条(键里带提交时刻);同一次批准补发 / 重复扫描不重发(唯一约束)。
|
|
287366
|
+
sourceKey: `connector:feishu:${actorId ?? "org"}@approved:${pending.at}`,
|
|
287367
|
+
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`,
|
|
287368
|
+
...actorId ? { actorId } : {},
|
|
287369
|
+
enteredAt: pending.approvedAt ?? new Date(now()).toISOString()
|
|
287370
|
+
}));
|
|
287371
|
+
}
|
|
287372
|
+
options.onNotifications?.(companyId, rows);
|
|
287373
|
+
state.inApp = true;
|
|
287374
|
+
} catch (err) {
|
|
287375
|
+
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)}`));
|
|
287376
|
+
}
|
|
287377
|
+
}
|
|
287378
|
+
if (state.dm === "pending") {
|
|
287379
|
+
try {
|
|
287380
|
+
const openId = await applicantOpenId(companyId, store, actorId, app, pending.applicant);
|
|
287381
|
+
if (!openId) {
|
|
287382
|
+
state.dm = "unavailable";
|
|
287383
|
+
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`);
|
|
287384
|
+
} else {
|
|
287385
|
+
const token2 = options.links.issue({
|
|
287386
|
+
companyId,
|
|
287387
|
+
...actorId ? { actorId } : {},
|
|
287388
|
+
connectorId: "feishu",
|
|
287389
|
+
purpose: "supplement",
|
|
287390
|
+
subject: openId
|
|
287391
|
+
});
|
|
287392
|
+
const link = options.apiBase ? feishuReauthUrl(options.apiBase, token2) : void 0;
|
|
287393
|
+
await notifyFeishuUser(store, actorId, feishuApprovalGrantedText({ agentName: name, modules, ...link ? { link } : {} }), openId);
|
|
287394
|
+
state.dm = "sent";
|
|
287395
|
+
}
|
|
287396
|
+
} catch (err) {
|
|
287397
|
+
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)}`));
|
|
287398
|
+
}
|
|
287399
|
+
}
|
|
287400
|
+
if ((!state.inApp || state.dm === "pending") && state.attempts >= MAX_NOTICE_ATTEMPTS) {
|
|
287401
|
+
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}`));
|
|
287402
|
+
}
|
|
287403
|
+
return state;
|
|
287404
|
+
};
|
|
287405
|
+
const savePendingApproval = async (store, actorId, at2, next) => {
|
|
287406
|
+
await withConnectorCredentialLock("feishu", actorId, async () => {
|
|
287407
|
+
const current = await readFeishuPendingApproval(store, actorId);
|
|
287408
|
+
if (current?.at !== at2) return;
|
|
287409
|
+
if (next) await writeFeishuPendingApproval(store, actorId, next);
|
|
287410
|
+
else await clearFeishuPendingApproval(store, actorId);
|
|
287411
|
+
});
|
|
287412
|
+
};
|
|
287413
|
+
const checkPendingApproval = async (companyId, store, actorId) => {
|
|
287414
|
+
const pending = await readFeishuPendingApproval(store, actorId);
|
|
287415
|
+
if (!pending) return;
|
|
287416
|
+
const t = now();
|
|
287417
|
+
const app = await appCredentials(store, actorId);
|
|
287418
|
+
if (!app || app.appId !== pending.appId) {
|
|
287419
|
+
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 ?? "-"}`);
|
|
287420
|
+
await savePendingApproval(store, actorId, pending.at, null);
|
|
287421
|
+
return;
|
|
287422
|
+
}
|
|
287423
|
+
let next;
|
|
287424
|
+
if (!pending.approvedAt) {
|
|
287425
|
+
if (t - Date.parse(pending.at) > FEISHU_PENDING_APPROVAL_WATCH_MS) {
|
|
287426
|
+
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(",")}`));
|
|
287427
|
+
await savePendingApproval(store, actorId, pending.at, null);
|
|
287428
|
+
return;
|
|
287429
|
+
}
|
|
287430
|
+
const scopes = await (options.fetchAppScopes ?? fetchFeishuAppScopes)(app.appId, app.appSecret);
|
|
287431
|
+
if (!feishuPendingApprovalSettled(pending, scopes)) return;
|
|
287432
|
+
next = { ...pending, approvedAt: new Date(t).toISOString(), notice: { inApp: false, dm: "pending", attempts: 0 } };
|
|
287433
|
+
console.warn(`[credential-refresh] \u98DE\u4E66\u5F85\u5BA1\u6279\u5DF2\u6279\u51C6 actor=${actorId ?? "-"} \u6743\u9650=${pending.pendingScopes.join(",")}`);
|
|
287434
|
+
} else {
|
|
287435
|
+
if (t - Date.parse(pending.approvedAt) > FEISHU_APPROVED_SUPPLEMENT_KEEP_MS) {
|
|
287436
|
+
await savePendingApproval(store, actorId, pending.at, null);
|
|
287437
|
+
return;
|
|
287438
|
+
}
|
|
287439
|
+
const n = pending.notice;
|
|
287440
|
+
if (!n || n.inApp && n.dm !== "pending" || n.attempts >= MAX_NOTICE_ATTEMPTS) return;
|
|
287441
|
+
next = pending;
|
|
287442
|
+
}
|
|
287443
|
+
await savePendingApproval(store, actorId, pending.at, { ...next, notice: await deliverApprovalNotice(companyId, store, actorId, next, app) });
|
|
287444
|
+
};
|
|
287445
|
+
const checkPendingApprovals = async (companyId, store) => {
|
|
287446
|
+
const svc = await options.actors(companyId);
|
|
287447
|
+
if (!svc) return;
|
|
287448
|
+
const ids2 = [void 0, ...(await svc.listActors({ status: "active" })).map((a) => a.id)];
|
|
287449
|
+
for (const actorId of ids2) {
|
|
287450
|
+
try {
|
|
287451
|
+
await checkPendingApproval(companyId, store, actorId);
|
|
287452
|
+
} catch (err) {
|
|
287453
|
+
options.warn(new Error(`\u98DE\u4E66\u5F85\u5BA1\u6279\u68C0\u6D4B\u5931\u8D25\uFF08\u4E0B\u4E00\u62CD\u91CD\u8BD5\uFF09actor=${actorId ?? "-"}: ${String(err)}`));
|
|
287454
|
+
}
|
|
287455
|
+
}
|
|
287456
|
+
};
|
|
287148
287457
|
const onFeishuRenewed = async (e, store) => {
|
|
287149
287458
|
if (await store.revealVariable(FEISHU_USER_OPEN_ID_VAR, e.actorId)) return;
|
|
287150
287459
|
const accessToken = e.outcome.credentials?.["user_access_token"];
|
|
@@ -287183,7 +287492,13 @@ function createConnectorRenewalRuntime(options) {
|
|
|
287183
287492
|
onRenewed: async (e, store) => {
|
|
287184
287493
|
if (e.connector.config.slug === "feishu") await onFeishuRenewed(e, store);
|
|
287185
287494
|
},
|
|
287186
|
-
afterCompany:
|
|
287495
|
+
afterCompany: async (companyId, store) => {
|
|
287496
|
+
try {
|
|
287497
|
+
await retryPendingNotices(companyId, store);
|
|
287498
|
+
} finally {
|
|
287499
|
+
await checkPendingApprovals(companyId, store);
|
|
287500
|
+
}
|
|
287501
|
+
},
|
|
287187
287502
|
warn: options.warn,
|
|
287188
287503
|
...options.now ? { now: options.now } : {}
|
|
287189
287504
|
});
|
|
@@ -287195,7 +287510,7 @@ function createConnectorRenewalRuntime(options) {
|
|
|
287195
287510
|
const store = await options.actors(claims.companyId);
|
|
287196
287511
|
if (!store) return;
|
|
287197
287512
|
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);
|
|
287513
|
+
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
287514
|
},
|
|
287200
287515
|
onRejected: async (claims, who) => {
|
|
287201
287516
|
const store = await options.actors(claims.companyId);
|
|
@@ -301084,7 +301399,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
301084
301399
|
}
|
|
301085
301400
|
}
|
|
301086
301401
|
}
|
|
301087
|
-
var CLI_VERSION = "2.2.
|
|
301402
|
+
var CLI_VERSION = "2.2.114" ? "2.2.114" : "dev";
|
|
301088
301403
|
function apiHeaders(token2, company) {
|
|
301089
301404
|
const headers = {
|
|
301090
301405
|
authorization: `Bearer ${token2}`,
|
|
@@ -305255,7 +305570,7 @@ function shimScript() {
|
|
|
305255
305570
|
}
|
|
305256
305571
|
|
|
305257
305572
|
// src/index.ts
|
|
305258
|
-
var PKG_VERSION = true ? "2.2.
|
|
305573
|
+
var PKG_VERSION = true ? "2.2.114" : "dev";
|
|
305259
305574
|
var LOCAL_BIN = localBin();
|
|
305260
305575
|
var NPM_PREFIX = npmPrefix();
|
|
305261
305576
|
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.114",
|
|
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": "46e4f9275679ea8eec37f0f1e30b45cc48e3e70c"
|
|
30
30
|
}
|
|
31
31
|
}
|