@lafken/bucket 0.10.1
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/LICENCE +21 -0
- package/README.md +259 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +19 -0
- package/lib/main/bucket/bucket.d.ts +30 -0
- package/lib/main/bucket/bucket.js +40 -0
- package/lib/main/bucket/bucket.types.d.ts +237 -0
- package/lib/main/bucket/bucket.types.js +8 -0
- package/lib/main/bucket/index.d.ts +2 -0
- package/lib/main/bucket/index.js +18 -0
- package/lib/main/index.d.ts +1 -0
- package/lib/main/index.js +17 -0
- package/lib/resolver/bucket/bucket.types.d.ts +10 -0
- package/lib/resolver/bucket/bucket.types.js +2 -0
- package/lib/resolver/bucket/external/external.d.ts +14 -0
- package/lib/resolver/bucket/external/external.js +15 -0
- package/lib/resolver/bucket/internal/internal.d.ts +14 -0
- package/lib/resolver/bucket/internal/internal.js +94 -0
- package/lib/resolver/index.d.ts +1 -0
- package/lib/resolver/index.js +17 -0
- package/lib/resolver/resolver.d.ts +14 -0
- package/lib/resolver/resolver.js +52 -0
- package/lib/resolver/resolver.types.d.ts +13 -0
- package/lib/resolver/resolver.types.js +2 -0
- package/lib/service/client/client.d.ts +3 -0
- package/lib/service/client/client.js +10 -0
- package/lib/service/index.d.ts +1 -0
- package/lib/service/index.js +17 -0
- package/lib/service/repository/index.d.ts +3 -0
- package/lib/service/repository/index.js +19 -0
- package/lib/service/repository/repository.d.ts +3 -0
- package/lib/service/repository/repository.js +62 -0
- package/lib/service/repository/repository.types.d.ts +13 -0
- package/lib/service/repository/repository.types.js +2 -0
- package/lib/service/repository/repository.utils.d.ts +2 -0
- package/lib/service/repository/repository.utils.js +9 -0
- package/package.json +96 -0
package/LICENCE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Aníbal Emilio Jorquera Cornejo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# @lafken/bucket
|
|
2
|
+
|
|
3
|
+
Define and manage Amazon S3 buckets using TypeScript decorators. `@lafken/bucket` lets you declare bucket configuration — versioning, ACL, lifecycle rules, transfer acceleration, and EventBridge integration — directly on a class. A built-in repository provides type-safe S3 operations at runtime.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @lafken/bucket
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Getting Started
|
|
12
|
+
|
|
13
|
+
Define a bucket class with `@Bucket`, register it in the `BucketResolver`, and use `createRepository` to interact with it:
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { createApp } from '@lafken/main';
|
|
17
|
+
import { BucketResolver } from '@lafken/bucket/resolver';
|
|
18
|
+
import { Bucket } from '@lafken/bucket/main';
|
|
19
|
+
import { createRepository } from '@lafken/bucket/service';
|
|
20
|
+
|
|
21
|
+
// 1. Define the bucket
|
|
22
|
+
@Bucket({ name: 'project-assets', versioned: true })
|
|
23
|
+
export class AssetsBucket {}
|
|
24
|
+
|
|
25
|
+
// 2. Create a repository for runtime operations
|
|
26
|
+
export const assetsRepository = createRepository(AssetsBucket);
|
|
27
|
+
|
|
28
|
+
// 3. Register the bucket in the resolver
|
|
29
|
+
createApp({
|
|
30
|
+
name: 'my-app',
|
|
31
|
+
resolvers: [new BucketResolver([AssetsBucket])],
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
### Defining a Bucket
|
|
38
|
+
|
|
39
|
+
Use the `@Bucket` decorator on a class to declare an S3 bucket. If `name` is omitted, the class name is used:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { Bucket } from '@lafken/bucket/main';
|
|
43
|
+
|
|
44
|
+
@Bucket({
|
|
45
|
+
name: 'upload-storage',
|
|
46
|
+
versioned: true,
|
|
47
|
+
acl: 'private',
|
|
48
|
+
forceDestroy: true,
|
|
49
|
+
tags: { environment: 'production' },
|
|
50
|
+
})
|
|
51
|
+
export class UploadBucket {}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### Bucket Options
|
|
55
|
+
|
|
56
|
+
| Option | Type | Default | Description |
|
|
57
|
+
| --------------------- | --------------------------------------------- | ------------ | --------------------------------------------------------- |
|
|
58
|
+
| `name` | `string` | class name | S3 bucket name |
|
|
59
|
+
| `versioned` | `boolean` | `false` | Enable object versioning |
|
|
60
|
+
| `acl` | `'private' \| 'public-read' \| 'public-read-write'` | — | Access control list |
|
|
61
|
+
| `forceDestroy` | `boolean` | `false` | Delete all objects when the bucket is destroyed |
|
|
62
|
+
| `eventBridgeEnabled` | `boolean` | `false` | Send bucket events to Amazon EventBridge |
|
|
63
|
+
| `transferAcceleration`| `boolean` | `false` | Enable CloudFront-based transfer acceleration |
|
|
64
|
+
| `tracing` | `boolean` | `false` | Enable AWS X-Ray tracing on repository operations |
|
|
65
|
+
| `tags` | `Record<string, string>` | — | Tags applied to the bucket resource |
|
|
66
|
+
| `lifeCycleRules` | `Record<string, KeyLifeCycleRule>` | — | Object lifecycle management rules |
|
|
67
|
+
|
|
68
|
+
### Lifecycle Rules
|
|
69
|
+
|
|
70
|
+
Define rules to automatically transition or expire objects based on age and size. Each key in `lifeCycleRules` represents an object prefix filter:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
@Bucket({
|
|
74
|
+
name: 'log-archive',
|
|
75
|
+
lifeCycleRules: {
|
|
76
|
+
'logs/': {
|
|
77
|
+
condition: {
|
|
78
|
+
objectSizeGreaterThan: 1024,
|
|
79
|
+
},
|
|
80
|
+
expiration: {
|
|
81
|
+
days: 90,
|
|
82
|
+
},
|
|
83
|
+
transitions: [
|
|
84
|
+
{ days: 30, storage: 'standard_ia' },
|
|
85
|
+
{ days: 60, storage: 'glacier' },
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
'tmp/': {
|
|
89
|
+
expiration: {
|
|
90
|
+
days: 7,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
})
|
|
95
|
+
export class LogBucket {}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### Expiration Options
|
|
99
|
+
|
|
100
|
+
| Option | Type | Description |
|
|
101
|
+
| ---------------------------- | --------- | ------------------------------------------------- |
|
|
102
|
+
| `days` | `number` | Delete objects after this many days |
|
|
103
|
+
| `date` | `Date` | Delete objects after a specific date |
|
|
104
|
+
| `expiredObjectDeleteMarker` | `boolean` | Remove expired object delete markers |
|
|
105
|
+
|
|
106
|
+
> [!NOTE]
|
|
107
|
+
> Only one expiration option can be set per rule.
|
|
108
|
+
|
|
109
|
+
#### Condition Options
|
|
110
|
+
|
|
111
|
+
| Option | Type | Description |
|
|
112
|
+
| ------------------------ | -------- | --------------------------------------------- |
|
|
113
|
+
| `objectSizeGreaterThan` | `number` | Apply rule only to objects larger than (bytes) |
|
|
114
|
+
| `objectSizeLessThan` | `number` | Apply rule only to objects smaller than (bytes)|
|
|
115
|
+
|
|
116
|
+
#### Available Storage Classes
|
|
117
|
+
|
|
118
|
+
| Storage Class | Description |
|
|
119
|
+
| ---------------------- | ------------------------------------------------ |
|
|
120
|
+
| `standard_ia` | Infrequent access, lower cost |
|
|
121
|
+
| `onezone_ia` | Single-AZ infrequent access |
|
|
122
|
+
| `intelligent_tiering` | Automatic cost optimization by access patterns |
|
|
123
|
+
| `glacier` | Long-term archive (minutes to hours retrieval) |
|
|
124
|
+
| `glacier_ir` | Instant retrieval archive |
|
|
125
|
+
| `deep_archive` | Lowest cost (12+ hours retrieval) |
|
|
126
|
+
|
|
127
|
+
### EventBridge Integration
|
|
128
|
+
|
|
129
|
+
Enable `eventBridgeEnabled` to send bucket events (object created, deleted, etc.) to Amazon EventBridge. Combine with `@lafken/event` to process these events:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
@Bucket({
|
|
133
|
+
name: 'document-uploads',
|
|
134
|
+
eventBridgeEnabled: true,
|
|
135
|
+
})
|
|
136
|
+
export class DocumentBucket {}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Repository
|
|
140
|
+
|
|
141
|
+
`createRepository` provides a type-safe API for S3 operations at runtime. The bucket name is automatically injected into every command:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { createRepository } from '@lafken/bucket/service';
|
|
145
|
+
|
|
146
|
+
export const docsRepository = createRepository(DocumentBucket);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### Put Object
|
|
150
|
+
|
|
151
|
+
Upload an object to the bucket:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
await docsRepository.putObject({
|
|
155
|
+
Key: 'reports/monthly.json',
|
|
156
|
+
Body: JSON.stringify({ revenue: 50000 }),
|
|
157
|
+
ContentType: 'application/json',
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### Get Object
|
|
162
|
+
|
|
163
|
+
Retrieve an object from the bucket:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
const response = await docsRepository.getObject({
|
|
167
|
+
Key: 'reports/monthly.json',
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const body = await response.Body?.transformToString();
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### Delete Object
|
|
174
|
+
|
|
175
|
+
Remove an object from the bucket:
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
await docsRepository.deleteObject({
|
|
179
|
+
Key: 'reports/old-report.json',
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### Copy Object
|
|
184
|
+
|
|
185
|
+
Copy an object within or across buckets:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
await docsRepository.copyObject({
|
|
189
|
+
Key: 'archive/monthly.json',
|
|
190
|
+
CopySource: 'document-uploads/reports/monthly.json',
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### Move Object
|
|
195
|
+
|
|
196
|
+
Copy an object to a new key and delete the original in a single operation:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
await docsRepository.moveObject({
|
|
200
|
+
Key: 'processed/monthly.json',
|
|
201
|
+
CopySource: 'document-uploads/reports/monthly.json',
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### List Objects
|
|
206
|
+
|
|
207
|
+
List all objects matching a prefix. Pagination is handled automatically:
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
const result = await docsRepository.listObjects({
|
|
211
|
+
Prefix: 'reports/',
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
for (const object of result.Contents) {
|
|
215
|
+
console.log(object.Key, object.Size);
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### X-Ray Tracing
|
|
220
|
+
|
|
221
|
+
Enable `tracing` in the `@Bucket` decorator to instrument all repository operations with AWS X-Ray:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
@Bucket({
|
|
225
|
+
name: 'traced-bucket',
|
|
226
|
+
tracing: true,
|
|
227
|
+
})
|
|
228
|
+
export class TracedBucket {}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Global Configuration
|
|
232
|
+
|
|
233
|
+
The `BucketResolver` accepts a second argument with global defaults applied to all buckets. Per-bucket options override global ones:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
new BucketResolver(
|
|
237
|
+
[AssetsBucket, LogBucket],
|
|
238
|
+
{
|
|
239
|
+
forceDestroy: true,
|
|
240
|
+
versioned: true,
|
|
241
|
+
tags: { team: 'platform' },
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Extending Buckets
|
|
247
|
+
|
|
248
|
+
Apply advanced CDKTN configuration to a bucket using the `extends` callback:
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
new BucketResolver([
|
|
252
|
+
{
|
|
253
|
+
bucket: AssetsBucket,
|
|
254
|
+
extends: ({ bucket, scope }) => {
|
|
255
|
+
// Add CORS rules, policies, or any CDKTN construct
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
]);
|
|
259
|
+
```
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./main"), exports);
|
|
18
|
+
__exportStar(require("./resolver"), exports);
|
|
19
|
+
__exportStar(require("./service"), exports);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type BucketProps } from './bucket.types';
|
|
2
|
+
/**
|
|
3
|
+
* Class decorator that registers a class as an S3 bucket resource.
|
|
4
|
+
*
|
|
5
|
+
* The decorated class represents an Amazon S3 bucket and its configuration.
|
|
6
|
+
* Options such as versioning, lifecycle rules, ACL, transfer acceleration,
|
|
7
|
+
* and EventBridge integration can be set through the decorator props.
|
|
8
|
+
*
|
|
9
|
+
* @param props - Optional bucket configuration. If omitted, defaults are used
|
|
10
|
+
* and the class name becomes the bucket resource name.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* @Bucket({ versioned: true, acl: 'private' })
|
|
15
|
+
* export class UserUploadsBucket {}
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* @Bucket({
|
|
21
|
+
* lifeCycleRules: {
|
|
22
|
+
* 'tmp/': {
|
|
23
|
+
* expiration: { days: 7 },
|
|
24
|
+
* },
|
|
25
|
+
* },
|
|
26
|
+
* })
|
|
27
|
+
* export class TempFilesBucket {}
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare const Bucket: (props?: BucketProps) => (target: Function) => void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Bucket = void 0;
|
|
4
|
+
const bucket_types_1 = require("./bucket.types");
|
|
5
|
+
/**
|
|
6
|
+
* Class decorator that registers a class as an S3 bucket resource.
|
|
7
|
+
*
|
|
8
|
+
* The decorated class represents an Amazon S3 bucket and its configuration.
|
|
9
|
+
* Options such as versioning, lifecycle rules, ACL, transfer acceleration,
|
|
10
|
+
* and EventBridge integration can be set through the decorator props.
|
|
11
|
+
*
|
|
12
|
+
* @param props - Optional bucket configuration. If omitted, defaults are used
|
|
13
|
+
* and the class name becomes the bucket resource name.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* @Bucket({ versioned: true, acl: 'private' })
|
|
18
|
+
* export class UserUploadsBucket {}
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* @Bucket({
|
|
24
|
+
* lifeCycleRules: {
|
|
25
|
+
* 'tmp/': {
|
|
26
|
+
* expiration: { days: 7 },
|
|
27
|
+
* },
|
|
28
|
+
* },
|
|
29
|
+
* })
|
|
30
|
+
* export class TempFilesBucket {}
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
const Bucket = (props = {}) => (target) => {
|
|
34
|
+
const { name = target.name } = props;
|
|
35
|
+
Reflect.defineMetadata(bucket_types_1.BucketMetadataKeys.bucket, {
|
|
36
|
+
name,
|
|
37
|
+
...props,
|
|
38
|
+
}, target);
|
|
39
|
+
};
|
|
40
|
+
exports.Bucket = Bucket;
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import type { BucketNames, OnlyOne, ResourceOutputType } from '@lafken/common';
|
|
2
|
+
import 'reflect-metadata';
|
|
3
|
+
export declare enum BucketMetadataKeys {
|
|
4
|
+
bucket = "s3:bucket"
|
|
5
|
+
}
|
|
6
|
+
export type TransitionStorage = 'glacier' | 'standard_ia' | 'onezone_ia' | 'intelligent_tiering' | 'deep_archive' | 'glacier_ir';
|
|
7
|
+
export type BucketOutputAttributes = 'id' | 'arn' | 'bucketDomainName' | 'bucketRegionalDomainName';
|
|
8
|
+
export interface Transition {
|
|
9
|
+
/**
|
|
10
|
+
* Target storage class for the transition.
|
|
11
|
+
*
|
|
12
|
+
* This defines the S3 storage class to which the objects will be moved.
|
|
13
|
+
*/
|
|
14
|
+
storage: TransitionStorage;
|
|
15
|
+
/**
|
|
16
|
+
* Number of days after object creation when the transition occurs.
|
|
17
|
+
*
|
|
18
|
+
* The object will be moved to the specified storage class after this
|
|
19
|
+
* number of days.
|
|
20
|
+
*/
|
|
21
|
+
days: number;
|
|
22
|
+
}
|
|
23
|
+
export interface Expiration {
|
|
24
|
+
days?: number;
|
|
25
|
+
date?: Date;
|
|
26
|
+
expiredObjectDeleteMarker?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface KeyLifeCycleRule {
|
|
29
|
+
/**
|
|
30
|
+
* Defines the expiration configuration for objects stored in the S3 bucket.
|
|
31
|
+
*
|
|
32
|
+
* This property specifies when the objects that match the lifecycle rule
|
|
33
|
+
* should be automatically deleted by Amazon S3.
|
|
34
|
+
* @example
|
|
35
|
+
* ```
|
|
36
|
+
* // one of
|
|
37
|
+
* {
|
|
38
|
+
* expiration: {
|
|
39
|
+
* days: 10
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* // or
|
|
43
|
+
* {
|
|
44
|
+
* expiration: {
|
|
45
|
+
* date: new Date()
|
|
46
|
+
* }
|
|
47
|
+
* }
|
|
48
|
+
* // or
|
|
49
|
+
* {
|
|
50
|
+
* expiration: {
|
|
51
|
+
* expiredObjectDeleteMarker: true
|
|
52
|
+
* }
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
expiration?: OnlyOne<Expiration>;
|
|
57
|
+
/**
|
|
58
|
+
* Optional conditions to apply the lifecycle rule only to objects
|
|
59
|
+
* that match certain size thresholds.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```
|
|
63
|
+
* {
|
|
64
|
+
* condition: {
|
|
65
|
+
* objectSizeGreaterThan: 10000,
|
|
66
|
+
* objectSizeLessThan: 100
|
|
67
|
+
* }
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
condition?: {
|
|
72
|
+
/**
|
|
73
|
+
* Minimum object size in bytes for the lifecycle rule to apply.
|
|
74
|
+
*
|
|
75
|
+
* The rule will only apply to objects larger than this value.
|
|
76
|
+
*/
|
|
77
|
+
objectSizeGreaterThan?: number;
|
|
78
|
+
/**
|
|
79
|
+
* Maximum object size in bytes for the lifecycle rule to apply.
|
|
80
|
+
*
|
|
81
|
+
* The rule will only apply to objects smaller than this value.
|
|
82
|
+
*/
|
|
83
|
+
objectSizeLessThan?: number;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Transition rules that define how and when objects are moved
|
|
87
|
+
* to different S3 storage classes (e.g., GLACIER, INTELLIGENT_TIERING).
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```
|
|
91
|
+
* {
|
|
92
|
+
* transitions: [
|
|
93
|
+
* {
|
|
94
|
+
* storage: 'standard_ia'
|
|
95
|
+
* days: 10,
|
|
96
|
+
* }
|
|
97
|
+
* ]
|
|
98
|
+
* }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
transitions?: Transition[];
|
|
102
|
+
}
|
|
103
|
+
export interface BaseBucketProps {
|
|
104
|
+
/**
|
|
105
|
+
* Bucket resource name.
|
|
106
|
+
*
|
|
107
|
+
* Defines the logical name of the bucket resource.
|
|
108
|
+
* If not specified, the name of the decorated class will be used.
|
|
109
|
+
*/
|
|
110
|
+
name?: BucketNames;
|
|
111
|
+
/**
|
|
112
|
+
* Enable X-Ray tracing.
|
|
113
|
+
*
|
|
114
|
+
* When enabled, AWS X-Ray tracing is activated for the bucket-related
|
|
115
|
+
* operations. This allows you to trace and analyze requests as they
|
|
116
|
+
* pass through AWS services, useful for debugging and performance
|
|
117
|
+
* monitoring.
|
|
118
|
+
*/
|
|
119
|
+
tracing?: boolean;
|
|
120
|
+
}
|
|
121
|
+
export interface InternalBucketProps extends BaseBucketProps {
|
|
122
|
+
isExternal?: never;
|
|
123
|
+
/**
|
|
124
|
+
* Enable EventBridge events.
|
|
125
|
+
*
|
|
126
|
+
* When enabled, Amazon S3 automatically sends events for this bucket
|
|
127
|
+
* to Amazon EventBridge. This allows you to capture S3 bucket events
|
|
128
|
+
* (such as object created, deleted, etc.).
|
|
129
|
+
*/
|
|
130
|
+
eventBridgeEnabled?: boolean;
|
|
131
|
+
/**
|
|
132
|
+
* Defines the Access Control List (ACL) configuration for the S3 bucket.
|
|
133
|
+
*
|
|
134
|
+
* This property determines the default access level applied to all objects
|
|
135
|
+
* within the bucket unless overridden at the object level.
|
|
136
|
+
*
|
|
137
|
+
* - `'private'`: Grants access only to the bucket owner. This is the most secure option
|
|
138
|
+
* and the default behavior in most cases.
|
|
139
|
+
* - `'public-read'`: Allows anyone on the internet to read objects in the bucket,
|
|
140
|
+
* but only the bucket owner can write or modify them.
|
|
141
|
+
* - `'public-read-write'`: Grants both read and write access to everyone.
|
|
142
|
+
* This setting is **not recommended** for production use, as it exposes your bucket
|
|
143
|
+
* to public writes and potential misuse.
|
|
144
|
+
*/
|
|
145
|
+
acl?: 'private' | 'public-read' | 'public-read-write';
|
|
146
|
+
/**
|
|
147
|
+
* Enable transfer acceleration for the S3 bucket.
|
|
148
|
+
*
|
|
149
|
+
* Transfer acceleration leverages Amazon CloudFront's globally distributed
|
|
150
|
+
* edge locations to accelerate data transfers between clients and the bucket.
|
|
151
|
+
* This reduces latency and improves throughput, particularly when
|
|
152
|
+
* users are geographically distant from the bucket's AWS region.
|
|
153
|
+
*/
|
|
154
|
+
transferAcceleration?: boolean;
|
|
155
|
+
/**
|
|
156
|
+
* Enable versioning for the S3 bucket.
|
|
157
|
+
*
|
|
158
|
+
* When enabled, the bucket keeps multiple versions of an object,
|
|
159
|
+
* allowing recovery from accidental overwrites or deletions.
|
|
160
|
+
* Versioning provides a safeguard for data protection and
|
|
161
|
+
* can also be used for auditing and historical tracking.
|
|
162
|
+
*/
|
|
163
|
+
versioned?: boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Lifecycle rules for the S3 bucket.
|
|
166
|
+
*
|
|
167
|
+
* Defines rules to automatically manage the lifecycle of objects in the bucket,
|
|
168
|
+
* such as transitioning them to different storage classes, expiring them after
|
|
169
|
+
* a given time, or cleaning up incomplete multipart uploads.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```
|
|
173
|
+
* {
|
|
174
|
+
* lifeCycleRules: {
|
|
175
|
+
* 'key-path': { // represents an object in the bucket
|
|
176
|
+
* expiration: {
|
|
177
|
+
* days: 20,
|
|
178
|
+
* },
|
|
179
|
+
* condition: {
|
|
180
|
+
* objectSizeGreaterThan: 2024 // value in bytes
|
|
181
|
+
* }
|
|
182
|
+
* }
|
|
183
|
+
* }
|
|
184
|
+
* }
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
lifeCycleRules?: Record<string, KeyLifeCycleRule>;
|
|
188
|
+
/**
|
|
189
|
+
* Indicates all objects from bucket should be deleted when bucket is destroyed
|
|
190
|
+
*/
|
|
191
|
+
forceDestroy?: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* tags.
|
|
194
|
+
*
|
|
195
|
+
* Specifies a set of tags that will be applied to s3 bucket.
|
|
196
|
+
*/
|
|
197
|
+
tags?: Record<string, string>;
|
|
198
|
+
/**
|
|
199
|
+
* Defines which S3 Bucket attributes should be exported.
|
|
200
|
+
*
|
|
201
|
+
* Supported attributes are based on Terraform `aws_s3_bucket`
|
|
202
|
+
* exported attributes and currently include:
|
|
203
|
+
* - `id`: Name of the bucket.
|
|
204
|
+
* - `arn`: ARN of the bucket (`arn:aws:s3:::bucketname`).
|
|
205
|
+
* - `bucketDomainName`: Bucket domain name (`bucketname.s3.amazonaws.com`).
|
|
206
|
+
* - `bucketRegionalDomainName`: Region-specific bucket domain name.
|
|
207
|
+
*
|
|
208
|
+
* Each selected attribute can be exported through SSM Parameter Store (`type: 'ssm'`)
|
|
209
|
+
* or Terraform outputs (`type: 'output'`).
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* {
|
|
213
|
+
* outputs: [
|
|
214
|
+
* { type: 'ssm', name: '/my-bucket/arn', value: 'arn' },
|
|
215
|
+
* { type: 'output', name: 'bucket_regional_domain', value: 'bucketRegionalDomainName' }
|
|
216
|
+
* ]
|
|
217
|
+
* }
|
|
218
|
+
*/
|
|
219
|
+
outputs?: ResourceOutputType<BucketOutputAttributes>;
|
|
220
|
+
}
|
|
221
|
+
export interface ExternalBucketProps extends BaseBucketProps {
|
|
222
|
+
/**
|
|
223
|
+
* Marks the bucket as an external resource.
|
|
224
|
+
*
|
|
225
|
+
* When set to `true`, the bucket is not created by the framework.
|
|
226
|
+
* Instead, it references an existing S3 bucket using the provided `name`.
|
|
227
|
+
*/
|
|
228
|
+
isExternal: true;
|
|
229
|
+
}
|
|
230
|
+
export type BucketProps = InternalBucketProps | ExternalBucketProps;
|
|
231
|
+
export interface InternalBucketMetadataProps extends Omit<InternalBucketProps, 'name'> {
|
|
232
|
+
name: string;
|
|
233
|
+
}
|
|
234
|
+
export interface ExternalBucketMetadataProps extends Omit<ExternalBucketProps, 'name'> {
|
|
235
|
+
name: string;
|
|
236
|
+
}
|
|
237
|
+
export type BucketMetadata = InternalBucketMetadataProps | ExternalBucketMetadataProps;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BucketMetadataKeys = void 0;
|
|
4
|
+
require("reflect-metadata");
|
|
5
|
+
var BucketMetadataKeys;
|
|
6
|
+
(function (BucketMetadataKeys) {
|
|
7
|
+
BucketMetadataKeys["bucket"] = "s3:bucket";
|
|
8
|
+
})(BucketMetadataKeys || (exports.BucketMetadataKeys = BucketMetadataKeys = {}));
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./bucket"), exports);
|
|
18
|
+
__exportStar(require("./bucket.types"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './bucket';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./bucket"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ClassResource } from '@lafken/common';
|
|
2
|
+
import type { InternalBucketProps as MainInternalBucketProps } from '../../main';
|
|
3
|
+
export interface BucketGlobalConfig extends Omit<MainInternalBucketProps, 'name' | 'tracing'> {
|
|
4
|
+
}
|
|
5
|
+
export interface InternalBucketProps extends BucketGlobalConfig {
|
|
6
|
+
classResource: ClassResource;
|
|
7
|
+
}
|
|
8
|
+
export interface ExternalBucketProps {
|
|
9
|
+
classResource: ClassResource;
|
|
10
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DataAwsS3Bucket } from '@cdktn/provider-aws/lib/data-aws-s3-bucket';
|
|
2
|
+
import type { Construct } from 'constructs';
|
|
3
|
+
import type { ExternalBucketMetadataProps } from '../../../main';
|
|
4
|
+
declare const ExternalBucket_base: (new (...args: any[]) => {
|
|
5
|
+
isGlobal(module: import("@lafken/common").ModuleGlobalReferenceNames | (string & {}), id: string): void;
|
|
6
|
+
isDependent(resolveDependency: () => void): void;
|
|
7
|
+
readonly node: import("constructs").Node;
|
|
8
|
+
with(...mixins: import("constructs").IMixin[]): import("constructs").IConstruct;
|
|
9
|
+
toString(): string;
|
|
10
|
+
}) & typeof DataAwsS3Bucket;
|
|
11
|
+
export declare class ExternalBucket extends ExternalBucket_base {
|
|
12
|
+
constructor(scope: Construct, props: ExternalBucketMetadataProps);
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExternalBucket = void 0;
|
|
4
|
+
const data_aws_s3_bucket_1 = require("@cdktn/provider-aws/lib/data-aws-s3-bucket");
|
|
5
|
+
const resolver_1 = require("@lafken/resolver");
|
|
6
|
+
class ExternalBucket extends resolver_1.lafkenResource.make(data_aws_s3_bucket_1.DataAwsS3Bucket) {
|
|
7
|
+
constructor(scope, props) {
|
|
8
|
+
const { name } = props;
|
|
9
|
+
super(scope, `${name}-bucket`, {
|
|
10
|
+
bucket: name,
|
|
11
|
+
});
|
|
12
|
+
this.isGlobal('bucket', name);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.ExternalBucket = ExternalBucket;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { S3Bucket } from '@cdktn/provider-aws/lib/s3-bucket';
|
|
2
|
+
import type { Construct } from 'constructs';
|
|
3
|
+
import type { InternalBucketMetadataProps } from '../../../main';
|
|
4
|
+
declare const InternalBucket_base: (new (...args: any[]) => {
|
|
5
|
+
isGlobal(module: import("@lafken/common").ModuleGlobalReferenceNames | (string & {}), id: string): void;
|
|
6
|
+
isDependent(resolveDependency: () => void): void;
|
|
7
|
+
readonly node: import("constructs").Node;
|
|
8
|
+
with(...mixins: import("constructs").IMixin[]): import("constructs").IConstruct;
|
|
9
|
+
toString(): string;
|
|
10
|
+
}) & typeof S3Bucket;
|
|
11
|
+
export declare class InternalBucket extends InternalBucket_base {
|
|
12
|
+
constructor(scope: Construct, props: InternalBucketMetadataProps);
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InternalBucket = void 0;
|
|
4
|
+
const s3_bucket_1 = require("@cdktn/provider-aws/lib/s3-bucket");
|
|
5
|
+
const s3_bucket_accelerate_configuration_1 = require("@cdktn/provider-aws/lib/s3-bucket-accelerate-configuration");
|
|
6
|
+
const s3_bucket_acl_1 = require("@cdktn/provider-aws/lib/s3-bucket-acl");
|
|
7
|
+
const s3_bucket_lifecycle_configuration_1 = require("@cdktn/provider-aws/lib/s3-bucket-lifecycle-configuration");
|
|
8
|
+
const s3_bucket_notification_1 = require("@cdktn/provider-aws/lib/s3-bucket-notification");
|
|
9
|
+
const s3_bucket_versioning_1 = require("@cdktn/provider-aws/lib/s3-bucket-versioning");
|
|
10
|
+
const common_1 = require("@lafken/common");
|
|
11
|
+
const resolver_1 = require("@lafken/resolver");
|
|
12
|
+
class InternalBucket extends resolver_1.lafkenResource.make(s3_bucket_1.S3Bucket) {
|
|
13
|
+
constructor(scope, props) {
|
|
14
|
+
const { name, eventBridgeEnabled, acl, forceDestroy, transferAcceleration, versioned, lifeCycleRules, tags, } = props;
|
|
15
|
+
super(scope, `${name}-bucket`, {
|
|
16
|
+
bucket: name,
|
|
17
|
+
forceDestroy: forceDestroy ?? props.forceDestroy,
|
|
18
|
+
tags: tags ?? {
|
|
19
|
+
...(tags || {}),
|
|
20
|
+
...(props.tags || {}),
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
this.isGlobal('bucket', name);
|
|
24
|
+
if (eventBridgeEnabled ?? props.eventBridgeEnabled) {
|
|
25
|
+
new s3_bucket_notification_1.S3BucketNotification(this, `${name}-notification`, {
|
|
26
|
+
bucket: this.id,
|
|
27
|
+
eventbridge: true,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (acl || props.acl) {
|
|
31
|
+
new s3_bucket_acl_1.S3BucketAcl(this, `${name}-acl`, {
|
|
32
|
+
bucket: this.id,
|
|
33
|
+
acl: acl || props.acl,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (versioned ?? props.versioned) {
|
|
37
|
+
new s3_bucket_versioning_1.S3BucketVersioningA(this, `${name}-versioned`, {
|
|
38
|
+
bucket: this.id,
|
|
39
|
+
versioningConfiguration: {
|
|
40
|
+
status: 'Enabled',
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
if (transferAcceleration ?? props.transferAcceleration) {
|
|
45
|
+
new s3_bucket_accelerate_configuration_1.S3BucketAccelerateConfiguration(this, `${name}-accelerate-config`, {
|
|
46
|
+
bucket: this.id,
|
|
47
|
+
status: 'Enabled',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const lifeCycle = lifeCycleRules || props.lifeCycleRules || {};
|
|
51
|
+
if (Object.keys(lifeCycle).length > 0) {
|
|
52
|
+
new s3_bucket_lifecycle_configuration_1.S3BucketLifecycleConfiguration(this, `${name}-lifecycle`, {
|
|
53
|
+
bucket: this.id,
|
|
54
|
+
rule: Object.keys(lifeCycle).map((key) => {
|
|
55
|
+
const rule = lifeCycle[key];
|
|
56
|
+
return {
|
|
57
|
+
id: `${name}-lc-rule-${(0, common_1.cleanString)(key)}`,
|
|
58
|
+
status: 'Enabled',
|
|
59
|
+
filter: [
|
|
60
|
+
{
|
|
61
|
+
prefix: key,
|
|
62
|
+
objectSizeGreaterThan: rule.condition?.objectSizeGreaterThan,
|
|
63
|
+
objectSizeLessThan: rule.condition?.objectSizeLessThan,
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
expiration: rule.expiration
|
|
67
|
+
? [
|
|
68
|
+
{
|
|
69
|
+
days: rule.expiration.days,
|
|
70
|
+
date: rule.expiration.date
|
|
71
|
+
? rule.expiration.date
|
|
72
|
+
.toLocaleDateString('en-GB', {
|
|
73
|
+
day: '2-digit',
|
|
74
|
+
month: '2-digit',
|
|
75
|
+
year: 'numeric',
|
|
76
|
+
})
|
|
77
|
+
.replace(/\//g, '-')
|
|
78
|
+
: undefined,
|
|
79
|
+
expiredObjectDeleteMarker: rule.expiration.expiredObjectDeleteMarker,
|
|
80
|
+
},
|
|
81
|
+
]
|
|
82
|
+
: undefined,
|
|
83
|
+
transition: (rule.transitions || []).map((transition) => ({
|
|
84
|
+
days: transition.days,
|
|
85
|
+
storageClass: transition.storage,
|
|
86
|
+
})),
|
|
87
|
+
};
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
new resolver_1.ResourceOutput(this, props.outputs);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.InternalBucket = InternalBucket;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './resolver';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./resolver"), exports);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ClassResource } from '@lafken/common';
|
|
2
|
+
import type { AppModule, AppStack, ResolverType } from '@lafken/resolver';
|
|
3
|
+
import type { BucketGlobalConfig } from './bucket/bucket.types';
|
|
4
|
+
import type { ClassResourceExtends } from './resolver.types';
|
|
5
|
+
export declare class BucketResolver implements ResolverType {
|
|
6
|
+
private buckets;
|
|
7
|
+
private config;
|
|
8
|
+
type: string;
|
|
9
|
+
private extensibleBuckets;
|
|
10
|
+
constructor(buckets: (ClassResource | ClassResourceExtends)[], config?: BucketGlobalConfig);
|
|
11
|
+
beforeCreate(scope: AppModule): void;
|
|
12
|
+
create(): void;
|
|
13
|
+
afterCreate(scope: AppStack): void;
|
|
14
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BucketResolver = void 0;
|
|
4
|
+
const main_1 = require("../main");
|
|
5
|
+
const external_1 = require("./bucket/external/external");
|
|
6
|
+
const internal_1 = require("./bucket/internal/internal");
|
|
7
|
+
class BucketResolver {
|
|
8
|
+
buckets;
|
|
9
|
+
config;
|
|
10
|
+
type = 'BUCKET';
|
|
11
|
+
extensibleBuckets = [];
|
|
12
|
+
constructor(buckets, config = {}) {
|
|
13
|
+
this.buckets = buckets;
|
|
14
|
+
this.config = config;
|
|
15
|
+
}
|
|
16
|
+
beforeCreate(scope) {
|
|
17
|
+
for (const bucket of this.buckets) {
|
|
18
|
+
const isExtensible = 'bucket' in bucket;
|
|
19
|
+
const bucketProps = Reflect.getMetadata(main_1.BucketMetadataKeys.bucket, isExtensible ? bucket.bucket : bucket);
|
|
20
|
+
let bucketResource;
|
|
21
|
+
if (bucketProps.isExternal) {
|
|
22
|
+
bucketResource = new external_1.ExternalBucket(scope, {
|
|
23
|
+
...bucketProps,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
bucketResource = new internal_1.InternalBucket(scope, {
|
|
28
|
+
...bucketProps,
|
|
29
|
+
...this.config,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
if (isExtensible) {
|
|
33
|
+
this.extensibleBuckets.push({
|
|
34
|
+
bucket: bucketResource,
|
|
35
|
+
extends: bucket.extends,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
create() {
|
|
41
|
+
throw new Error('It is not possible to parse this service');
|
|
42
|
+
}
|
|
43
|
+
afterCreate(scope) {
|
|
44
|
+
for (const extendBucket of this.extensibleBuckets) {
|
|
45
|
+
extendBucket.extends({
|
|
46
|
+
scope,
|
|
47
|
+
bucket: extendBucket.bucket,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.BucketResolver = BucketResolver;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DataAwsS3Bucket } from '@cdktn/provider-aws/lib/data-aws-s3-bucket';
|
|
2
|
+
import type { S3Bucket } from '@cdktn/provider-aws/lib/s3-bucket';
|
|
3
|
+
import type { ClassResource } from '@lafken/common';
|
|
4
|
+
import type { AppStack } from '@lafken/resolver';
|
|
5
|
+
interface ExtendProps {
|
|
6
|
+
scope: AppStack;
|
|
7
|
+
bucket: S3Bucket | DataAwsS3Bucket;
|
|
8
|
+
}
|
|
9
|
+
export interface ClassResourceExtends {
|
|
10
|
+
bucket: ClassResource;
|
|
11
|
+
extends: (props: ExtendProps) => void;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getClientWithXRay = exports.client = void 0;
|
|
4
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
5
|
+
const aws_xray_sdk_1 = require("aws-xray-sdk");
|
|
6
|
+
exports.client = new client_s3_1.S3Client();
|
|
7
|
+
const getClientWithXRay = () => {
|
|
8
|
+
return (0, aws_xray_sdk_1.captureAWSv3Client)(exports.client);
|
|
9
|
+
};
|
|
10
|
+
exports.getClientWithXRay = getClientWithXRay;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './repository';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./repository"), exports);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./repository"), exports);
|
|
18
|
+
__exportStar(require("./repository.types"), exports);
|
|
19
|
+
__exportStar(require("./repository.utils"), exports);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRepository = void 0;
|
|
4
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
5
|
+
const client_1 = require("../client/client");
|
|
6
|
+
const repository_utils_1 = require("./repository.utils");
|
|
7
|
+
const createRepository = (bucket) => {
|
|
8
|
+
const { name, tracing } = (0, repository_utils_1.getBucketInformation)(bucket);
|
|
9
|
+
const bucketClient = tracing ? (0, client_1.getClientWithXRay)() : client_1.client;
|
|
10
|
+
return {
|
|
11
|
+
putObject(props) {
|
|
12
|
+
const command = new client_s3_1.PutObjectCommand({
|
|
13
|
+
Bucket: name,
|
|
14
|
+
...props,
|
|
15
|
+
});
|
|
16
|
+
return bucketClient.send(command);
|
|
17
|
+
},
|
|
18
|
+
getObject(props) {
|
|
19
|
+
const command = new client_s3_1.GetObjectCommand({
|
|
20
|
+
Bucket: name,
|
|
21
|
+
...props,
|
|
22
|
+
});
|
|
23
|
+
return bucketClient.send(command);
|
|
24
|
+
},
|
|
25
|
+
deleteObject(props) {
|
|
26
|
+
const command = new client_s3_1.DeleteObjectCommand({
|
|
27
|
+
Bucket: name,
|
|
28
|
+
...props,
|
|
29
|
+
});
|
|
30
|
+
return bucketClient.send(command);
|
|
31
|
+
},
|
|
32
|
+
copyObject(props) {
|
|
33
|
+
const command = new client_s3_1.CopyObjectCommand({
|
|
34
|
+
Bucket: name,
|
|
35
|
+
...props,
|
|
36
|
+
});
|
|
37
|
+
return bucketClient.send(command);
|
|
38
|
+
},
|
|
39
|
+
async moveObject(props) {
|
|
40
|
+
await this.copyObject(props);
|
|
41
|
+
await this.deleteObject({
|
|
42
|
+
Key: props.Key,
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
async listObjects(props) {
|
|
46
|
+
let allContents = [];
|
|
47
|
+
let nextToken;
|
|
48
|
+
do {
|
|
49
|
+
const command = new client_s3_1.ListObjectsV2Command({
|
|
50
|
+
Bucket: name,
|
|
51
|
+
...props,
|
|
52
|
+
ContinuationToken: nextToken,
|
|
53
|
+
});
|
|
54
|
+
const response = await bucketClient.send(command);
|
|
55
|
+
allContents = [...allContents, ...(response.Contents || [])];
|
|
56
|
+
nextToken = response.IsTruncated ? response.ContinuationToken : undefined;
|
|
57
|
+
} while (nextToken);
|
|
58
|
+
return { Contents: allContents };
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
exports.createRepository = createRepository;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { _Object, CopyObjectCommandInput, CopyObjectCommandOutput, DeleteObjectCommandInput, DeleteObjectCommandOutput, GetObjectCommandInput, GetObjectCommandOutput, ListObjectsV2CommandInput, PutObjectCommandInput, PutObjectCommandOutput } from '@aws-sdk/client-s3';
|
|
2
|
+
import type { ClassResource } from '@lafken/common';
|
|
3
|
+
export type InputWithoutBucket<T> = Omit<T, 'Bucket'>;
|
|
4
|
+
export type RepositoryReturn<_E extends ClassResource> = {
|
|
5
|
+
putObject(props: InputWithoutBucket<PutObjectCommandInput>): Promise<PutObjectCommandOutput>;
|
|
6
|
+
getObject(props: InputWithoutBucket<GetObjectCommandInput>): Promise<GetObjectCommandOutput>;
|
|
7
|
+
deleteObject(props: InputWithoutBucket<DeleteObjectCommandInput>): Promise<DeleteObjectCommandOutput>;
|
|
8
|
+
copyObject(props: InputWithoutBucket<CopyObjectCommandInput>): Promise<CopyObjectCommandOutput>;
|
|
9
|
+
moveObject(props: InputWithoutBucket<CopyObjectCommandInput>): Promise<void>;
|
|
10
|
+
listObjects(props: InputWithoutBucket<ListObjectsV2CommandInput>): Promise<{
|
|
11
|
+
Contents: _Object[];
|
|
12
|
+
}>;
|
|
13
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getBucketInformation = void 0;
|
|
4
|
+
const bucket_1 = require("../../main/bucket");
|
|
5
|
+
const getBucketInformation = (bucket) => {
|
|
6
|
+
const bucketProps = Reflect.getMetadata(bucket_1.BucketMetadataKeys.bucket, bucket);
|
|
7
|
+
return bucketProps;
|
|
8
|
+
};
|
|
9
|
+
exports.getBucketInformation = getBucketInformation;
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lafken/bucket",
|
|
3
|
+
"version": "0.10.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Define S3 buckets using TypeScript decorators - automatic infrastructure generation with Lafken",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"aws",
|
|
8
|
+
"s3",
|
|
9
|
+
"storage",
|
|
10
|
+
"object storage",
|
|
11
|
+
"serverless",
|
|
12
|
+
"typescript",
|
|
13
|
+
"decorators",
|
|
14
|
+
"lafken"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/Hero64/lafken#readme",
|
|
17
|
+
"bugs": "https://github.com/Hero64/lafken/issues",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/Hero64/lafken",
|
|
21
|
+
"directory": "packages/bucket"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"author": "Aníbal Jorquera",
|
|
25
|
+
"exports": {
|
|
26
|
+
"./main": {
|
|
27
|
+
"types": "./lib/main/index.d.ts",
|
|
28
|
+
"import": "./lib/main/index.js",
|
|
29
|
+
"require": "./lib/main/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./service": {
|
|
32
|
+
"types": "./lib/service/index.d.ts",
|
|
33
|
+
"import": "./lib/service/index.js",
|
|
34
|
+
"require": "./lib/service/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./resolver": {
|
|
37
|
+
"types": "./lib/resolver/index.d.ts",
|
|
38
|
+
"import": "./lib/resolver/index.js",
|
|
39
|
+
"require": "./lib/resolver/index.js"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"typesVersions": {
|
|
43
|
+
"*": {
|
|
44
|
+
"main": [
|
|
45
|
+
"./lib/main/index.d.ts"
|
|
46
|
+
],
|
|
47
|
+
"service": [
|
|
48
|
+
"./lib/service/index.d.ts"
|
|
49
|
+
],
|
|
50
|
+
"resolver": [
|
|
51
|
+
"./lib/resolver/index.d.ts"
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"files": [
|
|
56
|
+
"lib"
|
|
57
|
+
],
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"aws-xray-sdk": "^3.12.0",
|
|
60
|
+
"reflect-metadata": "^0.2.2",
|
|
61
|
+
"@lafken/resolver": "0.10.1"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@aws-sdk/client-s3": "^3.1020.0",
|
|
65
|
+
"@cdktn/provider-aws": "^23.5.0",
|
|
66
|
+
"@swc/core": "^1.15.21",
|
|
67
|
+
"@swc/helpers": "^0.5.20",
|
|
68
|
+
"@vitest/runner": "^4.1.2",
|
|
69
|
+
"cdktn": "^0.22.1",
|
|
70
|
+
"cdktn-vitest": "^1.0.0",
|
|
71
|
+
"constructs": "^10.6.0",
|
|
72
|
+
"typescript": "6.0.2",
|
|
73
|
+
"unplugin-swc": "^1.5.9",
|
|
74
|
+
"vitest": "^4.1.2",
|
|
75
|
+
"@lafken/common": "0.10.1"
|
|
76
|
+
},
|
|
77
|
+
"peerDependencies": {
|
|
78
|
+
"@cdktn/provider-aws": ">=23.0.0",
|
|
79
|
+
"cdktn": ">=0.22.0",
|
|
80
|
+
"constructs": "^10.4.5",
|
|
81
|
+
"@lafken/common": "0.10.1"
|
|
82
|
+
},
|
|
83
|
+
"engines": {
|
|
84
|
+
"node": ">=20.19"
|
|
85
|
+
},
|
|
86
|
+
"publishConfig": {
|
|
87
|
+
"access": "public"
|
|
88
|
+
},
|
|
89
|
+
"scripts": {
|
|
90
|
+
"build": "pnpm clean && tsc -p ./tsconfig.build.json",
|
|
91
|
+
"check-types": "tsc --noEmit -p ./tsconfig.build.json",
|
|
92
|
+
"clean": "rm -rf ./lib",
|
|
93
|
+
"dev": "tsc -w",
|
|
94
|
+
"test": "vitest"
|
|
95
|
+
}
|
|
96
|
+
}
|