dsh-calendar 0.13.2 → 0.13.4

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/CHANGELOG.md CHANGED
@@ -4,6 +4,15 @@
4
4
 
5
5
  [历史英文记录](docs/CHANGELOG.en.md)
6
6
 
7
+ ## 0.13.4 (2026-10-29)
8
+
9
+ - 同步仓库与 npm 的简明介绍、中英文 README 和反馈入口;本次为文档与包元数据更新。
10
+ - Sync npm descriptions and both README guides with the repository, including issue and pull-request links.
11
+
12
+ ## 0.13.3 (2026-10-27)
13
+
14
+ - 修复分批更新时的新旧更新控件混用:保留原页面、草稿与安装保护,空闲后接管旧控制器,兼容旧入口。
15
+
7
16
  ## 0.13.2 (2026-10-27)
8
17
 
9
18
  - 更新控件移至原有工作台或原生插件详情页底部;更新记录与选项原地展开,移除独立更新菜单与页面。
package/README.en.md CHANGED
@@ -4,16 +4,13 @@
4
4
 
5
5
  ![dsh-calendar whale girl plugin cover](https://raw.githubusercontent.com/STARDUSTLC666/dsh-calendar/main/assets/cover-whale-girl.png)
6
6
 
7
- View, create and reschedule CalDAV events from DSH.
7
+ Connect CalDAV in the DSH calendar workbench to view, create and reschedule events. Use month, week or agenda views, and preview ICS files before choosing what to import.
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/dsh-calendar)](https://www.npmjs.com/package/dsh-calendar) [![downloads](https://raw.githubusercontent.com/STARDUSTLC666/dsh-suite/npm-downloads/assets/dsh-calendar-downloads.svg)](https://www.npmjs.com/package/dsh-calendar)
10
10
 
11
11
  Feedback and contributions are welcome: report [issues](https://github.com/STARDUSTLC666/dsh-calendar/issues) or submit [pull requests](https://github.com/STARDUSTLC666/dsh-calendar/pulls).
12
12
 
13
-
14
- See the [0.10.4 validation record](docs/validation/0.10.4.md) for DSH `0.2.1-alpha.5` browser checks and the remaining limits.
15
-
16
- Open the new native sidebar workbench after updating and restarting DSH. Settings remains available. See the [workbench guide and validation boundaries](docs/WORKBENCH.md).
13
+ Open the workbench from the native DSH sidebar. See the [workbench guide](docs/WORKBENCH.md) for configuration and operating boundaries.
17
14
 
18
15
  ## What it does
19
16
 
package/README.md CHANGED
@@ -4,16 +4,13 @@
4
4
 
5
5
  ![dsh-calendar 鲸鱼娘插件封面](https://raw.githubusercontent.com/STARDUSTLC666/dsh-calendar/main/assets/cover-whale-girl.png)
6
6
 
7
- 连接 CalDAV 日历,在 DSH 中查看、创建和调整日程。
7
+ 在 DSH 日历工作台连接 CalDAV,查看、创建和调整日程。支持月历、周视图与议程,以及先预览再选择导入的 ICS 日历文件。
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/dsh-calendar)](https://www.npmjs.com/package/dsh-calendar) [![downloads](https://raw.githubusercontent.com/STARDUSTLC666/dsh-suite/npm-downloads/assets/dsh-calendar-downloads.svg)](https://www.npmjs.com/package/dsh-calendar)
10
10
 
11
11
  欢迎使用,遇到问题或有改进建议,请提交 [issues](https://github.com/STARDUSTLC666/dsh-calendar/issues) 和 [PR](https://github.com/STARDUSTLC666/dsh-calendar/pulls)。
12
12
 
13
-
14
- DSH `0.2.1-alpha.5` 的本轮检查与未验收范围见 [0.10.4 验收记录](docs/validation/0.10.4.md)。
15
-
16
- 更新并重启 DSH 后,可从原生侧栏打开新版工作台,原设置入口继续保留。详见[工作台说明与验收范围](docs/WORKBENCH.md)。
13
+ 从 DSH 原生侧栏打开工作台;配置与操作边界见[工作台说明](docs/WORKBENCH.md)。
17
14
 
18
15
  ## 功能
19
16
 
package/lib/client.js CHANGED
@@ -176,7 +176,7 @@ function __stardustUpdatesGuard(React, name, { dirty = false, busy = false, reta
176
176
  function __StardustPluginUpdatesFooter({ React, name }) {
177
177
  const [, render] = React.useState(0), pool = __stardustUpdatesGuards();
178
178
  React.useEffect(() => { const fn = () => render(value => value + 1); pool.viewListeners.add(fn); return () => pool.viewListeners.delete(fn); }, []);
179
- const client = [...pool.clients].find(client => client.has(name));
179
+ const client = [...pool.clients].find(client => typeof client.Footer === 'function' && client.has(name));
180
180
  if (!client) return null;
181
181
  return React.createElement(client.Footer, { name });
182
182
  }
@@ -238,14 +238,22 @@ function __stardustUpdatesJoin(host, React, require, participant) {
238
238
  if (typeof root.plugin !== 'function') return;
239
239
  let record = pools.get(root);
240
240
  if (!record) {
241
- record = { refs: new Map(), timer: null, version: participant.version, alive: true, hold: false };
241
+ record = { refs: new Map(), timer: null, version: participant.version, alive: true, hold: false, uiRevision: 2 };
242
242
  pools.set(root, record);
243
+ __stardustUpdatesActivate(record, pools, root, React, require);
244
+ } else if (record.uiRevision !== 2 && !record.migration) {
245
+ // The first loaded participant may still own a pre-footer client. Keep
246
+ // its references and draft guards, wait for any admitted install, then
247
+ // replace that one client fiber instead of running two window heartbeats.
243
248
  const shared = record;
244
- record.fiber = root.plugin({ name: 'stardustlc-plugin-updates-client', inject: ['slots', 'locale', 'remote', 'remote.pluginManager'], apply(ctx) {
245
- const client = __stardustUpdatesClient(ctx, React, require, shared);
246
- ctx.effect(() => () => { shared.alive = false; client.dispose(); if (pools.get(root) === shared) pools.delete(root); });
247
- } });
248
- Promise.resolve(record.fiber).catch(() => { shared.alive = false; if (pools.get(root) === shared) pools.delete(root); });
249
+ record.migration = Promise.resolve().then(async () => {
250
+ while (shared.alive && shared.hold) await new Promise(resolve => setTimeout(resolve, 500));
251
+ if (!shared.alive || !shared.refs.size) return;
252
+ await shared.fiber?.dispose?.();
253
+ if (!shared.refs.size) return;
254
+ shared.alive = true; shared.uiRevision = 2; pools.set(root, shared);
255
+ __stardustUpdatesActivate(shared, pools, root, React, require);
256
+ }).catch(() => { /* The original page remains usable if host disposal fails. */ });
249
257
  }
250
258
  clearTimeout(record.timer);
251
259
  const ref = {}; record.refs.set(ref, participant);
@@ -259,10 +267,17 @@ function __stardustUpdatesJoin(host, React, require, participant) {
259
267
  if (!record.refs.size) record.timer = setTimeout(stop, 1000);
260
268
  });
261
269
  }
270
+ function __stardustUpdatesActivate(shared, pools, root, React, require) {
271
+ shared.fiber = root.plugin({ name: 'stardustlc-plugin-updates-client', inject: ['slots', 'locale', 'remote', 'remote.pluginManager'], apply(ctx) {
272
+ const client = __stardustUpdatesClient(ctx, React, require, shared);
273
+ ctx.effect(() => () => { shared.alive = false; client.dispose(); if (pools.get(root) === shared) pools.delete(root); });
274
+ } });
275
+ Promise.resolve(shared.fiber).catch(() => { shared.alive = false; if (pools.get(root) === shared) pools.delete(root); });
276
+ }
262
277
  function __stardustUpdatesClient(ctx, React, require, shared) {
263
278
  const h = React.createElement, W = createWorkbenchUI(React), route = new URL('api/stardustlc/plugin-updates', document.baseURI);
264
279
  const { useState, useEffect } = React, id = crypto.randomUUID(), listeners = new Set(), pool = __stardustUpdatesGuards(), requests = new Set(), notified = new Set(), knownRows = new Map();
265
- let alive = true, registered = false, state = null, lastInteraction = Date.now(), inPoll = false, manualOperation = false;
280
+ let alive = true, registered = false, state = null, lastInteraction = Date.now(), inPoll = false, manualOperation = false, legacyHint = null;
266
281
  const language = () => String(ctx.locale?.getSnapshot?.().active || '').startsWith('en') ? 'en' : 'zh';
267
282
  const t = (zh, en) => language() === 'en' ? en : zh;
268
283
  const preferences = name => state?.preferences.packages[name] || { checkEnabled: true, autoInstall: false, deferredUntil: 0, ignoredVersion: null };
@@ -387,11 +402,11 @@ function __stardustUpdatesClient(ctx, React, require, shared) {
387
402
  function Reminder() {
388
403
  useSnapshot();
389
404
  const row = state?.rows.find(row => { const prefs = preferences(row.name); return row.available && !row.updating && !row.bundledBy && prefs.checkEnabled && prefs.deferredUntil <= Date.now() && prefs.ignoredVersion !== row.release.version && !notified.has(row.name + '@' + row.release.version); });
390
- if (!row) return null;
405
+ if (!row && !legacyHint) return null;
391
406
  let Toast; try { Toast = require('@deepseek-ai/dsh-client-ui-primitives').Toast; } catch { return null; }
392
407
  if (!Toast) return null;
393
- const key = row.name + '@' + row.release.version;
394
- return h(Toast, { key, text: (language() === 'en' ? row.labelEn : row.label) + t('有新版本,可在页面底部查看。', ' has an update. Review it at the bottom of its page.'), icon: h(W.Icon, { name: 'refresh', size: 18 }), holdMs: 7000, onDone: () => { notified.add(key); notify(); } });
408
+ const hint = legacyHint, key = hint ? 'legacy-' + hint : row.name + '@' + row.release.version;
409
+ return h(Toast, { key, text: hint ? hint + t(':请打开「插件」中的此插件详情页,在底部管理更新。', ': open its details in Plugins to manage updates at the bottom.') : (language() === 'en' ? row.labelEn : row.label) + t('有新版本,可在页面底部查看。', ' has an update. Review it at the bottom of its page.'), icon: h(W.Icon, { name: 'refresh', size: 18 }), holdMs: 7000, onDone: () => { if (hint) legacyHint = null; else notified.add(key); notify(); } });
395
410
  }
396
411
  function register() {
397
412
  if (!alive) return;
@@ -410,7 +425,7 @@ function __stardustUpdatesClient(ctx, React, require, shared) {
410
425
  finally { inPoll = false; }
411
426
  }
412
427
  const timer = setInterval(() => { void poll(); }, 15000), first = setTimeout(() => { void poll(); }, 100);
413
- const client = { t, Footer: Panel, has: name => registered && !!originalRow(name), row: rowFor, dispose() {
428
+ const client = { t, Footer: Panel, Button: W.Button, open(name) { const footer = [...document.querySelectorAll('[data-plugin-update-footer]')].find(node => node.getAttribute('data-plugin-update-footer') === name); if (footer) footer.scrollIntoView({ block: 'end', behavior: 'smooth' }); else { legacyHint = name; notify(); } }, has: name => registered && !!originalRow(name), row: rowFor, dispose() {
414
429
  close(); alive = false; clearTimeout(first); clearInterval(timer); pool.clients.delete(client);
415
430
  pool.listeners.delete(guardChanged); listeners.clear();
416
431
  for (const event of ['pointerdown', 'keydown', 'input']) document.removeEventListener(event, interaction, true);
@@ -3047,7 +3062,7 @@ calendarHostContext=ctx;W.register(ctx,{id:'dsh-calendar.workbench',label:()=>t(
3047
3062
  exports.apply = apply;
3048
3063
  exports.inject = inject;
3049
3064
  return module.exports;
3050
- } },{"name":"dsh-calendar","version":"0.1.0","hasWorkbench":true,"packageVersion":"0.13.2","label":"日历","labelEn":"Calendar","suiteComponent":true}));
3065
+ } },{"name":"dsh-calendar","version":"0.1.0","hasWorkbench":true,"packageVersion":"0.13.4","label":"日历","labelEn":"Calendar","suiteComponent":true}));
3051
3066
 
3052
3067
  })();
3053
3068
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-calendar",
3
- "version": "0.13.2",
4
- "description": "连接 CalDAV 日历,在 DSH 中查看、创建和调整日程。",
3
+ "version": "0.13.4",
4
+ "description": "DSH 日历工作台:CalDAV 日程管理、月 / 周 / 议程视图与 ICS 预览导入。欢迎提交 issues 和 PR。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
@@ -64,7 +64,7 @@
64
64
  "tsdav": "^2.3.1",
65
65
  "undici": "^8.11.2",
66
66
  "yaml": "^2.9.1",
67
- "@stardustlc/dsh-updates": "0.1.2"
67
+ "@stardustlc/dsh-updates": "0.1.3"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@types/node": "^24.0.0",