|
| 1 | +# tree-magic-js |
| 2 | + |
| 3 | +Fast and accurate MIME type detection for Node.js, powered by Rust. |
| 4 | + |
| 5 | +[](https://www.npmjs.com/package/@hechang27/tree-magic-js) |
| 6 | +[](https://opensource.org/licenses/MIT) |
| 7 | + |
| 8 | +## Overview |
| 9 | + |
| 10 | +`tree-magic-js` is a high-performance MIME type detection library that wraps Rust crate [`tree_magic_mini`](https://crates.io/crates/tree_magic_mini). It can detect file types from both file buffers and file paths. |
| 11 | + |
| 12 | +## Installation |
| 13 | + |
| 14 | +```bash |
| 15 | +npm install @hechang27/tree-magic-js |
| 16 | +``` |
| 17 | + |
| 18 | +## Quick Start |
| 19 | + |
| 20 | +```javascript |
| 21 | +import { inferFromBuffer, inferFromPath } from "@hechang27/tree-magic-js"; |
| 22 | +import { readFile } from "fs/promises"; |
| 23 | + |
| 24 | +// Detect MIME type from file buffer |
| 25 | +const buffer = await readFile("example.jpg"); |
| 26 | +const mimeType = await inferFromBuffer(buffer); |
| 27 | +console.log(mimeType); // 'image/jpeg' |
| 28 | + |
| 29 | +// Detect MIME type from file path |
| 30 | +const mimeType2 = await inferFromPath("./document.pdf"); |
| 31 | +console.log(mimeType2); // 'application/pdf' |
| 32 | +``` |
| 33 | + |
| 34 | +## API Reference |
| 35 | + |
| 36 | +### `inferFromBuffer(bytes: Buffer): Promise<string>` |
| 37 | + |
| 38 | +Detects the MIME type of a file from its buffer contents. |
| 39 | + |
| 40 | +**Parameters:** |
| 41 | + |
| 42 | +- `bytes` (Buffer): The file content as a Buffer |
| 43 | + |
| 44 | +**Returns:** |
| 45 | + |
| 46 | +- `Promise<string>`: The detected MIME type (e.g., 'image/jpeg', 'text/plain') |
| 47 | + |
| 48 | +**Example:** |
| 49 | + |
| 50 | +```javascript |
| 51 | +import { inferFromBuffer } from "@hechang27/tree-magic-js"; |
| 52 | +import { readFile } from "fs/promises"; |
| 53 | + |
| 54 | +const buffer = await readFile("photo.png"); |
| 55 | +const mimeType = await inferFromBuffer(buffer); |
| 56 | +console.log(mimeType); // 'image/png' |
| 57 | +``` |
| 58 | + |
| 59 | +### `inferFromPath(path: string): Promise<string | null>` |
| 60 | + |
| 61 | +Detects the MIME type of a file from its file path. |
| 62 | + |
| 63 | +**Parameters:** |
| 64 | + |
| 65 | +- `path` (string): Path to the file |
| 66 | + |
| 67 | +**Returns:** |
| 68 | + |
| 69 | +- `Promise<string | null>`: The detected MIME type, or `null` if the file doesn't exist |
| 70 | + |
| 71 | +**Example:** |
| 72 | + |
| 73 | +```javascript |
| 74 | +import { inferFromPath } from "@hechang27/tree-magic-js"; |
| 75 | + |
| 76 | +const mimeType = await inferFromPath("./video.mp4"); |
| 77 | +console.log(mimeType); // 'video/mp4' |
| 78 | + |
| 79 | +const notFound = await inferFromPath("./nonexistent.txt"); |
| 80 | +console.log(notFound); // null |
| 81 | +``` |
| 82 | + |
| 83 | +### `matchBuffer(mimeType: string, bytes: Buffer): Promise<boolean>` |
| 84 | + |
| 85 | +Checks if a buffer matches a specific MIME type. |
| 86 | + |
| 87 | +**Parameters:** |
| 88 | + |
| 89 | +- `mimeType` (string): The MIME type to check against |
| 90 | +- `bytes` (Buffer): The file content as a Buffer |
| 91 | + |
| 92 | +**Returns:** |
| 93 | + |
| 94 | +- `Promise<boolean>`: `true` if the buffer matches the MIME type, `false` otherwise |
| 95 | + |
| 96 | +**Example:** |
| 97 | + |
| 98 | +```javascript |
| 99 | +import { matchBuffer } from "@hechang27/tree-magic-js"; |
| 100 | +import { readFile } from "fs/promises"; |
| 101 | + |
| 102 | +const buffer = await readFile("image.jpg"); |
| 103 | +const isJpeg = await matchBuffer("image/jpeg", buffer); |
| 104 | +console.log(isJpeg); // true |
| 105 | + |
| 106 | +const isPng = await matchBuffer("image/png", buffer); |
| 107 | +console.log(isPng); // false |
| 108 | +``` |
| 109 | + |
| 110 | +### `matchPath(mimeType: string, path: string): Promise<boolean>` |
| 111 | + |
| 112 | +Checks if a file matches a specific MIME type. |
| 113 | + |
| 114 | +**Parameters:** |
| 115 | + |
| 116 | +- `mimeType` (string): The MIME type to check against |
| 117 | +- `path` (string): Path to the file |
| 118 | + |
| 119 | +**Returns:** |
| 120 | + |
| 121 | +- `Promise<boolean>`: `true` if the file matches the MIME type, `false` otherwise |
| 122 | + |
| 123 | +**Example:** |
| 124 | + |
| 125 | +```javascript |
| 126 | +import { matchPath } from "@hechang27/tree-magic-js"; |
| 127 | + |
| 128 | +const isVideo = await matchPath("video/mp4", "./movie.mp4"); |
| 129 | +console.log(isVideo); // true |
| 130 | +``` |
| 131 | + |
| 132 | +## Configuration |
| 133 | + |
| 134 | +`tree-magic-js` supports several environment variables for customization: |
| 135 | + |
| 136 | +### `TREE_MAGIC_DIR` |
| 137 | + |
| 138 | +Specify a custom directory where the MIME database is located or should be stored. |
| 139 | + |
| 140 | +```bash |
| 141 | +export TREE_MAGIC_DIR="/path/to/custom/mime/database" |
| 142 | +``` |
| 143 | + |
| 144 | +### `TREE_MAGIC_URL` |
| 145 | + |
| 146 | +Specify a custom URL to download the MIME database from. |
| 147 | + |
| 148 | +```bash |
| 149 | +export TREE_MAGIC_URL="https://custom-server.com/mime-database.zip" |
| 150 | +``` |
| 151 | + |
| 152 | +### `XDG_DATA_HOME` |
| 153 | + |
| 154 | +Override the XDG data home directory (Linux/Unix). |
| 155 | + |
| 156 | +```bash |
| 157 | +export XDG_DATA_HOME="/custom/data/home" |
| 158 | +``` |
| 159 | + |
| 160 | +### `XDG_DATA_DIRS` |
| 161 | + |
| 162 | +Override the XDG data directories (Linux/Unix). |
| 163 | + |
| 164 | +```bash |
| 165 | +export XDG_DATA_DIRS="/usr/local/share:/usr/share:/custom/share" |
| 166 | +``` |
| 167 | + |
| 168 | +## How It Works |
| 169 | + |
| 170 | +### Automatic Database Management |
| 171 | + |
| 172 | +On first use, `tree-magic-js` automatically: |
| 173 | + |
| 174 | +1. **Searches for existing MIME databases** in standard system locations: |
| 175 | + - Linux: `/usr/share/mime`, `/usr/local/share/mime`, `~/.local/share/mime` |
| 176 | + - macOS: `/opt/homebrew/share/mime` |
| 177 | + - Windows: `C:\msys64\mingw64\share\mime` |
| 178 | + Or uses location provided by `TREE_MAGIC_DIR` if valid |
| 179 | + |
| 180 | +2. **Downloads the database** if not found locally: |
| 181 | + - Downloads from the configured URL (default: [GitHub release](https://github.com/hechang27-sprt/build-shared-mime-info/releases/download/db-20251031/mime-database.zip)) |
| 182 | + - Extracts to platform-appropriate data directory and set the `TREE_MAGIC_DIR` to point to that location. |
| 183 | + - Caches for future use |
| 184 | + |
| 185 | +3. the underlying rust library will either use the MIME databases in system location, or one that is specified by `TREE_MAGIC_DIR`. |
| 186 | + |
| 187 | +## Platform Support |
| 188 | + |
| 189 | +`tree-magic-js` provides pre-built native binaries for: |
| 190 | + |
| 191 | +- **macOS**: x64, ARM64 (Apple Silicon) |
| 192 | +- **Windows**: x64, x86, ARM64 |
| 193 | +- **Linux**: x64, ARM64, ARMv7 (glibc and musl) |
| 194 | +- **FreeBSD**: x64, ARM64 |
| 195 | +- **Android**: ARM64, ARMv7 |
| 196 | + |
| 197 | +### System Requirements |
| 198 | + |
| 199 | +- **Node.js**: Version 22 or higher |
| 200 | +- **Internet connection**: Required for initial database download (if not already present) |
| 201 | + |
| 202 | +### Custom Database |
| 203 | + |
| 204 | +To use a custom MIME database: |
| 205 | + |
| 206 | +```bash |
| 207 | +# Point to your custom database directory |
| 208 | +export TREE_MAGIC_DIR="/path/to/custom/mime/db" |
| 209 | + |
| 210 | +# Or provide a custom download URL |
| 211 | +# default URL is https://github.com/hechang27-sprt/build-shared-mime-info/releases/download/db-20251031/mime-database.zip |
| 212 | +export TREE_MAGIC_URL="https://your-server.com/custom-mime-db.zip" |
| 213 | +``` |
| 214 | + |
| 215 | +## Error Handling |
| 216 | + |
| 217 | +```javascript |
| 218 | +import { inferFromPath } from "@hechang27/tree-magic-js"; |
| 219 | + |
| 220 | +try { |
| 221 | + const mimeType = await inferFromPath("./file.txt"); |
| 222 | + if (mimeType) { |
| 223 | + console.log(`Detected: ${mimeType}`); |
| 224 | + } else { |
| 225 | + console.log("File not found"); |
| 226 | + } |
| 227 | +} catch (error) { |
| 228 | + console.error("Detection failed:", error); |
| 229 | +} |
| 230 | +``` |
| 231 | + |
| 232 | +## Examples |
| 233 | + |
| 234 | +### File Upload Validation |
| 235 | + |
| 236 | +```javascript |
| 237 | +import { inferFromBuffer, matchBuffer } from "@hechang27/tree-magic-js"; |
| 238 | + |
| 239 | +async function validateUpload(fileBuffer, allowedType) { |
| 240 | + if (await matchBuffer(allowedType, fileBuffer)) { |
| 241 | + return { valid: true, buf: fileBuffer }; |
| 242 | + } |
| 243 | + |
| 244 | + return { valid: false }; |
| 245 | +} |
| 246 | +``` |
| 247 | + |
| 248 | +## Contributing |
| 249 | + |
| 250 | +Contributions are welcome! Please feel free to submit a Pull Request. |
| 251 | + |
| 252 | +## License |
| 253 | + |
| 254 | +MIT License - see the [LICENSE](LICENSE) file for details. |
| 255 | + |
| 256 | +## Links |
| 257 | + |
| 258 | +- [GitHub Repository](https://github.com/hechang27-sprt/tree-magic-js) |
| 259 | +- [tree-magic-mini](https://crates.io/crates/tree_magic_mini) |
| 260 | +- [NPM Package](https://www.npmjs.com/package/@hechang27/tree-magic-js) |
| 261 | +- [Issues](https://github.com/hechang27-sprt/tree-magic-js/issues) |
0 commit comments