@kenz1117/dsh-ui-usage-billing 0.9.19 → 0.9.20

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
@@ -31,18 +31,25 @@ window.__ModuleLoader__.load({
31
31
  };
32
32
  /** localStorage key(与 budget store 的 `dsh.ui-usage-billing.*` 命名空间一致)。 */
33
33
  const FLOAT_WINDOW_STORAGE_KEY = "dsh.ui-usage-billing.float";
34
- /** 读取浮窗偏好(含损坏/缺失回退到默认)。仅在浏览器半区调用。 */
34
+ /** 读取浮窗偏好(含损坏/缺失回退到默认)。仅在浏览器半区调用。
35
+ * 返回全新对象(含 targets 数组拷贝),避免调用方就地修改污染共享默认值。 */
35
36
  function loadFloatWindowPrefs() {
36
37
  try {
37
38
  const raw = localStorage.getItem(FLOAT_WINDOW_STORAGE_KEY);
38
- if (raw === null) return DEFAULT_FLOAT_WINDOW_PREFS;
39
+ if (raw === null) return {
40
+ ...DEFAULT_FLOAT_WINDOW_PREFS,
41
+ targets: [...DEFAULT_FLOAT_WINDOW_PREFS.targets]
42
+ };
39
43
  const parsed = JSON.parse(raw);
40
44
  return {
41
45
  mode: parsed.mode === "subscription" ? "subscription" : "combined",
42
46
  targets: Array.isArray(parsed.targets) ? parsed.targets.filter((entry) => typeof entry === "string") : []
43
47
  };
44
48
  } catch {
45
- return DEFAULT_FLOAT_WINDOW_PREFS;
49
+ return {
50
+ ...DEFAULT_FLOAT_WINDOW_PREFS,
51
+ targets: [...DEFAULT_FLOAT_WINDOW_PREFS.targets]
52
+ };
46
53
  }
47
54
  }
48
55
  /** 写入浮窗偏好。失败静默(展示偏好非关键)。 */
@@ -63,347 +70,347 @@ window.__ModuleLoader__.load({
63
70
  document.head.appendChild(tag);
64
71
  }
65
72
  var UsageBilling_module_css_default = {
66
- "panel": "VWh0dG_panel",
73
+ "shareSegUser": "VWh0dG_shareSegUser",
74
+ "budgetFillWarn": "VWh0dG_budgetFillWarn",
75
+ "chartTooltipRow": "VWh0dG_chartTooltipRow",
76
+ "rateBadgeLive": "VWh0dG_rateBadgeLive",
77
+ "siteKindUnknown": "VWh0dG_siteKindUnknown",
78
+ "triggerSub": "VWh0dG_triggerSub",
79
+ "subscriptionFillWarn": "VWh0dG_subscriptionFillWarn",
80
+ "roundsFlagMark": "VWh0dG_roundsFlagMark",
81
+ "floatTargets": "VWh0dG_floatTargets",
82
+ "bucketStatLabel": "VWh0dG_bucketStatLabel",
83
+ "providerGroupName": "VWh0dG_providerGroupName",
84
+ "floatModeBtn": "VWh0dG_floatModeBtn",
85
+ "floatSub": "VWh0dG_floatSub",
86
+ "budgetFillOver": "VWh0dG_budgetFillOver",
87
+ "numCol": "VWh0dG_numCol",
88
+ "tokenModelPartOut": "VWh0dG_tokenModelPartOut",
89
+ "rangeToggle": "VWh0dG_rangeToggle",
90
+ "peakAlertPreview": "VWh0dG_peakAlertPreview",
91
+ "chartStack": "VWh0dG_chartStack",
92
+ "triggerSparkHot": "VWh0dG_triggerSparkHot",
93
+ "budgetFill": "VWh0dG_budgetFill",
94
+ "liveTierOff": "VWh0dG_liveTierOff",
95
+ "roundsAxis": "VWh0dG_roundsAxis",
96
+ "subscriptionWindow": "VWh0dG_subscriptionWindow",
97
+ "pricingChevronOpen": "VWh0dG_pricingChevronOpen",
98
+ "balanceDaysBadgeLow": "VWh0dG_balanceDaysBadgeLow",
99
+ "triggerPopMetricValue": "VWh0dG_triggerPopMetricValue",
100
+ "triggerPopBadgeDirect": "VWh0dG_triggerPopBadgeDirect",
101
+ "roundsBarColPeak": "VWh0dG_roundsBarColPeak",
102
+ "roundsBarColOff": "VWh0dG_roundsBarColOff",
103
+ "peakAlertCenter": "VWh0dG_peakAlertCenter",
104
+ "triggerPopMetricHighlight": "VWh0dG_triggerPopMetricHighlight",
105
+ "modelTable": "VWh0dG_modelTable",
106
+ "pluginInfoLabel": "VWh0dG_pluginInfoLabel",
107
+ "heroGauge": "VWh0dG_heroGauge",
108
+ "triggerPopValueStack": "VWh0dG_triggerPopValueStack",
67
109
  "triggerPopSwitchBtn": "VWh0dG_triggerPopSwitchBtn",
68
- "bucketStatValue": "VWh0dG_bucketStatValue",
69
- "chartTooltipSwatch": "VWh0dG_chartTooltipSwatch",
70
- "panelHead": "VWh0dG_panelHead",
71
- "roundsBarLabel": "VWh0dG_roundsBarLabel",
72
- "chartSvg": "VWh0dG_chartSvg",
73
- "heatmapLegend": "VWh0dG_heatmapLegend",
74
- "triggerPopMetric": "VWh0dG_triggerPopMetric",
75
- "siteRowMeta": "VWh0dG_siteRowMeta",
110
+ "shareSeg": "VWh0dG_shareSeg",
111
+ "billing-trigger": "VWh0dG_billing-trigger",
112
+ "deltaUp": "VWh0dG_deltaUp",
113
+ "heroTop": "VWh0dG_heroTop",
114
+ "budgetInputWrap": "VWh0dG_budgetInputWrap",
76
115
  "balanceDetailGrid": "VWh0dG_balanceDetailGrid",
77
- "subscriptionWindowLabel": "VWh0dG_subscriptionWindowLabel",
78
- "liveCostSep": "VWh0dG_liveCostSep",
79
- "pricingChevron": "VWh0dG_pricingChevron",
80
- "roundsBarCol": "VWh0dG_roundsBarCol",
81
- "heatmap": "VWh0dG_heatmap",
82
- "hero": "VWh0dG_hero",
83
- "triggerPopFootName": "VWh0dG_triggerPopFootName",
84
- "balanceDetailLabel": "VWh0dG_balanceDetailLabel",
85
- "heatmapYearCell": "VWh0dG_heatmapYearCell",
86
- "tabNav": "VWh0dG_tabNav",
87
- "roundsBarWrap": "VWh0dG_roundsBarWrap",
88
- "peakAlertTag": "VWh0dG_peakAlertTag",
89
- "dashboardModal": "VWh0dG_dashboardModal",
90
- "rateBadgeBuiltin": "VWh0dG_rateBadgeBuiltin",
91
- "heroGaugeLabel": "VWh0dG_heroGaugeLabel",
116
+ "peakAlertPanelLabel": "VWh0dG_peakAlertPanelLabel",
117
+ "budgetValue": "VWh0dG_budgetValue",
118
+ "healthBadgeOk": "VWh0dG_healthBadgeOk",
119
+ "triggerPopBadge": "VWh0dG_triggerPopBadge",
120
+ "liveCostItem": "VWh0dG_liveCostItem",
92
121
  "kpiLabel": "VWh0dG_kpiLabel",
93
- "rateBadge": "VWh0dG_rateBadge",
94
- "deltaDown": "VWh0dG_deltaDown",
95
- "pricingTip": "VWh0dG_pricingTip",
96
- "exportButton": "VWh0dG_exportButton",
97
- "siteRowName": "VWh0dG_siteRowName",
98
- "bucketThird": "VWh0dG_bucketThird",
99
- "chartLine": "VWh0dG_chartLine",
100
- "siteKindDirect": "VWh0dG_siteKindDirect",
101
- "planTag": "VWh0dG_planTag",
102
- "balanceDaysBadgeLow": "VWh0dG_balanceDaysBadgeLow",
103
- "subscriptionStatus": "VWh0dG_subscriptionStatus",
104
- "heatmapYearMonths": "VWh0dG_heatmapYearMonths",
105
- "floatSub": "VWh0dG_floatSub",
106
- "pluginInfoRow": "VWh0dG_pluginInfoRow",
107
- "kpiValue": "VWh0dG_kpiValue",
108
- "floatSubPlan": "VWh0dG_floatSubPlan",
109
- "triggerPopFootNotes": "VWh0dG_triggerPopFootNotes",
110
- "triggerPopMuted": "VWh0dG_triggerPopMuted",
122
+ "siteRowCost": "VWh0dG_siteRowCost",
123
+ "roundsEmpty": "VWh0dG_roundsEmpty",
124
+ "peakAlertOff": "VWh0dG_peakAlertOff",
125
+ "subscriptionFillOver": "VWh0dG_subscriptionFillOver",
126
+ "panel": "VWh0dG_panel",
127
+ "heroGaugeCenter": "VWh0dG_heroGaugeCenter",
128
+ "chartBarPlaceholder": "VWh0dG_chartBarPlaceholder",
129
+ "heroReadout": "VWh0dG_heroReadout",
130
+ "modelProvider": "VWh0dG_modelProvider",
131
+ "subscriptionGrid": "VWh0dG_subscriptionGrid",
132
+ "roundsBarLabel": "VWh0dG_roundsBarLabel",
133
+ "heatmapYear": "VWh0dG_heatmapYear",
134
+ "triggerPopFootNote": "VWh0dG_triggerPopFootNote",
135
+ "triggerPopFoot": "VWh0dG_triggerPopFoot",
136
+ "heatmap": "VWh0dG_heatmap",
137
+ "roundsFlagBadge": "VWh0dG_roundsFlagBadge",
138
+ "tokenModelPartIn": "VWh0dG_tokenModelPartIn",
111
139
  "heroSideSpacer": "VWh0dG_heroSideSpacer",
112
- "providerGroupMeta": "VWh0dG_providerGroupMeta",
113
- "bucketSep": "VWh0dG_bucketSep",
114
- "heatmapFooter": "VWh0dG_heatmapFooter",
115
- "shareLegend": "VWh0dG_shareLegend",
116
- "flatTag": "VWh0dG_flatTag",
117
- "balanceDetailHead": "VWh0dG_balanceDetailHead",
118
140
  "triggerWrap": "VWh0dG_triggerWrap",
119
- "reconcileNotice": "VWh0dG_reconcileNotice",
120
- "dashboardRight": "VWh0dG_dashboardRight",
121
- "triggerPopFoot": "VWh0dG_triggerPopFoot",
122
- "heroSideLabel": "VWh0dG_heroSideLabel",
123
- "heroGauge": "VWh0dG_heroGauge",
124
- "budgetLabel": "VWh0dG_budgetLabel",
125
- "budgetUnit": "VWh0dG_budgetUnit",
126
- "balanceDays": "VWh0dG_balanceDays",
127
- "shareTrack": "VWh0dG_shareTrack",
128
- "switch": "VWh0dG_switch",
129
- "subscriptionFillOver": "VWh0dG_subscriptionFillOver",
130
- "roundsBars": "VWh0dG_roundsBars",
131
- "unpricedHint": "VWh0dG_unpricedHint",
132
- "heatmapYearGrid": "VWh0dG_heatmapYearGrid",
133
- "balanceCell": "VWh0dG_balanceCell",
134
- "triggerIcon": "VWh0dG_triggerIcon",
135
- "tableScroll": "VWh0dG_tableScroll",
136
- "budgetInputWrap": "VWh0dG_budgetInputWrap",
137
- "rangeButtonActive": "VWh0dG_rangeButtonActive",
138
- "heroMeta": "VWh0dG_heroMeta",
139
- "heroGaugeTrack": "VWh0dG_heroGaugeTrack",
140
- "shareSegTool": "VWh0dG_shareSegTool",
141
- "budgetFillWarn": "VWh0dG_budgetFillWarn",
142
- "currencyButtonActive": "VWh0dG_currencyButtonActive",
143
- "bucketStatLabel": "VWh0dG_bucketStatLabel",
144
- "dashboardHead": "VWh0dG_dashboardHead",
145
- "chartTooltipRow": "VWh0dG_chartTooltipRow",
146
- "heatmapGrid": "VWh0dG_heatmapGrid",
147
- "panelHint": "VWh0dG_panelHint",
148
- "siteRow": "VWh0dG_siteRow",
149
- "triggerPopUpdated": "VWh0dG_triggerPopUpdated",
150
- "shareSegAssistant": "VWh0dG_shareSegAssistant",
151
- "heatmapCell": "VWh0dG_heatmapCell",
152
- "floatModeRow": "VWh0dG_floatModeRow",
153
- "pluginInfo": "VWh0dG_pluginInfo",
154
- "dashboardBody": "VWh0dG_dashboardBody",
155
- "peakAlert": "VWh0dG_peakAlert",
156
- "settingsHint": "VWh0dG_settingsHint",
157
- "healthOk": "VWh0dG_healthOk",
158
- "settingsHead": "VWh0dG_settingsHead",
159
- "budget": "VWh0dG_budget",
160
- "dashboardTitle": "VWh0dG_dashboardTitle",
161
- "budgetControls": "VWh0dG_budgetControls",
162
- "triggerPopLabel": "VWh0dG_triggerPopLabel",
163
- "floatModeBtnOn": "VWh0dG_floatModeBtnOn",
164
- "peakAlertPanelHead": "VWh0dG_peakAlertPanelHead",
165
- "siteRowCallsLow": "VWh0dG_siteRowCallsLow",
166
141
  "shareSegPeak": "VWh0dG_shareSegPeak",
167
- "siteRowCost": "VWh0dG_siteRowCost",
168
- "bucketStat": "VWh0dG_bucketStat",
169
- "shareItem": "VWh0dG_shareItem",
170
- "liveTierOff": "VWh0dG_liveTierOff",
171
- "subscriptionAuto": "VWh0dG_subscriptionAuto",
172
- "triggerPopFootStrong": "VWh0dG_triggerPopFootStrong",
173
- "subscriptionGoldFlow": "VWh0dG_subscriptionGoldFlow",
174
- "reconcileIcon": "VWh0dG_reconcileIcon",
175
- "kpiDetail": "VWh0dG_kpiDetail",
176
- "floatTargets": "VWh0dG_floatTargets",
177
- "peakAlertNum": "VWh0dG_peakAlertNum",
142
+ "tabPanel": "VWh0dG_tabPanel",
143
+ "tabButton": "VWh0dG_tabButton",
144
+ "triggerPopMetrics": "VWh0dG_triggerPopMetrics",
145
+ "triggerPopHead": "VWh0dG_triggerPopHead",
146
+ "currencyToggle": "VWh0dG_currencyToggle",
147
+ "bucketOfficial": "VWh0dG_bucketOfficial",
148
+ "settingsTitle": "VWh0dG_settingsTitle",
178
149
  "railButton": "VWh0dG_railButton",
179
- "heroGaugeSvg": "VWh0dG_heroGaugeSvg",
180
- "pluginInfoValue": "VWh0dG_pluginInfoValue",
181
- "staleNotice": "VWh0dG_staleNotice",
182
- "bucketStatSub": "VWh0dG_bucketStatSub",
150
+ "providerGroupTitle": "VWh0dG_providerGroupTitle",
151
+ "kpiGrid": "VWh0dG_kpiGrid",
152
+ "reconcileDismiss": "VWh0dG_reconcileDismiss",
153
+ "healthBad": "VWh0dG_healthBad",
154
+ "budgetOverPulse": "VWh0dG_budgetOverPulse",
155
+ "triggerPopFootTitle": "VWh0dG_triggerPopFootTitle",
156
+ "siteKindTag": "VWh0dG_siteKindTag",
157
+ "triggerPopSwitcher": "VWh0dG_triggerPopSwitcher",
158
+ "triggerAmount": "VWh0dG_triggerAmount",
159
+ "currencyButtonActive": "VWh0dG_currencyButtonActive",
160
+ "providerGroupBalanceLabel": "VWh0dG_providerGroupBalanceLabel",
161
+ "budgetLabel": "VWh0dG_budgetLabel",
183
162
  "heatmapRangeButton": "VWh0dG_heatmapRangeButton",
184
- "triggerPopValueStack": "VWh0dG_triggerPopValueStack",
185
- "triggerPopTitle": "VWh0dG_triggerPopTitle",
186
- "triggerSub": "VWh0dG_triggerSub",
187
- "triggerRow": "VWh0dG_triggerRow",
188
- "heroGaugeArcOver": "VWh0dG_heroGaugeArcOver",
189
- "roundsEmpty": "VWh0dG_roundsEmpty",
190
- "subscriptionName": "VWh0dG_subscriptionName",
191
- "triggerPopBars": "VWh0dG_triggerPopBars",
192
- "shareDot": "VWh0dG_shareDot",
193
- "dashboardIn": "VWh0dG_dashboardIn",
194
- "budgetFillOver": "VWh0dG_budgetFillOver",
195
- "subscriptionTier": "VWh0dG_subscriptionTier",
196
- "heroGaugeArc": "VWh0dG_heroGaugeArc",
197
- "uncataloguedTag": "VWh0dG_uncataloguedTag",
198
- "subscriptionExhausted": "VWh0dG_subscriptionExhausted",
199
- "heroGaugeCenter": "VWh0dG_heroGaugeCenter",
200
- "emptyRow": "VWh0dG_emptyRow",
201
- "providerGroupBalance": "VWh0dG_providerGroupBalance",
202
- "roundsFlagMark": "VWh0dG_roundsFlagMark",
203
- "panelTitle": "VWh0dG_panelTitle",
204
- "pricingToggle": "VWh0dG_pricingToggle",
205
- "dashboard": "VWh0dG_dashboard",
206
- "roundsAxis": "VWh0dG_roundsAxis",
207
- "liveQuotaCrit": "VWh0dG_liveQuotaCrit",
163
+ "bucketStat": "VWh0dG_bucketStat",
164
+ "tabButtonActive": "VWh0dG_tabButtonActive",
165
+ "peakAlertSelect": "VWh0dG_peakAlertSelect",
208
166
  "triggerPopStrong": "VWh0dG_triggerPopStrong",
209
- "pricingToggleText": "VWh0dG_pricingToggleText",
210
- "healthBad": "VWh0dG_healthBad",
211
- "triggerPopMetricValue": "VWh0dG_triggerPopMetricValue",
212
- "balanceDetailTitle": "VWh0dG_balanceDetailTitle",
213
- "roundsBarColPeak": "VWh0dG_roundsBarColPeak",
214
- "shareSegOff": "VWh0dG_shareSegOff",
167
+ "emptyRow": "VWh0dG_emptyRow",
168
+ "liveCostBar": "VWh0dG_liveCostBar",
169
+ "reconcileIcon": "VWh0dG_reconcileIcon",
170
+ "planTag": "VWh0dG_planTag",
171
+ "liveTierPeak": "VWh0dG_liveTierPeak",
172
+ "subscriptionTier": "VWh0dG_subscriptionTier",
173
+ "deltaDown": "VWh0dG_deltaDown",
174
+ "chartLine": "VWh0dG_chartLine",
175
+ "subscriptionGoldFlow": "VWh0dG_subscriptionGoldFlow",
176
+ "na": "VWh0dG_na",
177
+ "modelDot": "VWh0dG_modelDot",
178
+ "triggerPopFootNotes": "VWh0dG_triggerPopFootNotes",
179
+ "heroGaugeSvg": "VWh0dG_heroGaugeSvg",
180
+ "bucketThird": "VWh0dG_bucketThird",
215
181
  "heatmapYearWeekdays": "VWh0dG_heatmapYearWeekdays",
216
- "triggerPopSubscription": "VWh0dG_triggerPopSubscription",
217
- "peakAlertOff": "VWh0dG_peakAlertOff",
218
- "providerGroupBalanceLabel": "VWh0dG_providerGroupBalanceLabel",
219
- "balanceDaysLow": "VWh0dG_balanceDaysLow",
182
+ "heroSideValue": "VWh0dG_heroSideValue",
183
+ "triggerPopAlert": "VWh0dG_triggerPopAlert",
184
+ "heroLabel": "VWh0dG_heroLabel",
185
+ "triggerPopMuted": "VWh0dG_triggerPopMuted",
186
+ "switch": "VWh0dG_switch",
220
187
  "chartLegendLine": "VWh0dG_chartLegendLine",
221
- "peakAlertPeak": "VWh0dG_peakAlertPeak",
222
- "triggerPopName": "VWh0dG_triggerPopName",
223
- "heroSideItem": "VWh0dG_heroSideItem",
224
- "peakAlertPanelLabel": "VWh0dG_peakAlertPanelLabel",
188
+ "balanceDaysLow": "VWh0dG_balanceDaysLow",
189
+ "floatModeRow": "VWh0dG_floatModeRow",
190
+ "floatModeBtnOn": "VWh0dG_floatModeBtnOn",
191
+ "heatmapGrid": "VWh0dG_heatmapGrid",
192
+ "providerGroupList": "VWh0dG_providerGroupList",
193
+ "heroGaugeTrack": "VWh0dG_heroGaugeTrack",
194
+ "heroGaugePctOver": "VWh0dG_heroGaugePctOver",
195
+ "chartBar": "VWh0dG_chartBar",
196
+ "pricingTip": "VWh0dG_pricingTip",
197
+ "siteRowName": "VWh0dG_siteRowName",
198
+ "bandTagOff": "VWh0dG_bandTagOff",
199
+ "balanceDetailRow": "VWh0dG_balanceDetailRow",
200
+ "subscriptionExhausted": "VWh0dG_subscriptionExhausted",
201
+ "bandPriceOff": "VWh0dG_bandPriceOff",
202
+ "triggerPopFootStatusLow": "VWh0dG_triggerPopFootStatusLow",
203
+ "exportLabel": "VWh0dG_exportLabel",
204
+ "currencyButton": "VWh0dG_currencyButton",
205
+ "heatmapRangeButtonActive": "VWh0dG_heatmapRangeButtonActive",
206
+ "peakAlertHint": "VWh0dG_peakAlertHint",
207
+ "triggerSparkBar": "VWh0dG_triggerSparkBar",
208
+ "tokenPanel": "VWh0dG_tokenPanel",
209
+ "providerGroupBadge": "VWh0dG_providerGroupBadge",
210
+ "chartDot": "VWh0dG_chartDot",
211
+ "exportBar": "VWh0dG_exportBar",
212
+ "chartLegendBar": "VWh0dG_chartLegendBar",
213
+ "siteKindDirect": "VWh0dG_siteKindDirect",
214
+ "budget": "VWh0dG_budget",
225
215
  "estimatedTag": "VWh0dG_estimatedTag",
226
- "budgetOverPulse": "VWh0dG_budgetOverPulse",
227
- "chartStack": "VWh0dG_chartStack",
228
- "switchOn": "VWh0dG_switchOn",
229
- "balanceDetailValue": "VWh0dG_balanceDetailValue",
230
- "budgetHead": "VWh0dG_budgetHead",
231
- "heatmapYearScroll": "VWh0dG_heatmapYearScroll",
232
- "budgetValue": "VWh0dG_budgetValue",
233
- "providerGroupTitle": "VWh0dG_providerGroupTitle",
234
- "roundsBarColOff": "VWh0dG_roundsBarColOff",
235
- "floatSubName": "VWh0dG_floatSubName",
216
+ "kpiGreen": "VWh0dG_kpiGreen",
217
+ "heatmapYearMonth": "VWh0dG_heatmapYearMonth",
218
+ "heroGaugePct": "VWh0dG_heroGaugePct",
219
+ "triggerRow": "VWh0dG_triggerRow",
236
220
  "peakAlertPanelBody": "VWh0dG_peakAlertPanelBody",
237
- "deltaUp": "VWh0dG_deltaUp",
238
- "siteKindSite": "VWh0dG_siteKindSite",
239
- "peakAlertPanel": "VWh0dG_peakAlertPanel",
240
- "peakAlertPreview": "VWh0dG_peakAlertPreview",
241
- "rangeToggle": "VWh0dG_rangeToggle",
242
- "balanceDetailClose": "VWh0dG_balanceDetailClose",
243
- "peakAlertCheck": "VWh0dG_peakAlertCheck",
221
+ "roundsBars": "VWh0dG_roundsBars",
222
+ "balanceDetailLabel": "VWh0dG_balanceDetailLabel",
223
+ "shareDot": "VWh0dG_shareDot",
224
+ "chartTooltipSwatch": "VWh0dG_chartTooltipSwatch",
225
+ "heatmapYearMonths": "VWh0dG_heatmapYearMonths",
226
+ "heroGaugeArcOver": "VWh0dG_heroGaugeArcOver",
227
+ "healthBadge": "VWh0dG_healthBadge",
244
228
  "budgetHint": "VWh0dG_budgetHint",
245
- "triggerPopAlert": "VWh0dG_triggerPopAlert",
246
- "peakAlertHint": "VWh0dG_peakAlertHint",
247
- "subscriptionTrack": "VWh0dG_subscriptionTrack",
248
- "shareSeg": "VWh0dG_shareSeg",
249
- "balanceDetailPop": "VWh0dG_balanceDetailPop",
250
- "peakAlertCountdown": "VWh0dG_peakAlertCountdown",
251
- "subscriptionWindow": "VWh0dG_subscriptionWindow",
252
- "trendPanel": "VWh0dG_trendPanel",
253
- "liveCostItem": "VWh0dG_liveCostItem",
254
- "triggerPopBadgeDirect": "VWh0dG_triggerPopBadgeDirect",
255
- "heroMain": "VWh0dG_heroMain",
229
+ "dashboardBody": "VWh0dG_dashboardBody",
230
+ "rangeButtonActive": "VWh0dG_rangeButtonActive",
231
+ "reconcileNotice": "VWh0dG_reconcileNotice",
232
+ "budgetTrack": "VWh0dG_budgetTrack",
233
+ "chartCrosshair": "VWh0dG_chartCrosshair",
234
+ "heroGaugeLabel": "VWh0dG_heroGaugeLabel",
235
+ "chartAxisLabel": "VWh0dG_chartAxisLabel",
236
+ "shareSegOff": "VWh0dG_shareSegOff",
256
237
  "chartTooltip": "VWh0dG_chartTooltip",
257
- "roundsBarFlagged": "VWh0dG_roundsBarFlagged",
258
- "triggerPopMetricLabel": "VWh0dG_triggerPopMetricLabel",
259
- "bucketSummary": "VWh0dG_bucketSummary",
260
- "costCol": "VWh0dG_costCol",
261
- "chartEmpty": "VWh0dG_chartEmpty",
262
- "providerGroupName": "VWh0dG_providerGroupName",
238
+ "chartGrid": "VWh0dG_chartGrid",
239
+ "heatmapCellEmpty": "VWh0dG_heatmapCellEmpty",
240
+ "healthBadgeBad": "VWh0dG_healthBadgeBad",
241
+ "triggerIcon": "VWh0dG_triggerIcon",
242
+ "kpiTile": "VWh0dG_kpiTile",
243
+ "heatmapFooter": "VWh0dG_heatmapFooter",
244
+ "heatmapYearScroll": "VWh0dG_heatmapYearScroll",
245
+ "floatTargetLabel": "VWh0dG_floatTargetLabel",
263
246
  "peakAlertIn": "VWh0dG_peakAlertIn",
264
- "triggerSparkBar": "VWh0dG_triggerSparkBar",
265
- "triggerPopBadgeSub": "VWh0dG_triggerPopBadgeSub",
266
- "subscriptionFill": "VWh0dG_subscriptionFill",
267
- "providerGroupHead": "VWh0dG_providerGroupHead",
247
+ "costCol": "VWh0dG_costCol",
248
+ "headTitleRow": "VWh0dG_headTitleRow",
249
+ "switchKnob": "VWh0dG_switchKnob",
250
+ "triggerPopTitle": "VWh0dG_triggerPopTitle",
251
+ "bucketCost": "VWh0dG_bucketCost",
252
+ "providerGroupBalance": "VWh0dG_providerGroupBalance",
253
+ "shareItem": "VWh0dG_shareItem",
254
+ "siteRowCallsLow": "VWh0dG_siteRowCallsLow",
268
255
  "heatmapHover": "VWh0dG_heatmapHover",
269
- "triggerPopOpenBtn": "VWh0dG_triggerPopOpenBtn",
270
- "heroReadout": "VWh0dG_heroReadout",
271
- "roundsFlagBadge": "VWh0dG_roundsFlagBadge",
272
- "triggerSparkHot": "VWh0dG_triggerSparkHot",
273
- "chartBarPlaceholder": "VWh0dG_chartBarPlaceholder",
274
- "chartCrosshair": "VWh0dG_chartCrosshair",
275
- "heroTop": "VWh0dG_heroTop",
276
- "tokenModelBar": "VWh0dG_tokenModelBar",
277
- "triggerPopRow": "VWh0dG_triggerPopRow",
278
- "modelProvider": "VWh0dG_modelProvider",
279
- "triggerPopBar": "VWh0dG_triggerPopBar",
280
- "healthBadgeBad": "VWh0dG_healthBadgeBad",
281
- "trigger": "VWh0dG_trigger",
282
- "reconcileText": "VWh0dG_reconcileText",
283
- "billing-trigger": "VWh0dG_billing-trigger",
284
- "exportLabel": "VWh0dG_exportLabel",
256
+ "subscriptionPct": "VWh0dG_subscriptionPct",
257
+ "peakAlertPeak": "VWh0dG_peakAlertPeak",
258
+ "hero": "VWh0dG_hero",
259
+ "closeButton": "VWh0dG_closeButton",
260
+ "bucketSep": "VWh0dG_bucketSep",
261
+ "roundsBar": "VWh0dG_roundsBar",
262
+ "heroCurrency": "VWh0dG_heroCurrency",
263
+ "chartWrap": "VWh0dG_chartWrap",
264
+ "delta": "VWh0dG_delta",
265
+ "pricingToggle": "VWh0dG_pricingToggle",
266
+ "subscriptionHead": "VWh0dG_subscriptionHead",
267
+ "roundsBarCol": "VWh0dG_roundsBarCol",
268
+ "heroValue": "VWh0dG_heroValue",
285
269
  "siteRowTitle": "VWh0dG_siteRowTitle",
286
- "rangeButton": "VWh0dG_rangeButton",
287
- "currencyToggle": "VWh0dG_currencyToggle",
288
- "triggerMeta": "VWh0dG_triggerMeta",
289
- "shareValue": "VWh0dG_shareValue",
290
- "na": "VWh0dG_na",
291
- "floatSubHead": "VWh0dG_floatSubHead",
292
- "triggerPopMetrics": "VWh0dG_triggerPopMetrics",
293
- "heroSide": "VWh0dG_heroSide",
270
+ "healthOk": "VWh0dG_healthOk",
271
+ "dashboardHead": "VWh0dG_dashboardHead",
272
+ "heroMeta": "VWh0dG_heroMeta",
273
+ "liveCostSep": "VWh0dG_liveCostSep",
274
+ "pluginInfoLink": "VWh0dG_pluginInfoLink",
275
+ "tokenModelParts": "VWh0dG_tokenModelParts",
276
+ "chartSvg": "VWh0dG_chartSvg",
277
+ "liveQuotaCrit": "VWh0dG_liveQuotaCrit",
278
+ "balanceDetailValue": "VWh0dG_balanceDetailValue",
279
+ "rateBadgeBuiltin": "VWh0dG_rateBadgeBuiltin",
280
+ "balanceDetailTitle": "VWh0dG_balanceDetailTitle",
281
+ "heroSideItem": "VWh0dG_heroSideItem",
282
+ "exportButton": "VWh0dG_exportButton",
283
+ "shareSegAssistant": "VWh0dG_shareSegAssistant",
284
+ "chartLegend": "VWh0dG_chartLegend",
285
+ "subscriptionWindowLabel": "VWh0dG_subscriptionWindowLabel",
286
+ "tabNav": "VWh0dG_tabNav",
294
287
  "peakAlertCorner": "VWh0dG_peakAlertCorner",
295
- "pricingChevronOpen": "VWh0dG_pricingChevronOpen",
296
- "peakAlertField": "VWh0dG_peakAlertField",
297
- "siteRowCalls": "VWh0dG_siteRowCalls",
298
- "chartAxisLabel": "VWh0dG_chartAxisLabel",
299
- "triggerPopFootNote": "VWh0dG_triggerPopFootNote",
300
- "triggerSpark": "VWh0dG_triggerSpark",
301
- "bucketOfficial": "VWh0dG_bucketOfficial",
302
- "providerGroup": "VWh0dG_providerGroup",
303
- "floatModeBtn": "VWh0dG_floatModeBtn",
304
- "liveCostBar": "VWh0dG_liveCostBar",
305
- "siteKindUnknown": "VWh0dG_siteKindUnknown",
288
+ "heroSideLabel": "VWh0dG_heroSideLabel",
289
+ "pluginInfo": "VWh0dG_pluginInfo",
290
+ "dashboard": "VWh0dG_dashboard",
291
+ "heatmapYearBody": "VWh0dG_heatmapYearBody",
292
+ "flatTag": "VWh0dG_flatTag",
293
+ "modelName": "VWh0dG_modelName",
294
+ "dashboardModal": "VWh0dG_dashboardModal",
295
+ "providerGroupMeta": "VWh0dG_providerGroupMeta",
296
+ "triggerPopLabel": "VWh0dG_triggerPopLabel",
297
+ "triggerPopValue": "VWh0dG_triggerPopValue",
298
+ "kpiDetail": "VWh0dG_kpiDetail",
299
+ "balanceDays": "VWh0dG_balanceDays",
300
+ "subscriptionPlan": "VWh0dG_subscriptionPlan",
301
+ "bucketStatValue": "VWh0dG_bucketStatValue",
302
+ "tabPanelIn": "VWh0dG_tabPanelIn",
303
+ "chartEmpty": "VWh0dG_chartEmpty",
304
+ "triggerPopBars": "VWh0dG_triggerPopBars",
305
+ "switchOn": "VWh0dG_switchOn",
306
+ "shareLegend": "VWh0dG_shareLegend",
307
+ "shareSegTool": "VWh0dG_shareSegTool",
306
308
  "chartTooltipDate": "VWh0dG_chartTooltipDate",
307
- "subscriptionGrid": "VWh0dG_subscriptionGrid",
308
- "tokenPanel": "VWh0dG_tokenPanel",
309
- "closeButton": "VWh0dG_closeButton",
310
- "triggerPopFootStatus": "VWh0dG_triggerPopFootStatus",
311
- "triggerAmount": "VWh0dG_triggerAmount",
309
+ "triggerPopMetric": "VWh0dG_triggerPopMetric",
310
+ "triggerPopEmpty": "VWh0dG_triggerPopEmpty",
311
+ "triggerSpark": "VWh0dG_triggerSpark",
312
+ "shareTrack": "VWh0dG_shareTrack",
313
+ "trendPanel": "VWh0dG_trendPanel",
314
+ "heatmapCell": "VWh0dG_heatmapCell",
315
+ "siteKindSite": "VWh0dG_siteKindSite",
316
+ "rounds": "VWh0dG_rounds",
317
+ "floatSubName": "VWh0dG_floatSubName",
318
+ "uncataloguedTag": "VWh0dG_uncataloguedTag",
319
+ "budgetUnit": "VWh0dG_budgetUnit",
320
+ "tokenModelShareRow": "VWh0dG_tokenModelShareRow",
321
+ "peakAlertPanelHead": "VWh0dG_peakAlertPanelHead",
322
+ "panelHead": "VWh0dG_panelHead",
312
323
  "triggerPopTitleMonth": "VWh0dG_triggerPopTitleMonth",
313
- "liveQuotaWarn": "VWh0dG_liveQuotaWarn",
314
- "currencyButton": "VWh0dG_currencyButton",
315
- "kpiTile": "VWh0dG_kpiTile",
316
- "tokenModelPartIn": "VWh0dG_tokenModelPartIn",
317
- "tabButtonActive": "VWh0dG_tabButtonActive",
318
- "modelName": "VWh0dG_modelName",
319
- "bandPriceOff": "VWh0dG_bandPriceOff",
320
- "heroSideValue": "VWh0dG_heroSideValue",
324
+ "budgetControls": "VWh0dG_budgetControls",
325
+ "balanceCell": "VWh0dG_balanceCell",
326
+ "unpricedHint": "VWh0dG_unpricedHint",
321
327
  "healthIdle": "VWh0dG_healthIdle",
322
- "heroCurrency": "VWh0dG_heroCurrency",
323
- "switchKnob": "VWh0dG_switchKnob",
324
- "heroGaugePct": "VWh0dG_heroGaugePct",
325
- "heroValue": "VWh0dG_heroValue",
326
- "subscriptionPlan": "VWh0dG_subscriptionPlan",
327
- "exportBar": "VWh0dG_exportBar",
328
- "triggerPopHead": "VWh0dG_triggerPopHead",
329
- "triggerBody": "VWh0dG_triggerBody",
330
- "triggerPopValue": "VWh0dG_triggerPopValue",
331
- "chartBar": "VWh0dG_chartBar",
332
- "bandTagOff": "VWh0dG_bandTagOff",
333
- "chartGrid": "VWh0dG_chartGrid",
328
+ "settingsHead": "VWh0dG_settingsHead",
334
329
  "balanceDaysBadge": "VWh0dG_balanceDaysBadge",
335
- "liveTierPeak": "VWh0dG_liveTierPeak",
336
- "heatmapYearWeekday": "VWh0dG_heatmapYearWeekday",
337
- "kpiGrid": "VWh0dG_kpiGrid",
338
- "modelCell": "VWh0dG_modelCell",
339
- "roundsBar": "VWh0dG_roundsBar",
340
- "heatmapCellEmpty": "VWh0dG_heatmapCellEmpty",
341
- "heroLabel": "VWh0dG_heroLabel",
342
- "heatmapRangeButtonActive": "VWh0dG_heatmapRangeButtonActive",
343
- "tokenModelParts": "VWh0dG_tokenModelParts",
344
- "subscriptionReset": "VWh0dG_subscriptionReset",
345
- "budgetFill": "VWh0dG_budgetFill",
346
- "floatTarget": "VWh0dG_floatTarget",
347
- "shareSegUser": "VWh0dG_shareSegUser",
348
- "peakAlertCenter": "VWh0dG_peakAlertCenter",
349
- "pluginInfoLink": "VWh0dG_pluginInfoLink",
350
- "heatmapYear": "VWh0dG_heatmapYear",
351
- "bandPrice": "VWh0dG_bandPrice",
330
+ "siteRowCalls": "VWh0dG_siteRowCalls",
331
+ "triggerPopBadgeSub": "VWh0dG_triggerPopBadgeSub",
352
332
  "triggerPopSwitchCount": "VWh0dG_triggerPopSwitchCount",
353
- "headTitleRow": "VWh0dG_headTitleRow",
354
- "healthDot": "VWh0dG_healthDot",
355
- "tabPanel": "VWh0dG_tabPanel",
356
- "kpiGreen": "VWh0dG_kpiGreen",
357
- "triggerPopFootTitle": "VWh0dG_triggerPopFootTitle",
358
- "bandTag": "VWh0dG_bandTag",
359
- "tokenModelPartOut": "VWh0dG_tokenModelPartOut",
360
- "pluginInfoLabel": "VWh0dG_pluginInfoLabel",
361
- "balanceDetailRow": "VWh0dG_balanceDetailRow",
333
+ "dashboardRight": "VWh0dG_dashboardRight",
334
+ "heatmapRangeSwitch": "VWh0dG_heatmapRangeSwitch",
335
+ "triggerPopFootStatus": "VWh0dG_triggerPopFootStatus",
336
+ "budgetHead": "VWh0dG_budgetHead",
337
+ "peakAlertNum": "VWh0dG_peakAlertNum",
338
+ "peakAlertField": "VWh0dG_peakAlertField",
339
+ "triggerPopName": "VWh0dG_triggerPopName",
340
+ "subscriptionReset": "VWh0dG_subscriptionReset",
362
341
  "pricingTable": "VWh0dG_pricingTable",
363
- "siteKindTag": "VWh0dG_siteKindTag",
364
- "subscriptionHead": "VWh0dG_subscriptionHead",
365
- "delta": "VWh0dG_delta",
366
- "heatmapYearMonth": "VWh0dG_heatmapYearMonth",
342
+ "heroSide": "VWh0dG_heroSide",
343
+ "bandPrice": "VWh0dG_bandPrice",
344
+ "peakAlert": "VWh0dG_peakAlert",
345
+ "balanceDetailClose": "VWh0dG_balanceDetailClose",
346
+ "settingsHint": "VWh0dG_settingsHint",
347
+ "pluginInfoRow": "VWh0dG_pluginInfoRow",
348
+ "subscriptionCard": "VWh0dG_subscriptionCard",
349
+ "balanceDetailHead": "VWh0dG_balanceDetailHead",
350
+ "reconcileText": "VWh0dG_reconcileText",
367
351
  "dashboardSubtitle": "VWh0dG_dashboardSubtitle",
368
- "triggerPopSwitcher": "VWh0dG_triggerPopSwitcher",
369
- "budgetTrack": "VWh0dG_budgetTrack",
370
- "heatmapRangeSwitch": "VWh0dG_heatmapRangeSwitch",
371
- "heroGaugePctOver": "VWh0dG_heroGaugePctOver",
372
- "healthBadgeOk": "VWh0dG_healthBadgeOk",
352
+ "triggerPopRow": "VWh0dG_triggerPopRow",
353
+ "budgetInput": "VWh0dG_budgetInput",
354
+ "siteRowMeta": "VWh0dG_siteRowMeta",
355
+ "pricingToggleText": "VWh0dG_pricingToggleText",
356
+ "subscriptionAuto": "VWh0dG_subscriptionAuto",
357
+ "providerGroupHead": "VWh0dG_providerGroupHead",
358
+ "roundsBarFlagged": "VWh0dG_roundsBarFlagged",
359
+ "floatTarget": "VWh0dG_floatTarget",
360
+ "liveQuotaWarn": "VWh0dG_liveQuotaWarn",
361
+ "triggerPop": "VWh0dG_triggerPop",
362
+ "triggerPopUpdated": "VWh0dG_triggerPopUpdated",
363
+ "triggerPopOpenBtn": "VWh0dG_triggerPopOpenBtn",
364
+ "panelHint": "VWh0dG_panelHint",
365
+ "triggerPopFootStrong": "VWh0dG_triggerPopFootStrong",
366
+ "kpiValue": "VWh0dG_kpiValue",
367
+ "subscriptionName": "VWh0dG_subscriptionName",
368
+ "peakAlertPanel": "VWh0dG_peakAlertPanel",
373
369
  "modelTableScroll": "VWh0dG_modelTableScroll",
374
- "triggerPopBadge": "VWh0dG_triggerPopBadge",
375
- "triggerPopFootStatusLow": "VWh0dG_triggerPopFootStatusLow",
376
- "tabButton": "VWh0dG_tabButton",
377
- "chartLegend": "VWh0dG_chartLegend",
378
- "chartDot": "VWh0dG_chartDot",
379
- "heatmapYearBody": "VWh0dG_heatmapYearBody",
380
- "triggerPopEmpty": "VWh0dG_triggerPopEmpty",
370
+ "bandTag": "VWh0dG_bandTag",
371
+ "providerGroup": "VWh0dG_providerGroup",
372
+ "pluginInfoValue": "VWh0dG_pluginInfoValue",
373
+ "subscriptionFill": "VWh0dG_subscriptionFill",
374
+ "heatmapYearCell": "VWh0dG_heatmapYearCell",
375
+ "peakAlertCheck": "VWh0dG_peakAlertCheck",
376
+ "staleNotice": "VWh0dG_staleNotice",
377
+ "floatSubHead": "VWh0dG_floatSubHead",
378
+ "peakAlertCountdown": "VWh0dG_peakAlertCountdown",
379
+ "subscriptionStatus": "VWh0dG_subscriptionStatus",
380
+ "heatmapLegend": "VWh0dG_heatmapLegend",
381
+ "heatmapYearWeekday": "VWh0dG_heatmapYearWeekday",
381
382
  "peakAlertClose": "VWh0dG_peakAlertClose",
382
- "chartLegendBar": "VWh0dG_chartLegendBar",
383
- "rounds": "VWh0dG_rounds",
384
- "floatTargetLabel": "VWh0dG_floatTargetLabel",
385
- "peakAlertSelect": "VWh0dG_peakAlertSelect",
386
- "tokenModelShareRow": "VWh0dG_tokenModelShareRow",
387
- "peakAlertText": "VWh0dG_peakAlertText",
388
- "tabPanelIn": "VWh0dG_tabPanelIn",
389
- "reconcileDismiss": "VWh0dG_reconcileDismiss",
390
- "modelDot": "VWh0dG_modelDot",
391
- "numCol": "VWh0dG_numCol",
392
- "healthBadge": "VWh0dG_healthBadge",
393
- "providerGroupList": "VWh0dG_providerGroupList",
394
- "providerGroupBadge": "VWh0dG_providerGroupBadge",
395
- "rateBadgeLive": "VWh0dG_rateBadgeLive",
396
- "subscriptionFillWarn": "VWh0dG_subscriptionFillWarn",
397
- "triggerPop": "VWh0dG_triggerPop",
398
- "modelTable": "VWh0dG_modelTable",
399
- "budgetInput": "VWh0dG_budgetInput",
400
- "subscriptionPct": "VWh0dG_subscriptionPct",
401
- "chartWrap": "VWh0dG_chartWrap",
402
- "settingsTitle": "VWh0dG_settingsTitle",
383
+ "triggerPopSubscription": "VWh0dG_triggerPopSubscription",
384
+ "dashboardIn": "VWh0dG_dashboardIn",
385
+ "pricingChevron": "VWh0dG_pricingChevron",
386
+ "trigger": "VWh0dG_trigger",
387
+ "triggerPopBar": "VWh0dG_triggerPopBar",
388
+ "panelTitle": "VWh0dG_panelTitle",
389
+ "siteRow": "VWh0dG_siteRow",
390
+ "dashboardTitle": "VWh0dG_dashboardTitle",
391
+ "heroMain": "VWh0dG_heroMain",
392
+ "rangeButton": "VWh0dG_rangeButton",
393
+ "healthDot": "VWh0dG_healthDot",
394
+ "bucketStatSub": "VWh0dG_bucketStatSub",
395
+ "shareValue": "VWh0dG_shareValue",
403
396
  "subscriptionMeta": "VWh0dG_subscriptionMeta",
404
- "subscriptionCard": "VWh0dG_subscriptionCard",
405
- "bucketCost": "VWh0dG_bucketCost",
406
- "triggerPopMetricHighlight": "VWh0dG_triggerPopMetricHighlight"
397
+ "roundsBarWrap": "VWh0dG_roundsBarWrap",
398
+ "heatmapYearGrid": "VWh0dG_heatmapYearGrid",
399
+ "floatSubPlan": "VWh0dG_floatSubPlan",
400
+ "triggerBody": "VWh0dG_triggerBody",
401
+ "tableScroll": "VWh0dG_tableScroll",
402
+ "triggerPopMetricLabel": "VWh0dG_triggerPopMetricLabel",
403
+ "peakAlertTag": "VWh0dG_peakAlertTag",
404
+ "modelCell": "VWh0dG_modelCell",
405
+ "tokenModelBar": "VWh0dG_tokenModelBar",
406
+ "triggerMeta": "VWh0dG_triggerMeta",
407
+ "rateBadge": "VWh0dG_rateBadge",
408
+ "balanceDetailPop": "VWh0dG_balanceDetailPop",
409
+ "peakAlertText": "VWh0dG_peakAlertText",
410
+ "heroGaugeArc": "VWh0dG_heroGaugeArc",
411
+ "subscriptionTrack": "VWh0dG_subscriptionTrack",
412
+ "triggerPopFootName": "VWh0dG_triggerPopFootName",
413
+ "bucketSummary": "VWh0dG_bucketSummary"
407
414
  };
408
415
  //#endregion
409
416
  //#region src/client/plan-knowledge.ts
@@ -549,16 +556,6 @@ window.__ModuleLoader__.load({
549
556
  output: 10
550
557
  }
551
558
  ];
552
- //#endregion
553
- //#region src/client/pricing.ts
554
- /**
555
- * USD → CNY rate for display. Source: China Foreign Exchange Trade System
556
- * mid-rate 6.7878 on 2026-08-14; rounded to 6.79. Only applies to overseas
557
- * USD-priced models — domestic models never pass through this rate.
558
- * The node half may refresh this at boot via `/api/billing/pricing`; until a
559
- * live rate arrives the built-in value stays in force.
560
- */
561
- const USD_TO_CNY = 6.79;
562
559
  /** 运行时实时覆盖:undefined = 用内置目录与内置汇率(默认值降级)。 */
563
560
  let liveRate;
564
561
  let livePrices;
@@ -570,7 +567,7 @@ window.__ModuleLoader__.load({
570
567
  * @param pricing - the `/api/billing/pricing` response.
571
568
  */
572
569
  function applyLivePricing(pricing) {
573
- liveRate = pricing.rate;
570
+ liveRate = typeof pricing.rate === "number" && Number.isFinite(pricing.rate) && pricing.rate > 0 ? pricing.rate : void 0;
574
571
  livePrices = pricing.prices;
575
572
  liveExtraModels = pricing.extraModels;
576
573
  }
@@ -1214,7 +1211,10 @@ window.__ModuleLoader__.load({
1214
1211
  "step-3.7-flash": "step",
1215
1212
  "seed-2.0-mini": "doubao-mini",
1216
1213
  "k3": "kimi-k3",
1217
- "kimi-k3": "kimi-k3"
1214
+ "kimi-k3": "kimi-k3",
1215
+ "minimax-m1": "minimax",
1216
+ "minimax-m2": "minimax",
1217
+ "minimax-m3": "minimax"
1218
1218
  };
1219
1219
  /**
1220
1220
  * 模型 id 归一化:小写、去括号附注(如 `gpt5.6 luna(go)` 只看主体)、再去所有
@@ -1327,11 +1327,9 @@ window.__ModuleLoader__.load({
1327
1327
  return MODEL_CATALOG.find((item) => item.key === aliasKey);
1328
1328
  })() !== void 0) continue;
1329
1329
  if (known.has(rawKey)) continue;
1330
- const extra = (liveExtraModels ?? []).find((item) => item.key === rawKey);
1331
- const fallbackLive = extra === void 0 ? livePriceOf(rawKey) : void 0;
1330
+ const fallbackLive = livePriceOf(rawKey);
1332
1331
  let entry;
1333
- if (extra !== void 0) entry = { ...extraEntryOf(extra) };
1334
- else if (fallbackLive !== void 0) entry = {
1332
+ if (fallbackLive !== void 0) entry = {
1335
1333
  key: rawKey,
1336
1334
  name: model.name ?? model.id,
1337
1335
  provider: model.provider,
@@ -1400,9 +1398,11 @@ window.__ModuleLoader__.load({
1400
1398
  const off = entry.price.offPeak === void 0 ? peak : priceBandCost(entry.price.offPeak, buckets, entry.price.currency);
1401
1399
  return peak * peakShare + off * (1 - peakShare);
1402
1400
  }
1403
- /** 人民币 → 美元(显示换算用):1 USD = {@link USD_TO_CNY} CNY。 */
1401
+ /** 人民币 → 美元(显示换算用):用当前生效汇率(实时优先,缺失回退内置),
1402
+ * 与计价链路的 `currentRate()` 同口径,避免实时汇率生效时 USD 显示与计价不一致。 */
1404
1403
  function cnyToUsd(cny) {
1405
- return cny / USD_TO_CNY;
1404
+ const rate = currentRate();
1405
+ return rate > 0 ? cny / rate : cny;
1406
1406
  }
1407
1407
  /**
1408
1408
  * Format an amount with adaptive precision and the given currency symbol.
@@ -2176,7 +2176,7 @@ window.__ModuleLoader__.load({
2176
2176
  * @param props.onTrendDays - 切换趋势窗口。
2177
2177
  */
2178
2178
  function TokenPanel(props) {
2179
- const { stats, currency: _currency, trendDays, onTrendDays, t } = props;
2179
+ const { stats, trendDays, onTrendDays, t } = props;
2180
2180
  const { byDay, byModel, total } = stats;
2181
2181
  const days = (0, react.useMemo)(() => {
2182
2182
  const out = [];
@@ -2277,7 +2277,7 @@ window.__ModuleLoader__.load({
2277
2277
  a.href = URL.createObjectURL(blob);
2278
2278
  a.download = `token-daily-${localStamp()}.csv`;
2279
2279
  a.click();
2280
- URL.revokeObjectURL(a.href);
2280
+ setTimeout(() => URL.revokeObjectURL(a.href), 0);
2281
2281
  };
2282
2282
  const exportTokenJson = () => {
2283
2283
  const blob = new Blob([JSON.stringify({
@@ -2289,7 +2289,7 @@ window.__ModuleLoader__.load({
2289
2289
  a.href = URL.createObjectURL(blob);
2290
2290
  a.download = `token-${localStamp()}.json`;
2291
2291
  a.click();
2292
- URL.revokeObjectURL(a.href);
2292
+ setTimeout(() => URL.revokeObjectURL(a.href), 0);
2293
2293
  };
2294
2294
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2295
2295
  className: UsageBilling_module_css_default.tokenPanel,
@@ -3047,12 +3047,12 @@ window.__ModuleLoader__.load({
3047
3047
  * @returns 异常标记数组(保持输入顺序)。
3048
3048
  */
3049
3049
  function flagAnomalies(rounds, options) {
3050
- const opts = {
3051
- ...DEFAULTS,
3052
- ...options
3053
- };
3050
+ const window = options?.window ?? DEFAULTS.window;
3051
+ const threshold = options?.threshold ?? DEFAULTS.threshold;
3052
+ const reasonFactor = options?.reasonFactor ?? DEFAULTS.reasonFactor;
3053
+ const reasonHitDropPp = options?.reasonHitDropPp ?? DEFAULTS.reasonHitDropPp;
3054
3054
  const flags = [];
3055
- if (opts.window <= 0 || opts.threshold <= 0) return flags;
3055
+ if (window <= 0 || threshold <= 0) return flags;
3056
3056
  const baselineCosts = [];
3057
3057
  const baselineOutputs = [];
3058
3058
  const baselineInputs = [];
@@ -3064,13 +3064,13 @@ window.__ModuleLoader__.load({
3064
3064
  const hit = cacheHitRate(round);
3065
3065
  const baselineCost = mean(baselineCosts);
3066
3066
  const reasons = [];
3067
- if (baselineCost !== null && baselineCost > 0 && round.cost > baselineCost * opts.threshold) {
3067
+ if (baselineCost !== null && baselineCost > 0 && round.cost > baselineCost * threshold) {
3068
3068
  const baselineOutput = mean(baselineOutputs);
3069
3069
  const baselineInput = mean(baselineInputs);
3070
3070
  const baselineHit = mean(baselineHits);
3071
- if (baselineOutput !== null && baselineOutput > 0 && output > baselineOutput * opts.reasonFactor) reasons.push("output-growth");
3072
- if (baselineInput !== null && baselineInput > 0 && input > baselineInput * opts.reasonFactor) reasons.push("context-bloat");
3073
- if (baselineHit !== null && hit !== null && hit < baselineHit - opts.reasonHitDropPp) reasons.push("cache-hit-drop");
3071
+ if (baselineOutput !== null && baselineOutput > 0 && output > baselineOutput * reasonFactor) reasons.push("output-growth");
3072
+ if (baselineInput !== null && baselineInput > 0 && input > baselineInput * reasonFactor) reasons.push("context-bloat");
3073
+ if (baselineHit !== null && hit !== null && hit < baselineHit - reasonHitDropPp) reasons.push("cache-hit-drop");
3074
3074
  flags.push({
3075
3075
  sessionId: round.sessionId,
3076
3076
  turn: round.turn,
@@ -3082,18 +3082,23 @@ window.__ModuleLoader__.load({
3082
3082
  baselineOutputs.push(output);
3083
3083
  baselineInputs.push(input);
3084
3084
  if (hit !== null) baselineHits.push(hit);
3085
- while (baselineCosts.length > opts.window) baselineCosts.shift();
3086
- while (baselineOutputs.length > opts.window) baselineOutputs.shift();
3087
- while (baselineInputs.length > opts.window) baselineInputs.shift();
3088
- while (baselineHits.length > opts.window) baselineHits.shift();
3085
+ while (baselineCosts.length > window) baselineCosts.shift();
3086
+ while (baselineOutputs.length > window) baselineOutputs.shift();
3087
+ while (baselineInputs.length > window) baselineInputs.shift();
3088
+ while (baselineHits.length > window) baselineHits.shift();
3089
3089
  }
3090
3090
  return flags;
3091
3091
  }
3092
3092
  //#endregion
3093
3093
  //#region src/client/export.ts
3094
- /** CSV 单元格转义:含逗号 / 引号 / 换行的值加双引号并内层引号双写。 */
3094
+ /** CSV 单元格转义:含逗号 / 引号 / 换行 / 回车的值加双引号并内层引号双写。 */
3095
3095
  function csvCell(value) {
3096
- return /[",\n]/.test(value) ? `"${value.replace(/"/g, "\"\"")}"` : value;
3096
+ return /[",\r\n]/.test(value) ? `"${value.replace(/"/g, "\"\"")}"` : value;
3097
+ }
3098
+ /** 防 CSV 公式注入:以 `=` / `+` / `-` / `@` / tab / 回车开头的值前置单引号,
3099
+ * 避免在 Excel/WPS 打开时被当作公式执行。用户/模型可控的会话标题会进 CSV。 */
3100
+ function csvSafe(value) {
3101
+ return /^[=+\-@\t\r]/.test(value) ? `'${value}` : value;
3097
3102
  }
3098
3103
  /** 金额保留两位小数字符串(导出对账用,不做千分位)。 */
3099
3104
  function money(value) {
@@ -3121,7 +3126,7 @@ window.__ModuleLoader__.load({
3121
3126
  const site = key.startsWith("site:") ? key.slice(5) : key.startsWith("direct:") ? key.slice(7) : "unknown";
3122
3127
  const kind = key.startsWith("site:") ? "site" : key.startsWith("direct:") ? "direct" : "unknown";
3123
3128
  return [
3124
- csvCell(site),
3129
+ csvCell(csvSafe(site)),
3125
3130
  kind,
3126
3131
  usage.calls,
3127
3132
  money(usage.cost)
@@ -3136,9 +3141,9 @@ window.__ModuleLoader__.load({
3136
3141
  /** 按会话 CSV:会话 id,标题,项目,调用,费用(元),最后活跃(ISO)。 */
3137
3142
  function sessionRowsCsv(rows) {
3138
3143
  return ["session_id,title,project,calls,cost_cny,last_active", ...rows.map((row) => [
3139
- csvCell(row.id),
3140
- csvCell(row.title ?? ""),
3141
- csvCell(projectOf(row.cwd)),
3144
+ csvCell(csvSafe(row.id)),
3145
+ csvCell(csvSafe(row.title ?? "")),
3146
+ csvCell(csvSafe(projectOf(row.cwd))),
3142
3147
  row.calls,
3143
3148
  money(row.cost),
3144
3149
  row.lastActive > 0 ? new Date(row.lastActive).toISOString() : ""
@@ -3158,7 +3163,7 @@ window.__ModuleLoader__.load({
3158
3163
  anchor.href = url;
3159
3164
  anchor.download = filename;
3160
3165
  anchor.click();
3161
- URL.revokeObjectURL(url);
3166
+ setTimeout(() => URL.revokeObjectURL(url), 0);
3162
3167
  }
3163
3168
  //#endregion
3164
3169
  //#region src/client/locales.ts
@@ -3732,6 +3737,13 @@ window.__ModuleLoader__.load({
3732
3737
  const timer = setInterval(() => setNowMs(Date.now()), 1e3);
3733
3738
  return () => clearInterval(timer);
3734
3739
  }, []);
3740
+ (0, react.useEffect)(() => {
3741
+ if (nowMs >= hit.atMs) onDismiss();
3742
+ }, [
3743
+ nowMs,
3744
+ hit.atMs,
3745
+ onDismiss
3746
+ ]);
3735
3747
  if (nowMs >= hit.atMs) return null;
3736
3748
  const minutes = Math.max(1, Math.round((hit.atMs - nowMs) / 6e4));
3737
3749
  const entering = hit.entering;
@@ -4210,54 +4222,60 @@ window.__ModuleLoader__.load({
4210
4222
  * fabricate.
4211
4223
  * @param attempt - current retry index (0-based).
4212
4224
  */
4225
+ /** 实时定价重试链是否已在进行:挂载/开弹窗/轮询多个调用点会并发触发 loadLivePricing,
4226
+ * 若都在 `builtin` 时各自起 setTimeout 重试链会叠加出多余请求,这里只保留一条。 */
4227
+ let livePricingRetryPending = false;
4213
4228
  async function loadLivePricing(attempt = 0) {
4214
4229
  const MAX_ATTEMPTS = 4;
4215
4230
  try {
4216
4231
  const response = await fetch(PRICING_PATH);
4217
- if (!response.ok) return;
4232
+ if (!response.ok) {
4233
+ livePricingRetryPending = false;
4234
+ return;
4235
+ }
4218
4236
  const text = await response.text();
4219
4237
  const parsed = JSON.parse(text);
4220
- if (parsed === null || typeof parsed !== "object" || !("source" in parsed)) return;
4238
+ if (parsed === null || typeof parsed !== "object" || !("source" in parsed)) {
4239
+ livePricingRetryPending = false;
4240
+ return;
4241
+ }
4221
4242
  const pricing = parsed;
4222
4243
  if (pricing.source === "builtin" && attempt < MAX_ATTEMPTS - 1) {
4244
+ if (attempt === 0) {
4245
+ if (livePricingRetryPending) return;
4246
+ livePricingRetryPending = true;
4247
+ }
4223
4248
  setTimeout(() => {
4224
4249
  loadLivePricing(attempt + 1);
4225
4250
  }, 2e3);
4226
4251
  return;
4227
4252
  }
4253
+ livePricingRetryPending = false;
4228
4254
  applyLivePricing(pricing);
4229
- } catch {}
4230
- }
4231
- /**
4232
- * 拉取各提供方账户余额(供模型计费明细表的余额列);失败返回空列表。
4233
- * @returns the balance rows, or an empty list on any failure.
4234
- */
4235
- async function fetchBalances() {
4236
- try {
4237
- const response = await fetch(BALANCE_PATH);
4238
- if (!response.ok) return [];
4239
- const text = await response.text();
4240
- const parsed = JSON.parse(text);
4241
- if (parsed !== null && typeof parsed === "object" && "balances" in parsed) return parsed.balances;
4242
- return [];
4243
4255
  } catch {
4244
- return [];
4256
+ livePricingRetryPending = false;
4245
4257
  }
4246
4258
  }
4247
4259
  /**
4248
- * 拉取官方余额差对账提示(drift 时非空),供余额面板展示;失败返回 undefined。
4249
- * @returns the reconcile notice, or undefined on any failure / no drift.
4260
+ * 一次拉取 `/api/billing/balance` 的完整响应(余额行 + 对账提示)。余额与对账
4261
+ * 提示来自同一响应体,拆成两个函数会导致每 30 秒对同一端点发两次请求,故合并
4262
+ * 为单次 fetch;失败返回空值(余额 []、对账 undefined),由调用方降级。
4263
+ * @returns the balances and reconcile notice (both degraded on any failure).
4250
4264
  */
4251
- async function fetchReconcile() {
4265
+ async function fetchBalanceDoc() {
4252
4266
  try {
4253
4267
  const response = await fetch(BALANCE_PATH);
4254
- if (!response.ok) return void 0;
4268
+ if (!response.ok) return { balances: [] };
4255
4269
  const text = await response.text();
4256
4270
  const parsed = JSON.parse(text);
4257
- if (parsed !== null && typeof parsed === "object" && "reconcile" in parsed) return parsed.reconcile;
4258
- return;
4271
+ if (parsed === null || typeof parsed !== "object") return { balances: [] };
4272
+ const doc = parsed;
4273
+ return {
4274
+ balances: Array.isArray(doc.balances) ? doc.balances : [],
4275
+ ...doc.reconcile === void 0 ? {} : { reconcile: doc.reconcile }
4276
+ };
4259
4277
  } catch {
4260
- return;
4278
+ return { balances: [] };
4261
4279
  }
4262
4280
  }
4263
4281
  /**
@@ -4273,20 +4291,16 @@ window.__ModuleLoader__.load({
4273
4291
  throw new Error("subscriptions: invalid response");
4274
4292
  }
4275
4293
  /**
4276
- * 拉取中转站额度(New API / Sub2API 的余额与滚动窗口);失败返回空列表。
4277
- * @returns the relay-site quota rows, or an empty list on any failure.
4294
+ * 拉取中转站额度(New API / Sub2API 的余额与滚动窗口);失败抛出(调用方据此保留旧快照)。
4295
+ * @returns the relay-site quota rows(成功但无中转配置时为空数组)。
4278
4296
  */
4279
4297
  async function fetchRelayQuotas() {
4280
- try {
4281
- const response = await fetch(RELAY_PATH);
4282
- if (!response.ok) return [];
4283
- const text = await response.text();
4284
- const parsed = JSON.parse(text);
4285
- if (parsed !== null && typeof parsed === "object" && "quotas" in parsed) return parsed.quotas;
4286
- return [];
4287
- } catch {
4288
- return [];
4289
- }
4298
+ const response = await fetch(RELAY_PATH);
4299
+ if (!response.ok) throw new Error(`relay-quotas HTTP ${String(response.status)}`);
4300
+ const text = await response.text();
4301
+ const parsed = JSON.parse(text);
4302
+ if (parsed !== null && typeof parsed === "object" && "quotas" in parsed) return parsed.quotas;
4303
+ throw new Error("relay-quotas: invalid response");
4290
4304
  }
4291
4305
  /**
4292
4306
  * 读取 usage_stats 工具开关当前值(插件自带接口,不依赖宿主浏览器设置白名单)。
@@ -4391,7 +4405,9 @@ window.__ModuleLoader__.load({
4391
4405
  " ",
4392
4406
  formatMoney(todayCost),
4393
4407
  " · ",
4394
- weekCost > 0 ? `${t("billing.weekCost")} ${formatMoney(weekCost)}` : ""
4408
+ t("billing.weekCost"),
4409
+ " ",
4410
+ formatMoney(weekCost)
4395
4411
  ]
4396
4412
  })]
4397
4413
  }),
@@ -4795,7 +4811,7 @@ window.__ModuleLoader__.load({
4795
4811
  return {
4796
4812
  pct: Number.isFinite(budgetPct) ? Math.max(0, Math.min(100, budgetPct)) : yearCost > 0 ? Math.max(0, Math.min(100, monthCost / yearCost * 100)) : 0,
4797
4813
  over: Number.isFinite(budgetPct) && budgetPct >= 100,
4798
- label: t("billing.budget")
4814
+ label: Number.isFinite(budgetPct) ? t("billing.budget") : t("billing.monthCost")
4799
4815
  };
4800
4816
  }, [
4801
4817
  budgetEnabled,
@@ -4898,9 +4914,17 @@ window.__ModuleLoader__.load({
4898
4914
  else list.push(quota);
4899
4915
  }
4900
4916
  const modelsByVendor = /* @__PURE__ */ new Map();
4917
+ const vendorByNorm = /* @__PURE__ */ new Map();
4918
+ for (const vendor of subscriptionsByVendor.keys()) vendorByNorm.set(normalizeProvider(vendor), vendor);
4901
4919
  for (const row of modelRows) {
4902
- const list = modelsByVendor.get(row.provider);
4903
- if (list === void 0) modelsByVendor.set(row.provider, [row]);
4920
+ let vendorName = row.provider;
4921
+ if (row.plan === true) {
4922
+ const inferred = providerFromModelKey(row.key);
4923
+ if (inferred !== void 0) vendorName = inferred;
4924
+ }
4925
+ const key = vendorByNorm.get(normalizeProvider(vendorName)) ?? vendorName;
4926
+ const list = modelsByVendor.get(key);
4927
+ if (list === void 0) modelsByVendor.set(key, [row]);
4904
4928
  else list.push(row);
4905
4929
  }
4906
4930
  const groups = [...new Set([...modelsByVendor.keys(), ...subscriptionsByVendor.keys()])].map((name) => ({
@@ -6489,7 +6513,6 @@ window.__ModuleLoader__.load({
6489
6513
  "data-testid": "billing-tab-panel-token",
6490
6514
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TokenPanel, {
6491
6515
  stats,
6492
- currency,
6493
6516
  trendDays,
6494
6517
  onTrendDays: setTrendDays,
6495
6518
  t
@@ -6682,11 +6705,9 @@ window.__ModuleLoader__.load({
6682
6705
  loadUsageStats().then((data) => {
6683
6706
  if (data !== null) setStats(data);
6684
6707
  });
6685
- fetchBalances().then((list) => {
6686
- if (list.length > 0) setBalances(list);
6687
- });
6688
- fetchReconcile().then((notice) => {
6689
- setReconcile(notice);
6708
+ fetchBalanceDoc().then(({ balances, reconcile }) => {
6709
+ if (balances.length > 0) setBalances(balances);
6710
+ setReconcile(reconcile);
6690
6711
  });
6691
6712
  fetchSubscriptions().then((list) => {
6692
6713
  if (list.length > 0) {
@@ -6697,8 +6718,8 @@ window.__ModuleLoader__.load({
6697
6718
  setQuotasStale(true);
6698
6719
  });
6699
6720
  fetchRelayQuotas().then((list) => {
6700
- if (list.length > 0) setRelayQuotas(list);
6701
- });
6721
+ setRelayQuotas(list);
6722
+ }).catch(() => {});
6702
6723
  }, []);
6703
6724
  const openDashboard = (0, react.useCallback)(() => {
6704
6725
  reloadStats();
@@ -6741,6 +6762,13 @@ window.__ModuleLoader__.load({
6741
6762
  const [peakConfig, setPeakConfig] = (0, react.useState)(() => loadPeakAlertConfig());
6742
6763
  const [peakHit, setPeakHit] = (0, react.useState)(null);
6743
6764
  const [peakPreview, setPeakPreview] = (0, react.useState)(null);
6765
+ const [nowMs, setNowMs] = (0, react.useState)(() => Date.now());
6766
+ (0, react.useEffect)(() => {
6767
+ const timer = setInterval(() => setNowMs(Date.now()), STATS_REFRESH_INTERVAL_MS);
6768
+ return () => {
6769
+ clearInterval(timer);
6770
+ };
6771
+ }, []);
6744
6772
  const updatePeakConfig = (0, react.useCallback)((config) => {
6745
6773
  setPeakConfig(config);
6746
6774
  savePeakAlertConfig(config);
@@ -6779,19 +6807,20 @@ window.__ModuleLoader__.load({
6779
6807
  t
6780
6808
  ]);
6781
6809
  (0, react.useEffect)(() => {
6782
- const upcoming = computePeakAlert(Date.now(), peakConfig, lastTierSwitchAt);
6810
+ const upcoming = computePeakAlert(nowMs, peakConfig, lastTierSwitchAt);
6783
6811
  if (upcoming === null) return;
6784
6812
  actions.markTierSwitchAlerted(upcoming.atMs);
6785
6813
  setPeakHit(upcoming);
6786
6814
  if (!peakConfig.webNotify) return;
6787
6815
  if (typeof Notification === "undefined" || Notification.permission !== "granted") return;
6788
- const minutes = Math.max(1, Math.round((upcoming.atMs - Date.now()) / 6e4));
6816
+ const minutes = Math.max(1, Math.round((upcoming.atMs - nowMs) / 6e4));
6789
6817
  const title = upcoming.entering === "peak" ? t("billing.peakAlertTitlePeak") : t("billing.peakAlertTitleOff");
6790
6818
  const body = upcoming.entering === "peak" ? t("billing.tierAlertEnterPeak").replace("{minutes}", String(minutes)) : t("billing.tierAlertEnterOff").replace("{minutes}", String(minutes));
6791
6819
  try {
6792
6820
  new Notification(title, { body });
6793
6821
  } catch {}
6794
6822
  }, [
6823
+ nowMs,
6795
6824
  lastTierSwitchAt,
6796
6825
  peakConfig,
6797
6826
  actions,
@@ -6906,8 +6935,7 @@ window.__ModuleLoader__.load({
6906
6935
  input: total.input,
6907
6936
  output: total.output,
6908
6937
  cacheRead: total.cacheHit,
6909
- calls: total.calls,
6910
- updatedAt: stats.updatedAt === void 0 ? void 0 : `${localDayStamp(stats.updatedAt)} ${formatClock(stats.updatedAt)}`
6938
+ calls: total.calls
6911
6939
  };
6912
6940
  }, [stats]);
6913
6941
  (0, react.useEffect)(() => {
@@ -7207,7 +7235,9 @@ window.__ModuleLoader__.load({
7207
7235
  },
7208
7236
  publishCosts: (next) => {
7209
7237
  costs = next;
7210
- for (const listener of listeners) listener(next);
7238
+ for (const listener of listeners) try {
7239
+ listener(next);
7240
+ } catch {}
7211
7241
  },
7212
7242
  registerOpen: (handler) => {
7213
7243
  open = handler;
@@ -7295,11 +7325,15 @@ window.__ModuleLoader__.load({
7295
7325
  */
7296
7326
  function installCompletionNotifier(list, getConfig) {
7297
7327
  const previousFinished = /* @__PURE__ */ new Set();
7298
- let queuedTitle;
7328
+ const seen = /* @__PURE__ */ new Set();
7329
+ let closeTimer;
7299
7330
  const snapshot = list.getSnapshot();
7300
7331
  for (const id of snapshot.ids) {
7301
7332
  const summary = snapshot.byId[id];
7302
- if (summary !== void 0 && isFinished(summary)) previousFinished.add(String(id));
7333
+ if (summary !== void 0) {
7334
+ seen.add(String(id));
7335
+ if (isFinished(summary)) previousFinished.add(String(id));
7336
+ }
7303
7337
  }
7304
7338
  const notify = (title) => {
7305
7339
  const { enabled, timeout } = getConfig();
@@ -7307,14 +7341,18 @@ window.__ModuleLoader__.load({
7307
7341
  if (typeof Notification === "undefined") return;
7308
7342
  if (Notification.permission !== "granted") return;
7309
7343
  try {
7310
- new Notification(title, {
7344
+ const notification = new Notification(title, {
7311
7345
  body: title,
7312
7346
  tag: "dsh-billing-completion",
7313
7347
  requireInteraction: timeout === 0
7314
7348
  });
7349
+ if (timeout > 0) {
7350
+ if (closeTimer !== void 0) clearTimeout(closeTimer);
7351
+ closeTimer = setTimeout(() => notification.close(), timeout * 1e3);
7352
+ }
7315
7353
  } catch {}
7316
7354
  };
7317
- return list.subscribe(() => {
7355
+ const unsubscribe = list.subscribe(() => {
7318
7356
  const state = list.getSnapshot();
7319
7357
  const finishedTitles = [];
7320
7358
  for (const id of state.ids) {
@@ -7322,15 +7360,21 @@ window.__ModuleLoader__.load({
7322
7360
  if (summary === void 0) continue;
7323
7361
  const key = String(id);
7324
7362
  const finished = isFinished(summary);
7325
- if (finished && !previousFinished.has(key)) finishedTitles.push(summary.title ?? summary.id ?? key);
7363
+ const firstSeen = !seen.has(key);
7364
+ if (firstSeen) seen.add(key);
7365
+ if (finished && !firstSeen && !previousFinished.has(key)) finishedTitles.push(summary.title ?? summary.id ?? key);
7326
7366
  if (finished) previousFinished.add(key);
7327
7367
  else previousFinished.delete(key);
7328
7368
  }
7329
7369
  if (finishedTitles.length > 0) {
7330
- queuedTitle = finishedTitles.length === 1 ? finishedTitles[0] : `${finishedTitles.length} 个会话已完成`;
7331
- if (queuedTitle !== void 0) notify(queuedTitle);
7370
+ const title = finishedTitles.length === 1 ? finishedTitles[0] : `${finishedTitles.length} 个会话已完成`;
7371
+ if (title !== void 0) notify(title);
7332
7372
  }
7333
7373
  });
7374
+ return () => {
7375
+ unsubscribe();
7376
+ if (closeTimer !== void 0) clearTimeout(closeTimer);
7377
+ };
7334
7378
  }
7335
7379
  //#endregion
7336
7380
  //#region src/client/apply.ts