An effect layer to interact with Cloudware R2 storage service
npm install effect-cloudflare-r2-layer
!Last commit
!npm downloads
!npm bundle size
An effect layer to interact with Cloudware R2 storage service.
``bash`
npm i effect-cloudflare-r2-layeror
pnpm i effect-cloudflare-r2-layeror
bun i effect-cloudflare-r2-layer
`typescript
import { FetchHttpClient } from '@effect/platform';
import { Effect, Layer, pipe } from 'effect';
import {
CloudflareR2StorageLayerLive,
FileStorageLayer,
} from 'effect-cloudflare-r2-layer';
const task = pipe(
FileStorageLayer.readAsText('my-bucket', 'some-file.txt'),
Effect.scoped,
Effect.provide(
Layer.mergeAll(CloudflareR2StorageLayerLive, FetchHttpClient.layer)
)
);
/* task is of type
Effect.Effect<
string,
ConfigError | HttpClientError | FileStorageError,
never
>
*/
`
The layer requires the following env variables:
`env`
CLOUDFLARE_ACCOUNT_ID=""
R2_DOCUMENTS_ACCESS_KEY_ID=""
R2_DOCUMENTS_SECRET_ACCESS_KEY=""
| function | description |
| -------------------------------------- | ----------------------------------------------------------------------------------------- |
| createBucket | Create a bucket |
| bucketInfos | Get bucket infos |
| uploadFile | Adds a file to the specified bucket |
| deleteFile | Removes a file from the specified bucket |
| getFileUrl | Gets a pre-signed url to fetch a ressource by its filename from the specified bucket. |readAsJson
| | Fetches a file, expecting a content extending Record. |readAsText
| | Fetches a file as a string. |readAsRawBinary
| | Fetches a file as raw binary (ArrayBuffer). |fileExists
| | Checks if a file exists in a bucket |
`typescript`
type createBucket = (
input: CreateBucketCommandInput
) => Effect.Effect<
CreateBucketCommandOutput,
FileStorageError | ConfigError,
FileStorage
>;
#### 🧿 Example
`typescript
import { Effect, pipe } from 'effect';
import {
CloudflareR2StorageLayerLive,
FileStorageLayer,
} from 'effect-cloudflare-r2-layer';
const task = pipe(
Effect.gen(function* () {
const result = yield* FileStorageLayer.createBucket({
Bucket: 'test',
CreateBucketConfiguration: {
Bucket: {
Type: 'Directory',
DataRedundancy: 'SingleAvailabilityZone',
},
},
});
// ...
}),
Effect.provide(CloudflareR2StorageLayerLive)
);
`
`typescript
type BucketInfosInput
Bucket: TBucket;
ExpectedBucketOwner?: string;
};
type BucketInfosResult = {
region?: string;
};
type bucketInfos =
input: BucketInfosInput
) => Effect.Effect<
BucketInfosResult,
ConfigError | FileStorageError | BucketNotFoundError,
FileStorage
>;
`
#### 🧿 Example
`typescript
import { Effect, pipe } from 'effect';
import {
CloudflareR2StorageLayerLive,
FileStorageLayer,
} from 'effect-cloudflare-r2-layer';
type Buckets = 'assets' | 'config';
const task = pipe(
Effect.gen(function* () {
const result = yield* FileStorageLayer.bucketInfos
Bucket: 'assets',
});
// ...
}),
Effect.provide(CloudflareR2StorageLayerLive)
);
`
Adds a file to the specified bucket.
`typescript
interface UploadFileInput
bucketName: TBucket;
key: string;
data: Buffer;
contentType: string | undefined;
}
type uploadFile =
input: UploadFileInput
) => Effect.Effect<
PutObjectCommandOutput,
FileStorageError | ConfigError,
FileStorage
>;
`
#### 🧿 Example
`typescript
import { FileSystem } from '@effect/platform/FileSystem';
import { NodeFileSystem } from '@effect/platform-node';
import { Effect, Layer, pipe } from 'effect';
import {
CloudflareR2StorageLayerLive,
FileStorageLayer,
} from 'effect-cloudflare-r2-layer';
type Buckets = 'assets' | 'config';
const fileName = 'yolo.jpg';
const filePath = './assets/yolo.jpg';
const task = pipe(
Effect.gen(function* () {
const fs = yield* FileSystem;
const fileData = yield* fs.readFile(filePath);
yield* FileStorageLayer.uploadFile
bucketName: 'assets',
documentKey: fileName,
data: Buffer.from(fileData),
contentType: 'image/jpeg',
});
// ...
}),
Effect.provide(
Layer.mergeAll(CloudflareR2StorageLayerLive, NodeFileSystem.layer)
)
);
`
Removes a file from the specified bucket.
`typescript
interface DeleteFileInput
bucketName: TBucket;
key: string;
}
type deleteFile =
input: DeleteFileInput
) => Effect.Effect<
DeleteObjectCommandOutput,
FileStorageError | ConfigError,
FileStorage
>;
`
#### 🧿 Example
`typescript
import { Effect, pipe } from 'effect';
import {
CloudflareR2StorageLayerLive,
FileStorageLayer,
} from 'effect-cloudflare-r2-layer';
type Buckets = 'assets' | 'config';
const fileName = 'yolo.jpg';
const filePath = './assets/yolo.jpg';
const task = pipe(
Effect.gen(function* () {
yield* FileStorageLayer.deleteFile
bucketName: 'assets',
documentKey: fileName,
});
// ...
}),
Effect.provide(CloudflareR2StorageLayerLive);
);
`
Gets a pre-signed url to fetch a ressource by its filename from the specified bucket.
`typescript`
type getFileUrl =
bucket: TBucket
fileName: string,
) => Effect.Effect<
string,
FileStorageError | ConfigError,
FileStorage
>;
#### 🧿 Example
`typescript
import { Effect, pipe } from 'effect';
import {
CloudflareR2StorageLayerLive,
FileStorageLayer,
} from 'effect-cloudflare-r2-layer';
type Buckets = 'assets' | 'config';
const filename = 'yolo.jpg';
const task = pipe(
Effect.gen(function* () {
const url = yield* FileStorageLayer.getFileUrl
// ...
}),
Effect.provide(CloudflareR2StorageLayerLive);
);
`
Fetches a file, expecting a content extending Record.
`typescript`
type readAsJson = <
TBucket extends string,
TShape extends Record
>(
bucket: TBucket,
fileName: string
) => Effect.Effect<
TShape,
HttpClientError | FileStorageError | ConfigError,
FileStorage | Scope | HttpClient>
>;
#### 🧿 Example
`typescript
import { FetchHttpClient } from '@effect/platform';
import { Effect, Layer, pipe } from 'effect';
import {
CloudflareR2StorageLayerLive,
FileStorageLayer,
} from 'effect-cloudflare-r2-layer';
type Buckets = 'assets' | 'config';
type JsonData = {
cool: boolean;
yolo: string;
};
const task = pipe(
pipe(
Effect.gen(function* () {
const json = yield* FileStorageLayer.readAsJson
'config',
'app-config.json'
);
// json is of type JsonData ...
}),
Effect.scoped,
Effect.provide(
Layer.mergeAll(CloudflareR2StorageLayerLive, FetchHttpClient.layer)
)
)
);
`
Fetches a file as a string.
`typescript`
readAsText:
bucketName: TBucket,
documentKey: string
) =>
Effect.Effect<
string,
ConfigError | HttpClientError | FileStorageError,
FileStorage | Scope | HttpClient
>;
#### 🧿 Example
`typescript
import { FetchHttpClient } from '@effect/platform';
import { Effect, Layer, pipe } from 'effect';
import {
CloudflareR2StorageLayerLive,
FileStorageLayer,
} from 'effect-cloudflare-r2-layer';
type Buckets = 'assets' | 'config';
const task = pipe(
pipe(
Effect.gen(function* () {
const text = yield* FileStorageLayer.readAsText
'assets',
'content.txt'
);
// ...
}),
Effect.scoped,
Effect.provide(
Layer.mergeAll(CloudflareR2StorageLayerLive, FetchHttpClient.layer)
)
)
);
`
Fetches a file as raw binary.
`typescript`
readAsRawBinary:
bucketName: TBucket,
documentKey: string
) =>
Effect.Effect<
ArrayBuffer,
ConfigError | HttpClientError | FileStorageError,
FileStorage | Scope | HttpClient
>;
#### 🧿 Example
`typescript
import { FetchHttpClient } from '@effect/platform';
import { FileSystem } from '@effect/platform/FileSystem';
import { Effect, Layer, pipe } from 'effect';
import {
CloudflareR2StorageLayerLive,
FileStorageLayer,
} from 'effect-cloudflare-r2-layer';
type Buckets = 'assets' | 'config';
const task = pipe(
pipe(
Effect.gen(function* () {
const buffer = yield* FileStorageLayer.readAsRawBinary
'assets',
'yolo.jpg'
);
const fs = yield* FileSystem;
const buffer = Buffer.from(data);
yield* fs.writeFile('./file.jpg', buffer);
}),
Effect.scoped,
Effect.provide(
Layer.mergeAll(CloudflareR2StorageLayerLive, FetchHttpClient.layer)
)
)
);
`
`typescript`
type fileExists =
bucket: TBucket,
fileName: string
) => Effect.Effect
#### 🧿 Example
`typescript
import { Effect, pipe } from 'effect';
import {
CloudflareR2StorageLayerLive,
FileStorageLayer,
} from 'effect-cloudflare-r2-layer';
type Bucket = 'assets' | 'config';
const filePath = 'my-app/config.json';
const task = pipe(
Effect.gen(function* () {
const exists = yield* FileStorageLayer.fileExists
'config',
filePath
);
// ...
}),
Effect.provide(CloudflareR2StorageLayerLive)
);
``