@vankyle/storage-s3 0.1.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/README.md +114 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/mappers/index.d.ts +2 -0
- package/dist/mappers/index.d.ts.map +1 -0
- package/dist/mappers/index.js +2 -0
- package/dist/mappers/index.js.map +1 -0
- package/dist/mappers/s3-head-to-core.d.ts +4 -0
- package/dist/mappers/s3-head-to-core.d.ts.map +1 -0
- package/dist/mappers/s3-head-to-core.js +10 -0
- package/dist/mappers/s3-head-to-core.js.map +1 -0
- package/dist/storage/index.d.ts +2 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +2 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/s3-storage.d.ts +20 -0
- package/dist/storage/s3-storage.d.ts.map +1 -0
- package/dist/storage/s3-storage.js +214 -0
- package/dist/storage/s3-storage.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/s3-options.d.ts +6 -0
- package/dist/types/s3-options.d.ts.map +1 -0
- package/dist/types/s3-options.js +2 -0
- package/dist/types/s3-options.js.map +1 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# @vankyle-hub/storage-s3
|
|
2
|
+
|
|
3
|
+
`IStorage` implementation for any S3-compatible object storage backend.
|
|
4
|
+
|
|
5
|
+
## Supported backends
|
|
6
|
+
|
|
7
|
+
- AWS S3
|
|
8
|
+
- Cloudflare R2 (S3-compatible HTTP API)
|
|
9
|
+
- MinIO
|
|
10
|
+
- DigitalOcean Spaces
|
|
11
|
+
- Backblaze B2 (S3-compatible)
|
|
12
|
+
- Any storage that speaks the S3 signature protocol
|
|
13
|
+
|
|
14
|
+
> **Cloudflare R2 Worker Binding:** If you are running inside a Cloudflare Worker and want to use `env.BUCKET` directly, use [`@vankyle-hub/storage-cloudflare`](../cloudflare/README.md) instead.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm add @vankyle-hub/storage-s3 @vankyle-hub/storage-core @vankyle-hub/storage-shared
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### AWS S3
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { S3Storage } from "@vankyle-hub/storage-s3";
|
|
28
|
+
|
|
29
|
+
const storage = new S3Storage({
|
|
30
|
+
clientConfig: {
|
|
31
|
+
region: "us-east-1",
|
|
32
|
+
credentials: {
|
|
33
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
|
|
34
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Cloudflare R2 (S3 API)
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
const storage = new S3Storage({
|
|
44
|
+
clientConfig: {
|
|
45
|
+
region: "auto",
|
|
46
|
+
endpoint: `https://${process.env.CF_ACCOUNT_ID}.r2.cloudflarestorage.com`,
|
|
47
|
+
credentials: {
|
|
48
|
+
accessKeyId: process.env.R2_ACCESS_KEY_ID!,
|
|
49
|
+
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
forcePathStyle: true,
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### MinIO
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const storage = new S3Storage({
|
|
60
|
+
clientConfig: {
|
|
61
|
+
region: "us-east-1",
|
|
62
|
+
endpoint: "http://localhost:9000",
|
|
63
|
+
credentials: {
|
|
64
|
+
accessKeyId: "minioadmin",
|
|
65
|
+
secretAccessKey: "minioadmin",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
forcePathStyle: true,
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Capabilities
|
|
73
|
+
|
|
74
|
+
| Capability | Supported |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `multipartUpload` | ✓ |
|
|
77
|
+
| `signedReadUrl` | ✓ |
|
|
78
|
+
| `signedPutUrl` | ✓ |
|
|
79
|
+
| `signedPartUrl` | ✓ |
|
|
80
|
+
| `serverSideCopy` | ✗ |
|
|
81
|
+
|
|
82
|
+
All four URL types use `@aws-sdk/s3-request-presigner`.
|
|
83
|
+
|
|
84
|
+
## Options reference
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
interface S3StorageOptions {
|
|
88
|
+
/**
|
|
89
|
+
* Passed directly to the AWS SDK S3Client constructor.
|
|
90
|
+
* Set endpoint, region, credentials, etc. here.
|
|
91
|
+
*/
|
|
92
|
+
clientConfig: S3ClientConfig;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Use path-style URLs instead of virtual-hosted style.
|
|
96
|
+
* Required for MinIO and some S3-compatible services.
|
|
97
|
+
* Default: false
|
|
98
|
+
*/
|
|
99
|
+
forcePathStyle?: boolean;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Multipart upload
|
|
104
|
+
|
|
105
|
+
`S3Storage` maps the `IStorage` multipart lifecycle directly to S3 multipart:
|
|
106
|
+
|
|
107
|
+
| `IStorage` method | S3 API |
|
|
108
|
+
|---|---|
|
|
109
|
+
| `initUploadSession` | `CreateMultipartUpload` |
|
|
110
|
+
| `uploadPart` | `UploadPart` |
|
|
111
|
+
| `completeUploadSession` | `CompleteMultipartUpload` |
|
|
112
|
+
| `abortUploadSession` | `AbortMultipartUpload` |
|
|
113
|
+
|
|
114
|
+
The `providerUploadId` field on `InitUploadSessionResult` is the S3 `UploadId`.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mappers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mappers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { HeadObjectCommandOutput } from "@aws-sdk/client-s3";
|
|
2
|
+
import type { HeadObjectResult } from "@vankyle-hub/storage-core";
|
|
3
|
+
export declare function mapS3HeadToCore(output: HeadObjectCommandOutput): HeadObjectResult;
|
|
4
|
+
//# sourceMappingURL=s3-head-to-core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-head-to-core.d.ts","sourceRoot":"","sources":["../../src/mappers/s3-head-to-core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,wBAAgB,eAAe,CAAC,MAAM,EAAE,uBAAuB,GAAG,gBAAgB,CAQjF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function mapS3HeadToCore(output) {
|
|
2
|
+
return {
|
|
3
|
+
contentType: output.ContentType,
|
|
4
|
+
contentLength: output.ContentLength,
|
|
5
|
+
etag: output.ETag,
|
|
6
|
+
lastModified: output.LastModified,
|
|
7
|
+
metadata: output.Metadata,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=s3-head-to-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-head-to-core.js","sourceRoot":"","sources":["../../src/mappers/s3-head-to-core.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,eAAe,CAAC,MAA+B;IAC7D,OAAO;QACL,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type IStorage, type StorageCapabilities, type PutObjectInput, type PutObjectResult, type GetObjectInput, type GetObjectResult, type HeadObjectInput, type HeadObjectResult, type DeleteObjectInput, type InitUploadSessionInput, type InitUploadSessionResult, type UploadPartInput, type UploadPartResult, type CompleteUploadSessionInput, type CompleteUploadSessionResult, type AbortUploadSessionInput, type CreateReadUrlInput, type CreatePutUrlInput, type CreateUploadPartUrlInput, type SignedAccess } from "@vankyle-hub/storage-core";
|
|
2
|
+
import type { S3StorageOptions } from "../types/s3-options.js";
|
|
3
|
+
export declare class S3Storage implements IStorage {
|
|
4
|
+
readonly provider: "s3";
|
|
5
|
+
readonly capabilities: StorageCapabilities;
|
|
6
|
+
private readonly client;
|
|
7
|
+
constructor(options: S3StorageOptions);
|
|
8
|
+
putObject(input: PutObjectInput): Promise<PutObjectResult>;
|
|
9
|
+
getObject(input: GetObjectInput): Promise<GetObjectResult>;
|
|
10
|
+
headObject(input: HeadObjectInput): Promise<HeadObjectResult>;
|
|
11
|
+
deleteObject(input: DeleteObjectInput): Promise<void>;
|
|
12
|
+
initUploadSession(input: InitUploadSessionInput): Promise<InitUploadSessionResult>;
|
|
13
|
+
uploadPart(input: UploadPartInput): Promise<UploadPartResult>;
|
|
14
|
+
completeUploadSession(input: CompleteUploadSessionInput): Promise<CompleteUploadSessionResult>;
|
|
15
|
+
abortUploadSession(input: AbortUploadSessionInput): Promise<void>;
|
|
16
|
+
createReadUrl(input: CreateReadUrlInput): Promise<SignedAccess>;
|
|
17
|
+
createPutUrl(input: CreatePutUrlInput): Promise<SignedAccess>;
|
|
18
|
+
createUploadPartUrl(input: CreateUploadPartUrlInput): Promise<SignedAccess>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=s3-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-storage.d.ts","sourceRoot":"","sources":["../../src/storage/s3-storage.ts"],"names":[],"mappings":"AAYA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EAClB,MAAM,2BAA2B,CAAC;AAKnC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAK/D,qBAAa,SAAU,YAAW,QAAQ;IACxC,QAAQ,CAAC,QAAQ,OAAsB;IACvC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAKxC;IAEF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;gBAEtB,OAAO,EAAE,gBAAgB;IAU/B,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAuB1D,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IA0B1D,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAiB7D,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IASrD,iBAAiB,CACrB,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,uBAAuB,CAAC;IAmB7B,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA4B7D,qBAAqB,CACzB,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,2BAA2B,CAAC;IAqBjC,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAUjE,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC;IAkB/D,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC;IAiB7D,mBAAmB,CACvB,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,YAAY,CAAC;CAiBzB"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { S3Client, PutObjectCommand, GetObjectCommand, HeadObjectCommand, DeleteObjectCommand, CreateMultipartUploadCommand, UploadPartCommand, CompleteMultipartUploadCommand, AbortMultipartUploadCommand, } from "@aws-sdk/client-s3";
|
|
2
|
+
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
3
|
+
import { StorageProvider, } from "@vankyle-hub/storage-core";
|
|
4
|
+
import { StorageError, StorageObjectNotFoundError, } from "@vankyle-hub/storage-shared";
|
|
5
|
+
import { mapS3HeadToCore } from "../mappers/s3-head-to-core.js";
|
|
6
|
+
const DEFAULT_EXPIRES_IN = 3600; // 1 hour
|
|
7
|
+
export class S3Storage {
|
|
8
|
+
provider = StorageProvider.S3;
|
|
9
|
+
capabilities = {
|
|
10
|
+
multipartUpload: true,
|
|
11
|
+
signedReadUrl: true,
|
|
12
|
+
signedPutUrl: true,
|
|
13
|
+
signedPartUrl: true,
|
|
14
|
+
};
|
|
15
|
+
client;
|
|
16
|
+
constructor(options) {
|
|
17
|
+
const config = {
|
|
18
|
+
...options.clientConfig,
|
|
19
|
+
};
|
|
20
|
+
if (options.forcePathStyle !== undefined) {
|
|
21
|
+
config.forcePathStyle = options.forcePathStyle;
|
|
22
|
+
}
|
|
23
|
+
this.client = new S3Client(config);
|
|
24
|
+
}
|
|
25
|
+
async putObject(input) {
|
|
26
|
+
const body = input.body instanceof Uint8Array
|
|
27
|
+
? input.body
|
|
28
|
+
: await streamToBuffer(input.body);
|
|
29
|
+
const result = await this.client.send(new PutObjectCommand({
|
|
30
|
+
Bucket: input.bucket,
|
|
31
|
+
Key: input.objectKey,
|
|
32
|
+
Body: body,
|
|
33
|
+
ContentType: input.contentType,
|
|
34
|
+
ContentLength: input.contentLength,
|
|
35
|
+
ChecksumSHA256: input.sha256,
|
|
36
|
+
Metadata: input.metadata,
|
|
37
|
+
}));
|
|
38
|
+
return {
|
|
39
|
+
etag: result.ETag,
|
|
40
|
+
versionId: result.VersionId,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async getObject(input) {
|
|
44
|
+
const range = input.range
|
|
45
|
+
? `bytes=${input.range.start}-${input.range.end ?? ""}`
|
|
46
|
+
: undefined;
|
|
47
|
+
const result = await this.client.send(new GetObjectCommand({
|
|
48
|
+
Bucket: input.bucket,
|
|
49
|
+
Key: input.objectKey,
|
|
50
|
+
Range: range,
|
|
51
|
+
}));
|
|
52
|
+
if (!result.Body) {
|
|
53
|
+
throw new StorageObjectNotFoundError(input.bucket, input.objectKey);
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
body: result.Body.transformToWebStream(),
|
|
57
|
+
contentType: result.ContentType,
|
|
58
|
+
contentLength: result.ContentLength,
|
|
59
|
+
etag: result.ETag,
|
|
60
|
+
metadata: result.Metadata,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async headObject(input) {
|
|
64
|
+
try {
|
|
65
|
+
const result = await this.client.send(new HeadObjectCommand({
|
|
66
|
+
Bucket: input.bucket,
|
|
67
|
+
Key: input.objectKey,
|
|
68
|
+
}));
|
|
69
|
+
return mapS3HeadToCore(result);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (isNotFoundError(error)) {
|
|
73
|
+
throw new StorageObjectNotFoundError(input.bucket, input.objectKey, { cause: error });
|
|
74
|
+
}
|
|
75
|
+
throw new StorageError("Failed to head object", { cause: error });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async deleteObject(input) {
|
|
79
|
+
await this.client.send(new DeleteObjectCommand({
|
|
80
|
+
Bucket: input.bucket,
|
|
81
|
+
Key: input.objectKey,
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
async initUploadSession(input) {
|
|
85
|
+
const result = await this.client.send(new CreateMultipartUploadCommand({
|
|
86
|
+
Bucket: input.bucket,
|
|
87
|
+
Key: input.objectKey,
|
|
88
|
+
ContentType: input.contentType,
|
|
89
|
+
Metadata: input.metadata,
|
|
90
|
+
}));
|
|
91
|
+
if (!result.UploadId) {
|
|
92
|
+
throw new StorageError("Failed to create multipart upload: no UploadId returned");
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
providerUploadId: result.UploadId,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async uploadPart(input) {
|
|
99
|
+
const body = input.body instanceof Uint8Array
|
|
100
|
+
? input.body
|
|
101
|
+
: await streamToBuffer(input.body);
|
|
102
|
+
const result = await this.client.send(new UploadPartCommand({
|
|
103
|
+
Bucket: input.bucket,
|
|
104
|
+
Key: input.objectKey,
|
|
105
|
+
UploadId: input.providerUploadId,
|
|
106
|
+
PartNumber: input.partNumber,
|
|
107
|
+
Body: body,
|
|
108
|
+
ContentLength: input.contentLength,
|
|
109
|
+
}));
|
|
110
|
+
if (!result.ETag) {
|
|
111
|
+
throw new StorageError("Failed to upload part: no ETag returned");
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
etag: result.ETag,
|
|
115
|
+
partNumber: input.partNumber,
|
|
116
|
+
size: body.byteLength,
|
|
117
|
+
checksumSha256: result.ChecksumSHA256,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async completeUploadSession(input) {
|
|
121
|
+
const result = await this.client.send(new CompleteMultipartUploadCommand({
|
|
122
|
+
Bucket: input.bucket,
|
|
123
|
+
Key: input.objectKey,
|
|
124
|
+
UploadId: input.providerUploadId,
|
|
125
|
+
MultipartUpload: {
|
|
126
|
+
Parts: input.parts.map((p) => ({
|
|
127
|
+
PartNumber: p.partNumber,
|
|
128
|
+
ETag: p.etag,
|
|
129
|
+
})),
|
|
130
|
+
},
|
|
131
|
+
}));
|
|
132
|
+
return {
|
|
133
|
+
etag: result.ETag,
|
|
134
|
+
versionId: result.VersionId,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
async abortUploadSession(input) {
|
|
138
|
+
await this.client.send(new AbortMultipartUploadCommand({
|
|
139
|
+
Bucket: input.bucket,
|
|
140
|
+
Key: input.objectKey,
|
|
141
|
+
UploadId: input.providerUploadId,
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
async createReadUrl(input) {
|
|
145
|
+
const expiresIn = input.expiresInSeconds ?? DEFAULT_EXPIRES_IN;
|
|
146
|
+
const command = new GetObjectCommand({
|
|
147
|
+
Bucket: input.bucket,
|
|
148
|
+
Key: input.objectKey,
|
|
149
|
+
ResponseContentType: input.responseContentType,
|
|
150
|
+
ResponseContentDisposition: input.responseContentDisposition,
|
|
151
|
+
});
|
|
152
|
+
const url = await getSignedUrl(this.client, command, { expiresIn });
|
|
153
|
+
return {
|
|
154
|
+
url,
|
|
155
|
+
method: "GET",
|
|
156
|
+
expiresAt: new Date(Date.now() + expiresIn * 1000),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
async createPutUrl(input) {
|
|
160
|
+
const expiresIn = input.expiresInSeconds ?? DEFAULT_EXPIRES_IN;
|
|
161
|
+
const command = new PutObjectCommand({
|
|
162
|
+
Bucket: input.bucket,
|
|
163
|
+
Key: input.objectKey,
|
|
164
|
+
ContentType: input.contentType,
|
|
165
|
+
});
|
|
166
|
+
const url = await getSignedUrl(this.client, command, { expiresIn });
|
|
167
|
+
return {
|
|
168
|
+
url,
|
|
169
|
+
method: "PUT",
|
|
170
|
+
expiresAt: new Date(Date.now() + expiresIn * 1000),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
async createUploadPartUrl(input) {
|
|
174
|
+
const expiresIn = input.expiresInSeconds ?? DEFAULT_EXPIRES_IN;
|
|
175
|
+
const command = new UploadPartCommand({
|
|
176
|
+
Bucket: input.bucket,
|
|
177
|
+
Key: input.objectKey,
|
|
178
|
+
UploadId: input.providerUploadId,
|
|
179
|
+
PartNumber: input.partNumber,
|
|
180
|
+
});
|
|
181
|
+
const url = await getSignedUrl(this.client, command, { expiresIn });
|
|
182
|
+
return {
|
|
183
|
+
url,
|
|
184
|
+
method: "PUT",
|
|
185
|
+
expiresAt: new Date(Date.now() + expiresIn * 1000),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async function streamToBuffer(stream) {
|
|
190
|
+
const reader = stream.getReader();
|
|
191
|
+
const chunks = [];
|
|
192
|
+
let totalLength = 0;
|
|
193
|
+
for (;;) {
|
|
194
|
+
const { done, value } = await reader.read();
|
|
195
|
+
if (done)
|
|
196
|
+
break;
|
|
197
|
+
chunks.push(value);
|
|
198
|
+
totalLength += value.byteLength;
|
|
199
|
+
}
|
|
200
|
+
const result = new Uint8Array(totalLength);
|
|
201
|
+
let offset = 0;
|
|
202
|
+
for (const chunk of chunks) {
|
|
203
|
+
result.set(chunk, offset);
|
|
204
|
+
offset += chunk.byteLength;
|
|
205
|
+
}
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
function isNotFoundError(error) {
|
|
209
|
+
return (typeof error === "object" &&
|
|
210
|
+
error !== null &&
|
|
211
|
+
"name" in error &&
|
|
212
|
+
error.name === "NotFound");
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=s3-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-storage.js","sourceRoot":"","sources":["../../src/storage/s3-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-options.d.ts","sourceRoot":"","sources":["../../src/types/s3-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-options.js","sourceRoot":"","sources":["../../src/types/s3-options.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vankyle/storage-s3",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "S3-compatible object storage adapter for vankyle-storage.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc -b tsconfig.json --force",
|
|
19
|
+
"clean": "rimraf dist tsconfig.tsbuildinfo",
|
|
20
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
21
|
+
},
|
|
22
|
+
"license": "MPL-2.0",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/Vankyle-Hub/storage-ts.git",
|
|
26
|
+
"directory": "packages/s3"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/Vankyle-Hub/storage-ts/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/Vankyle-Hub/storage-ts",
|
|
32
|
+
"packageManager": "pnpm@10.28.2",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@vankyle/storage-core": "0.1.0",
|
|
35
|
+
"@vankyle/storage-shared": "0.1.0",
|
|
36
|
+
"@aws-sdk/client-s3": "^3.1006.0",
|
|
37
|
+
"@aws-sdk/s3-request-presigner": "^3.1006.0"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
}
|
|
42
|
+
}
|