dsh-vpn 0.1.0 → 0.1.1

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.md CHANGED
@@ -9,11 +9,21 @@
9
9
 
10
10
  ## 使用
11
11
 
12
+ 用你启动 dsh 的同一种方式安装。profile 名就是启动 dsh 时 `--profile` 后面的名字;用 `dsh web` 启动的话就是 `web`:
13
+
12
14
  ```bash
15
+ # 用 npx 运行 dsh 的
16
+ npx @deepseek-ai/dsh plugin --profile web add dsh-vpn
17
+ # 全局安装了 dsh 的
13
18
  dsh plugin --profile web add dsh-vpn
14
19
  ```
15
20
 
16
- 打开 dsh →「插件」→ dsh-vpn:
21
+ 装好后重启 dsh,然后打开设置页:
22
+
23
+ - dsh 0.1.5:「设置」→「插件」→「插件配置」→「VPN 节点」
24
+ - dsh 0.1.7 及以后:侧边栏「插件」→ dsh-vpn
25
+
26
+ 在设置页里:
17
27
 
18
28
  1. 填写服务器 IP、SSH 端口、用户名、密码,点「保存」和「测试连接」。
19
29
  2. 勾选要安装的协议,选择证书类型(推荐「IP 证书」),保存后点「安装 / 更新」。
package/lib/client.js CHANGED
@@ -243,6 +243,8 @@ var STYLES = `
243
243
  .dshvpn-hostkey small { flex-basis: 100%; }
244
244
  .dshvpn-protocols { display: flex; flex-direction: column; gap: 6px; }
245
245
  .dshvpn-protocol { display: flex; align-items: center; gap: 8px; }
246
+ .dshvpn-checkbox { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; cursor: pointer; }
247
+ .dshvpn-checkbox input { margin: 0; }
246
248
  .dshvpn-radio { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; cursor: pointer; }
247
249
  .dshvpn-radio input { margin-top: 3px; }
248
250
  .dshvpn-radio span { display: flex; flex-direction: column; gap: 2px; }
@@ -261,8 +263,16 @@ var STYLES = `
261
263
  .dshvpn-qr { background: #fff; padding: 6px; border-radius: 6px; line-height: 0; align-self: center; }
262
264
  .dshvpn-qr svg { width: 180px; height: 180px; }
263
265
  .dshvpn-link { display: block; max-width: 100%; max-height: 3.2em; overflow: hidden; color: var(--dsw-alias-label-secondary, #666); }
266
+ .dshvpn-card { list-style: none; border-radius: 10px; border: 1px solid var(--dsw-alias-border-l2, rgba(127,127,127,.3)); }
267
+ .dshvpn-card-head { all: unset; box-sizing: border-box; width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 14px; cursor: pointer; }
268
+ .dshvpn-card-title { display: flex; flex-direction: column; gap: 2px; font-size: 13px; }
269
+ .dshvpn-card-chevron { color: var(--dsw-alias-label-tertiary, #888); }
270
+ .dshvpn-card-body { padding: 4px 14px 16px; }
264
271
  `;
265
272
 
273
+ // src/client/VpnSettingsCard.tsx
274
+ var import_react2 = require("react");
275
+
266
276
  // src/client/VpnSettingsPage.tsx
267
277
  var import_react = require("react");
268
278
  var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
@@ -994,6 +1004,14 @@ function transportsFor(id) {
994
1004
  const t = PROTOCOLS.find((p) => p.id === id)?.transport ?? "TCP";
995
1005
  return t === "TCP+UDP" ? ["tcp", "udp"] : [t.toLowerCase()];
996
1006
  }
1007
+ function Checkbox({ label, checked, disabled, onChange }) {
1008
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "dshvpn-checkbox", children: [
1009
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked, disabled, onChange: (e) => {
1010
+ onChange(e.target.checked);
1011
+ } }),
1012
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: label })
1013
+ ] });
1014
+ }
997
1015
  function QrCard({ item, t }) {
998
1016
  const [copied, setCopied] = (0, import_react.useState)(false);
999
1017
  const info = PROTOCOLS.find((p) => p.id === item.id);
@@ -1163,7 +1181,7 @@ function VpnSettingsPage({ view, t, api }) {
1163
1181
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "dshvpn-muted", children: t("protocolHint") }),
1164
1182
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dshvpn-protocols", children: PROTOCOLS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dshvpn-protocol", children: [
1165
1183
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1166
- import_dsh_client_ui_primitives.Checkbox,
1184
+ Checkbox,
1167
1185
  {
1168
1186
  label: p.name,
1169
1187
  checked: form.protocols.includes(p.id),
@@ -1221,7 +1239,7 @@ function VpnSettingsPage({ view, t, api }) {
1221
1239
  ] }),
1222
1240
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
1223
1241
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: t("deploySection") }),
1224
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Checkbox, { label: t("regenerate"), checked: regenerate, disabled, onChange: setRegenerate }),
1242
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Checkbox, { label: t("regenerate"), checked: regenerate, disabled, onChange: setRegenerate }),
1225
1243
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dshvpn-actions", children: [
1226
1244
  confirming === "regenerate" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1227
1245
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "primary", onClick: () => {
@@ -1319,6 +1337,25 @@ ${t("certExpires", { date: new Date(cert.expires ?? "").toLocaleString(), hours
1319
1337
  ] });
1320
1338
  }
1321
1339
 
1340
+ // src/client/VpnSettingsCard.tsx
1341
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1342
+ function VpnSettingsCard(props) {
1343
+ const { t } = props;
1344
+ const [open, setOpen] = (0, import_react2.useState)(false);
1345
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: "dshvpn-card", children: [
1346
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { type: "button", className: "dshvpn-card-head", "aria-expanded": open, onClick: () => {
1347
+ setOpen(!open);
1348
+ }, children: [
1349
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dshvpn-card-title", children: [
1350
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: t("title") }),
1351
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("small", { className: "dshvpn-muted", children: t("description") })
1352
+ ] }),
1353
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "aria-hidden": "true", className: "dshvpn-card-chevron", children: open ? "\u25BE" : "\u25B8" })
1354
+ ] }),
1355
+ open && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "dshvpn-card-body", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(VpnSettingsPage, { ...props, view: "page" }) })
1356
+ ] });
1357
+ }
1358
+
1322
1359
  // src/client/index.ts
1323
1360
  var PACKAGE_NAME = "dsh-vpn";
1324
1361
  var inject = ["slots", "locale"];
@@ -1339,6 +1376,12 @@ function apply(ctx) {
1339
1376
  locale: NS,
1340
1377
  inject: () => ({ api: vpnApi })
1341
1378
  }, VpnSettingsPage));
1379
+ ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
1380
+ name: "settings.plugin.item",
1381
+ key: PACKAGE_NAME,
1382
+ locale: NS,
1383
+ inject: () => ({ api: vpnApi })
1384
+ }, VpnSettingsCard));
1342
1385
  }
1343
1386
 
1344
1387
  return module.exports;
package/lib/index.js CHANGED
@@ -20811,6 +20811,13 @@ function apply(ctx, config) {
20811
20811
  ctx.inject(["connection"], (webCtx) => {
20812
20812
  registerApi(webCtx, service);
20813
20813
  });
20814
+ ctx.inject(["settings"], (settingsCtx) => {
20815
+ const settings = settingsCtx.settings;
20816
+ try {
20817
+ settings?.register?.("dsh-vpn", Schema.object({}), {});
20818
+ } catch {
20819
+ }
20820
+ });
20814
20821
  }
20815
20822
  export {
20816
20823
  Config,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-vpn",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "DeepSeek Harness plugin: one-click sing-box deployment to a VPS over SSH, with a settings page and QR codes",
5
5
  "keywords": [
6
6
  "dsh-plugin",