@choonkeat/md-serve 0.1.0 → 0.2.1
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 +18 -10
- package/bin/md-serve.js +83 -14
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -33,16 +33,24 @@ md-serve -version
|
|
|
33
33
|
[github-markdown-css](https://github.com/sindresorhus/github-markdown-css).
|
|
34
34
|
Fenced code blocks are syntax-highlighted via
|
|
35
35
|
[chroma](https://github.com/alecthomas/chroma) (200+ languages).
|
|
36
|
-
- Directories
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
`index.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
-
|
|
36
|
+
- Directories: if `index.html` is present it's served raw (matches
|
|
37
|
+
nginx / Apache / Caddy / GitHub Pages, so md-serve can host real
|
|
38
|
+
static apps). Otherwise, if `index.md` / `README.md` / `readme.md` /
|
|
39
|
+
`index.markdown` is present, a combined page renders the directory
|
|
40
|
+
listing on top and the rendered README below GitHub-style. Otherwise
|
|
41
|
+
a plain generated listing with **Name / Size / Modified** columns.
|
|
42
|
+
- Everything else is served byte-for-byte. That means `.js`, `.css`,
|
|
43
|
+
`.wasm`, `.json`, images, fonts, and the rest all reach the browser
|
|
44
|
+
with their normal MIME types — ES module scripts load, fetch() works,
|
|
45
|
+
the static-app use case Just Works.
|
|
46
|
+
- Source files (`.go`, `.py`, `.yaml`, `.toml`, `Dockerfile`,
|
|
47
|
+
`Makefile`, ...) can be viewed as syntax-highlighted HTML with
|
|
48
|
+
linkable line numbers (`/main.go#L42`) by appending `?pretty=1` to
|
|
49
|
+
the URL. Directory listings already link source files this way, so
|
|
50
|
+
clicking from a listing lands on the highlighted view while direct
|
|
51
|
+
URLs / `curl` / `<script src>` get the raw bytes. Files larger than
|
|
52
|
+
1 MiB, files that look binary, or files chroma can't lex stay raw
|
|
53
|
+
even with `?pretty=1`.
|
|
46
54
|
- Dotfiles are hidden from listings.
|
|
47
55
|
- Path traversal is blocked: requests are rejected if they resolve
|
|
48
56
|
outside the served root.
|
package/bin/md-serve.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// GENERATED by distribute-go-bin v0.1.0 — do not edit.
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
+
import { spawn, execFileSync } from "child_process";
|
|
4
5
|
import { createRequire } from "module";
|
|
5
6
|
import { existsSync, chmodSync } from "fs";
|
|
6
7
|
import { dirname, join } from "path";
|
|
@@ -38,14 +39,40 @@ const binName = process.platform === "win32" ? "md-serve.exe" : "md-serve";
|
|
|
38
39
|
// npm-platforms/ is not published to npm, so this only takes effect during local dev.
|
|
39
40
|
const localPath = join(__dirname, "..", "npm-platforms", `${platform}-${arch}`, "bin", binName);
|
|
40
41
|
|
|
42
|
+
function resolveFromRegistry() {
|
|
43
|
+
try {
|
|
44
|
+
const pkgDir = dirname(require.resolve(`${pkgName}/package.json`));
|
|
45
|
+
return join(pkgDir, "bin", binName);
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
41
51
|
let binPath;
|
|
42
52
|
if (existsSync(localPath)) {
|
|
43
53
|
binPath = localPath;
|
|
44
54
|
} else {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
binPath = resolveFromRegistry();
|
|
56
|
+
// optionalDependencies may not be installed in some environments:
|
|
57
|
+
// - stale npx cache predating the dep being added
|
|
58
|
+
// - `npm install --omit=optional` or `npm ci --omit=optional`
|
|
59
|
+
// - cross-platform install caches (e.g. image built on amd64, run on arm64)
|
|
60
|
+
// - pnpm / yarn with different optional-dep semantics
|
|
61
|
+
// - `npm link` dev workflows
|
|
62
|
+
// Attempt a one-shot install to recover before giving up.
|
|
63
|
+
if (!binPath) {
|
|
64
|
+
try {
|
|
65
|
+
console.error(`Installing ${pkgName}...`);
|
|
66
|
+
execFileSync("npm", ["install", "--no-save", pkgName], {
|
|
67
|
+
stdio: "inherit",
|
|
68
|
+
cwd: join(__dirname, ".."),
|
|
69
|
+
});
|
|
70
|
+
binPath = resolveFromRegistry();
|
|
71
|
+
} catch {
|
|
72
|
+
// fall through to the error exit below
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!binPath) {
|
|
49
76
|
console.error(
|
|
50
77
|
`Could not find package ${pkgName}.\n` +
|
|
51
78
|
`Make sure it is installed — this usually means your platform is supported\n` +
|
|
@@ -62,18 +89,53 @@ if (!existsSync(binPath)) {
|
|
|
62
89
|
process.exit(1);
|
|
63
90
|
}
|
|
64
91
|
|
|
92
|
+
// Forward these signals from the dispatcher to the spawned Go binary so that
|
|
93
|
+
// `kill <dispatcher-pid>` does not orphan the child. Node does not propagate
|
|
94
|
+
// signals to children automatically; without these handlers, SIGTERM to this
|
|
95
|
+
// script would terminate the dispatcher and leave the child process running.
|
|
96
|
+
const FORWARDED_SIGNALS = ["SIGTERM", "SIGINT", "SIGHUP", "SIGQUIT"];
|
|
97
|
+
|
|
65
98
|
function run() {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
99
|
+
return new Promise((resolve) => {
|
|
100
|
+
let child;
|
|
101
|
+
try {
|
|
102
|
+
child = spawn(binPath, process.argv.slice(2), { stdio: "inherit" });
|
|
103
|
+
} catch (error) {
|
|
104
|
+
resolve({ error });
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
69
107
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
108
|
+
const handlers = {};
|
|
109
|
+
for (const sig of FORWARDED_SIGNALS) {
|
|
110
|
+
handlers[sig] = () => {
|
|
111
|
+
try {
|
|
112
|
+
child.kill(sig);
|
|
113
|
+
} catch {
|
|
114
|
+
// child may have already exited; nothing to do.
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
process.on(sig, handlers[sig]);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const cleanup = () => {
|
|
121
|
+
for (const sig of FORWARDED_SIGNALS) {
|
|
122
|
+
process.off(sig, handlers[sig]);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
child.on("error", (error) => {
|
|
127
|
+
cleanup();
|
|
128
|
+
resolve({ error });
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
child.on("exit", (code, signal) => {
|
|
132
|
+
cleanup();
|
|
133
|
+
resolve({ code, signal });
|
|
134
|
+
});
|
|
135
|
+
});
|
|
74
136
|
}
|
|
75
137
|
|
|
76
|
-
let result = run();
|
|
138
|
+
let result = await run();
|
|
77
139
|
|
|
78
140
|
// Handle EACCES by chmod +x and retrying
|
|
79
141
|
if (result.error && result.error.code === "EACCES") {
|
|
@@ -83,10 +145,17 @@ if (result.error && result.error.code === "EACCES") {
|
|
|
83
145
|
console.error(`Failed to chmod +x ${binPath}: ${e.message}`);
|
|
84
146
|
process.exit(1);
|
|
85
147
|
}
|
|
86
|
-
result = run();
|
|
148
|
+
result = await run();
|
|
87
149
|
}
|
|
88
150
|
|
|
89
151
|
if (result.error) {
|
|
90
152
|
console.error(`Failed to start md-serve: ${result.error.message}`);
|
|
91
153
|
process.exit(1);
|
|
92
154
|
}
|
|
155
|
+
|
|
156
|
+
if (result.signal) {
|
|
157
|
+
// Re-raise the signal the child died from so our own exit status reflects it.
|
|
158
|
+
process.kill(process.pid, result.signal);
|
|
159
|
+
} else {
|
|
160
|
+
process.exit(result.code ?? 0);
|
|
161
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@choonkeat/md-serve",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Tiny static file server that renders Markdown as GitHub-styled HTML",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
},
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"optionalDependencies": {
|
|
22
|
-
"@choonkeat/md-serve-darwin-arm64": "0.1
|
|
23
|
-
"@choonkeat/md-serve-darwin-x64": "0.1
|
|
24
|
-
"@choonkeat/md-serve-linux-arm64": "0.1
|
|
25
|
-
"@choonkeat/md-serve-linux-x64": "0.1
|
|
26
|
-
"@choonkeat/md-serve-win32-arm64": "0.1
|
|
27
|
-
"@choonkeat/md-serve-win32-x64": "0.1
|
|
22
|
+
"@choonkeat/md-serve-darwin-arm64": "0.2.1",
|
|
23
|
+
"@choonkeat/md-serve-darwin-x64": "0.2.1",
|
|
24
|
+
"@choonkeat/md-serve-linux-arm64": "0.2.1",
|
|
25
|
+
"@choonkeat/md-serve-linux-x64": "0.2.1",
|
|
26
|
+
"@choonkeat/md-serve-win32-arm64": "0.2.1",
|
|
27
|
+
"@choonkeat/md-serve-win32-x64": "0.2.1"
|
|
28
28
|
}
|
|
29
29
|
}
|