Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
effect-cloudflare-r2-layer
Advanced tools
An effect layer to interact with Cloudware R2 storage service
An effect layer to interact with Cloudware R2 storage service.
npm i effect-cloudflare-r2-layer
# or
pnpm i effect-cloudflare-r2-layer
# or
bun i effect-cloudflare-r2-layer
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:
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 |
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<string, unknown> . |
readAsText | Fetches a file as a string. |
readAsRawBinary | Fetches a file as raw binary (ArrayBuffer). |
createBucket
type createBucket = (
input: CreateBucketCommandInput
) => Effect.Effect<
CreateBucketCommandOutput,
FileStorageError | ConfigError.ConfigError,
FileStorage
>;
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)
);
bucketInfos
type BucketInfosInput<TBucket extends string> = {
Bucket: TBucket;
ExpectedBucketOwner?: string;
};
type BucketInfosResult = {
region?: string;
};
type bucketInfos = <TBucket extends string>(
input: BucketInfosInput<TBucket>
) => Effect.Effect<
BucketInfosResult,
ConfigError | FileStorageError | BucketNotFoundError,
FileStorage
>;
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<Buckets>({
Bucket: 'assets',
});
// ...
}),
Effect.provide(CloudflareR2StorageLayerLive)
);
uploadFile
Adds a file to the specified bucket.
interface UploadFileInput<TBucket extends string> {
bucketName: TBucket;
key: string;
data: Buffer;
contentType: string | undefined;
}
type uploadFile = <TBucket extends string>(
input: UploadFileInput<TBucket>
) => Effect.Effect<
PutObjectCommandOutput,
FileStorageError | ConfigError.ConfigError,
FileStorage
>;
import { Effect, pipe } from 'effect';
import {
CloudflareR2StorageLayerLive,
FileStorageLayer,
} from 'effect-cloudflare-r2-layer';
import { readFile } from 'fs-extra';
type Buckets = 'assets' | 'config';
const fileName = 'yolo.jpg';
const filePath = './assets/yolo.jpg';
const task = pipe(
Effect.gen(function* () {
const fileData = yield* Effect.tryPromise({
try: () => readFile(filePath),
catch: (e) => new FsError({ cause: e }),
});
yield* FileStorageLayer.uploadFile<Buckets>({
bucketName: 'assets',
documentKey: fileName,
data: fileData,
contentType: 'image/jpeg',
});
// ...
}),
Effect.provide(CloudflareR2StorageLayerLive);
);
getFileUrl
Gets a pre-signed url to fetch a ressource by its filename
from the specified bucket
.
type getFileUrl = <TBucket extends string>(
bucket: TBucket
fileName: string,
) => Effect.Effect<
string,
FileStorageError | ConfigError.ConfigError,
FileStorage
>;
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<Buckets>('assets', filename);
// ...
}),
Effect.provide(CloudflareR2StorageLayerLive);
);
readAsJson
Fetches a file, expecting a content extending Record<string, unknown>
.
type readAsJson = <
TBucket extends string,
TShape extends Record<string, unknown>
>(
bucket: TBucket,
fileName: string
) => Effect.Effect<
TShape,
HttpClientError | FileStorageError | ConfigError.ConfigError,
FileStorage | Scope | HttpClient<HttpClientError, Scope>
>;
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<Buckets, JsonData>(
'config',
'app-config.json'
);
// json is of type JsonData ...
}),
Effect.scoped,
Effect.provide(
Layer.mergeAll(CloudflareR2StorageLayerLive, FetchHttpClient.layer)
)
)
);
readAsText
Fetches a file as a string.
readAsText: <TBucket extends string>(
bucketName: TBucket,
documentKey: string
) =>
Effect.Effect<
string,
ConfigError | HttpClientError | FileStorageError,
FileStorage | Scope | HttpClient<HttpClientError, Scope>
>;
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<Buckets>(
'assets',
'content.txt'
);
// ...
}),
Effect.scoped,
Effect.provide(
Layer.mergeAll(CloudflareR2StorageLayerLive, FetchHttpClient.layer)
)
)
);
readAsRawBinary
Fetches a file as raw binary.
readAsRawBinary: <TBucket extends string>(
bucketName: TBucket,
documentKey: string
) =>
Effect.Effect<
ArrayBuffer,
ConfigError | HttpClientError | FileStorageError,
FileStorage | Scope | HttpClient<HttpClientError, Scope>
>;
import { FetchHttpClient } from '@effect/platform';
import { Effect, Layer, pipe } from 'effect';
import {
CloudflareR2StorageLayerLive,
FileStorageLayer,
} from 'effect-cloudflare-r2-layer';
import fs from 'fs-extra';
import { TaggedError } from 'effect/Data';
export class FsError extends TaggedError('FsError')<{
cause?: unknown;
}> {}
type Buckets = 'assets' | 'config';
const task = pipe(
pipe(
Effect.gen(function* () {
const buffer = yield* FileStorageLayer.readAsRawBinary<Buckets>(
'assets',
'yolo.jpg'
);
yield* Effect.tryPromise({
try: () =>
fs.writeFile('./file.jpg', Buffer.from(buffer), {
encoding: 'utf-8',
}),
catch: (e) => new FsError({ cause: e }),
});
}),
Effect.scoped,
Effect.provide(
Layer.mergeAll(CloudflareR2StorageLayerLive, FetchHttpClient.layer)
)
)
);
FAQs
An effect layer to interact with Cloudware R2 storage service
We found that effect-cloudflare-r2-layer demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.