@remix-run/static-middleware 0.0.0 → 0.2.0
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/dist/lib/static.d.ts +11 -3
- package/dist/lib/static.d.ts.map +1 -1
- package/dist/lib/static.js +50 -8
- package/package.json +9 -5
- package/src/lib/static.ts +60 -10
package/dist/lib/static.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type FileResponseOptions } from '@remix-run/fetch-router/response-helpers';
|
|
2
1
|
import type { Middleware } from '@remix-run/fetch-router';
|
|
3
|
-
|
|
2
|
+
import { type FileResponseOptions } from '@remix-run/fetch-router/response-helpers';
|
|
3
|
+
export interface StaticFilesOptions extends FileResponseOptions {
|
|
4
4
|
/**
|
|
5
5
|
* Filter function to determine which files should be served.
|
|
6
6
|
*
|
|
@@ -8,7 +8,15 @@ export type StaticFilesOptions = FileResponseOptions & {
|
|
|
8
8
|
* @returns Whether to serve the file
|
|
9
9
|
*/
|
|
10
10
|
filter?: (path: string) => boolean;
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Files to try and serve as the index file when the request path targets a directory.
|
|
13
|
+
*
|
|
14
|
+
* - `true` (default): Use default index files `['index.html', 'index.htm']`
|
|
15
|
+
* - `false`: Disable index file serving
|
|
16
|
+
* - `string[]`: Custom list of index files to try in order
|
|
17
|
+
*/
|
|
18
|
+
index?: boolean | string[];
|
|
19
|
+
}
|
|
12
20
|
/**
|
|
13
21
|
* Creates a middleware that serves static files from the filesystem.
|
|
14
22
|
*
|
package/dist/lib/static.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../src/lib/static.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../src/lib/static.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,0CAA0C,CAAA;AAEjD,MAAM,WAAW,kBAAmB,SAAQ,mBAAmB;IAC7D;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;IAClC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAAA;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,UAAU,CA4DtF"}
|
package/dist/lib/static.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import * as fsp from 'node:fs/promises';
|
|
3
|
+
import { openFile } from '@remix-run/fs';
|
|
4
|
+
import { file as sendFile, } from '@remix-run/fetch-router/response-helpers';
|
|
3
5
|
/**
|
|
4
6
|
* Creates a middleware that serves static files from the filesystem.
|
|
5
7
|
*
|
|
@@ -26,19 +28,59 @@ import { file } from '@remix-run/fetch-router/response-helpers';
|
|
|
26
28
|
* })
|
|
27
29
|
*/
|
|
28
30
|
export function staticFiles(root, options = {}) {
|
|
29
|
-
|
|
31
|
+
// Ensure root is an absolute path
|
|
32
|
+
root = path.resolve(root);
|
|
33
|
+
let { filter, index: indexOption, ...fileOptions } = options;
|
|
34
|
+
// Normalize index option
|
|
35
|
+
let index;
|
|
36
|
+
if (indexOption === false) {
|
|
37
|
+
index = [];
|
|
38
|
+
}
|
|
39
|
+
else if (indexOption === true || indexOption === undefined) {
|
|
40
|
+
index = ['index.html', 'index.htm'];
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
index = indexOption;
|
|
44
|
+
}
|
|
30
45
|
return async (context, next) => {
|
|
31
|
-
if (context.
|
|
46
|
+
if (context.method !== 'GET' && context.method !== 'HEAD') {
|
|
32
47
|
return next();
|
|
33
48
|
}
|
|
34
49
|
let relativePath = context.url.pathname.replace(/^\/+/, '');
|
|
35
50
|
if (filter && !filter(relativePath)) {
|
|
36
51
|
return next();
|
|
37
52
|
}
|
|
38
|
-
let
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
let targetPath = path.join(root, relativePath);
|
|
54
|
+
let filePath;
|
|
55
|
+
try {
|
|
56
|
+
let stats = await fsp.stat(targetPath);
|
|
57
|
+
if (stats.isFile()) {
|
|
58
|
+
filePath = targetPath;
|
|
59
|
+
}
|
|
60
|
+
else if (stats.isDirectory()) {
|
|
61
|
+
// Try each index file in turn
|
|
62
|
+
for (let indexFile of index) {
|
|
63
|
+
let indexPath = path.join(targetPath, indexFile);
|
|
64
|
+
try {
|
|
65
|
+
let indexStats = await fsp.stat(indexPath);
|
|
66
|
+
if (indexStats.isFile()) {
|
|
67
|
+
filePath = indexPath;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Index file doesn't exist, continue to next
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Path doesn't exist or isn't accessible, fall through
|
|
79
|
+
}
|
|
80
|
+
if (filePath) {
|
|
81
|
+
let fileName = path.relative(root, filePath);
|
|
82
|
+
let file = openFile(filePath, { name: fileName });
|
|
83
|
+
return sendFile(file, context.request, fileOptions);
|
|
41
84
|
}
|
|
42
|
-
return file(fileToServe, context.request, fileOptions);
|
|
43
85
|
};
|
|
44
86
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remix-run/static-middleware",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Middleware for serving static files from the filesystem",
|
|
5
5
|
"author": "Michael Jackson <mjijackson@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,12 +28,16 @@
|
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^24.6.0",
|
|
30
30
|
"typescript": "^5.9.3",
|
|
31
|
-
"@remix-run/fetch-router": "0.
|
|
32
|
-
"@remix-run/
|
|
31
|
+
"@remix-run/fetch-router": "0.10.0",
|
|
32
|
+
"@remix-run/form-data-middleware": "0.1.0",
|
|
33
|
+
"@remix-run/lazy-file": "4.0.0",
|
|
34
|
+
"@remix-run/fs": "0.1.0",
|
|
35
|
+
"@remix-run/method-override-middleware": "0.1.0"
|
|
33
36
|
},
|
|
34
37
|
"peerDependencies": {
|
|
35
|
-
"@remix-run/fetch-router": "^0.
|
|
36
|
-
"@remix-run/
|
|
38
|
+
"@remix-run/fetch-router": "^0.10.0",
|
|
39
|
+
"@remix-run/fs": "^0.1.0",
|
|
40
|
+
"@remix-run/lazy-file": "^4.0.0"
|
|
37
41
|
},
|
|
38
42
|
"keywords": [
|
|
39
43
|
"fetch",
|
package/src/lib/static.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
import * as path from 'node:path'
|
|
2
|
+
import * as fsp from 'node:fs/promises'
|
|
3
|
+
import { openFile } from '@remix-run/fs'
|
|
4
4
|
import type { Middleware } from '@remix-run/fetch-router'
|
|
5
|
+
import {
|
|
6
|
+
file as sendFile,
|
|
7
|
+
type FileResponseOptions,
|
|
8
|
+
} from '@remix-run/fetch-router/response-helpers'
|
|
5
9
|
|
|
6
|
-
export
|
|
10
|
+
export interface StaticFilesOptions extends FileResponseOptions {
|
|
7
11
|
/**
|
|
8
12
|
* Filter function to determine which files should be served.
|
|
9
13
|
*
|
|
@@ -11,6 +15,14 @@ export type StaticFilesOptions = FileResponseOptions & {
|
|
|
11
15
|
* @returns Whether to serve the file
|
|
12
16
|
*/
|
|
13
17
|
filter?: (path: string) => boolean
|
|
18
|
+
/**
|
|
19
|
+
* Files to try and serve as the index file when the request path targets a directory.
|
|
20
|
+
*
|
|
21
|
+
* - `true` (default): Use default index files `['index.html', 'index.htm']`
|
|
22
|
+
* - `false`: Disable index file serving
|
|
23
|
+
* - `string[]`: Custom list of index files to try in order
|
|
24
|
+
*/
|
|
25
|
+
index?: boolean | string[]
|
|
14
26
|
}
|
|
15
27
|
|
|
16
28
|
/**
|
|
@@ -39,10 +51,23 @@ export type StaticFilesOptions = FileResponseOptions & {
|
|
|
39
51
|
* })
|
|
40
52
|
*/
|
|
41
53
|
export function staticFiles(root: string, options: StaticFilesOptions = {}): Middleware {
|
|
42
|
-
|
|
54
|
+
// Ensure root is an absolute path
|
|
55
|
+
root = path.resolve(root)
|
|
56
|
+
|
|
57
|
+
let { filter, index: indexOption, ...fileOptions } = options
|
|
58
|
+
|
|
59
|
+
// Normalize index option
|
|
60
|
+
let index: string[]
|
|
61
|
+
if (indexOption === false) {
|
|
62
|
+
index = []
|
|
63
|
+
} else if (indexOption === true || indexOption === undefined) {
|
|
64
|
+
index = ['index.html', 'index.htm']
|
|
65
|
+
} else {
|
|
66
|
+
index = indexOption
|
|
67
|
+
}
|
|
43
68
|
|
|
44
69
|
return async (context, next) => {
|
|
45
|
-
if (context.
|
|
70
|
+
if (context.method !== 'GET' && context.method !== 'HEAD') {
|
|
46
71
|
return next()
|
|
47
72
|
}
|
|
48
73
|
|
|
@@ -52,12 +77,37 @@ export function staticFiles(root: string, options: StaticFilesOptions = {}): Mid
|
|
|
52
77
|
return next()
|
|
53
78
|
}
|
|
54
79
|
|
|
55
|
-
let
|
|
80
|
+
let targetPath = path.join(root, relativePath)
|
|
81
|
+
let filePath: string | undefined
|
|
56
82
|
|
|
57
|
-
|
|
58
|
-
|
|
83
|
+
try {
|
|
84
|
+
let stats = await fsp.stat(targetPath)
|
|
85
|
+
|
|
86
|
+
if (stats.isFile()) {
|
|
87
|
+
filePath = targetPath
|
|
88
|
+
} else if (stats.isDirectory()) {
|
|
89
|
+
// Try each index file in turn
|
|
90
|
+
for (let indexFile of index) {
|
|
91
|
+
let indexPath = path.join(targetPath, indexFile)
|
|
92
|
+
try {
|
|
93
|
+
let indexStats = await fsp.stat(indexPath)
|
|
94
|
+
if (indexStats.isFile()) {
|
|
95
|
+
filePath = indexPath
|
|
96
|
+
break
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
// Index file doesn't exist, continue to next
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} catch {
|
|
104
|
+
// Path doesn't exist or isn't accessible, fall through
|
|
59
105
|
}
|
|
60
106
|
|
|
61
|
-
|
|
107
|
+
if (filePath) {
|
|
108
|
+
let fileName = path.relative(root, filePath)
|
|
109
|
+
let file = openFile(filePath, { name: fileName })
|
|
110
|
+
return sendFile(file, context.request, fileOptions)
|
|
111
|
+
}
|
|
62
112
|
}
|
|
63
113
|
}
|