@dshtrading/client-ui-updater 0.2.0 → 0.3.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.
@@ -1,13 +1,8 @@
1
1
  //#region src/client/contract.d.ts
2
- /**
3
- * Locale contract for the updater settings section. The zh dictionary in
4
- * locales.ts is the key source of truth; this union + the LocaleNamespaceMap
5
- * merge give the framework-injected t seat its key types.
6
- */
7
- type UpdaterLocaleKey = 'nav' | 'lead' | 'currentVersion' | 'desktopApp' | 'unsupported' | 'viewReleases' | 'checkNow' | 'checking' | 'lastCheck' | 'never' | 'upToDate' | 'available' | 'publishedAt' | 'notesTitle' | 'applyNow' | 'payloadMissing' | 'phase.prepare' | 'phase.download' | 'phase.verify' | 'phase.install' | 'progress' | 'done' | 'restartHint' | 'restartNow' | 'restartManual' | 'checkError' | 'retry';
2
+ type UpdaterLocaleKey = 'nav' | 'lead' | 'currentVersion' | 'desktopApp' | 'unsupported' | 'viewReleases' | 'checkNow' | 'checking' | 'lastCheck' | 'never' | 'upToDate' | 'available' | 'publishedAt' | 'notesTitle' | 'applyNow' | 'payloadMissing' | 'phase.prepare' | 'phase.download' | 'phase.verify' | 'phase.install' | 'progress' | 'done' | 'restartHint' | 'restartNow' | 'restartManual' | 'checkError' | 'retry' | 'close';
8
3
  declare module '@deepseek-ai/dsh-client-ui-slots' {
9
4
  interface LocaleNamespaceMap {
10
- /** Updater settings section copy (check / notes / incremental apply). */
5
+ /** Software-update dialog copy (check / notes / incremental apply). */
11
6
  'dshtrading.updater': UpdaterLocaleKey;
12
7
  }
13
8
  }
@@ -26,7 +26,8 @@ const zh = {
26
26
  restartNow: "重启应用",
27
27
  restartManual: "请手动重启 DSH Trading 以完成更新。",
28
28
  checkError: "检查失败:{message}",
29
- retry: "重试"
29
+ retry: "重试",
30
+ close: "关闭"
30
31
  };
31
32
  const en = {
32
33
  nav: "Software updates",
@@ -55,7 +56,8 @@ const en = {
55
56
  restartNow: "Restart app",
56
57
  restartManual: "Please restart DSH Trading manually to finish the update.",
57
58
  checkError: "Check failed: {message}",
58
- retry: "Retry"
59
+ retry: "Retry",
60
+ close: "Close"
59
61
  };
60
62
  //#endregion
61
63
  export { en, zh };
package/lib/client.js CHANGED
@@ -34,7 +34,8 @@ window.__ModuleLoader__.load({
34
34
  restartNow: "重启应用",
35
35
  restartManual: "请手动重启 DSH Trading 以完成更新。",
36
36
  checkError: "检查失败:{message}",
37
- retry: "重试"
37
+ retry: "重试",
38
+ close: "关闭"
38
39
  };
39
40
  const en = {
40
41
  nav: "Software updates",
@@ -63,9 +64,25 @@ window.__ModuleLoader__.load({
63
64
  restartNow: "Restart app",
64
65
  restartManual: "Please restart DSH Trading manually to finish the update.",
65
66
  checkError: "Check failed: {message}",
66
- retry: "Retry"
67
+ retry: "Retry",
68
+ close: "Close"
67
69
  };
68
70
  //#endregion
71
+ //#region src/client/contract.ts
72
+ /**
73
+ * Window event contract with the trading shell sidebar (client-ui-trading
74
+ * MarketDock update entry). Cross-plugin coupling is intentionally a DOM
75
+ * custom event, not an import (client plugins never import each other's
76
+ * modules).
77
+ *
78
+ * - UPDATE_AVAILABLE_EVENT: fired by the dialog whenever the host snapshot
79
+ * changes. Detail: { available: boolean, version?: string }.
80
+ * - UPDATER_OPEN_EVENT: fired by the sidebar update entry to ask this plugin
81
+ * to open its dialog. No detail.
82
+ */
83
+ const UPDATE_AVAILABLE_EVENT = "dshtrading-update-available";
84
+ const UPDATER_OPEN_EVENT = "dshtrading-updater-open";
85
+ //#endregion
69
86
  //#region src/client/api.ts
70
87
  var UpdaterBridgeError = class extends Error {
71
88
  status;
@@ -112,65 +129,56 @@ window.__ModuleLoader__.load({
112
129
  return window.desktop;
113
130
  }
114
131
  //#endregion
115
- //#region src/client/contract.ts
116
- /**
117
- * Window event contract with the trading shell rail (client-ui-trading
118
- * SessionRail badge). Cross-plugin coupling is intentionally a DOM custom
119
- * event, not an import (client plugins never import each other's modules).
120
- * Detail: { available: boolean, version?: string }.
121
- */
122
- const UPDATE_AVAILABLE_EVENT = "dshtrading-update-available";
123
- //#endregion
124
- //#region \0dsh-css:/home/runner/work/dsh-trading/dsh-trading/packages/client-ui-updater/src/client/updater-section.module.css.mjs
125
- const css = ".D0_G6G_root{--upd-text-primary:var(--dsw-alias-text-primary,#1a1e24);--upd-text-secondary:var(--dsw-alias-text-secondary,#5f6672);--upd-text-muted:var(--dsw-alias-text-muted,#8e95a3);--upd-border:var(--dsw-alias-border-l2,#e3e6ea);--upd-bg-hover:var(--dsw-alias-fill-hover,#0000000a);--upd-bg-active:var(--dsw-alias-primary-bg,#2563eb0f);--upd-primary:var(--dsw-alias-primary,#2563eb);--upd-ok:#16a34a;--upd-danger:#dc2626;color:var(--upd-text-primary);flex-direction:column;gap:16px;padding:4px 0 24px;font-size:13px;display:flex}body[data-ds-dark-theme] .D0_G6G_root,[data-theme=dark] .D0_G6G_root,:root[data-theme=dark] .D0_G6G_root,html.dark .D0_G6G_root,body.dark .D0_G6G_root{--upd-text-primary:var(--dsw-alias-text-primary,#f3f4f6);--upd-text-secondary:var(--dsw-alias-text-secondary,#9ca3af);--upd-text-muted:var(--dsw-alias-text-muted,#6b7280);--upd-border:var(--dsw-alias-border-l2,#ffffff1a);--upd-bg-hover:var(--dsw-alias-fill-hover,#ffffff0f);--upd-bg-active:#2563eb29;--upd-primary:#3b82f6;--upd-ok:#4ade80;--upd-danger:#f87171}.D0_G6G_lead{color:var(--upd-text-secondary);margin:0;font-size:13.5px;line-height:1.6}.D0_G6G_versions{border:1px solid var(--upd-border);background:var(--upd-bg-hover);border-radius:8px;flex-wrap:wrap;gap:6px 24px;padding:10px 12px;display:flex}.D0_G6G_versionItem{flex-direction:column;gap:2px;display:flex}.D0_G6G_versionLabel{color:var(--upd-text-muted);font-size:11.5px}.D0_G6G_versionValue{font-variant-numeric:tabular-nums;font-size:13px;font-weight:600}.D0_G6G_statusRow{flex-wrap:wrap;align-items:center;gap:12px;display:flex}.D0_G6G_statusText{color:var(--upd-text-secondary)}.D0_G6G_statusTextOk{color:var(--upd-ok)}.D0_G6G_statusTextAvailable{color:var(--upd-primary);font-weight:600}.D0_G6G_statusTextError{color:var(--upd-danger)}.D0_G6G_availableCard{border:1px solid var(--upd-primary);background:var(--upd-bg-active);border-radius:8px;flex-direction:column;gap:10px;padding:14px;display:flex}.D0_G6G_availableTitle{color:var(--upd-primary);margin:0;font-size:14px;font-weight:600}.D0_G6G_availableMeta{color:var(--upd-text-muted);margin:0;font-size:12px}.D0_G6G_notesTitle{color:var(--upd-text-secondary);margin:0;font-size:12.5px;font-weight:600}.D0_G6G_notes{border:1px solid var(--upd-border);background:var(--upd-bg-hover);color:var(--upd-text-secondary);white-space:pre-wrap;word-break:break-word;border-radius:6px;max-height:260px;margin:0;padding:10px 12px;font-family:inherit;font-size:12.5px;line-height:1.6;overflow:auto}.D0_G6G_actions{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.D0_G6G_primaryButton{appearance:none;background:var(--upd-primary);color:#fff;cursor:pointer;border:none;border-radius:6px;padding:7px 16px;font-size:13px;font-weight:500}.D0_G6G_primaryButton:hover{filter:brightness(1.08)}.D0_G6G_primaryButton:disabled{opacity:.55;cursor:default;filter:none}.D0_G6G_secondaryButton{appearance:none;border:1px solid var(--upd-border);color:var(--upd-text-secondary);cursor:pointer;background:0 0;border-radius:6px;padding:6px 14px;font-size:13px}.D0_G6G_secondaryButton:hover{background:var(--upd-bg-hover)}.D0_G6G_secondaryButton:disabled{opacity:.55;cursor:default}.D0_G6G_link{color:var(--upd-primary);font-size:12.5px;text-decoration:none}.D0_G6G_link:hover{text-decoration:underline}.D0_G6G_progressWrap{flex-direction:column;gap:6px;display:flex}.D0_G6G_progressLabel{color:var(--upd-text-secondary);justify-content:space-between;font-size:12.5px;display:flex}.D0_G6G_progressTrack{background:var(--upd-bg-hover);border:1px solid var(--upd-border);border-radius:3px;height:6px;overflow:hidden}.D0_G6G_progressFill{background:var(--upd-primary);border-radius:3px;height:100%;transition:width .24s}.D0_G6G_progressIndeterminate{width:40%;animation:1.1s ease-in-out infinite alternate D0_G6G_upd-slide}@keyframes D0_G6G_upd-slide{0%{margin-left:0}to{margin-left:60%}}.D0_G6G_doneCard{border:1px solid var(--upd-ok);border-radius:8px;flex-direction:column;gap:8px;padding:14px;display:flex}.D0_G6G_doneTitle{color:var(--upd-ok);margin:0;font-size:14px;font-weight:600}.D0_G6G_doneMeta{color:var(--upd-text-secondary);margin:0;font-size:12.5px}.D0_G6G_errorText{color:var(--upd-danger);word-break:break-word;margin:0;font-size:12.5px}";
126
- const tagId = "@dshtrading/client-ui-updater/updater-section.module.css";
127
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
132
+ //#region \0dsh-css:/home/runner/work/dsh-trading/dsh-trading/packages/client-ui-updater/src/client/updater-panel.module.css.mjs
133
+ const css$1 = ".SgPada_root{--upd-text-primary:var(--dsw-alias-text-primary,#1a1e24);--upd-text-secondary:var(--dsw-alias-text-secondary,#5f6672);--upd-text-muted:var(--dsw-alias-text-muted,#8e95a3);--upd-border:var(--dsw-alias-border-l2,#e3e6ea);--upd-bg-hover:var(--dsw-alias-fill-hover,#0000000a);--upd-bg-active:var(--dsw-alias-primary-bg,#2563eb0f);--upd-primary:var(--dsw-alias-primary,#2563eb);--upd-ok:#16a34a;--upd-danger:#dc2626;color:var(--upd-text-primary);flex-direction:column;gap:16px;padding:0;font-size:13px;display:flex}body[data-ds-dark-theme] .SgPada_root,[data-theme=dark] .SgPada_root,:root[data-theme=dark] .SgPada_root,html.dark .SgPada_root,body.dark .SgPada_root{--upd-text-primary:var(--dsw-alias-text-primary,#f3f4f6);--upd-text-secondary:var(--dsw-alias-text-secondary,#9ca3af);--upd-text-muted:var(--dsw-alias-text-muted,#6b7280);--upd-border:var(--dsw-alias-border-l2,#ffffff1a);--upd-bg-hover:var(--dsw-alias-fill-hover,#ffffff0f);--upd-bg-active:#2563eb29;--upd-primary:#3b82f6;--upd-ok:#4ade80;--upd-danger:#f87171}.SgPada_lead{color:var(--upd-text-secondary);margin:0;font-size:13.5px;line-height:1.6}.SgPada_versions{border:1px solid var(--upd-border);background:var(--upd-bg-hover);border-radius:8px;flex-wrap:wrap;gap:6px 24px;padding:10px 12px;display:flex}.SgPada_versionItem{flex-direction:column;gap:2px;display:flex}.SgPada_versionLabel{color:var(--upd-text-muted);font-size:11.5px}.SgPada_versionValue{font-variant-numeric:tabular-nums;font-size:13px;font-weight:600}.SgPada_statusRow{flex-wrap:wrap;align-items:center;gap:12px;display:flex}.SgPada_statusText{color:var(--upd-text-secondary)}.SgPada_statusTextOk{color:var(--upd-ok)}.SgPada_statusTextAvailable{color:var(--upd-primary);font-weight:600}.SgPada_statusTextError{color:var(--upd-danger)}.SgPada_availableCard{border:1px solid var(--upd-primary);background:var(--upd-bg-active);border-radius:8px;flex-direction:column;gap:10px;padding:14px;display:flex}.SgPada_availableTitle{color:var(--upd-primary);margin:0;font-size:14px;font-weight:600}.SgPada_availableMeta{color:var(--upd-text-muted);margin:0;font-size:12px}.SgPada_notesTitle{color:var(--upd-text-secondary);margin:0;font-size:12.5px;font-weight:600}.SgPada_notes{border:1px solid var(--upd-border);background:var(--upd-bg-hover);color:var(--upd-text-secondary);white-space:pre-wrap;word-break:break-word;border-radius:6px;max-height:260px;margin:0;padding:10px 12px;font-family:inherit;font-size:12.5px;line-height:1.6;overflow:auto}.SgPada_actions{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.SgPada_primaryButton{appearance:none;background:var(--upd-primary);color:#fff;cursor:pointer;border:none;border-radius:6px;padding:7px 16px;font-size:13px;font-weight:500}.SgPada_primaryButton:hover{filter:brightness(1.08)}.SgPada_primaryButton:disabled{opacity:.55;cursor:default;filter:none}.SgPada_secondaryButton{appearance:none;border:1px solid var(--upd-border);color:var(--upd-text-secondary);cursor:pointer;background:0 0;border-radius:6px;padding:6px 14px;font-size:13px}.SgPada_secondaryButton:hover{background:var(--upd-bg-hover)}.SgPada_secondaryButton:disabled{opacity:.55;cursor:default}.SgPada_link{color:var(--upd-primary);font-size:12.5px;text-decoration:none}.SgPada_link:hover{text-decoration:underline}.SgPada_progressWrap{flex-direction:column;gap:6px;display:flex}.SgPada_progressLabel{color:var(--upd-text-secondary);justify-content:space-between;font-size:12.5px;display:flex}.SgPada_progressTrack{background:var(--upd-bg-hover);border:1px solid var(--upd-border);border-radius:3px;height:6px;overflow:hidden}.SgPada_progressFill{background:var(--upd-primary);border-radius:3px;height:100%;transition:width .24s}.SgPada_progressIndeterminate{width:40%;animation:1.1s ease-in-out infinite alternate SgPada_upd-slide}@keyframes SgPada_upd-slide{0%{margin-left:0}to{margin-left:60%}}.SgPada_doneCard{border:1px solid var(--upd-ok);border-radius:8px;flex-direction:column;gap:8px;padding:14px;display:flex}.SgPada_doneTitle{color:var(--upd-ok);margin:0;font-size:14px;font-weight:600}.SgPada_doneMeta{color:var(--upd-text-secondary);margin:0;font-size:12.5px}.SgPada_errorText{color:var(--upd-danger);word-break:break-word;margin:0;font-size:12.5px}";
134
+ const tagId$1 = "@dshtrading/client-ui-updater/updater-panel.module.css";
135
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
128
136
  const tag = document.createElement("style");
129
137
  tag.dataset.plugin = "@dshtrading/client-ui-updater";
130
- tag.dataset.pluginCss = tagId;
131
- tag.textContent = css;
138
+ tag.dataset.pluginCss = tagId$1;
139
+ tag.textContent = css$1;
132
140
  document.head.appendChild(tag);
133
141
  }
134
- var updater_section_module_css_default = {
135
- "availableCard": "D0_G6G_availableCard",
136
- "secondaryButton": "D0_G6G_secondaryButton",
137
- "actions": "D0_G6G_actions",
138
- "progressWrap": "D0_G6G_progressWrap",
139
- "statusTextError": "D0_G6G_statusTextError",
140
- "versionValue": "D0_G6G_versionValue",
141
- "root": "D0_G6G_root",
142
- "progressTrack": "D0_G6G_progressTrack",
143
- "versionLabel": "D0_G6G_versionLabel",
144
- "doneCard": "D0_G6G_doneCard",
145
- "lead": "D0_G6G_lead",
146
- "availableTitle": "D0_G6G_availableTitle",
147
- "doneMeta": "D0_G6G_doneMeta",
148
- "progressIndeterminate": "D0_G6G_progressIndeterminate",
149
- "statusTextOk": "D0_G6G_statusTextOk",
150
- "statusText": "D0_G6G_statusText",
151
- "progressLabel": "D0_G6G_progressLabel",
152
- "availableMeta": "D0_G6G_availableMeta",
153
- "progressFill": "D0_G6G_progressFill",
154
- "upd-slide": "D0_G6G_upd-slide",
155
- "link": "D0_G6G_link",
156
- "errorText": "D0_G6G_errorText",
157
- "versionItem": "D0_G6G_versionItem",
158
- "notes": "D0_G6G_notes",
159
- "versions": "D0_G6G_versions",
160
- "notesTitle": "D0_G6G_notesTitle",
161
- "primaryButton": "D0_G6G_primaryButton",
162
- "statusRow": "D0_G6G_statusRow",
163
- "doneTitle": "D0_G6G_doneTitle",
164
- "statusTextAvailable": "D0_G6G_statusTextAvailable"
142
+ var updater_panel_module_css_default = {
143
+ "primaryButton": "SgPada_primaryButton",
144
+ "progressLabel": "SgPada_progressLabel",
145
+ "actions": "SgPada_actions",
146
+ "versions": "SgPada_versions",
147
+ "availableCard": "SgPada_availableCard",
148
+ "notes": "SgPada_notes",
149
+ "link": "SgPada_link",
150
+ "doneTitle": "SgPada_doneTitle",
151
+ "doneMeta": "SgPada_doneMeta",
152
+ "progressWrap": "SgPada_progressWrap",
153
+ "availableMeta": "SgPada_availableMeta",
154
+ "upd-slide": "SgPada_upd-slide",
155
+ "versionItem": "SgPada_versionItem",
156
+ "statusTextError": "SgPada_statusTextError",
157
+ "notesTitle": "SgPada_notesTitle",
158
+ "versionValue": "SgPada_versionValue",
159
+ "statusTextAvailable": "SgPada_statusTextAvailable",
160
+ "progressTrack": "SgPada_progressTrack",
161
+ "doneCard": "SgPada_doneCard",
162
+ "progressIndeterminate": "SgPada_progressIndeterminate",
163
+ "progressFill": "SgPada_progressFill",
164
+ "availableTitle": "SgPada_availableTitle",
165
+ "versionLabel": "SgPada_versionLabel",
166
+ "lead": "SgPada_lead",
167
+ "statusText": "SgPada_statusText",
168
+ "statusTextOk": "SgPada_statusTextOk",
169
+ "errorText": "SgPada_errorText",
170
+ "root": "SgPada_root",
171
+ "statusRow": "SgPada_statusRow",
172
+ "secondaryButton": "SgPada_secondaryButton"
165
173
  };
166
174
  //#endregion
167
- //#region src/client/UpdaterSection.tsx
175
+ //#region src/client/UpdaterPanel.tsx
168
176
  /**
169
- * Software-update settings page (the first-level section registered by this
170
- * plugin). Pure view over /dshtrading/api/updater: renders the current
171
- * versions, the latest GitHub release with its notes, and drives the
172
- * incremental apply + restart flow. Polls the host snapshot while mounted
173
- * (faster while an apply is running); no SSE dependency.
177
+ * Software-update dialog body (rendered inside UpdaterDialog). Pure view over
178
+ * /dshtrading/api/updater: renders the current versions, the latest GitHub
179
+ * release with its notes, and drives the incremental apply + restart flow.
180
+ * Polls the host snapshot while mounted (faster while an apply is running);
181
+ * no SSE dependency.
174
182
  */
175
183
  /** Poll cadences: lazy when idle, tight while an apply pipeline is running. */
176
184
  const POLL_IDLE_MS = 3e4;
@@ -182,7 +190,7 @@ window.__ModuleLoader__.load({
182
190
  if (Number.isNaN(parsed.getTime())) return "";
183
191
  return parsed.toISOString().slice(0, 10);
184
192
  }
185
- function UpdaterSection({ t }) {
193
+ function UpdaterPanel({ t }) {
186
194
  const [state, setState] = (0, react.useState)(void 0);
187
195
  const [actionError, setActionError] = (0, react.useState)(void 0);
188
196
  const [checkBusy, setCheckBusy] = (0, react.useState)(false);
@@ -249,52 +257,52 @@ window.__ModuleLoader__.load({
249
257
  const hasUpdate = check?.available === true && apply?.phase !== "done";
250
258
  hasUpdate && latest?.payloadAvailable;
251
259
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
252
- className: updater_section_module_css_default.root,
260
+ className: updater_panel_module_css_default.root,
253
261
  children: [
254
262
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
255
- className: updater_section_module_css_default.lead,
263
+ className: updater_panel_module_css_default.lead,
256
264
  children: t("lead")
257
265
  }),
258
266
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
259
- className: updater_section_module_css_default.versions,
267
+ className: updater_panel_module_css_default.versions,
260
268
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
261
- className: updater_section_module_css_default.versionItem,
269
+ className: updater_panel_module_css_default.versionItem,
262
270
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
263
- className: updater_section_module_css_default.versionLabel,
271
+ className: updater_panel_module_css_default.versionLabel,
264
272
  children: t("currentVersion")
265
273
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
266
- className: updater_section_module_css_default.versionValue,
274
+ className: updater_panel_module_css_default.versionValue,
267
275
  children: environment?.familyVersion ?? "—"
268
276
  })]
269
277
  }), environment?.appVersion !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
270
- className: updater_section_module_css_default.versionItem,
278
+ className: updater_panel_module_css_default.versionItem,
271
279
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
272
- className: updater_section_module_css_default.versionLabel,
280
+ className: updater_panel_module_css_default.versionLabel,
273
281
  children: t("desktopApp")
274
282
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
275
- className: updater_section_module_css_default.versionValue,
283
+ className: updater_panel_module_css_default.versionValue,
276
284
  children: environment.appVersion
277
285
  })]
278
286
  })]
279
287
  }),
280
288
  environment !== void 0 && !environment.supported && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
281
- className: updater_section_module_css_default.statusText,
289
+ className: updater_panel_module_css_default.statusText,
282
290
  children: t("unsupported")
283
291
  }),
284
292
  environment?.supported === true && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
285
293
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
286
- className: updater_section_module_css_default.statusRow,
294
+ className: updater_panel_module_css_default.statusRow,
287
295
  children: [
288
296
  check?.status === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
289
- className: `${updater_section_module_css_default.statusText} ${updater_section_module_css_default.statusTextError}`,
297
+ className: `${updater_panel_module_css_default.statusText} ${updater_panel_module_css_default.statusTextError}`,
290
298
  children: t("checkError", { message: check.error ?? "" })
291
299
  }),
292
300
  check?.status === "ok" && !hasUpdate && apply?.phase !== "done" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
293
- className: `${updater_section_module_css_default.statusText} ${updater_section_module_css_default.statusTextOk}`,
301
+ className: `${updater_panel_module_css_default.statusText} ${updater_panel_module_css_default.statusTextOk}`,
294
302
  children: t("upToDate")
295
303
  }),
296
304
  check?.at !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
297
- className: updater_section_module_css_default.statusText,
305
+ className: updater_panel_module_css_default.statusText,
298
306
  children: [
299
307
  t("lastCheck"),
300
308
  ":",
@@ -303,12 +311,12 @@ window.__ModuleLoader__.load({
303
311
  ]
304
312
  }),
305
313
  check?.at === void 0 && check?.status !== "ok" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
306
- className: updater_section_module_css_default.statusText,
314
+ className: updater_panel_module_css_default.statusText,
307
315
  children: t("never")
308
316
  }),
309
317
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
310
318
  type: "button",
311
- className: updater_section_module_css_default.secondaryButton,
319
+ className: updater_panel_module_css_default.secondaryButton,
312
320
  disabled: checkBusy || running,
313
321
  onClick: () => {
314
322
  handleCheck();
@@ -317,7 +325,7 @@ window.__ModuleLoader__.load({
317
325
  }),
318
326
  actionError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
319
327
  type: "button",
320
- className: updater_section_module_css_default.secondaryButton,
328
+ className: updater_panel_module_css_default.secondaryButton,
321
329
  onClick: () => {
322
330
  handleCheck();
323
331
  },
@@ -326,51 +334,51 @@ window.__ModuleLoader__.load({
326
334
  ]
327
335
  }),
328
336
  running && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
329
- className: updater_section_module_css_default.progressWrap,
337
+ className: updater_panel_module_css_default.progressWrap,
330
338
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
331
- className: updater_section_module_css_default.progressLabel,
339
+ className: updater_panel_module_css_default.progressLabel,
332
340
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: progress?.step === "download" ? t("phase.download") : progress?.step === "verify" ? t("phase.verify") : progress?.step === "install" ? t("phase.install") : t("phase.prepare") }), progress?.percent !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("progress", { percent: progress.percent }) })]
333
341
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
334
- className: updater_section_module_css_default.progressTrack,
342
+ className: updater_panel_module_css_default.progressTrack,
335
343
  role: "progressbar",
336
344
  "aria-valuemin": 0,
337
345
  "aria-valuemax": 100,
338
346
  "aria-valuenow": progress?.percent ?? void 0,
339
347
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
340
- className: `${updater_section_module_css_default.progressFill} ${progress?.percent === void 0 ? updater_section_module_css_default.progressIndeterminate : ""}`,
348
+ className: `${updater_panel_module_css_default.progressFill} ${progress?.percent === void 0 ? updater_panel_module_css_default.progressIndeterminate : ""}`,
341
349
  style: progress?.percent === void 0 ? void 0 : { width: `${progress.percent}%` }
342
350
  })
343
351
  })]
344
352
  }),
345
353
  hasUpdate && latest !== void 0 && !running && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
346
- className: updater_section_module_css_default.availableCard,
354
+ className: updater_panel_module_css_default.availableCard,
347
355
  children: [
348
356
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
349
- className: updater_section_module_css_default.availableTitle,
357
+ className: updater_panel_module_css_default.availableTitle,
350
358
  children: t("available", { version: latest.version })
351
359
  }),
352
360
  publishedDay !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
353
- className: updater_section_module_css_default.availableMeta,
361
+ className: updater_panel_module_css_default.availableMeta,
354
362
  children: t("publishedAt", { date: publishedDay })
355
363
  }),
356
364
  latest.notes.trim() !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
357
- className: updater_section_module_css_default.notesTitle,
365
+ className: updater_panel_module_css_default.notesTitle,
358
366
  children: t("notesTitle")
359
367
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
360
- className: updater_section_module_css_default.notes,
368
+ className: updater_panel_module_css_default.notes,
361
369
  children: latest.notes
362
370
  })] }),
363
371
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
364
- className: updater_section_module_css_default.actions,
372
+ className: updater_panel_module_css_default.actions,
365
373
  children: [latest.payloadAvailable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
366
374
  type: "button",
367
- className: updater_section_module_css_default.primaryButton,
375
+ className: updater_panel_module_css_default.primaryButton,
368
376
  onClick: () => {
369
377
  handleApply();
370
378
  },
371
379
  children: t("applyNow")
372
380
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
373
- className: updater_section_module_css_default.link,
381
+ className: updater_panel_module_css_default.link,
374
382
  href: releasesUrl,
375
383
  target: "_blank",
376
384
  rel: "noreferrer",
@@ -378,37 +386,37 @@ window.__ModuleLoader__.load({
378
386
  })]
379
387
  }),
380
388
  !latest.payloadAvailable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
381
- className: updater_section_module_css_default.doneMeta,
389
+ className: updater_panel_module_css_default.doneMeta,
382
390
  children: t("payloadMissing")
383
391
  })
384
392
  ]
385
393
  }),
386
394
  apply?.phase === "done" && apply.targetVersion !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
387
- className: updater_section_module_css_default.doneCard,
395
+ className: updater_panel_module_css_default.doneCard,
388
396
  children: [
389
397
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
390
- className: updater_section_module_css_default.doneTitle,
398
+ className: updater_panel_module_css_default.doneTitle,
391
399
  children: t("done", { version: apply.targetVersion })
392
400
  }),
393
401
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
394
- className: updater_section_module_css_default.doneMeta,
402
+ className: updater_panel_module_css_default.doneMeta,
395
403
  children: t("restartHint")
396
404
  }),
397
405
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
398
- className: updater_section_module_css_default.actions,
406
+ className: updater_panel_module_css_default.actions,
399
407
  children: [
400
408
  desktopBridge()?.relaunch !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
401
409
  type: "button",
402
- className: updater_section_module_css_default.primaryButton,
410
+ className: updater_panel_module_css_default.primaryButton,
403
411
  onClick: handleRestart,
404
412
  children: t("restartNow")
405
413
  }),
406
414
  desktopBridge()?.relaunch === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
407
- className: updater_section_module_css_default.doneMeta,
415
+ className: updater_panel_module_css_default.doneMeta,
408
416
  children: t("restartManual")
409
417
  }),
410
418
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
411
- className: updater_section_module_css_default.link,
419
+ className: updater_panel_module_css_default.link,
412
420
  href: releasesUrl,
413
421
  target: "_blank",
414
422
  rel: "noreferrer",
@@ -419,12 +427,12 @@ window.__ModuleLoader__.load({
419
427
  ]
420
428
  }),
421
429
  apply?.phase === "error" && apply.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
422
- className: updater_section_module_css_default.errorText,
430
+ className: updater_panel_module_css_default.errorText,
423
431
  children: apply.error
424
432
  })
425
433
  ] }),
426
434
  environment === void 0 || !environment.supported ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
427
- className: updater_section_module_css_default.link,
435
+ className: updater_panel_module_css_default.link,
428
436
  href: releasesUrl,
429
437
  target: "_blank",
430
438
  rel: "noreferrer",
@@ -434,27 +442,128 @@ window.__ModuleLoader__.load({
434
442
  });
435
443
  }
436
444
  //#endregion
445
+ //#region \0dsh-css:/home/runner/work/dsh-trading/dsh-trading/packages/client-ui-updater/src/client/updater-dialog.module.css.mjs
446
+ const css = ".Sd___q_overlay{z-index:900;pointer-events:auto;--upd-text-primary:var(--dsw-alias-text-primary,#1a1e24);--upd-text-secondary:var(--dsw-alias-text-secondary,#5f6672);--upd-text-muted:var(--dsw-alias-text-muted,#8e95a3);--upd-border:var(--dsw-alias-border-l2,#e3e6ea);--upd-bg-layer:var(--dsw-alias-bg-layer-2,#fff);--upd-bg-hover:var(--dsw-alias-fill-hover,#0000000a);--upd-mask:var(--dsw-alias-bg-mask-1,#00000052);--upd-shadow:var(--dsw-elevation-prominent,0 12px 32px #0000002e);justify-content:center;align-items:center;display:flex;position:fixed;inset:0}body[data-ds-dark-theme] .Sd___q_overlay,[data-theme=dark] .Sd___q_overlay,:root[data-theme=dark] .Sd___q_overlay,html.dark .Sd___q_overlay,body.dark .Sd___q_overlay{--upd-text-primary:var(--dsw-alias-text-primary,#f3f4f6);--upd-text-secondary:var(--dsw-alias-text-secondary,#9ca3af);--upd-text-muted:var(--dsw-alias-text-muted,#6b7280);--upd-border:var(--dsw-alias-border-l2,#ffffff1a);--upd-bg-layer:var(--dsw-alias-bg-layer-2,#1f232b);--upd-bg-hover:var(--dsw-alias-fill-hover,#ffffff0f);--upd-mask:var(--dsw-alias-bg-mask-1,#00000080);--upd-shadow:var(--dsw-elevation-prominent,0 12px 32px #00000080)}.Sd___q_mask{background:var(--upd-mask);backdrop-filter:var(--dsw-mask-blur,blur(2px));position:absolute;inset:0}.Sd___q_panel{z-index:1;background:var(--upd-bg-layer);width:560px;max-width:calc(100vw - 48px);max-height:min(640px,100vh - 48px);color:var(--upd-text-primary);border:1px solid var(--upd-border);box-shadow:var(--upd-shadow);border-radius:16px;flex-direction:column;display:flex;position:relative;overflow:hidden}.Sd___q_header{border-bottom:1px solid var(--upd-border);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:14px 14px 10px 18px;display:flex}.Sd___q_title{color:var(--upd-text-primary);font-size:15px;font-weight:600}.Sd___q_close{appearance:none;color:var(--upd-text-secondary);cursor:pointer;background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:background .15s,color .15s;display:inline-flex}.Sd___q_close:hover{background:var(--upd-bg-hover);color:var(--upd-text-primary)}.Sd___q_body{flex:1;min-height:0;padding:14px 18px 18px;overflow-y:auto}";
447
+ const tagId = "@dshtrading/client-ui-updater/updater-dialog.module.css";
448
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
449
+ const tag = document.createElement("style");
450
+ tag.dataset.plugin = "@dshtrading/client-ui-updater";
451
+ tag.dataset.pluginCss = tagId;
452
+ tag.textContent = css;
453
+ document.head.appendChild(tag);
454
+ }
455
+ var updater_dialog_module_css_default = {
456
+ "mask": "Sd___q_mask",
457
+ "header": "Sd___q_header",
458
+ "panel": "Sd___q_panel",
459
+ "overlay": "Sd___q_overlay",
460
+ "title": "Sd___q_title",
461
+ "close": "Sd___q_close",
462
+ "body": "Sd___q_body"
463
+ };
464
+ //#endregion
465
+ //#region src/client/UpdaterDialog.tsx
466
+ /**
467
+ * Software-update dialog (the 'shell.overlay' entry registered by this plugin).
468
+ * The sidebar's update entry dispatches UPDATER_OPEN_EVENT; this component owns
469
+ * the modal chrome (mask click + Escape close) around UpdaterPanel. Frame-wide
470
+ * floating layer: fixed overlay opts back into pointer events.
471
+ */
472
+ function UpdaterDialog({ t }) {
473
+ const [open, setOpen] = (0, react.useState)(false);
474
+ (0, react.useEffect)(() => {
475
+ const onOpen = () => {
476
+ setOpen(true);
477
+ };
478
+ window.addEventListener(UPDATER_OPEN_EVENT, onOpen);
479
+ return () => {
480
+ window.removeEventListener(UPDATER_OPEN_EVENT, onOpen);
481
+ };
482
+ }, []);
483
+ const close = (0, react.useCallback)(() => {
484
+ setOpen(false);
485
+ }, []);
486
+ (0, react.useEffect)(() => {
487
+ if (!open) return;
488
+ const onKeyDown = (event) => {
489
+ if (event.key === "Escape") close();
490
+ };
491
+ document.addEventListener("keydown", onKeyDown);
492
+ return () => {
493
+ document.removeEventListener("keydown", onKeyDown);
494
+ };
495
+ }, [open, close]);
496
+ if (!open) return null;
497
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
498
+ className: updater_dialog_module_css_default.overlay,
499
+ role: "presentation",
500
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
501
+ className: updater_dialog_module_css_default.mask,
502
+ "aria-hidden": "true",
503
+ onClick: close
504
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
505
+ className: updater_dialog_module_css_default.panel,
506
+ role: "dialog",
507
+ "aria-modal": "true",
508
+ "aria-label": t("nav"),
509
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
510
+ className: updater_dialog_module_css_default.header,
511
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
512
+ className: updater_dialog_module_css_default.title,
513
+ children: t("nav")
514
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
515
+ type: "button",
516
+ className: updater_dialog_module_css_default.close,
517
+ "aria-label": t("close"),
518
+ title: t("close"),
519
+ onClick: close,
520
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
521
+ viewBox: "0 0 16 16",
522
+ width: 14,
523
+ height: 14,
524
+ "aria-hidden": "true",
525
+ fill: "none",
526
+ stroke: "currentColor",
527
+ strokeWidth: "1.4",
528
+ strokeLinecap: "round",
529
+ strokeLinejoin: "round",
530
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M4.25 4.25l7.5 7.5M11.75 4.25l-7.5 7.5" })
531
+ })
532
+ })]
533
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
534
+ className: updater_dialog_module_css_default.body,
535
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UpdaterPanel, { t })
536
+ })]
537
+ })]
538
+ });
539
+ }
540
+ //#endregion
437
541
  //#region src/client/index.ts
438
- /** 本面板/字符串翻译的 locale namespace。 */
542
+ /** This dialog's locale namespace. */
439
543
  const NS = "dshtrading.updater";
440
544
  /** Required services (cordis fiber inject). */
441
545
  const inject = ["slots", "locale"];
442
- /** 注册『软件更新』设置一级菜单。 */
546
+ /**
547
+ * Register the update dialog on shell.overlay (no settings.section: the entry
548
+ * moved beside Settings in the sidebar bottom bar). The sidebar asks this
549
+ * plugin to open through the UPDATER_OPEN_EVENT window event — cross-plugin
550
+ * coupling is a DOM event, never an import.
551
+ */
443
552
  function apply(ctx) {
444
- const t = ctx.locale.bind(NS);
553
+ ctx.locale.bind(NS);
445
554
  ctx.effect(() => ctx.locale.register(NS, {
446
555
  zh,
447
556
  en
448
557
  }), "dsh-trading-updater: dictionaries");
449
- ctx.slots.inject("settings.section", () => ctx.slots.register({
450
- name: "settings.section",
451
- id: "updater",
452
- order: 20,
453
- label: () => t("nav"),
558
+ ctx.slots.inject("shell.overlay", () => ctx.slots.register({
559
+ name: "shell.overlay",
560
+ id: "dshtrading-updater-dialog",
561
+ order: 90,
454
562
  locale: NS
455
- }, UpdaterSection));
563
+ }, UpdaterDialog));
456
564
  }
457
565
  //#endregion
566
+ exports.UPDATER_OPEN_EVENT = UPDATER_OPEN_EVENT;
458
567
  exports.UPDATE_AVAILABLE_EVENT = UPDATE_AVAILABLE_EVENT;
459
568
  exports.apply = apply;
460
569
  exports.inject = inject;
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["useState","useRef","useCallback","css"],"sources":["../src/client/locales.ts","../src/client/api.ts","../src/client/contract.ts","../src/client/UpdaterSection.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * client-ui-updater 词典(纯数据模块:零运行时依赖)。\n *\n * 单一来源:本包 client apply 注册 zh/en(typed register 编译期校验键位);\n * packages/dsh-i18n 语言包构建期 import 本模块注册 zh-CN;scripts/i18n-audit.mjs\n * 静态加载本模块做 zh/en 键对齐与占位符对齐门禁。\n */\nimport type { UpdaterLocaleKey } from './contract.ts'\n\nexport const zh: Record<UpdaterLocaleKey, string> = {\n nav: '软件更新',\n lead: '检测 GitHub Releases 上的新版本,增量更新只下载变动的交易插件包,无需重装应用。',\n currentVersion: '交易插件版本',\n desktopApp: '桌面应用版本',\n unsupported: '当前环境不支持自动增量更新(仅 DSH Trading 桌面版支持)。可以前往发布页手动下载完整安装包。',\n viewReleases: '在 GitHub 查看发布',\n checkNow: '检查更新',\n checking: '正在检查…',\n lastCheck: '上次检查',\n never: '尚未检查',\n upToDate: '已是最新版本。',\n available: '发现新版本 {version}',\n publishedAt: '发布于 {date}',\n notesTitle: '更新说明',\n applyNow: '立即更新',\n payloadMissing: '该版本未附带增量更新包,请前往发布页下载完整安装包。',\n 'phase.prepare': '正在准备…',\n 'phase.download': '正在下载增量包…',\n 'phase.verify': '正在校验增量包…',\n 'phase.install': '正在安装更新…',\n progress: '{percent}%',\n done: '已更新到 {version}',\n restartHint: '重启 DSH Trading 后生效。',\n restartNow: '重启应用',\n restartManual: '请手动重启 DSH Trading 以完成更新。',\n checkError: '检查失败:{message}',\n retry: '重试',\n}\n\nexport const en: Record<UpdaterLocaleKey, string> = {\n nav: 'Software updates',\n lead: 'Detects new versions published on GitHub Releases and applies incremental updates — only the changed trading plugin packages are downloaded, no reinstall needed.',\n currentVersion: 'Trading plugins',\n desktopApp: 'Desktop app',\n unsupported: 'Incremental updates are only available inside the DSH Trading desktop app. You can download a full installer from the releases page.',\n viewReleases: 'View releases on GitHub',\n checkNow: 'Check for updates',\n checking: 'Checking…',\n lastCheck: 'Last checked',\n never: 'Never checked',\n upToDate: 'You are up to date.',\n available: 'New version {version} available',\n publishedAt: 'Published {date}',\n notesTitle: 'Release notes',\n applyNow: 'Update now',\n payloadMissing: 'This release does not carry the incremental update payload. Please download a full installer from the releases page.',\n 'phase.prepare': 'Preparing…',\n 'phase.download': 'Downloading update payload…',\n 'phase.verify': 'Verifying update payload…',\n 'phase.install': 'Installing update…',\n progress: '{percent}%',\n done: 'Updated to {version}',\n restartHint: 'Restart DSH Trading to activate.',\n restartNow: 'Restart app',\n restartManual: 'Please restart DSH Trading manually to finish the update.',\n checkError: 'Check failed: {message}',\n retry: 'Retry',\n}\n","/**\n * Updater bridge client: same-origin fetch wrappers over\n * /dshtrading/api/updater (the node half registers the route behind the\n * browser-auth fence; same-origin fetch carries the auth cookie by default).\n * Error semantics mirror the tasks bridge: non-2xx or { ok:false } envelopes\n * become rejections carrying the business code.\n */\nimport type { UpdaterSnapshot } from '../updater-service.ts'\n\nexport class UpdaterBridgeError extends Error {\n constructor(readonly status: number, message: string, readonly code?: string) {\n super(message)\n }\n}\n\nasync function updaterJson<T>(path: string, init?: RequestInit): Promise<T> {\n const response = await fetch(path, init)\n if (!response.ok) {\n const body = await response.json().catch(() => undefined) as { code?: string; message?: string } | undefined\n const detail = typeof body?.message === 'string' && body.message !== '' ? ': ' + body.message : ''\n throw new UpdaterBridgeError(response.status, 'updater ' + path + ' failed: ' + String(response.status) + detail, body?.code)\n }\n const wire = await response.json() as T\n if (wire !== null && typeof wire === 'object' && (wire as { ok?: unknown }).ok === false) {\n const business = wire as { code?: string; message?: string }\n throw new UpdaterBridgeError(200, (business.code ?? 'UPDATER_UNKNOWN') + ': ' + (business.message ?? 'updater bridge error'), business.code)\n }\n return wire\n}\n\n/** Current updater snapshot (environment + check + apply state). */\nexport async function fetchUpdaterState(): Promise<UpdaterSnapshot> {\n return updaterJson<UpdaterSnapshot>('/dshtrading/api/updater/state', { headers: { accept: 'application/json' } })\n}\n\n/** Run a GitHub release check; force=true bypasses the host-side TTL cache. */\nexport async function requestUpdaterCheck(force: boolean): Promise<UpdaterSnapshot> {\n return updaterJson<UpdaterSnapshot>(`/dshtrading/api/updater/check?force=${force ? '1' : '0'}`, { headers: { accept: 'application/json' } })\n}\n\n/** Start the incremental apply pipeline; returns the running snapshot. */\nexport async function requestUpdaterApply(): Promise<UpdaterSnapshot> {\n return updaterJson<UpdaterSnapshot>('/dshtrading/api/updater/apply', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: '{}',\n })\n}\n\n/** Electron shell bridge exposed by the desktop preload (absent in browsers). */\ninterface DesktopBridge {\n relaunch?: () => void\n}\n\n/** Resolve the desktop shell bridge, if this page runs inside DSH Trading. */\nexport function desktopBridge(): DesktopBridge | undefined {\n if (typeof window === 'undefined' || !('desktop' in window)) return undefined\n return (window as { desktop?: DesktopBridge }).desktop\n}\n","/**\n * Locale contract for the updater settings section. The zh dictionary in\n * locales.ts is the key source of truth; this union + the LocaleNamespaceMap\n * merge give the framework-injected t seat its key types.\n */\nexport type UpdaterLocaleKey =\n | 'nav'\n | 'lead'\n | 'currentVersion'\n | 'desktopApp'\n | 'unsupported'\n | 'viewReleases'\n | 'checkNow'\n | 'checking'\n | 'lastCheck'\n | 'never'\n | 'upToDate'\n | 'available'\n | 'publishedAt'\n | 'notesTitle'\n | 'applyNow'\n | 'payloadMissing'\n | 'phase.prepare'\n | 'phase.download'\n | 'phase.verify'\n | 'phase.install'\n | 'progress'\n | 'done'\n | 'restartHint'\n | 'restartNow'\n | 'restartManual'\n | 'checkError'\n | 'retry'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Updater settings section copy (check / notes / incremental apply). */\n 'dshtrading.updater': UpdaterLocaleKey\n }\n}\n\n/**\n * Window event contract with the trading shell rail (client-ui-trading\n * SessionRail badge). Cross-plugin coupling is intentionally a DOM custom\n * event, not an import (client plugins never import each other's modules).\n * Detail: { available: boolean, version?: string }.\n */\nexport const UPDATE_AVAILABLE_EVENT = 'dshtrading-update-available'\n","/**\n * Software-update settings page (the first-level section registered by this\n * plugin). Pure view over /dshtrading/api/updater: renders the current\n * versions, the latest GitHub release with its notes, and drives the\n * incremental apply + restart flow. Polls the host snapshot while mounted\n * (faster while an apply is running); no SSE dependency.\n */\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { UpdaterSnapshot } from '../updater-service.ts'\nimport { desktopBridge, fetchUpdaterState, requestUpdaterApply, requestUpdaterCheck } from './api.ts'\nimport { UPDATE_AVAILABLE_EVENT } from './contract.ts'\nimport css from './updater-section.module.css'\n\nexport type UpdaterSectionProps =\n & PropsRuntime<'settings.section'>\n & PropsLocale<'dshtrading.updater'>\n\n/** Poll cadences: lazy when idle, tight while an apply pipeline is running. */\nconst POLL_IDLE_MS = 30_000\nconst POLL_RUNNING_MS = 1_200\n\n/** ISO date (yyyy-mm-dd) for the published line; empty when unknown. */\nfunction formatDay(iso: string | undefined): string {\n if (iso === undefined) return ''\n const parsed = new Date(iso)\n if (Number.isNaN(parsed.getTime())) return ''\n return parsed.toISOString().slice(0, 10)\n}\n\nexport function UpdaterSection({ t }: UpdaterSectionProps) {\n const [state, setState] = useState<UpdaterSnapshot | undefined>(undefined)\n const [actionError, setActionError] = useState<string | undefined>(undefined)\n const [checkBusy, setCheckBusy] = useState(false)\n const applyBusyRef = useRef(false)\n\n const running = state?.apply.phase === 'running'\n\n const refresh = useCallback(async () => {\n try {\n setState(await fetchUpdaterState())\n } catch {\n // Bridge absent (headless profile / old deployment): keep the page quiet.\n }\n }, [])\n\n useEffect(() => { void refresh() }, [refresh])\n\n useEffect(() => {\n const interval = setInterval(() => { void refresh() }, running ? POLL_RUNNING_MS : POLL_IDLE_MS)\n return () => { clearInterval(interval) }\n }, [refresh, running])\n\n // Rail badge sync: mirror availability onto the window event the trading\n // shell rail listens to (see UPDATE_AVAILABLE_EVENT in contract.ts).\n useEffect(() => {\n if (state === undefined) return\n const available = state.check.available === true && state.apply.phase !== 'done'\n window.dispatchEvent(new CustomEvent(UPDATE_AVAILABLE_EVENT, {\n detail: { available, version: state.check.latest?.version },\n }))\n }, [state])\n\n const handleCheck = async (): Promise<void> => {\n setCheckBusy(true)\n setActionError(undefined)\n try {\n setState(await requestUpdaterCheck(true))\n } catch (error) {\n setActionError(error instanceof Error ? error.message : String(error))\n } finally {\n setCheckBusy(false)\n }\n }\n\n const handleApply = async (): Promise<void> => {\n if (applyBusyRef.current) return\n applyBusyRef.current = true\n setActionError(undefined)\n try {\n setState(await requestUpdaterApply())\n // Pipeline started: tighten polling immediately instead of waiting a tick.\n void refresh()\n } catch (error) {\n setActionError(error instanceof Error ? error.message : String(error))\n } finally {\n applyBusyRef.current = false\n }\n }\n\n const handleRestart = (): void => {\n desktopBridge()?.relaunch?.()\n }\n\n const environment = state?.environment\n const check = state?.check\n const apply = state?.apply\n const progress = state?.progress\n const latest = check?.latest\n const releasesUrl = latest?.url ?? 'https://github.com/zhu1090093659/dsh-trading/releases'\n const publishedDay = formatDay(latest?.publishedAt)\n const hasUpdate = check?.available === true && apply?.phase !== 'done'\n const applyable = hasUpdate && latest?.payloadAvailable === true\n\n return (\n <div className={css.root}>\n <p className={css.lead}>{t('lead')}</p>\n\n <div className={css.versions}>\n <div className={css.versionItem}>\n <span className={css.versionLabel}>{t('currentVersion')}</span>\n <span className={css.versionValue}>{environment?.familyVersion ?? '—'}</span>\n </div>\n {environment?.appVersion !== undefined && (\n <div className={css.versionItem}>\n <span className={css.versionLabel}>{t('desktopApp')}</span>\n <span className={css.versionValue}>{environment.appVersion}</span>\n </div>\n )}\n </div>\n\n {environment !== undefined && !environment.supported && (\n <p className={css.statusText}>{t('unsupported')}</p>\n )}\n\n {environment?.supported === true && (\n <>\n <div className={css.statusRow}>\n {check?.status === 'error' && (\n <span className={`${css.statusText} ${css.statusTextError}`}>\n {t('checkError', { message: check.error ?? '' })}\n </span>\n )}\n {check?.status === 'ok' && !hasUpdate && apply?.phase !== 'done' && (\n <span className={`${css.statusText} ${css.statusTextOk}`}>{t('upToDate')}</span>\n )}\n {check?.at !== undefined && (\n <span className={css.statusText}>\n {t('lastCheck')}\n :\n {' '}\n {check.at.slice(0, 19).replace('T', ' ')}\n </span>\n )}\n {check?.at === undefined && check?.status !== 'ok' && (\n <span className={css.statusText}>{t('never')}</span>\n )}\n <button\n type=\"button\"\n className={css.secondaryButton}\n disabled={checkBusy || running}\n onClick={() => { void handleCheck() }}\n >\n {checkBusy ? t('checking') : t('checkNow')}\n </button>\n {actionError !== undefined && (\n <button type=\"button\" className={css.secondaryButton} onClick={() => { void handleCheck() }}>\n {t('retry')}\n </button>\n )}\n </div>\n\n {running && (\n <div className={css.progressWrap}>\n <span className={css.progressLabel}>\n <span>\n {progress?.step === 'download'\n ? t('phase.download')\n : progress?.step === 'verify'\n ? t('phase.verify')\n : progress?.step === 'install'\n ? t('phase.install')\n : t('phase.prepare')}\n </span>\n {progress?.percent !== undefined && (\n <span>{t('progress', { percent: progress.percent })}</span>\n )}\n </span>\n <div\n className={css.progressTrack}\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={progress?.percent ?? undefined}\n >\n <div\n className={`${css.progressFill} ${progress?.percent === undefined ? css.progressIndeterminate : ''}`}\n style={progress?.percent === undefined ? undefined : { width: `${progress.percent}%` }}\n />\n </div>\n </div>\n )}\n\n {hasUpdate && latest !== undefined && !running && (\n <div className={css.availableCard}>\n <p className={css.availableTitle}>{t('available', { version: latest.version })}</p>\n {publishedDay !== '' && (\n <p className={css.availableMeta}>{t('publishedAt', { date: publishedDay })}</p>\n )}\n {latest.notes.trim() !== '' && (\n <>\n <span className={css.notesTitle}>{t('notesTitle')}</span>\n <pre className={css.notes}>{latest.notes}</pre>\n </>\n )}\n <div className={css.actions}>\n {latest.payloadAvailable && (\n <button\n type=\"button\"\n className={css.primaryButton}\n onClick={() => { void handleApply() }}\n >\n {t('applyNow')}\n </button>\n )}\n <a className={css.link} href={releasesUrl} target=\"_blank\" rel=\"noreferrer\">\n {t('viewReleases')}\n </a>\n </div>\n {!latest.payloadAvailable && (\n <p className={css.doneMeta}>{t('payloadMissing')}</p>\n )}\n </div>\n )}\n\n {apply?.phase === 'done' && apply.targetVersion !== undefined && (\n <div className={css.doneCard}>\n <p className={css.doneTitle}>{t('done', { version: apply.targetVersion })}</p>\n <p className={css.doneMeta}>{t('restartHint')}</p>\n <div className={css.actions}>\n {desktopBridge()?.relaunch !== undefined && (\n <button type=\"button\" className={css.primaryButton} onClick={handleRestart}>\n {t('restartNow')}\n </button>\n )}\n {desktopBridge()?.relaunch === undefined && (\n <span className={css.doneMeta}>{t('restartManual')}</span>\n )}\n <a className={css.link} href={releasesUrl} target=\"_blank\" rel=\"noreferrer\">\n {t('viewReleases')}\n </a>\n </div>\n </div>\n )}\n\n {apply?.phase === 'error' && apply.error !== undefined && (\n <p className={css.errorText}>{apply.error}</p>\n )}\n </>\n )}\n\n {environment === undefined || !environment.supported ? (\n <a className={css.link} href={releasesUrl} target=\"_blank\" rel=\"noreferrer\">\n {t('viewReleases')}\n </a>\n ) : null}\n </div>\n )\n}\n","/**\n * dsh-trading auto-update, browser half — the '软件更新' first-level section\n * inside the host settings panel (settings.section, order 20: after the\n * official general/models/plugins and the trading section at order 8).\n *\n * The page talks to the node half over /dshtrading/api/updater (same-origin\n * fetch inside the browser-auth fence). In environments without incremental\n * support (dev checkouts, headless profiles) it degrades to an information\n * surface linking the GitHub releases page.\n */\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from './contract.ts'\nimport { en, zh } from './locales.ts'\nimport { UpdaterSection } from './UpdaterSection.tsx'\n\nimport { UPDATE_AVAILABLE_EVENT } from './contract.ts'\n/** 本面板/字符串翻译的 locale namespace。 */\nconst NS = 'dshtrading.updater'\n\n/** Required services (cordis fiber inject). */\nexport const inject = ['slots', 'locale']\n\n/** 注册『软件更新』设置一级菜单。 */\nexport function apply(ctx: ClientContext): void {\n const t = ctx.locale.bind(NS)\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-trading-updater: dictionaries')\n\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'updater',\n order: 20,\n label: () => t('nav'),\n locale: NS,\n }, UpdaterSection))\n}\n\nexport { UPDATE_AVAILABLE_EVENT } from './contract.ts'\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["useState","useRef","useCallback","css","useState","useCallback","css"],"sources":["../src/client/locales.ts","../src/client/contract.ts","../src/client/api.ts","../src/client/UpdaterPanel.tsx","../src/client/UpdaterDialog.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * client-ui-updater 词典(纯数据模块:零运行时依赖)。\n *\n * 单一来源:本包 client apply 注册 zh/en(typed register 编译期校验键位);\n * packages/dsh-i18n 语言包构建期 import 本模块注册 zh-CN;scripts/i18n-audit.mjs\n * 静态加载本模块做 zh/en 键对齐与占位符对齐门禁。\n */\nimport type { UpdaterLocaleKey } from './contract.ts'\n\nexport const zh: Record<UpdaterLocaleKey, string> = {\n nav: '软件更新',\n lead: '检测 GitHub Releases 上的新版本,增量更新只下载变动的交易插件包,无需重装应用。',\n currentVersion: '交易插件版本',\n desktopApp: '桌面应用版本',\n unsupported: '当前环境不支持自动增量更新(仅 DSH Trading 桌面版支持)。可以前往发布页手动下载完整安装包。',\n viewReleases: '在 GitHub 查看发布',\n checkNow: '检查更新',\n checking: '正在检查…',\n lastCheck: '上次检查',\n never: '尚未检查',\n upToDate: '已是最新版本。',\n available: '发现新版本 {version}',\n publishedAt: '发布于 {date}',\n notesTitle: '更新说明',\n applyNow: '立即更新',\n payloadMissing: '该版本未附带增量更新包,请前往发布页下载完整安装包。',\n 'phase.prepare': '正在准备…',\n 'phase.download': '正在下载增量包…',\n 'phase.verify': '正在校验增量包…',\n 'phase.install': '正在安装更新…',\n progress: '{percent}%',\n done: '已更新到 {version}',\n restartHint: '重启 DSH Trading 后生效。',\n restartNow: '重启应用',\n restartManual: '请手动重启 DSH Trading 以完成更新。',\n checkError: '检查失败:{message}',\n retry: '重试',\n close: '关闭',\n}\n\nexport const en: Record<UpdaterLocaleKey, string> = {\n nav: 'Software updates',\n lead: 'Detects new versions published on GitHub Releases and applies incremental updates — only the changed trading plugin packages are downloaded, no reinstall needed.',\n currentVersion: 'Trading plugins',\n desktopApp: 'Desktop app',\n unsupported: 'Incremental updates are only available inside the DSH Trading desktop app. You can download a full installer from the releases page.',\n viewReleases: 'View releases on GitHub',\n checkNow: 'Check for updates',\n checking: 'Checking…',\n lastCheck: 'Last checked',\n never: 'Never checked',\n upToDate: 'You are up to date.',\n available: 'New version {version} available',\n publishedAt: 'Published {date}',\n notesTitle: 'Release notes',\n applyNow: 'Update now',\n payloadMissing: 'This release does not carry the incremental update payload. Please download a full installer from the releases page.',\n 'phase.prepare': 'Preparing…',\n 'phase.download': 'Downloading update payload…',\n 'phase.verify': 'Verifying update payload…',\n 'phase.install': 'Installing update…',\n progress: '{percent}%',\n done: 'Updated to {version}',\n restartHint: 'Restart DSH Trading to activate.',\n restartNow: 'Restart app',\n restartManual: 'Please restart DSH Trading manually to finish the update.',\n checkError: 'Check failed: {message}',\n retry: 'Retry',\n close: 'Close',\n}\n","/**\n * Locale contract for the software-update dialog. The zh dictionary in\n * locales.ts is the key source of truth; this union + the LocaleNamespaceMap\n * merge give the framework-injected t seat its key types.\n *\n * Type-only imports pull the host slot augmentations (shell.overlay) into the\n * program so the dialog registers against a declared slot.\n */\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\n\nexport type UpdaterLocaleKey =\n | 'nav'\n | 'lead'\n | 'currentVersion'\n | 'desktopApp'\n | 'unsupported'\n | 'viewReleases'\n | 'checkNow'\n | 'checking'\n | 'lastCheck'\n | 'never'\n | 'upToDate'\n | 'available'\n | 'publishedAt'\n | 'notesTitle'\n | 'applyNow'\n | 'payloadMissing'\n | 'phase.prepare'\n | 'phase.download'\n | 'phase.verify'\n | 'phase.install'\n | 'progress'\n | 'done'\n | 'restartHint'\n | 'restartNow'\n | 'restartManual'\n | 'checkError'\n | 'retry'\n | 'close'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Software-update dialog copy (check / notes / incremental apply). */\n 'dshtrading.updater': UpdaterLocaleKey\n }\n}\n\n/**\n * Window event contract with the trading shell sidebar (client-ui-trading\n * MarketDock update entry). Cross-plugin coupling is intentionally a DOM\n * custom event, not an import (client plugins never import each other's\n * modules).\n *\n * - UPDATE_AVAILABLE_EVENT: fired by the dialog whenever the host snapshot\n * changes. Detail: { available: boolean, version?: string }.\n * - UPDATER_OPEN_EVENT: fired by the sidebar update entry to ask this plugin\n * to open its dialog. No detail.\n */\nexport const UPDATE_AVAILABLE_EVENT = 'dshtrading-update-available'\nexport const UPDATER_OPEN_EVENT = 'dshtrading-updater-open'\n","/**\n * Updater bridge client: same-origin fetch wrappers over\n * /dshtrading/api/updater (the node half registers the route behind the\n * browser-auth fence; same-origin fetch carries the auth cookie by default).\n * Error semantics mirror the tasks bridge: non-2xx or { ok:false } envelopes\n * become rejections carrying the business code.\n */\nimport type { UpdaterSnapshot } from '../updater-service.ts'\n\nexport class UpdaterBridgeError extends Error {\n constructor(readonly status: number, message: string, readonly code?: string) {\n super(message)\n }\n}\n\nasync function updaterJson<T>(path: string, init?: RequestInit): Promise<T> {\n const response = await fetch(path, init)\n if (!response.ok) {\n const body = await response.json().catch(() => undefined) as { code?: string; message?: string } | undefined\n const detail = typeof body?.message === 'string' && body.message !== '' ? ': ' + body.message : ''\n throw new UpdaterBridgeError(response.status, 'updater ' + path + ' failed: ' + String(response.status) + detail, body?.code)\n }\n const wire = await response.json() as T\n if (wire !== null && typeof wire === 'object' && (wire as { ok?: unknown }).ok === false) {\n const business = wire as { code?: string; message?: string }\n throw new UpdaterBridgeError(200, (business.code ?? 'UPDATER_UNKNOWN') + ': ' + (business.message ?? 'updater bridge error'), business.code)\n }\n return wire\n}\n\n/** Current updater snapshot (environment + check + apply state). */\nexport async function fetchUpdaterState(): Promise<UpdaterSnapshot> {\n return updaterJson<UpdaterSnapshot>('/dshtrading/api/updater/state', { headers: { accept: 'application/json' } })\n}\n\n/** Run a GitHub release check; force=true bypasses the host-side TTL cache. */\nexport async function requestUpdaterCheck(force: boolean): Promise<UpdaterSnapshot> {\n return updaterJson<UpdaterSnapshot>(`/dshtrading/api/updater/check?force=${force ? '1' : '0'}`, { headers: { accept: 'application/json' } })\n}\n\n/** Start the incremental apply pipeline; returns the running snapshot. */\nexport async function requestUpdaterApply(): Promise<UpdaterSnapshot> {\n return updaterJson<UpdaterSnapshot>('/dshtrading/api/updater/apply', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: '{}',\n })\n}\n\n/** Electron shell bridge exposed by the desktop preload (absent in browsers). */\ninterface DesktopBridge {\n relaunch?: () => void\n}\n\n/** Resolve the desktop shell bridge, if this page runs inside DSH Trading. */\nexport function desktopBridge(): DesktopBridge | undefined {\n if (typeof window === 'undefined' || !('desktop' in window)) return undefined\n return (window as { desktop?: DesktopBridge }).desktop\n}\n","/**\n * Software-update dialog body (rendered inside UpdaterDialog). Pure view over\n * /dshtrading/api/updater: renders the current versions, the latest GitHub\n * release with its notes, and drives the incremental apply + restart flow.\n * Polls the host snapshot while mounted (faster while an apply is running);\n * no SSE dependency.\n */\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { UpdaterSnapshot } from '../updater-service.ts'\nimport { desktopBridge, fetchUpdaterState, requestUpdaterApply, requestUpdaterCheck } from './api.ts'\nimport { UPDATE_AVAILABLE_EVENT } from './contract.ts'\nimport css from './updater-panel.module.css'\n\nexport type UpdaterPanelProps = PropsLocale<'dshtrading.updater'>\n\n/** Poll cadences: lazy when idle, tight while an apply pipeline is running. */\nconst POLL_IDLE_MS = 30_000\nconst POLL_RUNNING_MS = 1_200\n\n/** ISO date (yyyy-mm-dd) for the published line; empty when unknown. */\nfunction formatDay(iso: string | undefined): string {\n if (iso === undefined) return ''\n const parsed = new Date(iso)\n if (Number.isNaN(parsed.getTime())) return ''\n return parsed.toISOString().slice(0, 10)\n}\n\nexport function UpdaterPanel({ t }: UpdaterPanelProps) {\n const [state, setState] = useState<UpdaterSnapshot | undefined>(undefined)\n const [actionError, setActionError] = useState<string | undefined>(undefined)\n const [checkBusy, setCheckBusy] = useState(false)\n const applyBusyRef = useRef(false)\n\n const running = state?.apply.phase === 'running'\n\n const refresh = useCallback(async () => {\n try {\n setState(await fetchUpdaterState())\n } catch {\n // Bridge absent (headless profile / old deployment): keep the page quiet.\n }\n }, [])\n\n useEffect(() => { void refresh() }, [refresh])\n\n useEffect(() => {\n const interval = setInterval(() => { void refresh() }, running ? POLL_RUNNING_MS : POLL_IDLE_MS)\n return () => { clearInterval(interval) }\n }, [refresh, running])\n\n // Sidebar badge sync: mirror availability onto the window event the trading\n // shell sidebar listens to (see UPDATE_AVAILABLE_EVENT in contract.ts).\n useEffect(() => {\n if (state === undefined) return\n const available = state.check.available === true && state.apply.phase !== 'done'\n window.dispatchEvent(new CustomEvent(UPDATE_AVAILABLE_EVENT, {\n detail: { available, version: state.check.latest?.version },\n }))\n }, [state])\n\n const handleCheck = async (): Promise<void> => {\n setCheckBusy(true)\n setActionError(undefined)\n try {\n setState(await requestUpdaterCheck(true))\n } catch (error) {\n setActionError(error instanceof Error ? error.message : String(error))\n } finally {\n setCheckBusy(false)\n }\n }\n\n const handleApply = async (): Promise<void> => {\n if (applyBusyRef.current) return\n applyBusyRef.current = true\n setActionError(undefined)\n try {\n setState(await requestUpdaterApply())\n // Pipeline started: tighten polling immediately instead of waiting a tick.\n void refresh()\n } catch (error) {\n setActionError(error instanceof Error ? error.message : String(error))\n } finally {\n applyBusyRef.current = false\n }\n }\n\n const handleRestart = (): void => {\n desktopBridge()?.relaunch?.()\n }\n\n const environment = state?.environment\n const check = state?.check\n const apply = state?.apply\n const progress = state?.progress\n const latest = check?.latest\n const releasesUrl = latest?.url ?? 'https://github.com/zhu1090093659/dsh-trading/releases'\n const publishedDay = formatDay(latest?.publishedAt)\n const hasUpdate = check?.available === true && apply?.phase !== 'done'\n const applyable = hasUpdate && latest?.payloadAvailable === true\n\n return (\n <div className={css.root}>\n <p className={css.lead}>{t('lead')}</p>\n\n <div className={css.versions}>\n <div className={css.versionItem}>\n <span className={css.versionLabel}>{t('currentVersion')}</span>\n <span className={css.versionValue}>{environment?.familyVersion ?? '—'}</span>\n </div>\n {environment?.appVersion !== undefined && (\n <div className={css.versionItem}>\n <span className={css.versionLabel}>{t('desktopApp')}</span>\n <span className={css.versionValue}>{environment.appVersion}</span>\n </div>\n )}\n </div>\n\n {environment !== undefined && !environment.supported && (\n <p className={css.statusText}>{t('unsupported')}</p>\n )}\n\n {environment?.supported === true && (\n <>\n <div className={css.statusRow}>\n {check?.status === 'error' && (\n <span className={`${css.statusText} ${css.statusTextError}`}>\n {t('checkError', { message: check.error ?? '' })}\n </span>\n )}\n {check?.status === 'ok' && !hasUpdate && apply?.phase !== 'done' && (\n <span className={`${css.statusText} ${css.statusTextOk}`}>{t('upToDate')}</span>\n )}\n {check?.at !== undefined && (\n <span className={css.statusText}>\n {t('lastCheck')}\n :\n {' '}\n {check.at.slice(0, 19).replace('T', ' ')}\n </span>\n )}\n {check?.at === undefined && check?.status !== 'ok' && (\n <span className={css.statusText}>{t('never')}</span>\n )}\n <button\n type=\"button\"\n className={css.secondaryButton}\n disabled={checkBusy || running}\n onClick={() => { void handleCheck() }}\n >\n {checkBusy ? t('checking') : t('checkNow')}\n </button>\n {actionError !== undefined && (\n <button type=\"button\" className={css.secondaryButton} onClick={() => { void handleCheck() }}>\n {t('retry')}\n </button>\n )}\n </div>\n\n {running && (\n <div className={css.progressWrap}>\n <span className={css.progressLabel}>\n <span>\n {progress?.step === 'download'\n ? t('phase.download')\n : progress?.step === 'verify'\n ? t('phase.verify')\n : progress?.step === 'install'\n ? t('phase.install')\n : t('phase.prepare')}\n </span>\n {progress?.percent !== undefined && (\n <span>{t('progress', { percent: progress.percent })}</span>\n )}\n </span>\n <div\n className={css.progressTrack}\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={progress?.percent ?? undefined}\n >\n <div\n className={`${css.progressFill} ${progress?.percent === undefined ? css.progressIndeterminate : ''}`}\n style={progress?.percent === undefined ? undefined : { width: `${progress.percent}%` }}\n />\n </div>\n </div>\n )}\n\n {hasUpdate && latest !== undefined && !running && (\n <div className={css.availableCard}>\n <p className={css.availableTitle}>{t('available', { version: latest.version })}</p>\n {publishedDay !== '' && (\n <p className={css.availableMeta}>{t('publishedAt', { date: publishedDay })}</p>\n )}\n {latest.notes.trim() !== '' && (\n <>\n <span className={css.notesTitle}>{t('notesTitle')}</span>\n <pre className={css.notes}>{latest.notes}</pre>\n </>\n )}\n <div className={css.actions}>\n {latest.payloadAvailable && (\n <button\n type=\"button\"\n className={css.primaryButton}\n onClick={() => { void handleApply() }}\n >\n {t('applyNow')}\n </button>\n )}\n <a className={css.link} href={releasesUrl} target=\"_blank\" rel=\"noreferrer\">\n {t('viewReleases')}\n </a>\n </div>\n {!latest.payloadAvailable && (\n <p className={css.doneMeta}>{t('payloadMissing')}</p>\n )}\n </div>\n )}\n\n {apply?.phase === 'done' && apply.targetVersion !== undefined && (\n <div className={css.doneCard}>\n <p className={css.doneTitle}>{t('done', { version: apply.targetVersion })}</p>\n <p className={css.doneMeta}>{t('restartHint')}</p>\n <div className={css.actions}>\n {desktopBridge()?.relaunch !== undefined && (\n <button type=\"button\" className={css.primaryButton} onClick={handleRestart}>\n {t('restartNow')}\n </button>\n )}\n {desktopBridge()?.relaunch === undefined && (\n <span className={css.doneMeta}>{t('restartManual')}</span>\n )}\n <a className={css.link} href={releasesUrl} target=\"_blank\" rel=\"noreferrer\">\n {t('viewReleases')}\n </a>\n </div>\n </div>\n )}\n\n {apply?.phase === 'error' && apply.error !== undefined && (\n <p className={css.errorText}>{apply.error}</p>\n )}\n </>\n )}\n\n {environment === undefined || !environment.supported ? (\n <a className={css.link} href={releasesUrl} target=\"_blank\" rel=\"noreferrer\">\n {t('viewReleases')}\n </a>\n ) : null}\n </div>\n )\n}\n","/**\n * Software-update dialog (the 'shell.overlay' entry registered by this plugin).\n * The sidebar's update entry dispatches UPDATER_OPEN_EVENT; this component owns\n * the modal chrome (mask click + Escape close) around UpdaterPanel. Frame-wide\n * floating layer: fixed overlay opts back into pointer events.\n */\nimport { useCallback, useEffect, useState } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport { UPDATER_OPEN_EVENT } from './contract.ts'\nimport { UpdaterPanel } from './UpdaterPanel.tsx'\nimport css from './updater-dialog.module.css'\n\nexport type UpdaterDialogProps = PropsLocale<'dshtrading.updater'>\n\nexport function UpdaterDialog({ t }: UpdaterDialogProps) {\n const [open, setOpen] = useState(false)\n\n useEffect(() => {\n const onOpen = (): void => { setOpen(true) }\n window.addEventListener(UPDATER_OPEN_EVENT, onOpen)\n return () => { window.removeEventListener(UPDATER_OPEN_EVENT, onOpen) }\n }, [])\n\n const close = useCallback((): void => { setOpen(false) }, [])\n\n useEffect(() => {\n if (!open) return\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') close()\n }\n document.addEventListener('keydown', onKeyDown)\n return () => { document.removeEventListener('keydown', onKeyDown) }\n }, [open, close])\n\n if (!open) return null\n\n return (\n <div className={css.overlay} role=\"presentation\">\n <div className={css.mask} aria-hidden=\"true\" onClick={close} />\n <div className={css.panel} role=\"dialog\" aria-modal=\"true\" aria-label={t('nav')}>\n <div className={css.header}>\n <span className={css.title}>{t('nav')}</span>\n <button type=\"button\" className={css.close} aria-label={t('close')} title={t('close')} onClick={close}>\n <svg viewBox=\"0 0 16 16\" width={14} height={14} aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.4\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M4.25 4.25l7.5 7.5M11.75 4.25l-7.5 7.5\" />\n </svg>\n </button>\n </div>\n <div className={css.body}>\n <UpdaterPanel t={t} />\n </div>\n </div>\n </div>\n )\n}\n","/**\n * dsh-trading auto-update, browser half — the software-update dialog on the\n * host's frame-wide shell.overlay layer. The entry point is the update button\n * beside Settings in the trading sidebar's bottom bar (client-ui-trading\n * dispatches UPDATER_OPEN_EVENT); this plugin owns the modal chrome and body.\n *\n * The dialog talks to the node half over /dshtrading/api/updater (same-origin\n * fetch inside the browser-auth fence). In environments without incremental\n * support (dev checkouts, headless profiles) it degrades to an information\n * surface linking the GitHub releases page.\n */\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from './contract.ts'\nimport { en, zh } from './locales.ts'\nimport { UpdaterDialog } from './UpdaterDialog.tsx'\n\nimport { UPDATE_AVAILABLE_EVENT, UPDATER_OPEN_EVENT } from './contract.ts'\n/** This dialog's locale namespace. */\nconst NS = 'dshtrading.updater'\n\n/** Required services (cordis fiber inject). */\nexport const inject = ['slots', 'locale']\n\n/**\n * Register the update dialog on shell.overlay (no settings.section: the entry\n * moved beside Settings in the sidebar bottom bar). The sidebar asks this\n * plugin to open through the UPDATER_OPEN_EVENT window event — cross-plugin\n * coupling is a DOM event, never an import.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.locale.bind(NS)\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-trading-updater: dictionaries')\n\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay',\n id: 'dshtrading-updater-dialog',\n order: 90,\n locale: NS,\n }, UpdaterDialog))\n}\n\nexport { UPDATE_AVAILABLE_EVENT, UPDATER_OPEN_EVENT } from './contract.ts'\n"],"mappings":";;;;;;;;;EASA,MAAa,KAAuC;GAClD,KAAK;GACL,MAAM;GACN,gBAAgB;GAChB,YAAY;GACZ,aAAa;GACb,cAAc;GACd,UAAU;GACV,UAAU;GACV,WAAW;GACX,OAAO;GACP,UAAU;GACV,WAAW;GACX,aAAa;GACb,YAAY;GACZ,UAAU;GACV,gBAAgB;GAChB,iBAAiB;GACjB,kBAAkB;GAClB,gBAAgB;GAChB,iBAAiB;GACjB,UAAU;GACV,MAAM;GACN,aAAa;GACb,YAAY;GACZ,eAAe;GACf,YAAY;GACZ,OAAO;GACP,OAAO;EACT;EAEA,MAAa,KAAuC;GAClD,KAAK;GACL,MAAM;GACN,gBAAgB;GAChB,YAAY;GACZ,aAAa;GACb,cAAc;GACd,UAAU;GACV,UAAU;GACV,WAAW;GACX,OAAO;GACP,UAAU;GACV,WAAW;GACX,aAAa;GACb,YAAY;GACZ,UAAU;GACV,gBAAgB;GAChB,iBAAiB;GACjB,kBAAkB;GAClB,gBAAgB;GAChB,iBAAiB;GACjB,UAAU;GACV,MAAM;GACN,aAAa;GACb,YAAY;GACZ,eAAe;GACf,YAAY;GACZ,OAAO;GACP,OAAO;EACT;;;;;;;;;;;;;;ECVA,MAAa,yBAAyB;EACtC,MAAa,qBAAqB;;;ECnDlC,IAAa,qBAAb,cAAwC,MAAM;GACvB;GAA0C;GAA/D,YAAY,QAAyB,SAAiB,MAAwB;IAC5E,MAAM,OAAO;IADM,KAAA,SAAA;IAA0C,KAAA,OAAA;GAE/D;EACF;EAEA,eAAe,YAAe,MAAc,MAAgC;GAC1E,MAAM,WAAW,MAAM,MAAM,MAAM,IAAI;GACvC,IAAI,CAAC,SAAS,IAAI;IAChB,MAAM,OAAO,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;IACxD,MAAM,SAAS,OAAO,MAAM,YAAY,YAAY,KAAK,YAAY,KAAK,OAAO,KAAK,UAAU;IAChG,MAAM,IAAI,mBAAmB,SAAS,QAAQ,aAAa,OAAO,cAAc,OAAO,SAAS,MAAM,IAAI,QAAQ,MAAM,IAAI;GAC9H;GACA,MAAM,OAAO,MAAM,SAAS,KAAK;GACjC,IAAI,SAAS,QAAQ,OAAO,SAAS,YAAa,KAA0B,OAAO,OAAO;IACxF,MAAM,WAAW;IACjB,MAAM,IAAI,mBAAmB,MAAM,SAAS,QAAQ,qBAAqB,QAAQ,SAAS,WAAW,yBAAyB,SAAS,IAAI;GAC7I;GACA,OAAO;EACT;;EAGA,eAAsB,oBAA8C;GAClE,OAAO,YAA6B,iCAAiC,EAAE,SAAS,EAAE,QAAQ,mBAAmB,EAAE,CAAC;EAClH;;EAGA,eAAsB,oBAAoB,OAA0C;GAClF,OAAO,YAA6B,uCAAuC,QAAQ,MAAM,OAAO,EAAE,SAAS,EAAE,QAAQ,mBAAmB,EAAE,CAAC;EAC7I;;EAGA,eAAsB,sBAAgD;GACpE,OAAO,YAA6B,iCAAiC;IACnE,QAAQ;IACR,SAAS,EAAE,gBAAgB,mBAAmB;IAC9C,MAAM;GACR,CAAC;EACH;;EAQA,SAAgB,gBAA2C;GACzD,IAAI,OAAO,WAAW,eAAe,EAAE,aAAa,SAAS,OAAO,KAAA;GACpE,OAAQ,OAAuC;EACjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECzCA,MAAM,eAAe;EACrB,MAAM,kBAAkB;;EAGxB,SAAS,UAAU,KAAiC;GAClD,IAAI,QAAQ,KAAA,GAAW,OAAO;GAC9B,MAAM,SAAS,IAAI,KAAK,GAAG;GAC3B,IAAI,OAAO,MAAM,OAAO,QAAQ,CAAC,GAAG,OAAO;GAC3C,OAAO,OAAO,YAAY,CAAC,CAAC,MAAM,GAAG,EAAE;EACzC;EAEA,SAAgB,aAAa,EAAE,KAAwB;GACrD,MAAM,CAAC,OAAO,aAAA,GAAYA,MAAAA,SAAAA,CAAsC,KAAA,CAAS;GACzE,MAAM,CAAC,aAAa,mBAAA,GAAkBA,MAAAA,SAAAA,CAA6B,KAAA,CAAS;GAC5E,MAAM,CAAC,WAAW,iBAAA,GAAgBA,MAAAA,SAAAA,CAAS,KAAK;GAChD,MAAM,gBAAA,GAAeC,MAAAA,OAAAA,CAAO,KAAK;GAEjC,MAAM,UAAU,OAAO,MAAM,UAAU;GAEvC,MAAM,WAAA,GAAUC,MAAAA,YAAAA,CAAY,YAAY;IACtC,IAAI;KACF,SAAS,MAAM,kBAAkB,CAAC;IACpC,QAAQ,CAER;GACF,GAAG,CAAC,CAAC;GAEL,CAAA,GAAA,MAAA,UAAA,OAAgB;IAAE,QAAa;GAAE,GAAG,CAAC,OAAO,CAAC;GAE7C,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,WAAW,kBAAkB;KAAE,QAAa;IAAE,GAAG,UAAU,kBAAkB,YAAY;IAC/F,aAAa;KAAE,cAAc,QAAQ;IAAE;GACzC,GAAG,CAAC,SAAS,OAAO,CAAC;GAIrB,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,UAAU,KAAA,GAAW;IACzB,MAAM,YAAY,MAAM,MAAM,cAAc,QAAQ,MAAM,MAAM,UAAU;IAC1E,OAAO,cAAc,IAAI,YAAY,wBAAwB,EAC3D,QAAQ;KAAE;KAAW,SAAS,MAAM,MAAM,QAAQ;IAAQ,EAC5D,CAAC,CAAC;GACJ,GAAG,CAAC,KAAK,CAAC;GAEV,MAAM,cAAc,YAA2B;IAC7C,aAAa,IAAI;IACjB,eAAe,KAAA,CAAS;IACxB,IAAI;KACF,SAAS,MAAM,oBAAoB,IAAI,CAAC;IAC1C,SAAS,OAAO;KACd,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;IACvE,UAAU;KACR,aAAa,KAAK;IACpB;GACF;GAEA,MAAM,cAAc,YAA2B;IAC7C,IAAI,aAAa,SAAS;IAC1B,aAAa,UAAU;IACvB,eAAe,KAAA,CAAS;IACxB,IAAI;KACF,SAAS,MAAM,oBAAoB,CAAC;KAEpC,QAAa;IACf,SAAS,OAAO;KACd,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;IACvE,UAAU;KACR,aAAa,UAAU;IACzB;GACF;GAEA,MAAM,sBAA4B;IAChC,cAAc,CAAC,EAAE,WAAW;GAC9B;GAEA,MAAM,cAAc,OAAO;GAC3B,MAAM,QAAQ,OAAO;GACrB,MAAM,QAAQ,OAAO;GACrB,MAAM,WAAW,OAAO;GACxB,MAAM,SAAS,OAAO;GACtB,MAAM,cAAc,QAAQ,OAAO;GACnC,MAAM,eAAe,UAAU,QAAQ,WAAW;GAClD,MAAM,YAAY,OAAO,cAAc,QAAQ,OAAO,UAAU;GAC9C,aAAa,QAAQ;GAEvC,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWC,iCAAI;IAApB,UAAA;KACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,iCAAI;MAAO,UAAA,EAAE,MAAM;KAAK,CAAA;KAEtC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,iCAAI;MAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,iCAAI;OAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,iCAAI;QAAe,UAAA,EAAE,gBAAgB;OAAQ,CAAA,GAC9D,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,iCAAI;QAAe,UAAA,aAAa,iBAAiB;OAAU,CAAA,CACzE;MACJ,CAAA,GAAA,aAAa,eAAe,KAAA,KAC3B,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,iCAAI;OAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,iCAAI;QAAe,UAAA,EAAE,YAAY;OAAQ,CAAA,GAC1D,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,iCAAI;QAAe,UAAA,YAAY;OAAiB,CAAA,CAC9D;MAEJ,CAAA,CAAA;;KAEJ,gBAAgB,KAAA,KAAa,CAAC,YAAY,aACzC,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,iCAAI;MAAa,UAAA,EAAE,aAAa;KAAK,CAAA;KAGpD,aAAa,cAAc,QAC1B,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;MACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,iCAAI;OAApB,UAAA;QACG,OAAO,WAAW,WACjB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAW,GAAGA,iCAAI,WAAW,GAAGA,iCAAI;SACvC,UAAA,EAAE,cAAc,EAAE,SAAS,MAAM,SAAS,GAAG,CAAC;QAC3C,CAAA;QAEP,OAAO,WAAW,QAAQ,CAAC,aAAa,OAAO,UAAU,UACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAW,GAAGA,iCAAI,WAAW,GAAGA,iCAAI;SAAiB,UAAA,EAAE,UAAU;QAAQ,CAAA;QAEhF,OAAO,OAAO,KAAA,KACb,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;SAAM,WAAWA,iCAAI;SAArB,UAAA;UACG,EAAE,WAAW;UAAE;UAEf;UACA,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,CAAC,QAAQ,KAAK,GAAG;SACnC;;QAEP,OAAO,OAAO,KAAA,KAAa,OAAO,WAAW,QAC5C,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,iCAAI;SAAa,UAAA,EAAE,OAAO;QAAQ,CAAA;QAErD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SACE,MAAK;SACL,WAAWA,iCAAI;SACf,UAAU,aAAa;SACvB,eAAe;UAAE,YAAiB;SAAE;SAEnC,UAAA,YAAY,EAAE,UAAU,IAAI,EAAE,UAAU;QACnC,CAAA;QACP,gBAAgB,KAAA,KACf,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;SAAQ,MAAK;SAAS,WAAWA,iCAAI;SAAiB,eAAe;UAAE,YAAiB;SAAE;SACvF,UAAA,EAAE,OAAO;QACJ,CAAA;OAEP;;MAEJ,WACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,iCAAI;OAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;QAAM,WAAWA,iCAAI;QAArB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UACG,UAAU,SAAS,aAChB,EAAE,gBAAgB,IAClB,UAAU,SAAS,WACjB,EAAE,cAAc,IAChB,UAAU,SAAS,YACjB,EAAE,eAAe,IACjB,EAAE,eAAe,EACrB,CAAA,GACL,UAAU,YAAY,KAAA,KACrB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,EAAE,YAAY,EAAE,SAAS,SAAS,QAAQ,CAAC,EAAQ,CAAA,CAExD;OACN,CAAA,GAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QACE,WAAWA,iCAAI;QACf,MAAK;QACL,iBAAe;QACf,iBAAe;QACf,iBAAe,UAAU,WAAW,KAAA;QAEpC,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SACE,WAAW,GAAGA,iCAAI,aAAa,GAAG,UAAU,YAAY,KAAA,IAAYA,iCAAI,wBAAwB;SAChG,OAAO,UAAU,YAAY,KAAA,IAAY,KAAA,IAAY,EAAE,OAAO,GAAG,SAAS,QAAQ,GAAG;QACtF,CAAA;OACE,CAAA,CACF;;MAGN,aAAa,WAAW,KAAA,KAAa,CAAC,WACrC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,iCAAI;OAApB,UAAA;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAWA,iCAAI;SAAiB,UAAA,EAAE,aAAa,EAAE,SAAS,OAAO,QAAQ,CAAC;QAAK,CAAA;QACjF,iBAAiB,MAChB,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAWA,iCAAI;SAAgB,UAAA,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;QAAK,CAAA;QAE/E,OAAO,MAAM,KAAK,MAAM,MACvB,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,iCAAI;SAAa,UAAA,EAAE,YAAY;QAAQ,CAAA,GACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAWA,iCAAI;SAAQ,UAAA,OAAO;QAAW,CAAA,CAC9C,EAAA,CAAA;QAEJ,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,iCAAI;SAApB,UAAA,CACG,OAAO,oBACN,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UACE,MAAK;UACL,WAAWA,iCAAI;UACf,eAAe;WAAE,YAAiB;UAAE;UAEnC,UAAA,EAAE,UAAU;SACP,CAAA,GAEV,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;UAAG,WAAWA,iCAAI;UAAM,MAAM;UAAa,QAAO;UAAS,KAAI;UAC5D,UAAA,EAAE,cAAc;SAChB,CAAA,CACA;;QACJ,CAAC,OAAO,oBACP,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAWA,iCAAI;SAAW,UAAA,EAAE,gBAAgB;QAAK,CAAA;OAEnD;;MAGN,OAAO,UAAU,UAAU,MAAM,kBAAkB,KAAA,KAClD,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,iCAAI;OAApB,UAAA;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAWA,iCAAI;SAAY,UAAA,EAAE,QAAQ,EAAE,SAAS,MAAM,cAAc,CAAC;QAAK,CAAA;QAC7E,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAWA,iCAAI;SAAW,UAAA,EAAE,aAAa;QAAK,CAAA;QACjD,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,iCAAI;SAApB,UAAA;UACG,cAAc,CAAC,EAAE,aAAa,KAAA,KAC7B,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WAAQ,MAAK;WAAS,WAAWA,iCAAI;WAAe,SAAS;WAC1D,UAAA,EAAE,YAAY;UACT,CAAA;UAET,cAAc,CAAC,EAAE,aAAa,KAAA,KAC7B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,iCAAI;WAAW,UAAA,EAAE,eAAe;UAAQ,CAAA;UAE3D,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;WAAG,WAAWA,iCAAI;WAAM,MAAM;WAAa,QAAO;WAAS,KAAI;WAC5D,UAAA,EAAE,cAAc;UAChB,CAAA;SACA;;OACF;;MAGN,OAAO,UAAU,WAAW,MAAM,UAAU,KAAA,KAC3C,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,iCAAI;OAAY,UAAA,MAAM;MAAS,CAAA;KAE/C,EAAA,CAAA;KAGH,gBAAgB,KAAA,KAAa,CAAC,YAAY,YACzC,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAWA,iCAAI;MAAM,MAAM;MAAa,QAAO;MAAS,KAAI;MAC5D,UAAA,EAAE,cAAc;KAChB,CAAA,IACD;IACD;;EAET;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EClPA,SAAgB,cAAc,EAAE,KAAyB;GACvD,MAAM,CAAC,MAAM,YAAA,GAAWC,MAAAA,SAAAA,CAAS,KAAK;GAEtC,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,eAAqB;KAAE,QAAQ,IAAI;IAAE;IAC3C,OAAO,iBAAiB,oBAAoB,MAAM;IAClD,aAAa;KAAE,OAAO,oBAAoB,oBAAoB,MAAM;IAAE;GACxE,GAAG,CAAC,CAAC;GAEL,MAAM,SAAA,GAAQC,MAAAA,YAAAA,OAAwB;IAAE,QAAQ,KAAK;GAAE,GAAG,CAAC,CAAC;GAE5D,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,CAAC,MAAM;IACX,MAAM,aAAa,UAA+B;KAChD,IAAI,MAAM,QAAQ,UAAU,MAAM;IACpC;IACA,SAAS,iBAAiB,WAAW,SAAS;IAC9C,aAAa;KAAE,SAAS,oBAAoB,WAAW,SAAS;IAAE;GACpE,GAAG,CAAC,MAAM,KAAK,CAAC;GAEhB,IAAI,CAAC,MAAM,OAAO;GAElB,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWC,kCAAI;IAAS,MAAK;IAAlC,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAWA,kCAAI;KAAM,eAAY;KAAO,SAAS;IAAQ,CAAA,GAC9D,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,kCAAI;KAAO,MAAK;KAAS,cAAW;KAAO,cAAY,EAAE,KAAK;KAA9E,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,kCAAI;MAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,kCAAI;OAAQ,UAAA,EAAE,KAAK;MAAQ,CAAA,GAC5C,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OAAQ,MAAK;OAAS,WAAWA,kCAAI;OAAO,cAAY,EAAE,OAAO;OAAG,OAAO,EAAE,OAAO;OAAG,SAAS;OAC9F,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,SAAQ;QAAY,OAAO;QAAI,QAAQ;QAAI,eAAY;QAAO,MAAK;QAAO,QAAO;QAAe,aAAY;QAAM,eAAc;QAAQ,gBAAe;QAC1J,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,GAAE,yCAA0C,CAAA;OAC/C,CAAA;MACC,CAAA,CACL;KACL,CAAA,GAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAWA,kCAAI;MAClB,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD,EAAiB,EAAI,CAAA;KAClB,CAAA,CACF;IACF,CAAA,CAAA;;EAET;;;;ECnCA,MAAM,KAAK;;EAGX,MAAa,SAAS,CAAC,SAAS,QAAQ;;;;;;;EAQxC,SAAgB,MAAM,KAA0B;GAC9C,IAAI,OAAO,KAAK,EAAE;GAClB,IAAI,aAAa,IAAI,OAAO,SAAS,IAAI;IAAE;IAAI;GAAG,CAAC,GAAG,mCAAmC;GAEzF,IAAI,MAAM,OAAO,uBAAuB,IAAI,MAAM,SAAS;IACzD,MAAM;IACN,IAAI;IACJ,OAAO;IACP,QAAQ;GACV,GAAG,aAAa,CAAC;EACnB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dshtrading/client-ui-updater",
3
- "description": "dsh-trading auto-update plugin: GitHub Releases version check with release notes, incremental update of the @dshtrading/* plugin family inside a desktop-seeded profile (vendor payload zip, per-package swap), and the '软件更新' first-level settings section. Browser half registers the settings.section; node half registers the /dshtrading/api/updater routes and the update engine.",
4
- "version": "0.2.0",
3
+ "description": "dsh-trading auto-update plugin: GitHub Releases version check with release notes, incremental update of the @dshtrading/* plugin family inside a desktop-seeded profile (vendor payload zip, per-package swap), and the software-update dialog opened from the trading sidebar's update entry. Browser half registers the shell.overlay dialog; node half registers the /dshtrading/api/updater routes and the update engine.",
4
+ "version": "0.3.0",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "./lib/index.d.ts",
@@ -26,12 +26,13 @@
26
26
  "license": "PolyForm-Noncommercial-1.0.0",
27
27
  "dependencies": {
28
28
  "fflate": "^0.8.2",
29
- "@dshtrading/dsh-home": "^0.2.0"
29
+ "@dshtrading/dsh-home": "^0.3.0"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "@deepseek-ai/cordis": ">=4.0.0",
33
- "@deepseek-ai/dsh-client-locale": ">=0.1.2-rc.1",
34
- "@deepseek-ai/dsh-client-ui-slots": ">=0.1.2-rc.1",
33
+ "@deepseek-ai/dsh-client-locale": ">=0.1.5-rc.1",
34
+ "@deepseek-ai/dsh-client-ui-layout": ">=0.1.5-rc.1",
35
+ "@deepseek-ai/dsh-client-ui-slots": ">=0.1.5-rc.1",
35
36
  "react": "^18.2.0",
36
37
  "@types/react": "~18.3.1"
37
38
  },
@@ -46,8 +47,9 @@
46
47
  },
47
48
  "devDependencies": {
48
49
  "@deepseek-ai/cordis": "^4.0.2",
49
- "@deepseek-ai/dsh-client-locale": "0.1.2-rc.1",
50
- "@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1",
50
+ "@deepseek-ai/dsh-client-locale": "0.1.5-rc.1",
51
+ "@deepseek-ai/dsh-client-ui-layout": "0.1.5-rc.1",
52
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.1",
51
53
  "@types/node": "^24.0.0",
52
54
  "@types/react": "~18.3.1",
53
55
  "lightningcss": "^1.0.0",