dsh-connect 0.7.2 → 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 +196 -43
- package/README.zh.md +171 -42
- package/client/client.js +817 -0
- package/client/client.js.map +7 -0
- package/client/locale.mjs +227 -0
- package/client/panel-state.mjs +54 -0
- package/client/settings-client.mjs +389 -0
- 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/examples/minimal.config.json +16 -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/adapter.d.ts +59 -0
- package/lib/channels/dingtalk/adapter.d.ts.map +1 -0
- package/lib/channels/dingtalk/adapter.js +123 -0
- package/lib/channels/dingtalk/adapter.js.map +1 -0
- package/lib/channels/dingtalk/i18n.d.ts +14 -0
- package/lib/channels/dingtalk/i18n.d.ts.map +1 -0
- package/lib/channels/dingtalk/i18n.js +16 -0
- package/lib/channels/dingtalk/i18n.js.map +1 -0
- package/lib/channels/dingtalk/index.d.ts +127 -0
- package/lib/channels/dingtalk/index.d.ts.map +1 -0
- package/lib/channels/dingtalk/index.js +144 -0
- package/lib/channels/dingtalk/index.js.map +1 -0
- package/lib/channels/dingtalk/message.d.ts +49 -0
- package/lib/channels/dingtalk/message.d.ts.map +1 -0
- package/lib/channels/dingtalk/message.js +50 -0
- package/lib/channels/dingtalk/message.js.map +1 -0
- package/lib/channels/dingtalk/stomp.d.ts +36 -0
- package/lib/channels/dingtalk/stomp.d.ts.map +1 -0
- package/lib/channels/dingtalk/stomp.js +107 -0
- package/lib/channels/dingtalk/stomp.js.map +1 -0
- package/lib/channels/dingtalk/stream.d.ts +53 -0
- package/lib/channels/dingtalk/stream.d.ts.map +1 -0
- package/lib/channels/dingtalk/stream.js +199 -0
- package/lib/channels/dingtalk/stream.js.map +1 -0
- package/lib/channels/dingtalk/webhook.d.ts +84 -0
- package/lib/channels/dingtalk/webhook.d.ts.map +1 -0
- package/lib/channels/dingtalk/webhook.js +143 -0
- package/lib/channels/dingtalk/webhook.js.map +1 -0
- package/lib/channels/feishu/adapter.d.ts +133 -0
- package/lib/channels/feishu/adapter.d.ts.map +1 -0
- package/lib/channels/feishu/adapter.js +662 -0
- package/lib/channels/feishu/adapter.js.map +1 -0
- package/lib/channels/feishu/i18n.d.ts +30 -0
- package/lib/channels/feishu/i18n.d.ts.map +1 -0
- package/lib/channels/feishu/i18n.js +42 -0
- package/lib/channels/feishu/i18n.js.map +1 -0
- package/lib/channels/feishu/index.d.ts +82 -0
- package/lib/channels/feishu/index.d.ts.map +1 -0
- package/lib/channels/feishu/index.js +103 -0
- package/lib/channels/feishu/index.js.map +1 -0
- package/lib/channels/feishu/onboard.d.ts +16 -0
- package/lib/channels/feishu/onboard.d.ts.map +1 -0
- package/lib/channels/feishu/onboard.js +86 -0
- package/lib/channels/feishu/onboard.js.map +1 -0
- package/lib/channels/telegram/adapter.d.ts +70 -0
- package/lib/channels/telegram/adapter.d.ts.map +1 -0
- package/lib/channels/telegram/adapter.js +460 -0
- package/lib/channels/telegram/adapter.js.map +1 -0
- package/lib/channels/telegram/client.d.ts +115 -0
- package/lib/channels/telegram/client.d.ts.map +1 -0
- package/lib/channels/telegram/client.js +198 -0
- package/lib/channels/telegram/client.js.map +1 -0
- package/lib/channels/telegram/i18n.d.ts +14 -0
- package/lib/channels/telegram/i18n.d.ts.map +1 -0
- package/lib/channels/telegram/i18n.js +18 -0
- package/lib/channels/telegram/i18n.js.map +1 -0
- package/lib/channels/telegram/index.d.ts +46 -0
- package/lib/channels/telegram/index.d.ts.map +1 -0
- package/lib/channels/telegram/index.js +54 -0
- package/lib/channels/telegram/index.js.map +1 -0
- package/lib/channels/web/adapter.d.ts +103 -0
- package/lib/channels/web/adapter.d.ts.map +1 -0
- package/lib/channels/web/adapter.js +161 -0
- package/lib/channels/web/adapter.js.map +1 -0
- package/lib/channels/web/index.d.ts +47 -0
- package/lib/channels/web/index.d.ts.map +1 -0
- package/lib/channels/web/index.js +59 -0
- package/lib/channels/web/index.js.map +1 -0
- 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 +78 -11
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +312 -9
- package/lib/index.js.map +1 -1
- package/lib/runner.d.ts +55 -2
- 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 +17 -1
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +47 -3
- 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 +62 -0
- package/lib/settings/channels.d.ts.map +1 -0
- package/lib/settings/channels.js +132 -0
- package/lib/settings/channels.js.map +1 -0
- package/lib/settings/credential-store.d.ts +85 -0
- package/lib/settings/credential-store.d.ts.map +1 -0
- package/lib/settings/credential-store.js +142 -0
- package/lib/settings/credential-store.js.map +1 -0
- package/lib/settings/index.d.ts +14 -0
- package/lib/settings/index.d.ts.map +1 -0
- package/lib/settings/index.js +14 -0
- package/lib/settings/index.js.map +1 -0
- 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/rpc-client.d.ts +36 -0
- package/lib/settings/rpc-client.d.ts.map +1 -0
- package/lib/settings/rpc-client.js +45 -0
- package/lib/settings/rpc-client.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 +124 -0
- package/lib/settings/settings-model.d.ts.map +1 -0
- package/lib/settings/settings-model.js +118 -0
- package/lib/settings/settings-model.js.map +1 -0
- package/lib/settings/settings-rpc.d.ts +130 -0
- package/lib/settings/settings-rpc.d.ts.map +1 -0
- package/lib/settings/settings-rpc.js +233 -0
- package/lib/settings/settings-rpc.js.map +1 -0
- package/lib/settings/settings-service.d.ts +35 -0
- package/lib/settings/settings-service.d.ts.map +1 -0
- package/lib/settings/settings-service.js +171 -0
- package/lib/settings/settings-service.js.map +1 -0
- 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 +56 -12
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-side credential store for dsh-connect channels. Adapts the DSH
|
|
3
|
+
* `credentials` provider (`resolve/describe/set/unset`, env-style refs) into a
|
|
4
|
+
* per-channel interface, so secrets live in the DSH credential store instead of
|
|
5
|
+
* the plugin config (mirroring dsh-im's `credential-store.mjs`). The web
|
|
6
|
+
* settings pane reports `configured` booleans and may echo store-backed secret
|
|
7
|
+
* values (e.g. an appId) so an upgraded user can confirm them, but secrets
|
|
8
|
+
* never persist to the settings state file — the credential store is the only
|
|
9
|
+
* place secret values are held.
|
|
10
|
+
*
|
|
11
|
+
* @module dsh-connect/settings/credential-store
|
|
12
|
+
*/
|
|
13
|
+
import { CHANNELS } from "./channels.js";
|
|
14
|
+
/** Unwrap either resolution shape to a non-empty string, else undefined. */
|
|
15
|
+
function resolveValue(resolved) {
|
|
16
|
+
const value = typeof resolved === "string" ? resolved : resolved?.value;
|
|
17
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
18
|
+
}
|
|
19
|
+
/** Maps each channel's secret *config key* to its credential ref, so the
|
|
20
|
+
* settings service and activation can enrich a channel config from the store.
|
|
21
|
+
*
|
|
22
|
+
* This is the **authoritative list of refs a channel owns**: every ref that
|
|
23
|
+
* `save` can write appears here. A ref reachable only through
|
|
24
|
+
* {@link CREDENTIAL_GROUPS} would be writable-but-unclearable — `save` and
|
|
25
|
+
* `clear` both derive from this table for exactly that reason. */
|
|
26
|
+
export const CHANNEL_SECRET_KEYS = Object.freeze({
|
|
27
|
+
feishu: { appId: "DSH_CONNECT_FEISHU_APP_ID", appSecret: "DSH_CONNECT_FEISHU_APP_SECRET" },
|
|
28
|
+
telegram: { botToken: "DSH_CONNECT_TELEGRAM_BOT_TOKEN" },
|
|
29
|
+
dingtalk: {
|
|
30
|
+
webhookUrl: "DSH_CONNECT_DINGTALK_WEBHOOK_URL",
|
|
31
|
+
secret: "DSH_CONNECT_DINGTALK_SECRET",
|
|
32
|
+
clientId: "DSH_CONNECT_DINGTALK_CLIENT_ID",
|
|
33
|
+
clientSecret: "DSH_CONNECT_DINGTALK_CLIENT_SECRET",
|
|
34
|
+
},
|
|
35
|
+
web: {},
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Credential sets that satisfy a channel, as groups-of-refs.
|
|
39
|
+
*
|
|
40
|
+
* Within a group every ref must be configured; between groups any one group
|
|
41
|
+
* being complete is enough. The grouping exists for DingTalk, which has two
|
|
42
|
+
* mutually exclusive transports — webhook push (url + signing secret) and
|
|
43
|
+
* stream mode (client id + secret). A flat all-of list would report a
|
|
44
|
+
* webhook-only user as "未配置凭据" because their stream refs are empty.
|
|
45
|
+
*
|
|
46
|
+
* An empty group list means the channel needs no credentials at all, so it is
|
|
47
|
+
* always satisfied — `web` mirrors the DSH Web UI in-process and holds no
|
|
48
|
+
* secret. Reporting that as unconfigured was pure noise in the pane's badge.
|
|
49
|
+
*/
|
|
50
|
+
export const CREDENTIAL_GROUPS = Object.freeze({
|
|
51
|
+
feishu: [["DSH_CONNECT_FEISHU_APP_ID", "DSH_CONNECT_FEISHU_APP_SECRET"]],
|
|
52
|
+
telegram: [["DSH_CONNECT_TELEGRAM_BOT_TOKEN"]],
|
|
53
|
+
dingtalk: [
|
|
54
|
+
["DSH_CONNECT_DINGTALK_WEBHOOK_URL", "DSH_CONNECT_DINGTALK_SECRET"],
|
|
55
|
+
["DSH_CONNECT_DINGTALK_CLIENT_ID", "DSH_CONNECT_DINGTALK_CLIENT_SECRET"],
|
|
56
|
+
],
|
|
57
|
+
web: [],
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* Flat, de-duplicated view of every ref named by {@link CREDENTIAL_GROUPS},
|
|
61
|
+
* in declaration order. Kept because existing callers and tests import it;
|
|
62
|
+
* new code should prefer `CHANNEL_SECRET_KEYS` for the refs a channel owns.
|
|
63
|
+
*/
|
|
64
|
+
export const CREDENTIAL_REFS = Object.freeze(Object.fromEntries(CHANNELS.map((channel) => [channel, groupRefs(channel)])));
|
|
65
|
+
/** De-duplicated union of every ref named by a channel's groups. */
|
|
66
|
+
function groupRefs(channel) {
|
|
67
|
+
const seen = new Set();
|
|
68
|
+
for (const group of CREDENTIAL_GROUPS[channel] ?? []) {
|
|
69
|
+
for (const ref of group)
|
|
70
|
+
seen.add(ref);
|
|
71
|
+
}
|
|
72
|
+
return Object.freeze([...seen]);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Every ref a channel may have written, i.e. the union of the refs named by its
|
|
76
|
+
* groups and its config-key table. `clear` uses this so it cannot leave behind
|
|
77
|
+
* a ref that `save` was able to write.
|
|
78
|
+
*/
|
|
79
|
+
function ownedRefs(channel) {
|
|
80
|
+
const seen = new Set(groupRefs(channel));
|
|
81
|
+
for (const ref of Object.values(CHANNEL_SECRET_KEYS[channel] ?? {}))
|
|
82
|
+
seen.add(ref);
|
|
83
|
+
return [...seen];
|
|
84
|
+
}
|
|
85
|
+
function assertProvider(provider) {
|
|
86
|
+
for (const method of ["resolve", "describe", "set", "unset"]) {
|
|
87
|
+
if (typeof provider[method] !== "function") {
|
|
88
|
+
throw new TypeError(`A DSH credential provider with ${method}() is required`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** Build a per-channel credential store over a DSH `credentials` provider. */
|
|
93
|
+
export function createCredentialStore(provider) {
|
|
94
|
+
assertProvider(provider);
|
|
95
|
+
return Object.freeze({
|
|
96
|
+
async configured(channel) {
|
|
97
|
+
const groups = CREDENTIAL_GROUPS[channel] ?? [];
|
|
98
|
+
// No credential requirement at all (e.g. the in-process Web mirror):
|
|
99
|
+
// nothing to be missing, so the channel counts as configured.
|
|
100
|
+
if (groups.length === 0)
|
|
101
|
+
return true;
|
|
102
|
+
for (const group of groups) {
|
|
103
|
+
const described = await Promise.all(group.map((ref) => provider.describe(ref)));
|
|
104
|
+
if (described.every((d) => d.configured === true))
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
},
|
|
109
|
+
async save(channel, values) {
|
|
110
|
+
// Iterate the config-key table, not the group union: it is the complete
|
|
111
|
+
// list of refs this channel owns. Deriving the write set from the groups
|
|
112
|
+
// silently dropped DingTalk's stream credentials, because only the
|
|
113
|
+
// webhook group was represented there — the pane reported `ok: true`
|
|
114
|
+
// while the clientId/clientSecret the user typed were never stored.
|
|
115
|
+
for (const ref of Object.values(CHANNEL_SECRET_KEYS[channel] ?? {})) {
|
|
116
|
+
const value = values[ref];
|
|
117
|
+
if (value !== undefined)
|
|
118
|
+
await provider.set(ref, value);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
async get(channel) {
|
|
122
|
+
const map = CHANNEL_SECRET_KEYS[channel] ?? {};
|
|
123
|
+
const entries = await Promise.all(Object.entries(map).map(async ([configKey, ref]) => {
|
|
124
|
+
const value = resolveValue(await provider.resolve(ref));
|
|
125
|
+
return [configKey, value];
|
|
126
|
+
}));
|
|
127
|
+
const out = {};
|
|
128
|
+
for (const [configKey, value] of entries) {
|
|
129
|
+
if (value !== undefined)
|
|
130
|
+
out[configKey] = value;
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
},
|
|
134
|
+
async clear(channel) {
|
|
135
|
+
const outcomes = await Promise.allSettled(ownedRefs(channel).map((ref) => provider.unset(ref)));
|
|
136
|
+
if (outcomes.some((o) => o.status === "rejected")) {
|
|
137
|
+
throw new Error(`Unable to clear ${channel} credentials.`);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=credential-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../src/settings/credential-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel for the dsh-connect web-settings stack: channel orchestration, the DSH
|
|
3
|
+
* credential-store adapter, the host RPC facade, the persistence service, and
|
|
4
|
+
* the client-side model/RPC helpers. Imported by the merged entry; also the
|
|
5
|
+
* `dsh-connect/settings` subpath export.
|
|
6
|
+
* @module dsh-connect/settings
|
|
7
|
+
*/
|
|
8
|
+
export * from "./channels.js";
|
|
9
|
+
export * from "./credential-store.js";
|
|
10
|
+
export * from "./settings-rpc.js";
|
|
11
|
+
export * from "./settings-service.js";
|
|
12
|
+
export * from "./settings-model.js";
|
|
13
|
+
export * from "./rpc-client.js";
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/settings/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel for the dsh-connect web-settings stack: channel orchestration, the DSH
|
|
3
|
+
* credential-store adapter, the host RPC facade, the persistence service, and
|
|
4
|
+
* the client-side model/RPC helpers. Imported by the merged entry; also the
|
|
5
|
+
* `dsh-connect/settings` subpath export.
|
|
6
|
+
* @module dsh-connect/settings
|
|
7
|
+
*/
|
|
8
|
+
export * from "./channels.js";
|
|
9
|
+
export * from "./credential-store.js";
|
|
10
|
+
export * from "./settings-rpc.js";
|
|
11
|
+
export * from "./settings-service.js";
|
|
12
|
+
export * from "./settings-model.js";
|
|
13
|
+
export * from "./rpc-client.js";
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/settings/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `dsh-connect` user-settings namespace.
|
|
3
|
+
*
|
|
4
|
+
* DSH ships a first-party user-settings seam (`ctx.settings`, backed by
|
|
5
|
+
* `$DSH_HOME/settings.yaml` via `@deepseek-ai/dsh-settings-file`, hot-reloaded,
|
|
6
|
+
* atomic, file-locked, comment-preserving). Registering a namespace is how a
|
|
7
|
+
* plugin makes its configuration user-editable *and effective*: the official
|
|
8
|
+
* Plugins page renders the fields from the schema, writes go through the
|
|
9
|
+
* provider, and `scope.watch()` tells the plugin to re-read.
|
|
10
|
+
*
|
|
11
|
+
* Two properties of that seam shape this module:
|
|
12
|
+
*
|
|
13
|
+
* - **`installSection` is the consumer entry point.** It registers the plugin's
|
|
14
|
+
* own composition entry as the schema's *base* layer while the settings
|
|
15
|
+
* service is present, and falls back to that entry if the service detaches.
|
|
16
|
+
* Bare `register` would make `$DSH_HOME/settings.yaml` the only source and
|
|
17
|
+
* silently drop a YAML-configured profile.
|
|
18
|
+
* - **The schema is applied to `mergeLayers(base, userSection)` at registration
|
|
19
|
+
* time**, so a stored section that fails validation throws out of
|
|
20
|
+
* `installSection`. Every install here is therefore guarded: a hand-edited
|
|
21
|
+
* `settings.yaml` with a typo must degrade to the plugin config, not abort
|
|
22
|
+
* the plugin's `apply`.
|
|
23
|
+
*
|
|
24
|
+
* **Secrets are deliberately not part of this schema.** They live in the DSH
|
|
25
|
+
* credential store (`ctx.credentials`), which is where the onboarding flow and
|
|
26
|
+
* the `FEISHU_*`-style env layering already put them; `settings.yaml` is a
|
|
27
|
+
* plain document users are invited to paste into bug reports. `sectionOf()`
|
|
28
|
+
* projects secret keys *out* of the base for the same reason — schemastery
|
|
29
|
+
* preserves undeclared keys verbatim, so anything left in the base rides out
|
|
30
|
+
* through `describe()` and the settings RPC. The same projection guards the
|
|
31
|
+
* write path (`LiveConnectSection.write`), which is the mirror hazard: an
|
|
32
|
+
* undeclared key in a *submitted* section would be preserved into the document.
|
|
33
|
+
*
|
|
34
|
+
* `installSection` returns nothing, so the write handle it hands back is built
|
|
35
|
+
* here: `setSource` already wires a thunk onto `scope.get()`, which reads the
|
|
36
|
+
* registration's resolved value at call time — live in both directions.
|
|
37
|
+
*
|
|
38
|
+
* @module dsh-connect/settings/namespace
|
|
39
|
+
*/
|
|
40
|
+
import z from "@deepseek-ai/schemastery";
|
|
41
|
+
import { type ChannelName, type ChannelsConfig, type LoggerLike } from "./channels.js";
|
|
42
|
+
/** The settings namespace this plugin owns. */
|
|
43
|
+
export declare const CONNECT_SETTINGS_NS = "dsh-connect";
|
|
44
|
+
/** Channel-agnostic defaults section of the namespace. */
|
|
45
|
+
export type ConnectSectionDefaults = Record<string, unknown> & {
|
|
46
|
+
language?: string;
|
|
47
|
+
notifyLevel?: string;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* The resolved namespace value. Every field is optional: a user who only ever
|
|
51
|
+
* edits `channels` leaves the rest absent, and each adapter applies its own
|
|
52
|
+
* default for anything missing.
|
|
53
|
+
*/
|
|
54
|
+
export interface ConnectSection {
|
|
55
|
+
channels?: ChannelName[];
|
|
56
|
+
channelDefaults?: ConnectSectionDefaults;
|
|
57
|
+
feishu?: Record<string, unknown>;
|
|
58
|
+
telegram?: Record<string, unknown>;
|
|
59
|
+
dingtalk?: Record<string, unknown>;
|
|
60
|
+
web?: Record<string, unknown>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The namespace schema, derived from the same field tables the settings pane
|
|
64
|
+
* renders. Deriving rather than restating them is the point: a field added to
|
|
65
|
+
* `CHANNEL_CONFIG_FIELDS` becomes user-editable and hot-appliable in one edit,
|
|
66
|
+
* and a field that the pane exposes can never be silently unrepresentable in
|
|
67
|
+
* `settings.yaml`.
|
|
68
|
+
*
|
|
69
|
+
* `required(false)` on every field means an absent key stays absent — it does
|
|
70
|
+
* *not* materialize a default. That matters for `dmMode`, whose first option is
|
|
71
|
+
* the permissive one: a schema-provided default would silently open DMs for
|
|
72
|
+
* every user who never touched the field.
|
|
73
|
+
*/
|
|
74
|
+
export declare const ConnectSectionSchema: z<Schemastery.ObjectS<{
|
|
75
|
+
channels: z<ChannelName[], ChannelName[]>;
|
|
76
|
+
channelDefaults: z<any, any>;
|
|
77
|
+
feishu: z<any, any>;
|
|
78
|
+
telegram: z<any, any>;
|
|
79
|
+
dingtalk: z<any, any>;
|
|
80
|
+
web: z<any, any>;
|
|
81
|
+
}>, Schemastery.ObjectT<{
|
|
82
|
+
channels: z<ChannelName[], ChannelName[]>;
|
|
83
|
+
channelDefaults: z<any, any>;
|
|
84
|
+
feishu: z<any, any>;
|
|
85
|
+
telegram: z<any, any>;
|
|
86
|
+
dingtalk: z<any, any>;
|
|
87
|
+
web: z<any, any>;
|
|
88
|
+
}>>;
|
|
89
|
+
/**
|
|
90
|
+
* Project a channel config onto the namespace's schema: only declared,
|
|
91
|
+
* non-secret keys, with `channels` always present.
|
|
92
|
+
*
|
|
93
|
+
* `channels` is emitted unconditionally because an absent array resolves to
|
|
94
|
+
* `[]` (schemastery's array default), which would read as "activate nothing".
|
|
95
|
+
*
|
|
96
|
+
* Secret keys are dropped here, not by the schema: `redactSecrets` only strips
|
|
97
|
+
* nodes declared with `role("secret")`, and we declare none — so the projection
|
|
98
|
+
* is what keeps an `appSecret` from a legacy profile out of the settings
|
|
99
|
+
* document and off the RPC.
|
|
100
|
+
*
|
|
101
|
+
* The argument is typed `unknown` because this doubles as the *write* guard:
|
|
102
|
+
* a section submitted through the settings RPC is untrusted JSON, and it must
|
|
103
|
+
* go through the same projection before it can reach the document.
|
|
104
|
+
*/
|
|
105
|
+
export declare function sectionOf(config: unknown): ConnectSection;
|
|
106
|
+
/**
|
|
107
|
+
* The slice of the settings service this module calls. Declared structurally so
|
|
108
|
+
* the plugin keeps no dependency on `@deepseek-ai/dsh-settings` — the service is
|
|
109
|
+
* a `dsh-base` row, present whenever dsh-connect loads, and a missing method
|
|
110
|
+
* degrades to "no settings support" rather than a crash.
|
|
111
|
+
*/
|
|
112
|
+
export interface SettingsProviderLike {
|
|
113
|
+
installSection?(owner: unknown, ns: string, schema: unknown, entry: unknown, hooks: {
|
|
114
|
+
setSource: (source: () => unknown) => void;
|
|
115
|
+
onChange: () => void;
|
|
116
|
+
}): void;
|
|
117
|
+
/** Resolved value of a registered namespace, `undefined` while unregistered. */
|
|
118
|
+
get?(ns: string): unknown;
|
|
119
|
+
/**
|
|
120
|
+
* Replace a registered namespace's *user* section wholesale (validated by the
|
|
121
|
+
* provider, persisted by whichever file provider is wired up). Resolves after
|
|
122
|
+
* the new value is committed, so a read straight after it is fresh.
|
|
123
|
+
*
|
|
124
|
+
* Replace rather than merge, because the settings pane always submits its
|
|
125
|
+
* complete visible config: a merge would make a cleared field un-clearable
|
|
126
|
+
* (the stale value stays in the user layer and reappears on the next read).
|
|
127
|
+
* The declared-key set is identical for both writers of this namespace (this
|
|
128
|
+
* plugin's pane and the host's own Plugins page, which renders the same
|
|
129
|
+
* schema), so a replace cannot drop anything either surface can produce.
|
|
130
|
+
*/
|
|
131
|
+
replace?(ns: string, section: unknown, expectedRevision?: number): Promise<unknown>;
|
|
132
|
+
}
|
|
133
|
+
/** A live handle onto the installed namespace: read the effective section, write a new one. */
|
|
134
|
+
export interface LiveConnectSection {
|
|
135
|
+
/** The section in force right now (base layered under the user's section). */
|
|
136
|
+
read(): ConnectSection;
|
|
137
|
+
/**
|
|
138
|
+
* Replace the user's section with the declared-key projection of `config`.
|
|
139
|
+
* Rejects if the provider's schema refuses the result — the caller is
|
|
140
|
+
* expected to surface that rather than swallow it.
|
|
141
|
+
*/
|
|
142
|
+
write(config: unknown): Promise<void>;
|
|
143
|
+
}
|
|
144
|
+
/** Outcome of wiring the namespace. */
|
|
145
|
+
export interface InstallConnectSectionResult {
|
|
146
|
+
/** True when this fiber owns the namespace and receives live updates. */
|
|
147
|
+
live: boolean;
|
|
148
|
+
/** The section in force at install time (resolved, or the entry fallback). */
|
|
149
|
+
section: ConnectSection;
|
|
150
|
+
/**
|
|
151
|
+
* Read/write onto the registration. Present only when this fiber owns a live
|
|
152
|
+
* namespace *and* the provider exposes a write method; otherwise the caller
|
|
153
|
+
* keeps its own fallback (the plugin config, or the legacy state file).
|
|
154
|
+
*/
|
|
155
|
+
handle?: LiveConnectSection;
|
|
156
|
+
}
|
|
157
|
+
export interface InstallConnectSectionOptions<Ctx extends LoggerLike> {
|
|
158
|
+
/** Context whose unload releases the registration. */
|
|
159
|
+
owner: Ctx;
|
|
160
|
+
settings: SettingsProviderLike | undefined;
|
|
161
|
+
/** The plugin's own config: the schema's `base` layer and the fallback. */
|
|
162
|
+
entry: ChannelsConfig | null | undefined;
|
|
163
|
+
/** Called with the in-force section now and on every change. */
|
|
164
|
+
onChange: (section: ConnectSection) => void;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Register `dsh-connect` and report the section in force.
|
|
168
|
+
*
|
|
169
|
+
* Never throws: a missing settings service, an already-claimed namespace, or a
|
|
170
|
+
* `settings.yaml` section that fails validation all fall back to the plugin's
|
|
171
|
+
* own config with a warning. A user's typo in a settings document must not be
|
|
172
|
+
* able to stop the bridge from starting.
|
|
173
|
+
*/
|
|
174
|
+
export declare function installConnectSection<Ctx extends LoggerLike>(options: InstallConnectSectionOptions<Ctx>): InstallConnectSectionResult;
|
|
175
|
+
//# sourceMappingURL=namespace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namespace.d.ts","sourceRoot":"","sources":["../../src/settings/namespace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,CAAC,MAAM,0BAA0B,CAAC;AACzC,OAAO,EAAY,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAOjG,+CAA+C;AAC/C,eAAO,MAAM,mBAAmB,gBAAgB,CAAC;AAEjD,0DAA0D;AAC1D,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3G;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAyBD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;GAO/B,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CAoBzD;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,cAAc,CAAC,CACb,KAAK,EAAE,OAAO,EACd,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,OAAO,EACd,KAAK,EAAE;QAAE,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;QAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;KAAE,GAC1E,IAAI,CAAC;IACR,gFAAgF;IAChF,GAAG,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACrF;AAED,+FAA+F;AAC/F,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,IAAI,IAAI,cAAc,CAAC;IACvB;;;;OAIG;IACH,KAAK,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,uCAAuC;AACvC,MAAM,WAAW,2BAA2B;IAC1C,yEAAyE;IACzE,IAAI,EAAE,OAAO,CAAC;IACd,8EAA8E;IAC9E,OAAO,EAAE,cAAc,CAAC;IACxB;;;;OAIG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAED,MAAM,WAAW,4BAA4B,CAAC,GAAG,SAAS,UAAU;IAClE,sDAAsD;IACtD,KAAK,EAAE,GAAG,CAAC;IACX,QAAQ,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC3C,2EAA2E;IAC3E,KAAK,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,gEAAgE;IAChE,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CAC7C;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,SAAS,UAAU,EAC1D,OAAO,EAAE,4BAA4B,CAAC,GAAG,CAAC,GACzC,2BAA2B,CAmE7B"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `dsh-connect` user-settings namespace.
|
|
3
|
+
*
|
|
4
|
+
* DSH ships a first-party user-settings seam (`ctx.settings`, backed by
|
|
5
|
+
* `$DSH_HOME/settings.yaml` via `@deepseek-ai/dsh-settings-file`, hot-reloaded,
|
|
6
|
+
* atomic, file-locked, comment-preserving). Registering a namespace is how a
|
|
7
|
+
* plugin makes its configuration user-editable *and effective*: the official
|
|
8
|
+
* Plugins page renders the fields from the schema, writes go through the
|
|
9
|
+
* provider, and `scope.watch()` tells the plugin to re-read.
|
|
10
|
+
*
|
|
11
|
+
* Two properties of that seam shape this module:
|
|
12
|
+
*
|
|
13
|
+
* - **`installSection` is the consumer entry point.** It registers the plugin's
|
|
14
|
+
* own composition entry as the schema's *base* layer while the settings
|
|
15
|
+
* service is present, and falls back to that entry if the service detaches.
|
|
16
|
+
* Bare `register` would make `$DSH_HOME/settings.yaml` the only source and
|
|
17
|
+
* silently drop a YAML-configured profile.
|
|
18
|
+
* - **The schema is applied to `mergeLayers(base, userSection)` at registration
|
|
19
|
+
* time**, so a stored section that fails validation throws out of
|
|
20
|
+
* `installSection`. Every install here is therefore guarded: a hand-edited
|
|
21
|
+
* `settings.yaml` with a typo must degrade to the plugin config, not abort
|
|
22
|
+
* the plugin's `apply`.
|
|
23
|
+
*
|
|
24
|
+
* **Secrets are deliberately not part of this schema.** They live in the DSH
|
|
25
|
+
* credential store (`ctx.credentials`), which is where the onboarding flow and
|
|
26
|
+
* the `FEISHU_*`-style env layering already put them; `settings.yaml` is a
|
|
27
|
+
* plain document users are invited to paste into bug reports. `sectionOf()`
|
|
28
|
+
* projects secret keys *out* of the base for the same reason — schemastery
|
|
29
|
+
* preserves undeclared keys verbatim, so anything left in the base rides out
|
|
30
|
+
* through `describe()` and the settings RPC. The same projection guards the
|
|
31
|
+
* write path (`LiveConnectSection.write`), which is the mirror hazard: an
|
|
32
|
+
* undeclared key in a *submitted* section would be preserved into the document.
|
|
33
|
+
*
|
|
34
|
+
* `installSection` returns nothing, so the write handle it hands back is built
|
|
35
|
+
* here: `setSource` already wires a thunk onto `scope.get()`, which reads the
|
|
36
|
+
* registration's resolved value at call time — live in both directions.
|
|
37
|
+
*
|
|
38
|
+
* @module dsh-connect/settings/namespace
|
|
39
|
+
*/
|
|
40
|
+
import z from "@deepseek-ai/schemastery";
|
|
41
|
+
import { CHANNELS } from "./channels.js";
|
|
42
|
+
import { CHANNEL_CONFIG_FIELDS, CHANNEL_DEFAULT_FIELDS, } from "./settings-model.js";
|
|
43
|
+
/** The settings namespace this plugin owns. */
|
|
44
|
+
export const CONNECT_SETTINGS_NS = "dsh-connect";
|
|
45
|
+
/** schemastery schema for one non-secret config field. */
|
|
46
|
+
function fieldSchema(field) {
|
|
47
|
+
switch (field.kind) {
|
|
48
|
+
case "number":
|
|
49
|
+
return z.number().required(false);
|
|
50
|
+
case "boolean":
|
|
51
|
+
return z.boolean().required(false);
|
|
52
|
+
case "select":
|
|
53
|
+
return field.options !== undefined && field.options.length > 0
|
|
54
|
+
? z.union(field.options.map((option) => z.const(option))).required(false)
|
|
55
|
+
: z.string().required(false);
|
|
56
|
+
default:
|
|
57
|
+
return z.string().required(false);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Build an object schema from a field table (unknown keys pass through). */
|
|
61
|
+
function objectSchema(fields) {
|
|
62
|
+
return z.object(Object.fromEntries(fields.map((field) => [field.key, fieldSchema(field)])));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The namespace schema, derived from the same field tables the settings pane
|
|
66
|
+
* renders. Deriving rather than restating them is the point: a field added to
|
|
67
|
+
* `CHANNEL_CONFIG_FIELDS` becomes user-editable and hot-appliable in one edit,
|
|
68
|
+
* and a field that the pane exposes can never be silently unrepresentable in
|
|
69
|
+
* `settings.yaml`.
|
|
70
|
+
*
|
|
71
|
+
* `required(false)` on every field means an absent key stays absent — it does
|
|
72
|
+
* *not* materialize a default. That matters for `dmMode`, whose first option is
|
|
73
|
+
* the permissive one: a schema-provided default would silently open DMs for
|
|
74
|
+
* every user who never touched the field.
|
|
75
|
+
*/
|
|
76
|
+
export const ConnectSectionSchema = z.object({
|
|
77
|
+
channels: z.array(z.union(CHANNELS.map((name) => z.const(name)))).required(false),
|
|
78
|
+
channelDefaults: objectSchema(CHANNEL_DEFAULT_FIELDS).required(false),
|
|
79
|
+
feishu: objectSchema(CHANNEL_CONFIG_FIELDS.feishu).required(false),
|
|
80
|
+
telegram: objectSchema(CHANNEL_CONFIG_FIELDS.telegram).required(false),
|
|
81
|
+
dingtalk: objectSchema(CHANNEL_CONFIG_FIELDS.dingtalk).required(false),
|
|
82
|
+
web: objectSchema(CHANNEL_CONFIG_FIELDS.web).required(false),
|
|
83
|
+
});
|
|
84
|
+
/**
|
|
85
|
+
* Project a channel config onto the namespace's schema: only declared,
|
|
86
|
+
* non-secret keys, with `channels` always present.
|
|
87
|
+
*
|
|
88
|
+
* `channels` is emitted unconditionally because an absent array resolves to
|
|
89
|
+
* `[]` (schemastery's array default), which would read as "activate nothing".
|
|
90
|
+
*
|
|
91
|
+
* Secret keys are dropped here, not by the schema: `redactSecrets` only strips
|
|
92
|
+
* nodes declared with `role("secret")`, and we declare none — so the projection
|
|
93
|
+
* is what keeps an `appSecret` from a legacy profile out of the settings
|
|
94
|
+
* document and off the RPC.
|
|
95
|
+
*
|
|
96
|
+
* The argument is typed `unknown` because this doubles as the *write* guard:
|
|
97
|
+
* a section submitted through the settings RPC is untrusted JSON, and it must
|
|
98
|
+
* go through the same projection before it can reach the document.
|
|
99
|
+
*/
|
|
100
|
+
export function sectionOf(config) {
|
|
101
|
+
const source = (config !== null && typeof config === "object" ? config : {});
|
|
102
|
+
const section = { channels: (source.channels ?? CHANNELS) };
|
|
103
|
+
const defaults = {};
|
|
104
|
+
const rawDefaults = (source.channelDefaults ?? {});
|
|
105
|
+
for (const field of CHANNEL_DEFAULT_FIELDS) {
|
|
106
|
+
if (rawDefaults[field.key] !== undefined)
|
|
107
|
+
defaults[field.key] = rawDefaults[field.key];
|
|
108
|
+
}
|
|
109
|
+
if (Object.keys(defaults).length > 0)
|
|
110
|
+
section.channelDefaults = defaults;
|
|
111
|
+
for (const name of CHANNELS) {
|
|
112
|
+
const raw = (source[name] ?? {});
|
|
113
|
+
const projected = {};
|
|
114
|
+
for (const field of CHANNEL_CONFIG_FIELDS[name]) {
|
|
115
|
+
if (raw[field.key] !== undefined)
|
|
116
|
+
projected[field.key] = raw[field.key];
|
|
117
|
+
}
|
|
118
|
+
if (Object.keys(projected).length > 0)
|
|
119
|
+
section[name] = projected;
|
|
120
|
+
}
|
|
121
|
+
return section;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Register `dsh-connect` and report the section in force.
|
|
125
|
+
*
|
|
126
|
+
* Never throws: a missing settings service, an already-claimed namespace, or a
|
|
127
|
+
* `settings.yaml` section that fails validation all fall back to the plugin's
|
|
128
|
+
* own config with a warning. A user's typo in a settings document must not be
|
|
129
|
+
* able to stop the bridge from starting.
|
|
130
|
+
*/
|
|
131
|
+
export function installConnectSection(options) {
|
|
132
|
+
const { settings, entry, onChange } = options;
|
|
133
|
+
const entrySection = sectionOf(entry);
|
|
134
|
+
const warn = (message) => {
|
|
135
|
+
options.owner.logger?.warn?.(`connect: ${message}`);
|
|
136
|
+
};
|
|
137
|
+
if (settings?.installSection === undefined) {
|
|
138
|
+
// No settings service: the plugin config is the only source, as it was
|
|
139
|
+
// before this namespace existed.
|
|
140
|
+
onChange(entrySection);
|
|
141
|
+
return { live: false, section: entrySection };
|
|
142
|
+
}
|
|
143
|
+
let source = () => entrySection;
|
|
144
|
+
try {
|
|
145
|
+
settings.installSection(options.owner, CONNECT_SETTINGS_NS, ConnectSectionSchema, entrySection, {
|
|
146
|
+
setSource: (fn) => {
|
|
147
|
+
source = () => fn();
|
|
148
|
+
},
|
|
149
|
+
onChange: () => onChange(source()),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
// Two reachable causes, both handled the same way:
|
|
154
|
+
// - a stored section that fails the schema (a hand-edited settings.yaml);
|
|
155
|
+
// - the namespace is already registered by an earlier fiber. `register`
|
|
156
|
+
// is an effect on the *settings service*, which outlives a plugin
|
|
157
|
+
// reload, so a live config reload lands here.
|
|
158
|
+
// `get()` returns the previously resolved value in the second case, which
|
|
159
|
+
// keeps the user's saved settings effective — only the live watch is gone
|
|
160
|
+
// until the process restarts.
|
|
161
|
+
const resolved = readRegistered(settings);
|
|
162
|
+
if (resolved !== undefined) {
|
|
163
|
+
warn(`settings namespace "${CONNECT_SETTINGS_NS}" is already registered ` +
|
|
164
|
+
`(the plugin reloaded without a host restart); using the saved section — ` +
|
|
165
|
+
`restart dsh to re-enable live settings updates`);
|
|
166
|
+
onChange(resolved);
|
|
167
|
+
return { live: false, section: resolved };
|
|
168
|
+
}
|
|
169
|
+
warn(`settings namespace "${CONNECT_SETTINGS_NS}" unavailable (${String(error)}); ` +
|
|
170
|
+
`falling back to the plugin config`);
|
|
171
|
+
onChange(entrySection);
|
|
172
|
+
return { live: false, section: entrySection };
|
|
173
|
+
}
|
|
174
|
+
// `source` is reassigned (not rebound) by `setSource`, so a thunk closing
|
|
175
|
+
// over the variable reads whatever the provider's `scope.get()` returns now.
|
|
176
|
+
const read = () => source();
|
|
177
|
+
const replace = settings.replace?.bind(settings);
|
|
178
|
+
return {
|
|
179
|
+
live: true,
|
|
180
|
+
section: source(),
|
|
181
|
+
...(replace === undefined
|
|
182
|
+
? {}
|
|
183
|
+
: {
|
|
184
|
+
handle: {
|
|
185
|
+
read,
|
|
186
|
+
write: async (config) => {
|
|
187
|
+
await replace(CONNECT_SETTINGS_NS, sectionOf(config));
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
}),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/** Read a namespace an earlier fiber registered, if any. */
|
|
194
|
+
function readRegistered(settings) {
|
|
195
|
+
const value = settings.get?.(CONNECT_SETTINGS_NS);
|
|
196
|
+
if (value === null || typeof value !== "object")
|
|
197
|
+
return undefined;
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=namespace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../src/settings/namespace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,CAAC,MAAM,0BAA0B,CAAC;AACzC,OAAO,EAAE,QAAQ,EAA0D,MAAM,eAAe,CAAC;AACjG,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GAEvB,MAAM,qBAAqB,CAAC;AAE7B,+CAA+C;AAC/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,aAAa,CAAC;AAmBjD,0DAA0D;AAC1D,SAAS,WAAW,CAAC,KAAkB;IACrC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,QAAQ;YACX,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACpC,KAAK,SAAS;YACZ,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACrC,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;gBAC5D,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;gBACzE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACjC;YACE,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,SAAS,YAAY,CAAC,MAA8B;IAClD,OAAO,CAAC,CAAC,MAAM,CACb,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAC3E,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;IACjF,eAAe,EAAE,YAAY,CAAC,sBAAsB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;IACrE,MAAM,EAAE,YAAY,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;IAClE,QAAQ,EAAE,YAAY,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;IACtE,QAAQ,EAAE,YAAY,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;IACtE,GAAG,EAAE,YAAY,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;CAC7D,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,SAAS,CAAC,MAAe;IACvC,MAAM,MAAM,GAAG,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAA4B,CAAC;IACxG,MAAM,OAAO,GAAmB,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,QAAQ,IAAI,QAAQ,CAAkB,EAAE,CAAC;IAE7F,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,eAAe,IAAI,EAAE,CAA4B,CAAC;IAC9E,KAAK,MAAM,KAAK,IAAI,sBAAsB,EAAE,CAAC;QAC3C,IAAI,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzF,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,eAAe,GAAG,QAAkC,CAAC;IAEnG,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAA4B,CAAC;QAC5D,MAAM,SAAS,GAA4B,EAAE,CAAC;QAC9C,KAAK,MAAM,KAAK,IAAI,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;YAChD,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS;gBAAE,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1E,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;IACnE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAqED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAA0C;IAE1C,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAC9C,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,CAAC,OAAe,EAAQ,EAAE;QACrC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC;IAEF,IAAI,QAAQ,EAAE,cAAc,KAAK,SAAS,EAAE,CAAC;QAC3C,uEAAuE;QACvE,iCAAiC;QACjC,QAAQ,CAAC,YAAY,CAAC,CAAC;QACvB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IAChD,CAAC;IAED,IAAI,MAAM,GAAyB,GAAG,EAAE,CAAC,YAAY,CAAC;IACtD,IAAI,CAAC;QACH,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,YAAY,EAAE;YAC9F,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE;gBAChB,MAAM,GAAG,GAAG,EAAE,CAAC,EAAE,EAAoB,CAAC;YACxC,CAAC;YACD,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;SACnC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,mDAAmD;QACnD,4EAA4E;QAC5E,0EAA0E;QAC1E,sEAAsE;QACtE,kDAAkD;QAClD,0EAA0E;QAC1E,0EAA0E;QAC1E,8BAA8B;QAC9B,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,CACF,uBAAuB,mBAAmB,0BAA0B;gBAClE,0EAA0E;gBAC1E,gDAAgD,CACnD,CAAC;YACF,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACnB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;QAC5C,CAAC;QACD,IAAI,CACF,uBAAuB,mBAAmB,kBAAkB,MAAM,CAAC,KAAK,CAAC,KAAK;YAC5E,mCAAmC,CACtC,CAAC;QACF,QAAQ,CAAC,YAAY,CAAC,CAAC;QACvB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IAChD,CAAC;IAED,0EAA0E;IAC1E,6EAA6E;IAC7E,MAAM,IAAI,GAAG,GAAmB,EAAE,CAAC,MAAM,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjD,OAAO;QACL,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,MAAM,EAAE;QACjB,GAAG,CAAC,OAAO,KAAK,SAAS;YACvB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC;gBACE,MAAM,EAAE;oBACN,IAAI;oBACJ,KAAK,EAAE,KAAK,EAAE,MAAe,EAAiB,EAAE;wBAC9C,MAAM,OAAO,CAAC,mBAAmB,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;oBACxD,CAAC;iBACF;aACF,CAAC;KACP,CAAC;AACJ,CAAC;AAED,4DAA4D;AAC5D,SAAS,cAAc,CAAC,QAA8B;IACpD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,CAAC;IAClD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAClE,OAAO,KAAuB,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side RPC helper for the dsh-connect web settings pane.
|
|
3
|
+
*
|
|
4
|
+
* The frontend talks to the host over the `/dsh-connect` channel; the channel
|
|
5
|
+
* returns `{ ok, value }`/`{ ok:false, error }` envelopes (see `settings-rpc.js`).
|
|
6
|
+
* This helper unwraps the envelope and throws a typed error on failure, so the
|
|
7
|
+
* UI can catch it and render a message. Pure + dependency-free for easy testing.
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-connect/settings/rpc-client
|
|
10
|
+
*/
|
|
11
|
+
import type { SettingsSnapshot } from "./settings-rpc.js";
|
|
12
|
+
/** The `ctx.connection.rpc.call` signature the settings pane uses. */
|
|
13
|
+
export type RpcCall = (endpoint: string, payload?: unknown, signal?: AbortSignal) => Promise<{
|
|
14
|
+
ok: boolean;
|
|
15
|
+
value?: unknown;
|
|
16
|
+
error?: {
|
|
17
|
+
code: string;
|
|
18
|
+
message: string;
|
|
19
|
+
};
|
|
20
|
+
}>;
|
|
21
|
+
/** A typed RPC failure, surfaced to the settings UI. */
|
|
22
|
+
export declare class RpcError extends Error {
|
|
23
|
+
readonly code: string;
|
|
24
|
+
constructor(code: string, message: string);
|
|
25
|
+
}
|
|
26
|
+
/** Invoke one endpoint and unwrap the envelope (throws `RpcError` on failure). */
|
|
27
|
+
export declare function callRpc<T = unknown>(rpcCall: RpcCall, endpoint: string, payload?: unknown, signal?: AbortSignal): Promise<T>;
|
|
28
|
+
/** Load the current settings snapshot via `settings.get`. */
|
|
29
|
+
export declare function loadSettings(rpcCall: RpcCall): Promise<SettingsSnapshot>;
|
|
30
|
+
/** Persist the settings via `settings.save`. */
|
|
31
|
+
export declare function saveSettings(rpcCall: RpcCall, config: Record<string, unknown>): Promise<SettingsSnapshot>;
|
|
32
|
+
/** Persist channel secrets to the credential store via `credentials.save`. */
|
|
33
|
+
export declare function saveCredentials(rpcCall: RpcCall, channel: string, values: Record<string, string>): Promise<SettingsSnapshot>;
|
|
34
|
+
/** Ask the host for a fresh status snapshot via `settings.status`. */
|
|
35
|
+
export declare function loadStatus(rpcCall: RpcCall): Promise<SettingsSnapshot>;
|
|
36
|
+
//# sourceMappingURL=rpc-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-client.d.ts","sourceRoot":"","sources":["../../src/settings/rpc-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,sEAAsE;AACtE,MAAM,MAAM,OAAO,GAAG,CACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,OAAO,EACjB,MAAM,CAAC,EAAE,WAAW,KACjB,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC,CAAC;AAE1F,wDAAwD;AACxD,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBACV,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAED,kFAAkF;AAClF,wBAAgB,OAAO,CAAC,CAAC,GAAG,OAAO,EACjC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,OAAO,EACjB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,CAAC,CAAC,CAMZ;AAED,6DAA6D;AAC7D,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAExE;AAED,gDAAgD;AAChD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEzG;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAC7B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,gBAAgB,CAAC,CAE3B;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEtE"}
|