@fonlan/dsh-model-router 0.3.6 → 0.3.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/lib/client.js CHANGED
@@ -4,9 +4,32 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ //#region \0rolldown/runtime.js
8
+ var __create = Object.create;
9
+ var __defProp = Object.defineProperty;
10
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
11
+ var __getOwnPropNames = Object.getOwnPropertyNames;
12
+ var __getProtoOf = Object.getPrototypeOf;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
16
+ key = keys[i];
17
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
18
+ get: ((k) => from[k]).bind(null, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
25
+ value: mod,
26
+ enumerable: true
27
+ }) : target, mod));
28
+ //#endregion
7
29
  let react = require("react");
8
30
  let react_jsx_runtime = require("react/jsx-runtime");
9
31
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
32
+ _deepseek_ai_dsh_client_ui_primitives = __toESM(_deepseek_ai_dsh_client_ui_primitives, 1);
10
33
  //#region src/client/locales.ts
11
34
  const LOCALE_NS = "model-router";
12
35
  const zh = {
@@ -172,14 +195,14 @@ window.__ModuleLoader__.load({
172
195
  * page draws its own static header (title plus a one-line summary) over the
173
196
  * router controls: every routed model with its providers, their order and the
174
197
  * provider the model currently routes to. All reads/mutations go through the
175
- * plugin's fenced API; the server persists through the `model-router` settings
176
- * namespace, so a switch here is live for the next request globally.
198
+ * plugin's fenced API; the server persists into this plugin's loader-entry
199
+ * config (dsh >= 0.1.7), so a switch here is live for the next request
200
+ * globally.
177
201
  *
178
- * The bound settings scope (the same `model-router` namespace the host half
179
- * registers) supplies the page's dispatch state: while the namespace is merely
180
- * loading the page stays mounted, and when it is unavailable (deployment
181
- * without the host half) nothing renders. A read-only deployment shows the
182
- * banner and disables the mutation controls.
202
+ * The page needs no settings service: whether the deployment can persist is
203
+ * reported by the API itself (`state.writable`), so the page registers and
204
+ * mounts everywhere the host half serves its API. A read-only deployment
205
+ * shows the banner and disables the mutation controls.
183
206
  */
184
207
  function arrayMove(list, from, to) {
185
208
  const next = [...list];
@@ -212,9 +235,7 @@ window.__ModuleLoader__.load({
212
235
  return (key) => key;
213
236
  }
214
237
  })();
215
- return function ModelRouterSettingsSection(props) {
216
- const { scope } = props;
217
- const snapshot = (0, react.useSyncExternalStore)((listener) => scope.subscribe(listener), () => scope.getSnapshot());
238
+ return function ModelRouterSettingsSection() {
218
239
  useLocaleRevision(ctx);
219
240
  const [state, setState] = (0, react.useState)(null);
220
241
  const [error, setError] = (0, react.useState)(null);
@@ -228,7 +249,8 @@ window.__ModuleLoader__.load({
228
249
  const load = (0, react.useCallback)(async () => {
229
250
  setLoading(true);
230
251
  try {
231
- setState(await api.state());
252
+ const next = await api.state();
253
+ setState(next);
232
254
  setError(null);
233
255
  } catch (cause) {
234
256
  setError(cause instanceof Error ? cause.message : String(cause));
@@ -362,8 +384,7 @@ window.__ModuleLoader__.load({
362
384
  setSortBusy(false);
363
385
  }
364
386
  }, [state, t]);
365
- if (snapshot.status === "unavailable") return null;
366
- const writable = snapshot.writable;
387
+ const writable = state?.writable ?? true;
367
388
  const models = (0, react.useMemo)(() => state?.models ?? [], [state]);
368
389
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
369
390
  className: "mr-page",
@@ -378,7 +399,7 @@ window.__ModuleLoader__.load({
378
399
  })]
379
400
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
380
401
  className: "mr-body",
381
- children: [!writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
402
+ children: [!loading && state !== null && !writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
382
403
  className: "mr-settings-readonly",
383
404
  role: "status",
384
405
  children: t("readOnly")
@@ -664,6 +685,84 @@ window.__ModuleLoader__.load({
664
685
  });
665
686
  }
666
687
  //#endregion
688
+ //#region src/client/icons.tsx
689
+ /** The runtime export table, read by capability instead of by one hard-coded name. */
690
+ const table = _deepseek_ai_dsh_client_ui_primitives;
691
+ /** First name the runtime actually provides (a missing export is `undefined`). */
692
+ function firstDefined(...names) {
693
+ for (const name of names) {
694
+ let candidate;
695
+ try {
696
+ candidate = table[name];
697
+ } catch {
698
+ continue;
699
+ }
700
+ if (typeof candidate === "function") return candidate;
701
+ }
702
+ }
703
+ /** One-path stroked glyph fallback (16×16 viewBox — the 0.1.7 artwork). */
704
+ function glyph(path, defaultSize) {
705
+ return function Glyph({ size = defaultSize, className }) {
706
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
707
+ width: size,
708
+ height: size,
709
+ className,
710
+ viewBox: "0 0 16 16",
711
+ fill: "none",
712
+ xmlns: "http://www.w3.org/2000/svg",
713
+ "aria-hidden": "true",
714
+ strokeWidth: 1,
715
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
716
+ d: path,
717
+ stroke: "currentColor"
718
+ })
719
+ });
720
+ };
721
+ }
722
+ /** Warning circle fallback (the 0.1.7 artwork: ring, stem, dot). */
723
+ function WarningFallback({ size = 16, className }) {
724
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
725
+ width: size,
726
+ height: size,
727
+ className,
728
+ viewBox: "0 0 16 16",
729
+ fill: "none",
730
+ xmlns: "http://www.w3.org/2000/svg",
731
+ "aria-hidden": "true",
732
+ strokeWidth: 1,
733
+ children: [
734
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
735
+ d: "M8 14.5C11.5899 14.5 14.5 11.5899 14.5 8C14.5 4.41015 11.5899 1.5 8 1.5C4.41015 1.5 1.5 4.41015 1.5 8C1.5 11.5899 4.41015 14.5 8 14.5Z",
736
+ stroke: "currentColor"
737
+ }),
738
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
739
+ d: "M8 4.29199V9.79199",
740
+ stroke: "currentColor"
741
+ }),
742
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
743
+ d: "M8 10.708V11.708",
744
+ stroke: "currentColor"
745
+ })
746
+ ]
747
+ });
748
+ }
749
+ /**
750
+ * Shell icons used by the model seat.
751
+ *
752
+ * DSH 0.1.7 renamed every size-suffixed icon export (`IconCheckOutline16`,
753
+ * `IconChevronDownOutline14`, …) into stroke-weight variants (`…OutlineRegular`
754
+ * 1px / `…OutlineMedium` 1.3px). A stale named import resolves to `undefined`
755
+ * and React then throws "Element type is invalid" while rendering the slot
756
+ * entry — the whole seat is dropped from the conversation input instead of
757
+ * degrading (this is exactly what the 0.1.7 upgrade did to this plugin).
758
+ * Resolve the names at runtime, newest first, so the next rename lands on
759
+ * another shipped variant or on the inlined artwork below.
760
+ */
761
+ const CheckIcon = firstDefined("IconCheckOutlineRegular", "IconCheckOutlineMedium", "IconCheckOutline16") ?? glyph("M2.25 8.5L5.49732 11.7473C5.90519 12.1552 6.57263 12.1344 6.95426 11.7018L13.75 4", 16);
762
+ const ChevronDownIcon = firstDefined("IconChevronDownOutlineRegular", "IconChevronDownOutlineMedium", "IconChevronDownOutline14") ?? glyph("M4 6L7.29289 9.29289C7.68342 9.68342 8.31658 9.68342 8.70711 9.29289L12 6", 14);
763
+ const ChevronRightIcon = firstDefined("IconChevronRightOutlineRegular", "IconChevronRightOutlineMedium", "IconChevronRightOutline14") ?? glyph("M6 12L9.29289 8.70711C9.68342 8.31658 9.68342 7.68342 9.29289 7.29289L6 4", 14);
764
+ const WarningIcon = firstDefined("IconWarningOutlineRegular", "IconWarningOutlineMedium", "IconWarningOutline16") ?? WarningFallback;
765
+ //#endregion
667
766
  //#region \0dsh-css:/home/runner/work/dsh-model-router/dsh-model-router/src/client/model-seat.css.mjs
668
767
  const css = "/*\n * Composer model seat (shadows the host ModelSelect). Styles mirror the host\n * ModelSelect.module.css exactly (same tokens, sizes and spacing) so the\n * replacement is visually indistinguishable, plus the provider pane's title\n * and hint rows.\n */\n\n.mr-seat-root {\n min-width: 0;\n position: relative;\n}\n\n.mr-seat-trigger {\n min-width: 0;\n max-width: 220px;\n height: 28px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: 24px;\n outline: none;\n align-items: center;\n gap: 4px;\n padding: 0 4px 0 8px;\n font-size: 13px;\n font-weight: 500;\n line-height: 20px;\n display: flex;\n}\n\n.mr-seat-trigger:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.mr-seat-trigger:focus-visible {\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n.mr-seat-trigger:disabled {\n color: var(--dsw-alias-label-dimmed);\n cursor: default;\n}\n\n.mr-seat-triggerLabel {\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n overflow: hidden;\n}\n\n.mr-seat-triggerEffort {\n color: var(--dsw-alias-label-caption);\n flex: none;\n}\n\n.mr-seat-chevron {\n color: var(--dsw-alias-label-caption);\n flex: none;\n transition: transform 0.12s;\n}\n\n.mr-seat-chevronOpen {\n transform: rotate(180deg);\n}\n\n.mr-seat-menu {\n z-index: 20;\n border: 1px solid var(--dsw-alias-border-inverted);\n background: var(--dsw-specific-menu);\n width: min(240px, 100vw - 32px);\n max-height: min(360px, 100vh - 96px);\n box-shadow: var(--dsw-shadow-lv3);\n color: var(--dsw-alias-label-primary);\n --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);\n --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);\n border-radius: 12px;\n flex-direction: column;\n padding: 4px;\n display: flex;\n position: absolute;\n bottom: calc(100% + 8px);\n right: 0;\n overflow: hidden;\n}\n\n.mr-seat-status,\n.mr-seat-empty {\n color: var(--dsw-alias-label-tertiary);\n padding: 10px;\n font-size: 13px;\n line-height: 20px;\n}\n\n.mr-seat-error,\n.mr-seat-warning {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n color: var(--dsw-alias-state-error-primary);\n border-radius: 8px;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px;\n margin-bottom: 4px;\n padding: 7px 8px;\n font-size: 12px;\n line-height: 18px;\n display: flex;\n}\n\n.mr-seat-warning {\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-state-warn-label);\n}\n\n.mr-seat-retry {\n color: inherit;\n font: inherit;\n cursor: pointer;\n background: transparent;\n border: none;\n flex: none;\n padding: 0;\n font-weight: 600;\n}\n\n.mr-seat-groups {\n min-height: 0;\n overflow-y: auto;\n}\n\n.mr-seat-group + .mr-seat-group {\n margin-top: 4px;\n}\n\n.mr-seat-groupTitle {\n z-index: 1;\n background: var(--dsw-specific-menu);\n color: var(--dsw-alias-label-tertiary);\n padding: 5px 8px 3px;\n font-size: 12px;\n font-weight: 500;\n line-height: 18px;\n position: sticky;\n top: 0;\n}\n\n/* Provider pane: non-sticky title row above the provider list. */\n.mr-seat-title {\n color: var(--dsw-alias-label-tertiary);\n padding: 5px 8px 3px;\n font-size: 12px;\n font-weight: 500;\n line-height: 18px;\n}\n\n.mr-seat-option {\n width: 100%;\n min-height: 38px;\n color: inherit;\n text-align: left;\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: 10px;\n outline: none;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n display: flex;\n}\n\n.mr-seat-option:hover:not(:disabled),\n.mr-seat-option:focus-visible {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.mr-seat-selected {\n background: transparent;\n}\n\n.mr-seat-option:disabled {\n color: var(--dsw-alias-label-dimmed);\n cursor: default;\n}\n\n.mr-seat-optionCopy {\n flex-direction: column;\n flex: 1;\n min-width: 0;\n display: flex;\n}\n\n.mr-seat-modelName {\n color: inherit;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 500;\n line-height: 20px;\n overflow: hidden;\n}\n\n.mr-seat-description {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n line-height: 18px;\n overflow: hidden;\n}\n\n.mr-seat-check {\n color: var(--dsw-alias-label-primary);\n flex: 0 0 18px;\n place-items: center;\n display: grid;\n}\n\n.mr-seat-cell {\n width: 100%;\n height: 40px;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n text-align: left;\n background: transparent;\n border: none;\n border-radius: 10px;\n align-items: center;\n gap: 8px;\n padding: 0 10px;\n font-size: 14px;\n line-height: 22px;\n display: flex;\n}\n\n.mr-seat-cell:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.mr-seat-cellLabel {\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: auto;\n min-width: 0;\n overflow: hidden;\n}\n\n.mr-seat-cellValue {\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n color: var(--dsw-alias-label-tertiary);\n flex: 0 auto;\n overflow: hidden;\n}\n\n.mr-seat-cellChevron {\n color: var(--dsw-alias-label-tertiary);\n flex: none;\n}\n\n/* Global hint footer of the provider pane. */\n.mr-seat-hint {\n color: var(--dsw-alias-label-tertiary);\n padding: 5px 8px 3px;\n font-size: 12px;\n line-height: 18px;\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin-top: 4px;\n}\n\n/*\n * Mobile portrait: the composer row is an inline-size container. With the\n * quick route switcher gone from the right tool row, let the model seat\n * absorb the remaining row width (same rule the old switcher enforced).\n * The breakpoint matches DSH's own narrow-composer rule (<=460px).\n */\n@container (width <= 460px) {\n [data-slot=\"conversation.input.model\"] > * {\n flex: 1 1 0;\n min-width: 0;\n max-width: 100%;\n }\n\n [data-slot=\"conversation.input.model\"] [aria-haspopup=\"menu\"] {\n width: 100%;\n max-width: 100%;\n }\n}\n";
669
768
  const tagId = "@fonlan/dsh-model-router/model-seat.css";
@@ -942,7 +1041,7 @@ window.__ModuleLoader__.load({
942
1041
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
943
1042
  className: `mr-seat-chevron${open ? " mr-seat-chevronOpen" : ""}`,
944
1043
  "aria-hidden": true,
945
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})
1044
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, {})
946
1045
  })
947
1046
  ]
948
1047
  }),
@@ -972,7 +1071,7 @@ window.__ModuleLoader__.load({
972
1071
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
973
1072
  className: "mr-seat-cellChevron",
974
1073
  "aria-hidden": true,
975
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {})
1074
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronRightIcon, {})
976
1075
  })
977
1076
  ]
978
1077
  }),
@@ -994,7 +1093,7 @@ window.__ModuleLoader__.load({
994
1093
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
995
1094
  className: "mr-seat-cellChevron",
996
1095
  "aria-hidden": true,
997
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {})
1096
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronRightIcon, {})
998
1097
  })
999
1098
  ]
1000
1099
  }),
@@ -1016,7 +1115,7 @@ window.__ModuleLoader__.load({
1016
1115
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1017
1116
  className: "mr-seat-cellChevron",
1018
1117
  "aria-hidden": true,
1019
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {})
1118
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronRightIcon, {})
1020
1119
  })
1021
1120
  ]
1022
1121
  })
@@ -1085,7 +1184,7 @@ window.__ModuleLoader__.load({
1085
1184
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1086
1185
  className: "mr-seat-check",
1087
1186
  "aria-hidden": true,
1088
- children: selected ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutline16, {}) : null
1187
+ children: selected ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}) : null
1089
1188
  })]
1090
1189
  }, model.id);
1091
1190
  })]
@@ -1140,7 +1239,7 @@ window.__ModuleLoader__.load({
1140
1239
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1141
1240
  className: "mr-seat-check",
1142
1241
  "aria-hidden": true,
1143
- children: selected ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutline16, {}) : null
1242
+ children: selected ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}) : null
1144
1243
  })]
1145
1244
  }, provider.id);
1146
1245
  })
@@ -1181,26 +1280,33 @@ window.__ModuleLoader__.load({
1181
1280
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1182
1281
  className: "mr-seat-check",
1183
1282
  "aria-hidden": true,
1184
- children: effectiveEffort === level.effort ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutline16, {}) : null
1283
+ children: effectiveEffort === level.effort ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}) : null
1185
1284
  })]
1186
1285
  }, level.key))] })
1187
1286
  ]
1188
1287
  }),
1189
1288
  toast !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
1190
1289
  text: toast.text,
1191
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutline16, {}),
1290
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WarningIcon, {}),
1192
1291
  anchor: rootRef.current?.closest("[data-composer-card]") ?? null,
1193
1292
  onDone: () => setToast(null)
1194
1293
  }, toast.seq)
1195
1294
  ]
1196
1295
  });
1197
1296
  }
1297
+ /**
1298
+ * Idle directory snapshot for the inert seat face. Mirrors the shape the
1299
+ * official `ModelDirectory` store starts from, including `pending` (the
1300
+ * selection an in-flight `select` submitted; null when none) — required by
1301
+ * `ModelDirectoryState` and present in both 0.1.x and 0.2.x.
1302
+ */
1198
1303
  const EMPTY_DIRECTORY_STATE = {
1199
1304
  current: null,
1200
1305
  routable: null,
1201
1306
  groups: [],
1202
1307
  failures: [],
1203
1308
  status: "idle",
1309
+ pending: null,
1204
1310
  error: null
1205
1311
  };
1206
1312
  /**
@@ -1279,8 +1385,6 @@ window.__ModuleLoader__.load({
1279
1385
  }
1280
1386
  //#endregion
1281
1387
  //#region src/client/index.tsx
1282
- /** The settings namespace this page edits (must match the host half). */
1283
- const ROUTER_NS = "model-router";
1284
1388
  /** The settings sidebar entry this page owns (must stay stable). */
1285
1389
  const SECTION_ID = "model-router";
1286
1390
  /** Services required before mounting (provided by the client runtime).
@@ -1292,7 +1396,6 @@ window.__ModuleLoader__.load({
1292
1396
  "locale",
1293
1397
  "modelDirectories",
1294
1398
  "sessions",
1295
- "settingsScope",
1296
1399
  "connection",
1297
1400
  "remote",
1298
1401
  "remote.session"
@@ -1308,15 +1411,13 @@ window.__ModuleLoader__.load({
1308
1411
  }, "model-router: dictionaries");
1309
1412
  const t = ctx.locale.bind(LOCALE_NS);
1310
1413
  const SettingsSection = makeSettingsSection(ctx);
1311
- const services = ctx;
1312
- const scope = services.settingsScope.bind({ namespace: ROUTER_NS });
1313
- services.slots.inject("settings.section", () => services.slots.register({
1414
+ const slots = ctx.slots;
1415
+ slots.inject("settings.section", () => slots.register({
1314
1416
  name: "settings.section",
1315
1417
  id: SECTION_ID,
1316
1418
  order: 300,
1317
1419
  label: () => t("settingsTitle"),
1318
- locale: LOCALE_NS,
1319
- inject: () => ({ scope })
1420
+ locale: LOCALE_NS
1320
1421
  }, SettingsSection));
1321
1422
  registerModelRouterSeat(ctx);
1322
1423
  }