- added own provider for drive methods
Some checks failed
CI Pipeline / japa-tests (push) Failing after 1m13s
Some checks failed
CI Pipeline / japa-tests (push) Failing after 1m13s
- renamed middleware Role and Can to role_middleware and can_middleware - added some typing for inertia vue3 components - npm updates
This commit is contained in:
parent
cb51a4136f
commit
296c8fd46e
67 changed files with 2515 additions and 1913 deletions
|
@ -11,8 +11,7 @@ export type PbkdfConfig = {
|
|||
rounds: number;
|
||||
saltSize?: number;
|
||||
version?: number;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const saltRounds = 10;
|
||||
export class LaravelDriver implements HashDriverContract {
|
||||
|
@ -24,8 +23,8 @@ export class LaravelDriver implements HashDriverContract {
|
|||
this.config = {
|
||||
rounds: 10,
|
||||
saltSize: 16,
|
||||
version: 98,
|
||||
...config
|
||||
version: 98,
|
||||
...config,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -135,9 +134,8 @@ export class LaravelDriver implements HashDriverContract {
|
|||
* Factory function to reference the driver
|
||||
* inside the config file.
|
||||
*/
|
||||
export function laravelDriver (config: PbkdfConfig): ManagerDriverFactory {
|
||||
export function laravelDriver(config: PbkdfConfig): ManagerDriverFactory {
|
||||
return () => {
|
||||
return new LaravelDriver(config)
|
||||
}
|
||||
}
|
||||
|
||||
return new LaravelDriver(config);
|
||||
};
|
||||
}
|
||||
|
|
133
providers/drive/drivers/local.ts
Normal file
133
providers/drive/drivers/local.ts
Normal file
|
@ -0,0 +1,133 @@
|
|||
import fsExtra from 'fs-extra'
|
||||
// import { RouterContract } from '@ioc:Adonis/Core/Route';
|
||||
// import { Visibility, DriveFileStats, ContentHeaders, LocalDriverConfig, LocalDriverContract, DirectoryListingContract, LocalDriveListItem } from '@ioc:Adonis/Core/Drive';
|
||||
|
||||
import { CannotGetMetaDataException, CannotDeleteFileException, CannotListDirectoryException } from '../exceptions/index.js';
|
||||
import PathPrefixer from '../path_prefixer/index.js';
|
||||
import {
|
||||
LocalDriverContract,
|
||||
LocalDriverConfig,
|
||||
DriverContract,
|
||||
DriveListItem,
|
||||
} from '../src/types/drive.js';
|
||||
import { AsyncIterableArray } from '../src/iterable_array.js';
|
||||
/**
|
||||
* Local driver interacts with the local file system
|
||||
*/
|
||||
export class LocalDriver implements LocalDriverContract {
|
||||
private diskName: string;
|
||||
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);
|
||||
constructor(diskName: string, config: LocalDriverConfig) {
|
||||
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.fromPath(this.config.root); //root: '/storage/app/public',
|
||||
}
|
||||
|
||||
/**
|
||||
* A boolean to find if the location path exists or not
|
||||
*/
|
||||
exists(location: string): Promise<boolean>;
|
||||
/**
|
||||
* A boolean to find if the location path exists or not
|
||||
*/
|
||||
public async exists(location: string): Promise<boolean> {
|
||||
try {
|
||||
return await this.adapter.pathExists(this.makePath(location));
|
||||
} catch (error) {
|
||||
throw CannotGetMetaDataException.invoke(location, 'exists', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make absolute path to a given location
|
||||
*/
|
||||
public makePath(location: string): string {
|
||||
return this.prefixer.prefixPath(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a given location path
|
||||
*/
|
||||
// delete(location: string, ...args: any[]): Promise<void>;
|
||||
public async delete(location: string): Promise<void> {
|
||||
try {
|
||||
await this.adapter.remove(this.makePath(location));
|
||||
} catch (error) {
|
||||
throw CannotDeleteFileException.invoke(location, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a listing directory iterator for given location.
|
||||
*/
|
||||
public list(location: string): AsyncIterableArray<DriverContract, DriveListItem<any>> {
|
||||
// public async list(location: string): Promise<DirectoryListing<DriverContract, DriveListItem<any>>> {
|
||||
const fullPath = this.makePath(location); //'/storage/app/public/files/307'
|
||||
|
||||
// let dirListing: DirectoryListing<DriverContract, DriveListItem<any>> = new DirectoryListing(this, () => this.getListing(fullPath, location));
|
||||
let dirListing: AsyncIterableArray<DriverContract, DriveListItem<any>> = new AsyncIterableArray(this, () => this.getListing(fullPath, location));
|
||||
return dirListing;
|
||||
// let listing: DriveListItem<fsExtra.Dirent>[] = await this.getListing(fullPath, location);
|
||||
// let test = new DirectoryListing(this, listing);
|
||||
// return test;
|
||||
}
|
||||
|
||||
// Example usage
|
||||
// private async *generateNumbers(): AsyncGenerator<number, void, unknown> {
|
||||
// yield 1;
|
||||
// yield 2;
|
||||
// yield 3;
|
||||
// }
|
||||
|
||||
private async *getListing(fullPath: string, location: string): AsyncGenerator<DriveListItem<fsExtra.Dirent>, void, unknown> {
|
||||
// private async getListing(fullPath: string, location: string): Promise<DriveListItem<fsExtra.Dirent>[]> {
|
||||
try {
|
||||
const dir = await this.adapter.opendir(fullPath);
|
||||
const prefixer = this.prefixer.withStrippedPrefix(fullPath);
|
||||
// const listing: DriveListItem<fsExtra.Dirent>[] = new Array();
|
||||
for await (const dirent of dir) {
|
||||
yield {
|
||||
location: prefixer.prefixPath(dirent.name),
|
||||
isFile: dirent.isFile(),
|
||||
original: dirent,
|
||||
};
|
||||
}
|
||||
// return listing;
|
||||
} catch (error) {
|
||||
throw CannotListDirectoryException.invoke(location, error);
|
||||
}
|
||||
}
|
||||
}
|
73
providers/drive/exceptions/index.ts
Normal file
73
providers/drive/exceptions/index.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
// const utils_1 = require("@poppinss/utils");
|
||||
// import * as utils_1 from "@poppinss/utils";
|
||||
import { Exception } from '@poppinss/utils';
|
||||
|
||||
/**
|
||||
* Custom exception for when a file cannot be deleted from a specified location
|
||||
*/
|
||||
export class CannotDeleteFileException extends Exception {
|
||||
location: string;
|
||||
original: any;
|
||||
|
||||
static invoke(location: string, original: any): CannotDeleteFileException {
|
||||
const error = new this(`Cannot delete file at location "${location}"`, {
|
||||
code: 'E_CANNOT_DELETE_FILE',
|
||||
status: 500,
|
||||
});
|
||||
error.location = location;
|
||||
error.original = original;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom exception for when file metadata cannot be retrieved
|
||||
*/
|
||||
export class CannotGetMetaDataException extends Exception {
|
||||
location: string;
|
||||
operation: string;
|
||||
original: any;
|
||||
|
||||
static invoke(location: string, operation: string, original: any): CannotGetMetaDataException {
|
||||
const error = new this(`Unable to retrieve the "${operation}" for file at location "${location}"`, {
|
||||
code: 'E_CANNOT_GET_METADATA',
|
||||
status: 500,
|
||||
});
|
||||
error.location = location;
|
||||
error.operation = operation;
|
||||
error.original = original;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given location is trying to traverse beyond the root path
|
||||
*/
|
||||
export class PathTraversalDetectedException extends Exception {
|
||||
location: string;
|
||||
static invoke(location: string) {
|
||||
const error = new this(`Path traversal detected: "${location}"`, {
|
||||
code: 'E_PATH_TRAVERSAL_DETECTED',
|
||||
status: 500,
|
||||
});
|
||||
error.location = location;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unable to list directory contents of given location
|
||||
*/
|
||||
export class CannotListDirectoryException extends Exception {
|
||||
location: string;
|
||||
original: any;
|
||||
static invoke(location: string, original: any): CannotListDirectoryException {
|
||||
const error = new this(`Cannot list directory contents of location "${location}"`, {
|
||||
status: 500,
|
||||
code: 'E_CANNOT_LIST_DIRECTORY',
|
||||
});
|
||||
error.location = location;
|
||||
error.original = original;
|
||||
return error;
|
||||
}
|
||||
}
|
96
providers/drive/path_prefixer/index.ts
Normal file
96
providers/drive/path_prefixer/index.ts
Normal file
|
@ -0,0 +1,96 @@
|
|||
import { slash } from '@poppinss/utils';
|
||||
import { relative, normalize } from 'path';
|
||||
import { PathTraversalDetectedException } from '../exceptions/index.js';
|
||||
/**
|
||||
* Path prefixer for resolving and prefixing paths for disk drivers
|
||||
*/
|
||||
export default 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);
|
||||
|
||||
constructor(prefix: string = '') {
|
||||
/**
|
||||
* 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: string): string {
|
||||
// const converted = (0, utils_1.slash)(path);
|
||||
const converted = 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 PathTraversalDetectedException.invoke(converted);
|
||||
}
|
||||
parts.pop();
|
||||
} else {
|
||||
parts.push(part);
|
||||
}
|
||||
}
|
||||
return parts.join(this.separator);
|
||||
}
|
||||
/**
|
||||
* Ruturns normalized and prefixed location path.
|
||||
*/
|
||||
prefixPath(location: string): string {
|
||||
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: string): string {
|
||||
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: string): string {
|
||||
// const path = (0, path_1.relative)(this.prefix, (0, utils_1.slash)(location));
|
||||
const path = relative(this.prefix, 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: string): PathPrefixer {
|
||||
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: string): PathPrefixer {
|
||||
return new PathPrefixer(this.prefixPath(prefix));
|
||||
}
|
||||
/**
|
||||
* Returns a new instance of `PathPrefixer` which is using as prefix provided normalized path.
|
||||
*/
|
||||
static fromPath(path: string): PathPrefixer {
|
||||
// return new this((0, utils_1.slash)((0, path_1.normalize)(path)));
|
||||
return new this(slash(normalize(path)));
|
||||
}
|
||||
}
|
62
providers/drive/provider/drive_provider.ts
Normal file
62
providers/drive/provider/drive_provider.ts
Normal file
|
@ -0,0 +1,62 @@
|
|||
import type { ApplicationService } from '@adonisjs/core/types';
|
||||
import { RuntimeException } from '@poppinss/utils';
|
||||
// import DriveManager from '../src/drive_manager.js';
|
||||
import { DriveConfig } from '../src/types/drive.js';
|
||||
|
||||
|
||||
|
||||
export default class DriveProvider {
|
||||
constructor(protected app: ApplicationService) {}
|
||||
|
||||
/**
|
||||
* Register bindings to the container
|
||||
*/
|
||||
async register() {
|
||||
const { default: DriveManager } = await import('../src/drive_manager.js');
|
||||
this.app.container.singleton(DriveManager, async () => {
|
||||
// 1. import the oai configuration
|
||||
// const ttl: number = 86400;
|
||||
const config: DriveConfig = this.app.config.get('drive');
|
||||
// const config: DriveConfig | null = await configProvider.resolve(this.app, driveConfigProvider);
|
||||
// const vite = await this.app.container.make("vite");
|
||||
if (!config) {
|
||||
throw new RuntimeException('Invalid "config/drive.ts" file. Make sure you are using the "defineConfig" method');
|
||||
}
|
||||
|
||||
return new DriveManager(this.app, config);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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'));
|
||||
// });
|
||||
// }
|
||||
|
||||
/**
|
||||
* The container bindings have booted
|
||||
*/
|
||||
async boot() {}
|
||||
|
||||
/**
|
||||
* The application has been booted
|
||||
*/
|
||||
async start() {}
|
||||
|
||||
/**
|
||||
* The process has been started
|
||||
*/
|
||||
async ready() {}
|
||||
|
||||
/**
|
||||
* Preparing to shutdown the app
|
||||
*/
|
||||
async shutdown() {}
|
||||
}
|
154
providers/drive/src/drive_manager.ts
Normal file
154
providers/drive/src/drive_manager.ts
Normal file
|
@ -0,0 +1,154 @@
|
|||
import type { ApplicationService } from '@adonisjs/core/types';
|
||||
import { Manager } from '@poppinss/manager';
|
||||
import { Exception } from '@poppinss/utils';
|
||||
import { DriverContract, DriversList, DriveConfig, DriveListItem, DirectoryListingContract, LocalDriverConfig } from './types/drive.js';
|
||||
// import { LocalDriver } from './drivers/local.js';
|
||||
import { LocalDriver } from '../drivers/local.js';
|
||||
|
||||
type test = {
|
||||
[P in keyof DriversList]: DriversList[P];
|
||||
};
|
||||
// type DriveMappings = {
|
||||
// local: string
|
||||
// fake: string
|
||||
// }
|
||||
|
||||
// interface DriversList {
|
||||
// local: {
|
||||
// implementation: LocalDriverContract;
|
||||
// config: LocalDriverConfig;
|
||||
// };
|
||||
// }
|
||||
|
||||
// type DriverConfig = {
|
||||
// disk: keyof DriversList
|
||||
// disks: {
|
||||
// [K in keyof DriversList]: any
|
||||
// }
|
||||
// }
|
||||
|
||||
// const mailerConfig: DriveConfig = {
|
||||
// disk: 'local',
|
||||
|
||||
// disks: {
|
||||
// local: {
|
||||
// driver: 'local',
|
||||
// root: '',
|
||||
// visibility: '',
|
||||
// serveFiles: false,
|
||||
// basePath: '',
|
||||
// },
|
||||
|
||||
// // 'fake': {
|
||||
// // driver: 'fake',
|
||||
// // root: '',
|
||||
// // },
|
||||
// },
|
||||
// };
|
||||
|
||||
export default class DriveManager extends Manager<
|
||||
ApplicationService,
|
||||
DriverContract,
|
||||
DriverContract,
|
||||
{
|
||||
[P in keyof DriversList]: DriversList[P]['implementation'];
|
||||
}
|
||||
> {
|
||||
protected singleton = true;
|
||||
private config;
|
||||
/**
|
||||
* Find if drive is ready to be used
|
||||
*/
|
||||
private isReady: boolean;
|
||||
|
||||
protected getDefaultMappingName() {
|
||||
return this.config.disk; // "local"
|
||||
}
|
||||
|
||||
protected getMappingConfig(mappingName: string) {
|
||||
return this.config.disks[mappingName];
|
||||
}
|
||||
|
||||
protected getMappingDriver(mappingName: string) {
|
||||
return this.config.disks[mappingName].driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make instance of the local driver
|
||||
*/
|
||||
protected createLocal(diskName: keyof DriversList, config: LocalDriverConfig) {
|
||||
// const { LocalDriver } = await import('../drivers/local.js');
|
||||
return new LocalDriver(diskName, config);
|
||||
}
|
||||
|
||||
constructor(application: ApplicationService, config: DriveConfig) {
|
||||
super(application);
|
||||
this.config = config;
|
||||
|
||||
/**
|
||||
* Find if drive is ready to be used
|
||||
*/
|
||||
this.isReady = false;
|
||||
|
||||
this.validateConfig();
|
||||
}
|
||||
/**
|
||||
* Validate config
|
||||
*/
|
||||
private 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve instance for a disk
|
||||
*/
|
||||
use(disk?: keyof test): DriversList[keyof DriversList]['implementation'] {
|
||||
if (!this.isReady) {
|
||||
throw new Exception('Missing configuration for drive. Visit https://bit.ly/2WnR5j9 for setup instructions', {
|
||||
status: 500,
|
||||
code: 'E_MISSING_DRIVE_CONFIG',
|
||||
});
|
||||
}
|
||||
disk = disk || this.getDefaultMappingName();
|
||||
// if (this.fakeDrive.isFaked(disk)) {
|
||||
// return this.fakeDrive.use(disk);
|
||||
// }
|
||||
return super.use(disk);
|
||||
}
|
||||
|
||||
/**
|
||||
* A boolean to find if the location path exists or not
|
||||
*/
|
||||
exists(location: string): Promise<boolean> {
|
||||
const driver = this.use();
|
||||
return driver.exists(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a given location path
|
||||
*/
|
||||
delete(location: string): Promise<void> {
|
||||
const driver = this.use();
|
||||
return driver.delete(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a listing directory iterator for given location.
|
||||
*/
|
||||
list(location: string): DirectoryListingContract<DriverContract, DriveListItem> {
|
||||
const driver = this.use();
|
||||
if (typeof driver.list !== 'function') {
|
||||
throw new Exception(`List is not supported by the "${driver.name}" driver.`, {
|
||||
status: 500,
|
||||
code: 'E_LIST_NOT_SUPPORTED',
|
||||
});
|
||||
}
|
||||
return driver.list(location);
|
||||
}
|
||||
}
|
68
providers/drive/src/iterable_array.ts
Normal file
68
providers/drive/src/iterable_array.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import { DriveListItem, DriverContract } from './types/drive.js';
|
||||
// import * as fsExtra from 'fs-extra';
|
||||
import { DirectoryListingContract } from './types/drive.js';
|
||||
|
||||
// class AsyncIterableArray<T> implements AsyncIterable<T> {
|
||||
export class AsyncIterableArray<SpecificDriver extends DriverContract, T extends DriveListItem>
|
||||
implements DirectoryListingContract<SpecificDriver, T>
|
||||
{
|
||||
public driver: SpecificDriver;
|
||||
private generator: () => AsyncGenerator<T, void, unknown>;
|
||||
// private generator: () => AsyncGenerator<T, void, unknown>;
|
||||
private chain: any[];
|
||||
|
||||
constructor(driver: SpecificDriver, generator: () => AsyncGenerator<T, void, unknown>) {
|
||||
// constructor(driver: SpecificDriver, listing: T) {
|
||||
this.driver = driver;
|
||||
this.generator = generator;
|
||||
/**
|
||||
* Functions chain to be executed for transforming generated listing iterable
|
||||
*/
|
||||
this.chain = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert directory listing to array.
|
||||
*/
|
||||
// public async toArray(): Promise<T[]> {
|
||||
// const arr = [];
|
||||
// for await (const item of this.toIterable()) {
|
||||
// arr.push(item);
|
||||
// }
|
||||
// return arr;
|
||||
// }
|
||||
async toArray(): Promise<T[]> {
|
||||
const arr: T[] = [];
|
||||
for await (const item of this) {
|
||||
arr.push(item);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that returns the default async iterator for an object.
|
||||
*/
|
||||
public async *[Symbol.asyncIterator](): AsyncIterableIterator<T> {
|
||||
// yield* this.toIterable();
|
||||
for await (const item of this.generator.call(this.driver)) {
|
||||
yield item;
|
||||
}
|
||||
// yield 1
|
||||
// // await something()
|
||||
// yield 2
|
||||
// // await somethingElse()
|
||||
// yield 3
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the final async iterable after passing directory listing through chain of piping functions modifying the output.
|
||||
*/
|
||||
public toIterable(): AsyncIterable<T> {
|
||||
const generator = this.generator.call(this.driver);
|
||||
const iterable = this.chain.reduce((prevIterable, currentIterable) => {
|
||||
return currentIterable.call(this.driver, prevIterable);
|
||||
}, generator);
|
||||
|
||||
return iterable;
|
||||
}
|
||||
}
|
5
providers/drive/src/types/define_config.ts
Normal file
5
providers/drive/src/types/define_config.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { DriveConfig } from "./drive.js";
|
||||
|
||||
export function defineConfig(config: DriveConfig): DriveConfig {
|
||||
return config;
|
||||
}
|
176
providers/drive/src/types/drive.ts
Normal file
176
providers/drive/src/types/drive.ts
Normal file
|
@ -0,0 +1,176 @@
|
|||
import fsExtra from 'fs-extra';
|
||||
import { LocalDriver } from '#providers/drive/drivers/local';
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
/**
|
||||
* List item returned from local disk driver
|
||||
*/
|
||||
export interface LocalDriveListItem extends DriveListItem<fsExtra.Dirent> {}
|
||||
|
||||
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>;
|
||||
|
||||
/**
|
||||
* Remove a given location path
|
||||
*/
|
||||
delete(location: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Return a listing directory iterator for given location.
|
||||
* @experimental
|
||||
*/
|
||||
list?(location: string): DirectoryListingContract<DriverContract, DriveListItem>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
// interface LocalDriverContract {
|
||||
// delete(): Promise<void>;
|
||||
// }
|
||||
export type LocalDriverConfig = {
|
||||
driver: 'local';
|
||||
// visibility: Visibility
|
||||
root: string;
|
||||
|
||||
/**
|
||||
* Base path is always required when "serveFiles = true"
|
||||
*/
|
||||
serveFiles?: boolean;
|
||||
basePath?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* List of registered drivers. Drivers shipped via other packages
|
||||
* should merge drivers to this interface
|
||||
*/
|
||||
export interface DriversList {
|
||||
// [key: string]: {implementation : DriverContract, config: {}};
|
||||
local: {
|
||||
implementation: LocalDriver;
|
||||
config: {
|
||||
driver: string;
|
||||
visibility: string;
|
||||
root: string;
|
||||
serveFiles: boolean;
|
||||
basePath: string;
|
||||
};
|
||||
};
|
||||
|
||||
// [key: string]: DriverContract;
|
||||
// local: LocalDriver;
|
||||
// fake: {
|
||||
// implementation: LocalDriverContract;
|
||||
// config: LocalDriverConfig;
|
||||
// };
|
||||
}
|
||||
|
||||
export type DriveConfig = {
|
||||
disk: keyof DriversList;
|
||||
// disks: {
|
||||
// [name: string]: {
|
||||
// driver: DriverContract;
|
||||
// };
|
||||
// };
|
||||
disks: {
|
||||
[name: string]: {
|
||||
[K in keyof DriversList]: DriversList[K]['config'] & {
|
||||
driver: K;
|
||||
visibility: string;
|
||||
root: string;
|
||||
serveFiles: boolean;
|
||||
basePath: string;
|
||||
};
|
||||
}[keyof DriversList];
|
||||
};
|
||||
};
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue