dsh-links-panel 0.77.0 → 0.78.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -3254,10 +3254,84 @@ window.__ModuleLoader__.load({
3254
3254
  * whether to bypass the Host cache.
3255
3255
  * @returns {Promise<void>} completion of this pass.
3256
3256
  */
3257
+ // Opening a link in the built-in browser is the moment we know the user cares
3258
+ // about that site: fetch its declared icon once, cache it, and update the row.
3259
+ // Requests are chained so they never run in parallel.
3260
+ const warmChainRef = React.useRef(Promise.resolve())
3261
+ const warmFavicon = React.useCallback(
3262
+ (reference) => {
3263
+ const host = reference.host.replace(/^www\./, '')
3264
+ const domain = rootDomain(reference.host)
3265
+ if (faviconLibrary[host] !== undefined || faviconLibrary[domain] !== undefined) return
3266
+ const requestFavicon = async (iconUrl) => {
3267
+ try {
3268
+ const url = new URL('/dsh-links/favicon', document.baseURI)
3269
+ url.searchParams.set('url', iconUrl)
3270
+ const response = await fetch(url)
3271
+ if (!response || !response.ok) return ''
3272
+ const payload = await response.json()
3273
+ return payload && typeof payload.dataUrl === 'string' && payload.dataUrl.indexOf('data:') === 0 ? payload.dataUrl : ''
3274
+ } catch (error) {
3275
+ return ''
3276
+ }
3277
+ }
3278
+ const run = async () => {
3279
+ try {
3280
+ const base = new URL('/dsh-links/meta', document.baseURI)
3281
+ base.searchParams.set('urls', JSON.stringify([reference.url]))
3282
+ const response = await fetch(base)
3283
+ let iconUrl = ''
3284
+ if (response && response.ok) {
3285
+ const payload = await response.json()
3286
+ const page = payload && payload.pages && payload.pages[reference.url]
3287
+ iconUrl = page && typeof page.icon === 'string' ? page.icon : ''
3288
+ }
3289
+ if (iconUrl !== '') {
3290
+ const dataUrl = await requestFavicon(iconUrl)
3291
+ if (dataUrl !== '') {
3292
+ setFaviconLibrary((current) => (current[host] ? current : { ...current, [host]: dataUrl }))
3293
+ return
3294
+ }
3295
+ }
3296
+ const candidates = [
3297
+ `https://${host}/favicon.ico`,
3298
+ `https://${host}/apple-touch-icon.png`,
3299
+ `https://${host}/favicon.png`,
3300
+ `https://${host}/favicon.svg`,
3301
+ ]
3302
+ if (domain !== host) {
3303
+ candidates.push(
3304
+ `https://${domain}/favicon.ico`,
3305
+ `https://${domain}/apple-touch-icon.png`,
3306
+ `https://${domain}/favicon.png`,
3307
+ `https://${domain}/favicon.svg`,
3308
+ )
3309
+ }
3310
+ for (const candidate of candidates) {
3311
+ const dataUrl = await requestFavicon(candidate)
3312
+ if (dataUrl !== '') {
3313
+ setFaviconLibrary((current) => (current[host] ? current : { ...current, [host]: dataUrl }))
3314
+ return
3315
+ }
3316
+ }
3317
+ } catch (error) {
3318
+ /* the background queue will retry later */
3319
+ }
3320
+ }
3321
+ warmChainRef.current = warmChainRef.current.then(run, run)
3322
+ },
3323
+ [faviconLibrary],
3324
+ )
3325
+
3257
3326
  const openReference = React.useCallback(
3258
3327
  (reference, event) => {
3259
3328
  const external = !!(event && (event.metaKey || event.ctrlKey || event.altKey))
3260
3329
  if (!external && tab && tab.actions && typeof tab.actions.openTab === 'function') {
3330
+ try {
3331
+ warmFavicon(reference)
3332
+ } catch (error) {
3333
+ /* caching is best-effort */
3334
+ }
3261
3335
  try {
3262
3336
  tab.actions.openTab(BROWSER_KIND, { params: { url: reference.url } })
3263
3337
  return
@@ -3271,7 +3345,7 @@ window.__ModuleLoader__.load({
3271
3345
  window.location.href = reference.url
3272
3346
  }
3273
3347
  },
3274
- [tab],
3348
+ [tab, warmFavicon],
3275
3349
  )
3276
3350
 
3277
3351
  const copyList = React.useCallback(() => {
@@ -4028,7 +4102,7 @@ window.__ModuleLoader__.load({
4028
4102
  const inject = ['slots', 'sidebarRightTabs', 'sessions', 'locale']
4029
4103
 
4030
4104
  /** Build stamp shown in the footer, so a stale bundle is visible at a glance. */
4031
- const BUILD = 'v0.77.0'
4105
+ const BUILD = 'v0.78.0'
4032
4106
  /**
4033
4107
  * Translate one key and fill `{name}` placeholders.
4034
4108
  * @param {string} key - dictionary key.
package/lib/index.js CHANGED
@@ -37,7 +37,7 @@ function withOutboundLock(task) {
37
37
  }
38
38
 
39
39
  /** Host build stamp, echoed to the panel so a stale bundle is detectable. */
40
- export const BUILD = 'v0.77.0'
40
+ export const BUILD = 'v0.78.0'
41
41
  /**
42
42
  * The desktop browser reaches the network through the system proxy; the Host's own
43
43
  * Node requests bypass it. Detect that proxy so probes can use the same route.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-links-panel",
3
- "version": "0.77.0",
3
+ "version": "0.78.0",
4
4
  "description": "Reference links panel for DeepSeek Harness: collects every URL of a conversation into the right sidebar with pins, turn counts, metadata and favicon caching. DSH 右栏「应用链接」面板。",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -47,5 +47,14 @@
47
47
  ],
48
48
  "publishConfig": {
49
49
  "access": "public"
50
+ },
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "git+https://github.com/brickhu/dsh-plugins.git",
54
+ "directory": "references"
55
+ },
56
+ "homepage": "https://github.com/brickhu/dsh-plugins/tree/main/references#readme",
57
+ "bugs": {
58
+ "url": "https://github.com/brickhu/dsh-plugins/issues"
50
59
  }
51
60
  }