@effect-pantry/storage 0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 effect-pantry contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,223 @@
1
+ # @effect-pantry/storage
2
+
3
+ > [!WARNING]
4
+ > **Early-stage package** — APIs may change without notice. Not recommended for production use yet. Feedback and contributions welcome!
5
+
6
+ **Effect-native object storage** — wraps [files-sdk](https://files-sdk.dev) as typed Effect functions. Swap backends by swapping adapters — the API stays the same.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @effect-pantry/storage effect
12
+ ```
13
+
14
+ > **`files-sdk` is a peer dependency.** Install your own version and choose which adapters to bring in (e.g., `files-sdk/s3`, `files-sdk/memory`). Targets **Effect v3** and **files-sdk ^1.6.0**.
15
+
16
+ ## Quick Start
17
+
18
+ ```ts
19
+ import { memory } from "files-sdk/memory"
20
+ import { Storage, StorageAdapter } from "@effect-pantry/storage"
21
+ import { Effect, Layer } from "effect"
22
+
23
+ const layer = Storage.layer().pipe(
24
+ Layer.provide(Layer.succeed(StorageAdapter, memory())),
25
+ )
26
+
27
+ const program = Effect.gen(function* () {
28
+ const s = yield* Storage.Storage
29
+
30
+ // Upload
31
+ const { result } = yield* s.upload("data.json", JSON.stringify({ hello: "world" }))
32
+ yield* result;
33
+
34
+ // Download
35
+ const file = yield* s.download("data.json")
36
+ const text = yield* file.text()
37
+
38
+ return text
39
+ })
40
+
41
+ Effect.runPromise(Effect.provide(program, layer))
42
+ ```
43
+
44
+ ## API Reference
45
+
46
+ ### `Storage.Storage` (Context.Tag)
47
+
48
+ The service tag. Inject with `yield* Storage.Storage`.
49
+
50
+ ### `StorageAdapter` (Context.Tag)
51
+
52
+ Provide any `files-sdk` adapter:
53
+
54
+ ```ts
55
+ import { s3 } from "files-sdk/s3"
56
+
57
+ Layer.succeed(StorageAdapter, s3({
58
+ bucket: "my-bucket",
59
+ region: "us-east-1",
60
+ }))
61
+ ```
62
+
63
+ ### `Storage.layer`
64
+
65
+ Creates a layer that requires `StorageAdapter` and provides `Storage.Storage`.
66
+ Accepts optional {@link MakeOptions} (e.g. `prefix`, `timeout`, `retries`).
67
+
68
+ ```ts
69
+ const layer = Storage.layer().pipe(
70
+ Layer.provide(Layer.succeed(StorageAdapter, memory())),
71
+ )
72
+
73
+ // With options
74
+ const layerWithPrefix = Storage.layer({ prefix: "app-data/" }).pipe(
75
+ Layer.provide(Layer.succeed(StorageAdapter, memory())),
76
+ )
77
+ ```
78
+
79
+ ### `Storage.make`
80
+
81
+ Creates a `Storage` service. Reads the adapter from context.
82
+ Accepts optional {@link MakeOptions} forwarded to the underlying
83
+ `FilesSDK.Files` constructor.
84
+
85
+ ```ts
86
+ const s = yield* Storage.make()
87
+ ```
88
+
89
+ With options:
90
+
91
+ ```ts
92
+ const s = yield* Storage.make({ prefix: "uploads/", timeout: 30_000 })
93
+ ```
94
+
95
+ Or inline:
96
+
97
+ ```ts
98
+ const s = yield* Storage.make().pipe(
99
+ Effect.provideService(StorageAdapter, memory()),
100
+ )
101
+ ```
102
+
103
+ ### Methods
104
+
105
+ | Method | Signature | Returns |
106
+ |--------|-----------|---------|
107
+ | `upload(key, body, opts?)` | `Effect<{ result, progress }, never>` | Returns `{ result: Effect<UploadResult, StorageError>, progress: Stream<UploadProgress> }`. Consume progress concurrently, then `yield*` the result. |
108
+ | `download(key, opts?)` | `Effect<StoredFile, StorageError>` | File with lazy body accessors |
109
+ | `head(key, opts?)` | `Effect<StoredFile, StorageError>` | Metadata without the body |
110
+ | `exists(key, opts?)` | `Effect<boolean, StorageError>` | Existence check |
111
+ | `delete(key, opts?)` | `Effect<void, StorageError>` | Permanent removal |
112
+ | `copy(from, to, opts?)` | `Effect<void, StorageError>` | Server-side copy |
113
+ | `move(from, to, opts?)` | `Effect<void, StorageError>` | Rename / relocate |
114
+ | `list(opts?)` | `Effect<ListResult, StorageError>` | Cursor-paginated listing |
115
+ | `url(key, opts?)` | `Effect<string, StorageError>` | Public or signed download URL |
116
+ | `file(key)` | `FileHandle` | Key-bound handle for ergonomic single-key ops |
117
+ | `signedUploadUrl(key, opts)` | `Effect<SignedUpload, StorageError>` | Presigned upload URL |
118
+ | `hookStream(name)` | `Stream<HookEventMap[N]>` | Observable hook events |
119
+
120
+ ### `FileHandle`
121
+
122
+ A key-bound storage handle. Every method operates on a pre-bound key.
123
+
124
+ ```ts
125
+ const avatar = s.file("avatars/abc.png")
126
+
127
+ // Upload
128
+ yield* avatar.upload(body, { contentType: "image/png" })
129
+
130
+ // Check existence
131
+ if (yield* avatar.exists()) {
132
+ const meta = yield* avatar.head()
133
+ }
134
+
135
+ // Copy / move
136
+ yield* avatar.copyTo("avatars/abc.bak.png")
137
+ yield* avatar.copyFrom("legacy/abc.png")
138
+ ```
139
+
140
+ | Method | Equivalent |
141
+ |--------|-----------|
142
+ | `upload(body, opts?)` | `s.upload(key, body, opts?)` |
143
+ | `download(opts?)` | `s.download(key, opts?)` |
144
+ | `head(opts?)` | `s.head(key, opts?)` |
145
+ | `exists(opts?)` | `s.exists(key, opts?)` |
146
+ | `delete(opts?)` | `s.delete(key, opts?)` |
147
+ | `url(opts?)` | `s.url(key, opts?)` |
148
+ | `signedUploadUrl(opts)` | `s.signedUploadUrl(key, opts)` |
149
+ | `copyTo(destKey, opts?)` | `s.copy(key, destKey, opts?)` |
150
+ | `copyFrom(srcKey, opts?)` | `s.copy(srcKey, key, opts?)` |
151
+
152
+ ### Errors
153
+
154
+ All methods return typed, tagged errors:
155
+
156
+ | Error | Code | When |
157
+ |-------|------|------|
158
+ | `StorageNotFoundError` | `NotFound` | Key, bucket, or container missing |
159
+ | `StorageUnauthorizedError` | `Unauthorized` | Credentials missing, expired, or insufficient |
160
+ | `StorageConflictError` | `Conflict` | Precondition failed |
161
+ | `StorageProviderError` | `Provider` | Network, throttling, 5xx, timeout, cancellation |
162
+
163
+ ```ts
164
+ import { StorageNotFoundError, StorageUnauthorizedError } from "@effect-pantry/storage"
165
+
166
+ yield* s.download("missing.txt").pipe(
167
+ Effect.catchTags({
168
+ StorageNotFoundError: (e) => Effect.succeed(null),
169
+ StorageUnauthorizedError: (e) => Effect.fail(new Error("Check credentials")),
170
+ StorageConflictError: (e) => Effect.fail(e),
171
+ StorageProviderError: (e) => Effect.fail(e),
172
+ }),
173
+ )
174
+ ```
175
+
176
+ > Use `toStorageError(error)` to manually map unknown errors into typed `StorageError` values when working outside the `Storage` service.
177
+
178
+ ### Hooks
179
+
180
+ Observe SDK events as Effect streams:
181
+
182
+ ```ts
183
+ const s = yield* Storage.Storage
184
+
185
+ yield* s.hookStream("onAction").pipe(
186
+ Stream.runForEach((e) => Effect.log(`[${e.status}] ${e.type} ${e.key}`)),
187
+ Effect.forkScoped,
188
+ )
189
+
190
+ yield* s.hookStream("onError").pipe(
191
+ Stream.runForEach((e) => Effect.log(`[${e.error.code}] ${e.key}`)),
192
+ Effect.forkScoped,
193
+ )
194
+ ```
195
+
196
+ ### `transfer(source, dest, opts?)`
197
+
198
+ Cross-provider migration using `FilesSDK.Files` instances. → [Full example](./examples/04-cross-provider-transfer.ts)
199
+
200
+ ```ts
201
+ import { transfer } from "@effect-pantry/storage"
202
+ import * as FilesSDK from "files-sdk"
203
+ import { s3 } from "files-sdk/s3"
204
+ import { r2 } from "files-sdk/r2"
205
+
206
+ const from = new FilesSDK.Files({ adapter: s3({ bucket: "old", region: "us-east-1" }) })
207
+ const to = new FilesSDK.Files({ adapter: r2({ bucket: "new", accountId: "..." }) })
208
+
209
+ const { result, progress } = yield* transfer(from, to, { prefix: "uploads/" })
210
+ const { transferred, skipped, errors } = yield* result
211
+ ```
212
+
213
+ ## Examples
214
+
215
+ - [Basic usage](./examples/01-basic-usage.ts) — Full CRUD with the memory adapter
216
+ - [S3 adapter](./examples/02-s3-adapter.ts) — Real S3/R2 configuration patterns
217
+ - [Hooks & monitoring](./examples/03-hooks-and-monitoring.ts) — Logging, metrics, alerting
218
+ - [Cross-provider transfer](./examples/04-cross-provider-transfer.ts) — S3 → R2 migration with progress
219
+ - [Streams & progress](./examples/05-streams-and-progress.ts) — Upload/download progress, cancellation
220
+
221
+ ## License
222
+
223
+ MIT
@@ -0,0 +1,13 @@
1
+ import * as FilesSDK from 'files-sdk';
2
+ import { Context } from 'effect';
3
+ declare const StorageAdapter_base: Context.TagClass<StorageAdapter, "@effect-pantry/storage/Adapter", FilesSDK.Adapter<unknown>>;
4
+ /**
5
+ * The `files-sdk` {@link FilesSDK.Adapter} powering the {@link Storage} service.
6
+ *
7
+ * Provide via `Layer.succeed(StorageAdapter, myAdapter)` to plug any of
8
+ * the 40+ adapters (memory, fs, S3, R2, Vercel Blob, …) into the service.
9
+ */
10
+ export declare class StorageAdapter extends StorageAdapter_base {
11
+ }
12
+ export {};
13
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;;AAEjC;;;;;GAKG;AACH,qBAAa,cAAe,SAAQ,mBAGjC;CAAG"}
@@ -0,0 +1,10 @@
1
+ import { Context } from 'effect';
2
+ /**
3
+ * The `files-sdk` {@link FilesSDK.Adapter} powering the {@link Storage} service.
4
+ *
5
+ * Provide via `Layer.succeed(StorageAdapter, myAdapter)` to plug any of
6
+ * the 40+ adapters (memory, fs, S3, R2, Vercel Blob, …) into the service.
7
+ */
8
+ export class StorageAdapter extends Context.Tag('@effect-pantry/storage/Adapter')() {
9
+ }
10
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEjC;;;;;GAKG;AACH,MAAM,OAAO,cAAe,SAAQ,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,EAG9E;CAAG"}
@@ -0,0 +1,62 @@
1
+ declare const StorageNotFoundError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
2
+ readonly _tag: "StorageNotFoundError";
3
+ } & Readonly<A>;
4
+ /**
5
+ * The requested key, bucket, or container does not exist.
6
+ *
7
+ * @param cause - The original underlying error from the storage provider.
8
+ */
9
+ export declare class StorageNotFoundError extends StorageNotFoundError_base<{
10
+ readonly message: string;
11
+ readonly cause: unknown;
12
+ }> {
13
+ }
14
+ declare const StorageUnauthorizedError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
15
+ readonly _tag: "StorageUnauthorizedError";
16
+ } & Readonly<A>;
17
+ /**
18
+ * Credentials are missing, expired, or have insufficient permissions.
19
+ *
20
+ * @param cause - The original underlying error from the storage provider.
21
+ */
22
+ export declare class StorageUnauthorizedError extends StorageUnauthorizedError_base<{
23
+ readonly message: string;
24
+ readonly cause: unknown;
25
+ }> {
26
+ }
27
+ declare const StorageConflictError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
28
+ readonly _tag: "StorageConflictError";
29
+ } & Readonly<A>;
30
+ /**
31
+ * A precondition failed (e.g. a conditional write lost a race).
32
+ *
33
+ * @param cause - The original underlying error from the storage provider.
34
+ */
35
+ export declare class StorageConflictError extends StorageConflictError_base<{
36
+ readonly message: string;
37
+ readonly cause: unknown;
38
+ }> {
39
+ }
40
+ declare const StorageProviderError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
41
+ readonly _tag: "StorageProviderError";
42
+ } & Readonly<A>;
43
+ /**
44
+ * A provider-level failure: network, throttling, 5xx, timeout, or cancellation.
45
+ *
46
+ * @param cause - The original underlying error from the storage provider.
47
+ */
48
+ export declare class StorageProviderError extends StorageProviderError_base<{
49
+ readonly message: string;
50
+ readonly cause: unknown;
51
+ readonly aborted: boolean;
52
+ }> {
53
+ }
54
+ export type StorageError = StorageNotFoundError | StorageUnauthorizedError | StorageConflictError | StorageProviderError;
55
+ /**
56
+ * Map an unknown error (ideally an SDK `FilesError`) to a tagged Effect error.
57
+ *
58
+ * Fallback: unknown errors become `StorageProviderError` with `aborted: false`.
59
+ */
60
+ export declare const toStorageError: (error: unknown) => StorageError;
61
+ export {};
62
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAGA;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,0BAAyC;IACjF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,CAAC;CAAG;;;;AAEL;;;;GAIG;AACH,qBAAa,wBAAyB,SAAQ,8BAA6C;IACzF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,CAAC;CAAG;;;;AAEL;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,0BAAyC;IACjF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,CAAC;CAAG;;;;AAEL;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,0BAAyC;IACjF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B,CAAC;CAAG;AAEL,MAAM,MAAM,YAAY,GACpB,oBAAoB,GACpB,wBAAwB,GACxB,oBAAoB,GACpB,oBAAoB,CAAC;AAEzB;;;;GAIG;AACH,eAAO,MAAM,cAAc,UAAW,OAAO,KAAG,YAuB/C,CAAC"}
package/dist/errors.js ADDED
@@ -0,0 +1,60 @@
1
+ import { Data } from 'effect';
2
+ import * as FilesSDK from 'files-sdk';
3
+ /**
4
+ * The requested key, bucket, or container does not exist.
5
+ *
6
+ * @param cause - The original underlying error from the storage provider.
7
+ */
8
+ export class StorageNotFoundError extends Data.TaggedError('StorageNotFoundError') {
9
+ }
10
+ /**
11
+ * Credentials are missing, expired, or have insufficient permissions.
12
+ *
13
+ * @param cause - The original underlying error from the storage provider.
14
+ */
15
+ export class StorageUnauthorizedError extends Data.TaggedError('StorageUnauthorizedError') {
16
+ }
17
+ /**
18
+ * A precondition failed (e.g. a conditional write lost a race).
19
+ *
20
+ * @param cause - The original underlying error from the storage provider.
21
+ */
22
+ export class StorageConflictError extends Data.TaggedError('StorageConflictError') {
23
+ }
24
+ /**
25
+ * A provider-level failure: network, throttling, 5xx, timeout, or cancellation.
26
+ *
27
+ * @param cause - The original underlying error from the storage provider.
28
+ */
29
+ export class StorageProviderError extends Data.TaggedError('StorageProviderError') {
30
+ }
31
+ /**
32
+ * Map an unknown error (ideally an SDK `FilesError`) to a tagged Effect error.
33
+ *
34
+ * Fallback: unknown errors become `StorageProviderError` with `aborted: false`.
35
+ */
36
+ export const toStorageError = (error) => {
37
+ if (error instanceof FilesSDK.FilesError) {
38
+ const message = error.message;
39
+ const cause = error.cause;
40
+ switch (error.code) {
41
+ case 'NotFound':
42
+ return new StorageNotFoundError({ message, cause });
43
+ case 'Unauthorized':
44
+ return new StorageUnauthorizedError({ message, cause });
45
+ case 'Conflict':
46
+ return new StorageConflictError({ message, cause });
47
+ default:
48
+ // files-sdk v1.6 has exactly four codes ("NotFound", "Unauthorized",
49
+ // "Conflict", "Provider"). If this branch triggers, the SDK added a new
50
+ // error code — file an issue to add a dedicated tagged error.
51
+ return new StorageProviderError({ message, cause, aborted: error.aborted });
52
+ }
53
+ }
54
+ return new StorageProviderError({
55
+ message: error instanceof Error ? error.message : String(error),
56
+ cause: error,
57
+ aborted: false,
58
+ });
59
+ };
60
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,KAAK,QAAQ,MAAM,WAAW,CAAC;AAEtC;;;;GAIG;AACH,MAAM,OAAO,oBAAqB,SAAQ,IAAI,CAAC,WAAW,CAAC,sBAAsB,CAG/E;CAAG;AAEL;;;;GAIG;AACH,MAAM,OAAO,wBAAyB,SAAQ,IAAI,CAAC,WAAW,CAAC,0BAA0B,CAGvF;CAAG;AAEL;;;;GAIG;AACH,MAAM,OAAO,oBAAqB,SAAQ,IAAI,CAAC,WAAW,CAAC,sBAAsB,CAG/E;CAAG;AAEL;;;;GAIG;AACH,MAAM,OAAO,oBAAqB,SAAQ,IAAI,CAAC,WAAW,CAAC,sBAAsB,CAI/E;CAAG;AAQL;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAc,EAAgB,EAAE;IAC7D,IAAI,KAAK,YAAY,QAAQ,CAAC,UAAU,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAC1B,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,UAAU;gBACb,OAAO,IAAI,oBAAoB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YACtD,KAAK,cAAc;gBACjB,OAAO,IAAI,wBAAwB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAC1D,KAAK,UAAU;gBACb,OAAO,IAAI,oBAAoB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YACtD;gBACE,qEAAqE;gBACrE,wEAAwE;gBACxE,8DAA8D;gBAC9D,OAAO,IAAI,oBAAoB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;IACD,OAAO,IAAI,oBAAoB,CAAC;QAC9B,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;QAC/D,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,50 @@
1
+ import * as FilesSDK from 'files-sdk';
2
+ /** Options for {@link transfer}, with `signal` and `onProgress` managed internally. */
3
+ export type TransferOptions = Omit<FilesSDK.TransferOptions, 'signal' | 'onProgress'>;
4
+ /**
5
+ * Cross-provider migration: walks every object the `source` exposes and
6
+ * streams each one straight to `dest`, whatever the backends are.
7
+ *
8
+ * Returns an `{ result, progress }` pair where `result` is a **deferred
9
+ * Effect** — the transfer does not start until you `yield*` it, and
10
+ * `progress` is a {@link Stream} of {@link FilesSDK.TransferProgress}
11
+ * events emitted while the transfer runs. Consume the stream concurrently
12
+ * with the result:
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { s3 } from "files-sdk/s3";
17
+ * import { r2 } from "files-sdk/r2";
18
+ * import * as FilesSDK from "files-sdk";
19
+ * import { transfer } from "@effect-pantry/storage";
20
+ *
21
+ * const from = new FilesSDK.Files({ adapter: s3({ bucket: "old" }) });
22
+ * const to = new FilesSDK.Files({ adapter: r2({ bucket: "new", ... }) });
23
+ *
24
+ * // With progress — fork the stream consumer before awaiting the result
25
+ * const { result, progress } = yield* transfer(from, to, { prefix: "uploads/" });
26
+ * yield* Stream.runForEach(progress, (p) =>
27
+ * Effect.log(`${p.status} ${p.key} (${p.done}/${p.total})`)
28
+ * ).pipe(Effect.forkScoped);
29
+ * const { transferred, skipped, errors } = yield* result;
30
+ *
31
+ * // Without progress — just yield the result
32
+ * const { transferred, skipped, errors } = yield* transfer(from, to).pipe(
33
+ * Effect.flatMap(({ result }) => result)
34
+ * );
35
+ * ```
36
+ *
37
+ * Both arguments are full {@link FilesSDK.Files} instances, not raw
38
+ * adapters, so each leg honors its own `prefix`, retries, timeouts, and
39
+ * hooks.
40
+ *
41
+ * @returns An {@link Effect} resolving to `{ result, progress }` where
42
+ * `result` is a deferred effect that yields a
43
+ * {@link FilesSDK.TransferResult} when executed, and `progress` is a
44
+ * stream of {@link FilesSDK.TransferProgress} events.
45
+ */
46
+ export declare const transfer: (source: FilesSDK.Files, dest: FilesSDK.Files, opts?: TransferOptions) => import("effect/Effect").Effect<{
47
+ result: import("effect/Effect").Effect<FilesSDK.TransferResult, import("../errors.ts").StorageError, never>;
48
+ progress: import("effect/Stream").Stream<FilesSDK.TransferProgress, never, never>;
49
+ }, never, never>;
50
+ //# sourceMappingURL=transfer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transfer.d.ts","sourceRoot":"","sources":["../../src/features/transfer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,WAAW,CAAC;AAGtC,uFAAuF;AACvF,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,QAAQ,GAAG,YAAY,CAAC,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,QAAQ,WAAY,QAAQ,CAAC,KAAK,QAAQ,QAAQ,CAAC,KAAK,SAAS,eAAe;;;gBAG1F,CAAC"}
@@ -0,0 +1,46 @@
1
+ import * as FilesSDK from 'files-sdk';
2
+ import { bridgeProgress } from '../internal.js';
3
+ /**
4
+ * Cross-provider migration: walks every object the `source` exposes and
5
+ * streams each one straight to `dest`, whatever the backends are.
6
+ *
7
+ * Returns an `{ result, progress }` pair where `result` is a **deferred
8
+ * Effect** — the transfer does not start until you `yield*` it, and
9
+ * `progress` is a {@link Stream} of {@link FilesSDK.TransferProgress}
10
+ * events emitted while the transfer runs. Consume the stream concurrently
11
+ * with the result:
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { s3 } from "files-sdk/s3";
16
+ * import { r2 } from "files-sdk/r2";
17
+ * import * as FilesSDK from "files-sdk";
18
+ * import { transfer } from "@effect-pantry/storage";
19
+ *
20
+ * const from = new FilesSDK.Files({ adapter: s3({ bucket: "old" }) });
21
+ * const to = new FilesSDK.Files({ adapter: r2({ bucket: "new", ... }) });
22
+ *
23
+ * // With progress — fork the stream consumer before awaiting the result
24
+ * const { result, progress } = yield* transfer(from, to, { prefix: "uploads/" });
25
+ * yield* Stream.runForEach(progress, (p) =>
26
+ * Effect.log(`${p.status} ${p.key} (${p.done}/${p.total})`)
27
+ * ).pipe(Effect.forkScoped);
28
+ * const { transferred, skipped, errors } = yield* result;
29
+ *
30
+ * // Without progress — just yield the result
31
+ * const { transferred, skipped, errors } = yield* transfer(from, to).pipe(
32
+ * Effect.flatMap(({ result }) => result)
33
+ * );
34
+ * ```
35
+ *
36
+ * Both arguments are full {@link FilesSDK.Files} instances, not raw
37
+ * adapters, so each leg honors its own `prefix`, retries, timeouts, and
38
+ * hooks.
39
+ *
40
+ * @returns An {@link Effect} resolving to `{ result, progress }` where
41
+ * `result` is a deferred effect that yields a
42
+ * {@link FilesSDK.TransferResult} when executed, and `progress` is a
43
+ * stream of {@link FilesSDK.TransferProgress} events.
44
+ */
45
+ export const transfer = (source, dest, opts) => bridgeProgress((signal, onProgress) => FilesSDK.transfer(source, dest, { ...opts, signal, onProgress }));
46
+ //# sourceMappingURL=transfer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transfer.js","sourceRoot":"","sources":["../../src/features/transfer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,MAAsB,EAAE,IAAoB,EAAE,IAAsB,EAAE,EAAE,CAC/F,cAAc,CAAqD,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,CACxF,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CACjE,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { FilesActionEvent, FilesErrorEvent, FilesRetryEvent } from 'files-sdk';
2
+ /**
3
+ * Discriminated union of every hook event emitted through the PubSub.
4
+ *
5
+ * Use {@link Storage.hookStream} to subscribe to a single kind of event;
6
+ * the stream filters on `_tag` automatically.
7
+ */
8
+ export type HookEvent = {
9
+ readonly _tag: 'onAction';
10
+ readonly event: FilesActionEvent;
11
+ } | {
12
+ readonly _tag: 'onError';
13
+ readonly event: FilesErrorEvent;
14
+ } | {
15
+ readonly _tag: 'onRetry';
16
+ readonly event: FilesRetryEvent;
17
+ };
18
+ /** Maps each constructor hook name to its event payload type. */
19
+ export interface HookEventMap {
20
+ readonly onAction: FilesActionEvent;
21
+ readonly onError: FilesErrorEvent;
22
+ readonly onRetry: FilesRetryEvent;
23
+ }
24
+ /** The three constructor hook names supported by files-sdk. */
25
+ export type HookName = keyof HookEventMap;
26
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEpF;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,GAC/D;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;CAAE,GAC7D;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;CAAE,CAAC;AAElE,iEAAiE;AACjE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;CACnC;AAED,+DAA+D;AAC/D,MAAM,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC"}
package/dist/hooks.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @effect-pantry/storage — Effect-native storage wrapping files-sdk.
3
+ *
4
+ * Provides a {@link Storage} context tag backed by any files-sdk adapter
5
+ * (memory, fs, S3, R2, Vercel Blob, and 35+ more), with typed errors and
6
+ * automatic cancellation bridging.
7
+ *
8
+ * **⚠️ Early-stage package** — APIs may change without notice.
9
+ * Not recommended for production use yet.
10
+ *
11
+ * @module
12
+ */
13
+ export * as Storage from './service.js';
14
+ export * as StorageAdapter from './adapter.js';
15
+ export type { FileHandle, MakeOptions, UploadOptions } from './service-types.js';
16
+ export { transfer } from './features/transfer.js';
17
+ export type { TransferOptions } from './features/transfer.js';
18
+ export { StorageNotFoundError, StorageUnauthorizedError, StorageConflictError, StorageProviderError, toStorageError, } from './errors.js';
19
+ export type { StorageError } from './errors.js';
20
+ export type { HookEvent, HookEventMap, HookName } from './hooks.js';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,cAAc,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @effect-pantry/storage — Effect-native storage wrapping files-sdk.
3
+ *
4
+ * Provides a {@link Storage} context tag backed by any files-sdk adapter
5
+ * (memory, fs, S3, R2, Vercel Blob, and 35+ more), with typed errors and
6
+ * automatic cancellation bridging.
7
+ *
8
+ * **⚠️ Early-stage package** — APIs may change without notice.
9
+ * Not recommended for production use yet.
10
+ *
11
+ * @module
12
+ */
13
+ export * as Storage from './service.js';
14
+ export * as StorageAdapter from './adapter.js';
15
+ export { transfer } from './features/transfer.js';
16
+ export { StorageNotFoundError, StorageUnauthorizedError, StorageConflictError, StorageProviderError, toStorageError, } from './errors.js';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,cAAc,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGlD,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,GACf,MAAM,aAAa,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { Effect, Stream } from 'effect';
2
+ import { type StorageError } from './errors.js';
3
+ /** @internal */
4
+ export declare const wrapSDKCall: <A>(fn: (signal: AbortSignal) => Promise<A>) => Effect.Effect<A, StorageError, never>;
5
+ /** @internal
6
+ *
7
+ * Bridges a callback-style progress operation to an Effect returning both
8
+ * a deferred result and a progress {@link Stream}. The caller consumes
9
+ * the stream concurrently with the result — e.g. fork the stream consumer
10
+ * then `yield*` the result.
11
+ *
12
+ * Progress callbacks are pushed synchronously via {@link Queue.unsafeOffer}
13
+ * so no extra fibers are spawned per callback. The queue is shut down when
14
+ * the result effect completes, fails, or is interrupted (via `ensuring`).
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const { result, progress } = yield* bridgeProgress((signal, onProgress) =>
19
+ * sdk.upload(key, body, { signal, onProgress })
20
+ * );
21
+ *
22
+ * // Fork progress consumption
23
+ * yield* Stream.runForEach(progress, (p) => Effect.log(p)).pipe(Effect.forkScoped);
24
+ * // Await result
25
+ * const uploadResult = yield* result;
26
+ * ```
27
+ */
28
+ export declare const bridgeProgress: <A, P>(fn: (signal: AbortSignal, onProgress: (progress: P) => void) => Promise<A>) => Effect.Effect<{
29
+ result: Effect.Effect<A, StorageError>;
30
+ progress: Stream.Stream<P>;
31
+ }, never>;
32
+ //# sourceMappingURL=internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAS,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhE,gBAAgB;AAChB,eAAO,MAAM,WAAW,GAAI,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,0CACf,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,EAAE,CAAC,MAC7B,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KACzE,MAAM,CAAC,MAAM,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;CAAE,EAAE,KAAK,CAa1F,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { Effect, Queue, Stream } from 'effect';
2
+ import { toStorageError } from './errors.js';
3
+ /** @internal */
4
+ export const wrapSDKCall = (fn) => Effect.tryPromise({ try: fn, catch: toStorageError });
5
+ /** @internal
6
+ *
7
+ * Bridges a callback-style progress operation to an Effect returning both
8
+ * a deferred result and a progress {@link Stream}. The caller consumes
9
+ * the stream concurrently with the result — e.g. fork the stream consumer
10
+ * then `yield*` the result.
11
+ *
12
+ * Progress callbacks are pushed synchronously via {@link Queue.unsafeOffer}
13
+ * so no extra fibers are spawned per callback. The queue is shut down when
14
+ * the result effect completes, fails, or is interrupted (via `ensuring`).
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const { result, progress } = yield* bridgeProgress((signal, onProgress) =>
19
+ * sdk.upload(key, body, { signal, onProgress })
20
+ * );
21
+ *
22
+ * // Fork progress consumption
23
+ * yield* Stream.runForEach(progress, (p) => Effect.log(p)).pipe(Effect.forkScoped);
24
+ * // Await result
25
+ * const uploadResult = yield* result;
26
+ * ```
27
+ */
28
+ export const bridgeProgress = (fn) => Effect.gen(function* () {
29
+ const queue = yield* Queue.unbounded();
30
+ const result = Effect.tryPromise({
31
+ try: (signal) => fn(signal, (progress) => {
32
+ queue.unsafeOffer(progress);
33
+ }),
34
+ catch: toStorageError,
35
+ }).pipe(Effect.ensuring(queue.shutdown));
36
+ return { result, progress: Stream.fromQueue(queue) };
37
+ });
38
+ //# sourceMappingURL=internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAqB,MAAM,aAAa,CAAC;AAEhE,gBAAgB;AAChB,MAAM,CAAC,MAAM,WAAW,GAAG,CAAI,EAAuC,EAAE,EAAE,CACxE,MAAM,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,EAA0E,EACoB,EAAE,CAChG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,EAAK,CAAC;IAE1C,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC;QAC/B,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,CACd,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE;YACtB,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC,CAAC;QACJ,KAAK,EAAE,cAAc;KACtB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEzC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;AACvD,CAAC,CAAC,CAAC"}
@@ -0,0 +1,156 @@
1
+ import * as FilesSDK from 'files-sdk';
2
+ import { Effect, Stream } from 'effect';
3
+ import type { StorageError } from './errors.js';
4
+ import type { HookEventMap, HookName } from './hooks.js';
5
+ /** Options for {@link Storage.upload}, with `signal` and `onProgress` managed internally. */
6
+ export type UploadOptions = Omit<FilesSDK.UploadOptions, 'signal' | 'onProgress'>;
7
+ /**
8
+ * A key-bound handle to a single storage object.
9
+ *
10
+ * Returned by {@link StorageInterface.file} — every method operates on the
11
+ * pre-bound key so callers don't need to pass it on each call. Key
12
+ * validation happens eagerly at construction; all I/O defers to the
13
+ * underlying {@link StorageInterface} methods.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const avatar = svc.file("avatars/abc.png");
18
+ * yield* avatar.upload(body, { contentType: "image/png" });
19
+ * if (yield* avatar.exists()) {
20
+ * const meta = yield* avatar.head();
21
+ * }
22
+ * ```
23
+ */
24
+ export interface FileHandle {
25
+ /** The key this handle is bound to. */
26
+ readonly key: string;
27
+ readonly upload: (body: FilesSDK.Body, opts?: UploadOptions) => Effect.Effect<{
28
+ result: Effect.Effect<FilesSDK.UploadResult, StorageError>;
29
+ progress: Stream.Stream<FilesSDK.UploadProgress>;
30
+ }, never>;
31
+ readonly download: (opts?: FilesSDK.DownloadOptions) => Effect.Effect<FilesSDK.StoredFile, StorageError>;
32
+ readonly head: (opts?: FilesSDK.OperationOptions) => Effect.Effect<FilesSDK.StoredFile, StorageError>;
33
+ readonly exists: (opts?: FilesSDK.OperationOptions) => Effect.Effect<boolean, StorageError>;
34
+ readonly delete: (opts?: FilesSDK.OperationOptions) => Effect.Effect<void, StorageError>;
35
+ readonly url: (opts?: FilesSDK.UrlOptions) => Effect.Effect<string, StorageError>;
36
+ readonly signedUploadUrl: (opts: FilesSDK.SignUploadOptions) => Effect.Effect<FilesSDK.SignedUpload, StorageError>;
37
+ /**
38
+ * Copy the handle's object to a new key. The handle is the source.
39
+ * Shortcut for `Storage.copy(handle.key, destKey, opts)`.
40
+ */
41
+ readonly copyTo: (destKey: string, opts?: FilesSDK.OperationOptions) => Effect.Effect<void, StorageError>;
42
+ /**
43
+ * Copy from a source key into the handle's key. The handle is the destination.
44
+ * Shortcut for `Storage.copy(srcKey, handle.key, opts)`.
45
+ */
46
+ readonly copyFrom: (srcKey: string, opts?: FilesSDK.OperationOptions) => Effect.Effect<void, StorageError>;
47
+ }
48
+ /**
49
+ * Options passed to {@link Storage.make} to configure the underlying
50
+ * {@link FilesSDK.Files} instance.
51
+ *
52
+ * `adapter` and `hooks` are excluded — the adapter comes from the
53
+ * {@link StorageAdapter} context tag and hooks are wired internally to
54
+ * the PubSub event stream.
55
+ */
56
+ export type MakeOptions = Omit<FilesSDK.FilesOptions<FilesSDK.Adapter>, 'adapter' | 'hooks'>;
57
+ /**
58
+ * Type interface for the Storage service — separated from the
59
+ * implementation to keep each file focused and under the module-size
60
+ * guideline.
61
+ *
62
+ * The runtime {@link Context.Tag} lives in `service.ts` alongside
63
+ * {@link make} and {@link layer}.
64
+ */
65
+ export interface StorageInterface {
66
+ readonly upload: (
67
+ /** Object key (path) to store the object at. */
68
+ key: string,
69
+ /** Body content to upload (string, Buffer, ReadableStream, Blob, File, etc.). */
70
+ body: FilesSDK.Body,
71
+ /** Optional upload configuration (contentType, multipart threshold, etc.). */
72
+ opts?: UploadOptions) => Effect.Effect<{
73
+ result: Effect.Effect<FilesSDK.UploadResult, StorageError>;
74
+ progress: Stream.Stream<FilesSDK.UploadProgress>;
75
+ }, never>;
76
+ readonly download: (
77
+ /** Object key (path) to retrieve. */
78
+ key: string,
79
+ /** Optional download configuration (range, accept header, stream mode, etc.). */
80
+ opts?: FilesSDK.DownloadOptions) => Effect.Effect<FilesSDK.StoredFile, StorageError>;
81
+ readonly head: (
82
+ /** Object key (path) to inspect without downloading. */
83
+ key: string, opts?: FilesSDK.OperationOptions) => Effect.Effect<FilesSDK.StoredFile, StorageError>;
84
+ readonly exists: (
85
+ /** Object key (path) to check for existence. */
86
+ key: string, opts?: FilesSDK.OperationOptions) => Effect.Effect<boolean, StorageError>;
87
+ readonly delete: (
88
+ /** Object key (path) to permanently remove. */
89
+ key: string, opts?: FilesSDK.OperationOptions) => Effect.Effect<void, StorageError>;
90
+ readonly copy: (
91
+ /** Source key (path) to copy from. */
92
+ from: string,
93
+ /** Destination key (path) to copy to. */
94
+ to: string, opts?: FilesSDK.OperationOptions) => Effect.Effect<void, StorageError>;
95
+ readonly move: (
96
+ /** Source key (path) to move from. */
97
+ from: string,
98
+ /** Destination key (path) to move to. */
99
+ to: string, opts?: FilesSDK.OperationOptions) => Effect.Effect<void, StorageError>;
100
+ readonly list: (
101
+ /** Optional listing configuration (prefix, maxKeys, cursor, recursive, etc.). */
102
+ opts?: FilesSDK.ListOptions) => Effect.Effect<FilesSDK.ListResult, StorageError>;
103
+ readonly url: (
104
+ /** Object key (path) to generate a public/download URL for. */
105
+ key: string,
106
+ /** Optional URL configuration (expiresIn, etc.). */
107
+ opts?: FilesSDK.UrlOptions) => Effect.Effect<string, StorageError>;
108
+ readonly signedUploadUrl: (
109
+ /** Object key (path) to generate a signed upload URL for. */
110
+ key: string,
111
+ /** Required by the underlying SDK — `expiresIn` is always required;
112
+ * `contentType` and `maxSize` may also be needed depending on the adapter. */
113
+ opts: FilesSDK.SignUploadOptions) => Effect.Effect<FilesSDK.SignedUpload, StorageError>;
114
+ /**
115
+ * Create a {@link FileHandle} bound to a single key.
116
+ *
117
+ * The key is validated eagerly — an empty key throws synchronously.
118
+ * Every method on the handle delegates to the corresponding
119
+ * {@link StorageInterface} method, so adapters implement nothing extra.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * const avatar = svc.file("avatars/abc.png");
124
+ * yield* avatar.upload(body, { contentType: "image/png" });
125
+ * yield* avatar.copyTo("avatars/abc.bak.png");
126
+ * ```
127
+ */
128
+ readonly file: (key: string) => FileHandle;
129
+ /**
130
+ * Subscribe to constructor hook events as an Effect {@link Stream}.
131
+ *
132
+ * Events are emitted from an unbounded internal {@link PubSub} — every
133
+ * storage operation pushes into it, and the stream filters to the chosen
134
+ * hook kind. Multiple consumers can subscribe independently; each gets
135
+ * its own subscription.
136
+ *
137
+ * The stream ends when the storage layer's scope is released.
138
+ *
139
+ * **Note:** The internal PubSub is unbounded. If consumers never drain
140
+ * the stream, memory grows without limit. Always run the stream consumer
141
+ * or cancel it before producing a large volume of events.
142
+ *
143
+ * @example
144
+ * ```ts
145
+ * const svc = yield* Storage;
146
+ *
147
+ * // Stream of FilesActionEvent
148
+ * yield* svc.hookStream("onAction").pipe(
149
+ * Stream.runForEach((e) => Effect.log(`Storage ${e.type}: ${e.status}`)),
150
+ * Effect.forkScoped,
151
+ * );
152
+ * ```
153
+ */
154
+ readonly hookStream: <N extends HookName>(name: N) => Stream.Stream<HookEventMap[N], never>;
155
+ }
156
+ //# sourceMappingURL=service-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-types.d.ts","sourceRoot":"","sources":["../src/service-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEzD,6FAA6F;AAC7F,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,GAAG,YAAY,CAAC,CAAC;AAElF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,UAAU;IACzB,uCAAuC;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB,QAAQ,CAAC,MAAM,EAAE,CACf,IAAI,EAAE,QAAQ,CAAC,IAAI,EACnB,IAAI,CAAC,EAAE,aAAa,KACjB,MAAM,CAAC,MAAM,CAChB;QACE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAC3D,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;KAClD,EACD,KAAK,CACN,CAAC;IAEF,QAAQ,CAAC,QAAQ,EAAE,CACjB,IAAI,CAAC,EAAE,QAAQ,CAAC,eAAe,KAC5B,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAEtD,QAAQ,CAAC,IAAI,EAAE,CACb,IAAI,CAAC,EAAE,QAAQ,CAAC,gBAAgB,KAC7B,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAEtD,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,gBAAgB,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAE5F,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,gBAAgB,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAEzF,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAElF,QAAQ,CAAC,eAAe,EAAE,CACxB,IAAI,EAAE,QAAQ,CAAC,iBAAiB,KAC7B,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IAExD;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,CACf,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,QAAQ,CAAC,gBAAgB,KAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAEvC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,CACjB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,QAAQ,CAAC,gBAAgB,KAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;CACxC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC;AAE7F;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE;IACf,gDAAgD;IAChD,GAAG,EAAE,MAAM;IACX,iFAAiF;IACjF,IAAI,EAAE,QAAQ,CAAC,IAAI;IACnB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,aAAa,KACjB,MAAM,CAAC,MAAM,CAChB;QACE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAC3D,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;KAClD,EACD,KAAK,CACN,CAAC;IAEF,QAAQ,CAAC,QAAQ,EAAE;IACjB,qCAAqC;IACrC,GAAG,EAAE,MAAM;IACX,iFAAiF;IACjF,IAAI,CAAC,EAAE,QAAQ,CAAC,eAAe,KAC5B,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAEtD,QAAQ,CAAC,IAAI,EAAE;IACb,wDAAwD;IACxD,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,QAAQ,CAAC,gBAAgB,KAC7B,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAEtD,QAAQ,CAAC,MAAM,EAAE;IACf,gDAAgD;IAChD,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,QAAQ,CAAC,gBAAgB,KAC7B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAE1C,QAAQ,CAAC,MAAM,EAAE;IACf,+CAA+C;IAC/C,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,QAAQ,CAAC,gBAAgB,KAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAEvC,QAAQ,CAAC,IAAI,EAAE;IACb,sCAAsC;IACtC,IAAI,EAAE,MAAM;IACZ,yCAAyC;IACzC,EAAE,EAAE,MAAM,EACV,IAAI,CAAC,EAAE,QAAQ,CAAC,gBAAgB,KAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAEvC,QAAQ,CAAC,IAAI,EAAE;IACb,sCAAsC;IACtC,IAAI,EAAE,MAAM;IACZ,yCAAyC;IACzC,EAAE,EAAE,MAAM,EACV,IAAI,CAAC,EAAE,QAAQ,CAAC,gBAAgB,KAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAEvC,QAAQ,CAAC,IAAI,EAAE;IACb,iFAAiF;IACjF,IAAI,CAAC,EAAE,QAAQ,CAAC,WAAW,KACxB,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAEtD,QAAQ,CAAC,GAAG,EAAE;IACZ,+DAA+D;IAC/D,GAAG,EAAE,MAAM;IACX,oDAAoD;IACpD,IAAI,CAAC,EAAE,QAAQ,CAAC,UAAU,KACvB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAEzC,QAAQ,CAAC,eAAe,EAAE;IACxB,6DAA6D;IAC7D,GAAG,EAAE,MAAM;IACX;mFAC+E;IAC/E,IAAI,EAAE,QAAQ,CAAC,iBAAiB,KAC7B,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IAExD;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,CAAC;IAE3C;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,SAAS,QAAQ,EAAE,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;CAC7F"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=service-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-types.js","sourceRoot":"","sources":["../src/service-types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,66 @@
1
+ import { Context, Effect, Layer } from 'effect';
2
+ import { StorageAdapter } from './adapter.js';
3
+ import type { MakeOptions, StorageInterface } from './service-types.js';
4
+ declare const Storage_base: Context.TagClass<Storage, "@effect-pantry/storage/Storage", StorageInterface>;
5
+ /**
6
+ * Effect-native storage service wrapping a `files-sdk` {@link FilesSDK.Files} instance.
7
+ *
8
+ * Depends on {@link StorageAdapter} from the Effect context to create the underlying
9
+ * SDK client. Every method bridges the SDK's promise-based API to Effect,
10
+ * carrying typed errors via {@link StorageError} and automatically handling
11
+ * cancellation through Effect's interruption model.
12
+ *
13
+ * **Note:** Bulk operations (`uploadAll`, `downloadAll`, etc.) are not yet
14
+ * exposed on this service. Use {@link FilesSDK.Files} directly or combine
15
+ * individual calls with {@link Effect.all} for concurrent operations.
16
+ *
17
+ * Provide via {@link Storage.layer}.
18
+ */
19
+ export declare class Storage extends Storage_base {
20
+ }
21
+ /**
22
+ * Create a {@link Storage} service from the adapter found in the Effect context.
23
+ *
24
+ * Accepts optional {@link MakeOptions} to configure the underlying
25
+ * {@link FilesSDK.Files} instance (e.g. `prefix`, `timeout`, `retries`).
26
+ * The `adapter` and `hooks` options are managed internally and cannot be
27
+ * overridden.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const svc = yield* Storage.make();
32
+ * ```
33
+ *
34
+ * @example With options
35
+ * ```ts
36
+ * const svc = yield* Storage.make({ prefix: "uploads/", timeout: 30_000 });
37
+ * ```
38
+ */
39
+ export declare const make: (options?: MakeOptions) => Effect.Effect<StorageInterface, never, StorageAdapter>;
40
+ /**
41
+ * Create an {@link Effect.Layer} that requires {@link StorageAdapter} and provides
42
+ * {@link Storage}. The consumer supplies the adapter layer.
43
+ *
44
+ * Accepts optional {@link MakeOptions} forwarded to
45
+ * {@link make}.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * import { memory } from "files-sdk/memory";
50
+ * import { Storage, StorageAdapter } from "@effect-pantry/storage";
51
+ *
52
+ * const layer = Storage.layer().pipe(
53
+ * Layer.provide(Layer.succeed(StorageAdapter, memory())),
54
+ * );
55
+ * ```
56
+ *
57
+ * @example With options
58
+ * ```ts
59
+ * const layer = Storage.layer({ prefix: "app-data/" }).pipe(
60
+ * Layer.provide(Layer.succeed(StorageAdapter, memory())),
61
+ * );
62
+ * ```
63
+ */
64
+ export declare const layer: (options?: MakeOptions) => Layer.Layer<Storage, never, StorageAdapter>;
65
+ export {};
66
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAwB,MAAM,QAAQ,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,OAAO,KAAK,EAAc,WAAW,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;;AAEpF;;;;;;;;;;;;;GAaG;AACH,qBAAa,OAAQ,SAAQ,YAG1B;CAAG;AAEN;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,IAAI,aAAc,WAAW,2DAyEtC,CAAC;AAEL;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,KAAK,aAAc,WAAW,gDAAyC,CAAC"}
@@ -0,0 +1,110 @@
1
+ import * as FilesSDK from 'files-sdk';
2
+ import { Context, Effect, Layer, pipe, PubSub, Stream } from 'effect';
3
+ import { StorageAdapter } from './adapter.js';
4
+ import { bridgeProgress, wrapSDKCall } from './internal.js';
5
+ /**
6
+ * Effect-native storage service wrapping a `files-sdk` {@link FilesSDK.Files} instance.
7
+ *
8
+ * Depends on {@link StorageAdapter} from the Effect context to create the underlying
9
+ * SDK client. Every method bridges the SDK's promise-based API to Effect,
10
+ * carrying typed errors via {@link StorageError} and automatically handling
11
+ * cancellation through Effect's interruption model.
12
+ *
13
+ * **Note:** Bulk operations (`uploadAll`, `downloadAll`, etc.) are not yet
14
+ * exposed on this service. Use {@link FilesSDK.Files} directly or combine
15
+ * individual calls with {@link Effect.all} for concurrent operations.
16
+ *
17
+ * Provide via {@link Storage.layer}.
18
+ */
19
+ export class Storage extends Context.Tag('@effect-pantry/storage/Storage')() {
20
+ }
21
+ /**
22
+ * Create a {@link Storage} service from the adapter found in the Effect context.
23
+ *
24
+ * Accepts optional {@link MakeOptions} to configure the underlying
25
+ * {@link FilesSDK.Files} instance (e.g. `prefix`, `timeout`, `retries`).
26
+ * The `adapter` and `hooks` options are managed internally and cannot be
27
+ * overridden.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const svc = yield* Storage.make();
32
+ * ```
33
+ *
34
+ * @example With options
35
+ * ```ts
36
+ * const svc = yield* Storage.make({ prefix: "uploads/", timeout: 30_000 });
37
+ * ```
38
+ */
39
+ export const make = (options) => Effect.gen(function* () {
40
+ yield* Effect.logWarning('@effect-pantry/storage is in early development — APIs may change. Not recommended for production yet.');
41
+ const adapter = yield* StorageAdapter;
42
+ const pubsub = yield* PubSub.unbounded();
43
+ const offer = (event) => {
44
+ const ok = pubsub.unsafeOffer(event);
45
+ if (!ok) {
46
+ console.warn('[Storage] hook event dropped: PubSub not accepting');
47
+ }
48
+ };
49
+ const files = new FilesSDK.Files({
50
+ ...options,
51
+ adapter,
52
+ hooks: {
53
+ onAction: (event) => offer({ _tag: 'onAction', event }),
54
+ onError: (event) => offer({ _tag: 'onError', event }),
55
+ onRetry: (event) => offer({ _tag: 'onRetry', event }),
56
+ },
57
+ });
58
+ const svc = {
59
+ upload: (key, body, opts) => bridgeProgress((signal, onProgress) => files.upload(key, body, { ...opts, signal, onProgress })),
60
+ download: (key, opts) => wrapSDKCall((signal) => files.download(key, { ...opts, signal })),
61
+ head: (key, opts) => wrapSDKCall((signal) => files.head(key, { ...opts, signal })),
62
+ exists: (key, opts) => wrapSDKCall((signal) => files.exists(key, { ...opts, signal })),
63
+ delete: (key, opts) => wrapSDKCall((signal) => files.delete(key, { ...opts, signal })),
64
+ copy: (from, to, opts) => wrapSDKCall((signal) => files.copy(from, to, { ...opts, signal })),
65
+ move: (from, to, opts) => wrapSDKCall((signal) => files.move(from, to, { ...opts, signal })),
66
+ list: (opts) => wrapSDKCall((signal) => files.list({ ...opts, signal })),
67
+ url: (key, opts) => wrapSDKCall((signal) => files.url(key, { ...opts, signal })),
68
+ signedUploadUrl: (key, opts) => wrapSDKCall((signal) => files.signedUploadUrl(key, { ...opts, signal })),
69
+ hookStream: (name) => pipe(Stream.fromPubSub(pubsub), Stream.filter((e) => e._tag === name), Stream.map((e) => e.event)),
70
+ file: (key) => ({
71
+ key,
72
+ upload: (body, opts) => svc.upload(key, body, opts),
73
+ download: (opts) => svc.download(key, opts),
74
+ head: (opts) => svc.head(key, opts),
75
+ exists: (opts) => svc.exists(key, opts),
76
+ delete: (opts) => svc.delete(key, opts),
77
+ url: (opts) => svc.url(key, opts),
78
+ signedUploadUrl: (opts) => svc.signedUploadUrl(key, opts),
79
+ copyTo: (destKey, opts) => svc.copy(key, destKey, opts),
80
+ copyFrom: (srcKey, opts) => svc.copy(srcKey, key, opts),
81
+ }),
82
+ };
83
+ return Storage.of(svc);
84
+ });
85
+ /**
86
+ * Create an {@link Effect.Layer} that requires {@link StorageAdapter} and provides
87
+ * {@link Storage}. The consumer supplies the adapter layer.
88
+ *
89
+ * Accepts optional {@link MakeOptions} forwarded to
90
+ * {@link make}.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * import { memory } from "files-sdk/memory";
95
+ * import { Storage, StorageAdapter } from "@effect-pantry/storage";
96
+ *
97
+ * const layer = Storage.layer().pipe(
98
+ * Layer.provide(Layer.succeed(StorageAdapter, memory())),
99
+ * );
100
+ * ```
101
+ *
102
+ * @example With options
103
+ * ```ts
104
+ * const layer = Storage.layer({ prefix: "app-data/" }).pipe(
105
+ * Layer.provide(Layer.succeed(StorageAdapter, memory())),
106
+ * );
107
+ * ```
108
+ */
109
+ export const layer = (options) => Layer.effect(Storage, make(options));
110
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@effect-pantry/storage",
3
+ "version": "0.0.1",
4
+ "description": "Effect-native storage — wraps files-sdk as typed Effect functions with scope-managed lifecycle",
5
+ "keywords": [
6
+ "effect",
7
+ "file-storage",
8
+ "files-sdk",
9
+ "r2",
10
+ "s3"
11
+ ],
12
+ "homepage": "https://github.com/nipakke/effect-pantry/tree/main/packages/storage#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/nipakke/effect-pantry/issues"
15
+ },
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/nipakke/effect-pantry.git",
20
+ "directory": "packages/storage"
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "type": "module",
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "default": "./dist/index.js"
32
+ }
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "dependencies": {
38
+ "effect": "^3.21.2"
39
+ },
40
+ "devDependencies": {
41
+ "@effect/vitest": "^0.29.0",
42
+ "@types/node": "^25.8.0",
43
+ "@typescript/native-preview": "7.0.0-dev.20260515.1",
44
+ "@vitest/ui": "0.1.21",
45
+ "rimraf": "^6.0.1",
46
+ "vite-plus": "^0.1.21",
47
+ "vitest": "^3.2.0",
48
+ "@tooling/tsconfig": "0.0.1"
49
+ },
50
+ "peerDependencies": {
51
+ "files-sdk": "^1.6.0"
52
+ },
53
+ "engines": {
54
+ "node": ">=22"
55
+ },
56
+ "scripts": {
57
+ "clean": "rimraf dist",
58
+ "build": "pnpm clean && tsgo",
59
+ "test": "vitest run",
60
+ "check": "vp check",
61
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json"
62
+ }
63
+ }