Skip to main content

@eik/sink reference

The @eik/sink module specifies the public API for all Eik storage backends. The existing sinks are good examples to look at when implementing a custom sink.

Constructor

A sink must be a class which extends the Eik sink interface.

import Sink from "@eik/sink";

class SinkCustom extends Sink {
constructor() {
super();
}
write() {}
read() {}
delete() {}
exist() {}
get metrics() {}
}

API

A sink must implement the following API:

write(filePath, contentType)

argumentdefaulttyperequireddetails
filePathnullstringtruePathname of the file relative to root in the file structure in Eik
contentTypenullstringtrueContent type of the file

This method is called when a file is to be written to storage. The method must return a Promise and resolve with a WritableStream when the storage is ready to be written too. The server will pipe the byte stream of the file to this stream. Upon any errors, the promise should reject with an Error object

import { Writable } from 'node:stream';
import Sink from '@eik/sink';

export class SinkCustom extends Sink {
constructor() {
super();
}
write() {
return new Promise(resolve, reject) {
const to = new Writable();
resolve(to);
}
}
}

read(filePath)

argumentdefaulttyperequireddetails
filePathnullstringtruePathname of the file relative to root in the file structure in Eik

This method is called when a file is to be read from storage. The method must return a Promise and resolve with a ReadableStream when the storage is ready to be read from. Upon any errors, the promise should reject with an Error object

import { Readable } from 'node:stream';
import Sink from '@eik/sink';

export class SinkCustom extends Sink {
constructor() {
super();
}
read() {
return new Promise(resolve, reject) {
const to = new Readable();
resolve(to);
}
}
}

delete(filePath)

argumentdefaulttyperequireddetails
filePathnullstringtruePathname of the file relative to root in the file structure in Eik

This method is called when a file is to be deleted from storage. The method must return a Promise and resolve with no value when the file is deleted from storage. If any errors occur, the promise should reject with an Error object

exist(filePath)

argumentdefaulttyperequireddetails
filePathnullstringtruePathname of the file relative to root in the file structure in Eik

This method is called to check if a file exists in storage. The method must return a Promise and resolve with no value if the file exists in storage. If the file does not exist the promise should reject with no error object. Upon any errors, the promise should reject with an Error object.

Properties

A sink must implement the following properties:

.metrics

A getter for a metric stream. The metric stream can be used to emit metrics from the sink into the overall metric stream in the server.

Example:

import Metrics from @metrics/client';
import Sink from @eik/sink';

export class SinkCustom extends Sink {
constructor() {
super();
this._metrics = new Metrics();
this._counter = this._metrics.counter({
name: 'eik_custom_sink',
description: 'Counter measuring access to the custom sink',
});
}
write(filePath, contentType) {
return new Promise(resolve, reject) {
this._counter.inc();

}
}
}

Validation

We recommend you validate the arguments for all methods. The Eik sink interface contain static methods to do so which can be used when implementing a sink:

import Sink from @eik/sink';

export class SinkCustom extends Sink {
constructor() {
super();
}
write(filePath, contentType) {
return new Promise(resolve, reject) {
try {
super.constructor.validateFilePath(filePath);
super.constructor.validateContentType(contentType);
} catch (error) {
reject(error);
return;
}

}
}
}

Security

A sink should take care of protecting against Path Traversal. It should not be possible to access files outside the root of the file structure in Eik by passing in a hostile pathname through the REST API of Eik. Each filePath argument on each method should be checked for such.

Please see OWASPs guide on preventing Path Traversal.