feat(core): add provider defaults, strengthen WebDAV validation, and modernize tests and package metadata
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @pushrocks/commitinfo
|
||||
* autocreated commitinfo by @push.rocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@push.rocks/smartexpose',
|
||||
version: '1.0.6',
|
||||
description: 'a package to expose things to the internet'
|
||||
version: '1.1.0',
|
||||
description: 'A TypeScript package for temporarily exposing files through WebDAV-backed public URLs.'
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ import * as plugins from './plugins.js';
|
||||
|
||||
/**
|
||||
* An expose provider provides a standardized interface for exposing data
|
||||
* Note: SmartExpose comes with some default implmentations of ExposeProvider
|
||||
*
|
||||
* Note: SmartExpose comes with some default implementations of ExposeProvider
|
||||
*
|
||||
* notably:
|
||||
* - WebDavExposeProvider
|
||||
*/
|
||||
@@ -13,15 +13,15 @@ export abstract class ExposeProvider {
|
||||
* Should take care of any housekeeping required to keep things in a healthy state.
|
||||
*/
|
||||
public abstract houseKeeping(): Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* should return a url with info about how to access the file
|
||||
* @param optionsArg
|
||||
* @param optionsArg
|
||||
*/
|
||||
public abstract exposeFile(optionsArg: {
|
||||
smartFile: plugins.smartfile.SmartFile,
|
||||
deleteAfterMillis?: number,
|
||||
privateUrl?: boolean, // wether the returned url should be private by design
|
||||
smartFile: plugins.smartfile.SmartFile;
|
||||
deleteAfterMillis?: number;
|
||||
privateUrl?: boolean; // whether the returned url should be private by design
|
||||
}): Promise<{
|
||||
url: string;
|
||||
id: string;
|
||||
@@ -29,9 +29,9 @@ export abstract class ExposeProvider {
|
||||
}>;
|
||||
|
||||
public abstract exposeFileArray(optionsArg: {
|
||||
smartFiles: plugins.smartfile.SmartFile[],
|
||||
deleteAfterMillis?: number,
|
||||
privateUrl?: boolean,
|
||||
smartFiles: plugins.smartfile.SmartFile[];
|
||||
deleteAfterMillis?: number;
|
||||
privateUrl?: boolean;
|
||||
}): Promise<{
|
||||
url: string;
|
||||
id: string;
|
||||
@@ -45,9 +45,10 @@ export abstract class ExposeProvider {
|
||||
public abstract wipeAll(): Promise<{
|
||||
id: string;
|
||||
status: 'deleted' | 'failed' | 'notfound';
|
||||
}[]>
|
||||
}[]>;
|
||||
|
||||
public abstract deleteFileById(idArg: string): Promise<{
|
||||
id: string;
|
||||
status: 'deleted' | 'failed' | 'notfound';
|
||||
}>
|
||||
}
|
||||
}>;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export interface IWebdavExposeProviderOptions {
|
||||
|
||||
export class WebDavExposeProvider extends ExposeProvider {
|
||||
public smartExposeRef: SmartExpose;
|
||||
public webdavClient: plugins.smartwebdav.WebdavClient;
|
||||
public webdavClient!: plugins.smartwebdav.WebdavClient;
|
||||
public options: IWebdavExposeProviderOptions;
|
||||
|
||||
constructor(smartexposeRefArg: SmartExpose, optionsArg: IWebdavExposeProviderOptions) {
|
||||
@@ -65,27 +65,37 @@ export class WebDavExposeProvider extends ExposeProvider {
|
||||
)})`
|
||||
);
|
||||
const webdavFilePath = await this.getFilePathById(fileId);
|
||||
const fileToUpload = await plugins.smartfile.SmartFile.fromBuffer(
|
||||
webdavFilePath,
|
||||
optionsArg.smartFile.contents
|
||||
);
|
||||
const fileToUpload = new plugins.smartfile.SmartFile({
|
||||
path: webdavFilePath,
|
||||
contentBuffer: optionsArg.smartFile.contents,
|
||||
base: '/',
|
||||
});
|
||||
await this.webdavClient.uploadSmartFileArray([fileToUpload]);
|
||||
console.log(`checking file presence: ${webdavFilePath}`);
|
||||
const existsOnWebdav = await this.webdavClient.wdClient.exists(webdavFilePath);
|
||||
if (!existsOnWebdav) {
|
||||
throw new Error(`Uploaded file does not exist on WebDAV: ${webdavFilePath}`);
|
||||
}
|
||||
const publicUrl = plugins.smartpath.join(
|
||||
this.smartExposeRef.options.exposedBaseUrl,
|
||||
webdavFilePath
|
||||
);
|
||||
console.log(`cehcking for file at ${publicUrl}`);
|
||||
const response = await plugins.smartrequest.getBinary(publicUrl);
|
||||
plugins.smartexpect.expect(response.body).toEqual(fileToUpload.contents);
|
||||
console.log(`checking for file at ${publicUrl}`);
|
||||
const response = await plugins.smartrequest.SmartRequest.create()
|
||||
.url(publicUrl)
|
||||
.accept('binary')
|
||||
.get();
|
||||
const responseBuffer = Buffer.from(await response.arrayBuffer());
|
||||
if (!responseBuffer.equals(fileToUpload.contents)) {
|
||||
throw new Error(`Public URL did not return the uploaded file contents: ${publicUrl}`);
|
||||
}
|
||||
if (optionsArg.deleteAfterMillis) {
|
||||
console.log(
|
||||
`Scheduling deletion of file with id: ${fileId} in ${optionsArg.deleteAfterMillis}ms...`
|
||||
);
|
||||
plugins.smartdelay.delayFor(optionsArg.deleteAfterMillis).then(() => {
|
||||
void plugins.smartdelay.delayFor(optionsArg.deleteAfterMillis).then(async () => {
|
||||
console.log(`Deleting file with id: ${fileId}...`);
|
||||
this.deleteFileById(fileId);
|
||||
await this.deleteFileById(fileId);
|
||||
console.log(`Deleted file with id: ${fileId}`);
|
||||
});
|
||||
}
|
||||
@@ -96,8 +106,10 @@ export class WebDavExposeProvider extends ExposeProvider {
|
||||
};
|
||||
}
|
||||
|
||||
public async exposeFileArray(optionsArg: Parameters<ExposeProvider['exposeFileArray']>[0]) {
|
||||
const returnArray = [];
|
||||
public async exposeFileArray(
|
||||
optionsArg: Parameters<ExposeProvider['exposeFileArray']>[0]
|
||||
): ReturnType<ExposeProvider['exposeFileArray']> {
|
||||
const returnArray: Awaited<ReturnType<ExposeProvider['exposeFile']>>[] = [];
|
||||
for (const smartFile of optionsArg.smartFiles) {
|
||||
returnArray.push(
|
||||
await this.exposeFile({
|
||||
@@ -125,7 +137,7 @@ export class WebDavExposeProvider extends ExposeProvider {
|
||||
idArg: string
|
||||
): Promise<{ id: string; status: 'deleted' | 'failed' | 'notfound' }> {
|
||||
const filePath = await this.getFilePathById(idArg);
|
||||
if (!this.webdavClient.wdClient.exists(filePath)) {
|
||||
if (!(await this.webdavClient.wdClient.exists(filePath))) {
|
||||
return {
|
||||
id: idArg,
|
||||
status: 'notfound',
|
||||
|
||||
+27
-12
@@ -3,25 +3,32 @@ import { WebDavExposeProvider } from './classes.exposeprovider.webdav.js';
|
||||
import * as plugins from './plugins.js';
|
||||
|
||||
export interface ISmartExposeOptions {
|
||||
deleteAfterMillis?: number,
|
||||
privateUrl?: boolean,
|
||||
exposedBaseUrl: string,
|
||||
deleteAfterMillis?: number;
|
||||
privateUrl?: boolean;
|
||||
exposedBaseUrl: string;
|
||||
webdav?: {
|
||||
webdavCredentials: plugins.smartwebdav.IWebdavClientOptions,
|
||||
webdavSubPath: string,
|
||||
}
|
||||
webdavCredentials: plugins.smartwebdav.IWebdavClientOptions;
|
||||
webdavSubPath: string;
|
||||
};
|
||||
}
|
||||
|
||||
export class SmartExpose {
|
||||
// INSTANCE
|
||||
public taskmanager: plugins.taskbuffer.TaskManager;
|
||||
public provider: ExposeProvider;
|
||||
public taskmanager!: plugins.taskbuffer.TaskManager;
|
||||
public provider!: ExposeProvider;
|
||||
public options: ISmartExposeOptions;
|
||||
|
||||
constructor(optionsArg: ISmartExposeOptions) {
|
||||
this.options = optionsArg;
|
||||
}
|
||||
|
||||
private getProvider(): ExposeProvider {
|
||||
if (!this.provider) {
|
||||
throw new Error('No expose provider has been configured.');
|
||||
}
|
||||
return this.provider;
|
||||
}
|
||||
|
||||
public async start() {
|
||||
this.taskmanager = new plugins.taskbuffer.TaskManager();
|
||||
if (this.options.webdav) {
|
||||
@@ -30,20 +37,28 @@ export class SmartExpose {
|
||||
webdavSubPath: this.options.webdav.webdavSubPath,
|
||||
});
|
||||
}
|
||||
await this.provider.start();
|
||||
await this.getProvider().start();
|
||||
this.taskmanager.start();
|
||||
}
|
||||
|
||||
public async stop() {
|
||||
await this.provider.stop();
|
||||
await this.getProvider().stop();
|
||||
this.taskmanager.stop();
|
||||
}
|
||||
|
||||
public async exposeFile(optionsArg: Parameters<ExposeProvider['exposeFile']>[0]) {
|
||||
return this.provider.exposeFile(optionsArg);
|
||||
return this.getProvider().exposeFile({
|
||||
...optionsArg,
|
||||
deleteAfterMillis: optionsArg.deleteAfterMillis ?? this.options.deleteAfterMillis,
|
||||
privateUrl: optionsArg.privateUrl ?? this.options.privateUrl,
|
||||
});
|
||||
}
|
||||
|
||||
public async exposeFileArray(optionsArg: Parameters<ExposeProvider['exposeFileArray']>[0]) {
|
||||
return this.provider.exposeFileArray(optionsArg);
|
||||
return this.getProvider().exposeFileArray({
|
||||
...optionsArg,
|
||||
deleteAfterMillis: optionsArg.deleteAfterMillis ?? this.options.deleteAfterMillis,
|
||||
privateUrl: optionsArg.privateUrl ?? this.options.privateUrl,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+1
-5
@@ -1,9 +1,7 @@
|
||||
// @push.rocks scope
|
||||
import * as smartdelay from '@push.rocks/smartdelay';
|
||||
import * as smartexpect from '@push.rocks/smartexpect';
|
||||
import * as smartfile from '@push.rocks/smartfile';
|
||||
import * as smartformat from '@push.rocks/smartformat';
|
||||
import * as smartjson from '@push.rocks/smartjson';
|
||||
import * as smartpath from '@push.rocks/smartpath';
|
||||
import * as smartrequest from '@push.rocks/smartrequest';
|
||||
import * as smartunique from '@push.rocks/smartunique';
|
||||
@@ -12,13 +10,11 @@ import * as taskbuffer from '@push.rocks/taskbuffer';
|
||||
|
||||
export {
|
||||
smartdelay,
|
||||
smartexpect,
|
||||
smartfile,
|
||||
smartformat,
|
||||
smartjson,
|
||||
smartpath,
|
||||
smartrequest,
|
||||
smartunique,
|
||||
smartwebdav,
|
||||
taskbuffer,
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user