fs-object-storage 1.0.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/.github/workflows/npm-publish.yml +41 -0
- package/LICENSE +21 -0
- package/README.md +287 -0
- package/docker-compose.yml +24 -0
- package/package.json +45 -0
- package/quick-test.js +36 -0
- package/samples/fs-minio-test.js +135 -0
- package/samples/memfs-sample.js +44 -0
- package/samples/minio-connection-test.js +66 -0
- package/samples/minio-sample.js +64 -0
- package/src/index.d.ts +98 -0
- package/src/index.js +17 -0
- package/src/lib/ErrorHandler.js +149 -0
- package/src/lib/FsMinioClient.js +480 -0
- package/src/lib/PathConverter.js +209 -0
- package/src/lib/StreamConverter.js +281 -0
- package/test-package.json +9 -0
- package/tests/unit/ErrorHandler.test.js +117 -0
- package/tests/unit/PathConverter.test.js +224 -0
- package/tests/unit/StreamConverter.test.js +267 -0
- package/unit-tests.js +101 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
|
|
2
|
+
# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
|
|
3
|
+
|
|
4
|
+
name: Node.js Package
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
release:
|
|
8
|
+
types: [created]
|
|
9
|
+
push:
|
|
10
|
+
branches:
|
|
11
|
+
- main
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
build:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
|
|
17
|
+
strategy:
|
|
18
|
+
matrix:
|
|
19
|
+
node-version: [16.x]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
23
|
+
uses: actions/setup-node@v4
|
|
24
|
+
with:
|
|
25
|
+
node-version: ${{ matrix.node-version }}
|
|
26
|
+
- run: npm ci
|
|
27
|
+
- run: npm test
|
|
28
|
+
|
|
29
|
+
publish-npm:
|
|
30
|
+
needs: build
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v4
|
|
34
|
+
- uses: actions/setup-node@v4
|
|
35
|
+
with:
|
|
36
|
+
node-version: '16.x'
|
|
37
|
+
registry-url: https://registry.npmjs.org/
|
|
38
|
+
- run: npm ci
|
|
39
|
+
- run: npm publish
|
|
40
|
+
env:
|
|
41
|
+
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 nojaja
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# fs-object-storage
|
|
2
|
+
|
|
3
|
+
Node.js fs互換APIでオブジェクトストレージ(MinIO/S3)を操作するライブラリです。
|
|
4
|
+
|
|
5
|
+
既存のファイルシステムコードを最小限の変更でオブジェクトストレージに対応させることができます。
|
|
6
|
+
|
|
7
|
+
## 🚀 特徴
|
|
8
|
+
|
|
9
|
+
- **fs互換API**: 標準のNode.js fsモジュールと同じインターフェース
|
|
10
|
+
- **MinIO/S3対応**: MinIOおよびAmazon S3と互換性
|
|
11
|
+
- **型安全性**: TypeScriptサポート(型定義含む)
|
|
12
|
+
- **ES Modules**: モダンなES Modules形式
|
|
13
|
+
- **ストリーミング**: 大容量ファイルのストリーミング処理対応
|
|
14
|
+
- **エラーハンドリング**: fs互換のエラーコード変換
|
|
15
|
+
|
|
16
|
+
## 📦 インストール
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install fs-object-storage
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 🏃♂️ クイックスタート
|
|
23
|
+
|
|
24
|
+
### 基本的な使用方法
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
import { FsMinioClient } from 'fs-object-storage';
|
|
28
|
+
|
|
29
|
+
// MinIO/S3クライアントの設定
|
|
30
|
+
const client = new FsMinioClient({
|
|
31
|
+
endPoint: 'localhost',
|
|
32
|
+
port: 9000,
|
|
33
|
+
useSSL: false,
|
|
34
|
+
accessKey: 'minioadmin',
|
|
35
|
+
secretKey: 'minioadmin123'
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// ファイル操作(fs互換)
|
|
39
|
+
try {
|
|
40
|
+
// ファイル書き込み
|
|
41
|
+
await client.writeFile('/mybucket/path/to/file.txt', 'Hello, World!');
|
|
42
|
+
|
|
43
|
+
// ファイル読み込み
|
|
44
|
+
const data = await client.readFile('/mybucket/path/to/file.txt', 'utf8');
|
|
45
|
+
console.log(data); // "Hello, World!"
|
|
46
|
+
|
|
47
|
+
// ファイル存在確認
|
|
48
|
+
const exists = await client.exists('/mybucket/path/to/file.txt');
|
|
49
|
+
console.log(exists); // true
|
|
50
|
+
|
|
51
|
+
// ディレクトリ一覧
|
|
52
|
+
const files = await client.readdir('/mybucket/path');
|
|
53
|
+
console.log(files); // ['to/']
|
|
54
|
+
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error('エラー:', error.message);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### ストリーミング操作
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
import fs from 'fs';
|
|
64
|
+
|
|
65
|
+
// 大容量ファイルのアップロード
|
|
66
|
+
const readStream = fs.createReadStream('./large-file.zip');
|
|
67
|
+
const writeStream = await client.createWriteStream('/mybucket/uploads/large-file.zip');
|
|
68
|
+
readStream.pipe(writeStream);
|
|
69
|
+
|
|
70
|
+
// ダウンロードストリーム
|
|
71
|
+
const downloadStream = await client.createReadStream('/mybucket/uploads/large-file.zip');
|
|
72
|
+
const localWriteStream = fs.createWriteStream('./downloaded-file.zip');
|
|
73
|
+
downloadStream.pipe(localWriteStream);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 🔧 開発環境のセットアップ
|
|
77
|
+
|
|
78
|
+
### MinIO開発環境(Docker)
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# リポジトリをクローン
|
|
82
|
+
git clone <repository-url>
|
|
83
|
+
cd fs-object-storage
|
|
84
|
+
|
|
85
|
+
# 依存関係のインストール
|
|
86
|
+
npm install
|
|
87
|
+
|
|
88
|
+
# MinIO開発環境の起動
|
|
89
|
+
docker-compose up -d
|
|
90
|
+
|
|
91
|
+
# MinIO管理画面: http://localhost:9001
|
|
92
|
+
# ユーザー名: minioadmin
|
|
93
|
+
# パスワード: minioadmin123
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### テスト実行
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# 単体テスト
|
|
100
|
+
npm run test
|
|
101
|
+
|
|
102
|
+
# 統合テスト(MinIO必須)
|
|
103
|
+
npm run test:integration
|
|
104
|
+
|
|
105
|
+
# 全テスト
|
|
106
|
+
npm run test:all
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 📚 API リファレンス
|
|
110
|
+
|
|
111
|
+
### コンストラクタ
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
new FsMinioClient(options)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**options**:
|
|
118
|
+
- `endPoint`: MinIO/S3エンドポイント
|
|
119
|
+
- `port`: ポート番号
|
|
120
|
+
- `useSSL`: SSL使用フラグ
|
|
121
|
+
- `accessKey`: アクセスキー
|
|
122
|
+
- `secretKey`: シークレットキー
|
|
123
|
+
|
|
124
|
+
### ファイル操作メソッド
|
|
125
|
+
|
|
126
|
+
#### `readFile(path, encoding?)`
|
|
127
|
+
ファイルを読み込みます。
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
const data = await client.readFile('/bucket/file.txt', 'utf8');
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### `writeFile(path, data, options?)`
|
|
134
|
+
ファイルを書き込みます。
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
await client.writeFile('/bucket/file.txt', 'データ');
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### `exists(path)`
|
|
141
|
+
ファイル/ディレクトリの存在を確認します。
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
const exists = await client.exists('/bucket/file.txt');
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### `stat(path)`
|
|
148
|
+
ファイル/ディレクトリの統計情報を取得します。
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
const stats = await client.stat('/bucket/file.txt');
|
|
152
|
+
console.log(stats.size, stats.isFile(), stats.isDirectory());
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### `unlink(path)`
|
|
156
|
+
ファイルを削除します。
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
await client.unlink('/bucket/file.txt');
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### `copyFile(src, dest)`
|
|
163
|
+
ファイルをコピーします。
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
await client.copyFile('/bucket/src.txt', '/bucket/dest.txt');
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### ディレクトリ操作メソッド
|
|
170
|
+
|
|
171
|
+
#### `readdir(path)`
|
|
172
|
+
ディレクトリの内容を一覧します。
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
const files = await client.readdir('/bucket/directory');
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
#### `mkdir(path, options?)`
|
|
179
|
+
ディレクトリを作成します。
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
await client.mkdir('/bucket/new-directory', { recursive: true });
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### `rmdir(path)`
|
|
186
|
+
空のディレクトリを削除します。
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
await client.rmdir('/bucket/empty-directory');
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### ストリーム操作メソッド
|
|
193
|
+
|
|
194
|
+
#### `createReadStream(path)`
|
|
195
|
+
読み込みストリームを作成します。
|
|
196
|
+
|
|
197
|
+
```javascript
|
|
198
|
+
const stream = await client.createReadStream('/bucket/file.txt');
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### `createWriteStream(path)`
|
|
202
|
+
書き込みストリームを作成します。
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
const stream = await client.createWriteStream('/bucket/file.txt');
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## 🗺️ パス形式
|
|
209
|
+
|
|
210
|
+
ファイルパスは `/bucket/path/to/file.txt` 形式で指定します:
|
|
211
|
+
|
|
212
|
+
- 先頭の `/` は必須
|
|
213
|
+
- 最初のセグメントがバケット名
|
|
214
|
+
- それ以降がオブジェクトキー
|
|
215
|
+
|
|
216
|
+
例:
|
|
217
|
+
- `/mybucket/documents/report.pdf` → バケット: `mybucket`, キー: `documents/report.pdf`
|
|
218
|
+
- `/photos/2023/vacation.jpg` → バケット: `photos`, キー: `2023/vacation.jpg`
|
|
219
|
+
|
|
220
|
+
## 🚨 エラーハンドリング
|
|
221
|
+
|
|
222
|
+
MinIOのエラーは自動的にfs互換のエラーコードに変換されます:
|
|
223
|
+
|
|
224
|
+
```javascript
|
|
225
|
+
try {
|
|
226
|
+
await client.readFile('/bucket/nonexistent.txt');
|
|
227
|
+
} catch (error) {
|
|
228
|
+
console.log(error.code); // 'ENOENT'
|
|
229
|
+
console.log(error.errno); // -2
|
|
230
|
+
console.log(error.path); // '/bucket/nonexistent.txt'
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## 📋 対応エラーコード
|
|
235
|
+
|
|
236
|
+
| MinIOエラー | fsエラーコード | 説明 |
|
|
237
|
+
|-------------|----------------|------|
|
|
238
|
+
| NoSuchKey | ENOENT | ファイルが存在しない |
|
|
239
|
+
| NoSuchBucket | ENOENT | バケットが存在しない |
|
|
240
|
+
| AccessDenied | EACCES | アクセス権限がない |
|
|
241
|
+
| BucketAlreadyExists | EEXIST | バケットが既に存在 |
|
|
242
|
+
|
|
243
|
+
## 🔍 使用例
|
|
244
|
+
|
|
245
|
+
詳細な使用例は以下のファイルを参照してください:
|
|
246
|
+
|
|
247
|
+
- [`docs/technical/usage-examples.md`](./docs/technical/usage-examples.md) - 包括的な使用例
|
|
248
|
+
- [`samples/fs-minio-test.js`](./samples/fs-minio-test.js) - 統合テストサンプル
|
|
249
|
+
- [`quick-test.js`](./quick-test.js) - 基本動作確認
|
|
250
|
+
|
|
251
|
+
## 🏗️ アーキテクチャ
|
|
252
|
+
|
|
253
|
+
本ライブラリは以下のコンポーネントで構成されています:
|
|
254
|
+
|
|
255
|
+
- **FsMinioClient**: メインのfs互換クライアント
|
|
256
|
+
- **ErrorHandler**: MinIO→fs エラー変換
|
|
257
|
+
- **PathConverter**: ファイルパス⇔バケット/キー変換
|
|
258
|
+
- **StreamConverter**: ストリーム/データ形式変換
|
|
259
|
+
|
|
260
|
+
詳細は [`docs/technical/architecture.md`](./docs/technical/architecture.md) を参照してください。
|
|
261
|
+
|
|
262
|
+
## 🧪 テスト
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
# 単体テスト(3つのコンポーネント)
|
|
266
|
+
npm run test
|
|
267
|
+
|
|
268
|
+
# 統合テスト(MinIO接続必須)
|
|
269
|
+
npm run test:integration
|
|
270
|
+
|
|
271
|
+
# 全テスト実行
|
|
272
|
+
npm run test:all
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## 📄 ライセンス
|
|
276
|
+
|
|
277
|
+
MIT
|
|
278
|
+
|
|
279
|
+
## 🤝 コントリビューション
|
|
280
|
+
|
|
281
|
+
バグ報告や機能提案は Issue からお願いします。プルリクエストも歓迎します。
|
|
282
|
+
|
|
283
|
+
## 📞 サポート
|
|
284
|
+
|
|
285
|
+
- **ドキュメント**: [`docs/`](./docs/) フォルダ
|
|
286
|
+
- **GitHub Issues**: バグ報告・機能要求
|
|
287
|
+
- **サンプルコード**: [`samples/`](./samples/) フォルダ"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
version: '3.8'
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
minio:
|
|
5
|
+
image: minio/minio:latest
|
|
6
|
+
container_name: fs-object-storage-minio
|
|
7
|
+
ports:
|
|
8
|
+
- "9000:9000"
|
|
9
|
+
- "9001:9001"
|
|
10
|
+
environment:
|
|
11
|
+
MINIO_ROOT_USER: minioadmin
|
|
12
|
+
MINIO_ROOT_PASSWORD: minioadmin123
|
|
13
|
+
command: server /data --console-address ":9001"
|
|
14
|
+
volumes:
|
|
15
|
+
- minio_data:/data
|
|
16
|
+
healthcheck:
|
|
17
|
+
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
|
18
|
+
interval: 30s
|
|
19
|
+
timeout: 20s
|
|
20
|
+
retries: 3
|
|
21
|
+
|
|
22
|
+
volumes:
|
|
23
|
+
minio_data:
|
|
24
|
+
driver: local
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fs-object-storage",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Node.js fs compatible API for object storage (MinIO/S3)",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "src/index.d.ts",
|
|
7
|
+
"type": "module", "scripts": {
|
|
8
|
+
"test": "node --test unit-tests.js",
|
|
9
|
+
"test:integration": "node samples/fs-minio-test.js",
|
|
10
|
+
"test:all": "npm run test && npm run test:integration",
|
|
11
|
+
"dev": "node src/index.js",
|
|
12
|
+
"build": "webpack --mode production"
|
|
13
|
+
},"keywords": [
|
|
14
|
+
"filesystem",
|
|
15
|
+
"fs",
|
|
16
|
+
"object-storage",
|
|
17
|
+
"minio",
|
|
18
|
+
"s3",
|
|
19
|
+
"compatible",
|
|
20
|
+
"node",
|
|
21
|
+
"typescript"
|
|
22
|
+
],
|
|
23
|
+
"author": "nojaja <free.riccia@gmail.com> (https://github.com/nojaja)",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/nojaja/fs-object-storage.git"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/nojaja/fs-object-storage/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/nojaja/fs-object-storage#readme",
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=16.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"jest": "^28.1.3",
|
|
38
|
+
"webpack": "^5.99.8",
|
|
39
|
+
"webpack-cli": "^5.1.4"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"memfs": "^4.17.2",
|
|
43
|
+
"minio": "^8.0.5"
|
|
44
|
+
}
|
|
45
|
+
}
|
package/quick-test.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// quick-test.js - Quick test of fs-minio library
|
|
2
|
+
|
|
3
|
+
console.log('Starting fs-minio quick test...');
|
|
4
|
+
|
|
5
|
+
import { FsMinioClient } from './src/index.js';
|
|
6
|
+
|
|
7
|
+
async function quickTest() {
|
|
8
|
+
try {
|
|
9
|
+
console.log('Creating client...'); const client = new FsMinioClient({
|
|
10
|
+
endpoint: 'localhost:9000',
|
|
11
|
+
accessKey: 'minioadmin',
|
|
12
|
+
secretKey: 'minioadmin123',
|
|
13
|
+
bucket: 'fs-minio-test',
|
|
14
|
+
useSSL: false
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
console.log('Initializing client...');
|
|
18
|
+
await client.initialize();
|
|
19
|
+
console.log('Client initialized!');
|
|
20
|
+
|
|
21
|
+
console.log('Writing test file...');
|
|
22
|
+
await client.writeFile('/test.txt', 'Hello World!', 'utf8');
|
|
23
|
+
console.log('File written!');
|
|
24
|
+
|
|
25
|
+
console.log('Reading test file...');
|
|
26
|
+
const content = await client.readFile('/test.txt', 'utf8');
|
|
27
|
+
console.log('File content:', content);
|
|
28
|
+
|
|
29
|
+
console.log('Test completed successfully!');
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('Test failed:', error.message);
|
|
32
|
+
console.error('Stack:', error.stack);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
quickTest();
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// fs-minio-test.js - Test the fs-minio library implementation
|
|
2
|
+
|
|
3
|
+
import { FsMinioClient } from '../src/index.js';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
async function testFsMinioLibrary() {
|
|
7
|
+
console.log('🧪 Testing fs-minio library implementation...\n');
|
|
8
|
+
|
|
9
|
+
// Create client instance
|
|
10
|
+
const client = new FsMinioClient({
|
|
11
|
+
endpoint: 'localhost:9000',
|
|
12
|
+
accessKey: 'minioadmin',
|
|
13
|
+
secretKey: 'minioadmin123',
|
|
14
|
+
bucket: 'fs-minio-test',
|
|
15
|
+
useSSL: false,
|
|
16
|
+
prefix: 'test'
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
console.log('📝 Initializing client...');
|
|
21
|
+
await client.initialize();
|
|
22
|
+
console.log('✅ Client initialized successfully\n');
|
|
23
|
+
|
|
24
|
+
// Test 1: Write file
|
|
25
|
+
console.log('📝 Test 1: writeFile()');
|
|
26
|
+
const testContent = 'Hello from fs-minio library!\nThis is a test file.\n今日は良い天気ですね。';
|
|
27
|
+
await client.writeFile('/data/hello.txt', testContent, 'utf8');
|
|
28
|
+
console.log('✅ File written successfully\n');
|
|
29
|
+
|
|
30
|
+
// Test 2: Check if file exists
|
|
31
|
+
console.log('📝 Test 2: exists()');
|
|
32
|
+
const fileExists = await client.exists('/data/hello.txt');
|
|
33
|
+
console.log(`✅ File exists: ${fileExists}\n`);
|
|
34
|
+
|
|
35
|
+
// Test 3: Read file
|
|
36
|
+
console.log('📝 Test 3: readFile()');
|
|
37
|
+
const readContent = await client.readFile('/data/hello.txt', 'utf8');
|
|
38
|
+
console.log(`✅ File content: "${readContent}"\n`);
|
|
39
|
+
|
|
40
|
+
// Verify content matches
|
|
41
|
+
if (readContent === testContent) {
|
|
42
|
+
console.log('✅ Content matches original\n');
|
|
43
|
+
} else {
|
|
44
|
+
console.log('❌ Content does not match!\n');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Test 4: Get file stats
|
|
48
|
+
console.log('📝 Test 4: stat()');
|
|
49
|
+
const stats = await client.stat('/data/hello.txt');
|
|
50
|
+
console.log('✅ File stats:');
|
|
51
|
+
console.log(` Size: ${stats.size} bytes`);
|
|
52
|
+
console.log(` Modified: ${stats.mtime}`);
|
|
53
|
+
console.log(` Is file: ${stats.isFile()}`);
|
|
54
|
+
console.log(` Is directory: ${stats.isDirectory()}\n`);
|
|
55
|
+
|
|
56
|
+
// Test 5: Write binary file
|
|
57
|
+
console.log('📝 Test 5: writeFile() with binary data');
|
|
58
|
+
const binaryData = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]); // PNG header
|
|
59
|
+
await client.writeFile('/images/test.png', binaryData);
|
|
60
|
+
console.log('✅ Binary file written successfully\n');
|
|
61
|
+
|
|
62
|
+
// Test 6: Read binary file
|
|
63
|
+
console.log('📝 Test 6: readFile() binary data');
|
|
64
|
+
const readBinary = await client.readFile('/images/test.png');
|
|
65
|
+
console.log(`✅ Binary data read: ${readBinary.length} bytes`);
|
|
66
|
+
console.log(` First 8 bytes: ${Array.from(readBinary.slice(0, 8)).map(b => '0x' + b.toString(16).padStart(2, '0')).join(', ')}\n`);
|
|
67
|
+
|
|
68
|
+
// Test 7: Create directory
|
|
69
|
+
console.log('📝 Test 7: mkdir()');
|
|
70
|
+
await client.mkdir('/documents/projects', { recursive: true });
|
|
71
|
+
console.log('✅ Directory created successfully\n');
|
|
72
|
+
|
|
73
|
+
// Test 8: List files in root
|
|
74
|
+
console.log('📝 Test 8: readdir()');
|
|
75
|
+
const rootFiles = await client.readdir('/');
|
|
76
|
+
console.log(`✅ Root directory contents: ${JSON.stringify(rootFiles)}\n`);
|
|
77
|
+
|
|
78
|
+
// Test 9: Test error handling (non-existent file)
|
|
79
|
+
console.log('📝 Test 9: Error handling');
|
|
80
|
+
try {
|
|
81
|
+
await client.readFile('/nonexistent/file.txt');
|
|
82
|
+
console.log('❌ Should have thrown error');
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.log(`✅ Correctly threw error: ${error.code} - ${error.message}\n`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Test 10: Delete file
|
|
88
|
+
console.log('📝 Test 10: unlink()');
|
|
89
|
+
await client.unlink('/data/hello.txt');
|
|
90
|
+
console.log('✅ File deleted successfully\n');
|
|
91
|
+
|
|
92
|
+
// Test 11: Verify file is deleted
|
|
93
|
+
console.log('📝 Test 11: Verify deletion');
|
|
94
|
+
const fileExistsAfterDelete = await client.exists('/data/hello.txt');
|
|
95
|
+
console.log(`✅ File exists after delete: ${fileExistsAfterDelete}\n`);
|
|
96
|
+
|
|
97
|
+
// Test 12: Test streams
|
|
98
|
+
console.log('📝 Test 12: createReadStream()');
|
|
99
|
+
const streamContent = 'This is stream test content\nLine 2\nLine 3';
|
|
100
|
+
await client.writeFile('/streams/test.txt', streamContent);
|
|
101
|
+
|
|
102
|
+
const readStream = await client.createReadStream('/streams/test.txt');
|
|
103
|
+
const chunks = [];
|
|
104
|
+
|
|
105
|
+
readStream.on('data', (chunk) => {
|
|
106
|
+
chunks.push(chunk);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
await new Promise((resolve, reject) => {
|
|
110
|
+
readStream.on('end', () => {
|
|
111
|
+
const streamData = Buffer.concat(chunks).toString('utf8');
|
|
112
|
+
console.log(`✅ Stream content: "${streamData}"`);
|
|
113
|
+
if (streamData === streamContent) {
|
|
114
|
+
console.log('✅ Stream content matches original\n');
|
|
115
|
+
} else {
|
|
116
|
+
console.log('❌ Stream content does not match!\n');
|
|
117
|
+
}
|
|
118
|
+
resolve();
|
|
119
|
+
});
|
|
120
|
+
readStream.on('error', reject);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
console.log('🎉 All tests completed successfully!');
|
|
124
|
+
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error('❌ Test failed:', error.message);
|
|
127
|
+
if (error.originalError) {
|
|
128
|
+
console.error('Original error:', error.originalError.message);
|
|
129
|
+
}
|
|
130
|
+
console.error('Stack:', error.stack);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Run tests
|
|
135
|
+
testFsMinioLibrary().catch(console.error);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// memfsライブラリのAPI調査用サンプル
|
|
2
|
+
import { fs } from 'memfs';
|
|
3
|
+
|
|
4
|
+
console.log('=== memfs API調査 ===');
|
|
5
|
+
|
|
6
|
+
// 1. memfsの基本的なfs互換API確認
|
|
7
|
+
console.log('\n1. 利用可能なメソッド:');
|
|
8
|
+
const fsMethods = Object.getOwnPropertyNames(fs).filter(name => typeof fs[name] === 'function');
|
|
9
|
+
console.log(fsMethods.slice(0, 20)); // 最初の20個のメソッドを表示
|
|
10
|
+
|
|
11
|
+
// 2. fs.writeFileの動作確認
|
|
12
|
+
try {
|
|
13
|
+
fs.writeFileSync('/test.txt', 'Hello memfs!');
|
|
14
|
+
console.log('\n2. writeFileSync成功');
|
|
15
|
+
|
|
16
|
+
// 3. fs.readFileの動作確認
|
|
17
|
+
const content = fs.readFileSync('/test.txt', 'utf8');
|
|
18
|
+
console.log('3. readFileSync結果:', content);
|
|
19
|
+
|
|
20
|
+
// 4. fs.existsSyncの動作確認
|
|
21
|
+
const exists = fs.existsSync('/test.txt');
|
|
22
|
+
console.log('4. existsSync結果:', exists);
|
|
23
|
+
|
|
24
|
+
// 5. fs.statSyncの動作確認
|
|
25
|
+
const stats = fs.statSync('/test.txt');
|
|
26
|
+
console.log('5. statSync結果:', {
|
|
27
|
+
size: stats.size,
|
|
28
|
+
isFile: stats.isFile(),
|
|
29
|
+
isDirectory: stats.isDirectory()
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// 6. Promise版APIの確認
|
|
33
|
+
console.log('\n6. Promise版API確認:');
|
|
34
|
+
console.log('fs.promises利用可能:', typeof fs.promises === 'object');
|
|
35
|
+
if (fs.promises) {
|
|
36
|
+
const promiseMethods = Object.getOwnPropertyNames(fs.promises).filter(name => typeof fs.promises[name] === 'function');
|
|
37
|
+
console.log('Promise版メソッド例:', promiseMethods.slice(0, 10));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error('エラーが発生したのだ:', error.message);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
console.log('\n=== memfs調査完了 ===');
|