@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.
- package/CHANGELOG.md +6 -1
- package/dist/body-BMUcBeQ0.js +93 -0
- package/dist/body-BMUcBeQ0.js.map +1 -0
- package/dist/client/index.d.ts +49 -46
- package/dist/client/index.js +207 -228
- package/dist/client/index.js.map +1 -0
- package/dist/drivers/memory/index.d.ts +17 -13
- package/dist/drivers/memory/index.js +190 -197
- package/dist/drivers/memory/index.js.map +1 -0
- package/dist/drivers/r2/index.d.ts +7 -4
- package/dist/drivers/r2/index.js +162 -160
- package/dist/drivers/r2/index.js.map +1 -0
- package/dist/drivers/r2-http/index.d.ts +23 -19
- package/dist/drivers/r2-http/index.js +52 -45
- package/dist/drivers/r2-http/index.js.map +1 -0
- package/dist/drivers/s3/index.d.ts +79 -5
- package/dist/drivers/s3/index.js +2 -3
- package/dist/index.d.ts +271 -17
- package/dist/index.js +1078 -16
- package/dist/index.js.map +1 -0
- package/dist/middleware/index.d.ts +177 -15
- package/dist/middleware/index.js +553 -8
- package/dist/middleware/index.js.map +1 -0
- package/dist/protocol.types-C5PPBD12.d.ts +80 -0
- package/dist/r2.types-Bw4Ft83t.d.ts +71 -0
- package/dist/retry-DXtO6R9D.js +119 -0
- package/dist/retry-DXtO6R9D.js.map +1 -0
- package/dist/s3-DrE9NrnD.js +557 -0
- package/dist/s3-DrE9NrnD.js.map +1 -0
- package/dist/storage.error-DVCOkJhc.js +49 -0
- package/dist/storage.error-DVCOkJhc.js.map +1 -0
- package/dist/storage.types-BJN7Yp1J.d.ts +288 -0
- package/dist/storagesdk/index.d.ts +73 -69
- package/dist/storagesdk/index.js +117 -130
- package/dist/storagesdk/index.js.map +1 -0
- package/dist/stored-file-2Yl07eRc.js +105 -0
- package/dist/stored-file-2Yl07eRc.js.map +1 -0
- package/dist/testing/index.d.ts +12 -8
- package/dist/testing/index.js +36 -53
- package/dist/testing/index.js.map +1 -0
- package/package.json +62 -48
- package/dist/base64.d.ts +0 -8
- package/dist/base64.js +0 -25
- package/dist/decorators/inject-storage.decorator.d.ts +0 -17
- package/dist/decorators/inject-storage.decorator.js +0 -21
- package/dist/drivers/r2/r2.types.d.ts +0 -67
- package/dist/drivers/r2/r2.types.js +0 -5
- package/dist/drivers/s3/s3-client.d.ts +0 -33
- package/dist/drivers/s3/s3-client.js +0 -154
- package/dist/drivers/s3/s3.driver.d.ts +0 -4
- package/dist/drivers/s3/s3.driver.js +0 -404
- package/dist/drivers/s3/s3.types.d.ts +0 -28
- package/dist/drivers/s3/s3.types.js +0 -1
- package/dist/drivers/s3/xml.d.ts +0 -6
- package/dist/drivers/s3/xml.js +0 -52
- package/dist/http/authorizer.types.d.ts +0 -59
- package/dist/http/authorizer.types.js +0 -1
- package/dist/http/http-helpers.d.ts +0 -22
- package/dist/http/http-helpers.js +0 -80
- package/dist/http/protocol.types.d.ts +0 -76
- package/dist/http/protocol.types.js +0 -1
- package/dist/internal/body.d.ts +0 -18
- package/dist/internal/body.js +0 -90
- package/dist/internal/retry.d.ts +0 -41
- package/dist/internal/retry.js +0 -127
- package/dist/internal/stored-file.d.ts +0 -27
- package/dist/internal/stored-file.js +0 -114
- package/dist/middleware/cache.d.ts +0 -50
- package/dist/middleware/cache.js +0 -101
- package/dist/middleware/compose.d.ts +0 -12
- package/dist/middleware/compose.js +0 -11
- package/dist/middleware/compression.d.ts +0 -16
- package/dist/middleware/compression.js +0 -101
- package/dist/middleware/encryption.d.ts +0 -14
- package/dist/middleware/encryption.js +0 -134
- package/dist/middleware/failover.d.ts +0 -18
- package/dist/middleware/failover.js +0 -52
- package/dist/middleware/retry.d.ts +0 -14
- package/dist/middleware/retry.js +0 -47
- package/dist/middleware/versioning.d.ts +0 -36
- package/dist/middleware/versioning.js +0 -89
- package/dist/middleware/wrap.d.ts +0 -11
- package/dist/middleware/wrap.js +0 -46
- package/dist/object-key.d.ts +0 -17
- package/dist/object-key.js +0 -42
- package/dist/storage.controller.d.ts +0 -21
- package/dist/storage.controller.js +0 -380
- package/dist/storage.error.d.ts +0 -28
- package/dist/storage.error.js +0 -46
- package/dist/storage.facade.d.ts +0 -47
- package/dist/storage.facade.js +0 -443
- package/dist/storage.module.d.ts +0 -46
- package/dist/storage.module.js +0 -113
- package/dist/storage.service.d.ts +0 -42
- package/dist/storage.service.js +0 -86
- package/dist/storage.tokens.d.ts +0 -13
- package/dist/storage.tokens.js +0 -26
- package/dist/storage.types.d.ts +0 -245
- 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":"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"}
|
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
interface MemoryDriverOptions {
|
|
12
|
+
/** Pre-seed the store with `{ key: bytes|string }`. */
|
|
13
|
+
initial?: Record<string, Uint8Array | string>;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
type MemoryDriver = StorageDriver<Map<string, MemoryEntry>>;
|
|
15
16
|
/** In-memory storage driver — the test/dev workhorse and reference impl. */
|
|
16
|
-
|
|
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 {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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. */
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
|
2
|
-
import
|
|
3
|
-
|
|
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
|
-
|
|
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
|