fsd-fs 0.14.0 → 0.15.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/LICENSE +1 -1
- package/README.md +66 -16
- package/index.d.ts +138 -0
- package/lib/index.js +44 -43
- package/package.json +9 -5
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2026 Liang Xingchen https://github.com/liangxingchen
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -1,29 +1,79 @@
|
|
|
1
1
|
# fsd-fs
|
|
2
|
-
FSD 本地磁盘文件读写适配器。
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
const FSD = require('fsd');
|
|
6
|
-
const FSAdapter = require('fsd-fs');
|
|
3
|
+
FSD 本地文件系统适配器 - 提供对服务器磁盘文件的读写访问。
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/fsd-fs)
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
## 概述
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
`fsd-fs` 是 `fsd` 核心库的本地文件系统适配器,提供完整的文件和目录操作能力。
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
### 核心特性
|
|
15
12
|
|
|
13
|
+
- ✅ 完整的文件读写操作
|
|
14
|
+
- ✅ 目录管理(创建、删除、遍历)
|
|
15
|
+
- ✅ 流式读写(大文件处理)
|
|
16
|
+
- ✅ 分段上传(大文件优化)
|
|
17
|
+
- ✅ 递归目录列表
|
|
18
|
+
- ✅ Glob 模式匹配
|
|
19
|
+
- ✅ 文件权限控制
|
|
20
|
+
- ✅ 并发控制优化
|
|
21
|
+
|
|
22
|
+
## 安装
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install fsd-fs
|
|
16
26
|
```
|
|
17
27
|
|
|
18
|
-
|
|
28
|
+
## 配置
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import FSD from 'fsd';
|
|
32
|
+
import FSAdapter from 'fsd-fs';
|
|
33
|
+
|
|
34
|
+
// 创建适配器
|
|
35
|
+
const adapter = new FSAdapter({
|
|
36
|
+
root: '/app/uploads', // 必需:本地存储根路径
|
|
37
|
+
mode: 0o644, // 可选:创建文件权限(默认 0o644)
|
|
38
|
+
tmpdir: '/tmp/fsd-multipart', // 可选:临时目录(分段上传时使用,默认系统临时目录)
|
|
39
|
+
urlPrefix: 'https://cdn.example.com' // 可选:URL 前缀(生成访问链接时使用)
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// 创建 FSD 实例
|
|
43
|
+
const fsd = FSD({ adapter });
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 配置选项说明
|
|
47
|
+
|
|
48
|
+
| 选项 | 类型 | 必需 | 默认值 | 说明 |
|
|
49
|
+
|------|------|------|--------|------|
|
|
50
|
+
| `root` | string | 是 | - | 本地存储根路径,所有文件操作限制在此目录下 |
|
|
51
|
+
| `mode` | number | 否 | 0o644 | 创建文件时的权限模式(八进制) |
|
|
52
|
+
| `tmpdir` | string | 否 | os.tmpdir() | 分段上传时的临时文件存储目录 |
|
|
53
|
+
| `urlPrefix` | string | 否 | - | URL 前缀,用于生成访问链接,通常配合 CDN 或反向代理使用 |
|
|
54
|
+
|
|
55
|
+
### 文件权限模式
|
|
56
|
+
|
|
57
|
+
文件权限使用八进制表示法:
|
|
58
|
+
|
|
59
|
+
| 模式 | 说明 |
|
|
60
|
+
|------|------|
|
|
61
|
+
| 0o644 | rw-r--r-- (用户读写,组和其他只读) - 最常用 |
|
|
62
|
+
| 0o755 | rwxr-xr-x (用户读写执行,组和其他读执行) - 目录常用 |
|
|
63
|
+
| 0o600 | rw------- (仅用户可读写) - 敏感文件 |
|
|
64
|
+
| 0o666 | rw-rw-rw- (用户、组、其他都可读写) - 默认值 |
|
|
19
65
|
|
|
20
|
-
|
|
66
|
+
权限位说明:
|
|
67
|
+
- `4` = read (读)
|
|
68
|
+
- `2` = write (写)
|
|
69
|
+
- `1` = execute (执行)
|
|
70
|
+
- `0` = 无权限
|
|
21
71
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
| tmpdir | string | | 临时目录,用于分段上传时暂存文件,如不使用分段上传,可省略 |
|
|
27
|
-
| urlPrefix | string | | URL前缀,用于生成下载链接 |
|
|
72
|
+
示例 `0o644`:
|
|
73
|
+
- 用户: 4+2+0 = 6 (rw)
|
|
74
|
+
- 组: 4+0+0 = 4 (r--)
|
|
75
|
+
- 其他: 4+0+0 = 4 (r--)
|
|
28
76
|
|
|
77
|
+
## License
|
|
29
78
|
|
|
79
|
+
MIT
|
package/index.d.ts
CHANGED
|
@@ -1,10 +1,148 @@
|
|
|
1
1
|
import { Adapter } from 'fsd';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* FSAdapter 配置选项
|
|
5
|
+
*
|
|
6
|
+
* 本地文件系统适配器的初始化配置。
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const adapter = new FSAdapter({
|
|
11
|
+
* root: '/app/uploads',
|
|
12
|
+
* mode: 0o644,
|
|
13
|
+
* tmpdir: '/tmp/fsd-tmp',
|
|
14
|
+
* urlPrefix: 'https://cdn.example.com'
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
3
18
|
export interface FSAdapterOptions {
|
|
19
|
+
/**
|
|
20
|
+
* 本地存储根路径(必需)
|
|
21
|
+
*
|
|
22
|
+
* 所有文件操作都会在此根路径下进行。
|
|
23
|
+
* 此路径必须是绝对路径,并且适配器有读取/写入权限。
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* // Linux/Mac
|
|
28
|
+
* root: '/app/uploads'
|
|
29
|
+
*
|
|
30
|
+
* // Windows
|
|
31
|
+
* root: 'C:\\app\\uploads'
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* 确保此目录存在且有适当的读写权限。
|
|
36
|
+
*/
|
|
4
37
|
root: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 创建文件的权限模式(可选)
|
|
41
|
+
*
|
|
42
|
+
* 默认值:`0o644` (rw-rw-rw-)
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* mode: 0o644, // rw-r--r-- (用户读写,组和其他只读)
|
|
47
|
+
* mode: 0o755, // rwxr-xr-x (用户读写执行,组和其他读执行)
|
|
48
|
+
* mode: 0o600, // rw------- (仅用户可读写)
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* 使用八进制表示法(0o 前缀)或十进制都可以。
|
|
53
|
+
*/
|
|
5
54
|
mode?: number;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* URL 前缀(可选)
|
|
58
|
+
*
|
|
59
|
+
* 用于生成访问链接时添加前缀。
|
|
60
|
+
* 通常配合 CDN 或反向代理使用。
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* urlPrefix: 'https://cdn.example.com',
|
|
65
|
+
* // file.createUrl() 返回: https://cdn.example.com/uploads/file.txt
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @remarks
|
|
69
|
+
* 尾部会自动去除 `/`,例如 `'https://cdn.com/'` 会被标准化为 `'https://cdn.com'`。
|
|
70
|
+
*/
|
|
6
71
|
urlPrefix?: string;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 临时目录(可选)
|
|
75
|
+
*
|
|
76
|
+
* 用于分段上传时暂存分片文件。
|
|
77
|
+
* 如果不使用分段上传功能,可以省略此选项。
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* tmpdir: '/tmp/fsd-multipart',
|
|
82
|
+
* // 或使用系统默认临时目录
|
|
83
|
+
* tmpdir: os.tmpdir()
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @remarks
|
|
87
|
+
* 默认值:系统临时目录(通过 `os.tmpdir()` 获取)。
|
|
88
|
+
* 确保临时目录有足够的磁盘空间用于存储分片文件。
|
|
89
|
+
*/
|
|
7
90
|
tmpdir?: string;
|
|
8
91
|
}
|
|
9
92
|
|
|
93
|
+
/**
|
|
94
|
+
* 本地文件系统适配器
|
|
95
|
+
*
|
|
96
|
+
* 提供对服务器本地磁盘文件的读写访问。
|
|
97
|
+
*
|
|
98
|
+
* @remarks
|
|
99
|
+
* ### 特性
|
|
100
|
+
* - 支持完整的文件和目录操作
|
|
101
|
+
* - 支持流式读写
|
|
102
|
+
* - 支持分段上传(大文件)
|
|
103
|
+
* - 支持递归目录列表
|
|
104
|
+
* - 使用 glob 模式匹配
|
|
105
|
+
*
|
|
106
|
+
* ### 权限要求
|
|
107
|
+
* - `root` 目录必须有读写权限
|
|
108
|
+
* - `tmpdir` 目录(用于分段上传)必须有读写权限
|
|
109
|
+
*
|
|
110
|
+
* ### 性能优化
|
|
111
|
+
* - 使用 `mapLimit` 限制并发操作,避免文件系统过载
|
|
112
|
+
* - 使用 `glob` 进行高效的目录遍历
|
|
113
|
+
*
|
|
114
|
+
* ### 分段上传机制
|
|
115
|
+
* 1. 调用 `initMultipartUpload()` 初始化任务
|
|
116
|
+
* 2. 每个分片写入到 `tmpdir` 下的临时文件
|
|
117
|
+
* 3. 调用 `completeMultipartUpload()` 时,所有临时文件会被顺序追加到目标文件
|
|
118
|
+
* 4. 完成后临时文件会被自动删除
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* import FSAdapter from 'fsd-fs';
|
|
123
|
+
* import FSD from 'fsd';
|
|
124
|
+
*
|
|
125
|
+
* // 创建适配器
|
|
126
|
+
* const adapter = new FSAdapter({
|
|
127
|
+
* root: '/app/uploads',
|
|
128
|
+
* mode: 0o644,
|
|
129
|
+
* tmpdir: '/tmp/fsd-tmp'
|
|
130
|
+
* });
|
|
131
|
+
*
|
|
132
|
+
* // 创建 FSD 实例
|
|
133
|
+
* const fsd = FSD({ adapter });
|
|
134
|
+
*
|
|
135
|
+
* // 基本操作
|
|
136
|
+
* await fsd('/test.txt').write('Hello, FS!');
|
|
137
|
+
* const content = await fsd('/test.txt').read('utf8');
|
|
138
|
+
*
|
|
139
|
+
* // 分段上传大文件
|
|
140
|
+
* const file = fsd('/large-file.dat');
|
|
141
|
+
* const tasks = await file.initMultipartUpload(3);
|
|
142
|
+
* for (let i = 0; i < tasks.length; i++) {
|
|
143
|
+
* await file.writePart(tasks[i], getDataForPart(i));
|
|
144
|
+
* }
|
|
145
|
+
* await file.completeMultipartUpload(['part://...', 'part://...', 'part://...']);
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
10
148
|
export default class FSAdapter extends Adapter<FSAdapterOptions> {}
|
package/lib/index.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const os_1 = tslib_1.__importDefault(require("os"));
|
|
5
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
6
|
+
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
7
|
+
const is_stream_1 = tslib_1.__importDefault(require("is-stream"));
|
|
7
8
|
const glob_1 = require("glob");
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const debug =
|
|
9
|
+
const mapLimit_1 = tslib_1.__importDefault(require("async/mapLimit"));
|
|
10
|
+
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
11
|
+
const debug = (0, debug_1.default)('fsd-fs');
|
|
11
12
|
async function getStat(path) {
|
|
12
13
|
try {
|
|
13
|
-
return await
|
|
14
|
+
return await fs_1.default.promises.stat(path);
|
|
14
15
|
}
|
|
15
16
|
catch (_e) {
|
|
16
17
|
return null;
|
|
@@ -24,8 +25,8 @@ class FSAdapter {
|
|
|
24
25
|
this._options = Object.assign({
|
|
25
26
|
urlPrefix: '',
|
|
26
27
|
root: '/',
|
|
27
|
-
mode:
|
|
28
|
-
tmpdir:
|
|
28
|
+
mode: 0o644,
|
|
29
|
+
tmpdir: os_1.default.tmpdir()
|
|
29
30
|
}, options);
|
|
30
31
|
let { urlPrefix } = this._options;
|
|
31
32
|
if (urlPrefix.endsWith('/')) {
|
|
@@ -36,13 +37,13 @@ class FSAdapter {
|
|
|
36
37
|
async append(path, data) {
|
|
37
38
|
debug('append %s', path);
|
|
38
39
|
let { root, mode } = this._options;
|
|
39
|
-
let p =
|
|
40
|
-
if (
|
|
40
|
+
let p = path_1.default.join(root, path);
|
|
41
|
+
if (is_stream_1.default.readable(data)) {
|
|
41
42
|
let stream = data;
|
|
42
43
|
await new Promise((resolve, reject) => {
|
|
43
|
-
|
|
44
|
+
fs_1.default.stat(p, (error, stat) => {
|
|
44
45
|
let start = error ? 0 : stat.size;
|
|
45
|
-
let writeStream =
|
|
46
|
+
let writeStream = fs_1.default.createWriteStream(p, {
|
|
46
47
|
flags: 'a',
|
|
47
48
|
mode,
|
|
48
49
|
start
|
|
@@ -52,33 +53,33 @@ class FSAdapter {
|
|
|
52
53
|
});
|
|
53
54
|
return;
|
|
54
55
|
}
|
|
55
|
-
await
|
|
56
|
+
await fs_1.default.promises.appendFile(p, data, { mode });
|
|
56
57
|
}
|
|
57
58
|
async createReadStream(path, options) {
|
|
58
59
|
debug('createReadStream %s options: %o', path, options);
|
|
59
|
-
let p =
|
|
60
|
-
return
|
|
60
|
+
let p = path_1.default.join(this._options.root, path);
|
|
61
|
+
return fs_1.default.createReadStream(p, options);
|
|
61
62
|
}
|
|
62
63
|
async createWriteStream(path, options) {
|
|
63
64
|
debug('createWriteStream %s', path);
|
|
64
65
|
let p;
|
|
65
66
|
if (path.startsWith('task://')) {
|
|
66
|
-
p =
|
|
67
|
+
p = path_1.default.join(this._options.tmpdir, path.replace('task://', ''));
|
|
67
68
|
}
|
|
68
69
|
else {
|
|
69
|
-
p =
|
|
70
|
+
p = path_1.default.join(this._options.root, path);
|
|
70
71
|
}
|
|
71
|
-
return
|
|
72
|
+
return fs_1.default.createWriteStream(p, options);
|
|
72
73
|
}
|
|
73
74
|
async unlink(path) {
|
|
74
75
|
debug('unlink %s', path);
|
|
75
|
-
let p =
|
|
76
|
-
await
|
|
76
|
+
let p = path_1.default.join(this._options.root, path);
|
|
77
|
+
await fs_1.default.promises.rm(p, { recursive: true, force: true });
|
|
77
78
|
}
|
|
78
79
|
async mkdir(path, recursive) {
|
|
79
80
|
debug('mkdir %s', path);
|
|
80
|
-
let fsPath =
|
|
81
|
-
await
|
|
81
|
+
let fsPath = path_1.default.join(this._options.root, path);
|
|
82
|
+
await fs_1.default.promises.mkdir(fsPath, { recursive });
|
|
82
83
|
}
|
|
83
84
|
async readdir(path, recursion) {
|
|
84
85
|
debug('readdir %s', path);
|
|
@@ -86,13 +87,13 @@ class FSAdapter {
|
|
|
86
87
|
recursion = '**/*';
|
|
87
88
|
}
|
|
88
89
|
let pattern = recursion || '*';
|
|
89
|
-
let p =
|
|
90
|
+
let p = path_1.default.join(this._options.root, path);
|
|
90
91
|
let files = await (0, glob_1.glob)(pattern, {
|
|
91
92
|
cwd: p
|
|
92
93
|
});
|
|
93
94
|
files.reverse();
|
|
94
|
-
return await
|
|
95
|
-
let filePath =
|
|
95
|
+
return await (0, mapLimit_1.default)(files, 20, async (name) => {
|
|
96
|
+
let filePath = path_1.default.join(p, name);
|
|
96
97
|
let stat = await getStat(filePath);
|
|
97
98
|
let isDir = stat.isDirectory();
|
|
98
99
|
return {
|
|
@@ -112,44 +113,44 @@ class FSAdapter {
|
|
|
112
113
|
async copy(path, dest) {
|
|
113
114
|
debug('copy %s to %s', path, dest);
|
|
114
115
|
const { root } = this._options;
|
|
115
|
-
let from =
|
|
116
|
-
let to =
|
|
116
|
+
let from = path_1.default.join(root, path);
|
|
117
|
+
let to = path_1.default.join(root, dest);
|
|
117
118
|
if (!(await getStat(from)))
|
|
118
119
|
throw new Error(`source file '${path}' is not exists!`);
|
|
119
|
-
await
|
|
120
|
+
await fs_1.default.promises.cp(from, to, { recursive: true, force: true });
|
|
120
121
|
}
|
|
121
122
|
async rename(path, dest) {
|
|
122
123
|
debug('rename %s to %s', path, dest);
|
|
123
|
-
let from =
|
|
124
|
-
let to =
|
|
125
|
-
await
|
|
124
|
+
let from = path_1.default.join(this._options.root, path);
|
|
125
|
+
let to = path_1.default.join(this._options.root, dest);
|
|
126
|
+
await fs_1.default.promises.rename(from, to);
|
|
126
127
|
}
|
|
127
128
|
async exists(path) {
|
|
128
129
|
debug('check exists %s', path);
|
|
129
|
-
let p =
|
|
130
|
+
let p = path_1.default.join(this._options.root, path);
|
|
130
131
|
return !!(await getStat(p));
|
|
131
132
|
}
|
|
132
133
|
async isFile(path) {
|
|
133
134
|
debug('check is file %s', path);
|
|
134
|
-
let p =
|
|
135
|
+
let p = path_1.default.join(this._options.root, path);
|
|
135
136
|
let stat = await getStat(p);
|
|
136
137
|
return stat?.isFile();
|
|
137
138
|
}
|
|
138
139
|
async isDirectory(path) {
|
|
139
140
|
debug('check is directory %s', path);
|
|
140
|
-
let p =
|
|
141
|
+
let p = path_1.default.join(this._options.root, path);
|
|
141
142
|
let stat = await getStat(p);
|
|
142
143
|
return stat?.isDirectory();
|
|
143
144
|
}
|
|
144
145
|
async size(path) {
|
|
145
146
|
debug('get file size %s', path);
|
|
146
|
-
let p =
|
|
147
|
+
let p = path_1.default.join(this._options.root, path);
|
|
147
148
|
let stat = await getStat(p);
|
|
148
149
|
return stat.size;
|
|
149
150
|
}
|
|
150
151
|
async lastModified(path) {
|
|
151
152
|
debug('get file lastModified %s', path);
|
|
152
|
-
let p =
|
|
153
|
+
let p = path_1.default.join(this._options.root, path);
|
|
153
154
|
let stat = await getStat(p);
|
|
154
155
|
return stat.mtime;
|
|
155
156
|
}
|
|
@@ -178,27 +179,27 @@ class FSAdapter {
|
|
|
178
179
|
for (let part of parts) {
|
|
179
180
|
if (!part.startsWith('part://'))
|
|
180
181
|
throw new Error(`${part} is not a part file`);
|
|
181
|
-
let partPath =
|
|
182
|
+
let partPath = path_1.default.join(this._options.tmpdir, part.replace('part://', ''));
|
|
182
183
|
let stat = await getStat(partPath);
|
|
183
184
|
if (!stat)
|
|
184
185
|
throw new Error(`part file ${part} is not exists`);
|
|
185
186
|
partPaths.push({ file: partPath, size: stat.size });
|
|
186
187
|
}
|
|
187
|
-
let p =
|
|
188
|
+
let p = path_1.default.join(this._options.root, path);
|
|
188
189
|
let start = 0;
|
|
189
190
|
for (let info of partPaths) {
|
|
190
|
-
let writeStream =
|
|
191
|
+
let writeStream = fs_1.default.createWriteStream(p, {
|
|
191
192
|
flags: 'a',
|
|
192
193
|
start
|
|
193
194
|
});
|
|
194
|
-
let stream =
|
|
195
|
+
let stream = fs_1.default.createReadStream(info.file);
|
|
195
196
|
await new Promise((resolve, reject) => {
|
|
196
197
|
stream.pipe(writeStream).on('close', resolve).on('error', reject);
|
|
197
198
|
});
|
|
198
199
|
start += info.size;
|
|
199
200
|
writeStream.close();
|
|
200
201
|
}
|
|
201
|
-
partPaths.forEach((info) =>
|
|
202
|
+
partPaths.forEach((info) => fs_1.default.promises.rm(info.file, { force: true }));
|
|
202
203
|
}
|
|
203
204
|
}
|
|
204
205
|
exports.default = FSAdapter;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fsd-fs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "File system adapter for fsd",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -9,13 +9,17 @@
|
|
|
9
9
|
"prepublish": "npm run build"
|
|
10
10
|
},
|
|
11
11
|
"repository": "https://github.com/liangxingchen/fsd/tree/master/packages/fsd-fs",
|
|
12
|
-
"author":
|
|
12
|
+
"author": {
|
|
13
|
+
"name": "Liang",
|
|
14
|
+
"email": "liang@miaomo.cn",
|
|
15
|
+
"url": "https://github.com/liangxingchen"
|
|
16
|
+
},
|
|
13
17
|
"license": "MIT",
|
|
14
18
|
"dependencies": {
|
|
15
19
|
"async": "*",
|
|
16
|
-
"debug": "^4.4.
|
|
17
|
-
"glob": "^10.
|
|
20
|
+
"debug": "^4.4.3",
|
|
21
|
+
"glob": "^10.5.0",
|
|
18
22
|
"is-stream": "^2.0.1"
|
|
19
23
|
},
|
|
20
|
-
"gitHead": "
|
|
24
|
+
"gitHead": "ea754919fb95b49deffd529b5c01c66da0dc08f9"
|
|
21
25
|
}
|