@h3ravel/filesystem 0.4.17 → 1.29.0-alpha.11

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
@@ -14,7 +14,97 @@
14
14
 
15
15
  # About H3ravel/filesystem
16
16
 
17
- This is the filesystem manager for the [H3ravel](https://h3ravel.toneflix.net) framework.
17
+ This is the filesystem manager for the [H3ravel](https://h3ravel.toneflix.net) framework, providing shared file storage and filesystem utitlities for the framework.
18
+
19
+ ## Google Cloud Storage
20
+
21
+ Install and configure the filesystem package with a `gcs` disk:
22
+
23
+ ```ts
24
+ export default () => ({
25
+ default: 'gcs',
26
+ disks: {
27
+ gcs: {
28
+ driver: 'gcs',
29
+ projectId: env('GOOGLE_CLOUD_PROJECT'),
30
+ keyFilename: env('GOOGLE_APPLICATION_CREDENTIALS'),
31
+ bucket: env('GOOGLE_CLOUD_STORAGE_BUCKET'),
32
+ visibility: 'private',
33
+ usingUniformAcl: true,
34
+ },
35
+ },
36
+ links: {},
37
+ })
38
+ ```
39
+
40
+ The driver also accepts an initialized `@google-cloud/storage` client through
41
+ the `storage` option.
42
+
43
+ ## Custom Drivers
44
+
45
+ @h3ravel/filesystem allows you to configure and use custom storage drivers.
46
+
47
+ **CloudinaryFileDriver.ts**
48
+
49
+ ```ts
50
+ import type { DriverContract, ObjectVisibility } from 'flydrive/types';
51
+ import type { CustomDiskConfig } from '@h3ravel/filesystem';
52
+
53
+ export class CloudinaryFileDriver implements DriverContract {
54
+ constructor(private config?: CustomDiskConfig) {}
55
+ async exists(key: string) {}
56
+ async get(key: string) {}
57
+ async getStream(key: string) {}
58
+ async getBytes(key: string) {}
59
+ async getMetaData(key: string) {}
60
+ async getVisibility(): Promise<ObjectVisibility> {}
61
+ async getUrl(key: string) {}
62
+ async getSignedUrl(key: string) {}
63
+ async getSignedUploadUrl(key: string) {}
64
+ async setVisibility() {}
65
+ async put() {}
66
+ async putStream() {}
67
+ async copy() {}
68
+ async move() {}
69
+ async delete() {}
70
+ async deleteAll() {}
71
+ async listAll() {}
72
+ async bucket() {}
73
+ }
74
+ ```
75
+
76
+ **src/config/filesystem.ts**
77
+
78
+ ```ts
79
+ import { CloudinaryFileDriver } from '../CloudinaryFileDriver';
80
+ export default () => {
81
+ return {
82
+ default: 'images',
83
+ disks: {
84
+ images: {
85
+ //...Other Disks Here
86
+ driver: 'cloudinary',
87
+ },
88
+ },
89
+ links: {},
90
+ custom_drivers: {
91
+ cloudinary: CloudinaryFileDriver,
92
+ },
93
+ };
94
+ };
95
+ ```
96
+
97
+ To improve type safety and auto complete, you may augment the `CustomDiskDriverRegistry`
98
+
99
+ **env.d.ts**
100
+
101
+ ```ts
102
+ declare module '@h3ravel/filesystem' {
103
+ interface CustomDiskDriverRegistry {
104
+ cloudinary: { cloud_name: string; api_key: string; api_secret: string };
105
+ }
106
+ }
107
+ ```
18
108
 
19
109
  ## Contributing
20
110
 
@@ -0,0 +1,9 @@
1
+ import { IFilesystemManager } from 'h3ravel/foundation'
2
+
3
+ export { }
4
+
5
+ declare module '@h3ravel/contracts' {
6
+ interface Bindings {
7
+ 'storage': IFilesystemManager
8
+ }
9
+ }
@@ -0,0 +1,31 @@
1
+ import { Command } from "@h3ravel/musket";
2
+
3
+ //#region src/Commands/StorageLinkCommand.d.ts
4
+ declare class StorageLinkCommand extends Command {
5
+ /**
6
+ * The name and signature of the console command.
7
+ *
8
+ * @var string
9
+ */
10
+ protected signature: string;
11
+ /**
12
+ * The console command description.
13
+ *
14
+ * @var string
15
+ */
16
+ protected description: string;
17
+ /**
18
+ * Execute the console command.
19
+ */
20
+ handle(this: any): Promise<void>;
21
+ /**
22
+ * Create the symbolic links configured for the application.
23
+ */
24
+ link(): Promise<void>;
25
+ /**
26
+ * Delete existing symbolic links configured for the application.
27
+ */
28
+ unlink(): Promise<void>;
29
+ }
30
+ //#endregion
31
+ export { StorageLinkCommand };
@@ -1,10 +1,8 @@
1
- let __h3ravel_shared = require("@h3ravel/shared");
2
- let fs_promises = require("fs/promises");
3
- let __h3ravel_musket = require("@h3ravel/musket");
4
- let __h3ravel_core = require("@h3ravel/core");
5
-
1
+ import { FileSystem, Logger } from "@h3ravel/shared";
2
+ import { rm, symlink, unlink } from "fs/promises";
3
+ import { Command } from "@h3ravel/musket";
6
4
  //#region src/Commands/StorageLinkCommand.ts
7
- var StorageLinkCommand = class extends __h3ravel_musket.Command {
5
+ var StorageLinkCommand = class extends Command {
8
6
  /**
9
7
  * The name and signature of the console command.
10
8
  *
@@ -40,23 +38,23 @@ var StorageLinkCommand = class extends __h3ravel_musket.Command {
40
38
  const force = this.option("force");
41
39
  const newPath = key;
42
40
  const existingPath = links[key];
43
- if (!force && await __h3ravel_shared.FileSystem.fileExists(newPath)) {
44
- __h3ravel_shared.Logger.log([
41
+ if (!force && await FileSystem.fileExists(newPath)) {
42
+ Logger.log([
45
43
  [" ERROR ", "bgRed"],
46
44
  ["The", "white"],
47
45
  [`[${newPath.replace(process.cwd(), "")}]`, "bold"],
48
46
  ["link already exists.\n", "white"]
49
47
  ], " ");
50
48
  continue;
51
- } else if (force) await (0, fs_promises.rm)(newPath, {
49
+ } else if (force) await rm(newPath, {
52
50
  recursive: true,
53
51
  force: true
54
52
  });
55
53
  /**
56
54
  * Create the symlink
57
55
  */
58
- await (0, fs_promises.symlink)(existingPath, newPath);
59
- __h3ravel_shared.Logger.log([
56
+ await symlink(existingPath, newPath);
57
+ Logger.log([
60
58
  [" INFO ", "bgBlue"],
61
59
  [" The ", "white"],
62
60
  [`[${newPath.replace(process.cwd(), "")}] `, "bold"],
@@ -71,12 +69,12 @@ var StorageLinkCommand = class extends __h3ravel_musket.Command {
71
69
  */
72
70
  async unlink() {
73
71
  const links = config("filesystem.links");
74
- for (const path in links) if (await __h3ravel_shared.FileSystem.fileExists(path)) {
72
+ for (const path in links) if (await FileSystem.fileExists(path)) {
75
73
  /**
76
74
  * Remove the symlink
77
75
  */
78
- await (0, fs_promises.unlink)(path);
79
- __h3ravel_shared.Logger.log([
76
+ await unlink(path);
77
+ Logger.log([
80
78
  [" INFO ", "bgBlue"],
81
79
  [" The ", "white"],
82
80
  [`[${path.replace(process.cwd(), "")}] `, "bold"],
@@ -86,20 +84,5 @@ var StorageLinkCommand = class extends __h3ravel_musket.Command {
86
84
  }
87
85
  }
88
86
  };
89
-
90
87
  //#endregion
91
- //#region src/Providers/FilesystemProvider.ts
92
- /**
93
- * Sets up Filesystem management and lifecycle.
94
- *
95
- */
96
- var FilesystemProvider = class extends __h3ravel_core.ServiceProvider {
97
- static priority = 997;
98
- register() {
99
- this.registerCommands([StorageLinkCommand]);
100
- }
101
- };
102
-
103
- //#endregion
104
- exports.FilesystemProvider = FilesystemProvider;
105
- exports.StorageLinkCommand = StorageLinkCommand;
88
+ export { StorageLinkCommand };
@@ -0,0 +1,6 @@
1
+ import { IFilesystemManager } from "@h3ravel/foundation";
2
+
3
+ //#region src/Facades/StorageFacade.d.ts
4
+ declare const Storage: IFilesystemManager<keyof import("@h3ravel/foundation").KnownDisks>;
5
+ //#endregion
6
+ export { Storage };
@@ -0,0 +1,10 @@
1
+ import { Facades } from "@h3ravel/support/facades";
2
+ //#region src/Facades/StorageFacade.ts
3
+ var StorageFacade = class extends Facades {
4
+ static getFacadeAccessor() {
5
+ return "storage";
6
+ }
7
+ };
8
+ const Storage = StorageFacade.createFacade();
9
+ //#endregion
10
+ export { Storage };
package/dist/index.d.ts CHANGED
@@ -1,33 +1,390 @@
1
1
  /// <reference path="./app.globals.d.ts" />
2
- import { Command } from "@h3ravel/musket";
3
- import { ServiceProvider } from "@h3ravel/core";
2
+ import { StorageLinkCommand } from "./commands.js";
3
+ import { FSDriver } from "flydrive/drivers/fs";
4
+ import { DriveDirectory, DriveFile, DriveManager } from "flydrive";
5
+ import { CustomDiskDriverRegistry, DiskConfig, FileLike, FilesystemConfig, IFilesystemDriver, IFilesystemManager, IFtpDiskDriver, KnownDisks } from "@h3ravel/foundation";
6
+ import { Readable } from "node:stream";
7
+ import { GCSDriver } from "flydrive/drivers/gcs";
8
+ import { S3Driver } from "flydrive/drivers/s3";
9
+ import { ServiceProvider } from "@h3ravel/support";
10
+ import { DriverContract, ObjectMetaData, ObjectVisibility, SignedURLOptions, WriteOptions } from "flydrive/types";
4
11
 
5
- //#region src/Commands/StorageLinkCommand.d.ts
6
- declare class StorageLinkCommand extends Command {
12
+ //#region src/FtpDriver.d.ts
13
+ declare class FtpDriver extends IFtpDiskDriver implements DriverContract {
14
+ private config;
15
+ constructor(config: string | {
16
+ host: string;
17
+ username: string;
18
+ password: string;
19
+ port?: number;
20
+ verbose?: boolean;
21
+ privateKey?: string;
22
+ });
23
+ getConfig(): {
24
+ host: string;
25
+ username: string;
26
+ password: string;
27
+ port?: number;
28
+ verbose?: boolean;
29
+ privateKey?: string;
30
+ };
31
+ private init;
32
+ private load;
7
33
  /**
8
- * The name and signature of the console command.
34
+ * Return a boolean value indicating if the file exists
35
+ * or not.
36
+ */
37
+ exists(key: string): Promise<boolean>;
38
+ /**
39
+ * Return the file contents as a UTF-8 string. Throw an exception
40
+ * if the file is missing.
41
+ */
42
+ get(key: string): Promise<string>;
43
+ /**
44
+ * Return the file contents as a Readable stream. Throw an exception
45
+ * if the file is missing.
46
+ */
47
+ getStream(key: string): Promise<Readable>;
48
+ /**
49
+ * Return the file contents as a Uint8Array. Throw an exception
50
+ * if the file is missing.
51
+ */
52
+ getBytes(key: string): Promise<Uint8Array>;
53
+ /**
54
+ * Return metadata of the file. Throw an exception
55
+ * if the file is missing.
56
+ */
57
+ getMetaData(key: string): Promise<ObjectMetaData>;
58
+ /**
59
+ * Return visibility of the file. Infer visibility from the initial
60
+ * config, when the driver does not support the concept of visibility.
61
+ */
62
+ getVisibility(key: string): Promise<ObjectVisibility>;
63
+ /**
64
+ * Return the public URL of the file. Throw an exception when the driver
65
+ * does not support generating URLs.
66
+ */
67
+ getUrl(key: string): Promise<string>;
68
+ /**
69
+ * Return the signed URL to serve a private file. Throw exception
70
+ * when the driver does not support generating URLs.
71
+ */
72
+ getSignedUrl(key: string, options?: SignedURLOptions): Promise<string>;
73
+ /**
74
+ * Return the signed/temporary URL that can be used to directly upload
75
+ * the file contents to the storage.
76
+ */
77
+ getSignedUploadUrl(key: string, options?: SignedURLOptions): Promise<string>;
78
+ /**
79
+ * Update the visibility of the file. Result in a NOOP
80
+ * when the driver does not support the concept of
81
+ * visibility.
82
+ */
83
+ setVisibility(key: string, visibility: ObjectVisibility): Promise<void>;
84
+ /**
85
+ * Create a new file or update an existing file. The contents
86
+ * will be a UTF-8 string or "Uint8Array".
87
+ */
88
+ put(key: string, contents: string | Uint8Array, options?: WriteOptions): Promise<void>;
89
+ /**
90
+ * Create a new file or update an existing file. The contents
91
+ * will be a Readable stream.
92
+ */
93
+ putStream(key: string, contents: Readable, options?: WriteOptions): Promise<void>;
94
+ /**
95
+ * Copy the existing file to the destination. Make sure the new file
96
+ * has the same visibility as the existing file. It might require
97
+ * manually fetching the visibility of the "source" file.
98
+ */
99
+ copy(source: string, destination: string, options?: WriteOptions): Promise<void>;
100
+ /**
101
+ * Move the existing file to the destination. Make sure the new file
102
+ * has the same visibility as the existing file. It might require
103
+ * manually fetching the visibility of the "source" file.
104
+ */
105
+ move(source: string, destination: string, options?: WriteOptions): Promise<void>;
106
+ /**
107
+ * Delete an existing file. Do not throw an error if the
108
+ * file is already missing
109
+ */
110
+ delete(key: string): Promise<void>;
111
+ /**
112
+ * Delete all files inside a folder. Do not throw an error
113
+ * if the folder does not exist or is empty.
114
+ */
115
+ deleteAll(prefix: string): Promise<void>;
116
+ /**
117
+ * Switch bucket at runtime if supported.
118
+ */
119
+ bucket(config: string | {
120
+ host: string;
121
+ username: string;
122
+ password: string;
123
+ port?: number;
124
+ verbose?: boolean;
125
+ privateKey?: string;
126
+ }): DriverContract;
127
+ /**
128
+ * List all files from a given folder or the root of the storage.
129
+ * Do not throw an error if the request folder does not exist.
130
+ */
131
+ listAll(prefix: string, options?: {
132
+ recursive?: boolean;
133
+ paginationToken?: string;
134
+ }): Promise<{
135
+ paginationToken?: string;
136
+ objects: Iterable<DriveFile | DriveDirectory>;
137
+ }>;
138
+ }
139
+ //#endregion
140
+ //#region src/Driver.d.ts
141
+ type BuiltInDriverMap = { [K in keyof Driver]: Driver[K] };
142
+ type DriverFor<K extends string> = K extends keyof BuiltInDriverMap ? ReturnType<BuiltInDriverMap[K]> : ReturnType<BuiltInDriverMap['custom']>;
143
+ declare class Driver extends IFilesystemDriver {
144
+ private config;
145
+ private static customDrivers;
146
+ constructor(config: DiskConfig);
147
+ static make<K extends 'local' | 'ftp' | 's3' | 'gcs' | (string & {})>(config: DiskConfig): DriverFor<K>;
148
+ local(): FSDriver;
149
+ s3(): S3Driver;
150
+ gcs(): GCSDriver;
151
+ ftp(): FtpDriver;
152
+ custom(name: string): DriverContract;
153
+ /**
154
+ * Register a new custom driver
9
155
  *
10
- * @var string
156
+ * @param name
157
+ * @param driver
11
158
  */
12
- protected signature: string;
159
+ static registerDriver(name: string, driver: DriverContract): void;
13
160
  /**
14
- * The console command description.
161
+ * Unregister a new custom driver
15
162
  *
16
- * @var string
163
+ * @param name
17
164
  */
18
- protected description: string;
165
+ static removeDriver(name: string): void;
166
+ }
167
+ //#endregion
168
+ //#region src/FilesystemManager.d.ts
169
+ declare class FilesystemManager<D extends keyof KnownDisks | keyof CustomDiskDriverRegistry = keyof KnownDisks | keyof CustomDiskDriverRegistry> extends IFilesystemManager implements DriverContract {
170
+ driver: DriveManager<any>;
171
+ services: Record<string, () => DriverContract>;
172
+ diskName: D;
173
+ driverName: FilesystemConfig['disks'][D]['driver'];
174
+ constructor();
19
175
  /**
20
- * Execute the console command.
176
+ * Select a configured disk on the filesystem manager.
177
+ *
178
+ * @param diskName The name of the disk to use. If not provided, the default disk will be used.
179
+ * @returns The filesystem manager instance
21
180
  */
22
- handle(this: any): Promise<void>;
181
+ disk<K extends keyof KnownDisks | keyof CustomDiskDriverRegistry>(diskName: K): this;
23
182
  /**
24
- * Create the symbolic links configured for the application.
183
+ * Generate a unique name for the file based on random numbers and original extension
184
+ *
185
+ * @param file The file object containing the original name
186
+ * @returns A unique file name
25
187
  */
26
- link(): Promise<void>;
188
+ generateName(file: {
189
+ name?: string;
190
+ originalname?: string;
191
+ }): string;
27
192
  /**
28
- * Delete existing symbolic links configured for the application.
193
+ * Save the file to the storage and return the public URL and the file path
194
+ *
195
+ * @param file The file object containing the file data
196
+ * @param filePath The path where the file should be saved
197
+ * @param fileName The name to save the file as (optional)
198
+ * @returns A tuple containing the public URL and the file path
199
+ */
200
+ saveFile(file: FileLike, filePath?: string, fileName?: string): Promise<[string, string]>;
201
+ /**
202
+ * Return a boolean indicating if the file exists
203
+ *
204
+ * @param key
205
+ * @returns
206
+ */
207
+ exists(key: string): Promise<boolean>;
208
+ /**
209
+ * Return contents of a object for the given key as a UTF-8 string.
210
+ * Should throw "E_CANNOT_READ_FILE" error when the file
211
+ * does not exists.
212
+ *
213
+ * @param key
214
+ * @returns
215
+ */
216
+ get(key: string): Promise<string>;
217
+ /**
218
+ * Get the name of the disk currently in use.
219
+ *
220
+ * @returns
221
+ */
222
+ getDiskName(): D;
223
+ /**
224
+ * Get the name of the driver currently in use.
225
+ *
226
+ * @returns
227
+ */
228
+ getDriverName(): (KnownDisks & CustomDiskDriverRegistry)[D]["driver"];
229
+ /**
230
+ * Get the driver currently in use.
231
+ *
232
+ * @returns
233
+ */
234
+ getDriver(): DriveManager<any>;
235
+ /**
236
+ * Return contents of a object for the given key as a Readable stream.
237
+ * Should throw "E_CANNOT_READ_FILE" error when the file
238
+ * does not exists.
239
+ *
240
+ * @param key
241
+ * @returns
242
+ */
243
+ getStream(key: string): Promise<Readable>;
244
+ /**
245
+ * Return contents of an object for the given key as an Uint8Array.
246
+ * Should throw "E_CANNOT_READ_FILE" error when the file
247
+ * does not exists.
248
+ *
249
+ * @param key
250
+ * @returns
251
+ */
252
+ getBytes(key: string): Promise<Uint8Array>;
253
+ /**
254
+ * Return metadata of an object for the given key.
255
+ *
256
+ * @param key
257
+ * @returns
258
+ */
259
+ getMetaData(key: string): Promise<ObjectMetaData>;
260
+ /**
261
+ * Return the visibility of the file
262
+ *
263
+ * @param key
264
+ * @returns
265
+ */
266
+ getVisibility(key: string): Promise<ObjectVisibility>;
267
+ /**
268
+ * Return the public URL to access the file
269
+ *
270
+ * @param key
271
+ * @returns
272
+ */
273
+ getUrl(key: string): Promise<string>;
274
+ /**
275
+ * Return the signed/temporary URL to access the file
276
+ *
277
+ * @param key
278
+ * @param options
279
+ * @returns
280
+ */
281
+ getSignedUrl(key: string, options?: SignedURLOptions): Promise<string>;
282
+ /**
283
+ * Return the signed/temporary URL that can be used to directly upload
284
+ * the file contents to the storage.
285
+ *
286
+ * @param key
287
+ * @param options
288
+ * @returns
289
+ */
290
+ getSignedUploadUrl(key: string, options?: SignedURLOptions): Promise<string>;
291
+ /**
292
+ * Update the visibility of the file
293
+ *
294
+ * @param key
295
+ * @param visibility
296
+ * @returns
297
+ */
298
+ setVisibility(key: string, visibility: ObjectVisibility): Promise<void>;
299
+ /**
300
+ * Write object to the destination with the provided
301
+ * contents.
302
+ *
303
+ * @param key
304
+ * @param contents
305
+ * @param options
306
+ * @returns
307
+ */
308
+ put(key: string, contents: string | Uint8Array | FileLike, options?: WriteOptions): Promise<void>;
309
+ /**
310
+ * Write object to the destination with the provided
311
+ * contents as a readable stream
312
+ *
313
+ * @param key
314
+ * @param contents
315
+ * @param options
316
+ * @returns
317
+ */
318
+ putStream(key: string, contents: Readable, options?: WriteOptions): Promise<void>;
319
+ /**
320
+ * Copy the file from within the disk root location. Both
321
+ * the "source" and "destination" will be the key names
322
+ * and not absolute paths.
323
+ *
324
+ * @param source
325
+ * @param destination
326
+ * @param options
327
+ * @returns
328
+ */
329
+ copy(source: string, destination: string, options?: WriteOptions): Promise<void>;
330
+ /**
331
+ * Move the file from within the disk root location. Both
332
+ * the "source" and "destination" will be the key names
333
+ * and not absolute paths.
334
+ *
335
+ * @param source
336
+ * @param destination
337
+ * @param options
338
+ * @returns
339
+ */
340
+ move(source: string, destination: string, options?: WriteOptions): Promise<void>;
341
+ /**
342
+ * Delete the file for the given key. Should not throw
343
+ * error when file does not exist in first place
344
+ *
345
+ * @param key
346
+ * @returns
347
+ */
348
+ delete(key: string): Promise<void>;
349
+ /**
350
+ * Delete the files and directories matching the provided prefix.
351
+ *
352
+ * @param prefix
353
+ * @returns
354
+ */
355
+ deleteAll(prefix: string): Promise<void>;
356
+ /**
357
+ * The list all method must return an array of objects with
358
+ * the ability to paginate results (if supported).
359
+ *
360
+ * @param prefix
361
+ * @param options
362
+ * @returns
363
+ */
364
+ listAll(prefix: string, options?: {
365
+ recursive?: boolean;
366
+ paginationToken?: string;
367
+ }): Promise<{
368
+ paginationToken?: string;
369
+ objects: Iterable<DriveFile | DriveDirectory>;
370
+ }>;
371
+ /**
372
+ * Switch bucket at runtime if supported.
373
+ *
374
+ * @param bucket
375
+ * @returns
376
+ */
377
+ bucket(bucket: string): DriverContract;
378
+ /**
379
+ * Create symbolic links for all configured links in the application configuration.
380
+ *
381
+ * @param param0
29
382
  */
30
- unlink(): Promise<void>;
383
+ link({
384
+ force
385
+ }?: {
386
+ force?: boolean;
387
+ }): void;
31
388
  }
32
389
  //#endregion
33
390
  //#region src/Providers/FilesystemProvider.d.ts
@@ -40,4 +397,4 @@ declare class FilesystemProvider extends ServiceProvider {
40
397
  register(): void;
41
398
  }
42
399
  //#endregion
43
- export { FilesystemProvider, StorageLinkCommand };
400
+ export { Driver, FilesystemManager, FilesystemProvider, FtpDriver, StorageLinkCommand };