@alepha/bucket-vercel 0.10.2 → 0.10.3
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/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,15 @@ import * as _alepha_core1 from "@alepha/core";
|
|
|
3
3
|
import { Alepha, FileLike, Static } from "@alepha/core";
|
|
4
4
|
import { DateTimeProvider } from "@alepha/datetime";
|
|
5
5
|
import * as _alepha_logger0 from "@alepha/logger";
|
|
6
|
+
import { del, head, put } from "@vercel/blob";
|
|
6
7
|
|
|
8
|
+
//#region src/providers/VercelBlobProvider.d.ts
|
|
9
|
+
declare class VercelBlobApi {
|
|
10
|
+
put: typeof put;
|
|
11
|
+
head: typeof head;
|
|
12
|
+
del: typeof del;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
7
15
|
//#region src/providers/VercelFileStorageProvider.d.ts
|
|
8
16
|
declare const envSchema: _alepha_core1.TObject<{
|
|
9
17
|
BLOB_READ_WRITE_TOKEN: _alepha_core1.TString;
|
|
@@ -22,6 +30,7 @@ declare class VercelFileStorageProvider implements FileStorageProvider {
|
|
|
22
30
|
protected readonly alepha: Alepha;
|
|
23
31
|
protected readonly time: DateTimeProvider;
|
|
24
32
|
protected readonly stores: Set<string>;
|
|
33
|
+
protected readonly vercelBlobApi: VercelBlobApi;
|
|
25
34
|
protected readonly onStart: _alepha_core1.HookDescriptor<"start">;
|
|
26
35
|
convertName(name: string): string;
|
|
27
36
|
upload(bucketName: string, file: FileLike, fileId?: string): Promise<string>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/providers/VercelFileStorageProvider.ts","../src/index.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/providers/VercelBlobProvider.ts","../src/providers/VercelFileStorageProvider.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;cAEa,aAAA;cACA;eACC;cACD;;;;cCgBP,yBAAS;yBAIb,aAAA,CAAA;;;EDvBW,UAAA,GAAA,SC0BU,OD1BG,CC0BK,MD1BL,CAAA,OC0BmB,SD1BnB,CAAA,CAAA,CAAA,CAAA;;;;;cCgCb,yBAAA,YAAqC;0BAAX,eAAA,CAChB;;IAdjB,qBAIJ,EAAA,MAAA;EAAA,CAAA;qBAAA,MAAA,EAYwB,MAZxB;qBAJa,IAAA,EAiBS,gBAjBT;EAAA,mBAAA,MAAA,EAkBa,GAlBb,CAAA,MAAA,CAAA;EAAA,mBAAA,aAAA,EAmBkB,aAnBlB;EAAA,mBAAA,OAAA,EAmBkB,aAAA,CAEN,cArBZ,CAAA,OAAA,CAAA;aAO8B,CAAA,IAAA,EAAA,MAAA,CAAA,EAAA,MAAA;QAAd,CAAA,UAAA,EAAA,MAAA,EAAA,IAAA,EA0CvB,QA1CuB,EAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EA4C3B,OA5C2B,CAAA,MAAA,CAAA;UAAR,CAAA,UAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAkFqC,OAlFrC,CAkF6C,QAlF7C,CAAA;EAAO,MAAA,CAAA,UAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EA0I4B,OA1I5B,CAAA,OAAA,CAAA;EAAA,MAAA,CAAA,UAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EA6J4B,OA7J5B,CAAA,IAAA,CAAA;AAM9B;;;;;;;;;cClBa,oBAAkB,aAAA,CAAA,QAW7B,aAAA,CAX6B"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,14 @@ import { createFile } from "@alepha/file";
|
|
|
5
5
|
import { $logger } from "@alepha/logger";
|
|
6
6
|
import { del, head, put } from "@vercel/blob";
|
|
7
7
|
|
|
8
|
+
//#region src/providers/VercelBlobProvider.ts
|
|
9
|
+
var VercelBlobApi = class {
|
|
10
|
+
put = put;
|
|
11
|
+
head = head;
|
|
12
|
+
del = del;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
8
16
|
//#region src/providers/VercelFileStorageProvider.ts
|
|
9
17
|
const envSchema = t.object({ BLOB_READ_WRITE_TOKEN: t.string({ size: "long" }) });
|
|
10
18
|
/**
|
|
@@ -16,6 +24,7 @@ var VercelFileStorageProvider = class {
|
|
|
16
24
|
alepha = $inject(Alepha);
|
|
17
25
|
time = $inject(DateTimeProvider);
|
|
18
26
|
stores = /* @__PURE__ */ new Set();
|
|
27
|
+
vercelBlobApi = $inject(VercelBlobApi);
|
|
19
28
|
onStart = $hook({
|
|
20
29
|
on: "start",
|
|
21
30
|
handler: async () => {
|
|
@@ -37,10 +46,11 @@ var VercelFileStorageProvider = class {
|
|
|
37
46
|
const storeName = this.convertName(bucketName);
|
|
38
47
|
const pathname = `${storeName}/${fileId}`;
|
|
39
48
|
try {
|
|
40
|
-
const result = await put(pathname, file.stream(), {
|
|
49
|
+
const result = await this.vercelBlobApi.put(pathname, file.stream(), {
|
|
41
50
|
access: "public",
|
|
42
51
|
contentType: file.type,
|
|
43
|
-
token: this.env.BLOB_READ_WRITE_TOKEN
|
|
52
|
+
token: this.env.BLOB_READ_WRITE_TOKEN,
|
|
53
|
+
allowOverwrite: true
|
|
44
54
|
});
|
|
45
55
|
this.log.trace(`File uploaded successfully: ${result.url}`);
|
|
46
56
|
return fileId;
|
|
@@ -55,7 +65,7 @@ var VercelFileStorageProvider = class {
|
|
|
55
65
|
const storeName = this.convertName(bucketName);
|
|
56
66
|
const pathname = `${storeName}/${fileId}`;
|
|
57
67
|
try {
|
|
58
|
-
const headResult = await head(pathname, { token: this.env.BLOB_READ_WRITE_TOKEN });
|
|
68
|
+
const headResult = await this.vercelBlobApi.head(pathname, { token: this.env.BLOB_READ_WRITE_TOKEN });
|
|
59
69
|
if (!headResult) throw new FileNotFoundError(`File '${fileId}' not found in bucket '${bucketName}'`);
|
|
60
70
|
const response = await fetch(headResult.url);
|
|
61
71
|
if (!response.ok) throw new FileNotFoundError(`Failed to fetch file: ${response.statusText}`);
|
|
@@ -79,7 +89,7 @@ var VercelFileStorageProvider = class {
|
|
|
79
89
|
const storeName = this.convertName(bucketName);
|
|
80
90
|
const pathname = `${storeName}/${fileId}`;
|
|
81
91
|
try {
|
|
82
|
-
const result = await head(pathname, { token: this.env.BLOB_READ_WRITE_TOKEN });
|
|
92
|
+
const result = await this.vercelBlobApi.head(pathname, { token: this.env.BLOB_READ_WRITE_TOKEN });
|
|
83
93
|
return result !== null;
|
|
84
94
|
} catch (error) {
|
|
85
95
|
return false;
|
|
@@ -90,7 +100,7 @@ var VercelFileStorageProvider = class {
|
|
|
90
100
|
const storeName = this.convertName(bucketName);
|
|
91
101
|
const pathname = `${storeName}/${fileId}`;
|
|
92
102
|
try {
|
|
93
|
-
await del(pathname, { token: this.env.BLOB_READ_WRITE_TOKEN });
|
|
103
|
+
await this.vercelBlobApi.del(pathname, { token: this.env.BLOB_READ_WRITE_TOKEN });
|
|
94
104
|
} catch (error) {
|
|
95
105
|
this.log.error(`Failed to delete file: ${error}`);
|
|
96
106
|
if (error instanceof Error) throw new FileNotFoundError("Error deleting file", { cause: error });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/providers/VercelFileStorageProvider.ts","../src/index.ts"],"sourcesContent":["import type { Readable } from \"node:stream\";\nimport {\n\t$bucket,\n\tFileNotFoundError,\n\ttype FileStorageProvider,\n} from \"@alepha/bucket\";\nimport {\n\t$env,\n\t$hook,\n\t$inject,\n\tAlepha,\n\tAlephaError,\n\ttype FileLike,\n\ttype Static,\n\tt,\n} from \"@alepha/core\";\nimport { DateTimeProvider } from \"@alepha/datetime\";\nimport { createFile } from \"@alepha/file\";\nimport { $logger } from \"@alepha/logger\";\nimport {
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/providers/VercelBlobProvider.ts","../src/providers/VercelFileStorageProvider.ts","../src/index.ts"],"sourcesContent":["import { del, head, put } from \"@vercel/blob\";\n\nexport class VercelBlobApi {\n\tput: typeof put = put;\n\thead: typeof head = head;\n\tdel: typeof del = del;\n}\n","import type { Readable } from \"node:stream\";\nimport {\n\t$bucket,\n\tFileNotFoundError,\n\ttype FileStorageProvider,\n} from \"@alepha/bucket\";\nimport {\n\t$env,\n\t$hook,\n\t$inject,\n\tAlepha,\n\tAlephaError,\n\ttype FileLike,\n\ttype Static,\n\tt,\n} from \"@alepha/core\";\nimport { DateTimeProvider } from \"@alepha/datetime\";\nimport { createFile } from \"@alepha/file\";\nimport { $logger } from \"@alepha/logger\";\nimport { VercelBlobApi } from \"./VercelBlobProvider.ts\";\n\nconst envSchema = t.object({\n\tBLOB_READ_WRITE_TOKEN: t.string({\n\t\tsize: \"long\",\n\t}),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n}\n\n/**\n * Vercel Blob Storage implementation of File Storage Provider.\n */\nexport class VercelFileStorageProvider implements FileStorageProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly env = $env(envSchema);\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly time = $inject(DateTimeProvider);\n\tprotected readonly stores: Set<string> = new Set();\n\tprotected readonly vercelBlobApi = $inject(VercelBlobApi);\n\n\tprotected readonly onStart = $hook({\n\t\ton: \"start\",\n\t\thandler: async () => {\n\t\t\tfor (const bucket of this.alepha.descriptors($bucket)) {\n\t\t\t\tif (bucket.provider !== this) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst storeName = this.convertName(bucket.name);\n\n\t\t\t\tthis.log.debug(`Prepare store '${storeName}' ...`);\n\n\t\t\t\t// Vercel Blob doesn't require explicit store/container creation\n\t\t\t\t// We just track the store names for reference\n\t\t\t\tthis.stores.add(storeName);\n\n\t\t\t\tthis.log.info(`Store '${bucket.name}' OK`);\n\t\t\t}\n\t\t},\n\t});\n\n\tpublic convertName(name: string): string {\n\t\t// Convert to a valid path-like name for Vercel Blob\n\t\treturn name.replaceAll(\"/\", \"-\").toLowerCase();\n\t}\n\n\tpublic async upload(\n\t\tbucketName: string,\n\t\tfile: FileLike,\n\t\tfileId?: string,\n\t): Promise<string> {\n\t\t// force file id as filename for Vercel because we can't store filename as metadata\n\t\t// it's bad, but we have no choice for now\n\t\tfileId = file.name;\n\n\t\tthis.log.trace(\n\t\t\t`Uploading file '${file.name}' to bucket '${bucketName}' with id '${fileId}'...`,\n\t\t);\n\n\t\tconst storeName = this.convertName(bucketName);\n\t\tconst pathname = `${storeName}/${fileId}`;\n\n\t\ttry {\n\t\t\tconst result = await this.vercelBlobApi.put(\n\t\t\t\tpathname,\n\t\t\t\tfile.stream() as Readable,\n\t\t\t\t{\n\t\t\t\t\taccess: \"public\",\n\t\t\t\t\tcontentType: file.type,\n\t\t\t\t\ttoken: this.env.BLOB_READ_WRITE_TOKEN,\n\t\t\t\t\tallowOverwrite: true,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tthis.log.trace(`File uploaded successfully: ${result.url}`);\n\t\t\treturn fileId;\n\t\t} catch (error) {\n\t\t\tthis.log.error(`Failed to upload file: ${error}`);\n\t\t\tif (error instanceof Error) {\n\t\t\t\tthrow new AlephaError(`Upload failed: ${error.message}`, {\n\t\t\t\t\tcause: error,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async download(bucketName: string, fileId: string): Promise<FileLike> {\n\t\tthis.log.trace(\n\t\t\t`Downloading file '${fileId}' from bucket '${bucketName}'...`,\n\t\t);\n\n\t\tconst storeName = this.convertName(bucketName);\n\t\tconst pathname = `${storeName}/${fileId}`;\n\n\t\ttry {\n\t\t\t// check if the file exists and get metadata\n\t\t\tconst headResult = await this.vercelBlobApi.head(pathname, {\n\t\t\t\ttoken: this.env.BLOB_READ_WRITE_TOKEN,\n\t\t\t});\n\n\t\t\tif (!headResult) {\n\t\t\t\tthrow new FileNotFoundError(\n\t\t\t\t\t`File '${fileId}' not found in bucket '${bucketName}'`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// fetch the actual file content\n\t\t\tconst response = await fetch(headResult.url);\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new FileNotFoundError(\n\t\t\t\t\t`Failed to fetch file: ${response.statusText}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst stream = response.body;\n\t\t\tif (!stream) {\n\t\t\t\tthrow new FileNotFoundError(\"File not found - empty response body\");\n\t\t\t}\n\n\t\t\tconst originalType =\n\t\t\t\tresponse.headers.get(\"Content-Type\") || \"application/octet-stream\";\n\n\t\t\treturn createFile(stream, {\n\t\t\t\tname: fileId,\n\t\t\t\ttype: originalType,\n\t\t\t\tsize: headResult.size,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (error instanceof FileNotFoundError) {\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tthis.log.error(`Failed to download file: ${error}`);\n\t\t\tif (error instanceof Error) {\n\t\t\t\tthrow new FileNotFoundError(\"Error downloading file\", { cause: error });\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async exists(bucketName: string, fileId: string): Promise<boolean> {\n\t\tthis.log.trace(\n\t\t\t`Checking existence of file '${fileId}' in bucket '${bucketName}'...`,\n\t\t);\n\n\t\tconst storeName = this.convertName(bucketName);\n\t\tconst pathname = `${storeName}/${fileId}`;\n\n\t\ttry {\n\t\t\tconst result = await this.vercelBlobApi.head(pathname, {\n\t\t\t\ttoken: this.env.BLOB_READ_WRITE_TOKEN,\n\t\t\t});\n\t\t\treturn result !== null;\n\t\t} catch (error) {\n\t\t\t// Vercel Blob head() throws for non-existent files\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic async delete(bucketName: string, fileId: string): Promise<void> {\n\t\tthis.log.trace(`Deleting file '${fileId}' from bucket '${bucketName}'...`);\n\n\t\tconst storeName = this.convertName(bucketName);\n\t\tconst pathname = `${storeName}/${fileId}`;\n\n\t\ttry {\n\t\t\tawait this.vercelBlobApi.del(pathname, {\n\t\t\t\ttoken: this.env.BLOB_READ_WRITE_TOKEN,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis.log.error(`Failed to delete file: ${error}`);\n\t\t\tif (error instanceof Error) {\n\t\t\t\tthrow new FileNotFoundError(\"Error deleting file\", { cause: error });\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n","import { AlephaBucket, FileStorageProvider } from \"@alepha/bucket\";\nimport { $module } from \"@alepha/core\";\nimport { VercelFileStorageProvider } from \"./providers/VercelFileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./providers/VercelFileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Plugin for Alepha Bucket that provides Vercel Blob Storage capabilities.\n *\n * @see {@link VercelFileStorageProvider}\n * @module alepha.bucket.vercel\n */\nexport const AlephaBucketVercel = $module({\n\tname: \"alepha.bucket.vercel\",\n\tservices: [VercelFileStorageProvider],\n\tregister: (alepha) =>\n\t\talepha\n\t\t\t.with({\n\t\t\t\toptional: true,\n\t\t\t\tprovide: FileStorageProvider,\n\t\t\t\tuse: VercelFileStorageProvider,\n\t\t\t})\n\t\t\t.with(AlephaBucket),\n});\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"blob"
|
|
11
11
|
],
|
|
12
12
|
"author": "Feunard",
|
|
13
|
-
"version": "0.10.
|
|
13
|
+
"version": "0.10.3",
|
|
14
14
|
"type": "module",
|
|
15
15
|
"engines": {
|
|
16
16
|
"node": ">=22.0.0"
|
|
@@ -23,16 +23,16 @@
|
|
|
23
23
|
"src"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@alepha/bucket": "0.10.
|
|
27
|
-
"@alepha/core": "0.10.
|
|
28
|
-
"@alepha/datetime": "0.10.
|
|
29
|
-
"@alepha/file": "0.10.
|
|
30
|
-
"@alepha/logger": "0.10.
|
|
26
|
+
"@alepha/bucket": "0.10.3",
|
|
27
|
+
"@alepha/core": "0.10.3",
|
|
28
|
+
"@alepha/datetime": "0.10.3",
|
|
29
|
+
"@alepha/file": "0.10.3",
|
|
30
|
+
"@alepha/logger": "0.10.3",
|
|
31
31
|
"@vercel/blob": "^2.0.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@biomejs/biome": "^2.2.
|
|
35
|
-
"@types/node": "^24.6.
|
|
34
|
+
"@biomejs/biome": "^2.2.5",
|
|
35
|
+
"@types/node": "^24.6.2",
|
|
36
36
|
"tsdown": "^0.15.6",
|
|
37
37
|
"typescript": "^5.9.3",
|
|
38
38
|
"vitest": "^3.2.4"
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import { DateTimeProvider } from "@alepha/datetime";
|
|
18
18
|
import { createFile } from "@alepha/file";
|
|
19
19
|
import { $logger } from "@alepha/logger";
|
|
20
|
-
import {
|
|
20
|
+
import { VercelBlobApi } from "./VercelBlobProvider.ts";
|
|
21
21
|
|
|
22
22
|
const envSchema = t.object({
|
|
23
23
|
BLOB_READ_WRITE_TOKEN: t.string({
|
|
@@ -38,6 +38,7 @@ export class VercelFileStorageProvider implements FileStorageProvider {
|
|
|
38
38
|
protected readonly alepha = $inject(Alepha);
|
|
39
39
|
protected readonly time = $inject(DateTimeProvider);
|
|
40
40
|
protected readonly stores: Set<string> = new Set();
|
|
41
|
+
protected readonly vercelBlobApi = $inject(VercelBlobApi);
|
|
41
42
|
|
|
42
43
|
protected readonly onStart = $hook({
|
|
43
44
|
on: "start",
|
|
@@ -82,11 +83,16 @@ export class VercelFileStorageProvider implements FileStorageProvider {
|
|
|
82
83
|
const pathname = `${storeName}/${fileId}`;
|
|
83
84
|
|
|
84
85
|
try {
|
|
85
|
-
const result = await put(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
const result = await this.vercelBlobApi.put(
|
|
87
|
+
pathname,
|
|
88
|
+
file.stream() as Readable,
|
|
89
|
+
{
|
|
90
|
+
access: "public",
|
|
91
|
+
contentType: file.type,
|
|
92
|
+
token: this.env.BLOB_READ_WRITE_TOKEN,
|
|
93
|
+
allowOverwrite: true,
|
|
94
|
+
},
|
|
95
|
+
);
|
|
90
96
|
|
|
91
97
|
this.log.trace(`File uploaded successfully: ${result.url}`);
|
|
92
98
|
return fileId;
|
|
@@ -112,7 +118,7 @@ export class VercelFileStorageProvider implements FileStorageProvider {
|
|
|
112
118
|
|
|
113
119
|
try {
|
|
114
120
|
// check if the file exists and get metadata
|
|
115
|
-
const headResult = await head(pathname, {
|
|
121
|
+
const headResult = await this.vercelBlobApi.head(pathname, {
|
|
116
122
|
token: this.env.BLOB_READ_WRITE_TOKEN,
|
|
117
123
|
});
|
|
118
124
|
|
|
@@ -167,7 +173,7 @@ export class VercelFileStorageProvider implements FileStorageProvider {
|
|
|
167
173
|
const pathname = `${storeName}/${fileId}`;
|
|
168
174
|
|
|
169
175
|
try {
|
|
170
|
-
const result = await head(pathname, {
|
|
176
|
+
const result = await this.vercelBlobApi.head(pathname, {
|
|
171
177
|
token: this.env.BLOB_READ_WRITE_TOKEN,
|
|
172
178
|
});
|
|
173
179
|
return result !== null;
|
|
@@ -184,7 +190,7 @@ export class VercelFileStorageProvider implements FileStorageProvider {
|
|
|
184
190
|
const pathname = `${storeName}/${fileId}`;
|
|
185
191
|
|
|
186
192
|
try {
|
|
187
|
-
await del(pathname, {
|
|
193
|
+
await this.vercelBlobApi.del(pathname, {
|
|
188
194
|
token: this.env.BLOB_READ_WRITE_TOKEN,
|
|
189
195
|
});
|
|
190
196
|
} catch (error) {
|