@tdio/static-serve 0.0.4 → 0.0.5-dev.5
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 +86 -4
- package/bin/static-serve +190 -0
- package/install.js +259 -0
- package/main.js +26 -0
- package/package.json +17 -9
- package/bin/cli.js +0 -51
package/README.md
CHANGED
|
@@ -92,8 +92,10 @@ If `ROOT_DIR` is not specified, it defaults to the current directory (`./`).
|
|
|
92
92
|
| Flag | Description | Default |
|
|
93
93
|
|------|-------------|---------|
|
|
94
94
|
| `--address` | The TCP address to listen on. | `:3000` |
|
|
95
|
+
| `--config` | Load options from a YAML config file. CLI scalar flags override config values; repeated `--proxy` and `--mount` flags append to config lists. | `""` |
|
|
96
|
+
| `--log-level` | Server log level. Supported values: `error`, `warn`, `info`, `debug`, `trace`. | `info` |
|
|
95
97
|
| `--mount` | Mount specific directory to a virtual path (can be repeated). Format: `<physical_path>:<virtual_path>` or `src=<physical_path>,dst=<virtual_path>` | `""` |
|
|
96
|
-
| `--proxy` | Proxy specific upstream to a virtual path (can be repeated). | `""` |
|
|
98
|
+
| `--proxy` | Proxy specific upstream to a virtual path (can be repeated), including `unix:///path.sock` upstreams. | `""` |
|
|
97
99
|
| `--spa` | Enable SPA mode (redirects missing files to `/index.html`). | `false` |
|
|
98
100
|
| `--logger-format` | Custom server logger format (Go template syntax). | `{{.Method}} {{.URL.Path}} {{.Status}} {{.RemoteAddr}} {{.UserAgent}}` |
|
|
99
101
|
| `--tls-cert` | Path to TLS certificate file. Enables HTTPS (requires `--tls-key`). | `""` |
|
|
@@ -156,6 +158,8 @@ This is useful for:
|
|
|
156
158
|
|
|
157
159
|
Example: `/api:http://localhost:8080`
|
|
158
160
|
|
|
161
|
+
Unix socket example: `/api:unix:///tmp/app.sock`
|
|
162
|
+
|
|
159
163
|
_Note: This format automatically enables `change_origin` and `strip_prefix`._
|
|
160
164
|
|
|
161
165
|
#### Advanced Format (Key-Value)
|
|
@@ -164,11 +168,72 @@ _Note: This format automatically enables `change_origin` and `strip_prefix`._
|
|
|
164
168
|
|
|
165
169
|
Parameters:
|
|
166
170
|
- `path`: The virtual path on the current server to match.
|
|
167
|
-
- `url`: The upstream URL to forward requests to.
|
|
171
|
+
- `url`: The upstream URL to forward requests to. Supports `http://...`, `https://...`, and `unix:///path.sock` for HTTP over Unix domain sockets.
|
|
168
172
|
- `change_origin`: Whether to rewrite the `Host` header to match the upstream URL. **Default: `true`**.
|
|
169
173
|
- `strip_prefix`: Whether to strip the matched path prefix before forwarding the request. **Default: `true`**.
|
|
170
174
|
- `method(s)`: pipe-separated list of HTTP methods to proxy. If specified, only these methods will be proxied. Others will pass through to local file serving or return 405. **Default: all methods**.
|
|
171
175
|
|
|
176
|
+
### YAML Config
|
|
177
|
+
|
|
178
|
+
For larger setups, you can keep server options in YAML and load them with `--config`.
|
|
179
|
+
|
|
180
|
+
An example config template is included at `docs/static-serve.example.yaml`. It shows a fuller setup with SPA, proxy, mount, TLS, and CORS settings, but you will need to update the sample paths and upstreams for your environment before using it.
|
|
181
|
+
|
|
182
|
+
```yaml
|
|
183
|
+
address: ":3001"
|
|
184
|
+
root_dir: "./"
|
|
185
|
+
spa: false
|
|
186
|
+
log_level: info
|
|
187
|
+
|
|
188
|
+
proxies:
|
|
189
|
+
- path: /
|
|
190
|
+
url: unix:///tmp/nextjs.sock
|
|
191
|
+
- path: /dify/console/api
|
|
192
|
+
url: http://192.168.0.57:5001/console/api
|
|
193
|
+
strip_prefix: true
|
|
194
|
+
- path: /dify/api
|
|
195
|
+
url: http://192.168.0.57:5001/api
|
|
196
|
+
strip_prefix: true
|
|
197
|
+
|
|
198
|
+
mounts:
|
|
199
|
+
- src: ./assets
|
|
200
|
+
dst: /static
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Run it with:
|
|
204
|
+
|
|
205
|
+
```sh
|
|
206
|
+
static-serve --config ./static-serve.yaml
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
CLI scalar flags override the YAML values:
|
|
210
|
+
|
|
211
|
+
```sh
|
|
212
|
+
static-serve --config ./static-serve.yaml --address :4000 ./dist
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Repeated route flags append after the YAML lists:
|
|
216
|
+
|
|
217
|
+
```sh
|
|
218
|
+
static-serve --config ./static-serve.yaml --proxy /:unix:///tmp/nextjs.sock --mount ./extra-assets:/extra
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Supported YAML fields mirror the existing CLI options:
|
|
222
|
+
|
|
223
|
+
- `address`
|
|
224
|
+
- `root_dir`
|
|
225
|
+
- `spa`
|
|
226
|
+
- `log_level`
|
|
227
|
+
- `logger_format`
|
|
228
|
+
- `tls_cert`
|
|
229
|
+
- `tls_key`
|
|
230
|
+
- `cors`
|
|
231
|
+
- `cors_allow_origins`
|
|
232
|
+
- `cors_allow_credentials`
|
|
233
|
+
- `cors_max_age`
|
|
234
|
+
- `proxies`
|
|
235
|
+
- `mounts`
|
|
236
|
+
|
|
172
237
|
### Examples
|
|
173
238
|
|
|
174
239
|
**Serve current directory on port 8080:**
|
|
@@ -209,14 +274,21 @@ static-serve --mount "src=./config.json,dst=/api/config"
|
|
|
209
274
|
```
|
|
210
275
|
Requests to `http://localhost:3000/api/users` will be forwarded to `http://localhost:8080/api/users` (if no local file exists).
|
|
211
276
|
|
|
212
|
-
3. **
|
|
277
|
+
3. **Unix Socket Upstream**: Forward `/api` to an HTTP server listening on a Unix domain socket.
|
|
278
|
+
```sh
|
|
279
|
+
static-serve --proxy "/api:unix:///tmp/app.sock"
|
|
280
|
+
static-serve --proxy "path=/api,url=unix:///tmp/app.sock"
|
|
281
|
+
```
|
|
282
|
+
Requests to `http://localhost:3000/api/users` will be forwarded over the Unix socket to `/users` (if no local file exists).
|
|
283
|
+
|
|
284
|
+
4. **Method Filtering**: Only proxy POST and PUT requests to the upstream server.
|
|
213
285
|
```sh
|
|
214
286
|
static-serve --proxy "path=/api,url=http://localhost:8080,methods=POST|PUT"
|
|
215
287
|
```
|
|
216
288
|
- `GET /api/users` → serves local `./api/users` or 404
|
|
217
289
|
- `POST /api/users` → proxies to `http://localhost:8080/users` (if no local file exists)
|
|
218
290
|
|
|
219
|
-
|
|
291
|
+
5. **Local Override Pattern**: Override specific upstream assets with local versions.
|
|
220
292
|
```sh
|
|
221
293
|
# Create local override
|
|
222
294
|
mkdir -p ./assets
|
|
@@ -228,6 +300,16 @@ static-serve --mount "src=./config.json,dst=/api/config"
|
|
|
228
300
|
- `GET /assets/config.json` → serves local `./assets/config.json`
|
|
229
301
|
- `GET /assets/other.js` → proxies to `http://cdn.example.com/assets/other.js`
|
|
230
302
|
|
|
303
|
+
6. **Trace Proxy Requests**: Emit detailed per-request proxy logs such as `Proxying "GET ..."` only in trace mode.
|
|
304
|
+
```sh
|
|
305
|
+
static-serve --log-level trace --proxy "/api:http://localhost:8080"
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
7. **Show Route Wiring Details**: Use debug mode to inspect mount and proxy registration without enabling full trace noise.
|
|
309
|
+
```sh
|
|
310
|
+
static-serve --log-level debug --mount ./assets:/static --proxy "/api:http://localhost:8080"
|
|
311
|
+
```
|
|
312
|
+
|
|
231
313
|
**Serve over HTTPS:**
|
|
232
314
|
```sh
|
|
233
315
|
static-serve --tls-cert ./cert.pem --tls-key ./key.pem ./public
|
package/bin/static-serve
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// lib/npm/node-platform.ts
|
|
27
|
+
var fs = require("fs");
|
|
28
|
+
var os = require("os");
|
|
29
|
+
var path = require("path");
|
|
30
|
+
var STATIC_SERVE_BINARY_PATH = process.env.STATIC_SERVE_BINARY_PATH || STATIC_SERVE_BINARY_PATH;
|
|
31
|
+
var PACKAGE_PREFIX = "static-serve";
|
|
32
|
+
var PACKAGE_SCOPE = "@tdio";
|
|
33
|
+
var knownPackages = {
|
|
34
|
+
"darwin arm64 LE": `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-darwin-arm64`,
|
|
35
|
+
"darwin x64 LE": `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-darwin-x64`,
|
|
36
|
+
"linux arm64 LE": `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-linux-arm64`,
|
|
37
|
+
"linux x64 LE": `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-linux-x64`,
|
|
38
|
+
"win32 arm64 LE": `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-win32-arm64`,
|
|
39
|
+
"win32 x64 LE": `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-win32-x64`
|
|
40
|
+
};
|
|
41
|
+
function pkgAndSubpathForCurrentPlatform() {
|
|
42
|
+
const platformKey = `${process.platform} ${os.arch()} ${os.endianness()}`;
|
|
43
|
+
const pkg = knownPackages[platformKey];
|
|
44
|
+
if (!pkg) {
|
|
45
|
+
throw new Error(`Unsupported platform: ${platformKey}`);
|
|
46
|
+
}
|
|
47
|
+
const subpath = process.platform === "win32" ? "static-serve.exe" : "static-serve";
|
|
48
|
+
return { pkg, subpath };
|
|
49
|
+
}
|
|
50
|
+
function pkgForSomeOtherPlatform() {
|
|
51
|
+
const libMainJS = require.resolve("@tdio/static-serve");
|
|
52
|
+
const nodeModulesDirectory = path.dirname(path.dirname(path.dirname(libMainJS)));
|
|
53
|
+
if (path.basename(nodeModulesDirectory) === "node_modules") {
|
|
54
|
+
for (const platformKey in knownPackages) {
|
|
55
|
+
try {
|
|
56
|
+
const pkg = knownPackages[platformKey];
|
|
57
|
+
if (fs.existsSync(path.join(nodeModulesDirectory, pkg))) return pkg;
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
function downloadedBinPath(pkg, subpath) {
|
|
65
|
+
const staticServeLibDir = path.dirname(require.resolve("@tdio/static-serve"));
|
|
66
|
+
return path.join(staticServeLibDir, `downloaded-${pkg.replace("/", "-")}-${path.basename(subpath)}`);
|
|
67
|
+
}
|
|
68
|
+
function generateBinPath() {
|
|
69
|
+
if (STATIC_SERVE_BINARY_PATH) {
|
|
70
|
+
if (fs.existsSync(STATIC_SERVE_BINARY_PATH)) {
|
|
71
|
+
return STATIC_SERVE_BINARY_PATH;
|
|
72
|
+
}
|
|
73
|
+
console.warn(`[static-serve] Ignoring bad configuration: STATIC_SERVE_BINARY_PATH=${STATIC_SERVE_BINARY_PATH}`);
|
|
74
|
+
}
|
|
75
|
+
const { pkg, subpath } = pkgAndSubpathForCurrentPlatform();
|
|
76
|
+
let binPath;
|
|
77
|
+
try {
|
|
78
|
+
binPath = require.resolve(`${pkg}/${subpath}`);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
binPath = downloadedBinPath(pkg, subpath);
|
|
81
|
+
if (!fs.existsSync(binPath)) {
|
|
82
|
+
try {
|
|
83
|
+
require.resolve(pkg);
|
|
84
|
+
} catch {
|
|
85
|
+
const otherPkg = pkgForSomeOtherPlatform();
|
|
86
|
+
if (otherPkg) {
|
|
87
|
+
let suggestions = `
|
|
88
|
+
Specifically the "${otherPkg}" package is present but this platform
|
|
89
|
+
needs the "${pkg}" package instead. People often get into this
|
|
90
|
+
situation by installing static-serve on Windows or macOS and copying "node_modules"
|
|
91
|
+
into a Docker image that runs Linux, or by copying "node_modules" between
|
|
92
|
+
Windows and WSL environments.
|
|
93
|
+
|
|
94
|
+
If you are installing with npm, you can try not copying the "node_modules"
|
|
95
|
+
directory when you copy the files over, and running "npm ci" or "npm install"
|
|
96
|
+
on the destination platform after the copy. Or you could consider using yarn
|
|
97
|
+
instead of npm which has built-in support for installing a package on multiple
|
|
98
|
+
platforms simultaneously.
|
|
99
|
+
|
|
100
|
+
If you are installing with yarn, you can try listing both this platform and the
|
|
101
|
+
other platform in your ".yarnrc.yml" file using the "supportedArchitectures"
|
|
102
|
+
feature: https://yarnpkg.com/configuration/yarnrc/#supportedArchitectures
|
|
103
|
+
Keep in mind that this means multiple copies of static-serve will be present.
|
|
104
|
+
`;
|
|
105
|
+
const packageDarwin_x64 = `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-darwin-x64`;
|
|
106
|
+
const packageDarwin_arm64 = `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-darwin-arm64`;
|
|
107
|
+
if (pkg === packageDarwin_x64 && otherPkg === packageDarwin_arm64 || pkg === packageDarwin_arm64 && otherPkg === packageDarwin_x64) {
|
|
108
|
+
suggestions = `
|
|
109
|
+
Specifically the "${otherPkg}" package is present but this platform
|
|
110
|
+
needs the "${pkg}" package instead. People often get into this
|
|
111
|
+
situation by installing static-serve with npm running inside of Rosetta 2 and then
|
|
112
|
+
trying to use it with node running outside of Rosetta 2, or vice versa (Rosetta
|
|
113
|
+
2 is Apple's on-the-fly x86_64-to-arm64 translation service).
|
|
114
|
+
|
|
115
|
+
If you are installing with npm, you can try ensuring that both npm and node are
|
|
116
|
+
not running under Rosetta 2 and then reinstalling static-serve. This likely involves
|
|
117
|
+
changing how you installed npm and/or node. For example, installing node with
|
|
118
|
+
the universal installer here should work: https://nodejs.org/en/download/. Or
|
|
119
|
+
you could consider using yarn instead of npm which has built-in support for
|
|
120
|
+
installing a package on multiple platforms simultaneously.
|
|
121
|
+
|
|
122
|
+
If you are installing with yarn, you can try listing both "arm64" and "x64"
|
|
123
|
+
in your ".yarnrc.yml" file using the "supportedArchitectures" feature:
|
|
124
|
+
https://yarnpkg.com/configuration/yarnrc/#supportedArchitectures
|
|
125
|
+
Keep in mind that this means multiple copies of static-serve will be present.
|
|
126
|
+
`;
|
|
127
|
+
}
|
|
128
|
+
throw new Error(`
|
|
129
|
+
You installed static-serve for another platform than the one you're currently using.
|
|
130
|
+
This won't work because static-serve is written with native code and needs to
|
|
131
|
+
install a platform-specific binary executable.
|
|
132
|
+
${suggestions}
|
|
133
|
+
`);
|
|
134
|
+
}
|
|
135
|
+
throw new Error(`The package "${pkg}" could not be found, and is needed by static-serve.
|
|
136
|
+
|
|
137
|
+
If you are installing static-serve with npm, make sure that you don't specify the
|
|
138
|
+
"--no-optional" or "--omit=optional" flags. The "optionalDependencies" feature
|
|
139
|
+
of "package.json" is used by static-serve to install the correct binary executable
|
|
140
|
+
for your current platform.`);
|
|
141
|
+
}
|
|
142
|
+
throw e;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return binPath;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// lib/npm/cli.ts
|
|
149
|
+
var child_process = require("child_process");
|
|
150
|
+
var path2 = require("path");
|
|
151
|
+
var fs2 = require("fs");
|
|
152
|
+
var PACKAGE_PREFIX2 = "static-serve";
|
|
153
|
+
function getLocalBuildPath() {
|
|
154
|
+
const platform = process.platform;
|
|
155
|
+
const arch = process.arch;
|
|
156
|
+
const goOs = platform === "win32" ? "windows" : platform;
|
|
157
|
+
const goArch = arch === "x64" ? "amd64" : arch;
|
|
158
|
+
const binFile = platform === "win32" ? `${PACKAGE_PREFIX2}-${goOs}-${goArch}.exe` : `${PACKAGE_PREFIX2}-${goOs}-${goArch}`;
|
|
159
|
+
const searchPaths = [
|
|
160
|
+
path2.join(__dirname, "..", "..", "out", binFile),
|
|
161
|
+
// from lib/npm/
|
|
162
|
+
path2.join(__dirname, "..", "..", "..", "out", binFile)
|
|
163
|
+
// from npm/static-serve/bin/
|
|
164
|
+
];
|
|
165
|
+
for (const p of searchPaths) {
|
|
166
|
+
if (fs2.existsSync(p)) {
|
|
167
|
+
return p;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return "";
|
|
171
|
+
}
|
|
172
|
+
var binaryPath;
|
|
173
|
+
try {
|
|
174
|
+
binaryPath = generateBinPath();
|
|
175
|
+
} catch (err) {
|
|
176
|
+
const localPath = getLocalBuildPath();
|
|
177
|
+
if (localPath) {
|
|
178
|
+
binaryPath = localPath;
|
|
179
|
+
} else {
|
|
180
|
+
console.error(`Failed to locate binary for ${process.platform}-${process.arch}.`);
|
|
181
|
+
console.error(`Error: ${err.message}`);
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
var child = child_process.spawn(binaryPath, process.argv.slice(2), {
|
|
186
|
+
stdio: "inherit"
|
|
187
|
+
});
|
|
188
|
+
child.on("exit", (code) => {
|
|
189
|
+
process.exit(code ?? 0);
|
|
190
|
+
});
|
package/install.js
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// lib/npm/node-platform.ts
|
|
27
|
+
var fs = require("fs");
|
|
28
|
+
var os = require("os");
|
|
29
|
+
var path = require("path");
|
|
30
|
+
var STATIC_SERVE_BINARY_PATH = process.env.STATIC_SERVE_BINARY_PATH || STATIC_SERVE_BINARY_PATH;
|
|
31
|
+
var isValidBinaryPath = (x) => !!x && fs.existsSync(x);
|
|
32
|
+
var PACKAGE_PREFIX = "static-serve";
|
|
33
|
+
var PACKAGE_SCOPE = "@tdio";
|
|
34
|
+
var knownPackages = {
|
|
35
|
+
"darwin arm64 LE": `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-darwin-arm64`,
|
|
36
|
+
"darwin x64 LE": `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-darwin-x64`,
|
|
37
|
+
"linux arm64 LE": `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-linux-arm64`,
|
|
38
|
+
"linux x64 LE": `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-linux-x64`,
|
|
39
|
+
"win32 arm64 LE": `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-win32-arm64`,
|
|
40
|
+
"win32 x64 LE": `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-win32-x64`
|
|
41
|
+
};
|
|
42
|
+
function pkgAndSubpathForCurrentPlatform() {
|
|
43
|
+
const platformKey = `${process.platform} ${os.arch()} ${os.endianness()}`;
|
|
44
|
+
const pkg = knownPackages[platformKey];
|
|
45
|
+
if (!pkg) {
|
|
46
|
+
throw new Error(`Unsupported platform: ${platformKey}`);
|
|
47
|
+
}
|
|
48
|
+
const subpath = process.platform === "win32" ? "static-serve.exe" : "static-serve";
|
|
49
|
+
return { pkg, subpath };
|
|
50
|
+
}
|
|
51
|
+
function downloadedBinPath(pkg, subpath) {
|
|
52
|
+
const staticServeLibDir = path.dirname(require.resolve("@tdio/static-serve"));
|
|
53
|
+
return path.join(staticServeLibDir, `downloaded-${pkg.replace("/", "-")}-${path.basename(subpath)}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// lib/npm/install.ts
|
|
57
|
+
var fs2 = require("fs");
|
|
58
|
+
var os2 = require("os");
|
|
59
|
+
var path2 = require("path");
|
|
60
|
+
var zlib = require("zlib");
|
|
61
|
+
var https = require("https");
|
|
62
|
+
var child_process = require("child_process");
|
|
63
|
+
var versionFromPackageJSON = require(path2.join(__dirname, "package.json")).version;
|
|
64
|
+
var toPath = path2.join(__dirname, "bin", "static-serve");
|
|
65
|
+
var isToPathJS = true;
|
|
66
|
+
function validateBinaryVersion(...command) {
|
|
67
|
+
command.push("-v");
|
|
68
|
+
let stdout;
|
|
69
|
+
try {
|
|
70
|
+
stdout = child_process.execFileSync(command.shift(), command, {
|
|
71
|
+
// Without this, this install script strangely crashes with the error
|
|
72
|
+
// "EACCES: permission denied, write" but only on Ubuntu Linux when node is
|
|
73
|
+
// installed from the Snap Store. This is not a problem when you download
|
|
74
|
+
// the official version of node. The problem appears to be that stderr
|
|
75
|
+
// (i.e. file descriptor 2) isn't writable?
|
|
76
|
+
stdio: "pipe"
|
|
77
|
+
}).toString().trim();
|
|
78
|
+
} catch (err) {
|
|
79
|
+
if (os2.platform() === "darwin" && /_SecTrustEvaluateWithError/.test(err + "")) {
|
|
80
|
+
let osVersion = "this version of macOS";
|
|
81
|
+
try {
|
|
82
|
+
osVersion = "macOS " + child_process.execFileSync("sw_vers", ["-productVersion"]).toString().trim();
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
85
|
+
throw new Error(`The "static-serve" package cannot be installed because ${osVersion} is too outdated.
|
|
86
|
+
|
|
87
|
+
The Go compiler (which static-serve relies on) no longer supports ${osVersion},
|
|
88
|
+
which means the "static-serve" binary executable can't be run. You can either:
|
|
89
|
+
|
|
90
|
+
* Update your version of macOS to one that the Go compiler supports
|
|
91
|
+
* Build static-serve yourself using an older version of the Go compiler
|
|
92
|
+
`);
|
|
93
|
+
}
|
|
94
|
+
throw err;
|
|
95
|
+
}
|
|
96
|
+
const versionMatch = stdout.match(/version\s+([^\s,]+)/);
|
|
97
|
+
if (versionMatch && versionMatch[1] !== versionFromPackageJSON) {
|
|
98
|
+
throw new Error(`Expected ${JSON.stringify(versionFromPackageJSON)} but got ${JSON.stringify(versionMatch[1])}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function isYarn() {
|
|
102
|
+
const { npm_config_user_agent } = process.env;
|
|
103
|
+
if (npm_config_user_agent) {
|
|
104
|
+
return /\byarn\//.test(npm_config_user_agent);
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
function fetch(url) {
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
https.get(url, (res) => {
|
|
111
|
+
if ((res.statusCode === 301 || res.statusCode === 302) && res.headers.location)
|
|
112
|
+
return fetch(res.headers.location).then(resolve, reject);
|
|
113
|
+
if (res.statusCode !== 200)
|
|
114
|
+
return reject(new Error(`Server responded with ${res.statusCode}`));
|
|
115
|
+
let chunks = [];
|
|
116
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
117
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
118
|
+
}).on("error", reject);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function extractFileFromTarGzip(buffer, subpath) {
|
|
122
|
+
try {
|
|
123
|
+
buffer = zlib.unzipSync(buffer);
|
|
124
|
+
} catch (err) {
|
|
125
|
+
throw new Error(`Invalid gzip data in archive: ${err && err.message || err}`);
|
|
126
|
+
}
|
|
127
|
+
let str = (i, n) => String.fromCharCode(...buffer.subarray(i, i + n)).replace(/\0.*$/, "");
|
|
128
|
+
let offset = 0;
|
|
129
|
+
subpath = `package/${subpath}`;
|
|
130
|
+
while (offset < buffer.length) {
|
|
131
|
+
let name = str(offset, 100);
|
|
132
|
+
let size = parseInt(str(offset + 124, 12), 8);
|
|
133
|
+
offset += 512;
|
|
134
|
+
if (!isNaN(size)) {
|
|
135
|
+
if (name === subpath) return buffer.subarray(offset, offset + size);
|
|
136
|
+
offset += size + 511 & ~511;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
throw new Error(`Could not find ${JSON.stringify(subpath)} in archive`);
|
|
140
|
+
}
|
|
141
|
+
function installUsingNPM(pkg, subpath, binPath) {
|
|
142
|
+
const env = { ...process.env, npm_config_global: void 0 };
|
|
143
|
+
const staticServeLibDir = path2.dirname(require.resolve("@tdio/static-serve"));
|
|
144
|
+
const installDir = path2.join(staticServeLibDir, "npm-install");
|
|
145
|
+
fs2.mkdirSync(installDir, { recursive: true });
|
|
146
|
+
try {
|
|
147
|
+
fs2.writeFileSync(path2.join(installDir, "package.json"), "{}");
|
|
148
|
+
child_process.execSync(
|
|
149
|
+
`npm install --loglevel=error --prefer-offline --no-audit --progress=false ${pkg}@${versionFromPackageJSON}`,
|
|
150
|
+
{ cwd: installDir, stdio: "pipe", env }
|
|
151
|
+
);
|
|
152
|
+
const installedBinPath = path2.join(installDir, "node_modules", pkg, subpath);
|
|
153
|
+
fs2.renameSync(installedBinPath, binPath);
|
|
154
|
+
} finally {
|
|
155
|
+
try {
|
|
156
|
+
removeRecursive(installDir);
|
|
157
|
+
} catch {
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function removeRecursive(dir) {
|
|
162
|
+
for (const entry of fs2.readdirSync(dir)) {
|
|
163
|
+
const entryPath = path2.join(dir, entry);
|
|
164
|
+
let stats;
|
|
165
|
+
try {
|
|
166
|
+
stats = fs2.lstatSync(entryPath);
|
|
167
|
+
} catch {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (stats.isDirectory()) removeRecursive(entryPath);
|
|
171
|
+
else fs2.unlinkSync(entryPath);
|
|
172
|
+
}
|
|
173
|
+
fs2.rmdirSync(dir);
|
|
174
|
+
}
|
|
175
|
+
function applyManualBinaryPathOverride(overridePath) {
|
|
176
|
+
const pathString = JSON.stringify(overridePath);
|
|
177
|
+
fs2.writeFileSync(toPath, `#!/usr/bin/env node
|
|
178
|
+
require('child_process').execFileSync(${pathString}, process.argv.slice(2), { stdio: 'inherit' });
|
|
179
|
+
`);
|
|
180
|
+
const libMain = path2.join(__dirname, "lib", "main.js");
|
|
181
|
+
const code = fs2.readFileSync(libMain, "utf8");
|
|
182
|
+
fs2.writeFileSync(libMain, `var STATIC_SERVE_BINARY_PATH = ${pathString};
|
|
183
|
+
${code}`);
|
|
184
|
+
}
|
|
185
|
+
function maybeOptimizePackage(binPath) {
|
|
186
|
+
if (os2.platform() !== "win32" && !isYarn()) {
|
|
187
|
+
const tempPath = path2.join(__dirname, "bin-static-serve");
|
|
188
|
+
try {
|
|
189
|
+
fs2.linkSync(binPath, tempPath);
|
|
190
|
+
fs2.renameSync(tempPath, toPath);
|
|
191
|
+
isToPathJS = false;
|
|
192
|
+
fs2.unlinkSync(tempPath);
|
|
193
|
+
} catch {
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async function downloadDirectlyFromNPM(pkg, subpath, binPath) {
|
|
198
|
+
const pkgName = pkg.replace("@tdio/", "");
|
|
199
|
+
const url = `https://registry.npmjs.org/${pkg}/-/${pkgName}-${versionFromPackageJSON}.tgz`;
|
|
200
|
+
console.error(`[static-serve] Trying to download ${JSON.stringify(url)}`);
|
|
201
|
+
try {
|
|
202
|
+
fs2.writeFileSync(binPath, extractFileFromTarGzip(await fetch(url), subpath));
|
|
203
|
+
fs2.chmodSync(binPath, 493);
|
|
204
|
+
} catch (e) {
|
|
205
|
+
console.error(`[static-serve] Failed to download ${JSON.stringify(url)}: ${e && e.message || e}`);
|
|
206
|
+
throw e;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
async function checkAndPreparePackage() {
|
|
210
|
+
if (isValidBinaryPath(STATIC_SERVE_BINARY_PATH)) {
|
|
211
|
+
if (!fs2.existsSync(STATIC_SERVE_BINARY_PATH)) {
|
|
212
|
+
console.warn(`[static-serve] Ignoring bad configuration: STATIC_SERVE_BINARY_PATH=${STATIC_SERVE_BINARY_PATH}`);
|
|
213
|
+
} else {
|
|
214
|
+
applyManualBinaryPathOverride(STATIC_SERVE_BINARY_PATH);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const { pkg, subpath } = pkgAndSubpathForCurrentPlatform();
|
|
219
|
+
let binPath;
|
|
220
|
+
let downloadedBinPathToCleanup;
|
|
221
|
+
try {
|
|
222
|
+
binPath = require.resolve(`${pkg}/${subpath}`);
|
|
223
|
+
} catch (e) {
|
|
224
|
+
console.error(`[static-serve] Failed to find package "${pkg}" on the file system
|
|
225
|
+
|
|
226
|
+
This can happen if you use the "--no-optional" flag. The "optionalDependencies"
|
|
227
|
+
package.json feature is used by static-serve to install the correct binary executable
|
|
228
|
+
for your current platform. This install script will now attempt to work around
|
|
229
|
+
this. If that fails, you need to remove the "--no-optional" flag to use static-serve.
|
|
230
|
+
`);
|
|
231
|
+
binPath = downloadedBinPath(pkg, subpath);
|
|
232
|
+
try {
|
|
233
|
+
console.error(`[static-serve] Trying to install package "${pkg}" using npm`);
|
|
234
|
+
installUsingNPM(pkg, subpath, binPath);
|
|
235
|
+
} catch (e2) {
|
|
236
|
+
console.error(`[static-serve] Failed to install package "${pkg}" using npm: ${e2 && e2.message || e2}`);
|
|
237
|
+
try {
|
|
238
|
+
await downloadDirectlyFromNPM(pkg, subpath, binPath);
|
|
239
|
+
downloadedBinPathToCleanup = binPath;
|
|
240
|
+
} catch (e3) {
|
|
241
|
+
throw new Error(`Failed to install package "${pkg}"`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
maybeOptimizePackage(binPath);
|
|
246
|
+
if (downloadedBinPathToCleanup && !isToPathJS) {
|
|
247
|
+
try {
|
|
248
|
+
fs2.unlinkSync(downloadedBinPathToCleanup);
|
|
249
|
+
} catch {
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
checkAndPreparePackage().then(() => {
|
|
254
|
+
if (isToPathJS) {
|
|
255
|
+
validateBinaryVersion(process.execPath, toPath);
|
|
256
|
+
} else {
|
|
257
|
+
validateBinaryVersion(toPath);
|
|
258
|
+
}
|
|
259
|
+
});
|
package/main.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// lib/npm/main.ts
|
|
21
|
+
var main_exports = {};
|
|
22
|
+
__export(main_exports, {
|
|
23
|
+
default: () => main_default
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(main_exports);
|
|
26
|
+
var main_default = {};
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tdio/static-serve",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5-dev.5",
|
|
4
4
|
"description": "A simple, lightweight static file server written in Go, designed with features for modern web application serving",
|
|
5
|
+
"main": "main.js",
|
|
5
6
|
"bin": {
|
|
6
|
-
"static-serve": "
|
|
7
|
+
"static-serve": "bin/static-serve"
|
|
7
8
|
},
|
|
8
9
|
"author": "allex <allex.wxn@gmail.com> (http://iallex.com/)",
|
|
9
10
|
"repository": {
|
|
@@ -20,15 +21,22 @@
|
|
|
20
21
|
"arm64"
|
|
21
22
|
],
|
|
22
23
|
"files": [
|
|
23
|
-
"bin
|
|
24
|
+
"bin",
|
|
25
|
+
"install.js"
|
|
24
26
|
],
|
|
25
27
|
"license": "MIT",
|
|
28
|
+
"scripts": {
|
|
29
|
+
"postinstall": "node install.js"
|
|
30
|
+
},
|
|
26
31
|
"optionalDependencies": {
|
|
27
|
-
"@tdio/static-serve-darwin-x64": "0.0.
|
|
28
|
-
"@tdio/static-serve-darwin-arm64": "0.0.
|
|
29
|
-
"@tdio/static-serve-linux-x64": "0.0.
|
|
30
|
-
"@tdio/static-serve-linux-arm64": "0.0.
|
|
31
|
-
"@tdio/static-serve-win32-x64": "0.0.
|
|
32
|
-
"@tdio/static-serve-win32-arm64": "0.0.
|
|
32
|
+
"@tdio/static-serve-darwin-x64": "0.0.5-dev.5",
|
|
33
|
+
"@tdio/static-serve-darwin-arm64": "0.0.5-dev.5",
|
|
34
|
+
"@tdio/static-serve-linux-x64": "0.0.5-dev.5",
|
|
35
|
+
"@tdio/static-serve-linux-arm64": "0.0.5-dev.5",
|
|
36
|
+
"@tdio/static-serve-win32-x64": "0.0.5-dev.5",
|
|
37
|
+
"@tdio/static-serve-win32-arm64": "0.0.5-dev.5"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
33
41
|
}
|
|
34
42
|
}
|
package/bin/cli.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const { spawn } = require('child_process');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
|
|
7
|
-
const PACKAGE_PREFIX = 'static-serve'; // Must match build-npm.js
|
|
8
|
-
const PACKAGE_SCOPE = '@tdio'; // Must match build-npm.js
|
|
9
|
-
|
|
10
|
-
// Map generic 'x64' to Node's arch if needed, but usually they match.
|
|
11
|
-
// Node: x64, arm64, ia32, etc.
|
|
12
|
-
const platform = process.platform;
|
|
13
|
-
const arch = process.arch;
|
|
14
|
-
|
|
15
|
-
const targetPackage = `${PACKAGE_SCOPE}/${PACKAGE_PREFIX}-${platform}-${arch}`
|
|
16
|
-
|
|
17
|
-
let binaryPath;
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
// Resolve the package.json of the platform-specific package
|
|
21
|
-
// This throws if the package is not installed
|
|
22
|
-
const pkgJsonPath = require.resolve(`${targetPackage}/package.json`);
|
|
23
|
-
const pkgDir = path.dirname(pkgJsonPath);
|
|
24
|
-
|
|
25
|
-
// Binary name is predictable: static-serve on Unix, static-serve.exe on Windows
|
|
26
|
-
const binFile = platform === 'win32' ? `${PACKAGE_PREFIX}.exe` : PACKAGE_PREFIX;
|
|
27
|
-
binaryPath = path.join(pkgDir, binFile);
|
|
28
|
-
|
|
29
|
-
} catch (err) {
|
|
30
|
-
// Fallback: Check if we are running from the source repo/local build
|
|
31
|
-
// Useful for development
|
|
32
|
-
const localBuildPath = path.join(__dirname, '..', 'out', `${PACKAGE_PREFIX}-${platform === 'win32' ? 'windows' : platform}-${arch === 'x64' ? 'amd64' : arch}${platform === 'win32' ? '.exe' : ''}`);
|
|
33
|
-
|
|
34
|
-
if (fs.existsSync(localBuildPath)) {
|
|
35
|
-
binaryPath = localBuildPath;
|
|
36
|
-
} else {
|
|
37
|
-
console.error(`Failed to locate binary for ${platform}-${arch}.`);
|
|
38
|
-
console.error(`Tried package: ${targetPackage}`);
|
|
39
|
-
console.error(`Error: ${err.message}`);
|
|
40
|
-
process.exit(1);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const child = spawn(binaryPath, process.argv.slice(2), {
|
|
45
|
-
stdio: 'inherit'
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
child.on('exit', (code) => {
|
|
49
|
-
process.exit(code);
|
|
50
|
-
});
|
|
51
|
-
|