hmr-serve 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/README.md +45 -14
- package/bin/hmr-serve.js +6 -1
- package/dist/cli/banner.d.ts +2 -0
- package/dist/cli/banner.js +59 -0
- package/dist/cli/banner.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +10 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/server/createServer.d.ts +5 -0
- package/dist/server/createServer.js +10 -1
- package/dist/server/createServer.js.map +1 -1
- package/dist/server/fs.d.ts +9 -4
- package/dist/server/fs.js +41 -7
- package/dist/server/fs.js.map +1 -1
- package/dist/server/index/watcher.d.ts +3 -0
- package/dist/server/index/watcher.js +10 -1
- package/dist/server/index/watcher.js.map +1 -1
- package/dist/server/mount.d.ts +11 -0
- package/dist/server/mount.js +19 -0
- package/dist/server/mount.js.map +1 -0
- package/dist/server/noNav.d.ts +22 -0
- package/dist/server/noNav.js +202 -0
- package/dist/server/noNav.js.map +1 -0
- package/dist/server/plugin.d.ts +6 -0
- package/dist/server/plugin.js +211 -20
- package/dist/server/plugin.js.map +1 -1
- package/dist/server/renderers/csv.d.ts +4 -0
- package/dist/server/renderers/csv.js +85 -0
- package/dist/server/renderers/csv.js.map +1 -0
- package/dist/server/renderers/html.js +1 -0
- package/dist/server/renderers/html.js.map +1 -1
- package/dist/server/renderers/markdown.js +24 -1
- package/dist/server/renderers/markdown.js.map +1 -1
- package/dist/server/renderers/media.d.ts +3 -0
- package/dist/server/renderers/media.js +19 -0
- package/dist/server/renderers/media.js.map +1 -0
- package/dist/server/renderers/registry.d.ts +8 -0
- package/dist/server/renderers/registry.js +39 -2
- package/dist/server/renderers/registry.js.map +1 -1
- package/dist/server/renderers/source.d.ts +5 -3
- package/dist/server/renderers/source.js +45 -15
- package/dist/server/renderers/source.js.map +1 -1
- package/dist/server/renderers/types.d.ts +3 -1
- package/dist/shared/types.d.ts +20 -8
- package/dist/shared/types.js +17 -3
- package/dist/shared/types.js.map +1 -1
- package/package.json +19 -8
- package/src/client/App.vue +193 -31
- package/src/client/api.ts +18 -1
- package/src/client/components/ContentPane.vue +337 -26
- package/src/client/components/FileIcon.vue +81 -0
- package/src/client/components/FileTree.vue +85 -0
- package/src/client/components/SettingsMenu.vue +109 -0
- package/src/client/components/TreeNode.vue +25 -8
- package/src/client/env.d.ts +6 -0
- package/src/client/favicon.svg +15 -0
- package/src/client/index.html +1 -0
- package/src/client/main.ts +1 -0
- package/src/client/router.ts +40 -0
- package/src/client/settings.ts +143 -0
- package/src/client/styles.css +423 -31
- package/src/shared/types.ts +38 -9
package/README.md
CHANGED
|
@@ -6,34 +6,57 @@
|
|
|
6
6
|
|
|
7
7
|
Point `hmr-serve` at any folder and review it live in the browser: a VSCode-style
|
|
8
8
|
file tree on the left, a content pane on the right, and **instant updates as files
|
|
9
|
-
change on disk** — powered by Vite's real dev server and
|
|
9
|
+
change on disk** — powered by Vite's real dev server and
|
|
10
|
+
[HMR](https://vitejs.dev/guide/features.html#hot-module-replacement) client, not a
|
|
10
11
|
hand-rolled watcher/websocket.
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
**HMR** (Hot Module Replacement) is the mechanism that pushes file changes into the
|
|
14
|
+
browser over a WebSocket so the page updates without a full refresh. This project
|
|
15
|
+
uses [Vite's HMR](https://vitejs.dev/guide/features.html#hot-module-replacement)
|
|
16
|
+
rather than inventing its own.
|
|
17
|
+
|
|
18
|
+
> **Tip:** Helpful for reviewing AI agent output (markdown/HTML docs) as it iterates.
|
|
19
|
+
|
|
20
|
+
## Quickstart
|
|
13
21
|
|
|
14
22
|
```bash
|
|
15
23
|
npx hmr-serve ./some-folder
|
|
16
24
|
# → opens http://localhost:5183 with a live tree + content pane
|
|
17
25
|
```
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
Or run it like **[serve](https://www.npmjs.com/package/serve)** without the nav — serves directory
|
|
28
|
+
listing or `index.html` if present, plus rendered Markdown, CSV/TSV, all with HMR:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx hmr-serve ./some-folder --no-nav
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
For a permanent setup, install globally and use the short `hmr` command:
|
|
20
35
|
|
|
21
36
|
```bash
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
37
|
+
npm install -g hmr-serve
|
|
38
|
+
hmr ./some-folder
|
|
39
|
+
hmr ./some-folder --no-nav
|
|
25
40
|
```
|
|
26
41
|
|
|
27
42
|
CLI:
|
|
28
43
|
|
|
29
44
|
```
|
|
30
|
-
hmr
|
|
45
|
+
hmr [dir] Folder to serve (default: current directory)
|
|
31
46
|
--port <port> Port to listen on (default: 5183)
|
|
32
47
|
--open Open the browser on start
|
|
48
|
+
--no-nav Like serve, without the tree UI
|
|
33
49
|
```
|
|
34
50
|
|
|
35
|
-
|
|
36
|
-
|
|
51
|
+
**Default (nav) mode** shows a VS Code-style file tree and content pane. Supported
|
|
52
|
+
types: **Markdown** (rendered), **HTML** (sandboxed iframe), **code** (`.css`,
|
|
53
|
+
`.js`, `.ts`, `.json`, … syntax-highlighted), **text**, **CSV/TSV** (tables),
|
|
54
|
+
**images**, and **video**. A gear menu toggles which categories show in the tree,
|
|
55
|
+
plus an **Other files** option. Choices are remembered per folder (localStorage).
|
|
56
|
+
|
|
57
|
+
**`--no-nav`** skips the tree UI: if the folder has `index.html` (or `index.htm`),
|
|
58
|
+
that is the root page; otherwise you get a directory listing. Markdown, CSV, and
|
|
59
|
+
TSV are still rendered to HTML, and edits hot-reload via Vite.
|
|
37
60
|
|
|
38
61
|
## Architecture
|
|
39
62
|
|
|
@@ -46,16 +69,24 @@ Supported file types at launch: `.md` (rendered), `.html` (sandboxed iframe),
|
|
|
46
69
|
server over HTTP and Vite's HMR socket. No File System Access API, no
|
|
47
70
|
Chromium-only APIs — works in Safari and Firefox.
|
|
48
71
|
4. **Extensible renderer registry.** `.md` → `markdown-it`; `.html` → sandboxed
|
|
49
|
-
iframe; `.css`/`.txt` → server-side `highlight.js`.
|
|
50
|
-
`src/server/renderers/`
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
6. **Lightweight CLI** via [`cac`](https://github.com/cacjs/cac): `<path>`, `--port`, `--open`.
|
|
72
|
+
iframe; `.css`/`.txt` → server-side `highlight.js`; `.csv`/`.tsv` → HTML tables
|
|
73
|
+
styled with GitHub markdown CSS. New types register in `src/server/renderers/`
|
|
74
|
+
without touching routing.
|
|
75
|
+
5. **Lightweight CLI** via [`cac`](https://github.com/cacjs/cac): `<path>`, `--port`, `--open`, `--no-nav`.
|
|
54
76
|
|
|
55
77
|
Live content updates ride Vite's HMR channel: the server pushes a custom
|
|
56
78
|
`hmr-serve:update` event and the content pane re-fetches — so Vite's client
|
|
57
79
|
handles transport and reconnection for us.
|
|
58
80
|
|
|
81
|
+
**Links & URLs.** Raw HTML is served at mirror paths (`/__hmrserve/raw/<file>`),
|
|
82
|
+
so **relative** links and assets inside a framed doc (`href="contact.html"`,
|
|
83
|
+
`<img src="logo.png">`) resolve against the real folder layout. The selected file
|
|
84
|
+
is reflected in a clean, bookmarkable URL under the served folder's name — e.g.
|
|
85
|
+
serving `./aurora-notes` gives `/aurora-notes/docs/intro.md`. These are real
|
|
86
|
+
History-API paths (no `#`): shareable, reload-safe, and back/forward works.
|
|
87
|
+
Unknown paths 404 rather than rendering the app, so a stray absolute link can't
|
|
88
|
+
nest the shell inside the content pane.
|
|
89
|
+
|
|
59
90
|
```
|
|
60
91
|
src/
|
|
61
92
|
cli/ arg parsing + entry
|
package/bin/hmr-serve.js
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
// Published entry point. Invokes the compiled CLI directly rather than relying
|
|
3
3
|
// on import-time self-execution detection, which is unreliable when launched
|
|
4
4
|
// through npm's .bin symlink (argv[1] is the symlink, not this file).
|
|
5
|
-
|
|
5
|
+
//
|
|
6
|
+
// Stamp startup time before importing the CLI (and Vite) so "ready in N ms"
|
|
7
|
+
// includes module load — same approach as Vite's own bin.
|
|
8
|
+
globalThis.__hmr_serve_start = performance.now();
|
|
9
|
+
|
|
10
|
+
const { run } = await import('../dist/cli/index.js');
|
|
6
11
|
|
|
7
12
|
run(process.argv.slice(2)).catch((error) => {
|
|
8
13
|
console.error(`\n ${error instanceof Error ? error.message : String(error)}\n`);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
const { version } = createRequire(import.meta.url)('../../package.json');
|
|
3
|
+
const REPO = 'floodtide/hmr-serve';
|
|
4
|
+
/** Tiny ANSI helpers — no dependency. Respects NO_COLOR / FORCE_COLOR / TTY. */
|
|
5
|
+
function useColor() {
|
|
6
|
+
if (process.env.NO_COLOR != null && process.env.NO_COLOR !== '')
|
|
7
|
+
return false;
|
|
8
|
+
if (process.env.FORCE_COLOR != null && process.env.FORCE_COLOR !== '0')
|
|
9
|
+
return true;
|
|
10
|
+
return Boolean(process.stdout.isTTY);
|
|
11
|
+
}
|
|
12
|
+
const ansi = {
|
|
13
|
+
reset: '\x1b[0m',
|
|
14
|
+
bold: '\x1b[1m',
|
|
15
|
+
dim: '\x1b[2m',
|
|
16
|
+
green: '\x1b[32m',
|
|
17
|
+
cyan: '\x1b[36m',
|
|
18
|
+
};
|
|
19
|
+
function paint(code, text, enabled) {
|
|
20
|
+
return enabled ? `${code}${text}${ansi.reset}` : text;
|
|
21
|
+
}
|
|
22
|
+
/** Strip ANSI escapes so padding uses visible width. */
|
|
23
|
+
function visibleLength(text) {
|
|
24
|
+
return text.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
25
|
+
}
|
|
26
|
+
/** Vite-style URL: cyan, with the port bolded. */
|
|
27
|
+
function colorUrl(url, enabled) {
|
|
28
|
+
if (!enabled)
|
|
29
|
+
return url;
|
|
30
|
+
return (ansi.cyan + url.replace(/:(\d+)\//, `:${ansi.bold}$1${ansi.reset}${ansi.cyan}/`) + ansi.reset);
|
|
31
|
+
}
|
|
32
|
+
/** Boot banner modeled on Vite's startup output. */
|
|
33
|
+
export function printLaunchBanner(targetDir, url, readyMs) {
|
|
34
|
+
const color = useColor();
|
|
35
|
+
const brand = color
|
|
36
|
+
? `${ansi.green}${ansi.bold}HMR-SERVE${ansi.reset}${ansi.green} v${version}${ansi.reset}`
|
|
37
|
+
: `HMR-SERVE v${version}`;
|
|
38
|
+
const repo = paint(ansi.dim, REPO, color);
|
|
39
|
+
const ready = color
|
|
40
|
+
? `${ansi.dim}ready in ${ansi.reset}${ansi.bold}${Math.ceil(readyMs)}${ansi.reset}${ansi.dim} ms${ansi.reset}`
|
|
41
|
+
: `ready in ${Math.ceil(readyMs)} ms`;
|
|
42
|
+
const arrow = paint(ansi.green, '➜', color);
|
|
43
|
+
const localLabel = paint(ansi.bold, 'Local', color);
|
|
44
|
+
const servingLabel = paint(ansi.bold, 'Serving', color);
|
|
45
|
+
// Sit the repo to the right of the brand without hugging the terminal edge.
|
|
46
|
+
// Cap the line so it stays readable in wide windows (Vite-style).
|
|
47
|
+
const cols = Math.min(process.stdout.columns ?? 80, 72);
|
|
48
|
+
const left = ` ${brand}`;
|
|
49
|
+
const gap = Math.max(2, cols - visibleLength(left) - visibleLength(repo));
|
|
50
|
+
const titleLine = `${left}${' '.repeat(gap)}${repo}`;
|
|
51
|
+
console.log(`
|
|
52
|
+
${titleLine}
|
|
53
|
+
${ready}
|
|
54
|
+
|
|
55
|
+
${arrow} ${localLabel}: ${colorUrl(url, color)}
|
|
56
|
+
${arrow} ${servingLabel}: ${paint(ansi.dim, targetDir, color)}
|
|
57
|
+
`);
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=banner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"banner.js","sourceRoot":"","sources":["../../src/cli/banner.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/index.d.ts
CHANGED
package/dist/cli/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { statSync } from 'node:fs';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { cac } from 'cac';
|
|
4
|
+
import { printLaunchBanner } from './banner.js';
|
|
4
5
|
import { createServer } from '../server/createServer.js';
|
|
5
6
|
/** Pure arg parsing, split out so it can be unit-tested without a live server.
|
|
6
7
|
* Throws `Error` with a user-facing message on invalid input. */
|
|
@@ -9,7 +10,11 @@ export function parseArgs(argv) {
|
|
|
9
10
|
cli
|
|
10
11
|
.command('[dir]', 'Serve a folder with a live file tree + content pane')
|
|
11
12
|
.option('--port <port>', 'Port to listen on', { default: 5183 })
|
|
12
|
-
.option('--open', 'Open the browser on start', { default: false })
|
|
13
|
+
.option('--open', 'Open the browser on start', { default: false })
|
|
14
|
+
// cac/mri: `--no-nav` sets `nav: false` (negation of `--nav`).
|
|
15
|
+
.option('--nav', 'Show the file-tree UI (use --no-nav for serve-like mode)', {
|
|
16
|
+
default: true,
|
|
17
|
+
});
|
|
13
18
|
cli.help();
|
|
14
19
|
const parsed = cli.parse(['node', 'hmr-serve', ...argv], { run: false });
|
|
15
20
|
const dir = parsed.args[0] ?? '.';
|
|
@@ -21,6 +26,7 @@ export function parseArgs(argv) {
|
|
|
21
26
|
targetDir: resolve(process.cwd(), dir),
|
|
22
27
|
port,
|
|
23
28
|
open: Boolean(parsed.options.open),
|
|
29
|
+
noNav: parsed.options.nav === false,
|
|
24
30
|
};
|
|
25
31
|
}
|
|
26
32
|
/** Validate the target is an existing directory. Throws on failure. */
|
|
@@ -37,16 +43,18 @@ export function assertDirectory(targetDir) {
|
|
|
37
43
|
}
|
|
38
44
|
}
|
|
39
45
|
export async function run(argv) {
|
|
46
|
+
const started = globalThis.__hmr_serve_start ?? performance.now();
|
|
40
47
|
const args = parseArgs(argv);
|
|
41
48
|
assertDirectory(args.targetDir);
|
|
42
49
|
const server = await createServer({
|
|
43
50
|
targetDir: args.targetDir,
|
|
44
51
|
port: args.port,
|
|
45
52
|
open: args.open,
|
|
53
|
+
noNav: args.noNav,
|
|
46
54
|
});
|
|
47
55
|
await server.listen();
|
|
48
56
|
const info = server.resolvedUrls?.local[0] ?? `http://localhost:${args.port}/`;
|
|
49
|
-
|
|
57
|
+
printLaunchBanner(args.targetDir, info, performance.now() - started);
|
|
50
58
|
}
|
|
51
59
|
// Self-execute only when this module is the directly-run script (e.g.
|
|
52
60
|
// `tsx src/cli/index.ts` in dev/e2e, or `node dist/cli/index.js`). The published
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,10 +6,15 @@ export interface CreateServerOptions {
|
|
|
6
6
|
/** Open the browser once listening. */
|
|
7
7
|
open?: boolean;
|
|
8
8
|
host?: string;
|
|
9
|
+
/** Skip the Vue nav shell and serve files like `serve` (with HMR + MD/CSV/TSV). */
|
|
10
|
+
noNav?: boolean;
|
|
9
11
|
}
|
|
10
12
|
/**
|
|
11
13
|
* Build (but do not start) a Vite dev server whose root is our app shell, with
|
|
12
14
|
* the target folder mounted via {@link hmrServePlugin}. Call `.listen()` on the
|
|
13
15
|
* returned server to start it.
|
|
16
|
+
*
|
|
17
|
+
* With `noNav`, the Vue shell is unused — middleware serves the folder directly
|
|
18
|
+
* (index file or directory listing) while Vite still provides HMR.
|
|
14
19
|
*/
|
|
15
20
|
export declare function createServer(options: CreateServerOptions): Promise<ViteDevServer>;
|
|
@@ -17,6 +17,9 @@ function resolveClientRoot() {
|
|
|
17
17
|
* Build (but do not start) a Vite dev server whose root is our app shell, with
|
|
18
18
|
* the target folder mounted via {@link hmrServePlugin}. Call `.listen()` on the
|
|
19
19
|
* returned server to start it.
|
|
20
|
+
*
|
|
21
|
+
* With `noNav`, the Vue shell is unused — middleware serves the folder directly
|
|
22
|
+
* (index file or directory listing) while Vite still provides HMR.
|
|
20
23
|
*/
|
|
21
24
|
export async function createServer(options) {
|
|
22
25
|
const targetDir = resolve(process.cwd(), options.targetDir);
|
|
@@ -24,10 +27,16 @@ export async function createServer(options) {
|
|
|
24
27
|
// The package root (…/src/client → package) holds the shell, shared types and
|
|
25
28
|
// node_modules; the target folder lives anywhere. Both must be fs-allowed.
|
|
26
29
|
const packageRoot = resolve(clientRoot, '../..');
|
|
30
|
+
const noNav = Boolean(options.noNav);
|
|
27
31
|
return createViteServer({
|
|
28
32
|
root: clientRoot,
|
|
29
33
|
configFile: false,
|
|
30
|
-
|
|
34
|
+
// MPA (not SPA) so Vite does NOT history-fallback unknown paths to index.html.
|
|
35
|
+
// The shell is a single page at '/', and framed content uses its own /raw
|
|
36
|
+
// URLs — an unmatched path (e.g. a stray absolute link) should 404, not render
|
|
37
|
+
// the whole app inside the content iframe.
|
|
38
|
+
appType: 'mpa',
|
|
39
|
+
plugins: [...(noNav ? [] : [vue()]), hmrServePlugin({ targetDir, noNav })],
|
|
31
40
|
server: {
|
|
32
41
|
port: options.port ?? 5183,
|
|
33
42
|
host: options.host,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createServer.js","sourceRoot":"","sources":["../../src/server/createServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAsB,MAAM,MAAM,CAAC;AAC5E,OAAO,GAAG,MAAM,oBAAoB,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"createServer.js","sourceRoot":"","sources":["../../src/server/createServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAsB,MAAM,MAAM,CAAC;AAC5E,OAAO,GAAG,MAAM,oBAAoB,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAa7C;mFACmF;AACnF,SAAS,iBAAiB;IACxB,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,0FAA0F;IAC1F,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;IACnD,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAA4B;IAC7D,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAC5D,MAAM,UAAU,GAAG,iBAAiB,EAAE,CAAC;IACvC,8EAA8E;IAC9E,2EAA2E;IAC3E,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAErC,OAAO,gBAAgB,CAAC;QACtB,IAAI,EAAE,UAAU;QAChB,UAAU,EAAE,KAAK;QACjB,+EAA+E;QAC/E,0EAA0E;QAC1E,+EAA+E;QAC/E,2CAA2C;QAC3C,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,cAAc,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1E,MAAM,EAAE;YACN,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI;YAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,KAAK;YAC3B,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,EAAE;SACxC;QACD,2EAA2E;QAC3E,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;AACL,CAAC"}
|
package/dist/server/fs.d.ts
CHANGED
|
@@ -5,12 +5,17 @@ export declare function extOf(name: string): string;
|
|
|
5
5
|
/** Absolute path → root-relative, POSIX-separated path used everywhere in the API. */
|
|
6
6
|
export declare function toRelPosix(root: string, abs: string): string;
|
|
7
7
|
export declare function readFileText(abs: string): Promise<string>;
|
|
8
|
+
/** Raw bytes — used by the /raw endpoint, which must not corrupt binary assets
|
|
9
|
+
* (images, fonts) by decoding them as UTF-8. */
|
|
10
|
+
export declare function readFileBuffer(abs: string): Promise<Buffer>;
|
|
11
|
+
export declare function contentTypeFor(ext: string): string;
|
|
8
12
|
/**
|
|
9
|
-
* Recursively build the file tree
|
|
10
|
-
*
|
|
11
|
-
*
|
|
13
|
+
* Recursively build the file tree for every non-ignored file. Supported and
|
|
14
|
+
* unsupported files are both included so the client can filter by category /
|
|
15
|
+
* "Other files". Empty directories are pruned. Entries are sorted dirs-first,
|
|
16
|
+
* then by name.
|
|
12
17
|
*/
|
|
13
|
-
export declare function buildTree(root: string
|
|
18
|
+
export declare function buildTree(root: string): Promise<FileNode[]>;
|
|
14
19
|
/** Collect every supported file (root-relative paths) for the initial index scan. */
|
|
15
20
|
export declare function listSupportedFiles(root: string, registry: RendererRegistry): Promise<string[]>;
|
|
16
21
|
/** Whether `abs` resolves to a real file (used to guard endpoint reads). */
|
package/dist/server/fs.js
CHANGED
|
@@ -16,12 +16,48 @@ const IGNORED_DIRS = new Set(['.git', 'node_modules', '.vite', 'dist', '.DS_Stor
|
|
|
16
16
|
export async function readFileText(abs) {
|
|
17
17
|
return readFile(abs, 'utf8');
|
|
18
18
|
}
|
|
19
|
+
/** Raw bytes — used by the /raw endpoint, which must not corrupt binary assets
|
|
20
|
+
* (images, fonts) by decoding them as UTF-8. */
|
|
21
|
+
export async function readFileBuffer(abs) {
|
|
22
|
+
return readFile(abs);
|
|
23
|
+
}
|
|
24
|
+
/** Minimal extension → MIME map for raw-served content and its relative assets
|
|
25
|
+
* (stylesheets, scripts, images, fonts a framed HTML doc may reference).
|
|
26
|
+
* Unknowns fall back to octet-stream so the browser downloads rather than guesses. */
|
|
27
|
+
const MIME_BY_EXT = {
|
|
28
|
+
html: 'text/html; charset=utf-8',
|
|
29
|
+
htm: 'text/html; charset=utf-8',
|
|
30
|
+
css: 'text/css; charset=utf-8',
|
|
31
|
+
js: 'text/javascript; charset=utf-8',
|
|
32
|
+
mjs: 'text/javascript; charset=utf-8',
|
|
33
|
+
json: 'application/json; charset=utf-8',
|
|
34
|
+
txt: 'text/plain; charset=utf-8',
|
|
35
|
+
md: 'text/plain; charset=utf-8',
|
|
36
|
+
csv: 'text/csv; charset=utf-8',
|
|
37
|
+
tsv: 'text/tab-separated-values; charset=utf-8',
|
|
38
|
+
svg: 'image/svg+xml',
|
|
39
|
+
png: 'image/png',
|
|
40
|
+
jpg: 'image/jpeg',
|
|
41
|
+
jpeg: 'image/jpeg',
|
|
42
|
+
gif: 'image/gif',
|
|
43
|
+
webp: 'image/webp',
|
|
44
|
+
avif: 'image/avif',
|
|
45
|
+
ico: 'image/x-icon',
|
|
46
|
+
woff: 'font/woff',
|
|
47
|
+
woff2: 'font/woff2',
|
|
48
|
+
ttf: 'font/ttf',
|
|
49
|
+
otf: 'font/otf',
|
|
50
|
+
};
|
|
51
|
+
export function contentTypeFor(ext) {
|
|
52
|
+
return MIME_BY_EXT[ext.toLowerCase()] ?? 'application/octet-stream';
|
|
53
|
+
}
|
|
19
54
|
/**
|
|
20
|
-
* Recursively build the file tree
|
|
21
|
-
*
|
|
22
|
-
*
|
|
55
|
+
* Recursively build the file tree for every non-ignored file. Supported and
|
|
56
|
+
* unsupported files are both included so the client can filter by category /
|
|
57
|
+
* "Other files". Empty directories are pruned. Entries are sorted dirs-first,
|
|
58
|
+
* then by name.
|
|
23
59
|
*/
|
|
24
|
-
export async function buildTree(root
|
|
60
|
+
export async function buildTree(root) {
|
|
25
61
|
async function walk(dir) {
|
|
26
62
|
let entries;
|
|
27
63
|
try {
|
|
@@ -48,9 +84,7 @@ export async function buildTree(root, registry) {
|
|
|
48
84
|
}
|
|
49
85
|
else if (entry.isFile()) {
|
|
50
86
|
const ext = extOf(entry.name);
|
|
51
|
-
|
|
52
|
-
nodes.push({ path: toRelPosix(root, abs), name: entry.name, type: 'file', ext });
|
|
53
|
-
}
|
|
87
|
+
nodes.push({ path: toRelPosix(root, abs), name: entry.name, type: 'file', ext });
|
|
54
88
|
}
|
|
55
89
|
}
|
|
56
90
|
return sortNodes(nodes);
|
package/dist/server/fs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/server/fs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAIhD,mEAAmE;AACnE,MAAM,UAAU,KAAK,CAAC,IAAY;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACxB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;AAC3C,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,GAAW;IAClD,OAAO,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,CAAC;AAED,uEAAuE;AACvE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AAErF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW;IAC5C,OAAO,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/server/fs.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,5 +27,8 @@ export interface WatchHandlers {
|
|
|
27
27
|
* with injected `readFile`/`emit`. `add`/`change` are debounced per path (an
|
|
28
28
|
* editor save often fires several writes); `unlink` is applied immediately so a
|
|
29
29
|
* deleted file can't linger in the index behind a pending change.
|
|
30
|
+
*
|
|
31
|
+
* Unsupported extensions are never indexed, but `add`/`unlink` still emit so the
|
|
32
|
+
* client can refresh the tree when "Other files" is shown.
|
|
30
33
|
*/
|
|
31
34
|
export declare function createWatchHandler(options: WatchHandlerOptions): WatchHandlers;
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
* with injected `readFile`/`emit`. `add`/`change` are debounced per path (an
|
|
4
4
|
* editor save often fires several writes); `unlink` is applied immediately so a
|
|
5
5
|
* deleted file can't linger in the index behind a pending change.
|
|
6
|
+
*
|
|
7
|
+
* Unsupported extensions are never indexed, but `add`/`unlink` still emit so the
|
|
8
|
+
* client can refresh the tree when "Other files" is shown.
|
|
6
9
|
*/
|
|
7
10
|
export function createWatchHandler(options) {
|
|
8
11
|
const { index, extOf, isSupported, readFile, emit, debounceMs = 40 } = options;
|
|
@@ -44,6 +47,10 @@ export function createWatchHandler(options) {
|
|
|
44
47
|
}
|
|
45
48
|
return {
|
|
46
49
|
onAdd(path) {
|
|
50
|
+
if (!isSupported(extOf(path))) {
|
|
51
|
+
emit({ event: 'add', path });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
47
54
|
schedule(path, 'add');
|
|
48
55
|
},
|
|
49
56
|
onChange(path) {
|
|
@@ -55,8 +62,10 @@ export function createWatchHandler(options) {
|
|
|
55
62
|
clearTimeout(timer);
|
|
56
63
|
timers.delete(path);
|
|
57
64
|
pending.delete(path);
|
|
58
|
-
if (!isSupported(extOf(path)))
|
|
65
|
+
if (!isSupported(extOf(path))) {
|
|
66
|
+
emit({ event: 'unlink', path });
|
|
59
67
|
return;
|
|
68
|
+
}
|
|
60
69
|
index.remove(path);
|
|
61
70
|
emit({ event: 'unlink', path });
|
|
62
71
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../../src/server/index/watcher.ts"],"names":[],"mappings":"AA2BA
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../../src/server/index/watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive the URL mount prefix from the served folder's name, e.g.
|
|
3
|
+
* `/Users/me/aurora-notes` → `/aurora-notes`, `My Docs` → `/my-docs`.
|
|
4
|
+
*
|
|
5
|
+
* Content lives under this prefix so its paths can never collide with the app
|
|
6
|
+
* shell's own root assets (`/main.ts`, `/styles.css`, `/@vite/client`) or the
|
|
7
|
+
* API base (`/__hmrserve`). The slug only emits [a-z0-9-], which structurally
|
|
8
|
+
* rules out those names (they contain `.`, `_` or `@`). Empty names fall back
|
|
9
|
+
* to `/files`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function mountPrefixFor(targetDir: string): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { basename } from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* Derive the URL mount prefix from the served folder's name, e.g.
|
|
4
|
+
* `/Users/me/aurora-notes` → `/aurora-notes`, `My Docs` → `/my-docs`.
|
|
5
|
+
*
|
|
6
|
+
* Content lives under this prefix so its paths can never collide with the app
|
|
7
|
+
* shell's own root assets (`/main.ts`, `/styles.css`, `/@vite/client`) or the
|
|
8
|
+
* API base (`/__hmrserve`). The slug only emits [a-z0-9-], which structurally
|
|
9
|
+
* rules out those names (they contain `.`, `_` or `@`). Empty names fall back
|
|
10
|
+
* to `/files`.
|
|
11
|
+
*/
|
|
12
|
+
export function mountPrefixFor(targetDir) {
|
|
13
|
+
const slug = basename(targetDir)
|
|
14
|
+
.toLowerCase()
|
|
15
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
16
|
+
.replace(/^-+|-+$/g, '');
|
|
17
|
+
return `/${slug || 'files'}`;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=mount.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mount.js","sourceRoot":"","sources":["../../src/server/mount.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC;SAC7B,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,OAAO,IAAI,IAAI,IAAI,OAAO,EAAE,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Index files checked (in order) when a directory URL is requested — same idea
|
|
2
|
+
* as vercel/serve: an index file wins over a directory listing. */
|
|
3
|
+
export declare const INDEX_NAMES: readonly ["index.html", "index.htm"];
|
|
4
|
+
/** Extensions rendered to an HTML preview page in `--no-nav` mode (everything
|
|
5
|
+
* else is served as raw bytes with the appropriate MIME type). */
|
|
6
|
+
export declare const PREVIEW_EXTENSIONS: Set<string>;
|
|
7
|
+
export interface ListingEntry {
|
|
8
|
+
name: string;
|
|
9
|
+
href: string;
|
|
10
|
+
type: 'directory' | 'file';
|
|
11
|
+
}
|
|
12
|
+
/** Find an index file inside `dirAbs`. Returns the absolute path, or null. */
|
|
13
|
+
export declare function findIndexFile(dirAbs: string): Promise<string | null>;
|
|
14
|
+
/** Directory listing entries (dirs first, then files), with an optional `..`. */
|
|
15
|
+
export declare function listDirectory(dirAbs: string, urlPath: string): Promise<ListingEntry[]>;
|
|
16
|
+
/** Wrap rendered markdown/csv/tsv HTML in a full document with live reload. */
|
|
17
|
+
export declare function wrapPreviewHtml(title: string, bodyHtml: string): string;
|
|
18
|
+
/** Inject the Vite client into an HTML document so edits trigger a full reload. */
|
|
19
|
+
export declare function injectViteClient(html: string): string;
|
|
20
|
+
/** Serve-style directory listing page. */
|
|
21
|
+
export declare function renderDirectoryListing(urlPath: string, entries: ListingEntry[]): string;
|
|
22
|
+
export declare function isPreviewExtension(ext: string): boolean;
|