@simplysm/storage 13.0.96 → 13.0.98
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 +108 -152
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,223 +1,179 @@
|
|
|
1
1
|
# @simplysm/storage
|
|
2
2
|
|
|
3
|
-
FTP, FTPS, SFTP
|
|
3
|
+
Storage Module (node) -- FTP, FTPS, and SFTP storage client with a unified interface and factory pattern.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install @simplysm/storage
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## API Overview
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
### Types
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
| API | Type | Description |
|
|
16
|
+
|-----|------|-------------|
|
|
17
|
+
| `StorageProtocol` | type | Protocol type: `"ftp"`, `"ftps"`, `"sftp"` |
|
|
18
|
+
| `StorageConnConfig` | interface | Connection configuration (host, port, user, password) |
|
|
19
|
+
| `FileInfo` | interface | File entry info (`name`, `isFile`) |
|
|
20
|
+
| `StorageClient` | interface | Unified storage client interface |
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
await storage.put("/local/file.zip", "/remote/file.zip");
|
|
26
|
-
await storage.uploadDir("/local/dist", "/remote/www");
|
|
27
|
-
const files = await storage.list("/remote/www");
|
|
28
|
-
const exists = await storage.exists("/remote/file.zip");
|
|
29
|
-
});
|
|
30
|
-
// 콜백 종료 시 연결 자동 해제 (예외 발생해도 보장)
|
|
31
|
-
```
|
|
22
|
+
### Factory
|
|
23
|
+
|
|
24
|
+
| API | Type | Description |
|
|
25
|
+
|-----|------|-------------|
|
|
26
|
+
| `StorageFactory` | class | Factory that creates and manages storage connections |
|
|
27
|
+
|
|
28
|
+
### Clients
|
|
32
29
|
|
|
33
|
-
|
|
30
|
+
| API | Type | Description |
|
|
31
|
+
|-----|------|-------------|
|
|
32
|
+
| `FtpStorageClient` | class | FTP/FTPS storage client (basic-ftp) |
|
|
33
|
+
| `SftpStorageClient` | class | SFTP storage client (ssh2-sftp-client) |
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
## `StorageProtocol`
|
|
36
36
|
|
|
37
37
|
```typescript
|
|
38
38
|
type StorageProtocol = "ftp" | "ftps" | "sftp";
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|-----|------|----------------|
|
|
43
|
-
| `"ftp"` | File Transfer Protocol | `FtpStorageClient(secure=false)` |
|
|
44
|
-
| `"ftps"` | FTP over SSL/TLS | `FtpStorageClient(secure=true)` |
|
|
45
|
-
| `"sftp"` | SSH File Transfer Protocol | `SftpStorageClient` |
|
|
46
|
-
|
|
47
|
-
### StorageConnConfig
|
|
41
|
+
## `StorageConnConfig`
|
|
48
42
|
|
|
49
43
|
```typescript
|
|
50
44
|
interface StorageConnConfig {
|
|
51
45
|
host: string;
|
|
52
|
-
port?: number;
|
|
46
|
+
port?: number;
|
|
53
47
|
user?: string;
|
|
54
48
|
password?: string;
|
|
55
49
|
}
|
|
56
50
|
```
|
|
57
51
|
|
|
58
|
-
|
|
59
|
-
1. `~/.ssh/id_ed25519` 키 파일 자동 탐색
|
|
60
|
-
2. 키 파싱 실패 시 `SSH_AUTH_SOCK` 환경변수의 SSH 에이전트로 재시도
|
|
61
|
-
|
|
62
|
-
### FileInfo
|
|
52
|
+
## `FileInfo`
|
|
63
53
|
|
|
64
54
|
```typescript
|
|
65
55
|
interface FileInfo {
|
|
66
|
-
name: string;
|
|
67
|
-
isFile: boolean;
|
|
56
|
+
name: string;
|
|
57
|
+
isFile: boolean;
|
|
68
58
|
}
|
|
69
59
|
```
|
|
70
60
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
`@simplysm/core-common`에서 정의한 바이트 배열 타입 (`Uint8Array` 기반).
|
|
74
|
-
|
|
75
|
-
## API 레퍼런스
|
|
76
|
-
|
|
77
|
-
### StorageFactory
|
|
78
|
-
|
|
79
|
-
프로토콜에 독립적으로 스토리지 클라이언트를 생성하고 연결을 관리하는 팩토리 클래스.
|
|
80
|
-
|
|
81
|
-
#### `StorageFactory.connect<R>(type, config, fn): Promise<R>`
|
|
61
|
+
## `StorageClient`
|
|
82
62
|
|
|
83
63
|
```typescript
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
): Promise<
|
|
64
|
+
interface StorageClient {
|
|
65
|
+
connect(config: StorageConnConfig): Promise<void>;
|
|
66
|
+
mkdir(dirPath: string): Promise<void>;
|
|
67
|
+
rename(fromPath: string, toPath: string): Promise<void>;
|
|
68
|
+
list(dirPath: string): Promise<FileInfo[]>;
|
|
69
|
+
readFile(filePath: string): Promise<Bytes>;
|
|
70
|
+
exists(filePath: string): Promise<boolean>;
|
|
71
|
+
put(localPathOrBuffer: string | Bytes, storageFilePath: string): Promise<void>;
|
|
72
|
+
uploadDir(fromPath: string, toPath: string): Promise<void>;
|
|
73
|
+
remove(filePath: string): Promise<void>;
|
|
74
|
+
close(): Promise<void>;
|
|
75
|
+
}
|
|
89
76
|
```
|
|
90
77
|
|
|
91
|
-
|
|
92
|
-
- 콜백에서 예외가 발생해도 `finally`에서 연결이 안전하게 종료됨
|
|
93
|
-
- 콜백의 반환값을 그대로 반환 (제네릭 `R`)
|
|
78
|
+
## `StorageFactory`
|
|
94
79
|
|
|
95
80
|
```typescript
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
81
|
+
class StorageFactory {
|
|
82
|
+
static async connect<R>(
|
|
83
|
+
type: StorageProtocol,
|
|
84
|
+
config: StorageConnConfig,
|
|
85
|
+
fn: (storage: StorageClient) => R | Promise<R>,
|
|
86
|
+
): Promise<R>;
|
|
87
|
+
}
|
|
101
88
|
```
|
|
102
89
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
`FtpStorageClient`와 `SftpStorageClient`가 구현하는 공통 인터페이스. `StorageFactory.connect` 콜백의 `storage` 파라미터 타입이다.
|
|
106
|
-
|
|
107
|
-
| 메서드 | 시그니처 | 설명 |
|
|
108
|
-
|--------|---------|------|
|
|
109
|
-
| `connect` | `(config: StorageConnConfig) => Promise<void>` | 서버 연결. 이미 연결된 인스턴스에서 호출하면 에러 발생 |
|
|
110
|
-
| `close` | `() => Promise<void>` | 연결 종료. 이미 종료된 상태에서 호출해도 안전함 |
|
|
111
|
-
| `mkdir` | `(dirPath: string) => Promise<void>` | 디렉토리 생성 (부모 디렉토리 자동 생성) |
|
|
112
|
-
| `rename` | `(fromPath: string, toPath: string) => Promise<void>` | 파일/디렉토리 이름 변경 |
|
|
113
|
-
| `list` | `(dirPath: string) => Promise<FileInfo[]>` | 디렉토리 내 항목 목록 조회 |
|
|
114
|
-
| `readFile` | `(filePath: string) => Promise<Bytes>` | 원격 파일을 바이트 배열로 읽기 |
|
|
115
|
-
| `exists` | `(filePath: string) => Promise<boolean>` | 파일/디렉토리 존재 여부 확인 |
|
|
116
|
-
| `put` | `(localPathOrBuffer: string \| Bytes, remotePath: string) => Promise<void>` | 로컬 파일 경로 또는 바이트 데이터를 원격 경로에 업로드 |
|
|
117
|
-
| `uploadDir` | `(fromPath: string, toPath: string) => Promise<void>` | 로컬 디렉토리 전체를 원격 경로에 업로드 |
|
|
118
|
-
| `remove` | `(filePath: string) => Promise<void>` | 원격 파일 삭제 |
|
|
119
|
-
|
|
120
|
-
#### 메서드별 주의사항
|
|
121
|
-
|
|
122
|
-
**`exists`**: 부모 디렉토리가 존재하지 않아도 `false` 반환. 네트워크 오류/권한 오류 등 모든 예외에 대해서도 `false` 반환.
|
|
123
|
-
- FTP: `size()` 명령으로 파일 확인 (O(1)), 실패 시 부모 디렉토리 `list()`로 폴백
|
|
124
|
-
- SFTP: `exists()` 내장 메서드 사용 (반환값 `false | 'd' | '-' | 'l'`)
|
|
125
|
-
|
|
126
|
-
**`mkdir`**: 부모 디렉토리가 없으면 재귀적으로 생성한다.
|
|
127
|
-
|
|
128
|
-
**`put`**: 첫 번째 인자로 로컬 파일 경로(string) 또는 바이트 데이터(Bytes)를 받는다.
|
|
129
|
-
- SFTP는 파일 경로 전달 시 `fastPut` 사용 (병렬 전송으로 더 빠름)
|
|
130
|
-
|
|
131
|
-
**`connect`**: 이미 연결된 인스턴스에서 중복 호출하면 `SdError` 발생. 반드시 `close()` 후 재연결해야 한다.
|
|
90
|
+
Creates a storage connection, executes the callback, and automatically closes the connection. The connection is closed even if the callback throws an exception. This is the recommended way to use storage clients.
|
|
132
91
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
FTP/FTPS 프로토콜 클라이언트. 내부적으로 `basic-ftp` 라이브러리를 사용한다.
|
|
92
|
+
## `FtpStorageClient`
|
|
136
93
|
|
|
137
94
|
```typescript
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
95
|
+
class FtpStorageClient implements StorageClient {
|
|
96
|
+
constructor(secure?: boolean);
|
|
97
|
+
async connect(config: StorageConnConfig): Promise<void>;
|
|
98
|
+
async mkdir(dirPath: string): Promise<void>;
|
|
99
|
+
async rename(fromPath: string, toPath: string): Promise<void>;
|
|
100
|
+
async list(dirPath: string): Promise<FileInfo[]>;
|
|
101
|
+
async readFile(filePath: string): Promise<Bytes>;
|
|
102
|
+
async exists(filePath: string): Promise<boolean>;
|
|
103
|
+
async put(localPathOrBuffer: string | Bytes, storageFilePath: string): Promise<void>;
|
|
104
|
+
async uploadDir(fromPath: string, toPath: string): Promise<void>;
|
|
105
|
+
async remove(filePath: string): Promise<void>;
|
|
106
|
+
close(): Promise<void>;
|
|
107
|
+
}
|
|
143
108
|
```
|
|
144
109
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
### SftpStorageClient
|
|
110
|
+
FTP/FTPS storage client. The `secure` constructor parameter controls FTPS mode. Use `StorageFactory.connect` instead of direct usage for automatic connection lifecycle management.
|
|
148
111
|
|
|
149
|
-
|
|
112
|
+
## `SftpStorageClient`
|
|
150
113
|
|
|
151
114
|
```typescript
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
115
|
+
class SftpStorageClient implements StorageClient {
|
|
116
|
+
async connect(config: StorageConnConfig): Promise<void>;
|
|
117
|
+
async mkdir(dirPath: string): Promise<void>;
|
|
118
|
+
async rename(fromPath: string, toPath: string): Promise<void>;
|
|
119
|
+
async list(dirPath: string): Promise<FileInfo[]>;
|
|
120
|
+
async readFile(filePath: string): Promise<Bytes>;
|
|
121
|
+
async exists(filePath: string): Promise<boolean>;
|
|
122
|
+
async put(localPathOrBuffer: string | Bytes, storageFilePath: string): Promise<void>;
|
|
123
|
+
async uploadDir(fromPath: string, toPath: string): Promise<void>;
|
|
124
|
+
async remove(filePath: string): Promise<void>;
|
|
125
|
+
async close(): Promise<void>;
|
|
126
|
+
}
|
|
155
127
|
```
|
|
156
128
|
|
|
157
|
-
|
|
158
|
-
1. `password`가 있으면 비밀번호 인증
|
|
159
|
-
2. `password`가 없으면 키 기반 인증:
|
|
160
|
-
- `~/.ssh/id_ed25519` 키 파일 + SSH 에이전트(`SSH_AUTH_SOCK`) 시도
|
|
161
|
-
- 키 파싱 실패 시 SSH 에이전트만으로 재시도
|
|
129
|
+
SFTP storage client. Supports password authentication and SSH key/agent authentication. Use `StorageFactory.connect` instead of direct usage for automatic connection lifecycle management.
|
|
162
130
|
|
|
163
|
-
##
|
|
131
|
+
## Usage Examples
|
|
164
132
|
|
|
165
|
-
###
|
|
133
|
+
### Upload files via StorageFactory (recommended)
|
|
166
134
|
|
|
167
135
|
```typescript
|
|
168
|
-
|
|
169
|
-
// 로컬 파일 업로드
|
|
170
|
-
await storage.put("/local/path/file.txt", "/remote/path/file.txt");
|
|
171
|
-
|
|
172
|
-
// 바이트 데이터 직접 업로드
|
|
173
|
-
const data = new TextEncoder().encode("hello");
|
|
174
|
-
await storage.put(data, "/remote/path/hello.txt");
|
|
175
|
-
|
|
176
|
-
// 파일 읽기
|
|
177
|
-
const content = await storage.readFile("/remote/path/file.txt");
|
|
178
|
-
});
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
### 디렉토리 관리
|
|
136
|
+
import { StorageFactory } from "@simplysm/storage";
|
|
182
137
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
await storage.
|
|
190
|
-
|
|
191
|
-
// 디렉토리 목록 조회
|
|
192
|
-
const items = await storage.list("/remote/www");
|
|
193
|
-
for (const item of items) {
|
|
194
|
-
// item.name: 이름, item.isFile: 파일 여부
|
|
195
|
-
}
|
|
138
|
+
await StorageFactory.connect("sftp", {
|
|
139
|
+
host: "example.com",
|
|
140
|
+
user: "deploy",
|
|
141
|
+
password: "secret",
|
|
142
|
+
}, async (storage) => {
|
|
143
|
+
await storage.mkdir("/var/www/app");
|
|
144
|
+
await storage.put("/local/dist/bundle.js", "/var/www/app/bundle.js");
|
|
196
145
|
});
|
|
146
|
+
// Connection is automatically closed
|
|
197
147
|
```
|
|
198
148
|
|
|
199
|
-
###
|
|
149
|
+
### List remote directory
|
|
200
150
|
|
|
201
151
|
```typescript
|
|
202
|
-
|
|
203
|
-
if (await storage.exists("/remote/old-file.txt")) {
|
|
204
|
-
await storage.remove("/remote/old-file.txt");
|
|
205
|
-
}
|
|
152
|
+
import { StorageFactory } from "@simplysm/storage";
|
|
206
153
|
|
|
207
|
-
|
|
154
|
+
const files = await StorageFactory.connect("ftp", {
|
|
155
|
+
host: "files.example.com",
|
|
156
|
+
user: "admin",
|
|
157
|
+
password: "pass",
|
|
158
|
+
}, async (storage) => {
|
|
159
|
+
return await storage.list("/uploads");
|
|
208
160
|
});
|
|
161
|
+
|
|
162
|
+
for (const file of files) {
|
|
163
|
+
// file.name, file.isFile
|
|
164
|
+
}
|
|
209
165
|
```
|
|
210
166
|
|
|
211
|
-
###
|
|
167
|
+
### Upload entire directory via FTPS
|
|
212
168
|
|
|
213
169
|
```typescript
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
170
|
+
import { StorageFactory } from "@simplysm/storage";
|
|
171
|
+
|
|
172
|
+
await StorageFactory.connect("ftps", {
|
|
173
|
+
host: "secure.example.com",
|
|
218
174
|
user: "deploy",
|
|
219
|
-
|
|
175
|
+
password: "secret",
|
|
220
176
|
}, async (storage) => {
|
|
221
|
-
await storage.uploadDir("/local/
|
|
177
|
+
await storage.uploadDir("/local/dist", "/remote/app");
|
|
222
178
|
});
|
|
223
179
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/storage",
|
|
3
|
-
"version": "13.0.
|
|
3
|
+
"version": "13.0.98",
|
|
4
4
|
"description": "Simplysm Package - Storage Module (node)",
|
|
5
5
|
"author": "simplysm",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"basic-ftp": "^5.2.0",
|
|
23
23
|
"ssh2-sftp-client": "^12.1.0",
|
|
24
|
-
"@simplysm/core-common": "13.0.
|
|
24
|
+
"@simplysm/core-common": "13.0.98"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/ssh2-sftp-client": "^9.0.6"
|