@fonlan/dsh-web-auth 0.1.7 → 0.1.8

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/cordis.patch.yml CHANGED
@@ -11,13 +11,13 @@
11
11
  # the auth gate wraps the HTTP listener after it is bound.
12
12
  #
13
13
  # The package also declares `dsh.client` (see package.json), so the web app
14
- # loads the browser half (the plugin's own Settings Card) automatically. The
15
- # card registers on the `settings.plugin.item` slot keyed by the `web-auth`
16
- # settings namespace (see src/settings.ts) — the 设置 → 插件 → 插件配置 tab
17
- # pairs the two.
14
+ # loads the browser half (the plugin's own settings page) automatically. The
15
+ # page registers on the `settings.section` slot as the 「访问认证」 entry in the
16
+ # settings sidebar and binds the `web-auth` settings namespace
17
+ # (see src/settings.ts) through the client settings scope.
18
18
  #
19
19
  # There is intentionally NO password here: passwords are maintained through
20
- # the GUI (login page first setup / settings card change), stored hashed
20
+ # the GUI (login page first setup / settings page change), stored hashed
21
21
  # under $DSH_HOME/web-auth/. Until a password is set, auth stays disabled
22
22
  # (see the README for the warning this prints at boot).
23
23
  - insert:
@@ -4,11 +4,11 @@ import type { Context } from '@deepseek-ai/cordis';
4
4
  * `connection` and `remote` are required by `settingsScope.bind` (it resolves
5
5
  * the settings transport and the forwarded-invalidation subscription through
6
6
  * `ctx.get`), so the fiber must wait for them — exactly like
7
- * dsh-client-ui-settings-plugins does for its own cards.
7
+ * the settings shell does for its own sections.
8
8
  */
9
9
  export declare const inject: string[];
10
10
  /**
11
- * Client plugin body: register the settings card. The shell's declaration
11
+ * Client plugin body: register the settings page. The shell's declaration
12
12
  * may not be on the ledger yet, so the registration waits via slots.inject.
13
13
  * @param ctx - the client cordis context.
14
14
  */
package/lib/client.js CHANGED
@@ -40,33 +40,11 @@ var dshWebAuthModule = (() => {
40
40
  var inject = ["slots", "settingsScope", "connection", "remote"];
41
41
  var WEB_AUTH_NS = "web-auth";
42
42
  var CSS = `
43
- .dwa-card {
44
- border: 1px solid var(--dsw-alias-border-l2, #2a3346);
45
- background: var(--dsw-alias-bg-layer-3, #0d1017);
46
- border-radius: 12px;
47
- list-style: none;
48
- transition: border-color .16s, background .16s;
49
- }
50
- .dwa-card:hover { border-color: var(--dsw-alias-label-dimmed, #4a5468); }
51
- .dwa-card[data-open] {
52
- background: var(--dsw-alias-bg-layer-2, #141a26);
53
- border-color: var(--dsw-alias-label-dimmed, #4a5468);
54
- }
55
- .dwa-head {
56
- appearance: none; width: 100%; font: inherit; color: inherit; text-align: left; cursor: pointer;
57
- background: transparent; border: 0; border-radius: 12px;
58
- align-items: center; gap: 12px; padding: 14px 16px; display: flex;
59
- }
60
- .dwa-head:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #4f8cff); outline-offset: -2px; }
61
- .dwa-headText { flex-direction: column; flex: 1; gap: 4px; min-width: 0; display: flex; }
62
- .dwa-title { color: var(--dsw-alias-label-primary, #e6e6e6); font-size: 15px; font-weight: 600; line-height: 1.4; }
63
- .dwa-sub { color: var(--dsw-alias-label-tertiary, #8b93a7); font-size: 13px; line-height: 1.5; }
64
- .dwa-chevron {
65
- color: var(--dsw-alias-label-tertiary, #8b93a7); flex: none;
66
- transition: transform .16s; display: flex; align-items: center; justify-content: center;
67
- }
68
- .dwa-chevron[data-open] { transform: rotate(180deg); }
69
- .dwa-body { border-top: 1px solid var(--dsw-alias-border-l2, #2a3346); margin: 0 16px; padding: 12px 0 8px; display: flex; flex-direction: column; gap: 12px; }
43
+ .dwa-page { display: flex; flex-direction: column; gap: 16px; max-width: 720px; }
44
+ .dwa-page-head { display: flex; flex-direction: column; gap: 6px; }
45
+ .dwa-page-title { color: var(--dsw-alias-label-primary, #e6e6e6); margin: 0; font-size: 15px; font-weight: 600; line-height: 1.4; }
46
+ .dwa-page-sub { color: var(--dsw-alias-label-tertiary, #8b93a7); margin: 0; font-size: 13px; line-height: 1.5; }
47
+ .dwa-body { display: flex; flex-direction: column; gap: 12px; }
70
48
  .dwa-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
71
49
  .dwa-status { font-size: 13px; line-height: 1.6; }
72
50
  .dwa-status[data-on] { color: var(--dsw-alias-label-primary, #e6e6e6); }
@@ -99,7 +77,7 @@ var dshWebAuthModule = (() => {
99
77
  .dwa-divider { border: none; border-top: 1px solid var(--dsw-alias-border-l1, #232a38); margin: 2px 0; }
100
78
  `;
101
79
  function injectStyle() {
102
- const id = "dsh-web-auth/card.css";
80
+ const id = "dsh-web-auth/settings-section.css";
103
81
  if (document.getElementById(id) !== null) return;
104
82
  const tag = document.createElement("style");
105
83
  tag.id = id;
@@ -141,7 +119,7 @@ var dshWebAuthModule = (() => {
141
119
  return null;
142
120
  }
143
121
  }
144
- function AuthCard(props) {
122
+ function WebAuthSettingsSection(props) {
145
123
  const { scope } = props;
146
124
  const snapshot = (0, import_react.useSyncExternalStore)(
147
125
  (listener) => scope.subscribe(listener),
@@ -157,7 +135,6 @@ var dshWebAuthModule = (() => {
157
135
  const [listenPick, setListenPick] = (0, import_react.useState)("127.0.0.1");
158
136
  const [listenBusy, setListenBusy] = (0, import_react.useState)(false);
159
137
  const [listenMsg, setListenMsg] = (0, import_react.useState)(null);
160
- const [open, setOpen] = (0, import_react.useState)(false);
161
138
  (0, import_react.useEffect)(() => {
162
139
  let alive = true;
163
140
  void fetchStatus().then((status) => {
@@ -220,34 +197,12 @@ var dshWebAuthModule = (() => {
220
197
  setListenBusy(false);
221
198
  }
222
199
  };
223
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dwa-card", "data-open": open ? "" : void 0, children: [
224
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
225
- "button",
226
- {
227
- type: "button",
228
- className: "dwa-head",
229
- "aria-expanded": open,
230
- "aria-label": (open ? "\u6536\u8D77" : "\u5C55\u5F00") + "\uFF1A\u8BBF\u95EE\u8BA4\u8BC1",
231
- onClick: () => setOpen(!open),
232
- children: [
233
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dwa-headText", children: [
234
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dwa-title", children: "\u8BBF\u95EE\u8BA4\u8BC1" }),
235
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dwa-sub", children: "Web \u8BBF\u95EE\u5BC6\u7801\u4E0E\u76D1\u542C\u5730\u5740" })
236
- ] }),
237
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dwa-chevron", "data-open": open ? "" : void 0, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
238
- "path",
239
- {
240
- d: "M3.5 5.25L7 8.75L10.5 5.25",
241
- stroke: "currentColor",
242
- strokeWidth: "1.5",
243
- strokeLinecap: "round",
244
- strokeLinejoin: "round"
245
- }
246
- ) }) })
247
- ]
248
- }
249
- ),
250
- open && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dwa-body", children: [
200
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dwa-page", children: [
201
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", { className: "dwa-page-head", children: [
202
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "dwa-page-title", children: "\u8BBF\u95EE\u8BA4\u8BC1" }),
203
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dwa-page-sub", children: "Web \u8BBF\u95EE\u5BC6\u7801\u4E0E\u76D1\u542C\u5730\u5740" })
204
+ ] }),
205
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dwa-body", children: [
251
206
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dwa-row", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dwa-status", "data-on": configured ? void 0 : "", "data-off": configured ? "" : void 0, children: configured === null ? "\u52A0\u8F7D\u4E2D\u2026" : configured ? "\u8BBF\u95EE\u8BA4\u8BC1\uFF1A\u5DF2\u542F\u7528" : "\u8BBF\u95EE\u8BA4\u8BC1\uFF1A\u672A\u8BBE\u7F6E\u5BC6\u7801\uFF08\u5F53\u524D\u672A\u542F\u7528\uFF09" }) }),
252
207
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dwa-hint", children: "\u8BBE\u7F6E\u540E\uFF0C\u8BBF\u95EE\u672C\u670D\u52A1\u9700\u8981\u8F93\u5165\u5BC6\u7801\uFF1B\u4F1A\u8BDD\u6709\u6548\u671F 7 \u5929\uFF08\u6D3B\u52A8\u81EA\u52A8\u7EED\u671F\uFF09\u3002\u4FEE\u6539\u5BC6\u7801\u4F1A\u4F7F\u6240\u6709\u5DF2\u767B\u5F55\u4F1A\u8BDD\u7ACB\u5373\u5931\u6548\u3002" }),
253
208
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("hr", { className: "dwa-divider" }),
@@ -334,14 +289,16 @@ var dshWebAuthModule = (() => {
334
289
  const services = ctx;
335
290
  const scope = services.settingsScope.bind({ namespace: WEB_AUTH_NS });
336
291
  services.slots.inject(
337
- "settings.plugin.item",
292
+ "settings.section",
338
293
  () => services.slots.register(
339
294
  {
340
- name: "settings.plugin.item",
341
- key: WEB_AUTH_NS,
295
+ name: "settings.section",
296
+ id: "web-auth",
297
+ order: 120,
298
+ label: "\u8BBF\u95EE\u8BA4\u8BC1",
342
299
  inject: () => ({ scope })
343
300
  },
344
- AuthCard
301
+ WebAuthSettingsSection
345
302
  )
346
303
  );
347
304
  }
package/lib/handlers.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * dsh-web-auth — request handlers: the gate decision (whitelist + session
3
3
  * check), the /login page + form processing (including first-password setup),
4
- * /logout, and the JSON change-password API for the settings card.
4
+ * /logout, and the JSON change-password API for the settings page.
5
5
  */
6
6
  import type { IncomingMessage, ServerResponse } from 'node:http';
7
7
  import { type RateLimiter } from './auth-core.ts';
@@ -45,7 +45,7 @@ export interface HandlerEnv {
45
45
  loopbackAuthority?: string;
46
46
  /**
47
47
  * Listen-address controller (bound by the host half when the profile
48
- * patch layer is reachable). Absent = the settings card cannot change
48
+ * patch layer is reachable). Absent = the settings page cannot change
49
49
  * the bind host.
50
50
  */
51
51
  listen?: ListenController;
package/lib/handlers.js CHANGED
@@ -353,7 +353,7 @@ export function handleLogout(req, res, env) {
353
353
  clearCookie(res, isSecureRequest(req));
354
354
  redirect(res, '/login?loggedOut=1');
355
355
  }
356
- // ── GET /api/web-auth/status — settings-card state ─────────────────────────
356
+ // ── GET /api/web-auth/status — settings page state ─────────────────────────
357
357
  export function handleStatus(req, res, env) {
358
358
  const body = { configured: env.state.readHash() !== undefined };
359
359
  const current = env.listen?.current();
package/lib/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Host half: wraps the webserver's HTTP/upgrade listeners so every request
5
5
  * (routes, static fallback, WebSocket upgrades) must carry a valid session
6
6
  * cookie, serves the /login page (including first-password setup), /logout,
7
- * and the JSON change-password API used by the settings card (client half).
7
+ * and the JSON change-password API used by the settings page (client half).
8
8
  *
9
9
  * State lives under $DSH_HOME/web-auth/ (password.hash, secret) — see
10
10
  * state.ts. Until a password is configured the gate is OPEN and a boot
@@ -86,10 +86,10 @@ export function apply(ctx, config) {
86
86
  // away; failures are logged, never thrown — the client was confirmed.
87
87
  listen: buildListenController(ctx)
88
88
  };
89
- // The plugin's own Settings Card (设置 → 插件配置 → web-auth) rides the
90
- // `web-auth` settings namespace: registering it makes the tab dispatch the
91
- // card, and committed listenHost changes are applied here. Attaches only
92
- // when a settings service exists (CLI/headless profiles skip it).
89
+ // The plugin's own settings page (设置 → 侧栏「访问认证」) rides the
90
+ // `web-auth` settings namespace: binding the namespace is how the page reads
91
+ // and writes it, and committed listenHost changes are applied here. Attaches
92
+ // only when a settings service exists (CLI/headless profiles skip it).
93
93
  installWebAuthSettings(ctx, env.listen);
94
94
  if (state.readHash() === undefined) {
95
95
  // console.error, not ctx.logger.warn: the cordis default logger level
package/lib/settings.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * dsh-web-auth — the `web-auth` settings namespace.
3
3
  *
4
- * The namespace exists so the plugin's browser half can register its own
5
- * Settings Card: the settings section ("插件配置" tab) dispatches
6
- * `settings.plugin.item` for every namespace the Host serves, keyed by the
7
- * namespace string, and the client registers its card under the same key.
4
+ * The namespace exists so the plugin's browser half can read and write its
5
+ * own settings page: the page registers on the `settings.section` slot (the
6
+ * 「访问认证」 entry in the settings sidebar) and binds this namespace through
7
+ * the client settings scope, which is the only write path to `listenHost`.
8
8
  * The namespace carries the one genuine configuration value the plugin owns:
9
9
  * the web server's bind host (`listenHost`). The password is deliberately
10
10
  * NOT here — it is a secret stored hashed under `$DSH_HOME/web-auth/` and
package/lib/settings.js CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * dsh-web-auth — the `web-auth` settings namespace.
3
3
  *
4
- * The namespace exists so the plugin's browser half can register its own
5
- * Settings Card: the settings section ("插件配置" tab) dispatches
6
- * `settings.plugin.item` for every namespace the Host serves, keyed by the
7
- * namespace string, and the client registers its card under the same key.
4
+ * The namespace exists so the plugin's browser half can read and write its
5
+ * own settings page: the page registers on the `settings.section` slot (the
6
+ * 「访问认证」 entry in the settings sidebar) and binds this namespace through
7
+ * the client settings scope, which is the only write path to `listenHost`.
8
8
  * The namespace carries the one genuine configuration value the plugin owns:
9
9
  * the web server's bind host (`listenHost`). The password is deliberately
10
10
  * NOT here — it is a secret stored hashed under `$DSH_HOME/web-auth/` and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fonlan/dsh-web-auth",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "DSH web plugin: password-gate authentication (login page + HttpOnly signed cookie) for exposing dsh web behind a reverse proxy",
5
5
  "type": "module",
6
6
  "license": "MIT",