@dsh-plus/access-gate 0.3.9 → 0.3.11
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/lib/client.js +46 -10
- package/package.json +2 -2
- package/src/client/card.tsx +10 -4
- package/src/client/client.ts +12 -15
- package/src/client/i18n.ts +2 -0
- package/src/ns.ts +5 -3
package/lib/client.js
CHANGED
|
@@ -72,6 +72,35 @@ window.__ModuleLoader__.load({
|
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
//#endregion
|
|
75
|
+
//#region ../shared/src/client/config-slots.ts
|
|
76
|
+
/** dsh-plus 聚合 bundle 的包名(各插件 row 均经其补丁层插入 profile)。 */
|
|
77
|
+
const DSH_PLUS_BUNDLE = "@dsh-plus/bundle-main";
|
|
78
|
+
/**
|
|
79
|
+
* 把一张配置卡片同时注册进 legacy 与新版三个槽位。
|
|
80
|
+
* 任一槽位在当前 dsh 版本未声明时对应 inject 挂起等待,版本不命中即 no-op。
|
|
81
|
+
*/
|
|
82
|
+
function injectPluginConfigCard(slots, reg) {
|
|
83
|
+
const base = {
|
|
84
|
+
locale: reg.ns,
|
|
85
|
+
inject: reg.inject
|
|
86
|
+
};
|
|
87
|
+
slots.inject("settings.plugin.item", () => slots.register({
|
|
88
|
+
name: "settings.plugin.item",
|
|
89
|
+
key: reg.ns,
|
|
90
|
+
...base
|
|
91
|
+
}, reg.component));
|
|
92
|
+
slots.inject("plugins.row.config", () => slots.register({
|
|
93
|
+
name: "plugins.row.config",
|
|
94
|
+
key: `${DSH_PLUS_BUNDLE}#${reg.rowId}`,
|
|
95
|
+
...base
|
|
96
|
+
}, reg.component));
|
|
97
|
+
slots.inject("plugins.bundle.config", () => slots.register({
|
|
98
|
+
name: "plugins.bundle.config",
|
|
99
|
+
key: reg.pkg,
|
|
100
|
+
...base
|
|
101
|
+
}, reg.component));
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
75
104
|
//#region ../shared/src/client/fields.tsx
|
|
76
105
|
/**
|
|
77
106
|
* 勾选行:自绘圆角扁平开关(switch),对齐官方 WebUI 无原生 checkbox 的
|
|
@@ -335,16 +364,19 @@ ${extra}
|
|
|
335
364
|
//#region src/ns.ts
|
|
336
365
|
/**
|
|
337
366
|
* settings 命名空间字面量(纯常量,零依赖,浏览器半可安全引入)。
|
|
338
|
-
* 服务端直接以字面量注册(0.1.2-alpha.2 起 dsh-settings
|
|
339
|
-
*
|
|
340
|
-
*
|
|
367
|
+
* 服务端直接以字面量注册(0.1.2-alpha.2 起 dsh-settings 对命名空间做编译期
|
|
368
|
+
* 语法校验,见 config.ts);浏览器半把它作为配置卡片的注册键
|
|
369
|
+
* (legacy settings.plugin.item keyed 槽位按「卡片编辑的 settings 命名空间」
|
|
370
|
+
* 分发;0.1.6-alpha.2 起改挂插件页 row/bundle config,见 shared/config-slots),
|
|
371
|
+
* 同一字面量两处共用,防止漂移。
|
|
341
372
|
* @module access-gate/ns
|
|
342
373
|
*/
|
|
343
374
|
const SETTINGS_NS = "dsh-plus-access-gate";
|
|
344
375
|
//#endregion
|
|
345
376
|
//#region src/client/card.tsx
|
|
346
377
|
/**
|
|
347
|
-
*
|
|
378
|
+
* 「访问控制」配置卡片:经 injectPluginConfigCard 注册(legacy settings.plugin.item
|
|
379
|
+
* 与 0.1.6-alpha.2 插件页 plugins.row.config / plugins.bundle.config,view 分发 summary/page)。
|
|
348
380
|
* 外壳与基础控件走 @dsh-plus/shared/client 套件(CardChrome/TextField/CheckRow),
|
|
349
381
|
* 本文件保留业务字段(白名单 textarea/诊断面板)与保存逻辑。
|
|
350
382
|
* 配置读写走官方 settingsScope 传输:value 为 schema 解析后的视图,
|
|
@@ -394,7 +426,7 @@ ${extra}
|
|
|
394
426
|
const { t, scope, api } = props;
|
|
395
427
|
const snapshot = (0, react.useSyncExternalStore)((listener) => scope.subscribe(listener), () => scope.getSnapshot());
|
|
396
428
|
const value = snapshot.value;
|
|
397
|
-
const [open, setOpen] = (0, react.useState)(
|
|
429
|
+
const [open, setOpen] = (0, react.useState)(props.view === "page");
|
|
398
430
|
const [draft, setDraft] = (0, react.useState)(null);
|
|
399
431
|
const [diag, setDiag] = (0, react.useState)(null);
|
|
400
432
|
const [saving, setSaving] = (0, react.useState)(false);
|
|
@@ -413,6 +445,7 @@ ${extra}
|
|
|
413
445
|
};
|
|
414
446
|
}, [snapshot]);
|
|
415
447
|
const dirty = (0, react.useMemo)(() => value !== void 0 && draft !== null && JSON.stringify(toPatch(draft)) !== JSON.stringify(toPatch(draftFromValue(value))), [value, draft]);
|
|
448
|
+
if (props.view === "summary") return t("summaryLine");
|
|
416
449
|
if (value === void 0 || draft === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
417
450
|
className: "dag-card",
|
|
418
451
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
@@ -611,6 +644,7 @@ ${extra}
|
|
|
611
644
|
const ownZh = {
|
|
612
645
|
title: "访问控制",
|
|
613
646
|
description: "Web 访问围栏:与官方登录合并——官方 cookie 为唯一凭据;未认证导航显示启动令牌输入页(PWA 内可用);可选 IP 附加围栏。",
|
|
647
|
+
summaryLine: "Web 访问围栏:官方登录合并、启动令牌页与可选 IP 白名单。",
|
|
614
648
|
enabled: "启用访问围栏",
|
|
615
649
|
enabledHint: "关闭即完全旁路(等价插件缺席);启用后未认证流量被拦截到令牌输入页或拒绝。",
|
|
616
650
|
mergedHint: "登录凭据由官方认证持有(启动令牌换 30 天 cookie)。获取当前令牌:服务器执行 dshctl url,或本机访问 /dsh-plus/gate/launch-url。",
|
|
@@ -642,6 +676,7 @@ ${extra}
|
|
|
642
676
|
const ownEn = {
|
|
643
677
|
title: "Access Control",
|
|
644
678
|
description: "Web access gate merged with official auth: the official cookie is the sole credential; unauthenticated navigations get a launch-token page (works inside the PWA); optional IP fence.",
|
|
679
|
+
summaryLine: "Web access gate: merged official auth, launch-token page, optional IP allowlist.",
|
|
645
680
|
enabled: "Enable access gate",
|
|
646
681
|
enabledHint: "Off means full bypass (as if absent); on, unauthenticated traffic hits the token page or is refused.",
|
|
647
682
|
mergedHint: "Credentials are owned by official auth (launch token exchange, 30-day cookie). Get the current token: run dshctl url on the server, or visit /dsh-plus/gate/launch-url locally.",
|
|
@@ -724,16 +759,17 @@ ${extra}
|
|
|
724
759
|
}), "access-gate: locale");
|
|
725
760
|
const scope = createSettingsScope(c, SETTINGS_NS, "access-gate: settings scope");
|
|
726
761
|
const api = createNamespaceApi(c.get("remote").settings, SETTINGS_NS);
|
|
727
|
-
c.slots
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
762
|
+
injectPluginConfigCard(c.slots, {
|
|
763
|
+
ns: SETTINGS_NS,
|
|
764
|
+
rowId: "dsh-plus-access-gate",
|
|
765
|
+
pkg: "@dsh-plus/access-gate",
|
|
766
|
+
component: AccessGateCard,
|
|
731
767
|
inject: () => ({
|
|
732
768
|
t: c.locale.bind(NS),
|
|
733
769
|
scope,
|
|
734
770
|
api
|
|
735
771
|
})
|
|
736
|
-
}
|
|
772
|
+
});
|
|
737
773
|
}
|
|
738
774
|
//#endregion
|
|
739
775
|
exports.apply = apply;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-plus/access-gate",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.11",
|
|
4
4
|
"description": "dsh-plus service+ui plugin: dsh web 全量访问围栏——与官方 browser-auth 合并:官方 cookie 为唯一凭据,可选 IP 附加围栏,未认证导航渲染 token 输入页(PWA 可恢复),loopback 管理通道",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@dsh-plus/shared": "0.1.
|
|
34
|
+
"@dsh-plus/shared": "0.1.20"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"@deepseek-ai/cordis": "^4.0.2",
|
package/src/client/card.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 「访问控制」配置卡片:经 injectPluginConfigCard 注册(legacy settings.plugin.item
|
|
3
|
+
* 与 0.1.6-alpha.2 插件页 plugins.row.config / plugins.bundle.config,view 分发 summary/page)。
|
|
3
4
|
* 外壳与基础控件走 @dsh-plus/shared/client 套件(CardChrome/TextField/CheckRow),
|
|
4
5
|
* 本文件保留业务字段(白名单 textarea/诊断面板)与保存逻辑。
|
|
5
6
|
* 配置读写走官方 settingsScope 传输:value 为 schema 解析后的视图,
|
|
@@ -18,12 +19,13 @@ import {
|
|
|
18
19
|
CheckRow,
|
|
19
20
|
IDLE_STATUS,
|
|
20
21
|
type NamespaceSettingsApi,
|
|
22
|
+
type PluginConfigViewProps,
|
|
21
23
|
type Scope,
|
|
22
24
|
} from '@dsh-plus/shared/client'
|
|
23
25
|
import { type ReactElement, useEffect, useMemo, useState, useSyncExternalStore } from 'react'
|
|
24
26
|
import type { DictKey, Translate } from './i18n.ts'
|
|
25
27
|
|
|
26
|
-
export interface CardProps {
|
|
28
|
+
export interface CardProps extends PluginConfigViewProps {
|
|
27
29
|
t: Translate
|
|
28
30
|
scope: Scope
|
|
29
31
|
api: NamespaceSettingsApi
|
|
@@ -99,14 +101,15 @@ function verdictLabel(t: Translate, diag: Diag): string {
|
|
|
99
101
|
return t('diagBlock')
|
|
100
102
|
}
|
|
101
103
|
|
|
102
|
-
export function AccessGateCard(props: CardProps): ReactElement | null {
|
|
104
|
+
export function AccessGateCard(props: CardProps): ReactElement | string | null {
|
|
103
105
|
const { t, scope, api } = props
|
|
104
106
|
const snapshot = useSyncExternalStore(
|
|
105
107
|
(listener: () => void) => scope.subscribe(listener),
|
|
106
108
|
() => scope.getSnapshot(),
|
|
107
109
|
)
|
|
108
110
|
const value = snapshot.value as ConfigValue | undefined
|
|
109
|
-
|
|
111
|
+
// 0.1.6-alpha.2 插件页 page 视图为表单落地页,默认展开;旧槽位无 view,保持折叠。
|
|
112
|
+
const [open, setOpen] = useState(props.view === 'page')
|
|
110
113
|
const [draft, setDraft] = useState<Draft | null>(null)
|
|
111
114
|
const [diag, setDiag] = useState<Diag | null>(null)
|
|
112
115
|
const [saving, setSaving] = useState(false)
|
|
@@ -141,6 +144,9 @@ export function AccessGateCard(props: CardProps): ReactElement | null {
|
|
|
141
144
|
[value, draft],
|
|
142
145
|
)
|
|
143
146
|
|
|
147
|
+
// 插件页 summary 视图只出一行简介(hooks 已全部落定,可安全提前返回)。
|
|
148
|
+
if (props.view === 'summary') return t('summaryLine')
|
|
149
|
+
|
|
144
150
|
if (value === undefined || draft === null) {
|
|
145
151
|
return (
|
|
146
152
|
<li className="dag-card">
|
package/src/client/client.ts
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 浏览器半入口:注册 locale 字典 +
|
|
2
|
+
* 浏览器半入口:注册 locale 字典 + 注册「访问控制」卡片
|
|
3
|
+
* (injectPluginConfigCard 三槽位:legacy settings.plugin.item 与 0.1.6-alpha.2
|
|
4
|
+
* 独立插件页的 plugins.row.config / plugins.bundle.config)。
|
|
3
5
|
* 构建产物为 window.__ModuleLoader__.load({id, factory}) 形式的 CJS factory
|
|
4
6
|
* (包装见 tsdown.config.ts);样式沿用官方 data-plugin-css 约定,HMR 据此卸载。
|
|
5
7
|
*
|
|
6
8
|
* 类型说明:浏览器半只用到 slots/locale/remote 的很窄一面,
|
|
7
9
|
* scope 与基础控件走 @dsh-plus/shared/client 套件(收编自本插件原实现)。
|
|
8
|
-
* 该插槽为 keyed 槽位:key 必须是卡片编辑的 settings 命名空间
|
|
9
|
-
* (即服务端注册的同一字面量,见 ../ns.ts),
|
|
10
|
-
* 官方配置页按此 key 与 Host 已注册命名空间配对分发。
|
|
11
10
|
* 配置读写经 ctx.remote.settings 直连(0.1.2-alpha.1 起 connection.api.settings
|
|
12
11
|
* 已移除;不复用 settingsScope 服务——非 loopback 页面下它固定 memory 模式无数据)。
|
|
12
|
+
* 卡片 key/rowId 约定见 @dsh-plus/shared/client/config-slots。
|
|
13
13
|
* @module @dsh-plus/access-gate/client
|
|
14
14
|
*/
|
|
15
15
|
import type { Context } from '@deepseek-ai/cordis'
|
|
16
16
|
import {
|
|
17
17
|
createNamespaceApi,
|
|
18
18
|
createSettingsScope,
|
|
19
|
+
injectPluginConfigCard,
|
|
19
20
|
type PluginClientContext,
|
|
20
21
|
} from '@dsh-plus/shared/client'
|
|
21
22
|
import { SETTINGS_NS } from '../ns.ts'
|
|
@@ -43,15 +44,11 @@ export function apply(ctx: Context): void {
|
|
|
43
44
|
c.effect(() => c.locale.register(NS, { zh, en }), 'access-gate: locale')
|
|
44
45
|
const scope = createSettingsScope(c, SETTINGS_NS, 'access-gate: settings scope')
|
|
45
46
|
const api = createNamespaceApi(c.get('remote').settings, SETTINGS_NS)
|
|
46
|
-
c.slots
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
},
|
|
54
|
-
AccessGateCard,
|
|
55
|
-
),
|
|
56
|
-
)
|
|
47
|
+
injectPluginConfigCard(c.slots, {
|
|
48
|
+
ns: SETTINGS_NS,
|
|
49
|
+
rowId: 'dsh-plus-access-gate',
|
|
50
|
+
pkg: '@dsh-plus/access-gate',
|
|
51
|
+
component: AccessGateCard,
|
|
52
|
+
inject: () => ({ t: c.locale.bind(NS), scope, api }),
|
|
53
|
+
})
|
|
57
54
|
}
|
package/src/client/i18n.ts
CHANGED
|
@@ -11,6 +11,7 @@ const ownZh = {
|
|
|
11
11
|
title: '访问控制',
|
|
12
12
|
description:
|
|
13
13
|
'Web 访问围栏:与官方登录合并——官方 cookie 为唯一凭据;未认证导航显示启动令牌输入页(PWA 内可用);可选 IP 附加围栏。',
|
|
14
|
+
summaryLine: 'Web 访问围栏:官方登录合并、启动令牌页与可选 IP 白名单。',
|
|
14
15
|
enabled: '启用访问围栏',
|
|
15
16
|
enabledHint: '关闭即完全旁路(等价插件缺席);启用后未认证流量被拦截到令牌输入页或拒绝。',
|
|
16
17
|
mergedHint:
|
|
@@ -48,6 +49,7 @@ const ownEn = {
|
|
|
48
49
|
title: 'Access Control',
|
|
49
50
|
description:
|
|
50
51
|
'Web access gate merged with official auth: the official cookie is the sole credential; unauthenticated navigations get a launch-token page (works inside the PWA); optional IP fence.',
|
|
52
|
+
summaryLine: 'Web access gate: merged official auth, launch-token page, optional IP allowlist.',
|
|
51
53
|
enabled: 'Enable access gate',
|
|
52
54
|
enabledHint:
|
|
53
55
|
'Off means full bypass (as if absent); on, unauthenticated traffic hits the token page or is refused.',
|
package/src/ns.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* settings 命名空间字面量(纯常量,零依赖,浏览器半可安全引入)。
|
|
3
|
-
* 服务端直接以字面量注册(0.1.2-alpha.2 起 dsh-settings
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* 服务端直接以字面量注册(0.1.2-alpha.2 起 dsh-settings 对命名空间做编译期
|
|
4
|
+
* 语法校验,见 config.ts);浏览器半把它作为配置卡片的注册键
|
|
5
|
+
* (legacy settings.plugin.item keyed 槽位按「卡片编辑的 settings 命名空间」
|
|
6
|
+
* 分发;0.1.6-alpha.2 起改挂插件页 row/bundle config,见 shared/config-slots),
|
|
7
|
+
* 同一字面量两处共用,防止漂移。
|
|
6
8
|
* @module access-gate/ns
|
|
7
9
|
*/
|
|
8
10
|
export const SETTINGS_NS = 'dsh-plus-access-gate'
|