@linxin666/dsh-remote-web-ui 0.4.2 → 0.4.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.
Files changed (79) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +12 -10
  3. package/README.zh.md +12 -10
  4. package/lib/client.js +278 -599
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +396 -913
  7. package/lib/types/client/RemoteEntry.d.ts.map +1 -1
  8. package/lib/types/client/RemoteEntry.js +8 -9
  9. package/lib/types/client/RemoteSettingsCard.d.ts.map +1 -1
  10. package/lib/types/client/RemoteSettingsCard.js +1 -1
  11. package/lib/types/client/index.d.ts +32 -3
  12. package/lib/types/client/index.d.ts.map +1 -1
  13. package/lib/types/client/index.js +51 -8
  14. package/lib/types/client/locales.d.ts +0 -84
  15. package/lib/types/client/locales.d.ts.map +1 -1
  16. package/lib/types/client/locales.js +0 -84
  17. package/lib/types/client/mobile-adapt.d.ts.map +1 -1
  18. package/lib/types/client/mobile-adapt.js +142 -8
  19. package/lib/types/client/settings-entry-form.d.ts +50 -0
  20. package/lib/types/client/settings-entry-form.d.ts.map +1 -0
  21. package/lib/types/client/settings-entry-form.js +98 -0
  22. package/lib/types/index.d.ts +99 -7
  23. package/lib/types/index.d.ts.map +1 -1
  24. package/lib/types/index.js +150 -149
  25. package/lib/types/lan-bind-plan.d.ts +14 -0
  26. package/lib/types/lan-bind-plan.d.ts.map +1 -1
  27. package/lib/types/lan-bind-plan.js +16 -0
  28. package/lib/types/lan-bind.d.ts +1 -1
  29. package/lib/types/lan-bind.js +1 -1
  30. package/lib/types/mount-once.d.ts +38 -7
  31. package/lib/types/mount-once.d.ts.map +1 -1
  32. package/lib/types/mount-once.js +96 -12
  33. package/lib/types/pairing.d.ts.map +1 -1
  34. package/lib/types/pairing.js +43 -0
  35. package/lib/types/remote-api.d.ts +13 -1
  36. package/lib/types/remote-api.d.ts.map +1 -1
  37. package/lib/types/remote-api.js +14 -1
  38. package/lib/types/tunnel.d.ts +60 -3
  39. package/lib/types/tunnel.d.ts.map +1 -1
  40. package/lib/types/tunnel.js +136 -3
  41. package/package.json +20 -20
  42. package/src/client/RemoteEntry.tsx +7 -9
  43. package/src/client/RemoteSettingsCard.tsx +0 -2
  44. package/src/client/index.ts +53 -9
  45. package/src/client/locales.ts +0 -84
  46. package/src/client/mobile-adapt.ts +144 -5
  47. package/src/client/remote.module.css +50 -200
  48. package/src/client/settings-entry-form.ts +142 -0
  49. package/src/index.ts +202 -164
  50. package/src/lan-bind-plan.ts +22 -0
  51. package/src/lan-bind.ts +1 -1
  52. package/src/mount-once.ts +107 -13
  53. package/src/pairing.ts +44 -1
  54. package/src/remote-api.ts +14 -1
  55. package/src/tunnel.ts +142 -3
  56. package/lib/types/client/UpdateEntry.d.ts +0 -14
  57. package/lib/types/client/UpdateEntry.d.ts.map +0 -1
  58. package/lib/types/client/UpdateEntry.js +0 -112
  59. package/lib/types/client/UpdatePanel.d.ts +0 -42
  60. package/lib/types/client/UpdatePanel.d.ts.map +0 -1
  61. package/lib/types/client/UpdatePanel.js +0 -101
  62. package/lib/types/client/update-api.d.ts +0 -29
  63. package/lib/types/client/update-api.d.ts.map +0 -1
  64. package/lib/types/client/update-api.js +0 -47
  65. package/lib/types/console-output.d.ts +0 -41
  66. package/lib/types/console-output.d.ts.map +0 -1
  67. package/lib/types/console-output.js +0 -89
  68. package/lib/types/update-routes.d.ts +0 -30
  69. package/lib/types/update-routes.d.ts.map +0 -1
  70. package/lib/types/update-routes.js +0 -47
  71. package/lib/types/update.d.ts +0 -282
  72. package/lib/types/update.d.ts.map +0 -1
  73. package/lib/types/update.js +0 -773
  74. package/src/client/UpdateEntry.tsx +0 -144
  75. package/src/client/UpdatePanel.tsx +0 -256
  76. package/src/client/update-api.ts +0 -49
  77. package/src/console-output.ts +0 -97
  78. package/src/update-routes.ts +0 -65
  79. package/src/update.ts +0 -915
@@ -1,101 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { IconCloseOutlineRegular, IconRefreshOutlineRegular } from '@deepseek-ai/dsh-client-ui-primitives';
3
- import css from "./remote.module.css";
4
- /** The anchor package name (aggregate first) for copy purposes. */
5
- function anchorName(status) {
6
- return status?.anchor ?? status?.packages[0]?.name;
7
- }
8
- /** The latest npm release of the anchor, for reference copy. */
9
- function anchorLatest(status) {
10
- return status?.packages[0]?.latest;
11
- }
12
- /**
13
- * Render the update panel.
14
- * @param props - copy, view state, and actions.
15
- * @returns the panel element tree.
16
- */
17
- export function UpdatePanel({ t, view, onClose, onRecheck, onStartUpdate }) {
18
- const status = view.kind === "result" || view.kind === "updating" ? view.status : undefined;
19
- const title = view.kind === "done" && view.result.ok ? t("update.done") : t("update.title");
20
- const subtitle = subtitleOf(t, view);
21
- return (_jsxs("div", { className: css.panel, role: "dialog", "aria-modal": "true", "aria-label": title, children: [_jsxs("div", { className: css.header, children: [_jsxs("div", { className: css.heading, children: [_jsx("h2", { className: css.title, children: title }), subtitle !== undefined && _jsx("p", { className: css.subtitle, children: subtitle })] }), _jsx("button", { type: "button", className: css.close, "aria-label": t("update.close"), onClick: onClose, children: _jsx(IconCloseOutlineRegular, {}) })] }), view.kind === "checking" && _jsx("p", { className: css.updateStatus, children: t("update.checking") }), view.kind === "result" && status !== undefined && _jsx(ResultBody, { t: t, status: status }), view.kind === "result" && status !== undefined && status.mode === "npm" && status.outdated && status.error === undefined && (_jsx("div", { className: css.updateActions, children: _jsx("button", { type: "button", className: css.updateRetry, onClick: () => onStartUpdate(status), children: t("update.start") }) })), view.kind === "updating" && status !== undefined && (_jsxs("div", { children: [_jsx("p", { className: css.updateStatus, children: t("update.updating", { name: anchorName(status) ?? "", version: anchorLatest(status) ?? "" }) }), _jsx("p", { className: css.updateDetail, children: t("update.cooldownNotice") }), _jsx(PackageSummary, { t: t, status: status })] })), view.kind === "done" && _jsx(DoneBody, { t: t, result: view.result }), view.kind === "error" && (_jsxs("div", { children: [_jsx("p", { className: css.updateError, children: view.message }), view.detail !== undefined && _jsx("pre", { className: css.updateOutput, children: view.detail })] })), (view.kind === "done" || view.kind === "error") && (_jsx("div", { className: css.updateActions, children: _jsxs("button", { type: "button", className: css.updateRetry, onClick: onRecheck, children: [_jsx(IconRefreshOutlineRegular, {}), " ", t("update.retry")] }) }))] }));
22
- }
23
- /** The subtitle copy per view state (absent on plain results). */
24
- function subtitleOf(t, view) {
25
- switch (view.kind) {
26
- case "checking":
27
- return t("update.checking");
28
- case "updating":
29
- return t("update.updatingTitle");
30
- case "result":
31
- return undefined;
32
- case "done":
33
- return view.result.ok ? t("update.doneDetail") : t("update.error");
34
- case "error":
35
- // The error body below carries the message; no subtitle duplication.
36
- return undefined;
37
- }
38
- }
39
- /** The checked result body: mode banner + version list. */
40
- function ResultBody({ t, status }) {
41
- const anchor = anchorName(status);
42
- const latest = anchorLatest(status);
43
- if (status.mode === "link") {
44
- return (_jsxs("div", { children: [_jsx("p", { className: css.updateStatus, children: t("update.linkMode") }), _jsx("p", { className: css.updateDetail, children: t("update.linkModeDetail", { version: latest ?? "-" }) })] }));
45
- }
46
- if (status.mode === "missing") {
47
- return (_jsxs("div", { children: [_jsx("p", { className: css.updateStatus, children: t("update.missing") }), _jsx("p", { className: css.updateDetail, children: t("update.missingDetail") })] }));
48
- }
49
- if (status.error === "registry-unreachable") {
50
- return (_jsxs("div", { children: [_jsx("p", { className: css.updateStatus, children: t("update.offline") }), _jsx("p", { className: css.updateDetail, children: t("update.offlineDetail") })] }));
51
- }
52
- if (status.outdated) {
53
- return (_jsxs("div", { children: [_jsx("p", { className: css.updateStatus, children: t("update.found") }), _jsx("p", { className: css.updateDetail, children: anchor !== undefined ? t("update.foundDetail", { name: anchor, version: latest ?? "" }) : "" }), _jsx("p", { className: css.updateDetail, children: t("update.cooldownNotice") }), _jsx(PackageSummary, { t: t, status: status })] }));
54
- }
55
- return (_jsxs("div", { children: [_jsx("p", { className: css.updateStatus, children: t("update.upToDate") }), anchor !== undefined && latest !== undefined && (_jsx("p", { className: css.updateDetail, children: t("update.upToDateDetail", { name: anchor, version: latest }) })), _jsx(PackageSummary, { t: t, status: status })] }));
56
- }
57
- /** Release-note summary when available; otherwise fall back to the package list. */
58
- function PackageSummary({ t, status }) {
59
- if (status.notes === undefined)
60
- return _jsx(PackageList, { status: status });
61
- return (_jsxs("div", { children: [_jsx(ReleaseNotes, { t: t, notes: status.notes }), _jsxs("details", { className: css.updateVersions, children: [_jsx("summary", { className: css.updateVersionsSummary, children: t("update.componentVersions") }), _jsx(PackageList, { status: status })] })] }));
62
- }
63
- /** Render GitHub Release sections as a compact three-group list. */
64
- function ReleaseNotes({ t, notes }) {
65
- const sections = [
66
- { key: 'features', title: t("update.releaseFeatures"), items: notes.features },
67
- { key: 'fixes', title: t("update.releaseFixes"), items: notes.fixes },
68
- { key: 'other', title: t("update.releaseOther"), items: notes.other },
69
- ].filter(section => section.items.length > 0);
70
- if (sections.length === 0)
71
- return _jsx("p", { className: css.updateDetail, children: t("update.releaseUnavailable") });
72
- return (_jsxs("div", { className: css.updateNotes, children: [_jsx("h3", { className: css.updateNotesTitle, children: t("update.releaseNotes", { version: notes.version }) }), sections.map(section => (_jsxs("section", { className: css.updateNoteSection, children: [_jsx("h4", { className: css.updateNoteHeading, children: section.title }), _jsx("ul", { className: css.updateNoteList, children: section.items.map((item, index) => (_jsx("li", { className: css.updateNoteItem, children: item }, index))) })] }, section.key)))] }));
73
- }
74
- /** The per-package current → latest comparison list. */
75
- function PackageList({ status }) {
76
- if (status.packages.length === 0)
77
- return null;
78
- return (_jsx("ul", { className: css.updateList, children: status.packages.map(packageStatus => (_jsxs("li", { className: css.updateListItem, children: [_jsx("span", { className: css.updateListName, children: packageStatus.name }), _jsxs("span", { className: css.updateListVersions, children: [packageStatus.current, packageStatus.latest !== undefined && packageStatus.latest !== packageStatus.current && (_jsxs(_Fragment, { children: [" \u2192 ", packageStatus.latest] }))] })] }, packageStatus.name))) }));
79
- }
80
- /** The outcome body: success + restart hint, or the translated failure. */
81
- function DoneBody({ t, result }) {
82
- if (result.ok) {
83
- // The title already reads "Update complete"; the body carries the details.
84
- return (_jsxs("div", { children: [_jsx("p", { className: css.updateDetail, children: t("update.doneDetail") }), _jsx("p", { className: css.updateDetail, children: t("update.restartHint") })] }));
85
- }
86
- const message = errorMessageOf(t, result);
87
- return (_jsxs("div", { children: [_jsx("p", { className: css.updateError, children: message }), result.output.trim() !== "" && _jsx("pre", { className: css.updateOutput, children: result.output.trim() })] }));
88
- }
89
- /** Translate a structured failure code; fall back to the raw message. */
90
- function errorMessageOf(t, result) {
91
- switch (result.errorCode) {
92
- case "pnpm-missing": return t("update.error.pnpmMissing");
93
- case "timeout": return t("update.error.timeout");
94
- case "not-found": return t("update.error.notFound");
95
- case "link": return t("update.error.link");
96
- case "pnpm-failed": return t("update.error.pnpmFailed", { code: String(result.exitCode ?? "?") });
97
- case "stale": return t("update.error.stale");
98
- case "verify-failed": return t("update.error.verifyFailed");
99
- default: return result.error ?? t("update.error.unknown");
100
- }
101
- }
@@ -1,29 +0,0 @@
1
- /**
2
- * Browser-side wire helpers for the /api/update surface. Plain fetch over
3
- * same-origin /api like the pairing client; the host half enforces the
4
- * loopback-only fence and owns the pnpm run.
5
- */
6
- import type { UpdateRunResult, UpdateStatus } from '../update.ts';
7
- /**
8
- * Error thrown when the update status probe fails: carries the HTTP status
9
- * so the panel can tell "the update route is not mounted" (404 — the host
10
- * process runs an older plugin build) apart from real network failures.
11
- */
12
- export declare class UpdateStatusError extends Error {
13
- /** HTTP status of the failed response (0 when the fetch never returned). */
14
- readonly status: number;
15
- constructor(status: number);
16
- }
17
- /**
18
- * Probe the update status: install mode, owning profile, and the
19
- * current-vs-latest comparison for every family package.
20
- * @returns the status snapshot.
21
- */
22
- export declare function fetchUpdateStatus(): Promise<UpdateStatus>;
23
- /**
24
- * Run the update (pnpm update in the owning profile). Blocks until pnpm
25
- * exits — the panel shows an in-flight state meanwhile.
26
- * @returns the run outcome.
27
- */
28
- export declare function runUpdate(): Promise<UpdateRunResult>;
29
- //# sourceMappingURL=update-api.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"update-api.d.ts","sourceRoot":"","sources":["../../../src/client/update-api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEjE;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;gBACX,MAAM,EAAE,MAAM;CAI3B;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,YAAY,CAAC,CAU/D;AAED;;;;GAIG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC,CAI1D"}
@@ -1,47 +0,0 @@
1
- /**
2
- * Browser-side wire helpers for the /api/update surface. Plain fetch over
3
- * same-origin /api like the pairing client; the host half enforces the
4
- * loopback-only fence and owns the pnpm run.
5
- */
6
- /**
7
- * Error thrown when the update status probe fails: carries the HTTP status
8
- * so the panel can tell "the update route is not mounted" (404 — the host
9
- * process runs an older plugin build) apart from real network failures.
10
- */
11
- export class UpdateStatusError extends Error {
12
- /** HTTP status of the failed response (0 when the fetch never returned). */
13
- status;
14
- constructor(status) {
15
- super('update status unavailable (HTTP ' + String(status) + ')');
16
- this.status = status;
17
- }
18
- }
19
- /**
20
- * Probe the update status: install mode, owning profile, and the
21
- * current-vs-latest comparison for every family package.
22
- * @returns the status snapshot.
23
- */
24
- export async function fetchUpdateStatus() {
25
- let response;
26
- try {
27
- response = await fetch('api/update/status');
28
- }
29
- catch {
30
- // Network-level failure: nothing came back at all.
31
- throw new UpdateStatusError(0);
32
- }
33
- if (!response.ok)
34
- throw new UpdateStatusError(response.status);
35
- return await response.json();
36
- }
37
- /**
38
- * Run the update (pnpm update in the owning profile). Blocks until pnpm
39
- * exits — the panel shows an in-flight state meanwhile.
40
- * @returns the run outcome.
41
- */
42
- export async function runUpdate() {
43
- const response = await fetch('api/update/run', { method: 'POST' });
44
- if (!response.ok)
45
- throw new Error('update run unavailable');
46
- return await response.json();
47
- }
@@ -1,41 +0,0 @@
1
- /**
2
- * Console-output capture shared by the family's Host halves.
3
- *
4
- * A child process's stdout/stderr are raw bytes, and on Windows a console
5
- * program writes the OEM code page (CP936/GBK on a zh-CN system), not UTF-8.
6
- * Decoding each chunk on its own corrupts the text twice over: the
7
- * encoding is guessed wrong, and a multi-byte character split across two reads
8
- * decodes into two replacement characters. This capture accumulates raw bytes
9
- * under a byte budget and decodes exactly once, at read time.
10
- */
11
- /** Bounded byte accumulator for one child process's interleaved stdout/stderr. */
12
- export interface OutputCapture {
13
- /** Append one raw chunk (the bytes are copied into the budget). */
14
- push(chunk: Uint8Array): void;
15
- /**
16
- * Decode everything captured so far. Idempotent, so a caller may read the
17
- * tail both after a failure branch and at settlement.
18
- */
19
- read(): string;
20
- }
21
- /**
22
- * Decode one console byte buffer. Strict UTF-8 wins whenever it is valid;
23
- * otherwise the bytes are not UTF-8 at all and the console wrote its own code
24
- * page, so the candidate that loses the least text is taken.
25
- * @param bytes - the captured bytes.
26
- * @returns the decoded text.
27
- */
28
- export declare function decodeConsoleBytes(bytes: Uint8Array): string;
29
- /**
30
- * Create a capture bounded to a byte budget. Overflow drops from the FRONT
31
- * (the tail is what carries a failure reason), and the cut never lands inside
32
- * a character: leading UTF-8 continuation bytes are dropped with it, and a
33
- * legacy code page's dangling lead byte — indistinguishable from a real byte
34
- * without knowing the encoding until the whole buffer is decoded — is removed
35
- * with the one replacement character it produced, so an over-long stream still
36
- * reads cleanly at the seam.
37
- * @param maxBytes - maximum retained bytes.
38
- * @returns the capture.
39
- */
40
- export declare function createOutputCapture(maxBytes: number): OutputCapture;
41
- //# sourceMappingURL=console-output.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"console-output.d.ts","sourceRoot":"","sources":["../../src/console-output.ts"],"names":[],"mappings":"AACA;;;;;;;;;GASG;AAEH,kFAAkF;AAClF,MAAM,WAAW,aAAa;IAC5B,mEAAmE;IACnE,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;IAC7B;;;OAGG;IACH,IAAI,IAAI,MAAM,CAAA;CACf;AAWD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CA2B5D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAiBnE"}
@@ -1,89 +0,0 @@
1
- // Generated by scripts/sync-shared.mjs from shared/host/console-output.ts. Do not edit this copy; edit the shared source and run "node scripts/sync-shared.mjs".
2
- /**
3
- * Console-output capture shared by the family's Host halves.
4
- *
5
- * A child process's stdout/stderr are raw bytes, and on Windows a console
6
- * program writes the OEM code page (CP936/GBK on a zh-CN system), not UTF-8.
7
- * Decoding each chunk on its own corrupts the text twice over: the
8
- * encoding is guessed wrong, and a multi-byte character split across two reads
9
- * decodes into two replacement characters. This capture accumulates raw bytes
10
- * under a byte budget and decodes exactly once, at read time.
11
- */
12
- /** Count the U+FFFD replacement characters one candidate decode produced. */
13
- function replacementCount(text) {
14
- let count = 0;
15
- for (const character of text) {
16
- if (character === '\uFFFD')
17
- count += 1;
18
- }
19
- return count;
20
- }
21
- /**
22
- * Decode one console byte buffer. Strict UTF-8 wins whenever it is valid;
23
- * otherwise the bytes are not UTF-8 at all and the console wrote its own code
24
- * page, so the candidate that loses the least text is taken.
25
- * @param bytes - the captured bytes.
26
- * @returns the decoded text.
27
- */
28
- export function decodeConsoleBytes(bytes) {
29
- try {
30
- return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
31
- }
32
- catch {
33
- // Not valid UTF-8. Prefer whichever candidate leaves the fewest
34
- // replacement characters so real UTF-8 text carrying one bad byte is not
35
- // rewritten wholesale as GBK gibberish; without the legacy code page
36
- // (small-ICU builds) the lenient UTF-8 pass is all that is left.
37
- let best;
38
- let bestLoss = Number.POSITIVE_INFINITY;
39
- for (const label of ['gbk', 'utf-8']) {
40
- let text;
41
- try {
42
- text = new TextDecoder(label).decode(bytes);
43
- }
44
- catch {
45
- continue;
46
- }
47
- const loss = replacementCount(text);
48
- if (loss < bestLoss) {
49
- best = text;
50
- bestLoss = loss;
51
- }
52
- }
53
- /* v8 ignore next 3 -- reachable only without the legacy code page AND without the lenient pass */
54
- if (best === undefined)
55
- return Buffer.from(bytes).toString('utf8');
56
- return best;
57
- }
58
- }
59
- /**
60
- * Create a capture bounded to a byte budget. Overflow drops from the FRONT
61
- * (the tail is what carries a failure reason), and the cut never lands inside
62
- * a character: leading UTF-8 continuation bytes are dropped with it, and a
63
- * legacy code page's dangling lead byte — indistinguishable from a real byte
64
- * without knowing the encoding until the whole buffer is decoded — is removed
65
- * with the one replacement character it produced, so an over-long stream still
66
- * reads cleanly at the seam.
67
- * @param maxBytes - maximum retained bytes.
68
- * @returns the capture.
69
- */
70
- export function createOutputCapture(maxBytes) {
71
- let buffer = Buffer.alloc(0);
72
- let trimmed = false;
73
- return {
74
- push(chunk) {
75
- buffer = buffer.length === 0 ? Buffer.from(chunk) : Buffer.concat([buffer, Buffer.from(chunk)]);
76
- if (buffer.length <= maxBytes)
77
- return;
78
- let start = buffer.length - maxBytes;
79
- while (start < buffer.length && (buffer[start] & 0xc0) === 0x80)
80
- start += 1;
81
- buffer = Buffer.from(buffer.subarray(start));
82
- trimmed = true;
83
- },
84
- read() {
85
- const text = decodeConsoleBytes(buffer);
86
- return trimmed && text.startsWith('\uFFFD') ? text.slice(1) : text;
87
- },
88
- };
89
- }
@@ -1,30 +0,0 @@
1
- /**
2
- * The /api/update route family: the status probe and the update run. Both
3
- * are loopback-only control surfaces — the run endpoint triggers a real
4
- * pnpm install inside the owning profile, so it must never be reachable
5
- * from a LAN/phone origin.
6
- */
7
- import type { IncomingMessage } from 'node:http';
8
- import type { WebRoute } from '@deepseek-ai/dsh-host-webserver';
9
- import type { UpdateRunResult, UpdateStatus } from './update.ts';
10
- /** Route paths (exact matches under /api). */
11
- export declare const UPDATE_PATHS: {
12
- readonly status: "/api/update/status";
13
- readonly run: "/api/update/run";
14
- };
15
- /** Route-family dependencies (test seam). */
16
- export interface UpdateRoutesDeps {
17
- /** Loopback-only fence: the control endpoints are host-surface only. */
18
- fence(request: IncomingMessage): boolean;
19
- /** Probe registry versions and report the comparison. */
20
- check(): Promise<UpdateStatus>;
21
- /** Run the pnpm update (resolves when pnpm exits). */
22
- run(): Promise<UpdateRunResult>;
23
- }
24
- /**
25
- * Build the /api/update route family.
26
- * @param deps - fence + check/run seams.
27
- * @returns the exact routes to register on webServer.
28
- */
29
- export declare function makeUpdateRoutes(deps: UpdateRoutesDeps): WebRoute[];
30
- //# sourceMappingURL=update-routes.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"update-routes.d.ts","sourceRoot":"","sources":["../../src/update-routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,WAAW,CAAA;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAGhE,8CAA8C;AAC9C,eAAO,MAAM,YAAY;;;CAGf,CAAA;AAEV,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAC/B,wEAAwE;IACxE,KAAK,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAA;IACxC,yDAAyD;IACzD,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC,CAAA;IAC9B,sDAAsD;IACtD,GAAG,IAAI,OAAO,CAAC,eAAe,CAAC,CAAA;CAChC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,GAAG,QAAQ,EAAE,CA+BnE"}
@@ -1,47 +0,0 @@
1
- /**
2
- * The /api/update route family: the status probe and the update run. Both
3
- * are loopback-only control surfaces — the run endpoint triggers a real
4
- * pnpm install inside the owning profile, so it must never be reachable
5
- * from a LAN/phone origin.
6
- */
7
- import { writeJson } from "./http.js";
8
- /** Route paths (exact matches under /api). */
9
- export const UPDATE_PATHS = {
10
- status: '/api/update/status',
11
- run: '/api/update/run',
12
- };
13
- /**
14
- * Build the /api/update route family.
15
- * @param deps - fence + check/run seams.
16
- * @returns the exact routes to register on webServer.
17
- */
18
- export function makeUpdateRoutes(deps) {
19
- const handleStatus = async (req, res) => {
20
- if (req.method !== 'GET') {
21
- res.writeHead(405, { 'content-type': 'text/plain; charset=utf-8' });
22
- res.end('method not allowed');
23
- return;
24
- }
25
- if (!deps.fence(req)) {
26
- writeJson(res, 403, { ok: false, code: "forbidden" });
27
- return;
28
- }
29
- writeJson(res, 200, await deps.check());
30
- };
31
- const handleRun = async (req, res) => {
32
- if (req.method !== 'POST') {
33
- res.writeHead(405, { 'content-type': 'text/plain; charset=utf-8' });
34
- res.end('method not allowed');
35
- return;
36
- }
37
- if (!deps.fence(req)) {
38
- writeJson(res, 403, { ok: false, code: "forbidden" });
39
- return;
40
- }
41
- writeJson(res, 200, await deps.run());
42
- };
43
- return [
44
- { kind: 'exact', path: UPDATE_PATHS.status, handler: handleStatus },
45
- { kind: 'exact', path: UPDATE_PATHS.run, handler: handleRun },
46
- ];
47
- }