@dsh-plus/access-gate 0.1.2 → 0.1.4

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 CHANGED
@@ -6,6 +6,25 @@ window.__ModuleLoader__.load({
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react_jsx_runtime = require("react/jsx-runtime");
8
8
  let react = require("react");
9
+ //#region ../shared/src/client/icons.tsx
10
+ /** 官方 IconChevronDownOutline14 的同构实现(path 数据逐字一致)。 */
11
+ function ChevronDownIcon(props) {
12
+ const size = props.size ?? 14;
13
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
14
+ width: size,
15
+ height: size,
16
+ className: props.className,
17
+ viewBox: "0 0 14 14",
18
+ fill: "none",
19
+ xmlns: "http://www.w3.org/2000/svg",
20
+ "aria-hidden": "true",
21
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
22
+ d: "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z",
23
+ fill: "currentColor"
24
+ })
25
+ });
26
+ }
27
+ //#endregion
9
28
  //#region ../shared/src/client/card.tsx
10
29
  const IDLE_STATUS = {
11
30
  kind: "idle",
@@ -41,10 +60,7 @@ window.__ModuleLoader__.load({
41
60
  className: `${p}-pending`,
42
61
  children: props.dirtyLabel
43
62
  }) : null,
44
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
45
- className: `${p}-chevron${props.open ? ` ${p}-chevronOpen` : ""}`,
46
- children: "▾"
47
- })
63
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, { className: `${p}-chevron${props.open ? ` ${p}-chevronOpen` : ""}` })
48
64
  ]
49
65
  }), props.open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
50
66
  className: `${p}-body`,
@@ -110,6 +126,11 @@ window.__ModuleLoader__.load({
110
126
  ]
111
127
  });
112
128
  }
129
+ /**
130
+ * 勾选行:自绘圆角扁平开关(switch),对齐官方 WebUI 无原生 checkbox 的
131
+ * 设计语言(官方选择类控件全走胶囊/菜单,见 cardCss 的 -switch 规则)。
132
+ * 语义保持 checkbox(无障碍树与表单语义不变),视觉自绘。
133
+ */
113
134
  function CheckRow(props) {
114
135
  const p = props.prefix ?? "dshp";
115
136
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -117,6 +138,8 @@ window.__ModuleLoader__.load({
117
138
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
118
139
  id: props.id,
119
140
  type: "checkbox",
141
+ role: "switch",
142
+ "aria-checked": props.checked,
120
143
  checked: props.checked,
121
144
  disabled: props.disabled === true,
122
145
  onChange: (event) => props.onEdit(event.target.checked)
@@ -173,14 +196,15 @@ window.__ModuleLoader__.load({
173
196
  //#endregion
174
197
  //#region ../shared/src/client/scope.ts
175
198
  /**
176
- * api 直连实现的命名空间 scope(官方配置页 tab 同款模式)。
199
+ * remote.settings 直连实现的命名空间 scope(官方配置页 tab 同款模式)。
177
200
  * 读:describe 取命名空间视图(脱敏 value/revision + 顶层 writable);
178
201
  * 刷新:remote `settings/document-updated`(按命名空间过滤)与
179
202
  * `connection/reset`;generation 防旧读覆盖新发布。任何页面 origin
180
203
  * (loopback 或 tailnet 信任域名)下行为一致。
181
204
  * effect 归属调用方 fiber(label 需含插件名以便诊断)。
182
205
  */
183
- function createApiScope(api, ns, c, label) {
206
+ function createSettingsScope(c, ns, label) {
207
+ const remote = c.get("remote");
184
208
  let state = {
185
209
  status: "loading",
186
210
  value: void 0,
@@ -195,36 +219,37 @@ window.__ModuleLoader__.load({
195
219
  };
196
220
  const load = async () => {
197
221
  const gen = ++generation;
198
- let response;
222
+ let view;
199
223
  try {
200
- response = await api.describe({});
224
+ const response = await remote.settings.describe();
225
+ if (!response.ok) return;
226
+ view = response.value;
201
227
  } catch {
202
228
  return;
203
229
  }
204
- if (gen !== generation || !response.result.ok) return;
205
- const writable = response.result.value?.writable ?? false;
206
- const view = response.result.value?.namespaces.find((candidate) => candidate.ns === ns);
207
- if (view === void 0) {
230
+ if (gen !== generation) return;
231
+ const namespace = view.namespaces.find((candidate) => candidate.ns === ns);
232
+ if (namespace === void 0) {
208
233
  publish({
209
234
  status: "unavailable",
210
235
  value: void 0,
211
236
  revision: void 0,
212
- writable
237
+ writable: view.writable
213
238
  });
214
239
  return;
215
240
  }
216
241
  publish({
217
242
  status: "ready",
218
- value: view.value,
219
- revision: view.revision,
220
- writable
243
+ value: namespace.value,
244
+ revision: namespace.revision,
245
+ writable: view.writable
221
246
  });
222
247
  };
223
248
  const refresh = (namespace) => {
224
249
  if (namespace !== void 0 && namespace !== ns) return;
225
250
  load();
226
251
  };
227
- const disposers = [c.get("remote").$on("settings/document-updated", refresh), c.on("connection/reset", () => {
252
+ const disposers = [remote.$on("settings/document-updated", refresh), c.on("connection/reset", () => {
228
253
  load();
229
254
  })];
230
255
  c.effect(() => () => {
@@ -242,6 +267,20 @@ window.__ModuleLoader__.load({
242
267
  load
243
268
  };
244
269
  }
270
+ /** 以 remote.settings 构造命名空间绑定的 api 面。 */
271
+ function createNamespaceApi(remote, ns) {
272
+ return {
273
+ update: async (patch, expectedRevision) => {
274
+ const response = await remote.update(ns, patch, expectedRevision);
275
+ if (!response.ok) throw new Error(response.error.message ?? "settings update failed");
276
+ },
277
+ describe: async () => {
278
+ const response = await remote.describe();
279
+ if (!response.ok) throw new Error(response.error.message ?? "settings describe failed");
280
+ return response.value;
281
+ }
282
+ };
283
+ }
245
284
  //#endregion
246
285
  //#region ../shared/src/client/styles.ts
247
286
  /**
@@ -265,7 +304,7 @@ window.__ModuleLoader__.load({
265
304
  .${prefix}-headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}
266
305
  .${prefix}-name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}
267
306
  .${prefix}-description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}
268
- .${prefix}-chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s;font-size:12px}
307
+ .${prefix}-chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s;display:inline-flex}
269
308
  .${prefix}-chevronOpen{transform:rotate(180deg)}
270
309
  .${prefix}-pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
271
310
  .${prefix}-statusBadge{white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
@@ -279,16 +318,24 @@ window.__ModuleLoader__.load({
279
318
  .${prefix}-badge{white-space:nowrap;border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
280
319
  .${prefix}-badgeSet{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary)}
281
320
  .${prefix}-badgeUnset{color:var(--dsw-alias-label-tertiary)}
282
- .${prefix}-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px}
321
+ .${prefix}-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;transition:border-color .18s,background .18s}
322
+ .${prefix}-input:hover:not(:disabled):not(:focus-visible){border-color:var(--dsw-alias-label-dimmed)}
283
323
  .${prefix}-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}
284
324
  .${prefix}-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}
285
325
  .${prefix}-inputInvalid{border-color:var(--dsw-alias-label-error)}
286
- .${prefix}-select{appearance:none;background-image:linear-gradient(45deg,transparent 50%,var(--dsw-alias-label-tertiary) 50%),linear-gradient(135deg,var(--dsw-alias-label-tertiary) 50%,transparent 50%);background-position:calc(100% - 16px) 50%,calc(100% - 11px) 50%;background-size:5px 5px;background-repeat:no-repeat;padding-right:28px}
326
+ .${prefix}-select{appearance:none;background:var(--dsw-alias-bg-module-platform);border:none;cursor:pointer;background-image:linear-gradient(45deg,transparent 50%,var(--dsw-alias-label-secondary) 50%),linear-gradient(135deg,var(--dsw-alias-label-secondary) 50%,transparent 50%);background-position:calc(100% - 16px) 50%,calc(100% - 11px) 50%;background-size:5px 5px;background-repeat:no-repeat;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;height:34px;box-sizing:border-box;border-radius:8px;padding:0 30px 0 12px;transition:background-color .18s}
327
+ .${prefix}-select:hover:not(:disabled){background-color:var(--dsw-alias-interactive-bg-hover)}
287
328
  .${prefix}-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
288
329
  .${prefix}-invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}
289
- .${prefix}-checkRow{align-items:center;gap:8px;display:flex;padding:6px 0}
290
- .${prefix}-checkRow input{accent-color:var(--dsw-alias-brand-primary)}
291
- .${prefix}-checkRow label{color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.5;cursor:pointer}
330
+ .${prefix}-checkRow{align-items:center;gap:10px;display:flex;padding:6px 0}
331
+ .${prefix}-checkRow label{color:var(--dsw-alias-label-primary);font-size:13px;line-height:1.5;cursor:pointer;flex:1;min-width:0}
332
+ /* 自绘圆角扁平开关(官方 UI 无可见原生 checkbox,选择类全走胶囊/菜单) */
333
+ .${prefix}-checkRow input{appearance:none;-webkit-appearance:none;position:relative;box-sizing:border-box;background:var(--dsw-alias-bg-module-platform);border:none;border-radius:999px;width:34px;height:20px;flex:none;cursor:pointer;transition:background .18s;margin:0}
334
+ .${prefix}-checkRow input::after{content:"";position:absolute;top:2px;left:2px;background:var(--dsw-alias-label-primary);border-radius:999px;width:16px;height:16px;transition:left .18s cubic-bezier(.4,0,.2,1)}
335
+ .${prefix}-checkRow input:checked{background:var(--dsw-alias-brand-primary)}
336
+ .${prefix}-checkRow input:checked::after{left:16px;background:var(--dsw-alias-bg-base)}
337
+ .${prefix}-checkRow input:disabled{opacity:.4;cursor:default}
338
+ .${prefix}-checkRow input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
292
339
  .${prefix}-groupLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600;padding:12px 0 2px;margin:0}
293
340
  .${prefix}-readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}
294
341
  .${prefix}-warn{color:var(--dsw-alias-label-error);margin:12px 0 0;font-size:12px;line-height:1.5}
@@ -306,7 +353,6 @@ window.__ModuleLoader__.load({
306
353
  .${prefix}-header{padding:12px 12px}
307
354
  .${prefix}-input,.${prefix}-select{font-size:16px;height:40px}
308
355
  .${prefix}-checkRow{min-height:44px;padding:8px 0}
309
- .${prefix}-checkRow input{width:18px;height:18px;flex:none}
310
356
  .${prefix}-footer{position:sticky;bottom:0;background:var(--dsw-alias-bg-layer-2);margin:0 -10px;padding:10px 10px 6px;border-top:1px solid var(--dsw-alias-border-l2);border-bottom-left-radius:12px;border-bottom-right-radius:12px}
311
357
  .${prefix}-status{flex-basis:100%;flex:none}
312
358
  .${prefix}-btn{min-height:44px;flex:1;min-width:96px}
@@ -408,10 +454,10 @@ ${extra}
408
454
  }, [value, draft]);
409
455
  (0, react.useEffect)(() => {
410
456
  let alive = true;
411
- api.describe({}).then((response) => {
412
- if (!alive || !response.result.ok) return;
413
- const view = response.result.value?.namespaces.find((ns) => ns.ns === SETTINGS_NS);
414
- setTokenConfigured(view?.secrets.some((secret) => secret.path.join(".") === "token" && secret.set) ?? false);
457
+ api.describe().then((view) => {
458
+ if (!alive) return;
459
+ const ns = view.namespaces.find((candidate) => candidate.ns === SETTINGS_NS);
460
+ setTokenConfigured(ns?.secrets.some((secret) => secret.path.join(".") === "token" && secret.set) ?? false);
415
461
  }).catch(() => {});
416
462
  return () => {
417
463
  alive = false;
@@ -448,12 +494,7 @@ ${extra}
448
494
  const patch = toPatch(draft);
449
495
  if (draft.token !== "") patch.token = draft.token;
450
496
  const revision = scope.getSnapshot().revision;
451
- api.update({
452
- ns: SETTINGS_NS,
453
- patch,
454
- ...revision !== void 0 ? { expectedRevision: revision } : {}
455
- }).then(async (response) => {
456
- if (!response.result.ok) throw new Error(response.result.error?.message ?? t("saveFailed"));
497
+ api.update(patch, revision).then(async () => {
457
498
  await scope.load();
458
499
  const next = scope.getSnapshot().value;
459
500
  if (next !== void 0) setDraft(draftFromValue(next));
@@ -757,8 +798,8 @@ ${extra}
757
798
  const inject = [
758
799
  "slots",
759
800
  "locale",
760
- "connection",
761
- "remote"
801
+ "remote",
802
+ "remote.settings"
762
803
  ];
763
804
  function apply(ctx) {
764
805
  const c = ctx;
@@ -770,8 +811,8 @@ ${extra}
770
811
  zh,
771
812
  en
772
813
  }), "access-gate: locale");
773
- const api = c.get("connection").api.settings;
774
- const scope = createApiScope(api, SETTINGS_NS, c, "access-gate: settings scope");
814
+ const scope = createSettingsScope(c, SETTINGS_NS, "access-gate: settings scope");
815
+ const api = createNamespaceApi(c.get("remote").settings, SETTINGS_NS);
775
816
  c.slots.inject("settings.plugin.item", () => c.slots.register({
776
817
  name: "settings.plugin.item",
777
818
  key: SETTINGS_NS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-plus/access-gate",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "dsh-plus service+ui plugin: dsh web 全量访问围栏——本机直连永久放行,远程按白名单 IP(XFF 还原)或 token(登录页 + cookie)放行",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -23,28 +23,27 @@
23
23
  "dsh": {
24
24
  "client": {
25
25
  "inject": [
26
- "@deepseek-ai/dsh-client-runtime",
27
26
  "@deepseek-ai/dsh-client-locale",
28
- "@deepseek-ai/dsh-client-connection",
27
+ "@deepseek-ai/dsh-client-ui-renderer",
29
28
  "@deepseek-ai/dsh-api-remotes"
30
29
  ],
31
30
  "platform": "web"
32
31
  }
33
32
  },
34
33
  "dependencies": {
35
- "@dsh-plus/shared": "0.1.3"
34
+ "@dsh-plus/shared": "0.1.6"
36
35
  },
37
36
  "peerDependencies": {
38
37
  "@deepseek-ai/cordis": "^4.0.1",
39
- "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8",
40
- "@deepseek-ai/dsh-settings": "^0.1.0-rc.8",
38
+ "@deepseek-ai/dsh-home-paths": "^0.1.2-alpha.1",
39
+ "@deepseek-ai/dsh-settings": "^0.1.2-alpha.1",
41
40
  "@deepseek-ai/schemastery": "^3.18.1"
42
41
  },
43
42
  "devDependencies": {
44
43
  "@deepseek-ai/cordis": "4.0.1",
45
- "@deepseek-ai/dsh-home-paths": "0.1.1-rc.2",
46
- "@deepseek-ai/dsh-settings": "0.1.1-rc.2",
47
- "@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
44
+ "@deepseek-ai/dsh-home-paths": "0.1.2-alpha.1",
45
+ "@deepseek-ai/dsh-settings": "0.1.2-alpha.1",
46
+ "@deepseek-ai/dsh-host-webserver": "0.1.2-alpha.1",
48
47
  "@deepseek-ai/schemastery": "3.18.1",
49
48
  "@types/react": "~18.3.1",
50
49
  "react": "^18.2.0"
@@ -14,8 +14,8 @@ import {
14
14
  type CardStatusState,
15
15
  CheckRow,
16
16
  IDLE_STATUS,
17
+ type NamespaceSettingsApi,
17
18
  type Scope,
18
- type SettingsApi,
19
19
  TextField,
20
20
  } from '@dsh-plus/shared/client'
21
21
  import { type ReactElement, useEffect, useMemo, useState, useSyncExternalStore } from 'react'
@@ -24,7 +24,7 @@ import { SETTINGS_NS } from '../ns.ts'
24
24
  export interface CardProps {
25
25
  t(key: string): string
26
26
  scope: Scope
27
- api: SettingsApi
27
+ api: NamespaceSettingsApi
28
28
  }
29
29
 
30
30
  /** settings 命名空间的脱敏解析值(token 被脱敏剥除)。 */
@@ -126,12 +126,12 @@ export function AccessGateCard(props: CardProps): ReactElement | null {
126
126
  useEffect(() => {
127
127
  let alive = true
128
128
  api
129
- .describe({})
130
- .then((response) => {
131
- if (!alive || !response.result.ok) return
132
- const view = response.result.value?.namespaces.find((ns) => ns.ns === SETTINGS_NS)
129
+ .describe()
130
+ .then((view) => {
131
+ if (!alive) return
132
+ const ns = view.namespaces.find((candidate) => candidate.ns === SETTINGS_NS)
133
133
  setTokenConfigured(
134
- view?.secrets.some((secret) => secret.path.join('.') === 'token' && secret.set) ?? false,
134
+ ns?.secrets.some((secret) => secret.path.join('.') === 'token' && secret.set) ?? false,
135
135
  )
136
136
  })
137
137
  .catch(() => {})
@@ -192,15 +192,8 @@ export function AccessGateCard(props: CardProps): ReactElement | null {
192
192
  if (draft.token !== '') patch.token = draft.token
193
193
  const revision = scope.getSnapshot().revision
194
194
  api
195
- .update({
196
- ns: SETTINGS_NS,
197
- patch,
198
- ...(revision !== undefined ? { expectedRevision: revision } : {}),
199
- })
200
- .then(async (response) => {
201
- if (!response.result.ok) {
202
- throw new Error(response.result.error?.message ?? t('saveFailed'))
203
- }
195
+ .update(patch, revision)
196
+ .then(async () => {
204
197
  await scope.load()
205
198
  const next = scope.getSnapshot().value as ConfigValue | undefined
206
199
  if (next !== undefined) setDraft(draftFromValue(next))
@@ -3,17 +3,21 @@
3
3
  * 构建产物为 window.__ModuleLoader__.load({id, factory}) 形式的 CJS factory
4
4
  * (包装见 tsdown.config.ts);样式沿用官方 data-plugin-css 约定,HMR 据此卸载。
5
5
  *
6
- * 类型说明:浏览器半只用到 slots/locale/connection/remote 的很窄一面,
6
+ * 类型说明:浏览器半只用到 slots/locale/remote 的很窄一面,
7
7
  * scope 与基础控件走 @dsh-plus/shared/client 套件(收编自本插件原实现)。
8
- * rc7 起该插槽为 keyed 槽位:key 必须是卡片编辑的 settings 命名空间
8
+ * 该插槽为 keyed 槽位:key 必须是卡片编辑的 settings 命名空间
9
9
  * (即服务端 settingsNamespace() 注册的同一字面量,见 ../ns.ts),
10
10
  * 官方配置页按此 key 与 Host 已注册命名空间配对分发。
11
- * 配置读写经官方 settings RPC 直连(rc7 起第三方命名空间全量开放;
12
- * 不复用 settingsScope 服务——非 loopback 页面下它无数据)。
11
+ * 配置读写经 ctx.remote.settings 直连(0.1.2-alpha.1 起 connection.api.settings
12
+ * 已移除;不复用 settingsScope 服务——非 loopback 页面下它固定 memory 模式无数据)。
13
13
  * @module @dsh-plus/access-gate/client
14
14
  */
15
15
  import type { Context } from '@deepseek-ai/cordis'
16
- import { createApiScope } from '@dsh-plus/shared/client'
16
+ import {
17
+ createNamespaceApi,
18
+ createSettingsScope,
19
+ type SettingsRemoteFace,
20
+ } from '@dsh-plus/shared/client'
17
21
  import { SETTINGS_NS } from '../ns.ts'
18
22
  import { AccessGateCard } from './card.tsx'
19
23
  import { en, NS, zh } from './i18n.ts'
@@ -22,7 +26,7 @@ import { injectStyle } from './styles.ts'
22
26
  export const name = 'dsh-plus-access-gate'
23
27
 
24
28
  /** 浏览器半需要的 cordis 服务 key(loader 据此注入;package.json 的 dsh.client.inject 管包加载顺序)。 */
25
- export const inject = ['slots', 'locale', 'connection', 'remote'] as const
29
+ export const inject = ['slots', 'locale', 'remote', 'remote.settings'] as const
26
30
 
27
31
  interface SlotsLike {
28
32
  inject(key: string, callback: () => unknown): unknown
@@ -35,17 +39,13 @@ interface LocaleLike {
35
39
  }
36
40
 
37
41
  interface RemoteLike {
42
+ settings: SettingsRemoteFace
38
43
  $on(event: string, listener: (payload?: unknown) => void): () => void
39
44
  }
40
45
 
41
- interface ConnectionLike {
42
- api: { settings: Parameters<typeof createApiScope>[0] }
43
- }
44
-
45
46
  interface ClientContext {
46
47
  slots: SlotsLike
47
48
  locale: LocaleLike
48
- get(key: 'connection'): ConnectionLike
49
49
  get(key: 'remote'): RemoteLike
50
50
  on(event: string, listener: () => void): () => void
51
51
  effect(execute: () => () => void, label?: string): unknown
@@ -61,8 +61,8 @@ export function apply(ctx: Context): void {
61
61
  'access-gate: style',
62
62
  )
63
63
  c.effect(() => c.locale.register(NS, { zh, en }), 'access-gate: locale')
64
- const api = c.get('connection').api.settings
65
- const scope = createApiScope(api, SETTINGS_NS, c, 'access-gate: settings scope')
64
+ const scope = createSettingsScope(c, SETTINGS_NS, 'access-gate: settings scope')
65
+ const api = createNamespaceApi(c.get('remote').settings, SETTINGS_NS)
66
66
  c.slots.inject('settings.plugin.item', () =>
67
67
  c.slots.register(
68
68
  {