dsh-update-status 0.1.0 → 0.1.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/lib/index.js CHANGED
@@ -8,12 +8,20 @@ import { dirname, join, normalize, sep } from "node:path";
8
8
  *
9
9
  * The static package uses the authenticated Connection RPC channel because
10
10
  * `harness.handle` / `host.call` are dynamic-Cordis-only closure APIs in DSH
11
- * 0.1.2-rc.1. The endpoint vocabulary remains deliberately small and private
11
+ * 0.1.5-rc.1. The endpoint vocabulary remains deliberately small and private
12
12
  * to this plugin channel.
13
13
  */
14
14
  const PLUGIN_ID = "dsh-update-status";
15
15
  const PACKAGE_NAME = "@deepseek-ai/dsh";
16
- const UPDATE_STATUS_CHANNEL = "/dsh-update-status";
16
+ /** Shared Connection RPC channel. Custom prefixes 405 on the SPA fallback. */
17
+ const UPDATE_STATUS_CHANNEL = "/api";
18
+ /**
19
+ * DSH releases this bundle has actually been verified against. The same list is
20
+ * declared in package.json's `dsh.compatibility.dshReleases`, and every other
21
+ * release the registry reports stays `unverified` — the plugin never claims a
22
+ * compatibility nobody checked.
23
+ */
24
+ const VERIFIED_DSH_VERSIONS = ["0.1.5-rc.1", "0.1.6-alpha.1"];
17
25
  const RELEASE_CHANNELS = [
18
26
  "latest",
19
27
  "next",
@@ -23,8 +31,8 @@ function isCacheTtlMinutes(value) {
23
31
  return typeof value === "number" && Number.isInteger(value) && value >= 30 && value <= 1440;
24
32
  }
25
33
  const UPDATE_ENDPOINTS = {
26
- getStatus: "get-status",
27
- checkUpdate: "check-update"
34
+ getStatus: "dsh-update-status.get-status",
35
+ checkUpdate: "dsh-update-status.check-update"
28
36
  };
29
37
  function isReleaseChannel(value) {
30
38
  return value === "latest" || value === "next" || value === "alpha";
@@ -176,6 +184,32 @@ function requestOf(value) {
176
184
  ...record.cacheTtlMinutes === void 0 ? {} : { cacheTtlMinutes: record.cacheTtlMinutes }
177
185
  };
178
186
  }
187
+ function jsonResponse(rpcId, result) {
188
+ return Response.json({
189
+ type: "server-response",
190
+ rpcId,
191
+ result
192
+ });
193
+ }
194
+ /** Envelope-compatible Fetch adapter for one namespaced `/api` endpoint. */
195
+ async function dispatchUpdateStatusFetch(endpoint, handler, request) {
196
+ if (request.method !== "POST") return new Response("not found", { status: 404 });
197
+ if (request.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() !== "application/json") return new Response("content type must be application/json", { status: 415 });
198
+ let body;
199
+ try {
200
+ body = await request.json();
201
+ } catch {
202
+ return new Response("body is not JSON", { status: 400 });
203
+ }
204
+ const record = body !== null && typeof body === "object" && !Array.isArray(body) ? body : {};
205
+ const rpcId = typeof record.rpcId === "string" ? record.rpcId : "invalid-request";
206
+ if (record.type !== "client-request" || record.method !== endpoint) return jsonResponse(rpcId, failure("gateway/bad-request", "invalid client-request message"));
207
+ try {
208
+ return jsonResponse(rpcId, await handler(endpoint, record.payload, request.signal));
209
+ } catch (error) {
210
+ return new Response(`handler failure: ${String(error)}`, { status: 500 });
211
+ }
212
+ }
179
213
  /** Endpoint dispatcher, exported to allow exact JSON-shape tests without a Host. */
180
214
  function createUpdateStatusRpcHandler(service) {
181
215
  return async (endpoint, payload) => {
@@ -204,21 +238,27 @@ function createUpdateStatusRpcHandler(service) {
204
238
  }
205
239
  /**
206
240
  * Static packages do not receive dynamic Cordis's `harness.handle` closure.
207
- * This registration uses DSH's existing authenticated Connection RPC transport
208
- * and is removed with the plugin fiber.
241
+ * DSH 0.1.5 serves browser unary RPC only on the shared `/api` channel; a
242
+ * private prefix such as `/dsh-update-status` is answered by the SPA fallback
243
+ * with HTTP 405. Exact Fetch routes on `/api/<endpoint>` are dispatched by
244
+ * Connection before the Typert interceptor and do not need a new HTTP prefix.
209
245
  */
210
246
  function installUpdateStatusRpc(ctx, service) {
211
247
  const handler = createUpdateStatusRpcHandler(service);
212
- ctx.inject(["connection"], (connectionCtx) => {
213
- const connection = connectionCtx.get("connection");
214
- const handle = typeof connection?.rpc?.handle === "function" ? connection.rpc.handle.bind(connection.rpc) : void 0;
215
- if (handle === void 0) return;
216
- connectionCtx.effect(() => {
217
- const unregister = handle(UPDATE_STATUS_CHANNEL, handler);
218
- return () => {
219
- Promise.resolve(unregister()).catch(() => {});
220
- };
221
- }, "dsh-update-status: authenticated RPC channel");
248
+ ctx.inject(["connection"], (owned) => {
249
+ const connection = owned.connection;
250
+ const register = typeof connection.fetch?.register === "function" ? connection.fetch.register.bind(connection.fetch) : void 0;
251
+ if (register === void 0) return;
252
+ try {
253
+ for (const endpoint of Object.values(UPDATE_ENDPOINTS)) register({
254
+ path: `${UPDATE_STATUS_CHANNEL}/${endpoint}`,
255
+ methods: ["POST"],
256
+ requestBody: "buffered",
257
+ fetch: (request) => dispatchUpdateStatusFetch(endpoint, handler, request)
258
+ });
259
+ } catch (error) {
260
+ console.error("[dsh-update-status] authenticated RPC route registration failed:", error);
261
+ }
222
262
  });
223
263
  }
224
264
  //#endregion
@@ -321,7 +361,7 @@ function dateOrNull(value) {
321
361
  return Number.isFinite(time) ? new Date(time).toISOString() : null;
322
362
  }
323
363
  function compatibilityOf(version) {
324
- return version === "0.1.2-rc.1" ? "verified" : "unverified";
364
+ return version !== null && VERIFIED_DSH_VERSIONS.includes(version) ? "verified" : "unverified";
325
365
  }
326
366
  function registryReleaseOf(value) {
327
367
  if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("npm registry returned an invalid document");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-update-status",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "description": "Read-only DeepSeek Harness Web plugin that shows the running DSH version, discovers latest/next/alpha releases, warns about compatibility, and generates copy-only upgrade commands.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -29,15 +29,6 @@
29
29
  "engines": {
30
30
  "node": ">=20"
31
31
  },
32
- "scripts": {
33
- "build": "tsdown",
34
- "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.tests.json",
35
- "test": "pnpm run typecheck && vitest run",
36
- "test:unit": "vitest run",
37
- "clean": "rm -rf lib coverage",
38
- "prepack": "pnpm run build",
39
- "verify": "pnpm run test && pnpm run build && pnpm pack --dry-run"
40
- },
41
32
  "repository": {
42
33
  "type": "git",
43
34
  "url": "git+https://github.com/idoall/dsh-update-status.git"
@@ -59,14 +50,14 @@
59
50
  "@deepseek-ai/dsh-client-connection",
60
51
  "@deepseek-ai/dsh-client-ui-layout",
61
52
  "@deepseek-ai/dsh-client-ui-sidebar",
62
- "@deepseek-ai/dsh-client-ui-slots",
63
53
  "@deepseek-ai/dsh-client-ui-settings",
64
54
  "@deepseek-ai/dsh-client-ui-settings-general"
65
55
  ]
66
56
  },
67
57
  "compatibility": {
68
58
  "dshReleases": {
69
- "0.1.2-rc.1": "compatible"
59
+ "0.1.5-rc.1": "compatible",
60
+ "0.1.6-alpha.1": "compatible"
70
61
  }
71
62
  }
72
63
  },
@@ -84,11 +75,11 @@
84
75
  },
85
76
  "peerDependencies": {
86
77
  "@deepseek-ai/cordis": "^4.0.2",
87
- "@deepseek-ai/dsh-settings": "0.1.2-rc.1"
78
+ "@deepseek-ai/dsh-settings": ">=0.1.5-rc.1"
88
79
  },
89
80
  "devDependencies": {
90
81
  "@deepseek-ai/cordis": "^4.0.2",
91
- "@deepseek-ai/dsh-settings": "0.1.2-rc.1",
82
+ "@deepseek-ai/dsh-settings": "0.1.5-rc.1",
92
83
  "@deepseek-ai/schemastery": "^3.18.2",
93
84
  "@types/node": "^26.2.0",
94
85
  "@types/react": "^18.3.31",
@@ -97,5 +88,12 @@
97
88
  "typescript": "^7.0.2",
98
89
  "vitest": "^4.1.11"
99
90
  },
100
- "packageManager": "pnpm@10.33.1"
101
- }
91
+ "scripts": {
92
+ "build": "tsdown",
93
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.tests.json",
94
+ "test": "pnpm run typecheck && vitest run",
95
+ "test:unit": "vitest run",
96
+ "clean": "rm -rf lib coverage",
97
+ "verify": "pnpm run test && pnpm run build && pnpm pack --dry-run"
98
+ }
99
+ }