@simplysm/storage 13.0.69 → 13.0.71

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 CHANGED
@@ -1,292 +1,33 @@
1
1
  # @simplysm/storage
2
2
 
3
- A storage client package that supports FTP, FTPS, and SFTP protocols. Through the unified `Storage` interface, you can perform file upload, download, directory manipulation and other operations with the same API regardless of protocol.
4
-
5
- Using `StorageFactory`, you can automatically manage connection/disconnection, and you can also directly instantiate `FtpStorageClient` or `SftpStorageClient` if needed.
3
+ Simplysm Package - Storage Module (node)
6
4
 
7
5
  ## Installation
8
6
 
9
- ```bash
10
- npm install @simplysm/storage
11
- # or
12
7
  pnpm add @simplysm/storage
13
- ```
14
-
15
- ## Main Modules
16
-
17
- ### Export List
18
-
19
- | Module | Type | Description |
20
- |------|------|------|
21
- | `StorageFactory` | Class | Creates clients based on storage type and automatically manages connection/disconnection |
22
- | `FtpStorageClient` | Class | FTP/FTPS protocol client (based on `basic-ftp`) |
23
- | `SftpStorageClient` | Class | SFTP protocol client (based on `ssh2-sftp-client`) |
24
- | `Storage` | Interface | Common interface implemented by all storage clients |
25
- | `StorageConnConfig` | Interface | Connection configuration |
26
- | `FileInfo` | Interface | Directory entry information |
27
- | `StorageType` | Type | Storage protocol types (`"ftp" \| "ftps" \| "sftp"`) |
28
-
29
- ## Type Definitions
30
-
31
- ### StorageConnConfig
32
-
33
- Configuration required for server connection.
34
-
35
- ```typescript
36
- interface StorageConnConfig {
37
- host: string; // Server host
38
- port?: number; // Port (FTP default: 21, SFTP default: 22)
39
- user?: string; // Username
40
- pass?: string; // Password (required for FTP/FTPS; optional for SFTP)
41
- }
42
- ```
43
-
44
- **SFTP SSH Key Authentication:**
45
- - If `pass` is omitted for SFTP connections, the client automatically attempts authentication using:
46
- 1. SSH key file at `~/.ssh/id_ed25519`
47
- 2. SSH agent (if `SSH_AUTH_SOCK` environment variable is set)
48
- - Both methods are tried in order; if the key file authentication fails (e.g., encrypted keys), the client falls back to agent-only authentication.
49
-
50
- ### FileInfo
51
-
52
- File/directory information returned by `readdir()`.
53
-
54
- ```typescript
55
- interface FileInfo {
56
- name: string; // File or directory name
57
- isFile: boolean; // true if file, false if directory
58
- }
59
- ```
60
-
61
- ### StorageType
62
-
63
- Supported storage protocol types.
64
-
65
- ```typescript
66
- type StorageType = "ftp" | "ftps" | "sftp";
67
- ```
68
-
69
- | Value | Protocol | Default Port | Description |
70
- |-----|---------|----------|------|
71
- | `"ftp"` | FTP | 21 | Unencrypted FTP |
72
- | `"ftps"` | FTPS | 21 | TLS-encrypted FTP |
73
- | `"sftp"` | SFTP | 22 | SSH-based file transfer |
74
-
75
- ### Storage Interface
76
-
77
- Common interface implemented by all storage clients (`FtpStorageClient`, `SftpStorageClient`). `Bytes` is a `Uint8Array` type alias defined in `@simplysm/core-common`.
78
-
79
- | Method | Signature | Description |
80
- |--------|---------|------|
81
- | `connect` | `(config: StorageConnConfig) => Promise<void>` | Connect to server |
82
- | `close` | `() => Promise<void>` | Close connection |
83
- | `put` | `(localPathOrBuffer: string \| Bytes, storageFilePath: string) => Promise<void>` | Upload file (local path or byte data) |
84
- | `readFile` | `(filePath: string) => Promise<Bytes>` | Download file (returns `Bytes`) |
85
- | `readdir` | `(dirPath: string) => Promise<FileInfo[]>` | List directory contents |
86
- | `remove` | `(filePath: string) => Promise<void>` | Delete file |
87
- | `exists` | `(filePath: string) => Promise<boolean>` | Check if file/directory exists |
88
- | `mkdir` | `(dirPath: string) => Promise<void>` | Create directory (recursive) |
89
- | `rename` | `(fromPath: string, toPath: string) => Promise<void>` | Rename file/directory |
90
- | `uploadDir` | `(fromPath: string, toPath: string) => Promise<void>` | Upload entire local directory to remote |
91
-
92
- ## Usage
93
-
94
- ### StorageFactory (Recommended)
95
-
96
- `StorageFactory.connect()` automatically manages connection and disconnection with a callback pattern. The connection is always closed even if an exception occurs in the callback, so it's recommended over using clients directly.
97
-
98
- ```typescript
99
- import { StorageFactory } from "@simplysm/storage";
100
-
101
- // FTP connection
102
- const result = await StorageFactory.connect("ftp", {
103
- host: "ftp.example.com",
104
- port: 21,
105
- user: "username",
106
- pass: "password",
107
- }, async (client) => {
108
- // Upload local file to remote server
109
- await client.put("/local/path/file.txt", "/remote/path/file.txt");
110
-
111
- // Upload byte data directly
112
- const data = new TextEncoder().encode("hello world");
113
- await client.put(data, "/remote/path/hello.txt");
114
-
115
- // Download remote file
116
- const content = await client.readFile("/remote/path/file.txt");
117
-
118
- // The callback's return value becomes the return value of StorageFactory.connect()
119
- return content;
120
- });
121
- ```
122
-
123
- ```typescript
124
- // FTPS connection (TLS encryption)
125
- await StorageFactory.connect("ftps", {
126
- host: "ftps.example.com",
127
- user: "username",
128
- pass: "password",
129
- }, async (client) => {
130
- await client.put("/local/file.txt", "/remote/file.txt");
131
- });
132
- ```
133
-
134
- ```typescript
135
- // SFTP connection with password
136
- await StorageFactory.connect("sftp", {
137
- host: "sftp.example.com",
138
- port: 22,
139
- user: "username",
140
- pass: "password",
141
- }, async (client) => {
142
- // List directory contents
143
- const files = await client.readdir("/remote/path");
144
- for (const file of files) {
145
- console.log(`${file.name} - ${file.isFile ? "File" : "Directory"}`);
146
- }
147
-
148
- // Upload entire directory
149
- await client.uploadDir("/local/dir", "/remote/dir");
150
- });
151
- ```
152
-
153
- ```typescript
154
- // SFTP connection with SSH key (if pass is omitted, uses ~/.ssh/id_ed25519 or SSH agent)
155
- await StorageFactory.connect("sftp", {
156
- host: "sftp.example.com",
157
- port: 22,
158
- user: "username",
159
- // No password provided - uses SSH key authentication
160
- }, async (client) => {
161
- const files = await client.readdir("/remote/path");
162
- await client.uploadDir("/local/dir", "/remote/dir");
163
- });
164
- ```
165
-
166
- ### FtpStorageClient (Direct Usage)
167
-
168
- Client that uses FTP or FTPS protocol. The `secure` parameter in the constructor determines whether to use FTPS.
169
-
170
- ```typescript
171
- import { FtpStorageClient } from "@simplysm/storage";
172
-
173
- // FTP client (secure: false is default)
174
- const client = new FtpStorageClient();
175
-
176
- // FTPS client
177
- const secureClient = new FtpStorageClient(true);
178
-
179
- await client.connect({
180
- host: "ftp.example.com",
181
- port: 21,
182
- user: "username",
183
- pass: "password",
184
- });
185
-
186
- try {
187
- // Upload file - from local file path
188
- await client.put("/local/path/file.txt", "/remote/path/file.txt");
189
-
190
- // Upload file - from Uint8Array byte data
191
- const bytes = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
192
- await client.put(bytes, "/remote/path/hello.bin");
193
-
194
- // Download file (returns Bytes, i.e. Uint8Array)
195
- const data = await client.readFile("/remote/path/file.txt");
196
- const text = new TextDecoder().decode(data);
197
-
198
- // List directory contents
199
- const files = await client.readdir("/remote/path");
200
-
201
- // Check if file/directory exists
202
- const exists = await client.exists("/remote/path/file.txt");
203
-
204
- // Create directory (creates parent directories too)
205
- await client.mkdir("/remote/new/nested/path");
206
-
207
- // Rename file
208
- await client.rename("/remote/old-name.txt", "/remote/new-name.txt");
209
-
210
- // Delete file
211
- await client.remove("/remote/path/file.txt");
212
-
213
- // Upload entire local directory to remote
214
- await client.uploadDir("/local/dir", "/remote/dir");
215
- } finally {
216
- // Connection must be closed
217
- await client.close();
218
- }
219
- ```
220
-
221
- ### SftpStorageClient (Direct Usage)
222
-
223
- Client that uses SFTP protocol. It implements the same `Storage` interface as `FtpStorageClient`, so the API is identical.
224
-
225
- ```typescript
226
- import { SftpStorageClient } from "@simplysm/storage";
227
-
228
- const client = new SftpStorageClient();
229
-
230
- // Connection with password
231
- await client.connect({
232
- host: "sftp.example.com",
233
- port: 22,
234
- user: "username",
235
- pass: "password",
236
- });
237
-
238
- try {
239
- // All methods of the Storage interface can be used identically
240
- await client.put("/local/path/file.txt", "/remote/path/file.txt");
241
- const data = await client.readFile("/remote/path/file.txt");
242
- const files = await client.readdir("/remote/path");
243
- const exists = await client.exists("/remote/path/file.txt");
244
- await client.mkdir("/remote/new/path");
245
- await client.rename("/remote/old.txt", "/remote/new.txt");
246
- await client.remove("/remote/path/file.txt");
247
- await client.uploadDir("/local/dir", "/remote/dir");
248
- } finally {
249
- await client.close();
250
- }
251
- ```
252
-
253
- ```typescript
254
- // Connection with SSH key (password omitted)
255
- const client = new SftpStorageClient();
256
-
257
- await client.connect({
258
- host: "sftp.example.com",
259
- port: 22,
260
- user: "username",
261
- // Uses ~/.ssh/id_ed25519 or SSH agent for authentication
262
- });
263
-
264
- try {
265
- await client.put("/local/path/file.txt", "/remote/path/file.txt");
266
- // ... other operations
267
- } finally {
268
- await client.close();
269
- }
270
- ```
271
8
 
272
- ## Caveats
9
+ ## Source Index
273
10
 
274
- ### Connection Management
11
+ ### Types
275
12
 
276
- - Using `StorageFactory.connect()` is recommended. The connection is automatically closed when the callback ends, and closure is guaranteed in the `finally` block even if an exception occurs.
277
- - When using clients directly, you must call `close()` with a `try/finally` pattern. Otherwise, connections may leak.
278
- - Calling `connect()` again on an already connected instance will cause an error. If reconnection is needed, call `close()` first.
279
- - Calling `close()` when already closed does not cause an error.
13
+ | Source | Exports | Description | Test |
14
+ |--------|---------|-------------|------|
15
+ | `src/types/storage-conn-config.ts` | `StorageConnConfig` | Connection config interface (host, port, user, pass) | - |
16
+ | `src/types/storage.ts` | `FileInfo`, `Storage` | Storage interface and file entry type | - |
17
+ | `src/types/storage-type.ts` | `StorageType` | Union type for supported protocols: ftp, ftps, sftp | - |
280
18
 
281
- ### exists() Behavior
19
+ ### Clients
282
20
 
283
- - FTP: Checks files with the `SIZE` command (O(1)), and on failure, lists the parent directory to check if a directory exists. Performance may degrade in directories with many entries.
284
- - SFTP: Uses `ssh2-sftp-client`'s `exists()` method, returns `true` for files (`"-"`), directories (`"d"`), and symbolic links (`"l"`).
285
- - Both implementations return `false` instead of throwing exceptions when the parent directory doesn't exist or on network/permission errors.
21
+ | Source | Exports | Description | Test |
22
+ |--------|---------|-------------|------|
23
+ | `src/clients/ftp-storage-client.ts` | `FtpStorageClient` | Storage client for FTP/FTPS protocol | `ftp-storage-client.spec.ts` |
24
+ | `src/clients/sftp-storage-client.ts` | `SftpStorageClient` | Storage client for SFTP protocol with SSH key support | `sftp-storage-client.spec.ts` |
286
25
 
287
- ### Byte Data Type
26
+ ### Factory
288
27
 
289
- - `Bytes` used in the return type of `readFile()` and input type of `put()` is a `Uint8Array` type alias defined in `@simplysm/core-common`.
28
+ | Source | Exports | Description | Test |
29
+ |--------|---------|-------------|------|
30
+ | `src/storage-factory.ts` | `StorageFactory` | Factory that creates and auto-closes storage connections | `storage-factory.spec.ts` |
290
31
 
291
32
  ## License
292
33
 
@@ -2,54 +2,54 @@ import type { Bytes } from "@simplysm/core-common";
2
2
  import type { Storage, FileInfo } from "../types/storage";
3
3
  import type { StorageConnConfig } from "../types/storage-conn-config";
4
4
  /**
5
- * FTP/FTPS 프로토콜을 사용하는 스토리지 클라이언트.
5
+ * Storage client using FTP/FTPS protocol.
6
6
  *
7
7
  * @remarks
8
- * 생성자의 `secure` 파라미터로 FTPS 사용 여부를 설정합니다.
9
- * 직접 사용보다 {@link StorageFactory.connect} 통한 사용을 권장합니다.
8
+ * The `secure` constructor parameter configures whether to use FTPS.
9
+ * Using {@link StorageFactory.connect} is recommended over direct usage.
10
10
  */
11
11
  export declare class FtpStorageClient implements Storage {
12
12
  private readonly _secure;
13
13
  private _client;
14
14
  constructor(_secure?: boolean);
15
15
  /**
16
- * FTP 서버에 연결합니다.
16
+ * Connect to the FTP server.
17
17
  *
18
18
  * @remarks
19
- * - 연결 반드시 {@link close} 연결을 종료해야 합니다.
20
- * - 동일 인스턴스에서 여러 호출하지 마세요. (연결 누수 발생)
21
- * - 자동 연결/종료 관리가 필요하면 {@link StorageFactory.connect} 사용하세요. (권장)
19
+ * - Must close the connection with {@link close} after use.
20
+ * - Do not call multiple times on the same instance (connection leak).
21
+ * - Use {@link StorageFactory.connect} for automatic connection/close management (recommended).
22
22
  */
23
23
  connect(config: StorageConnConfig): Promise<void>;
24
24
  private _requireClient;
25
- /** 디렉토리를 생성합니다. 상위 디렉토리가 없으면 함께 생성합니다. */
25
+ /** Create a directory. Creates parent directories if they do not exist. */
26
26
  mkdir(dirPath: string): Promise<void>;
27
27
  rename(fromPath: string, toPath: string): Promise<void>;
28
28
  readdir(dirPath: string): Promise<FileInfo[]>;
29
29
  readFile(filePath: string): Promise<Bytes>;
30
30
  /**
31
- * 파일 또는 디렉토리 존재 여부를 확인합니다.
31
+ * Check whether a file or directory exists.
32
32
  *
33
33
  * @remarks
34
- * 파일 확인 size() 명령으로 O(1) 성능을 제공합니다.
35
- * 디렉토리 확인 상위 디렉토리 목록을 조회하므로, 항목 수가 많으면 성능이 저하될 있습니다.
34
+ * For files, uses the size() command for O(1) performance.
35
+ * For directories, queries the parent directory listing, so performance may degrade with many entries.
36
36
  *
37
- * 슬래시가 없는 경로(예: `file.txt`) 루트 디렉토리(`/`)에서 검색합니다.
37
+ * Paths without slashes (e.g. `file.txt`) are searched in the root directory (`/`).
38
38
  *
39
- * 상위 디렉토리가 존재하지 않는 경우에도 false를 반환합니다.
40
- * 네트워크 오류, 권한 오류 모든 예외도 false를 반환합니다.
39
+ * Returns false even if the parent directory does not exist.
40
+ * Returns false for all exceptions including network errors and permission errors.
41
41
  */
42
42
  exists(filePath: string): Promise<boolean>;
43
43
  remove(filePath: string): Promise<void>;
44
- /** 로컬 파일 경로 또는 바이트 데이터를 원격 경로에 업로드합니다. */
44
+ /** Upload a local file path or byte data to the remote path. */
45
45
  put(localPathOrBuffer: string | Bytes, storageFilePath: string): Promise<void>;
46
46
  uploadDir(fromPath: string, toPath: string): Promise<void>;
47
47
  /**
48
- * 연결을 종료합니다.
48
+ * Close the connection.
49
49
  *
50
50
  * @remarks
51
- * 이미 종료된 상태에서 호출해도 에러가 발생하지 않습니다.
52
- * 종료 후에는 동일 인스턴스에서 {@link connect} 다시 호출하여 재연결할 있습니다.
51
+ * Safe to call when already closed (no error thrown).
52
+ * After closing, you can reconnect by calling {@link connect} again on the same instance.
53
53
  */
54
54
  close(): Promise<void>;
55
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ftp-storage-client.d.ts","sourceRoot":"","sources":["..\\..\\src\\clients\\ftp-storage-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAInD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEtE;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,OAAO;IAGlC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,OAAO,CAAyB;gBAEX,OAAO,GAAE,OAAe;IAErD;;;;;;;OAOG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBvD,OAAO,CAAC,cAAc;IAOtB,0CAA0C;IACpC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAK7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAWhD;;;;;;;;;;;OAWG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmB1C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,0CAA0C;IACpC,GAAG,CAAC,iBAAiB,EAAE,MAAM,GAAG,KAAK,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU9E,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhE;;;;;;OAMG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CASvB"}
1
+ {"version":3,"file":"ftp-storage-client.d.ts","sourceRoot":"","sources":["..\\..\\src\\clients\\ftp-storage-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAInD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEtE;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,OAAO;IAGlC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,OAAO,CAAyB;gBAEX,OAAO,GAAE,OAAe;IAErD;;;;;;;OAOG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBvD,OAAO,CAAC,cAAc;IAOtB,2EAA2E;IACrE,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAK7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAWhD;;;;;;;;;;;OAWG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmB1C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,gEAAgE;IAC1D,GAAG,CAAC,iBAAiB,EAAE,MAAM,GAAG,KAAK,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU9E,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhE;;;;;;OAMG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CASvB"}
@@ -7,16 +7,16 @@ class FtpStorageClient {
7
7
  }
8
8
  _client;
9
9
  /**
10
- * FTP 서버에 연결합니다.
10
+ * Connect to the FTP server.
11
11
  *
12
12
  * @remarks
13
- * - 연결 반드시 {@link close} 연결을 종료해야 합니다.
14
- * - 동일 인스턴스에서 여러 호출하지 마세요. (연결 누수 발생)
15
- * - 자동 연결/종료 관리가 필요하면 {@link StorageFactory.connect} 사용하세요. (권장)
13
+ * - Must close the connection with {@link close} after use.
14
+ * - Do not call multiple times on the same instance (connection leak).
15
+ * - Use {@link StorageFactory.connect} for automatic connection/close management (recommended).
16
16
  */
17
17
  async connect(config) {
18
18
  if (this._client !== void 0) {
19
- throw new SdError("\uC774\uBBF8 FTP \uC11C\uBC84\uC5D0 \uC5F0\uACB0\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 close()\uB97C \uD638\uCD9C\uD558\uC138\uC694.");
19
+ throw new SdError("FTP server is already connected. Please call close() first.");
20
20
  }
21
21
  const client = new ftp.Client();
22
22
  try {
@@ -35,11 +35,11 @@ class FtpStorageClient {
35
35
  }
36
36
  _requireClient() {
37
37
  if (this._client === void 0) {
38
- throw new SdError("FTP \uC11C\uBC84\uC5D0 \uC5F0\uACB0\uB418\uC5B4\uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
38
+ throw new SdError("Not connected to FTP server.");
39
39
  }
40
40
  return this._client;
41
41
  }
42
- /** 디렉토리를 생성합니다. 상위 디렉토리가 없으면 함께 생성합니다. */
42
+ /** Create a directory. Creates parent directories if they do not exist. */
43
43
  async mkdir(dirPath) {
44
44
  await this._requireClient().ensureDir(dirPath);
45
45
  }
@@ -61,16 +61,16 @@ class FtpStorageClient {
61
61
  return bytesConcat(chunks);
62
62
  }
63
63
  /**
64
- * 파일 또는 디렉토리 존재 여부를 확인합니다.
64
+ * Check whether a file or directory exists.
65
65
  *
66
66
  * @remarks
67
- * 파일 확인 size() 명령으로 O(1) 성능을 제공합니다.
68
- * 디렉토리 확인 상위 디렉토리 목록을 조회하므로, 항목 수가 많으면 성능이 저하될 있습니다.
67
+ * For files, uses the size() command for O(1) performance.
68
+ * For directories, queries the parent directory listing, so performance may degrade with many entries.
69
69
  *
70
- * 슬래시가 없는 경로(예: `file.txt`) 루트 디렉토리(`/`)에서 검색합니다.
70
+ * Paths without slashes (e.g. `file.txt`) are searched in the root directory (`/`).
71
71
  *
72
- * 상위 디렉토리가 존재하지 않는 경우에도 false를 반환합니다.
73
- * 네트워크 오류, 권한 오류 모든 예외도 false를 반환합니다.
72
+ * Returns false even if the parent directory does not exist.
73
+ * Returns false for all exceptions including network errors and permission errors.
74
74
  */
75
75
  async exists(filePath) {
76
76
  try {
@@ -91,7 +91,7 @@ class FtpStorageClient {
91
91
  async remove(filePath) {
92
92
  await this._requireClient().remove(filePath);
93
93
  }
94
- /** 로컬 파일 경로 또는 바이트 데이터를 원격 경로에 업로드합니다. */
94
+ /** Upload a local file path or byte data to the remote path. */
95
95
  async put(localPathOrBuffer, storageFilePath) {
96
96
  let param;
97
97
  if (typeof localPathOrBuffer === "string") {
@@ -105,11 +105,11 @@ class FtpStorageClient {
105
105
  await this._requireClient().uploadFromDir(fromPath, toPath);
106
106
  }
107
107
  /**
108
- * 연결을 종료합니다.
108
+ * Close the connection.
109
109
  *
110
110
  * @remarks
111
- * 이미 종료된 상태에서 호출해도 에러가 발생하지 않습니다.
112
- * 종료 후에는 동일 인스턴스에서 {@link connect} 다시 호출하여 재연결할 있습니다.
111
+ * Safe to call when already closed (no error thrown).
112
+ * After closing, you can reconnect by calling {@link connect} again on the same instance.
113
113
  */
114
114
  close() {
115
115
  if (this._client === void 0) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/clients/ftp-storage-client.ts"],
4
- "mappings": "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",
4
+ "mappings": "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",
5
5
  "names": []
6
6
  }
@@ -2,46 +2,46 @@ import type { Bytes } from "@simplysm/core-common";
2
2
  import type { Storage, FileInfo } from "../types/storage";
3
3
  import type { StorageConnConfig } from "../types/storage-conn-config";
4
4
  /**
5
- * SFTP 프로토콜을 사용하는 스토리지 클라이언트.
5
+ * Storage client using SFTP protocol.
6
6
  *
7
7
  * @remarks
8
- * 직접 사용보다 {@link StorageFactory.connect} 통한 사용을 권장합니다.
8
+ * Using {@link StorageFactory.connect} is recommended over direct usage.
9
9
  */
10
10
  export declare class SftpStorageClient implements Storage {
11
11
  private _client;
12
12
  /**
13
- * SFTP 서버에 연결합니다.
13
+ * Connect to the SFTP server.
14
14
  *
15
15
  * @remarks
16
- * - 연결 반드시 {@link close} 연결을 종료해야 합니다.
17
- * - 동일 인스턴스에서 여러 호출하지 마세요. (연결 누수 발생)
18
- * - 자동 연결/종료 관리가 필요하면 {@link StorageFactory.connect} 사용하세요. (권장)
16
+ * - Must close the connection with {@link close} after use.
17
+ * - Do not call multiple times on the same instance (connection leak).
18
+ * - Use {@link StorageFactory.connect} for automatic connection/close management (recommended).
19
19
  */
20
20
  connect(config: StorageConnConfig): Promise<void>;
21
21
  private _requireClient;
22
- /** 디렉토리를 생성합니다. 상위 디렉토리가 없으면 함께 생성합니다. */
22
+ /** Create a directory. Creates parent directories if they do not exist. */
23
23
  mkdir(dirPath: string): Promise<void>;
24
24
  rename(fromPath: string, toPath: string): Promise<void>;
25
25
  /**
26
- * 파일 또는 디렉토리 존재 여부를 확인합니다.
26
+ * Check whether a file or directory exists.
27
27
  *
28
28
  * @remarks
29
- * 상위 디렉토리가 존재하지 않는 경우에도 false를 반환합니다.
30
- * 네트워크 오류, 권한 오류 모든 예외도 false를 반환합니다.
29
+ * Returns false even if the parent directory does not exist.
30
+ * Returns false for all exceptions including network errors and permission errors.
31
31
  */
32
32
  exists(filePath: string): Promise<boolean>;
33
33
  readdir(dirPath: string): Promise<FileInfo[]>;
34
34
  readFile(filePath: string): Promise<Bytes>;
35
35
  remove(filePath: string): Promise<void>;
36
- /** 로컬 파일 경로 또는 바이트 데이터를 원격 경로에 업로드합니다. */
36
+ /** Upload a local file path or byte data to the remote path. */
37
37
  put(localPathOrBuffer: string | Bytes, storageFilePath: string): Promise<void>;
38
38
  uploadDir(fromPath: string, toPath: string): Promise<void>;
39
39
  /**
40
- * 연결을 종료합니다.
40
+ * Close the connection.
41
41
  *
42
42
  * @remarks
43
- * 이미 종료된 상태에서 호출해도 에러가 발생하지 않습니다.
44
- * 종료 후에는 동일 인스턴스에서 {@link connect} 다시 호출하여 재연결할 있습니다.
43
+ * Safe to call when already closed (no error thrown).
44
+ * After closing, you can reconnect by calling {@link connect} again on the same instance.
45
45
  */
46
46
  close(): Promise<void>;
47
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sftp-storage-client.d.ts","sourceRoot":"","sources":["..\\..\\src\\clients\\sftp-storage-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGnD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAKtE;;;;;GAKG;AACH,qBAAa,iBAAkB,YAAW,OAAO;IAC/C,OAAO,CAAC,OAAO,CAAyB;IAExC;;;;;;;OAOG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IA6CvD,OAAO,CAAC,cAAc;IAOtB,0CAA0C;IACpC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7D;;;;;;OAMG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAW1C,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAQ7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAc1C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,0CAA0C;IACpC,GAAG,CAAC,iBAAiB,EAAE,MAAM,GAAG,KAAK,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9E,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhE;;;;;;OAMG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B"}
1
+ {"version":3,"file":"sftp-storage-client.d.ts","sourceRoot":"","sources":["..\\..\\src\\clients\\sftp-storage-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGnD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAKtE;;;;;GAKG;AACH,qBAAa,iBAAkB,YAAW,OAAO;IAC/C,OAAO,CAAC,OAAO,CAAyB;IAExC;;;;;;;OAOG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IA6CvD,OAAO,CAAC,cAAc;IAOtB,2EAA2E;IACrE,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7D;;;;;;OAMG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAW1C,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAQ7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAc1C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,gEAAgE;IAC1D,GAAG,CAAC,iBAAiB,EAAE,MAAM,GAAG,KAAK,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9E,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhE;;;;;;OAMG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B"}
@@ -3,16 +3,16 @@ import SftpClient from "ssh2-sftp-client";
3
3
  class SftpStorageClient {
4
4
  _client;
5
5
  /**
6
- * SFTP 서버에 연결합니다.
6
+ * Connect to the SFTP server.
7
7
  *
8
8
  * @remarks
9
- * - 연결 반드시 {@link close} 연결을 종료해야 합니다.
10
- * - 동일 인스턴스에서 여러 호출하지 마세요. (연결 누수 발생)
11
- * - 자동 연결/종료 관리가 필요하면 {@link StorageFactory.connect} 사용하세요. (권장)
9
+ * - Must close the connection with {@link close} after use.
10
+ * - Do not call multiple times on the same instance (connection leak).
11
+ * - Use {@link StorageFactory.connect} for automatic connection/close management (recommended).
12
12
  */
13
13
  async connect(config) {
14
14
  if (this._client !== void 0) {
15
- throw new SdError("\uC774\uBBF8 SFTP \uC11C\uBC84\uC5D0 \uC5F0\uACB0\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 close()\uB97C \uD638\uCD9C\uD558\uC138\uC694.");
15
+ throw new SdError("SFTP server is already connected. Please call close() first.");
16
16
  }
17
17
  const client = new SftpClient();
18
18
  try {
@@ -51,11 +51,11 @@ class SftpStorageClient {
51
51
  }
52
52
  _requireClient() {
53
53
  if (this._client === void 0) {
54
- throw new SdError("SFTP \uC11C\uBC84\uC5D0 \uC5F0\uACB0\uB418\uC5B4\uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
54
+ throw new SdError("Not connected to SFTP server.");
55
55
  }
56
56
  return this._client;
57
57
  }
58
- /** 디렉토리를 생성합니다. 상위 디렉토리가 없으면 함께 생성합니다. */
58
+ /** Create a directory. Creates parent directories if they do not exist. */
59
59
  async mkdir(dirPath) {
60
60
  await this._requireClient().mkdir(dirPath, true);
61
61
  }
@@ -63,11 +63,11 @@ class SftpStorageClient {
63
63
  await this._requireClient().rename(fromPath, toPath);
64
64
  }
65
65
  /**
66
- * 파일 또는 디렉토리 존재 여부를 확인합니다.
66
+ * Check whether a file or directory exists.
67
67
  *
68
68
  * @remarks
69
- * 상위 디렉토리가 존재하지 않는 경우에도 false를 반환합니다.
70
- * 네트워크 오류, 권한 오류 모든 예외도 false를 반환합니다.
69
+ * Returns false even if the parent directory does not exist.
70
+ * Returns false for all exceptions including network errors and permission errors.
71
71
  */
72
72
  async exists(filePath) {
73
73
  try {
@@ -92,12 +92,12 @@ class SftpStorageClient {
92
92
  if (typeof result === "string") {
93
93
  return new TextEncoder().encode(result);
94
94
  }
95
- throw new SdError("\uC608\uC0C1\uCE58 \uBABB\uD55C \uC751\uB2F5 \uD0C0\uC785\uC785\uB2C8\uB2E4.");
95
+ throw new SdError("Unexpected response type.");
96
96
  }
97
97
  async remove(filePath) {
98
98
  await this._requireClient().delete(filePath);
99
99
  }
100
- /** 로컬 파일 경로 또는 바이트 데이터를 원격 경로에 업로드합니다. */
100
+ /** Upload a local file path or byte data to the remote path. */
101
101
  async put(localPathOrBuffer, storageFilePath) {
102
102
  if (typeof localPathOrBuffer === "string") {
103
103
  await this._requireClient().fastPut(localPathOrBuffer, storageFilePath);
@@ -109,11 +109,11 @@ class SftpStorageClient {
109
109
  await this._requireClient().uploadDir(fromPath, toPath);
110
110
  }
111
111
  /**
112
- * 연결을 종료합니다.
112
+ * Close the connection.
113
113
  *
114
114
  * @remarks
115
- * 이미 종료된 상태에서 호출해도 에러가 발생하지 않습니다.
116
- * 종료 후에는 동일 인스턴스에서 {@link connect} 다시 호출하여 재연결할 있습니다.
115
+ * Safe to call when already closed (no error thrown).
116
+ * After closing, you can reconnect by calling {@link connect} again on the same instance.
117
117
  */
118
118
  async close() {
119
119
  if (this._client === void 0) {