@zfdx123/dsh-session-cleaner 1.0.5 → 1.0.7

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.
Files changed (2) hide show
  1. package/client.js +43 -14
  2. package/package.json +1 -1
package/client.js CHANGED
@@ -143,15 +143,31 @@ window.__ModuleLoader__.load({
143
143
  * look. Null means the delete still works through the browser's own
144
144
  * confirmation, and every glyph falls back to the hand-drawn SVG.
145
145
  */
146
+ /**
147
+ * Whether a value can be rendered as a React component.
148
+ *
149
+ * `typeof x === 'function'` is NOT enough: the shell's `Button` is built with
150
+ * `React.forwardRef(...)`, so its `typeof` is always `'object'`
151
+ * (`$$typeof = Symbol(react.forward_ref)`, `render` is the function). A guard
152
+ * that asks for `typeof primitives.Button === 'function'` is therefore always
153
+ * false, which throws away the whole kit even though Modal/Input/Switch really
154
+ * are functions — the failure looks like "only the icons are wrong".
155
+ */
156
+ function isRenderable(value) {
157
+ if (typeof value === 'function') return true
158
+ if (typeof value !== 'object' || value === null) return false
159
+ return value.$$typeof === Symbol.for('react.forward_ref') || value.$$typeof === Symbol.for('react.memo')
160
+ }
161
+
146
162
  function loadPrimitives(require) {
147
163
  try {
148
164
  const primitives = require(PRIMITIVES)
149
165
  if (
150
- typeof primitives?.Modal === 'function' &&
151
- typeof primitives?.Button === 'function' &&
152
- typeof primitives?.IconSearchOutline === 'function' &&
153
- typeof primitives?.IconChevronDownOutline === 'function' &&
154
- typeof primitives?.IconTrashOutline === 'function'
166
+ isRenderable(primitives?.Modal) &&
167
+ isRenderable(primitives?.Button) &&
168
+ isRenderable(primitives?.IconSearchOutlineRegular) &&
169
+ isRenderable(primitives?.IconChevronDownOutlineRegular) &&
170
+ isRenderable(primitives?.IconTrashOutlineRegular)
155
171
  )
156
172
  return primitives
157
173
  } catch (error) {
@@ -701,7 +717,7 @@ window.__ModuleLoader__.load({
701
717
  React.createElement(Glyph, {
702
718
  key: 'chevron',
703
719
  primitives,
704
- name: 'IconChevronDownOutline',
720
+ name: 'IconChevronDownOutlineRegular',
705
721
  size: 12,
706
722
  box: Object.assign({}, S.chevron, collapsed ? S.chevronFolded : {}),
707
723
  fallback: ChevronIcon,
@@ -723,7 +739,7 @@ window.__ModuleLoader__.load({
723
739
  React.createElement(Glyph, {
724
740
  key: 'i',
725
741
  primitives,
726
- name: 'IconSearchOutline',
742
+ name: 'IconSearchOutlineRegular',
727
743
  size: 16,
728
744
  box: S.searchGlyph,
729
745
  fallback: SearchIcon,
@@ -981,7 +997,7 @@ window.__ModuleLoader__.load({
981
997
  * root mounted behind it. Null keeps the hand-drawn SVG above in charge.
982
998
  */
983
999
  function kitTrashIcon(primitives) {
984
- const Icon = kitIcon(primitives, 'IconTrashOutline')
1000
+ const Icon = kitIcon(primitives, 'IconTrashOutlineRegular')
985
1001
  if (Icon === null) return null
986
1002
  try {
987
1003
  const scratch = document.createElement('span')
@@ -992,7 +1008,7 @@ window.__ModuleLoader__.load({
992
1008
  root.unmount()
993
1009
  return node
994
1010
  } catch (error) {
995
- report('icon-fallback', { icon: 'IconTrashOutline', message: String(error?.message ?? error) })
1011
+ report('icon-fallback', { icon: 'IconTrashOutlineRegular', message: String(error?.message ?? error) })
996
1012
  return null
997
1013
  }
998
1014
  }
@@ -1091,6 +1107,21 @@ window.__ModuleLoader__.load({
1091
1107
  report('trigger', { name: name.slice(0, 60) })
1092
1108
  }
1093
1109
 
1110
+ // 目录请求的序号:只有最新一次的结果允许写进 `catalog`。
1111
+ //
1112
+ // 回归:启动时一次拉取(下面 1142 行)与「行内 id 没解出来时」的重试
1113
+ // (1124 行)会同时在飞,先发的旧响应可能后到并覆盖 `catalog`。已经插进去的
1114
+ // 菜单项不会被重建(标签看起来是对的),但 `catalog` 会一直陈旧到刷新页面,
1115
+ // 于是**下一个**打开的菜单会把运行中的会话显示成可删除。
1116
+ let catalogSeq = 0
1117
+ const loadCatalog = () => {
1118
+ const seq = (catalogSeq += 1)
1119
+ return fetchCatalog().then((resolved) => {
1120
+ if (catalogSeq === seq) catalog = resolved
1121
+ return resolved
1122
+ })
1123
+ }
1124
+
1094
1125
  const attempt = (added) => {
1095
1126
  const found = findSessionMenu(added)
1096
1127
  if (found === undefined) return
@@ -1105,10 +1136,9 @@ window.__ModuleLoader__.load({
1105
1136
  pendingRow = null
1106
1137
  return
1107
1138
  }
1108
- fetchCatalog()
1139
+ loadCatalog()
1109
1140
  .then((resolved) => {
1110
- catalog = resolved
1111
- if (found.menu.isConnected) augmentMenu(found, row, catalog, ctx, dict)
1141
+ if (found.menu.isConnected) augmentMenu(found, row, resolved, ctx, dict)
1112
1142
  })
1113
1143
  .catch(() => {})
1114
1144
  }
@@ -1123,9 +1153,8 @@ window.__ModuleLoader__.load({
1123
1153
  })
1124
1154
  document.addEventListener('pointerdown', onPointerDown, true)
1125
1155
  observer.observe(document.body, { childList: true, subtree: true })
1126
- fetchCatalog()
1156
+ loadCatalog()
1127
1157
  .then((resolved) => {
1128
- catalog = resolved
1129
1158
  report('catalog', { ok: resolved !== null, known: resolved === null ? 0 : resolved.byId.size })
1130
1159
  })
1131
1160
  .catch(() => {})
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zfdx123/dsh-session-cleaner",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "会话清理:在运行中的 web 运行时里彻底删除 DSH 会话——实时 store 条目、工作区记录、磁盘产物与投影缓存行一并清掉,并在会话行菜单里加一个删除入口。",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/zfdx123/dsh-atelier/tree/main/packages/dsh-session-cleaner#readme",