@nebutra/uploads 0.1.2 → 2.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 +13 -2
- 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/package.json +3 -2
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;AAMH,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;
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,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;AA6FD;;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,CAyB1D"}
|
package/dist/factory.js
CHANGED
|
@@ -40,8 +40,19 @@ function createUploadProviderByType(type, config) {
|
|
|
40
40
|
* Auto-detect provider based on environment
|
|
41
41
|
*/
|
|
42
42
|
function autoDetectProvider(config) {
|
|
43
|
-
// Priority 1: Check explicit UPLOAD_PROVIDER
|
|
44
|
-
const
|
|
43
|
+
// Priority 1: Check explicit UPLOAD_PROVIDER (r2 is an alias for S3-compatible)
|
|
44
|
+
const explicitRaw = process.env.UPLOAD_PROVIDER?.trim().toLowerCase();
|
|
45
|
+
if (explicitRaw === "r2") {
|
|
46
|
+
logger.info("Using explicit upload provider", { provider: "r2→s3" });
|
|
47
|
+
return new S3UploadProvider({
|
|
48
|
+
accessKeyId: process.env.R2_ACCESS_KEY_ID || "",
|
|
49
|
+
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY || "",
|
|
50
|
+
region: "auto",
|
|
51
|
+
...(process.env.R2_ENDPOINT !== undefined ? { endpoint: process.env.R2_ENDPOINT } : {}),
|
|
52
|
+
...(process.env.R2_PUBLIC_URL !== undefined ? { publicUrl: process.env.R2_PUBLIC_URL } : {}),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const explicitProvider = explicitRaw;
|
|
45
56
|
if (explicitProvider) {
|
|
46
57
|
logger.info("Using explicit upload provider", { provider: explicitProvider });
|
|
47
58
|
return createUploadProviderByType(explicitProvider, config);
|
|
@@ -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/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nebutra/uploads",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "2.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,7 +44,7 @@
|
|
|
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": "2.0.0"
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
49
50
|
"@vercel/blob": ">=0.23.0",
|