npm package: @n7e/storage
Description: A simple file storage abstraction.
Author: Martin Pettersson
Latest version: 0.2.0

# Storage

A simple file storage abstraction.

For further insights, read on.

- [Installation](#installation)
- [Storage Entry](#storage-entry)
- [Locations](#locations)
- [Storage Client](#storage-client)
    - [List Entries](#list-entries)
    - [Retrieve Entries](#retrieve-entries)
    - [Create Entries](#create-entries)
    - [Remove Entries](#remove-entries)
- [Storage Client Builder](#storage-client-builder)
- [Storage Client Builder Registry](#storage-client-builder-registry)
    - [Default Storage Client Builder Registry](#default-storage-client-builder-registry)
- [Storage Client Factory](#storage-client-factory)
    - [Default Storage Client Factory](#default-storage-client-factory)


## Installation

To install this library use your favorite package manager. No additional steps
are required to start using the library.

```shell
npm install @n7e/storage
```

*This library is implemented in TypeScript but can be used with JavaScript
without any additional steps.*


## Storage Entry

A storage entry represents either a file of a directory in a storage medium. If
a storage entry represents a directory the content stream won't generate any
data.

```typescript
import type { StorageEntry } from "@n7e/storage";

function doSomethingWith(entry: StorageEntry): void {
    // ...
}
```

*`StorageEntry` is just an interface describing the functionality of a storage
entry. To obtain a storage entry use a [storage client](#storage-client).*


## Locations

Storage entries are located using URLs. Any supported or preferred URI schemes
are up to the implementation to communicate. Examples in this documentation will
use the `file` scheme.


## Storage Client

All operations to storage entries are done through a storage client.

```typescript
import type { StorageClient } from "@n7e/storage";

function doSomethingWith(client: StorageClient): void {
    // ...
}
```


### List Entries

To list entries in a given location use the `list` method:

```typescript
const entries = await client.list(new URL("file://some/directory"));
```

The location is optional and if omitted implementations should list entries in
the "root directory". What "root directory" really means is ultimately up to the
implementation.

```typescript
const entries = await client.list();
```

If the given location points to an existing file, storage clients should throw
an `InvalidLocation` error.

```typescript
const enties = await client.list(new URL("file://some/file.txt"));
```


### Retrieve Entries

To retrieve a single entry at a given location use the `get` method:

```typescript
const file = await client.get(new URL("file://some/file.txt"));
const directory = await client.get(new URL("file://some/directory"));
```

*Note that the content stream of a directory won't produce any data.*


### Create Entries

To create a new entry or update an existing entry at a given location use the
`put` method:

```typescript
await client.put(new URL("file://some/file.txt"), generateContentStream());
```

*Note that there's currently no explicit way to create directories. It is up to
the implementation to either create directories or simulate directories in some
fashion when needed.*

If attempting to create a file where a directory already exists, storage clients
should throw an `InvalidLocation` error.

```typescript
await client.put(new URL("file://some/directory"), generateContentStream());
```


### Remove Entries

To remove an entry use the `delete` method:

```typescript
await client.delete(new URL("file://some/file.txt"));
```

When removing a directory, storage clients may choose to recursively remove any
entries in the given directory or throw an `InvalidLocation` error. It's up to
the implementation to define the behaviour.


## Storage Client Builder

Storage clients can be created using the builder pattern. Storage client
builders should implement the `StorageClientBuilder` interface to be used in
[storage client builder registries](#storage-client-builder-registry) and/or
[storage client factories](#storage-client-factory). Any other builder
configuration is up to the implementation.

```typescript
import type { StorageClientBuilder } from "@n7e/storage";

function doSomethingWith(storageClientBuilder: StorageClientBuilder): void {
    const client = storageClientBuilder.build();
    
    // ...
}
```


## Storage Client Builder Registry

A storage client builder registry is used to register a set of storage client
builder that should be available in an application. This allows specific
implementations to be provided where needed, retrieved by name.

```typescript
import type { StorageClientBuilderRegistry } from "@n7e/storage";

function registerStorageClient(clientBuilders: StorageClientBuilderRegistry): void {
    clientBuilders.register("images", someStorageClientBuilder);
}

async function retrieveStorageClient(clientBuilders: StorageClientBuilderRegistry): Promise<void> {
    const client = clientBuilders.retrieve("images").build();
    
    // ...
}
```

*`StorageClientBuilderRegistry` is just an interface describing the
functionality of a storage client builder registry. To create a storage client
builder registry use a specific
[implementation](#default-storage-client-builder-registry).*

This paradigm enables an application to store files on different storage mediums
with a single API. It makes it easy to use different storage mediums between
application environments. For example storing files in memory when developing or
running tests.

To further abstract the use of storage client builders use the
[storage client factory](#storage-client-factory).


### Default Storage Client Builder Registry

This library provides a `StorageClientBuilderRegistry` implementation. To use it
simply import it and create an instance:

```typescript
import { DefaultStorageClientBuilderRegistry } from "@n7e/storage";

const storageClientBuilders = new DefaultStorageClientBuilderRegistry();
```


## Storage Client Factory

To abstract away the use of storage client builders from the user a
`StorageClientFactory` can be used to create storage clients.

```typescript
import type { StorageClientFactory } from "@n7e/storage";

function doSomethingWith(storageClientFactory: StorageClientFactory): void {
    const client = storageClientFactory.createClient("images");
    
    // ...
}
```

*`StorageClientFactory` is just an interface describing the functionality of a
storage client factory. To create a storage client factory use a specific
[implementation](#default-storage-client-factory).*


### Default Storage Client Factory

This library provides a `StorageClientFactory` implementation. It uses a
[StorageClientBuilderRegistry](#storage-client-builder-registry) to retrieve
named storage clients.

```typescript
import { DefaultStorageClientFactory } from "@n7e/storage";

const storageClientFactory = new DefaultStorageClientFactory(someStorageClientBuilderRegistry);
```