dsh-coding-sidebar 1.0.3 → 1.0.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 (89) hide show
  1. package/README.md +27 -42
  2. package/lib/client-editor.js +297 -4179
  3. package/lib/client-registry.js +639 -1341
  4. package/lib/client-terminal.js +176 -266
  5. package/lib/client.js +640 -1342
  6. package/lib/index.js +4 -110
  7. package/lib/types/bundle-route.d.ts +1 -1
  8. package/lib/types/client/SideCardSection.d.ts +3 -3
  9. package/lib/types/client/TextEditor.d.ts +20 -10
  10. package/lib/types/client/add-plugin-modal.d.ts +0 -4
  11. package/lib/types/client/api.d.ts +8 -11
  12. package/lib/types/client/builtins/index.d.ts +10 -10
  13. package/lib/types/client/chunk-loader.d.ts +7 -8
  14. package/lib/types/client/locales.d.ts +0 -26
  15. package/lib/types/client/native-avoid.d.ts +2 -0
  16. package/lib/types/client/plugins-shared.d.ts +6 -6
  17. package/lib/types/client/service.d.ts +13 -83
  18. package/lib/types/index.d.ts +1 -1
  19. package/lib/types/prefs-shared.d.ts +1 -24
  20. package/package.json +26 -29
  21. package/src/bundle-route.ts +1 -1
  22. package/src/client/EditorHost.tsx +52 -122
  23. package/src/client/SandboxStatusBar.tsx +12 -9
  24. package/src/client/SideCardSection.tsx +28 -81
  25. package/src/client/TextEditor.tsx +89 -266
  26. package/src/client/add-plugin-modal.tsx +16 -24
  27. package/src/client/api.ts +1 -25
  28. package/src/client/builtins/index.ts +10 -14
  29. package/src/client/chunk-loader.ts +7 -8
  30. package/src/client/index.tsx +12 -3
  31. package/src/client/locales-ar.ts +0 -6
  32. package/src/client/locales-de.ts +0 -6
  33. package/src/client/locales-fr.ts +0 -6
  34. package/src/client/locales-hi.ts +0 -6
  35. package/src/client/locales-id.ts +0 -6
  36. package/src/client/locales-it.ts +0 -6
  37. package/src/client/locales-ja.ts +0 -6
  38. package/src/client/locales-ko.ts +0 -6
  39. package/src/client/locales-nl.ts +0 -6
  40. package/src/client/locales-pl.ts +0 -6
  41. package/src/client/locales-pt.ts +0 -6
  42. package/src/client/locales-ru.ts +0 -6
  43. package/src/client/locales-sv.ts +0 -6
  44. package/src/client/locales-th.ts +0 -6
  45. package/src/client/locales-tr.ts +0 -6
  46. package/src/client/locales-vi.ts +0 -6
  47. package/src/client/locales-zh-HK.ts +0 -6
  48. package/src/client/locales-zh-MO.ts +0 -6
  49. package/src/client/locales-zh-TW.ts +0 -6
  50. package/src/client/locales.ts +0 -52
  51. package/src/client/native-avoid.ts +155 -0
  52. package/src/client/plugins-shared.ts +6 -6
  53. package/src/client/prefs.ts +0 -7
  54. package/src/client/service.ts +13 -150
  55. package/src/client/sidebar.module.css +1 -425
  56. package/src/config.ts +1 -4
  57. package/src/index.ts +7 -74
  58. package/src/prefs-shared.ts +1 -27
  59. package/lib/client-mermaid.js +0 -200776
  60. package/lib/types/client/MarkdownHtml.d.ts +0 -32
  61. package/lib/types/client/PdfView.d.ts +0 -6
  62. package/lib/types/client/builtins/viewers.d.ts +0 -3
  63. package/lib/types/client/chunks/mermaid.d.ts +0 -10
  64. package/lib/types/client/editor-load.d.ts +0 -66
  65. package/lib/types/client/image-types.d.ts +0 -3
  66. package/lib/types/client/markdown-html.d.ts +0 -96
  67. package/lib/types/client/markdown-images.d.ts +0 -45
  68. package/lib/types/client/md-toc.d.ts +0 -4
  69. package/lib/types/client/mermaid-blocks.d.ts +0 -47
  70. package/lib/types/client/mermaid-sanitize.d.ts +0 -2
  71. package/lib/types/client/mermaid.d.ts +0 -12
  72. package/lib/types/client/pdf-types.d.ts +0 -2
  73. package/lib/types/client/plugins-viewers.d.ts +0 -3
  74. package/lib/types/html-route.d.ts +0 -59
  75. package/src/client/MarkdownHtml.tsx +0 -296
  76. package/src/client/PdfView.tsx +0 -110
  77. package/src/client/builtins/viewers.tsx +0 -125
  78. package/src/client/chunks/mermaid.tsx +0 -10
  79. package/src/client/editor-load.ts +0 -92
  80. package/src/client/image-types.ts +0 -8
  81. package/src/client/markdown-html.ts +0 -331
  82. package/src/client/markdown-images.ts +0 -137
  83. package/src/client/md-toc.tsx +0 -127
  84. package/src/client/mermaid-blocks.ts +0 -110
  85. package/src/client/mermaid-sanitize.ts +0 -93
  86. package/src/client/mermaid.tsx +0 -406
  87. package/src/client/pdf-types.ts +0 -4
  88. package/src/client/plugins-viewers.ts +0 -30
  89. package/src/html-route.ts +0 -106
@@ -1,32 +0,0 @@
1
- import { type ReactNode } from 'react';
2
- import { type AnalyzedMarkdownHtml } from './markdown-html.ts';
3
- import { type MermaidMarkdownProps } from './mermaid-blocks.ts';
4
- import type { SessionScope } from './api.ts';
5
- /** The chunk-resident markdown renderer (mermaid lazy chunk), shared with the
6
- * legacy no-HTML preview path in TextEditor. */
7
- export declare const LazyMermaidMarkdown: (props: MermaidMarkdownProps) => ReactNode;
8
- /** Everything the sanitizers need to resolve local media + scope the route. */
9
- export interface MarkdownHtmlMedia {
10
- scope: SessionScope;
11
- path: string;
12
- origin: string;
13
- }
14
- interface MarkdownDocumentProps {
15
- info: AnalyzedMarkdownHtml;
16
- media: MarkdownHtmlMedia;
17
- codeLabels: {
18
- copyLabel: string;
19
- copiedLabel: string;
20
- };
21
- }
22
- /**
23
- * The split-document renderer: markdown runs render through MarkdownSegment,
24
- * HTML runs render as sanitized leaves, and unclosed block elements lower the
25
- * following runs into themselves until their close part pops the frame (the
26
- * renderer's frame stack persists across segments). Stray closes at the top
27
- * level render nothing (the sanitizer/parser would drop them anyway), and
28
- * frames still open at the end of the document are closed like a browser
29
- * parser would. Sanitization runs once per prepared change, in a memo.
30
- */
31
- export declare function MarkdownDocument({ info, media, codeLabels }: MarkdownDocumentProps): ReactNode;
32
- export {};
@@ -1,6 +0,0 @@
1
- import { type SessionScope } from './api.ts';
2
- export declare function PdfView(props: {
3
- scope: SessionScope;
4
- path: string;
5
- title: string;
6
- }): import("react").JSX.Element;
@@ -1,3 +0,0 @@
1
- import type { FileViewerDescriptor } from '../service.ts';
2
- /** The 6 built-in file viewer descriptors. */
3
- export declare function builtinViewers(): readonly FileViewerDescriptor[];
@@ -1,10 +0,0 @@
1
- /**
2
- * Lazy chunk entry: the mermaid diagram renderer for the markdown preview
3
- * (mermaid + its d3/dagre/cytoscape graph deps). Built as
4
- * lib/client-mermaid.js and registered under the `mermaid` global chunk
5
- * slot — fetched only when a previewed markdown file contains a mermaid
6
- * fence (see chunk-loader.ts and the mermaid markdown preview design doc).
7
- * Never import this module from the core bundle: it pulls mermaid into the
8
- * startup path.
9
- */
10
- export { MermaidMarkdown } from '../mermaid.tsx';
@@ -1,66 +0,0 @@
1
- /**
2
- * Pure editor-load planning: the decision logic the editor host needs to
3
- * turn a matched file viewer + a host fs.read result into a render action.
4
- * Kept dependency-free (no React, no fetch) so the strategy dispatch is
5
- * unit-testable and the wire contract (head bytes, binary flag) is pinned.
6
- *
7
- * The host flow this module drives:
8
- * 1. `matchFileViewer(path)` picks a viewer by extension/priority.
9
- * 2. `planFirstMatch` dispatches its fetchStrategy.
10
- * 3. An fsRead viewer fetches through the host; `planFsReadOutcome`
11
- * decides what to do with the result — including the head-based
12
- * re-match that lets a `detect` viewer claim a binary the extension
13
- * match could not see (the builtin NUL probe on `binary-download`).
14
- */
15
- import type { FileViewerDescriptor } from './service.ts';
16
- /** One host fs.read result (mirror of the wire; `head` present when binary). */
17
- export interface FsReadOutcome {
18
- binary: boolean;
19
- content: string;
20
- truncated: boolean;
21
- /** base64 of the first bytes (present on binary reads; sniffing material). */
22
- head?: string;
23
- }
24
- /** What the editor host should do next. */
25
- export type EditorLoadAction =
26
- /** No renderer: show the download UI. */
27
- {
28
- kind: 'binary';
29
- }
30
- /** Render `viewer`'s component with the carried payload. */
31
- | {
32
- kind: 'render';
33
- viewer: FileViewerDescriptor;
34
- content?: string;
35
- truncated?: boolean;
36
- mediaUrl?: string;
37
- customData?: unknown;
38
- }
39
- /** Fetch the file through the host (fsRead strategy). */
40
- | {
41
- kind: 'fetchFsRead';
42
- viewer: FileViewerDescriptor;
43
- }
44
- /** Call the viewer's load() and render with its return value. */
45
- | {
46
- kind: 'customLoad';
47
- viewer: FileViewerDescriptor;
48
- };
49
- /** Decode the host's base64 head bytes into the sniffing buffer. */
50
- export declare function decodeHead(headBase64: string): Uint8Array;
51
- /**
52
- * Dispatch one matched viewer's fetchStrategy. A missing viewer or a
53
- * `binary-download` strategy both mean "no client-side renderer" → the
54
- * download UI. `mediaUrlOf` builds the media URL for `mediaUrl`/`none`
55
- * strategies (pure, but scope-bound — injected by the host).
56
- */
57
- export declare function planFirstMatch(viewer: FileViewerDescriptor | undefined, mediaUrlOf: () => string): EditorLoadAction;
58
- /**
59
- * Decide what an fsRead result means for the editor.
60
- * - Text: the first match stands (content is valid for any fsRead viewer).
61
- * - Binary: the host head bytes enable a re-match — a `detect` viewer (e.g.
62
- * a plugin sniffing a binary format) may claim the file. `custom` viewers
63
- * load their own bytes; `mediaUrl`/`none` viewers render the media route;
64
- * an fsRead viewer or nothing cannot render binary → download UI.
65
- */
66
- export declare function planFsReadOutcome(viewer: FileViewerDescriptor, result: FsReadOutcome, rematch: (head: Uint8Array) => FileViewerDescriptor | undefined, mediaUrlOf: () => string): EditorLoadAction;
@@ -1,3 +0,0 @@
1
- /** Image extension dispatch, separate from React for unit testing. */
2
- export declare const IMAGE_EXTENSIONS: readonly string[];
3
- export declare function isImageExt(ext: string): boolean;
@@ -1,96 +0,0 @@
1
- /**
2
- * Raw-HTML block detection for the markdown preview. The shared `MarkdownText`
3
- * renders raw HTML as literal text (a chat-security stance), so a GitHub-style
4
- * README (`<div align="center">` badge walls, `<details>` collapsibles with
5
- * markdown inside, table cells full of inline tags) previews as source soup.
6
- * This module's pure splitter lifts those HTML runs OUT of the markdown stream
7
- * before rendering: markdown runs keep flowing through `MarkdownText` (shiki /
8
- * KaTeX / GFM intact, mermaid chunk path unchanged) while HTML runs render as
9
- * sanitized DOM (see markdown-html.tsx).
10
- *
11
- * Splitting follows CommonMark's shape closely enough for real-world READMEs:
12
- * a line outside code fences that starts with a block-level tag (type-6 list
13
- * below) or `<!--` opens an HTML run that extends to the next blank line
14
- * (comments end at the line containing `-->`). Inline-only tags (`<b>`, `<br>`,
15
- * `<a>`…) never open a run — they stay in the markdown stream and are handled
16
- * by the inline pass instead. Unclosed block tags (`<details>` … markdown …
17
- * `</details>`) are surfaced by {@link analyzeHtmlSegment} as ordered parts so
18
- * the renderer can nest the in-between markdown inside the open element, the
19
- * way GitHub's linear HTML output nests.
20
- */
21
- /** A run of raw HTML lines lifted out of the markdown stream. */
22
- export interface HtmlSegment {
23
- kind: 'html';
24
- text: string;
25
- }
26
- /** A run of markdown source (may contain non-mermaid fences, inline HTML…). */
27
- export interface MarkdownHtmlSegment {
28
- kind: 'markdown';
29
- text: string;
30
- }
31
- export type MdHtmlSegment = MarkdownHtmlSegment | HtmlSegment;
32
- /** The doc-wide analysis the preview consumes (all pure, unit-tested here). */
33
- export interface AnalyzedMarkdownHtml {
34
- /** The document split into markdown / html runs (empty input → []). */
35
- segments: MdHtmlSegment[];
36
- /** True when at least one html run was lifted out. */
37
- hasBlockHtml: boolean;
38
- /** True when the source contains any tag-like text (block OR inline). */
39
- hasInlineHtml: boolean;
40
- /** Every reference definition found in the markdown runs (`[label]: dest`
41
- * lines), joined — appended to each markdown run so `[text][id]` keeps
42
- * resolving across the lifted HTML runs (first-match wins makes the
43
- * appended copy inert inside runs that already define it). */
44
- referenceDefinitions: string;
45
- }
46
- /**
47
- * CommonMark HTML-block type-6 tag names (block-level elements), lowercased.
48
- * A line starting with one of these (open or close) outside a fence begins an
49
- * HTML run. `<summary>` is CommonMark-inline but intentionally included: it is
50
- * the idiomatic first child of a `<details>` run in GitHub-flavored READMEs.
51
- */
52
- export declare const HTML_BLOCK_TAGS: ReadonlySet<string>;
53
- /** One structural piece of a lifted HTML run, in document order. */
54
- export type HtmlPart = {
55
- kind: 'html';
56
- html: string;
57
- } | {
58
- kind: 'open';
59
- tag: string;
60
- attrs: string;
61
- } | {
62
- kind: 'close';
63
- tag: string;
64
- };
65
- /** The run's structure relative to the surrounding document nesting. */
66
- export interface HtmlSegmentShape {
67
- parts: HtmlPart[];
68
- }
69
- /**
70
- * Reduce a lifted HTML run to ordered parts: balanced spans become `html`
71
- * leaves, unclosed open tags become `open` (a wrapper the renderer lowers
72
- * following markdown runs into), unmatched closes become `close` (pops one
73
- * wrapper level). A mismatched close pops through the matching open — the
74
- * HTML parser's implicit-close behavior. Runs with no structural tags reduce
75
- * to a single `html` part.
76
- */
77
- export declare function analyzeHtmlSegment(source: string): HtmlSegmentShape;
78
- /**
79
- * Split markdown source into markdown / html runs (fence-aware: an HTML-looking
80
- * line inside any fenced code block is content, not a run start). Blank lines
81
- * terminate HTML runs and are dropped between segments (they carry no markdown
82
- * semantics the preview needs); everything else stays byte-identical.
83
- */
84
- export declare function splitHtmlBlocks(text: string): MdHtmlSegment[];
85
- /**
86
- * Collect the reference definitions of every markdown run (HTML runs cannot
87
- * define them), in document order, newline-joined for appending.
88
- */
89
- export declare function collectReferenceDefinitions(segments: readonly MdHtmlSegment[]): string;
90
- /**
91
- * The whole-document gate + split the preview consumes. `hasInlineHtml` is a
92
- * cheap source-level regex (code-fence content may false-positive; the inline
93
- * pass skips rendered code blocks anyway, so a false positive only costs the
94
- * enhanced render path, never a behavior change).
95
- */
96
- export declare function analyzeMarkdownHtml(text: string): AnalyzedMarkdownHtml;
@@ -1,45 +0,0 @@
1
- /**
2
- * Markdown-preview local-image resolution. The shared `MarkdownText` (from
3
- * @deepseek-ai/dsh-client-ui-primitives) only renders absolute http(s) image
4
- * URLs — relative links are disabled for chat security — so a local image in
5
- * a previewed `.md` (`![alt](./img.png)`, an absolute `/cwd/img.png`, or a
6
- * reference definition) would otherwise fall back to its alt text. This
7
- * dependency-free helper rewrites those destinations into absolute
8
- * `/sidebar/file` media URLs (prefixed with the GUI's own origin) so
9
- * `MarkdownText` accepts them; the host media route then serves the bytes,
10
- * still restricted to files under the session cwd.
11
- */
12
- import type { SessionScope } from './api.ts';
13
- /**
14
- * Rewrite markdown image destinations that point at local files into
15
- * absolute `/sidebar/file` media URLs. Relative destinations resolve against
16
- * the opened file's directory (normalizing `.`/`..` segments); absolute
17
- * local paths pass through. Remote (http/https/data/mailto) and `#`-anchor
18
- * destinations are left untouched for `MarkdownText`. Reference-style images
19
- * (`![x][id]` + `[id]: url`) are covered by rewriting their definition lines.
20
- *
21
- * Code spans (`` `...` ``) and fenced code blocks (``` ```...``` ```) are
22
- * masked before rewriting so documentation that demonstrates `![alt](./img.png)`
23
- * is not mutated into a `/sidebar/file` URL. Reference definitions are only
24
- * rewritten when their label is actually referenced by an image (collapsed
25
- * `[![][id]]`, full `![alt][id]`, or shortcut `![]` referencing the next
26
- * definition) — a plain link `[text][id]` must not have its destination
27
- * redirected to the media route.
28
- * @param text - The raw markdown source (inline + reference images).
29
- * @param scope - The session scope (sessionId + cwd) for the media route.
30
- * @param filePath - The absolute path of the opened `.md` file.
31
- * @param origin - The GUI's own origin (`window.location.origin`); injected
32
- * so the core rewrite stays pure and unit-testable.
33
- * @returns The markdown with local image destinations rewritten in place.
34
- */
35
- /**
36
- * Resolve one media destination against the session's media route: local
37
- * (relative or absolute) paths become absolute `/sidebar/file` URLs (prefixed
38
- * with the GUI's own origin so the shared MarkdownText http(s) allowlist
39
- * accepts them), while remote URLs, `#`-anchors and empty destinations are
40
- * returned untouched. Shared by the markdown image rewriter below and by the
41
- * preview's raw-HTML sanitizer (`markdown-html.tsx`, which meets the same
42
- * allowlist when rendering `<img src="./x.png">` inside HTML blocks).
43
- */
44
- export declare function resolveLocalMediaDest(dest: string, scope: SessionScope, filePath: string, origin: string): string;
45
- export declare function rewriteLocalImageUrls(text: string, scope: SessionScope, filePath: string, origin: string): string;
@@ -1,4 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- /** Fewer headings than this and the button stays hidden (no outline value). */
3
- export declare const TOC_MIN_HEADINGS = 3;
4
- export declare function MdToc(): ReactNode;
@@ -1,47 +0,0 @@
1
- /**
2
- * Markdown/mermaid fence detection for the markdown preview. The preview
3
- * renders the WHOLE document through one DSH `MarkdownText` pass (so
4
- * cross-fence semantics — reference-style links, footnotes, list
5
- * continuity — stay intact) and the mermaid lazy chunk then swaps the
6
- * rendered `language-mermaid` code blocks for diagrams. This module's pure
7
- * splitter exists to detect whether the source contains a mermaid fence at
8
- * all, so the mermaid chunk is only fetched when needed (unit-tested in
9
- * tests/mermaid-blocks.spec.ts).
10
- */
11
- /** One fenced mermaid diagram lifted out of the markdown source. */
12
- export interface MermaidBlock {
13
- kind: 'mermaid';
14
- /** The raw diagram source between the fences (info string stripped). */
15
- code: string;
16
- }
17
- /** A span of plain markdown source (may itself contain non-mermaid fences). */
18
- export interface MarkdownBlock {
19
- kind: 'markdown';
20
- text: string;
21
- }
22
- export type MdBlock = MarkdownBlock | MermaidBlock;
23
- /** Props of the chunk-resident `MermaidMarkdown` component (shared contract). */
24
- export interface MermaidMarkdownProps {
25
- /** The full markdown source (rendered in a single MarkdownText pass). */
26
- text: string;
27
- codeLabels: {
28
- copyLabel: string;
29
- copiedLabel: string;
30
- };
31
- }
32
- /** CommonMark opening fence: 0-3 spaces indent + a run of 3+ backticks or tildes. */
33
- export declare const OPEN_FENCE_RE: RegExp;
34
- /** A closing-fence line: 0-3 spaces indent + 3+ backticks/tildes + trailing spaces only. */
35
- export declare const CLOSE_FENCE_RE: RegExp;
36
- /** Parse the info string from the line tail after the fence run; null when invalid. */
37
- export declare function fenceInfo(rest: string, fence: string): string | null;
38
- /**
39
- * Split markdown source into md/mermaid blocks for detection: only fences
40
- * whose info string names mermaid are lifted; every other line stays in the
41
- * markdown stream untouched. CommonMark fence rules are honored — opening
42
- * fences of 3+ backticks OR tildes, and a closing fence must use the same
43
- * character with at least as many characters as the opening fence. An
44
- * unterminated mermaid fence swallows the rest of the file (the same
45
- * recovery CommonMark applies to open fences).
46
- */
47
- export declare function splitMermaidBlocks(text: string): MdBlock[];
@@ -1,2 +0,0 @@
1
- /** A parse failure keeps nothing of the input: the caller shows the error. */
2
- export declare function sanitizeSvg(svg: string): string;
@@ -1,12 +0,0 @@
1
- import type { MermaidMarkdownProps } from './mermaid-blocks.ts';
2
- /**
3
- * The chunk-resident markdown preview renderer: ONE MarkdownText pass over
4
- * the full source (cross-fence reference/footnote/list semantics intact),
5
- * then every rendered `language-mermaid` code block is swapped for a
6
- * `MermaidDiagram`. The `.md-code-block` host stays in the React tree —
7
- * only its children are replaced — so reconciliation never loses the host;
8
- * a block that stops being a mermaid fence gets its original children back.
9
- * Only mounted when the source contains at least one mermaid fence (see
10
- * TextEditor.tsx).
11
- */
12
- export declare function MermaidMarkdown({ text, codeLabels }: MermaidMarkdownProps): React.ReactNode;
@@ -1,2 +0,0 @@
1
- /** Pure PDF extension dispatch, separate from React for unit testing. */
2
- export declare function isPdfExt(ext: string): boolean;
@@ -1,3 +0,0 @@
1
- import type { PluginEntry } from './plugins-shared.ts';
2
- /** File-previewer plugins (alphabetical order). */
3
- export declare const builtinViewerPlugins: readonly PluginEntry[];
@@ -1,59 +0,0 @@
1
- /**
2
- * Pure URL vocabulary of the /sidebar/html route (HTML previewer).
3
- *
4
- * Why path-encoded parameters instead of a query string: the previewed
5
- * page resolves its relative assets (./style.css, img/x.png) against the
6
- * document URL, and the WHATWG URL algorithm DROPS the query of a
7
- * path-relative reference — `/sidebar/html?a=1&path=/a/b/` + `./style.css`
8
- * would lose the session scope and the route would reject the asset.
9
- * Encoding everything into the URL path keeps relative resolution inside
10
- * the same route with every request self-contained:
11
- *
12
- * /sidebar/html/<sessionId>/<absolute-path segments, encodeURIComponent'd>
13
- * /sidebar/html/S/Users/me/proj/index.html
14
- * + ./style.css → /sidebar/html/S/Users/me/proj/style.css
15
- * Windows: C:\Users\me\a.html → /sidebar/html/S/C%3A/Users/me/a.html
16
- * UNC (\\server\share\... or //server/share/...):
17
- * → /sidebar/html/S//server/share/proj/a.html ('//' right after the
18
- * sessionId marks the UNC prefix; the WHATWG URL keeps '//' intact so
19
- * relative assets still resolve inside the same route)
20
- *
21
- * The decoder rebuilds the marker as a forward-slash `//server/share/...`
22
- * path. That form is intentionally platform-neutral: `node:path` resolves it
23
- * to `\\server\share\...` on win32 and `/server/share/...` on POSIX, so the
24
- * host's existing requireAbsolute + isWithin fence needs no platform signal
25
- * (a leading `//` is a legal POSIX absolute path, so no data is lost on
26
- * either platform).
27
- *
28
- * This module is intentionally dependency-free (no node imports, no wire
29
- * helpers) so the client bundle can import `encodeHtmlUrl` without tripping
30
- * the build-time purity gate; the host converts decode failures into
31
- * SidebarError responses at the route boundary.
32
- */
33
- /** One decoded route reference. */
34
- export interface HtmlRouteRef {
35
- sessionId: string;
36
- /** Absolute file path (leading slash; Windows drives keep their colon). */
37
- path: string;
38
- }
39
- /** Decode outcome: the reference, or a client-error description. */
40
- export type HtmlDecodeResult = {
41
- ok: true;
42
- ref: HtmlRouteRef;
43
- } | {
44
- ok: false;
45
- status: 400 | 404;
46
- message: string;
47
- };
48
- /** The route prefix both encoders/decoders agree on. */
49
- export declare const HTML_ROUTE_PREFIX = "/sidebar/html/";
50
- /** Build the route URL for one absolute file path (client + tests). */
51
- export declare function encodeHtmlUrl(sessionId: string, path: string): string;
52
- /**
53
- * Decode a route pathname into the session + absolute file path. Rejects
54
- * a wrong prefix (404), an empty path, malformed percent encoding, and a
55
- * missing sessionId or file path (400). The caller still must bound the
56
- * decoded path with the workspace real-path guard — a decoded `..`
57
- * segment resolves outside the cwd and is refused there.
58
- */
59
- export declare function decodeHtmlUrl(pathname: string): HtmlDecodeResult;