@miguelmorales13/nestkit 0.4.0 → 0.5.0

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.
@@ -0,0 +1,528 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+ var _chunk2REOCMUDcjs = require('../chunk-2REOCMUD.cjs');
4
+
5
+ // src/storage/storage.port.ts
6
+ var STORAGE = /* @__PURE__ */ Symbol("STORAGE");
7
+
8
+ // src/storage/storage.options.ts
9
+ var STORAGE_OPTIONS = /* @__PURE__ */ Symbol("STORAGE_OPTIONS");
10
+
11
+ // src/storage/storage.module.ts
12
+ var _common = require('@nestjs/common');
13
+
14
+ // src/storage/adapters/local.storage.ts
15
+ var _fs = require('fs');
16
+ var _promises = require('fs/promises');
17
+ var _path = require('path');
18
+ var _promises3 = require('stream/promises');
19
+
20
+ var LocalStorage = class {
21
+ constructor(options) {
22
+ this.root = _path.resolve.call(void 0, options.root);
23
+ this.publicBaseUrl = _optionalChain([options, 'access', _ => _.publicBaseUrl, 'optionalAccess', _2 => _2.replace, 'call', _3 => _3(/\/$/, "")]);
24
+ }
25
+ /** Resolve a key to an absolute path, refusing anything that escapes the root. */
26
+ pathOf(key) {
27
+ const target = _path.resolve.call(void 0, _path.join.call(void 0, this.root, _path.normalize.call(void 0, key)));
28
+ if (target !== this.root && !target.startsWith(this.root + _path.sep)) {
29
+ throw new Error(`LocalStorage: key escapes the storage root: ${key}`);
30
+ }
31
+ return target;
32
+ }
33
+ async put(key, data) {
34
+ const path = this.pathOf(key);
35
+ await _promises.mkdir.call(void 0, _path.dirname.call(void 0, path), { recursive: true });
36
+ await _promises.writeFile.call(void 0, path, data);
37
+ return { key, size: data.byteLength };
38
+ }
39
+ async putStream(key, stream) {
40
+ const path = this.pathOf(key);
41
+ await _promises.mkdir.call(void 0, _path.dirname.call(void 0, path), { recursive: true });
42
+ await _promises3.pipeline.call(void 0, stream, _fs.createWriteStream.call(void 0, path));
43
+ const s = await _promises.stat.call(void 0, path);
44
+ return { key, size: s.size, lastModified: s.mtime };
45
+ }
46
+ async get(key) {
47
+ return _promises.readFile.call(void 0, this.pathOf(key));
48
+ }
49
+ async getStream(key, range) {
50
+ const path = this.pathOf(key);
51
+ const s = await _promises.stat.call(void 0, path);
52
+ if (!range) {
53
+ return { stream: _fs.createReadStream.call(void 0, path), contentLength: s.size, totalSize: s.size, lastModified: s.mtime };
54
+ }
55
+ const end = _nullishCoalesce(range.end, () => ( s.size - 1));
56
+ return {
57
+ stream: _fs.createReadStream.call(void 0, path, { start: range.start, end }),
58
+ contentLength: end - range.start + 1,
59
+ totalSize: s.size,
60
+ contentRange: `bytes ${range.start}-${end}/${s.size}`,
61
+ lastModified: s.mtime
62
+ };
63
+ }
64
+ async stat(key) {
65
+ try {
66
+ const s = await _promises.stat.call(void 0, this.pathOf(key));
67
+ return { key, size: s.size, lastModified: s.mtime };
68
+ } catch (e2) {
69
+ return null;
70
+ }
71
+ }
72
+ async exists(key) {
73
+ return await this.stat(key) !== null;
74
+ }
75
+ async delete(key) {
76
+ await _promises.rm.call(void 0, this.pathOf(key), { force: true });
77
+ }
78
+ async list(prefix, options) {
79
+ const base = this.pathOf(prefix);
80
+ const objects = [];
81
+ const walk = async (dir) => {
82
+ let entries;
83
+ try {
84
+ entries = await _promises.readdir.call(void 0, dir, { withFileTypes: true });
85
+ } catch (e3) {
86
+ return;
87
+ }
88
+ for (const entry of entries) {
89
+ if (_optionalChain([options, 'optionalAccess', _4 => _4.limit]) && objects.length >= options.limit) return;
90
+ const full = _path.join.call(void 0, dir, String(entry.name));
91
+ if (entry.isDirectory()) await walk(full);
92
+ else {
93
+ const s = await _promises.stat.call(void 0, full);
94
+ objects.push({ key: _path.relative.call(void 0, this.root, full).split(_path.sep).join("/"), size: s.size, lastModified: s.mtime });
95
+ }
96
+ }
97
+ };
98
+ await walk(base);
99
+ return { objects };
100
+ }
101
+ publicUrl(key) {
102
+ return this.publicBaseUrl ? `${this.publicBaseUrl}/${key}` : `/${key}`;
103
+ }
104
+ async signedReadUrl(key) {
105
+ return _nullishCoalesce(this.publicUrl(key), () => ( `/${key}`));
106
+ }
107
+ async signedUploadUrl() {
108
+ throw new Error(
109
+ "LocalStorage does not support direct signed uploads \u2014 a client cannot PUT to the server disk. Upload through your API in dev, or use the S3/R2 or Bunny adapter."
110
+ );
111
+ }
112
+ };
113
+
114
+ // src/storage/adapters/s3.storage.ts
115
+ var S3Storage = class {
116
+ constructor(options) {
117
+ this.bucket = options.bucket;
118
+ this.publicBaseUrl = _optionalChain([options, 'access', _5 => _5.publicBaseUrl, 'optionalAccess', _6 => _6.replace, 'call', _7 => _7(/\/$/, "")]);
119
+ this.config = {
120
+ region: _nullishCoalesce(options.region, () => ( "us-east-1")),
121
+ endpoint: options.endpoint,
122
+ forcePathStyle: options.forcePathStyle,
123
+ credentials: {
124
+ accessKeyId: options.accessKeyId,
125
+ secretAccessKey: options.secretAccessKey
126
+ }
127
+ };
128
+ }
129
+ /** Lazily construct (and memoize) the S3 client, loading the SDK on first use. */
130
+ async client() {
131
+ if (!this.clientPromise) {
132
+ this.clientPromise = Promise.resolve().then(() => _interopRequireWildcard(require("@aws-sdk/client-s3"))).then(
133
+ ({ S3Client }) => new S3Client(this.config)
134
+ );
135
+ }
136
+ return this.clientPromise;
137
+ }
138
+ async put(key, data, options) {
139
+ const [client, { PutObjectCommand }] = await Promise.all([
140
+ this.client(),
141
+ Promise.resolve().then(() => _interopRequireWildcard(require("@aws-sdk/client-s3")))
142
+ ]);
143
+ const out = await client.send(
144
+ new PutObjectCommand({
145
+ Bucket: this.bucket,
146
+ Key: key,
147
+ Body: data,
148
+ ContentType: _optionalChain([options, 'optionalAccess', _8 => _8.contentType]),
149
+ CacheControl: _optionalChain([options, 'optionalAccess', _9 => _9.cacheControl]),
150
+ ContentDisposition: _optionalChain([options, 'optionalAccess', _10 => _10.contentDisposition]),
151
+ Metadata: _optionalChain([options, 'optionalAccess', _11 => _11.metadata])
152
+ })
153
+ );
154
+ return { key, size: data.byteLength, contentType: _optionalChain([options, 'optionalAccess', _12 => _12.contentType]), etag: out.ETag };
155
+ }
156
+ async putStream(key, stream, options) {
157
+ const [client, { Upload }] = await Promise.all([this.client(), Promise.resolve().then(() => _interopRequireWildcard(require("@aws-sdk/lib-storage")))]);
158
+ const upload = new Upload({
159
+ client,
160
+ params: {
161
+ Bucket: this.bucket,
162
+ Key: key,
163
+ Body: stream,
164
+ ContentType: _optionalChain([options, 'optionalAccess', _13 => _13.contentType]),
165
+ CacheControl: _optionalChain([options, 'optionalAccess', _14 => _14.cacheControl]),
166
+ ContentDisposition: _optionalChain([options, 'optionalAccess', _15 => _15.contentDisposition]),
167
+ Metadata: _optionalChain([options, 'optionalAccess', _16 => _16.metadata])
168
+ }
169
+ });
170
+ const out = await upload.done();
171
+ const info = await this.stat(key);
172
+ return { key, size: _nullishCoalesce(_optionalChain([info, 'optionalAccess', _17 => _17.size]), () => ( 0)), contentType: _optionalChain([options, 'optionalAccess', _18 => _18.contentType]), etag: _optionalChain([out, 'optionalAccess', _19 => _19.ETag]) };
173
+ }
174
+ async get(key) {
175
+ const { stream } = await this.getStream(key);
176
+ const chunks = [];
177
+ for await (const chunk of stream) chunks.push(Buffer.from(chunk));
178
+ return Buffer.concat(chunks);
179
+ }
180
+ async getStream(key, range) {
181
+ const [client, { GetObjectCommand }] = await Promise.all([
182
+ this.client(),
183
+ Promise.resolve().then(() => _interopRequireWildcard(require("@aws-sdk/client-s3")))
184
+ ]);
185
+ const out = await client.send(
186
+ new GetObjectCommand({
187
+ Bucket: this.bucket,
188
+ Key: key,
189
+ Range: range ? `bytes=${range.start}-${_nullishCoalesce(range.end, () => ( ""))}` : void 0
190
+ })
191
+ );
192
+ return {
193
+ stream: out.Body,
194
+ contentType: out.ContentType,
195
+ contentLength: out.ContentLength,
196
+ contentRange: out.ContentRange,
197
+ totalSize: out.ContentRange ? Number(out.ContentRange.split("/")[1]) : out.ContentLength,
198
+ lastModified: out.LastModified,
199
+ etag: out.ETag
200
+ };
201
+ }
202
+ async stat(key) {
203
+ const [client, { HeadObjectCommand }] = await Promise.all([
204
+ this.client(),
205
+ Promise.resolve().then(() => _interopRequireWildcard(require("@aws-sdk/client-s3")))
206
+ ]);
207
+ try {
208
+ const out = await client.send(new HeadObjectCommand({ Bucket: this.bucket, Key: key }));
209
+ return {
210
+ key,
211
+ size: _nullishCoalesce(out.ContentLength, () => ( 0)),
212
+ contentType: out.ContentType,
213
+ lastModified: out.LastModified,
214
+ etag: out.ETag
215
+ };
216
+ } catch (err) {
217
+ if (_optionalChain([err, 'optionalAccess', _20 => _20.$metadata, 'optionalAccess', _21 => _21.httpStatusCode]) === 404 || _optionalChain([err, 'optionalAccess', _22 => _22.name]) === "NotFound") return null;
218
+ throw err;
219
+ }
220
+ }
221
+ async exists(key) {
222
+ return await this.stat(key) !== null;
223
+ }
224
+ async delete(key) {
225
+ const [client, { DeleteObjectCommand }] = await Promise.all([
226
+ this.client(),
227
+ Promise.resolve().then(() => _interopRequireWildcard(require("@aws-sdk/client-s3")))
228
+ ]);
229
+ await client.send(new DeleteObjectCommand({ Bucket: this.bucket, Key: key }));
230
+ }
231
+ async list(prefix, options) {
232
+ const [client, { ListObjectsV2Command }] = await Promise.all([
233
+ this.client(),
234
+ Promise.resolve().then(() => _interopRequireWildcard(require("@aws-sdk/client-s3")))
235
+ ]);
236
+ const out = await client.send(
237
+ new ListObjectsV2Command({
238
+ Bucket: this.bucket,
239
+ Prefix: prefix,
240
+ MaxKeys: _optionalChain([options, 'optionalAccess', _23 => _23.limit]),
241
+ ContinuationToken: _optionalChain([options, 'optionalAccess', _24 => _24.cursor])
242
+ })
243
+ );
244
+ return {
245
+ objects: (_nullishCoalesce(out.Contents, () => ( []))).map((o) => ({
246
+ key: o.Key,
247
+ size: _nullishCoalesce(o.Size, () => ( 0)),
248
+ lastModified: o.LastModified,
249
+ etag: o.ETag
250
+ })),
251
+ cursor: out.NextContinuationToken
252
+ };
253
+ }
254
+ async signedReadUrl(key, ttlSeconds = 3600) {
255
+ const [client, { GetObjectCommand }, { getSignedUrl }] = await Promise.all([
256
+ this.client(),
257
+ Promise.resolve().then(() => _interopRequireWildcard(require("@aws-sdk/client-s3"))),
258
+ Promise.resolve().then(() => _interopRequireWildcard(require("@aws-sdk/s3-request-presigner")))
259
+ ]);
260
+ return getSignedUrl(client, new GetObjectCommand({ Bucket: this.bucket, Key: key }), {
261
+ expiresIn: ttlSeconds
262
+ });
263
+ }
264
+ async signedUploadUrl(key, options) {
265
+ const [client, { PutObjectCommand }, { getSignedUrl }] = await Promise.all([
266
+ this.client(),
267
+ Promise.resolve().then(() => _interopRequireWildcard(require("@aws-sdk/client-s3"))),
268
+ Promise.resolve().then(() => _interopRequireWildcard(require("@aws-sdk/s3-request-presigner")))
269
+ ]);
270
+ const ttl = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _25 => _25.ttlSeconds]), () => ( 900));
271
+ const url = await getSignedUrl(
272
+ client,
273
+ new PutObjectCommand({
274
+ Bucket: this.bucket,
275
+ Key: key,
276
+ ContentType: _optionalChain([options, 'optionalAccess', _26 => _26.contentType]),
277
+ CacheControl: _optionalChain([options, 'optionalAccess', _27 => _27.cacheControl])
278
+ }),
279
+ { expiresIn: ttl }
280
+ );
281
+ return {
282
+ url,
283
+ method: "PUT",
284
+ headers: _optionalChain([options, 'optionalAccess', _28 => _28.contentType]) ? { "Content-Type": options.contentType } : void 0,
285
+ key,
286
+ expiresAt: new Date(Date.now() + ttl * 1e3)
287
+ };
288
+ }
289
+ publicUrl(key) {
290
+ return this.publicBaseUrl ? `${this.publicBaseUrl}/${key}` : null;
291
+ }
292
+ };
293
+
294
+ // src/storage/adapters/bunny.storage.ts
295
+ var _crypto = require('crypto');
296
+ var _stream = require('stream');
297
+ var BunnyStorage = class {
298
+ constructor(options) {
299
+ const host = `${options.region ? `${options.region}.` : ""}storage.bunnycdn.com`;
300
+ this.base = `https://${host}/${options.storageZone}`;
301
+ this.apiKey = options.apiKey;
302
+ this.pullZoneUrl = _optionalChain([options, 'access', _29 => _29.pullZoneUrl, 'optionalAccess', _30 => _30.replace, 'call', _31 => _31(/\/$/, "")]);
303
+ this.tokenSecurityKey = options.tokenSecurityKey;
304
+ }
305
+ url(key) {
306
+ return `${this.base}/${key.split("/").map(encodeURIComponent).join("/")}`;
307
+ }
308
+ async put(key, data, options) {
309
+ const res = await fetch(this.url(key), {
310
+ method: "PUT",
311
+ headers: {
312
+ AccessKey: this.apiKey,
313
+ "Content-Type": _nullishCoalesce(_optionalChain([options, 'optionalAccess', _32 => _32.contentType]), () => ( "application/octet-stream"))
314
+ },
315
+ body: data
316
+ });
317
+ if (!res.ok) throw new Error(`Bunny put ${key} failed: ${res.status} ${await res.text()}`);
318
+ return { key, size: data.byteLength, contentType: _optionalChain([options, 'optionalAccess', _33 => _33.contentType]) };
319
+ }
320
+ async putStream(key, stream, options) {
321
+ const res = await fetch(this.url(key), {
322
+ method: "PUT",
323
+ headers: {
324
+ AccessKey: this.apiKey,
325
+ "Content-Type": _nullishCoalesce(_optionalChain([options, 'optionalAccess', _34 => _34.contentType]), () => ( "application/octet-stream"))
326
+ },
327
+ body: _stream.Readable.toWeb(stream),
328
+ // Required by fetch when the body is a stream.
329
+ duplex: "half"
330
+ });
331
+ if (!res.ok) throw new Error(`Bunny putStream ${key} failed: ${res.status} ${await res.text()}`);
332
+ const info = await this.stat(key);
333
+ return { key, size: _nullishCoalesce(_nullishCoalesce(_optionalChain([info, 'optionalAccess', _35 => _35.size]), () => ( _optionalChain([options, 'optionalAccess', _36 => _36.contentLength]))), () => ( 0)), contentType: _optionalChain([options, 'optionalAccess', _37 => _37.contentType]) };
334
+ }
335
+ async get(key) {
336
+ const res = await fetch(this.url(key), { headers: { AccessKey: this.apiKey } });
337
+ if (!res.ok) throw new Error(`Bunny get ${key} failed: ${res.status}`);
338
+ return Buffer.from(await res.arrayBuffer());
339
+ }
340
+ async getStream(key, range) {
341
+ const headers = { AccessKey: this.apiKey };
342
+ if (range) headers.Range = `bytes=${range.start}-${_nullishCoalesce(range.end, () => ( ""))}`;
343
+ const res = await fetch(this.url(key), { headers });
344
+ if (!res.ok && res.status !== 206) throw new Error(`Bunny getStream ${key} failed: ${res.status}`);
345
+ if (!res.body) throw new Error(`Bunny getStream ${key}: empty body`);
346
+ const contentLength = Number(res.headers.get("content-length")) || void 0;
347
+ const contentRange = _nullishCoalesce(res.headers.get("content-range"), () => ( void 0));
348
+ return {
349
+ stream: _stream.Readable.fromWeb(res.body),
350
+ contentType: _nullishCoalesce(res.headers.get("content-type"), () => ( void 0)),
351
+ contentLength,
352
+ contentRange,
353
+ totalSize: contentRange ? Number(contentRange.split("/")[1]) : contentLength
354
+ };
355
+ }
356
+ async stat(key) {
357
+ const slash = key.lastIndexOf("/");
358
+ const dir = slash >= 0 ? key.slice(0, slash) : "";
359
+ const name = slash >= 0 ? key.slice(slash + 1) : key;
360
+ const entries = await this.listRaw(dir);
361
+ const found = entries.find((e) => !e.IsDirectory && e.ObjectName === name);
362
+ if (!found) return null;
363
+ return {
364
+ key,
365
+ size: found.Length,
366
+ contentType: found.ContentType || void 0,
367
+ lastModified: found.LastChanged ? new Date(found.LastChanged) : void 0
368
+ };
369
+ }
370
+ async exists(key) {
371
+ return await this.stat(key) !== null;
372
+ }
373
+ async delete(key) {
374
+ const res = await fetch(this.url(key), { method: "DELETE", headers: { AccessKey: this.apiKey } });
375
+ if (!res.ok && res.status !== 404) {
376
+ throw new Error(`Bunny delete ${key} failed: ${res.status} ${await res.text()}`);
377
+ }
378
+ }
379
+ async listRaw(prefix) {
380
+ const path = prefix ? `${prefix.replace(/\/$/, "")}/` : "";
381
+ const res = await fetch(`${this.base}/${path}`, { headers: { AccessKey: this.apiKey } });
382
+ if (res.status === 404) return [];
383
+ if (!res.ok) throw new Error(`Bunny list ${prefix} failed: ${res.status}`);
384
+ return await res.json();
385
+ }
386
+ async list(prefix, options) {
387
+ const entries = await this.listRaw(prefix);
388
+ const base = prefix ? `${prefix.replace(/\/$/, "")}/` : "";
389
+ let objects = entries.filter((e) => !e.IsDirectory).map((e) => ({
390
+ key: `${base}${e.ObjectName}`,
391
+ size: e.Length,
392
+ contentType: e.ContentType || void 0,
393
+ lastModified: e.LastChanged ? new Date(e.LastChanged) : void 0
394
+ }));
395
+ if (_optionalChain([options, 'optionalAccess', _38 => _38.limit])) objects = objects.slice(0, options.limit);
396
+ return { objects };
397
+ }
398
+ publicUrl(key) {
399
+ if (!this.pullZoneUrl) return null;
400
+ return `${this.pullZoneUrl}/${key.split("/").map(encodeURIComponent).join("/")}`;
401
+ }
402
+ async signedReadUrl(key, ttlSeconds = 3600) {
403
+ if (!this.pullZoneUrl) {
404
+ throw new Error("BunnyStorage.signedReadUrl: set pullZoneUrl (Bunny signs Pull Zone URLs).");
405
+ }
406
+ if (!this.tokenSecurityKey) {
407
+ return this.publicUrl(key);
408
+ }
409
+ const path = `/${key.split("/").map(encodeURIComponent).join("/")}`;
410
+ const expires = Math.floor(Date.now() / 1e3) + ttlSeconds;
411
+ const token = _crypto.createHash.call(void 0, "sha256").update(this.tokenSecurityKey + path + expires).digest("base64").replace(/\n/g, "").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
412
+ return `${this.pullZoneUrl}${path}?token=${token}&expires=${expires}`;
413
+ }
414
+ async signedUploadUrl() {
415
+ throw new Error(
416
+ "BunnyStorage does not support presigned direct uploads (Storage has no PUT signature that hides the zone password). Upload through your API, or use Bunny Stream/TUS for large video."
417
+ );
418
+ }
419
+ };
420
+
421
+ // src/storage/storage.module.ts
422
+ var env = (k) => process.env[k] || void 0;
423
+ function r2ToS3Options(r2) {
424
+ return {
425
+ bucket: r2.bucket,
426
+ region: "auto",
427
+ endpoint: `https://${r2.accountId}.r2.cloudflarestorage.com`,
428
+ accessKeyId: r2.accessKeyId,
429
+ secretAccessKey: r2.secretAccessKey,
430
+ publicBaseUrl: r2.publicBaseUrl
431
+ };
432
+ }
433
+ function resolveStorageOptions(options = {}) {
434
+ const provider = _nullishCoalesce(_nullishCoalesce(options.provider, () => ( env("STORAGE_PROVIDER"))), () => ( "local"));
435
+ return {
436
+ provider,
437
+ local: _nullishCoalesce(options.local, () => ( {
438
+ root: _nullishCoalesce(env("STORAGE_LOCAL_ROOT"), () => ( ".storage")),
439
+ publicBaseUrl: env("STORAGE_PUBLIC_BASE_URL")
440
+ })),
441
+ s3: _nullishCoalesce(options.s3, () => ( (env("S3_BUCKET") ? {
442
+ bucket: env("S3_BUCKET"),
443
+ region: env("S3_REGION"),
444
+ endpoint: env("S3_ENDPOINT"),
445
+ accessKeyId: _nullishCoalesce(env("S3_ACCESS_KEY_ID"), () => ( "")),
446
+ secretAccessKey: _nullishCoalesce(env("S3_SECRET_ACCESS_KEY"), () => ( "")),
447
+ publicBaseUrl: env("S3_PUBLIC_BASE_URL"),
448
+ forcePathStyle: env("S3_FORCE_PATH_STYLE") === "true"
449
+ } : void 0))),
450
+ r2: _nullishCoalesce(options.r2, () => ( (env("R2_ACCOUNT_ID") ? {
451
+ accountId: env("R2_ACCOUNT_ID"),
452
+ bucket: _nullishCoalesce(env("R2_BUCKET"), () => ( "")),
453
+ accessKeyId: _nullishCoalesce(env("R2_ACCESS_KEY_ID"), () => ( "")),
454
+ secretAccessKey: _nullishCoalesce(env("R2_SECRET_ACCESS_KEY"), () => ( "")),
455
+ publicBaseUrl: env("R2_PUBLIC_BASE_URL")
456
+ } : void 0))),
457
+ bunny: _nullishCoalesce(options.bunny, () => ( (env("BUNNY_STORAGE_ZONE") ? {
458
+ storageZone: env("BUNNY_STORAGE_ZONE"),
459
+ apiKey: _nullishCoalesce(env("BUNNY_API_KEY"), () => ( "")),
460
+ region: env("BUNNY_REGION"),
461
+ pullZoneUrl: env("BUNNY_PULL_ZONE_URL"),
462
+ tokenSecurityKey: env("BUNNY_TOKEN_SECURITY_KEY")
463
+ } : void 0)))
464
+ };
465
+ }
466
+ function createStorageAdapter(options) {
467
+ const resolved = resolveStorageOptions(options);
468
+ switch (resolved.provider) {
469
+ case "local":
470
+ return new LocalStorage(resolved.local);
471
+ case "s3":
472
+ if (!resolved.s3) throw new Error('StorageModule: provider "s3" selected but no s3 options / S3_* env set.');
473
+ return new S3Storage(resolved.s3);
474
+ case "r2":
475
+ if (!resolved.r2) throw new Error('StorageModule: provider "r2" selected but no r2 options / R2_* env set.');
476
+ return new S3Storage(r2ToS3Options(resolved.r2));
477
+ case "bunny":
478
+ if (!resolved.bunny)
479
+ throw new Error('StorageModule: provider "bunny" selected but no bunny options / BUNNY_* env set.');
480
+ return new BunnyStorage(resolved.bunny);
481
+ default:
482
+ throw new Error(`StorageModule: unknown provider "${resolved.provider}".`);
483
+ }
484
+ }
485
+ var StorageModule = class {
486
+ static forRoot(options = {}) {
487
+ const providers = [
488
+ { provide: STORAGE_OPTIONS, useValue: options },
489
+ { provide: STORAGE, useFactory: () => createStorageAdapter(options) }
490
+ ];
491
+ return { module: StorageModule, providers, exports: [STORAGE, STORAGE_OPTIONS] };
492
+ }
493
+ static forRootAsync(config) {
494
+ const providers = [
495
+ {
496
+ provide: STORAGE_OPTIONS,
497
+ useFactory: config.useFactory,
498
+ inject: _nullishCoalesce(config.inject, () => ( []))
499
+ },
500
+ {
501
+ provide: STORAGE,
502
+ useFactory: (options) => createStorageAdapter(options),
503
+ inject: [STORAGE_OPTIONS]
504
+ }
505
+ ];
506
+ return {
507
+ module: StorageModule,
508
+ imports: _nullishCoalesce(config.imports, () => ( [])),
509
+ providers,
510
+ exports: [STORAGE, STORAGE_OPTIONS]
511
+ };
512
+ }
513
+ };
514
+ StorageModule = exports.StorageModule = _chunk2REOCMUDcjs.__decorateClass.call(void 0, [
515
+ _common.Global.call(void 0, ),
516
+ _common.Module.call(void 0, {})
517
+ ], StorageModule);
518
+
519
+
520
+
521
+
522
+
523
+
524
+
525
+
526
+
527
+
528
+ exports.BunnyStorage = BunnyStorage; exports.LocalStorage = LocalStorage; exports.S3Storage = S3Storage; exports.STORAGE = STORAGE; exports.STORAGE_OPTIONS = STORAGE_OPTIONS; exports.StorageModule = StorageModule; exports.createStorageAdapter = createStorageAdapter; exports.r2ToS3Options = r2ToS3Options; exports.resolveStorageOptions = resolveStorageOptions;
@@ -0,0 +1,8 @@
1
+ export { STORAGE } from './storage.port.js';
2
+ export type { StoragePort, PutOptions, ObjectInfo, ByteRange, ReadStream, SignedUploadTarget, ListResult, } from './storage.port.js';
3
+ export { STORAGE_OPTIONS } from './storage.options.js';
4
+ export type { StorageOptions, StorageProvider, LocalStorageOptions, S3StorageOptions, R2StorageOptions, BunnyStorageOptions, } from './storage.options.js';
5
+ export { StorageModule, createStorageAdapter, resolveStorageOptions, r2ToS3Options, } from './storage.module.js';
6
+ export { LocalStorage } from './adapters/local.storage.js';
7
+ export { S3Storage } from './adapters/s3.storage.js';
8
+ export { BunnyStorage } from './adapters/bunny.storage.js';