@dsh-plus/access-gate 0.1.3 → 0.2.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/lib/client.js CHANGED
@@ -91,41 +91,6 @@ window.__ModuleLoader__.load({
91
91
  }
92
92
  //#endregion
93
93
  //#region ../shared/src/client/fields.tsx
94
- function TextField(props) {
95
- const p = props.prefix ?? "dshp";
96
- const invalid = props.invalid === true;
97
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
98
- className: `${p}-field`,
99
- children: [
100
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
101
- className: `${p}-head`,
102
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
103
- className: `${p}-label`,
104
- htmlFor: props.id,
105
- children: props.label
106
- }), props.badge !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
107
- className: `${p}-badge ${props.badge.set ? `${p}-badgeSet` : `${p}-badgeUnset`}`,
108
- children: props.badge.text
109
- }) : null]
110
- }),
111
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
112
- id: props.id,
113
- className: `${p}-input${invalid ? ` ${p}-inputInvalid` : ""}`,
114
- type: props.password === true ? "password" : "text",
115
- inputMode: props.numeric === true ? "numeric" : void 0,
116
- autoComplete: props.password === true ? "off" : void 0,
117
- "aria-invalid": invalid || void 0,
118
- value: props.value,
119
- disabled: props.disabled === true,
120
- onChange: (event) => props.onEdit(event.target.value)
121
- }),
122
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
123
- className: invalid ? `${p}-invalid` : `${p}-hint`,
124
- children: invalid ? props.invalidLabel ?? "" : props.hint ?? ""
125
- })
126
- ]
127
- });
128
- }
129
94
  /**
130
95
  * 勾选行:自绘圆角扁平开关(switch),对齐官方 WebUI 无原生 checkbox 的
131
96
  * 设计语言(官方选择类控件全走胶囊/菜单,见 cardCss 的 -switch 规则)。
@@ -196,14 +161,15 @@ window.__ModuleLoader__.load({
196
161
  //#endregion
197
162
  //#region ../shared/src/client/scope.ts
198
163
  /**
199
- * api 直连实现的命名空间 scope(官方配置页 tab 同款模式)。
164
+ * remote.settings 直连实现的命名空间 scope(官方配置页 tab 同款模式)。
200
165
  * 读:describe 取命名空间视图(脱敏 value/revision + 顶层 writable);
201
166
  * 刷新:remote `settings/document-updated`(按命名空间过滤)与
202
167
  * `connection/reset`;generation 防旧读覆盖新发布。任何页面 origin
203
168
  * (loopback 或 tailnet 信任域名)下行为一致。
204
169
  * effect 归属调用方 fiber(label 需含插件名以便诊断)。
205
170
  */
206
- function createApiScope(api, ns, c, label) {
171
+ function createSettingsScope(c, ns, label) {
172
+ const remote = c.get("remote");
207
173
  let state = {
208
174
  status: "loading",
209
175
  value: void 0,
@@ -218,36 +184,37 @@ window.__ModuleLoader__.load({
218
184
  };
219
185
  const load = async () => {
220
186
  const gen = ++generation;
221
- let response;
187
+ let view;
222
188
  try {
223
- response = await api.describe({});
189
+ const response = await remote.settings.describe();
190
+ if (!response.ok) return;
191
+ view = response.value;
224
192
  } catch {
225
193
  return;
226
194
  }
227
- if (gen !== generation || !response.result.ok) return;
228
- const writable = response.result.value?.writable ?? false;
229
- const view = response.result.value?.namespaces.find((candidate) => candidate.ns === ns);
230
- if (view === void 0) {
195
+ if (gen !== generation) return;
196
+ const namespace = view.namespaces.find((candidate) => candidate.ns === ns);
197
+ if (namespace === void 0) {
231
198
  publish({
232
199
  status: "unavailable",
233
200
  value: void 0,
234
201
  revision: void 0,
235
- writable
202
+ writable: view.writable
236
203
  });
237
204
  return;
238
205
  }
239
206
  publish({
240
207
  status: "ready",
241
- value: view.value,
242
- revision: view.revision,
243
- writable
208
+ value: namespace.value,
209
+ revision: namespace.revision,
210
+ writable: view.writable
244
211
  });
245
212
  };
246
213
  const refresh = (namespace) => {
247
214
  if (namespace !== void 0 && namespace !== ns) return;
248
215
  load();
249
216
  };
250
- const disposers = [c.get("remote").$on("settings/document-updated", refresh), c.on("connection/reset", () => {
217
+ const disposers = [remote.$on("settings/document-updated", refresh), c.on("connection/reset", () => {
251
218
  load();
252
219
  })];
253
220
  c.effect(() => () => {
@@ -265,6 +232,20 @@ window.__ModuleLoader__.load({
265
232
  load
266
233
  };
267
234
  }
235
+ /** 以 remote.settings 构造命名空间绑定的 api 面。 */
236
+ function createNamespaceApi(remote, ns) {
237
+ return {
238
+ update: async (patch, expectedRevision) => {
239
+ const response = await remote.update(ns, patch, expectedRevision);
240
+ if (!response.ok) throw new Error(response.error.message ?? "settings update failed");
241
+ },
242
+ describe: async () => {
243
+ const response = await remote.describe();
244
+ if (!response.ok) throw new Error(response.error.message ?? "settings describe failed");
245
+ return response.value;
246
+ }
247
+ };
248
+ }
268
249
  //#endregion
269
250
  //#region ../shared/src/client/styles.ts
270
251
  /**
@@ -379,47 +360,39 @@ ${extra}
379
360
  /**
380
361
  * 「访问控制」配置卡片:注册进 settings.plugin.item 插槽(官方插件配置页)。
381
362
  * 外壳与基础控件走 @dsh-plus/shared/client 套件(CardChrome/TextField/CheckRow),
382
- * 本文件保留业务字段(token/白名单 textarea/诊断面板)与保存逻辑。
383
- * 配置读写走官方 settingsScope 传输:value 为 schema 解析后的脱敏视图
384
- * (token 不出现,tokenConfigured 经 describe 的 secrets 探测),
385
- * 保存经 settings.update 深合并(空 token 剔除 = 保持不变)。
386
- * 卡片顶部「当前页面诊断」读 /dsh-plus/gate/status(本页放行原因/客户端 IP)。
363
+ * 本文件保留业务字段(白名单 textarea/诊断面板)与保存逻辑。
364
+ * 配置读写走官方 settingsScope 传输:value 为 schema 解析后的视图,
365
+ * 保存经 settings.update 深合并。
366
+ * 卡片顶部「当前页面诊断」读 /dsh-plus/gate/status(本页放行原因/客户端 IP/
367
+ * 官方 cookie 状态)。
368
+ *
369
+ * 与官方认证合并后:访问凭据由官方 browser-auth 持有(30 天 cookie),
370
+ * 卡片不再管理令牌;allowedIps 仅为可选附加 IP 围栏。
387
371
  * @module access-gate/client/card
388
372
  */
389
373
  function draftFromValue(value) {
390
374
  return {
391
375
  enabled: value.enabled,
392
- token: "",
393
376
  allowedIpsText: value.allowedIps.join("\n"),
394
- trustForwardedFor: value.trustForwardedFor,
395
- cookieMaxAgeHours: String(value.cookieMaxAgeHours),
396
- loginFailLimit: String(value.loginFailLimit),
397
- loginCooldownMs: String(value.loginCooldownMs)
377
+ trustForwardedFor: value.trustForwardedFor
398
378
  };
399
379
  }
400
- function isPositiveInt(text) {
401
- return /^[0-9]+$/.test(text) && Number(text) > 0;
402
- }
403
380
  function toPatch(draft) {
404
381
  return {
405
382
  enabled: draft.enabled,
406
383
  allowedIps: draft.allowedIpsText.split("\n").map((s) => s.trim()).filter((s) => s.length > 0),
407
- trustForwardedFor: draft.trustForwardedFor,
408
- cookieMaxAgeHours: Number(draft.cookieMaxAgeHours),
409
- loginFailLimit: Number(draft.loginFailLimit),
410
- loginCooldownMs: Number(draft.loginCooldownMs)
384
+ trustForwardedFor: draft.trustForwardedFor
411
385
  };
412
386
  }
413
387
  /** reason 枚举 → 文案 key。 */
414
388
  const REASON_KEYS = {
415
389
  local: "diagLocal",
416
- "allowed-ip": "diagAllowedIp",
417
- token: "diagToken"
390
+ cookie: "diagCookie"
418
391
  };
419
392
  function verdictLabel(t, diag) {
420
393
  if (!diag.enabled) return t("diagOff");
421
394
  if (diag.verdict === "pass") return t("diagPass");
422
- if (diag.verdict === "login") return t("diagLogin");
395
+ if (diag.verdict === "token-page") return t("diagTokenPage");
423
396
  return t("diagBlock");
424
397
  }
425
398
  function AccessGateCard(props) {
@@ -428,7 +401,6 @@ ${extra}
428
401
  const value = snapshot.value;
429
402
  const [open, setOpen] = (0, react.useState)(false);
430
403
  const [draft, setDraft] = (0, react.useState)(null);
431
- const [tokenConfigured, setTokenConfigured] = (0, react.useState)(false);
432
404
  const [diag, setDiag] = (0, react.useState)(null);
433
405
  const [saving, setSaving] = (0, react.useState)(false);
434
406
  const [status, setStatus] = (0, react.useState)(IDLE_STATUS);
@@ -436,17 +408,6 @@ ${extra}
436
408
  if (value === void 0 || draft !== null) return;
437
409
  setDraft(draftFromValue(value));
438
410
  }, [value, draft]);
439
- (0, react.useEffect)(() => {
440
- let alive = true;
441
- api.describe({}).then((response) => {
442
- if (!alive || !response.result.ok) return;
443
- const view = response.result.value?.namespaces.find((ns) => ns.ns === SETTINGS_NS);
444
- setTokenConfigured(view?.secrets.some((secret) => secret.path.join(".") === "token" && secret.set) ?? false);
445
- }).catch(() => {});
446
- return () => {
447
- alive = false;
448
- };
449
- }, [api, snapshot]);
450
411
  (0, react.useEffect)(() => {
451
412
  let alive = true;
452
413
  fetch("/dsh-plus/gate/status").then((res) => res.ok ? res.json() : null).then((body) => {
@@ -456,9 +417,7 @@ ${extra}
456
417
  alive = false;
457
418
  };
458
419
  }, [snapshot]);
459
- const failClosed = (0, react.useMemo)(() => value?.enabled === true && value.allowedIps.length === 0 && !tokenConfigured, [value, tokenConfigured]);
460
420
  const dirty = (0, react.useMemo)(() => value !== void 0 && draft !== null && JSON.stringify(toPatch(draft)) !== JSON.stringify(toPatch(draftFromValue(value))), [value, draft]);
461
- const invalid = (0, react.useMemo)(() => draft !== null && (!isPositiveInt(draft.cookieMaxAgeHours) || !isPositiveInt(draft.loginFailLimit) || !isPositiveInt(draft.loginCooldownMs)), [draft]);
462
421
  if (value === void 0 || draft === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
463
422
  className: "dag-card",
464
423
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -476,14 +435,8 @@ ${extra}
476
435
  const onSave = () => {
477
436
  setSaving(true);
478
437
  const patch = toPatch(draft);
479
- if (draft.token !== "") patch.token = draft.token;
480
438
  const revision = scope.getSnapshot().revision;
481
- api.update({
482
- ns: SETTINGS_NS,
483
- patch,
484
- ...revision !== void 0 ? { expectedRevision: revision } : {}
485
- }).then(async (response) => {
486
- if (!response.result.ok) throw new Error(response.result.error?.message ?? t("saveFailed"));
439
+ api.update(patch, revision).then(async () => {
487
440
  await scope.load();
488
441
  const next = scope.getSnapshot().value;
489
442
  if (next !== void 0) setDraft(draftFromValue(next));
@@ -523,14 +476,14 @@ ${extra}
523
476
  key: "save",
524
477
  label: t(saving ? "saving" : "save"),
525
478
  variant: "primary",
526
- disabled: !dirty || invalid || saving || disabled,
479
+ disabled: !dirty || saving || disabled,
527
480
  onClick: onSave
528
481
  }],
529
482
  children: [
530
- failClosed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
531
- className: "dag-warn",
532
- children: t("warnFailClosed")
533
- }) : null,
483
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
484
+ className: "dag-hint",
485
+ children: t("mergedHint")
486
+ }),
534
487
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckRow, {
535
488
  prefix: "dag",
536
489
  id: "dag-enabled",
@@ -539,20 +492,6 @@ ${extra}
539
492
  disabled,
540
493
  onEdit: (v) => edit("enabled", v)
541
494
  }),
542
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
543
- prefix: "dag",
544
- id: "dag-token",
545
- label: t("token"),
546
- hint: t("tokenHint"),
547
- value: draft.token,
548
- password: true,
549
- disabled,
550
- badge: {
551
- text: t(tokenConfigured ? "tokenSet" : "tokenUnset"),
552
- set: tokenConfigured
553
- },
554
- onEdit: (v) => edit("token", v)
555
- }),
556
495
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
557
496
  className: "dag-field",
558
497
  children: [
@@ -586,42 +525,6 @@ ${extra}
586
525
  disabled,
587
526
  onEdit: (v) => edit("trustForwardedFor", v)
588
527
  }),
589
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
590
- prefix: "dag",
591
- id: "dag-cookie",
592
- label: t("cookieMaxAgeHours"),
593
- hint: t("cookieMaxAgeHoursHint"),
594
- value: draft.cookieMaxAgeHours,
595
- numeric: true,
596
- disabled,
597
- invalid: !isPositiveInt(draft.cookieMaxAgeHours),
598
- invalidLabel: t("invalidNumber"),
599
- onEdit: (v) => edit("cookieMaxAgeHours", v)
600
- }),
601
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
602
- prefix: "dag",
603
- id: "dag-faillimit",
604
- label: t("loginFailLimit"),
605
- hint: t("loginFailLimitHint"),
606
- value: draft.loginFailLimit,
607
- numeric: true,
608
- disabled,
609
- invalid: !isPositiveInt(draft.loginFailLimit),
610
- invalidLabel: t("invalidNumber"),
611
- onEdit: (v) => edit("loginFailLimit", v)
612
- }),
613
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TextField, {
614
- prefix: "dag",
615
- id: "dag-cooldown",
616
- label: t("loginCooldownMs"),
617
- hint: t("loginCooldownMsHint"),
618
- value: draft.loginCooldownMs,
619
- numeric: true,
620
- disabled,
621
- invalid: !isPositiveInt(draft.loginCooldownMs),
622
- invalidLabel: t("invalidNumber"),
623
- onEdit: (v) => edit("loginCooldownMs", v)
624
- }),
625
528
  diag !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
626
529
  className: `dag-diag${diag.invalidEntries.length > 0 ? " dag-diagWarn" : ""}`,
627
530
  children: [
@@ -659,6 +562,16 @@ ${extra}
659
562
  children: diag.reason !== null ? t(REASON_KEYS[diag.reason] ?? diag.reason) : "—"
660
563
  })]
661
564
  }),
565
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
566
+ className: "dag-diagRow",
567
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
568
+ className: "dag-diagKey",
569
+ children: t("diagOfficial")
570
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
571
+ className: "dag-diagVal",
572
+ children: diag.officialAuthed ? t("diagOfficialYes") : t("diagOfficialNo")
573
+ })]
574
+ }),
662
575
  diag.invalidEntries.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
663
576
  className: "dag-diagRow",
664
577
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -684,69 +597,53 @@ ${extra}
684
597
  const NS = "dsh-plus-access-gate";
685
598
  const ownZh = {
686
599
  title: "访问控制",
687
- description: "Web 访问围栏:本机直连放行;远程按白名单 IP 或访问令牌放行,其余拦截到登录页。",
600
+ description: "Web 访问围栏:与官方登录合并——官方 cookie 为唯一凭据;未认证导航显示启动令牌输入页(PWA 内可用);可选 IP 附加围栏。",
688
601
  enabled: "启用访问围栏",
689
- enabledHint: "关闭即完全旁路(等价插件缺席);启用后远程流量需命中白名单或令牌。",
690
- token: "访问令牌",
691
- tokenHint: "留空表示保持已存令牌不变;清空并保存需先输入既有令牌确认。",
692
- tokenSet: "已配置",
693
- tokenUnset: "未配置",
694
- allowedIps: "放行 IP 白名单",
695
- allowedIpsHint: "每行一个:精确 IP 或 CIDR(IPv4/IPv6 皆可),如 100.86.108.55 或 fd7a:115c:a1e0::/48。",
602
+ enabledHint: "关闭即完全旁路(等价插件缺席);启用后未认证流量被拦截到令牌输入页或拒绝。",
603
+ mergedHint: "登录凭据由官方认证持有(启动令牌换 30 天 cookie)。获取当前令牌:服务器执行 dshctl url,或本机访问 /dsh-plus/gate/launch-url。",
604
+ allowedIps: "附加 IP 围栏白名单",
605
+ allowedIpsHint: "每行一个:精确 IP 或 CIDR(IPv4/IPv6 皆可)。非空时仅白名单来源可通行与登录;留空 = 不限制来源 IP(仅官方登录保护)。",
696
606
  trustForwardedFor: "信任 x-forwarded-for 还原客户端 IP",
697
607
  trustForwardedForHint: "仅当入口代理强制覆盖该头时开启(tailscale serve 满足);直连暴露场景必须关闭。",
698
- cookieMaxAgeHours: "登录有效期(小时)",
699
- cookieMaxAgeHoursHint: "令牌登录后 cookie 的有效期。",
700
- loginFailLimit: "登录失败阈值",
701
- loginFailLimitHint: "每个 IP 在冷却窗口内允许的失败次数,超出进入冷却。",
702
- loginCooldownMs: "登录冷却(毫秒)",
703
- loginCooldownMsHint: "失败达到阈值后的冷却时长。",
704
608
  diagTitle: "当前页面诊断",
705
609
  diagVerdict: "本页判定",
706
610
  diagClientIp: "客户端 IP",
707
611
  diagReason: "放行原因",
708
612
  diagLocal: "本机直连",
709
- diagAllowedIp: "白名单 IP",
710
- diagToken: "令牌",
613
+ diagCookie: "官方 cookie",
614
+ diagOfficial: "官方登录状态",
615
+ diagOfficialYes: "已登录",
616
+ diagOfficialNo: "未登录",
711
617
  diagPass: "放行",
712
618
  diagBlock: "拦截",
713
- diagLogin: "登录页",
619
+ diagTokenPage: "令牌输入页",
714
620
  diagOff: "围栏未启用",
715
- diagInvalid: "白名单存在无法解析的条目:",
716
- warnFailClosed: "警告:已启用但令牌与白名单均为空——所有远程访问将被拒绝(含本页之外的设备)。"
621
+ diagInvalid: "白名单存在无法解析的条目:"
717
622
  };
718
623
  const ownEn = {
719
624
  title: "Access Control",
720
- description: "Web access gate: loopback passes; remote traffic needs an allowlisted IP or the token, others hit the login page.",
625
+ 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.",
721
626
  enabled: "Enable access gate",
722
- enabledHint: "Off means full bypass (as if absent); on, remote traffic must match the allowlist or the token.",
723
- token: "Access token",
724
- tokenHint: "Leave blank to keep the stored token; clearing requires typing the current one.",
725
- tokenSet: "Set",
726
- tokenUnset: "Not set",
727
- allowedIps: "Allowed IP allowlist",
728
- allowedIpsHint: "One per line: exact IP or CIDR (IPv4/IPv6), e.g. 100.86.108.55 or fd7a:115c:a1e0::/48.",
627
+ enabledHint: "Off means full bypass (as if absent); on, unauthenticated traffic hits the token page or is refused.",
628
+ 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.",
629
+ allowedIps: "Additional IP fence allowlist",
630
+ allowedIpsHint: "One per line: exact IP or CIDR (IPv4/IPv6). When non-empty only listed sources may pass or log in; empty = no IP restriction (official login only).",
729
631
  trustForwardedFor: "Trust x-forwarded-for for client IP",
730
632
  trustForwardedForHint: "Enable only when the entry proxy overwrites that header (tailscale serve does); must be off for direct exposure.",
731
- cookieMaxAgeHours: "Login validity (hours)",
732
- cookieMaxAgeHoursHint: "Cookie lifetime after a token login.",
733
- loginFailLimit: "Login failure limit",
734
- loginFailLimitHint: "Failures per IP within the cooldown window before throttling.",
735
- loginCooldownMs: "Login cooldown (ms)",
736
- loginCooldownMsHint: "Cooldown duration after reaching the limit.",
737
633
  diagTitle: "This page",
738
634
  diagVerdict: "Verdict",
739
635
  diagClientIp: "Client IP",
740
636
  diagReason: "Reason",
741
637
  diagLocal: "loopback",
742
- diagAllowedIp: "allowlisted IP",
743
- diagToken: "token",
638
+ diagCookie: "official cookie",
639
+ diagOfficial: "Official login",
640
+ diagOfficialYes: "authenticated",
641
+ diagOfficialNo: "not authenticated",
744
642
  diagPass: "pass",
745
643
  diagBlock: "blocked",
746
- diagLogin: "login page",
644
+ diagTokenPage: "token page",
747
645
  diagOff: "gate disabled",
748
- diagInvalid: "Allowlist entries that failed to parse:",
749
- warnFailClosed: "Warning: enabled with no token and an empty allowlist — all remote access will be refused."
646
+ diagInvalid: "Allowlist entries that failed to parse:"
750
647
  };
751
648
  const zh = mergeDict(commonZh, ownZh);
752
649
  const en = mergeDict(commonEn, ownEn);
@@ -787,8 +684,8 @@ ${extra}
787
684
  const inject = [
788
685
  "slots",
789
686
  "locale",
790
- "connection",
791
- "remote"
687
+ "remote",
688
+ "remote.settings"
792
689
  ];
793
690
  function apply(ctx) {
794
691
  const c = ctx;
@@ -800,8 +697,8 @@ ${extra}
800
697
  zh,
801
698
  en
802
699
  }), "access-gate: locale");
803
- const api = c.get("connection").api.settings;
804
- const scope = createApiScope(api, SETTINGS_NS, c, "access-gate: settings scope");
700
+ const scope = createSettingsScope(c, SETTINGS_NS, "access-gate: settings scope");
701
+ const api = createNamespaceApi(c.get("remote").settings, SETTINGS_NS);
805
702
  c.slots.inject("settings.plugin.item", () => c.slots.register({
806
703
  name: "settings.plugin.item",
807
704
  key: SETTINGS_NS,
package/lib/index.d.ts CHANGED
@@ -3,26 +3,18 @@ import z from "@deepseek-ai/schemastery";
3
3
  //#region src/config.d.ts
4
4
  declare const Config: z<Schemastery.ObjectS<{
5
5
  enabled: z<boolean, boolean>;
6
- token: z<string, string>;
7
6
  allowedIps: z<string[], string[]>;
8
7
  trustForwardedFor: z<boolean, boolean>;
9
- cookieMaxAgeHours: z<number, number>;
10
- loginFailLimit: z<number, number>;
11
- loginCooldownMs: z<number, number>;
12
8
  }>, Schemastery.ObjectT<{
13
9
  enabled: z<boolean, boolean>;
14
- token: z<string, string>;
15
10
  allowedIps: z<string[], string[]>;
16
11
  trustForwardedFor: z<boolean, boolean>;
17
- cookieMaxAgeHours: z<number, number>;
18
- loginFailLimit: z<number, number>;
19
- loginCooldownMs: z<number, number>;
20
12
  }>>;
21
13
  type AccessGateConfig = Schemastery.TypeT<typeof Config>;
22
14
  //#endregion
23
15
  //#region src/index.d.ts
24
16
  declare const name = "dsh-plus-access-gate";
25
- declare const inject: readonly ["webServer"];
17
+ declare const inject: readonly ["webServer", "connection"];
26
18
  declare module '@deepseek-ai/cordis' {
27
19
  interface Context {
28
20
  accessGate: AccessGateService;