@vercel/kv2 0.0.16 → 0.0.18
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/README.md +4 -7
- package/SKILL.md +15 -4
- package/dist/blob-stores/disk-blob-store.d.ts +20 -0
- package/dist/blob-stores/disk-blob-store.d.ts.map +1 -0
- package/dist/blob-stores/disk-blob-store.js +270 -0
- package/dist/blob-stores/disk-blob-store.js.map +1 -0
- package/dist/blob-stores/in-memory-blob-store.d.ts +30 -0
- package/dist/blob-stores/in-memory-blob-store.d.ts.map +1 -0
- package/dist/blob-stores/in-memory-blob-store.js +187 -0
- package/dist/blob-stores/in-memory-blob-store.js.map +1 -0
- package/dist/blob-stores/index.d.ts +4 -0
- package/dist/blob-stores/index.d.ts.map +1 -0
- package/dist/blob-stores/index.js +4 -0
- package/dist/blob-stores/index.js.map +1 -0
- package/dist/blob-stores/vercel-blob-store.d.ts +11 -0
- package/dist/blob-stores/vercel-blob-store.d.ts.map +1 -0
- package/dist/blob-stores/vercel-blob-store.js +34 -0
- package/dist/blob-stores/vercel-blob-store.js.map +1 -0
- package/dist/cached-kv.d.ts +12 -0
- package/dist/cached-kv.d.ts.map +1 -1
- package/dist/cached-kv.js +18 -0
- package/dist/cached-kv.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/readme.test.js +2 -0
- package/dist/readme.test.js.map +1 -1
- package/dist/testing/test-index.d.ts +3 -0
- package/dist/testing/test-index.d.ts.map +1 -1
- package/dist/testing/test-index.js +4 -0
- package/dist/testing/test-index.js.map +1 -1
- package/dist/typed-kv.d.ts +59 -3
- package/dist/typed-kv.d.ts.map +1 -1
- package/dist/typed-kv.js +69 -3
- package/dist/typed-kv.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/upstream-kv.d.ts +1 -0
- package/dist/upstream-kv.d.ts.map +1 -1
- package/dist/upstream-kv.js +6 -6
- package/dist/upstream-kv.js.map +1 -1
- package/docs/api-reference.md +31 -0
- package/docs/getting-started.md +4 -0
- package/docs/indexes.md +7 -3
- package/docs/typed-stores.md +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,6 +31,10 @@ if (result.exists) {
|
|
|
31
31
|
console.log((await result.value).name); // "Alice"
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// Or use getValue() for a simpler read (returns undefined if not found)
|
|
35
|
+
const user = await users.getValue("alice");
|
|
36
|
+
console.log(user?.name); // "Alice"
|
|
37
|
+
|
|
34
38
|
// Delete, iterate keys, entries, getMany — see docs
|
|
35
39
|
await users.delete("alice");
|
|
36
40
|
```
|
|
@@ -75,13 +79,6 @@ BLOB_READ_WRITE_TOKEN=vercel_blob_...
|
|
|
75
79
|
|
|
76
80
|
See [Getting Started](https://github.com/vercel-labs/KV2/blob/main/docs/getting-started.md) for full environment setup.
|
|
77
81
|
|
|
78
|
-
## Testing
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
pnpm test # Unit tests (fake blob store)
|
|
82
|
-
pnpm test:integration # Integration tests (real Vercel Blob)
|
|
83
|
-
```
|
|
84
|
-
|
|
85
82
|
## License
|
|
86
83
|
|
|
87
84
|
ISC
|
package/SKILL.md
CHANGED
|
@@ -22,7 +22,16 @@ await users.set("alice", { name: "Alice", email: "alice@example.com" });
|
|
|
22
22
|
|
|
23
23
|
### Reading values
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
For simple reads where you just need the value, use `getValue()` — it returns `V | undefined`:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
const user = await users.getValue("alice");
|
|
29
|
+
if (user) {
|
|
30
|
+
console.log(user.name);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
When you need metadata, version, stream, or `update()`, use `get()` — it returns a discriminated union:
|
|
26
35
|
|
|
27
36
|
```typescript
|
|
28
37
|
const result = await users.get("alice");
|
|
@@ -34,13 +43,15 @@ if (result.exists) {
|
|
|
34
43
|
|
|
35
44
|
### Indexes
|
|
36
45
|
|
|
37
|
-
Define indexes in `getStore()` to enable lookups by secondary keys.
|
|
46
|
+
Define indexes in `getStore()` to enable lookups by secondary keys. Use `defineIndexes<V>()` to let TypeScript infer index names automatically:
|
|
38
47
|
|
|
39
48
|
```typescript
|
|
40
|
-
|
|
49
|
+
import { defineIndexes } from "@vercel/kv2";
|
|
50
|
+
|
|
51
|
+
const users = kv.getStore("users/", defineIndexes<User>()({
|
|
41
52
|
byEmail: { key: (u) => u.email, unique: true },
|
|
42
53
|
byRole: { key: (u) => u.role },
|
|
43
|
-
});
|
|
54
|
+
}));
|
|
44
55
|
|
|
45
56
|
// Exact match on unique index — returns single result
|
|
46
57
|
const result = await users.get({ byEmail: "alice@example.com" });
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type GetBlobResult, type GetCommandOptions, type ListBlobResult, type ListCommandOptions, type PutBlobResult, type PutCommandOptions } from "@vercel/blob";
|
|
2
|
+
import type { BlobStore, PutBody } from "../types.js";
|
|
3
|
+
export declare class DiskBlobStore implements BlobStore {
|
|
4
|
+
private rootDir;
|
|
5
|
+
private locks;
|
|
6
|
+
constructor(rootDir: string);
|
|
7
|
+
private filePath;
|
|
8
|
+
private metaPath;
|
|
9
|
+
private withLock;
|
|
10
|
+
private readMeta;
|
|
11
|
+
get(pathname: string, _options: GetCommandOptions): Promise<GetBlobResult | null>;
|
|
12
|
+
put(pathname: string, body: PutBody, options: PutCommandOptions): Promise<PutBlobResult>;
|
|
13
|
+
del(urlOrPathname: string | string[]): Promise<void>;
|
|
14
|
+
list(options?: ListCommandOptions): Promise<ListBlobResult>;
|
|
15
|
+
private walkDir;
|
|
16
|
+
clear(): Promise<void>;
|
|
17
|
+
has(pathname: string): Promise<boolean>;
|
|
18
|
+
getContent(pathname: string): Promise<Buffer | undefined>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=disk-blob-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disk-blob-store.d.ts","sourceRoot":"","sources":["../../src/blob-stores/disk-blob-store.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AA4CtD,qBAAa,aAAc,YAAW,SAAS;IAC7C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAoC;gBAErC,OAAO,EAAE,MAAM;IAI3B,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,QAAQ;YAIF,QAAQ;YAsBR,QAAQ;IAUhB,GAAG,CACP,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAwC1B,GAAG,CACP,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,aAAa,CAAC;IA6CnB,GAAG,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBpD,IAAI,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC;YA8CnD,OAAO;IA+Bf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASvC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAOhE"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { BlobPreconditionFailedError, } from "@vercel/blob";
|
|
4
|
+
let etagCounter = 0;
|
|
5
|
+
function generateEtag() {
|
|
6
|
+
return `"disk-etag-${++etagCounter}-${Date.now()}"`;
|
|
7
|
+
}
|
|
8
|
+
async function toBuffer(body) {
|
|
9
|
+
if (typeof body === "string") {
|
|
10
|
+
return Buffer.from(body, "utf-8");
|
|
11
|
+
}
|
|
12
|
+
if (body instanceof Buffer) {
|
|
13
|
+
return body;
|
|
14
|
+
}
|
|
15
|
+
if (body instanceof Blob) {
|
|
16
|
+
const arrayBuffer = await body.arrayBuffer();
|
|
17
|
+
return Buffer.from(arrayBuffer);
|
|
18
|
+
}
|
|
19
|
+
if (body instanceof ArrayBuffer) {
|
|
20
|
+
return Buffer.from(body);
|
|
21
|
+
}
|
|
22
|
+
if (ArrayBuffer.isView(body)) {
|
|
23
|
+
return Buffer.from(body.buffer, body.byteOffset, body.byteLength);
|
|
24
|
+
}
|
|
25
|
+
if (body instanceof ReadableStream) {
|
|
26
|
+
const chunks = [];
|
|
27
|
+
const reader = body.getReader();
|
|
28
|
+
while (true) {
|
|
29
|
+
const { done, value } = await reader.read();
|
|
30
|
+
if (done)
|
|
31
|
+
break;
|
|
32
|
+
chunks.push(value);
|
|
33
|
+
}
|
|
34
|
+
return Buffer.concat(chunks);
|
|
35
|
+
}
|
|
36
|
+
throw new Error("Unsupported body type");
|
|
37
|
+
}
|
|
38
|
+
export class DiskBlobStore {
|
|
39
|
+
rootDir;
|
|
40
|
+
locks = new Map();
|
|
41
|
+
constructor(rootDir) {
|
|
42
|
+
this.rootDir = rootDir;
|
|
43
|
+
}
|
|
44
|
+
filePath(pathname) {
|
|
45
|
+
return path.join(this.rootDir, pathname);
|
|
46
|
+
}
|
|
47
|
+
metaPath(pathname) {
|
|
48
|
+
return `${path.join(this.rootDir, pathname)}.meta`;
|
|
49
|
+
}
|
|
50
|
+
async withLock(pathname, fn) {
|
|
51
|
+
while (this.locks.has(pathname)) {
|
|
52
|
+
await this.locks.get(pathname);
|
|
53
|
+
}
|
|
54
|
+
let resolve;
|
|
55
|
+
const lock = new Promise((r) => {
|
|
56
|
+
resolve = r;
|
|
57
|
+
});
|
|
58
|
+
this.locks.set(pathname, lock);
|
|
59
|
+
try {
|
|
60
|
+
return await fn();
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
this.locks.delete(pathname);
|
|
64
|
+
resolve();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async readMeta(pathname) {
|
|
68
|
+
try {
|
|
69
|
+
const raw = await fs.readFile(this.metaPath(pathname), "utf-8");
|
|
70
|
+
return JSON.parse(raw);
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
if (e.code === "ENOENT")
|
|
74
|
+
return null;
|
|
75
|
+
throw e;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async get(pathname, _options) {
|
|
79
|
+
const meta = await this.readMeta(pathname);
|
|
80
|
+
if (!meta)
|
|
81
|
+
return null;
|
|
82
|
+
let content;
|
|
83
|
+
try {
|
|
84
|
+
content = await fs.readFile(this.filePath(pathname));
|
|
85
|
+
}
|
|
86
|
+
catch (e) {
|
|
87
|
+
if (e.code === "ENOENT")
|
|
88
|
+
return null;
|
|
89
|
+
throw e;
|
|
90
|
+
}
|
|
91
|
+
const stream = new ReadableStream({
|
|
92
|
+
start(controller) {
|
|
93
|
+
controller.enqueue(new Uint8Array(content));
|
|
94
|
+
controller.close();
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
return {
|
|
98
|
+
stream,
|
|
99
|
+
blob: {
|
|
100
|
+
url: `disk://${pathname}`,
|
|
101
|
+
downloadUrl: `disk://${pathname}?download=1`,
|
|
102
|
+
pathname,
|
|
103
|
+
contentType: meta.contentType,
|
|
104
|
+
contentDisposition: `attachment; filename="${pathname.split("/").pop()}"`,
|
|
105
|
+
cacheControl: "public, max-age=31536000, immutable",
|
|
106
|
+
size: meta.size,
|
|
107
|
+
uploadedAt: new Date(meta.uploadedAt),
|
|
108
|
+
etag: meta.etag,
|
|
109
|
+
},
|
|
110
|
+
headers: new Headers({
|
|
111
|
+
"content-type": meta.contentType,
|
|
112
|
+
"content-length": String(meta.size),
|
|
113
|
+
etag: meta.etag,
|
|
114
|
+
}),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
async put(pathname, body, options) {
|
|
118
|
+
const content = await toBuffer(body);
|
|
119
|
+
return this.withLock(pathname, async () => {
|
|
120
|
+
const existingMeta = await this.readMeta(pathname);
|
|
121
|
+
const allowOverwrite = options.allowOverwrite ?? true;
|
|
122
|
+
if (!allowOverwrite && existingMeta) {
|
|
123
|
+
throw new BlobPreconditionFailedError();
|
|
124
|
+
}
|
|
125
|
+
if (options.ifMatch !== undefined) {
|
|
126
|
+
if (!existingMeta) {
|
|
127
|
+
throw new BlobPreconditionFailedError();
|
|
128
|
+
}
|
|
129
|
+
if (existingMeta.etag !== options.ifMatch) {
|
|
130
|
+
throw new BlobPreconditionFailedError();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const etag = generateEtag();
|
|
134
|
+
const contentType = options.contentType ?? "application/octet-stream";
|
|
135
|
+
const meta = {
|
|
136
|
+
etag,
|
|
137
|
+
contentType,
|
|
138
|
+
uploadedAt: new Date().toISOString(),
|
|
139
|
+
size: content.length,
|
|
140
|
+
};
|
|
141
|
+
const fp = this.filePath(pathname);
|
|
142
|
+
await fs.mkdir(path.dirname(fp), { recursive: true });
|
|
143
|
+
await fs.writeFile(fp, content);
|
|
144
|
+
await fs.writeFile(this.metaPath(pathname), JSON.stringify(meta));
|
|
145
|
+
return {
|
|
146
|
+
url: `disk://${pathname}`,
|
|
147
|
+
downloadUrl: `disk://${pathname}?download=1`,
|
|
148
|
+
pathname,
|
|
149
|
+
contentType,
|
|
150
|
+
contentDisposition: `attachment; filename="${pathname.split("/").pop()}"`,
|
|
151
|
+
etag,
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
async del(urlOrPathname) {
|
|
156
|
+
const paths = Array.isArray(urlOrPathname)
|
|
157
|
+
? urlOrPathname
|
|
158
|
+
: [urlOrPathname];
|
|
159
|
+
for (const p of paths) {
|
|
160
|
+
const pathname = p.startsWith("disk://") ? p.slice(7) : p;
|
|
161
|
+
try {
|
|
162
|
+
await fs.unlink(this.filePath(pathname));
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
if (e.code !== "ENOENT")
|
|
166
|
+
throw e;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
await fs.unlink(this.metaPath(pathname));
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
if (e.code !== "ENOENT")
|
|
173
|
+
throw e;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async list(options) {
|
|
178
|
+
// Scope the walk to the deepest directory implied by the prefix
|
|
179
|
+
// e.g. prefix "users/posts/" walks <rootDir>/users/posts/ instead of <rootDir>/
|
|
180
|
+
const prefix = options?.prefix ?? "";
|
|
181
|
+
const prefixDir = prefix.includes("/")
|
|
182
|
+
? prefix.slice(0, prefix.lastIndexOf("/") + 1)
|
|
183
|
+
: "";
|
|
184
|
+
const walkRoot = prefixDir
|
|
185
|
+
? path.join(this.rootDir, prefixDir)
|
|
186
|
+
: this.rootDir;
|
|
187
|
+
const allFiles = await this.walkDir(walkRoot);
|
|
188
|
+
// Filter to content files (skip .meta), compute relative pathnames
|
|
189
|
+
const entries = [];
|
|
190
|
+
for (const absPath of allFiles) {
|
|
191
|
+
if (absPath.endsWith(".meta"))
|
|
192
|
+
continue;
|
|
193
|
+
const pathname = path.relative(this.rootDir, absPath);
|
|
194
|
+
if (prefix && !pathname.startsWith(prefix))
|
|
195
|
+
continue;
|
|
196
|
+
const meta = await this.readMeta(pathname);
|
|
197
|
+
if (meta)
|
|
198
|
+
entries.push({ pathname, meta });
|
|
199
|
+
}
|
|
200
|
+
entries.sort((a, b) => a.pathname.localeCompare(b.pathname));
|
|
201
|
+
const limit = options?.limit ?? 1000;
|
|
202
|
+
const cursorIndex = options?.cursor
|
|
203
|
+
? Number.parseInt(options.cursor, 10)
|
|
204
|
+
: 0;
|
|
205
|
+
const slice = entries.slice(cursorIndex, cursorIndex + limit);
|
|
206
|
+
const hasMore = cursorIndex + limit < entries.length;
|
|
207
|
+
return {
|
|
208
|
+
blobs: slice.map((e) => ({
|
|
209
|
+
url: `disk://${e.pathname}`,
|
|
210
|
+
downloadUrl: `disk://${e.pathname}?download=1`,
|
|
211
|
+
pathname: e.pathname,
|
|
212
|
+
size: e.meta.size,
|
|
213
|
+
uploadedAt: new Date(e.meta.uploadedAt),
|
|
214
|
+
etag: e.meta.etag,
|
|
215
|
+
})),
|
|
216
|
+
hasMore,
|
|
217
|
+
cursor: hasMore ? String(cursorIndex + limit) : undefined,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
async walkDir(dir, concurrency = 16) {
|
|
221
|
+
let names;
|
|
222
|
+
try {
|
|
223
|
+
names = await fs.readdir(dir);
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
if (e.code === "ENOENT")
|
|
227
|
+
return [];
|
|
228
|
+
throw e;
|
|
229
|
+
}
|
|
230
|
+
const results = [];
|
|
231
|
+
// Process entries in batches to limit open file descriptors
|
|
232
|
+
for (let i = 0; i < names.length; i += concurrency) {
|
|
233
|
+
const batch = names.slice(i, i + concurrency);
|
|
234
|
+
const settled = await Promise.all(batch.map(async (name) => {
|
|
235
|
+
const full = path.join(dir, name);
|
|
236
|
+
const stat = await fs.stat(full);
|
|
237
|
+
if (stat.isDirectory()) {
|
|
238
|
+
return this.walkDir(full, concurrency);
|
|
239
|
+
}
|
|
240
|
+
return [full];
|
|
241
|
+
}));
|
|
242
|
+
for (const files of settled) {
|
|
243
|
+
results.push(...files);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return results;
|
|
247
|
+
}
|
|
248
|
+
// Test helpers
|
|
249
|
+
async clear() {
|
|
250
|
+
await fs.rm(this.rootDir, { recursive: true, force: true });
|
|
251
|
+
}
|
|
252
|
+
async has(pathname) {
|
|
253
|
+
try {
|
|
254
|
+
await fs.access(this.filePath(pathname));
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async getContent(pathname) {
|
|
262
|
+
try {
|
|
263
|
+
return await fs.readFile(this.filePath(pathname));
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=disk-blob-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disk-blob-store.js","sourceRoot":"","sources":["../../src/blob-stores/disk-blob-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type GetBlobResult, type GetCommandOptions, type ListBlobResult, type ListCommandOptions, type PutBlobResult, type PutCommandOptions } from "@vercel/blob";
|
|
2
|
+
import type { BlobStore, PutBody } from "../types.js";
|
|
3
|
+
interface StoredBlob {
|
|
4
|
+
pathname: string;
|
|
5
|
+
content: Buffer;
|
|
6
|
+
contentType: string;
|
|
7
|
+
uploadedAt: Date;
|
|
8
|
+
size: number;
|
|
9
|
+
etag: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class InMemoryBlobStore implements BlobStore {
|
|
12
|
+
private blobs;
|
|
13
|
+
private locks;
|
|
14
|
+
/**
|
|
15
|
+
* Serialize writes to the same key to prevent race conditions
|
|
16
|
+
* where concurrent callers all pass precondition checks before
|
|
17
|
+
* any write lands.
|
|
18
|
+
*/
|
|
19
|
+
private withLock;
|
|
20
|
+
get(pathname: string, _options: GetCommandOptions): Promise<GetBlobResult | null>;
|
|
21
|
+
put(pathname: string, body: PutBody, options: PutCommandOptions): Promise<PutBlobResult>;
|
|
22
|
+
del(urlOrPathname: string | string[]): Promise<void>;
|
|
23
|
+
list(options?: ListCommandOptions): Promise<ListBlobResult>;
|
|
24
|
+
clear(): void;
|
|
25
|
+
has(pathname: string): boolean;
|
|
26
|
+
getContent(pathname: string): Buffer | undefined;
|
|
27
|
+
getAll(): Map<string, StoredBlob>;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=in-memory-blob-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-blob-store.d.ts","sourceRoot":"","sources":["../../src/blob-stores/in-memory-blob-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtD,UAAU,UAAU;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,IAAI,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAqCD,qBAAa,iBAAkB,YAAW,SAAS;IACjD,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,KAAK,CAAoC;IAEjD;;;;OAIG;YACW,QAAQ;IAuBhB,GAAG,CACP,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAmC1B,GAAG,CACP,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,aAAa,CAAC;IA+CnB,GAAG,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAWpD,IAAI,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC;IAoCjE,KAAK,IAAI,IAAI;IAIb,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAI9B,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIhD,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC;CAGlC"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { BlobPreconditionFailedError, } from "@vercel/blob";
|
|
2
|
+
let etagCounter = 0;
|
|
3
|
+
function generateEtag() {
|
|
4
|
+
return `"fake-etag-${++etagCounter}-${Date.now()}"`;
|
|
5
|
+
}
|
|
6
|
+
async function toBuffer(body) {
|
|
7
|
+
if (typeof body === "string") {
|
|
8
|
+
return Buffer.from(body, "utf-8");
|
|
9
|
+
}
|
|
10
|
+
if (body instanceof Buffer) {
|
|
11
|
+
return body;
|
|
12
|
+
}
|
|
13
|
+
if (body instanceof Blob) {
|
|
14
|
+
const arrayBuffer = await body.arrayBuffer();
|
|
15
|
+
return Buffer.from(arrayBuffer);
|
|
16
|
+
}
|
|
17
|
+
if (body instanceof ArrayBuffer) {
|
|
18
|
+
return Buffer.from(body);
|
|
19
|
+
}
|
|
20
|
+
if (ArrayBuffer.isView(body)) {
|
|
21
|
+
return Buffer.from(body.buffer, body.byteOffset, body.byteLength);
|
|
22
|
+
}
|
|
23
|
+
if (body instanceof ReadableStream) {
|
|
24
|
+
const chunks = [];
|
|
25
|
+
const reader = body.getReader();
|
|
26
|
+
while (true) {
|
|
27
|
+
const { done, value } = await reader.read();
|
|
28
|
+
if (done)
|
|
29
|
+
break;
|
|
30
|
+
chunks.push(value);
|
|
31
|
+
}
|
|
32
|
+
return Buffer.concat(chunks);
|
|
33
|
+
}
|
|
34
|
+
throw new Error("Unsupported body type");
|
|
35
|
+
}
|
|
36
|
+
export class InMemoryBlobStore {
|
|
37
|
+
blobs = new Map();
|
|
38
|
+
locks = new Map();
|
|
39
|
+
/**
|
|
40
|
+
* Serialize writes to the same key to prevent race conditions
|
|
41
|
+
* where concurrent callers all pass precondition checks before
|
|
42
|
+
* any write lands.
|
|
43
|
+
*/
|
|
44
|
+
async withLock(pathname, fn) {
|
|
45
|
+
// Wait for any in-flight write to this key
|
|
46
|
+
while (this.locks.has(pathname)) {
|
|
47
|
+
await this.locks.get(pathname);
|
|
48
|
+
}
|
|
49
|
+
let resolve;
|
|
50
|
+
const lock = new Promise((r) => {
|
|
51
|
+
resolve = r;
|
|
52
|
+
});
|
|
53
|
+
this.locks.set(pathname, lock);
|
|
54
|
+
try {
|
|
55
|
+
return await fn();
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
this.locks.delete(pathname);
|
|
59
|
+
resolve();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async get(pathname, _options) {
|
|
63
|
+
const blob = this.blobs.get(pathname);
|
|
64
|
+
if (!blob) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const content = blob.content;
|
|
68
|
+
const stream = new ReadableStream({
|
|
69
|
+
start(controller) {
|
|
70
|
+
controller.enqueue(new Uint8Array(content));
|
|
71
|
+
controller.close();
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
stream,
|
|
76
|
+
blob: {
|
|
77
|
+
url: `fake://${pathname}`,
|
|
78
|
+
downloadUrl: `fake://${pathname}?download=1`,
|
|
79
|
+
pathname,
|
|
80
|
+
contentType: blob.contentType,
|
|
81
|
+
contentDisposition: `attachment; filename="${pathname.split("/").pop()}"`,
|
|
82
|
+
cacheControl: "public, max-age=31536000, immutable",
|
|
83
|
+
size: blob.size,
|
|
84
|
+
uploadedAt: blob.uploadedAt,
|
|
85
|
+
etag: blob.etag,
|
|
86
|
+
},
|
|
87
|
+
headers: new Headers({
|
|
88
|
+
"content-type": blob.contentType,
|
|
89
|
+
"content-length": String(blob.size),
|
|
90
|
+
etag: blob.etag,
|
|
91
|
+
}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
async put(pathname, body, options) {
|
|
95
|
+
// Buffer the body outside the lock to avoid holding the lock
|
|
96
|
+
// during potentially slow stream reads, matching real blob store
|
|
97
|
+
// behavior where the server handles serialization.
|
|
98
|
+
const content = await toBuffer(body);
|
|
99
|
+
return this.withLock(pathname, () => {
|
|
100
|
+
const existingBlob = this.blobs.get(pathname);
|
|
101
|
+
// Check allowOverwrite option (default: true based on @vercel/blob behavior)
|
|
102
|
+
const allowOverwrite = options.allowOverwrite ?? true;
|
|
103
|
+
if (!allowOverwrite && existingBlob) {
|
|
104
|
+
throw new BlobPreconditionFailedError();
|
|
105
|
+
}
|
|
106
|
+
// Check ifMatch (optimistic locking)
|
|
107
|
+
if (options.ifMatch !== undefined) {
|
|
108
|
+
if (!existingBlob) {
|
|
109
|
+
// Real @vercel/blob throws "The specified key does not exist"
|
|
110
|
+
throw new BlobPreconditionFailedError();
|
|
111
|
+
}
|
|
112
|
+
if (existingBlob.etag !== options.ifMatch) {
|
|
113
|
+
throw new BlobPreconditionFailedError();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const etag = generateEtag();
|
|
117
|
+
this.blobs.set(pathname, {
|
|
118
|
+
pathname,
|
|
119
|
+
content,
|
|
120
|
+
contentType: options.contentType ?? "application/octet-stream",
|
|
121
|
+
uploadedAt: new Date(),
|
|
122
|
+
size: content.length,
|
|
123
|
+
etag,
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
url: `fake://${pathname}`,
|
|
127
|
+
downloadUrl: `fake://${pathname}?download=1`,
|
|
128
|
+
pathname,
|
|
129
|
+
contentType: options.contentType ?? "application/octet-stream",
|
|
130
|
+
contentDisposition: `attachment; filename="${pathname.split("/").pop()}"`,
|
|
131
|
+
etag,
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async del(urlOrPathname) {
|
|
136
|
+
const paths = Array.isArray(urlOrPathname)
|
|
137
|
+
? urlOrPathname
|
|
138
|
+
: [urlOrPathname];
|
|
139
|
+
for (const p of paths) {
|
|
140
|
+
// Handle both URLs and pathnames
|
|
141
|
+
const pathname = p.startsWith("fake://") ? p.slice(7) : p;
|
|
142
|
+
this.blobs.delete(pathname);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async list(options) {
|
|
146
|
+
let entries = [...this.blobs.values()];
|
|
147
|
+
// Filter by prefix
|
|
148
|
+
if (options?.prefix) {
|
|
149
|
+
entries = entries.filter((b) => b.pathname.startsWith(options.prefix));
|
|
150
|
+
}
|
|
151
|
+
// Sort by pathname for consistent ordering
|
|
152
|
+
entries.sort((a, b) => a.pathname.localeCompare(b.pathname));
|
|
153
|
+
// Handle pagination
|
|
154
|
+
const limit = options?.limit ?? 1000;
|
|
155
|
+
const cursorIndex = options?.cursor
|
|
156
|
+
? Number.parseInt(options.cursor, 10)
|
|
157
|
+
: 0;
|
|
158
|
+
const slice = entries.slice(cursorIndex, cursorIndex + limit);
|
|
159
|
+
const hasMore = cursorIndex + limit < entries.length;
|
|
160
|
+
return {
|
|
161
|
+
blobs: slice.map((b) => ({
|
|
162
|
+
url: `fake://${b.pathname}`,
|
|
163
|
+
downloadUrl: `fake://${b.pathname}?download=1`,
|
|
164
|
+
pathname: b.pathname,
|
|
165
|
+
size: b.size,
|
|
166
|
+
uploadedAt: b.uploadedAt,
|
|
167
|
+
etag: b.etag,
|
|
168
|
+
})),
|
|
169
|
+
hasMore,
|
|
170
|
+
cursor: hasMore ? String(cursorIndex + limit) : undefined,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
// Test helpers
|
|
174
|
+
clear() {
|
|
175
|
+
this.blobs.clear();
|
|
176
|
+
}
|
|
177
|
+
has(pathname) {
|
|
178
|
+
return this.blobs.has(pathname);
|
|
179
|
+
}
|
|
180
|
+
getContent(pathname) {
|
|
181
|
+
return this.blobs.get(pathname)?.content;
|
|
182
|
+
}
|
|
183
|
+
getAll() {
|
|
184
|
+
return new Map(this.blobs);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=in-memory-blob-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-blob-store.js","sourceRoot":"","sources":["../../src/blob-stores/in-memory-blob-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blob-stores/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/blob-stores/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type GetBlobResult, type GetCommandOptions, type ListBlobResult, type ListCommandOptions, type PutBlobResult, type PutCommandOptions } from "@vercel/blob";
|
|
2
|
+
import type { BlobStore, PutBody } from "../types.js";
|
|
3
|
+
export declare class VercelBlobStore implements BlobStore {
|
|
4
|
+
private token?;
|
|
5
|
+
constructor(token?: string);
|
|
6
|
+
get(pathname: string, options: GetCommandOptions): Promise<GetBlobResult | null>;
|
|
7
|
+
put(pathname: string, body: PutBody, options: PutCommandOptions): Promise<PutBlobResult>;
|
|
8
|
+
del(urlOrPathname: string | string[]): Promise<void>;
|
|
9
|
+
list(options?: ListCommandOptions): Promise<ListBlobResult>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=vercel-blob-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel-blob-store.d.ts","sourceRoot":"","sources":["../../src/blob-stores/vercel-blob-store.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EAKvB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGtD,qBAAa,eAAgB,YAAW,SAAS;IAC/C,OAAO,CAAC,KAAK,CAAC,CAAS;gBAEX,KAAK,CAAC,EAAE,MAAM;IAIpB,GAAG,CACP,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAQ1B,GAAG,CACP,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,aAAa,CAAC;IAOnB,GAAG,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpD,IAAI,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC;CAMlE"}
|