@cdklabs/cdk-appmod-catalog-blueprints 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +8644 -0
- package/LICENSE +202 -0
- package/README.md +212 -0
- package/lib/document-processing/agentic-document-processing.d.ts +16 -0
- package/lib/document-processing/agentic-document-processing.js +90 -0
- package/lib/document-processing/base-document-processing.d.ts +189 -0
- package/lib/document-processing/base-document-processing.js +509 -0
- package/lib/document-processing/bedrock-document-processing.d.ts +167 -0
- package/lib/document-processing/bedrock-document-processing.js +297 -0
- package/lib/document-processing/index.d.ts +3 -0
- package/lib/document-processing/index.js +20 -0
- package/lib/document-processing/resources/default-bedrock-invoke/index.py +63 -0
- package/lib/document-processing/resources/default-bedrock-invoke/requirements.txt +4 -0
- package/lib/document-processing/resources/default-doc-retrieval-lambda/index.mjs +92 -0
- package/lib/document-processing/resources/default-doc-retrieval-lambda/package.json +10 -0
- package/lib/document-processing/resources/default-error-handler/index.js +46 -0
- package/lib/document-processing/resources/default-error-handler/package.json +4 -0
- package/lib/document-processing/resources/default-image-processor/classifier.mjs +665 -0
- package/lib/document-processing/resources/default-image-processor/extractors.mjs +465 -0
- package/lib/document-processing/resources/default-image-processor/index.mjs +143 -0
- package/lib/document-processing/resources/default-image-processor/package-lock.json +12 -0
- package/lib/document-processing/resources/default-image-processor/package.json +4 -0
- package/lib/document-processing/resources/default-image-validator/index.mjs +76 -0
- package/lib/document-processing/resources/default-image-validator/package-lock.json +154 -0
- package/lib/document-processing/resources/default-image-validator/package.json +7 -0
- package/lib/document-processing/resources/default-pdf-processor/index.js +46 -0
- package/lib/document-processing/resources/default-pdf-validator/index.js +36 -0
- package/lib/document-processing/resources/default-sqs-consumer/index.py +111 -0
- package/lib/document-processing/resources/default-sqs-consumer/requirements.txt +4 -0
- package/lib/document-processing/resources/default-sqs-consumer/sample_payload.json +20 -0
- package/lib/document-processing/resources/default-sqs-consumer/sample_payload_multi.json +24 -0
- package/lib/document-processing/resources/default-strands-agent/index.py +111 -0
- package/lib/document-processing/resources/default-strands-agent/requirements.txt +6 -0
- package/lib/document-processing/tests/agentic-document-processing-nag.test.d.ts +1 -0
- package/lib/document-processing/tests/agentic-document-processing-nag.test.js +107 -0
- package/lib/document-processing/tests/agentic-document-processing.test.d.ts +1 -0
- package/lib/document-processing/tests/agentic-document-processing.test.js +125 -0
- package/lib/document-processing/tests/bedrock-document-processing-nag.test.d.ts +1 -0
- package/lib/document-processing/tests/bedrock-document-processing-nag.test.js +101 -0
- package/lib/document-processing/tests/bedrock-document-processing.test.d.ts +1 -0
- package/lib/document-processing/tests/bedrock-document-processing.test.js +79 -0
- package/lib/framework/custom-resource/default-runtimes.d.ts +21 -0
- package/lib/framework/custom-resource/default-runtimes.js +34 -0
- package/lib/framework/custom-resource/index.d.ts +1 -0
- package/lib/framework/custom-resource/index.js +18 -0
- package/lib/framework/foundation/access-log.d.ts +69 -0
- package/lib/framework/foundation/access-log.js +121 -0
- package/lib/framework/foundation/eventbridge-broker.d.ts +18 -0
- package/lib/framework/foundation/eventbridge-broker.js +42 -0
- package/lib/framework/foundation/index.d.ts +3 -0
- package/lib/framework/foundation/index.js +20 -0
- package/lib/framework/foundation/network.d.ts +19 -0
- package/lib/framework/foundation/network.js +83 -0
- package/lib/framework/index.d.ts +2 -0
- package/lib/framework/index.js +19 -0
- package/lib/framework/quickstart/base-quickstart.d.ts +30 -0
- package/lib/framework/quickstart/base-quickstart.js +30 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +21 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/lib/utilities/cdk-nag-config.d.ts +42 -0
- package/lib/utilities/cdk-nag-config.js +194 -0
- package/lib/utilities/data-loader-lambda/index.py +282 -0
- package/lib/utilities/data-loader-lambda/requirements.txt +3 -0
- package/lib/utilities/data-loader.d.ts +173 -0
- package/lib/utilities/data-loader.js +447 -0
- package/lib/utilities/index.d.ts +3 -0
- package/lib/utilities/index.js +20 -0
- package/lib/utilities/lambda-iam-utils.d.ts +145 -0
- package/lib/utilities/lambda-iam-utils.js +235 -0
- package/lib/utilities/lambda_layers/data-masking/layer-construct.d.ts +42 -0
- package/lib/utilities/lambda_layers/data-masking/layer-construct.js +53 -0
- package/lib/utilities/lambda_layers/data-masking/layer-construct.ts +88 -0
- package/lib/utilities/observability/bedrock-observability.d.ts +18 -0
- package/lib/utilities/observability/bedrock-observability.js +131 -0
- package/lib/utilities/observability/cloudfront-distribution-observability-property-injector.d.ts +6 -0
- package/lib/utilities/observability/cloudfront-distribution-observability-property-injector.js +22 -0
- package/lib/utilities/observability/index.d.ts +6 -0
- package/lib/utilities/observability/index.js +25 -0
- package/lib/utilities/observability/lambda-observability-property-injector.d.ts +8 -0
- package/lib/utilities/observability/lambda-observability-property-injector.js +43 -0
- package/lib/utilities/observability/log-group-data-protection-props.d.ts +19 -0
- package/lib/utilities/observability/log-group-data-protection-props.js +5 -0
- package/lib/utilities/observability/observability.d.ts +83 -0
- package/lib/utilities/observability/observability.js +278 -0
- package/lib/utilities/observability/observable.d.ts +32 -0
- package/lib/utilities/observability/observable.js +3 -0
- package/lib/utilities/observability/powertools-config.d.ts +3 -0
- package/lib/utilities/observability/powertools-config.js +25 -0
- package/lib/utilities/observability/resources/bedrock-manage-logging-configuration/index.py +27 -0
- package/lib/utilities/observability/state-machine-observability-property-injector.d.ts +8 -0
- package/lib/utilities/observability/state-machine-observability-property-injector.js +49 -0
- package/lib/utilities/tests/data-loader-nag.test.d.ts +1 -0
- package/lib/utilities/tests/data-loader-nag.test.js +432 -0
- package/lib/utilities/tests/data-loader.test.d.ts +1 -0
- package/lib/utilities/tests/data-loader.test.js +284 -0
- package/lib/webapp/frontend-construct.d.ts +136 -0
- package/lib/webapp/frontend-construct.js +253 -0
- package/lib/webapp/index.d.ts +1 -0
- package/lib/webapp/index.js +18 -0
- package/lib/webapp/tests/frontend-construct-nag.test.d.ts +1 -0
- package/lib/webapp/tests/frontend-construct-nag.test.js +266 -0
- package/lib/webapp/tests/frontend-construct.test.d.ts +1 -0
- package/lib/webapp/tests/frontend-construct.test.js +385 -0
- package/package.json +183 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "default-image-validator",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "default-image-validator",
|
|
9
|
+
"version": "0.0.1",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"file-type": "^20.5.0"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"node_modules/@tokenizer/inflate": {
|
|
15
|
+
"version": "0.2.7",
|
|
16
|
+
"resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.2.7.tgz",
|
|
17
|
+
"integrity": "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"debug": "^4.4.0",
|
|
20
|
+
"fflate": "^0.8.2",
|
|
21
|
+
"token-types": "^6.0.0"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
},
|
|
26
|
+
"funding": {
|
|
27
|
+
"type": "github",
|
|
28
|
+
"url": "https://github.com/sponsors/Borewit"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"node_modules/@tokenizer/token": {
|
|
32
|
+
"version": "0.3.0",
|
|
33
|
+
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
|
|
34
|
+
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
|
|
35
|
+
},
|
|
36
|
+
"node_modules/debug": {
|
|
37
|
+
"version": "4.4.0",
|
|
38
|
+
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
|
39
|
+
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"ms": "^2.1.3"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=6.0"
|
|
45
|
+
},
|
|
46
|
+
"peerDependenciesMeta": {
|
|
47
|
+
"supports-color": {
|
|
48
|
+
"optional": true
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"node_modules/fflate": {
|
|
53
|
+
"version": "0.8.2",
|
|
54
|
+
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
|
55
|
+
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="
|
|
56
|
+
},
|
|
57
|
+
"node_modules/file-type": {
|
|
58
|
+
"version": "20.5.0",
|
|
59
|
+
"resolved": "https://registry.npmjs.org/file-type/-/file-type-20.5.0.tgz",
|
|
60
|
+
"integrity": "sha512-BfHZtG/l9iMm4Ecianu7P8HRD2tBHLtjXinm4X62XBOYzi7CYA7jyqfJzOvXHqzVrVPYqBo2/GvbARMaaJkKVg==",
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"@tokenizer/inflate": "^0.2.6",
|
|
63
|
+
"strtok3": "^10.2.0",
|
|
64
|
+
"token-types": "^6.0.0",
|
|
65
|
+
"uint8array-extras": "^1.4.0"
|
|
66
|
+
},
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": ">=18"
|
|
69
|
+
},
|
|
70
|
+
"funding": {
|
|
71
|
+
"url": "https://github.com/sindresorhus/file-type?sponsor=1"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"node_modules/ieee754": {
|
|
75
|
+
"version": "1.2.1",
|
|
76
|
+
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
|
77
|
+
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
|
78
|
+
"funding": [
|
|
79
|
+
{
|
|
80
|
+
"type": "github",
|
|
81
|
+
"url": "https://github.com/sponsors/feross"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"type": "patreon",
|
|
85
|
+
"url": "https://www.patreon.com/feross"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"type": "consulting",
|
|
89
|
+
"url": "https://feross.org/support"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
"node_modules/ms": {
|
|
94
|
+
"version": "2.1.3",
|
|
95
|
+
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
|
96
|
+
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
|
97
|
+
},
|
|
98
|
+
"node_modules/peek-readable": {
|
|
99
|
+
"version": "7.0.0",
|
|
100
|
+
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-7.0.0.tgz",
|
|
101
|
+
"integrity": "sha512-nri2TO5JE3/mRryik9LlHFT53cgHfRK0Lt0BAZQXku/AW3E6XLt2GaY8siWi7dvW/m1z0ecn+J+bpDa9ZN3IsQ==",
|
|
102
|
+
"engines": {
|
|
103
|
+
"node": ">=18"
|
|
104
|
+
},
|
|
105
|
+
"funding": {
|
|
106
|
+
"type": "github",
|
|
107
|
+
"url": "https://github.com/sponsors/Borewit"
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"node_modules/strtok3": {
|
|
111
|
+
"version": "10.2.2",
|
|
112
|
+
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.2.2.tgz",
|
|
113
|
+
"integrity": "sha512-Xt18+h4s7Z8xyZ0tmBoRmzxcop97R4BAh+dXouUDCYn+Em+1P3qpkUfI5ueWLT8ynC5hZ+q4iPEmGG1urvQGBg==",
|
|
114
|
+
"dependencies": {
|
|
115
|
+
"@tokenizer/token": "^0.3.0",
|
|
116
|
+
"peek-readable": "^7.0.0"
|
|
117
|
+
},
|
|
118
|
+
"engines": {
|
|
119
|
+
"node": ">=18"
|
|
120
|
+
},
|
|
121
|
+
"funding": {
|
|
122
|
+
"type": "github",
|
|
123
|
+
"url": "https://github.com/sponsors/Borewit"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"node_modules/token-types": {
|
|
127
|
+
"version": "6.0.0",
|
|
128
|
+
"resolved": "https://registry.npmjs.org/token-types/-/token-types-6.0.0.tgz",
|
|
129
|
+
"integrity": "sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==",
|
|
130
|
+
"dependencies": {
|
|
131
|
+
"@tokenizer/token": "^0.3.0",
|
|
132
|
+
"ieee754": "^1.2.1"
|
|
133
|
+
},
|
|
134
|
+
"engines": {
|
|
135
|
+
"node": ">=14.16"
|
|
136
|
+
},
|
|
137
|
+
"funding": {
|
|
138
|
+
"type": "github",
|
|
139
|
+
"url": "https://github.com/sponsors/Borewit"
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"node_modules/uint8array-extras": {
|
|
143
|
+
"version": "1.4.0",
|
|
144
|
+
"resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.4.0.tgz",
|
|
145
|
+
"integrity": "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==",
|
|
146
|
+
"engines": {
|
|
147
|
+
"node": ">=18"
|
|
148
|
+
},
|
|
149
|
+
"funding": {
|
|
150
|
+
"url": "https://github.com/sponsors/sindresorhus"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
exports.handler = async (event) => {
|
|
2
|
+
console.log('Received event:', JSON.stringify(event, null, 2));
|
|
3
|
+
|
|
4
|
+
try {
|
|
5
|
+
// Extract document info from event
|
|
6
|
+
const { documentId, bucket, key, status } = event;
|
|
7
|
+
|
|
8
|
+
// Check if document was valid
|
|
9
|
+
if (status !== 'VALID') {
|
|
10
|
+
throw new Error('Cannot process invalid document');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Simulate processing
|
|
14
|
+
console.log(`Processing document ${documentId} from ${bucket}/${key}`);
|
|
15
|
+
|
|
16
|
+
// In a real implementation, this would:
|
|
17
|
+
// 1. Download the PDF from S3
|
|
18
|
+
// 2. Process it (OCR, text extraction, etc)
|
|
19
|
+
// 3. Apply data masking
|
|
20
|
+
// 4. Upload processed result back to S3
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
statusCode: 200,
|
|
24
|
+
documentId,
|
|
25
|
+
bucket,
|
|
26
|
+
key,
|
|
27
|
+
status: 'PROCESSED',
|
|
28
|
+
outputKey: `processed/${documentId}.pdf`,
|
|
29
|
+
metadata: {
|
|
30
|
+
pageCount: 5, // Example metadata
|
|
31
|
+
processedAt: new Date().toISOString(),
|
|
32
|
+
contentType: 'application/pdf'
|
|
33
|
+
},
|
|
34
|
+
timestamp: new Date().toISOString()
|
|
35
|
+
};
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error('Processing error:', error);
|
|
38
|
+
return {
|
|
39
|
+
statusCode: 500,
|
|
40
|
+
documentId: event.documentId,
|
|
41
|
+
error: error.message,
|
|
42
|
+
status: 'PROCESSING_FAILED',
|
|
43
|
+
timestamp: new Date().toISOString()
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
exports.handler = async (event) => {
|
|
2
|
+
console.log('Received event:', JSON.stringify(event, null, 2));
|
|
3
|
+
|
|
4
|
+
try {
|
|
5
|
+
// Extract document info from event
|
|
6
|
+
const { documentId, bucket, key } = event;
|
|
7
|
+
|
|
8
|
+
// Basic validation
|
|
9
|
+
if (!documentId || !bucket || !key) {
|
|
10
|
+
throw new Error('Missing required fields: documentId, bucket, or key');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Check file extension
|
|
14
|
+
if (!key.toLowerCase().endsWith('.pdf')) {
|
|
15
|
+
throw new Error('Invalid file format. Only PDF files are supported.');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
statusCode: 200,
|
|
20
|
+
documentId,
|
|
21
|
+
bucket,
|
|
22
|
+
key,
|
|
23
|
+
status: 'VALID',
|
|
24
|
+
timestamp: new Date().toISOString()
|
|
25
|
+
};
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error('Validation error:', error);
|
|
28
|
+
return {
|
|
29
|
+
statusCode: 400,
|
|
30
|
+
documentId: event.documentId,
|
|
31
|
+
error: error.message,
|
|
32
|
+
status: 'INVALID',
|
|
33
|
+
timestamp: new Date().toISOString()
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import boto3
|
|
4
|
+
from urllib.parse import unquote_plus
|
|
5
|
+
import time
|
|
6
|
+
import re
|
|
7
|
+
from aws_lambda_powertools import Metrics, Tracer
|
|
8
|
+
from aws_lambda_powertools.metrics import MetricUnit
|
|
9
|
+
|
|
10
|
+
sfn_client = boto3.client('stepfunctions')
|
|
11
|
+
metrics = Metrics()
|
|
12
|
+
tracer = Tracer()
|
|
13
|
+
|
|
14
|
+
@metrics.log_metrics
|
|
15
|
+
@tracer.capture_lambda_handler
|
|
16
|
+
def handler(event, context):
|
|
17
|
+
tracer.put_annotation(key="invoke_type", value="sqsconsumer")
|
|
18
|
+
metrics.add_dimension(name="invoke_type", value="sqsconsumer")
|
|
19
|
+
print(f'SQS Consumer: Received event: {json.dumps(event, indent=2)}')
|
|
20
|
+
|
|
21
|
+
results = []
|
|
22
|
+
|
|
23
|
+
for record in event['Records']:
|
|
24
|
+
try:
|
|
25
|
+
print(f'Processing SQS record: {record["messageId"]}')
|
|
26
|
+
|
|
27
|
+
# Parse S3 event from SQS message body
|
|
28
|
+
s3_event = json.loads(record['body'])
|
|
29
|
+
print(f'Parsed S3 event: {json.dumps(s3_event, indent=2)}')
|
|
30
|
+
|
|
31
|
+
# Skip S3 test events
|
|
32
|
+
if "Event" in s3_event and s3_event["Event"] == 's3:TestEvent':
|
|
33
|
+
print(f'Skipping S3 test event: {s3_event["Event"]}')
|
|
34
|
+
continue
|
|
35
|
+
|
|
36
|
+
if "Records" in s3_event:
|
|
37
|
+
# Process each S3 record in the event
|
|
38
|
+
for s3_record in s3_event['Records']:
|
|
39
|
+
event_name = s3_record['eventName']
|
|
40
|
+
|
|
41
|
+
bucket = s3_record['s3']['bucket']['name']
|
|
42
|
+
key = unquote_plus(s3_record['s3']['object']['key'])
|
|
43
|
+
|
|
44
|
+
# Skip folder creation events (keys ending with '/')
|
|
45
|
+
if key.endswith('/'):
|
|
46
|
+
print(f'Skipping folder creation event: s3://{bucket}/{key}')
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
event_time = s3_record['eventTime']
|
|
50
|
+
|
|
51
|
+
print(f'Processing S3 object: s3://{bucket}/{key}')
|
|
52
|
+
|
|
53
|
+
# Generate unique document ID from S3 key and timestamp
|
|
54
|
+
timestamp = int(time.time() * 1000)
|
|
55
|
+
document_id = (key
|
|
56
|
+
.replace('raw/', '', 1) # Remove raw/ prefix
|
|
57
|
+
.rsplit('.', 1)[0] # Remove file extension
|
|
58
|
+
)
|
|
59
|
+
document_id = re.sub(r'[^a-zA-Z0-9-]', '-', document_id) + '-' + str(timestamp)
|
|
60
|
+
|
|
61
|
+
# Extract filename from key
|
|
62
|
+
filename = key.replace('raw/', '', 1) # Remove raw/ prefix
|
|
63
|
+
|
|
64
|
+
# Prepare Step Functions execution input
|
|
65
|
+
step_function_input = {
|
|
66
|
+
'documentId': document_id,
|
|
67
|
+
'bucket': bucket,
|
|
68
|
+
'key': key,
|
|
69
|
+
'filename': filename,
|
|
70
|
+
'eventTime': event_time,
|
|
71
|
+
'eventName': event_name,
|
|
72
|
+
'source': 'sqs-consumer'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
print(f'Starting Step Functions execution with input: {json.dumps(step_function_input, indent=2)}')
|
|
76
|
+
|
|
77
|
+
# Start Step Functions execution
|
|
78
|
+
execution_name = f'{document_id}-execution'[:80] # AWS limit
|
|
79
|
+
|
|
80
|
+
response = sfn_client.start_execution(
|
|
81
|
+
stateMachineArn=os.environ['STATE_MACHINE_ARN'],
|
|
82
|
+
input=json.dumps(step_function_input),
|
|
83
|
+
name=execution_name
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
print(f'Step Functions execution started: {response["executionArn"]}')
|
|
87
|
+
|
|
88
|
+
results.append({
|
|
89
|
+
'documentId': document_id,
|
|
90
|
+
'executionArn': response['executionArn'],
|
|
91
|
+
's3Location': f's3://{bucket}/{key}'
|
|
92
|
+
})
|
|
93
|
+
else:
|
|
94
|
+
print(f"Skipping")
|
|
95
|
+
|
|
96
|
+
except Exception as error:
|
|
97
|
+
metrics.add_metric(name="FailedToProcessed", unit=MetricUnit.Count, value=1)
|
|
98
|
+
print(f'Error processing SQS record: {record["messageId"]} {str(error)}')
|
|
99
|
+
|
|
100
|
+
# Re-raise error to trigger SQS retry mechanism
|
|
101
|
+
# After max retries, message will go to Dead Letter Queue
|
|
102
|
+
raise Exception(f'Failed to process SQS record {record["messageId"]}: {str(error)}')
|
|
103
|
+
|
|
104
|
+
metrics.add_metric(name="SuccessfullyProcessed", unit=MetricUnit.Count, value=len(results))
|
|
105
|
+
print(f'Successfully processed {len(results)} documents: {results}')
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
'statusCode': 200,
|
|
109
|
+
'processedCount': len(results),
|
|
110
|
+
'results': results
|
|
111
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Records": [
|
|
3
|
+
{
|
|
4
|
+
"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
|
|
5
|
+
"receiptHandle": "MessageReceiptHandle",
|
|
6
|
+
"body": "{\"Records\":[{\"eventVersion\":\"2.1\",\"eventSource\":\"aws:s3\",\"awsRegion\":\"us-east-1\",\"eventTime\":\"2024-01-15T10:30:00.000Z\",\"eventName\":\"ObjectCreated:Put\",\"userIdentity\":{\"principalId\":\"EXAMPLE\"},\"requestParameters\":{\"sourceIPAddress\":\"127.0.0.1\"},\"responseElements\":{\"x-amz-request-id\":\"EXAMPLE123456789\",\"x-amz-id-2\":\"EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH\"},\"s3\":{\"s3SchemaVersion\":\"1.0\",\"configurationId\":\"testConfigRule\",\"bucket\":{\"name\":\"my-document-bucket\",\"ownerIdentity\":{\"principalId\":\"EXAMPLE\"},\"arn\":\"arn:aws:s3:::my-document-bucket\"},\"object\":{\"key\":\"raw/invoice-2024-001.pdf\",\"size\":1024,\"eTag\":\"0123456789abcdef0123456789abcdef\",\"sequencer\":\"0A1B2C3D4E5F678901\"}}}]}",
|
|
7
|
+
"attributes": {
|
|
8
|
+
"ApproximateReceiveCount": "1",
|
|
9
|
+
"SentTimestamp": "1705315800000",
|
|
10
|
+
"SenderId": "AIDACKCEVSQ6C2EXAMPLE",
|
|
11
|
+
"ApproximateFirstReceiveTimestamp": "1705315800000"
|
|
12
|
+
},
|
|
13
|
+
"messageAttributes": {},
|
|
14
|
+
"md5OfBody": "7b270e59b47ff90a553787216d55d91d",
|
|
15
|
+
"eventSource": "aws:sqs",
|
|
16
|
+
"eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:my-queue",
|
|
17
|
+
"awsRegion": "us-east-1"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Records": [
|
|
3
|
+
{
|
|
4
|
+
"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
|
|
5
|
+
"receiptHandle": "MessageReceiptHandle1",
|
|
6
|
+
"body": "{\"Records\":[{\"eventVersion\":\"2.1\",\"eventSource\":\"aws:s3\",\"awsRegion\":\"us-east-1\",\"eventTime\":\"2024-01-15T10:30:00.000Z\",\"eventName\":\"ObjectCreated:Put\",\"s3\":{\"s3SchemaVersion\":\"1.0\",\"bucket\":{\"name\":\"my-document-bucket\"},\"object\":{\"key\":\"raw/receipt-scan.jpg\",\"size\":2048}}}]}",
|
|
7
|
+
"attributes": {
|
|
8
|
+
"ApproximateReceiveCount": "1"
|
|
9
|
+
},
|
|
10
|
+
"eventSource": "aws:sqs",
|
|
11
|
+
"awsRegion": "us-east-1"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"messageId": "29dd0b57-b21e-4ac1-bd88-01bbb068cb79",
|
|
15
|
+
"receiptHandle": "MessageReceiptHandle2",
|
|
16
|
+
"body": "{\"Records\":[{\"eventVersion\":\"2.1\",\"eventSource\":\"aws:s3\",\"awsRegion\":\"us-east-1\",\"eventTime\":\"2024-01-15T10:31:00.000Z\",\"eventName\":\"ObjectCreated:Put\",\"s3\":{\"s3SchemaVersion\":\"1.0\",\"bucket\":{\"name\":\"my-document-bucket\"},\"object\":{\"key\":\"raw/contract%20document.pdf\",\"size\":4096}}}]}",
|
|
17
|
+
"attributes": {
|
|
18
|
+
"ApproximateReceiveCount": "1"
|
|
19
|
+
},
|
|
20
|
+
"eventSource": "aws:sqs",
|
|
21
|
+
"awsRegion": "us-east-1"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import boto3
|
|
2
|
+
import os
|
|
3
|
+
import json
|
|
4
|
+
from strands import Agent, tool
|
|
5
|
+
from strands_tools import file_read
|
|
6
|
+
from aws_lambda_powertools import Metrics, Tracer
|
|
7
|
+
from aws_lambda_powertools.metrics import MetricUnit
|
|
8
|
+
|
|
9
|
+
s3 = boto3.client('s3')
|
|
10
|
+
metrics = Metrics()
|
|
11
|
+
tracer = Tracer()
|
|
12
|
+
|
|
13
|
+
@tracer.capture_method
|
|
14
|
+
def extract_json_from_text(text):
|
|
15
|
+
"""Extract JSON object from text body enclosed in ```json blocks or raw JSON."""
|
|
16
|
+
import re
|
|
17
|
+
|
|
18
|
+
# First try to find JSON in ```json blocks
|
|
19
|
+
match = re.search(r'```json\s*({.*?})\s*```', text, re.DOTALL)
|
|
20
|
+
if match:
|
|
21
|
+
try:
|
|
22
|
+
return json.loads(match.group(1))
|
|
23
|
+
except json.JSONDecodeError:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
# If no ```json blocks, look for raw JSON objects in the text
|
|
27
|
+
json_match = re.search(r'({[^{}]*(?:{[^{}]*}[^{}]*)*})', text, re.DOTALL)
|
|
28
|
+
if json_match:
|
|
29
|
+
try:
|
|
30
|
+
return json.loads(json_match.group(1))
|
|
31
|
+
except json.JSONDecodeError:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
return None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@tracer.capture_method
|
|
38
|
+
def download_tools():
|
|
39
|
+
tools = json.loads(os.environ['TOOLS_CONFIG'])
|
|
40
|
+
tools_arr = []
|
|
41
|
+
for tool in tools:
|
|
42
|
+
bucket, key, filename = parse_s3_path(tool)
|
|
43
|
+
local_path = f"/tmp/{filename}"
|
|
44
|
+
s3.download_file(bucket, key, local_path)
|
|
45
|
+
tools_arr.append(local_path)
|
|
46
|
+
|
|
47
|
+
return tools_arr
|
|
48
|
+
|
|
49
|
+
@tracer.capture_method
|
|
50
|
+
def parse_s3_path(s3_path):
|
|
51
|
+
# Remove s3:// prefix if present
|
|
52
|
+
path = s3_path.replace('s3://', '')
|
|
53
|
+
|
|
54
|
+
# Split into parts
|
|
55
|
+
parts = path.split('/', 1)
|
|
56
|
+
bucket = parts[0]
|
|
57
|
+
|
|
58
|
+
if len(parts) == 1:
|
|
59
|
+
return bucket, '', ''
|
|
60
|
+
|
|
61
|
+
# Key is the prefix (includes filename)
|
|
62
|
+
prefix = parts[1]
|
|
63
|
+
filename = prefix.split('/')[-1]
|
|
64
|
+
|
|
65
|
+
return bucket, prefix, filename
|
|
66
|
+
|
|
67
|
+
@tracer.capture_method
|
|
68
|
+
def download_attached_document(event):
|
|
69
|
+
bucket = event['bucket']
|
|
70
|
+
key = event['key']
|
|
71
|
+
|
|
72
|
+
# Download file to /tmp
|
|
73
|
+
local_path = f"/tmp/{key.split('/')[-1]}"
|
|
74
|
+
s3.download_file(bucket, key, local_path)
|
|
75
|
+
|
|
76
|
+
return local_path
|
|
77
|
+
|
|
78
|
+
agent_tools = download_tools()
|
|
79
|
+
|
|
80
|
+
@metrics.log_metrics
|
|
81
|
+
@tracer.capture_lambda_handler
|
|
82
|
+
def handler(event, context):
|
|
83
|
+
model_id = os.getenv("MODEL_ID")
|
|
84
|
+
prompt = os.getenv("PROMPT")
|
|
85
|
+
system_prompt = os.getenv("SYSTEM_PROMPT")
|
|
86
|
+
invoke_type = os.environ["INVOKE_TYPE"]
|
|
87
|
+
|
|
88
|
+
tracer.put_annotation(key="invoke_type", value=invoke_type)
|
|
89
|
+
metrics.add_dimension(name="invoke_type", value=invoke_type)
|
|
90
|
+
|
|
91
|
+
if prompt is None:
|
|
92
|
+
prompt = "Analyze the attached document and verify the information using the provided tools."
|
|
93
|
+
|
|
94
|
+
if system_prompt is None:
|
|
95
|
+
system_prompt = "You're a document analysis specialist. You specialized in analyzing provided documents using the tools that have been provided."
|
|
96
|
+
|
|
97
|
+
local_path_attached_doc = download_attached_document(event)
|
|
98
|
+
|
|
99
|
+
if 'classificationResult' in event:
|
|
100
|
+
classification = event['classificationResult']['documentClassification']
|
|
101
|
+
prompt = prompt.replace("[ACTUAL_CLASSIFICATION]", classification)
|
|
102
|
+
|
|
103
|
+
prompt += f" Attached document is located in {local_path_attached_doc}"
|
|
104
|
+
|
|
105
|
+
agent = Agent(model=model_id, tools=agent_tools + [file_read], system_prompt=system_prompt)
|
|
106
|
+
response = agent(prompt)
|
|
107
|
+
|
|
108
|
+
metrics.add_metric(name="SuccessfulAgentInvocation", unit=MetricUnit.Count, value=1)
|
|
109
|
+
return {
|
|
110
|
+
"result": extract_json_from_text(response.message["content"][0]["text"])
|
|
111
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
4
|
+
const assertions_1 = require("aws-cdk-lib/assertions");
|
|
5
|
+
const aws_s3_1 = require("aws-cdk-lib/aws-s3");
|
|
6
|
+
const cdk_nag_1 = require("cdk-nag");
|
|
7
|
+
const framework_1 = require("../../framework");
|
|
8
|
+
const agentic_document_processing_1 = require("../agentic-document-processing");
|
|
9
|
+
// Create app and stack
|
|
10
|
+
const app = new aws_cdk_lib_1.App();
|
|
11
|
+
const stack = new aws_cdk_lib_1.Stack(app, 'TestStack', {
|
|
12
|
+
env: {
|
|
13
|
+
account: '123456789012',
|
|
14
|
+
region: 'us-east-1',
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
const accessLog = new framework_1.AccessLog(stack, 'AccessLog');
|
|
18
|
+
// Create S3 bucket for agentic tools
|
|
19
|
+
const bucket = new aws_s3_1.Bucket(stack, 'AgenticDocumentProcessingBucket', {
|
|
20
|
+
serverAccessLogsBucket: accessLog.bucket,
|
|
21
|
+
serverAccessLogsPrefix: accessLog.bucketPrefix,
|
|
22
|
+
enforceSSL: true,
|
|
23
|
+
});
|
|
24
|
+
// Create the main AgenticDocumentProcessing construct
|
|
25
|
+
new agentic_document_processing_1.AgenticDocumentProcessing(stack, 'AgenticDocumentProcessing', {
|
|
26
|
+
bucket,
|
|
27
|
+
useCrossRegionInference: true,
|
|
28
|
+
processingAgentParameters: {
|
|
29
|
+
agentSystemPrompt: `
|
|
30
|
+
You're an insurance claims specialist. Use the provided tools to ensure that the submitted claims and supporting documents are valid and there are no discrepancies.
|
|
31
|
+
`,
|
|
32
|
+
toolsLocation: [
|
|
33
|
+
`s3://${bucket.bucketName}/agentic-tools/download_policy.py`,
|
|
34
|
+
`s3://${bucket.bucketName}/agentic-tools/download_supporting_documents.py`,
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
processingPrompt: `
|
|
38
|
+
Analyze the attached insurance claim document and check if this is a valid claim or not.
|
|
39
|
+
Final output should in JSON format with claim_approved and justification fields.
|
|
40
|
+
`,
|
|
41
|
+
enableObservability: true,
|
|
42
|
+
});
|
|
43
|
+
// Suppress CDK-managed BucketNotificationsHandler AWS managed policy
|
|
44
|
+
cdk_nag_1.NagSuppressions.addResourceSuppressionsByPath(stack, '/TestStack/BucketNotificationsHandler050a0587b7544547bf325f094a3db834/Role', [
|
|
45
|
+
{
|
|
46
|
+
id: 'AwsSolutions-IAM4',
|
|
47
|
+
reason: 'CDK-managed BucketNotificationsHandler requires AWSLambdaBasicExecutionRole for S3 event processing',
|
|
48
|
+
appliesTo: ['Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'],
|
|
49
|
+
},
|
|
50
|
+
]);
|
|
51
|
+
// Suppress S3 bucket wildcard permissions for Lambda roles
|
|
52
|
+
cdk_nag_1.NagSuppressions.addResourceSuppressions(stack, [
|
|
53
|
+
{
|
|
54
|
+
id: 'AwsSolutions-IAM5',
|
|
55
|
+
reason: 'Lambda functions require wildcard access to S3 bucket objects for document processing',
|
|
56
|
+
appliesTo: ['Resource::<AgenticDocumentProcessingBucketC4E254EC.Arn>/*'],
|
|
57
|
+
},
|
|
58
|
+
], true);
|
|
59
|
+
// Suppress Bedrock foundation model wildcard permissions
|
|
60
|
+
cdk_nag_1.NagSuppressions.addResourceSuppressions(stack, [
|
|
61
|
+
{
|
|
62
|
+
id: 'AwsSolutions-IAM5',
|
|
63
|
+
reason: 'Cross-region inference requires wildcard region access to Bedrock foundation models',
|
|
64
|
+
appliesTo: ['Resource::arn:aws:bedrock:*::foundation-model/anthropic.claude-3-7-sonnet-20250219-v1:0'],
|
|
65
|
+
},
|
|
66
|
+
], true);
|
|
67
|
+
// Suppress SQSConsumerRole wildcard permissions for Lambda log streams
|
|
68
|
+
cdk_nag_1.NagSuppressions.addResourceSuppressions(stack, [
|
|
69
|
+
{
|
|
70
|
+
id: 'AwsSolutions-IAM5',
|
|
71
|
+
reason: 'Lambda log stream ARN is only known at runtime, wildcard required for CloudWatch Logs access',
|
|
72
|
+
},
|
|
73
|
+
], true);
|
|
74
|
+
// Suppress StateMachineRole wildcard permissions for Lambda invocation
|
|
75
|
+
cdk_nag_1.NagSuppressions.addResourceSuppressionsByPath(stack, '/TestStack/AgenticDocumentProcessing/StateMachineRole/DefaultPolicy', [
|
|
76
|
+
{
|
|
77
|
+
id: 'AwsSolutions-IAM5',
|
|
78
|
+
reason: 'Step Functions requires wildcard permissions to invoke Lambda functions with version-specific ARNs',
|
|
79
|
+
},
|
|
80
|
+
]);
|
|
81
|
+
// Suppress Lambda log group wildcard permissions
|
|
82
|
+
cdk_nag_1.NagSuppressions.addResourceSuppressions(stack, [
|
|
83
|
+
{
|
|
84
|
+
id: 'AwsSolutions-IAM5',
|
|
85
|
+
reason: 'Lambda log stream names are generated at runtime, wildcard required for CloudWatch Logs access',
|
|
86
|
+
},
|
|
87
|
+
], true);
|
|
88
|
+
// Apply CDK Nag checks
|
|
89
|
+
aws_cdk_lib_1.Aspects.of(app).add(new cdk_nag_1.AwsSolutionsChecks({ verbose: true }));
|
|
90
|
+
// Synthesize the stack and check for unsuppressed warnings and errors
|
|
91
|
+
const warnings = assertions_1.Annotations.fromStack(stack).findWarning('*', assertions_1.Match.stringLikeRegexp('AwsSolutions-.*'));
|
|
92
|
+
const errors = assertions_1.Annotations.fromStack(stack).findError('*', assertions_1.Match.stringLikeRegexp('AwsSolutions-.*'));
|
|
93
|
+
// Test: No unsuppressed warnings
|
|
94
|
+
test('No unsuppressed warnings', () => {
|
|
95
|
+
if (warnings.length > 0) {
|
|
96
|
+
console.log('CDK Nag Warnings:', JSON.stringify(warnings, null, 2));
|
|
97
|
+
}
|
|
98
|
+
expect(warnings).toHaveLength(0);
|
|
99
|
+
});
|
|
100
|
+
// Test: No unsuppressed errors
|
|
101
|
+
test('No unsuppressed errors', () => {
|
|
102
|
+
if (errors.length > 0) {
|
|
103
|
+
console.log('CDK Nag Errors:', JSON.stringify(errors, null, 2));
|
|
104
|
+
}
|
|
105
|
+
expect(errors).toHaveLength(0);
|
|
106
|
+
});
|
|
107
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnRpYy1kb2N1bWVudC1wcm9jZXNzaW5nLW5hZy50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdXNlLWNhc2VzL2RvY3VtZW50LXByb2Nlc3NpbmcvdGVzdHMvYWdlbnRpYy1kb2N1bWVudC1wcm9jZXNzaW5nLW5hZy50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsNkNBQWtEO0FBQ2xELHVEQUE0RDtBQUM1RCwrQ0FBNEM7QUFDNUMscUNBQThEO0FBQzlELCtDQUE0QztBQUM1QyxnRkFBMkU7QUFFM0UsdUJBQXVCO0FBQ3ZCLE1BQU0sR0FBRyxHQUFHLElBQUksaUJBQUcsRUFBRSxDQUFDO0FBQ3RCLE1BQU0sS0FBSyxHQUFHLElBQUksbUJBQUssQ0FBQyxHQUFHLEVBQUUsV0FBVyxFQUFFO0lBQ3hDLEdBQUcsRUFBRTtRQUNILE9BQU8sRUFBRSxjQUFjO1FBQ3ZCLE1BQU0sRUFBRSxXQUFXO0tBQ3BCO0NBQ0YsQ0FBQyxDQUFDO0FBRUgsTUFBTSxTQUFTLEdBQUcsSUFBSSxxQkFBUyxDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsQ0FBQztBQUVwRCxxQ0FBcUM7QUFDckMsTUFBTSxNQUFNLEdBQUcsSUFBSSxlQUFNLENBQUMsS0FBSyxFQUFFLGlDQUFpQyxFQUFFO0lBQ2xFLHNCQUFzQixFQUFFLFNBQVMsQ0FBQyxNQUFNO0lBQ3hDLHNCQUFzQixFQUFFLFNBQVMsQ0FBQyxZQUFZO0lBQzlDLFVBQVUsRUFBRSxJQUFJO0NBQ2pCLENBQUMsQ0FBQztBQUVILHNEQUFzRDtBQUN0RCxJQUFJLHVEQUF5QixDQUFDLEtBQUssRUFBRSwyQkFBMkIsRUFBRTtJQUNoRSxNQUFNO0lBQ04sdUJBQXVCLEVBQUUsSUFBSTtJQUM3Qix5QkFBeUIsRUFBRTtRQUN6QixpQkFBaUIsRUFBRTs7S0FFbEI7UUFDRCxhQUFhLEVBQUU7WUFDYixRQUFRLE1BQU0sQ0FBQyxVQUFVLG1DQUFtQztZQUM1RCxRQUFRLE1BQU0s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QVMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEUsQ0FBQztJQUNELE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDakMsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBcHAsIFN0YWNrLCBBc3BlY3RzIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgQW5ub3RhdGlvbnMsIE1hdGNoIH0gZnJvbSAnYXdzLWNkay1saWIvYXNzZXJ0aW9ucyc7XG5pbXBvcnQgeyBCdWNrZXQgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtczMnO1xuaW1wb3J0IHsgQXdzU29sdXRpb25zQ2hlY2tzLCBOYWdTdXBwcmVzc2lvbnMgfSBmcm9tICdjZGstbmFnJztcbmltcG9ydCB7IEFjY2Vzc0xvZyB9IGZyb20gJy4uLy4uL2ZyYW1ld29yayc7XG5pbXBvcnQgeyBBZ2VudGljRG9jdW1lbnRQcm9jZXNzaW5nIH0gZnJvbSAnLi4vYWdlbnRpYy1kb2N1bWVudC1wcm9jZXNzaW5nJztcblxuLy8gQ3JlYXRlIGFwcCBhbmQgc3RhY2tcbmNvbnN0IGFwcCA9IG5ldyBBcHAoKTtcbmNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKGFwcCwgJ1Rlc3RTdGFjaycsIHtcbiAgZW52OiB7XG4gICAgYWNjb3VudDogJzEyMzQ1Njc4OTAxMicsXG4gICAgcmVnaW9uOiAndXMtZWFzdC0xJyxcbiAgfSxcbn0pO1xuXG5jb25zdCBhY2Nlc3NMb2cgPSBuZXcgQWNjZXNzTG9nKHN0YWNrLCAnQWNjZXNzTG9nJyk7XG5cbi8vIENyZWF0ZSBTMyBidWNrZXQgZm9yIGFnZW50aWMgdG9vbHNcbmNvbnN0IGJ1Y2tldCA9IG5ldyBCdWNrZXQoc3RhY2ssICdBZ2VudGljRG9jdW1lbnRQcm9jZXNzaW5nQnVja2V0Jywge1xuICBzZXJ2ZXJBY2Nlc3NMb2dzQnVja2V0OiBhY2Nlc3NMb2cuYnVja2V0LFxuICBzZXJ2ZXJBY2Nlc3NMb2dzUHJlZml4OiBhY2Nlc3NMb2cuYnVja2V0UHJlZml4LFxuICBlbmZvcmNlU1NMOiB0cnVlLFxufSk7XG5cbi8vIENyZWF0ZSB0aGUgbWFpbiBBZ2VudGljRG9jdW1lbnRQcm9jZXNzaW5nIGNvbnN0cnVjdFxubmV3IEFnZW50aWNEb2N1bWVudFByb2Nlc3Npbmcoc3RhY2ssICdBZ2VudGljRG9jdW1lbnRQcm9jZXNzaW5nJywge1xuICBidWNrZXQsXG4gIHVzZUNyb3NzUmVnaW9uSW5mZXJlbmNlOiB0cnVlLFxuICBwcm9jZXNzaW5nQWdlbnRQYXJhbWV0ZXJzOiB7XG4gICAgYWdlbnRTeXN0ZW1Qcm9tcHQ6IGBcbiAgICAgIFlvdSdyZSBhbiBpbnN1cmFuY2UgY2xhaW1zIHNwZWNpYWxpc3QuIFVzZSB0aGUgcHJvdmlkZWQgdG9vbHMgdG8gZW5zdXJlIHRoYXQgdGhlIHN1Ym1pdHRlZCBjbGFpbXMgYW5kIHN1cHBvcnRpbmcgZG9jdW1lbnRzIGFyZSB2YWxpZCBhbmQgdGhlcmUgYXJlIG5vIGRpc2NyZXBhbmNpZXMuXG4gICAgYCxcbiAgICB0b29sc0xvY2F0aW9uOiBbXG4gICAgICBgczM6Ly8ke2J1Y2tldC5idWNrZXROYW1lfS9hZ2VudGljLXRvb2xzL2Rvd25sb2FkX3BvbGljeS5weWAsXG4gICAgICBgczM6Ly8ke2J1Y2tldC5idWNrZXROYW1lfS9hZ2VudGljLXRvb2xzL2Rvd25sb2FkX3N1cHBvcnRpbmdfZG9jdW1lbnRzLnB5YCxcbiAgICBdLFxuICB9LFxuICBwcm9jZXNzaW5nUHJvbXB0OiBgXG4gICAgQW5hbHl6ZSB0aGUgYXR0YWNoZWQgaW5zdXJhbmNlIGNsYWltIGRvY3VtZW50IGFuZCBjaGVjayBpZiB0aGlzIGlzIGEgdmFsaWQgY2xhaW0gb3Igbm90LlxuICAgIEZpbmFsIG91dHB1dCBzaG91bGQgaW4gSlNPTiBmb3JtYXQgd2l0aCBjbGFpbV9hcHByb3ZlZCBhbmQganVzdGlmaWNhdGlvbiBmaWVsZHMuXG4gIGAsXG4gIGVuYWJsZU9ic2VydmFiaWxpdHk6IHRydWUsXG59KTtcblxuLy8gU3VwcHJlc3MgQ0RLLW1hbmFnZWQgQnVja2V0Tm90aWZpY2F0aW9uc0hhbmRsZXIgQVdTIG1hbmFnZWQgcG9saWN5XG5OYWdTdXBwcmVzc2lvbnMuYWRkUmVzb3VyY2VTdXBwcmVzc2lvbnNCeVBhdGgoXG4gIHN0YWNrLFxuICAnL1Rlc3RTdGFjay9CdWNrZXROb3RpZmljYXRpb25zSGFuZGxlcjA1MGEwNTg3Yjc1NDQ1NDdiZjMyNWYwOTRhM2RiODM0L1JvbGUnLFxuICBbXG4gICAge1xuICAgICAgaWQ6ICdBd3NTb2x1dGlvbnMtSUFNNCcsXG4gICAgICByZWFzb246ICdDREstbWFuYWdlZCBCdWNrZXROb3RpZmljYXRpb25zSGFuZGxlciByZXF1aXJlcyBBV1NMYW1iZGFCYXNpY0V4ZWN1dGlvblJvbGUgZm9yIFMzIGV2ZW50IHByb2Nlc3NpbmcnLFxuICAgICAgYXBwbGllc1RvOiBbJ1BvbGljeTo6YXJuOjxBV1M6OlBhcnRpdGlvbj46aWFtOjphd3M6cG9saWN5L3NlcnZpY2Utcm9sZS9BV1NMYW1iZGFCYXNpY0V4ZWN1dGlvblJvbGUnXSxcbiAgICB9LFxuICBdLFxuKTtcblxuLy8gU3VwcHJlc3MgUzMgYnVja2V0IHdpbGRjYXJkIHBlcm1pc3Npb25zIGZvciBMYW1iZGEgcm9sZXNcbk5hZ1N1cHByZXNzaW9ucy5hZGRSZXNvdXJjZVN1cHByZXNzaW9ucyhcbiAgc3RhY2ssXG4gIFtcbiAgICB7XG4gICAgICBpZDogJ0F3c1NvbHV0aW9ucy1JQU01JyxcbiAgICAgIHJlYXNvbjogJ0xhbWJkYSBmdW5jdGlvbnMgcmVxdWlyZSB3aWxkY2FyZCBhY2Nlc3MgdG8gUzMgYnVja2V0IG9iamVjdHMgZm9yIGRvY3VtZW50IHByb2Nlc3NpbmcnLFxuICAgICAgYXBwbGllc1RvOiBbJ1Jlc291cmNlOjo8QWdlbnRpY0RvY3VtZW50UHJvY2Vzc2luZ0J1Y2tldEM0RTI1NEVDLkFybj4vKiddLFxuICAgIH0sXG4gIF0sXG4gIHRydWUsXG4pO1xuXG4vLyBTdXBwcmVzcyBCZWRyb2NrIGZvdW5kYXRpb24gbW9kZWwgd2lsZGNhcmQgcGVybWlzc2lvbnNcbk5hZ1N1cHByZXNzaW9ucy5hZGRSZXNvdXJjZVN1cHByZXNzaW9ucyhcbiAgc3RhY2ssXG4gIFtcbiAgICB7XG4gICAgICBpZDogJ0F3c1NvbHV0aW9ucy1JQU01JyxcbiAgICAgIHJlYXNvbjogJ0Nyb3NzLXJlZ2lvbiBpbmZlcmVuY2UgcmVxdWlyZXMgd2lsZGNhcmQgcmVnaW9uIGFjY2VzcyB0byBCZWRyb2NrIGZvdW5kYXRpb24gbW9kZWxzJyxcbiAgICAgIGFwcGxpZXNUbzogWydSZXNvdXJjZTo6YXJuOmF3czpiZWRyb2NrOio6OmZvdW5kYXRpb24tbW9kZWwvYW50aHJvcGljLmNsYXVkZS0zLTctc29ubmV0LTIwMjUwMjE5LXYxOjAnXSxcbiAgICB9LFxuICBdLFxuICB0cnVlLFxuKTtcblxuLy8gU3VwcHJlc3MgU1FTQ29uc3VtZXJSb2xlIHdpbGRjYXJkIHBlcm1pc3Npb25zIGZvciBMYW1iZGEgbG9nIHN0cmVhbXNcbk5hZ1N1cHByZXNzaW9ucy5hZGRSZXNvdXJjZVN1cHByZXNzaW9ucyhcbiAgc3RhY2ssXG4gIFtcbiAgICB7XG4gICAgICBpZDogJ0F3c1NvbHV0aW9ucy1JQU01JyxcbiAgICAgIHJlYXNvbjogJ0xhbWJkYSBsb2cgc3RyZWFtIEFSTiBpcyBvbmx5IGtub3duIGF0IHJ1bnRpbWUsIHdpbGRjYXJkIHJlcXVpcmVkIGZvciBDbG91ZFdhdGNoIExvZ3MgYWNjZXNzJyxcbiAgICB9LFxuICBdLFxuICB0cnVlLFxuKTtcblxuLy8gU3VwcHJlc3MgU3RhdGVNYWNoaW5lUm9sZSB3aWxkY2FyZCBwZXJtaXNzaW9ucyBmb3IgTGFtYmRhIGludm9jYXRpb25cbk5hZ1N1cHByZXNzaW9ucy5hZGRSZXNvdXJjZVN1cHByZXNzaW9uc0J5UGF0aChcbiAgc3RhY2ssXG4gICcvVGVzdFN0YWNrL0FnZW50aWNEb2N1bWVudFByb2Nlc3NpbmcvU3RhdGVNYWNoaW5lUm9sZS9EZWZhdWx0UG9saWN5JyxcbiAgW1xuICAgIHtcbiAgICAgIGlkOiAnQXdzU29sdXRpb25zLUlBTTUnLFxuICAgICAgcmVhc29uOiAnU3RlcCBGdW5jdGlvbnMgcmVxdWlyZXMgd2lsZGNhcmQgcGVybWlzc2lvbnMgdG8gaW52b2tlIExhbWJkYSBmdW5jdGlvbnMgd2l0aCB2ZXJzaW9uLXNwZWNpZmljIEFSTnMnLFxuICAgIH0sXG4gIF0sXG4pO1xuXG4vLyBTdXBwcmVzcyBMYW1iZGEgbG9nIGdyb3VwIHdpbGRjYXJkIHBlcm1pc3Npb25zXG5OYWdTdXBwcmVzc2lvbnMuYWRkUmVzb3VyY2VTdXBwcmVzc2lvbnMoXG4gIHN0YWNrLFxuICBbXG4gICAge1xuICAgICAgaWQ6ICdBd3NTb2x1dGlvbnMtSUFNNScsXG4gICAgICByZWFzb246ICdMYW1iZGEgbG9nIHN0cmVhbSBuYW1lcyBhcmUgZ2VuZXJhdGVkIGF0IHJ1bnRpbWUsIHdpbGRjYXJkIHJlcXVpcmVkIGZvciBDbG91ZFdhdGNoIExvZ3MgYWNjZXNzJyxcbiAgICB9LFxuICBdLFxuICB0cnVlLFxuKTtcblxuXG4vLyBBcHBseSBDREsgTmFnIGNoZWNrc1xuQXNwZWN0cy5vZihhcHApLmFkZChuZXcgQXdzU29sdXRpb25zQ2hlY2tzKHsgdmVyYm9zZTogdHJ1ZSB9KSk7XG5cbi8vIFN5bnRoZXNpemUgdGhlIHN0YWNrIGFuZCBjaGVjayBmb3IgdW5zdXBwcmVzc2VkIHdhcm5pbmdzIGFuZCBlcnJvcnNcbmNvbnN0IHdhcm5pbmdzID0gQW5ub3RhdGlvbnMuZnJvbVN0YWNrKHN0YWNrKS5maW5kV2FybmluZygnKicsIE1hdGNoLnN0cmluZ0xpa2VSZWdleHAoJ0F3c1NvbHV0aW9ucy0uKicpKTtcbmNvbnN0IGVycm9ycyA9IEFubm90YXRpb25zLmZyb21TdGFjayhzdGFjaykuZmluZEVycm9yKCcqJywgTWF0Y2guc3RyaW5nTGlrZVJlZ2V4cCgnQXdzU29sdXRpb25zLS4qJykpO1xuXG4vLyBUZXN0OiBObyB1bnN1cHByZXNzZWQgd2FybmluZ3NcbnRlc3QoJ05vIHVuc3VwcHJlc3NlZCB3YXJuaW5ncycsICgpID0+IHtcbiAgaWYgKHdhcm5pbmdzLmxlbmd0aCA+IDApIHtcbiAgICBjb25zb2xlLmxvZygnQ0RLIE5hZyBXYXJuaW5nczonLCBKU09OLnN0cmluZ2lmeSh3YXJuaW5ncywgbnVsbCwgMikpO1xuICB9XG4gIGV4cGVjdCh3YXJuaW5ncykudG9IYXZlTGVuZ3RoKDApO1xufSk7XG5cbi8vIFRlc3Q6IE5vIHVuc3VwcHJlc3NlZCBlcnJvcnNcbnRlc3QoJ05vIHVuc3VwcHJlc3NlZCBlcnJvcnMnLCAoKSA9PiB7XG4gIGlmIChlcnJvcnMubGVuZ3RoID4gMCkge1xuICAgIGNvbnNvbGUubG9nKCdDREsgTmFnIEVycm9yczonLCBKU09OLnN0cmluZ2lmeShlcnJvcnMsIG51bGwsIDIpKTtcbiAgfVxuICBleHBlY3QoZXJyb3JzKS50b0hhdmVMZW5ndGgoMCk7XG59KTtcbiJdfQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|