This commit is contained in:
Tutur33
2023-11-24 22:35:41 +01:00
parent 3c0b507a93
commit 7644b2a0f7
45165 changed files with 4803356 additions and 3 deletions
+9
View File
@@ -0,0 +1,9 @@
# The MIT License
Copyright 2022 Harminder Virk, contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+59
View File
@@ -0,0 +1,59 @@
<div align="center">
<img src="https://res.cloudinary.com/adonisjs/image/upload/q_100/v1558612869/adonis-readme_zscycu.jpg" width="600px">
</div>
<br />
<div align="center">
<h3>AdonisJS Drive</h3>
<p>
An abstraction on top of cloud storage services like <strong>Google cloud</strong>, <strong>Amazon S3</strong>, and <strong>Digital ocean spaces</strong>. Can be extended to add custom drivers.
</p>
</div>
<br />
<div align="center">
[![gh-workflow-image]][gh-workflow-url] [![npm-image]][npm-url] ![][typescript-image] [![license-image]][license-url] [![synk-image]][synk-url]
</div>
<div align="center">
<h3>
<a href="https://adonisjs.com">
Website
</a>
<span> | </span>
<a href="https://docs.adonisjs.com/guides/drive">
Guides
</a>
<span> | </span>
<a href="CONTRIBUTING.md">
Contributing
</a>
<span> | </span>
<a href="benchmarks.md">
Benchmarks
</a>
</h3>
</div>
<div align="center">
<sub>Built with ❤︎ by <a href="https://twitter.com/AmanVirk1">Harminder Virk</a>
</div>
[gh-workflow-image]: https://img.shields.io/github/workflow/status/adonisjs/drive/test?style=for-the-badge
[gh-workflow-url]: https://github.com/adonisjs/drive/actions/workflows/test.yml "Github action"
[typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
[typescript-url]: "typescript"
[npm-image]: https://img.shields.io/npm/v/@adonisjs/drive.svg?style=for-the-badge&logo=npm
[npm-url]: https://npmjs.org/package/@adonisjs/drive "npm"
[license-image]: https://img.shields.io/npm/l/@adonisjs/drive?color=blueviolet&style=for-the-badge
[license-url]: LICENSE.md "license"
[synk-image]: https://img.shields.io/snyk/vulnerabilities/github/adonisjs/drive?label=Synk%20Vulnerabilities&style=for-the-badge
[synk-url]: https://snyk.io/test/github/adonisjs/drive?targetFile=package.json "synk"
+6
View File
@@ -0,0 +1,6 @@
declare module '@ioc:Adonis/Core/Application' {
import { DriveManagerContract } from '@ioc:Adonis/Core/Drive';
interface ContainerBindings {
'Adonis/Core/Drive': DriveManagerContract;
}
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+340
View File
@@ -0,0 +1,340 @@
/// <reference types="node" />
/// <reference types="node" />
/// <reference types="node" />
declare module '@ioc:Adonis/Core/Drive' {
import * as fsExtra from 'fs-extra';
import type { Volume as MemfsVolume } from 'memfs/lib/volume';
import type { Dirent as MemfsDirent } from 'memfs/lib/Dirent';
import { ManagerContract } from '@poppinss/manager';
import { ApplicationContract } from '@ioc:Adonis/Core/Application';
/**
* Content options for files
*/
export type ContentHeaders = {
contentType?: string;
contentLanguage?: string;
contentEncoding?: string;
contentDisposition?: string;
cacheControl?: string;
contentLength?: string | number;
};
/**
* Options for writing, moving and copying
* files
*/
export type WriteOptions = {
visibility?: string;
} & ContentHeaders & Record<string, any>;
/**
* Available visibilities
*/
export type Visibility = 'public' | 'private';
/**
* Stats returned by the drive drivers
*/
export type DriveFileStats = {
size: number;
modified: Date;
isFile: boolean;
etag?: string;
};
/**
* List item returned by the drive drivers
*/
export interface DriveListItem<T = any> {
/**
* Location of list item on disk which can be used in driver methods
*/
location: string;
/**
* Flag to know if item represents file or directory
*/
isFile: boolean;
/**
* Original list item returned from underlying driver
*/
original: T;
}
/**
* Shape of the directory listing async iterable returned from list allowing to transform listing.
* This can be iterated directly using for-await-of loop or it can be converted to array using toArray().
*/
export interface DirectoryListingContract<Driver extends DriverContract, T> extends AsyncIterable<T> {
/**
* Reference to the driver for which the listing was created.
*/
driver: Driver;
/**
* Filter generated items of listing with the given predicate function.
*/
filter(predicate: (item: T, index: number, driver: Driver) => Promise<boolean> | boolean): DirectoryListingContract<Driver, T>;
/**
* Transform generated items of listing with the given mapper function.
*/
map<M>(mapper: (item: T, index: number, driver: Driver) => Promise<M> | M): DirectoryListingContract<Driver, M>;
/**
* Do recursive listing of items. Without the next function it will do listing of leaf nodes only.
* For advanced usage you can pass the next function which will get as parameter current item and it should
* return the next location for list or null if the recursion should stop and yield the current item.
* For advanced usage you can also limit the depth of recursion using the second argument of next function.
*/
recursive(next?: (current: T, depth: number, driver: Driver) => Promise<string | null> | string | null): DirectoryListingContract<Driver, T>;
/**
* Add a piping chain function which gets the current async iterable and returns
* new async iterable with modified directory listing output.
* Function this is bound to instance of driver for which the listing is generated.
* This allows using async generator functions and reference the driver methods easily.
* Piping will always return clone of the current instance and add the function
* to the chain of new cloned instance only to prevent side effects.
*/
pipe<U>(fn: (this: Driver, source: AsyncIterable<T>) => AsyncIterable<U>): DirectoryListingContract<Driver, U>;
/**
* Get the final async iterable after passing directory listing through chain of piping functions modifying the output.
*/
toIterable(): AsyncIterable<T>;
/**
* Convert directory listing to array.
*/
toArray(): Promise<T[]>;
}
/**
* Shape of the generic driver
*/
export interface DriverContract {
/**
* Name of the driver
*/
name: string;
/**
* A boolean to find if the location path exists or not
*/
exists(location: string): Promise<boolean>;
/**
* Returns the file contents as a buffer.
*/
get(location: string): Promise<Buffer>;
/**
* Returns the file contents as a stream
*/
getStream(location: string): Promise<NodeJS.ReadableStream>;
/**
* Returns the location path visibility
*/
getVisibility(location: string): Promise<Visibility>;
/**
* Returns the location path stats
*/
getStats(location: string): Promise<DriveFileStats>;
/**
* Returns a signed URL for a given location path
*/
getSignedUrl(location: string, options?: ContentHeaders & {
expiresIn?: string | number;
}): Promise<string>;
/**
* Returns a URL for a given location path
*/
getUrl(location: string): Promise<string>;
/**
* Write string|buffer contents to a destination. The missing
* intermediate directories will be created (if required).
*/
put(location: string, contents: Buffer | string, options?: WriteOptions): Promise<void>;
/**
* Write a stream to a destination. The missing intermediate
* directories will be created (if required).
*/
putStream(location: string, contents: NodeJS.ReadableStream, options?: WriteOptions): Promise<void>;
/**
* Update the visibility of the file
*/
setVisibility(location: string, visibility: Visibility): Promise<void>;
/**
* Remove a given location path
*/
delete(location: string): Promise<void>;
/**
* Copy a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
copy(source: string, destination: string, options?: WriteOptions): Promise<void>;
/**
* Move a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
move(source: string, destination: string, options?: WriteOptions): Promise<void>;
/**
* Return a listing directory iterator for given location.
* @experimental
*/
list?(location: string): DirectoryListingContract<this, DriveListItem>;
}
/**
* List item returned from fake disk driver
*/
export interface FakeDriveListItem extends DriveListItem<MemfsDirent> {
}
/**
* Shape of the fake implementation for the driver. Any custom implementation
* must adhere to it.
*/
export interface FakeDriverContract extends DriverContract {
/**
* The name is static
*/
name: 'fake';
/**
* Reference to the underlying adapter. Which is memfs
*/
adapter: MemfsVolume;
/**
* The disk its faking
*/
disk: keyof DisksList;
/**
* Make path to a given file location
*/
makePath(location: string): string;
/**
* Return a listing directory iterator for given location.
* @experimental
*/
list(location: string): DirectoryListingContract<this, FakeDriveListItem>;
}
/**
* Config accepted by the local disk driver
*/
export type LocalDriverConfig = {
driver: 'local';
visibility: Visibility;
root: string;
/**
* Base path is always required when "serveFiles = true"
*/
serveFiles?: boolean;
basePath?: string;
};
/**
* List item returned from local disk driver
*/
export interface LocalDriveListItem extends DriveListItem<fsExtra.Dirent> {
}
/**
* Shape of the local disk driver
*/
export interface LocalDriverContract extends DriverContract {
name: 'local';
/**
* Reference to the underlying adapter. Which is fs-extra
*/
adapter: typeof fsExtra;
/**
* Make path to a given file location
*/
makePath(location: string): string;
/**
* Return a listing directory iterator for given location.
* @experimental
*/
list(location: string): DirectoryListingContract<this, LocalDriveListItem>;
}
/**
* List of registered drivers. Drivers shipped via other packages
* should merge drivers to this interface
*/
export interface DriversList {
local: {
implementation: LocalDriverContract;
config: LocalDriverConfig;
};
}
/**
* A list of disks registered in the user land
*/
export interface DisksList {
}
/**
* The config accepted by Drive
* @type {Object}
*/
export type DriveConfig = {
disk: keyof DisksList;
disks: {
[P in keyof DisksList]: DisksList[P]['config'];
};
};
/**
* Fake drive
*/
export interface FakeDriveContract {
/**
* Access to the fake instances created so far
*/
fakes: Map<keyof DisksList, FakeDriverContract>;
/**
* Find if a fake file exists
*/
exists(location: string): Promise<boolean>;
/**
* Returns the file contents as a buffer.
*/
get(location: string): Promise<Buffer>;
/**
* Get the size of the file in bytes
*/
bytes(location: string): Promise<number>;
/**
* Find if the disk is faked
*/
isFaked(disk: keyof DisksList): boolean;
/**
* Returns the fake implementation for a given
* disk
*/
use(disk: keyof DisksList): FakeDriverContract;
/**
* Restore a fake
*/
restore(disk: keyof DisksList): void;
}
/**
* Shape of the fake implementation callback
*/
export type FakeImplementationCallback = (manager: DriveManagerContract, mappingName: keyof DisksList, config: any) => FakeDriverContract;
/**
* Drive manager to manage disk instances
*/
export interface DriveManagerContract extends ManagerContract<ApplicationContract, DriverContract, DriverContract, {
[P in keyof DisksList]: DisksList[P]['implementation'];
}>, Omit<DriverContract, 'name'> {
/**
* Access to the fake instances created so far.
* @deprecated
*/
fakes: Map<keyof DisksList, FakeDriverContract>;
/**
* Fake the default or a named disk
*/
fake(disk?: keyof DisksList | keyof DisksList[]): FakeDriveContract;
/**
* Restore fake for the default or a named disk
*/
restore(disk?: keyof DisksList | keyof DisksList[]): void;
/**
* Restore all fakes
*/
restoreAll(): void;
/**
* Define a custom fake implementation. An instance of it
* will be created anytime a fake is created
*/
setFakeImplementation(callback: FakeImplementationCallback): void;
/**
* Return a listing directory iterator for given location.
* @experimental
*/
list(location: string): DirectoryListingContract<DriverContract, DriveListItem>;
}
const Drive: DriveManagerContract;
export default Drive;
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+2
View File
@@ -0,0 +1,2 @@
/// <reference path="drive.d.ts" />
/// <reference path="container.d.ts" />
+10
View File
@@ -0,0 +1,10 @@
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/// <reference path="./drive.ts" />
/// <reference path="./container.ts" />
+28
View File
@@ -0,0 +1,28 @@
import { DriversList } from '@ioc:Adonis/Core/Drive';
/**
* Expected shape of the config accepted by the "driveConfig"
* method
*/
declare type DriveConfig = {
disks: {
[name: string]: {
[K in keyof DriversList]: DriversList[K]['config'] & {
driver: K;
};
}[keyof DriversList];
};
};
/**
* Define config for AdonisJS drive
*/
export declare function driveConfig<T extends DriveConfig & {
disk: keyof T['disks'];
}>(config: T): T;
/**
* Pull disks from the config defined inside the "config/drive.ts"
* file
*/
export declare type InferDisksFromConfig<T extends DriveConfig> = {
[K in keyof T['disks']]: DriversList[T['disks'][K]['driver']];
};
export {};
+18
View File
@@ -0,0 +1,18 @@
"use strict";
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.driveConfig = void 0;
/**
* Define config for AdonisJS drive
*/
function driveConfig(config) {
return config;
}
exports.driveConfig = driveConfig;
+24
View File
@@ -0,0 +1,24 @@
import { ApplicationContract } from '@ioc:Adonis/Core/Application';
/**
* Registers drive with the IoC container
*/
export default class DriveProvider {
protected app: ApplicationContract;
constructor(app: ApplicationContract);
/**
* Register drive with the container
*/
protected registerDrive(): void;
/**
* Register routes for disks using "local" driver.
*/
protected defineDriveRoutes(): void;
/**
* Registering all required bindings to the container
*/
register(): void;
/**
* Register drive routes
*/
boot(): void;
}
+69
View File
@@ -0,0 +1,69 @@
"use strict";
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Registers drive with the IoC container
*/
class DriveProvider {
constructor(app) {
this.app = app;
}
/**
* Register drive with the container
*/
registerDrive() {
this.app.container.singleton('Adonis/Core/Drive', () => {
const { DriveManager } = require('../src/DriveManager');
const Router = this.app.container.resolveBinding('Adonis/Core/Route');
const Config = this.app.container.resolveBinding('Adonis/Core/Config');
const Logger = this.app.container.resolveBinding('Adonis/Core/Logger');
return new DriveManager(this.app, Router, Logger, Config.get('drive'));
});
}
/**
* Register routes for disks using "local" driver.
*/
defineDriveRoutes() {
this.app.container.withBindings(['Adonis/Core/Config', 'Adonis/Core/Route', 'Adonis/Core/Logger'], (Config, Router, Logger) => {
/**
* Do not attempt to resolve Drive from the container when there is
* no configuration in place.
*
* This is a make shift arrangement. Later, we will have a universal
* approach to disabling modules
*/
const driveConfig = Config.get('drive');
if (!driveConfig) {
return;
}
const Drive = this.app.container.resolveBinding('Adonis/Core/Drive');
const { LocalFileServer } = require('../src/LocalFileServer');
Object.keys(driveConfig.disks).forEach((diskName) => {
const diskConfig = driveConfig.disks[diskName];
if (diskConfig.driver === 'local' && diskConfig.serveFiles) {
new LocalFileServer(diskName, diskConfig, Drive.use(diskName), Router, Logger).registerRoute();
}
});
});
}
/**
* Registering all required bindings to the container
*/
register() {
this.registerDrive();
}
/**
* Register drive routes
*/
boot() {
this.defineDriveRoutes();
}
}
exports.default = DriveProvider;
+51
View File
@@ -0,0 +1,51 @@
/// <reference path="../../adonis-typings/index.d.ts" />
import { DirectoryListingContract, DriveListItem, DriverContract } from '@ioc:Adonis/Core/Drive';
/**
* Directory listing exposes the API to list directory contents using async iterators
* and also adds some helper functions for transforming the output of driver list.
*/
export declare class DirectoryListing<Driver extends DriverContract, T extends DriveListItem> implements DirectoryListingContract<Driver, T> {
driver: Driver;
private listing;
/**
* Functions chain to be executed for transforming generated listing iterable
*/
private chain;
constructor(driver: Driver, listing: (this: Driver) => AsyncGenerator<T>);
/**
* Filter generated items of listing with the given predicate function.
*/
filter(predicate: (item: T, index: number, driver: Driver) => Promise<boolean> | boolean): DirectoryListingContract<Driver, T>;
/**
* Transform generated items of listing with the given mapper function.
*/
map<M>(mapper: (item: T, index: number, driver: Driver) => M | Promise<M>): DirectoryListingContract<Driver, Awaited<M>>;
/**
* Do recursive listing of items. Without the next function it will do listing of leaf nodes only.
* For advanced usage you can pass the next function which will get as parameter current item and it should
* return the next location for list or null if the recursion should stop and yield the current item.
* For advanced usage you can also limit the depth of recursion using the second argument of next function.
*/
recursive(next?: (current: T, depth: number, driver: Driver) => Promise<string | null> | string | null): DirectoryListingContract<Driver, any>;
/**
* Add a piping chain function which gets the current async iterable and returns
* new async iterable with modified directory listing output.
* Function this is bound to instance of driver for which the listing is generated.
* This allows using async generator functions and reference the driver methods easily.
* Piping will always return clone of the current instance and add the function
* to the chain of new cloned instance only to prevent side effects.
*/
pipe<U>(fn: (this: Driver, iterable: AsyncIterable<T>) => AsyncIterable<U>): DirectoryListingContract<Driver, U>;
/**
* Get the final async iterable after passing directory listing through chain of piping functions modifying the output.
*/
toIterable(): AsyncIterable<T>;
/**
* Convert directory listing to array.
*/
toArray(): Promise<T[]>;
/**
* A method that returns the default async iterator for an object.
*/
[Symbol.asyncIterator](): AsyncIterableIterator<T>;
}
+129
View File
@@ -0,0 +1,129 @@
"use strict";
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.DirectoryListing = void 0;
/**
* Directory listing exposes the API to list directory contents using async iterators
* and also adds some helper functions for transforming the output of driver list.
*/
class DirectoryListing {
constructor(driver, listing) {
this.driver = driver;
this.listing = listing;
/**
* Functions chain to be executed for transforming generated listing iterable
*/
this.chain = [];
}
/**
* Filter generated items of listing with the given predicate function.
*/
filter(predicate) {
return this.pipe(async function* (source) {
let index = 0;
for await (const item of source) {
if (await predicate(item, index++, this)) {
yield item;
}
}
});
}
/**
* Transform generated items of listing with the given mapper function.
*/
map(mapper) {
return this.pipe(async function* (source) {
let index = 0;
for await (const item of source) {
yield await mapper(item, index++, this);
}
});
}
/**
* Do recursive listing of items. Without the next function it will do listing of leaf nodes only.
* For advanced usage you can pass the next function which will get as parameter current item and it should
* return the next location for list or null if the recursion should stop and yield the current item.
* For advanced usage you can also limit the depth of recursion using the second argument of next function.
*/
recursive(next = (current) => (current.isFile ? null : current.location)) {
// get copy of current chain until call to recursive
// so we can apply it to listing when doing recursion
const chain = this.chain.slice();
return this.pipe(async function* (source) {
for await (const item of source) {
// call the next function to know if we should continue recursion
const location = await next(item, 0, this);
if (location === null) {
yield item;
}
else {
// create next function to pass to recursive for next level of recursion
// we are using the original function if it is not using the depth parameter
const nextWithDepth = next.length > 1
? (current, depth, driver) => next(current, depth + 1, driver)
: next;
// list the returned location from next function and also apply the chain to it
const list = chain
.reduce((listing, fn) => listing.pipe(fn), this.list(location))
.recursive(nextWithDepth);
const iterator = list[Symbol.asyncIterator]();
let nextItem = await iterator.next();
// if the directory is empty it means it is a leaf and we will yield it
// else we will yield the items in the directory
if (nextItem.done) {
yield item;
}
else {
do {
yield nextItem.value;
nextItem = await iterator.next();
} while (!nextItem.done);
}
}
}
});
}
/**
* Add a piping chain function which gets the current async iterable and returns
* new async iterable with modified directory listing output.
* Function this is bound to instance of driver for which the listing is generated.
* This allows using async generator functions and reference the driver methods easily.
* Piping will always return clone of the current instance and add the function
* to the chain of new cloned instance only to prevent side effects.
*/
pipe(fn) {
const clone = new DirectoryListing(this.driver, this.listing);
clone.chain = this.chain.concat(fn);
return clone;
}
/**
* Get the final async iterable after passing directory listing through chain of piping functions modifying the output.
*/
toIterable() {
return this.chain.reduce((iterable, next) => next.call(this.driver, iterable), this.listing.call(this.driver));
}
/**
* Convert directory listing to array.
*/
async toArray() {
const arr = [];
for await (const item of this.toIterable()) {
arr.push(item);
}
return arr;
}
/**
* A method that returns the default async iterator for an object.
*/
async *[Symbol.asyncIterator]() {
yield* this.toIterable();
}
}
exports.DirectoryListing = DirectoryListing;
+147
View File
@@ -0,0 +1,147 @@
/// <reference path="../../adonis-typings/index.d.ts" />
/// <reference path="../../adonis-typings/drive.d.ts" />
/// <reference path="../../test-helpers/drive.d.ts" />
/// <reference types="@adonisjs/logger/build/adonis-typings/logger" />
/// <reference types="node" />
/// <reference types="node" />
import { Manager } from '@poppinss/manager';
import { RouterContract } from '@ioc:Adonis/Core/Route';
import { LoggerContract } from '@ioc:Adonis/Core/Logger';
import { ApplicationContract } from '@ioc:Adonis/Core/Application';
import { DisksList, Visibility, DriveConfig, DriverContract, DriveFileStats, LocalDriverConfig, DriveManagerContract, FakeImplementationCallback, DirectoryListingContract, DriveListItem } from '@ioc:Adonis/Core/Drive';
import { FakeDrive } from '../Fake';
/**
* Drive manager exposes the API to resolve disks and extend by
* adding custom drivers
*/
export declare class DriveManager extends Manager<ApplicationContract, DriverContract, DriverContract, {
[P in keyof DisksList]: DisksList[P]['implementation'];
}> implements DriveManagerContract {
application: ApplicationContract;
router: RouterContract;
private logger;
private config;
/**
* Find if drive is ready to be used
*/
private isReady;
/**
* The fake callback
*/
private fakeCallback;
/**
* Reference to the fake drive
*/
private fakeDrive;
/**
* Cache all disks instances
*/
protected singleton: boolean;
/**
* Reference to registered fakes
*/
fakes: Map<"local", import("@ioc:Adonis/Core/Drive").FakeDriverContract>;
constructor(application: ApplicationContract, router: RouterContract, logger: LoggerContract, config: DriveConfig);
/**
* Validate config
*/
private validateConfig;
/**
* Returns the default mapping name
*/
protected getDefaultMappingName(): "local";
/**
* Returns config for a given mapping
*/
protected getMappingConfig(diskName: keyof DisksList): LocalDriverConfig;
/**
* Returns the name of the drive used by a given mapping
*/
protected getMappingDriver(diskName: keyof DisksList): string | undefined;
/**
* Make instance of the local driver
*/
protected createLocal(diskName: keyof DisksList, config: LocalDriverConfig): any;
/**
* Fake default or a named disk
*/
fake(disks?: keyof DisksList | keyof DisksList[]): FakeDrive;
/**
* Restore the fake for the default or a named disk
*/
restore(disks?: keyof DisksList | keyof DisksList[]): void;
/**
* Restore all fakes1
*/
restoreAll(): void;
/**
* Resolve instance for a disk
*/
use(disk?: keyof DisksList): any;
/**
* Register a custom fake implementation
*/
setFakeImplementation(callback: FakeImplementationCallback): void;
/**
* Returns the file contents as a buffer. The buffer return
* value allows you to self choose the encoding when
* converting the buffer to a string.
*/
get(location: string, ...args: any[]): Promise<Buffer>;
/**
* Returns the file contents as a stream
*/
getStream(location: string, ...args: any[]): Promise<NodeJS.ReadableStream>;
/**
* A boolean to find if the location path exists or not
*/
exists(location: string, ...args: any[]): Promise<boolean>;
/**
* Returns the location path visibility
*/
getVisibility(location: string, ...args: any[]): Promise<Visibility>;
/**
* Returns the location path stats
*/
getStats(location: string, ...args: any[]): Promise<DriveFileStats>;
/**
* Returns a signed URL for a given location path
*/
getSignedUrl(location: string, ...args: any[]): Promise<string>;
/**
* Returns a URL for a given location path
*/
getUrl(location: string, ...args: any[]): Promise<string>;
/**
* Write string|buffer contents to a destination. The missing
* intermediate directories will be created (if required).
*/
put(location: string, ...args: any[]): Promise<void>;
/**
* Write a stream to a destination. The missing intermediate
* directories will be created (if required).
*/
putStream(location: string, ...args: any[]): Promise<void>;
/**
* Not supported
*/
setVisibility(location: string, ...args: any[]): Promise<void>;
/**
* Remove a given location path
*/
delete(location: string, ...args: any[]): Promise<void>;
/**
* Copy a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
copy(source: string, ...args: any[]): Promise<void>;
/**
* Move a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
move(source: string, ...args: any[]): Promise<void>;
/**
* Return a listing directory iterator for given location.
*/
list(location: string): DirectoryListingContract<DriverContract, DriveListItem>;
}
+236
View File
@@ -0,0 +1,236 @@
"use strict";
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.DriveManager = void 0;
/// <reference path="../../adonis-typings/index.ts" />
const manager_1 = require("@poppinss/manager");
const utils_1 = require("@poppinss/utils");
const Fake_1 = require("../Fake");
/**
* Drive manager exposes the API to resolve disks and extend by
* adding custom drivers
*/
class DriveManager extends manager_1.Manager {
constructor(application, router, logger, config) {
super(application);
this.application = application;
this.router = router;
this.logger = logger;
this.config = config;
/**
* Find if drive is ready to be used
*/
this.isReady = false;
/**
* The fake callback
*/
this.fakeCallback = (_, disk, config) => {
const { FakeDriver } = require('../Drivers/Fake');
return new FakeDriver(disk, config, this.router);
};
/**
* Reference to the fake drive
*/
this.fakeDrive = new Fake_1.FakeDrive();
/**
* Cache all disks instances
*/
this.singleton = true;
/**
* Reference to registered fakes
*/
this.fakes = this.fakeDrive.fakes;
this.validateConfig();
}
/**
* Validate config
*/
validateConfig() {
if (!this.config) {
return;
}
const validator = new utils_1.ManagerConfigValidator(this.config, 'drive', 'config/drive');
validator.validateDefault('disk');
validator.validateList('disks', 'disk');
this.isReady = true;
}
/**
* Returns the default mapping name
*/
getDefaultMappingName() {
return this.config.disk;
}
/**
* Returns config for a given mapping
*/
getMappingConfig(diskName) {
return this.config.disks[diskName];
}
/**
* Returns the name of the drive used by a given mapping
*/
getMappingDriver(diskName) {
return this.getMappingConfig(diskName)?.driver;
}
/**
* Make instance of the local driver
*/
createLocal(diskName, config) {
const { LocalDriver } = require('../Drivers/Local');
return new LocalDriver(diskName, config, this.router);
}
/**
* Fake default or a named disk
*/
fake(disks) {
disks = disks || this.getDefaultMappingName();
const disksToFake = Array.isArray(disks) ? disks : [disks];
disksToFake.forEach((disk) => {
if (!this.fakeDrive.isFaked(disk)) {
this.logger.trace({ disk: disk }, 'drive faking disk');
this.fakeDrive.fakes.set(disk, this.fakeCallback(this, disk, this.getMappingConfig(disk)));
}
});
return this.fakeDrive;
}
/**
* Restore the fake for the default or a named disk
*/
restore(disks) {
disks = disks || this.getDefaultMappingName();
const disksToRestore = Array.isArray(disks) ? disks : [disks];
disksToRestore.forEach((disk) => {
if (this.fakeDrive.isFaked(disk)) {
this.logger.trace({ disk: disk }, 'drive restoring disk fake');
this.fakeDrive.restore(disk);
}
});
}
/**
* Restore all fakes1
*/
restoreAll() {
this.fakeDrive.fakes = new Map();
}
/**
* Resolve instance for a disk
*/
use(disk) {
if (!this.isReady) {
throw new utils_1.Exception('Missing configuration for drive. Visit https://bit.ly/2WnR5j9 for setup instructions', 500, 'E_MISSING_DRIVE_CONFIG');
}
disk = disk || this.getDefaultMappingName();
if (this.fakeDrive.isFaked(disk)) {
return this.fakeDrive.use(disk);
}
return super.use(disk);
}
/**
* Register a custom fake implementation
*/
setFakeImplementation(callback) {
this.fakeCallback = callback;
}
/**
* Returns the file contents as a buffer. The buffer return
* value allows you to self choose the encoding when
* converting the buffer to a string.
*/
async get(location, ...args) {
return this.use().get(location, ...args);
}
/**
* Returns the file contents as a stream
*/
async getStream(location, ...args) {
return this.use().getStream(location, ...args);
}
/**
* A boolean to find if the location path exists or not
*/
exists(location, ...args) {
return this.use().exists(location, ...args);
}
/**
* Returns the location path visibility
*/
async getVisibility(location, ...args) {
return this.use().getVisibility(location, ...args);
}
/**
* Returns the location path stats
*/
async getStats(location, ...args) {
return this.use().getStats(location, ...args);
}
/**
* Returns a signed URL for a given location path
*/
getSignedUrl(location, ...args) {
return this.use().getSignedUrl(location, ...args);
}
/**
* Returns a URL for a given location path
*/
getUrl(location, ...args) {
return this.use().getUrl(location, ...args);
}
/**
* Write string|buffer contents to a destination. The missing
* intermediate directories will be created (if required).
*/
put(location, ...args) {
return this.use().put(location, ...args);
}
/**
* Write a stream to a destination. The missing intermediate
* directories will be created (if required).
*/
putStream(location, ...args) {
return this.use().putStream(location, ...args);
}
/**
* Not supported
*/
setVisibility(location, ...args) {
return this.use().setVisibility(location, ...args);
}
/**
* Remove a given location path
*/
delete(location, ...args) {
return this.use().delete(location, ...args);
}
/**
* Copy a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
copy(source, ...args) {
return this.use().copy(source, ...args);
}
/**
* Move a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
move(source, ...args) {
return this.use().move(source, ...args);
}
/**
* Return a listing directory iterator for given location.
*/
list(location) {
const driver = this.use();
if (typeof driver.list !== 'function') {
throw new utils_1.Exception(`List is not supported by the "${driver.name}" driver.`, 500, 'E_LIST_NOT_SUPPORTED');
}
return driver.list(location);
}
}
exports.DriveManager = DriveManager;
+104
View File
@@ -0,0 +1,104 @@
/// <reference path="../../adonis-typings/index.d.ts" />
/// <reference types="node" />
/// <reference types="node" />
import { RouterContract } from '@ioc:Adonis/Core/Route';
import { DisksList, Visibility, ContentHeaders, DriveFileStats, FakeDriverContract, DirectoryListingContract, FakeDriveListItem } from '@ioc:Adonis/Core/Drive';
/**
* Memory driver is mainly used for testing
*/
export declare class FakeDriver implements FakeDriverContract {
disk: keyof DisksList;
private config;
private router;
/**
* Reference to the underlying adapter. Which is memfs
*/
adapter: import("memfs/lib/volume").Volume;
/**
* Name of the driver
*/
name: 'fake';
/**
* Path prefixer used for prefixing paths with disk root
* It doesn't play any role but we will try to construct same path as faked driver is using
* We use the root path if it is available for driver and also add prefix if provided
*/
private prefixer;
/**
* Rely on the config for visibility or fallback to private
*/
private visibility;
constructor(disk: keyof DisksList, config: any, router: RouterContract);
/**
* Make absolute path to a given location
*/
makePath(location: string): string;
/**
* Creates the directory recursively with in the memory
*/
private ensureDir;
/**
* Returns the file contents as a buffer. The buffer return
* value allows you to self choose the encoding when
* converting the buffer to a string.
*/
get(location: string): Promise<Buffer>;
/**
* Returns the file contents as a stream
*/
getStream(location: string): Promise<NodeJS.ReadableStream>;
/**
* A boolean to find if the location path exists or not
*/
exists(location: string): Promise<boolean>;
/**
* Not supported
*/
getVisibility(): Promise<Visibility>;
/**
* Returns the file stats
*/
getStats(location: string): Promise<DriveFileStats>;
/**
* Returns a signed URL for a given location path
*/
getSignedUrl(location: string, options?: ContentHeaders & {
expiresIn?: string | number;
}): Promise<string>;
/**
* Returns a URL for a given location path
*/
getUrl(location: string): Promise<string>;
/**
* Write string|buffer contents to a destination. The missing
* intermediate directories will be created (if required).
*/
put(location: string, contents: Buffer | string): Promise<void>;
/**
* Write a stream to a destination. The missing intermediate
* directories will be created (if required).
*/
putStream(location: string, contents: NodeJS.ReadableStream): Promise<void>;
/**
* Not supported
*/
setVisibility(): Promise<void>;
/**
* Remove a given location path
*/
delete(location: string): Promise<void>;
/**
* Copy a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
copy(source: string, destination: string): Promise<void>;
/**
* Move a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
move(source: string, destination: string): Promise<void>;
/**
* Return a listing directory iterator for given location.
*/
list(location: string): DirectoryListingContract<this, FakeDriveListItem>;
}
+287
View File
@@ -0,0 +1,287 @@
"use strict";
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FakeDriver = void 0;
/// <reference path="../../adonis-typings/index.ts" />
const etag_1 = __importDefault(require("etag"));
const memfs_1 = require("memfs");
const path_1 = require("path");
const utils_1 = require("../utils");
const LocalFileServer_1 = require("../LocalFileServer");
const Exceptions_1 = require("../Exceptions");
const DirectoryListing_1 = require("../DirectoryListing");
const PathPrefixer_1 = require("../PathPrefixer");
/**
* Memory driver is mainly used for testing
*/
class FakeDriver {
constructor(disk, config, router) {
this.disk = disk;
this.config = config;
this.router = router;
/**
* Reference to the underlying adapter. Which is memfs
*/
this.adapter = new memfs_1.Volume();
/**
* Name of the driver
*/
this.name = 'fake';
/**
* Path prefixer used for prefixing paths with disk root
* It doesn't play any role but we will try to construct same path as faked driver is using
* We use the root path if it is available for driver and also add prefix if provided
*/
this.prefixer = PathPrefixer_1.PathPrefixer.fromPath(this.config.root || '/').withPrefix(this.config.prefix || '');
/**
* Rely on the config for visibility or fallback to private
*/
this.visibility = this.config.visibility || 'private';
}
/**
* Make absolute path to a given location
*/
makePath(location) {
return this.prefixer.prefixPath(location);
}
/**
* Creates the directory recursively with in the memory
*/
ensureDir(location) {
return new Promise((resolve, reject) => {
this.adapter.mkdirp((0, path_1.dirname)(location), (error) => {
if (error) {
reject(error);
}
else {
resolve();
}
});
});
}
/**
* Returns the file contents as a buffer. The buffer return
* value allows you to self choose the encoding when
* converting the buffer to a string.
*/
async get(location) {
return new Promise((resolve, reject) => {
this.adapter.readFile(this.makePath(location), (error, data) => {
if (error) {
reject(Exceptions_1.CannotReadFileException.invoke(location, error));
}
else {
resolve(data);
}
});
});
}
/**
* Returns the file contents as a stream
*/
async getStream(location) {
return this.adapter.createReadStream(this.makePath(location));
}
/**
* A boolean to find if the location path exists or not
*/
exists(location) {
return new Promise((resolve) => {
this.adapter.exists(this.makePath(location), (exists) => {
resolve(exists);
});
});
}
/**
* Not supported
*/
async getVisibility() {
return this.visibility;
}
/**
* Returns the file stats
*/
async getStats(location) {
return new Promise((resolve, reject) => {
this.adapter.stat(this.makePath(location), (error, stats) => {
if (error) {
reject(Exceptions_1.CannotGetMetaDataException.invoke(location, 'stats', error));
}
else {
resolve({
modified: stats.mtime,
size: stats.size,
isFile: stats.isFile(),
etag: (0, etag_1.default)(stats),
});
}
});
});
}
/**
* Returns a signed URL for a given location path
*/
async getSignedUrl(location, options) {
const { expiresIn, ...qs } = options || {};
return this.router.makeSignedUrl('/__drive_fake', {
disk: this.disk,
[LocalFileServer_1.LocalFileServer.filePathParamName]: [this.prefixer.normalizePath(location)],
}, {
expiresIn,
qs,
disableRouteLookup: true,
});
}
/**
* Returns a URL for a given location path
*/
async getUrl(location) {
return this.router.makeUrl('/__drive_fake', {
disk: this.disk,
[LocalFileServer_1.LocalFileServer.filePathParamName]: [this.prefixer.normalizePath(location)],
}, {
disableRouteLookup: true,
});
}
/**
* Write string|buffer contents to a destination. The missing
* intermediate directories will be created (if required).
*/
async put(location, contents) {
const absolutePath = this.makePath(location);
await this.ensureDir(absolutePath);
return new Promise((resolve, reject) => {
this.adapter.writeFile(absolutePath, contents, (error) => {
if (error) {
reject(Exceptions_1.CannotWriteFileException.invoke(location, error));
}
else {
resolve();
}
});
});
}
/**
* Write a stream to a destination. The missing intermediate
* directories will be created (if required).
*/
async putStream(location, contents) {
const absolutePath = this.makePath(location);
try {
await this.ensureDir(absolutePath);
const writeStream = this.adapter.createWriteStream(absolutePath);
/**
* If streaming is interrupted, then the destination file will be
* created with partial or empty contents.
*
* Earlier we are cleaning up the empty file, which addresses one
* use case (no pre-existing file was there).
*
* However, in case there was already a file, it will be then emptied
* out. So basically there is no way to get the original contents
* back unless we read the existing content in buffer, but then
* we don't know how large the file is.
*/
await (0, utils_1.pipelinePromise)(contents, writeStream);
}
catch (error) {
throw Exceptions_1.CannotWriteFileException.invoke(location, error);
}
}
/**
* Not supported
*/
async setVisibility() {
return;
}
/**
* Remove a given location path
*/
async delete(location) {
if (!(await this.exists(location))) {
return;
}
return new Promise((resolve, reject) => {
this.adapter.unlink(this.makePath(location), (error) => {
if (error) {
reject(Exceptions_1.CannotDeleteFileException.invoke(location, error));
}
else {
resolve();
}
});
});
}
/**
* Copy a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
async copy(source, destination) {
const desintationAbsolutePath = this.makePath(destination);
await this.ensureDir(desintationAbsolutePath);
return new Promise((resolve, reject) => {
this.adapter.copyFile(this.makePath(source), desintationAbsolutePath, (error) => {
if (error) {
reject(Exceptions_1.CannotCopyFileException.invoke(source, destination, error));
}
else {
resolve();
}
});
});
}
/**
* Move a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
async move(source, destination) {
const sourceAbsolutePath = this.makePath(source);
const desintationAbsolutePath = this.makePath(destination);
await this.ensureDir(desintationAbsolutePath);
return new Promise((resolve, reject) => {
this.adapter.copyFile(sourceAbsolutePath, desintationAbsolutePath, (error) => {
if (error) {
reject(Exceptions_1.CannotMoveFileException.invoke(source, destination, error));
}
else {
resolve();
}
});
}).then(() => this.delete(source));
}
/**
* Return a listing directory iterator for given location.
*/
list(location) {
const fullPath = this.makePath(location);
return new DirectoryListing_1.DirectoryListing(this, async function* () {
try {
const dir = (await this.adapter.promises.readdir(fullPath, {
withFileTypes: true,
}));
const prefixer = this.prefixer.withStrippedPrefix(fullPath);
for (const dirent of dir) {
yield {
location: prefixer.prefixPath(dirent.name),
isFile: dirent.isFile(),
original: dirent,
};
}
}
catch (error) {
throw Exceptions_1.CannotListDirectoryException.invoke(location, error);
}
});
}
}
exports.FakeDriver = FakeDriver;
+97
View File
@@ -0,0 +1,97 @@
/// <reference path="../../adonis-typings/index.d.ts" />
/// <reference types="node" />
/// <reference types="node" />
import * as fsExtra from 'fs-extra';
import { RouterContract } from '@ioc:Adonis/Core/Route';
import { Visibility, DriveFileStats, ContentHeaders, LocalDriverConfig, LocalDriverContract, DirectoryListingContract, LocalDriveListItem } from '@ioc:Adonis/Core/Drive';
/**
* Local driver interacts with the local file system
*/
export declare class LocalDriver implements LocalDriverContract {
private diskName;
private config;
private router;
private routeName;
/**
* Reference to the underlying adapter. Which is
* fs-extra
*/
adapter: typeof fsExtra;
/**
* Name of the driver
*/
name: 'local';
/**
* Path prefixer used for prefixing paths with disk root
*/
private prefixer;
constructor(diskName: string, config: LocalDriverConfig, router: RouterContract);
/**
* Make absolute path to a given location
*/
makePath(location: string): string;
/**
* Returns the file contents as a buffer. The buffer return
* value allows you to self choose the encoding when
* converting the buffer to a string.
*/
get(location: string): Promise<Buffer>;
/**
* Returns the file contents as a stream
*/
getStream(location: string): Promise<NodeJS.ReadableStream>;
/**
* A boolean to find if the location path exists or not
*/
exists(location: string): Promise<boolean>;
/**
* Not supported
*/
getVisibility(_: string): Promise<Visibility>;
/**
* Returns the file stats
*/
getStats(location: string): Promise<DriveFileStats>;
/**
* Returns a signed URL for a given location path
*/
getSignedUrl(location: string, options?: ContentHeaders & {
expiresIn?: string | number;
}): Promise<string>;
/**
* Returns a URL for a given location path
*/
getUrl(location: string): Promise<string>;
/**
* Write string|buffer contents to a destination. The missing
* intermediate directories will be created (if required).
*/
put(location: string, contents: Buffer | string): Promise<void>;
/**
* Write a stream to a destination. The missing intermediate
* directories will be created (if required).
*/
putStream(location: string, contents: NodeJS.ReadableStream): Promise<void>;
/**
* Not supported
*/
setVisibility(_: string, __: string): Promise<void>;
/**
* Remove a given location path
*/
delete(location: string): Promise<void>;
/**
* Copy a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
copy(source: string, destination: string): Promise<void>;
/**
* Move a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
move(source: string, destination: string): Promise<void>;
/**
* Return a listing directory iterator for given location.
*/
list(location: string): DirectoryListingContract<this, LocalDriveListItem>;
}
+266
View File
@@ -0,0 +1,266 @@
"use strict";
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LocalDriver = void 0;
/// <reference path="../../adonis-typings/index.ts" />
const etag_1 = __importDefault(require("etag"));
const fsExtra = __importStar(require("fs-extra"));
const path_1 = require("path");
const DirectoryListing_1 = require("../DirectoryListing");
const utils_1 = require("../utils");
const LocalFileServer_1 = require("../LocalFileServer");
const PathPrefixer_1 = require("../PathPrefixer");
const Exceptions_1 = require("../Exceptions");
/**
* Local driver interacts with the local file system
*/
class LocalDriver {
constructor(diskName, config, router) {
this.diskName = diskName;
this.config = config;
this.router = router;
this.routeName = LocalFileServer_1.LocalFileServer.makeRouteName(this.diskName);
/**
* Reference to the underlying adapter. Which is
* fs-extra
*/
this.adapter = fsExtra;
/**
* Name of the driver
*/
this.name = 'local';
/**
* Path prefixer used for prefixing paths with disk root
*/
this.prefixer = PathPrefixer_1.PathPrefixer.fromPath(this.config.root);
}
/**
* Make absolute path to a given location
*/
makePath(location) {
return this.prefixer.prefixPath(location);
}
/**
* Returns the file contents as a buffer. The buffer return
* value allows you to self choose the encoding when
* converting the buffer to a string.
*/
async get(location) {
try {
return await this.adapter.readFile(this.makePath(location));
}
catch (error) {
throw Exceptions_1.CannotReadFileException.invoke(location, error);
}
}
/**
* Returns the file contents as a stream
*/
async getStream(location) {
try {
return this.adapter.createReadStream(this.makePath(location));
}
catch (error) {
throw Exceptions_1.CannotReadFileException.invoke(location, error);
}
}
/**
* A boolean to find if the location path exists or not
*/
async exists(location) {
try {
return await this.adapter.pathExists(this.makePath(location));
}
catch (error) {
throw Exceptions_1.CannotGetMetaDataException.invoke(location, 'exists', error);
}
}
/**
* Not supported
*/
async getVisibility(_) {
return this.config.visibility;
}
/**
* Returns the file stats
*/
async getStats(location) {
try {
const stats = await this.adapter.stat(this.makePath(location));
return {
modified: stats.mtime,
size: stats.size,
isFile: stats.isFile(),
etag: (0, etag_1.default)(stats),
};
}
catch (error) {
throw Exceptions_1.CannotGetMetaDataException.invoke(location, 'stats', error);
}
}
/**
* Returns a signed URL for a given location path
*/
async getSignedUrl(location, options) {
if (!this.config.serveFiles) {
throw Exceptions_1.CannotGenerateUrlException.invoke(location, this.diskName);
}
const { expiresIn, ...qs } = options || {};
return this.router.makeSignedUrl(this.routeName, { [LocalFileServer_1.LocalFileServer.filePathParamName]: [this.prefixer.normalizePath(location)] }, {
expiresIn,
qs,
});
}
/**
* Returns a URL for a given location path
*/
async getUrl(location) {
if (!this.config.serveFiles) {
throw Exceptions_1.CannotGenerateUrlException.invoke(location, this.diskName);
}
return this.router.makeUrl(this.routeName, {
[LocalFileServer_1.LocalFileServer.filePathParamName]: [this.prefixer.normalizePath(location)],
});
}
/**
* Write string|buffer contents to a destination. The missing
* intermediate directories will be created (if required).
*/
async put(location, contents) {
try {
await this.adapter.outputFile(this.makePath(location), contents);
}
catch (error) {
throw Exceptions_1.CannotWriteFileException.invoke(location, error);
}
}
/**
* Write a stream to a destination. The missing intermediate
* directories will be created (if required).
*/
async putStream(location, contents) {
const absolutePath = this.makePath(location);
const dir = (0, path_1.dirname)(absolutePath);
await this.adapter.ensureDir(dir);
const writeStream = this.adapter.createWriteStream(absolutePath);
/**
* If streaming is interrupted, then the destination file will be
* created with partial or empty contents.
*
* Earlier we are cleaning up the empty file, which addresses one
* use case (no pre-existing file was there).
*
* However, in case there was already a file, it will be then emptied
* out. So basically there is no way to get the original contents
* back unless we read the existing content in buffer, but then
* we don't know how large the file is.
*/
try {
await (0, utils_1.pipelinePromise)(contents, writeStream);
}
catch (error) {
throw Exceptions_1.CannotWriteFileException.invoke(location, error);
}
}
/**
* Not supported
*/
async setVisibility(_, __) {
return;
}
/**
* Remove a given location path
*/
async delete(location) {
try {
await this.adapter.remove(this.makePath(location));
}
catch (error) {
throw Exceptions_1.CannotDeleteFileException.invoke(location, error);
}
}
/**
* Copy a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
async copy(source, destination) {
try {
await this.adapter.copy(this.makePath(source), this.makePath(destination), {
overwrite: true,
});
}
catch (error) {
throw Exceptions_1.CannotCopyFileException.invoke(source, destination, error);
}
}
/**
* Move a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
async move(source, destination) {
try {
await this.adapter.move(this.makePath(source), this.makePath(destination), {
overwrite: true,
});
}
catch (error) {
throw Exceptions_1.CannotMoveFileException.invoke(source, destination, error);
}
}
/**
* Return a listing directory iterator for given location.
*/
list(location) {
const fullPath = this.makePath(location);
return new DirectoryListing_1.DirectoryListing(this, async function* () {
try {
const dir = await this.adapter.opendir(fullPath);
const prefixer = this.prefixer.withStrippedPrefix(fullPath);
for await (const dirent of dir) {
yield {
location: prefixer.prefixPath(dirent.name),
isFile: dirent.isFile(),
original: dirent,
};
}
}
catch (error) {
throw Exceptions_1.CannotListDirectoryException.invoke(location, error);
}
});
}
}
exports.LocalDriver = LocalDriver;
+82
View File
@@ -0,0 +1,82 @@
import { Exception } from '@poppinss/utils';
/**
* Unable to write file to the destination
*/
export declare class CannotWriteFileException extends Exception {
location: string;
original: any;
static invoke(location: string, original: any): CannotWriteFileException;
}
/**
* Unable to read file from a given location
*/
export declare class CannotReadFileException extends Exception {
location: string;
original: any;
static invoke(location: string, original: any): CannotReadFileException;
}
/**
* Unable to delete file from a given location
*/
export declare class CannotDeleteFileException extends Exception {
location: string;
original: any;
static invoke(location: string, original: any): CannotDeleteFileException;
}
/**
* Unable to copy file from source to destination
*/
export declare class CannotCopyFileException extends Exception {
source: string;
destination: string;
original: any;
static invoke(source: string, destination: string, original: any): CannotCopyFileException;
}
/**
* Unable to move file from source to destination
*/
export declare class CannotMoveFileException extends Exception {
source: string;
destination: string;
original: any;
static invoke(source: string, destination: string, original: any): CannotMoveFileException;
}
/**
* Unable to get file metadata
*/
export declare class CannotGetMetaDataException extends Exception {
location: string;
operation: string;
original: any;
static invoke(location: string, operation: string, original: any): CannotGetMetaDataException;
}
/**
* Unable to set visibility
*/
export declare class CannotSetVisibilityException extends Exception {
location: string;
original: any;
static invoke(location: string, original: any): CannotSetVisibilityException;
}
/**
* Unable to generate url for a file. The assets serving is disabled
*/
export declare class CannotGenerateUrlException extends Exception {
location: string;
static invoke(location: string, diskName: string): CannotGenerateUrlException;
}
/**
* Unable to list directory contents of given location
*/
export declare class CannotListDirectoryException extends Exception {
location: string;
original: any;
static invoke(location: string, original: any): CannotListDirectoryException;
}
/**
* Given location is trying to traverse beyond the root path
*/
export declare class PathTraversalDetectedException extends Exception {
location: string;
static invoke(location: string): PathTraversalDetectedException;
}
+133
View File
@@ -0,0 +1,133 @@
"use strict";
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.PathTraversalDetectedException = exports.CannotListDirectoryException = exports.CannotGenerateUrlException = exports.CannotSetVisibilityException = exports.CannotGetMetaDataException = exports.CannotMoveFileException = exports.CannotCopyFileException = exports.CannotDeleteFileException = exports.CannotReadFileException = exports.CannotWriteFileException = void 0;
const utils_1 = require("@poppinss/utils");
/**
* Unable to write file to the destination
*/
class CannotWriteFileException extends utils_1.Exception {
static invoke(location, original) {
const error = new this(`Cannot write file at location "${location}"`, 500, 'E_CANNOT_WRITE_FILE');
error.location = location;
error.original = original;
return error;
}
}
exports.CannotWriteFileException = CannotWriteFileException;
/**
* Unable to read file from a given location
*/
class CannotReadFileException extends utils_1.Exception {
static invoke(location, original) {
const error = new this(`Cannot read file from location "${location}"`, 500, 'E_CANNOT_READ_FILE');
error.location = location;
error.original = original;
return error;
}
}
exports.CannotReadFileException = CannotReadFileException;
/**
* Unable to delete file from a given location
*/
class CannotDeleteFileException extends utils_1.Exception {
static invoke(location, original) {
const error = new this(`Cannot delete file at location "${location}"`, 500, 'E_CANNOT_DELETE_FILE');
error.location = location;
error.original = original;
return error;
}
}
exports.CannotDeleteFileException = CannotDeleteFileException;
/**
* Unable to copy file from source to destination
*/
class CannotCopyFileException extends utils_1.Exception {
static invoke(source, destination, original) {
const error = new this(`Cannot copy file from "${source}" to "${destination}"`, 500, 'E_CANNOT_COPY_FILE');
error.source = source;
error.destination = destination;
error.original = original;
return error;
}
}
exports.CannotCopyFileException = CannotCopyFileException;
/**
* Unable to move file from source to destination
*/
class CannotMoveFileException extends utils_1.Exception {
static invoke(source, destination, original) {
const error = new this(`Cannot move file from "${source}" to "${destination}"`, 500, 'E_CANNOT_MOVE_FILE');
error.source = source;
error.destination = destination;
error.original = original;
return error;
}
}
exports.CannotMoveFileException = CannotMoveFileException;
/**
* Unable to get file metadata
*/
class CannotGetMetaDataException extends utils_1.Exception {
static invoke(location, operation, original) {
const error = new this(`Unable to retrieve the "${operation}" for file at location "${location}"`, 500, 'E_CANNOT_GET_METADATA');
error.location = location;
error.operation = operation;
error.original = original;
return error;
}
}
exports.CannotGetMetaDataException = CannotGetMetaDataException;
/**
* Unable to set visibility
*/
class CannotSetVisibilityException extends utils_1.Exception {
static invoke(location, original) {
const error = new this(`Unable to set visibility for file at location "${location}"`, 500, 'E_CANNOT_SET_VISIBILITY');
error.location = location;
error.original = original;
return error;
}
}
exports.CannotSetVisibilityException = CannotSetVisibilityException;
/**
* Unable to generate url for a file. The assets serving is disabled
*/
class CannotGenerateUrlException extends utils_1.Exception {
static invoke(location, diskName) {
const error = new this(`Cannot generate URL for location "${location}". Make sure to set "serveFiles = true" for "${diskName}" disk`, 500, 'E_CANNOT_GENERATE_URL');
error.location = location;
return error;
}
}
exports.CannotGenerateUrlException = CannotGenerateUrlException;
/**
* Unable to list directory contents of given location
*/
class CannotListDirectoryException extends utils_1.Exception {
static invoke(location, original) {
const error = new this(`Cannot list directory contents of location "${location}"`, 500, 'E_CANNOT_LIST_DIRECTORY');
error.location = location;
error.original = original;
return error;
}
}
exports.CannotListDirectoryException = CannotListDirectoryException;
/**
* Given location is trying to traverse beyond the root path
*/
class PathTraversalDetectedException extends utils_1.Exception {
static invoke(location) {
const error = new this(`Path traversal detected: "${location}"`, 500, 'E_PATH_TRAVERSAL_DETECTED');
error.location = location;
return error;
}
}
exports.PathTraversalDetectedException = PathTraversalDetectedException;
+36
View File
@@ -0,0 +1,36 @@
/// <reference types="node" />
import { DisksList, FakeDriveContract, FakeDriverContract } from '@ioc:Adonis/Core/Drive';
/**
* An implementation of the fake drive
*/
export declare class FakeDrive implements FakeDriveContract {
/**
* Reference to registered fakes
*/
fakes: Map<keyof DisksList, FakeDriverContract>;
/**
* Find a file for the given path exists. Searched
* across all the faked disk
*/
exists(location: string): Promise<boolean>;
/**
* Get the contents of the file as buffer
*/
get(location: string): Promise<Buffer>;
/**
* Get the contents of the file as buffer
*/
bytes(location: string): Promise<number>;
/**
* Access the faked driver
*/
use(disk: keyof DisksList): FakeDriverContract;
/**
* Find if a disk has been faked
*/
isFaked(disk: keyof DisksList): boolean;
/**
* Restore a fake
*/
restore(disk: keyof DisksList): void;
}
+74
View File
@@ -0,0 +1,74 @@
"use strict";
/*
* @adonisjs/drive
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.FakeDrive = void 0;
const Exceptions_1 = require("../Exceptions");
/**
* An implementation of the fake drive
*/
class FakeDrive {
constructor() {
/**
* Reference to registered fakes
*/
this.fakes = new Map();
}
/**
* Find a file for the given path exists. Searched
* across all the faked disk
*/
async exists(location) {
for (let [, fake] of this.fakes) {
const exists = await fake.exists(location);
if (exists) {
return true;
}
}
return false;
}
/**
* Get the contents of the file as buffer
*/
async get(location) {
for (let [, fake] of this.fakes) {
const exists = await fake.exists(location);
if (exists) {
return fake.get(location);
}
}
throw Exceptions_1.CannotReadFileException.invoke(location, new Error('File not found'));
}
/**
* Get the contents of the file as buffer
*/
async bytes(location) {
const contents = await this.get(location);
return contents.length;
}
/**
* Access the faked driver
*/
use(disk) {
return this.fakes.get(disk);
}
/**
* Find if a disk has been faked
*/
isFaked(disk) {
return this.fakes.has(disk);
}
/**
* Restore a fake
*/
restore(disk) {
this.fakes.delete(disk);
}
}
exports.FakeDrive = FakeDrive;
+30
View File
@@ -0,0 +1,30 @@
/// <reference path="../../adonis-typings/index.d.ts" />
/// <reference types="@adonisjs/logger/build/adonis-typings/logger" />
import { LoggerContract } from '@ioc:Adonis/Core/Logger';
import { RouterContract } from '@ioc:Adonis/Core/Route';
import { LocalDriverConfig, LocalDriverContract } from '@ioc:Adonis/Core/Drive';
/**
* Registers the route to serve files from the local driver
* or the memory driver.
*/
export declare class LocalFileServer {
private diskName;
private config;
private driver;
private router;
private logger;
/**
* Makes the route name for a given disk name
*/
static makeRouteName(diskName: string): string;
/**
* The file path route param name
*/
static filePathParamName: string;
constructor(diskName: string, config: LocalDriverConfig, driver: LocalDriverContract, router: RouterContract, logger: LoggerContract);
/**
* Registers route for disk using "local" driver and "serveFiles"
* true
*/
registerRoute(): void;
}
+173
View File
@@ -0,0 +1,173 @@
"use strict";
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.LocalFileServer = void 0;
/// <reference path="../../adonis-typings/index.ts" />
const path_1 = require("path");
const utils_1 = require("@poppinss/utils");
/**
* Registers the route to serve files from the local driver
* or the memory driver.
*/
class LocalFileServer {
constructor(diskName, config, driver, router, logger) {
this.diskName = diskName;
this.config = config;
this.driver = driver;
this.router = router;
this.logger = logger;
}
/**
* Makes the route name for a given disk name
*/
static makeRouteName(diskName) {
return `drive.${diskName}.serve`;
}
/**
* Registers route for disk using "local" driver and "serveFiles"
* true
*/
registerRoute() {
/**
* Base path must always be defined
*/
if (!this.config.basePath) {
throw new utils_1.Exception(`Missing property "basePath" in "${this.diskName}" disk config`, 500, 'E_MISSING_LOCAL_DRIVER_BASEPATH');
}
const routeName = LocalFileServer.makeRouteName(this.diskName);
const routePattern = `${this.config.basePath.replace(/\/$/, '')}/${LocalFileServer.filePathParamName}`;
this.logger.trace({ route: routePattern, name: routeName }, 'registering drive route');
this.router
.get(routePattern, async ({ response, request, logger }) => {
let location = request.param(LocalFileServer.filePathParamName).join('/');
try {
location = decodeURIComponent(location);
}
catch (error) {
// keep location should be raised as it is
}
const fileVisibility = await this.driver.getVisibility(location);
const usingSignature = !!request.input('signature');
/**
* Deny request when not using signature and file is "private"
*/
if (!usingSignature && fileVisibility === 'private') {
response.unauthorized('Access denied');
return;
}
/**
* Deny request when using signature but its invalid. File
* visibility doesn't play a role here.
*/
if (usingSignature && !request.hasValidSignature()) {
response.unauthorized('Access denied');
return;
}
/**
* Read https://datatracker.ietf.org/doc/html/rfc7234#section-4.3.5 for
* headers management
*/
try {
const stats = await this.driver.getStats(location);
/**
* Ignore requests for directories
*/
if (!stats.isFile) {
return response.notFound('File not found');
}
/**
* Set Last-Modified or the Cache-Control header. We pick
* the cache control header from the query string only
* when a valid signature is presented.
*/
if (usingSignature && request.input('cacheControl')) {
response.header('Cache-Control', request.input('cacheControl'));
}
else {
response.header('Last-Modified', stats.modified.toUTCString());
}
/**
* Set the Content-Type header. We pick the contentType header
* from the query string only when a valid signature
* is presented
*/
if (usingSignature && request.input('contentType')) {
response.header('Content-Type', request.input('contentType'));
}
else {
response.type((0, path_1.extname)(location));
}
/**
* Set the following headers by reading the query string values. Must
* be done when a signature was presented.
*/
if (usingSignature && request.input('contentDisposition')) {
response.header('Content-Disposition', request.input('contentDisposition'));
}
if (usingSignature && request.input('contentEncoding')) {
response.header('Content-Encoding', request.input('contentEncoding'));
}
if (usingSignature && request.input('contentLanguage')) {
response.header('Content-Language', request.input('contentLanguage'));
}
/**
* Define etag when present in stats
*/
if (stats.etag) {
response.header('etag', stats.etag);
}
/*
* Do not stream files for HEAD request, but set the appropriate
* status code.
*
* 200: When NOT using etags or cache is NOT fresh. This forces browser
* to always make a GET request
*
* 304: When etags are used and cache is fresh
*/
if (request.method() === 'HEAD') {
response.status(response.fresh() ? 304 : 200);
return;
}
/*
* Regardless of request method, if cache is
* fresh, then we must respond with 304
*/
if (response.fresh()) {
response.status(304);
return;
}
/**
* Set content length if serving the file
*/
response.header('Content-length', stats.size.toString());
/**
* Stream file.
*/
return response.stream(await this.driver.getStream(location));
}
catch (error) {
if (error.original?.code === 'ENOENT' || error.code === 'ENOENT') {
response.notFound('File not found');
}
else {
logger.fatal(error, `drive: Unable to serve file "${location}" from "${this.diskName}" disk`);
response.internalServerError('Cannot process file');
}
}
})
.as(routeName);
}
}
exports.LocalFileServer = LocalFileServer;
/**
* The file path route param name
*/
LocalFileServer.filePathParamName = '*';
+46
View File
@@ -0,0 +1,46 @@
/// <reference path="../../adonis-typings/index.d.ts" />
/**
* Path prefixer for resolving and prefixing paths for disk drivers
*/
export declare class PathPrefixer {
/**
* Separator used for dividing path segments is always unix-style forward slash
*/
separator: "/";
/**
* Prefix used for path prefixing. Can be empty string for cloud drivers.
*/
prefix: string;
constructor(prefix?: string);
/**
* Normalize given path to always use `/` as separator and resolve relative paths using `.` and `..`.
* It also guards against path traversal beyond the root.
*/
normalizePath(path: string): string;
/**
* Ruturns normalized and prefixed location path.
*/
prefixPath(location: string): string;
/**
* Ruturns normalized and prefixed location path for directory so always ending with slash.
* Useful for cloud drivers prefix when listitng files.
*/
prefixDirectoryPath(location: string): string;
/**
* Returns normalized path after stripping the current prefix from it.
* It is a reverse operation of `prefixPath`.
*/
stripPrefix(location: string): string;
/**
* Returns a new instance of `PathPrefixer` which is using as prefix stripped prefix from path of current `PathPrefixer`.
*/
withStrippedPrefix(path: string): PathPrefixer;
/**
* Returns a new instance of `PathPrefixer` which is using as prefix current prefix merged with provided prefix.
*/
withPrefix(prefix: string): PathPrefixer;
/**
* Returns a new instance of `PathPrefixer` which is using as prefix provided normalized path.
*/
static fromPath(path: string): PathPrefixer;
}
+96
View File
@@ -0,0 +1,96 @@
"use strict";
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.PathPrefixer = void 0;
/// <reference path="../../adonis-typings/index.ts" />
const utils_1 = require("@poppinss/utils");
const path_1 = require("path");
const Exceptions_1 = require("../Exceptions");
/**
* Path prefixer for resolving and prefixing paths for disk drivers
*/
class PathPrefixer {
constructor(prefix = '') {
/**
* Separator used for dividing path segments is always unix-style forward slash
*/
this.separator = '/';
// strip slashes from the end of the prefix
this.prefix = prefix.replace(/\/+$/g, '');
// always end prefix with separator if it is not empty
if (this.prefix !== '' || prefix === this.separator) {
this.prefix += this.separator;
}
}
/**
* Normalize given path to always use `/` as separator and resolve relative paths using `.` and `..`.
* It also guards against path traversal beyond the root.
*/
normalizePath(path) {
const converted = (0, utils_1.slash)(path);
const parts = [];
for (const part of converted.split(this.separator)) {
if (['', '.'].includes(part)) {
continue;
}
if (part === '..') {
// if we are traversing beyond the root
if (parts.length === 0) {
throw Exceptions_1.PathTraversalDetectedException.invoke(converted);
}
parts.pop();
}
else {
parts.push(part);
}
}
return parts.join(this.separator);
}
/**
* Ruturns normalized and prefixed location path.
*/
prefixPath(location) {
return this.prefix + this.normalizePath(location);
}
/**
* Ruturns normalized and prefixed location path for directory so always ending with slash.
* Useful for cloud drivers prefix when listitng files.
*/
prefixDirectoryPath(location) {
return this.prefixPath(location) + this.separator;
}
/**
* Returns normalized path after stripping the current prefix from it.
* It is a reverse operation of `prefixPath`.
*/
stripPrefix(location) {
const path = (0, path_1.relative)(this.prefix, (0, utils_1.slash)(location));
return this.normalizePath(path);
}
/**
* Returns a new instance of `PathPrefixer` which is using as prefix stripped prefix from path of current `PathPrefixer`.
*/
withStrippedPrefix(path) {
return new PathPrefixer(this.stripPrefix(path));
}
/**
* Returns a new instance of `PathPrefixer` which is using as prefix current prefix merged with provided prefix.
*/
withPrefix(prefix) {
return new PathPrefixer(this.prefixPath(prefix));
}
/**
* Returns a new instance of `PathPrefixer` which is using as prefix provided normalized path.
*/
static fromPath(path) {
return new this((0, utils_1.slash)((0, path_1.normalize)(path)));
}
}
exports.PathPrefixer = PathPrefixer;
+3
View File
@@ -0,0 +1,3 @@
/// <reference types="node" />
import { pipeline } from 'stream';
export declare const pipelinePromise: typeof pipeline.__promisify__;
+14
View File
@@ -0,0 +1,14 @@
"use strict";
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.pipelinePromise = void 0;
const util_1 = require("util");
const stream_1 = require("stream");
exports.pipelinePromise = (0, util_1.promisify)(stream_1.pipeline);
+8
View File
@@ -0,0 +1,8 @@
export * from './src/Exceptions';
export { FakeDrive } from './src/Fake';
export { DriveManager } from './src/DriveManager';
export { LocalDriver } from './src/Drivers/Local';
export { FakeDriver } from './src/Drivers/Fake';
export { LocalFileServer } from './src/LocalFileServer';
export { DirectoryListing } from './src/DirectoryListing';
export { PathPrefixer } from './src/PathPrefixer';
+40
View File
@@ -0,0 +1,40 @@
"use strict";
/*
* @adonisjs/drive
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PathPrefixer = exports.DirectoryListing = exports.LocalFileServer = exports.FakeDriver = exports.LocalDriver = exports.DriveManager = exports.FakeDrive = void 0;
__exportStar(require("./src/Exceptions"), exports);
var Fake_1 = require("./src/Fake");
Object.defineProperty(exports, "FakeDrive", { enumerable: true, get: function () { return Fake_1.FakeDrive; } });
var DriveManager_1 = require("./src/DriveManager");
Object.defineProperty(exports, "DriveManager", { enumerable: true, get: function () { return DriveManager_1.DriveManager; } });
var Local_1 = require("./src/Drivers/Local");
Object.defineProperty(exports, "LocalDriver", { enumerable: true, get: function () { return Local_1.LocalDriver; } });
var Fake_2 = require("./src/Drivers/Fake");
Object.defineProperty(exports, "FakeDriver", { enumerable: true, get: function () { return Fake_2.FakeDriver; } });
var LocalFileServer_1 = require("./src/LocalFileServer");
Object.defineProperty(exports, "LocalFileServer", { enumerable: true, get: function () { return LocalFileServer_1.LocalFileServer; } });
var DirectoryListing_1 = require("./src/DirectoryListing");
Object.defineProperty(exports, "DirectoryListing", { enumerable: true, get: function () { return DirectoryListing_1.DirectoryListing; } });
var PathPrefixer_1 = require("./src/PathPrefixer");
Object.defineProperty(exports, "PathPrefixer", { enumerable: true, get: function () { return PathPrefixer_1.PathPrefixer; } });
+143
View File
@@ -0,0 +1,143 @@
{
"name": "@adonisjs/drive",
"version": "2.3.0",
"description": "Drive is an abstraction on cloud storage service for AdonisJS applications",
"main": "build/providers/DriveProvider.js",
"files": [
"build/adonis-typings",
"build/providers",
"build/src",
"build/standalone.d.ts",
"build/standalone.js",
"build/config.d.ts",
"build/config.js"
],
"scripts": {
"mrm": "mrm --preset=@adonisjs/mrm-preset",
"pretest": "npm run lint",
"test": "node -r @adonisjs/require-ts/build/register bin/test.ts",
"clean": "del build",
"compile": "npm run lint && npm run clean && tsc",
"build": "npm run compile",
"prepublishOnly": "npm run build",
"lint": "eslint . --ext=.ts",
"format": "prettier --write .",
"commit": "git-cz",
"release": "np --message=\"chore(release): %s\"",
"version": "npm run build",
"sync-labels": "github-label-sync --labels ./node_modules/@adonisjs/mrm-preset/gh-labels.json adonisjs/drive"
},
"keywords": [
"drive",
"adonisjs",
"adonis-drive"
],
"author": "virk,adonisjs",
"license": "MIT",
"devDependencies": {
"@adonisjs/application": "^5.2.5",
"@adonisjs/encryption": "^4.0.8",
"@adonisjs/http-server": "^5.11.0",
"@adonisjs/mrm-preset": "^5.0.3",
"@adonisjs/require-ts": "^2.0.13",
"@japa/assert": "^1.3.6",
"@japa/run-failed-tests": "^1.1.0",
"@japa/runner": "^2.2.1",
"@japa/spec-reporter": "^1.3.1",
"@poppinss/dev-utils": "^2.0.3",
"@types/node": "^18.8.3",
"commitizen": "^4.2.5",
"cz-conventional-changelog": "^3.3.0",
"del-cli": "^5.0.0",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-adonis": "^2.1.1",
"eslint-plugin-prettier": "^4.2.1",
"github-label-sync": "^2.2.0",
"husky": "^8.0.1",
"mrm": "^4.1.6",
"np": "^7.6.2",
"prettier": "^2.7.1",
"supertest": "^6.3.0",
"typescript": "^4.8.4"
},
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
},
"np": {
"contents": ".",
"anyBranch": false
},
"dependencies": {
"@poppinss/manager": "^5.0.2",
"@poppinss/utils": "^5.0.0",
"@types/fs-extra": "^9.0.13",
"etag": "^1.8.1",
"fs-extra": "^10.1.0",
"memfs": "^3.4.7"
},
"peerDependencies": {
"@adonisjs/application": "^5.0.0",
"@adonisjs/http-server": "^5.0.0"
},
"directories": {
"test": "test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/adonisjs/drive.git"
},
"bugs": {
"url": "https://github.com/adonisjs/drive/issues"
},
"homepage": "https://github.com/adonisjs/drive#readme",
"publishConfig": {
"access": "public",
"tag": "latest"
},
"mrmConfig": {
"core": true,
"license": "MIT",
"services": [
"github-actions"
],
"minNodeVersion": "14.17.0",
"probotApps": [
"stale",
"lock"
],
"runGhActionsOnWindows": true
},
"eslintConfig": {
"extends": [
"plugin:adonis/typescriptPackage",
"prettier"
],
"plugins": [
"prettier"
],
"rules": {
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
]
}
},
"eslintIgnore": [
"build"
],
"prettier": {
"trailingComma": "es5",
"semi": false,
"singleQuote": true,
"useTabs": false,
"quoteProps": "consistent",
"bracketSpacing": true,
"arrowParens": "always",
"printWidth": 100
}
}