@flink-app/s3-plugin 0.12.1-alpha.9 → 0.13.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/CHANGELOG.md +20 -0
- package/dist/index.js +4 -2
- package/dist/s3Client.d.ts +0 -2
- package/dist/s3Client.js +4 -2
- package/dist/schemas/s3ClientOptions.d.ts +2 -0
- package/dist/schemas/s3PluginOptions.d.ts +2 -0
- package/package.json +30 -33
- package/readme.md +275 -31
- package/src/index.ts +2 -0
- package/src/s3Client.ts +2 -0
- package/src/schemas/s3ClientOptions.ts +2 -0
- package/src/schemas/s3PluginOptions.ts +2 -0
- package/tsconfig.json +1 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# @flink-app/s3-plugin
|
|
2
|
+
|
|
3
|
+
## 0.13.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fixed invalid types and improve typescript error message during schema compilation
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @flink-app/flink@0.13.1
|
|
10
|
+
|
|
11
|
+
## 0.13.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- Migrate to pnpm and streamlines build process.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies
|
|
20
|
+
- @flink-app/flink@0.13.0
|
package/dist/index.js
CHANGED
|
@@ -35,8 +35,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
35
35
|
});
|
|
36
36
|
};
|
|
37
37
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
38
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
39
|
-
return g =
|
|
38
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
39
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
40
40
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
41
41
|
function step(op) {
|
|
42
42
|
if (f) throw new TypeError("Generator is already executing.");
|
|
@@ -79,6 +79,8 @@ var s3Plugin = function (options) {
|
|
|
79
79
|
bucket: options.bucket,
|
|
80
80
|
s3Acl: options.s3Acl,
|
|
81
81
|
endpoint: options.endpoint,
|
|
82
|
+
signatureVersion: options.signatureVersion,
|
|
83
|
+
region: options.region,
|
|
82
84
|
});
|
|
83
85
|
return {
|
|
84
86
|
id: "s3Plugin",
|
package/dist/s3Client.d.ts
CHANGED
package/dist/s3Client.js
CHANGED
|
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
-
return g =
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
14
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
15
|
function step(op) {
|
|
16
16
|
if (f) throw new TypeError("Generator is already executing.");
|
|
@@ -57,6 +57,8 @@ var S3Client = /** @class */ (function () {
|
|
|
57
57
|
},
|
|
58
58
|
// @ts-ignore
|
|
59
59
|
endpoint: this.s3Endpoint ? new aws_sdk_1.default.Endpoint(this.s3Endpoint) : undefined,
|
|
60
|
+
signatureVersion: options.signatureVersion,
|
|
61
|
+
region: options.region,
|
|
60
62
|
});
|
|
61
63
|
}
|
|
62
64
|
S3Client.prototype.checkIfExists = function (fileName) {
|
package/package.json
CHANGED
|
@@ -1,34 +1,31 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
"gitHead": "3007ad036607014176930446fde56203bde8d6f5"
|
|
34
|
-
}
|
|
2
|
+
"name": "@flink-app/s3-plugin",
|
|
3
|
+
"version": "0.13.1",
|
|
4
|
+
"description": "Flink plugin to work with s3",
|
|
5
|
+
"author": "johan@frost.se",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@types/mime-types": "^2.1.1",
|
|
14
|
+
"aws-sdk": "^2.1117.0",
|
|
15
|
+
"express-fileupload": "^1.3.1",
|
|
16
|
+
"mime-types": "^2.1.35",
|
|
17
|
+
"node-color-log": "^5.3.1",
|
|
18
|
+
"@flink-app/flink": "0.13.1"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/express-fileupload": "^1.2.2",
|
|
22
|
+
"@types/node": "22.13.10",
|
|
23
|
+
"@types/uuid": "^8.3.4"
|
|
24
|
+
},
|
|
25
|
+
"gitHead": "4243e3b3cd6d4e1ca001a61baa8436bf2bbe4113",
|
|
26
|
+
"scripts": {
|
|
27
|
+
"test": "echo \"Error: no test specified\"",
|
|
28
|
+
"build": "tsc",
|
|
29
|
+
"clean": "rimraf dist .flink"
|
|
30
|
+
}
|
|
31
|
+
}
|
package/readme.md
CHANGED
|
@@ -1,57 +1,301 @@
|
|
|
1
|
-
#
|
|
1
|
+
# S3 Plugin
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A Flink plugin for AWS S3 integration, providing file storage, upload, and management operations. Works with AWS S3 and S3-compatible services.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @flink-app/s3-plugin
|
|
9
|
+
```
|
|
6
10
|
|
|
7
11
|
## Usage
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
Add and configure the plugin in your app startup:
|
|
10
14
|
|
|
15
|
+
```typescript
|
|
16
|
+
import { s3Plugin } from "@flink-app/s3-plugin";
|
|
17
|
+
import { FlinkApp } from "@flink-app/flink";
|
|
18
|
+
import AppContext from "./ApplicationContext";
|
|
19
|
+
|
|
20
|
+
async function start() {
|
|
21
|
+
await new FlinkApp<AppContext>({
|
|
22
|
+
name: "My app",
|
|
23
|
+
plugins: [
|
|
24
|
+
s3Plugin({
|
|
25
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
26
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
27
|
+
bucket: "my-bucket-name",
|
|
28
|
+
region: "us-east-1",
|
|
29
|
+
s3Acl: "public-read",
|
|
30
|
+
enableUpload: true,
|
|
31
|
+
uploadUrl: "/file-upload",
|
|
32
|
+
maxFileSize: 10, // MB
|
|
33
|
+
uploadPermissionRequired: "authenticated",
|
|
34
|
+
}),
|
|
35
|
+
],
|
|
36
|
+
}).start();
|
|
37
|
+
}
|
|
11
38
|
```
|
|
12
|
-
|
|
39
|
+
|
|
40
|
+
Add the plugin context to your application context:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { s3PluginContext } from "@flink-app/s3-plugin";
|
|
44
|
+
import { FlinkContext } from "@flink-app/flink";
|
|
45
|
+
|
|
46
|
+
interface ApplicationContext extends FlinkContext<s3PluginContext> {
|
|
47
|
+
// your context here
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default ApplicationContext;
|
|
13
51
|
```
|
|
14
52
|
|
|
15
|
-
|
|
53
|
+
## Configuration Options
|
|
16
54
|
|
|
55
|
+
```typescript
|
|
56
|
+
interface s3PluginOptions {
|
|
57
|
+
accessKeyId: string; // AWS access key ID (required)
|
|
58
|
+
secretAccessKey: string; // AWS secret access key (required)
|
|
59
|
+
bucket: string; // S3 bucket name (required)
|
|
60
|
+
s3Acl?: string; // Access control list (e.g., "public-read", "private")
|
|
61
|
+
endpoint?: string; // Custom S3 endpoint (for S3-compatible services)
|
|
62
|
+
signatureVersion?: string; // AWS signature version
|
|
63
|
+
region?: string; // AWS region (e.g., "us-east-1")
|
|
64
|
+
enableUpload: boolean; // Enable file upload endpoint (required)
|
|
65
|
+
uploadUrl?: string; // Custom upload endpoint path (default: "/file-upload")
|
|
66
|
+
maxFileSize?: number; // Max file size in MB (default: 10)
|
|
67
|
+
uploadPermissionRequired?: string; // Permission required for uploads
|
|
68
|
+
}
|
|
17
69
|
```
|
|
18
|
-
import { s3Plugin } from "@flink-app/s3-plugin";
|
|
19
70
|
|
|
71
|
+
## Built-in Upload Endpoint
|
|
20
72
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
73
|
+
When `enableUpload` is set to `true`, the plugin registers a file upload endpoint:
|
|
74
|
+
|
|
75
|
+
### POST /file-upload (or custom uploadUrl)
|
|
76
|
+
|
|
77
|
+
Upload a file using multipart form data:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
curl -X POST http://localhost:3333/file-upload?path=images/ \
|
|
81
|
+
-F "file=@photo.jpg" \
|
|
82
|
+
-H "Authorization: Bearer <token>"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Query Parameters:**
|
|
86
|
+
- `path` (optional): S3 path prefix for the uploaded file
|
|
87
|
+
|
|
88
|
+
**Response:**
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"status": 200,
|
|
92
|
+
"data": {
|
|
93
|
+
"url": "https://my-bucket.s3.amazonaws.com/images/photo-1234567890.jpg"
|
|
94
|
+
}
|
|
35
95
|
}
|
|
36
96
|
```
|
|
37
97
|
|
|
38
|
-
|
|
98
|
+
**Permission Protection:**
|
|
99
|
+
Set `uploadPermissionRequired` to require authentication:
|
|
100
|
+
```typescript
|
|
101
|
+
s3Plugin({
|
|
102
|
+
// ...
|
|
103
|
+
enableUpload: true,
|
|
104
|
+
uploadPermissionRequired: "authenticated", // or any custom permission
|
|
105
|
+
})
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## S3Client API
|
|
109
|
+
|
|
110
|
+
Access the S3 client from your handlers:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import { Handler } from "@flink-app/flink";
|
|
114
|
+
import AppContext from "../ApplicationContext";
|
|
115
|
+
|
|
116
|
+
const UploadFile: Handler<AppContext, UploadReq, UploadRes> = async ({ ctx, req }) => {
|
|
117
|
+
const s3Client = ctx.plugins.s3Plugin.s3Client;
|
|
118
|
+
|
|
119
|
+
// Your S3 operations here
|
|
120
|
+
};
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Available Methods
|
|
124
|
+
|
|
125
|
+
#### uploadFile(fileName, data, mime)
|
|
126
|
+
Upload a file to S3.
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
const url = await ctx.plugins.s3Plugin.s3Client.uploadFile(
|
|
130
|
+
"documents/report.pdf",
|
|
131
|
+
fileBuffer,
|
|
132
|
+
"application/pdf"
|
|
133
|
+
);
|
|
39
134
|
```
|
|
40
|
-
import { s3PluginContext } from "@flink-app/s3-plugin"
|
|
41
|
-
export interface Ctx extends FlinkContext<s3PluginContext> {
|
|
42
135
|
|
|
136
|
+
#### getObject(key)
|
|
137
|
+
Retrieve a file from S3.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
const file = await ctx.plugins.s3Plugin.s3Client.getObject("documents/report.pdf");
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### getObjects()
|
|
144
|
+
List all objects in the bucket.
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
const objects = await ctx.plugins.s3Plugin.s3Client.getObjects();
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### deleteObject(file, version?)
|
|
151
|
+
Delete a single object.
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
await ctx.plugins.s3Plugin.s3Client.deleteObject("documents/old-report.pdf");
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### deleteObjects(files)
|
|
158
|
+
Bulk delete multiple objects.
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
await ctx.plugins.s3Plugin.s3Client.deleteObjects([
|
|
162
|
+
"file1.jpg",
|
|
163
|
+
"file2.jpg",
|
|
164
|
+
"file3.jpg",
|
|
165
|
+
]);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### getSignedUrl(key, expires)
|
|
169
|
+
Generate a temporary signed URL for private objects.
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
const signedUrl = await ctx.plugins.s3Plugin.s3Client.getSignedUrl(
|
|
173
|
+
"private/document.pdf",
|
|
174
|
+
3600 // expires in seconds
|
|
175
|
+
);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
#### checkIfExists(fileName)
|
|
179
|
+
Check if a file exists in the bucket.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
const exists = await ctx.plugins.s3Plugin.s3Client.checkIfExists("documents/report.pdf");
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Complete Example
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import { Handler } from "@flink-app/flink";
|
|
189
|
+
import AppContext from "../ApplicationContext";
|
|
190
|
+
|
|
191
|
+
interface UploadDocumentReq {
|
|
192
|
+
fileName: string;
|
|
193
|
+
fileData: string; // base64 encoded
|
|
194
|
+
mimeType: string;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
interface UploadDocumentRes {
|
|
198
|
+
url: string;
|
|
199
|
+
exists: boolean;
|
|
43
200
|
}
|
|
201
|
+
|
|
202
|
+
export const Route = {
|
|
203
|
+
path: "/document/upload",
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const UploadDocument: Handler<AppContext, UploadDocumentReq, UploadDocumentRes> = async ({ ctx, req }) => {
|
|
207
|
+
const { fileName, fileData, mimeType } = req.body;
|
|
208
|
+
const s3Client = ctx.plugins.s3Plugin.s3Client;
|
|
209
|
+
|
|
210
|
+
// Check if file already exists
|
|
211
|
+
const exists = await s3Client.checkIfExists(fileName);
|
|
212
|
+
|
|
213
|
+
if (exists) {
|
|
214
|
+
return {
|
|
215
|
+
status: 409,
|
|
216
|
+
data: {
|
|
217
|
+
url: "",
|
|
218
|
+
exists: true,
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Upload file
|
|
224
|
+
const buffer = Buffer.from(fileData, "base64");
|
|
225
|
+
const url = await s3Client.uploadFile(fileName, buffer, mimeType);
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
status: 200,
|
|
229
|
+
data: {
|
|
230
|
+
url,
|
|
231
|
+
exists: false,
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
export default UploadDocument;
|
|
44
237
|
```
|
|
45
238
|
|
|
239
|
+
## S3-Compatible Services
|
|
46
240
|
|
|
241
|
+
This plugin works with S3-compatible services like MinIO, DigitalOcean Spaces, etc.:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
s3Plugin({
|
|
245
|
+
accessKeyId: "your-key",
|
|
246
|
+
secretAccessKey: "your-secret",
|
|
247
|
+
bucket: "my-bucket",
|
|
248
|
+
endpoint: "https://nyc3.digitaloceanspaces.com", // Custom endpoint
|
|
249
|
+
region: "nyc3",
|
|
250
|
+
s3Acl: "public-read",
|
|
251
|
+
enableUpload: true,
|
|
252
|
+
})
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Access Control Lists (ACL)
|
|
256
|
+
|
|
257
|
+
Common ACL values:
|
|
258
|
+
- `private`: Owner gets full control, no one else has access
|
|
259
|
+
- `public-read`: Owner gets full control, public gets read access
|
|
260
|
+
- `public-read-write`: Owner gets full control, public gets read/write access
|
|
261
|
+
- `authenticated-read`: Owner gets full control, authenticated users get read access
|
|
262
|
+
|
|
263
|
+
## Environment Variables
|
|
264
|
+
|
|
265
|
+
Recommended setup using environment variables:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
AWS_ACCESS_KEY_ID=your-access-key-id
|
|
269
|
+
AWS_SECRET_ACCESS_KEY=your-secret-access-key
|
|
270
|
+
AWS_REGION=us-east-1
|
|
271
|
+
S3_BUCKET=my-bucket-name
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
s3Plugin({
|
|
276
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
|
|
277
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
|
|
278
|
+
bucket: process.env.S3_BUCKET!,
|
|
279
|
+
region: process.env.AWS_REGION,
|
|
280
|
+
s3Acl: "public-read",
|
|
281
|
+
enableUpload: true,
|
|
282
|
+
})
|
|
283
|
+
```
|
|
47
284
|
|
|
48
|
-
##
|
|
49
|
-
Set `enableUpload = true` to enable the /file-upload endpoint.
|
|
50
|
-
Post a multipart file upload to that endpoint to upload the file to S3.
|
|
51
|
-
Protect this route by specifying the required permission by specifying `uploadPermissionRequired` property to the required permission. Eg. `uploadPermissionRequired="authenticated"` setting.
|
|
285
|
+
## Features
|
|
52
286
|
|
|
287
|
+
- ✅ AWS S3 integration
|
|
288
|
+
- ✅ S3-compatible service support
|
|
289
|
+
- ✅ Built-in file upload endpoint
|
|
290
|
+
- ✅ Permission-based access control
|
|
291
|
+
- ✅ Multipart file upload support
|
|
292
|
+
- ✅ File size limits
|
|
293
|
+
- ✅ Signed URL generation
|
|
294
|
+
- ✅ Bulk operations
|
|
295
|
+
- ✅ File existence checking
|
|
53
296
|
|
|
54
|
-
##
|
|
55
|
-
From your handlers, access the s3Client by `ctx.plugins.s3Plugin.s3Client`.
|
|
56
|
-
You will find methods for upload, delete and so on.
|
|
297
|
+
## Requirements
|
|
57
298
|
|
|
299
|
+
- AWS account with S3 access (or S3-compatible service)
|
|
300
|
+
- Valid AWS credentials (access key ID and secret access key)
|
|
301
|
+
- S3 bucket created and accessible
|
package/src/index.ts
CHANGED
package/src/s3Client.ts
CHANGED