@lowdefy/plugin-aws 0.0.0-experimental-20260720135014 → 0.0.0-experimental-20260722143027
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/blocks/S3Download/S3Download.js +12 -54
- package/dist/blocks/S3UploadButton/S3UploadButton.js +19 -79
- package/dist/blocks/S3UploadDragger/S3UploadDragger.js +19 -92
- package/dist/blocks/S3UploadPhoto/S3UploadPhoto.js +19 -93
- package/dist/connections/AwsS3Bucket/AwsS3Bucket.js +6 -2
- package/dist/connections/AwsS3Bucket/AwsS3GetObject/AwsS3GetObject.js +54 -0
- package/dist/connections/AwsS3Bucket/AwsS3GetObject/schema.js +42 -0
- package/dist/connections/AwsS3Bucket/AwsS3PresignedGetObject/AwsS3PresignedGetObject.js +11 -8
- package/dist/connections/AwsS3Bucket/AwsS3PresignedGetObject/schema.js +8 -0
- package/dist/connections/AwsS3Bucket/AwsS3PresignedPostPolicy/AwsS3PresignedPostPolicy.js +16 -12
- package/dist/connections/AwsS3Bucket/AwsS3PutObject/AwsS3PutObject.js +48 -0
- package/dist/connections/AwsS3Bucket/AwsS3PutObject/schema.js +70 -0
- package/dist/connections/AwsS3Bucket/createS3Client.js +34 -0
- package/dist/connections/AwsS3Bucket/getPublicUrl.js +30 -0
- package/dist/connections/AwsS3Bucket/schema.js +21 -0
- package/dist/types.js +3 -1
- package/package.json +18 -15
- package/dist/blocks/S3UploadDragger/style.module.css +0 -30
- package/dist/blocks/utils/getOnPaste.js +0 -48
- package/dist/blocks/utils/getS3Upload.js +0 -92
- package/dist/blocks/utils/useFileList.js +0 -138
- package/dist/blocks/withTheme.js +0 -40
|
@@ -13,62 +13,20 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import React, { useEffect } from 'react';
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const s3DownloadPolicy = await methods.triggerEvent({
|
|
21
|
-
name: '__getS3DownloadPolicy',
|
|
22
|
-
event: {
|
|
23
|
-
file
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
window.open(s3DownloadPolicy?.responses?.__getS3DownloadPolicy?.response?.[0]);
|
|
27
|
-
};
|
|
28
|
-
const S3Download = ({ blockId, classNames = {}, methods, properties, styles = {} })=>{
|
|
16
|
+
import { Download } from '@lowdefy/blocks-files/blocks';
|
|
17
|
+
// Deprecated alias for the generic Download block in @lowdefy/blocks-files.
|
|
18
|
+
// Maps the legacy s3GetPolicyRequestId property onto downloadPolicyRequestId.
|
|
19
|
+
const S3Download = (props)=>{
|
|
29
20
|
useEffect(()=>{
|
|
30
|
-
|
|
31
|
-
name: '__getS3DownloadPolicy',
|
|
32
|
-
actions: [
|
|
33
|
-
{
|
|
34
|
-
id: '__getS3DownloadPolicy',
|
|
35
|
-
type: 'Request',
|
|
36
|
-
params: [
|
|
37
|
-
properties.s3GetPolicyRequestId
|
|
38
|
-
]
|
|
39
|
-
}
|
|
40
|
-
]
|
|
41
|
-
});
|
|
21
|
+
console.warn('The S3Download block is deprecated. Use the Download block with "downloadPolicyRequestId" instead.');
|
|
42
22
|
}, []);
|
|
43
|
-
const
|
|
44
|
-
return /*#__PURE__*/ React.createElement(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
onPreview: async (file)=>await downloadFile({
|
|
50
|
-
file,
|
|
51
|
-
methods
|
|
52
|
-
}),
|
|
53
|
-
onDownload: async (file)=>await downloadFile({
|
|
54
|
-
file,
|
|
55
|
-
methods
|
|
56
|
-
}),
|
|
57
|
-
onRemove: (file)=>{
|
|
58
|
-
methods.triggerEvent({
|
|
59
|
-
name: 'onRemove',
|
|
60
|
-
event: {
|
|
61
|
-
file
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
// Controlled fileList: the YAML handler decides whether to update state.
|
|
65
|
-
// Return false so antd doesn't fire onChange with a removed-file list.
|
|
66
|
-
return false;
|
|
67
|
-
},
|
|
68
|
-
showUploadList: {
|
|
69
|
-
showDownloadIcon: true,
|
|
70
|
-
showRemoveIcon
|
|
23
|
+
const { s3GetPolicyRequestId, ...properties } = props.properties ?? {};
|
|
24
|
+
return /*#__PURE__*/ React.createElement(Download, {
|
|
25
|
+
...props,
|
|
26
|
+
properties: {
|
|
27
|
+
downloadPolicyRequestId: s3GetPolicyRequestId,
|
|
28
|
+
...properties
|
|
71
29
|
}
|
|
72
30
|
});
|
|
73
31
|
};
|
|
74
|
-
export default
|
|
32
|
+
export default S3Download;
|
|
@@ -13,88 +13,28 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import React, { useEffect } from 'react';
|
|
16
|
-
import { cn
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const [state, loadFileList, setFileList, removeFile, setValue] = useFileList({
|
|
24
|
-
properties,
|
|
25
|
-
methods,
|
|
26
|
-
value
|
|
27
|
-
});
|
|
28
|
-
const s3UploadRequest = getS3Upload({
|
|
29
|
-
methods,
|
|
30
|
-
setFileList
|
|
31
|
-
});
|
|
16
|
+
import { cn } from '@lowdefy/block-utils';
|
|
17
|
+
import { Upload } from '@lowdefy/blocks-files/blocks';
|
|
18
|
+
// Deprecated alias for the generic Upload block in @lowdefy/blocks-files.
|
|
19
|
+
// Maps the legacy s3PostPolicyRequestId property onto uploadPolicyRequestId
|
|
20
|
+
// and keeps the legacy element class so existing app CSS targeting the S3
|
|
21
|
+
// block name keeps matching.
|
|
22
|
+
const S3UploadButton = (props)=>{
|
|
32
23
|
useEffect(()=>{
|
|
33
|
-
|
|
34
|
-
file: null,
|
|
35
|
-
fileList: []
|
|
36
|
-
});
|
|
37
|
-
methods.registerEvent({
|
|
38
|
-
name: '__getS3PostPolicy',
|
|
39
|
-
actions: [
|
|
40
|
-
{
|
|
41
|
-
id: '__getS3PostPolicy',
|
|
42
|
-
type: 'Request',
|
|
43
|
-
params: [
|
|
44
|
-
properties.s3PostPolicyRequestId
|
|
45
|
-
]
|
|
46
|
-
}
|
|
47
|
-
]
|
|
48
|
-
});
|
|
24
|
+
console.warn('The S3UploadButton block is deprecated. Use the Upload block with "uploadPolicyRequestId" instead.');
|
|
49
25
|
}, []);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}, [
|
|
55
|
-
value
|
|
56
|
-
]);
|
|
57
|
-
return /*#__PURE__*/ React.createElement("div", {
|
|
58
|
-
id: blockId,
|
|
59
|
-
className: cn('lf-s3-upload-button', classNames.element),
|
|
60
|
-
style: styles.element
|
|
61
|
-
}, /*#__PURE__*/ React.createElement(Upload, {
|
|
62
|
-
accept: properties.accept ?? '*',
|
|
63
|
-
beforeUpload: loadFileList,
|
|
26
|
+
const { s3PostPolicyRequestId, ...properties } = props.properties ?? {};
|
|
27
|
+
const classNames = props.classNames ?? {};
|
|
28
|
+
return /*#__PURE__*/ React.createElement(Upload, {
|
|
29
|
+
...props,
|
|
64
30
|
classNames: {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
item: classNames.item
|
|
68
|
-
},
|
|
69
|
-
styles: {
|
|
70
|
-
trigger: styles.trigger,
|
|
71
|
-
list: styles.list,
|
|
72
|
-
item: styles.item
|
|
31
|
+
...classNames,
|
|
32
|
+
element: cn('lf-s3-upload-button', classNames.element)
|
|
73
33
|
},
|
|
74
|
-
customRequest: s3UploadRequest,
|
|
75
|
-
disabled: properties.disabled,
|
|
76
|
-
fileList: state.fileList,
|
|
77
|
-
maxCount: properties.maxCount,
|
|
78
|
-
multiple: !properties.singleFile,
|
|
79
|
-
onRemove: removeFile,
|
|
80
|
-
showUploadList: properties.showUploadList,
|
|
81
|
-
onChange: ()=>{
|
|
82
|
-
methods.triggerEvent({
|
|
83
|
-
name: 'onChange'
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}, /*#__PURE__*/ React.createElement(Button, {
|
|
87
|
-
blockId: `${blockId}_button`,
|
|
88
|
-
components: components,
|
|
89
|
-
events: events,
|
|
90
34
|
properties: {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
...properties.button
|
|
96
|
-
},
|
|
97
|
-
methods: methods
|
|
98
|
-
})));
|
|
35
|
+
uploadPolicyRequestId: s3PostPolicyRequestId,
|
|
36
|
+
...properties
|
|
37
|
+
}
|
|
38
|
+
});
|
|
99
39
|
};
|
|
100
|
-
export default
|
|
40
|
+
export default S3UploadButton;
|
|
@@ -13,101 +13,28 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import React, { useEffect } from 'react';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
import './style.module.css';
|
|
24
|
-
const { Dragger } = Upload;
|
|
25
|
-
const S3UploadDragger = ({ blockId, classNames = {}, methods, properties, styles = {}, value })=>{
|
|
26
|
-
const [state, loadFileList, setFileList, removeFile, setValue] = useFileList({
|
|
27
|
-
properties,
|
|
28
|
-
methods,
|
|
29
|
-
value
|
|
30
|
-
});
|
|
31
|
-
const s3UploadRequest = getS3Upload({
|
|
32
|
-
methods,
|
|
33
|
-
setFileList
|
|
34
|
-
});
|
|
35
|
-
const onPaste = getOnPaste({
|
|
36
|
-
s3UploadRequest,
|
|
37
|
-
properties
|
|
38
|
-
});
|
|
16
|
+
import { cn } from '@lowdefy/block-utils';
|
|
17
|
+
import { UploadDragger } from '@lowdefy/blocks-files/blocks';
|
|
18
|
+
// Deprecated alias for the generic UploadDragger block in @lowdefy/blocks-files.
|
|
19
|
+
// Maps the legacy s3PostPolicyRequestId property onto uploadPolicyRequestId
|
|
20
|
+
// and keeps the legacy element class so existing app CSS targeting the S3
|
|
21
|
+
// block name keeps matching.
|
|
22
|
+
const S3UploadDragger = (props)=>{
|
|
39
23
|
useEffect(()=>{
|
|
40
|
-
|
|
41
|
-
name: '__getS3PostPolicy',
|
|
42
|
-
actions: [
|
|
43
|
-
{
|
|
44
|
-
id: '__getS3PostPolicy',
|
|
45
|
-
type: 'Request',
|
|
46
|
-
params: [
|
|
47
|
-
properties.s3PostPolicyRequestId
|
|
48
|
-
]
|
|
49
|
-
}
|
|
50
|
-
]
|
|
51
|
-
});
|
|
24
|
+
console.warn('The S3UploadDragger block is deprecated. Use the UploadDragger block with "uploadPolicyRequestId" instead.');
|
|
52
25
|
}, []);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}, [
|
|
58
|
-
value
|
|
59
|
-
]);
|
|
60
|
-
useEffect(()=>{
|
|
61
|
-
methods.registerMethod('uploadFromPaste', async ()=>{
|
|
62
|
-
await onPaste();
|
|
63
|
-
});
|
|
64
|
-
}, [
|
|
65
|
-
onPaste
|
|
66
|
-
]);
|
|
67
|
-
const { token } = antdTheme.useToken();
|
|
68
|
-
const height = type.isNone(properties.height) ? token.controlHeight : properties.height;
|
|
69
|
-
return /*#__PURE__*/ React.createElement("div", {
|
|
70
|
-
id: blockId,
|
|
71
|
-
className: cn('lf-s3-upload-dragger', classNames.element),
|
|
72
|
-
onPaste: onPaste,
|
|
73
|
-
style: {
|
|
74
|
-
'--lf-s3-dragger-height': type.isNumber(height) ? `${height}px` : height,
|
|
75
|
-
...styles.element
|
|
76
|
-
}
|
|
77
|
-
}, /*#__PURE__*/ React.createElement(Dragger, {
|
|
78
|
-
accept: properties.accept ?? '*',
|
|
79
|
-
beforeUpload: loadFileList,
|
|
26
|
+
const { s3PostPolicyRequestId, ...properties } = props.properties ?? {};
|
|
27
|
+
const classNames = props.classNames ?? {};
|
|
28
|
+
return /*#__PURE__*/ React.createElement(UploadDragger, {
|
|
29
|
+
...props,
|
|
80
30
|
classNames: {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
item: classNames.item
|
|
31
|
+
...classNames,
|
|
32
|
+
element: cn('lf-s3-upload-dragger', classNames.element)
|
|
84
33
|
},
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
},
|
|
89
|
-
trigger: styles.trigger,
|
|
90
|
-
list: styles.list,
|
|
91
|
-
item: styles.item
|
|
92
|
-
},
|
|
93
|
-
customRequest: s3UploadRequest,
|
|
94
|
-
disabled: properties.disabled,
|
|
95
|
-
fileList: state.fileList,
|
|
96
|
-
maxCount: properties.maxCount,
|
|
97
|
-
multiple: !properties.singleFile,
|
|
98
|
-
onRemove: removeFile,
|
|
99
|
-
showUploadList: properties.showUploadList,
|
|
100
|
-
onChange: ()=>{
|
|
101
|
-
methods.triggerEvent({
|
|
102
|
-
name: 'onChange'
|
|
103
|
-
});
|
|
34
|
+
properties: {
|
|
35
|
+
uploadPolicyRequestId: s3PostPolicyRequestId,
|
|
36
|
+
...properties
|
|
104
37
|
}
|
|
105
|
-
}
|
|
106
|
-
className: cn(classNames.hint),
|
|
107
|
-
style: styles.hint
|
|
108
|
-
}, renderHtml({
|
|
109
|
-
html: properties.title ?? 'Click or drag to add a file.',
|
|
110
|
-
methods
|
|
111
|
-
}))));
|
|
38
|
+
});
|
|
112
39
|
};
|
|
113
|
-
export default
|
|
40
|
+
export default S3UploadDragger;
|
|
@@ -12,103 +12,29 @@
|
|
|
12
12
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
|
-
*/ import React, { useEffect
|
|
16
|
-
import { cn
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
properties,
|
|
24
|
-
methods,
|
|
25
|
-
value
|
|
26
|
-
});
|
|
27
|
-
const [loading, setLoading] = useState(false);
|
|
28
|
-
const s3UploadRequest = getS3Upload({
|
|
29
|
-
methods,
|
|
30
|
-
setFileList,
|
|
31
|
-
setLoading
|
|
32
|
-
});
|
|
15
|
+
*/ import React, { useEffect } from 'react';
|
|
16
|
+
import { cn } from '@lowdefy/block-utils';
|
|
17
|
+
import { UploadPhoto } from '@lowdefy/blocks-files/blocks';
|
|
18
|
+
// Deprecated alias for the generic UploadPhoto block in @lowdefy/blocks-files.
|
|
19
|
+
// Maps the legacy s3PostPolicyRequestId property onto uploadPolicyRequestId
|
|
20
|
+
// and keeps the legacy element class so existing app CSS targeting the S3
|
|
21
|
+
// block name keeps matching.
|
|
22
|
+
const S3UploadPhoto = (props)=>{
|
|
33
23
|
useEffect(()=>{
|
|
34
|
-
|
|
35
|
-
file: null,
|
|
36
|
-
fileList: []
|
|
37
|
-
});
|
|
38
|
-
methods.registerEvent({
|
|
39
|
-
name: '__getS3PostPolicy',
|
|
40
|
-
actions: [
|
|
41
|
-
{
|
|
42
|
-
id: '__getS3PostPolicy',
|
|
43
|
-
type: 'Request',
|
|
44
|
-
params: [
|
|
45
|
-
properties.s3PostPolicyRequestId
|
|
46
|
-
]
|
|
47
|
-
}
|
|
48
|
-
]
|
|
49
|
-
});
|
|
24
|
+
console.warn('The S3UploadPhoto block is deprecated. Use the UploadPhoto block with "uploadPolicyRequestId" instead.');
|
|
50
25
|
}, []);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}, [
|
|
56
|
-
value
|
|
57
|
-
]);
|
|
58
|
-
return /*#__PURE__*/ React.createElement("div", {
|
|
59
|
-
id: blockId,
|
|
60
|
-
className: cn('lf-s3-upload-photo', classNames.element),
|
|
61
|
-
style: styles.element
|
|
62
|
-
}, /*#__PURE__*/ React.createElement(Upload, {
|
|
63
|
-
accept: "image/*",
|
|
64
|
-
beforeUpload: loadFileList,
|
|
26
|
+
const { s3PostPolicyRequestId, ...properties } = props.properties ?? {};
|
|
27
|
+
const classNames = props.classNames ?? {};
|
|
28
|
+
return /*#__PURE__*/ React.createElement(UploadPhoto, {
|
|
29
|
+
...props,
|
|
65
30
|
classNames: {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
item: classNames.item
|
|
69
|
-
},
|
|
70
|
-
styles: {
|
|
71
|
-
trigger: styles.trigger,
|
|
72
|
-
list: styles.list,
|
|
73
|
-
item: styles.item
|
|
31
|
+
...classNames,
|
|
32
|
+
element: cn('lf-s3-upload-photo', classNames.element)
|
|
74
33
|
},
|
|
75
|
-
customRequest: s3UploadRequest,
|
|
76
|
-
disabled: properties.disabled,
|
|
77
|
-
fileList: state.fileList,
|
|
78
|
-
listType: "picture-card",
|
|
79
|
-
maxCount: properties.maxCount,
|
|
80
|
-
multiple: !properties.singleFile,
|
|
81
|
-
onRemove: removeFile,
|
|
82
|
-
showUploadList: properties.showUploadList,
|
|
83
|
-
onChange: ()=>{
|
|
84
|
-
methods.triggerEvent({
|
|
85
|
-
name: 'onChange'
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
}, /*#__PURE__*/ React.createElement("div", {
|
|
89
|
-
className: "lf-s3-upload-photo-content"
|
|
90
|
-
}, /*#__PURE__*/ React.createElement(Icon, {
|
|
91
|
-
blockId: `${blockId}_icon`,
|
|
92
|
-
classNames: {
|
|
93
|
-
element: cn('lf-s3-upload-photo-icon', classNames.icon)
|
|
94
|
-
},
|
|
95
|
-
events: events,
|
|
96
34
|
properties: {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
},
|
|
100
|
-
styles: {
|
|
101
|
-
element: styles.icon
|
|
35
|
+
uploadPolicyRequestId: s3PostPolicyRequestId,
|
|
36
|
+
...properties
|
|
102
37
|
}
|
|
103
|
-
})
|
|
104
|
-
className: cn('lf-s3-upload-photo-title', classNames.title),
|
|
105
|
-
style: {
|
|
106
|
-
marginTop: 8,
|
|
107
|
-
...styles.title
|
|
108
|
-
}
|
|
109
|
-
}, renderHtml({
|
|
110
|
-
html: properties.title ?? 'Upload image',
|
|
111
|
-
methods
|
|
112
|
-
})))));
|
|
38
|
+
});
|
|
113
39
|
};
|
|
114
|
-
export default
|
|
40
|
+
export default S3UploadPhoto;
|
|
@@ -12,13 +12,17 @@
|
|
|
12
12
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
|
-
*/ import
|
|
15
|
+
*/ import AwsS3GetObject from './AwsS3GetObject/AwsS3GetObject.js';
|
|
16
|
+
import AwsS3PresignedGetObject from './AwsS3PresignedGetObject/AwsS3PresignedGetObject.js';
|
|
16
17
|
import AwsS3PresignedPostPolicy from './AwsS3PresignedPostPolicy/AwsS3PresignedPostPolicy.js';
|
|
18
|
+
import AwsS3PutObject from './AwsS3PutObject/AwsS3PutObject.js';
|
|
17
19
|
import schema from './schema.js';
|
|
18
20
|
export default {
|
|
19
21
|
schema,
|
|
20
22
|
requests: {
|
|
23
|
+
AwsS3GetObject,
|
|
21
24
|
AwsS3PresignedGetObject,
|
|
22
|
-
AwsS3PresignedPostPolicy
|
|
25
|
+
AwsS3PresignedPostPolicy,
|
|
26
|
+
AwsS3PutObject
|
|
23
27
|
}
|
|
24
28
|
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { GetObjectCommand } from '@aws-sdk/client-s3';
|
|
16
|
+
import { type } from '@lowdefy/helpers';
|
|
17
|
+
import createS3Client from '../createS3Client.js';
|
|
18
|
+
import schema from './schema.js';
|
|
19
|
+
// Server-side read: returns the object content as a base64 string so routine
|
|
20
|
+
// steps can process it with operators and pass it to other steps (base64
|
|
21
|
+
// survives JSON serialization; consumers decode with Buffer.from(content, 'base64')).
|
|
22
|
+
async function AwsS3GetObject({ request, connection }) {
|
|
23
|
+
const { bucket } = connection;
|
|
24
|
+
const { key, versionId } = request;
|
|
25
|
+
const params = {
|
|
26
|
+
Bucket: bucket,
|
|
27
|
+
Key: key
|
|
28
|
+
};
|
|
29
|
+
if (versionId) {
|
|
30
|
+
params.VersionId = versionId;
|
|
31
|
+
}
|
|
32
|
+
const s3 = createS3Client({
|
|
33
|
+
connection
|
|
34
|
+
});
|
|
35
|
+
const response = await s3.send(new GetObjectCommand(params));
|
|
36
|
+
const buffer = Buffer.from(await response.Body.transformToByteArray());
|
|
37
|
+
const result = {
|
|
38
|
+
bucket,
|
|
39
|
+
key,
|
|
40
|
+
content: buffer.toString('base64'),
|
|
41
|
+
// Derived from the returned content so it always matches, byte for byte.
|
|
42
|
+
size: buffer.length
|
|
43
|
+
};
|
|
44
|
+
if (!type.isNone(response.ContentType)) {
|
|
45
|
+
result.contentType = response.ContentType;
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
AwsS3GetObject.schema = schema;
|
|
50
|
+
AwsS3GetObject.meta = {
|
|
51
|
+
checkRead: true,
|
|
52
|
+
checkWrite: false
|
|
53
|
+
};
|
|
54
|
+
export default AwsS3GetObject;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ export default {
|
|
16
|
+
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
17
|
+
title: 'Lowdefy Request Schema - AwsS3GetObject',
|
|
18
|
+
type: 'object',
|
|
19
|
+
required: [
|
|
20
|
+
'key'
|
|
21
|
+
],
|
|
22
|
+
properties: {
|
|
23
|
+
key: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
description: 'Key under which the object is stored.',
|
|
26
|
+
errorMessage: {
|
|
27
|
+
type: 'AwsS3GetObject request property "key" should be a string.'
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
versionId: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
description: 'VersionId used to reference a specific version of the object.',
|
|
33
|
+
errorMessage: {
|
|
34
|
+
type: 'AwsS3GetObject request property "versionId" should be a string.'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
errorMessage: {
|
|
39
|
+
type: 'AwsS3GetObject request properties should be an object.',
|
|
40
|
+
required: 'AwsS3GetObject request should have required property "key".'
|
|
41
|
+
}
|
|
42
|
+
};
|
|
@@ -12,12 +12,19 @@
|
|
|
12
12
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
|
-
*/ import {
|
|
15
|
+
*/ import { GetObjectCommand } from '@aws-sdk/client-s3';
|
|
16
16
|
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
17
|
+
import createS3Client from '../createS3Client.js';
|
|
18
|
+
import getPublicUrl from '../getPublicUrl.js';
|
|
17
19
|
import schema from './schema.js';
|
|
18
20
|
async function AwsS3PresignedGetObject({ request, connection }) {
|
|
19
|
-
const { accessKeyId, secretAccessKey, region } = connection;
|
|
20
21
|
const { expires, key, versionId, responseContentDisposition, responseContentType } = request;
|
|
22
|
+
if (request.public === true) {
|
|
23
|
+
return getPublicUrl({
|
|
24
|
+
connection,
|
|
25
|
+
key
|
|
26
|
+
});
|
|
27
|
+
}
|
|
21
28
|
const params = {
|
|
22
29
|
Bucket: connection.bucket,
|
|
23
30
|
Key: key,
|
|
@@ -25,12 +32,8 @@ async function AwsS3PresignedGetObject({ request, connection }) {
|
|
|
25
32
|
ResponseContentDisposition: responseContentDisposition,
|
|
26
33
|
ResponseContentType: responseContentType
|
|
27
34
|
};
|
|
28
|
-
const s3 =
|
|
29
|
-
|
|
30
|
-
accessKeyId,
|
|
31
|
-
secretAccessKey
|
|
32
|
-
},
|
|
33
|
-
region
|
|
35
|
+
const s3 = createS3Client({
|
|
36
|
+
connection
|
|
34
37
|
});
|
|
35
38
|
const command = new GetObjectCommand(params);
|
|
36
39
|
return getSignedUrl(s3, command, {
|
|
@@ -35,6 +35,14 @@
|
|
|
35
35
|
type: 'AwsS3PresignedGetObject request property "key" should be a string.'
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
|
+
public: {
|
|
39
|
+
type: 'boolean',
|
|
40
|
+
default: false,
|
|
41
|
+
description: 'Return a stable, non-expiring public URL instead of a signed URL. The object must be publicly readable (e.g. uploaded with acl "public-read") — public is author-declared and never checked at runtime.',
|
|
42
|
+
errorMessage: {
|
|
43
|
+
type: 'AwsS3PresignedGetObject request property "public" should be a boolean.'
|
|
44
|
+
}
|
|
45
|
+
},
|
|
38
46
|
responseContentDisposition: {
|
|
39
47
|
type: 'string',
|
|
40
48
|
description: 'Sets the Content-Disposition header of the response.',
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
|
-
*/ import {
|
|
16
|
-
import { createPresignedPost } from '@aws-sdk/s3-presigned-post';
|
|
17
|
-
import schema from './schema.js';
|
|
15
|
+
*/ import { createPresignedPost } from '@aws-sdk/s3-presigned-post';
|
|
18
16
|
import { type } from '@lowdefy/helpers';
|
|
17
|
+
import createS3Client from '../createS3Client.js';
|
|
18
|
+
import schema from './schema.js';
|
|
19
19
|
async function AwsS3PresignedPostPolicy({ request, connection }) {
|
|
20
|
-
const {
|
|
20
|
+
const { bucket } = connection;
|
|
21
21
|
const { acl, conditions, expires, key, fields = {} } = request;
|
|
22
22
|
const params = {
|
|
23
23
|
Bucket: bucket,
|
|
@@ -34,7 +34,7 @@ async function AwsS3PresignedPostPolicy({ request, connection }) {
|
|
|
34
34
|
params.Fields.acl = acl;
|
|
35
35
|
}
|
|
36
36
|
if (type.isObject(fields) === false) {
|
|
37
|
-
throw new Error(
|
|
37
|
+
throw new Error(`properties.fields must be an object. Received ${JSON.stringify(fields)}.`);
|
|
38
38
|
}
|
|
39
39
|
Object.keys(fields).forEach((field)=>{
|
|
40
40
|
if (fields[field]) {
|
|
@@ -44,14 +44,18 @@ async function AwsS3PresignedPostPolicy({ request, connection }) {
|
|
|
44
44
|
params.Fields[field] = field.toLowerCase().startsWith('x-amz-meta-') ? encodeURIComponent(fields[field]) : fields[field];
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
|
-
const s3 =
|
|
48
|
-
|
|
49
|
-
accessKeyId,
|
|
50
|
-
secretAccessKey
|
|
51
|
-
},
|
|
52
|
-
region
|
|
47
|
+
const s3 = createS3Client({
|
|
48
|
+
connection
|
|
53
49
|
});
|
|
54
|
-
|
|
50
|
+
const policy = await createPresignedPost(s3, params);
|
|
51
|
+
// Top-level key/bucket/method make the response a standard upload-policy
|
|
52
|
+
// descriptor — the client reads object identity from here, never from fields.
|
|
53
|
+
return {
|
|
54
|
+
...policy,
|
|
55
|
+
bucket,
|
|
56
|
+
key,
|
|
57
|
+
method: 'POST'
|
|
58
|
+
};
|
|
55
59
|
}
|
|
56
60
|
AwsS3PresignedPostPolicy.schema = schema;
|
|
57
61
|
AwsS3PresignedPostPolicy.meta = {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { PutObjectCommand } from '@aws-sdk/client-s3';
|
|
16
|
+
import createS3Client from '../createS3Client.js';
|
|
17
|
+
import schema from './schema.js';
|
|
18
|
+
// Server-side write: stores base64 content as an object. Used by API endpoint
|
|
19
|
+
// routines that receive files as endpoint payloads (emitFileContent + CallAPI).
|
|
20
|
+
async function AwsS3PutObject({ request, connection }) {
|
|
21
|
+
const { bucket } = connection;
|
|
22
|
+
const { acl, content, contentType, key } = request;
|
|
23
|
+
const params = {
|
|
24
|
+
Bucket: bucket,
|
|
25
|
+
Key: key,
|
|
26
|
+
Body: Buffer.from(content, 'base64')
|
|
27
|
+
};
|
|
28
|
+
if (contentType) {
|
|
29
|
+
params.ContentType = contentType;
|
|
30
|
+
}
|
|
31
|
+
if (acl) {
|
|
32
|
+
params.ACL = acl;
|
|
33
|
+
}
|
|
34
|
+
const s3 = createS3Client({
|
|
35
|
+
connection
|
|
36
|
+
});
|
|
37
|
+
await s3.send(new PutObjectCommand(params));
|
|
38
|
+
return {
|
|
39
|
+
bucket,
|
|
40
|
+
key
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
AwsS3PutObject.schema = schema;
|
|
44
|
+
AwsS3PutObject.meta = {
|
|
45
|
+
checkRead: false,
|
|
46
|
+
checkWrite: true
|
|
47
|
+
};
|
|
48
|
+
export default AwsS3PutObject;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ export default {
|
|
16
|
+
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
17
|
+
title: 'Lowdefy Request Schema - AwsS3PutObject',
|
|
18
|
+
type: 'object',
|
|
19
|
+
required: [
|
|
20
|
+
'key',
|
|
21
|
+
'content'
|
|
22
|
+
],
|
|
23
|
+
properties: {
|
|
24
|
+
acl: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
enum: [
|
|
27
|
+
'private',
|
|
28
|
+
'public-read',
|
|
29
|
+
'public-read-write',
|
|
30
|
+
'aws-exec-read',
|
|
31
|
+
'authenticated-read',
|
|
32
|
+
'bucket-owner-read',
|
|
33
|
+
'bucket-owner-full-control'
|
|
34
|
+
],
|
|
35
|
+
description: 'Access control lists used to grant read and write access.',
|
|
36
|
+
errorMessage: {
|
|
37
|
+
type: 'AwsS3PutObject request property "acl" should be a string.',
|
|
38
|
+
enum: 'AwsS3PutObject request property "acl" is not one of "private", "public-read", "public-read-write", "aws-exec-read", "authenticated-read", "bucket-owner-read", "bucket-owner-full-control".'
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
content: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
description: 'Object content as a base64 encoded string.',
|
|
44
|
+
errorMessage: {
|
|
45
|
+
type: 'AwsS3PutObject request property "content" should be a string.'
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
contentType: {
|
|
49
|
+
type: 'string',
|
|
50
|
+
description: 'MIME type of the object (sets the Content-Type of the stored object).',
|
|
51
|
+
errorMessage: {
|
|
52
|
+
type: 'AwsS3PutObject request property "contentType" should be a string.'
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
key: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: 'Key under which the object will be stored.',
|
|
58
|
+
errorMessage: {
|
|
59
|
+
type: 'AwsS3PutObject request property "key" should be a string.'
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
errorMessage: {
|
|
64
|
+
type: 'AwsS3PutObject request properties should be an object.',
|
|
65
|
+
required: {
|
|
66
|
+
key: 'AwsS3PutObject request should have required property "key".',
|
|
67
|
+
content: 'AwsS3PutObject request should have required property "content".'
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { S3Client } from '@aws-sdk/client-s3';
|
|
16
|
+
import { type } from '@lowdefy/helpers';
|
|
17
|
+
function createS3Client({ connection }) {
|
|
18
|
+
const { accessKeyId, secretAccessKey, region, endpoint, forcePathStyle } = connection;
|
|
19
|
+
const config = {
|
|
20
|
+
credentials: {
|
|
21
|
+
accessKeyId,
|
|
22
|
+
secretAccessKey
|
|
23
|
+
},
|
|
24
|
+
region
|
|
25
|
+
};
|
|
26
|
+
if (!type.isNone(endpoint)) {
|
|
27
|
+
config.endpoint = endpoint;
|
|
28
|
+
}
|
|
29
|
+
if (!type.isNone(forcePathStyle)) {
|
|
30
|
+
config.forcePathStyle = forcePathStyle;
|
|
31
|
+
}
|
|
32
|
+
return new S3Client(config);
|
|
33
|
+
}
|
|
34
|
+
export default createS3Client;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { type } from '@lowdefy/helpers';
|
|
16
|
+
// Stable, non-expiring URL for a public-read object. Public is author-declared,
|
|
17
|
+
// never runtime-checked — a public URL to a private object 403s.
|
|
18
|
+
function getPublicUrl({ connection, key }) {
|
|
19
|
+
const { bucket, endpoint, publicUrlBase, region } = connection;
|
|
20
|
+
const encodedKey = key.split('/').map(encodeURIComponent).join('/');
|
|
21
|
+
if (!type.isNone(publicUrlBase)) {
|
|
22
|
+
return `${publicUrlBase.replace(/\/+$/, '')}/${encodedKey}`;
|
|
23
|
+
}
|
|
24
|
+
if (!type.isNone(endpoint)) {
|
|
25
|
+
// Custom endpoints (R2, MinIO, Spaces) serve public objects path-style.
|
|
26
|
+
return `${endpoint.replace(/\/+$/, '')}/${bucket}/${encodedKey}`;
|
|
27
|
+
}
|
|
28
|
+
return `https://${bucket}.s3.${region}.amazonaws.com/${encodedKey}`;
|
|
29
|
+
}
|
|
30
|
+
export default getPublicUrl;
|
|
@@ -51,6 +51,27 @@
|
|
|
51
51
|
type: 'AwsS3Bucket connection property "bucket" should be a string.'
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
|
+
endpoint: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
description: 'Custom S3 API endpoint for S3-compatible providers (e.g. Cloudflare R2, MinIO, DigitalOcean Spaces, Backblaze B2, Wasabi).',
|
|
57
|
+
errorMessage: {
|
|
58
|
+
type: 'AwsS3Bucket connection property "endpoint" should be a string.'
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
forcePathStyle: {
|
|
62
|
+
type: 'boolean',
|
|
63
|
+
description: 'Force path-style bucket addressing (https://endpoint/bucket/key). Required by MinIO and some self-hosted S3-compatible setups.',
|
|
64
|
+
errorMessage: {
|
|
65
|
+
type: 'AwsS3Bucket connection property "forcePathStyle" should be a boolean.'
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
publicUrlBase: {
|
|
69
|
+
type: 'string',
|
|
70
|
+
description: 'Base URL used to construct stable public object URLs (e.g. a CloudFront or CDN domain in front of the bucket). Used by download requests when the request sets "public: true".',
|
|
71
|
+
errorMessage: {
|
|
72
|
+
type: 'AwsS3Bucket connection property "publicUrlBase" should be a string.'
|
|
73
|
+
}
|
|
74
|
+
},
|
|
54
75
|
read: {
|
|
55
76
|
type: 'boolean',
|
|
56
77
|
default: true,
|
package/dist/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowdefy/plugin-aws",
|
|
3
|
-
"version": "0.0.0-experimental-
|
|
3
|
+
"version": "0.0.0-experimental-20260722143027",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "",
|
|
6
6
|
"homepage": "https://lowdefy.com",
|
|
@@ -36,20 +36,22 @@
|
|
|
36
36
|
},
|
|
37
37
|
"type": "module",
|
|
38
38
|
"exports": {
|
|
39
|
-
"
|
|
40
|
-
"./connections/*": "./dist/connections/*",
|
|
39
|
+
"./connections": "./dist/connections.js",
|
|
41
40
|
"./blocks": "./dist/blocks.js",
|
|
42
41
|
"./metas": "./dist/metas.js",
|
|
43
|
-
"./types": "./dist/types.js"
|
|
42
|
+
"./types": "./dist/types.js",
|
|
43
|
+
"./connections/*": "./dist/connections/*",
|
|
44
|
+
"./*": "./dist/*"
|
|
44
45
|
},
|
|
45
46
|
"files": [
|
|
46
47
|
"dist/*"
|
|
47
48
|
],
|
|
48
49
|
"dependencies": {
|
|
49
|
-
"@lowdefy/block-utils": "0.0.0-experimental-
|
|
50
|
-
"@lowdefy/blocks-antd": "0.0.0-experimental-
|
|
51
|
-
"@lowdefy/
|
|
52
|
-
"@lowdefy/
|
|
50
|
+
"@lowdefy/block-utils": "0.0.0-experimental-20260722143027",
|
|
51
|
+
"@lowdefy/blocks-antd": "0.0.0-experimental-20260722143027",
|
|
52
|
+
"@lowdefy/blocks-files": "0.0.0-experimental-20260722143027",
|
|
53
|
+
"@lowdefy/errors": "0.0.0-experimental-20260722143027",
|
|
54
|
+
"@lowdefy/helpers": "0.0.0-experimental-20260722143027",
|
|
53
55
|
"@aws-sdk/client-s3": "3.797.0",
|
|
54
56
|
"@aws-sdk/s3-presigned-post": "3.797.0",
|
|
55
57
|
"@aws-sdk/s3-request-presigner": "3.797.0"
|
|
@@ -60,15 +62,15 @@
|
|
|
60
62
|
"react-dom": ">=18"
|
|
61
63
|
},
|
|
62
64
|
"devDependencies": {
|
|
63
|
-
"@lowdefy/ajv": "0.0.0-experimental-
|
|
64
|
-
"@lowdefy/block-dev": "0.0.0-experimental-
|
|
65
|
-
"@lowdefy/jest-yaml-transform": "0.0.0-experimental-
|
|
66
|
-
"@swc/cli": "0.8.
|
|
67
|
-
"@swc/core": "1.15.
|
|
65
|
+
"@lowdefy/ajv": "0.0.0-experimental-20260722143027",
|
|
66
|
+
"@lowdefy/block-dev": "0.0.0-experimental-20260722143027",
|
|
67
|
+
"@lowdefy/jest-yaml-transform": "0.0.0-experimental-20260722143027",
|
|
68
|
+
"@swc/cli": "0.8.1",
|
|
69
|
+
"@swc/core": "1.15.32",
|
|
68
70
|
"@swc/jest": "0.2.39",
|
|
69
71
|
"@testing-library/dom": "8.19.1",
|
|
70
72
|
"@testing-library/react": "13.4.0",
|
|
71
|
-
"@testing-library/user-event": "14.
|
|
73
|
+
"@testing-library/user-event": "14.6.1",
|
|
72
74
|
"copyfiles": "2.4.1",
|
|
73
75
|
"jest": "28.1.3",
|
|
74
76
|
"jest-environment-jsdom": "28.1.3",
|
|
@@ -80,6 +82,7 @@
|
|
|
80
82
|
"scripts": {
|
|
81
83
|
"build": "swc src --out-dir dist --config-file ../../../../.swcrc --cli-config-file ../../../../.swc-cli.json --copy-files",
|
|
82
84
|
"clean": "rm -rf dist",
|
|
83
|
-
"copyfiles": "copyfiles -u 1 \"./src/**/*\" dist -e \"./src/**/*.js\" -e \"./src/**/*.yaml\" -e \"./src/**/*.snap\""
|
|
85
|
+
"copyfiles": "copyfiles -u 1 \"./src/**/*\" dist -e \"./src/**/*.js\" -e \"./src/**/*.yaml\" -e \"./src/**/*.snap\"",
|
|
86
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
|
|
84
87
|
}
|
|
85
88
|
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
@layer components {
|
|
18
|
-
/* Height applies to the drop zone, not the outer wrapper, so the file list
|
|
19
|
-
(rendered as a sibling of `.ant-upload-drag` inside the Dragger root) can
|
|
20
|
-
flow inline below it instead of overflowing a fixed-height container. */
|
|
21
|
-
:global(.lf-s3-upload-dragger .ant-upload-drag) {
|
|
22
|
-
height: var(--lf-s3-dragger-height);
|
|
23
|
-
}
|
|
24
|
-
/* antd v6 applies `padding: token.padding` to `.ant-upload-drag .ant-upload`,
|
|
25
|
-
which overflows the drag area when the wrapper height is small. Scope the
|
|
26
|
-
override to this block and let users add padding via style.hint. */
|
|
27
|
-
:global(.lf-s3-upload-dragger .ant-upload-drag .ant-upload) {
|
|
28
|
-
padding: 0;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
*/ const getFileFromEvent = async (event)=>{
|
|
16
|
-
const items = event.clipboardData.items;
|
|
17
|
-
for (const item of items){
|
|
18
|
-
if (item.kind === 'file') {
|
|
19
|
-
return item.getAsFile();
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
const getFileFromNavigator = async ()=>{
|
|
24
|
-
const items = await navigator.clipboard.read();
|
|
25
|
-
for (const item of items){
|
|
26
|
-
for (const type of item.types){
|
|
27
|
-
if (type === 'image/png' || type === 'image/jpeg') {
|
|
28
|
-
const blob = await item.getType(type);
|
|
29
|
-
return new File([
|
|
30
|
-
blob
|
|
31
|
-
], 'clipboard.png', {
|
|
32
|
-
type: blob.type
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
const getOnPaste = ({ s3UploadRequest, properties })=>async (event)=>{
|
|
39
|
-
event?.preventDefault?.();
|
|
40
|
-
if (properties.disabled) return;
|
|
41
|
-
const file = event ? await getFileFromEvent(event) : await getFileFromNavigator();
|
|
42
|
-
if (!file) return;
|
|
43
|
-
file.uid = `${properties.fileName ?? file.name ?? 'clipboard'}-${Date.now()}`;
|
|
44
|
-
await s3UploadRequest({
|
|
45
|
-
file
|
|
46
|
-
});
|
|
47
|
-
};
|
|
48
|
-
export default getOnPaste;
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
*/ import { ServiceError } from '@lowdefy/errors';
|
|
16
|
-
const getS3Upload = ({ methods, setFileList, setLoading = ()=>null })=>async ({ file })=>{
|
|
17
|
-
if (!file) {
|
|
18
|
-
console.warn('File is undefined in useS3Upload');
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
try {
|
|
22
|
-
setLoading(true);
|
|
23
|
-
const { lastModified, name, size, type, uid } = file;
|
|
24
|
-
const s3PostPolicyResponse = await methods.triggerEvent({
|
|
25
|
-
name: '__getS3PostPolicy',
|
|
26
|
-
event: {
|
|
27
|
-
file: {
|
|
28
|
-
name,
|
|
29
|
-
lastModified,
|
|
30
|
-
size,
|
|
31
|
-
type,
|
|
32
|
-
uid
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
if (s3PostPolicyResponse.success !== true) {
|
|
37
|
-
throw new Error('S3 post policy request error.');
|
|
38
|
-
}
|
|
39
|
-
const { url, fields = {} } = s3PostPolicyResponse.responses.__getS3PostPolicy.response[0];
|
|
40
|
-
const { bucket, key } = fields;
|
|
41
|
-
file.bucket = bucket;
|
|
42
|
-
file.key = key;
|
|
43
|
-
file.percent = 20;
|
|
44
|
-
const formData = new FormData();
|
|
45
|
-
Object.keys(fields).forEach((field)=>{
|
|
46
|
-
formData.append(field, fields[field]);
|
|
47
|
-
});
|
|
48
|
-
formData.append('file', file);
|
|
49
|
-
await new Promise((resolve, reject)=>{
|
|
50
|
-
const xhr = new XMLHttpRequest();
|
|
51
|
-
xhr.upload.onprogress = async (event)=>{
|
|
52
|
-
if (event.lengthComputable) {
|
|
53
|
-
await setFileList({
|
|
54
|
-
event: 'onProgress',
|
|
55
|
-
file,
|
|
56
|
-
percent: event.loaded / event.total * 80 + 20
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
xhr.addEventListener('load', ()=>{
|
|
61
|
-
if (xhr.status >= 200 && xhr.status < 300) {
|
|
62
|
-
resolve();
|
|
63
|
-
} else {
|
|
64
|
-
reject(new Error(`S3 upload failed with status ${xhr.status}.`));
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
xhr.addEventListener('error', ()=>{
|
|
68
|
-
reject(new ServiceError(`S3 upload failed for "${name}" — CORS or network error. ` + `Check that the S3 bucket CORS configuration allows requests from this origin.`, {
|
|
69
|
-
service: 'S3'
|
|
70
|
-
}));
|
|
71
|
-
});
|
|
72
|
-
xhr.addEventListener('abort', ()=>{
|
|
73
|
-
reject(new Error(`S3 upload aborted for "${name}".`));
|
|
74
|
-
});
|
|
75
|
-
xhr.open('post', url);
|
|
76
|
-
xhr.send(formData);
|
|
77
|
-
});
|
|
78
|
-
await setFileList({
|
|
79
|
-
event: 'onSuccess',
|
|
80
|
-
file
|
|
81
|
-
});
|
|
82
|
-
setLoading(false);
|
|
83
|
-
} catch (error) {
|
|
84
|
-
await setFileList({
|
|
85
|
-
event: 'onError',
|
|
86
|
-
file
|
|
87
|
-
});
|
|
88
|
-
setLoading(false);
|
|
89
|
-
throw error;
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
export default getS3Upload;
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
*/ import { useState } from 'react';
|
|
16
|
-
import { type } from '@lowdefy/helpers';
|
|
17
|
-
const useFileList = ({ properties, methods, value = {} })=>{
|
|
18
|
-
const checkedValue = (value)=>{
|
|
19
|
-
let file = type.isObject(value?.file) ? value.file : null;
|
|
20
|
-
if (!file && type.isObject(value?.fileList?.[0])) {
|
|
21
|
-
file = value.fileList[0];
|
|
22
|
-
}
|
|
23
|
-
const fileList = type.isArray(value?.fileList) ? value.fileList : [];
|
|
24
|
-
if (properties.singleFile === true) {
|
|
25
|
-
fileList.splice(1);
|
|
26
|
-
}
|
|
27
|
-
if (type.isInt(properties.maxCount)) {
|
|
28
|
-
fileList.splice(properties.maxCount);
|
|
29
|
-
}
|
|
30
|
-
return {
|
|
31
|
-
file,
|
|
32
|
-
fileList
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
const [state, setState] = useState(checkedValue(value));
|
|
36
|
-
const setValue = (stateValue)=>{
|
|
37
|
-
setState(()=>{
|
|
38
|
-
return checkedValue(stateValue);
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
const setFileList = async ({ event, file, percent })=>{
|
|
42
|
-
if (!file) {
|
|
43
|
-
throw new Error('File is undefined in useFileList');
|
|
44
|
-
}
|
|
45
|
-
// destruct the file object to avoid the file object being mutated.
|
|
46
|
-
const { bucket, key, lastModified, name, size, status, type, uid } = file;
|
|
47
|
-
const fileObj = {
|
|
48
|
-
bucket,
|
|
49
|
-
key,
|
|
50
|
-
lastModified,
|
|
51
|
-
name,
|
|
52
|
-
percent: percent ?? file.percent ?? 0,
|
|
53
|
-
size,
|
|
54
|
-
status,
|
|
55
|
-
type,
|
|
56
|
-
uid,
|
|
57
|
-
url: file instanceof Blob || file instanceof File ? URL.createObjectURL(file) : null
|
|
58
|
-
};
|
|
59
|
-
switch(event){
|
|
60
|
-
case 'onProgress':
|
|
61
|
-
fileObj.status = 'uploading';
|
|
62
|
-
fileObj.percent = percent ?? fileObj.percent;
|
|
63
|
-
break;
|
|
64
|
-
case 'onSuccess':
|
|
65
|
-
fileObj.status = 'done';
|
|
66
|
-
fileObj.percent = 100;
|
|
67
|
-
break;
|
|
68
|
-
case 'onRemove':
|
|
69
|
-
fileObj.status = 'removed';
|
|
70
|
-
break;
|
|
71
|
-
default:
|
|
72
|
-
fileObj.status = 'error';
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
state.fileList.splice(state.fileList.findIndex((f)=>f.uid === fileObj.uid), 1, fileObj);
|
|
76
|
-
const nextState = checkedValue({
|
|
77
|
-
file: fileObj,
|
|
78
|
-
fileList: state.fileList
|
|
79
|
-
});
|
|
80
|
-
await methods.triggerEvent({
|
|
81
|
-
name: event,
|
|
82
|
-
event: nextState
|
|
83
|
-
});
|
|
84
|
-
setValue(nextState);
|
|
85
|
-
methods.setValue(nextState);
|
|
86
|
-
};
|
|
87
|
-
const loadFileList = async (file, nextFiles)=>{
|
|
88
|
-
if (properties.singleFile === true && nextFiles.filter((f)=>type.isString(f.uid)).length > 1) {
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
if (type.isInt(properties.maxCount) && nextFiles.filter((f)=>type.isString(f.uid)).length > properties.maxCount) {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
// Extract file properties into a serialization-safe plain object.
|
|
95
|
-
// Raw File/Blob objects are destroyed by serializer.copy() in _event resolution.
|
|
96
|
-
const fileData = {
|
|
97
|
-
name: file.name,
|
|
98
|
-
type: file.type,
|
|
99
|
-
size: file.size,
|
|
100
|
-
lastModified: file.lastModified,
|
|
101
|
-
uid: file.uid
|
|
102
|
-
};
|
|
103
|
-
if (file instanceof Blob || file instanceof File) {
|
|
104
|
-
fileData.url = URL.createObjectURL(file);
|
|
105
|
-
}
|
|
106
|
-
const result = await methods.triggerEvent({
|
|
107
|
-
name: 'onBeforeUpload',
|
|
108
|
-
event: {
|
|
109
|
-
file: fileData
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
if (result.success === false) {
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
const nextState = {
|
|
116
|
-
file: fileData,
|
|
117
|
-
fileList: [
|
|
118
|
-
...nextFiles,
|
|
119
|
-
...state.fileList
|
|
120
|
-
]
|
|
121
|
-
};
|
|
122
|
-
setValue(nextState);
|
|
123
|
-
methods.setValue(nextState);
|
|
124
|
-
};
|
|
125
|
-
const removeFile = (file)=>{
|
|
126
|
-
state.fileList.splice(state.fileList.findIndex((f)=>f.uid === file.uid), 1);
|
|
127
|
-
setValue(state);
|
|
128
|
-
methods.setValue(state);
|
|
129
|
-
};
|
|
130
|
-
return [
|
|
131
|
-
state,
|
|
132
|
-
loadFileList,
|
|
133
|
-
setFileList,
|
|
134
|
-
removeFile,
|
|
135
|
-
setValue
|
|
136
|
-
];
|
|
137
|
-
};
|
|
138
|
-
export default useFileList;
|
package/dist/blocks/withTheme.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
-
|
|
4
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
you may not use this file except in compliance with the License.
|
|
6
|
-
You may obtain a copy of the License at
|
|
7
|
-
|
|
8
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
|
|
10
|
-
Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
See the License for the specific language governing permissions and
|
|
14
|
-
limitations under the License.
|
|
15
|
-
*/ import React from 'react';
|
|
16
|
-
import { ConfigProvider } from 'antd';
|
|
17
|
-
import { type } from '@lowdefy/helpers';
|
|
18
|
-
function withTheme(antdComponentName, BlockComponent) {
|
|
19
|
-
const Wrapped = (props)=>{
|
|
20
|
-
const { theme, ...restProperties } = props.properties;
|
|
21
|
-
// Only intercept object themes (design tokens for ConfigProvider).
|
|
22
|
-
// String themes (e.g. Menu's 'dark'/'light') pass through to the component.
|
|
23
|
-
if (!type.isObject(theme)) {
|
|
24
|
-
return /*#__PURE__*/ React.createElement(BlockComponent, props);
|
|
25
|
-
}
|
|
26
|
-
return /*#__PURE__*/ React.createElement(ConfigProvider, {
|
|
27
|
-
theme: {
|
|
28
|
-
components: {
|
|
29
|
-
[antdComponentName]: theme
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}, /*#__PURE__*/ React.createElement(BlockComponent, {
|
|
33
|
-
...props,
|
|
34
|
-
properties: restProperties
|
|
35
|
-
}));
|
|
36
|
-
};
|
|
37
|
-
Wrapped.displayName = BlockComponent.displayName || BlockComponent.name;
|
|
38
|
-
return Wrapped;
|
|
39
|
-
}
|
|
40
|
-
export default withTheme;
|