@devbro/neko-storage 0.1.4 → 0.1.6

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.
@@ -0,0 +1,82 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { Storage as GCPStorage } from "@google-cloud/storage";
4
+ import Stream from "stream";
5
+ import * as mime from "mime-types";
6
+ class GCPStorageProvider {
7
+ constructor(config) {
8
+ this.config = config;
9
+ const { bucket, ...gcpOptions } = config;
10
+ this.storage = new GCPStorage(gcpOptions);
11
+ }
12
+ static {
13
+ __name(this, "GCPStorageProvider");
14
+ }
15
+ storage;
16
+ async exists(path) {
17
+ try {
18
+ const file = this.storage.bucket(this.config.bucket).file(path);
19
+ const [exists] = await file.exists();
20
+ return exists;
21
+ } catch (error) {
22
+ return false;
23
+ }
24
+ }
25
+ async put(path, content) {
26
+ const file = this.storage.bucket(this.config.bucket).file(path);
27
+ let data;
28
+ if (typeof content === "string" || content instanceof Buffer) {
29
+ data = content;
30
+ } else if (typeof content === "object" && !(content instanceof Stream)) {
31
+ data = JSON.stringify(content);
32
+ } else if (content instanceof Stream) {
33
+ data = content;
34
+ } else {
35
+ throw new Error("Unsupported content type");
36
+ }
37
+ if (data instanceof Stream) {
38
+ await new Promise((resolve, reject) => {
39
+ data.pipe(file.createWriteStream()).on("finish", () => resolve()).on("error", reject);
40
+ });
41
+ } else {
42
+ await file.save(data);
43
+ }
44
+ return true;
45
+ }
46
+ async getJson(path) {
47
+ const data = await this.getString(path);
48
+ return JSON.parse(data);
49
+ }
50
+ async getString(path) {
51
+ const file = this.storage.bucket(this.config.bucket).file(path);
52
+ const [content] = await file.download();
53
+ return content.toString("utf-8");
54
+ }
55
+ async getBuffer(path) {
56
+ const file = this.storage.bucket(this.config.bucket).file(path);
57
+ const [content] = await file.download();
58
+ return content;
59
+ }
60
+ async getStream(path) {
61
+ const file = this.storage.bucket(this.config.bucket).file(path);
62
+ return file.createReadStream();
63
+ }
64
+ async delete(path) {
65
+ const file = this.storage.bucket(this.config.bucket).file(path);
66
+ await file.delete();
67
+ return true;
68
+ }
69
+ async metadata(path) {
70
+ const file = this.storage.bucket(this.config.bucket).file(path);
71
+ const [metadata] = await file.getMetadata();
72
+ return {
73
+ size: typeof metadata.size === "number" ? metadata.size : parseInt(metadata.size || "0", 10),
74
+ mimeType: metadata.contentType || mime.lookup(path) || "unknown",
75
+ lastModifiedDate: metadata.updated || (/* @__PURE__ */ new Date(0)).toISOString()
76
+ };
77
+ }
78
+ }
79
+ export {
80
+ GCPStorageProvider
81
+ };
82
+ //# sourceMappingURL=GCPStorageProvider.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/GCPStorageProvider.mts"],"sourcesContent":["import { Storage as GCPStorage } from '@google-cloud/storage';\nimport { Metadata, GCPStorageConfig } from '../types.mjs';\nimport { StorageProviderInterface } from '../StorageProviderInterface.mjs';\nimport { ReadStream } from 'fs';\nimport Stream from 'stream';\nimport * as mime from 'mime-types';\n\nexport class GCPStorageProvider implements StorageProviderInterface {\n private storage: GCPStorage;\n\n constructor(protected config: GCPStorageConfig) {\n const { bucket, ...gcpOptions } = config;\n this.storage = new GCPStorage(gcpOptions);\n }\n\n async exists(path: string): Promise<boolean> {\n try {\n const file = this.storage.bucket(this.config.bucket).file(path);\n const [exists] = await file.exists();\n return exists;\n } catch (error) {\n return false;\n }\n }\n\n async put(path: string, content: string | object | Stream | Buffer): Promise<boolean> {\n const file = this.storage.bucket(this.config.bucket).file(path);\n\n let data: string | Buffer | Stream;\n if (typeof content === 'string' || content instanceof Buffer) {\n data = content;\n } else if (typeof content === 'object' && !(content instanceof Stream)) {\n data = JSON.stringify(content);\n } else if (content instanceof Stream) {\n data = content;\n } else {\n throw new Error('Unsupported content type');\n }\n\n if (data instanceof Stream) {\n await new Promise<void>((resolve, reject) => {\n data\n .pipe(file.createWriteStream())\n .on('finish', () => resolve())\n .on('error', reject);\n });\n } else {\n await file.save(data);\n }\n\n return true;\n }\n\n async getJson(path: string): Promise<object> {\n const data = await this.getString(path);\n return JSON.parse(data);\n }\n\n async getString(path: string): Promise<string> {\n const file = this.storage.bucket(this.config.bucket).file(path);\n const [content] = await file.download();\n return content.toString('utf-8');\n }\n\n async getBuffer(path: string): Promise<Buffer> {\n const file = this.storage.bucket(this.config.bucket).file(path);\n const [content] = await file.download();\n return content;\n }\n\n async getStream(path: string): Promise<ReadStream> {\n const file = this.storage.bucket(this.config.bucket).file(path);\n return file.createReadStream() as unknown as ReadStream;\n }\n\n async delete(path: string): Promise<boolean> {\n const file = this.storage.bucket(this.config.bucket).file(path);\n await file.delete();\n return true;\n }\n\n async metadata(path: string): Promise<Metadata> {\n const file = this.storage.bucket(this.config.bucket).file(path);\n const [metadata] = await file.getMetadata();\n\n return {\n size: typeof metadata.size === 'number' ? metadata.size : parseInt(metadata.size || '0', 10),\n mimeType: metadata.contentType || mime.lookup(path) || 'unknown',\n lastModifiedDate: metadata.updated || new Date(0).toISOString(),\n };\n }\n}\n"],"mappings":";;AAAA,SAAS,WAAW,kBAAkB;AAItC,OAAO,YAAY;AACnB,YAAY,UAAU;AAEf,MAAM,mBAAuD;AAAA,EAGlE,YAAsB,QAA0B;AAA1B;AACpB,UAAM,EAAE,QAAQ,GAAG,WAAW,IAAI;AAClC,SAAK,UAAU,IAAI,WAAW,UAAU;AAAA,EAC1C;AAAA,EAbF,OAOoE;AAAA;AAAA;AAAA,EAC1D;AAAA,EAOR,MAAM,OAAO,MAAgC;AAC3C,QAAI;AACF,YAAM,OAAO,KAAK,QAAQ,OAAO,KAAK,OAAO,MAAM,EAAE,KAAK,IAAI;AAC9D,YAAM,CAAC,MAAM,IAAI,MAAM,KAAK,OAAO;AACnC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,MAAc,SAA8D;AACpF,UAAM,OAAO,KAAK,QAAQ,OAAO,KAAK,OAAO,MAAM,EAAE,KAAK,IAAI;AAE9D,QAAI;AACJ,QAAI,OAAO,YAAY,YAAY,mBAAmB,QAAQ;AAC5D,aAAO;AAAA,IACT,WAAW,OAAO,YAAY,YAAY,EAAE,mBAAmB,SAAS;AACtE,aAAO,KAAK,UAAU,OAAO;AAAA,IAC/B,WAAW,mBAAmB,QAAQ;AACpC,aAAO;AAAA,IACT,OAAO;AACL,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,QAAI,gBAAgB,QAAQ;AAC1B,YAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,aACG,KAAK,KAAK,kBAAkB,CAAC,EAC7B,GAAG,UAAU,MAAM,QAAQ,CAAC,EAC5B,GAAG,SAAS,MAAM;AAAA,MACvB,CAAC;AAAA,IACH,OAAO;AACL,YAAM,KAAK,KAAK,IAAI;AAAA,IACtB;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAQ,MAA+B;AAC3C,UAAM,OAAO,MAAM,KAAK,UAAU,IAAI;AACtC,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB;AAAA,EAEA,MAAM,UAAU,MAA+B;AAC7C,UAAM,OAAO,KAAK,QAAQ,OAAO,KAAK,OAAO,MAAM,EAAE,KAAK,IAAI;AAC9D,UAAM,CAAC,OAAO,IAAI,MAAM,KAAK,SAAS;AACtC,WAAO,QAAQ,SAAS,OAAO;AAAA,EACjC;AAAA,EAEA,MAAM,UAAU,MAA+B;AAC7C,UAAM,OAAO,KAAK,QAAQ,OAAO,KAAK,OAAO,MAAM,EAAE,KAAK,IAAI;AAC9D,UAAM,CAAC,OAAO,IAAI,MAAM,KAAK,SAAS;AACtC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,MAAmC;AACjD,UAAM,OAAO,KAAK,QAAQ,OAAO,KAAK,OAAO,MAAM,EAAE,KAAK,IAAI;AAC9D,WAAO,KAAK,iBAAiB;AAAA,EAC/B;AAAA,EAEA,MAAM,OAAO,MAAgC;AAC3C,UAAM,OAAO,KAAK,QAAQ,OAAO,KAAK,OAAO,MAAM,EAAE,KAAK,IAAI;AAC9D,UAAM,KAAK,OAAO;AAClB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,SAAS,MAAiC;AAC9C,UAAM,OAAO,KAAK,QAAQ,OAAO,KAAK,OAAO,MAAM,EAAE,KAAK,IAAI;AAC9D,UAAM,CAAC,QAAQ,IAAI,MAAM,KAAK,YAAY;AAE1C,WAAO;AAAA,MACL,MAAM,OAAO,SAAS,SAAS,WAAW,SAAS,OAAO,SAAS,SAAS,QAAQ,KAAK,EAAE;AAAA,MAC3F,UAAU,SAAS,eAAe,KAAK,OAAO,IAAI,KAAK;AAAA,MACvD,kBAAkB,SAAS,YAAW,oBAAI,KAAK,CAAC,GAAE,YAAY;AAAA,IAChE;AAAA,EACF;AACF;","names":[]}
@@ -1,12 +1,13 @@
1
1
  import Stream from 'stream';
2
2
  import { ReadStream } from 'fs';
3
- import { StorageConfig, Metadata } from '../types.mjs';
3
+ import { LocalStorageConfig, Metadata } from '../types.mjs';
4
4
  import { StorageProviderInterface } from '../StorageProviderInterface.mjs';
5
5
  import '@aws-sdk/client-s3';
6
+ import '@google-cloud/storage';
6
7
 
7
8
  declare class LocalStorageProvider implements StorageProviderInterface {
8
9
  private config;
9
- constructor(config: StorageConfig);
10
+ constructor(config: LocalStorageConfig);
10
11
  metadata(path: string): Promise<Metadata>;
11
12
  getFullPath(filePath: string): string;
12
13
  exists(path: string): Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/LocalStorageProvider.mts"],"sourcesContent":["import Stream from 'stream';\nimport * as fs from 'fs/promises';\nimport { createWriteStream, createReadStream, ReadStream } from 'fs';\nimport * as path from 'path';\nimport * as mime from 'mime-types';\nimport { Metadata, StorageConfig } from '../types.mjs';\nimport { Storage } from '../Storage.mjs';\nimport { StorageProviderInterface } from '../StorageProviderInterface.mjs';\n\nexport class LocalStorageProvider implements StorageProviderInterface {\n constructor(private config: StorageConfig) {\n // Ensure the base folder exists\n fs.mkdir(this.config.basePath, { recursive: true }).catch((error) => {\n throw error;\n });\n }\n\n async metadata(path: string): Promise<Metadata> {\n const fullPath = this.getFullPath(path);\n const stats = await fs.stat(fullPath);\n return {\n size: stats.size,\n mimeType: mime.lookup(fullPath) || 'unknown',\n lastModifiedDate: stats.mtime.toISOString(),\n };\n }\n\n getFullPath(filePath: string) {\n return path.join(this.config.basePath, filePath);\n }\n\n async exists(path: string): Promise<boolean> {\n try {\n await fs.access(this.getFullPath(path));\n return true;\n } catch {\n return false;\n }\n }\n\n async put(filepath: string, content: string | object | Stream | Buffer): Promise<boolean> {\n const fullPath = this.getFullPath(filepath);\n\n const dir = path.dirname(fullPath);\n await fs.mkdir(dir, { recursive: true });\n\n if (typeof content === 'string' || content instanceof Buffer) {\n await fs.writeFile(fullPath, content);\n } else if (typeof content === 'object' && !(content instanceof Stream)) {\n await fs.writeFile(fullPath, JSON.stringify(content, null, 2));\n } else if (typeof content === 'object' && content instanceof Stream) {\n const writeStream = createWriteStream(fullPath);\n await new Promise((resolve, reject) => {\n (content as Stream).pipe(writeStream);\n (content as Stream).on('end', resolve);\n (content as Stream).on('error', reject);\n });\n } else {\n throw new Error('Unsupported content type');\n }\n\n return true;\n }\n\n async getJson(path: string): Promise<object> {\n const fullPath = this.getFullPath(path);\n const content = await fs.readFile(fullPath, 'utf-8');\n return JSON.parse(content);\n }\n\n async getString(path: string, encoding: BufferEncoding = 'utf-8'): Promise<string> {\n const fullPath = this.getFullPath(path);\n return await fs.readFile(fullPath, encoding);\n }\n\n async getBuffer(path: string): Promise<Buffer> {\n const fullPath = this.getFullPath(path);\n return await fs.readFile(fullPath);\n }\n\n async getStream(path: string): Promise<ReadStream> {\n const fullPath = this.getFullPath(path);\n return createReadStream(fullPath);\n }\n\n async delete(path: string): Promise<boolean> {\n const fullPath = this.getFullPath(path);\n await fs.unlink(fullPath);\n return true;\n }\n}\n"],"mappings":";;AAAA,OAAO,YAAY;AACnB,YAAY,QAAQ;AACpB,SAAS,mBAAmB,wBAAoC;AAChE,YAAY,UAAU;AACtB,YAAY,UAAU;AAKf,MAAM,qBAAyD;AAAA,EACpE,YAAoB,QAAuB;AAAvB;AAElB,OAAG,MAAM,KAAK,OAAO,UAAU,EAAE,WAAW,KAAK,CAAC,EAAE,MAAM,CAAC,UAAU;AACnE,YAAM;AAAA,IACR,CAAC;AAAA,EACH;AAAA,EAfF,OASsE;AAAA;AAAA;AAAA,EAQpE,MAAM,SAASA,OAAiC;AAC9C,UAAM,WAAW,KAAK,YAAYA,KAAI;AACtC,UAAM,QAAQ,MAAM,GAAG,KAAK,QAAQ;AACpC,WAAO;AAAA,MACL,MAAM,MAAM;AAAA,MACZ,UAAU,KAAK,OAAO,QAAQ,KAAK;AAAA,MACnC,kBAAkB,MAAM,MAAM,YAAY;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,YAAY,UAAkB;AAC5B,WAAO,KAAK,KAAK,KAAK,OAAO,UAAU,QAAQ;AAAA,EACjD;AAAA,EAEA,MAAM,OAAOA,OAAgC;AAC3C,QAAI;AACF,YAAM,GAAG,OAAO,KAAK,YAAYA,KAAI,CAAC;AACtC,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,UAAkB,SAA8D;AACxF,UAAM,WAAW,KAAK,YAAY,QAAQ;AAE1C,UAAM,MAAM,KAAK,QAAQ,QAAQ;AACjC,UAAM,GAAG,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AAEvC,QAAI,OAAO,YAAY,YAAY,mBAAmB,QAAQ;AAC5D,YAAM,GAAG,UAAU,UAAU,OAAO;AAAA,IACtC,WAAW,OAAO,YAAY,YAAY,EAAE,mBAAmB,SAAS;AACtE,YAAM,GAAG,UAAU,UAAU,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAAA,IAC/D,WAAW,OAAO,YAAY,YAAY,mBAAmB,QAAQ;AACnE,YAAM,cAAc,kBAAkB,QAAQ;AAC9C,YAAM,IAAI,QAAQ,CAAC,SAAS,WAAW;AACrC,QAAC,QAAmB,KAAK,WAAW;AACpC,QAAC,QAAmB,GAAG,OAAO,OAAO;AACrC,QAAC,QAAmB,GAAG,SAAS,MAAM;AAAA,MACxC,CAAC;AAAA,IACH,OAAO;AACL,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAQA,OAA+B;AAC3C,UAAM,WAAW,KAAK,YAAYA,KAAI;AACtC,UAAM,UAAU,MAAM,GAAG,SAAS,UAAU,OAAO;AACnD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B;AAAA,EAEA,MAAM,UAAUA,OAAc,WAA2B,SAA0B;AACjF,UAAM,WAAW,KAAK,YAAYA,KAAI;AACtC,WAAO,MAAM,GAAG,SAAS,UAAU,QAAQ;AAAA,EAC7C;AAAA,EAEA,MAAM,UAAUA,OAA+B;AAC7C,UAAM,WAAW,KAAK,YAAYA,KAAI;AACtC,WAAO,MAAM,GAAG,SAAS,QAAQ;AAAA,EACnC;AAAA,EAEA,MAAM,UAAUA,OAAmC;AACjD,UAAM,WAAW,KAAK,YAAYA,KAAI;AACtC,WAAO,iBAAiB,QAAQ;AAAA,EAClC;AAAA,EAEA,MAAM,OAAOA,OAAgC;AAC3C,UAAM,WAAW,KAAK,YAAYA,KAAI;AACtC,UAAM,GAAG,OAAO,QAAQ;AACxB,WAAO;AAAA,EACT;AACF;","names":["path"]}
1
+ {"version":3,"sources":["../../src/providers/LocalStorageProvider.mts"],"sourcesContent":["import Stream from 'stream';\nimport * as fs from 'fs/promises';\nimport { createWriteStream, createReadStream, ReadStream } from 'fs';\nimport * as path from 'path';\nimport * as mime from 'mime-types';\nimport { Metadata, LocalStorageConfig } from '../types.mjs';\nimport { StorageProviderInterface } from '../StorageProviderInterface.mjs';\n\nexport class LocalStorageProvider implements StorageProviderInterface {\n constructor(private config: LocalStorageConfig) {\n // Ensure the base folder exists\n fs.mkdir(this.config.basePath, { recursive: true }).catch((error) => {\n throw error;\n });\n }\n\n async metadata(path: string): Promise<Metadata> {\n const fullPath = this.getFullPath(path);\n const stats = await fs.stat(fullPath);\n return {\n size: stats.size,\n mimeType: mime.lookup(fullPath) || 'unknown',\n lastModifiedDate: stats.mtime.toISOString(),\n };\n }\n\n getFullPath(filePath: string) {\n return path.join(this.config.basePath, filePath);\n }\n\n async exists(path: string): Promise<boolean> {\n try {\n await fs.access(this.getFullPath(path));\n return true;\n } catch {\n return false;\n }\n }\n\n async put(filepath: string, content: string | object | Stream | Buffer): Promise<boolean> {\n const fullPath = this.getFullPath(filepath);\n\n const dir = path.dirname(fullPath);\n await fs.mkdir(dir, { recursive: true });\n\n if (typeof content === 'string' || content instanceof Buffer) {\n await fs.writeFile(fullPath, content);\n } else if (typeof content === 'object' && !(content instanceof Stream)) {\n await fs.writeFile(fullPath, JSON.stringify(content, null, 2));\n } else if (typeof content === 'object' && content instanceof Stream) {\n const writeStream = createWriteStream(fullPath);\n await new Promise((resolve, reject) => {\n (content as Stream).pipe(writeStream);\n (content as Stream).on('end', resolve);\n (content as Stream).on('error', reject);\n });\n } else {\n throw new Error('Unsupported content type');\n }\n\n return true;\n }\n\n async getJson(path: string): Promise<object> {\n const fullPath = this.getFullPath(path);\n const content = await fs.readFile(fullPath, 'utf-8');\n return JSON.parse(content);\n }\n\n async getString(path: string, encoding: BufferEncoding = 'utf-8'): Promise<string> {\n const fullPath = this.getFullPath(path);\n return await fs.readFile(fullPath, encoding);\n }\n\n async getBuffer(path: string): Promise<Buffer> {\n const fullPath = this.getFullPath(path);\n return await fs.readFile(fullPath);\n }\n\n async getStream(path: string): Promise<ReadStream> {\n const fullPath = this.getFullPath(path);\n return createReadStream(fullPath);\n }\n\n async delete(path: string): Promise<boolean> {\n const fullPath = this.getFullPath(path);\n await fs.unlink(fullPath);\n return true;\n }\n}\n"],"mappings":";;AAAA,OAAO,YAAY;AACnB,YAAY,QAAQ;AACpB,SAAS,mBAAmB,wBAAoC;AAChE,YAAY,UAAU;AACtB,YAAY,UAAU;AAIf,MAAM,qBAAyD;AAAA,EACpE,YAAoB,QAA4B;AAA5B;AAElB,OAAG,MAAM,KAAK,OAAO,UAAU,EAAE,WAAW,KAAK,CAAC,EAAE,MAAM,CAAC,UAAU;AACnE,YAAM;AAAA,IACR,CAAC;AAAA,EACH;AAAA,EAdF,OAQsE;AAAA;AAAA;AAAA,EAQpE,MAAM,SAASA,OAAiC;AAC9C,UAAM,WAAW,KAAK,YAAYA,KAAI;AACtC,UAAM,QAAQ,MAAM,GAAG,KAAK,QAAQ;AACpC,WAAO;AAAA,MACL,MAAM,MAAM;AAAA,MACZ,UAAU,KAAK,OAAO,QAAQ,KAAK;AAAA,MACnC,kBAAkB,MAAM,MAAM,YAAY;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,YAAY,UAAkB;AAC5B,WAAO,KAAK,KAAK,KAAK,OAAO,UAAU,QAAQ;AAAA,EACjD;AAAA,EAEA,MAAM,OAAOA,OAAgC;AAC3C,QAAI;AACF,YAAM,GAAG,OAAO,KAAK,YAAYA,KAAI,CAAC;AACtC,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,UAAkB,SAA8D;AACxF,UAAM,WAAW,KAAK,YAAY,QAAQ;AAE1C,UAAM,MAAM,KAAK,QAAQ,QAAQ;AACjC,UAAM,GAAG,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AAEvC,QAAI,OAAO,YAAY,YAAY,mBAAmB,QAAQ;AAC5D,YAAM,GAAG,UAAU,UAAU,OAAO;AAAA,IACtC,WAAW,OAAO,YAAY,YAAY,EAAE,mBAAmB,SAAS;AACtE,YAAM,GAAG,UAAU,UAAU,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAAA,IAC/D,WAAW,OAAO,YAAY,YAAY,mBAAmB,QAAQ;AACnE,YAAM,cAAc,kBAAkB,QAAQ;AAC9C,YAAM,IAAI,QAAQ,CAAC,SAAS,WAAW;AACrC,QAAC,QAAmB,KAAK,WAAW;AACpC,QAAC,QAAmB,GAAG,OAAO,OAAO;AACrC,QAAC,QAAmB,GAAG,SAAS,MAAM;AAAA,MACxC,CAAC;AAAA,IACH,OAAO;AACL,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAQA,OAA+B;AAC3C,UAAM,WAAW,KAAK,YAAYA,KAAI;AACtC,UAAM,UAAU,MAAM,GAAG,SAAS,UAAU,OAAO;AACnD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B;AAAA,EAEA,MAAM,UAAUA,OAAc,WAA2B,SAA0B;AACjF,UAAM,WAAW,KAAK,YAAYA,KAAI;AACtC,WAAO,MAAM,GAAG,SAAS,UAAU,QAAQ;AAAA,EAC7C;AAAA,EAEA,MAAM,UAAUA,OAA+B;AAC7C,UAAM,WAAW,KAAK,YAAYA,KAAI;AACtC,WAAO,MAAM,GAAG,SAAS,QAAQ;AAAA,EACnC;AAAA,EAEA,MAAM,UAAUA,OAAmC;AACjD,UAAM,WAAW,KAAK,YAAYA,KAAI;AACtC,WAAO,iBAAiB,QAAQ;AAAA,EAClC;AAAA,EAEA,MAAM,OAAOA,OAAgC;AAC3C,UAAM,WAAW,KAAK,YAAYA,KAAI;AACtC,UAAM,GAAG,OAAO,QAAQ;AACxB,WAAO;AAAA,EACT;AACF;","names":["path"]}
@@ -0,0 +1,22 @@
1
+ import { SFTPConfig, Metadata } from '../types.mjs';
2
+ import { StorageProviderInterface } from '../StorageProviderInterface.mjs';
3
+ import { ReadStream } from 'fs';
4
+ import Stream from 'stream';
5
+ import '@aws-sdk/client-s3';
6
+ import '@google-cloud/storage';
7
+
8
+ declare class SFTPStorageProvider implements StorageProviderInterface {
9
+ private config;
10
+ constructor(config: SFTPConfig);
11
+ private getClient;
12
+ exists(path: string): Promise<boolean>;
13
+ put(path: string, content: string | object | Stream | Buffer): Promise<boolean>;
14
+ getJson(path: string): Promise<object>;
15
+ getString(path: string): Promise<string>;
16
+ getBuffer(path: string): Promise<Buffer>;
17
+ getStream(path: string): Promise<ReadStream>;
18
+ delete(path: string): Promise<boolean>;
19
+ metadata(path: string): Promise<Metadata>;
20
+ }
21
+
22
+ export { SFTPStorageProvider };
@@ -0,0 +1,124 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import SFTPClient from "ssh2-sftp-client";
4
+ import Stream, { Readable, PassThrough } from "stream";
5
+ import * as mime from "mime-types";
6
+ class SFTPStorageProvider {
7
+ constructor(config) {
8
+ this.config = config;
9
+ }
10
+ static {
11
+ __name(this, "SFTPStorageProvider");
12
+ }
13
+ async getClient() {
14
+ const client = new SFTPClient();
15
+ await client.connect({
16
+ host: this.config.host,
17
+ port: this.config.port || 22,
18
+ username: this.config.username,
19
+ password: this.config.password,
20
+ privateKey: this.config.privateKey,
21
+ passphrase: this.config.passphrase
22
+ });
23
+ return client;
24
+ }
25
+ async exists(path) {
26
+ const client = await this.getClient();
27
+ try {
28
+ const result = await client.exists(path);
29
+ return result !== false;
30
+ } catch (error) {
31
+ return false;
32
+ } finally {
33
+ await client.end();
34
+ }
35
+ }
36
+ async put(path, content) {
37
+ const client = await this.getClient();
38
+ try {
39
+ let data;
40
+ if (typeof content === "string") {
41
+ data = content;
42
+ } else if (content instanceof Buffer) {
43
+ data = content;
44
+ } else if (typeof content === "object" && !(content instanceof Stream)) {
45
+ data = Buffer.from(JSON.stringify(content));
46
+ } else if (content instanceof Stream) {
47
+ data = content;
48
+ } else {
49
+ throw new Error("Unsupported content type");
50
+ }
51
+ await client.put(data, path);
52
+ return true;
53
+ } finally {
54
+ await client.end();
55
+ }
56
+ }
57
+ async getJson(path) {
58
+ const data = await this.getString(path);
59
+ return JSON.parse(data);
60
+ }
61
+ async getString(path) {
62
+ const buffer = await this.getBuffer(path);
63
+ return buffer.toString("utf-8");
64
+ }
65
+ async getBuffer(path) {
66
+ const client = await this.getClient();
67
+ try {
68
+ const buffer = await client.get(path);
69
+ return buffer;
70
+ } finally {
71
+ await client.end();
72
+ }
73
+ }
74
+ async getStream(path) {
75
+ const client = await this.getClient();
76
+ const passThrough = new PassThrough();
77
+ client.get(path).then((data) => {
78
+ if (data instanceof Buffer) {
79
+ const readable = new Readable();
80
+ readable.push(data);
81
+ readable.push(null);
82
+ readable.pipe(passThrough);
83
+ } else if (data instanceof Stream) {
84
+ data.pipe(passThrough);
85
+ }
86
+ return client.end();
87
+ }).catch((error) => {
88
+ client.end().catch(() => {
89
+ });
90
+ passThrough.destroy(error);
91
+ });
92
+ passThrough.on("close", () => {
93
+ client.end().catch(() => {
94
+ });
95
+ });
96
+ return passThrough;
97
+ }
98
+ async delete(path) {
99
+ const client = await this.getClient();
100
+ try {
101
+ await client.delete(path);
102
+ return true;
103
+ } finally {
104
+ await client.end();
105
+ }
106
+ }
107
+ async metadata(path) {
108
+ const client = await this.getClient();
109
+ try {
110
+ const stats = await client.stat(path);
111
+ return {
112
+ size: stats.size || 0,
113
+ mimeType: mime.lookup(path) || "unknown",
114
+ lastModifiedDate: new Date((stats.modifyTime || 0) * 1e3).toISOString()
115
+ };
116
+ } finally {
117
+ await client.end();
118
+ }
119
+ }
120
+ }
121
+ export {
122
+ SFTPStorageProvider
123
+ };
124
+ //# sourceMappingURL=SFTPStorageProvider.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/SFTPStorageProvider.mts"],"sourcesContent":["import SFTPClient from 'ssh2-sftp-client';\nimport { Metadata, SFTPConfig } from '../types.mjs';\nimport { StorageProviderInterface } from '../StorageProviderInterface.mjs';\nimport { ReadStream } from 'fs';\nimport Stream, { Readable, PassThrough } from 'stream';\nimport * as mime from 'mime-types';\n\nexport class SFTPStorageProvider implements StorageProviderInterface {\n constructor(private config: SFTPConfig) {}\n\n private async getClient(): Promise<SFTPClient> {\n const client = new SFTPClient();\n await client.connect({\n host: this.config.host,\n port: this.config.port || 22,\n username: this.config.username,\n password: this.config.password,\n privateKey: this.config.privateKey,\n passphrase: this.config.passphrase,\n });\n return client;\n }\n\n async exists(path: string): Promise<boolean> {\n const client = await this.getClient();\n try {\n const result = await client.exists(path);\n return result !== false;\n } catch (error) {\n return false;\n } finally {\n await client.end();\n }\n }\n\n async put(path: string, content: string | object | Stream | Buffer): Promise<boolean> {\n const client = await this.getClient();\n try {\n let data: string | Buffer | Readable;\n if (typeof content === 'string') {\n data = content;\n } else if (content instanceof Buffer) {\n data = content;\n } else if (typeof content === 'object' && !(content instanceof Stream)) {\n data = Buffer.from(JSON.stringify(content));\n } else if (content instanceof Stream) {\n data = content as Readable;\n } else {\n throw new Error('Unsupported content type');\n }\n\n await client.put(data, path);\n return true;\n } finally {\n await client.end();\n }\n }\n\n async getJson(path: string): Promise<object> {\n const data = await this.getString(path);\n return JSON.parse(data);\n }\n\n async getString(path: string): Promise<string> {\n const buffer = await this.getBuffer(path);\n return buffer.toString('utf-8');\n }\n\n async getBuffer(path: string): Promise<Buffer> {\n const client = await this.getClient();\n try {\n const buffer = await client.get(path);\n return buffer as Buffer;\n } finally {\n await client.end();\n }\n }\n\n async getStream(path: string): Promise<ReadStream> {\n const client = await this.getClient();\n const passThrough = new PassThrough();\n\n // Get the file as a stream and close client when done\n client\n .get(path)\n .then((data) => {\n if (data instanceof Buffer) {\n const readable = new Readable();\n readable.push(data);\n readable.push(null);\n readable.pipe(passThrough);\n } else if (data instanceof Stream) {\n (data as Stream).pipe(passThrough);\n }\n return client.end();\n })\n .catch((error) => {\n client.end().catch(() => {\n // Ignore errors when closing client during error handling\n });\n passThrough.destroy(error);\n });\n\n // Ensure client is closed when stream is destroyed\n passThrough.on('close', () => {\n client.end().catch(() => {\n // Ignore errors if already closed\n });\n });\n\n return passThrough as unknown as ReadStream;\n }\n\n async delete(path: string): Promise<boolean> {\n const client = await this.getClient();\n try {\n await client.delete(path);\n return true;\n } finally {\n await client.end();\n }\n }\n\n async metadata(path: string): Promise<Metadata> {\n const client = await this.getClient();\n try {\n const stats = await client.stat(path);\n\n return {\n size: stats.size || 0,\n mimeType: mime.lookup(path) || 'unknown',\n lastModifiedDate: new Date((stats.modifyTime || 0) * 1000).toISOString(),\n };\n } finally {\n await client.end();\n }\n }\n}\n"],"mappings":"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","names":[]}
package/dist/types.d.mts CHANGED
@@ -1,15 +1,41 @@
1
- import { S3ClientConfig } from '@aws-sdk/client-s3';
1
+ import { S3ClientConfig as S3ClientConfig$1 } from '@aws-sdk/client-s3';
2
+ import { StorageOptions } from '@google-cloud/storage';
2
3
 
3
4
  type Metadata = {
4
5
  size: number;
5
6
  mimeType: string;
6
7
  lastModifiedDate: string;
7
8
  };
8
- type StorageConfig = {
9
- engine: string;
9
+ type AzureStorageConfig = {
10
+ accountName: string;
11
+ accountKey?: string;
12
+ sasToken?: string;
13
+ containerName: string;
14
+ };
15
+ type FTPConfig = {
16
+ host: string;
17
+ port?: number;
18
+ user?: string;
19
+ password?: string;
20
+ secure?: boolean;
21
+ };
22
+ type SFTPConfig = {
23
+ host: string;
24
+ port?: number;
25
+ username?: string;
26
+ password?: string;
27
+ privateKey?: string;
28
+ passphrase?: string;
29
+ };
30
+ type S3ClientConfig = S3ClientConfig$1 & {
31
+ bucket: string;
32
+ };
33
+ type LocalStorageConfig = {
10
34
  basePath: string;
11
- bucket?: string;
12
- s3Config?: S3ClientConfig;
13
35
  };
36
+ type GCPStorageConfig = StorageOptions & {
37
+ bucket: string;
38
+ };
39
+ type StorageConfig = LocalStorageConfig | S3ClientConfig | GCPStorageConfig | AzureStorageConfig | FTPConfig | SFTPConfig;
14
40
 
15
- export type { Metadata, StorageConfig };
41
+ export type { AzureStorageConfig, FTPConfig, GCPStorageConfig, LocalStorageConfig, Metadata, S3ClientConfig, SFTPConfig, StorageConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devbro/neko-storage",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "abstracted file storage implementation",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -28,23 +28,25 @@
28
28
  "author": "Farzad Meow Khalafi",
29
29
  "license": "MIT",
30
30
  "devDependencies": {
31
+ "@types/mime-types": "^2.1.4",
31
32
  "@types/node": "^22.14.1",
33
+ "@types/ssh2-sftp-client": "^9.0.5",
32
34
  "@typescript-eslint/eslint-plugin": "^7.1.1",
33
35
  "@typescript-eslint/parser": "^7.1.1",
34
36
  "eslint": "8.57.0",
35
37
  "husky": "^9.1.7",
36
- "pinst": "^3.0.0",
37
38
  "prettier": "^3.5.3",
38
- "ts-jest": "^29.1.2",
39
- "ts-node": "^10.9.2",
40
39
  "tsup": "^8.0.2",
41
- "typescript": "^5.3.3",
42
- "@types/mime-types": "^2.1.4"
40
+ "typescript": "^5.8.3"
43
41
  },
44
42
  "dependencies": {
45
43
  "@aws-sdk/client-s3": "^3.817.0",
44
+ "@azure/storage-blob": "^12.29.1",
45
+ "@devbro/neko-helper": "0.1.*",
46
+ "@google-cloud/storage": "^7.17.3",
47
+ "basic-ftp": "^5.0.5",
46
48
  "mime-types": "^3.0.1",
47
- "@devbro/neko-helper": "0.1.*"
49
+ "ssh2-sftp-client": "^12.0.1"
48
50
  },
49
51
  "directories": {
50
52
  "doc": "docs",