effect-cloudflare-r2-layer 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }