oasis_test_v2 2.2.112 → 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/feishu/wrapper.sh +103 -31
- package/dist/index.js +567 -112
- package/package.json +2 -2
package/dist/feishu/wrapper.sh
CHANGED
|
@@ -11,13 +11,15 @@
|
|
|
11
11
|
# LARK_BIN — 真实 lark-cli 绝对路径(避免递归调用自身)
|
|
12
12
|
# FEISHU_CREDS_FILE — 凭据文件路径(内含 export LARKSUITE_CLI_* 行)
|
|
13
13
|
#
|
|
14
|
-
# 按 Agent 限制可用模块(产品反馈「飞书连接器·按 Agent
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
14
|
+
# 按 Agent 限制可用模块(产品反馈「飞书连接器·按 Agent 的权限模型」):只放行所选模块的
|
|
15
|
+
# `lark-cli <domain> …` 与 `lark-cli api <METHOD> /open-apis/<service>/…`,机器人与用户身份一样拦
|
|
16
|
+
# (bot 的企业 token 能调应用开通的全集,飞书侧分不开)。放行表由 inject() 按 FEISHU_AUTH_SELECTION
|
|
17
|
+
# 算好写入凭据文件(feishuModulePolicyEnv),这里不认识任何模块,只按规则表(OASIS_FEISHU_RULES)查。
|
|
18
|
+
# 共用的 drive 命令/接口按子命令、路径细分。**没有放行表、没有有效选择都按一个模块都没开放拦**,不会退成不限制。
|
|
18
19
|
# 被拦时照 lark-cli 的错误形状往 stderr 打一段 JSON、退出码 3(与 lark-cli 自己的鉴权失败同码)。
|
|
19
20
|
|
|
20
21
|
set -euo pipefail
|
|
22
|
+
shopt -s extglob # 放行规则用 +([!/]) / ?(/*) 表示「一段」「零到多段」
|
|
21
23
|
|
|
22
24
|
OASIS_BIN_VAR="LARK_BIN"
|
|
23
25
|
OASIS_CMD_NAME="lark-cli"
|
|
@@ -28,7 +30,7 @@ oasis_resolve_bin
|
|
|
28
30
|
oasis_check_available
|
|
29
31
|
|
|
30
32
|
# 放行表只认凭据文件里的:先清掉 agent 环境里可能带进来的同名变量。
|
|
31
|
-
unset OASIS_FEISHU_ALLOW
|
|
33
|
+
unset OASIS_FEISHU_POLICY OASIS_FEISHU_ALLOW OASIS_FEISHU_RULES OASIS_FEISHU_LABELS OASIS_FEISHU_MODULES
|
|
32
34
|
|
|
33
35
|
# Load feishu credentials into THIS process only (not visible to the agent).
|
|
34
36
|
if [ -n "${FEISHU_CREDS_FILE:-}" ] && [ -f "${FEISHU_CREDS_FILE}" ]; then
|
|
@@ -41,34 +43,82 @@ FEISHU_NEUTRAL_COMMANDS=" help schema skills whoami doctor completion auth confi
|
|
|
41
43
|
# 任何模块都放行的接口 service;与 scopes.ts FEISHU_NEUTRAL_API_SERVICES 同一份。
|
|
42
44
|
FEISHU_NEUTRAL_API=" authen auth "
|
|
43
45
|
|
|
46
|
+
feishu_reply_blocked() {
|
|
47
|
+
printf '{\n "ok": false,\n "error": {\n "type": "oasis_module_blocked",\n "message": "%s",\n "hint": "%s"\n }\n}\n' "$1" "$2" >&2
|
|
48
|
+
exit 3
|
|
49
|
+
}
|
|
50
|
+
|
|
44
51
|
feishu_blocked() {
|
|
45
|
-
# $1 =
|
|
46
|
-
local
|
|
47
|
-
local
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
# $1 = 规则要求的模块(逗号分隔,空 = 不属于任何模块);$2 = 给人看的命令写法(已过滤成安全字符)。
|
|
53
|
+
local mods="$1" shown="$2" need="" m entry label
|
|
54
|
+
local reconnect="请让配置人在 Oasis 里这个 agent 的飞书连接器详情点「重新连接」"
|
|
55
|
+
case "${OASIS_FEISHU_POLICY:-}" in
|
|
56
|
+
ok) ;;
|
|
57
|
+
none)
|
|
58
|
+
feishu_reply_blocked "本 agent 的飞书连接器还没有保存过可用模块的选择,Oasis 按「一个模块都没开放」处理,${shown} 已被拦下(机器人与用户身份都不可用)。" \
|
|
59
|
+
"${reconnect},勾选需要的模块后完成授权。" ;;
|
|
60
|
+
invalid)
|
|
61
|
+
feishu_reply_blocked "本 agent 的飞书连接器保存的模块选择无法识别,Oasis 按「一个模块都没开放」处理,${shown} 已被拦下(机器人与用户身份都不可用)。" \
|
|
62
|
+
"${reconnect},重新勾选模块后完成授权。" ;;
|
|
63
|
+
*)
|
|
64
|
+
feishu_reply_blocked "本次运行没有拿到飞书模块放行表,Oasis 不放行 ${shown}(机器人与用户身份都不可用)。" \
|
|
65
|
+
"请重新发起任务;仍出现请联系 Oasis 管理员检查飞书连接器。" ;;
|
|
66
|
+
esac
|
|
67
|
+
if [ -n "$mods" ]; then
|
|
68
|
+
for m in ${mods//,/ }; do
|
|
69
|
+
label="$m"
|
|
70
|
+
for entry in ${OASIS_FEISHU_LABELS:-}; do
|
|
71
|
+
if [ "${entry%%=*}" = "$m" ]; then label="${entry#*=}"; break; fi
|
|
72
|
+
done
|
|
73
|
+
need="${need:+${need}」或「}${label}"
|
|
74
|
+
done
|
|
75
|
+
feishu_reply_blocked "本 agent 的飞书连接器没有开放「${need}」模块,${shown} 已被 Oasis 拦下(机器人与用户身份都不可用)。当前开放的模块:${OASIS_FEISHU_MODULES:-无}。" \
|
|
76
|
+
"如需使用,${reconnect},勾选「${need}」后完成授权。"
|
|
57
77
|
fi
|
|
58
|
-
|
|
59
|
-
|
|
78
|
+
feishu_reply_blocked "${shown} 不属于任何可勾选的飞书功能模块;本 agent 的飞书调用已按模块限制,Oasis 不放行它。当前开放的模块:${OASIS_FEISHU_MODULES:-无}。" \
|
|
79
|
+
"请改用已开放模块对应的 lark-cli 命令;共用的 drive 子命令须紧跟在 drive 之后写。确需此能力请联系 Oasis 管理员。"
|
|
60
80
|
}
|
|
61
81
|
|
|
62
82
|
# 只把「看起来像命令名 / service 名」的字符串回显出来,其余一律写成占位——它要进 JSON。
|
|
63
83
|
feishu_safe() {
|
|
64
84
|
case "$1" in
|
|
65
|
-
''|*[!A-Za-z0-9_
|
|
85
|
+
''|*[!A-Za-z0-9_.+-]*) printf '%s' "该命令" ;;
|
|
86
|
+
*) printf '%s' "$1" ;;
|
|
87
|
+
esac
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# 按规则表判 $1(cmd/<domain>/… 或 api/<METHOD>/<service>/…):命中且所需模块里有一个已放行 → 放行;
|
|
91
|
+
# 命中但都没放行 → 拦并说缺哪个;一条都没命中 → 拦(不属于任何模块)。
|
|
92
|
+
feishu_check_key() {
|
|
93
|
+
local key="$1" shown="$2" entry pat mods m
|
|
94
|
+
set -f
|
|
95
|
+
for entry in ${OASIS_FEISHU_RULES:-}; do
|
|
96
|
+
pat="${entry%=*}"; mods="${entry##*=}"
|
|
97
|
+
# shellcheck disable=SC2254
|
|
98
|
+
case "$key" in
|
|
99
|
+
$pat)
|
|
100
|
+
set +f
|
|
101
|
+
if [ "${OASIS_FEISHU_POLICY:-}" = "ok" ]; then
|
|
102
|
+
for m in ${mods//,/ }; do
|
|
103
|
+
case "${OASIS_FEISHU_ALLOW:-}" in *" $m "*) return 0 ;; esac
|
|
104
|
+
done
|
|
105
|
+
fi
|
|
106
|
+
feishu_blocked "$mods" "$shown" ;;
|
|
107
|
+
esac
|
|
108
|
+
done
|
|
109
|
+
set +f
|
|
110
|
+
feishu_blocked "" "$shown"
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# 命令行里的一个词能不能原样进规则 key:只允许命令名字符,其余写成 ?(不会命中任何规则)。
|
|
114
|
+
feishu_seg() {
|
|
115
|
+
case "$1" in
|
|
116
|
+
''|*[!A-Za-z0-9_.+-]*) printf '?' ;;
|
|
66
117
|
*) printf '%s' "$1" ;;
|
|
67
118
|
esac
|
|
68
119
|
}
|
|
69
120
|
|
|
70
121
|
feishu_enforce_modules() {
|
|
71
|
-
[ -n "${OASIS_FEISHU_ALLOW:-}" ] || return 0 # 没保存过模块选择:不限制
|
|
72
122
|
local args=("$@") i=0 n=$# cmd=""
|
|
73
123
|
# 跳过命令前的全局参数(--profile X、-h/--help、-v/--version)。
|
|
74
124
|
while [ "$i" -lt "$n" ]; do
|
|
@@ -82,8 +132,8 @@ feishu_enforce_modules() {
|
|
|
82
132
|
case "$FEISHU_NEUTRAL_COMMANDS" in *" $cmd "*) return 0 ;; esac
|
|
83
133
|
|
|
84
134
|
if [ "$cmd" = "api" ]; then
|
|
85
|
-
# lark-cli api <METHOD> <path> [flags]
|
|
86
|
-
local pos=0 path="" a
|
|
135
|
+
# lark-cli api <METHOD> <path> [flags]:api 之后第一、二个位置参数为 method、path(跳过带值的参数)。
|
|
136
|
+
local pos=0 method="" path="" a
|
|
87
137
|
i=$((i + 1))
|
|
88
138
|
while [ "$i" -lt "$n" ]; do
|
|
89
139
|
a="${args[$i]}"
|
|
@@ -92,27 +142,49 @@ feishu_enforce_modules() {
|
|
|
92
142
|
-*) i=$((i + 1)); continue ;;
|
|
93
143
|
esac
|
|
94
144
|
pos=$((pos + 1))
|
|
145
|
+
if [ "$pos" -eq 1 ]; then method="$a"; fi
|
|
95
146
|
if [ "$pos" -eq 2 ]; then path="$a"; break; fi
|
|
96
147
|
i=$((i + 1))
|
|
97
148
|
done
|
|
98
149
|
[ -n "$path" ] || return 0 # 没给 path:lark-cli 自己报用法错,不会发请求
|
|
99
|
-
# 归一成 <service>/…:lark-cli 接受完整 URL、/open-apis/
|
|
150
|
+
# 归一成 <service>/…:lark-cli 接受完整 URL、/open-apis/ 前缀可省、前导斜杠可省;连续斜杠并成一个。
|
|
100
151
|
local p="$path"
|
|
101
152
|
p="${p#http://}"; p="${p#https://}"
|
|
102
153
|
case "$path" in http://*|https://*) p="${p#*/}" ;; esac
|
|
103
154
|
while [ "${p#/}" != "$p" ]; do p="${p#/}"; done
|
|
104
155
|
p="${p#open-apis/}"
|
|
105
156
|
while [ "${p#/}" != "$p" ]; do p="${p#/}"; done
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
157
|
+
p="${p%%[?#]*}"
|
|
158
|
+
while [ "${p//\/\//\/}" != "$p" ]; do p="${p//\/\//\/}"; done
|
|
159
|
+
# 路径里带 ..、. 段或百分号编码的,不去猜它最后落到哪个接口——直接拒。
|
|
160
|
+
case "/$p/" in *..*|*%*|*\\*|*/./*) feishu_blocked "" "lark-cli api(路径含 .. 或编码字符)" ;; esac
|
|
161
|
+
local svc="${p%%/*}"
|
|
109
162
|
case "$FEISHU_NEUTRAL_API" in *" $svc "*) return 0 ;; esac
|
|
110
|
-
case "$
|
|
111
|
-
|
|
163
|
+
case "$p" in *[!A-Za-z0-9_./:-]*) feishu_blocked "" "lark-cli api(路径含非法字符)" ;; esac
|
|
164
|
+
# 方法名转大写(macOS 自带 bash 3.2 没有 ${x^^})。
|
|
165
|
+
method="$(feishu_seg "$method" | tr '[:lower:]' '[:upper:]')"
|
|
166
|
+
feishu_check_key "api/$method/$p" "lark-cli api …/open-apis/$(feishu_safe "$svc")/…"
|
|
167
|
+
return 0
|
|
112
168
|
fi
|
|
113
169
|
|
|
114
|
-
|
|
115
|
-
|
|
170
|
+
# lark-cli <domain> [子命令] [方法]:只取紧跟在 domain 后面的词(drive 这类共用 domain 按子命令分模块);
|
|
171
|
+
# domain 后面先出现参数的,key 里记成「-」,共用 domain 的细分规则一条都不会命中。
|
|
172
|
+
local key="cmd/$(feishu_seg "$cmd")" depth=0 j=$((i + 1)) only_help=1 w
|
|
173
|
+
while [ "$j" -lt "$n" ]; do
|
|
174
|
+
case "${args[$j]}" in -h|--help) ;; *) only_help=0 ;; esac
|
|
175
|
+
j=$((j + 1))
|
|
176
|
+
done
|
|
177
|
+
[ "$only_help" -eq 1 ] && [ $((i + 1)) -lt "$n" ] && return 0 # lark-cli <domain> --help
|
|
178
|
+
j=$((i + 1))
|
|
179
|
+
while [ "$j" -lt "$n" ] && [ "$depth" -lt 2 ]; do
|
|
180
|
+
w="${args[$j]}"
|
|
181
|
+
case "$w" in -*) key="$key/-"; break ;; esac
|
|
182
|
+
key="$key/$(feishu_seg "$w")"
|
|
183
|
+
depth=$((depth + 1)); j=$((j + 1))
|
|
184
|
+
done
|
|
185
|
+
local shown="lark-cli $(feishu_safe "$cmd")"
|
|
186
|
+
[ "$depth" -ge 1 ] && shown="$shown $(feishu_safe "${args[$((i + 1))]}")"
|
|
187
|
+
feishu_check_key "$key" "$shown"
|
|
116
188
|
}
|
|
117
189
|
|
|
118
190
|
feishu_enforce_modules "$@"
|
package/dist/index.js
CHANGED
|
@@ -19673,49 +19673,69 @@ function feishuAuthSelectionRecord(sel, sendAsUserRequested, tokenResponse) {
|
|
|
19673
19673
|
...granted ? { grantedScopes: granted } : {}
|
|
19674
19674
|
};
|
|
19675
19675
|
}
|
|
19676
|
-
function
|
|
19677
|
-
const
|
|
19678
|
-
|
|
19679
|
-
|
|
19680
|
-
|
|
19681
|
-
|
|
19682
|
-
|
|
19683
|
-
|
|
19684
|
-
const
|
|
19685
|
-
|
|
19686
|
-
|
|
19687
|
-
if (allow.has(k2)) continue;
|
|
19688
|
-
need2.set(k2, [...need2.get(k2) ?? [], (FEISHU_MODULE_LABELS[m2] ?? m2).replace(/\s+/g, "")]);
|
|
19689
|
-
}
|
|
19690
|
-
}
|
|
19691
|
-
return {
|
|
19692
|
-
OASIS_FEISHU_ALLOW: ` ${[...allow].sort().join(" ")} `,
|
|
19693
|
-
OASIS_FEISHU_NEED: ` ${[...need2].sort(([a], [b2]) => a.localeCompare(b2)).map(([k2, v2]) => `${k2}=${v2.join("/")}`).join(" ")} `,
|
|
19694
|
-
OASIS_FEISHU_MODULES: picked.map((m2) => FEISHU_MODULE_LABELS[m2] ?? m2).join("\u3001")
|
|
19695
|
-
};
|
|
19676
|
+
function feishuModuleRules() {
|
|
19677
|
+
const own3 = Object.entries(FEISHU_MODULE_ACCESS).flatMap(([m2, a]) => [
|
|
19678
|
+
...a.commands.map((c) => ({ pattern: `cmd/${c}/**`, modules: [m2] })),
|
|
19679
|
+
...a.apiServices.map((s2) => ({ pattern: `api/*/${s2}/**`, modules: [m2] }))
|
|
19680
|
+
]);
|
|
19681
|
+
return [...own3, ...FEISHU_SHARED_RULES];
|
|
19682
|
+
}
|
|
19683
|
+
function ruleToExtglob(pattern) {
|
|
19684
|
+
const tail = pattern.endsWith("/**");
|
|
19685
|
+
const body2 = (tail ? pattern.slice(0, -3) : pattern).split("/").map((seg) => seg === "*" ? "+([!/])" : seg).join("/");
|
|
19686
|
+
return tail ? `${body2}?(/*)` : body2;
|
|
19696
19687
|
}
|
|
19697
|
-
function
|
|
19698
|
-
if (!raw) return [];
|
|
19688
|
+
function feishuParseSelection(raw) {
|
|
19689
|
+
if (!raw) return { state: "none", modules: [] };
|
|
19690
|
+
let parsed;
|
|
19699
19691
|
try {
|
|
19700
|
-
|
|
19701
|
-
return Array.isArray(parsed.modules) ? parsed.modules.filter((m2) => typeof m2 === "string" && !!FEISHU_MODULE_ACCESS[m2]) : [];
|
|
19692
|
+
parsed = JSON.parse(raw);
|
|
19702
19693
|
} catch {
|
|
19703
|
-
return [];
|
|
19694
|
+
return { state: "invalid", modules: [] };
|
|
19704
19695
|
}
|
|
19696
|
+
const modules = Array.isArray(parsed?.modules) ? [...new Set(parsed.modules.filter((m2) => typeof m2 === "string" && !!FEISHU_MODULE_ACCESS[m2]))] : [];
|
|
19697
|
+
return modules.length > 0 ? { state: "ok", modules } : { state: "invalid", modules: [] };
|
|
19698
|
+
}
|
|
19699
|
+
function feishuModulePolicyEnv(selection) {
|
|
19700
|
+
const picked = selection.state === "ok" ? selection.modules.filter((m2) => FEISHU_MODULE_ACCESS[m2]) : [];
|
|
19701
|
+
const label2 = (m2) => (FEISHU_MODULE_LABELS[m2] ?? m2).replace(/\s+/g, "");
|
|
19702
|
+
return {
|
|
19703
|
+
OASIS_FEISHU_POLICY: picked.length > 0 ? "ok" : selection.state === "ok" ? "invalid" : selection.state,
|
|
19704
|
+
OASIS_FEISHU_ALLOW: ` ${picked.join(" ")} `,
|
|
19705
|
+
OASIS_FEISHU_RULES: feishuModuleRules().map((r) => `${ruleToExtglob(r.pattern)}=${r.modules.join(",")}`).join(" "),
|
|
19706
|
+
OASIS_FEISHU_LABELS: Object.keys(FEISHU_MODULE_ACCESS).map((m2) => `${m2}=${label2(m2)}`).join(" "),
|
|
19707
|
+
OASIS_FEISHU_MODULES: picked.map((m2) => FEISHU_MODULE_LABELS[m2] ?? m2).join("\u3001")
|
|
19708
|
+
};
|
|
19705
19709
|
}
|
|
19706
19710
|
function feishuModuleAccessReport(input) {
|
|
19707
19711
|
const granted = input.grantedScopes ? new Set(input.grantedScopes) : null;
|
|
19708
|
-
const tenant =
|
|
19712
|
+
const tenant = /* @__PURE__ */ new Map();
|
|
19713
|
+
for (const s2 of input.appScopes ?? []) {
|
|
19714
|
+
if (s2.scope_type !== "tenant" || !s2.scope_name) continue;
|
|
19715
|
+
const ok3 = s2.grant_status === void 0 || s2.grant_status === 1;
|
|
19716
|
+
tenant.set(s2.scope_name, (tenant.get(s2.scope_name) ?? false) || ok3);
|
|
19717
|
+
}
|
|
19709
19718
|
return input.modules.filter((m2) => FEISHU_MODULE_ACCESS[m2]).map((m2) => {
|
|
19710
|
-
const
|
|
19711
|
-
|
|
19712
|
-
|
|
19719
|
+
const gaps = [];
|
|
19720
|
+
let anyGranted = false;
|
|
19721
|
+
let anyPending = false;
|
|
19722
|
+
for (const cap of FEISHU_MODULE_ACCESS[m2].botCapabilities) {
|
|
19723
|
+
if (cap.anyOf.some((s2) => tenant.get(s2) === true)) {
|
|
19724
|
+
anyGranted = true;
|
|
19725
|
+
continue;
|
|
19726
|
+
}
|
|
19727
|
+
const pending = cap.anyOf.some((s2) => tenant.has(s2));
|
|
19728
|
+
if (pending) anyPending = true;
|
|
19729
|
+
gaps.push({ label: cap.label, state: pending ? "pending" : "missing", scopes: [...cap.anyOf] });
|
|
19730
|
+
}
|
|
19731
|
+
const bot = input.appScopes === null ? "unknown" : gaps.length === 0 ? "granted" : anyGranted ? "partial" : anyPending ? "pending" : "missing";
|
|
19713
19732
|
const missingUserScopes = granted ? (FEISHU_DOMAIN_SCOPES[m2]?.scopes ?? []).filter((s2) => !granted.has(s2)) : [];
|
|
19714
|
-
const user = input.userAuthInvalid ? "invalid" : !input.hasUserAuth ? "none" : missingUserScopes.length > 0 ? "partial" : "granted";
|
|
19733
|
+
const user = input.userAuthInvalid ? "invalid" : !input.hasUserAuth ? "none" : !granted ? "unknown" : missingUserScopes.length > 0 ? "partial" : "granted";
|
|
19715
19734
|
return {
|
|
19716
19735
|
id: m2,
|
|
19717
19736
|
label: FEISHU_MODULE_LABELS[m2] ?? m2,
|
|
19718
19737
|
bot,
|
|
19738
|
+
missingBotCapabilities: bot === "unknown" ? [] : gaps,
|
|
19719
19739
|
user,
|
|
19720
19740
|
missingUserScopes: user === "partial" ? missingUserScopes : []
|
|
19721
19741
|
};
|
|
@@ -19730,7 +19750,7 @@ function feishuSendAsUserState(sel) {
|
|
|
19730
19750
|
function feishuAppPermissionConsoleUrl(appId) {
|
|
19731
19751
|
return `https://open.feishu.cn/app/${encodeURIComponent(appId)}/auth`;
|
|
19732
19752
|
}
|
|
19733
|
-
var FEISHU_BASIC_SCOPES, FEISHU_DOMAIN_SCOPES, FEISHU_USER_SCOPES, FEISHU_USER_SCOPE_STRING, FEISHU_SEND_AS_USER_SCOPE, FEISHU_AUTH_SELECTION_VAR, AUTO_APPROVED, FEISHU_MODULE_ACCESS, FEISHU_MODULE_LABELS;
|
|
19753
|
+
var FEISHU_BASIC_SCOPES, FEISHU_DOMAIN_SCOPES, FEISHU_USER_SCOPES, FEISHU_USER_SCOPE_STRING, FEISHU_SEND_AS_USER_SCOPE, FEISHU_AUTH_SELECTION_VAR, AUTO_APPROVED, FEISHU_MODULE_ACCESS, DRIVE_DOCS_ONLY_SHORTCUTS, DRIVE_DOCS_ONLY_RESOURCES, DRIVE_SHARED_SHORTCUTS, FEISHU_SHARED_RULES, FEISHU_MODULE_LABELS;
|
|
19734
19754
|
var init_scopes = __esm({
|
|
19735
19755
|
"../connectors/src/feishu/scopes.ts"() {
|
|
19736
19756
|
"use strict";
|
|
@@ -20134,25 +20154,154 @@ var init_scopes = __esm({
|
|
|
20134
20154
|
FEISHU_AUTH_SELECTION_VAR = "FEISHU_AUTH_SELECTION";
|
|
20135
20155
|
AUTO_APPROVED = new Set(FEISHU_BASIC_SCOPES);
|
|
20136
20156
|
FEISHU_MODULE_ACCESS = {
|
|
20137
|
-
im: { commands: ["im"], apiServices: ["im"],
|
|
20138
|
-
|
|
20139
|
-
|
|
20140
|
-
|
|
20141
|
-
|
|
20142
|
-
|
|
20143
|
-
|
|
20144
|
-
|
|
20145
|
-
|
|
20146
|
-
|
|
20147
|
-
|
|
20148
|
-
|
|
20149
|
-
|
|
20150
|
-
|
|
20151
|
-
|
|
20152
|
-
|
|
20153
|
-
|
|
20154
|
-
|
|
20155
|
-
|
|
20157
|
+
im: { commands: ["im"], apiServices: ["im"], botCapabilities: [
|
|
20158
|
+
{ label: "\u53D1\u6D88\u606F", anyOf: ["im:message:send_as_bot", "im:message", "im:message:send"] },
|
|
20159
|
+
{ label: "\u8BFB\u6D88\u606F", anyOf: ["im:message:readonly", "im:message", "im:message.group_msg", "im:message.p2p_msg:readonly", "im:message.group_at_msg:readonly"] },
|
|
20160
|
+
{ label: "\u7FA4\u4FE1\u606F", anyOf: ["im:chat:readonly", "im:chat:read", "im:chat"] }
|
|
20161
|
+
] },
|
|
20162
|
+
calendar: { commands: ["calendar"], apiServices: ["calendar"], botCapabilities: [
|
|
20163
|
+
{ label: "\u8BFB\u65E5\u7A0B", anyOf: ["calendar:calendar:readonly", "calendar:calendar", "calendar:calendar:read", "calendar:calendar.event:read"] },
|
|
20164
|
+
{ label: "\u5199\u65E5\u7A0B", anyOf: ["calendar:calendar", "calendar:calendar.event:create", "calendar:calendar.event:update"] }
|
|
20165
|
+
] },
|
|
20166
|
+
docs: { commands: ["docs", "mindnotes"], apiServices: ["docx", "doc", "docs", "mindnote", "mindnotes", "suite"], botCapabilities: [
|
|
20167
|
+
{ label: "\u8BFB\u6587\u6863", anyOf: ["docx:document:readonly", "docx:document", "docs:document.content:read", "docs:doc:readonly", "docs:doc"] },
|
|
20168
|
+
{ label: "\u5199\u6587\u6863", anyOf: ["docx:document", "docx:document:create", "docx:document:write_only", "docs:doc"] }
|
|
20169
|
+
] },
|
|
20170
|
+
drive: { commands: ["markdown"], apiServices: [], botCapabilities: [
|
|
20171
|
+
{ label: "\u4E0B\u8F7D\u6587\u4EF6", anyOf: ["drive:drive:readonly", "drive:drive", "drive:file:download", "drive:file:readonly", "drive:file"] },
|
|
20172
|
+
{ label: "\u4E0A\u4F20\u6587\u4EF6", anyOf: ["drive:drive", "drive:file:upload", "drive:file"] }
|
|
20173
|
+
] },
|
|
20174
|
+
sheets: { commands: ["sheets"], apiServices: ["sheets"], botCapabilities: [
|
|
20175
|
+
{ label: "\u8BFB\u8868\u683C", anyOf: ["sheets:spreadsheet:readonly", "sheets:spreadsheet", "sheets:spreadsheet:read"] },
|
|
20176
|
+
{ label: "\u5199\u8868\u683C", anyOf: ["sheets:spreadsheet", "sheets:spreadsheet:write_only", "sheets:spreadsheet:create"] }
|
|
20177
|
+
] },
|
|
20178
|
+
base: { commands: ["base"], apiServices: ["bitable", "base"], botCapabilities: [
|
|
20179
|
+
{ label: "\u8BFB\u8BB0\u5F55", anyOf: ["bitable:app:readonly", "bitable:app", "base:record:read", "base:app:read"] },
|
|
20180
|
+
{ label: "\u5199\u8BB0\u5F55", anyOf: ["bitable:app", "base:record:create", "base:record:update"] }
|
|
20181
|
+
] },
|
|
20182
|
+
wiki: { commands: ["wiki"], apiServices: ["wiki"], botCapabilities: [
|
|
20183
|
+
{ label: "\u8BFB\u77E5\u8BC6\u5E93", anyOf: ["wiki:wiki:readonly", "wiki:wiki", "wiki:node:read", "wiki:space:read"] },
|
|
20184
|
+
{ label: "\u5199\u77E5\u8BC6\u5E93", anyOf: ["wiki:wiki", "wiki:node:create", "wiki:space:write_only"] }
|
|
20185
|
+
] },
|
|
20186
|
+
slides: { commands: ["slides"], apiServices: ["slides", "slides_ai"], botCapabilities: [
|
|
20187
|
+
{ label: "\u8BFB\u5E7B\u706F\u7247", anyOf: ["slides:presentation:read", "slides:presentation:readonly", "slides:presentation"] },
|
|
20188
|
+
{ label: "\u5199\u5E7B\u706F\u7247", anyOf: ["slides:presentation:update", "slides:presentation:write_only", "slides:presentation:create", "slides:presentation"] }
|
|
20189
|
+
] },
|
|
20190
|
+
task: { commands: ["task"], apiServices: ["task"], botCapabilities: [
|
|
20191
|
+
{ label: "\u8BFB\u4EFB\u52A1", anyOf: ["task:task:read", "task:task:readonly", "task:task"] },
|
|
20192
|
+
{ label: "\u5199\u4EFB\u52A1", anyOf: ["task:task:write", "task:task"] }
|
|
20193
|
+
] },
|
|
20194
|
+
approval: { commands: ["approval"], apiServices: ["approval"], botCapabilities: [
|
|
20195
|
+
{ label: "\u8BFB\u5BA1\u6279", anyOf: ["approval:instance:read", "approval:approval:readonly", "approval:approval"] },
|
|
20196
|
+
{ label: "\u5904\u7406\u5BA1\u6279", anyOf: ["approval:instance:write", "approval:task:write", "approval:approval"] }
|
|
20197
|
+
] },
|
|
20198
|
+
mail: { commands: ["mail"], apiServices: ["mail"], botCapabilities: [
|
|
20199
|
+
{ label: "\u8BFB\u90AE\u4EF6", anyOf: ["mail:user_mailbox.message:readonly", "mail:user_mailbox:readonly", "mail:user_mailbox"] }
|
|
20200
|
+
] },
|
|
20201
|
+
minutes: { commands: ["minutes"], apiServices: ["minutes"], botCapabilities: [
|
|
20202
|
+
{ label: "\u8BFB\u5999\u8BB0", anyOf: ["minutes:minutes:readonly", "minutes:minutes", "minutes:minutes.search:read"] }
|
|
20203
|
+
] },
|
|
20204
|
+
vc: { commands: ["vc", "note"], apiServices: ["vc"], botCapabilities: [
|
|
20205
|
+
{ label: "\u8BFB\u4F1A\u8BAE", anyOf: ["vc:meeting:readonly", "vc:meeting", "vc:meeting.meetingevent:read", "vc:record:readonly"] }
|
|
20206
|
+
] },
|
|
20207
|
+
contact: { commands: ["contact"], apiServices: ["contact"], botCapabilities: [
|
|
20208
|
+
{ label: "\u8BFB\u901A\u8BAF\u5F55", anyOf: ["contact:user.base:readonly", "contact:contact:readonly_as_app", "contact:contact:readonly", "contact:contact", "contact:user.basic_profile:readonly"] }
|
|
20209
|
+
] },
|
|
20210
|
+
okr: { commands: ["okr"], apiServices: ["okr"], botCapabilities: [
|
|
20211
|
+
{ label: "\u8BFB OKR", anyOf: ["okr:okr:readonly", "okr:okr", "okr:okr:read"] }
|
|
20212
|
+
] },
|
|
20213
|
+
attendance: { commands: ["attendance"], apiServices: ["attendance"], botCapabilities: [
|
|
20214
|
+
{ label: "\u8BFB\u8003\u52E4", anyOf: ["attendance:task:readonly", "attendance:record:read", "attendance:task"] }
|
|
20215
|
+
] },
|
|
20216
|
+
board: { commands: ["whiteboard"], apiServices: ["board"], botCapabilities: [
|
|
20217
|
+
{ label: "\u8BFB\u767D\u677F", anyOf: ["board:whiteboard:node:read"] },
|
|
20218
|
+
{ label: "\u5199\u767D\u677F", anyOf: ["board:whiteboard:node:create"] }
|
|
20219
|
+
] },
|
|
20220
|
+
spark: { commands: ["apps"], apiServices: ["spark"], botCapabilities: [
|
|
20221
|
+
{ label: "\u8BFB\u5E94\u7528", anyOf: ["spark:app:read"] },
|
|
20222
|
+
{ label: "\u5199\u5E94\u7528", anyOf: ["spark:app:write"] }
|
|
20223
|
+
] }
|
|
20224
|
+
};
|
|
20225
|
+
DRIVE_DOCS_ONLY_SHORTCUTS = [
|
|
20226
|
+
// 评论
|
|
20227
|
+
"+add-comment",
|
|
20228
|
+
"+add-reply",
|
|
20229
|
+
"+batch-query-comments",
|
|
20230
|
+
"+delete-reply",
|
|
20231
|
+
"+list-comments",
|
|
20232
|
+
"+list-replies",
|
|
20233
|
+
"+react-reply",
|
|
20234
|
+
"+resolve-comment",
|
|
20235
|
+
"+restore-comment",
|
|
20236
|
+
"+update-reply",
|
|
20237
|
+
// 协作者与分享权限
|
|
20238
|
+
"+apply-permission",
|
|
20239
|
+
"+member-add",
|
|
20240
|
+
"+member-list",
|
|
20241
|
+
"+member-remove",
|
|
20242
|
+
"+permission-get-setting",
|
|
20243
|
+
// 导入导出、搜索、密级
|
|
20244
|
+
"+export",
|
|
20245
|
+
"+export-download",
|
|
20246
|
+
"+import",
|
|
20247
|
+
"+search",
|
|
20248
|
+
"+secure-label-list",
|
|
20249
|
+
"+secure-label-update"
|
|
20250
|
+
];
|
|
20251
|
+
DRIVE_DOCS_ONLY_RESOURCES = [
|
|
20252
|
+
"file.comment.reply.reactions",
|
|
20253
|
+
"file.comment.replys",
|
|
20254
|
+
"file.comments",
|
|
20255
|
+
"permission.members",
|
|
20256
|
+
"permission.public",
|
|
20257
|
+
"user"
|
|
20258
|
+
];
|
|
20259
|
+
DRIVE_SHARED_SHORTCUTS = ["+copy", "+create-folder", "+create-shortcut", "+delete", "+move", "+update-title", "+inspect", "+task_result"];
|
|
20260
|
+
FEISHU_SHARED_RULES = [
|
|
20261
|
+
...DRIVE_DOCS_ONLY_SHORTCUTS.map((s2) => ({ pattern: `cmd/drive/${s2}/**`, modules: ["docs"] })),
|
|
20262
|
+
...DRIVE_DOCS_ONLY_RESOURCES.map((r) => ({ pattern: `cmd/drive/${r}/*/**`, modules: ["docs"] })),
|
|
20263
|
+
...DRIVE_SHARED_SHORTCUTS.map((s2) => ({ pattern: `cmd/drive/${s2}/**`, modules: ["docs", "drive"] })),
|
|
20264
|
+
...["copy", "create_folder", "patch"].map((m2) => ({ pattern: `cmd/drive/files/${m2}/**`, modules: ["docs", "drive"] })),
|
|
20265
|
+
{ pattern: "cmd/drive/metas/*/**", modules: ["docs", "drive"] },
|
|
20266
|
+
// drive 后面先写参数再写子命令的(`drive --as bot +add-comment`),认不出子命令归谁——谁都不放行。
|
|
20267
|
+
{ pattern: "cmd/drive/-/**", modules: [] },
|
|
20268
|
+
{ pattern: "cmd/drive/**", modules: ["drive"] },
|
|
20269
|
+
...[
|
|
20270
|
+
"drive/v1/permissions/**",
|
|
20271
|
+
"drive/v2/permissions/**",
|
|
20272
|
+
"drive/permission/**",
|
|
20273
|
+
"drive/v1/files/*/comments/**",
|
|
20274
|
+
"drive/v1/files/*/new_comments/**",
|
|
20275
|
+
"drive/v2/files/*/comments/**",
|
|
20276
|
+
"drive/v2/files/*/likes/**",
|
|
20277
|
+
"drive/v1/files/*/subscribe/**",
|
|
20278
|
+
"drive/v1/files/*/get_subscribe/**",
|
|
20279
|
+
"drive/v1/files/*/delete_subscribe/**",
|
|
20280
|
+
"drive/v1/files/*/subscriptions/**",
|
|
20281
|
+
"drive/v1/user/**",
|
|
20282
|
+
"drive/v1/import_tasks/**",
|
|
20283
|
+
"drive/v1/export_tasks/**",
|
|
20284
|
+
"drive/v1/medias/**",
|
|
20285
|
+
"drive/v2/files/*/secure_label/**",
|
|
20286
|
+
"drive/v2/my_secure_labels/**"
|
|
20287
|
+
].map((p2) => ({ pattern: `api/*/${p2}`, modules: ["docs"] })),
|
|
20288
|
+
...[
|
|
20289
|
+
"*/drive/v1/files/create_folder/**",
|
|
20290
|
+
"*/drive/v1/files/create_shortcut/**",
|
|
20291
|
+
"*/drive/v1/files/task_check/**",
|
|
20292
|
+
"*/drive/v1/files/*/move/**",
|
|
20293
|
+
"*/drive/v1/files/*/copy/**",
|
|
20294
|
+
"DELETE/drive/v1/files/*",
|
|
20295
|
+
"PATCH/drive/v1/files/*",
|
|
20296
|
+
"*/drive/v1/metas/**",
|
|
20297
|
+
"*/drive/v2/files/query_by_token/**",
|
|
20298
|
+
"*/drive/explorer/**"
|
|
20299
|
+
].map((p2) => ({ pattern: `api/${p2}`, modules: ["docs", "drive"] })),
|
|
20300
|
+
{ pattern: "api/*/drive/**", modules: ["drive"] },
|
|
20301
|
+
{ pattern: "api/*/search/v1/user/**", modules: ["contact"] },
|
|
20302
|
+
{ pattern: "api/*/search/v2/message/**", modules: ["im"] },
|
|
20303
|
+
{ pattern: "api/*/search/v2/doc_wiki/**", modules: ["docs", "wiki"] }
|
|
20304
|
+
];
|
|
20156
20305
|
FEISHU_MODULE_LABELS = {
|
|
20157
20306
|
im: "\u5373\u65F6\u6D88\u606F",
|
|
20158
20307
|
calendar: "\u65E5\u5386",
|
|
@@ -20330,7 +20479,8 @@ var init_feishu = __esm({
|
|
|
20330
20479
|
"FEISHU_REFRESH_TOKEN_EXPIRES_AT",
|
|
20331
20480
|
FEISHU_USER_OPEN_ID_VAR,
|
|
20332
20481
|
FEISHU_AUTHORIZED_BY_VAR,
|
|
20333
|
-
FEISHU_USER_AUTH_INVALID_VAR
|
|
20482
|
+
FEISHU_USER_AUTH_INVALID_VAR,
|
|
20483
|
+
"FEISHU_AUTH_PENDING_APPROVAL"
|
|
20334
20484
|
];
|
|
20335
20485
|
/** 宿主机登录态隔离,理由同 github(见接口注释):由通用装配层无条件设。 */
|
|
20336
20486
|
hostCredentialIsolationEnvKeys = ["LARKSUITE_CLI_CONFIG_DIR"];
|
|
@@ -20403,7 +20553,7 @@ var init_feishu = __esm({
|
|
|
20403
20553
|
if (!appSecret) throw new Error("feishu inject: missing app_secret");
|
|
20404
20554
|
const userAccessToken = credentials2["user_access_token"] ?? credentials2["FEISHU_USER_ACCESS_TOKEN"];
|
|
20405
20555
|
const modulePolicy = feishuModulePolicyEnv(
|
|
20406
|
-
|
|
20556
|
+
feishuParseSelection(credentials2["auth_selection"] ?? credentials2[FEISHU_AUTH_SELECTION_VAR])
|
|
20407
20557
|
);
|
|
20408
20558
|
const tenantAccessToken = this.isSimulated() ? null : await this.fetchTenantToken(appId, appSecret) ?? previousTenantToken(sessionEnv.get("FEISHU_CREDS_FILE"), appId);
|
|
20409
20559
|
const creds = await writeSessionCredsFile(this.config.slug, {
|
|
@@ -20411,7 +20561,7 @@ var init_feishu = __esm({
|
|
|
20411
20561
|
LARKSUITE_CLI_APP_SECRET: appSecret,
|
|
20412
20562
|
...tenantAccessToken ? { LARKSUITE_CLI_TENANT_ACCESS_TOKEN: tenantAccessToken } : {},
|
|
20413
20563
|
...userAccessToken ? { LARKSUITE_CLI_USER_ACCESS_TOKEN: userAccessToken } : {},
|
|
20414
|
-
...modulePolicy
|
|
20564
|
+
...modulePolicy
|
|
20415
20565
|
}, sessionEnv.get("FEISHU_RUN_TMPDIR"));
|
|
20416
20566
|
const configDir = (0, import_node_path12.join)(creds.dir, "lark-config");
|
|
20417
20567
|
await (0, import_promises5.mkdir)(configDir, { recursive: true, mode: 448 });
|
|
@@ -20522,7 +20672,8 @@ async function pollFeishuDeviceToken(input) {
|
|
|
20522
20672
|
const data = await resp.json();
|
|
20523
20673
|
const errStr = data["error"];
|
|
20524
20674
|
if (errStr === "authorization_pending" || errStr === "slow_down") return { status: "pending" };
|
|
20525
|
-
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"));
|
|
20526
20677
|
if (!data["access_token"]) throw new Error("no access_token in response");
|
|
20527
20678
|
return { status: "ok", data };
|
|
20528
20679
|
}
|
|
@@ -20571,7 +20722,7 @@ function feishuUserAuthInvalidText(input) {
|
|
|
20571
20722
|
${input.link}` : `${head}
|
|
20572
20723
|
\u8BF7\u5230 Oasis \u8BE5 Agent \u7684\u300C\u8FDE\u63A5\u5668\u300D\u9875\u91CD\u65B0\u6388\u6743\u98DE\u4E66\u3002`;
|
|
20573
20724
|
}
|
|
20574
|
-
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;
|
|
20575
20726
|
var init_user_auth = __esm({
|
|
20576
20727
|
"../connectors/src/feishu/user-auth.ts"() {
|
|
20577
20728
|
"use strict";
|
|
@@ -20580,6 +20731,78 @@ var init_user_auth = __esm({
|
|
|
20580
20731
|
FEISHU_USER_INFO_URL = "https://open.feishu.cn/open-apis/authen/v1/user_info";
|
|
20581
20732
|
FEISHU_SEND_MESSAGE_URL = "https://open.feishu.cn/open-apis/im/v1/messages";
|
|
20582
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";
|
|
20583
20806
|
}
|
|
20584
20807
|
});
|
|
20585
20808
|
|
|
@@ -24504,6 +24727,7 @@ var init_src3 = __esm({
|
|
|
24504
24727
|
init_host_isolation();
|
|
24505
24728
|
init_feishu();
|
|
24506
24729
|
init_user_auth();
|
|
24730
|
+
init_pending_approval();
|
|
24507
24731
|
init_scopes();
|
|
24508
24732
|
init_oauth();
|
|
24509
24733
|
init_scheduled_refresh();
|
|
@@ -24525,6 +24749,14 @@ var init_src3 = __esm({
|
|
|
24525
24749
|
});
|
|
24526
24750
|
|
|
24527
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
|
+
}
|
|
24528
24760
|
async function reauthSelection(store, actorId) {
|
|
24529
24761
|
const raw = await store.revealVariable(FEISHU_AUTH_SELECTION_VAR, actorId).catch(() => null);
|
|
24530
24762
|
if (raw) {
|
|
@@ -24565,17 +24797,31 @@ function createFeishuReauth(deps) {
|
|
|
24565
24797
|
};
|
|
24566
24798
|
}
|
|
24567
24799
|
await withConnectorCredentialLock("feishu", claims.actorId, async () => {
|
|
24800
|
+
const pending2 = claims.purpose === "supplement" ? await readFeishuPendingApproval(store, claims.actorId) : null;
|
|
24568
24801
|
await persistFeishuUserAuthorization(store, claims.actorId, data, now(), {
|
|
24569
24802
|
openId: who.openId,
|
|
24570
|
-
...who.name ? { userName: who.name } : {}
|
|
24803
|
+
...who.name ? { userName: who.name } : {},
|
|
24804
|
+
...pending2?.applicant ? { authorizedBy: pending2.applicant } : {}
|
|
24571
24805
|
});
|
|
24806
|
+
const record10 = feishuAuthSelectionRecord(sel, sendAsUserRequested, data);
|
|
24572
24807
|
await store.putVariable({
|
|
24573
24808
|
key: FEISHU_AUTH_SELECTION_VAR,
|
|
24574
|
-
value: JSON.stringify(
|
|
24809
|
+
value: JSON.stringify(record10),
|
|
24575
24810
|
...claims.actorId ? { scope: "personal", actorId: claims.actorId } : { scope: "global" },
|
|
24576
24811
|
connectorId: "feishu",
|
|
24577
24812
|
encrypted: false
|
|
24578
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
|
+
}
|
|
24579
24825
|
});
|
|
24580
24826
|
await deps.onRestored?.(claims, { openId: who.openId, ...who.name ? { userName: who.name } : {} }).catch((e) => warn(`onRestored: ${String(e)}`));
|
|
24581
24827
|
return { state: "restored", ...who.name ? { userName: who.name } : {} };
|
|
@@ -24607,7 +24853,15 @@ function createFeishuReauth(deps) {
|
|
|
24607
24853
|
if (!store) return { ok: false, status: 404, message: "\u627E\u4E0D\u5230\u8FD9\u4E2A\u94FE\u63A5\u6240\u5C5E\u7684\u7EC4\u7EC7\u3002" };
|
|
24608
24854
|
const app = await appCredentials(store, claims.actorId);
|
|
24609
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" };
|
|
24610
|
-
|
|
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;
|
|
24611
24865
|
const auth = await (deps.start ?? startFeishuDeviceAuthorization)({
|
|
24612
24866
|
appId: app.appId,
|
|
24613
24867
|
appSecret: app.appSecret,
|
|
@@ -24622,7 +24876,7 @@ function createFeishuReauth(deps) {
|
|
|
24622
24876
|
const intervalSec = auth.interval ?? DEFAULT_POLL_INTERVAL_SEC;
|
|
24623
24877
|
void watch(auth.deviceCode, entry, { store, ...app, sel, sendAsUser, intervalSec });
|
|
24624
24878
|
const agentName = await deps.agentName?.(claims.companyId, claims.actorId).catch(() => void 0) ?? claims.actorId ?? "\u7EC4\u7EC7";
|
|
24625
|
-
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 };
|
|
24626
24880
|
},
|
|
24627
24881
|
/** 页面轮询结果。票与 deviceCode 必须是同一次 begin 发出来的。 */
|
|
24628
24882
|
status(token2, deviceCode) {
|
|
@@ -24639,17 +24893,18 @@ function createFeishuReauth(deps) {
|
|
|
24639
24893
|
function feishuReauthPageHtml(input) {
|
|
24640
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>
|
|
24641
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>`;
|
|
24642
|
-
if (!input.ok) return `${head}<h2>\u65E0\u6CD5\
|
|
24643
|
-
const
|
|
24644
|
-
|
|
24645
|
-
<
|
|
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>
|
|
24646
24901
|
<p><a class="btn" href="${escapeHtml(input.verificationUrl)}" target="_blank" rel="noopener">\u53BB\u98DE\u4E66\u6388\u6743</a></p>
|
|
24647
24902
|
<p id="s">\u7B49\u5F85\u4F60\u5728\u98DE\u4E66\u70B9\u300C\u6388\u6743\u300D\u2026</p>
|
|
24648
24903
|
<script>(function(){var c=${cfg};var el=document.getElementById("s");
|
|
24649
24904
|
function tick(){fetch("reauth/status",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({t:c.t,deviceCode:c.d})})
|
|
24650
24905
|
.then(function(r){return r.json()}).then(function(b){
|
|
24651
24906
|
if(b.state==="pending"){setTimeout(tick,c.i*1000);return}
|
|
24652
|
-
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}
|
|
24653
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)})}
|
|
24654
24909
|
setTimeout(tick,c.i*1000)})();</script></body></html>`;
|
|
24655
24910
|
}
|
|
@@ -212007,10 +212262,10 @@ async function feishuModuleAccess(store, actorId, fetchScopes = fetchFeishuAppSc
|
|
|
212007
212262
|
const appSecret = await read3("FEISHU_APP_SECRET");
|
|
212008
212263
|
if (!appId || !appSecret) return { configured: false };
|
|
212009
212264
|
const rawSelection = await read3(FEISHU_AUTH_SELECTION_VAR);
|
|
212010
|
-
const modules =
|
|
212265
|
+
const { state: selection, modules } = feishuParseSelection(rawSelection);
|
|
212011
212266
|
let parsed = {};
|
|
212012
212267
|
try {
|
|
212013
|
-
parsed = rawSelection ? JSON.parse(rawSelection) : {};
|
|
212268
|
+
parsed = rawSelection ? JSON.parse(rawSelection) ?? {} : {};
|
|
212014
212269
|
} catch {
|
|
212015
212270
|
parsed = {};
|
|
212016
212271
|
}
|
|
@@ -212028,7 +212283,7 @@ async function feishuModuleAccess(store, actorId, fetchScopes = fetchFeishuAppSc
|
|
|
212028
212283
|
}
|
|
212029
212284
|
return {
|
|
212030
212285
|
configured: true,
|
|
212031
|
-
|
|
212286
|
+
selection,
|
|
212032
212287
|
modules: feishuModuleAccessReport({ modules, grantedScopes, hasUserAuth, userAuthInvalid, appScopes }),
|
|
212033
212288
|
hasUserAuth,
|
|
212034
212289
|
userAuthInvalid,
|
|
@@ -212048,6 +212303,42 @@ var init_feishu_module_access = __esm({
|
|
|
212048
212303
|
}
|
|
212049
212304
|
});
|
|
212050
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
|
+
|
|
212051
212342
|
// ../server/src/github-app-inventory.ts
|
|
212052
212343
|
async function collectOasisGithubApps(svc) {
|
|
212053
212344
|
const rows = (await svc.listVariables()).filter((r) => r.scope === "global" || r.scope === "personal");
|
|
@@ -218349,12 +218640,40 @@ ${composed}`;
|
|
|
218349
218640
|
const pollSvc = await connectorActorsService();
|
|
218350
218641
|
const appSecret = pollSvc ? await pollSvc.revealResolvedVariable("FEISHU_APP_SECRET", actorId) : null;
|
|
218351
218642
|
if (!appSecret) throw new Error("FEISHU_APP_SECRET not found \u2014 please complete app setup first");
|
|
218352
|
-
|
|
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
|
+
}
|
|
218353
218671
|
if (polled.status === "pending") {
|
|
218354
218672
|
res.writeHead(200).end(JSON.stringify({ ok: false, error: "authorization_pending" }));
|
|
218355
218673
|
return;
|
|
218356
218674
|
}
|
|
218357
218675
|
const data = polled.data;
|
|
218676
|
+
let pendingApproval = null;
|
|
218358
218677
|
const svc = await connectorActorsService();
|
|
218359
218678
|
if (svc) {
|
|
218360
218679
|
if (actorId) {
|
|
@@ -218379,6 +218698,23 @@ ${composed}`;
|
|
|
218379
218698
|
connectorId: "feishu",
|
|
218380
218699
|
encrypted: false
|
|
218381
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
|
+
}
|
|
218382
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");
|
|
218383
218719
|
try {
|
|
218384
218720
|
const secret = await svc.revealResolvedVariable("FEISHU_APP_SECRET", actorId);
|
|
@@ -218403,7 +218739,12 @@ ${composed}`;
|
|
|
218403
218739
|
}
|
|
218404
218740
|
}
|
|
218405
218741
|
}
|
|
218406
|
-
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
|
+
}));
|
|
218407
218748
|
} catch (e) {
|
|
218408
218749
|
res.writeHead(500).end(JSON.stringify({ error: String(e) }));
|
|
218409
218750
|
}
|
|
@@ -218746,6 +219087,7 @@ var init_server3 = __esm({
|
|
|
218746
219087
|
init_child_live_turn();
|
|
218747
219088
|
init_registry_audit_sink();
|
|
218748
219089
|
init_feishu_module_access();
|
|
219090
|
+
init_feishu_pending_approval();
|
|
218749
219091
|
init_src3();
|
|
218750
219092
|
init_github_app_inventory();
|
|
218751
219093
|
init_github_app_timing();
|
|
@@ -286888,53 +287230,43 @@ function createConnectorRenewalRuntime(options) {
|
|
|
286888
287230
|
return "sent";
|
|
286889
287231
|
};
|
|
286890
287232
|
const recipientsFor = async (companyId, store, actorId) => {
|
|
286891
|
-
const out = /* @__PURE__ */ new Set();
|
|
286892
287233
|
const by = await store.revealVariable(FEISHU_AUTHORIZED_BY_VAR, actorId).catch(() => null);
|
|
286893
|
-
if (by && isHumanActorId(by))
|
|
286894
|
-
if (
|
|
286895
|
-
|
|
286896
|
-
|
|
286897
|
-
|
|
286898
|
-
if (human) out.add(human);
|
|
286899
|
-
}
|
|
286900
|
-
}
|
|
286901
|
-
return [...out];
|
|
287234
|
+
if (by && isHumanActorId(by)) return { recipients: [by], authorizer: by };
|
|
287235
|
+
if (!actorId) return { recipients: [], authorizer: null };
|
|
287236
|
+
if (isHumanActorId(actorId)) return { recipients: [actorId], authorizer: null };
|
|
287237
|
+
const human = await options.boundHuman(actorId, companyId).catch(() => null);
|
|
287238
|
+
return { recipients: human ? [human] : [], authorizer: null };
|
|
286902
287239
|
};
|
|
286903
|
-
const recoverOpenId = async (companyId, app,
|
|
286904
|
-
|
|
286905
|
-
|
|
286906
|
-
if (!email2) continue;
|
|
286907
|
-
const openId = await lookupFeishuOpenIdByEmail({ ...app, email: email2 });
|
|
286908
|
-
if (openId) return openId;
|
|
286909
|
-
}
|
|
286910
|
-
return null;
|
|
287240
|
+
const recoverOpenId = async (companyId, app, authorizer) => {
|
|
287241
|
+
const email2 = await options.memberEmail?.(authorizer, companyId).catch(() => null);
|
|
287242
|
+
return email2 ? lookupFeishuOpenIdByEmail({ ...app, email: email2 }) : null;
|
|
286911
287243
|
};
|
|
286912
287244
|
const deliverInvalidNotice = async (companyId, store, actorId, marker) => {
|
|
286913
287245
|
const prev = marker.notice ?? { inApp: false, dm: "pending", attempts: 0 };
|
|
286914
287246
|
const state = { ...prev, attempts: prev.attempts + 1 };
|
|
286915
287247
|
const who = `actor=${actorId ?? "-"} \u7B2C ${state.attempts}/${MAX_NOTICE_ATTEMPTS} \u6B21`;
|
|
286916
287248
|
const name = await agentName(companyId, actorId);
|
|
286917
|
-
const recipients = await recipientsFor(companyId, store, actorId);
|
|
287249
|
+
const { recipients, authorizer } = await recipientsFor(companyId, store, actorId);
|
|
287250
|
+
const unverified = !authorizer && !await store.revealVariable(FEISHU_USER_OPEN_ID_VAR, actorId).catch(() => "?");
|
|
286918
287251
|
if (!state.inApp) {
|
|
286919
287252
|
try {
|
|
286920
287253
|
const ledger = await options.notifications(companyId);
|
|
286921
|
-
if (ledger)
|
|
286922
|
-
|
|
286923
|
-
|
|
286924
|
-
|
|
286925
|
-
|
|
286926
|
-
|
|
286927
|
-
|
|
286928
|
-
|
|
286929
|
-
|
|
286930
|
-
|
|
286931
|
-
|
|
286932
|
-
|
|
286933
|
-
|
|
286934
|
-
}
|
|
286935
|
-
if (rows.length > 0) options.onNotifications?.(companyId, rows);
|
|
287254
|
+
if (!ledger) throw new Error("\u8BE5\u516C\u53F8\u7684\u901A\u77E5\u53F0\u8D26\u4E0D\u53EF\u7528");
|
|
287255
|
+
if (recipients.length === 0) throw new Error("\u6CA1\u6709\u6536\u4EF6\u4EBA\uFF08\u6CA1\u8BB0\u6388\u6743\u4EBA\u3001\u5458\u5DE5\u4E5F\u6CA1\u6709\u7ED1\u5B9A\u771F\u4EBA\uFF09");
|
|
287256
|
+
const rows = [];
|
|
287257
|
+
for (const recipient of recipients) {
|
|
287258
|
+
rows.push(await ledger.insert({
|
|
287259
|
+
recipient,
|
|
287260
|
+
category: "connector",
|
|
287261
|
+
kind: "feishu-auth-invalid",
|
|
287262
|
+
// 每次失效一条:键里带失效时刻,重新授权后再失效还会再提醒;同一次失效补发 / 重复扫描不重发(唯一约束)。
|
|
287263
|
+
sourceKey: `connector:feishu:${actorId ?? "org"}@invalid:${marker.at}`,
|
|
287264
|
+
title: unverified ? `\u300C${name}\u300D\u7684\u98DE\u4E66\u7528\u6237\u6388\u6743\u5DF2\u5931\u6548\uFF0C\u8BF7\u5230\u8FDE\u63A5\u5668\u9875\u91CD\u65B0\u8FDE\u63A5` : `\u300C${name}\u300D\u7684\u98DE\u4E66\u7528\u6237\u6388\u6743\u5DF2\u5931\u6548\uFF0C\u9700\u8981\u91CD\u65B0\u6388\u6743`,
|
|
287265
|
+
...actorId ? { actorId } : {},
|
|
287266
|
+
enteredAt: marker.at
|
|
287267
|
+
}));
|
|
286936
287268
|
}
|
|
286937
|
-
|
|
287269
|
+
options.onNotifications?.(companyId, rows);
|
|
286938
287270
|
state.inApp = true;
|
|
286939
287271
|
} catch (err) {
|
|
286940
287272
|
options.warn(new Error(`\u98DE\u4E66\u6388\u6743\u5931\u6548\u7AD9\u5185\u901A\u77E5\u672A\u5199\u5165\uFF08${who}\uFF0C\u4E0B\u4E00\u62CD\u91CD\u8BD5\uFF09: ${String(err)}`));
|
|
@@ -286943,12 +287275,13 @@ function createConnectorRenewalRuntime(options) {
|
|
|
286943
287275
|
if (state.dm === "pending") {
|
|
286944
287276
|
try {
|
|
286945
287277
|
const app = await appCredentials(store, actorId);
|
|
286946
|
-
const
|
|
286947
|
-
const recovered = !
|
|
286948
|
-
const openId =
|
|
287278
|
+
const storedOpenId = await store.revealVariable(FEISHU_USER_OPEN_ID_VAR, actorId);
|
|
287279
|
+
const recovered = !storedOpenId && app && authorizer ? await recoverOpenId(companyId, app, authorizer) : null;
|
|
287280
|
+
const openId = storedOpenId || recovered;
|
|
286949
287281
|
if (!app || !openId) {
|
|
286950
287282
|
state.dm = "unavailable";
|
|
286951
|
-
|
|
287283
|
+
const why = !app ? "\u6CA1\u6709\u5E94\u7528\u51ED\u636E" : unverified ? "\u6CA1\u8BB0\u539F\u6388\u6743\u4EBA\uFF0C\u6838\u5B9E\u4E0D\u4E86\u672C\u4EBA\uFF0C\u4E0D\u7B7E\u94FE\u63A5\uFF1B\u9700\u5230\u8FDE\u63A5\u5668\u9875\u91CD\u65B0\u8FDE\u63A5" : "\u901A\u8BAF\u5F55\u6CA1\u6309\u539F\u6388\u6743\u4EBA\u7684\u8D26\u53F7\u90AE\u7BB1\u627E\u5230\u4ED6";
|
|
287284
|
+
console.warn(`[credential-refresh] \u98DE\u4E66\u6388\u6743\u5931\u6548\u79C1\u4FE1\u65E0\u4ECE\u53D1\u51FA\uFF08${why}\uFF09actor=${actorId ?? "-"}\uFF1B\u53EA\u6709\u7AD9\u5185\u901A\u77E5`);
|
|
286952
287285
|
} else {
|
|
286953
287286
|
const token2 = await issueFeishuReauthToken(options.links, store, {
|
|
286954
287287
|
companyId,
|
|
@@ -287005,6 +287338,122 @@ function createConnectorRenewalRuntime(options) {
|
|
|
287005
287338
|
}
|
|
287006
287339
|
for (const k2 of handledThisSweep) if (JSON.parse(k2)[0] === companyId) handledThisSweep.delete(k2);
|
|
287007
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
|
+
};
|
|
287008
287457
|
const onFeishuRenewed = async (e, store) => {
|
|
287009
287458
|
if (await store.revealVariable(FEISHU_USER_OPEN_ID_VAR, e.actorId)) return;
|
|
287010
287459
|
const accessToken = e.outcome.credentials?.["user_access_token"];
|
|
@@ -287043,7 +287492,13 @@ function createConnectorRenewalRuntime(options) {
|
|
|
287043
287492
|
onRenewed: async (e, store) => {
|
|
287044
287493
|
if (e.connector.config.slug === "feishu") await onFeishuRenewed(e, store);
|
|
287045
287494
|
},
|
|
287046
|
-
afterCompany:
|
|
287495
|
+
afterCompany: async (companyId, store) => {
|
|
287496
|
+
try {
|
|
287497
|
+
await retryPendingNotices(companyId, store);
|
|
287498
|
+
} finally {
|
|
287499
|
+
await checkPendingApprovals(companyId, store);
|
|
287500
|
+
}
|
|
287501
|
+
},
|
|
287047
287502
|
warn: options.warn,
|
|
287048
287503
|
...options.now ? { now: options.now } : {}
|
|
287049
287504
|
});
|
|
@@ -287055,7 +287510,7 @@ function createConnectorRenewalRuntime(options) {
|
|
|
287055
287510
|
const store = await options.actors(claims.companyId);
|
|
287056
287511
|
if (!store) return;
|
|
287057
287512
|
const name = await agentName(claims.companyId, claims.actorId);
|
|
287058
|
-
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);
|
|
287059
287514
|
},
|
|
287060
287515
|
onRejected: async (claims, who) => {
|
|
287061
287516
|
const store = await options.actors(claims.companyId);
|
|
@@ -300944,7 +301399,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
300944
301399
|
}
|
|
300945
301400
|
}
|
|
300946
301401
|
}
|
|
300947
|
-
var CLI_VERSION = "2.2.
|
|
301402
|
+
var CLI_VERSION = "2.2.114" ? "2.2.114" : "dev";
|
|
300948
301403
|
function apiHeaders(token2, company) {
|
|
300949
301404
|
const headers = {
|
|
300950
301405
|
authorization: `Bearer ${token2}`,
|
|
@@ -305115,7 +305570,7 @@ function shimScript() {
|
|
|
305115
305570
|
}
|
|
305116
305571
|
|
|
305117
305572
|
// src/index.ts
|
|
305118
|
-
var PKG_VERSION = true ? "2.2.
|
|
305573
|
+
var PKG_VERSION = true ? "2.2.114" : "dev";
|
|
305119
305574
|
var LOCAL_BIN = localBin();
|
|
305120
305575
|
var NPM_PREFIX = npmPrefix();
|
|
305121
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
|
}
|