effect-cloudflare-r2-layer 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +268 -0
  2. package/cjs/dts/effects/tapLayer.effect.d.ts +3 -0
  3. package/cjs/dts/errors/file-storage.error.d.ts +9 -0
  4. package/cjs/dts/index.d.ts +5 -0
  5. package/cjs/dts/layer/file-storage.layer.d.ts +22 -0
  6. package/cjs/dts/r2/implementations/get-file-url.effect.d.ts +2 -0
  7. package/cjs/dts/r2/implementations/get-url.effect.d.ts +4 -0
  8. package/cjs/dts/r2/implementations/index.d.ts +2 -0
  9. package/cjs/dts/r2/implementations/read-as-json.effect.d.ts +3 -0
  10. package/cjs/dts/r2/implementations/read-as-raw-binary.effect.d.ts +3 -0
  11. package/cjs/dts/r2/implementations/read-as-text.effect.d.ts +3 -0
  12. package/cjs/dts/r2/implementations/upload-file.effect.d.ts +9 -0
  13. package/cjs/dts/r2/providers/r2-file-storage.provider.d.ts +3 -0
  14. package/cjs/dts/r2/r2-file-storage.layer.d.ts +2 -0
  15. package/cjs/effects/tapLayer.effect.js +7 -0
  16. package/cjs/effects/tapLayer.effect.js.map +1 -0
  17. package/cjs/errors/file-storage.error.js +8 -0
  18. package/cjs/errors/file-storage.error.js.map +1 -0
  19. package/cjs/index.js +26 -0
  20. package/cjs/index.js.map +1 -0
  21. package/cjs/layer/file-storage.layer.js +14 -0
  22. package/cjs/layer/file-storage.layer.js.map +1 -0
  23. package/cjs/package.json +1 -0
  24. package/cjs/r2/implementations/get-file-url.effect.js +9 -0
  25. package/cjs/r2/implementations/get-file-url.effect.js.map +1 -0
  26. package/cjs/r2/implementations/get-url.effect.js +19 -0
  27. package/cjs/r2/implementations/get-url.effect.js.map +1 -0
  28. package/cjs/r2/implementations/index.js +19 -0
  29. package/cjs/r2/implementations/index.js.map +1 -0
  30. package/cjs/r2/implementations/read-as-json.effect.js +19 -0
  31. package/cjs/r2/implementations/read-as-json.effect.js.map +1 -0
  32. package/cjs/r2/implementations/read-as-raw-binary.effect.js +18 -0
  33. package/cjs/r2/implementations/read-as-raw-binary.effect.js.map +1 -0
  34. package/cjs/r2/implementations/read-as-text.effect.js +18 -0
  35. package/cjs/r2/implementations/read-as-text.effect.js.map +1 -0
  36. package/cjs/r2/implementations/upload-file.effect.js +20 -0
  37. package/cjs/r2/implementations/upload-file.effect.js.map +1 -0
  38. package/cjs/r2/providers/r2-file-storage.provider.js +23 -0
  39. package/cjs/r2/providers/r2-file-storage.provider.js.map +1 -0
  40. package/cjs/r2/r2-file-storage.layer.js +17 -0
  41. package/cjs/r2/r2-file-storage.layer.js.map +1 -0
  42. package/esm/dts/effects/tapLayer.effect.d.ts +3 -0
  43. package/esm/dts/errors/file-storage.error.d.ts +9 -0
  44. package/esm/dts/index.d.ts +5 -0
  45. package/esm/dts/layer/file-storage.layer.d.ts +22 -0
  46. package/esm/dts/r2/implementations/get-file-url.effect.d.ts +2 -0
  47. package/esm/dts/r2/implementations/get-url.effect.d.ts +4 -0
  48. package/esm/dts/r2/implementations/index.d.ts +2 -0
  49. package/esm/dts/r2/implementations/read-as-json.effect.d.ts +3 -0
  50. package/esm/dts/r2/implementations/read-as-raw-binary.effect.d.ts +3 -0
  51. package/esm/dts/r2/implementations/read-as-text.effect.d.ts +3 -0
  52. package/esm/dts/r2/implementations/upload-file.effect.d.ts +9 -0
  53. package/esm/dts/r2/providers/r2-file-storage.provider.d.ts +3 -0
  54. package/esm/dts/r2/r2-file-storage.layer.d.ts +2 -0
  55. package/esm/effects/tapLayer.effect.js +3 -0
  56. package/esm/effects/tapLayer.effect.js.map +1 -0
  57. package/esm/errors/file-storage.error.js +4 -0
  58. package/esm/errors/file-storage.error.js.map +1 -0
  59. package/esm/index.js +6 -0
  60. package/esm/index.js.map +1 -0
  61. package/esm/layer/file-storage.layer.js +11 -0
  62. package/esm/layer/file-storage.layer.js.map +1 -0
  63. package/esm/package.json +1 -0
  64. package/esm/r2/implementations/get-file-url.effect.js +5 -0
  65. package/esm/r2/implementations/get-file-url.effect.js.map +1 -0
  66. package/esm/r2/implementations/get-url.effect.js +15 -0
  67. package/esm/r2/implementations/get-url.effect.js.map +1 -0
  68. package/esm/r2/implementations/index.js +3 -0
  69. package/esm/r2/implementations/index.js.map +1 -0
  70. package/esm/r2/implementations/read-as-json.effect.js +15 -0
  71. package/esm/r2/implementations/read-as-json.effect.js.map +1 -0
  72. package/esm/r2/implementations/read-as-raw-binary.effect.js +14 -0
  73. package/esm/r2/implementations/read-as-raw-binary.effect.js.map +1 -0
  74. package/esm/r2/implementations/read-as-text.effect.js +14 -0
  75. package/esm/r2/implementations/read-as-text.effect.js.map +1 -0
  76. package/esm/r2/implementations/upload-file.effect.js +16 -0
  77. package/esm/r2/implementations/upload-file.effect.js.map +1 -0
  78. package/esm/r2/providers/r2-file-storage.provider.js +20 -0
  79. package/esm/r2/providers/r2-file-storage.provider.js.map +1 -0
  80. package/esm/r2/r2-file-storage.layer.js +14 -0
  81. package/esm/r2/r2-file-storage.layer.js.map +1 -0
  82. package/package.json +64 -0
package/README.md ADDED
@@ -0,0 +1,268 @@
1
+ # effect-cloudflare-r2-layer
2
+
3
+ An effect layer to interact with Cloudware R2 storage service.
4
+
5
+ <!-- readme-package-icons start -->
6
+
7
+ <p align="left"><a href="https://www.typescriptlang.org/docs/" target="_blank"><img height="50" src="https://raw.githubusercontent.com/jpb06/jpb06/master/icons/TypeScript.svg" /></a>&nbsp;<a href="https://nodejs.org/en/docs/" target="_blank"><img height="50" src="https://raw.githubusercontent.com/jpb06/jpb06/master/icons/NodeJS-Dark.svg" /></a>&nbsp;<a href="https://bun.sh/docs" target="_blank"><img height="50" src="https://raw.githubusercontent.com/jpb06/jpb06/master/icons/Bun-Dark.svg" /></a>&nbsp;<a href="https://aws.amazon.com/developer/language/javascript/" target="_blank"><img height="50" src="https://raw.githubusercontent.com/jpb06/jpb06/master/icons/AWS-Dark.svg" /></a>&nbsp;<a href="https://biomejs.dev/guides/getting-started/" target="_blank"><img height="50" src="https://raw.githubusercontent.com/jpb06/jpb06/master/icons/Biome-Dark.svg" /></a>&nbsp;<a href="https://github.com/motdotla/dotenv#readme" target="_blank"><img height="50" src="https://raw.githubusercontent.com/jpb06/jpb06/master/icons/Dotenv-Dark.svg" /></a>&nbsp;<a href="https://www.effect.website/docs/quickstart" target="_blank"><img height="50" src="https://raw.githubusercontent.com/jpb06/jpb06/master/icons/Effect-Dark.svg" /></a></p>
8
+
9
+ <!-- readme-package-icons end -->
10
+
11
+ ## ⚡ Env variables
12
+
13
+ The layer requires the following env variables:
14
+
15
+ ```env
16
+ CLOUDFLARE_ACCOUNT_ID=""
17
+ R2_DOCUMENTS_ACCESS_KEY_ID=""
18
+ R2_DOCUMENTS_SECRET_ACCESS_KEY=""
19
+ ```
20
+
21
+ ## ⚡ API
22
+
23
+ ### 🔶 `uploadFile`
24
+
25
+ Adds a file to the specified bucket.
26
+
27
+ ```typescript
28
+ interface UploadFileInput<TBucket extends string> {
29
+ bucketName: TBucket;
30
+ key: string;
31
+ data: Buffer;
32
+ contentType: string | undefined;
33
+ }
34
+
35
+ type uploadFile = <TBucket extends string>(
36
+ input: UploadFileInput<TBucket>
37
+ ) => Effect.Effect<
38
+ void,
39
+ FileStorageError | ConfigError.ConfigError,
40
+ FileStorage
41
+ >;
42
+ ```
43
+
44
+ #### 🧿 Example
45
+
46
+ ```typescript
47
+ import { Effect, pipe } from 'effect';
48
+ import {
49
+ CloudflareR2StorageLayerLive,
50
+ FileStorageLayer,
51
+ } from 'effect-cloudflare-r2-layer';
52
+ import { readFile } from 'fs-extra';
53
+
54
+ type Buckets = 'assets' | 'config';
55
+ const fileName = 'yolo.jpg';
56
+ const filePath = './assets/yolo.jpg';
57
+
58
+ const task = pipe(
59
+ Effect.gen(function* () {
60
+ const fileData = yield* Effect.tryPromise({
61
+ try: () => readFile(filePath),
62
+ catch: (e) => new FsError({ cause: e }),
63
+ });
64
+
65
+ yield* FileStorageLayer.uploadFile<Buckets>({
66
+ key: fileName,
67
+ bucketName: 'assets',
68
+ data: fileData,
69
+ contentType: 'image/jpeg',
70
+ });
71
+
72
+ // ...
73
+ }),
74
+ Effect.provide(CloudflareR2StorageLayerLive);
75
+ );
76
+ ```
77
+
78
+ ### 🔶 `getFileUrl`
79
+
80
+ Gets a pre-signed url to fetch a ressource by its `filename` from the specified `bucket`.
81
+
82
+ ```typescript
83
+ type getFileUrl = <TBucket extends string>(
84
+ bucket: TBucket
85
+ fileName: string,
86
+ ) => Effect.Effect<
87
+ string,
88
+ FileStorageError | ConfigError.ConfigError,
89
+ FileStorage
90
+ >;
91
+ ```
92
+
93
+ #### 🧿 Example
94
+
95
+ ```typescript
96
+ import { Effect, pipe } from 'effect';
97
+ import {
98
+ CloudflareR2StorageLayerLive,
99
+ FileStorageLayer,
100
+ } from 'effect-cloudflare-r2-layer';
101
+
102
+ type Buckets = 'assets' | 'config';
103
+ const filename = 'yolo.jpg';
104
+
105
+ const task = pipe(
106
+ Effect.gen(function* () {
107
+ const url = yield* FileStorageLayer.getFileUrl<Buckets>('assets', filename);
108
+
109
+ // ...
110
+ }),
111
+ Effect.provide(CloudflareR2StorageLayerLive);
112
+ );
113
+ ```
114
+
115
+ ### 🔶 `readAsJson`
116
+
117
+ Fetches a file, expecting a content extending `Record<string, unknown>`.
118
+
119
+ ```typescript
120
+ readAsJson: <TBucket extends string, TShape extends Record<string, unknown>>(
121
+ bucketName: TBucket,
122
+ documentKey: string
123
+ ) =>
124
+ Effect.Effect<
125
+ TShape,
126
+ ConfigError | HttpClientError | FileStorageError,
127
+ Scope | HttpClient.HttpClient.Service
128
+ >;
129
+ ```
130
+
131
+ #### 🧿 Example
132
+
133
+ ```typescript
134
+ import { FetchHttpClient } from '@effect/platform';
135
+ import { Effect, Layer, pipe } from 'effect';
136
+ import {
137
+ CloudflareR2StorageLayerLive,
138
+ FileStorageLayer,
139
+ } from 'effect-cloudflare-r2-layer';
140
+
141
+ type Buckets = 'assets' | 'config';
142
+
143
+ type JsonData = {
144
+ cool: boolean;
145
+ yolo: string;
146
+ };
147
+
148
+ const task = pipe(
149
+ pipe(
150
+ Effect.gen(function* () {
151
+ const json = yield* FileStorageLayer.readAsJson<Buckets, JsonData>(
152
+ 'config',
153
+ 'app-config.json'
154
+ );
155
+
156
+ // json is of type JsonData ...
157
+ }),
158
+ Effect.scoped,
159
+ Effect.provide(
160
+ Layer.mergeAll(CloudflareR2StorageLayerLive, FetchHttpClient.layer)
161
+ )
162
+ )
163
+ );
164
+ ```
165
+
166
+ ### 🔶 `readAsText`
167
+
168
+ Fetches a file as a string.
169
+
170
+ ```typescript
171
+ readAsText: <TBucket extends string>(
172
+ bucketName: TBucket,
173
+ documentKey: string
174
+ ) =>
175
+ Effect.Effect<
176
+ string,
177
+ ConfigError | HttpClientError | FileStorageError,
178
+ Scope | HttpClient.HttpClient.Service
179
+ >;
180
+ ```
181
+
182
+ #### 🧿 Example
183
+
184
+ ```typescript
185
+ import { FetchHttpClient } from '@effect/platform';
186
+ import { Effect, Layer, pipe } from 'effect';
187
+ import {
188
+ CloudflareR2StorageLayerLive,
189
+ FileStorageLayer,
190
+ } from 'effect-cloudflare-r2-layer';
191
+
192
+ type Buckets = 'assets' | 'config';
193
+
194
+ const task = pipe(
195
+ pipe(
196
+ Effect.gen(function* () {
197
+ const text = yield* FileStorageLayer.readAsText<Buckets>(
198
+ 'assets',
199
+ 'content.txt'
200
+ );
201
+
202
+ // ...
203
+ }),
204
+ Effect.scoped,
205
+ Effect.provide(
206
+ Layer.mergeAll(CloudflareR2StorageLayerLive, FetchHttpClient.layer)
207
+ )
208
+ )
209
+ );
210
+ ```
211
+
212
+ ### 🔶 `readAsRawBinary`
213
+
214
+ Fetches a file as raw binary.
215
+
216
+ ```typescript
217
+ readAsRawBinary: <TBucket extends string>(
218
+ bucketName: TBucket,
219
+ documentKey: string
220
+ ) =>
221
+ Effect.Effect<
222
+ ArrayBuffer,
223
+ ConfigError | HttpClientError | FileStorageError,
224
+ Scope | HttpClient.HttpClient.Service
225
+ >;
226
+ ```
227
+
228
+ #### 🧿 Example
229
+
230
+ ```typescript
231
+ import { FetchHttpClient } from '@effect/platform';
232
+ import { Effect, Layer, pipe } from 'effect';
233
+ import {
234
+ CloudflareR2StorageLayerLive,
235
+ FileStorageLayer,
236
+ } from 'effect-cloudflare-r2-layer';
237
+ import fs from 'fs-extra';
238
+ import { TaggedError } from 'effect/Data';
239
+
240
+ export class FsError extends TaggedError('FsError')<{
241
+ cause?: unknown;
242
+ }> {}
243
+
244
+ type Buckets = 'assets' | 'config';
245
+
246
+ const task = pipe(
247
+ pipe(
248
+ Effect.gen(function* () {
249
+ const buffer = yield* FileStorageLayer.readAsRawBinary<Buckets>(
250
+ 'assets',
251
+ 'yolo.jpg'
252
+ );
253
+
254
+ yield* Effect.tryPromise({
255
+ try: () =>
256
+ fs.writeFile('./file.jpg', Buffer.from(buffer), {
257
+ encoding: 'utf-8',
258
+ }),
259
+ catch: (e) => new FsError({ cause: e }),
260
+ });
261
+ }),
262
+ Effect.scoped,
263
+ Effect.provide(
264
+ Layer.mergeAll(CloudflareR2StorageLayerLive, FetchHttpClient.layer)
265
+ )
266
+ )
267
+ );
268
+ ```
@@ -0,0 +1,3 @@
1
+ import type { Context } from 'effect';
2
+ import { Effect } from 'effect';
3
+ export declare const tapLayer: <L, R, E, A>(context: Context.Tag<L, L>, effect: (layer: L) => Effect.Effect<R, E, A>) => Effect.Effect<R, E, L | A>;
@@ -0,0 +1,9 @@
1
+ declare const FileStorageError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
2
+ readonly _tag: "file-storage-error";
3
+ } & Readonly<A>;
4
+ export declare class FileStorageError extends FileStorageError_base<{
5
+ cause?: unknown;
6
+ message?: string;
7
+ }> {
8
+ }
9
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { FileStorage } from './layer/file-storage.layer.js';
2
+ import { FileStorageLayer } from './layer/file-storage.layer.js';
3
+ export { FileStorageLayer };
4
+ export type { FileStorage };
5
+ export * from './r2/r2-file-storage.layer.js';
@@ -0,0 +1,22 @@
1
+ import { HttpClientError } from '@effect/platform/HttpClientError';
2
+ import type { ConfigError, Effect } from 'effect';
3
+ import { Context } from 'effect';
4
+ import { HttpClient } from '@effect/platform';
5
+ import { Scope } from 'effect/Scope';
6
+ import type { FileStorageError } from '../errors/file-storage.error.js';
7
+ import type { UploadFileInput } from '../r2/implementations/upload-file.effect.js';
8
+ export interface FileStorage {
9
+ readonly getFileUrl: <TBucket extends string>(fileName: string, bucket: TBucket) => Effect.Effect<string, FileStorageError | ConfigError.ConfigError>;
10
+ readonly readAsRawBinary: <TBucket extends string>(bucketName: TBucket, documentKey: string) => Effect.Effect<ArrayBuffer, ConfigError.ConfigError | HttpClientError | FileStorageError, Scope | HttpClient.HttpClient.Service>;
11
+ readonly readAsJson: <TBucket extends string, TShape extends Record<string, unknown>>(bucketName: TBucket, documentKey: string) => Effect.Effect<TShape, ConfigError.ConfigError | HttpClientError | FileStorageError, Scope | HttpClient.HttpClient.Service>;
12
+ readonly readAsText: <TBucket extends string>(bucketName: TBucket, documentKey: string) => Effect.Effect<string, ConfigError.ConfigError | HttpClientError | FileStorageError, Scope | HttpClient.HttpClient.Service>;
13
+ readonly uploadFile: <TBucket extends string>(input: UploadFileInput<TBucket>) => Effect.Effect<void, FileStorageError | ConfigError.ConfigError>;
14
+ }
15
+ export declare const FileStorageLayerContext: Context.Tag<FileStorage, FileStorage>;
16
+ export declare const FileStorageLayer: {
17
+ getFileUrl: <TBucket extends string>(bucket: TBucket, fileName: string) => Effect.Effect<string, FileStorageError | ConfigError.ConfigError, FileStorage>;
18
+ readAsRawBinary: <TBucket extends string>(bucket: TBucket, fileName: string) => Effect.Effect<ArrayBuffer, FileStorageError | ConfigError.ConfigError | HttpClientError, FileStorage | Scope | HttpClient.HttpClient.Service>;
19
+ readAsJson: <TBucket extends string, TShape extends Record<string, unknown>>(bucket: TBucket, fileName: string) => Effect.Effect<TShape, FileStorageError | ConfigError.ConfigError | HttpClientError, FileStorage | Scope | HttpClient.HttpClient.Service>;
20
+ readAsText: <TBucket extends string>(bucket: TBucket, fileName: string) => Effect.Effect<string, FileStorageError | ConfigError.ConfigError | HttpClientError, FileStorage | Scope | HttpClient.HttpClient.Service>;
21
+ uploadFile: <TBucket extends string>(input: UploadFileInput<TBucket>) => Effect.Effect<void, FileStorageError | ConfigError.ConfigError, FileStorage>;
22
+ };
@@ -0,0 +1,2 @@
1
+ import { Effect } from 'effect';
2
+ export declare const getFileUrl: <TBucket extends string>(bucketName: TBucket, documentKey: string) => Effect.Effect<string, import("../../errors/file-storage.error.js").FileStorageError | import("effect/ConfigError").ConfigError, never>;
@@ -0,0 +1,4 @@
1
+ import type { S3Client } from '@aws-sdk/client-s3';
2
+ import { Effect } from 'effect';
3
+ import { FileStorageError } from '../../errors/file-storage.error.js';
4
+ export declare const getUrl: <TBucket extends string>(provider: S3Client, bucketName: TBucket, documentKey: TBucket) => Effect.Effect<string, FileStorageError, never>;
@@ -0,0 +1,2 @@
1
+ export * from './get-file-url.effect.js';
2
+ export * from './upload-file.effect.js';
@@ -0,0 +1,3 @@
1
+ import { HttpClient } from '@effect/platform';
2
+ import { Effect } from 'effect';
3
+ export declare const readAsJson: <TBucket extends string, TShape extends Record<string, unknown>>(bucketName: TBucket, documentKey: string) => Effect.Effect<TShape, import("../../errors/file-storage.error.js").FileStorageError | import("effect/ConfigError").ConfigError | import("@effect/platform/HttpClientError").HttpClientError, import("effect/Scope").Scope | HttpClient.HttpClient.Service>;
@@ -0,0 +1,3 @@
1
+ import { HttpClient } from '@effect/platform';
2
+ import { Effect } from 'effect';
3
+ export declare const readAsRawBinary: <TBucket extends string>(bucketName: TBucket, documentKey: string) => Effect.Effect<ArrayBuffer, import("../../errors/file-storage.error.js").FileStorageError | import("effect/ConfigError").ConfigError | import("@effect/platform/HttpClientError").HttpClientError, import("effect/Scope").Scope | HttpClient.HttpClient.Service>;
@@ -0,0 +1,3 @@
1
+ import { HttpClient } from '@effect/platform';
2
+ import { Effect } from 'effect';
3
+ export declare const readAsText: <TBucket extends string>(bucketName: TBucket, documentKey: string) => Effect.Effect<string, import("../../errors/file-storage.error.js").FileStorageError | import("effect/ConfigError").ConfigError | import("@effect/platform/HttpClientError").HttpClientError, import("effect/Scope").Scope | HttpClient.HttpClient.Service>;
@@ -0,0 +1,9 @@
1
+ import { Effect } from 'effect';
2
+ import { FileStorageError } from '../../errors/file-storage.error.js';
3
+ export interface UploadFileInput<TBucket extends string> {
4
+ bucketName: TBucket;
5
+ key: string;
6
+ data: Buffer;
7
+ contentType: string | undefined;
8
+ }
9
+ export declare const uploadFile: <TBucket extends string>({ bucketName, key, data, contentType, }: UploadFileInput<TBucket>) => Effect.Effect<import("@aws-sdk/client-s3").PutObjectCommandOutput, FileStorageError | import("effect/ConfigError").ConfigError, never>;
@@ -0,0 +1,3 @@
1
+ import { S3Client } from '@aws-sdk/client-s3';
2
+ import { Effect } from 'effect';
3
+ export declare const cloudflareR2StorageProvider: Effect.Effect<S3Client, import("effect/ConfigError").ConfigError, never>;
@@ -0,0 +1,2 @@
1
+ import { Layer } from 'effect';
2
+ export declare const CloudflareR2StorageLayerLive: Layer.Layer<import("../layer/file-storage.layer.js").FileStorage, never, never>;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tapLayer = void 0;
4
+ const effect_1 = require("effect");
5
+ const tapLayer = (context, effect) => (0, effect_1.pipe)(context, effect_1.Effect.flatMap(effect));
6
+ exports.tapLayer = tapLayer;
7
+ //# sourceMappingURL=tapLayer.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tapLayer.effect.js","sourceRoot":"","sources":["../../../src/effects/tapLayer.effect.ts"],"names":[],"mappings":";;;AACA,mCAAsC;AAE/B,MAAM,QAAQ,GAAG,CACtB,OAA0B,EAC1B,MAA4C,EAC5C,EAAE,CAAC,IAAA,aAAI,EAAC,OAAO,EAAE,eAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AAH9B,QAAA,QAAQ,YAGsB"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FileStorageError = void 0;
4
+ const Data_1 = require("effect/Data");
5
+ class FileStorageError extends (0, Data_1.TaggedError)('file-storage-error') {
6
+ }
7
+ exports.FileStorageError = FileStorageError;
8
+ //# sourceMappingURL=file-storage.error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-storage.error.js","sourceRoot":"","sources":["../../../src/errors/file-storage.error.ts"],"names":[],"mappings":";;;AAAA,sCAA0C;AAE1C,MAAa,gBAAiB,SAAQ,IAAA,kBAAW,EAAC,oBAAoB,CAGpE;CAAG;AAHL,4CAGK"}
package/cjs/index.js ADDED
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.FileStorageLayer = void 0;
21
+ const dotenv_1 = __importDefault(require("dotenv"));
22
+ dotenv_1.default.config();
23
+ const file_storage_layer_js_1 = require("./layer/file-storage.layer.js");
24
+ Object.defineProperty(exports, "FileStorageLayer", { enumerable: true, get: function () { return file_storage_layer_js_1.FileStorageLayer; } });
25
+ __exportStar(require("./r2/r2-file-storage.layer.js"), exports);
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,oDAA4B;AAC5B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAGhB,yEAAiE;AAExD,iGAFA,wCAAgB,OAEA;AAEzB,gEAA8C"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FileStorageLayer = exports.FileStorageLayerContext = void 0;
4
+ const effect_1 = require("effect");
5
+ const tapLayer_effect_js_1 = require("./../effects/tapLayer.effect.js");
6
+ exports.FileStorageLayerContext = effect_1.Context.GenericTag('file-storage');
7
+ exports.FileStorageLayer = {
8
+ getFileUrl: (bucket, fileName) => (0, tapLayer_effect_js_1.tapLayer)(exports.FileStorageLayerContext, ({ getFileUrl }) => getFileUrl(bucket, fileName)),
9
+ readAsRawBinary: (bucket, fileName) => (0, tapLayer_effect_js_1.tapLayer)(exports.FileStorageLayerContext, ({ readAsRawBinary }) => readAsRawBinary(bucket, fileName)),
10
+ readAsJson: (bucket, fileName) => (0, tapLayer_effect_js_1.tapLayer)(exports.FileStorageLayerContext, ({ readAsJson }) => readAsJson(bucket, fileName)),
11
+ readAsText: (bucket, fileName) => (0, tapLayer_effect_js_1.tapLayer)(exports.FileStorageLayerContext, ({ readAsText }) => readAsText(bucket, fileName)),
12
+ uploadFile: (input) => (0, tapLayer_effect_js_1.tapLayer)(exports.FileStorageLayerContext, ({ uploadFile }) => uploadFile(input)),
13
+ };
14
+ //# sourceMappingURL=file-storage.layer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-storage.layer.js","sourceRoot":"","sources":["../../../src/layer/file-storage.layer.ts"],"names":[],"mappings":";;;AAEA,mCAAiC;AAMjC,wEAA2D;AAuC9C,QAAA,uBAAuB,GAClC,gBAAO,CAAC,UAAU,CAAc,cAAc,CAAC,CAAC;AAErC,QAAA,gBAAgB,GAAG;IAC9B,UAAU,EAAE,CAAyB,MAAe,EAAE,QAAgB,EAAE,EAAE,CACxE,IAAA,6BAAQ,EAAC,+BAAuB,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CACnD,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAC7B;IACH,eAAe,EAAE,CACf,MAAe,EACf,QAAgB,EAChB,EAAE,CACF,IAAA,6BAAQ,EAAC,+BAAuB,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE,CACxD,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAClC;IACH,UAAU,EAAE,CACV,MAAe,EACf,QAAgB,EAChB,EAAE,CACF,IAAA,6BAAQ,EAAC,+BAAuB,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CACnD,UAAU,CAAkB,MAAM,EAAE,QAAQ,CAAC,CAC9C;IACH,UAAU,EAAE,CAAyB,MAAe,EAAE,QAAgB,EAAE,EAAE,CACxE,IAAA,6BAAQ,EAAC,+BAAuB,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CACnD,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAC7B;IACH,UAAU,EAAE,CAAyB,KAA+B,EAAE,EAAE,CACtE,IAAA,6BAAQ,EAAC,+BAAuB,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;CAC3E,CAAC"}
@@ -0,0 +1 @@
1
+ {"type": "commonjs"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFileUrl = void 0;
4
+ const effect_1 = require("effect");
5
+ const r2_file_storage_provider_js_1 = require("../providers/r2-file-storage.provider.js");
6
+ const get_url_effect_js_1 = require("./get-url.effect.js");
7
+ const getFileUrl = (bucketName, documentKey) => effect_1.Effect.withSpan('get-file-url', { attributes: { bucketName, documentKey } })((0, effect_1.pipe)(r2_file_storage_provider_js_1.cloudflareR2StorageProvider, effect_1.Effect.flatMap((provider) => (0, get_url_effect_js_1.getUrl)(provider, bucketName, documentKey))));
8
+ exports.getFileUrl = getFileUrl;
9
+ //# sourceMappingURL=get-file-url.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-file-url.effect.js","sourceRoot":"","sources":["../../../../src/r2/implementations/get-file-url.effect.ts"],"names":[],"mappings":";;;AAAA,mCAAsC;AAEtC,0FAAuF;AACvF,2DAA6C;AAEtC,MAAM,UAAU,GAAG,CACxB,UAAmB,EACnB,WAAmB,EACnB,EAAE,CACF,eAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,CAAC,CAC1E,IAAA,aAAI,EACF,yDAA2B,EAC3B,eAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAA,0BAAM,EAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CACxE,CACF,CAAC;AATS,QAAA,UAAU,cASnB"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getUrl = void 0;
4
+ const client_s3_1 = require("@aws-sdk/client-s3");
5
+ const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
6
+ const effect_1 = require("effect");
7
+ const file_storage_error_js_1 = require("../../errors/file-storage.error.js");
8
+ const oneHourDuration = 60 * 60;
9
+ const getUrl = (provider, bucketName, documentKey) => effect_1.Effect.withSpan('get-url', { attributes: { bucketName, documentKey } })(effect_1.Effect.tryPromise({
10
+ try: () => (0, s3_request_presigner_1.getSignedUrl)(provider, new client_s3_1.GetObjectCommand({
11
+ Bucket: bucketName,
12
+ Key: documentKey,
13
+ }), {
14
+ expiresIn: oneHourDuration,
15
+ }),
16
+ catch: (e) => new file_storage_error_js_1.FileStorageError({ cause: e }),
17
+ }));
18
+ exports.getUrl = getUrl;
19
+ //# sourceMappingURL=get-url.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-url.effect.js","sourceRoot":"","sources":["../../../../src/r2/implementations/get-url.effect.ts"],"names":[],"mappings":";;;AACA,kDAAsD;AACtD,wEAAgF;AAChF,mCAAgC;AAEhC,8EAAsE;AAEtE,MAAM,eAAe,GAAG,EAAE,GAAG,EAAE,CAAC;AAEzB,MAAM,MAAM,GAAG,CACpB,QAAkB,EAClB,UAAmB,EACnB,WAAoB,EACpB,EAAE,CACF,eAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,CAAC,CACrE,eAAM,CAAC,UAAU,CAAC;IAChB,GAAG,EAAE,GAAG,EAAE,CACR,IAAA,mCAAe,EACb,QAAQ,EACR,IAAI,4BAAgB,CAAC;QACnB,MAAM,EAAE,UAAU;QAClB,GAAG,EAAE,WAAW;KACjB,CAAC,EACF;QACE,SAAS,EAAE,eAAe;KAC3B,CACF;IACH,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,wCAAgB,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;CACjD,CAAC,CACH,CAAC;AApBS,QAAA,MAAM,UAoBf"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./get-file-url.effect.js"), exports);
18
+ __exportStar(require("./upload-file.effect.js"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/r2/implementations/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2DAAyC;AACzC,0DAAwC"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readAsJson = void 0;
4
+ const platform_1 = require("@effect/platform");
5
+ const effect_1 = require("effect");
6
+ const r2_file_storage_provider_js_1 = require("../providers/r2-file-storage.provider.js");
7
+ const get_url_effect_js_1 = require("./get-url.effect.js");
8
+ const readAsJson = (bucketName, documentKey) => effect_1.Effect.withSpan('read-as-json', {
9
+ attributes: { bucketName, documentKey },
10
+ })(effect_1.Effect.gen(function* () {
11
+ const provider = yield* r2_file_storage_provider_js_1.cloudflareR2StorageProvider;
12
+ const url = yield* (0, get_url_effect_js_1.getUrl)(provider, bucketName, documentKey);
13
+ const client = yield* platform_1.HttpClient.HttpClient;
14
+ const response = yield* client.get(url);
15
+ const json = yield* response.json;
16
+ return json;
17
+ }));
18
+ exports.readAsJson = readAsJson;
19
+ //# sourceMappingURL=read-as-json.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-as-json.effect.js","sourceRoot":"","sources":["../../../../src/r2/implementations/read-as-json.effect.ts"],"names":[],"mappings":";;;AAAA,+CAA8C;AAC9C,mCAAgC;AAEhC,0FAAuF;AACvF,2DAA6C;AAEtC,MAAM,UAAU,GAAG,CAIxB,UAAmB,EACnB,WAAmB,EACnB,EAAE,CACF,eAAM,CAAC,QAAQ,CAAC,cAAc,EAAE;IAC9B,UAAU,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE;CACxC,CAAC,CACA,eAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,yDAA2B,CAAC;IACpD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,IAAA,0BAAM,EAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,qBAAU,CAAC,UAAU,CAAC;IAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAExC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;IAElC,OAAO,IAAc,CAAC;AACxB,CAAC,CAAC,CACH,CAAC;AArBS,QAAA,UAAU,cAqBnB"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readAsRawBinary = void 0;
4
+ const platform_1 = require("@effect/platform");
5
+ const effect_1 = require("effect");
6
+ const r2_file_storage_provider_js_1 = require("../providers/r2-file-storage.provider.js");
7
+ const get_url_effect_js_1 = require("./get-url.effect.js");
8
+ const readAsRawBinary = (bucketName, documentKey) => effect_1.Effect.withSpan('read-as-raw-binary', {
9
+ attributes: { bucketName, documentKey },
10
+ })(effect_1.Effect.gen(function* () {
11
+ const provider = yield* r2_file_storage_provider_js_1.cloudflareR2StorageProvider;
12
+ const url = yield* (0, get_url_effect_js_1.getUrl)(provider, bucketName, documentKey);
13
+ const client = yield* platform_1.HttpClient.HttpClient;
14
+ const response = yield* client.get(url);
15
+ return yield* response.arrayBuffer;
16
+ }));
17
+ exports.readAsRawBinary = readAsRawBinary;
18
+ //# sourceMappingURL=read-as-raw-binary.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-as-raw-binary.effect.js","sourceRoot":"","sources":["../../../../src/r2/implementations/read-as-raw-binary.effect.ts"],"names":[],"mappings":";;;AAAA,+CAA8C;AAC9C,mCAAgC;AAEhC,0FAAuF;AACvF,2DAA6C;AAEtC,MAAM,eAAe,GAAG,CAC7B,UAAmB,EACnB,WAAmB,EACnB,EAAE,CACF,eAAM,CAAC,QAAQ,CAAC,oBAAoB,EAAE;IACpC,UAAU,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE;CACxC,CAAC,CACA,eAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,yDAA2B,CAAC;IACpD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,IAAA,0BAAM,EAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,qBAAU,CAAC,UAAU,CAAC;IAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAExC,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;AACrC,CAAC,CAAC,CACH,CAAC;AAhBS,QAAA,eAAe,mBAgBxB"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readAsText = void 0;
4
+ const platform_1 = require("@effect/platform");
5
+ const effect_1 = require("effect");
6
+ const r2_file_storage_provider_js_1 = require("../providers/r2-file-storage.provider.js");
7
+ const get_url_effect_js_1 = require("./get-url.effect.js");
8
+ const readAsText = (bucketName, documentKey) => effect_1.Effect.withSpan('read-as-text', {
9
+ attributes: { bucketName, documentKey },
10
+ })(effect_1.Effect.gen(function* () {
11
+ const provider = yield* r2_file_storage_provider_js_1.cloudflareR2StorageProvider;
12
+ const url = yield* (0, get_url_effect_js_1.getUrl)(provider, bucketName, documentKey);
13
+ const client = yield* platform_1.HttpClient.HttpClient;
14
+ const response = yield* client.get(url);
15
+ return yield* response.text;
16
+ }));
17
+ exports.readAsText = readAsText;
18
+ //# sourceMappingURL=read-as-text.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-as-text.effect.js","sourceRoot":"","sources":["../../../../src/r2/implementations/read-as-text.effect.ts"],"names":[],"mappings":";;;AAAA,+CAA8C;AAC9C,mCAAgC;AAEhC,0FAAuF;AACvF,2DAA6C;AAEtC,MAAM,UAAU,GAAG,CACxB,UAAmB,EACnB,WAAmB,EACnB,EAAE,CACF,eAAM,CAAC,QAAQ,CAAC,cAAc,EAAE;IAC9B,UAAU,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE;CACxC,CAAC,CACA,eAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,yDAA2B,CAAC;IACpD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,IAAA,0BAAM,EAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,qBAAU,CAAC,UAAU,CAAC;IAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAExC,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC9B,CAAC,CAAC,CACH,CAAC;AAhBS,QAAA,UAAU,cAgBnB"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uploadFile = void 0;
4
+ const client_s3_1 = require("@aws-sdk/client-s3");
5
+ const effect_1 = require("effect");
6
+ const file_storage_error_js_1 = require("../../errors/file-storage.error.js");
7
+ const r2_file_storage_provider_js_1 = require("../providers/r2-file-storage.provider.js");
8
+ const uploadFile = ({ bucketName, key, data, contentType, }) => effect_1.Effect.withSpan('upload-file', {
9
+ attributes: { bucketName, key, contentType },
10
+ })((0, effect_1.pipe)(r2_file_storage_provider_js_1.cloudflareR2StorageProvider, effect_1.Effect.flatMap((provider) => effect_1.Effect.tryPromise({
11
+ try: () => provider.send(new client_s3_1.PutObjectCommand({
12
+ Body: data,
13
+ ContentType: contentType,
14
+ Key: key,
15
+ Bucket: bucketName,
16
+ })),
17
+ catch: (e) => new file_storage_error_js_1.FileStorageError({ cause: e }),
18
+ }))));
19
+ exports.uploadFile = uploadFile;
20
+ //# sourceMappingURL=upload-file.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-file.effect.js","sourceRoot":"","sources":["../../../../src/r2/implementations/upload-file.effect.ts"],"names":[],"mappings":";;;AAAA,kDAAsD;AACtD,mCAAsC;AAEtC,8EAAsE;AACtE,0FAAuF;AAShF,MAAM,UAAU,GAAG,CAAyB,EACjD,UAAU,EACV,GAAG,EACH,IAAI,EACJ,WAAW,GACc,EAAE,EAAE,CAC7B,eAAM,CAAC,QAAQ,CAAC,aAAa,EAAE;IAC7B,UAAU,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,WAAW,EAAE;CAC7C,CAAC,CACA,IAAA,aAAI,EACF,yDAA2B,EAC3B,eAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC1B,eAAM,CAAC,UAAU,CAAC;IAChB,GAAG,EAAE,GAAG,EAAE,CACR,QAAQ,CAAC,IAAI,CACX,IAAI,4BAAgB,CAAC;QACnB,IAAI,EAAE,IAAI;QACV,WAAW,EAAE,WAAqB;QAClC,GAAG,EAAE,GAAG;QACR,MAAM,EAAE,UAAU;KACnB,CAAC,CACH;IACH,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,wCAAgB,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;CACjD,CAAC,CACH,CACF,CACF,CAAC;AA1BS,QAAA,UAAU,cA0BnB"}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cloudflareR2StorageProvider = void 0;
4
+ const client_s3_1 = require("@aws-sdk/client-s3");
5
+ const effect_1 = require("effect");
6
+ const getR2Config = (0, effect_1.pipe)(effect_1.Effect.all([
7
+ effect_1.Config.string('CLOUDFLARE_ACCOUNT_ID'),
8
+ effect_1.Config.string('R2_DOCUMENTS_ACCESS_KEY_ID'),
9
+ effect_1.Config.string('R2_DOCUMENTS_SECRET_ACCESS_KEY'),
10
+ ]), effect_1.Effect.map(([cloudflareAccountId, accessKeyId, secretAccessKey]) => ({
11
+ cloudflareAccountId,
12
+ accessKeyId,
13
+ secretAccessKey,
14
+ })));
15
+ exports.cloudflareR2StorageProvider = (0, effect_1.pipe)(getR2Config, effect_1.Effect.flatMap((config) => effect_1.Effect.succeed(new client_s3_1.S3Client({
16
+ region: 'auto',
17
+ endpoint: `https://${config.cloudflareAccountId}.r2.cloudflarestorage.com`,
18
+ credentials: {
19
+ accessKeyId: config.accessKeyId,
20
+ secretAccessKey: config.secretAccessKey,
21
+ },
22
+ }))));
23
+ //# sourceMappingURL=r2-file-storage.provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2-file-storage.provider.js","sourceRoot":"","sources":["../../../../src/r2/providers/r2-file-storage.provider.ts"],"names":[],"mappings":";;;AAAA,kDAA8C;AAC9C,mCAA8C;AAE9C,MAAM,WAAW,GAAG,IAAA,aAAI,EACtB,eAAM,CAAC,GAAG,CAAC;IACT,eAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC;IACtC,eAAM,CAAC,MAAM,CAAC,4BAA4B,CAAC;IAC3C,eAAM,CAAC,MAAM,CAAC,gCAAgC,CAAC;CAChD,CAAC,EACF,eAAM,CAAC,GAAG,CAAC,CAAC,CAAC,mBAAmB,EAAE,WAAW,EAAE,eAAe,CAAC,EAAE,EAAE,CAAC,CAAC;IACnE,mBAAmB;IACnB,WAAW;IACX,eAAe;CAChB,CAAC,CAAC,CACJ,CAAC;AAEW,QAAA,2BAA2B,GAAG,IAAA,aAAI,EAC7C,WAAW,EACX,eAAM,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CACxB,eAAM,CAAC,OAAO,CACZ,IAAI,oBAAQ,CAAC;IACX,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,WAAW,MAAM,CAAC,mBAAmB,2BAA2B;IAC1E,WAAW,EAAE;QACX,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,eAAe,EAAE,MAAM,CAAC,eAAe;KACxC;CACF,CAAC,CACH,CACF,CACF,CAAC"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CloudflareR2StorageLayerLive = void 0;
4
+ const effect_1 = require("effect");
5
+ const file_storage_layer_js_1 = require("../layer/file-storage.layer.js");
6
+ const index_js_1 = require("./implementations/index.js");
7
+ const read_as_json_effect_js_1 = require("./implementations/read-as-json.effect.js");
8
+ const read_as_raw_binary_effect_js_1 = require("./implementations/read-as-raw-binary.effect.js");
9
+ const read_as_text_effect_js_1 = require("./implementations/read-as-text.effect.js");
10
+ exports.CloudflareR2StorageLayerLive = effect_1.Layer.succeed(file_storage_layer_js_1.FileStorageLayerContext, file_storage_layer_js_1.FileStorageLayerContext.of({
11
+ getFileUrl: index_js_1.getFileUrl,
12
+ uploadFile: index_js_1.uploadFile,
13
+ readAsText: read_as_text_effect_js_1.readAsText,
14
+ readAsJson: read_as_json_effect_js_1.readAsJson,
15
+ readAsRawBinary: read_as_raw_binary_effect_js_1.readAsRawBinary,
16
+ }));
17
+ //# sourceMappingURL=r2-file-storage.layer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2-file-storage.layer.js","sourceRoot":"","sources":["../../../src/r2/r2-file-storage.layer.ts"],"names":[],"mappings":";;;AAAA,mCAA+B;AAE/B,0EAAyE;AACzE,yDAAoE;AACpE,qFAAsE;AACtE,iGAAiF;AACjF,qFAAsE;AAEzD,QAAA,4BAA4B,GAAG,cAAK,CAAC,OAAO,CACvD,+CAAuB,EACvB,+CAAuB,CAAC,EAAE,CAAC;IACzB,UAAU,EAAV,qBAAU;IACV,UAAU,EAAV,qBAAU;IACV,UAAU,EAAV,mCAAU;IACV,UAAU,EAAV,mCAAU;IACV,eAAe,EAAf,8CAAe;CAChB,CAAC,CACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Context } from 'effect';
2
+ import { Effect } from 'effect';
3
+ export declare const tapLayer: <L, R, E, A>(context: Context.Tag<L, L>, effect: (layer: L) => Effect.Effect<R, E, A>) => Effect.Effect<R, E, L | A>;
@@ -0,0 +1,9 @@
1
+ declare const FileStorageError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
2
+ readonly _tag: "file-storage-error";
3
+ } & Readonly<A>;
4
+ export declare class FileStorageError extends FileStorageError_base<{
5
+ cause?: unknown;
6
+ message?: string;
7
+ }> {
8
+ }
9
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { FileStorage } from './layer/file-storage.layer.js';
2
+ import { FileStorageLayer } from './layer/file-storage.layer.js';
3
+ export { FileStorageLayer };
4
+ export type { FileStorage };
5
+ export * from './r2/r2-file-storage.layer.js';
@@ -0,0 +1,22 @@
1
+ import { HttpClientError } from '@effect/platform/HttpClientError';
2
+ import type { ConfigError, Effect } from 'effect';
3
+ import { Context } from 'effect';
4
+ import { HttpClient } from '@effect/platform';
5
+ import { Scope } from 'effect/Scope';
6
+ import type { FileStorageError } from '../errors/file-storage.error.js';
7
+ import type { UploadFileInput } from '../r2/implementations/upload-file.effect.js';
8
+ export interface FileStorage {
9
+ readonly getFileUrl: <TBucket extends string>(fileName: string, bucket: TBucket) => Effect.Effect<string, FileStorageError | ConfigError.ConfigError>;
10
+ readonly readAsRawBinary: <TBucket extends string>(bucketName: TBucket, documentKey: string) => Effect.Effect<ArrayBuffer, ConfigError.ConfigError | HttpClientError | FileStorageError, Scope | HttpClient.HttpClient.Service>;
11
+ readonly readAsJson: <TBucket extends string, TShape extends Record<string, unknown>>(bucketName: TBucket, documentKey: string) => Effect.Effect<TShape, ConfigError.ConfigError | HttpClientError | FileStorageError, Scope | HttpClient.HttpClient.Service>;
12
+ readonly readAsText: <TBucket extends string>(bucketName: TBucket, documentKey: string) => Effect.Effect<string, ConfigError.ConfigError | HttpClientError | FileStorageError, Scope | HttpClient.HttpClient.Service>;
13
+ readonly uploadFile: <TBucket extends string>(input: UploadFileInput<TBucket>) => Effect.Effect<void, FileStorageError | ConfigError.ConfigError>;
14
+ }
15
+ export declare const FileStorageLayerContext: Context.Tag<FileStorage, FileStorage>;
16
+ export declare const FileStorageLayer: {
17
+ getFileUrl: <TBucket extends string>(bucket: TBucket, fileName: string) => Effect.Effect<string, FileStorageError | ConfigError.ConfigError, FileStorage>;
18
+ readAsRawBinary: <TBucket extends string>(bucket: TBucket, fileName: string) => Effect.Effect<ArrayBuffer, FileStorageError | ConfigError.ConfigError | HttpClientError, FileStorage | Scope | HttpClient.HttpClient.Service>;
19
+ readAsJson: <TBucket extends string, TShape extends Record<string, unknown>>(bucket: TBucket, fileName: string) => Effect.Effect<TShape, FileStorageError | ConfigError.ConfigError | HttpClientError, FileStorage | Scope | HttpClient.HttpClient.Service>;
20
+ readAsText: <TBucket extends string>(bucket: TBucket, fileName: string) => Effect.Effect<string, FileStorageError | ConfigError.ConfigError | HttpClientError, FileStorage | Scope | HttpClient.HttpClient.Service>;
21
+ uploadFile: <TBucket extends string>(input: UploadFileInput<TBucket>) => Effect.Effect<void, FileStorageError | ConfigError.ConfigError, FileStorage>;
22
+ };
@@ -0,0 +1,2 @@
1
+ import { Effect } from 'effect';
2
+ export declare const getFileUrl: <TBucket extends string>(bucketName: TBucket, documentKey: string) => Effect.Effect<string, import("../../errors/file-storage.error.js").FileStorageError | import("effect/ConfigError").ConfigError, never>;
@@ -0,0 +1,4 @@
1
+ import type { S3Client } from '@aws-sdk/client-s3';
2
+ import { Effect } from 'effect';
3
+ import { FileStorageError } from '../../errors/file-storage.error.js';
4
+ export declare const getUrl: <TBucket extends string>(provider: S3Client, bucketName: TBucket, documentKey: TBucket) => Effect.Effect<string, FileStorageError, never>;
@@ -0,0 +1,2 @@
1
+ export * from './get-file-url.effect.js';
2
+ export * from './upload-file.effect.js';
@@ -0,0 +1,3 @@
1
+ import { HttpClient } from '@effect/platform';
2
+ import { Effect } from 'effect';
3
+ export declare const readAsJson: <TBucket extends string, TShape extends Record<string, unknown>>(bucketName: TBucket, documentKey: string) => Effect.Effect<TShape, import("../../errors/file-storage.error.js").FileStorageError | import("effect/ConfigError").ConfigError | import("@effect/platform/HttpClientError").HttpClientError, import("effect/Scope").Scope | HttpClient.HttpClient.Service>;
@@ -0,0 +1,3 @@
1
+ import { HttpClient } from '@effect/platform';
2
+ import { Effect } from 'effect';
3
+ export declare const readAsRawBinary: <TBucket extends string>(bucketName: TBucket, documentKey: string) => Effect.Effect<ArrayBuffer, import("../../errors/file-storage.error.js").FileStorageError | import("effect/ConfigError").ConfigError | import("@effect/platform/HttpClientError").HttpClientError, import("effect/Scope").Scope | HttpClient.HttpClient.Service>;
@@ -0,0 +1,3 @@
1
+ import { HttpClient } from '@effect/platform';
2
+ import { Effect } from 'effect';
3
+ export declare const readAsText: <TBucket extends string>(bucketName: TBucket, documentKey: string) => Effect.Effect<string, import("../../errors/file-storage.error.js").FileStorageError | import("effect/ConfigError").ConfigError | import("@effect/platform/HttpClientError").HttpClientError, import("effect/Scope").Scope | HttpClient.HttpClient.Service>;
@@ -0,0 +1,9 @@
1
+ import { Effect } from 'effect';
2
+ import { FileStorageError } from '../../errors/file-storage.error.js';
3
+ export interface UploadFileInput<TBucket extends string> {
4
+ bucketName: TBucket;
5
+ key: string;
6
+ data: Buffer;
7
+ contentType: string | undefined;
8
+ }
9
+ export declare const uploadFile: <TBucket extends string>({ bucketName, key, data, contentType, }: UploadFileInput<TBucket>) => Effect.Effect<import("@aws-sdk/client-s3").PutObjectCommandOutput, FileStorageError | import("effect/ConfigError").ConfigError, never>;
@@ -0,0 +1,3 @@
1
+ import { S3Client } from '@aws-sdk/client-s3';
2
+ import { Effect } from 'effect';
3
+ export declare const cloudflareR2StorageProvider: Effect.Effect<S3Client, import("effect/ConfigError").ConfigError, never>;
@@ -0,0 +1,2 @@
1
+ import { Layer } from 'effect';
2
+ export declare const CloudflareR2StorageLayerLive: Layer.Layer<import("../layer/file-storage.layer.js").FileStorage, never, never>;
@@ -0,0 +1,3 @@
1
+ import { Effect, pipe } from 'effect';
2
+ export const tapLayer = (context, effect) => pipe(context, Effect.flatMap(effect));
3
+ //# sourceMappingURL=tapLayer.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tapLayer.effect.js","sourceRoot":"","sources":["../../../src/effects/tapLayer.effect.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEtC,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,OAA0B,EAC1B,MAA4C,EAC5C,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { TaggedError } from 'effect/Data';
2
+ export class FileStorageError extends TaggedError('file-storage-error') {
3
+ }
4
+ //# sourceMappingURL=file-storage.error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-storage.error.js","sourceRoot":"","sources":["../../../src/errors/file-storage.error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,OAAO,gBAAiB,SAAQ,WAAW,CAAC,oBAAoB,CAGpE;CAAG"}
package/esm/index.js ADDED
@@ -0,0 +1,6 @@
1
+ import dotenv from 'dotenv';
2
+ dotenv.config();
3
+ import { FileStorageLayer } from './layer/file-storage.layer.js';
4
+ export { FileStorageLayer };
5
+ export * from './r2/r2-file-storage.layer.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,MAAM,CAAC,MAAM,EAAE,CAAC;AAGhB,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEjE,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAE5B,cAAc,+BAA+B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Context } from 'effect';
2
+ import { tapLayer } from './../effects/tapLayer.effect.js';
3
+ export const FileStorageLayerContext = Context.GenericTag('file-storage');
4
+ export const FileStorageLayer = {
5
+ getFileUrl: (bucket, fileName) => tapLayer(FileStorageLayerContext, ({ getFileUrl }) => getFileUrl(bucket, fileName)),
6
+ readAsRawBinary: (bucket, fileName) => tapLayer(FileStorageLayerContext, ({ readAsRawBinary }) => readAsRawBinary(bucket, fileName)),
7
+ readAsJson: (bucket, fileName) => tapLayer(FileStorageLayerContext, ({ readAsJson }) => readAsJson(bucket, fileName)),
8
+ readAsText: (bucket, fileName) => tapLayer(FileStorageLayerContext, ({ readAsText }) => readAsText(bucket, fileName)),
9
+ uploadFile: (input) => tapLayer(FileStorageLayerContext, ({ uploadFile }) => uploadFile(input)),
10
+ };
11
+ //# sourceMappingURL=file-storage.layer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-storage.layer.js","sourceRoot":"","sources":["../../../src/layer/file-storage.layer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAMjC,OAAO,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAuC3D,MAAM,CAAC,MAAM,uBAAuB,GAClC,OAAO,CAAC,UAAU,CAAc,cAAc,CAAC,CAAC;AAElD,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,UAAU,EAAE,CAAyB,MAAe,EAAE,QAAgB,EAAE,EAAE,CACxE,QAAQ,CAAC,uBAAuB,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CACnD,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAC7B;IACH,eAAe,EAAE,CACf,MAAe,EACf,QAAgB,EAChB,EAAE,CACF,QAAQ,CAAC,uBAAuB,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE,CACxD,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAClC;IACH,UAAU,EAAE,CACV,MAAe,EACf,QAAgB,EAChB,EAAE,CACF,QAAQ,CAAC,uBAAuB,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CACnD,UAAU,CAAkB,MAAM,EAAE,QAAQ,CAAC,CAC9C;IACH,UAAU,EAAE,CAAyB,MAAe,EAAE,QAAgB,EAAE,EAAE,CACxE,QAAQ,CAAC,uBAAuB,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CACnD,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAC7B;IACH,UAAU,EAAE,CAAyB,KAA+B,EAAE,EAAE,CACtE,QAAQ,CAAC,uBAAuB,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;CAC3E,CAAC"}
@@ -0,0 +1 @@
1
+ {"type": "module"}
@@ -0,0 +1,5 @@
1
+ import { Effect, pipe } from 'effect';
2
+ import { cloudflareR2StorageProvider } from '../providers/r2-file-storage.provider.js';
3
+ import { getUrl } from './get-url.effect.js';
4
+ export const getFileUrl = (bucketName, documentKey) => Effect.withSpan('get-file-url', { attributes: { bucketName, documentKey } })(pipe(cloudflareR2StorageProvider, Effect.flatMap((provider) => getUrl(provider, bucketName, documentKey))));
5
+ //# sourceMappingURL=get-file-url.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-file-url.effect.js","sourceRoot":"","sources":["../../../../src/r2/implementations/get-file-url.effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AACvF,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,UAAmB,EACnB,WAAmB,EACnB,EAAE,CACF,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,CAAC,CAC1E,IAAI,CACF,2BAA2B,EAC3B,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CACxE,CACF,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { GetObjectCommand } from '@aws-sdk/client-s3';
2
+ import { getSignedUrl as awsGetSignedUrl } from '@aws-sdk/s3-request-presigner';
3
+ import { Effect } from 'effect';
4
+ import { FileStorageError } from '../../errors/file-storage.error.js';
5
+ const oneHourDuration = 60 * 60;
6
+ export const getUrl = (provider, bucketName, documentKey) => Effect.withSpan('get-url', { attributes: { bucketName, documentKey } })(Effect.tryPromise({
7
+ try: () => awsGetSignedUrl(provider, new GetObjectCommand({
8
+ Bucket: bucketName,
9
+ Key: documentKey,
10
+ }), {
11
+ expiresIn: oneHourDuration,
12
+ }),
13
+ catch: (e) => new FileStorageError({ cause: e }),
14
+ }));
15
+ //# sourceMappingURL=get-url.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-url.effect.js","sourceRoot":"","sources":["../../../../src/r2/implementations/get-url.effect.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,YAAY,IAAI,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,MAAM,eAAe,GAAG,EAAE,GAAG,EAAE,CAAC;AAEhC,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,QAAkB,EAClB,UAAmB,EACnB,WAAoB,EACpB,EAAE,CACF,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,CAAC,CACrE,MAAM,CAAC,UAAU,CAAC;IAChB,GAAG,EAAE,GAAG,EAAE,CACR,eAAe,CACb,QAAQ,EACR,IAAI,gBAAgB,CAAC;QACnB,MAAM,EAAE,UAAU;QAClB,GAAG,EAAE,WAAW;KACjB,CAAC,EACF;QACE,SAAS,EAAE,eAAe;KAC3B,CACF;IACH,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,gBAAgB,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;CACjD,CAAC,CACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './get-file-url.effect.js';
2
+ export * from './upload-file.effect.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/r2/implementations/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { HttpClient } from '@effect/platform';
2
+ import { Effect } from 'effect';
3
+ import { cloudflareR2StorageProvider } from '../providers/r2-file-storage.provider.js';
4
+ import { getUrl } from './get-url.effect.js';
5
+ export const readAsJson = (bucketName, documentKey) => Effect.withSpan('read-as-json', {
6
+ attributes: { bucketName, documentKey },
7
+ })(Effect.gen(function* () {
8
+ const provider = yield* cloudflareR2StorageProvider;
9
+ const url = yield* getUrl(provider, bucketName, documentKey);
10
+ const client = yield* HttpClient.HttpClient;
11
+ const response = yield* client.get(url);
12
+ const json = yield* response.json;
13
+ return json;
14
+ }));
15
+ //# sourceMappingURL=read-as-json.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-as-json.effect.js","sourceRoot":"","sources":["../../../../src/r2/implementations/read-as-json.effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AACvF,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,MAAM,CAAC,MAAM,UAAU,GAAG,CAIxB,UAAmB,EACnB,WAAmB,EACnB,EAAE,CACF,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE;IAC9B,UAAU,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE;CACxC,CAAC,CACA,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,2BAA2B,CAAC;IACpD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;IAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAExC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;IAElC,OAAO,IAAc,CAAC;AACxB,CAAC,CAAC,CACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { HttpClient } from '@effect/platform';
2
+ import { Effect } from 'effect';
3
+ import { cloudflareR2StorageProvider } from '../providers/r2-file-storage.provider.js';
4
+ import { getUrl } from './get-url.effect.js';
5
+ export const readAsRawBinary = (bucketName, documentKey) => Effect.withSpan('read-as-raw-binary', {
6
+ attributes: { bucketName, documentKey },
7
+ })(Effect.gen(function* () {
8
+ const provider = yield* cloudflareR2StorageProvider;
9
+ const url = yield* getUrl(provider, bucketName, documentKey);
10
+ const client = yield* HttpClient.HttpClient;
11
+ const response = yield* client.get(url);
12
+ return yield* response.arrayBuffer;
13
+ }));
14
+ //# sourceMappingURL=read-as-raw-binary.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-as-raw-binary.effect.js","sourceRoot":"","sources":["../../../../src/r2/implementations/read-as-raw-binary.effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AACvF,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAAmB,EACnB,WAAmB,EACnB,EAAE,CACF,MAAM,CAAC,QAAQ,CAAC,oBAAoB,EAAE;IACpC,UAAU,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE;CACxC,CAAC,CACA,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,2BAA2B,CAAC;IACpD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;IAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAExC,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;AACrC,CAAC,CAAC,CACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { HttpClient } from '@effect/platform';
2
+ import { Effect } from 'effect';
3
+ import { cloudflareR2StorageProvider } from '../providers/r2-file-storage.provider.js';
4
+ import { getUrl } from './get-url.effect.js';
5
+ export const readAsText = (bucketName, documentKey) => Effect.withSpan('read-as-text', {
6
+ attributes: { bucketName, documentKey },
7
+ })(Effect.gen(function* () {
8
+ const provider = yield* cloudflareR2StorageProvider;
9
+ const url = yield* getUrl(provider, bucketName, documentKey);
10
+ const client = yield* HttpClient.HttpClient;
11
+ const response = yield* client.get(url);
12
+ return yield* response.text;
13
+ }));
14
+ //# sourceMappingURL=read-as-text.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-as-text.effect.js","sourceRoot":"","sources":["../../../../src/r2/implementations/read-as-text.effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AACvF,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,UAAmB,EACnB,WAAmB,EACnB,EAAE,CACF,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE;IAC9B,UAAU,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE;CACxC,CAAC,CACA,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,2BAA2B,CAAC;IACpD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;IAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAExC,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC9B,CAAC,CAAC,CACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { PutObjectCommand } from '@aws-sdk/client-s3';
2
+ import { Effect, pipe } from 'effect';
3
+ import { FileStorageError } from '../../errors/file-storage.error.js';
4
+ import { cloudflareR2StorageProvider } from '../providers/r2-file-storage.provider.js';
5
+ export const uploadFile = ({ bucketName, key, data, contentType, }) => Effect.withSpan('upload-file', {
6
+ attributes: { bucketName, key, contentType },
7
+ })(pipe(cloudflareR2StorageProvider, Effect.flatMap((provider) => Effect.tryPromise({
8
+ try: () => provider.send(new PutObjectCommand({
9
+ Body: data,
10
+ ContentType: contentType,
11
+ Key: key,
12
+ Bucket: bucketName,
13
+ })),
14
+ catch: (e) => new FileStorageError({ cause: e }),
15
+ }))));
16
+ //# sourceMappingURL=upload-file.effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-file.effect.js","sourceRoot":"","sources":["../../../../src/r2/implementations/upload-file.effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AASvF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAyB,EACjD,UAAU,EACV,GAAG,EACH,IAAI,EACJ,WAAW,GACc,EAAE,EAAE,CAC7B,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE;IAC7B,UAAU,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,WAAW,EAAE;CAC7C,CAAC,CACA,IAAI,CACF,2BAA2B,EAC3B,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC1B,MAAM,CAAC,UAAU,CAAC;IAChB,GAAG,EAAE,GAAG,EAAE,CACR,QAAQ,CAAC,IAAI,CACX,IAAI,gBAAgB,CAAC;QACnB,IAAI,EAAE,IAAI;QACV,WAAW,EAAE,WAAqB;QAClC,GAAG,EAAE,GAAG;QACR,MAAM,EAAE,UAAU;KACnB,CAAC,CACH;IACH,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,gBAAgB,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;CACjD,CAAC,CACH,CACF,CACF,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { S3Client } from '@aws-sdk/client-s3';
2
+ import { Config, Effect, pipe } from 'effect';
3
+ const getR2Config = pipe(Effect.all([
4
+ Config.string('CLOUDFLARE_ACCOUNT_ID'),
5
+ Config.string('R2_DOCUMENTS_ACCESS_KEY_ID'),
6
+ Config.string('R2_DOCUMENTS_SECRET_ACCESS_KEY'),
7
+ ]), Effect.map(([cloudflareAccountId, accessKeyId, secretAccessKey]) => ({
8
+ cloudflareAccountId,
9
+ accessKeyId,
10
+ secretAccessKey,
11
+ })));
12
+ export const cloudflareR2StorageProvider = pipe(getR2Config, Effect.flatMap((config) => Effect.succeed(new S3Client({
13
+ region: 'auto',
14
+ endpoint: `https://${config.cloudflareAccountId}.r2.cloudflarestorage.com`,
15
+ credentials: {
16
+ accessKeyId: config.accessKeyId,
17
+ secretAccessKey: config.secretAccessKey,
18
+ },
19
+ }))));
20
+ //# sourceMappingURL=r2-file-storage.provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2-file-storage.provider.js","sourceRoot":"","sources":["../../../../src/r2/providers/r2-file-storage.provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9C,MAAM,WAAW,GAAG,IAAI,CACtB,MAAM,CAAC,GAAG,CAAC;IACT,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC;IACtC,MAAM,CAAC,MAAM,CAAC,4BAA4B,CAAC;IAC3C,MAAM,CAAC,MAAM,CAAC,gCAAgC,CAAC;CAChD,CAAC,EACF,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,mBAAmB,EAAE,WAAW,EAAE,eAAe,CAAC,EAAE,EAAE,CAAC,CAAC;IACnE,mBAAmB;IACnB,WAAW;IACX,eAAe;CAChB,CAAC,CAAC,CACJ,CAAC;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,CAC7C,WAAW,EACX,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CACxB,MAAM,CAAC,OAAO,CACZ,IAAI,QAAQ,CAAC;IACX,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,WAAW,MAAM,CAAC,mBAAmB,2BAA2B;IAC1E,WAAW,EAAE;QACX,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,eAAe,EAAE,MAAM,CAAC,eAAe;KACxC;CACF,CAAC,CACH,CACF,CACF,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { Layer } from 'effect';
2
+ import { FileStorageLayerContext } from '../layer/file-storage.layer.js';
3
+ import { getFileUrl, uploadFile } from './implementations/index.js';
4
+ import { readAsJson } from './implementations/read-as-json.effect.js';
5
+ import { readAsRawBinary } from './implementations/read-as-raw-binary.effect.js';
6
+ import { readAsText } from './implementations/read-as-text.effect.js';
7
+ export const CloudflareR2StorageLayerLive = Layer.succeed(FileStorageLayerContext, FileStorageLayerContext.of({
8
+ getFileUrl,
9
+ uploadFile,
10
+ readAsText,
11
+ readAsJson,
12
+ readAsRawBinary,
13
+ }));
14
+ //# sourceMappingURL=r2-file-storage.layer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"r2-file-storage.layer.js","sourceRoot":"","sources":["../../../src/r2/r2-file-storage.layer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE/B,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAEtE,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,CAAC,OAAO,CACvD,uBAAuB,EACvB,uBAAuB,CAAC,EAAE,CAAC;IACzB,UAAU;IACV,UAAU;IACV,UAAU;IACV,UAAU;IACV,eAAe;CAChB,CAAC,CACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "effect-cloudflare-r2-layer",
3
+ "version": "1.0.1",
4
+ "author": "jpb06 <jp.bois.06@outlook.fr>",
5
+ "description": "An effect layer to interact with Cloudware R2 storage service",
6
+ "keywords": [
7
+ "effect"
8
+ ],
9
+ "main": "./cjs/index.js",
10
+ "module": "./esm/index.js",
11
+ "type": "module",
12
+ "exports": {
13
+ ".": {
14
+ "require": {
15
+ "default": "./cjs/index.js",
16
+ "types": "./dts/cjs/index.d.ts"
17
+ },
18
+ "import": {
19
+ "default": "./esm/index.js",
20
+ "types": "./dts/esm/index.d.ts"
21
+ }
22
+ }
23
+ },
24
+ "engines": {
25
+ "node": "20.x"
26
+ },
27
+ "scripts": {
28
+ "update-deps": "bunx npm-check-updates --root --format group -i",
29
+ "copy-package": "copyfiles package.json ./dist/",
30
+ "copy-readme": "copyfiles README.md ./dist/",
31
+ "build": "del-cli ./dist && bun build-esm && bun build-cjs",
32
+ "build-esm": "tsc --project tsconfig.esm.json",
33
+ "build-cjs": "tsc --project tsconfig.cjs.json",
34
+ "postbuild-cjs": "echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json",
35
+ "postbuild-esm": "echo '{\"type\": \"module\"}' > dist/esm/package.json",
36
+ "postbuild": "bun run copy-package && bun run copy-readme",
37
+ "format": "biome format --write ./src",
38
+ "format-ci": "biome format ./src",
39
+ "lint": "biome lint ./src",
40
+ "type-check": "tsc --noEmit",
41
+ "sync-icons": "bun generateReadmeIcons -h 50"
42
+ },
43
+ "dependencies": {
44
+ "@aws-sdk/client-s3": "^3.658.1",
45
+ "@aws-sdk/s3-request-presigner": "^3.658.1",
46
+ "@effect/platform": "^0.66.2",
47
+ "dotenv": "^16.4.5",
48
+ "effect": "^3.8.4",
49
+ "effect-errors": "^1.7.11"
50
+ },
51
+ "peerDependencies": {
52
+ "typescript": "^5.0.0"
53
+ },
54
+ "devDependencies": {
55
+ "@biomejs/biome": "^1.9.2",
56
+ "@types/bun": "latest",
57
+ "@types/fs-extra": "^11.0.4",
58
+ "copyfiles": "^2.4.1",
59
+ "del-cli": "^5.1.0",
60
+ "fs-extra": "^11.2.0",
61
+ "readme-package-icons": "^1.1.15",
62
+ "tsx": "^4.19.1"
63
+ }
64
+ }