@simplysm/storage 13.0.100 → 14.0.4

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.
@@ -1,129 +1,145 @@
1
1
  import { SdError } from "@simplysm/core-common";
2
2
  import SftpClient from "ssh2-sftp-client";
3
- class SftpStorageClient {
4
- _client;
5
- /**
6
- * Connect to the SFTP server.
7
- *
8
- * @remarks
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
- */
13
- async connect(config) {
14
- if (this._client !== void 0) {
15
- throw new SdError("SFTP server is already connected. Please call close() first.");
3
+ import fsP from "fs/promises";
4
+ import os from "os";
5
+ import pathMod from "path";
6
+ /**
7
+ * SFTP 프로토콜을 사용하는 스토리지 클라이언트.
8
+ *
9
+ * @remarks
10
+ * 직접 사용하기보다 {@link StorageFactory.connect} 사용을 권장합니다.
11
+ */
12
+ export class SftpStorageClient {
13
+ _client;
14
+ /**
15
+ * SFTP 서버에 연결합니다.
16
+ *
17
+ * @remarks
18
+ * - 사용 후 {@link close}로 연결을 종료해야 합니다.
19
+ * - 동일 인스턴스에서 여러 번 호출하지 마세요 (연결 누수).
20
+ * - 자동 연결/종료 관리를 위해 {@link StorageFactory.connect} 사용을 권장합니다.
21
+ */
22
+ async connect(config) {
23
+ if (this._client !== undefined) {
24
+ throw new SdError("SFTP 서버에 이미 연결되어 있습니다. 먼저 close()를 호출해 주세요.");
25
+ }
26
+ const client = new SftpClient();
27
+ try {
28
+ if (config.password != null) {
29
+ await client.connect({
30
+ host: config.host,
31
+ port: config.port,
32
+ username: config.user,
33
+ password: config.password,
34
+ });
35
+ }
36
+ else {
37
+ // SSH agent + 키 파일로 인증
38
+ const keyPath = pathMod.join(os.homedir(), ".ssh", "id_ed25519");
39
+ const baseOptions = {
40
+ host: config.host,
41
+ port: config.port,
42
+ username: config.user,
43
+ ...(process.env["SSH_AUTH_SOCK"] != null ? { agent: process.env["SSH_AUTH_SOCK"] } : {}),
44
+ };
45
+ try {
46
+ await client.connect({
47
+ ...baseOptions,
48
+ privateKey: await fsP.readFile(keyPath),
49
+ });
50
+ }
51
+ catch {
52
+ // privateKey 파싱 실패 (암호화된 키 등) -> agent만으로 재시도
53
+ await client.connect(baseOptions);
54
+ }
55
+ }
56
+ this._client = client;
57
+ }
58
+ catch (err) {
59
+ await client.end();
60
+ throw err;
61
+ }
62
+ }
63
+ _requireClient() {
64
+ if (this._client === undefined) {
65
+ throw new SdError("SFTP 서버에 연결되어 있지 않습니다.");
66
+ }
67
+ return this._client;
68
+ }
69
+ /** 디렉토리를 생성합니다. 부모 디렉토리가 없으면 함께 생성합니다. */
70
+ async mkdir(dirPath) {
71
+ await this._requireClient().mkdir(dirPath, true);
16
72
  }
17
- const client = new SftpClient();
18
- try {
19
- if (config.password != null) {
20
- await client.connect({
21
- host: config.host,
22
- port: config.port,
23
- username: config.user,
24
- password: config.password
25
- });
26
- } else {
27
- const fsP = await import("fs/promises");
28
- const os = await import("os");
29
- const pathMod = await import("path");
30
- const keyPath = pathMod.join(os.homedir(), ".ssh", "id_ed25519");
31
- const baseOptions = {
32
- host: config.host,
33
- port: config.port,
34
- username: config.user,
35
- ...process.env["SSH_AUTH_SOCK"] != null ? { agent: process.env["SSH_AUTH_SOCK"] } : {}
36
- };
73
+ async rename(fromPath, toPath) {
74
+ await this._requireClient().rename(fromPath, toPath);
75
+ }
76
+ /**
77
+ * 파일 또는 디렉토리의 존재 여부를 확인합니다.
78
+ *
79
+ * @remarks
80
+ * 부모 디렉토리가 존재하지 않아도 false를 반환합니다.
81
+ * 네트워크 오류, 권한 오류 등 모든 예외에 대해 false를 반환합니다.
82
+ */
83
+ async exists(filePath) {
37
84
  try {
38
- await client.connect({
39
- ...baseOptions,
40
- privateKey: await fsP.readFile(keyPath)
41
- });
42
- } catch {
43
- await client.connect(baseOptions);
85
+ // ssh2-sftp-client의 exists()는 false | 'd' | '-' | 'l'을 반환합니다.
86
+ // false: 존재하지 않음, 'd': 디렉토리, '-': 파일, 'l': 심볼릭 링크
87
+ const result = await this._requireClient().exists(filePath);
88
+ return typeof result === "string";
89
+ }
90
+ catch {
91
+ return false;
44
92
  }
45
- }
46
- this._client = client;
47
- } catch (err) {
48
- await client.end();
49
- throw err;
50
93
  }
51
- }
52
- _requireClient() {
53
- if (this._client === void 0) {
54
- throw new SdError("Not connected to SFTP server.");
94
+ async list(dirPath) {
95
+ const list = await this._requireClient().list(dirPath);
96
+ return list.map((item) => ({
97
+ name: item.name,
98
+ isFile: item.type === "-",
99
+ }));
55
100
  }
56
- return this._client;
57
- }
58
- /** Create a directory. Creates parent directories if they do not exist. */
59
- async mkdir(dirPath) {
60
- await this._requireClient().mkdir(dirPath, true);
61
- }
62
- async rename(fromPath, toPath) {
63
- await this._requireClient().rename(fromPath, toPath);
64
- }
65
- /**
66
- * Check whether a file or directory exists.
67
- *
68
- * @remarks
69
- * Returns false even if the parent directory does not exist.
70
- * Returns false for all exceptions including network errors and permission errors.
71
- */
72
- async exists(filePath) {
73
- try {
74
- const result = await this._requireClient().exists(filePath);
75
- return typeof result === "string";
76
- } catch {
77
- return false;
101
+ async readFile(filePath) {
102
+ // ssh2-sftp-client의 get()은 dst가 제공되지 않으면 Buffer를 반환합니다.
103
+ // 타입 정의(string | WritableStream | Buffer)와 달리 실제로는 Buffer만 반환됩니다.
104
+ const result = (await this._requireClient().get(filePath));
105
+ if (result instanceof Uint8Array) {
106
+ return result;
107
+ }
108
+ // 타입 정의상 string도 가능하므로 방어 코드
109
+ if (typeof result === "string") {
110
+ return new TextEncoder().encode(result);
111
+ }
112
+ throw new SdError("예상하지 못한 응답 타입입니다.");
78
113
  }
79
- }
80
- async list(dirPath) {
81
- const list = await this._requireClient().list(dirPath);
82
- return list.map((item) => ({
83
- name: item.name,
84
- isFile: item.type === "-"
85
- }));
86
- }
87
- async readFile(filePath) {
88
- const result = await this._requireClient().get(filePath);
89
- if (result instanceof Uint8Array) {
90
- return result;
114
+ async remove(filePath) {
115
+ await this._requireClient().delete(filePath);
91
116
  }
92
- if (typeof result === "string") {
93
- return new TextEncoder().encode(result);
117
+ /** 로컬 파일 경로 또는 바이트 데이터를 원격 경로에 업로드합니다. */
118
+ async put(localPathOrBuffer, storageFilePath) {
119
+ if (typeof localPathOrBuffer === "string") {
120
+ await this._requireClient().fastPut(localPathOrBuffer, storageFilePath);
121
+ }
122
+ else {
123
+ // eslint-disable-next-line no-restricted-globals -- ssh2-sftp-client library requirement
124
+ await this._requireClient().put(Buffer.from(localPathOrBuffer), storageFilePath);
125
+ }
94
126
  }
95
- throw new SdError("Unexpected response type.");
96
- }
97
- async remove(filePath) {
98
- await this._requireClient().delete(filePath);
99
- }
100
- /** Upload a local file path or byte data to the remote path. */
101
- async put(localPathOrBuffer, storageFilePath) {
102
- if (typeof localPathOrBuffer === "string") {
103
- await this._requireClient().fastPut(localPathOrBuffer, storageFilePath);
104
- } else {
105
- await this._requireClient().put(Buffer.from(localPathOrBuffer), storageFilePath);
127
+ async uploadDir(fromPath, toPath) {
128
+ await this._requireClient().uploadDir(fromPath, toPath);
106
129
  }
107
- }
108
- async uploadDir(fromPath, toPath) {
109
- await this._requireClient().uploadDir(fromPath, toPath);
110
- }
111
- /**
112
- * Close the connection.
113
- *
114
- * @remarks
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
- */
118
- async close() {
119
- if (this._client === void 0) {
120
- return;
130
+ /**
131
+ * 연결을 종료합니다.
132
+ *
133
+ * @remarks
134
+ * 이미 종료된 상태에서 호출해도 안전합니다 (오류 미발생).
135
+ * 종료 동일 인스턴스에서 {@link connect}를 다시 호출하여 재연결할 수 있습니다.
136
+ */
137
+ async close() {
138
+ if (this._client === undefined) {
139
+ return;
140
+ }
141
+ await this._client.end();
142
+ this._client = undefined;
121
143
  }
122
- await this._client.end();
123
- this._client = void 0;
124
- }
125
144
  }
126
- export {
127
- SftpStorageClient
128
- };
129
- //# sourceMappingURL=sftp-storage-client.js.map
145
+ //# sourceMappingURL=sftp-storage-client.js.map
@@ -1,6 +1 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/clients/sftp-storage-client.ts"],
4
- "mappings": "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",
5
- "names": []
6
- }
1
+ {"version":3,"file":"sftp-storage-client.js","sourceRoot":"","sources":["..\\..\\src\\clients\\sftp-storage-client.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,7 +1,10 @@
1
+ // 타입
1
2
  export * from "./types/storage-conn-config.js";
2
3
  export * from "./types/storage.js";
3
4
  export * from "./types/storage-type.js";
5
+ // 클라이언트
4
6
  export * from "./clients/ftp-storage-client.js";
5
7
  export * from "./clients/sftp-storage-client.js";
8
+ // 팩토리
6
9
  export * from "./storage-factory.js";
7
- //# sourceMappingURL=index.js.map
10
+ //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,6 +1 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/index.ts"],
4
- "mappings": "AACA,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AAGd,cAAc;",
5
- "names": []
6
- }
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["..\\src\\index.ts"],"names":[],"mappings":"AAAA,KAAK;AACL,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AAErC,QAAQ;AACR,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC;AAE9C,MAAM;AACN,cAAc,mBAAmB,CAAC"}
@@ -2,17 +2,17 @@ import type { StorageConnConfig } from "./types/storage-conn-config";
2
2
  import type { StorageClient } from "./types/storage";
3
3
  import type { StorageProtocol } from "./types/storage-type";
4
4
  /**
5
- * Storage client factory
5
+ * 스토리지 클라이언트 팩토리
6
6
  *
7
- * Creates and manages FTP, FTPS, and SFTP storage connections.
7
+ * FTP, FTPS, SFTP 스토리지 연결을 생성하고 관리합니다.
8
8
  */
9
9
  export declare class StorageFactory {
10
10
  /**
11
- * Connect to storage, execute the callback, and automatically close the connection.
11
+ * 스토리지에 연결하고, 콜백을 실행한 후, 자동으로 연결을 종료합니다.
12
12
  *
13
13
  * @remarks
14
- * The callback pattern auto-manages connection/close, so this is preferred over direct client usage.
15
- * The connection is automatically closed even if the callback throws an exception.
14
+ * 콜백 패턴으로 연결/종료를 자동 관리하므로 직접 클라이언트를 사용하는 것보다 권장됩니다.
15
+ * 콜백에서 예외가 발생해도 연결은 자동으로 종료됩니다.
16
16
  */
17
17
  static connect<R>(type: StorageProtocol, config: StorageConnConfig, fn: (storage: StorageClient) => R | Promise<R>): Promise<R>;
18
18
  private static _createClient;
@@ -1,35 +1,39 @@
1
1
  import { FtpStorageClient } from "./clients/ftp-storage-client.js";
2
2
  import { SftpStorageClient } from "./clients/sftp-storage-client.js";
3
- class StorageFactory {
4
- /**
5
- * Connect to storage, execute the callback, and automatically close the connection.
6
- *
7
- * @remarks
8
- * The callback pattern auto-manages connection/close, so this is preferred over direct client usage.
9
- * The connection is automatically closed even if the callback throws an exception.
10
- */
11
- static async connect(type, config, fn) {
12
- const client = StorageFactory._createClient(type);
13
- await client.connect(config);
14
- try {
15
- return await fn(client);
16
- } finally {
17
- await client.close().catch(() => {
18
- });
3
+ /**
4
+ * 스토리지 클라이언트 팩토리
5
+ *
6
+ * FTP, FTPS, SFTP 스토리지 연결을 생성하고 관리합니다.
7
+ */
8
+ export class StorageFactory {
9
+ /**
10
+ * 스토리지에 연결하고, 콜백을 실행한 후, 자동으로 연결을 종료합니다.
11
+ *
12
+ * @remarks
13
+ * 콜백 패턴으로 연결/종료를 자동 관리하므로 직접 클라이언트를 사용하는 것보다 권장됩니다.
14
+ * 콜백에서 예외가 발생해도 연결은 자동으로 종료됩니다.
15
+ */
16
+ static async connect(type, config, fn) {
17
+ const client = StorageFactory._createClient(type);
18
+ await client.connect(config);
19
+ try {
20
+ return await fn(client);
21
+ }
22
+ finally {
23
+ await client.close().catch(() => {
24
+ // 이미 종료된 경우 무시
25
+ });
26
+ }
19
27
  }
20
- }
21
- static _createClient(type) {
22
- switch (type) {
23
- case "sftp":
24
- return new SftpStorageClient();
25
- case "ftps":
26
- return new FtpStorageClient(true);
27
- case "ftp":
28
- return new FtpStorageClient(false);
28
+ static _createClient(type) {
29
+ switch (type) {
30
+ case "sftp":
31
+ return new SftpStorageClient();
32
+ case "ftps":
33
+ return new FtpStorageClient(true);
34
+ case "ftp":
35
+ return new FtpStorageClient(false);
36
+ }
29
37
  }
30
- }
31
38
  }
32
- export {
33
- StorageFactory
34
- };
35
- //# sourceMappingURL=storage-factory.js.map
39
+ //# sourceMappingURL=storage-factory.js.map
@@ -1,6 +1 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/storage-factory.ts"],
4
- "mappings": "AAGA,SAAS,wBAAwB;AACjC,SAAS,yBAAyB;AAO3B,MAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ1B,aAAa,QACX,MACA,QACA,IACY;AACZ,UAAM,SAAS,eAAe,cAAc,IAAI;AAEhD,UAAM,OAAO,QAAQ,MAAM;AAC3B,QAAI;AACF,aAAO,MAAM,GAAG,MAAM;AAAA,IACxB,UAAE;AACA,YAAM,OAAO,MAAM,EAAE,MAAM,MAAM;AAAA,MAEjC,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,OAAe,cAAc,MAAsC;AACjE,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,eAAO,IAAI,kBAAkB;AAAA,MAC/B,KAAK;AACH,eAAO,IAAI,iBAAiB,IAAI;AAAA,MAClC,KAAK;AACH,eAAO,IAAI,iBAAiB,KAAK;AAAA,IACrC;AAAA,EACF;AACF;",
5
- "names": []
6
- }
1
+ {"version":3,"file":"storage-factory.js","sourceRoot":"","sources":["..\\src\\storage-factory.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAElE;;;;GAIG;AACH,MAAM,OAAO,cAAc;IACzB;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,CAAC,OAAO,CAClB,IAAqB,EACrB,MAAyB,EACzB,EAA8C;QAE9C,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAElD,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC7B,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;gBAC9B,eAAe;YACjB,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,aAAa,CAAC,IAAqB;QAChD,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,MAAM;gBACT,OAAO,IAAI,iBAAiB,EAAE,CAAC;YACjC,KAAK,MAAM;gBACT,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACpC,KAAK,KAAK;gBACR,OAAO,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;CACF"}
@@ -1 +1,2 @@
1
- //# sourceMappingURL=storage-conn-config.js.map
1
+ export {};
2
+ //# sourceMappingURL=storage-conn-config.js.map
@@ -1,6 +1 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "mappings": "",
5
- "names": []
6
- }
1
+ {"version":3,"file":"storage-conn-config.js","sourceRoot":"","sources":["..\\..\\src\\types\\storage-conn-config.ts"],"names":[],"mappings":""}
@@ -1 +1,2 @@
1
- //# sourceMappingURL=storage-type.js.map
1
+ export {};
2
+ //# sourceMappingURL=storage-type.js.map
@@ -1,6 +1 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "mappings": "",
5
- "names": []
6
- }
1
+ {"version":3,"file":"storage-type.js","sourceRoot":"","sources":["..\\..\\src\\types\\storage-type.ts"],"names":[],"mappings":""}
@@ -1 +1,2 @@
1
- //# sourceMappingURL=storage.js.map
1
+ export {};
2
+ //# sourceMappingURL=storage.js.map
@@ -1,6 +1 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "mappings": "",
5
- "names": []
6
- }
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["..\\..\\src\\types\\storage.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@simplysm/storage",
3
- "version": "13.0.100",
4
- "description": "Simplysm Package - Storage Module (node)",
5
- "author": "simplysm",
3
+ "version": "14.0.4",
4
+ "description": "심플리즘 패키지 - 저장소 (node)",
5
+ "author": "심플리즘",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",
@@ -14,14 +14,13 @@
14
14
  "types": "./dist/index.d.ts",
15
15
  "files": [
16
16
  "dist",
17
- "src",
18
- "tests"
17
+ "src"
19
18
  ],
20
19
  "sideEffects": false,
21
20
  "dependencies": {
22
21
  "basic-ftp": "^5.2.0",
23
- "ssh2-sftp-client": "^12.1.0",
24
- "@simplysm/core-common": "13.0.100"
22
+ "ssh2-sftp-client": "^12.1.1",
23
+ "@simplysm/core-common": "14.0.4"
25
24
  },
26
25
  "devDependencies": {
27
26
  "@types/ssh2-sftp-client": "^9.0.6"
@@ -6,11 +6,11 @@ import type { StorageClient, FileInfo } from "../types/storage";
6
6
  import type { StorageConnConfig } from "../types/storage-conn-config";
7
7
 
8
8
  /**
9
- * Storage client using FTP/FTPS protocol.
9
+ * FTP/FTPS 프로토콜을 사용하는 스토리지 클라이언트.
10
10
  *
11
11
  * @remarks
12
- * The `secure` constructor parameter configures whether to use FTPS.
13
- * Using {@link StorageFactory.connect} is recommended over direct usage.
12
+ * `secure` 생성자 매개변수로 FTPS 사용 여부를 설정합니다.
13
+ * 직접 사용하기보다 {@link StorageFactory.connect} 사용을 권장합니다.
14
14
  */
15
15
  export class FtpStorageClient implements StorageClient {
16
16
  private _client: ftp.Client | undefined;
@@ -18,16 +18,16 @@ export class FtpStorageClient implements StorageClient {
18
18
  constructor(private readonly _secure: boolean = false) {}
19
19
 
20
20
  /**
21
- * Connect to the FTP server.
21
+ * FTP 서버에 연결합니다.
22
22
  *
23
23
  * @remarks
24
- * - Must close the connection with {@link close} after use.
25
- * - Do not call multiple times on the same instance (connection leak).
26
- * - Use {@link StorageFactory.connect} for automatic connection/close management (recommended).
24
+ * - 사용 {@link close} 연결을 종료해야 합니다.
25
+ * - 동일 인스턴스에서 여러 호출하지 마세요 (연결 누수).
26
+ * - 자동 연결/종료 관리를 위해 {@link StorageFactory.connect} 사용을 권장합니다.
27
27
  */
28
28
  async connect(config: StorageConnConfig): Promise<void> {
29
29
  if (this._client !== undefined) {
30
- throw new SdError("FTP server is already connected. Please call close() first.");
30
+ throw new SdError("FTP 서버에 이미 연결되어 있습니다. 먼저 close() 호출해 주세요.");
31
31
  }
32
32
  const client = new ftp.Client();
33
33
  try {
@@ -47,12 +47,12 @@ export class FtpStorageClient implements StorageClient {
47
47
 
48
48
  private _requireClient(): ftp.Client {
49
49
  if (this._client === undefined) {
50
- throw new SdError("Not connected to FTP server.");
50
+ throw new SdError("FTP 서버에 연결되어 있지 않습니다.");
51
51
  }
52
52
  return this._client;
53
53
  }
54
54
 
55
- /** Create a directory. Creates parent directories if they do not exist. */
55
+ /** 디렉토리를 생성합니다. 부모 디렉토리가 없으면 함께 생성합니다. */
56
56
  async mkdir(dirPath: string): Promise<void> {
57
57
  await this._requireClient().ensureDir(dirPath);
58
58
  }
@@ -78,24 +78,24 @@ export class FtpStorageClient implements StorageClient {
78
78
  }
79
79
 
80
80
  /**
81
- * Check whether a file or directory exists.
81
+ * 파일 또는 디렉토리의 존재 여부를 확인합니다.
82
82
  *
83
83
  * @remarks
84
- * For files, uses the size() command for O(1) performance.
85
- * For directories, queries the parent directory listing, so performance may degrade with many entries.
84
+ * 파일의 경우 size() 명령으로 O(1) 성능을 제공합니다.
85
+ * 디렉토리의 경우 부모 디렉토리 목록을 조회하므로 항목이 많으면 성능이 저하될 있습니다.
86
86
  *
87
- * Paths without slashes (e.g. `file.txt`) are searched in the root directory (`/`).
87
+ * 슬래시가 없는 경로(예: `file.txt`) 루트 디렉토리(`/`)에서 검색합니다.
88
88
  *
89
- * Returns false even if the parent directory does not exist.
90
- * Returns false for all exceptions including network errors and permission errors.
89
+ * 부모 디렉토리가 존재하지 않아도 false를 반환합니다.
90
+ * 네트워크 오류, 권한 오류 모든 예외에 대해 false를 반환합니다.
91
91
  */
92
92
  async exists(filePath: string): Promise<boolean> {
93
93
  try {
94
- // Quick check for files via size() (O(1))
94
+ // size()로 파일 존재 여부 빠른 확인 (O(1))
95
95
  await this._requireClient().size(filePath);
96
96
  return true;
97
97
  } catch {
98
- // If size() fails, it may be a directory, so check via list()
98
+ // size() 실패 디렉토리일 있으므로 list()로 확인
99
99
  try {
100
100
  const lastSlash = filePath.lastIndexOf("/");
101
101
  const dirPath = lastSlash > 0 ? filePath.substring(0, lastSlash) : "/";
@@ -112,7 +112,7 @@ export class FtpStorageClient implements StorageClient {
112
112
  await this._requireClient().remove(filePath);
113
113
  }
114
114
 
115
- /** Upload a local file path or byte data to the remote path. */
115
+ /** 로컬 파일 경로 또는 바이트 데이터를 원격 경로에 업로드합니다. */
116
116
  async put(localPathOrBuffer: string | Bytes, storageFilePath: string): Promise<void> {
117
117
  let param: string | Readable;
118
118
  if (typeof localPathOrBuffer === "string") {
@@ -128,11 +128,11 @@ export class FtpStorageClient implements StorageClient {
128
128
  }
129
129
 
130
130
  /**
131
- * Close the connection.
131
+ * 연결을 종료합니다.
132
132
  *
133
133
  * @remarks
134
- * Safe to call when already closed (no error thrown).
135
- * After closing, you can reconnect by calling {@link connect} again on the same instance.
134
+ * 이미 종료된 상태에서 호출해도 안전합니다 (오류 미발생).
135
+ * 종료 동일 인스턴스에서 {@link connect} 다시 호출하여 재연결할 있습니다.
136
136
  */
137
137
  close(): Promise<void> {
138
138
  if (this._client === undefined) {