dsh-calendar 0.9.2 → 0.9.3
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 +7 -0
- package/README.en.md +5 -6
- package/README.md +4 -5
- package/lib/client.js +12 -8
- package/lib/web.js +5 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.3(2026-10-01)
|
|
4
|
+
|
|
5
|
+
- 修复 Google 切换到 iCloud、Nextcloud 或自建 CalDAV 时仍继承 OAuth 认证方式的问题;测试连接和保存使用新服务商的认证方式,原服务商的已有凭据继续保留。
|
|
6
|
+
- 连接摘要识别环境变量中的密码、client secret 和 refresh token,输入框仅提示“已配置”,不回传或复制环境密钥;纯空白值不算已配置。
|
|
7
|
+
- 修改连接草稿后清除过时的测试结论,避免把旧账号的失败或成功显示成新草稿的结果。
|
|
8
|
+
- 4 项新回归先复现后修复,178 项 Windows 测试通过;验证宿主为官方源码构建的 Harness 0.2.0-rc.2。
|
|
9
|
+
|
|
3
10
|
## 0.9.2(2026-09-29)
|
|
4
11
|
|
|
5
12
|
- 修复:OAuth 刷新失败改为**按错误码给出可操作指引**(授权失效 / 应用配置错误 / 权限范围不足 / 限流或服务端错误 / 需重新验证),并在诊断信息里带上 OAuth 标识与 HTTP 状态。
|
package/README.en.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# dsh-calendar
|
|
2
2
|
|
|
3
|
-
## 0.9.
|
|
3
|
+
## 0.9.3 update (2026-10-01)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Switching from Google to iCloud, Nextcloud or a custom server uses the new provider's authentication method for connection tests and saves. Environment credentials display a configured indicator without exposing their values. Editing the form clears the previous connection result.
|
|
6
6
|
|
|
7
|
-
Validation host: Harness `0.2.0-rc.
|
|
7
|
+
Validation host: Harness `0.2.0-rc.2` built from official sources (commit `639ed01539`) on 2026-10-01. All 178 Windows tests, the 18-plugin co-load and six calendar tool contracts pass. Browser checks use an isolated profile and a local CalDAV fixture: provider switching, connection testing, saving, event editing, month/week/agenda views and a 900px-wide window. Successful production Google/iCloud account flows still require separate validation.
|
|
8
8
|
|
|
9
9
|
   
|
|
10
10
|
|
|
@@ -14,9 +14,9 @@ DSH community plugin: read/write calendar events via CalDAV. Provides 5 calendar
|
|
|
14
14
|
|
|
15
15
|
## Compatibility
|
|
16
16
|
|
|
17
|
-
Version **0.9.0** (2026-09-23) follows the settings interface introduced in Harness **0.1.7**: the host removed `ctx.settings.register`, so configuration now lives in the entry's own `Config`. Every connection field is declared `volatile` (panel edits apply live, no restart) and the three credentials carry the `secret` role (never returned to the browser, only whether they are set). On the first start after an upgrade the plugin moves the retired `dsh-calendar` section of `settings.yaml` into the profile — filling only absent keys, once, with values already written in the profile winning. Hosts on 0.1.5 / 0.1.6 keep the previous namespace registration unchanged. The verified host baseline is official-source **0.
|
|
17
|
+
Version **0.9.0** (2026-09-23) follows the settings interface introduced in Harness **0.1.7**: the host removed `ctx.settings.register`, so configuration now lives in the entry's own `Config`. Every connection field is declared `volatile` (panel edits apply live, no restart) and the three credentials carry the `secret` role (never returned to the browser, only whether they are set). On the first start after an upgrade the plugin moves the retired `dsh-calendar` section of `settings.yaml` into the profile — filling only absent keys, once, with values already written in the profile winning. Hosts on 0.1.5 / 0.1.6 keep the previous namespace registration unchanged. The verified host baseline is official-source **0.2.0-rc.2**; live CalDAV operations still require their own account validation.
|
|
18
18
|
|
|
19
|
-
Version **0.8.4** (2026-09-23) supports the Web mount paths introduced in Harness **0.1.7**. The calendar panel keeps its requests under the application path when deployed through a reverse proxy, preserving normal settings and event operations.
|
|
19
|
+
Version **0.8.4** (2026-09-23) supports the Web mount paths introduced in Harness **0.1.7**. The calendar panel keeps its requests under the application path when deployed through a reverse proxy, preserving normal settings and event operations.
|
|
20
20
|
|
|
21
21
|
On 2026-09-10, npm `dsh-calendar@0.5.2` passed installation through this Harness release's official CLI and registration of all 6 tools. Host execution of `calendar_list` refreshed a real Google token (200), read via CalDAV REPORT (207) and rendered model-facing results. Only Google reads were tested; no writes were performed. This is a historical read-only verification record.
|
|
22
22
|
|
|
@@ -204,7 +204,6 @@ Input and output are uniformly ISO 8601. Timed events are output in UTC (e.g. `2
|
|
|
204
204
|
- Single-instance reads vs edit/delete: calendar_list honors RECURRENCE-ID overrides when expanding (an occurrence separately rescheduled/retitled is returned with the override time and fields, including when the original instant is EXDATE-excluded); calendar_update / calendar_delete still operate on the whole recurring series (by uid) and cannot modify or delete just one occurrence.
|
|
205
205
|
- OAuth credentials must be obtained beforehand: refresh-token authentication is supported, but there is no browser login UI / login CLI and runtime tokens are not written back to configuration.
|
|
206
206
|
- Timezone rules: events with TZID (named timezone) are output converted to UTC (Z); all-day boundaries, DST, and other complex timezone rules are not handled finely.
|
|
207
|
-
- No settings-page UI: this round is a node half-body; config only via cordis.patch.yml, no Web settings page.
|
|
208
207
|
- Calendar discovery: iCloud requires manually filling the full calendar collection URL; no principal auto-discovery or multi-calendar selection.
|
|
209
208
|
- Cancellation/timeout: tools use `timeoutMs` (60 seconds) and forward the host AbortSignal into token refresh and DAV network requests. Concurrent calls cancel independently.
|
|
210
209
|
|
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
# dsh-calendar
|
|
4
4
|
|
|
5
|
-
## 0.9.
|
|
5
|
+
## 0.9.3 更新(2026-10-01)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
从 Google 切换到 iCloud、Nextcloud 或自建服务时,连接测试与保存使用新服务商的认证方式。环境变量中的凭据会显示“已配置,留空不改”;修改表单后清除旧的连接测试结论。
|
|
8
8
|
|
|
9
|
-
验证宿主:官方源码构建的 Harness `0.2.0-rc.
|
|
9
|
+
验证宿主:官方源码构建的 Harness `0.2.0-rc.2`(commit `639ed01539`,2026-10-01)。178 项 Windows 插件测试、18 插件共同加载与 6 个日历工具的契约检查通过。浏览器使用隔离 profile 和本地 CalDAV 测试服务,完成服务商切换、连接测试、保存、日程编辑及月/周/议程视图检查,检查了 900px 宽的窗口。真实 Google/iCloud 等账号的业务验收仍需单独完成。
|
|
10
10
|
|
|
11
11
|
> **agent 从此会排期**:CalDAV 读写日历,重复日程自动展开。
|
|
12
12
|
|
|
@@ -19,7 +19,7 @@ DSH 社区插件:通过 CalDAV 读写日历事件。提供 5 个日历操作
|
|
|
19
19
|
|
|
20
20
|
## 兼容性
|
|
21
21
|
|
|
22
|
-
**0.9.0
|
|
22
|
+
**0.9.0** 起适配 Harness **0.1.7** 的设置接口:宿主移除了 `ctx.settings.register`,设置项改由 entry 的 `Config` 承载。连接字段全部声明为 `volatile`(面板改完即生效,无需重启),三个凭据按 `secret` 处理(不回传浏览器,只回「有没有」);升级后首次启动会把老 `settings.yaml` 里的 `dsh-calendar` 段搬进 profile(只补空缺、只搬一次,profile 里已写过的值优先)。0.1.5 / 0.1.6 宿主仍走原来的命名空间注册,行为不变。当前验证宿主为官方源码构建的 **0.2.0-rc.2**;真实 CalDAV 业务仍需有效账号单独验证。
|
|
23
23
|
|
|
24
24
|
**0.8.4(2026-09-23)**适配 Harness **0.1.7** 的 Web 子路径部署:日历面板的请求会跟随应用路径,修复经过反向代理访问时设置与事件操作失败的问题。真实 CalDAV 业务仍需有效账号单独验证。
|
|
25
25
|
|
|
@@ -230,7 +230,6 @@ Nextcloud / 自定义 Basic 服务:检查账号、密码或服务要求的应
|
|
|
230
230
|
- 单次实例的读取与改/删:calendar_list 展开时识别 RECURRENCE-ID 覆盖实例(单独改期/改标题的实例按覆盖后的时间与字段返回,被 EXDATE 排除原时间的覆盖实例仍会返回);calendar_update / calendar_delete 仍针对整个重复系列(按 uid 操作),无法只修改或删除某一次发生。
|
|
231
231
|
- OAuth 凭据需要事先取得:支持刷新令牌认证,但不提供浏览器登录 UI / 登录 CLI,也不把运行时令牌写回配置文件。
|
|
232
232
|
- 时区规则:带 TZID(命名时区)的事件输出会转成 UTC(Z);全天边界、夏令时等复杂时区规则不做精细化处理。
|
|
233
|
-
- 无设置页 UI:本轮为 node 半身,配置只走 cordis.patch.yml,不提供 Web 设置页。
|
|
234
233
|
- 日历发现:iCloud 需手动填完整日历集合 URL;不做 principal 自动发现与多日历选择。
|
|
235
234
|
- 取消/超时:工具使用 timeoutMs(60 秒),并向令牌刷新与 DAV 网络请求透传宿主 AbortSignal;并发调用独立取消。
|
|
236
235
|
|
package/lib/client.js
CHANGED
|
@@ -194,7 +194,7 @@ const UI = {
|
|
|
194
194
|
"conn.refreshToken": "refreshToken",
|
|
195
195
|
"conn.tokenUrl": "令牌地址(可留空)",
|
|
196
196
|
"conn.proxyUrl": "代理地址(可留空)",
|
|
197
|
-
"conn.keep": "
|
|
197
|
+
"conn.keep": "已配置,留空不改",
|
|
198
198
|
"conn.test": "测试连接",
|
|
199
199
|
"conn.testing": "正在连接…",
|
|
200
200
|
"conn.save": "保存并启用",
|
|
@@ -289,7 +289,7 @@ const UI = {
|
|
|
289
289
|
"conn.refreshToken": "refreshToken",
|
|
290
290
|
"conn.tokenUrl": "Token URL (optional)",
|
|
291
291
|
"conn.proxyUrl": "Proxy URL (optional)",
|
|
292
|
-
"conn.keep": "
|
|
292
|
+
"conn.keep": "configured — leave blank to keep",
|
|
293
293
|
"conn.test": "Test connection",
|
|
294
294
|
"conn.testing": "Connecting…",
|
|
295
295
|
"conn.save": "Save and enable",
|
|
@@ -1239,7 +1239,7 @@ function EventForm(props) {
|
|
|
1239
1239
|
const { draft, events, onCancel, onSubmit, busy, error } = props;
|
|
1240
1240
|
const [form, setForm] = useState(draft);
|
|
1241
1241
|
useEffect(() => { setForm(draft); }, [draft.uid, draft.date, draft.startTime, draft.summary]);
|
|
1242
|
-
const patch = (fields) => setForm((prev) => Object.assign({}, prev, fields));
|
|
1242
|
+
const patch = (fields) => setForm((prev) => Object.assign({}, prev, fields));
|
|
1243
1243
|
const isEdit = draft.uid !== undefined;
|
|
1244
1244
|
const pseudo = asPseudoEvent(form);
|
|
1245
1245
|
const conflicts = form.summary.trim() === "" ? [] : events.filter((event) => overlaps(event, pseudo) && event.uid !== form.uid);
|
|
@@ -1408,9 +1408,12 @@ function ConnectionForm(props) {
|
|
|
1408
1408
|
const { connection, onClose, onSaved } = props;
|
|
1409
1409
|
const [form, setForm] = useState(() => connectionDraftOf(connection));
|
|
1410
1410
|
const [busy, setBusy] = useState("");
|
|
1411
|
-
const [result, setResult] = useState(null);
|
|
1412
|
-
const maySave = connection === null || connection.settingsAvailable !== false;
|
|
1413
|
-
const patch = (fields) =>
|
|
1411
|
+
const [result, setResult] = useState(null);
|
|
1412
|
+
const maySave = connection === null || connection.settingsAvailable !== false;
|
|
1413
|
+
const patch = (fields) => {
|
|
1414
|
+
setForm((prev) => Object.assign({}, prev, fields));
|
|
1415
|
+
setResult(null);
|
|
1416
|
+
};
|
|
1414
1417
|
const visible = PROVIDER_FIELDS[form.provider] || [];
|
|
1415
1418
|
const payload = () => {
|
|
1416
1419
|
const out = {};
|
|
@@ -1421,8 +1424,9 @@ function ConnectionForm(props) {
|
|
|
1421
1424
|
if (SECRET_FIELDS.indexOf(key) !== -1 && value.trim() === "") continue;
|
|
1422
1425
|
out[key] = value.trim();
|
|
1423
1426
|
}
|
|
1424
|
-
if (form.provider !== "") out.provider = form.provider;
|
|
1425
|
-
if (form.provider === "google") out.authMethod = "oauth";
|
|
1427
|
+
if (form.provider !== "") out.provider = form.provider;
|
|
1428
|
+
if (form.provider === "google") out.authMethod = "oauth";
|
|
1429
|
+
else if (form.provider !== "" && connection && form.provider !== connection.provider) out.authMethod = "basic";
|
|
1426
1430
|
return out;
|
|
1427
1431
|
};
|
|
1428
1432
|
const test = async () => {
|
package/lib/web.js
CHANGED
|
@@ -248,6 +248,8 @@ export class CalendarSettingsBackend {
|
|
|
248
248
|
const resolved = effective[key];
|
|
249
249
|
return typeof resolved === 'string' ? resolved : '';
|
|
250
250
|
};
|
|
251
|
+
const env = this.options.env ?? process.env;
|
|
252
|
+
const hasCredential = (key, envKey) => text(key).trim() !== '' || (typeof env[envKey] === 'string' && env[envKey].trim() !== '');
|
|
251
253
|
return {
|
|
252
254
|
configured,
|
|
253
255
|
...(reason !== undefined ? { reason } : {}),
|
|
@@ -266,9 +268,9 @@ export class CalendarSettingsBackend {
|
|
|
266
268
|
clientId: text('clientId'),
|
|
267
269
|
tokenUrl: text('tokenUrl'),
|
|
268
270
|
proxyUrl: text('proxyUrl'),
|
|
269
|
-
hasPassword:
|
|
270
|
-
hasClientSecret:
|
|
271
|
-
hasRefreshToken:
|
|
271
|
+
hasPassword: hasCredential('password', 'DSH_CALENDAR_PASSWORD'),
|
|
272
|
+
hasClientSecret: hasCredential('clientSecret', 'DSH_CALENDAR_CLIENT_SECRET'),
|
|
273
|
+
hasRefreshToken: hasCredential('refreshToken', 'DSH_CALENDAR_REFRESH_TOKEN'),
|
|
272
274
|
};
|
|
273
275
|
}
|
|
274
276
|
/** 兼容旧动作名:status 就是连接摘要。 */
|