@nebutra/uploads 0.1.2 → 3.0.0
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/factory.d.ts.map +1 -1
- package/dist/factory.js +15 -19
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/providers/local.d.ts +2 -0
- package/dist/providers/local.d.ts.map +1 -1
- package/dist/providers/local.js +7 -1
- package/dist/providers/s3.d.ts +7 -0
- package/dist/providers/s3.d.ts.map +1 -1
- package/dist/providers/s3.js +21 -7
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -6
- package/dist/providers/blob.d.ts +0 -28
- package/dist/providers/blob.d.ts.map +0 -1
- package/dist/providers/blob.js +0 -88
package/dist/factory.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAIlF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,cAAc,CAM5E;AAmFD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAOxF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAO1C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,kBAAkB,CAkB1D"}
|
package/dist/factory.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Upload provider factory with auto-detection
|
|
3
3
|
*/
|
|
4
4
|
import { logger } from "@nebutra/logger";
|
|
5
|
-
import { createVercelBlobProvider, VercelBlobProvider } from "./providers/blob";
|
|
6
5
|
import { createLocalProvider, LocalUploadProvider } from "./providers/local";
|
|
7
6
|
import { createS3Provider, S3UploadProvider } from "./providers/s3";
|
|
8
7
|
let instance = null;
|
|
@@ -25,9 +24,6 @@ function createUploadProviderByType(type, config) {
|
|
|
25
24
|
}
|
|
26
25
|
return new S3UploadProvider(config.s3);
|
|
27
26
|
}
|
|
28
|
-
if (type === "blob") {
|
|
29
|
-
return createVercelBlobProvider();
|
|
30
|
-
}
|
|
31
27
|
if (type === "local") {
|
|
32
28
|
if (!config?.local) {
|
|
33
29
|
return createLocalProvider();
|
|
@@ -40,18 +36,24 @@ function createUploadProviderByType(type, config) {
|
|
|
40
36
|
* Auto-detect provider based on environment
|
|
41
37
|
*/
|
|
42
38
|
function autoDetectProvider(config) {
|
|
43
|
-
// Priority 1: Check explicit UPLOAD_PROVIDER
|
|
44
|
-
const
|
|
39
|
+
// Priority 1: Check explicit UPLOAD_PROVIDER (r2 is an alias for S3-compatible)
|
|
40
|
+
const explicitRaw = process.env.UPLOAD_PROVIDER?.trim().toLowerCase();
|
|
41
|
+
if (explicitRaw === "r2") {
|
|
42
|
+
logger.info("Using explicit upload provider", { provider: "r2→s3" });
|
|
43
|
+
return new S3UploadProvider({
|
|
44
|
+
accessKeyId: process.env.R2_ACCESS_KEY_ID || "",
|
|
45
|
+
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY || "",
|
|
46
|
+
region: "auto",
|
|
47
|
+
...(process.env.R2_ENDPOINT !== undefined ? { endpoint: process.env.R2_ENDPOINT } : {}),
|
|
48
|
+
...(process.env.R2_PUBLIC_URL !== undefined ? { publicUrl: process.env.R2_PUBLIC_URL } : {}),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const explicitProvider = explicitRaw;
|
|
45
52
|
if (explicitProvider) {
|
|
46
53
|
logger.info("Using explicit upload provider", { provider: explicitProvider });
|
|
47
54
|
return createUploadProviderByType(explicitProvider, config);
|
|
48
55
|
}
|
|
49
|
-
// Priority 2: Check for
|
|
50
|
-
if (process.env.BLOB_READ_WRITE_TOKEN) {
|
|
51
|
-
logger.info("Auto-detected Vercel Blob token, using Blob provider");
|
|
52
|
-
return createVercelBlobProvider();
|
|
53
|
-
}
|
|
54
|
-
// Priority 3: Check for R2 credentials
|
|
56
|
+
// Priority 2: Check for R2 credentials
|
|
55
57
|
if (process.env.R2_ACCESS_KEY_ID || process.env.R2_SECRET_ACCESS_KEY) {
|
|
56
58
|
logger.info("Auto-detected R2 credentials, using S3 provider");
|
|
57
59
|
return new S3UploadProvider({
|
|
@@ -67,7 +69,7 @@ function autoDetectProvider(config) {
|
|
|
67
69
|
logger.info("Auto-detected AWS credentials, using S3 provider");
|
|
68
70
|
return createS3Provider();
|
|
69
71
|
}
|
|
70
|
-
// Priority 4: Check for custom S3 endpoint (Minio, etc.)
|
|
72
|
+
// Priority 4: Check for custom S3 endpoint (Minio, Aliyun OSS, etc.)
|
|
71
73
|
if (process.env.S3_ENDPOINT) {
|
|
72
74
|
logger.info("Using custom S3 endpoint", { endpoint: process.env.S3_ENDPOINT });
|
|
73
75
|
return new S3UploadProvider({
|
|
@@ -110,15 +112,9 @@ export function getActiveProviderType() {
|
|
|
110
112
|
if (instance instanceof S3UploadProvider) {
|
|
111
113
|
return "s3";
|
|
112
114
|
}
|
|
113
|
-
if (instance instanceof VercelBlobProvider) {
|
|
114
|
-
return "blob";
|
|
115
|
-
}
|
|
116
115
|
if (instance instanceof LocalUploadProvider) {
|
|
117
116
|
return "local";
|
|
118
117
|
}
|
|
119
|
-
if (process.env.UPLOAD_PROVIDER === "blob" || process.env.BLOB_READ_WRITE_TOKEN) {
|
|
120
|
-
return "blob";
|
|
121
|
-
}
|
|
122
118
|
if (process.env.UPLOAD_PROVIDER === "s3" ||
|
|
123
119
|
process.env.R2_ACCESS_KEY_ID ||
|
|
124
120
|
process.env.AWS_ACCESS_KEY_ID ||
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Handles presigned, multipart, and Tus protocol uploads
|
|
4
4
|
*/
|
|
5
5
|
export { createUploadProvider, getActiveProviderType, getUploadProvider, resetUploadProvider, } from "./factory";
|
|
6
|
-
export { createVercelBlobProvider, VercelBlobProvider } from "./providers/blob";
|
|
7
6
|
export { createLocalProvider, LocalUploadProvider } from "./providers/local";
|
|
8
7
|
export { createS3Provider, S3UploadProvider } from "./providers/s3";
|
|
9
8
|
export type { ACLType, CompletePart, LocalProviderConfig, MultipartUpload, PresignedUpload, ProviderConfig, S3ProviderConfig, TusUploadConfig, UploadComplete, UploadMethod, UploadPart, UploadProvider, UploadProviderType, UploadTarget, ValidationRules, } from "./types";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEpE,YAAY,EACV,OAAO,EACP,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,YAAY,EACZ,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,eAAe,GAChB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,6BAA6B,EAC7B,0BAA0B,EAC1B,kBAAkB,EAClB,KAAK,eAAe,EACpB,uBAAuB,EACvB,cAAc,GACf,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
// Factory
|
|
6
6
|
export { createUploadProvider, getActiveProviderType, getUploadProvider, resetUploadProvider, } from "./factory";
|
|
7
7
|
// Providers
|
|
8
|
-
export { createVercelBlobProvider, VercelBlobProvider } from "./providers/blob";
|
|
9
8
|
export { createLocalProvider, LocalUploadProvider } from "./providers/local";
|
|
10
9
|
export { createS3Provider, S3UploadProvider } from "./providers/s3";
|
|
11
10
|
// Validation
|
|
@@ -11,6 +11,8 @@ export declare class LocalUploadProvider implements UploadProvider {
|
|
|
11
11
|
* Build object key with tenant prefix and UUID
|
|
12
12
|
*/
|
|
13
13
|
private buildKey;
|
|
14
|
+
/** Prefer an explicit full object key (contains `/`) over generating a new one. */
|
|
15
|
+
private resolveKey;
|
|
14
16
|
/**
|
|
15
17
|
* Generate presigned URL for simple uploads
|
|
16
18
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/providers/local.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,eAAe,EACf,cAAc,EACd,cAAc,EACd,YAAY,EACb,MAAM,UAAU,CAAC;AAElB,qBAAa,mBAAoB,YAAW,cAAc;IACxD,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,cAAc,CAA2D;gBAErE,MAAM,EAAE,mBAAmB;IAcvC;;OAEG;IACH,OAAO,CAAC,QAAQ;IAQhB;;OAEG;IACG,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IAqB3E;;OAEG;IACG,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAmC9F;;OAEG;IACG,uBAAuB,CAC3B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,YAAY,EAAE,GACrB,OAAO,CAAC,cAAc,CAAC;IAsC1B;;OAEG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzE;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IAcpE;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW7D;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI3F;;OAEG;YACW,SAAS;IAUvB;;OAEG;IACH,OAAO,CAAC,YAAY;IAUpB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,mBAAmB,CAUzD"}
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/providers/local.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,eAAe,EACf,cAAc,EACd,cAAc,EACd,YAAY,EACb,MAAM,UAAU,CAAC;AAElB,qBAAa,mBAAoB,YAAW,cAAc;IACxD,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,cAAc,CAA2D;gBAErE,MAAM,EAAE,mBAAmB;IAcvC;;OAEG;IACH,OAAO,CAAC,QAAQ;IAQhB,mFAAmF;IACnF,OAAO,CAAC,UAAU;IAKlB;;OAEG;IACG,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IAqB3E;;OAEG;IACG,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAmC9F;;OAEG;IACG,uBAAuB,CAC3B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,YAAY,EAAE,GACrB,OAAO,CAAC,cAAc,CAAC;IAsC1B;;OAEG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzE;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IAcpE;;OAEG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW7D;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI3F;;OAEG;YACW,SAAS;IAUvB;;OAEG;IACH,OAAO,CAAC,YAAY;IAUpB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,mBAAmB,CAUzD"}
|
package/dist/providers/local.js
CHANGED
|
@@ -31,11 +31,17 @@ export class LocalUploadProvider {
|
|
|
31
31
|
}
|
|
32
32
|
return `${id}/${target.key.split("/").pop()}`;
|
|
33
33
|
}
|
|
34
|
+
/** Prefer an explicit full object key (contains `/`) over generating a new one. */
|
|
35
|
+
resolveKey(target) {
|
|
36
|
+
if (target.key.includes("/"))
|
|
37
|
+
return target.key;
|
|
38
|
+
return this.buildKey(target);
|
|
39
|
+
}
|
|
34
40
|
/**
|
|
35
41
|
* Generate presigned URL for simple uploads
|
|
36
42
|
*/
|
|
37
43
|
async createPresignedUpload(target) {
|
|
38
|
-
const key = this.
|
|
44
|
+
const key = this.resolveKey(target);
|
|
39
45
|
// Ensure directory exists
|
|
40
46
|
await this.ensureDir(target.bucket);
|
|
41
47
|
const expiresIn = 3600; // 1 hour
|
package/dist/providers/s3.d.ts
CHANGED
|
@@ -8,10 +8,17 @@ export declare class S3UploadProvider implements UploadProvider {
|
|
|
8
8
|
private config;
|
|
9
9
|
private uploadTracking;
|
|
10
10
|
constructor(config: S3ProviderConfig);
|
|
11
|
+
/**
|
|
12
|
+
* AWS SDK `Client.send` types sometimes fail to resolve under standalone pnpm +
|
|
13
|
+
* moduleResolution bundler; call through a narrow helper so builds stay portable.
|
|
14
|
+
*/
|
|
15
|
+
private send;
|
|
11
16
|
/**
|
|
12
17
|
* Build object key with tenant prefix
|
|
13
18
|
*/
|
|
14
19
|
private buildKey;
|
|
20
|
+
/** Prefer an explicit full object key (contains `/`) over generating a new one. */
|
|
21
|
+
private resolveKey;
|
|
15
22
|
/**
|
|
16
23
|
* Generate presigned PUT URL for simple uploads
|
|
17
24
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../src/providers/s3.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,cAAc,EACd,YAAY,EACb,MAAM,UAAU,CAAC;AAElB,qBAAa,gBAAiB,YAAW,cAAc;IACrD,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,MAAM,CAOZ;IACF,OAAO,CAAC,cAAc,CAA+C;gBAEzD,MAAM,EAAE,gBAAgB;IAwBpC;;OAEG;IACH,OAAO,CAAC,QAAQ;IAQhB;;OAEG;IACG,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IA2B3E;;OAEG;IACG,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAgE9F;;OAEG;YACW,mBAAmB;IAUjC;;OAEG;IACG,uBAAuB,CAC3B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,YAAY,EAAE,GACpB,OAAO,CAAC,cAAc,CAAC;IAuC1B;;OAEG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBxE;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IA4BpE;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW5D;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,MAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAS/F;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAI3B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,gBAAgB,
|
|
1
|
+
{"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../src/providers/s3.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,cAAc,EACd,YAAY,EACb,MAAM,UAAU,CAAC;AAElB,qBAAa,gBAAiB,YAAW,cAAc;IACrD,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,MAAM,CAOZ;IACF,OAAO,CAAC,cAAc,CAA+C;gBAEzD,MAAM,EAAE,gBAAgB;IAwBpC;;;OAGG;IACH,OAAO,CAAC,IAAI;IAIZ;;OAEG;IACH,OAAO,CAAC,QAAQ;IAQhB,mFAAmF;IACnF,OAAO,CAAC,UAAU;IAKlB;;OAEG;IACG,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IA2B3E;;OAEG;IACG,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAgE9F;;OAEG;YACW,mBAAmB;IAUjC;;OAEG;IACG,uBAAuB,CAC3B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,YAAY,EAAE,GACpB,OAAO,CAAC,cAAc,CAAC;IAuC1B;;OAEG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBxE;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IA4BpE;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW5D;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,MAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAS/F;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAI3B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,gBAAgB,CAqBnD"}
|
package/dist/providers/s3.js
CHANGED
|
@@ -31,6 +31,13 @@ export class S3UploadProvider {
|
|
|
31
31
|
});
|
|
32
32
|
logger.info("S3 upload provider initialized", { provider: "s3", region: this.config.region });
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* AWS SDK `Client.send` types sometimes fail to resolve under standalone pnpm +
|
|
36
|
+
* moduleResolution bundler; call through a narrow helper so builds stay portable.
|
|
37
|
+
*/
|
|
38
|
+
send(command) {
|
|
39
|
+
return this.client.send(command);
|
|
40
|
+
}
|
|
34
41
|
/**
|
|
35
42
|
* Build object key with tenant prefix
|
|
36
43
|
*/
|
|
@@ -41,11 +48,17 @@ export class S3UploadProvider {
|
|
|
41
48
|
}
|
|
42
49
|
return `${id}/${target.key.split("/").pop()}`;
|
|
43
50
|
}
|
|
51
|
+
/** Prefer an explicit full object key (contains `/`) over generating a new one. */
|
|
52
|
+
resolveKey(target) {
|
|
53
|
+
if (target.key.includes("/"))
|
|
54
|
+
return target.key;
|
|
55
|
+
return this.buildKey(target);
|
|
56
|
+
}
|
|
44
57
|
/**
|
|
45
58
|
* Generate presigned PUT URL for simple uploads
|
|
46
59
|
*/
|
|
47
60
|
async createPresignedUpload(target) {
|
|
48
|
-
const key = this.
|
|
61
|
+
const key = this.resolveKey(target);
|
|
49
62
|
const expiresIn = 3600; // 1 hour
|
|
50
63
|
const command = new PutObjectCommand({
|
|
51
64
|
Bucket: target.bucket,
|
|
@@ -78,7 +91,7 @@ export class S3UploadProvider {
|
|
|
78
91
|
Metadata: target.metadata,
|
|
79
92
|
...(target.acl !== undefined ? { ACL: target.acl } : {}),
|
|
80
93
|
});
|
|
81
|
-
const response = await this.
|
|
94
|
+
const response = await this.send(createCmd);
|
|
82
95
|
if (!response.UploadId) {
|
|
83
96
|
throw new Error("Failed to initiate multipart upload: no UploadId returned");
|
|
84
97
|
}
|
|
@@ -150,7 +163,7 @@ export class S3UploadProvider {
|
|
|
150
163
|
Parts: completedParts,
|
|
151
164
|
},
|
|
152
165
|
});
|
|
153
|
-
const response = await this.
|
|
166
|
+
const response = await this.send(command);
|
|
154
167
|
const url = this.generateDownloadUrl(key);
|
|
155
168
|
logger.info("Multipart upload completed", { key, bucket, uploadId, etag: response.ETag });
|
|
156
169
|
return {
|
|
@@ -173,7 +186,7 @@ export class S3UploadProvider {
|
|
|
173
186
|
Key: key,
|
|
174
187
|
UploadId: uploadId,
|
|
175
188
|
});
|
|
176
|
-
await this.
|
|
189
|
+
await this.send(command);
|
|
177
190
|
this.uploadTracking.delete(uploadId);
|
|
178
191
|
logger.info("Multipart upload aborted", { key, bucket, uploadId });
|
|
179
192
|
}
|
|
@@ -188,7 +201,7 @@ export class S3UploadProvider {
|
|
|
188
201
|
Key: key,
|
|
189
202
|
ContentType: target.contentType,
|
|
190
203
|
});
|
|
191
|
-
const response = await this.
|
|
204
|
+
const response = await this.send(createCmd);
|
|
192
205
|
if (!response.UploadId) {
|
|
193
206
|
throw new Error("Failed to create Tus upload session");
|
|
194
207
|
}
|
|
@@ -211,7 +224,7 @@ export class S3UploadProvider {
|
|
|
211
224
|
Bucket: bucket,
|
|
212
225
|
Key: key,
|
|
213
226
|
});
|
|
214
|
-
await this.
|
|
227
|
+
await this.send(command);
|
|
215
228
|
logger.debug("File deleted from S3", { key, bucket });
|
|
216
229
|
}
|
|
217
230
|
/**
|
|
@@ -243,7 +256,8 @@ export class S3UploadProvider {
|
|
|
243
256
|
* Create S3 provider from environment variables
|
|
244
257
|
*/
|
|
245
258
|
export function createS3Provider() {
|
|
246
|
-
|
|
259
|
+
// R2 uses R2_ENDPOINT; generic S3 uses S3_ENDPOINT. Prefer explicit S3, else R2.
|
|
260
|
+
const endpoint = process.env.S3_ENDPOINT ?? process.env.R2_ENDPOINT;
|
|
247
261
|
const publicUrl = process.env.S3_PUBLIC_URL ?? process.env.R2_PUBLIC_URL;
|
|
248
262
|
const config = {
|
|
249
263
|
accessKeyId: process.env.AWS_ACCESS_KEY_ID ?? process.env.R2_ACCESS_KEY_ID ?? "",
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nebutra/uploads",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"nebutra": {
|
|
8
|
+
"graph": "core",
|
|
8
9
|
"status": "foundation",
|
|
9
10
|
"productionReady": false,
|
|
10
11
|
"requires": [
|
|
@@ -43,16 +44,12 @@
|
|
|
43
44
|
"@aws-sdk/client-s3": "^3.700.0",
|
|
44
45
|
"@aws-sdk/s3-request-presigner": "^3.700.0",
|
|
45
46
|
"zod": "^4.3.6",
|
|
46
|
-
"@nebutra/logger": "0.
|
|
47
|
+
"@nebutra/logger": "3.0.0"
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
49
|
-
"@vercel/blob": ">=0.23.0",
|
|
50
50
|
"tus-js-client": "^4.2.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependenciesMeta": {
|
|
53
|
-
"@vercel/blob": {
|
|
54
|
-
"optional": true
|
|
55
|
-
},
|
|
56
53
|
"tus-js-client": {
|
|
57
54
|
"optional": true
|
|
58
55
|
}
|
package/dist/providers/blob.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vercel Blob upload provider — zero-config file uploads on Vercel.
|
|
3
|
-
*
|
|
4
|
-
* Uses @vercel/blob for server-side uploads with public URLs.
|
|
5
|
-
* Requires BLOB_READ_WRITE_TOKEN env var (auto-provisioned on Vercel).
|
|
6
|
-
*
|
|
7
|
-
* Note: Vercel Blob doesn't support true multipart uploads or Tus protocol.
|
|
8
|
-
* For files > 500MB, use the S3 provider instead.
|
|
9
|
-
*/
|
|
10
|
-
import type { CompletePart, MultipartUpload, PresignedUpload, TusUploadConfig, UploadComplete, UploadProvider, UploadTarget } from "../types";
|
|
11
|
-
export interface VercelBlobConfig {
|
|
12
|
-
token?: string;
|
|
13
|
-
}
|
|
14
|
-
export declare class VercelBlobProvider implements UploadProvider {
|
|
15
|
-
private token;
|
|
16
|
-
constructor(config?: VercelBlobConfig);
|
|
17
|
-
private buildPathname;
|
|
18
|
-
createPresignedUpload(target: UploadTarget): Promise<PresignedUpload>;
|
|
19
|
-
createMultipartUpload(target: UploadTarget, _partCount: number): Promise<MultipartUpload>;
|
|
20
|
-
completeMultipartUpload(_uploadId: string, key: string, _parts: CompletePart[]): Promise<UploadComplete>;
|
|
21
|
-
abortMultipartUpload(_uploadId: string, key: string): Promise<void>;
|
|
22
|
-
getTusEndpoint(_target: UploadTarget): Promise<TusUploadConfig>;
|
|
23
|
-
deleteFile(_bucket: string, key: string): Promise<void>;
|
|
24
|
-
getDownloadUrl(_bucket: string, key: string, _expiresInSec?: number): Promise<string>;
|
|
25
|
-
close(): Promise<void>;
|
|
26
|
-
}
|
|
27
|
-
export declare function createVercelBlobProvider(config?: VercelBlobConfig): VercelBlobProvider;
|
|
28
|
-
//# sourceMappingURL=blob.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"blob.d.ts","sourceRoot":"","sources":["../../src/providers/blob.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,eAAe,EACf,eAAe,EACf,cAAc,EACd,cAAc,EACd,YAAY,EACb,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,kBAAmB,YAAW,cAAc;IACvD,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,GAAE,gBAAqB;IAIzC,OAAO,CAAC,aAAa;IAKf,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IAyBrE,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAazF,uBAAuB,CAC3B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,YAAY,EAAE,GACrB,OAAO,CAAC,cAAc,CAAC;IAWpB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnE,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;IAM/D,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvD,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQrF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAED,wBAAgB,wBAAwB,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,kBAAkB,CAEtF"}
|
package/dist/providers/blob.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vercel Blob upload provider — zero-config file uploads on Vercel.
|
|
3
|
-
*
|
|
4
|
-
* Uses @vercel/blob for server-side uploads with public URLs.
|
|
5
|
-
* Requires BLOB_READ_WRITE_TOKEN env var (auto-provisioned on Vercel).
|
|
6
|
-
*
|
|
7
|
-
* Note: Vercel Blob doesn't support true multipart uploads or Tus protocol.
|
|
8
|
-
* For files > 500MB, use the S3 provider instead.
|
|
9
|
-
*/
|
|
10
|
-
export class VercelBlobProvider {
|
|
11
|
-
token;
|
|
12
|
-
constructor(config = {}) {
|
|
13
|
-
this.token = config.token ?? process.env.BLOB_READ_WRITE_TOKEN ?? "";
|
|
14
|
-
}
|
|
15
|
-
buildPathname(target) {
|
|
16
|
-
const prefix = target.tenantId ? `${target.tenantId}/` : "";
|
|
17
|
-
return `${prefix}${target.key}`;
|
|
18
|
-
}
|
|
19
|
-
async createPresignedUpload(target) {
|
|
20
|
-
// Vercel Blob uses server-side put() — we generate a URL that the client
|
|
21
|
-
// can PUT to via the handleUpload client helper, or we return the blob URL
|
|
22
|
-
// after server-side upload.
|
|
23
|
-
const blob = await import("@vercel/blob");
|
|
24
|
-
const pathname = this.buildPathname(target);
|
|
25
|
-
const result = await blob.put(pathname, "", {
|
|
26
|
-
access: "public",
|
|
27
|
-
contentType: target.contentType,
|
|
28
|
-
token: this.token,
|
|
29
|
-
addRandomSuffix: true,
|
|
30
|
-
});
|
|
31
|
-
return {
|
|
32
|
-
url: result.url,
|
|
33
|
-
method: "PUT",
|
|
34
|
-
headers: {
|
|
35
|
-
"Content-Type": target.contentType,
|
|
36
|
-
"x-vercel-blob-token": this.token,
|
|
37
|
-
},
|
|
38
|
-
expiresAt: new Date(Date.now() + 3600 * 1000), // 1 hour
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
async createMultipartUpload(target, _partCount) {
|
|
42
|
-
// Vercel Blob handles large files internally — no client-side multipart needed
|
|
43
|
-
// We simulate the interface for compatibility
|
|
44
|
-
const presigned = await this.createPresignedUpload(target);
|
|
45
|
-
return {
|
|
46
|
-
uploadId: `blob_${Date.now()}`,
|
|
47
|
-
key: this.buildPathname(target),
|
|
48
|
-
bucket: target.bucket,
|
|
49
|
-
parts: [{ partNumber: 1, presignedUrl: presigned.url }],
|
|
50
|
-
completeUrl: presigned.url,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
async completeMultipartUpload(_uploadId, key, _parts) {
|
|
54
|
-
// Vercel Blob uploads are atomic — no completion step needed
|
|
55
|
-
return {
|
|
56
|
-
key,
|
|
57
|
-
bucket: "vercel-blob",
|
|
58
|
-
url: `https://blob.vercel-storage.com/${key}`,
|
|
59
|
-
size: 0,
|
|
60
|
-
contentType: "application/octet-stream",
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
async abortMultipartUpload(_uploadId, key) {
|
|
64
|
-
// Clean up the blob if partially uploaded
|
|
65
|
-
await this.deleteFile("vercel-blob", key);
|
|
66
|
-
}
|
|
67
|
-
async getTusEndpoint(_target) {
|
|
68
|
-
throw new Error("Vercel Blob does not support Tus protocol. Use S3 provider for resumable uploads.");
|
|
69
|
-
}
|
|
70
|
-
async deleteFile(_bucket, key) {
|
|
71
|
-
const blob = await import("@vercel/blob");
|
|
72
|
-
const url = key.startsWith("http") ? key : `https://blob.vercel-storage.com/${key}`;
|
|
73
|
-
await blob.del(url, { token: this.token });
|
|
74
|
-
}
|
|
75
|
-
async getDownloadUrl(_bucket, key, _expiresInSec) {
|
|
76
|
-
// Vercel Blob URLs are public by default — no signed URL needed
|
|
77
|
-
const blob = await import("@vercel/blob");
|
|
78
|
-
const url = key.startsWith("http") ? key : `https://blob.vercel-storage.com/${key}`;
|
|
79
|
-
const meta = await blob.head(url, { token: this.token });
|
|
80
|
-
return meta.url;
|
|
81
|
-
}
|
|
82
|
-
async close() {
|
|
83
|
-
// No-op — Vercel Blob has no persistent connections
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
export function createVercelBlobProvider(config) {
|
|
87
|
-
return new VercelBlobProvider(config);
|
|
88
|
-
}
|