@velajs/storage 0.3.0 → 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 -404
  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 -380
  88. package/dist/storage.error.d.ts +0 -28
  89. package/dist/storage.error.js +0 -46
  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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["#multipartUpload","#simpleUpload","#json"],"sources":["../../src/client/index.ts"],"sourcesContent":["// Browser upload client for @velajs/storage. Framework-agnostic, zero-dep.\n// Ships from the `./client` subpath (DOM code, not edge code). Talks to the\n// StorageController's JSON control-plane over fetch, and uploads bytes DIRECTLY\n// to the bucket via presigned URLs (XHR for progress; fetch has no upload\n// progress event). Wire types are imported type-only.\n\nimport type { UploadedPart, UploadResult } from '../storage.types';\nimport type {\n DeleteRequest,\n ListResponse,\n MultipartCreateResponse,\n SignPartResponse,\n SignUploadResponse,\n StorageErrorBody,\n} from '../http/protocol.types';\nimport type { DeleteManyResult } from '../storage.types';\n\nconst DEFAULT_MULTIPART_THRESHOLD = 16 * 1024 * 1024; // 16 MiB\nconst DEFAULT_CONCURRENCY = 4;\n\nexport interface StorageClientOptions {\n /** Base URL of the mounted controller, e.g. `/api/storage`. */\n baseUrl: string;\n /** Per-request headers (auth token/cookie). */\n headers?: () => Record<string, string> | Promise<Record<string, string>>;\n /** Override fetch (SSR/tests). */\n fetch?: typeof fetch;\n /** Files larger than this switch to multipart. Default 16 MiB. */\n multipartThreshold?: number;\n}\n\nexport interface ClientUploadOptions {\n /** Object key. Defaults to the file's name. The server may override it. */\n key?: string;\n contentType?: string;\n metadata?: Record<string, string>;\n multipart?: boolean | { partSize?: number; concurrency?: number };\n onProgress?: (p: { loaded: number; total: number }) => void;\n signal?: AbortSignal;\n /** Stable id enabling resume across reloads (multipart only). */\n resumeKey?: string;\n}\n\nexport class StorageClientError extends Error {\n constructor(\n readonly code: string,\n message: string,\n readonly status: number,\n ) {\n super(message);\n this.name = 'StorageClientError';\n }\n static async from(res: Response): Promise<StorageClientError> {\n let code = 'upstream_error';\n let message = `request failed: ${res.status}`;\n try {\n const body = (await res.json()) as StorageErrorBody;\n if (body?.error) {\n code = body.error.code;\n message = body.error.message;\n }\n } catch {\n /* non-JSON body */\n }\n return new StorageClientError(code, message, res.status);\n }\n}\n\nasync function pool<T>(\n items: T[],\n limit: number,\n worker: (item: T, index: number) => Promise<void>,\n): Promise<void> {\n let i = 0;\n const run = async () => {\n while (i < items.length) {\n const index = i++;\n await worker(items[index]!, index);\n }\n };\n await Promise.all(Array.from({ length: Math.min(Math.max(1, limit), items.length || 1) }, run));\n}\n\ninterface XhrResult {\n status: number;\n getHeader(name: string): string | null;\n}\n\nfunction xhrSend(o: {\n method: string;\n url: string;\n body: Blob | FormData;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n onProgress?: (p: { loaded: number; total: number }) => void;\n}): Promise<XhrResult> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.open(o.method, o.url, true);\n for (const [k, v] of Object.entries(o.headers ?? {})) xhr.setRequestHeader(k, v);\n if (o.onProgress) {\n xhr.upload.onprogress = (e) => o.onProgress!({ loaded: e.loaded, total: e.total });\n }\n xhr.onload = () =>\n xhr.status >= 200 && xhr.status < 300\n ? resolve({ status: xhr.status, getHeader: (n) => xhr.getResponseHeader(n) })\n : reject(\n new StorageClientError('upstream_error', `upload failed: ${xhr.status}`, xhr.status),\n );\n xhr.onerror = () => reject(new StorageClientError('upstream_error', 'network error', 0));\n o.signal?.addEventListener('abort', () => xhr.abort(), { once: true });\n xhr.send(o.body);\n });\n}\n\ninterface ResumeSession {\n key: string;\n uploadId: string;\n partSize: number;\n uploaded: Record<number, string>; // partNumber -> etag\n}\n\nfunction loadSession(\n resumeKey: string | undefined,\n fingerprint: string,\n): ResumeSession | undefined {\n if (!resumeKey || typeof localStorage === 'undefined') return undefined;\n try {\n const raw = localStorage.getItem(`vela.storage.resume:${resumeKey}`);\n if (!raw) return undefined;\n const s = JSON.parse(raw) as ResumeSession & { fingerprint?: string };\n return s.fingerprint === fingerprint ? s : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction saveSession(resumeKey: string | undefined, fingerprint: string, s: ResumeSession): void {\n if (!resumeKey || typeof localStorage === 'undefined') return;\n try {\n localStorage.setItem(`vela.storage.resume:${resumeKey}`, JSON.stringify({ ...s, fingerprint }));\n } catch {\n /* quota / private mode — resume is best-effort */\n }\n}\n\nfunction clearSession(resumeKey: string | undefined): void {\n if (!resumeKey || typeof localStorage === 'undefined') return;\n try {\n localStorage.removeItem(`vela.storage.resume:${resumeKey}`);\n } catch {\n /* ignore */\n }\n}\n\nexport class StorageClient {\n constructor(private readonly options: StorageClientOptions) {}\n\n async upload(file: File | Blob, opts: ClientUploadOptions = {}): Promise<UploadResult> {\n const threshold = this.options.multipartThreshold ?? DEFAULT_MULTIPART_THRESHOLD;\n const multipart =\n opts.multipart === true || (opts.multipart !== false && file.size > threshold);\n return multipart ? this.#multipartUpload(file, opts) : this.#simpleUpload(file, opts);\n }\n\n list(\n query: { prefix?: string; cursor?: string; limit?: number; delimiter?: string } = {},\n ): Promise<ListResponse> {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(query)) if (v != null) qs.set(k, String(v));\n return this.#json<ListResponse>('GET', `/list?${qs.toString()}`);\n }\n\n delete(keys: string[]): Promise<DeleteManyResult> {\n return this.#json<DeleteManyResult>('POST', '/delete', { keys } satisfies DeleteRequest);\n }\n\n async downloadUrl(key: string): Promise<string> {\n const r = await this.#json<{ url: string }>('POST', '/sign-download', { key });\n return r.url;\n }\n\n // ---- internals ----\n\n async #simpleUpload(file: File | Blob, opts: ClientUploadOptions): Promise<UploadResult> {\n const key = opts.key ?? fileName(file);\n const { upload } = await this.#json<SignUploadResponse>('POST', '/sign-upload', {\n key,\n contentType: opts.contentType ?? (file.type || undefined),\n size: file.size,\n metadata: opts.metadata,\n });\n if (upload.method === 'PUT') {\n await xhrSend({\n method: 'PUT',\n url: upload.url,\n body: file,\n headers: { 'content-type': file.type || 'application/octet-stream', ...upload.headers },\n signal: opts.signal,\n onProgress: opts.onProgress,\n });\n } else {\n const form = new FormData();\n for (const [k, v] of Object.entries(upload.fields)) form.append(k, v);\n form.append('file', file); // 'file' must be last for an S3/R2 POST policy\n await xhrSend({\n method: 'POST',\n url: upload.url,\n body: form,\n signal: opts.signal,\n onProgress: opts.onProgress,\n });\n }\n return {\n key,\n size: file.size,\n contentType: opts.contentType ?? (file.type || 'application/octet-stream'),\n };\n }\n\n async #multipartUpload(file: File | Blob, opts: ClientUploadOptions): Promise<UploadResult> {\n const key = opts.key ?? fileName(file);\n const fingerprint = `${fileName(file)}:${file.size}`;\n const concurrency =\n (typeof opts.multipart === 'object' && opts.multipart.concurrency) || DEFAULT_CONCURRENCY;\n\n let session = loadSession(opts.resumeKey, fingerprint);\n if (!session) {\n const created = await this.#json<MultipartCreateResponse>('POST', '/multipart/create', {\n key,\n contentType: opts.contentType ?? (file.type || undefined),\n metadata: opts.metadata,\n partSize: typeof opts.multipart === 'object' ? opts.multipart.partSize : undefined,\n });\n session = {\n key: created.key,\n uploadId: created.uploadId,\n partSize: created.partSize,\n uploaded: {},\n };\n }\n\n const partSize = session.partSize;\n const count = Math.ceil(file.size / partSize) || 1;\n const loaded = new Array<number>(count + 1).fill(0);\n for (const n of Object.keys(session.uploaded))\n loaded[Number(n)] = partBytes(Number(n), partSize, file.size);\n const report = () =>\n opts.onProgress?.({ loaded: loaded.reduce((a, b) => a + b, 0), total: file.size });\n\n const todo = Array.from({ length: count }, (_, i) => i + 1).filter(\n (n) => !session!.uploaded[n],\n );\n\n await pool(todo, concurrency, async (n) => {\n const blob = file.slice((n - 1) * partSize, Math.min(n * partSize, file.size));\n const signed = await this.#json<SignPartResponse>('POST', '/multipart/sign-part', {\n key: session!.key,\n uploadId: session!.uploadId,\n partNumber: n,\n });\n const res = await xhrSend({\n method: 'PUT',\n url: signed.url,\n body: blob,\n headers: signed.headers,\n signal: opts.signal,\n onProgress: (p) => {\n loaded[n] = p.loaded;\n report();\n },\n });\n const etag = res.getHeader('ETag') ?? res.getHeader('etag');\n if (!etag) {\n throw new StorageClientError(\n 'invalid_request',\n 'missing ETag on part upload (check bucket CORS ExposeHeaders: ETag)',\n res.status,\n );\n }\n session!.uploaded[n] = etag;\n saveSession(opts.resumeKey, fingerprint, session!);\n });\n\n const parts: UploadedPart[] = Object.entries(session.uploaded)\n .map(([n, etag]) => ({ partNumber: Number(n), etag }))\n .sort((a, b) => a.partNumber - b.partNumber);\n const result = await this.#json<UploadResult>('POST', '/multipart/complete', {\n key: session.key,\n uploadId: session.uploadId,\n parts,\n });\n clearSession(opts.resumeKey);\n return result;\n }\n\n async #json<T>(method: string, path: string, body?: unknown): Promise<T> {\n const fetchImpl = this.options.fetch ?? fetch;\n const res = await fetchImpl(this.options.baseUrl + path, {\n method,\n headers: { 'content-type': 'application/json', ...((await this.options.headers?.()) ?? {}) },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n if (!res.ok) throw await StorageClientError.from(res);\n return (await res.json()) as T;\n }\n}\n\nfunction fileName(file: File | Blob): string {\n return 'name' in file && typeof file.name === 'string' && file.name ? file.name : 'upload.bin';\n}\n\nfunction partBytes(partNumber: number, partSize: number, total: number): number {\n const start = (partNumber - 1) * partSize;\n return Math.max(0, Math.min(partSize, total - start));\n}\n"],"mappings":";AAiBA,MAAM,8BAA8B,KAAK,OAAO;AAChD,MAAM,sBAAsB;AAyB5B,IAAa,qBAAb,MAAa,2BAA2B,MAAM;CAEjC;CAEA;CAHX,YACE,MACA,SACA,QACA;EACA,MAAM,OAAO;EAJJ,KAAA,OAAA;EAEA,KAAA,SAAA;EAGT,KAAK,OAAO;CACd;CACA,aAAa,KAAK,KAA4C;EAC5D,IAAI,OAAO;EACX,IAAI,UAAU,mBAAmB,IAAI;EACrC,IAAI;GACF,MAAM,OAAQ,MAAM,IAAI,KAAK;GAC7B,IAAI,MAAM,OAAO;IACf,OAAO,KAAK,MAAM;IAClB,UAAU,KAAK,MAAM;GACvB;EACF,QAAQ,CAER;EACA,OAAO,IAAI,mBAAmB,MAAM,SAAS,IAAI,MAAM;CACzD;AACF;AAEA,eAAe,KACb,OACA,OACA,QACe;CACf,IAAI,IAAI;CACR,MAAM,MAAM,YAAY;EACtB,OAAO,IAAI,MAAM,QAAQ;GACvB,MAAM,QAAQ;GACd,MAAM,OAAO,MAAM,QAAS,KAAK;EACnC;CACF;CACA,MAAM,QAAQ,IAAI,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,GAAG,MAAM,UAAU,CAAC,EAAE,GAAG,GAAG,CAAC;AAChG;AAOA,SAAS,QAAQ,GAOM;CACrB,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,MAAM,IAAI,eAAe;EAC/B,IAAI,KAAK,EAAE,QAAQ,EAAE,KAAK,IAAI;EAC9B,KAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,EAAE,WAAW,CAAC,CAAC,GAAG,IAAI,iBAAiB,GAAG,CAAC;EAC/E,IAAI,EAAE,YACJ,IAAI,OAAO,cAAc,MAAM,EAAE,WAAY;GAAE,QAAQ,EAAE;GAAQ,OAAO,EAAE;EAAM,CAAC;EAEnF,IAAI,eACF,IAAI,UAAU,OAAO,IAAI,SAAS,MAC9B,QAAQ;GAAE,QAAQ,IAAI;GAAQ,YAAY,MAAM,IAAI,kBAAkB,CAAC;EAAE,CAAC,IAC1E,OACE,IAAI,mBAAmB,kBAAkB,kBAAkB,IAAI,UAAU,IAAI,MAAM,CACrF;EACN,IAAI,gBAAgB,OAAO,IAAI,mBAAmB,kBAAkB,iBAAiB,CAAC,CAAC;EACvF,EAAE,QAAQ,iBAAiB,eAAe,IAAI,MAAM,GAAG,EAAE,MAAM,KAAK,CAAC;EACrE,IAAI,KAAK,EAAE,IAAI;CACjB,CAAC;AACH;AASA,SAAS,YACP,WACA,aAC2B;CAC3B,IAAI,CAAC,aAAa,OAAO,iBAAiB,aAAa,OAAO,KAAA;CAC9D,IAAI;EACF,MAAM,MAAM,aAAa,QAAQ,uBAAuB,WAAW;EACnE,IAAI,CAAC,KAAK,OAAO,KAAA;EACjB,MAAM,IAAI,KAAK,MAAM,GAAG;EACxB,OAAO,EAAE,gBAAgB,cAAc,IAAI,KAAA;CAC7C,QAAQ;EACN;CACF;AACF;AAEA,SAAS,YAAY,WAA+B,aAAqB,GAAwB;CAC/F,IAAI,CAAC,aAAa,OAAO,iBAAiB,aAAa;CACvD,IAAI;EACF,aAAa,QAAQ,uBAAuB,aAAa,KAAK,UAAU;GAAE,GAAG;GAAG;EAAY,CAAC,CAAC;CAChG,QAAQ,CAER;AACF;AAEA,SAAS,aAAa,WAAqC;CACzD,IAAI,CAAC,aAAa,OAAO,iBAAiB,aAAa;CACvD,IAAI;EACF,aAAa,WAAW,uBAAuB,WAAW;CAC5D,QAAQ,CAER;AACF;AAEA,IAAa,gBAAb,MAA2B;CACI;CAA7B,YAAY,SAAgD;EAA/B,KAAA,UAAA;CAAgC;CAE7D,MAAM,OAAO,MAAmB,OAA4B,CAAC,GAA0B;EACrF,MAAM,YAAY,KAAK,QAAQ,sBAAsB;EAGrD,OADE,KAAK,cAAc,QAAS,KAAK,cAAc,SAAS,KAAK,OAAO,YACnD,KAAKA,iBAAiB,MAAM,IAAI,IAAI,KAAKC,cAAc,MAAM,IAAI;CACtF;CAEA,KACE,QAAkF,CAAC,GAC5D;EACvB,MAAM,KAAK,IAAI,gBAAgB;EAC/B,KAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,KAAK,GAAG,IAAI,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,CAAC;EAC9E,OAAO,KAAKC,MAAoB,OAAO,SAAS,GAAG,SAAS,GAAG;CACjE;CAEA,OAAO,MAA2C;EAChD,OAAO,KAAKA,MAAwB,QAAQ,WAAW,EAAE,KAAK,CAAyB;CACzF;CAEA,MAAM,YAAY,KAA8B;EAE9C,QAAO,MADS,KAAKA,MAAuB,QAAQ,kBAAkB,EAAE,IAAI,CAAC,EAAA,CACpE;CACX;CAIA,MAAMD,cAAc,MAAmB,MAAkD;EACvF,MAAM,MAAM,KAAK,OAAO,SAAS,IAAI;EACrC,MAAM,EAAE,WAAW,MAAM,KAAKC,MAA0B,QAAQ,gBAAgB;GAC9E;GACA,aAAa,KAAK,gBAAgB,KAAK,QAAQ,KAAA;GAC/C,MAAM,KAAK;GACX,UAAU,KAAK;EACjB,CAAC;EACD,IAAI,OAAO,WAAW,OACpB,MAAM,QAAQ;GACZ,QAAQ;GACR,KAAK,OAAO;GACZ,MAAM;GACN,SAAS;IAAE,gBAAgB,KAAK,QAAQ;IAA4B,GAAG,OAAO;GAAQ;GACtF,QAAQ,KAAK;GACb,YAAY,KAAK;EACnB,CAAC;OACI;GACL,MAAM,OAAO,IAAI,SAAS;GAC1B,KAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,OAAO,MAAM,GAAG,KAAK,OAAO,GAAG,CAAC;GACpE,KAAK,OAAO,QAAQ,IAAI;GACxB,MAAM,QAAQ;IACZ,QAAQ;IACR,KAAK,OAAO;IACZ,MAAM;IACN,QAAQ,KAAK;IACb,YAAY,KAAK;GACnB,CAAC;EACH;EACA,OAAO;GACL;GACA,MAAM,KAAK;GACX,aAAa,KAAK,gBAAgB,KAAK,QAAQ;EACjD;CACF;CAEA,MAAMF,iBAAiB,MAAmB,MAAkD;EAC1F,MAAM,MAAM,KAAK,OAAO,SAAS,IAAI;EACrC,MAAM,cAAc,GAAG,SAAS,IAAI,EAAE,GAAG,KAAK;EAC9C,MAAM,cACH,OAAO,KAAK,cAAc,YAAY,KAAK,UAAU,eAAgB;EAExE,IAAI,UAAU,YAAY,KAAK,WAAW,WAAW;EACrD,IAAI,CAAC,SAAS;GACZ,MAAM,UAAU,MAAM,KAAKE,MAA+B,QAAQ,qBAAqB;IACrF;IACA,aAAa,KAAK,gBAAgB,KAAK,QAAQ,KAAA;IAC/C,UAAU,KAAK;IACf,UAAU,OAAO,KAAK,cAAc,WAAW,KAAK,UAAU,WAAW,KAAA;GAC3E,CAAC;GACD,UAAU;IACR,KAAK,QAAQ;IACb,UAAU,QAAQ;IAClB,UAAU,QAAQ;IAClB,UAAU,CAAC;GACb;EACF;EAEA,MAAM,WAAW,QAAQ;EACzB,MAAM,QAAQ,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK;EACjD,MAAM,SAAS,IAAI,MAAc,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;EAClD,KAAK,MAAM,KAAK,OAAO,KAAK,QAAQ,QAAQ,GAC1C,OAAO,OAAO,CAAC,KAAK,UAAU,OAAO,CAAC,GAAG,UAAU,KAAK,IAAI;EAC9D,MAAM,eACJ,KAAK,aAAa;GAAE,QAAQ,OAAO,QAAQ,GAAG,MAAM,IAAI,GAAG,CAAC;GAAG,OAAO,KAAK;EAAK,CAAC;EAMnF,MAAM,KAJO,MAAM,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,QACzD,MAAM,CAAC,QAAS,SAAS,EAGd,GAAG,aAAa,OAAO,MAAM;GACzC,MAAM,OAAO,KAAK,OAAO,IAAI,KAAK,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,IAAI,CAAC;GAC7E,MAAM,SAAS,MAAM,KAAKA,MAAwB,QAAQ,wBAAwB;IAChF,KAAK,QAAS;IACd,UAAU,QAAS;IACnB,YAAY;GACd,CAAC;GACD,MAAM,MAAM,MAAM,QAAQ;IACxB,QAAQ;IACR,KAAK,OAAO;IACZ,MAAM;IACN,SAAS,OAAO;IAChB,QAAQ,KAAK;IACb,aAAa,MAAM;KACjB,OAAO,KAAK,EAAE;KACd,OAAO;IACT;GACF,CAAC;GACD,MAAM,OAAO,IAAI,UAAU,MAAM,KAAK,IAAI,UAAU,MAAM;GAC1D,IAAI,CAAC,MACH,MAAM,IAAI,mBACR,mBACA,uEACA,IAAI,MACN;GAEF,QAAS,SAAS,KAAK;GACvB,YAAY,KAAK,WAAW,aAAa,OAAQ;EACnD,CAAC;EAED,MAAM,QAAwB,OAAO,QAAQ,QAAQ,QAAQ,CAAC,CAC3D,KAAK,CAAC,GAAG,WAAW;GAAE,YAAY,OAAO,CAAC;GAAG;EAAK,EAAE,CAAC,CACrD,MAAM,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU;EAC7C,MAAM,SAAS,MAAM,KAAKA,MAAoB,QAAQ,uBAAuB;GAC3E,KAAK,QAAQ;GACb,UAAU,QAAQ;GAClB;EACF,CAAC;EACD,aAAa,KAAK,SAAS;EAC3B,OAAO;CACT;CAEA,MAAMA,MAAS,QAAgB,MAAc,MAA4B;EAEvE,MAAM,MAAM,OADM,KAAK,QAAQ,SAAS,MAAA,CACZ,KAAK,QAAQ,UAAU,MAAM;GACvD;GACA,SAAS;IAAE,gBAAgB;IAAoB,GAAK,MAAM,KAAK,QAAQ,UAAU,KAAM,CAAC;GAAG;GAC3F,MAAM,SAAS,KAAA,IAAY,KAAK,UAAU,IAAI,IAAI,KAAA;EACpD,CAAC;EACD,IAAI,CAAC,IAAI,IAAI,MAAM,MAAM,mBAAmB,KAAK,GAAG;EACpD,OAAQ,MAAM,IAAI,KAAK;CACzB;AACF;AAEA,SAAS,SAAS,MAA2B;CAC3C,OAAO,UAAU,QAAQ,OAAO,KAAK,SAAS,YAAY,KAAK,OAAO,KAAK,OAAO;AACpF;AAEA,SAAS,UAAU,YAAoB,UAAkB,OAAuB;CAC9E,MAAM,SAAS,aAAa,KAAK;CACjC,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,QAAQ,KAAK,CAAC;AACtD"}
@@ -1,16 +1,20 @@
1
- import type { StorageDriver } from '../../storage.types';
2
- export interface MemoryEntry {
3
- bytes: Uint8Array;
4
- contentType: string;
5
- cacheControl?: string;
6
- metadata?: Record<string, string>;
7
- etag: string;
8
- lastModified: number;
1
+ import { C as StorageDriver } from "../../storage.types-BJN7Yp1J.js";
2
+ //#region src/drivers/memory/index.d.ts
3
+ interface MemoryEntry {
4
+ bytes: Uint8Array;
5
+ contentType: string;
6
+ cacheControl?: string;
7
+ metadata?: Record<string, string>;
8
+ etag: string;
9
+ lastModified: number;
9
10
  }
10
- export interface MemoryDriverOptions {
11
- /** Pre-seed the store with `{ key: bytes|string }`. */
12
- initial?: Record<string, Uint8Array | string>;
11
+ interface MemoryDriverOptions {
12
+ /** Pre-seed the store with `{ key: bytes|string }`. */
13
+ initial?: Record<string, Uint8Array | string>;
13
14
  }
14
- export type MemoryDriver = StorageDriver<Map<string, MemoryEntry>>;
15
+ type MemoryDriver = StorageDriver<Map<string, MemoryEntry>>;
15
16
  /** In-memory storage driver — the test/dev workhorse and reference impl. */
16
- export declare function memoryDriver(options?: MemoryDriverOptions): MemoryDriver;
17
+ declare function memoryDriver(options?: MemoryDriverOptions): MemoryDriver;
18
+ //#endregion
19
+ export { MemoryDriver, MemoryDriverOptions, MemoryEntry, memoryDriver };
20
+ //# sourceMappingURL=index.d.ts.map
@@ -1,202 +1,195 @@
1
- import { concatChunks, toBytes } from "../../internal/body.js";
2
- import { createStoredFile } from "../../internal/stored-file.js";
3
- import { StorageError } from "../../storage.error.js";
4
- // FNV-1a 64-bit content hash — deterministic, edge-safe (BigInt, no node:crypto).
5
- // Memory is a dev/test driver; the ETag never interoperates with real S3 ETags.
6
- const FNV_OFFSET = 0xcbf29ce484222325n;
7
- const FNV_PRIME = 0x100000001b3n;
8
- const U64 = 0xffffffffffffffffn;
1
+ import { o as toBytes, r as concatChunks } from "../../body-BMUcBeQ0.js";
2
+ import { t as StorageError } from "../../storage.error-DVCOkJhc.js";
3
+ import { t as createStoredFile } from "../../stored-file-2Yl07eRc.js";
4
+ //#region src/drivers/memory/index.ts
5
+ const FNV_OFFSET = 14695981039346656037n;
6
+ const FNV_PRIME = 1099511628211n;
7
+ const U64 = 18446744073709551615n;
9
8
  function contentEtag(bytes) {
10
- let h = FNV_OFFSET;
11
- for (const b of bytes){
12
- h ^= BigInt(b);
13
- h = h * FNV_PRIME & U64;
14
- }
15
- return `"${h.toString(16).padStart(16, '0')}"`;
9
+ let h = FNV_OFFSET;
10
+ for (const b of bytes) {
11
+ h ^= BigInt(b);
12
+ h = h * FNV_PRIME & U64;
13
+ }
14
+ return `"${h.toString(16).padStart(16, "0")}"`;
16
15
  }
17
16
  function makeEntry(bytes, opts) {
18
- return {
19
- bytes,
20
- contentType: opts?.contentType ?? 'application/octet-stream',
21
- cacheControl: opts?.cacheControl,
22
- metadata: opts?.metadata,
23
- etag: contentEtag(bytes),
24
- lastModified: Date.now()
25
- };
17
+ return {
18
+ bytes,
19
+ contentType: opts?.contentType ?? "application/octet-stream",
20
+ cacheControl: opts?.cacheControl,
21
+ metadata: opts?.metadata,
22
+ etag: contentEtag(bytes),
23
+ lastModified: Date.now()
24
+ };
26
25
  }
27
- /** In-memory storage driver — the test/dev workhorse and reference impl. */ export function memoryDriver(options) {
28
- const store = new Map();
29
- const encoder = new TextEncoder();
30
- for (const [key, value] of Object.entries(options?.initial ?? {})){
31
- const bytes = typeof value === 'string' ? encoder.encode(value) : value;
32
- store.set(key, makeEntry(bytes));
33
- }
34
- const toStored = (key, entry, bytes)=>createStoredFile({
35
- key,
36
- size: bytes.byteLength,
37
- type: entry.contentType,
38
- lastModified: entry.lastModified,
39
- etag: entry.etag,
40
- metadata: entry.metadata
41
- }, {
42
- kind: 'bytes',
43
- bytes
44
- });
45
- const mustGet = (key)=>{
46
- const e = store.get(key);
47
- if (!e) throw new StorageError('NotFound', `object not found: ${key}`);
48
- return e;
49
- };
50
- return {
51
- name: 'memory',
52
- raw: store,
53
- supportsRange: true,
54
- supportsDelimiter: true,
55
- supportsMetadata: true,
56
- supportsCacheControl: true,
57
- supportsServerSideCopy: true,
58
- reportsUploadProgress: false,
59
- signedUrl: {
60
- supported: false,
61
- upload: false
62
- },
63
- async upload (key, body, opts) {
64
- const bytes = await toBytes(body);
65
- const entry = makeEntry(bytes, opts);
66
- store.set(key, entry);
67
- return {
68
- key,
69
- size: bytes.byteLength,
70
- contentType: entry.contentType,
71
- etag: entry.etag,
72
- lastModified: entry.lastModified
73
- };
74
- },
75
- async download (key, opts) {
76
- const entry = mustGet(key);
77
- if (opts?.range) {
78
- const start = opts.range.start;
79
- const end = opts.range.end ?? entry.bytes.byteLength - 1;
80
- return toStored(key, entry, entry.bytes.subarray(start, end + 1));
81
- }
82
- return toStored(key, entry, entry.bytes);
83
- },
84
- async head (key) {
85
- const entry = mustGet(key);
86
- return toStored(key, entry, entry.bytes);
87
- },
88
- async exists (key) {
89
- return store.has(key);
90
- },
91
- async delete (key) {
92
- store.delete(key);
93
- },
94
- async deleteMany (keys) {
95
- for (const k of keys)store.delete(k);
96
- return {
97
- deleted: keys
98
- };
99
- },
100
- async copy (from, to) {
101
- const e = mustGet(from);
102
- store.set(to, {
103
- ...e,
104
- bytes: e.bytes.slice(),
105
- lastModified: Date.now()
106
- });
107
- },
108
- async move (from, to) {
109
- const e = mustGet(from);
110
- store.set(to, e);
111
- store.delete(from);
112
- },
113
- async list (opts) {
114
- const prefix = opts?.prefix ?? '';
115
- const delimiter = opts?.delimiter;
116
- const limit = opts?.limit ?? 1000;
117
- const start = opts?.cursor ? Number.parseInt(opts.cursor, 10) : 0;
118
- const matched = [
119
- ...store.keys()
120
- ].filter((k)=>k.startsWith(prefix)).sort();
121
- if (delimiter) {
122
- const prefixes = new Set();
123
- const direct = [];
124
- for (const k of matched){
125
- const rest = k.slice(prefix.length);
126
- const idx = rest.indexOf(delimiter);
127
- if (idx === -1) direct.push(k);
128
- else prefixes.add(prefix + rest.slice(0, idx + delimiter.length));
129
- }
130
- const page = direct.slice(start, start + limit);
131
- const cursor = start + limit < direct.length ? String(start + limit) : undefined;
132
- return {
133
- items: page.map((k)=>toStored(k, mustGet(k), mustGet(k).bytes)),
134
- prefixes: start === 0 && prefixes.size ? [
135
- ...prefixes
136
- ].sort() : undefined,
137
- cursor
138
- };
139
- }
140
- const page = matched.slice(start, start + limit);
141
- const cursor = start + limit < matched.length ? String(start + limit) : undefined;
142
- return {
143
- items: page.map((k)=>toStored(k, mustGet(k), mustGet(k).bytes)),
144
- cursor
145
- };
146
- },
147
- async url (key) {
148
- throw new StorageError('Unsupported', 'memory driver cannot mint URLs');
149
- },
150
- async signedUploadUrl () {
151
- throw new StorageError('Unsupported', 'memory driver cannot presign uploads');
152
- },
153
- async createMultipartUpload (key, opts) {
154
- const uploadId = crypto.randomUUID();
155
- const parts = new Map();
156
- return {
157
- key,
158
- uploadId,
159
- async uploadPart (partNumber, body) {
160
- const bytes = await toBytes(body);
161
- parts.set(partNumber, bytes);
162
- return {
163
- partNumber,
164
- etag: contentEtag(bytes),
165
- size: bytes.byteLength
166
- };
167
- },
168
- async complete (uploaded) {
169
- const ordered = [
170
- ...uploaded
171
- ].sort((a, b)=>a.partNumber - b.partNumber).map((p)=>{
172
- const bytes = parts.get(p.partNumber);
173
- if (!bytes) throw new StorageError('InvalidRequest', `missing part ${p.partNumber}`);
174
- return bytes;
175
- });
176
- const all = concatChunks(ordered);
177
- const entry = makeEntry(all, opts);
178
- store.set(key, entry);
179
- return {
180
- key,
181
- size: all.byteLength,
182
- contentType: entry.contentType,
183
- etag: entry.etag,
184
- lastModified: entry.lastModified
185
- };
186
- },
187
- async abort () {
188
- parts.clear();
189
- },
190
- async listParts () {
191
- return [
192
- ...parts.entries()
193
- ].sort((a, b)=>a[0] - b[0]).map(([partNumber, bytes])=>({
194
- partNumber,
195
- etag: contentEtag(bytes),
196
- size: bytes.byteLength
197
- }));
198
- }
199
- };
200
- }
201
- };
26
+ /** In-memory storage driver — the test/dev workhorse and reference impl. */
27
+ function memoryDriver(options) {
28
+ const store = /* @__PURE__ */ new Map();
29
+ const encoder = new TextEncoder();
30
+ for (const [key, value] of Object.entries(options?.initial ?? {})) {
31
+ const bytes = typeof value === "string" ? encoder.encode(value) : value;
32
+ store.set(key, makeEntry(bytes));
33
+ }
34
+ const toStored = (key, entry, bytes) => createStoredFile({
35
+ key,
36
+ size: bytes.byteLength,
37
+ type: entry.contentType,
38
+ lastModified: entry.lastModified,
39
+ etag: entry.etag,
40
+ metadata: entry.metadata
41
+ }, {
42
+ kind: "bytes",
43
+ bytes
44
+ });
45
+ const mustGet = (key) => {
46
+ const e = store.get(key);
47
+ if (!e) throw new StorageError("NotFound", `object not found: ${key}`);
48
+ return e;
49
+ };
50
+ return {
51
+ name: "memory",
52
+ raw: store,
53
+ supportsRange: true,
54
+ supportsDelimiter: true,
55
+ supportsMetadata: true,
56
+ supportsCacheControl: true,
57
+ supportsServerSideCopy: true,
58
+ reportsUploadProgress: false,
59
+ signedUrl: {
60
+ supported: false,
61
+ upload: false
62
+ },
63
+ async upload(key, body, opts) {
64
+ const bytes = await toBytes(body);
65
+ const entry = makeEntry(bytes, opts);
66
+ store.set(key, entry);
67
+ return {
68
+ key,
69
+ size: bytes.byteLength,
70
+ contentType: entry.contentType,
71
+ etag: entry.etag,
72
+ lastModified: entry.lastModified
73
+ };
74
+ },
75
+ async download(key, opts) {
76
+ const entry = mustGet(key);
77
+ if (opts?.range) {
78
+ const start = opts.range.start;
79
+ const end = opts.range.end ?? entry.bytes.byteLength - 1;
80
+ return toStored(key, entry, entry.bytes.subarray(start, end + 1));
81
+ }
82
+ return toStored(key, entry, entry.bytes);
83
+ },
84
+ async head(key) {
85
+ const entry = mustGet(key);
86
+ return toStored(key, entry, entry.bytes);
87
+ },
88
+ async exists(key) {
89
+ return store.has(key);
90
+ },
91
+ async delete(key) {
92
+ store.delete(key);
93
+ },
94
+ async deleteMany(keys) {
95
+ for (const k of keys) store.delete(k);
96
+ return { deleted: keys };
97
+ },
98
+ async copy(from, to) {
99
+ const e = mustGet(from);
100
+ store.set(to, {
101
+ ...e,
102
+ bytes: e.bytes.slice(),
103
+ lastModified: Date.now()
104
+ });
105
+ },
106
+ async move(from, to) {
107
+ const e = mustGet(from);
108
+ store.set(to, e);
109
+ store.delete(from);
110
+ },
111
+ async list(opts) {
112
+ const prefix = opts?.prefix ?? "";
113
+ const delimiter = opts?.delimiter;
114
+ const limit = opts?.limit ?? 1e3;
115
+ const start = opts?.cursor ? Number.parseInt(opts.cursor, 10) : 0;
116
+ const matched = [...store.keys()].filter((k) => k.startsWith(prefix)).sort();
117
+ if (delimiter) {
118
+ const prefixes = /* @__PURE__ */ new Set();
119
+ const direct = [];
120
+ for (const k of matched) {
121
+ const rest = k.slice(prefix.length);
122
+ const idx = rest.indexOf(delimiter);
123
+ if (idx === -1) direct.push(k);
124
+ else prefixes.add(prefix + rest.slice(0, idx + delimiter.length));
125
+ }
126
+ const page = direct.slice(start, start + limit);
127
+ const cursor = start + limit < direct.length ? String(start + limit) : void 0;
128
+ return {
129
+ items: page.map((k) => toStored(k, mustGet(k), mustGet(k).bytes)),
130
+ prefixes: start === 0 && prefixes.size ? [...prefixes].sort() : void 0,
131
+ cursor
132
+ };
133
+ }
134
+ const page = matched.slice(start, start + limit);
135
+ const cursor = start + limit < matched.length ? String(start + limit) : void 0;
136
+ return {
137
+ items: page.map((k) => toStored(k, mustGet(k), mustGet(k).bytes)),
138
+ cursor
139
+ };
140
+ },
141
+ async url(key) {
142
+ throw new StorageError("Unsupported", "memory driver cannot mint URLs");
143
+ },
144
+ async signedUploadUrl() {
145
+ throw new StorageError("Unsupported", "memory driver cannot presign uploads");
146
+ },
147
+ async createMultipartUpload(key, opts) {
148
+ const uploadId = crypto.randomUUID();
149
+ const parts = /* @__PURE__ */ new Map();
150
+ return {
151
+ key,
152
+ uploadId,
153
+ async uploadPart(partNumber, body) {
154
+ const bytes = await toBytes(body);
155
+ parts.set(partNumber, bytes);
156
+ return {
157
+ partNumber,
158
+ etag: contentEtag(bytes),
159
+ size: bytes.byteLength
160
+ };
161
+ },
162
+ async complete(uploaded) {
163
+ const all = concatChunks([...uploaded].sort((a, b) => a.partNumber - b.partNumber).map((p) => {
164
+ const bytes = parts.get(p.partNumber);
165
+ if (!bytes) throw new StorageError("InvalidRequest", `missing part ${p.partNumber}`);
166
+ return bytes;
167
+ }));
168
+ const entry = makeEntry(all, opts);
169
+ store.set(key, entry);
170
+ return {
171
+ key,
172
+ size: all.byteLength,
173
+ contentType: entry.contentType,
174
+ etag: entry.etag,
175
+ lastModified: entry.lastModified
176
+ };
177
+ },
178
+ async abort() {
179
+ parts.clear();
180
+ },
181
+ async listParts() {
182
+ return [...parts.entries()].sort((a, b) => a[0] - b[0]).map(([partNumber, bytes]) => ({
183
+ partNumber,
184
+ etag: contentEtag(bytes),
185
+ size: bytes.byteLength
186
+ }));
187
+ }
188
+ };
189
+ }
190
+ };
202
191
  }
192
+ //#endregion
193
+ export { memoryDriver };
194
+
195
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/drivers/memory/index.ts"],"sourcesContent":["import { concatChunks, toBytes } from '../../internal/body';\nimport { createStoredFile } from '../../internal/stored-file';\nimport { StorageError } from '../../storage.error';\nimport type {\n Body,\n CreateMultipartOptions,\n DownloadOptions,\n ListOptions,\n ListResult,\n MultipartUpload,\n StorageDriver,\n StoredFile,\n UploadOptions,\n UploadResult,\n} from '../../storage.types';\n\nexport interface MemoryEntry {\n bytes: Uint8Array;\n contentType: string;\n cacheControl?: string;\n metadata?: Record<string, string>;\n etag: string;\n lastModified: number;\n}\n\nexport interface MemoryDriverOptions {\n /** Pre-seed the store with `{ key: bytes|string }`. */\n initial?: Record<string, Uint8Array | string>;\n}\n\nexport type MemoryDriver = StorageDriver<Map<string, MemoryEntry>>;\n\n// FNV-1a 64-bit content hash — deterministic, edge-safe (BigInt, no node:crypto).\n// Memory is a dev/test driver; the ETag never interoperates with real S3 ETags.\nconst FNV_OFFSET = 0xcbf29ce484222325n;\nconst FNV_PRIME = 0x100000001b3n;\nconst U64 = 0xffffffffffffffffn;\n\nfunction contentEtag(bytes: Uint8Array): string {\n let h = FNV_OFFSET;\n for (const b of bytes) {\n h ^= BigInt(b);\n h = (h * FNV_PRIME) & U64;\n }\n return `\"${h.toString(16).padStart(16, '0')}\"`;\n}\n\nfunction makeEntry(bytes: Uint8Array, opts?: UploadOptions | CreateMultipartOptions): MemoryEntry {\n return {\n bytes,\n contentType: opts?.contentType ?? 'application/octet-stream',\n cacheControl: opts?.cacheControl,\n metadata: opts?.metadata,\n etag: contentEtag(bytes),\n lastModified: Date.now(),\n };\n}\n\n/** In-memory storage driver — the test/dev workhorse and reference impl. */\nexport function memoryDriver(options?: MemoryDriverOptions): MemoryDriver {\n const store = new Map<string, MemoryEntry>();\n const encoder = new TextEncoder();\n\n for (const [key, value] of Object.entries(options?.initial ?? {})) {\n const bytes = typeof value === 'string' ? encoder.encode(value) : value;\n store.set(key, makeEntry(bytes));\n }\n\n const toStored = (key: string, entry: MemoryEntry, bytes: Uint8Array): StoredFile =>\n createStoredFile(\n {\n key,\n size: bytes.byteLength,\n type: entry.contentType,\n lastModified: entry.lastModified,\n etag: entry.etag,\n metadata: entry.metadata,\n },\n { kind: 'bytes', bytes },\n );\n\n const mustGet = (key: string): MemoryEntry => {\n const e = store.get(key);\n if (!e) throw new StorageError('NotFound', `object not found: ${key}`);\n return e;\n };\n\n return {\n name: 'memory',\n raw: store,\n supportsRange: true,\n supportsDelimiter: true,\n supportsMetadata: true,\n supportsCacheControl: true,\n supportsServerSideCopy: true,\n reportsUploadProgress: false,\n signedUrl: { supported: false, upload: false },\n\n async upload(key: string, body: Body, opts?: UploadOptions): Promise<UploadResult> {\n const bytes = await toBytes(body);\n const entry = makeEntry(bytes, opts);\n store.set(key, entry);\n return {\n key,\n size: bytes.byteLength,\n contentType: entry.contentType,\n etag: entry.etag,\n lastModified: entry.lastModified,\n };\n },\n\n async download(key: string, opts?: DownloadOptions): Promise<StoredFile> {\n const entry = mustGet(key);\n if (opts?.range) {\n const start = opts.range.start;\n const end = opts.range.end ?? entry.bytes.byteLength - 1;\n return toStored(key, entry, entry.bytes.subarray(start, end + 1));\n }\n return toStored(key, entry, entry.bytes);\n },\n\n async head(key: string): Promise<StoredFile> {\n const entry = mustGet(key);\n return toStored(key, entry, entry.bytes);\n },\n\n async exists(key: string): Promise<boolean> {\n return store.has(key);\n },\n\n async delete(key: string): Promise<void> {\n store.delete(key);\n },\n\n async deleteMany(keys: string[]) {\n for (const k of keys) store.delete(k);\n return { deleted: keys };\n },\n\n async copy(from: string, to: string): Promise<void> {\n const e = mustGet(from);\n store.set(to, { ...e, bytes: e.bytes.slice(), lastModified: Date.now() });\n },\n\n async move(from: string, to: string): Promise<void> {\n const e = mustGet(from);\n store.set(to, e);\n store.delete(from);\n },\n\n async list(opts?: ListOptions): Promise<ListResult> {\n const prefix = opts?.prefix ?? '';\n const delimiter = opts?.delimiter;\n const limit = opts?.limit ?? 1000;\n const start = opts?.cursor ? Number.parseInt(opts.cursor, 10) : 0;\n const matched = [...store.keys()].filter((k) => k.startsWith(prefix)).sort();\n\n if (delimiter) {\n const prefixes = new Set<string>();\n const direct: string[] = [];\n for (const k of matched) {\n const rest = k.slice(prefix.length);\n const idx = rest.indexOf(delimiter);\n if (idx === -1) direct.push(k);\n else prefixes.add(prefix + rest.slice(0, idx + delimiter.length));\n }\n const page = direct.slice(start, start + limit);\n const cursor = start + limit < direct.length ? String(start + limit) : undefined;\n return {\n items: page.map((k) => toStored(k, mustGet(k), mustGet(k).bytes)),\n prefixes: start === 0 && prefixes.size ? [...prefixes].sort() : undefined,\n cursor,\n };\n }\n\n const page = matched.slice(start, start + limit);\n const cursor = start + limit < matched.length ? String(start + limit) : undefined;\n return {\n items: page.map((k) => toStored(k, mustGet(k), mustGet(k).bytes)),\n cursor,\n };\n },\n\n async url(key: string): Promise<string> {\n throw new StorageError('Unsupported', 'memory driver cannot mint URLs');\n },\n\n async signedUploadUrl(): Promise<never> {\n throw new StorageError('Unsupported', 'memory driver cannot presign uploads');\n },\n\n async createMultipartUpload(\n key: string,\n opts?: CreateMultipartOptions,\n ): Promise<MultipartUpload> {\n const uploadId = crypto.randomUUID();\n const parts = new Map<number, Uint8Array>();\n return {\n key,\n uploadId,\n async uploadPart(partNumber, body) {\n const bytes = await toBytes(body);\n parts.set(partNumber, bytes);\n return { partNumber, etag: contentEtag(bytes), size: bytes.byteLength };\n },\n async complete(uploaded) {\n const ordered = [...uploaded]\n .sort((a, b) => a.partNumber - b.partNumber)\n .map((p) => {\n const bytes = parts.get(p.partNumber);\n if (!bytes) throw new StorageError('InvalidRequest', `missing part ${p.partNumber}`);\n return bytes;\n });\n const all = concatChunks(ordered);\n const entry = makeEntry(all, opts);\n store.set(key, entry);\n return {\n key,\n size: all.byteLength,\n contentType: entry.contentType,\n etag: entry.etag,\n lastModified: entry.lastModified,\n };\n },\n async abort() {\n parts.clear();\n },\n async listParts() {\n return [...parts.entries()]\n .sort((a, b) => a[0] - b[0])\n .map(([partNumber, bytes]) => ({\n partNumber,\n etag: contentEtag(bytes),\n size: bytes.byteLength,\n }));\n },\n };\n },\n };\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import type { StorageDriver } from '../../storage.types';
2
- import type { R2BucketLike, R2DriverOptions } from './r2.types';
3
- export type { R2BucketLike, R2DriverOptions, R2ObjectLike, R2ObjectBodyLike, R2MultipartUploadLike, } from './r2.types';
1
+ import { C as StorageDriver } from "../../storage.types-BJN7Yp1J.js";
2
+ import { a as R2ObjectLike, i as R2ObjectBodyLike, n as R2DriverOptions, r as R2MultipartUploadLike, t as R2BucketLike } from "../../r2.types-Bw4Ft83t.js";
3
+ //#region src/drivers/r2/index.d.ts
4
4
  /**
5
5
  * Cloudflare R2 driver — native binding mode only. Zero third-party deps
6
6
  * (no aws4fetch), fully edge-native I/O with no egress fees.
@@ -8,4 +8,7 @@ export type { R2BucketLike, R2DriverOptions, R2ObjectLike, R2ObjectBodyLike, R2M
8
8
  * It cannot presign (`signedUploadUrl` throws; `url()` needs `publicBaseUrl`).
9
9
  * For presigned URLs use `@velajs/storage/drivers/r2-http` (HTTP or hybrid mode).
10
10
  */
11
- export declare function r2Driver(options: R2DriverOptions): StorageDriver<R2BucketLike>;
11
+ declare function r2Driver(options: R2DriverOptions): StorageDriver<R2BucketLike>;
12
+ //#endregion
13
+ export { type R2BucketLike, type R2DriverOptions, type R2MultipartUploadLike, type R2ObjectBodyLike, type R2ObjectLike, r2Driver };
14
+ //# sourceMappingURL=index.d.ts.map