dsh-connect 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +134 -17
- package/README.zh.md +110 -17
- package/client/client.js +510 -80
- package/client/client.js.map +4 -4
- package/client/locale.mjs +227 -0
- package/client/panel-state.mjs +54 -0
- package/client/settings-client.mjs +272 -60
- package/docs/images/settings-advanced-en.png +0 -0
- package/docs/images/settings-advanced-zh.png +0 -0
- package/docs/images/settings-defaults-en.png +0 -0
- package/docs/images/settings-defaults-zh.png +0 -0
- package/docs/images/settings-overview-en.png +0 -0
- package/docs/images/settings-overview-zh.png +0 -0
- package/lib/binding.d.ts.map +1 -1
- package/lib/binding.js +2 -2
- package/lib/binding.js.map +1 -1
- package/lib/channels/dingtalk/message.d.ts.map +1 -1
- package/lib/channels/dingtalk/message.js +7 -0
- package/lib/channels/dingtalk/message.js.map +1 -1
- package/lib/channels/feishu/adapter.d.ts +6 -12
- package/lib/channels/feishu/adapter.d.ts.map +1 -1
- package/lib/channels/feishu/adapter.js +2 -17
- package/lib/channels/feishu/adapter.js.map +1 -1
- package/lib/channels/feishu/i18n.d.ts +2 -0
- package/lib/channels/feishu/i18n.d.ts.map +1 -1
- package/lib/channels/feishu/i18n.js +2 -0
- package/lib/channels/feishu/i18n.js.map +1 -1
- package/lib/channels/feishu/index.d.ts +23 -2
- package/lib/channels/feishu/index.d.ts.map +1 -1
- package/lib/channels/feishu/index.js +32 -6
- package/lib/channels/feishu/index.js.map +1 -1
- package/lib/channels/telegram/adapter.d.ts.map +1 -1
- package/lib/channels/telegram/adapter.js +7 -1
- package/lib/channels/telegram/adapter.js.map +1 -1
- package/lib/chat-key.d.ts +29 -0
- package/lib/chat-key.d.ts.map +1 -0
- package/lib/chat-key.js +38 -0
- package/lib/chat-key.js.map +1 -0
- package/lib/index.d.ts +15 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +201 -31
- package/lib/index.js.map +1 -1
- package/lib/runner.d.ts +54 -0
- package/lib/runner.d.ts.map +1 -1
- package/lib/runner.js +158 -23
- package/lib/runner.js.map +1 -1
- package/lib/scheduler.d.ts.map +1 -1
- package/lib/scheduler.js +2 -2
- package/lib/scheduler.js.map +1 -1
- package/lib/service.d.ts +16 -0
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +46 -2
- package/lib/service.js.map +1 -1
- package/lib/settings/channel-runtime.d.ts +75 -0
- package/lib/settings/channel-runtime.d.ts.map +1 -0
- package/lib/settings/channel-runtime.js +165 -0
- package/lib/settings/channel-runtime.js.map +1 -0
- package/lib/settings/channels.d.ts +11 -0
- package/lib/settings/channels.d.ts.map +1 -1
- package/lib/settings/channels.js +31 -0
- package/lib/settings/channels.js.map +1 -1
- package/lib/settings/credential-store.d.ts +52 -6
- package/lib/settings/credential-store.d.ts.map +1 -1
- package/lib/settings/credential-store.js +92 -18
- package/lib/settings/credential-store.js.map +1 -1
- package/lib/settings/namespace.d.ts +175 -0
- package/lib/settings/namespace.d.ts.map +1 -0
- package/lib/settings/namespace.js +200 -0
- package/lib/settings/namespace.js.map +1 -0
- package/lib/settings/secret-disclosure.d.ts +50 -0
- package/lib/settings/secret-disclosure.d.ts.map +1 -0
- package/lib/settings/secret-disclosure.js +132 -0
- package/lib/settings/secret-disclosure.js.map +1 -0
- package/lib/settings/settings-model.d.ts +17 -0
- package/lib/settings/settings-model.d.ts.map +1 -1
- package/lib/settings/settings-model.js +8 -0
- package/lib/settings/settings-model.js.map +1 -1
- package/lib/settings/settings-rpc.d.ts +71 -3
- package/lib/settings/settings-rpc.d.ts.map +1 -1
- package/lib/settings/settings-rpc.js +167 -24
- package/lib/settings/settings-rpc.js.map +1 -1
- package/lib/settings/settings-service.d.ts +9 -1
- package/lib/settings/settings-service.d.ts.map +1 -1
- package/lib/settings/settings-service.js +74 -6
- package/lib/settings/settings-service.js.map +1 -1
- package/lib/state-dir.d.ts +28 -0
- package/lib/state-dir.d.ts.map +1 -0
- package/lib/state-dir.js +33 -0
- package/lib/state-dir.js.map +1 -0
- package/lib/stream.d.ts.map +1 -1
- package/lib/stream.js +3 -2
- package/lib/stream.js.map +1 -1
- package/package.json +11 -9
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which channel cards the settings pane shows open, and which fields hide behind
|
|
3
|
+
* each card's "advanced" fold.
|
|
4
|
+
*
|
|
5
|
+
* Dependency-free and separate from the React component for the same reason
|
|
6
|
+
* `locale.mjs` is: these rules are the interesting part, they are pure, and a
|
|
7
|
+
* test can pin them without a DOM. The bundle test in particular cannot — it
|
|
8
|
+
* renders the component with pre-supplied hook values, so it can never observe
|
|
9
|
+
* what the component *initializes* to. Only this module can answer that.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Fields that are set once and then left alone, grouped by channel.
|
|
14
|
+
*
|
|
15
|
+
* These are what makes the pane tall: with every channel expanded the pane
|
|
16
|
+
* renders 20 field blocks, each a label + input + preview + hint. Folding the
|
|
17
|
+
* rarely-touched ones behind a second-level disclosure keeps the common case —
|
|
18
|
+
* credentials plus the handful of behavioural switches — on one screen.
|
|
19
|
+
* `test/panel-state.test.mjs` asserts every key here really exists in
|
|
20
|
+
* `CHANNEL_CONFIG_FIELDS`, because a typo would silently drop a field from the
|
|
21
|
+
* UI rather than fail anything.
|
|
22
|
+
*/
|
|
23
|
+
export const ADVANCED_KEYS = {
|
|
24
|
+
feishu: ['webhookPort', 'webhookPath'],
|
|
25
|
+
telegram: ['pollingTimeoutSeconds', 'baseUrl'],
|
|
26
|
+
dingtalk: ['defaultAt'],
|
|
27
|
+
web: ['pollIntervalMs'],
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** True when `key` is one of `channel`'s low-frequency fields. */
|
|
31
|
+
export function isAdvanced(channel, key) {
|
|
32
|
+
return (ADVANCED_KEYS[channel] ?? []).includes(key);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The channels whose card starts open: the enabled ones, or — when nothing is
|
|
37
|
+
* enabled at all — the first channel, so the pane never opens as a wall of
|
|
38
|
+
* collapsed headers with no contents in sight.
|
|
39
|
+
*
|
|
40
|
+
* Unknown names are filtered out rather than trusted: `enabled` comes from the
|
|
41
|
+
* host and would otherwise open a card that does not exist.
|
|
42
|
+
*/
|
|
43
|
+
export function initialOpenChannels(enabled, all) {
|
|
44
|
+
const open = (enabled ?? []).filter((ch) => all.includes(ch));
|
|
45
|
+
return new Set(open.length > 0 ? open : all.slice(0, 1));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Toggle one key in a Set, returning a new Set (never mutating the argument). */
|
|
49
|
+
export function toggleInSet(set, key) {
|
|
50
|
+
const next = new Set(set);
|
|
51
|
+
if (next.has(key)) next.delete(key);
|
|
52
|
+
else next.add(key);
|
|
53
|
+
return next;
|
|
54
|
+
}
|
|
@@ -8,46 +8,93 @@
|
|
|
8
8
|
* `settings-model.js` / `rpc-client.js` helpers; this component is a thin
|
|
9
9
|
* renderer. Build the lib first (`pnpm --filter dsh-connect build`), then
|
|
10
10
|
* bundle this in a `dsh web` shell (Vite).
|
|
11
|
+
*
|
|
12
|
+
* The pane is an accordion, not a flat list. Four channels with every field
|
|
13
|
+
* visible is ~2000px of content in a ~690px scroller, so the channel cards
|
|
14
|
+
* collapse, rarely-touched fields hide behind a second-level "advanced" fold,
|
|
15
|
+
* and a tab strip at the top jumps to (and opens) a channel. The rules for
|
|
16
|
+
* which cards start open live in `panel-state.mjs` — pure, and testable without
|
|
17
|
+
* a DOM, which matters because the bundle test's React stub can only supply a
|
|
18
|
+
* component's hook values, never observe what it initializes them to.
|
|
11
19
|
*/
|
|
12
20
|
import * as React from 'react';
|
|
13
21
|
|
|
14
22
|
import { SETTINGS_RPC_CHANNEL } from '../lib/settings/settings-rpc.js';
|
|
15
23
|
import { loadSettings, saveSettings, saveCredentials } from '../lib/settings/rpc-client.js';
|
|
16
24
|
import { snapshotToForm, buildConfigSave, buildCredentialSaves, CHANNEL_SECRET_FIELDS, CHANNEL_CONFIG_FIELDS, CHANNEL_DEFAULT_FIELDS, coerceConfigValue } from '../lib/settings/settings-model.js';
|
|
25
|
+
// Shared with the host, so the pane and the masking it displays can never
|
|
26
|
+
// disagree about which keys are confidential.
|
|
27
|
+
import { isMaskedSecret } from '../lib/settings/secret-disclosure.js';
|
|
28
|
+
import { LOCALES, tr, optionalText } from './locale.mjs';
|
|
29
|
+
import { initialOpenChannels, toggleInSet, isAdvanced } from './panel-state.mjs';
|
|
17
30
|
|
|
18
31
|
export const name = 'dsh-connect-settings';
|
|
19
32
|
export const inject = ['slots', 'connection', 'locale'];
|
|
20
33
|
export const NS = 'dsh-connect';
|
|
21
34
|
|
|
22
|
-
export const locale =
|
|
23
|
-
zh: { title: '连接设置', channels: '渠道', save: '保存', saved: '已保存', error: '保存失败', loading: '加载中', defaults: '公共默认(channelDefaults)', statePath: '设置文件', secret: '密钥', config: '配置', reachable: '已连接凭据', unreachable: '未配置凭据' },
|
|
24
|
-
en: { title: 'Connection Settings', channels: 'Channels', save: 'Save', saved: 'Saved', error: 'Save failed', loading: 'Loading', defaults: 'Defaults (channelDefaults)', statePath: 'Settings file', secret: 'Secret', config: 'Config', reachable: 'Credential set', unreachable: 'Credential missing' },
|
|
25
|
-
};
|
|
35
|
+
export const locale = LOCALES;
|
|
26
36
|
|
|
27
37
|
const h = React.createElement;
|
|
28
38
|
|
|
39
|
+
/** The channels the pane knows about, in the order the cards are rendered. */
|
|
40
|
+
const ALL_CHANNELS = Object.keys(CHANNEL_SECRET_FIELDS);
|
|
41
|
+
|
|
29
42
|
// Self-contained scoped stylesheet for the pane (injected once). The host's own
|
|
30
43
|
// settings panes use per-feature CSS modules we can't import into this separate
|
|
31
44
|
// bundle, so we ship our own consistent, theme-aware styles instead. Everything
|
|
32
45
|
// is scoped under `.dsh-connect-settings` so nothing leaks into the shell.
|
|
46
|
+
//
|
|
47
|
+
// Two things here are load-bearing rather than cosmetic:
|
|
48
|
+
//
|
|
49
|
+
// 1. The `box-sizing` reset. Neither this bundle nor the host shell ships a
|
|
50
|
+
// global one, so under the default `content-box` a `.ds-input` with
|
|
51
|
+
// `width:100%` is ~20px (padding + border) *wider* than the grid column it
|
|
52
|
+
// sits in, and paints over the neighbouring column's text. That overflow is
|
|
53
|
+
// what "文字跟窗口重叠" actually was.
|
|
54
|
+
// 2. The host's theme tokens, with our old hex values as fallbacks. The host
|
|
55
|
+
// puts `--dsw-alias-*` on `body` / `body[data-ds-dark-theme]`, so inheriting
|
|
56
|
+
// them follows the user's in-app theme. A `prefers-color-scheme` block — what
|
|
57
|
+
// used to be here — ignores that choice entirely and repaints the pane black
|
|
58
|
+
// on a light shell for anyone whose OS is dark. Do not bring it back.
|
|
33
59
|
const STYLE = `
|
|
34
|
-
.dsh-connect-settings
|
|
35
|
-
|
|
36
|
-
.dsh-connect-settings .ds-card{border:1px solid var(--ds-border);border-radius:10px;background:var(--ds-bg);padding:12px 14px
|
|
60
|
+
.dsh-connect-settings,.dsh-connect-settings *,.dsh-connect-settings *::before,.dsh-connect-settings *::after{box-sizing:border-box}
|
|
61
|
+
.dsh-connect-settings{--ds-bg:var(--dsw-alias-bg-layer-3,#ffffff);--ds-bg-sub:var(--dsw-alias-bg-layer-1,#f6f7f9);--ds-text:var(--dsw-alias-label-primary,#1f2329);--ds-muted:var(--dsw-alias-label-tertiary,#646a73);--ds-border:var(--dsw-alias-border-l2,#e2e4e8);--ds-border-2:var(--dsw-alias-border-l3,#c8cbd0);--ds-accent:var(--dsw-alias-state-business-primary,#3b82f6);--ds-hover:var(--dsw-alias-interactive-bg-hover,#2631480f);display:flex;flex-direction:column;gap:12px;max-width:760px;color:var(--ds-text);font:13px/1.6 -apple-system,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif}
|
|
62
|
+
.dsh-connect-settings .ds-card{display:flex;flex-direction:column;gap:10px;border:1px solid var(--ds-border);border-radius:10px;background:var(--ds-bg);padding:12px 14px}
|
|
37
63
|
.dsh-connect-settings .ds-card-title{margin:0;font-size:13px;font-weight:600}
|
|
38
|
-
.dsh-connect-settings .ds-
|
|
39
|
-
.dsh-connect-settings .ds-
|
|
40
|
-
.dsh-connect-settings .ds-
|
|
41
|
-
.dsh-connect-settings .ds-
|
|
42
|
-
.dsh-connect-settings .ds-
|
|
43
|
-
.dsh-connect-settings .ds-
|
|
44
|
-
.dsh-connect-settings .ds-
|
|
45
|
-
.dsh-connect-settings .ds-
|
|
46
|
-
.dsh-connect-settings .ds-
|
|
64
|
+
.dsh-connect-settings .ds-note{margin:0;font-size:11px;line-height:1.5;color:var(--ds-muted)}
|
|
65
|
+
.dsh-connect-settings .ds-tabs{display:flex;flex-wrap:wrap;gap:6px}
|
|
66
|
+
.dsh-connect-settings .ds-tab{display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 10px;border:1px solid var(--ds-border);border-radius:14px;background:transparent;color:var(--ds-text);font:inherit;font-size:12px;cursor:pointer}
|
|
67
|
+
.dsh-connect-settings .ds-tab:hover{background:var(--ds-hover)}
|
|
68
|
+
.dsh-connect-settings .ds-tab[aria-expanded=true]{border-color:var(--ds-accent);color:var(--ds-accent)}
|
|
69
|
+
.dsh-connect-settings .ds-dot{width:6px;height:6px;border-radius:50%;background:var(--ds-border-2);flex:none}
|
|
70
|
+
.dsh-connect-settings .ds-dot[data-on="1"]{background:var(--ds-accent)}
|
|
71
|
+
.dsh-connect-settings .ds-channel{border:1px solid var(--ds-border);border-radius:8px;background:var(--ds-bg-sub)}
|
|
72
|
+
.dsh-connect-settings .ds-channel-head{display:flex;align-items:center;gap:8px;padding:5px 10px}
|
|
73
|
+
.dsh-connect-settings .ds-enable{display:flex;align-items:center;flex:none}
|
|
74
|
+
.dsh-connect-settings .ds-channel-toggle{flex:1;min-width:0;display:flex;align-items:center;gap:8px;padding:5px 6px;border:0;border-radius:6px;background:transparent;color:inherit;font:inherit;font-size:12px;font-weight:600;text-align:left;cursor:pointer}
|
|
75
|
+
.dsh-connect-settings .ds-channel-toggle:hover{background:var(--ds-hover);color:var(--ds-accent)}
|
|
76
|
+
.dsh-connect-settings .ds-channel-name{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
77
|
+
.dsh-connect-settings .ds-channel-body{display:flex;flex-direction:column;gap:8px;padding:0 10px 10px}
|
|
78
|
+
.dsh-connect-settings .ds-chevron{width:7px;height:7px;margin:-3px 4px 0 auto;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:rotate(45deg);transition:transform .15s ease;flex:none}
|
|
79
|
+
.dsh-connect-settings [aria-expanded=true]>.ds-chevron,.dsh-connect-settings [aria-expanded=true] .ds-chevron{transform:rotate(-135deg);margin-top:2px}
|
|
80
|
+
.dsh-connect-settings .ds-badge{flex:none;font-size:11px;font-weight:500;padding:1px 8px;border-radius:99px;background:var(--ds-bg);color:var(--ds-muted);border:1px solid var(--ds-border-2)}
|
|
81
|
+
.dsh-connect-settings .ds-fields{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:10px 14px}
|
|
82
|
+
.dsh-connect-settings .ds-field{display:flex;flex-direction:column;gap:4px;min-width:0}
|
|
83
|
+
.dsh-connect-settings .ds-control{display:flex;flex-direction:column;gap:4px;font-size:12px;color:var(--ds-muted)}
|
|
84
|
+
.dsh-connect-settings .ds-control.ds-check-field{flex-direction:row;align-items:center;gap:6px}
|
|
85
|
+
.dsh-connect-settings .ds-hint{margin:0;font-size:11px;line-height:1.5;color:var(--ds-muted)}
|
|
86
|
+
.dsh-connect-settings .ds-preview{margin:0;font-size:11px;line-height:1.5;color:var(--ds-muted);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;word-break:break-all}
|
|
87
|
+
.dsh-connect-settings .ds-preview b{font-weight:500;font-family:inherit;opacity:.75}
|
|
88
|
+
.dsh-connect-settings .ds-check{flex:none;width:16px;height:16px;accent-color:var(--ds-accent)}
|
|
89
|
+
.dsh-connect-settings .ds-input{height:30px;width:100%;min-width:0;padding:0 9px;border:1px solid var(--ds-border-2);border-radius:6px;background:var(--ds-bg);color:var(--ds-text);font:inherit}
|
|
47
90
|
.dsh-connect-settings select.ds-input{cursor:pointer}
|
|
48
|
-
.dsh-connect-settings .ds-input:focus{outline:none;border-color:var(--ds-accent);box-shadow:0 0 0 2px var(--ds-
|
|
49
|
-
.dsh-connect-settings .ds-
|
|
50
|
-
.dsh-connect-settings .ds-
|
|
91
|
+
.dsh-connect-settings .ds-input:focus{outline:none;border-color:var(--ds-accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--ds-accent) 25%,transparent)}
|
|
92
|
+
.dsh-connect-settings .ds-adv{display:flex;flex-direction:column;gap:8px}
|
|
93
|
+
.dsh-connect-settings .ds-advanced-toggle{align-self:flex-start;display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border:1px dashed var(--ds-border-2);border-radius:99px;background:transparent;color:var(--ds-muted);font:inherit;font-size:11px;cursor:pointer}
|
|
94
|
+
.dsh-connect-settings .ds-advanced-toggle:hover{background:var(--ds-hover);color:var(--ds-text)}
|
|
95
|
+
.dsh-connect-settings .ds-footer{position:sticky;bottom:0;z-index:1;display:flex;align-items:center;gap:12px;margin:0 -14px -12px;padding:10px 14px;border-top:1px solid var(--ds-border);border-radius:0 0 9px 9px;background:var(--ds-bg)}
|
|
96
|
+
.dsh-connect-settings .ds-btn{height:32px;padding:0 18px;border:0;border-radius:6px;background:var(--dsw-alias-button-primary-fill,var(--ds-accent));color:var(--dsw-alias-label-primary-foreground,#ffffff);font:inherit;font-weight:500;cursor:pointer}
|
|
97
|
+
.dsh-connect-settings .ds-btn:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover,var(--ds-accent))}
|
|
51
98
|
.dsh-connect-settings .ds-btn:disabled{opacity:.55;cursor:default}
|
|
52
99
|
.dsh-connect-settings .ds-status{font-size:12px;color:var(--ds-muted)}
|
|
53
100
|
`;
|
|
@@ -61,29 +108,138 @@ function injectStyles() {
|
|
|
61
108
|
document.head.appendChild(el);
|
|
62
109
|
}
|
|
63
110
|
|
|
64
|
-
// Render
|
|
65
|
-
|
|
66
|
-
|
|
111
|
+
// Render one non-secret config field: its control, then its explanation.
|
|
112
|
+
//
|
|
113
|
+
// Label and hint are looked up by *config key* (`f.<key>`), so a field added
|
|
114
|
+
// without its text shows a legible fallback (`field.label`) instead of a raw
|
|
115
|
+
// identifier — and the locale-coverage test fails, which is the real guard.
|
|
116
|
+
function renderConfigField(field, value, onChange, t) {
|
|
117
|
+
const label = tr(t, `f.${field.key}`, field.label ?? field.key);
|
|
118
|
+
const hint = optionalText(t, `f.${field.key}.hint`);
|
|
119
|
+
let control;
|
|
67
120
|
if (field.kind === 'boolean') {
|
|
68
|
-
|
|
121
|
+
control = h('label', { className: 'ds-control ds-check-field' },
|
|
69
122
|
h('input', { className: 'ds-check', type: 'checkbox', checked: !!value, onChange: (e) => onChange(e.target.checked) }),
|
|
70
123
|
' ' + label);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return h('label', { className: 'ds-field', key: `cfg-${field.key}` },
|
|
74
|
-
label + ' ',
|
|
124
|
+
} else if (field.kind === 'select') {
|
|
125
|
+
control = h('label', { className: 'ds-control' }, label + ' ',
|
|
75
126
|
h('select', { className: 'ds-input', value: value ?? '', onChange: (e) => onChange(e.target.value) },
|
|
76
|
-
h('option', { value: '' }, '
|
|
77
|
-
...(field.options ?? []).map((opt) => h('option', { key: opt, value: opt }, opt))));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return h('label', { className: 'ds-field', key: `cfg-${field.key}` },
|
|
81
|
-
label + ' ',
|
|
127
|
+
h('option', { value: '' }, tr(t, 'o.default', label)),
|
|
128
|
+
...(field.options ?? []).map((opt) => h('option', { key: opt, value: opt }, tr(t, `o.${opt}`, opt)))));
|
|
129
|
+
} else if (field.kind === 'number') {
|
|
130
|
+
control = h('label', { className: 'ds-control' }, label + ' ',
|
|
82
131
|
h('input', { className: 'ds-input', type: 'number', value: value ?? '', onChange: (e) => onChange(e.target.value) }));
|
|
132
|
+
} else {
|
|
133
|
+
control = h('label', { className: 'ds-control' }, label + ' ',
|
|
134
|
+
h('input', { className: 'ds-input', type: 'text', value: value ?? '', onChange: (e) => onChange(e.target.value) }));
|
|
83
135
|
}
|
|
84
|
-
return h('
|
|
85
|
-
|
|
86
|
-
h('
|
|
136
|
+
return h('div', { className: 'ds-field', key: `cfg-${field.key}` },
|
|
137
|
+
control,
|
|
138
|
+
hint ? h('p', { className: 'ds-hint' }, hint) : null);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Render one secret field: a write-only input, plus a read-only preview of the
|
|
142
|
+
// stored value so the user can confirm what they configured.
|
|
143
|
+
//
|
|
144
|
+
// The preview is plain text, never the input's `value`. The host already masked
|
|
145
|
+
// it, and seeding an input with a mask would let a save write the mask *back* as
|
|
146
|
+
// the credential. Keeping the input blank also keeps "empty" meaning "leave the
|
|
147
|
+
// stored value alone", which is what a password field is expected to do.
|
|
148
|
+
function renderSecretField(ch, field, form, onChange, t) {
|
|
149
|
+
const preview = form.secretPreviews?.[ch]?.[field] ?? '';
|
|
150
|
+
const hint = optionalText(t, `s.${ch}.${field}.hint`);
|
|
151
|
+
return h('div', { className: 'ds-field', key: `sec-${ch}-${field}` },
|
|
152
|
+
h('label', { className: 'ds-control' },
|
|
153
|
+
tr(t, `s.${ch}.${field}`, field),
|
|
154
|
+
h('input', {
|
|
155
|
+
className: 'ds-input',
|
|
156
|
+
// Confidential keys stay masked while typing; identifiers (appId,
|
|
157
|
+
// clientId) don't, so a typo is visible before it is ever saved.
|
|
158
|
+
type: isMaskedSecret(field) ? 'password' : 'text',
|
|
159
|
+
autoComplete: 'off',
|
|
160
|
+
placeholder: preview ? t('configured') : t('notConfigured'),
|
|
161
|
+
value: form.secrets?.[ch]?.[field] ?? '',
|
|
162
|
+
onChange: (e) => onChange(e.target.value),
|
|
163
|
+
})),
|
|
164
|
+
h('p', { className: 'ds-preview' },
|
|
165
|
+
h('b', null, t('current')),
|
|
166
|
+
preview === '' ? t('notConfigured') : preview),
|
|
167
|
+
hint ? h('p', { className: 'ds-hint' }, hint) : null);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// One channel card: an enable checkbox, a header that folds the card, and — when
|
|
171
|
+
// open — its credentials and settings.
|
|
172
|
+
//
|
|
173
|
+
// A plain function rather than a child component, deliberately: the bundle test
|
|
174
|
+
// supplies hook values *positionally*, so every `useState` in the tree has to
|
|
175
|
+
// live in `ConnectSettingsTab` in a fixed order. Nothing in here may call a hook.
|
|
176
|
+
function renderChannel(ch, ctx) {
|
|
177
|
+
const { form, creds, t, open, advOverride, setChannels, setField, setChannelConfig, toggleOpen, toggleAdvanced } = ctx;
|
|
178
|
+
const name = tr(t, `channel.${ch}`, ch);
|
|
179
|
+
const channelHint = optionalText(t, `channel.${ch}.hint`);
|
|
180
|
+
const isOpen = open.has(ch);
|
|
181
|
+
const advOpen = advOverride?.has(ch) ?? false;
|
|
182
|
+
const configFields = CHANNEL_CONFIG_FIELDS[ch] ?? [];
|
|
183
|
+
// The split is what keeps a common case on one screen: two credentials and the
|
|
184
|
+
// behavioural switches, with the set-once fields one disclosure deeper.
|
|
185
|
+
const common = configFields.filter((f) => !isAdvanced(ch, f.key));
|
|
186
|
+
const advanced = configFields.filter((f) => isAdvanced(ch, f.key));
|
|
187
|
+
|
|
188
|
+
const configField = (field) => renderConfigField(
|
|
189
|
+
field,
|
|
190
|
+
form.channelConfigs?.[ch]?.[field.key],
|
|
191
|
+
(raw) => setChannelConfig(ch, field.key, raw),
|
|
192
|
+
t,
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
return h('div', { className: 'ds-channel', key: ch, id: `ds-ch-${ch}` },
|
|
196
|
+
// The checkbox sits beside the header button, not inside it: a button may not
|
|
197
|
+
// contain another interactive element, and browsers disagree about what to do
|
|
198
|
+
// when one does.
|
|
199
|
+
h('div', { className: 'ds-channel-head' },
|
|
200
|
+
h('label', { className: 'ds-enable' },
|
|
201
|
+
h('input', {
|
|
202
|
+
className: 'ds-check',
|
|
203
|
+
type: 'checkbox',
|
|
204
|
+
'aria-label': name,
|
|
205
|
+
checked: form.channels.includes(ch),
|
|
206
|
+
onChange: (e) => setChannels(ch, e.target.checked),
|
|
207
|
+
})),
|
|
208
|
+
h('button', {
|
|
209
|
+
type: 'button',
|
|
210
|
+
className: 'ds-channel-toggle',
|
|
211
|
+
'aria-expanded': isOpen,
|
|
212
|
+
// Only while the body exists: pointing at an id that is not in the
|
|
213
|
+
// document is worse than not pointing at all.
|
|
214
|
+
'aria-controls': isOpen ? `ds-ch-${ch}-body` : undefined,
|
|
215
|
+
'aria-label': `${name} — ${isOpen ? t('collapse') : t('expand')}`,
|
|
216
|
+
onClick: () => toggleOpen(ch),
|
|
217
|
+
},
|
|
218
|
+
h('span', { className: 'ds-channel-name' }, name),
|
|
219
|
+
h('span', { className: 'ds-badge' }, creds[ch] ? t('reachable') : t('unreachable')),
|
|
220
|
+
// Drawn in CSS, never a text node: the bundle test reads rendered text as
|
|
221
|
+
// user-visible copy, and a `▾` here would be collected as a stray string.
|
|
222
|
+
h('span', { className: 'ds-chevron' }))),
|
|
223
|
+
// Collapsed means *not rendered*, not `display:none`. The inputs are
|
|
224
|
+
// controlled from the parent's `form.secrets`, so folding a card cannot lose
|
|
225
|
+
// an unsaved secret — keeping it mounted would buy nothing.
|
|
226
|
+
isOpen ? h('div', { className: 'ds-channel-body', id: `ds-ch-${ch}-body` },
|
|
227
|
+
channelHint ? h('p', { className: 'ds-note' }, channelHint) : null,
|
|
228
|
+
h('div', { className: 'ds-fields' },
|
|
229
|
+
...CHANNEL_SECRET_FIELDS[ch].map((field) => renderSecretField(ch, field, form, (value) => setField(ch, field, value), t)),
|
|
230
|
+
...common.map(configField)),
|
|
231
|
+
advanced.length === 0 ? null : h('div', { className: 'ds-adv' },
|
|
232
|
+
h('button', {
|
|
233
|
+
type: 'button',
|
|
234
|
+
className: 'ds-advanced-toggle',
|
|
235
|
+
'aria-expanded': advOpen,
|
|
236
|
+
'aria-controls': advOpen ? `ds-ch-${ch}-adv` : undefined,
|
|
237
|
+
onClick: () => toggleAdvanced(ch),
|
|
238
|
+
},
|
|
239
|
+
h('span', null, t('advanced')),
|
|
240
|
+
h('span', { className: 'ds-chevron' })),
|
|
241
|
+
advOpen ? h('div', { className: 'ds-fields', id: `ds-ch-${ch}-adv` }, ...advanced.map(configField)) : null),
|
|
242
|
+
) : null);
|
|
87
243
|
}
|
|
88
244
|
|
|
89
245
|
// Thin React renderer over the tested settings-model helpers.
|
|
@@ -91,6 +247,8 @@ export function ConnectSettingsTab({ rpcCall, t }) {
|
|
|
91
247
|
const [form, setForm] = React.useState(null);
|
|
92
248
|
const [status, setStatus] = React.useState('loading');
|
|
93
249
|
const [creds, setCreds] = React.useState({});
|
|
250
|
+
const [openOverride, setOpenOverride] = React.useState(null);
|
|
251
|
+
const [advOverride, setAdvOverride] = React.useState(null);
|
|
94
252
|
const rpc = (endpoint, payload) => rpcCall(endpoint, payload);
|
|
95
253
|
|
|
96
254
|
React.useEffect(() => {
|
|
@@ -108,13 +266,25 @@ export function ConnectSettingsTab({ rpcCall, t }) {
|
|
|
108
266
|
if (!form) return;
|
|
109
267
|
setStatus('saving');
|
|
110
268
|
try {
|
|
111
|
-
|
|
112
|
-
|
|
269
|
+
// The last snapshot in the chain wins: it is the one that reflects every
|
|
270
|
+
// write this save performed. Re-seeding the form from it also drops the
|
|
271
|
+
// typed secret values (their inputs are write-only by design) and picks up
|
|
272
|
+
// the new presence flags.
|
|
273
|
+
let snap = await saveSettings(rpc, buildConfigSave(form));
|
|
274
|
+
for (const c of buildCredentialSaves(form)) snap = await saveCredentials(rpc, c.channel, c.values);
|
|
275
|
+
setForm(snapshotToForm(snap));
|
|
276
|
+
setCreds(snap.credentials ?? {});
|
|
113
277
|
setStatus('saved');
|
|
114
278
|
} catch { setStatus('error'); }
|
|
115
279
|
};
|
|
116
280
|
|
|
117
|
-
const setChannels = (ch, on) =>
|
|
281
|
+
const setChannels = (ch, on) => {
|
|
282
|
+
setForm((f) => ({ ...f, channels: on ? [...f.channels, ch] : f.channels.filter((x) => x !== ch) }));
|
|
283
|
+
// Enabling a channel opens it, and only ever opens: the user just said they
|
|
284
|
+
// care about this one. Ticking it back off leaves the fold alone rather than
|
|
285
|
+
// snapping shut under the cursor.
|
|
286
|
+
if (on && !open.has(ch)) setOpenOverride(new Set(open).add(ch));
|
|
287
|
+
};
|
|
118
288
|
const setField = (ch, field, value) => setForm((f) => ({ ...f, secrets: { ...f.secrets, [ch]: { ...(f.secrets[ch] ?? {}), [field]: value } } }));
|
|
119
289
|
const setChannelConfig = (ch, key, raw) => setForm((f) => {
|
|
120
290
|
const descriptor = (CHANNEL_CONFIG_FIELDS[ch] ?? []).find((x) => x.key === key);
|
|
@@ -132,35 +302,77 @@ export function ConnectSettingsTab({ rpcCall, t }) {
|
|
|
132
302
|
});
|
|
133
303
|
|
|
134
304
|
if (!form) return h('div', { className: 'dsh-connect-settings' }, t('loading'));
|
|
305
|
+
|
|
306
|
+
// Which cards are open is *derived*, not stored: the first render happens
|
|
307
|
+
// before the host's snapshot arrives, and the test stub cannot run effects, so
|
|
308
|
+
// an effect here would be the only place the default could ever be set — and
|
|
309
|
+
// it would never run. The override records only what the user has since done,
|
|
310
|
+
// on top of that default (`toggleInSet(open, …)` rather than a bare toggle),
|
|
311
|
+
// so opening DingTalk does not silently drop the enabled Feishu the user was
|
|
312
|
+
// already looking at.
|
|
313
|
+
const open = openOverride ?? initialOpenChannels(form.channels, ALL_CHANNELS);
|
|
314
|
+
|
|
315
|
+
const toggleOpen = (ch) => setOpenOverride(toggleInSet(open, ch));
|
|
316
|
+
// Advanced folds default to closed for every channel, so an empty set is the
|
|
317
|
+
// derived default here and no counterpart to `initialOpenChannels` is needed.
|
|
318
|
+
const toggleAdvanced = (ch) => setAdvOverride(toggleInSet(advOverride ?? new Set(), ch));
|
|
319
|
+
const focusChannel = (ch) => {
|
|
320
|
+
// A tab expands and scrolls, but never collapses: "show me Telegram" must not
|
|
321
|
+
// close the channel the user is halfway through editing.
|
|
322
|
+
if (!open.has(ch)) setOpenOverride(new Set(open).add(ch));
|
|
323
|
+
if (typeof document === 'undefined' || !document.getElementById) return;
|
|
324
|
+
// The header is rendered whether or not the card is open, so this resolves
|
|
325
|
+
// before React has re-rendered, and lands in the same place either way.
|
|
326
|
+
document.getElementById(`ds-ch-${ch}`)?.scrollIntoView?.({ block: 'nearest' });
|
|
327
|
+
};
|
|
328
|
+
|
|
135
329
|
return h('div', { className: 'dsh-connect-settings' },
|
|
136
330
|
h('section', { className: 'ds-card' },
|
|
137
331
|
h('h4', { className: 'ds-card-title' }, t('channels')),
|
|
332
|
+
// Explains the masking before the user meets a truncated value and wonders
|
|
333
|
+
// whether their stored secret is corrupt.
|
|
334
|
+
h('p', { className: 'ds-note' }, t('previewNote')),
|
|
335
|
+
// A tab strip, but not `role=tablist`: several channels can be open at
|
|
336
|
+
// once, so there is no single "selected" tab to report. These are buttons
|
|
337
|
+
// that open and jump to a channel, and `aria-expanded` says so honestly.
|
|
338
|
+
h('nav', { className: 'ds-tabs', 'aria-label': t('tabsAria') },
|
|
339
|
+
...ALL_CHANNELS.map((ch) => h('button', {
|
|
340
|
+
key: `tab-${ch}`,
|
|
341
|
+
type: 'button',
|
|
342
|
+
className: 'ds-tab',
|
|
343
|
+
'aria-expanded': open.has(ch),
|
|
344
|
+
'aria-controls': open.has(ch) ? `ds-ch-${ch}-body` : undefined,
|
|
345
|
+
onClick: () => focusChannel(ch),
|
|
346
|
+
},
|
|
347
|
+
h('span', { className: 'ds-dot', 'data-on': form.channels.includes(ch) ? '1' : '0' }),
|
|
348
|
+
tr(t, `channel.${ch}`, ch)))),
|
|
138
349
|
// One card per built-in channel: enable toggle + cred badge + secret + config fields.
|
|
139
|
-
...
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
h('span', null, ch),
|
|
144
|
-
h('span', { className: 'ds-badge' }, creds[ch] ? t('reachable') : t('unreachable'))),
|
|
145
|
-
),
|
|
146
|
-
h('div', { className: 'ds-fields' },
|
|
147
|
-
...CHANNEL_SECRET_FIELDS[ch].map((field) => h('label', { className: 'ds-field', key: `sec-${field}` },
|
|
148
|
-
field,
|
|
149
|
-
h('input', { className: 'ds-input', type: 'password', placeholder: field, value: form.secrets?.[ch]?.[field] ?? '', onChange: (e) => setField(ch, field, e.target.value) }))),
|
|
150
|
-
...(CHANNEL_CONFIG_FIELDS[ch] ?? []).map((field) => renderConfigField(field, form.channelConfigs?.[ch]?.[field.key], (raw) => setChannelConfig(ch, field.key, raw))),
|
|
151
|
-
),
|
|
152
|
-
)),
|
|
153
|
-
),
|
|
350
|
+
...ALL_CHANNELS.map((ch) => renderChannel(ch, {
|
|
351
|
+
form, creds, t, open, advOverride,
|
|
352
|
+
setChannels, setField, setChannelConfig, toggleOpen, toggleAdvanced,
|
|
353
|
+
}))),
|
|
154
354
|
h('section', { className: 'ds-card' },
|
|
155
355
|
h('h4', { className: 'ds-card-title' }, t('defaults')),
|
|
356
|
+
h('p', { className: 'ds-note' }, t('defaultsHint')),
|
|
156
357
|
h('div', { className: 'ds-fields' },
|
|
157
|
-
...CHANNEL_DEFAULT_FIELDS.map((field) => renderConfigField(field, form.channelDefaults?.[field.key], (raw) => setDefault(field.key, raw))),
|
|
158
|
-
|
|
159
|
-
|
|
358
|
+
...CHANNEL_DEFAULT_FIELDS.map((field) => renderConfigField(field, form.channelDefaults?.[field.key], (raw) => setDefault(field.key, raw), t)),
|
|
359
|
+
// Only meaningful on the fallback plane: it names the file the pane
|
|
360
|
+
// persists to. With the namespace live that path is not consulted (and
|
|
361
|
+
// is not part of the section), so showing an editable field for it would
|
|
362
|
+
// silently swallow edits.
|
|
363
|
+
form.live ? null : h('div', { className: 'ds-field' },
|
|
364
|
+
h('label', { className: 'ds-control' }, t('statePath'),
|
|
365
|
+
h('input', { className: 'ds-input', value: form.settingsStatePath ?? '', onChange: (e) => setForm((f) => ({ ...f, settingsStatePath: e.target.value })) })),
|
|
366
|
+
h('p', { className: 'ds-hint' }, t('statePathHint'))),
|
|
160
367
|
),
|
|
161
|
-
h('div', { className: 'ds-
|
|
162
|
-
|
|
163
|
-
|
|
368
|
+
h('div', { className: 'ds-status' }, form.live ? t('livePlane') : t('filePlane')),
|
|
369
|
+
// Sticky to the bottom of the host's scrolling region, so Save stays in
|
|
370
|
+
// reach however far the channel list has been unfolded.
|
|
371
|
+
h('div', { className: 'ds-footer' },
|
|
372
|
+
h('button', { className: 'ds-btn', type: 'button', onClick: onSave, disabled: status === 'saving' }, t('save')),
|
|
373
|
+
// Rendering `status` directly leaks the raw state ids (`idle`, `saving`)
|
|
374
|
+
// into the UI; every state has a locale entry instead.
|
|
375
|
+
h('span', { className: 'ds-status' }, tr(t, `status.${status}`, status)),
|
|
164
376
|
),
|
|
165
377
|
),
|
|
166
378
|
);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/binding.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"AAYA,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,KAAK,GAAG,OAAO,CAAC;IAC1B,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,0FAA0F;IAC1F,WAAW,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC9C,oGAAoG;IACpG,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,0FAA0F;IAC1F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sEAAsE;IACtE,SAAS,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;IAC7B,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sEAAsE;IACtE,cAAc,CAAC,EAAE,KAAK,CAAC;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC3B,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC1B,qFAAqF;QACrF,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,gEAAgE;IAChE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AA0BD,+CAA+C;AAC/C,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,KAAK,IAAI,CAAC;AAE5G,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkC;IACtD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAoC;gBAExD,QAAQ,CAAC,EAAE,MAAM;IAK7B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,IAAI;IAOrD;;OAEG;IACH,OAAO,CAAC,UAAU;IAUlB;;;OAGG;IACH,OAAO,IAAI,gBAAgB,CAAC,WAAW,CAAC;IAIxC;;OAEG;IACH,IAAI,IAAI,WAAW,EAAE;IAIrB;;;;OAIG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE;IAUjD,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI9D,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAQ/B,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAU9C,OAAO,CAAC,IAAI;IAoCZ,OAAO,CAAC,IAAI;CAQb"}
|
package/lib/binding.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
9
9
|
import { dirname, resolve } from "node:path";
|
|
10
|
+
import { resolveStateDir } from "./state-dir.js";
|
|
10
11
|
function keyOf(channel, chatKey) {
|
|
11
12
|
return `${channel}\u0000${chatKey}`;
|
|
12
13
|
}
|
|
@@ -35,8 +36,7 @@ export class BindingStore {
|
|
|
35
36
|
file;
|
|
36
37
|
changeListeners = new Set();
|
|
37
38
|
constructor(stateDir) {
|
|
38
|
-
|
|
39
|
-
this.file = resolve(dir, "bindings.json");
|
|
39
|
+
this.file = resolve(resolveStateDir({ stateDir }), "bindings.json");
|
|
40
40
|
this.load();
|
|
41
41
|
}
|
|
42
42
|
/**
|
package/lib/binding.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding.js","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"binding.js","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/channels/dingtalk/message.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iDAAiD;IACjD,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5D;AAED,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,8BAA8B,CAAC;AAC/D,6CAA6C;AAC7C,eAAO,MAAM,iBAAiB,gCAAgC,CAAC;AAC/D,wDAAwD;AACxD,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,kBAAkB,EAAE,OAAO,SAAa,GAAG,cAAc,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/channels/dingtalk/message.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iDAAiD;IACjD,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5D;AAED,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,8BAA8B,CAAC;AAC/D,6CAA6C;AAC7C,eAAO,MAAM,iBAAiB,gCAAgC,CAAC;AAC/D,wDAAwD;AACxD,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,kBAAkB,EAAE,OAAO,SAAa,GAAG,cAAc,GAAG,SAAS,CAkB7G;AAED,qDAAqD;AACrD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,mDAAmD;AACnD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzF;AAED,6CAA6C;AAC7C,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAE/E"}
|
|
@@ -19,6 +19,13 @@ export function normalizeBotMessage(raw, channel = "dingtalk") {
|
|
|
19
19
|
if (typeof raw.senderStaffId !== "string" || raw.senderStaffId === "")
|
|
20
20
|
return undefined;
|
|
21
21
|
const text = raw.msgType === "text" ? (raw.text?.content ?? "") : "";
|
|
22
|
+
// Nothing for the agent to act on: a non-text payload (image, file, sticker,
|
|
23
|
+
// recall notice) normalizes to an empty body, and stream mode carries no
|
|
24
|
+
// attachment download. Running a turn on it would burn a model call and post
|
|
25
|
+
// a reply to a message the user never sent. Same guard the Telegram adapter
|
|
26
|
+
// applies when it has no media either.
|
|
27
|
+
if (text.trim() === "")
|
|
28
|
+
return undefined;
|
|
22
29
|
return {
|
|
23
30
|
channel,
|
|
24
31
|
chatKey: raw.conversationId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/channels/dingtalk/message.ts"],"names":[],"mappings":"AAyBA,oEAAoE;AACpE,MAAM,CAAC,MAAM,mBAAmB,GAAG,2BAA2B,CAAC;AAC/D,6CAA6C;AAC7C,MAAM,CAAC,MAAM,iBAAiB,GAAG,6BAA6B,CAAC;AAC/D,wDAAwD;AACxD,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAC;AAE9C,iFAAiF;AACjF,MAAM,UAAU,aAAa,CAAC,GAAuB;IACnD,OAAO,GAAG,CAAC,UAAU,KAAK,IAAI,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAuB,EAAE,OAAO,GAAG,UAAU;IAC/E,IAAI,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ,IAAI,GAAG,CAAC,cAAc,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC1F,IAAI,OAAO,GAAG,CAAC,aAAa,KAAK,QAAQ,IAAI,GAAG,CAAC,aAAa,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACxF,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,OAAO;QACL,OAAO;QACP,OAAO,EAAE,GAAG,CAAC,cAAc;QAC3B,QAAQ,EAAE,GAAG,CAAC,gBAAgB,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;QACxD,SAAS,EAAE,GAAG,CAAC,aAAa;QAC5B,IAAI;QACJ,GAAG,CAAC,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtF,CAAC;AACJ,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,OAAe;IAC/D,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,sBAAsB,CAAC,KAAa,EAAE,KAAa,EAAE,IAAY;IAC/E,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AACxF,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,YAAoB;IACrE,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5E,CAAC"}
|
|
1
|
+
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/channels/dingtalk/message.ts"],"names":[],"mappings":"AAyBA,oEAAoE;AACpE,MAAM,CAAC,MAAM,mBAAmB,GAAG,2BAA2B,CAAC;AAC/D,6CAA6C;AAC7C,MAAM,CAAC,MAAM,iBAAiB,GAAG,6BAA6B,CAAC;AAC/D,wDAAwD;AACxD,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAC;AAE9C,iFAAiF;AACjF,MAAM,UAAU,aAAa,CAAC,GAAuB;IACnD,OAAO,GAAG,CAAC,UAAU,KAAK,IAAI,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAuB,EAAE,OAAO,GAAG,UAAU;IAC/E,IAAI,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ,IAAI,GAAG,CAAC,cAAc,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC1F,IAAI,OAAO,GAAG,CAAC,aAAa,KAAK,QAAQ,IAAI,GAAG,CAAC,aAAa,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACxF,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,6EAA6E;IAC7E,yEAAyE;IACzE,6EAA6E;IAC7E,4EAA4E;IAC5E,uCAAuC;IACvC,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACzC,OAAO;QACL,OAAO;QACP,OAAO,EAAE,GAAG,CAAC,cAAc;QAC3B,QAAQ,EAAE,GAAG,CAAC,gBAAgB,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;QACxD,SAAS,EAAE,GAAG,CAAC,aAAa;QAC5B,IAAI;QACJ,GAAG,CAAC,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtF,CAAC;AACJ,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,OAAe;IAC/D,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,sBAAsB,CAAC,KAAa,EAAE,KAAa,EAAE,IAAY;IAC/E,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AACxF,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,YAAoB;IACrE,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5E,CAAC"}
|
|
@@ -27,18 +27,6 @@ export declare function buildSelectMenu(options: readonly ChoiceOption[], placeh
|
|
|
27
27
|
* @param defaultColumns - Default number of columns per row (default: 2)
|
|
28
28
|
*/
|
|
29
29
|
export declare function buildChoiceElements(prompt: ChoicePrompt, defaultColumns?: number): unknown[];
|
|
30
|
-
/**
|
|
31
|
-
* Encode a chatKey with an optional thread id. With `threadIsolation` on, a
|
|
32
|
-
* group message inside a thread gets `chatId:thread=<rootId>` as its chatKey,
|
|
33
|
-
* so each thread binds its own DSH session while outbound sends still target
|
|
34
|
-
* the base chat id (replies land in the thread via replyRef).
|
|
35
|
-
*/
|
|
36
|
-
export declare function encodeChatKey(chatId: string, threadId?: string): string;
|
|
37
|
-
/** Decode a possibly thread-scoped chatKey back to its base chat id. */
|
|
38
|
-
export declare function decodeChatKey(chatKey: string): {
|
|
39
|
-
chatId: string;
|
|
40
|
-
threadId?: string;
|
|
41
|
-
};
|
|
42
30
|
/** Classify a local file name for the Feishu upload API (image vs stream file). */
|
|
43
31
|
export declare function classifyFeishuFile(filename: string): "image" | "file";
|
|
44
32
|
/** Strip path separators / control chars from a downloaded file's name. */
|
|
@@ -66,6 +54,12 @@ export interface FeishuConfig {
|
|
|
66
54
|
dmMode?: "open" | "allowlist" | "pair" | "disabled";
|
|
67
55
|
/** Bind one DSH session per group thread instead of one per chat (default false). */
|
|
68
56
|
threadIsolation?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Allow the interactive one-click onboarding flow when no credentials are
|
|
59
|
+
* configured (default true). Set `false` to never start it — the adapter then
|
|
60
|
+
* just warns, which is what a supervisor-managed deployment wants.
|
|
61
|
+
*/
|
|
62
|
+
onboarding?: boolean;
|
|
69
63
|
/** User-facing message language: `zh` (default) or `en`. */
|
|
70
64
|
language?: Language;
|
|
71
65
|
}
|