@velajs/storage 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/CHANGELOG.md +6 -1
  2. package/dist/body-BMUcBeQ0.js +93 -0
  3. package/dist/body-BMUcBeQ0.js.map +1 -0
  4. package/dist/client/index.d.ts +49 -46
  5. package/dist/client/index.js +207 -228
  6. package/dist/client/index.js.map +1 -0
  7. package/dist/drivers/memory/index.d.ts +17 -13
  8. package/dist/drivers/memory/index.js +190 -197
  9. package/dist/drivers/memory/index.js.map +1 -0
  10. package/dist/drivers/r2/index.d.ts +7 -4
  11. package/dist/drivers/r2/index.js +162 -160
  12. package/dist/drivers/r2/index.js.map +1 -0
  13. package/dist/drivers/r2-http/index.d.ts +23 -19
  14. package/dist/drivers/r2-http/index.js +52 -45
  15. package/dist/drivers/r2-http/index.js.map +1 -0
  16. package/dist/drivers/s3/index.d.ts +79 -5
  17. package/dist/drivers/s3/index.js +2 -3
  18. package/dist/index.d.ts +271 -17
  19. package/dist/index.js +1078 -16
  20. package/dist/index.js.map +1 -0
  21. package/dist/middleware/index.d.ts +177 -15
  22. package/dist/middleware/index.js +553 -8
  23. package/dist/middleware/index.js.map +1 -0
  24. package/dist/protocol.types-C5PPBD12.d.ts +80 -0
  25. package/dist/r2.types-Bw4Ft83t.d.ts +71 -0
  26. package/dist/retry-DXtO6R9D.js +119 -0
  27. package/dist/retry-DXtO6R9D.js.map +1 -0
  28. package/dist/s3-DrE9NrnD.js +557 -0
  29. package/dist/s3-DrE9NrnD.js.map +1 -0
  30. package/dist/storage.error-DVCOkJhc.js +49 -0
  31. package/dist/storage.error-DVCOkJhc.js.map +1 -0
  32. package/dist/storage.types-BJN7Yp1J.d.ts +288 -0
  33. package/dist/storagesdk/index.d.ts +73 -69
  34. package/dist/storagesdk/index.js +117 -130
  35. package/dist/storagesdk/index.js.map +1 -0
  36. package/dist/stored-file-2Yl07eRc.js +105 -0
  37. package/dist/stored-file-2Yl07eRc.js.map +1 -0
  38. package/dist/testing/index.d.ts +12 -8
  39. package/dist/testing/index.js +36 -53
  40. package/dist/testing/index.js.map +1 -0
  41. package/package.json +62 -48
  42. package/dist/base64.d.ts +0 -8
  43. package/dist/base64.js +0 -25
  44. package/dist/decorators/inject-storage.decorator.d.ts +0 -17
  45. package/dist/decorators/inject-storage.decorator.js +0 -21
  46. package/dist/drivers/r2/r2.types.d.ts +0 -67
  47. package/dist/drivers/r2/r2.types.js +0 -5
  48. package/dist/drivers/s3/s3-client.d.ts +0 -33
  49. package/dist/drivers/s3/s3-client.js +0 -154
  50. package/dist/drivers/s3/s3.driver.d.ts +0 -4
  51. package/dist/drivers/s3/s3.driver.js +0 -407
  52. package/dist/drivers/s3/s3.types.d.ts +0 -28
  53. package/dist/drivers/s3/s3.types.js +0 -1
  54. package/dist/drivers/s3/xml.d.ts +0 -6
  55. package/dist/drivers/s3/xml.js +0 -52
  56. package/dist/http/authorizer.types.d.ts +0 -59
  57. package/dist/http/authorizer.types.js +0 -1
  58. package/dist/http/http-helpers.d.ts +0 -22
  59. package/dist/http/http-helpers.js +0 -80
  60. package/dist/http/protocol.types.d.ts +0 -76
  61. package/dist/http/protocol.types.js +0 -1
  62. package/dist/internal/body.d.ts +0 -18
  63. package/dist/internal/body.js +0 -90
  64. package/dist/internal/retry.d.ts +0 -41
  65. package/dist/internal/retry.js +0 -127
  66. package/dist/internal/stored-file.d.ts +0 -27
  67. package/dist/internal/stored-file.js +0 -114
  68. package/dist/middleware/cache.d.ts +0 -50
  69. package/dist/middleware/cache.js +0 -101
  70. package/dist/middleware/compose.d.ts +0 -12
  71. package/dist/middleware/compose.js +0 -11
  72. package/dist/middleware/compression.d.ts +0 -16
  73. package/dist/middleware/compression.js +0 -101
  74. package/dist/middleware/encryption.d.ts +0 -14
  75. package/dist/middleware/encryption.js +0 -134
  76. package/dist/middleware/failover.d.ts +0 -18
  77. package/dist/middleware/failover.js +0 -52
  78. package/dist/middleware/retry.d.ts +0 -14
  79. package/dist/middleware/retry.js +0 -47
  80. package/dist/middleware/versioning.d.ts +0 -36
  81. package/dist/middleware/versioning.js +0 -89
  82. package/dist/middleware/wrap.d.ts +0 -11
  83. package/dist/middleware/wrap.js +0 -46
  84. package/dist/object-key.d.ts +0 -17
  85. package/dist/object-key.js +0 -42
  86. package/dist/storage.controller.d.ts +0 -21
  87. package/dist/storage.controller.js +0 -386
  88. package/dist/storage.error.d.ts +0 -38
  89. package/dist/storage.error.js +0 -52
  90. package/dist/storage.facade.d.ts +0 -47
  91. package/dist/storage.facade.js +0 -443
  92. package/dist/storage.module.d.ts +0 -46
  93. package/dist/storage.module.js +0 -113
  94. package/dist/storage.service.d.ts +0 -42
  95. package/dist/storage.service.js +0 -86
  96. package/dist/storage.tokens.d.ts +0 -13
  97. package/dist/storage.tokens.js +0 -26
  98. package/dist/storage.types.d.ts +0 -245
  99. package/dist/storage.types.js +0 -1
@@ -1,21 +0,0 @@
1
- import { type Token, type Type } from '@velajs/vela';
2
- import type { StorageService } from './storage.service';
3
- import type { StorageAuthorizer } from './http/authorizer.types';
4
- export interface ResolvedHttpOptions {
5
- driverName: string;
6
- authorize?: StorageAuthorizer;
7
- defaultPolicy: 'deny' | 'allow';
8
- download: 'redirect' | 'proxy';
9
- defaultExpiresIn: number;
10
- maxExpiresIn: number;
11
- maxUploadSize?: number;
12
- maxListLimit: number;
13
- deleteConcurrency: number;
14
- }
15
- /**
16
- * Build a vela controller exposing presigned/multipart upload + download
17
- * endpoints for one bucket. Factory-decorated (like better-auth's catch-all)
18
- * so `basePath` bakes in at decoration time. Consumes the {@link StorageService}
19
- * facade so gating/retry/prefix apply uniformly on the HTTP path.
20
- */
21
- export declare function createStorageController(basePath: string, serviceToken: Token<StorageService>, http: ResolvedHttpOptions): Type;
@@ -1,386 +0,0 @@
1
- function _ts_decorate(decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- }
7
- function _ts_metadata(k, v) {
8
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
- }
10
- function _ts_param(paramIndex, decorator) {
11
- return function(target, key) {
12
- decorator(target, key, paramIndex);
13
- };
14
- }
15
- import { Controller, Get, Inject, Injectable, Post, Req } from "@velajs/vela";
16
- import { sanitizeKey } from "./object-key.js";
17
- import { StorageError } from "./storage.error.js";
18
- import { clampExpiry, dispositionHeader, mapError, parseRange, serializeStored } from "./http/http-helpers.js";
19
- /**
20
- * Build a vela controller exposing presigned/multipart upload + download
21
- * endpoints for one bucket. Factory-decorated (like better-auth's catch-all)
22
- * so `basePath` bakes in at decoration time. Consumes the {@link StorageService}
23
- * facade so gating/retry/prefix apply uniformly on the HTTP path.
24
- */ export function createStorageController(basePath, serviceToken, http) {
25
- let StorageController = class StorageController {
26
- svc;
27
- constructor(svc){
28
- this.svc = svc;
29
- }
30
- get storage() {
31
- return this.svc.storage;
32
- }
33
- async authorize(c, action) {
34
- if (!http.authorize) {
35
- if (http.defaultPolicy === 'allow') return {};
36
- throw new StorageError('AccessDenied', 'storage: no authorizer configured (default deny)');
37
- }
38
- const res = await http.authorize(action, {
39
- req: c.req.raw,
40
- ctx: c,
41
- driver: http.driverName
42
- });
43
- if (res === false) throw new StorageError('AccessDenied', 'not allowed');
44
- if (res === true) return {};
45
- return res;
46
- }
47
- fail(c, e) {
48
- const err = e instanceof StorageError ? e : StorageError.wrap(e);
49
- const { wire, status } = mapError(err.code);
50
- // Never echo a provider/transport/wrapped message to the client: those are
51
- // flagged `internal` (driver <Message>/<Code>, StorageError.wrap, fromStatus)
52
- // and can carry host/bucket/credential detail — including on a 4xx status.
53
- // Redact internal errors at any status, plus all upstream (5xx) responses;
54
- // 4xx codes with an author-vouched message echo it.
55
- const message = err.internal || status >= 500 ? 'storage backend error' : err.message;
56
- return c.json({
57
- error: {
58
- code: wire,
59
- message
60
- }
61
- }, status);
62
- }
63
- async signUpload(c) {
64
- try {
65
- const b = await c.req.json();
66
- const ov = await this.authorize(c, {
67
- type: 'sign-upload',
68
- key: b.key,
69
- contentType: b.contentType,
70
- size: b.size
71
- });
72
- const key = sanitizeKey(ov.key ?? b.key);
73
- const upload = await this.storage.signedUploadUrl(key, {
74
- expiresIn: clampExpiry(ov.expiresIn ?? b.expiresIn, http.defaultExpiresIn, http.maxExpiresIn),
75
- contentType: b.contentType,
76
- maxSize: ov.maxSize ?? http.maxUploadSize
77
- });
78
- return c.json({
79
- key,
80
- upload
81
- });
82
- } catch (e) {
83
- return this.fail(c, e);
84
- }
85
- }
86
- async multipartCreate(c) {
87
- try {
88
- const b = await c.req.json();
89
- const ov = await this.authorize(c, {
90
- type: 'multipart-create',
91
- key: b.key,
92
- contentType: b.contentType
93
- });
94
- const key = sanitizeKey(ov.key ?? b.key);
95
- const sm = this.storage.signedMultipart;
96
- if (!sm) throw new StorageError('Unsupported', 'presigned multipart not supported');
97
- const created = await sm.create(key, {
98
- contentType: b.contentType,
99
- metadata: ov.metadata ?? b.metadata,
100
- partSize: b.partSize
101
- });
102
- return c.json({
103
- key,
104
- uploadId: created.uploadId,
105
- partSize: created.partSize
106
- });
107
- } catch (e) {
108
- return this.fail(c, e);
109
- }
110
- }
111
- async multipartSignPart(c) {
112
- try {
113
- const b = await c.req.json();
114
- const ov = await this.authorize(c, {
115
- type: 'multipart-sign-part',
116
- key: b.key,
117
- uploadId: b.uploadId,
118
- partNumber: b.partNumber
119
- });
120
- const key = sanitizeKey(ov.key ?? b.key);
121
- const sm = this.storage.signedMultipart;
122
- if (!sm) throw new StorageError('Unsupported', 'presigned multipart not supported');
123
- const part = await sm.signPart(key, b.uploadId, b.partNumber, {
124
- expiresIn: clampExpiry(ov.expiresIn, http.defaultExpiresIn, http.maxExpiresIn)
125
- });
126
- return c.json({
127
- partNumber: b.partNumber,
128
- method: 'PUT',
129
- url: part.url,
130
- headers: part.headers
131
- });
132
- } catch (e) {
133
- return this.fail(c, e);
134
- }
135
- }
136
- async multipartComplete(c) {
137
- try {
138
- const b = await c.req.json();
139
- const ov = await this.authorize(c, {
140
- type: 'multipart-complete',
141
- key: b.key,
142
- uploadId: b.uploadId
143
- });
144
- const key = sanitizeKey(ov.key ?? b.key);
145
- const sm = this.storage.signedMultipart;
146
- if (!sm) throw new StorageError('Unsupported', 'presigned multipart not supported');
147
- return c.json(await sm.complete(key, b.uploadId, b.parts));
148
- } catch (e) {
149
- return this.fail(c, e);
150
- }
151
- }
152
- async multipartAbort(c) {
153
- try {
154
- const b = await c.req.json();
155
- const ov = await this.authorize(c, {
156
- type: 'multipart-abort',
157
- key: b.key,
158
- uploadId: b.uploadId
159
- });
160
- const key = sanitizeKey(ov.key ?? b.key);
161
- const sm = this.storage.signedMultipart;
162
- if (!sm) throw new StorageError('Unsupported', 'presigned multipart not supported');
163
- await sm.abort(key, b.uploadId);
164
- return c.json({
165
- ok: true
166
- });
167
- } catch (e) {
168
- return this.fail(c, e);
169
- }
170
- }
171
- async list(c) {
172
- try {
173
- const prefix = c.req.query('prefix');
174
- const ov = await this.authorize(c, {
175
- type: 'list',
176
- prefix
177
- });
178
- const limit = c.req.query('limit');
179
- const res = await this.storage.list({
180
- prefix: ov.prefix ?? prefix,
181
- cursor: c.req.query('cursor'),
182
- delimiter: c.req.query('delimiter'),
183
- limit: limit ? Math.min(Number(limit), http.maxListLimit) : undefined
184
- });
185
- return c.json({
186
- items: res.items.map(serializeStored),
187
- prefixes: res.prefixes,
188
- cursor: res.cursor
189
- });
190
- } catch (e) {
191
- return this.fail(c, e);
192
- }
193
- }
194
- async head(c) {
195
- try {
196
- const key = sanitizeKey(c.req.query('key') ?? '');
197
- const ov = await this.authorize(c, {
198
- type: 'head',
199
- key
200
- });
201
- const file = await this.storage.head(sanitizeKey(ov.key ?? key));
202
- return c.json(serializeStored(file));
203
- } catch (e) {
204
- return this.fail(c, e);
205
- }
206
- }
207
- async delete(c) {
208
- try {
209
- const b = await c.req.json();
210
- const keys = b.keys.map((k)=>sanitizeKey(k));
211
- const ov = await this.authorize(c, {
212
- type: 'delete',
213
- keys
214
- });
215
- const effective = (ov.keys ?? keys).map((k)=>sanitizeKey(k));
216
- return c.json(await this.storage.delete(effective, {
217
- concurrency: http.deleteConcurrency
218
- }));
219
- } catch (e) {
220
- return this.fail(c, e);
221
- }
222
- }
223
- async download(c) {
224
- try {
225
- const key = sanitizeKey(c.req.query('key') ?? '');
226
- const disp = c.req.query('disposition');
227
- const ov = await this.authorize(c, {
228
- type: 'download',
229
- key
230
- });
231
- const ekey = sanitizeKey(ov.key ?? key);
232
- const name = ekey.slice(ekey.lastIndexOf('/') + 1);
233
- if (http.download === 'redirect' && this.storage.capabilities.signedUrl.supported) {
234
- const url = await this.storage.url(ekey, {
235
- expiresIn: clampExpiry(ov.expiresIn, http.defaultExpiresIn, http.maxExpiresIn),
236
- responseContentDisposition: dispositionHeader(disp, name)
237
- });
238
- return c.redirect(url, 302);
239
- }
240
- const range = parseRange(c.req.header('range'));
241
- const file = await this.storage.download(ekey, range ? {
242
- range
243
- } : undefined);
244
- const headers = new Headers({
245
- 'content-type': file.type,
246
- 'content-length': String(file.size),
247
- 'content-disposition': dispositionHeader(disp, file.name)
248
- });
249
- if (file.etag) headers.set('etag', file.etag);
250
- if (range) {
251
- headers.set('content-range', `bytes ${range.start}-${range.start + file.size - 1}/*`);
252
- return new Response(file.stream(), {
253
- status: 206,
254
- headers
255
- });
256
- }
257
- return new Response(file.stream(), {
258
- status: 200,
259
- headers
260
- });
261
- } catch (e) {
262
- return this.fail(c, e);
263
- }
264
- }
265
- async signDownload(c) {
266
- try {
267
- const b = await c.req.json();
268
- const ov = await this.authorize(c, {
269
- type: 'download',
270
- key: b.key
271
- });
272
- const key = sanitizeKey(ov.key ?? b.key);
273
- const expiresIn = clampExpiry(ov.expiresIn ?? b.expiresIn, http.defaultExpiresIn, http.maxExpiresIn);
274
- const url = await this.storage.url(key, {
275
- expiresIn
276
- });
277
- return c.json({
278
- url,
279
- expiresAt: Date.now() + expiresIn * 1000
280
- });
281
- } catch (e) {
282
- return this.fail(c, e);
283
- }
284
- }
285
- };
286
- _ts_decorate([
287
- Post('/sign-upload'),
288
- _ts_param(0, Req()),
289
- _ts_metadata("design:type", Function),
290
- _ts_metadata("design:paramtypes", [
291
- typeof Context === "undefined" ? Object : Context
292
- ]),
293
- _ts_metadata("design:returntype", Promise)
294
- ], StorageController.prototype, "signUpload", null);
295
- _ts_decorate([
296
- Post('/multipart/create'),
297
- _ts_param(0, Req()),
298
- _ts_metadata("design:type", Function),
299
- _ts_metadata("design:paramtypes", [
300
- typeof Context === "undefined" ? Object : Context
301
- ]),
302
- _ts_metadata("design:returntype", Promise)
303
- ], StorageController.prototype, "multipartCreate", null);
304
- _ts_decorate([
305
- Post('/multipart/sign-part'),
306
- _ts_param(0, Req()),
307
- _ts_metadata("design:type", Function),
308
- _ts_metadata("design:paramtypes", [
309
- typeof Context === "undefined" ? Object : Context
310
- ]),
311
- _ts_metadata("design:returntype", Promise)
312
- ], StorageController.prototype, "multipartSignPart", null);
313
- _ts_decorate([
314
- Post('/multipart/complete'),
315
- _ts_param(0, Req()),
316
- _ts_metadata("design:type", Function),
317
- _ts_metadata("design:paramtypes", [
318
- typeof Context === "undefined" ? Object : Context
319
- ]),
320
- _ts_metadata("design:returntype", Promise)
321
- ], StorageController.prototype, "multipartComplete", null);
322
- _ts_decorate([
323
- Post('/multipart/abort'),
324
- _ts_param(0, Req()),
325
- _ts_metadata("design:type", Function),
326
- _ts_metadata("design:paramtypes", [
327
- typeof Context === "undefined" ? Object : Context
328
- ]),
329
- _ts_metadata("design:returntype", Promise)
330
- ], StorageController.prototype, "multipartAbort", null);
331
- _ts_decorate([
332
- Get('/list'),
333
- _ts_param(0, Req()),
334
- _ts_metadata("design:type", Function),
335
- _ts_metadata("design:paramtypes", [
336
- typeof Context === "undefined" ? Object : Context
337
- ]),
338
- _ts_metadata("design:returntype", Promise)
339
- ], StorageController.prototype, "list", null);
340
- _ts_decorate([
341
- Get('/head'),
342
- _ts_param(0, Req()),
343
- _ts_metadata("design:type", Function),
344
- _ts_metadata("design:paramtypes", [
345
- typeof Context === "undefined" ? Object : Context
346
- ]),
347
- _ts_metadata("design:returntype", Promise)
348
- ], StorageController.prototype, "head", null);
349
- _ts_decorate([
350
- Post('/delete'),
351
- _ts_param(0, Req()),
352
- _ts_metadata("design:type", Function),
353
- _ts_metadata("design:paramtypes", [
354
- typeof Context === "undefined" ? Object : Context
355
- ]),
356
- _ts_metadata("design:returntype", Promise)
357
- ], StorageController.prototype, "delete", null);
358
- _ts_decorate([
359
- Get('/download'),
360
- _ts_param(0, Req()),
361
- _ts_metadata("design:type", Function),
362
- _ts_metadata("design:paramtypes", [
363
- typeof Context === "undefined" ? Object : Context
364
- ]),
365
- _ts_metadata("design:returntype", Promise)
366
- ], StorageController.prototype, "download", null);
367
- _ts_decorate([
368
- Post('/sign-download'),
369
- _ts_param(0, Req()),
370
- _ts_metadata("design:type", Function),
371
- _ts_metadata("design:paramtypes", [
372
- typeof Context === "undefined" ? Object : Context
373
- ]),
374
- _ts_metadata("design:returntype", Promise)
375
- ], StorageController.prototype, "signDownload", null);
376
- StorageController = _ts_decorate([
377
- Controller(basePath),
378
- Injectable(),
379
- _ts_param(0, Inject(serviceToken)),
380
- _ts_metadata("design:type", Function),
381
- _ts_metadata("design:paramtypes", [
382
- typeof StorageService === "undefined" ? Object : StorageService
383
- ])
384
- ], StorageController);
385
- return StorageController;
386
- }
@@ -1,38 +0,0 @@
1
- /**
2
- * The single error taxonomy for `@velajs/storage`. Every driver maps its
3
- * provider/transport failures onto a {@link StorageErrorCode}; the facade's
4
- * capability gates throw `Unsupported`; the retry loop keys off
5
- * {@link StorageError.retryable}; and the HTTP controller maps codes to
6
- * status via its own `codeToHttp()` table.
7
- */
8
- export type StorageErrorCode = 'NotFound' | 'AccessDenied' | 'Unsupported' | 'ReadOnly' | 'InvalidKey' | 'InvalidRequest' | 'Conflict' | 'RateLimited' | 'Network' | 'Timeout' | 'Aborted' | 'Provider' | 'Parse';
9
- export interface StorageErrorOptions {
10
- cause?: unknown;
11
- /** Underlying HTTP status, when the failure came from a transport response. */
12
- status?: number;
13
- /** Override the default retryability implied by {@link StorageErrorCode}. */
14
- retryable?: boolean;
15
- /**
16
- * True when `message` came from a provider/transport/wrapped source rather
17
- * than being authored as client-safe text. The HTTP controller redacts such
18
- * messages so raw provider detail never reaches a client. Default false —
19
- * a bare `new StorageError(code, msg)` is the author's vouch that `msg` is
20
- * client-safe; driver/wrap code MUST set this when echoing provider text.
21
- */
22
- internal?: boolean;
23
- }
24
- export declare class StorageError extends Error {
25
- name: string;
26
- readonly code: StorageErrorCode;
27
- readonly retryable: boolean;
28
- readonly status: number | undefined;
29
- /** Whether `message` is non-client-safe (provider/transport/wrapped origin). */
30
- readonly internal: boolean;
31
- constructor(code: StorageErrorCode, message: string, options?: StorageErrorOptions);
32
- /** Wrap an arbitrary thrown value as a `StorageError` (idempotent). */
33
- static wrap(e: unknown): StorageError;
34
- /** Map a transport status code to a `StorageError` (5xx/429 retryable). */
35
- static fromStatus(status: number, message: string, cause?: unknown): StorageError;
36
- }
37
- /** True for `AbortError`-shaped values (DOMException or `{ name: 'AbortError' }`). */
38
- export declare function isAbort(e: unknown): boolean;
@@ -1,52 +0,0 @@
1
- /**
2
- * The single error taxonomy for `@velajs/storage`. Every driver maps its
3
- * provider/transport failures onto a {@link StorageErrorCode}; the facade's
4
- * capability gates throw `Unsupported`; the retry loop keys off
5
- * {@link StorageError.retryable}; and the HTTP controller maps codes to
6
- * status via its own `codeToHttp()` table.
7
- */ /** Codes that are safe to retry by default (transient failures). */ const RETRYABLE = new Set([
8
- 'Network',
9
- 'RateLimited',
10
- 'Timeout',
11
- 'Provider'
12
- ]);
13
- export class StorageError extends Error {
14
- name = 'StorageError';
15
- code;
16
- retryable;
17
- status;
18
- /** Whether `message` is non-client-safe (provider/transport/wrapped origin). */ internal;
19
- constructor(code, message, options){
20
- super(message, options?.cause !== undefined ? {
21
- cause: options.cause
22
- } : undefined);
23
- this.code = code;
24
- this.status = options?.status;
25
- this.retryable = options?.retryable ?? RETRYABLE.has(code);
26
- this.internal = options?.internal ?? false;
27
- }
28
- /** Wrap an arbitrary thrown value as a `StorageError` (idempotent). */ static wrap(e) {
29
- if (e instanceof StorageError) return e;
30
- if (isAbort(e)) return new StorageError('Aborted', 'operation aborted', {
31
- cause: e
32
- });
33
- // The wrapped message is arbitrary provider/host text — never client-safe.
34
- return new StorageError('Provider', e instanceof Error ? e.message : String(e), {
35
- cause: e,
36
- internal: true
37
- });
38
- }
39
- /** Map a transport status code to a `StorageError` (5xx/429 retryable). */ static fromStatus(status, message, cause) {
40
- const code = status === 404 ? 'NotFound' : status === 403 || status === 401 ? 'AccessDenied' : status === 409 ? 'Conflict' : status === 429 ? 'RateLimited' : status >= 500 ? 'Provider' : 'InvalidRequest';
41
- return new StorageError(code, message, {
42
- status,
43
- cause,
44
- retryable: status === 429 || status >= 500,
45
- // Message came off a transport response — treat as non-client-safe.
46
- internal: true
47
- });
48
- }
49
- }
50
- /** True for `AbortError`-shaped values (DOMException or `{ name: 'AbortError' }`). */ export function isAbort(e) {
51
- return typeof e === 'object' && e !== null && 'name' in e && e.name === 'AbortError';
52
- }
@@ -1,47 +0,0 @@
1
- import type { Body, CreateMultipartOptions, DeleteManyOptions, DeleteManyResult, DownloadOptions, ListOptions, ListResult, MultipartUpload, OperationOptions, SignedMultipartCapability, SignedUpload, SignUploadOptions, StorageCapabilities, StorageDriver, StorageOptions, StoredFile, UploadOptions, UploadResult, UrlOptions } from './storage.types';
2
- /**
3
- * The consumer-facing storage handle. Wraps a {@link StorageDriver} with
4
- * capability-gating (throws before any driver call), retry/timeout/abort,
5
- * prefix scoping, generic `move`/`deleteMany` fallbacks, multipart
6
- * orchestration, progress synthesis, and observability hooks.
7
- *
8
- * Framework-free — `StorageService` builds and caches one of these per bucket.
9
- */
10
- export declare class Storage {
11
- #private;
12
- constructor(opts: StorageOptions);
13
- get raw(): unknown;
14
- get driver(): StorageDriver;
15
- get capabilities(): StorageCapabilities;
16
- upload(key: string, body: Body, opts?: UploadOptions): Promise<UploadResult>;
17
- download(key: string, opts?: DownloadOptions): Promise<StoredFile>;
18
- head(key: string, opts?: OperationOptions): Promise<StoredFile>;
19
- exists(key: string, opts?: OperationOptions): Promise<boolean>;
20
- delete(key: string, opts?: OperationOptions): Promise<void>;
21
- delete(keys: string[], opts?: DeleteManyOptions): Promise<DeleteManyResult>;
22
- copy(from: string, to: string, opts?: OperationOptions): Promise<void>;
23
- move(from: string, to: string, opts?: OperationOptions): Promise<void>;
24
- list(opts?: ListOptions): Promise<ListResult>;
25
- listAll(opts?: ListOptions): AsyncGenerator<StoredFile>;
26
- url(key: string, opts?: UrlOptions): Promise<string>;
27
- signedUploadUrl(key: string, opts: SignUploadOptions): Promise<SignedUpload>;
28
- /** Prefix-bound view of the driver's presigned-multipart capability. */
29
- get signedMultipart(): SignedMultipartCapability | undefined;
30
- createMultipartUpload(key: string, opts?: CreateMultipartOptions): Promise<MultipartUpload>;
31
- resumeMultipartUpload(key: string, uploadId: string): MultipartUpload;
32
- /** A key-bound handle over the common single-object operations. */
33
- file(key: string): FileHandle;
34
- /** A read-only clone of this handle (mutations throw `ReadOnly`). */
35
- readonly(): Storage;
36
- }
37
- export interface FileHandle {
38
- readonly key: string;
39
- upload(body: Body, opts?: UploadOptions): Promise<UploadResult>;
40
- download(opts?: DownloadOptions): Promise<StoredFile>;
41
- head(opts?: OperationOptions): Promise<StoredFile>;
42
- exists(opts?: OperationOptions): Promise<boolean>;
43
- delete(opts?: OperationOptions): Promise<void>;
44
- url(opts?: UrlOptions): Promise<string>;
45
- signedUploadUrl(opts: SignUploadOptions): Promise<SignedUpload>;
46
- }
47
- export declare function createStorage(opts: StorageOptions): Storage;