dsh-diff-approval 0.29.0 → 0.29.1
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/README.md +8 -0
- package/README.zh.md +8 -0
- package/lib/client.js +271 -247
- package/lib/index.js +74 -24
- package/lib/types/client/code-font.d.ts +10 -4
- package/lib/types/index.d.ts +29 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,3 +97,11 @@ pnpm run fonts:plan # what a page actually downloads, by how many hanzi it show
|
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
The bundled font is [JetBrains Maple Mono](https://github.com/SpaceTimee/Fusion-JetBrainsMapleMono) (SIL OFL 1.1), subset and sliced by `scripts/fonts` — see [`assets/fonts/README.md`](assets/fonts/README.md) for the pipeline, the licence and what the slices cost.
|
|
100
|
+
|
|
101
|
+
A `file:` profile install copies what the package's `files` list named *at install time*, so a checkout whose list grew needs a refresh before the host can hand the new files out:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
npx @deepseek-ai/dsh plugin --profile web install # then restart `dsh web`
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Only the client half reloads on its own (its bundle is watched), so a client change shows up on a page refresh while a host-half change — like the route that serves the font — waits for the restart.
|
package/README.zh.md
CHANGED
|
@@ -97,3 +97,11 @@ pnpm run fonts:plan # 页面上出现多少汉字时实际会下载多少
|
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
内置字体是 [JetBrains Maple Mono](https://github.com/SpaceTimee/Fusion-JetBrainsMapleMono)(SIL OFL 1.1),由 `scripts/fonts` 子集化并切片——流水线、许可证与各切片的体积见 [`assets/fonts/README.md`](assets/fonts/README.md)。
|
|
100
|
+
|
|
101
|
+
`file:` 方式安装的 profile 只复制**安装当时** `files` 列出的文件,所以本地 checkout 后来新增的文件(如 `assets/fonts`)必须先刷新安装,宿主才拿得到:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
npx @deepseek-ai/dsh plugin --profile web install # 然后重启 `dsh web`
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
客户端那半会自己热更新(它的 bundle 被监听),所以客户端改动刷新页面即可;宿主那半的改动(例如提供字体的这条路由)要等重启才生效。
|
package/lib/client.js
CHANGED
|
@@ -31,272 +31,272 @@ window.__ModuleLoader__.load({
|
|
|
31
31
|
document.head.appendChild(tag);
|
|
32
32
|
}
|
|
33
33
|
var PendingPanel_module_css_default = {
|
|
34
|
-
"
|
|
35
|
-
"
|
|
34
|
+
"gotoHost": "F1KBNa_gotoHost",
|
|
35
|
+
"chip": "F1KBNa_chip",
|
|
36
|
+
"splitRdel": "F1KBNa_splitRdel",
|
|
37
|
+
"discussionCode": "F1KBNa_discussionCode",
|
|
38
|
+
"diffActions": "F1KBNa_diffActions",
|
|
39
|
+
"missing": "F1KBNa_missing",
|
|
40
|
+
"quoteLines": "F1KBNa_quoteLines",
|
|
41
|
+
"divergedHint": "F1KBNa_divergedHint",
|
|
42
|
+
"gotoBox": "F1KBNa_gotoBox",
|
|
43
|
+
"searchBar": "F1KBNa_searchBar",
|
|
44
|
+
"headerActions": "F1KBNa_headerActions",
|
|
45
|
+
"listTitle": "F1KBNa_listTitle",
|
|
46
|
+
"actionError": "F1KBNa_actionError",
|
|
47
|
+
"missingHint": "F1KBNa_missingHint",
|
|
48
|
+
"splitCols": "F1KBNa_splitCols",
|
|
49
|
+
"noteCentered": "F1KBNa_noteCentered",
|
|
50
|
+
"listFold": "F1KBNa_listFold",
|
|
51
|
+
"fileListShrink": "F1KBNa_fileListShrink",
|
|
52
|
+
"gotoBackdrop": "F1KBNa_gotoBackdrop",
|
|
53
|
+
"toggle": "F1KBNa_toggle",
|
|
54
|
+
"diff": "F1KBNa_diff",
|
|
55
|
+
"tree": "F1KBNa_tree",
|
|
56
|
+
"searchToggle": "F1KBNa_searchToggle",
|
|
57
|
+
"layer": "F1KBNa_layer",
|
|
58
|
+
"quoteSplitTable": "F1KBNa_quoteSplitTable",
|
|
36
59
|
"colorPickerPanel": "F1KBNa_colorPickerPanel",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
60
|
+
"splitSealedLeft": "F1KBNa_splitSealedLeft",
|
|
61
|
+
"addButton": "F1KBNa_addButton",
|
|
62
|
+
"threadFontProbe": "F1KBNa_threadFontProbe",
|
|
63
|
+
"commentGroup": "F1KBNa_commentGroup",
|
|
64
|
+
"colorPickerChevron": "F1KBNa_colorPickerChevron",
|
|
65
|
+
"gutter": "F1KBNa_gutter",
|
|
66
|
+
"pickerName": "F1KBNa_pickerName",
|
|
67
|
+
"discussionInput": "F1KBNa_discussionInput",
|
|
45
68
|
"splitCol": "F1KBNa_splitCol",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"badge": "F1KBNa_badge",
|
|
55
|
-
"quoteSplitSide": "F1KBNa_quoteSplitSide",
|
|
69
|
+
"settingsRowText": "F1KBNa_settingsRowText",
|
|
70
|
+
"overviewRuler": "F1KBNa_overviewRuler",
|
|
71
|
+
"discussionAnswer": "F1KBNa_discussionAnswer",
|
|
72
|
+
"panelDocked": "F1KBNa_panelDocked",
|
|
73
|
+
"panelFailureRetry": "F1KBNa_panelFailureRetry",
|
|
74
|
+
"searchInput": "F1KBNa_searchInput",
|
|
75
|
+
"colorPickerInput": "F1KBNa_colorPickerInput",
|
|
76
|
+
"pickerCheck": "F1KBNa_pickerCheck",
|
|
56
77
|
"splitHScrollFill": "F1KBNa_splitHScrollFill",
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"discussionHead": "F1KBNa_discussionHead",
|
|
61
|
-
"rowDiscussed": "F1KBNa_rowDiscussed",
|
|
62
|
-
"listTabs": "F1KBNa_listTabs",
|
|
78
|
+
"title": "F1KBNa_title",
|
|
79
|
+
"addPath": "F1KBNa_addPath",
|
|
80
|
+
"discussionRow": "F1KBNa_discussionRow",
|
|
63
81
|
"quoteLine": "F1KBNa_quoteLine",
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
82
|
+
"intraAdd": "F1KBNa_intraAdd",
|
|
83
|
+
"settingsSelector": "F1KBNa_settingsSelector",
|
|
84
|
+
"fileList": "F1KBNa_fileList",
|
|
85
|
+
"gotoLayerRight": "F1KBNa_gotoLayerRight",
|
|
86
|
+
"stepperValue": "F1KBNa_stepperValue",
|
|
87
|
+
"badge": "F1KBNa_badge",
|
|
88
|
+
"diffBody": "F1KBNa_diffBody",
|
|
69
89
|
"groupHead": "F1KBNa_groupHead",
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"panelDocked": "F1KBNa_panelDocked",
|
|
76
|
-
"action": "F1KBNa_action",
|
|
77
|
-
"discussionDot": "F1KBNa_discussionDot",
|
|
78
|
-
"splitDiscussions": "F1KBNa_splitDiscussions",
|
|
79
|
-
"settingsRowText": "F1KBNa_settingsRowText",
|
|
80
|
-
"discussionSend": "F1KBNa_discussionSend",
|
|
81
|
-
"settingsGroupBody": "F1KBNa_settingsGroupBody",
|
|
90
|
+
"bulkActions": "F1KBNa_bulkActions",
|
|
91
|
+
"quoteText": "F1KBNa_quoteText",
|
|
92
|
+
"colorPickerTrigger": "F1KBNa_colorPickerTrigger",
|
|
93
|
+
"settingsRow": "F1KBNa_settingsRow",
|
|
94
|
+
"floatResizeHandle": "F1KBNa_floatResizeHandle",
|
|
82
95
|
"discussionBody": "F1KBNa_discussionBody",
|
|
83
|
-
"
|
|
84
|
-
"splitHScroll": "F1KBNa_splitHScroll",
|
|
85
|
-
"colorValue": "F1KBNa_colorValue",
|
|
86
|
-
"tree": "F1KBNa_tree",
|
|
87
|
-
"diffPreview": "F1KBNa_diffPreview",
|
|
88
|
-
"missingHint": "F1KBNa_missingHint",
|
|
89
|
-
"searchMatchCurrent": "F1KBNa_searchMatchCurrent",
|
|
90
|
-
"diffFlashShake": "F1KBNa_diffFlashShake",
|
|
91
|
-
"discussionPin": "F1KBNa_discussionPin",
|
|
92
|
-
"quoteSplit": "F1KBNa_quoteSplit",
|
|
96
|
+
"notice": "F1KBNa_notice",
|
|
93
97
|
"fileListKnobIn": "F1KBNa_fileListKnobIn",
|
|
94
|
-
"stepperButton": "F1KBNa_stepperButton",
|
|
95
|
-
"pickerIcon": "F1KBNa_pickerIcon",
|
|
96
|
-
"kindHint": "F1KBNa_kindHint",
|
|
97
|
-
"rowMenuAnchor": "F1KBNa_rowMenuAnchor",
|
|
98
|
-
"splitSealedRight": "F1KBNa_splitSealedRight",
|
|
99
|
-
"discussionSlack": "F1KBNa_discussionSlack",
|
|
100
|
-
"splitRdel": "F1KBNa_splitRdel",
|
|
101
98
|
"settingsGroupText": "F1KBNa_settingsGroupText",
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"fileListKnob": "F1KBNa_fileListKnob",
|
|
114
|
-
"confirmBackdrop": "F1KBNa_confirmBackdrop",
|
|
115
|
-
"listScroll": "F1KBNa_listScroll",
|
|
116
|
-
"diffFlashFade": "F1KBNa_diffFlashFade",
|
|
117
|
-
"hint": "F1KBNa_hint",
|
|
118
|
-
"actionQuietDisabled": "F1KBNa_actionQuietDisabled",
|
|
99
|
+
"splitRadd": "F1KBNa_splitRadd",
|
|
100
|
+
"settingsGroupHeader": "F1KBNa_settingsGroupHeader",
|
|
101
|
+
"toggleThumb": "F1KBNa_toggleThumb",
|
|
102
|
+
"markerDel": "F1KBNa_markerDel",
|
|
103
|
+
"states": "F1KBNa_states",
|
|
104
|
+
"colorSwatch": "F1KBNa_colorSwatch",
|
|
105
|
+
"diffFlashShake": "F1KBNa_diffFlashShake",
|
|
106
|
+
"row": "F1KBNa_row",
|
|
107
|
+
"noticeButton": "F1KBNa_noticeButton",
|
|
108
|
+
"settingsGroupBody": "F1KBNa_settingsGroupBody",
|
|
109
|
+
"searchMatchCurrent": "F1KBNa_searchMatchCurrent",
|
|
119
110
|
"subline": "F1KBNa_subline",
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
"
|
|
125
|
-
"
|
|
126
|
-
"discussionRangeWrap": "F1KBNa_discussionRangeWrap",
|
|
127
|
-
"splitLadd": "F1KBNa_splitLadd",
|
|
128
|
-
"stepper": "F1KBNa_stepper",
|
|
129
|
-
"badgeLabel": "F1KBNa_badgeLabel",
|
|
130
|
-
"commentRow": "F1KBNa_commentRow",
|
|
131
|
-
"rowHead": "F1KBNa_rowHead",
|
|
132
|
-
"colorPickerPreview": "F1KBNa_colorPickerPreview",
|
|
133
|
-
"quoteText": "F1KBNa_quoteText",
|
|
134
|
-
"expandExpanded": "F1KBNa_expandExpanded",
|
|
135
|
-
"settingsRowLink": "F1KBNa_settingsRowLink",
|
|
136
|
-
"markerAdd": "F1KBNa_markerAdd",
|
|
111
|
+
"treeRow": "F1KBNa_treeRow",
|
|
112
|
+
"pickerForm": "F1KBNa_pickerForm",
|
|
113
|
+
"discussionUser": "F1KBNa_discussionUser",
|
|
114
|
+
"rowPath": "F1KBNa_rowPath",
|
|
115
|
+
"discussionSlack": "F1KBNa_discussionSlack",
|
|
116
|
+
"discussionDot": "F1KBNa_discussionDot",
|
|
137
117
|
"colorPickerInputRow": "F1KBNa_colorPickerInputRow",
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
"
|
|
141
|
-
"
|
|
142
|
-
"
|
|
143
|
-
"close": "F1KBNa_close",
|
|
144
|
-
"mirrored": "F1KBNa_mirrored",
|
|
145
|
-
"settingsRowTitle": "F1KBNa_settingsRowTitle",
|
|
146
|
-
"coverNoticeCard": "F1KBNa_coverNoticeCard",
|
|
147
|
-
"discussionCompose": "F1KBNa_discussionCompose",
|
|
148
|
-
"confirmActions": "F1KBNa_confirmActions",
|
|
149
|
-
"colorBackdrop": "F1KBNa_colorBackdrop",
|
|
150
|
-
"readError": "F1KBNa_readError",
|
|
151
|
-
"importButton": "F1KBNa_importButton",
|
|
152
|
-
"coverCard": "F1KBNa_coverCard",
|
|
153
|
-
"toggle": "F1KBNa_toggle",
|
|
154
|
-
"noticeText": "F1KBNa_noticeText",
|
|
155
|
-
"resizeHandle": "F1KBNa_resizeHandle",
|
|
156
|
-
"note": "F1KBNa_note",
|
|
157
|
-
"actionPrimary": "F1KBNa_actionPrimary",
|
|
158
|
-
"coverNoticeText": "F1KBNa_coverNoticeText",
|
|
159
|
-
"diffPreviewScroll": "F1KBNa_diffPreviewScroll",
|
|
118
|
+
"markerAdd": "F1KBNa_markerAdd",
|
|
119
|
+
"searchCount": "F1KBNa_searchCount",
|
|
120
|
+
"commentGroupName": "F1KBNa_commentGroupName",
|
|
121
|
+
"rows": "F1KBNa_rows",
|
|
122
|
+
"split": "F1KBNa_split",
|
|
160
123
|
"settingsGroup": "F1KBNa_settingsGroup",
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
"
|
|
167
|
-
"
|
|
168
|
-
"
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
"
|
|
124
|
+
"emptyActions": "F1KBNa_emptyActions",
|
|
125
|
+
"discussionDots": "F1KBNa_discussionDots",
|
|
126
|
+
"searchMatch": "F1KBNa_searchMatch",
|
|
127
|
+
"stepperButtonUp": "F1KBNa_stepperButtonUp",
|
|
128
|
+
"langLabel": "F1KBNa_langLabel",
|
|
129
|
+
"emptyState": "F1KBNa_emptyState",
|
|
130
|
+
"fileListFloatClosing": "F1KBNa_fileListFloatClosing",
|
|
131
|
+
"divider": "F1KBNa_divider",
|
|
132
|
+
"settingsGroupTitle": "F1KBNa_settingsGroupTitle",
|
|
133
|
+
"blockActions": "F1KBNa_blockActions",
|
|
134
|
+
"presentationHost": "F1KBNa_presentationHost",
|
|
135
|
+
"coverButton": "F1KBNa_coverButton",
|
|
136
|
+
"settingsGroupChevron": "F1KBNa_settingsGroupChevron",
|
|
137
|
+
"splitSealedRight": "F1KBNa_splitSealedRight",
|
|
138
|
+
"action": "F1KBNa_action",
|
|
139
|
+
"mdPreviewDouble": "F1KBNa_mdPreviewDouble",
|
|
140
|
+
"treeNote": "F1KBNa_treeNote",
|
|
172
141
|
"code": "F1KBNa_code",
|
|
173
|
-
"line": "F1KBNa_line",
|
|
174
|
-
"gotoInput": "F1KBNa_gotoInput",
|
|
175
142
|
"wrapActive": "F1KBNa_wrapActive",
|
|
176
|
-
"
|
|
177
|
-
"
|
|
178
|
-
"mdPreviewFallback": "F1KBNa_mdPreviewFallback",
|
|
179
|
-
"statusAction": "F1KBNa_statusAction",
|
|
180
|
-
"settingsGroupHeader": "F1KBNa_settingsGroupHeader",
|
|
181
|
-
"actionChord": "F1KBNa_actionChord",
|
|
182
|
-
"listTitle": "F1KBNa_listTitle",
|
|
183
|
-
"splitHScrollRow": "F1KBNa_splitHScrollRow",
|
|
143
|
+
"badgeLabel": "F1KBNa_badgeLabel",
|
|
144
|
+
"fileListFloat": "F1KBNa_fileListFloat",
|
|
184
145
|
"colorHueCursor": "F1KBNa_colorHueCursor",
|
|
185
|
-
"
|
|
186
|
-
"
|
|
187
|
-
"
|
|
146
|
+
"settingsGroupDesc": "F1KBNa_settingsGroupDesc",
|
|
147
|
+
"discussion": "F1KBNa_discussion",
|
|
148
|
+
"toggleOn": "F1KBNa_toggleOn",
|
|
149
|
+
"commentTitle": "F1KBNa_commentTitle",
|
|
150
|
+
"pickerTitle": "F1KBNa_pickerTitle",
|
|
151
|
+
"colorSv": "F1KBNa_colorSv",
|
|
152
|
+
"coverNoticeText": "F1KBNa_coverNoticeText",
|
|
153
|
+
"chipLabel": "F1KBNa_chipLabel",
|
|
154
|
+
"splitRoot": "F1KBNa_splitRoot",
|
|
155
|
+
"pickerCard": "F1KBNa_pickerCard",
|
|
156
|
+
"line": "F1KBNa_line",
|
|
157
|
+
"splitDiscussions": "F1KBNa_splitDiscussions",
|
|
158
|
+
"listTabs": "F1KBNa_listTabs",
|
|
159
|
+
"expandExpanded": "F1KBNa_expandExpanded",
|
|
160
|
+
"del": "F1KBNa_del",
|
|
161
|
+
"noticeText": "F1KBNa_noticeText",
|
|
188
162
|
"panel": "F1KBNa_panel",
|
|
189
|
-
"
|
|
190
|
-
"gotoHost": "F1KBNa_gotoHost",
|
|
191
|
-
"blockFlash": "F1KBNa_blockFlash",
|
|
192
|
-
"rowMeta": "F1KBNa_rowMeta",
|
|
193
|
-
"panelFailure": "F1KBNa_panelFailure",
|
|
194
|
-
"stepperButtonUp": "F1KBNa_stepperButtonUp",
|
|
195
|
-
"searchMatch": "F1KBNa_searchMatch",
|
|
196
|
-
"overviewMarker": "F1KBNa_overviewMarker",
|
|
197
|
-
"title": "F1KBNa_title",
|
|
198
|
-
"lines": "F1KBNa_lines",
|
|
199
|
-
"wrap": "F1KBNa_wrap",
|
|
163
|
+
"rowMenuAnchor": "F1KBNa_rowMenuAnchor",
|
|
200
164
|
"add": "F1KBNa_add",
|
|
201
|
-
"
|
|
202
|
-
"
|
|
165
|
+
"splitHScroll": "F1KBNa_splitHScroll",
|
|
166
|
+
"commentLost": "F1KBNa_commentLost",
|
|
167
|
+
"searchToggleOn": "F1KBNa_searchToggleOn",
|
|
168
|
+
"mirrored": "F1KBNa_mirrored",
|
|
203
169
|
"splitDivider": "F1KBNa_splitDivider",
|
|
204
|
-
"
|
|
205
|
-
"
|
|
206
|
-
"
|
|
207
|
-
"
|
|
208
|
-
"quoteLines": "F1KBNa_quoteLines",
|
|
209
|
-
"colorPickerChevron": "F1KBNa_colorPickerChevron",
|
|
210
|
-
"mdPreviewSingle": "F1KBNa_mdPreviewSingle",
|
|
211
|
-
"fileList": "F1KBNa_fileList",
|
|
212
|
-
"commentLabel": "F1KBNa_commentLabel",
|
|
213
|
-
"rowPath": "F1KBNa_rowPath",
|
|
214
|
-
"listEmpty": "F1KBNa_listEmpty",
|
|
215
|
-
"expand": "F1KBNa_expand",
|
|
170
|
+
"pickerIcon": "F1KBNa_pickerIcon",
|
|
171
|
+
"rowFailed": "F1KBNa_rowFailed",
|
|
172
|
+
"colorHue": "F1KBNa_colorHue",
|
|
173
|
+
"gotoLayer": "F1KBNa_gotoLayer",
|
|
216
174
|
"blockFlashShake": "F1KBNa_blockFlashShake",
|
|
217
|
-
"
|
|
218
|
-
"
|
|
219
|
-
"
|
|
220
|
-
"
|
|
221
|
-
"
|
|
222
|
-
"
|
|
223
|
-
"
|
|
224
|
-
"
|
|
225
|
-
"
|
|
226
|
-
"
|
|
227
|
-
"
|
|
228
|
-
"
|
|
229
|
-
"
|
|
175
|
+
"colorValue": "F1KBNa_colorValue",
|
|
176
|
+
"wrap": "F1KBNa_wrap",
|
|
177
|
+
"headerEntry": "F1KBNa_headerEntry",
|
|
178
|
+
"discussionRangeWrap": "F1KBNa_discussionRangeWrap",
|
|
179
|
+
"gotoInput": "F1KBNa_gotoInput",
|
|
180
|
+
"stepper": "F1KBNa_stepper",
|
|
181
|
+
"blockActionsDivider": "F1KBNa_blockActionsDivider",
|
|
182
|
+
"addCount": "F1KBNa_addCount",
|
|
183
|
+
"stepperButton": "F1KBNa_stepperButton",
|
|
184
|
+
"diffHeader": "F1KBNa_diffHeader",
|
|
185
|
+
"statusBar": "F1KBNa_statusBar",
|
|
186
|
+
"settingsRowLink": "F1KBNa_settingsRowLink",
|
|
187
|
+
"kindTag": "F1KBNa_kindTag",
|
|
188
|
+
"rail": "F1KBNa_rail",
|
|
230
189
|
"gotoAction": "F1KBNa_gotoAction",
|
|
231
|
-
"
|
|
232
|
-
"
|
|
233
|
-
"
|
|
190
|
+
"intraDel": "F1KBNa_intraDel",
|
|
191
|
+
"vSpacer": "F1KBNa_vSpacer",
|
|
192
|
+
"listHead": "F1KBNa_listHead",
|
|
193
|
+
"pickerClose": "F1KBNa_pickerClose",
|
|
234
194
|
"discussionToggle": "F1KBNa_discussionToggle",
|
|
235
|
-
"
|
|
236
|
-
"
|
|
237
|
-
"
|
|
238
|
-
"
|
|
239
|
-
"
|
|
240
|
-
"
|
|
195
|
+
"settingsRowTitle": "F1KBNa_settingsRowTitle",
|
|
196
|
+
"rowDiscussed": "F1KBNa_rowDiscussed",
|
|
197
|
+
"header": "F1KBNa_header",
|
|
198
|
+
"actionQuietDisabled": "F1KBNa_actionQuietDisabled",
|
|
199
|
+
"discussionPin": "F1KBNa_discussionPin",
|
|
200
|
+
"pickerInput": "F1KBNa_pickerInput",
|
|
201
|
+
"diffPreviewScroll": "F1KBNa_diffPreviewScroll",
|
|
202
|
+
"importButton": "F1KBNa_importButton",
|
|
203
|
+
"diffPreview": "F1KBNa_diffPreview",
|
|
204
|
+
"discussionSend": "F1KBNa_discussionSend",
|
|
241
205
|
"coverBackdrop": "F1KBNa_coverBackdrop",
|
|
242
|
-
"
|
|
243
|
-
"
|
|
244
|
-
"
|
|
245
|
-
"
|
|
246
|
-
"
|
|
247
|
-
"
|
|
248
|
-
"
|
|
249
|
-
"
|
|
250
|
-
"vSpacer": "F1KBNa_vSpacer",
|
|
251
|
-
"fileListShrink": "F1KBNa_fileListShrink",
|
|
252
|
-
"statusBar": "F1KBNa_statusBar",
|
|
253
|
-
"presentationHost": "F1KBNa_presentationHost",
|
|
254
|
-
"searchBar": "F1KBNa_searchBar",
|
|
255
|
-
"fileListFloat": "F1KBNa_fileListFloat",
|
|
256
|
-
"context": "F1KBNa_context",
|
|
257
|
-
"discussionRange": "F1KBNa_discussionRange",
|
|
258
|
-
"headerActions": "F1KBNa_headerActions",
|
|
259
|
-
"detailEmpty": "F1KBNa_detailEmpty",
|
|
206
|
+
"panelFailureText": "F1KBNa_panelFailureText",
|
|
207
|
+
"discussionNote": "F1KBNa_discussionNote",
|
|
208
|
+
"splitHScrollRow": "F1KBNa_splitHScrollRow",
|
|
209
|
+
"footerButtons": "F1KBNa_footerButtons",
|
|
210
|
+
"splitSealed": "F1KBNa_splitSealed",
|
|
211
|
+
"overviewMarker": "F1KBNa_overviewMarker",
|
|
212
|
+
"colorBackdrop": "F1KBNa_colorBackdrop",
|
|
213
|
+
"expand": "F1KBNa_expand",
|
|
260
214
|
"quoteAdd": "F1KBNa_quoteAdd",
|
|
261
|
-
"
|
|
262
|
-
"
|
|
263
|
-
"settingsGroupTitle": "F1KBNa_settingsGroupTitle",
|
|
264
|
-
"rail": "F1KBNa_rail",
|
|
215
|
+
"resizeHandle": "F1KBNa_resizeHandle",
|
|
216
|
+
"note": "F1KBNa_note",
|
|
265
217
|
"settingsReset": "F1KBNa_settingsReset",
|
|
266
|
-
"
|
|
267
|
-
"
|
|
268
|
-
"pickerName": "F1KBNa_pickerName",
|
|
269
|
-
"diffHeader": "F1KBNa_diffHeader",
|
|
270
|
-
"quoteNoWrap": "F1KBNa_quoteNoWrap",
|
|
271
|
-
"badgeCount": "F1KBNa_badgeCount",
|
|
272
|
-
"quoteCode": "F1KBNa_quoteCode",
|
|
273
|
-
"discussion": "F1KBNa_discussion",
|
|
274
|
-
"diffStats": "F1KBNa_diffStats",
|
|
275
|
-
"headerEntry": "F1KBNa_headerEntry",
|
|
276
|
-
"gotoBackdrop": "F1KBNa_gotoBackdrop",
|
|
277
|
-
"del": "F1KBNa_del",
|
|
278
|
-
"pickerCheck": "F1KBNa_pickerCheck",
|
|
279
|
-
"treeNote": "F1KBNa_treeNote",
|
|
280
|
-
"searchInput": "F1KBNa_searchInput",
|
|
281
|
-
"settingsGroupDesc": "F1KBNa_settingsGroupDesc",
|
|
282
|
-
"toggleOn": "F1KBNa_toggleOn",
|
|
283
|
-
"actionError": "F1KBNa_actionError",
|
|
284
|
-
"commentTitleEmpty": "F1KBNa_commentTitleEmpty",
|
|
285
|
-
"markerDel": "F1KBNa_markerDel",
|
|
286
|
-
"discussionDots": "F1KBNa_discussionDots",
|
|
287
|
-
"diffPath": "F1KBNa_diffPath",
|
|
288
|
-
"treeRow": "F1KBNa_treeRow",
|
|
218
|
+
"blockPosition": "F1KBNa_blockPosition",
|
|
219
|
+
"listEmpty": "F1KBNa_listEmpty",
|
|
289
220
|
"settingsPage": "F1KBNa_settingsPage",
|
|
221
|
+
"coverNotice": "F1KBNa_coverNotice",
|
|
222
|
+
"mdPreviewBody": "F1KBNa_mdPreviewBody",
|
|
223
|
+
"close": "F1KBNa_close",
|
|
224
|
+
"quoteDel": "F1KBNa_quoteDel",
|
|
225
|
+
"quoteSplitSide": "F1KBNa_quoteSplitSide",
|
|
226
|
+
"diffPath": "F1KBNa_diffPath",
|
|
227
|
+
"detailEmpty": "F1KBNa_detailEmpty",
|
|
228
|
+
"mdPreviewContent": "F1KBNa_mdPreviewContent",
|
|
229
|
+
"colorPickerPopover": "F1KBNa_colorPickerPopover",
|
|
230
|
+
"delCount": "F1KBNa_delCount",
|
|
231
|
+
"listTab": "F1KBNa_listTab",
|
|
232
|
+
"flexSpacer": "F1KBNa_flexSpacer",
|
|
233
|
+
"quoteNoWrap": "F1KBNa_quoteNoWrap",
|
|
234
|
+
"treeName": "F1KBNa_treeName",
|
|
235
|
+
"discussionRange": "F1KBNa_discussionRange",
|
|
236
|
+
"splitLdel": "F1KBNa_splitLdel",
|
|
290
237
|
"confirmCard": "F1KBNa_confirmCard",
|
|
291
|
-
"
|
|
238
|
+
"rowHead": "F1KBNa_rowHead",
|
|
239
|
+
"coverCard": "F1KBNa_coverCard",
|
|
240
|
+
"coverNoticeFade": "F1KBNa_coverNoticeFade",
|
|
241
|
+
"treeCaret": "F1KBNa_treeCaret",
|
|
242
|
+
"panelFailure": "F1KBNa_panelFailure",
|
|
243
|
+
"mdPreviewSingle": "F1KBNa_mdPreviewSingle",
|
|
244
|
+
"tabCount": "F1KBNa_tabCount",
|
|
245
|
+
"langSelect": "F1KBNa_langSelect",
|
|
246
|
+
"quoteSplit": "F1KBNa_quoteSplit",
|
|
247
|
+
"discussionCompose": "F1KBNa_discussionCompose",
|
|
248
|
+
"colorPicker": "F1KBNa_colorPicker",
|
|
249
|
+
"confirmText": "F1KBNa_confirmText",
|
|
250
|
+
"rowMeta": "F1KBNa_rowMeta",
|
|
251
|
+
"settingsRowDesc": "F1KBNa_settingsRowDesc",
|
|
252
|
+
"presentationSelect": "F1KBNa_presentationSelect",
|
|
253
|
+
"readError": "F1KBNa_readError",
|
|
254
|
+
"commentHead": "F1KBNa_commentHead",
|
|
255
|
+
"commentLabel": "F1KBNa_commentLabel",
|
|
256
|
+
"diffBodyWrap": "F1KBNa_diffBodyWrap",
|
|
257
|
+
"overviewRulerSplit": "F1KBNa_overviewRulerSplit",
|
|
258
|
+
"coverNoticeGlyph": "F1KBNa_coverNoticeGlyph",
|
|
259
|
+
"colorPickerPreview": "F1KBNa_colorPickerPreview",
|
|
260
|
+
"discussionHead": "F1KBNa_discussionHead",
|
|
292
261
|
"headerEntryCount": "F1KBNa_headerEntryCount",
|
|
293
|
-
"
|
|
294
|
-
"
|
|
295
|
-
"
|
|
296
|
-
"
|
|
262
|
+
"quoteCode": "F1KBNa_quoteCode",
|
|
263
|
+
"lines": "F1KBNa_lines",
|
|
264
|
+
"group": "F1KBNa_group",
|
|
265
|
+
"mdPreviewWrap": "F1KBNa_mdPreviewWrap",
|
|
266
|
+
"badgeCount": "F1KBNa_badgeCount",
|
|
267
|
+
"colorSvCursor": "F1KBNa_colorSvCursor",
|
|
268
|
+
"pickerNote": "F1KBNa_pickerNote",
|
|
269
|
+
"actionChord": "F1KBNa_actionChord",
|
|
270
|
+
"coverHost": "F1KBNa_coverHost",
|
|
271
|
+
"dockHost": "F1KBNa_dockHost",
|
|
272
|
+
"splitLadd": "F1KBNa_splitLadd",
|
|
273
|
+
"commentTitleEmpty": "F1KBNa_commentTitleEmpty",
|
|
274
|
+
"confirmBackdrop": "F1KBNa_confirmBackdrop",
|
|
275
|
+
"hint": "F1KBNa_hint",
|
|
276
|
+
"diffStats": "F1KBNa_diffStats",
|
|
277
|
+
"blockFlash": "F1KBNa_blockFlash",
|
|
278
|
+
"diffFlashFade": "F1KBNa_diffFlashFade",
|
|
279
|
+
"chipPresentation": "F1KBNa_chipPresentation",
|
|
280
|
+
"markerSplitAdd": "F1KBNa_markerSplitAdd",
|
|
281
|
+
"statusAction": "F1KBNa_statusAction",
|
|
282
|
+
"context": "F1KBNa_context",
|
|
283
|
+
"listScroll": "F1KBNa_listScroll",
|
|
284
|
+
"iconAction": "F1KBNa_iconAction",
|
|
285
|
+
"importNote": "F1KBNa_importNote",
|
|
297
286
|
"discussionCell": "F1KBNa_discussionCell",
|
|
298
|
-
"
|
|
299
|
-
"
|
|
287
|
+
"coverPopover": "F1KBNa_coverPopover",
|
|
288
|
+
"splitDiscussion": "F1KBNa_splitDiscussion",
|
|
289
|
+
"confirmActions": "F1KBNa_confirmActions",
|
|
290
|
+
"markerSplitDel": "F1KBNa_markerSplitDel",
|
|
291
|
+
"detail": "F1KBNa_detail",
|
|
292
|
+
"fileListKnob": "F1KBNa_fileListKnob",
|
|
293
|
+
"kindHint": "F1KBNa_kindHint",
|
|
294
|
+
"commentRow": "F1KBNa_commentRow",
|
|
295
|
+
"mdPreviewFallback": "F1KBNa_mdPreviewFallback",
|
|
296
|
+
"coverNoticeCard": "F1KBNa_coverNoticeCard",
|
|
297
|
+
"diffPreviewTitle": "F1KBNa_diffPreviewTitle",
|
|
298
|
+
"diffBodySplit": "F1KBNa_diffBodySplit",
|
|
299
|
+
"actionPrimary": "F1KBNa_actionPrimary"
|
|
300
300
|
};
|
|
301
301
|
//#endregion
|
|
302
302
|
//#region lib/types/client/PathPicker.js
|
|
@@ -29751,6 +29751,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
29751
29751
|
/** The manifest path, resolved against the document's own origin. */
|
|
29752
29752
|
const MANIFEST_URL = `${FONT_ROUTE}/manifest.json`;
|
|
29753
29753
|
/**
|
|
29754
|
+
* The class the panel puts on the code table, read from the stylesheet module
|
|
29755
|
+
* that defines it.
|
|
29756
|
+
*
|
|
29757
|
+
* A literal `.lines` selector is a no-op: the build prefixes every class in that
|
|
29758
|
+
* module (`Ay7oXG_lines`), so a rule naming the source name matches no element
|
|
29759
|
+
* and the font silently never applies. The module's own export is the one value
|
|
29760
|
+
* that cannot drift from what the panel renders.
|
|
29761
|
+
*/
|
|
29762
|
+
const CODE_TABLE_CLASS = PendingPanel_module_css_default.lines ?? "";
|
|
29763
|
+
/**
|
|
29754
29764
|
* The `@font-face` rules for every slice of every weight, followed by the one
|
|
29755
29765
|
* rule that uses them: the code column.
|
|
29756
29766
|
*
|
|
@@ -29758,28 +29768,41 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
29758
29768
|
* font immediately, and swapping when the slices land only changes the column
|
|
29759
29769
|
* width, never the row height that the virtual window and the jump math are
|
|
29760
29770
|
* built on.
|
|
29771
|
+
*
|
|
29772
|
+
* @param slices - the manifest's slice list.
|
|
29773
|
+
* @param codeClass - the class the code table carries, defaulting to the one the
|
|
29774
|
+
* panel's stylesheet exports. It is a parameter so a test can pin the emitted
|
|
29775
|
+
* selector without importing the panel.
|
|
29761
29776
|
*/
|
|
29762
|
-
function codeFontCss(slices) {
|
|
29777
|
+
function codeFontCss(slices, codeClass = CODE_TABLE_CLASS) {
|
|
29763
29778
|
const rules = [];
|
|
29764
29779
|
for (const face of FONT_FACES) for (const slice of slices) {
|
|
29765
29780
|
if (slice.weight !== face.weight) continue;
|
|
29766
29781
|
if (slice.file.indexOf(`${face.name}-`) !== 0) continue;
|
|
29767
29782
|
rules.push(`@font-face{font-family:"${FONT_FAMILY}";src:url("${FONT_ROUTE}/${slice.file}") format("woff2");font-weight:${face.weight};font-style:normal;font-display:swap;unicode-range:${slice.unicodeRange}}`);
|
|
29768
29783
|
}
|
|
29769
|
-
rules.push(
|
|
29784
|
+
if (codeClass !== "") rules.push(`.${codeClass}{font-family:${FONT_STACK}}`);
|
|
29770
29785
|
return rules.join("\n");
|
|
29771
29786
|
}
|
|
29772
29787
|
/** The manifest, read once per page: the slices it lists never change under us. */
|
|
29773
29788
|
let manifestPromise;
|
|
29789
|
+
/** Whether the one "the switch is on but the host serves no slices" line was written. */
|
|
29790
|
+
let reportedMissing = false;
|
|
29774
29791
|
/** Fetch (or reuse) the slice list. Undefined when the host serves no slices. */
|
|
29775
29792
|
function fetchSlices() {
|
|
29776
29793
|
manifestPromise ??= (async () => {
|
|
29777
29794
|
try {
|
|
29778
29795
|
const response = await fetch(MANIFEST_URL, { credentials: "same-origin" });
|
|
29779
|
-
if (!response.ok)
|
|
29796
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
29780
29797
|
const slices = (await response.json()).slices ?? [];
|
|
29781
|
-
|
|
29782
|
-
|
|
29798
|
+
if (slices.length === 0) throw new Error("the manifest lists no slices");
|
|
29799
|
+
return slices;
|
|
29800
|
+
} catch (error) {
|
|
29801
|
+
manifestPromise = void 0;
|
|
29802
|
+
if (!reportedMissing) {
|
|
29803
|
+
reportedMissing = true;
|
|
29804
|
+
console.warn(`diff-approval: the bundled code font is unavailable (${MANIFEST_URL})`, error);
|
|
29805
|
+
}
|
|
29783
29806
|
return;
|
|
29784
29807
|
}
|
|
29785
29808
|
})();
|
|
@@ -29815,9 +29838,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
29815
29838
|
}
|
|
29816
29839
|
/**
|
|
29817
29840
|
* Follow the preference for as long as the client lives: apply it now, and again
|
|
29818
|
-
* whenever the Settings switch flips.
|
|
29819
|
-
*
|
|
29820
|
-
* system stack,
|
|
29841
|
+
* whenever the Settings switch flips. A host without the slices (a source
|
|
29842
|
+
* checkout that never ran the font build, or an install that arrived without
|
|
29843
|
+
* `assets/`) keeps the system stack, and says so once on the console: the
|
|
29844
|
+
* switch is on, so silence would read as "the font does nothing".
|
|
29821
29845
|
*
|
|
29822
29846
|
* @returns a disposer that stops following and removes the injected rules.
|
|
29823
29847
|
*/
|
package/lib/index.js
CHANGED
|
@@ -3271,9 +3271,9 @@ function apply(ctx, config) {
|
|
|
3271
3271
|
return typeof service.register === "function" ? service.register(ctx, DIFF_APPROVAL_CHANNEL, handle, { authority: "trusted-host" }) : service.rpc.handle(DIFF_APPROVAL_CHANNEL, handle, { authority: "trusted-host" });
|
|
3272
3272
|
}, "diff-approval: review channel");
|
|
3273
3273
|
ctx.effect(() => {
|
|
3274
|
-
const route = fontRoute();
|
|
3274
|
+
const route = fontRoute((message) => ctx.logger.warn(message));
|
|
3275
3275
|
const server = ctx.get("webServer");
|
|
3276
|
-
if (
|
|
3276
|
+
if (typeof server?.register !== "function") {
|
|
3277
3277
|
ctx.logger.debug("diff-approval: no web server, so the bundled code font is not served");
|
|
3278
3278
|
return () => {};
|
|
3279
3279
|
}
|
|
@@ -3420,38 +3420,79 @@ function openTargetOf(payload) {
|
|
|
3420
3420
|
}
|
|
3421
3421
|
/** The font slices the host is willing to serve, read once from the manifest. */
|
|
3422
3422
|
let fontSlicesPromise;
|
|
3423
|
-
/** Read `assets/fonts/manifest.json` next to the built bundle
|
|
3424
|
-
function
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3423
|
+
/** Read `assets/fonts/manifest.json` next to the built bundle. */
|
|
3424
|
+
async function loadFontSlices() {
|
|
3425
|
+
try {
|
|
3426
|
+
const dir = fileURLToPath(new URL(FONT_ASSET_DIR, import.meta.url));
|
|
3427
|
+
const text = await readFile(join(dir, "manifest.json"), "utf8");
|
|
3428
|
+
const manifest = JSON.parse(text);
|
|
3429
|
+
const slices = /* @__PURE__ */ new Map();
|
|
3430
|
+
for (const slice of manifest.slices ?? []) slices.set(slice.file, slice);
|
|
3431
|
+
return slices;
|
|
3432
|
+
} catch {
|
|
3433
|
+
return;
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
/**
|
|
3437
|
+
* The manifest, cached for the life of the host — but only once it has been
|
|
3438
|
+
* read. A missing `assets/fonts` is deliberately not cached: a deployment that
|
|
3439
|
+
* puts the assets beside a running bundle (a profile reinstall after the
|
|
3440
|
+
* package's file list grew) starts serving slices on the next request instead
|
|
3441
|
+
* of needing a restart, at the cost of one failed read per request until then.
|
|
3442
|
+
*/
|
|
3443
|
+
async function fontSlices() {
|
|
3444
|
+
if (fontSlicesPromise === void 0) {
|
|
3445
|
+
const pending = loadFontSlices();
|
|
3446
|
+
fontSlicesPromise = pending;
|
|
3447
|
+
const slices = await pending;
|
|
3448
|
+
if (slices === void 0) fontSlicesPromise = void 0;
|
|
3449
|
+
return slices;
|
|
3450
|
+
}
|
|
3437
3451
|
return fontSlicesPromise;
|
|
3438
3452
|
}
|
|
3439
3453
|
/**
|
|
3454
|
+
* Drop the cached slice list, so the next request reads the manifest again.
|
|
3455
|
+
*
|
|
3456
|
+
* The cache exists so a served page costs one read, which makes it state that
|
|
3457
|
+
* outlives a test: tests that need the "no manifest" path call this between
|
|
3458
|
+
* cases. Nothing in the app calls it.
|
|
3459
|
+
*/
|
|
3460
|
+
function resetFontSlicesForTests() {
|
|
3461
|
+
fontSlicesPromise = void 0;
|
|
3462
|
+
}
|
|
3463
|
+
/**
|
|
3440
3464
|
* Answer one font request. Exported so the route's behaviour is testable
|
|
3441
|
-
* without a listening server:
|
|
3442
|
-
*
|
|
3465
|
+
* without a listening server: the manifest itself is answered from the parsed
|
|
3466
|
+
* list, only files that list names are ever read, and everything else —
|
|
3467
|
+
* including a path traversal attempt — is a 404.
|
|
3443
3468
|
*
|
|
3444
3469
|
* @param req - the request, for its path.
|
|
3445
3470
|
* @param res - the response, whose lifecycle this owns.
|
|
3471
|
+
* @param nominate - how to report a missing manifest, called at most once per
|
|
3472
|
+
* route by {@link fontRoute}. Without the manifest every slice is a 404, and
|
|
3473
|
+
* that is a deployment problem the reader cannot see from the panel: the
|
|
3474
|
+
* switch is on, the font is simply absent, and nothing else says why.
|
|
3446
3475
|
*/
|
|
3447
|
-
async function serveFontSlice(req, res) {
|
|
3476
|
+
async function serveFontSlice(req, res, nominate) {
|
|
3448
3477
|
const slices = await fontSlices();
|
|
3449
3478
|
if (slices === void 0) {
|
|
3479
|
+
nominate?.(`diff-approval: no code-font manifest at ${join(fileURLToPath(new URL(FONT_ASSET_DIR, import.meta.url)), "manifest.json")}, so the bundled font cannot be served (reinstall the plugin so its assets arrive, then restart the host)`);
|
|
3450
3480
|
res.statusCode = 404;
|
|
3451
3481
|
res.end("font unavailable");
|
|
3452
3482
|
return;
|
|
3453
3483
|
}
|
|
3454
3484
|
const name = decodeURIComponent((req.url ?? "").split("?")[0] ?? "").split("/").pop() ?? "";
|
|
3485
|
+
if (name === "manifest.json") {
|
|
3486
|
+
res.statusCode = 200;
|
|
3487
|
+
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
3488
|
+
res.setHeader("cache-control", "no-store");
|
|
3489
|
+
res.end(JSON.stringify({ slices: [...slices.values()].map(({ file, unicodeRange, weight }) => ({
|
|
3490
|
+
file,
|
|
3491
|
+
unicodeRange,
|
|
3492
|
+
weight
|
|
3493
|
+
})) }));
|
|
3494
|
+
return;
|
|
3495
|
+
}
|
|
3455
3496
|
const slice = slices.get(name);
|
|
3456
3497
|
if (slice === void 0 || !/^[a-z]+-[a-z0-9-]*\.woff2$/.test(name)) {
|
|
3457
3498
|
res.statusCode = 404;
|
|
@@ -3473,15 +3514,24 @@ async function serveFontSlice(req, res) {
|
|
|
3473
3514
|
}
|
|
3474
3515
|
}
|
|
3475
3516
|
/**
|
|
3476
|
-
* The route serving the bundled font
|
|
3477
|
-
*
|
|
3517
|
+
* The route serving the bundled font.
|
|
3518
|
+
*
|
|
3519
|
+
* @param warn - where the once-per-route "no manifest beside the bundle" line
|
|
3520
|
+
* goes. It is the only signal a reader's switch gives when the deployment,
|
|
3521
|
+
* not the switch, is what is missing.
|
|
3522
|
+
* @returns the prefix route.
|
|
3478
3523
|
*/
|
|
3479
|
-
function fontRoute() {
|
|
3524
|
+
function fontRoute(warn) {
|
|
3525
|
+
let reported = false;
|
|
3480
3526
|
return {
|
|
3481
3527
|
kind: "prefix",
|
|
3482
3528
|
path: FONT_ROUTE,
|
|
3483
|
-
handler: serveFontSlice
|
|
3529
|
+
handler: (req, res) => serveFontSlice(req, res, (message) => {
|
|
3530
|
+
if (reported) return;
|
|
3531
|
+
reported = true;
|
|
3532
|
+
warn(message);
|
|
3533
|
+
})
|
|
3484
3534
|
};
|
|
3485
3535
|
}
|
|
3486
3536
|
//#endregion
|
|
3487
|
-
export { COMMENT_SKILL_NAME, DIFF_APPROVAL_CHANNEL, PendingDiffStore, PendingPersistence, apply, defaultOpenPath, defaultStorageDir, inject, name, serveFontSlice };
|
|
3537
|
+
export { COMMENT_SKILL_NAME, DIFF_APPROVAL_CHANNEL, PendingDiffStore, PendingPersistence, apply, defaultOpenPath, defaultStorageDir, fontRoute, inject, name, resetFontSlicesForTests, serveFontSlice };
|
|
@@ -42,8 +42,13 @@ interface ListedSlice {
|
|
|
42
42
|
* font immediately, and swapping when the slices land only changes the column
|
|
43
43
|
* width, never the row height that the virtual window and the jump math are
|
|
44
44
|
* built on.
|
|
45
|
+
*
|
|
46
|
+
* @param slices - the manifest's slice list.
|
|
47
|
+
* @param codeClass - the class the code table carries, defaulting to the one the
|
|
48
|
+
* panel's stylesheet exports. It is a parameter so a test can pin the emitted
|
|
49
|
+
* selector without importing the panel.
|
|
45
50
|
*/
|
|
46
|
-
export declare function codeFontCss(slices: readonly ListedSlice[]): string;
|
|
51
|
+
export declare function codeFontCss(slices: readonly ListedSlice[], codeClass?: string): string;
|
|
47
52
|
/**
|
|
48
53
|
* Drop the cached slice list and the injected rules.
|
|
49
54
|
*
|
|
@@ -54,9 +59,10 @@ export declare function codeFontCss(slices: readonly ListedSlice[]): string;
|
|
|
54
59
|
export declare function resetCodeFontForTests(): void;
|
|
55
60
|
/**
|
|
56
61
|
* Follow the preference for as long as the client lives: apply it now, and again
|
|
57
|
-
* whenever the Settings switch flips.
|
|
58
|
-
*
|
|
59
|
-
* system stack,
|
|
62
|
+
* whenever the Settings switch flips. A host without the slices (a source
|
|
63
|
+
* checkout that never ran the font build, or an install that arrived without
|
|
64
|
+
* `assets/`) keeps the system stack, and says so once on the console: the
|
|
65
|
+
* switch is on, so silence would read as "the font does nothing".
|
|
60
66
|
*
|
|
61
67
|
* @returns a disposer that stops following and removes the injected rules.
|
|
62
68
|
*/
|
package/lib/types/index.d.ts
CHANGED
|
@@ -84,12 +84,38 @@ interface WebServerResponse {
|
|
|
84
84
|
setHeader(name: string, value: string): unknown;
|
|
85
85
|
end(body?: Uint8Array | string): unknown;
|
|
86
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Drop the cached slice list, so the next request reads the manifest again.
|
|
89
|
+
*
|
|
90
|
+
* The cache exists so a served page costs one read, which makes it state that
|
|
91
|
+
* outlives a test: tests that need the "no manifest" path call this between
|
|
92
|
+
* cases. Nothing in the app calls it.
|
|
93
|
+
*/
|
|
94
|
+
export declare function resetFontSlicesForTests(): void;
|
|
87
95
|
/**
|
|
88
96
|
* Answer one font request. Exported so the route's behaviour is testable
|
|
89
|
-
* without a listening server:
|
|
90
|
-
*
|
|
97
|
+
* without a listening server: the manifest itself is answered from the parsed
|
|
98
|
+
* list, only files that list names are ever read, and everything else —
|
|
99
|
+
* including a path traversal attempt — is a 404.
|
|
91
100
|
*
|
|
92
101
|
* @param req - the request, for its path.
|
|
93
102
|
* @param res - the response, whose lifecycle this owns.
|
|
103
|
+
* @param nominate - how to report a missing manifest, called at most once per
|
|
104
|
+
* route by {@link fontRoute}. Without the manifest every slice is a 404, and
|
|
105
|
+
* that is a deployment problem the reader cannot see from the panel: the
|
|
106
|
+
* switch is on, the font is simply absent, and nothing else says why.
|
|
107
|
+
*/
|
|
108
|
+
export declare function serveFontSlice(req: WebServerRequest, res: WebServerResponse, nominate?: (message: string) => void): Promise<void>;
|
|
109
|
+
/**
|
|
110
|
+
* The route serving the bundled font.
|
|
111
|
+
*
|
|
112
|
+
* @param warn - where the once-per-route "no manifest beside the bundle" line
|
|
113
|
+
* goes. It is the only signal a reader's switch gives when the deployment,
|
|
114
|
+
* not the switch, is what is missing.
|
|
115
|
+
* @returns the prefix route.
|
|
94
116
|
*/
|
|
95
|
-
export declare function
|
|
117
|
+
export declare function fontRoute(warn: (message: string) => void): {
|
|
118
|
+
kind: 'prefix';
|
|
119
|
+
path: string;
|
|
120
|
+
handler: (req: WebServerRequest, res: WebServerResponse) => Promise<void>;
|
|
121
|
+
};
|
package/package.json
CHANGED