@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.
Files changed (105) hide show
  1. package/.jsii +8644 -0
  2. package/LICENSE +202 -0
  3. package/README.md +212 -0
  4. package/lib/document-processing/agentic-document-processing.d.ts +16 -0
  5. package/lib/document-processing/agentic-document-processing.js +90 -0
  6. package/lib/document-processing/base-document-processing.d.ts +189 -0
  7. package/lib/document-processing/base-document-processing.js +509 -0
  8. package/lib/document-processing/bedrock-document-processing.d.ts +167 -0
  9. package/lib/document-processing/bedrock-document-processing.js +297 -0
  10. package/lib/document-processing/index.d.ts +3 -0
  11. package/lib/document-processing/index.js +20 -0
  12. package/lib/document-processing/resources/default-bedrock-invoke/index.py +63 -0
  13. package/lib/document-processing/resources/default-bedrock-invoke/requirements.txt +4 -0
  14. package/lib/document-processing/resources/default-doc-retrieval-lambda/index.mjs +92 -0
  15. package/lib/document-processing/resources/default-doc-retrieval-lambda/package.json +10 -0
  16. package/lib/document-processing/resources/default-error-handler/index.js +46 -0
  17. package/lib/document-processing/resources/default-error-handler/package.json +4 -0
  18. package/lib/document-processing/resources/default-image-processor/classifier.mjs +665 -0
  19. package/lib/document-processing/resources/default-image-processor/extractors.mjs +465 -0
  20. package/lib/document-processing/resources/default-image-processor/index.mjs +143 -0
  21. package/lib/document-processing/resources/default-image-processor/package-lock.json +12 -0
  22. package/lib/document-processing/resources/default-image-processor/package.json +4 -0
  23. package/lib/document-processing/resources/default-image-validator/index.mjs +76 -0
  24. package/lib/document-processing/resources/default-image-validator/package-lock.json +154 -0
  25. package/lib/document-processing/resources/default-image-validator/package.json +7 -0
  26. package/lib/document-processing/resources/default-pdf-processor/index.js +46 -0
  27. package/lib/document-processing/resources/default-pdf-validator/index.js +36 -0
  28. package/lib/document-processing/resources/default-sqs-consumer/index.py +111 -0
  29. package/lib/document-processing/resources/default-sqs-consumer/requirements.txt +4 -0
  30. package/lib/document-processing/resources/default-sqs-consumer/sample_payload.json +20 -0
  31. package/lib/document-processing/resources/default-sqs-consumer/sample_payload_multi.json +24 -0
  32. package/lib/document-processing/resources/default-strands-agent/index.py +111 -0
  33. package/lib/document-processing/resources/default-strands-agent/requirements.txt +6 -0
  34. package/lib/document-processing/tests/agentic-document-processing-nag.test.d.ts +1 -0
  35. package/lib/document-processing/tests/agentic-document-processing-nag.test.js +107 -0
  36. package/lib/document-processing/tests/agentic-document-processing.test.d.ts +1 -0
  37. package/lib/document-processing/tests/agentic-document-processing.test.js +125 -0
  38. package/lib/document-processing/tests/bedrock-document-processing-nag.test.d.ts +1 -0
  39. package/lib/document-processing/tests/bedrock-document-processing-nag.test.js +101 -0
  40. package/lib/document-processing/tests/bedrock-document-processing.test.d.ts +1 -0
  41. package/lib/document-processing/tests/bedrock-document-processing.test.js +79 -0
  42. package/lib/framework/custom-resource/default-runtimes.d.ts +21 -0
  43. package/lib/framework/custom-resource/default-runtimes.js +34 -0
  44. package/lib/framework/custom-resource/index.d.ts +1 -0
  45. package/lib/framework/custom-resource/index.js +18 -0
  46. package/lib/framework/foundation/access-log.d.ts +69 -0
  47. package/lib/framework/foundation/access-log.js +121 -0
  48. package/lib/framework/foundation/eventbridge-broker.d.ts +18 -0
  49. package/lib/framework/foundation/eventbridge-broker.js +42 -0
  50. package/lib/framework/foundation/index.d.ts +3 -0
  51. package/lib/framework/foundation/index.js +20 -0
  52. package/lib/framework/foundation/network.d.ts +19 -0
  53. package/lib/framework/foundation/network.js +83 -0
  54. package/lib/framework/index.d.ts +2 -0
  55. package/lib/framework/index.js +19 -0
  56. package/lib/framework/quickstart/base-quickstart.d.ts +30 -0
  57. package/lib/framework/quickstart/base-quickstart.js +30 -0
  58. package/lib/index.d.ts +4 -0
  59. package/lib/index.js +21 -0
  60. package/lib/tsconfig.tsbuildinfo +1 -0
  61. package/lib/utilities/cdk-nag-config.d.ts +42 -0
  62. package/lib/utilities/cdk-nag-config.js +194 -0
  63. package/lib/utilities/data-loader-lambda/index.py +282 -0
  64. package/lib/utilities/data-loader-lambda/requirements.txt +3 -0
  65. package/lib/utilities/data-loader.d.ts +173 -0
  66. package/lib/utilities/data-loader.js +447 -0
  67. package/lib/utilities/index.d.ts +3 -0
  68. package/lib/utilities/index.js +20 -0
  69. package/lib/utilities/lambda-iam-utils.d.ts +145 -0
  70. package/lib/utilities/lambda-iam-utils.js +235 -0
  71. package/lib/utilities/lambda_layers/data-masking/layer-construct.d.ts +42 -0
  72. package/lib/utilities/lambda_layers/data-masking/layer-construct.js +53 -0
  73. package/lib/utilities/lambda_layers/data-masking/layer-construct.ts +88 -0
  74. package/lib/utilities/observability/bedrock-observability.d.ts +18 -0
  75. package/lib/utilities/observability/bedrock-observability.js +131 -0
  76. package/lib/utilities/observability/cloudfront-distribution-observability-property-injector.d.ts +6 -0
  77. package/lib/utilities/observability/cloudfront-distribution-observability-property-injector.js +22 -0
  78. package/lib/utilities/observability/index.d.ts +6 -0
  79. package/lib/utilities/observability/index.js +25 -0
  80. package/lib/utilities/observability/lambda-observability-property-injector.d.ts +8 -0
  81. package/lib/utilities/observability/lambda-observability-property-injector.js +43 -0
  82. package/lib/utilities/observability/log-group-data-protection-props.d.ts +19 -0
  83. package/lib/utilities/observability/log-group-data-protection-props.js +5 -0
  84. package/lib/utilities/observability/observability.d.ts +83 -0
  85. package/lib/utilities/observability/observability.js +278 -0
  86. package/lib/utilities/observability/observable.d.ts +32 -0
  87. package/lib/utilities/observability/observable.js +3 -0
  88. package/lib/utilities/observability/powertools-config.d.ts +3 -0
  89. package/lib/utilities/observability/powertools-config.js +25 -0
  90. package/lib/utilities/observability/resources/bedrock-manage-logging-configuration/index.py +27 -0
  91. package/lib/utilities/observability/state-machine-observability-property-injector.d.ts +8 -0
  92. package/lib/utilities/observability/state-machine-observability-property-injector.js +49 -0
  93. package/lib/utilities/tests/data-loader-nag.test.d.ts +1 -0
  94. package/lib/utilities/tests/data-loader-nag.test.js +432 -0
  95. package/lib/utilities/tests/data-loader.test.d.ts +1 -0
  96. package/lib/utilities/tests/data-loader.test.js +284 -0
  97. package/lib/webapp/frontend-construct.d.ts +136 -0
  98. package/lib/webapp/frontend-construct.js +253 -0
  99. package/lib/webapp/index.d.ts +1 -0
  100. package/lib/webapp/index.js +18 -0
  101. package/lib/webapp/tests/frontend-construct-nag.test.d.ts +1 -0
  102. package/lib/webapp/tests/frontend-construct-nag.test.js +266 -0
  103. package/lib/webapp/tests/frontend-construct.test.d.ts +1 -0
  104. package/lib/webapp/tests/frontend-construct.test.js +385 -0
  105. package/package.json +183 -0
@@ -0,0 +1,167 @@
1
+ import { Duration } from 'aws-cdk-lib';
2
+ import { FoundationModelIdentifier } from 'aws-cdk-lib/aws-bedrock';
3
+ import { Role } from 'aws-cdk-lib/aws-iam';
4
+ import { Function } from 'aws-cdk-lib/aws-lambda';
5
+ import { StateMachine } from 'aws-cdk-lib/aws-stepfunctions';
6
+ import { Construct } from 'constructs';
7
+ import { BaseDocumentProcessing, BaseDocumentProcessingProps, DocumentProcessingStepType } from './base-document-processing';
8
+ /**
9
+ * Configuration properties for BedrockDocumentProcessing construct.
10
+ * Extends BaseDocumentProcessingProps with Bedrock-specific options.
11
+ */
12
+ export interface BedrockDocumentProcessingProps extends BaseDocumentProcessingProps {
13
+ /**
14
+ * Bedrock foundation model for document classification step.
15
+ * @default FoundationModelIdentifier.ANTHROPIC_CLAUDE_3_7_SONNET_20250219_V1_0
16
+ */
17
+ readonly classificationModelId?: FoundationModelIdentifier;
18
+ /**
19
+ * Bedrock foundation model for document extraction step.
20
+ * @default FoundationModelIdentifier.ANTHROPIC_CLAUDE_3_7_SONNET_20250219_V1_0
21
+ */
22
+ readonly processingModelId?: FoundationModelIdentifier;
23
+ /**
24
+ * Custom prompt template for document classification.
25
+ * Must include placeholder for document content.
26
+ * @default DEFAULT_CLASSIFICATION_PROMPT
27
+ */
28
+ readonly classificationPrompt?: string;
29
+ /**
30
+ * Custom prompt template for document extraction.
31
+ * Must include placeholder for document content and classification result.
32
+ * @default DEFAULT_EXTRACTION_PROMPT
33
+ */
34
+ readonly processingPrompt?: string;
35
+ /**
36
+ * Optional Lambda function for document enrichment step.
37
+ * If provided, will be invoked after extraction with workflow state.
38
+ */
39
+ readonly enrichmentLambdaFunction?: Function;
40
+ /**
41
+ * Optional Lambda function for post-processing step.
42
+ * If provided, will be invoked after enrichment with workflow state.
43
+ */
44
+ readonly postProcessingLambdaFunction?: Function;
45
+ /**
46
+ * Timeout for individual Step Functions tasks (classification, extraction, etc.).
47
+ * @default Duration.minutes(5)
48
+ */
49
+ readonly stepTimeouts?: Duration;
50
+ /**
51
+ * Enable cross-region inference for Bedrock models to improve availability and performance.
52
+ * When enabled, uses inference profiles instead of direct model invocation.
53
+ * @default false
54
+ */
55
+ readonly useCrossRegionInference?: boolean;
56
+ /**
57
+ * Prefix for cross-region inference configuration.
58
+ * Only used when useCrossRegionInference is true.
59
+ * @default BedrockCrossRegionInferencePrefix.US
60
+ */
61
+ readonly crossRegionInferencePrefix?: BedrockCrossRegionInferencePrefix;
62
+ }
63
+ /**
64
+ * Cross-region inference prefix options for Bedrock models.
65
+ * Used to configure inference profiles for improved availability and performance.
66
+ */
67
+ export declare enum BedrockCrossRegionInferencePrefix {
68
+ /** US-based cross-region inference profile */
69
+ US = "us",
70
+ /** EU-based cross-region inference profile */
71
+ EU = "eu"
72
+ }
73
+ /**
74
+ * Document processing workflow powered by Amazon Bedrock foundation models.
75
+ *
76
+ * Extends BaseDocumentProcessing to provide AI-powered document classification and extraction
77
+ * using Amazon Bedrock foundation models. This implementation offers:
78
+ *
79
+ * ## Key Features
80
+ * - **AI-Powered Classification**: Uses Claude 3.7 Sonnet (configurable) to classify document types
81
+ * - **Intelligent Extraction**: Extracts structured data from documents using foundation models
82
+ * - **Cross-Region Inference**: Optional support for improved availability via inference profiles
83
+ * - **Flexible Processing**: Optional enrichment and post-processing Lambda functions
84
+ * - **Cost Optimized**: Configurable timeouts and model selection for cost control
85
+ *
86
+ * ## Processing Workflow
87
+ * S3 Upload → Classification (Bedrock) → Extraction (Bedrock) → [Enrichment] → [Post-Processing] → Results
88
+ *
89
+ * ## Default Models
90
+ * - Classification: Claude 3.7 Sonnet (anthropic.claude-3-7-sonnet-20250219-v1:0)
91
+ * - Extraction: Claude 3.7 Sonnet (anthropic.claude-3-7-sonnet-20250219-v1:0)
92
+ *
93
+ * ## Prompt Templates
94
+ * The construct uses default prompts that can be customized:
95
+ * - **Classification**: Analyzes document and returns JSON with documentClassification field
96
+ * - **Extraction**: Uses classification result to extract entities in structured JSON format
97
+ *
98
+ * ## Cross-Region Inference
99
+ * When enabled, uses Bedrock inference profiles for improved availability:
100
+ * - US prefix: Routes to US-based regions for lower latency
101
+ * - EU prefix: Routes to EU-based regions for data residency compliance
102
+ */
103
+ export declare class BedrockDocumentProcessing extends BaseDocumentProcessing {
104
+ protected static readonly DEFAULT_CLASSIFICATION_MODEL_ID: FoundationModelIdentifier;
105
+ protected static readonly DEFAULT_PROCESSING_MODEL_ID: FoundationModelIdentifier;
106
+ protected static readonly DEFAULT_CLASSIFICATION_PROMPT = "\n Analyze the document below, and classify the type of document it is (eg. INVOICE, IDENTITY_DOCUMENT, RECEIPT, etc). The result should be in JSON and should follow the following structure (only respond in JSON with the following structure and do not use markdown to indicate the json, just output plain old json with nothing else):\n\n {\n documentClassification: <CLASSIFICATION>\n }\n\n Attached document is as follows:\n\n ";
107
+ protected static readonly DEFAULT_PROCESSING_PROMPT = "\n The document below has been classified as [ACTUAL_CLASSIFICATION]. Extract important entities from the document and return the result as JSON following the structure below (only respond in JSON with the following structure and do not use markdown to indicate the json, just output plain old json with nothing else):\n\n {\n documentClassification: <CLASSIFICATION>,\n result: {\n entities: [\n {\n type: <TYPE OF ENTITY>\n value: <VALUE OF ENTITY>\n },\n ...\n ]\n }\n }\n\n Attached document is as follows:\n\n ";
108
+ /** Configuration properties specific to Bedrock document processing */
109
+ protected readonly bedrockDocumentProcessingProps: BedrockDocumentProcessingProps;
110
+ /** Cross-region inference prefix for Bedrock model routing */
111
+ protected readonly crossRegionInferencePrefix: BedrockCrossRegionInferencePrefix;
112
+ /** The Step Functions state machine that orchestrates the document processing workflow */
113
+ readonly stateMachine: StateMachine;
114
+ /**
115
+ * Creates a new BedrockDocumentProcessing construct.
116
+ *
117
+ * Initializes the Bedrock-powered document processing pipeline with AI classification
118
+ * and extraction capabilities. Creates Lambda functions with appropriate IAM roles
119
+ * for Bedrock model invocation and S3 access.
120
+ *
121
+ * @param scope - The scope in which to define this construct
122
+ * @param id - The scoped construct ID. Must be unique within the scope.
123
+ * @param props - Configuration properties for the Bedrock document processing pipeline
124
+ */
125
+ constructor(scope: Construct, id: string, props: BedrockDocumentProcessingProps);
126
+ /**
127
+ * Implements the document classification step using Amazon Bedrock.
128
+ *
129
+ * Creates a Lambda function that invokes the configured Bedrock model to classify
130
+ * the document type. The function reads the document from S3 and sends it to
131
+ * Bedrock with the classification prompt.
132
+ *
133
+ * @returns LambdaInvoke task configured for document classification
134
+ */
135
+ protected classificationStep(): DocumentProcessingStepType;
136
+ /**
137
+ * Implements the document extraction step using Amazon Bedrock.
138
+ *
139
+ * Creates a Lambda function that invokes the configured Bedrock model to extract
140
+ * structured data from the document. Uses the classification result from the
141
+ * previous step to provide context for more accurate extraction.
142
+ *
143
+ * @returns LambdaInvoke task configured for document extraction
144
+ */
145
+ protected processingStep(): DocumentProcessingStepType;
146
+ protected generateLambdaRoleForBedrock(fmModel: FoundationModelIdentifier, id: string): Role;
147
+ /**
148
+ * Implements the optional document enrichment step.
149
+ *
150
+ * If an enrichment Lambda function is provided in the props, creates a LambdaInvoke
151
+ * task to perform additional processing on the extracted data. This step is useful
152
+ * for data validation, transformation, or integration with external systems.
153
+ *
154
+ * @returns LambdaInvoke task for enrichment, or undefined to skip this step
155
+ */
156
+ protected enrichmentStep(): DocumentProcessingStepType | undefined;
157
+ /**
158
+ * Implements the optional post-processing step.
159
+ *
160
+ * If a post-processing Lambda function is provided in the props, creates a LambdaInvoke
161
+ * task to perform final processing on the workflow results. This step is useful for
162
+ * data formatting, notifications, or integration with downstream systems.
163
+ *
164
+ * @returns LambdaInvoke task for post-processing, or undefined to skip this step
165
+ */
166
+ protected postProcessingStep(): DocumentProcessingStepType | undefined;
167
+ }
@@ -0,0 +1,297 @@
1
+ "use strict";
2
+ var _a;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.BedrockDocumentProcessing = exports.BedrockCrossRegionInferencePrefix = void 0;
5
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
6
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
7
+ // SPDX-License-Identifier: Apache-2.0
8
+ const path = require("path");
9
+ const aws_lambda_python_alpha_1 = require("@aws-cdk/aws-lambda-python-alpha");
10
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
11
+ const aws_bedrock_1 = require("aws-cdk-lib/aws-bedrock");
12
+ const aws_ec2_1 = require("aws-cdk-lib/aws-ec2");
13
+ const aws_iam_1 = require("aws-cdk-lib/aws-iam");
14
+ const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
15
+ const aws_stepfunctions_tasks_1 = require("aws-cdk-lib/aws-stepfunctions-tasks");
16
+ const base_document_processing_1 = require("./base-document-processing");
17
+ const framework_1 = require("../framework");
18
+ const utilities_1 = require("../utilities");
19
+ const powertools_config_1 = require("../utilities/observability/powertools-config");
20
+ /**
21
+ * Cross-region inference prefix options for Bedrock models.
22
+ * Used to configure inference profiles for improved availability and performance.
23
+ */
24
+ var BedrockCrossRegionInferencePrefix;
25
+ (function (BedrockCrossRegionInferencePrefix) {
26
+ /** US-based cross-region inference profile */
27
+ BedrockCrossRegionInferencePrefix["US"] = "us";
28
+ /** EU-based cross-region inference profile */
29
+ BedrockCrossRegionInferencePrefix["EU"] = "eu";
30
+ })(BedrockCrossRegionInferencePrefix || (exports.BedrockCrossRegionInferencePrefix = BedrockCrossRegionInferencePrefix = {}));
31
+ /**
32
+ * Document processing workflow powered by Amazon Bedrock foundation models.
33
+ *
34
+ * Extends BaseDocumentProcessing to provide AI-powered document classification and extraction
35
+ * using Amazon Bedrock foundation models. This implementation offers:
36
+ *
37
+ * ## Key Features
38
+ * - **AI-Powered Classification**: Uses Claude 3.7 Sonnet (configurable) to classify document types
39
+ * - **Intelligent Extraction**: Extracts structured data from documents using foundation models
40
+ * - **Cross-Region Inference**: Optional support for improved availability via inference profiles
41
+ * - **Flexible Processing**: Optional enrichment and post-processing Lambda functions
42
+ * - **Cost Optimized**: Configurable timeouts and model selection for cost control
43
+ *
44
+ * ## Processing Workflow
45
+ * S3 Upload → Classification (Bedrock) → Extraction (Bedrock) → [Enrichment] → [Post-Processing] → Results
46
+ *
47
+ * ## Default Models
48
+ * - Classification: Claude 3.7 Sonnet (anthropic.claude-3-7-sonnet-20250219-v1:0)
49
+ * - Extraction: Claude 3.7 Sonnet (anthropic.claude-3-7-sonnet-20250219-v1:0)
50
+ *
51
+ * ## Prompt Templates
52
+ * The construct uses default prompts that can be customized:
53
+ * - **Classification**: Analyzes document and returns JSON with documentClassification field
54
+ * - **Extraction**: Uses classification result to extract entities in structured JSON format
55
+ *
56
+ * ## Cross-Region Inference
57
+ * When enabled, uses Bedrock inference profiles for improved availability:
58
+ * - US prefix: Routes to US-based regions for lower latency
59
+ * - EU prefix: Routes to EU-based regions for data residency compliance
60
+ */
61
+ class BedrockDocumentProcessing extends base_document_processing_1.BaseDocumentProcessing {
62
+ /**
63
+ * Creates a new BedrockDocumentProcessing construct.
64
+ *
65
+ * Initializes the Bedrock-powered document processing pipeline with AI classification
66
+ * and extraction capabilities. Creates Lambda functions with appropriate IAM roles
67
+ * for Bedrock model invocation and S3 access.
68
+ *
69
+ * @param scope - The scope in which to define this construct
70
+ * @param id - The scoped construct ID. Must be unique within the scope.
71
+ * @param props - Configuration properties for the Bedrock document processing pipeline
72
+ */
73
+ constructor(scope, id, props) {
74
+ super(scope, id, props);
75
+ if (props.network) {
76
+ props.network.createServiceEndpoint('vpce-bedrock', aws_ec2_1.InterfaceVpcEndpointAwsService.BEDROCK);
77
+ props.network.createServiceEndpoint('vpce-bedrock-runtime', aws_ec2_1.InterfaceVpcEndpointAwsService.BEDROCK_RUNTIME);
78
+ }
79
+ this.bedrockDocumentProcessingProps = props;
80
+ this.crossRegionInferencePrefix = props.crossRegionInferencePrefix || BedrockCrossRegionInferencePrefix.US;
81
+ this.stateMachine = this.handleStateMachineCreation('bedrock-document-processing-workflow');
82
+ }
83
+ /**
84
+ * Implements the document classification step using Amazon Bedrock.
85
+ *
86
+ * Creates a Lambda function that invokes the configured Bedrock model to classify
87
+ * the document type. The function reads the document from S3 and sends it to
88
+ * Bedrock with the classification prompt.
89
+ *
90
+ * @returns LambdaInvoke task configured for document classification
91
+ */
92
+ classificationStep() {
93
+ const prompt = this.bedrockDocumentProcessingProps.classificationPrompt || BedrockDocumentProcessing.DEFAULT_CLASSIFICATION_PROMPT;
94
+ const fmModel = this.bedrockDocumentProcessingProps.classificationModelId || BedrockDocumentProcessing.DEFAULT_CLASSIFICATION_MODEL_ID;
95
+ const adjustedModelId = this.bedrockDocumentProcessingProps.useCrossRegionInference ? `${this.crossRegionInferencePrefix}.${fmModel.modelId}` : fmModel.modelId;
96
+ const role = this.generateLambdaRoleForBedrock(fmModel, 'ClassificationLambdaRole');
97
+ const { region, account } = aws_cdk_lib_1.Stack.of(this);
98
+ const generatedLogPermissions = utilities_1.LambdaIamUtils.createLogsPermissions({
99
+ account,
100
+ functionName: 'bedrock-idp-classification',
101
+ region,
102
+ scope: this,
103
+ });
104
+ this.encryptionKey.grantEncryptDecrypt(role);
105
+ if (this.bucketEncryptionKey) {
106
+ this.bucketEncryptionKey.grantEncryptDecrypt(role);
107
+ }
108
+ const bedrockFunction = new aws_lambda_python_alpha_1.PythonFunction(this, 'BedrockClassificationFunction', {
109
+ functionName: generatedLogPermissions.uniqueFunctionName,
110
+ architecture: aws_lambda_1.Architecture.X86_64,
111
+ runtime: framework_1.DefaultRuntimes.PYTHON,
112
+ entry: path.join(__dirname, 'resources/default-bedrock-invoke'),
113
+ role,
114
+ memorySize: 512,
115
+ timeout: this.bedrockDocumentProcessingProps.stepTimeouts || aws_cdk_lib_1.Duration.minutes(5),
116
+ environment: {
117
+ MODEL_ID: adjustedModelId,
118
+ PROMPT: prompt,
119
+ INVOKE_TYPE: 'classification',
120
+ ...powertools_config_1.PowertoolsConfig.generateDefaultLambdaConfig(this.bedrockDocumentProcessingProps.enableObservability, this.metricNamespace, this.metricServiceName),
121
+ },
122
+ environmentEncryption: this.encryptionKey,
123
+ vpc: this.bedrockDocumentProcessingProps.network ? this.bedrockDocumentProcessingProps.network.vpc : undefined,
124
+ vpcSubnets: this.bedrockDocumentProcessingProps.network ? this.bedrockDocumentProcessingProps.network.applicationSubnetSelection() : undefined,
125
+ });
126
+ for (const statement of generatedLogPermissions.policyStatements) {
127
+ bedrockFunction.role?.addToPrincipalPolicy(statement);
128
+ }
129
+ if (this.bedrockDocumentProcessingProps.network) {
130
+ bedrockFunction.role?.addToPrincipalPolicy(utilities_1.LambdaIamUtils.generateLambdaVPCPermissions());
131
+ }
132
+ return new aws_stepfunctions_tasks_1.LambdaInvoke(this, 'ClassificationStep', {
133
+ lambdaFunction: bedrockFunction,
134
+ resultPath: '$.classificationResult',
135
+ resultSelector: {
136
+ 'documentClassification.$': '$.Payload.documentClassification',
137
+ },
138
+ });
139
+ }
140
+ /**
141
+ * Implements the document extraction step using Amazon Bedrock.
142
+ *
143
+ * Creates a Lambda function that invokes the configured Bedrock model to extract
144
+ * structured data from the document. Uses the classification result from the
145
+ * previous step to provide context for more accurate extraction.
146
+ *
147
+ * @returns LambdaInvoke task configured for document extraction
148
+ */
149
+ processingStep() {
150
+ const prompt = this.bedrockDocumentProcessingProps.processingPrompt || BedrockDocumentProcessing.DEFAULT_PROCESSING_PROMPT;
151
+ const fmModel = this.bedrockDocumentProcessingProps.processingModelId || BedrockDocumentProcessing.DEFAULT_PROCESSING_MODEL_ID;
152
+ const adjustedModelId = this.bedrockDocumentProcessingProps.useCrossRegionInference ? `${this.crossRegionInferencePrefix}.${fmModel.modelId}` : fmModel.modelId;
153
+ const role = this.generateLambdaRoleForBedrock(fmModel, 'ProcessingLambdaRole');
154
+ const { region, account } = aws_cdk_lib_1.Stack.of(this);
155
+ const generatedLogPermissions = utilities_1.LambdaIamUtils.createLogsPermissions({
156
+ account,
157
+ functionName: 'bedrock-idp-processing',
158
+ region,
159
+ scope: this,
160
+ });
161
+ this.encryptionKey.grantEncryptDecrypt(role);
162
+ if (this.bucketEncryptionKey) {
163
+ this.bucketEncryptionKey.grantEncryptDecrypt(role);
164
+ }
165
+ const bedrockFunction = new aws_lambda_python_alpha_1.PythonFunction(this, 'BedrockExtractionFunction', {
166
+ functionName: generatedLogPermissions.uniqueFunctionName,
167
+ runtime: framework_1.DefaultRuntimes.PYTHON,
168
+ architecture: aws_lambda_1.Architecture.X86_64,
169
+ entry: path.join(__dirname, 'resources/default-bedrock-invoke'),
170
+ role,
171
+ memorySize: 512,
172
+ timeout: this.bedrockDocumentProcessingProps.stepTimeouts || aws_cdk_lib_1.Duration.minutes(5),
173
+ environment: {
174
+ MODEL_ID: adjustedModelId,
175
+ PROMPT: prompt,
176
+ INVOKE_TYPE: 'processing',
177
+ ...powertools_config_1.PowertoolsConfig.generateDefaultLambdaConfig(this.bedrockDocumentProcessingProps.enableObservability, this.metricNamespace, this.metricServiceName),
178
+ },
179
+ environmentEncryption: this.encryptionKey,
180
+ vpc: this.bedrockDocumentProcessingProps.network ? this.bedrockDocumentProcessingProps.network.vpc : undefined,
181
+ vpcSubnets: this.bedrockDocumentProcessingProps.network ? this.bedrockDocumentProcessingProps.network.applicationSubnetSelection() : undefined,
182
+ });
183
+ for (const statement of generatedLogPermissions.policyStatements) {
184
+ bedrockFunction.role?.addToPrincipalPolicy(statement);
185
+ }
186
+ if (this.bedrockDocumentProcessingProps.network) {
187
+ bedrockFunction.role?.addToPrincipalPolicy(utilities_1.LambdaIamUtils.generateLambdaVPCPermissions());
188
+ }
189
+ return new aws_stepfunctions_tasks_1.LambdaInvoke(this, 'ProcessingStep', {
190
+ lambdaFunction: bedrockFunction,
191
+ resultPath: '$.processingResult',
192
+ resultSelector: {
193
+ 'documentClassification.$': '$.Payload.documentClassification',
194
+ 'result.$': '$.Payload.result',
195
+ },
196
+ });
197
+ }
198
+ generateLambdaRoleForBedrock(fmModel, id) {
199
+ const { region, account } = aws_cdk_lib_1.Stack.of(this);
200
+ return new aws_iam_1.Role(this, id, {
201
+ assumedBy: new aws_iam_1.ServicePrincipal('lambda.amazonaws.com'),
202
+ inlinePolicies: {
203
+ BedrockInvokePolicy: new aws_iam_1.PolicyDocument({
204
+ statements: [
205
+ new aws_iam_1.PolicyStatement({
206
+ effect: aws_iam_1.Effect.ALLOW,
207
+ actions: ['s3:GetObject'],
208
+ resources: [`${this.bucket.bucketArn}/*`],
209
+ }),
210
+ new aws_iam_1.PolicyStatement({
211
+ effect: aws_iam_1.Effect.ALLOW,
212
+ actions: [
213
+ 'bedrock:InvokeModel',
214
+ 'bedrock:InvokeModelWithResponseStream',
215
+ ],
216
+ resources: [
217
+ `arn:aws:bedrock:*::foundation-model/${fmModel.modelId}`,
218
+ `arn:aws:bedrock:${region}:${account}:inference-profile/${this.crossRegionInferencePrefix}.${fmModel.modelId}`,
219
+ ],
220
+ }),
221
+ ],
222
+ }),
223
+ },
224
+ });
225
+ }
226
+ /**
227
+ * Implements the optional document enrichment step.
228
+ *
229
+ * If an enrichment Lambda function is provided in the props, creates a LambdaInvoke
230
+ * task to perform additional processing on the extracted data. This step is useful
231
+ * for data validation, transformation, or integration with external systems.
232
+ *
233
+ * @returns LambdaInvoke task for enrichment, or undefined to skip this step
234
+ */
235
+ enrichmentStep() {
236
+ if (!this.bedrockDocumentProcessingProps.enrichmentLambdaFunction) {
237
+ return undefined;
238
+ }
239
+ return new aws_stepfunctions_tasks_1.LambdaInvoke(this, 'EnrichmentStep', {
240
+ lambdaFunction: this.bedrockDocumentProcessingProps.enrichmentLambdaFunction,
241
+ resultPath: '$.enrichedResult',
242
+ });
243
+ }
244
+ /**
245
+ * Implements the optional post-processing step.
246
+ *
247
+ * If a post-processing Lambda function is provided in the props, creates a LambdaInvoke
248
+ * task to perform final processing on the workflow results. This step is useful for
249
+ * data formatting, notifications, or integration with downstream systems.
250
+ *
251
+ * @returns LambdaInvoke task for post-processing, or undefined to skip this step
252
+ */
253
+ postProcessingStep() {
254
+ if (!this.bedrockDocumentProcessingProps.postProcessingLambdaFunction) {
255
+ return undefined;
256
+ }
257
+ return new aws_stepfunctions_tasks_1.LambdaInvoke(this, 'PostProcessingStep', {
258
+ lambdaFunction: this.bedrockDocumentProcessingProps.postProcessingLambdaFunction,
259
+ resultPath: '$.postProcessedResult',
260
+ });
261
+ }
262
+ }
263
+ exports.BedrockDocumentProcessing = BedrockDocumentProcessing;
264
+ _a = JSII_RTTI_SYMBOL_1;
265
+ BedrockDocumentProcessing[_a] = { fqn: "@cdklabs/cdk-appmod-catalog-blueprints.BedrockDocumentProcessing", version: "1.0.0" };
266
+ BedrockDocumentProcessing.DEFAULT_CLASSIFICATION_MODEL_ID = aws_bedrock_1.FoundationModelIdentifier.ANTHROPIC_CLAUDE_3_7_SONNET_20250219_V1_0;
267
+ BedrockDocumentProcessing.DEFAULT_PROCESSING_MODEL_ID = aws_bedrock_1.FoundationModelIdentifier.ANTHROPIC_CLAUDE_3_7_SONNET_20250219_V1_0;
268
+ BedrockDocumentProcessing.DEFAULT_CLASSIFICATION_PROMPT = `
269
+ Analyze the document below, and classify the type of document it is (eg. INVOICE, IDENTITY_DOCUMENT, RECEIPT, etc). The result should be in JSON and should follow the following structure (only respond in JSON with the following structure and do not use markdown to indicate the json, just output plain old json with nothing else):
270
+
271
+ {
272
+ documentClassification: <CLASSIFICATION>
273
+ }
274
+
275
+ Attached document is as follows:
276
+
277
+ `;
278
+ BedrockDocumentProcessing.DEFAULT_PROCESSING_PROMPT = `
279
+ The document below has been classified as [ACTUAL_CLASSIFICATION]. Extract important entities from the document and return the result as JSON following the structure below (only respond in JSON with the following structure and do not use markdown to indicate the json, just output plain old json with nothing else):
280
+
281
+ {
282
+ documentClassification: <CLASSIFICATION>,
283
+ result: {
284
+ entities: [
285
+ {
286
+ type: <TYPE OF ENTITY>
287
+ value: <VALUE OF ENTITY>
288
+ },
289
+ ...
290
+ ]
291
+ }
292
+ }
293
+
294
+ Attached document is as follows:
295
+
296
+ `;
297
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmVkcm9jay1kb2N1bWVudC1wcm9jZXNzaW5nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdXNlLWNhc2VzL2RvY3VtZW50LXByb2Nlc3NpbmcvYmVkcm9jay1kb2N1bWVudC1wcm9jZXNzaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEscUVBQXFFO0FBQ3JFLHNDQUFzQztBQUV0Qyw2QkFBNkI7QUFDN0IsOEVBQWtFO0FBQ2xFLDZDQUE4QztBQUM5Qyx5REFBb0U7QUFDcEUsaURBQXFFO0FBQ3JFLGlEQUFzRztBQUN0Ryx1REFBZ0U7QUFFaEUsaUZBQW1FO0FBRW5FLHlFQUE2SDtBQUM3SCw0Q0FBK0M7QUFDL0MsNENBQThDO0FBQzlDLG9GQUFnRjtBQTBEaEY7OztHQUdHO0FBQ0gsSUFBWSxpQ0FLWDtBQUxELFdBQVksaUNBQWlDO0lBQzNDLDhDQUE4QztJQUM5Qyw4Q0FBUyxDQUFBO0lBQ1QsOENBQThDO0lBQzlDLDhDQUFTLENBQUE7QUFDWCxDQUFDLEVBTFcsaUNBQWlDLGlEQUFqQyxpQ0FBaUMsUUFLNUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E2Qkc7QUFDSCxNQUFhLHlCQUEwQixTQUFRLGlEQUFzQjtJQTRDbkU7Ozs7Ozs7Ozs7T0FVRztJQUNILFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBcUM7UUFDN0UsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDeEIsSUFBSSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDbEIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQyxjQUFjLEVBQUUsd0NBQThCLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDNUYsS0FBSyxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQyxzQkFBc0IsRUFBRSx3Q0FBOEIsQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUM5RyxDQUFDO1FBRUQsSUFBSSxDQUFDLDhC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QUE3UUgsOERBOFFDOzs7QUE1UTJCLHlEQUErQixHQUNyRCx1Q0FBeUIsQ0FBQyx5Q0FBeUMsQ0FBQztBQUM5QyxxREFBMkIsR0FDakQsdUNBQXlCLENBQUMseUNBQXlDLENBQUM7QUFDOUMsdURBQTZCLEdBQUc7Ozs7Ozs7OztHQVN6RCxDQUFDO0FBRXdCLG1EQUF5QixHQUFHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQnJELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBQeXRob25GdW5jdGlvbiB9IGZyb20gJ0Bhd3MtY2RrL2F3cy1sYW1iZGEtcHl0aG9uLWFscGhhJztcbmltcG9ydCB7IER1cmF0aW9uLCBTdGFjayB9IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IEZvdW5kYXRpb25Nb2RlbElkZW50aWZpZXIgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtYmVkcm9jayc7XG5pbXBvcnQgeyBJbnRlcmZhY2VWcGNFbmRwb2ludEF3c1NlcnZpY2UgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWMyJztcbmltcG9ydCB7IFJvbGUsIFNlcnZpY2VQcmluY2lwYWwsIFBvbGljeVN0YXRlbWVudCwgUG9saWN5RG9jdW1lbnQsIEVmZmVjdCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0IHsgRnVuY3Rpb24sIEFyY2hpdGVjdHVyZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0IHsgU3RhdGVNYWNoaW5lIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXN0ZXBmdW5jdGlvbnMnO1xuaW1wb3J0IHsgTGFtYmRhSW52b2tlIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXN0ZXBmdW5jdGlvbnMtdGFza3MnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBCYXNlRG9jdW1lbnRQcm9jZXNzaW5nLCBCYXNlRG9jdW1lbnRQcm9jZXNzaW5nUHJvcHMsIERvY3VtZW50UHJvY2Vzc2luZ1N0ZXBUeXBlIH0gZnJvbSAnLi9iYXNlLWRvY3VtZW50LXByb2Nlc3NpbmcnO1xuaW1wb3J0IHsgRGVmYXVsdFJ1bnRpbWVzIH0gZnJvbSAnLi4vZnJhbWV3b3JrJztcbmltcG9ydCB7IExhbWJkYUlhbVV0aWxzIH0gZnJvbSAnLi4vdXRpbGl0aWVzJztcbmltcG9ydCB7IFBvd2VydG9vbHNDb25maWcgfSBmcm9tICcuLi91dGlsaXRpZXMvb2JzZXJ2YWJpbGl0eS9wb3dlcnRvb2xzLWNvbmZpZyc7XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBwcm9wZXJ0aWVzIGZvciBCZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nIGNvbnN0cnVjdC5cbiAqIEV4dGVuZHMgQmFzZURvY3VtZW50UHJvY2Vzc2luZ1Byb3BzIHdpdGggQmVkcm9jay1zcGVjaWZpYyBvcHRpb25zLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEJlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmdQcm9wcyBleHRlbmRzIEJhc2VEb2N1bWVudFByb2Nlc3NpbmdQcm9wcyB7XG4gIC8qKlxuICAgKiBCZWRyb2NrIGZvdW5kYXRpb24gbW9kZWwgZm9yIGRvY3VtZW50IGNsYXNzaWZpY2F0aW9uIHN0ZXAuXG4gICAqIEBkZWZhdWx0IEZvdW5kYXRpb25Nb2RlbElkZW50aWZpZXIuQU5USFJPUElDX0NMQVVERV8zXzdfU09OTkVUXzIwMjUwMjE5X1YxXzBcbiAgICovXG4gIHJlYWRvbmx5IGNsYXNzaWZpY2F0aW9uTW9kZWxJZD86IEZvdW5kYXRpb25Nb2RlbElkZW50aWZpZXI7XG4gIC8qKlxuICAgKiBCZWRyb2NrIGZvdW5kYXRpb24gbW9kZWwgZm9yIGRvY3VtZW50IGV4dHJhY3Rpb24gc3RlcC5cbiAgICogQGRlZmF1bHQgRm91bmRhdGlvbk1vZGVsSWRlbnRpZmllci5BTlRIUk9QSUNfQ0xBVURFXzNfN19TT05ORVRfMjAyNTAyMTlfVjFfMFxuICAgKi9cbiAgcmVhZG9ubHkgcHJvY2Vzc2luZ01vZGVsSWQ/OiBGb3VuZGF0aW9uTW9kZWxJZGVudGlmaWVyO1xuICAvKipcbiAgICogQ3VzdG9tIHByb21wdCB0ZW1wbGF0ZSBmb3IgZG9jdW1lbnQgY2xhc3NpZmljYXRpb24uXG4gICAqIE11c3QgaW5jbHVkZSBwbGFjZWhvbGRlciBmb3IgZG9jdW1lbnQgY29udGVudC5cbiAgICogQGRlZmF1bHQgREVGQVVMVF9DTEFTU0lGSUNBVElPTl9QUk9NUFRcbiAgICovXG4gIHJlYWRvbmx5IGNsYXNzaWZpY2F0aW9uUHJvbXB0Pzogc3RyaW5nO1xuICAvKipcbiAgICogQ3VzdG9tIHByb21wdCB0ZW1wbGF0ZSBmb3IgZG9jdW1lbnQgZXh0cmFjdGlvbi5cbiAgICogTXVzdCBpbmNsdWRlIHBsYWNlaG9sZGVyIGZvciBkb2N1bWVudCBjb250ZW50IGFuZCBjbGFzc2lmaWNhdGlvbiByZXN1bHQuXG4gICAqIEBkZWZhdWx0IERFRkFVTFRfRVhUUkFDVElPTl9QUk9NUFRcbiAgICovXG4gIHJlYWRvbmx5IHByb2Nlc3NpbmdQcm9tcHQ/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBPcHRpb25hbCBMYW1iZGEgZnVuY3Rpb24gZm9yIGRvY3VtZW50IGVucmljaG1lbnQgc3RlcC5cbiAgICogSWYgcHJvdmlkZWQsIHdpbGwgYmUgaW52b2tlZCBhZnRlciBleHRyYWN0aW9uIHdpdGggd29ya2Zsb3cgc3RhdGUuXG4gICAqL1xuICByZWFkb25seSBlbnJpY2htZW50TGFtYmRhRnVuY3Rpb24/OiBGdW5jdGlvbjtcbiAgLyoqXG4gICAqIE9wdGlvbmFsIExhbWJkYSBmdW5jdGlvbiBmb3IgcG9zdC1wcm9jZXNzaW5nIHN0ZXAuXG4gICAqIElmIHByb3ZpZGVkLCB3aWxsIGJlIGludm9rZWQgYWZ0ZXIgZW5yaWNobWVudCB3aXRoIHdvcmtmbG93IHN0YXRlLlxuICAgKi9cbiAgcmVhZG9ubHkgcG9zdFByb2Nlc3NpbmdMYW1iZGFGdW5jdGlvbj86IEZ1bmN0aW9uO1xuICAvKipcbiAgICogVGltZW91dCBmb3IgaW5kaXZpZHVhbCBTdGVwIEZ1bmN0aW9ucyB0YXNrcyAoY2xhc3NpZmljYXRpb24sIGV4dHJhY3Rpb24sIGV0Yy4pLlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5taW51dGVzKDUpXG4gICAqL1xuICByZWFkb25seSBzdGVwVGltZW91dHM/OiBEdXJhdGlvbjtcbiAgLyoqXG4gICAqIEVuYWJsZSBjcm9zcy1yZWdpb24gaW5mZXJlbmNlIGZvciBCZWRyb2NrIG1vZGVscyB0byBpbXByb3ZlIGF2YWlsYWJpbGl0eSBhbmQgcGVyZm9ybWFuY2UuXG4gICAqIFdoZW4gZW5hYmxlZCwgdXNlcyBpbmZlcmVuY2UgcHJvZmlsZXMgaW5zdGVhZCBvZiBkaXJlY3QgbW9kZWwgaW52b2NhdGlvbi5cbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHVzZUNyb3NzUmVnaW9uSW5mZXJlbmNlPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFByZWZpeCBmb3IgY3Jvc3MtcmVnaW9uIGluZmVyZW5jZSBjb25maWd1cmF0aW9uLlxuICAgKiBPbmx5IHVzZWQgd2hlbiB1c2VDcm9zc1JlZ2lvbkluZmVyZW5jZSBpcyB0cnVlLlxuICAgKiBAZGVmYXVsdCBCZWRyb2NrQ3Jvc3NSZWdpb25JbmZlcmVuY2VQcmVmaXguVVNcbiAgICovXG4gIHJlYWRvbmx5IGNyb3NzUmVnaW9uSW5mZXJlbmNlUHJlZml4PzogQmVkcm9ja0Nyb3NzUmVnaW9uSW5mZXJlbmNlUHJlZml4O1xufVxuXG4vKipcbiAqIENyb3NzLXJlZ2lvbiBpbmZlcmVuY2UgcHJlZml4IG9wdGlvbnMgZm9yIEJlZHJvY2sgbW9kZWxzLlxuICogVXNlZCB0byBjb25maWd1cmUgaW5mZXJlbmNlIHByb2ZpbGVzIGZvciBpbXByb3ZlZCBhdmFpbGFiaWxpdHkgYW5kIHBlcmZvcm1hbmNlLlxuICovXG5leHBvcnQgZW51bSBCZWRyb2NrQ3Jvc3NSZWdpb25JbmZlcmVuY2VQcmVmaXgge1xuICAvKiogVVMtYmFzZWQgY3Jvc3MtcmVnaW9uIGluZmVyZW5jZSBwcm9maWxlICovXG4gIFVTID0gJ3VzJyxcbiAgLyoqIEVVLWJhc2VkIGNyb3NzLXJlZ2lvbiBpbmZlcmVuY2UgcHJvZmlsZSAqL1xuICBFVSA9ICdldScsXG59XG5cbi8qKlxuICogRG9jdW1lbnQgcHJvY2Vzc2luZyB3b3JrZmxvdyBwb3dlcmVkIGJ5IEFtYXpvbiBCZWRyb2NrIGZvdW5kYXRpb24gbW9kZWxzLlxuICpcbiAqIEV4dGVuZHMgQmFzZURvY3VtZW50UHJvY2Vzc2luZyB0byBwcm92aWRlIEFJLXBvd2VyZWQgZG9jdW1lbnQgY2xhc3NpZmljYXRpb24gYW5kIGV4dHJhY3Rpb25cbiAqIHVzaW5nIEFtYXpvbiBCZWRyb2NrIGZvdW5kYXRpb24gbW9kZWxzLiBUaGlzIGltcGxlbWVudGF0aW9uIG9mZmVyczpcbiAqXG4gKiAjIyBLZXkgRmVhdHVyZXNcbiAqIC0gKipBSS1Qb3dlcmVkIENsYXNzaWZpY2F0aW9uKio6IFVzZXMgQ2xhdWRlIDMuNyBTb25uZXQgKGNvbmZpZ3VyYWJsZSkgdG8gY2xhc3NpZnkgZG9jdW1lbnQgdHlwZXNcbiAqIC0gKipJbnRlbGxpZ2VudCBFeHRyYWN0aW9uKio6IEV4dHJhY3RzIHN0cnVjdHVyZWQgZGF0YSBmcm9tIGRvY3VtZW50cyB1c2luZyBmb3VuZGF0aW9uIG1vZGVsc1xuICogLSAqKkNyb3NzLVJlZ2lvbiBJbmZlcmVuY2UqKjogT3B0aW9uYWwgc3VwcG9ydCBmb3IgaW1wcm92ZWQgYXZhaWxhYmlsaXR5IHZpYSBpbmZlcmVuY2UgcHJvZmlsZXNcbiAqIC0gKipGbGV4aWJsZSBQcm9jZXNzaW5nKio6IE9wdGlvbmFsIGVucmljaG1lbnQgYW5kIHBvc3QtcHJvY2Vzc2luZyBMYW1iZGEgZnVuY3Rpb25zXG4gKiAtICoqQ29zdCBPcHRpbWl6ZWQqKjogQ29uZmlndXJhYmxlIHRpbWVvdXRzIGFuZCBtb2RlbCBzZWxlY3Rpb24gZm9yIGNvc3QgY29udHJvbFxuICpcbiAqICMjIFByb2Nlc3NpbmcgV29ya2Zsb3dcbiAqIFMzIFVwbG9hZCDihpIgQ2xhc3NpZmljYXRpb24gKEJlZHJvY2spIOKGkiBFeHRyYWN0aW9uIChCZWRyb2NrKSDihpIgW0VucmljaG1lbnRdIOKGkiBbUG9zdC1Qcm9jZXNzaW5nXSDihpIgUmVzdWx0c1xuICpcbiAqICMjIERlZmF1bHQgTW9kZWxzXG4gKiAtIENsYXNzaWZpY2F0aW9uOiBDbGF1ZGUgMy43IFNvbm5ldCAoYW50aHJvcGljLmNsYXVkZS0zLTctc29ubmV0LTIwMjUwMjE5LXYxOjApXG4gKiAtIEV4dHJhY3Rpb246IENsYXVkZSAzLjcgU29ubmV0IChhbnRocm9waWMuY2xhdWRlLTMtNy1zb25uZXQtMjAyNTAyMTktdjE6MClcbiAqXG4gKiAjIyBQcm9tcHQgVGVtcGxhdGVzXG4gKiBUaGUgY29uc3RydWN0IHVzZXMgZGVmYXVsdCBwcm9tcHRzIHRoYXQgY2FuIGJlIGN1c3RvbWl6ZWQ6XG4gKiAtICoqQ2xhc3NpZmljYXRpb24qKjogQW5hbHl6ZXMgZG9jdW1lbnQgYW5kIHJldHVybnMgSlNPTiB3aXRoIGRvY3VtZW50Q2xhc3NpZmljYXRpb24gZmllbGRcbiAqIC0gKipFeHRyYWN0aW9uKio6IFVzZXMgY2xhc3NpZmljYXRpb24gcmVzdWx0IHRvIGV4dHJhY3QgZW50aXRpZXMgaW4gc3RydWN0dXJlZCBKU09OIGZvcm1hdFxuICpcbiAqICMjIENyb3NzLVJlZ2lvbiBJbmZlcmVuY2VcbiAqIFdoZW4gZW5hYmxlZCwgdXNlcyBCZWRyb2NrIGluZmVyZW5jZSBwcm9maWxlcyBmb3IgaW1wcm92ZWQgYXZhaWxhYmlsaXR5OlxuICogLSBVUyBwcmVmaXg6IFJvdXRlcyB0byBVUy1iYXNlZCByZWdpb25zIGZvciBsb3dlciBsYXRlbmN5XG4gKiAtIEVVIHByZWZpeDogUm91dGVzIHRvIEVVLWJhc2VkIHJlZ2lvbnMgZm9yIGRhdGEgcmVzaWRlbmN5IGNvbXBsaWFuY2VcbiAqL1xuZXhwb3J0IGNsYXNzIEJlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmcgZXh0ZW5kcyBCYXNlRG9jdW1lbnRQcm9jZXNzaW5nIHtcblxuICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IERFRkFVTFRfQ0xBU1NJRklDQVRJT05fTU9ERUxfSUQ6IEZvdW5kYXRpb25Nb2RlbElkZW50aWZpZXJcbiAgICA9IEZvdW5kYXRpb25Nb2RlbElkZW50aWZpZXIuQU5USFJPUElDX0NMQVVERV8zXzdfU09OTkVUXzIwMjUwMjE5X1YxXzA7XG4gIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgREVGQVVMVF9QUk9DRVNTSU5HX01PREVMX0lEOiBGb3VuZGF0aW9uTW9kZWxJZGVudGlmaWVyXG4gICAgPSBGb3VuZGF0aW9uTW9kZWxJZGVudGlmaWVyLkFOVEhST1BJQ19DTEFVREVfM183X1NPTk5FVF8yMDI1MDIxOV9WMV8wO1xuICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IERFRkFVTFRfQ0xBU1NJRklDQVRJT05fUFJPTVBUID0gYFxuICBBbmFseXplIHRoZSBkb2N1bWVudCBiZWxvdywgYW5kIGNsYXNzaWZ5IHRoZSB0eXBlIG9mIGRvY3VtZW50IGl0IGlzIChlZy4gSU5WT0lDRSwgSURFTlRJVFlfRE9DVU1FTlQsIFJFQ0VJUFQsIGV0YykuIFRoZSByZXN1bHQgc2hvdWxkIGJlIGluIEpTT04gYW5kIHNob3VsZCBmb2xsb3cgdGhlIGZvbGxvd2luZyBzdHJ1Y3R1cmUgKG9ubHkgcmVzcG9uZCBpbiBKU09OIHdpdGggdGhlIGZvbGxvd2luZyBzdHJ1Y3R1cmUgYW5kIGRvIG5vdCB1c2UgbWFya2Rvd24gdG8gaW5kaWNhdGUgdGhlIGpzb24sIGp1c3Qgb3V0cHV0IHBsYWluIG9sZCBqc29uIHdpdGggbm90aGluZyBlbHNlKTpcblxuICB7XG4gICAgICBkb2N1bWVudENsYXNzaWZpY2F0aW9uOiA8Q0xBU1NJRklDQVRJT04+XG4gIH1cblxuICBBdHRhY2hlZCBkb2N1bWVudCBpcyBhcyBmb2xsb3dzOlxuXG4gIGA7XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBERUZBVUxUX1BST0NFU1NJTkdfUFJPTVBUID0gYFxuICBUaGUgZG9jdW1lbnQgYmVsb3cgaGFzIGJlZW4gY2xhc3NpZmllZCBhcyBbQUNUVUFMX0NMQVNTSUZJQ0FUSU9OXS4gRXh0cmFjdCBpbXBvcnRhbnQgZW50aXRpZXMgZnJvbSB0aGUgZG9jdW1lbnQgYW5kIHJldHVybiB0aGUgcmVzdWx0IGFzIEpTT04gZm9sbG93aW5nIHRoZSBzdHJ1Y3R1cmUgYmVsb3cgKG9ubHkgcmVzcG9uZCBpbiBKU09OIHdpdGggdGhlIGZvbGxvd2luZyBzdHJ1Y3R1cmUgYW5kIGRvIG5vdCB1c2UgbWFya2Rvd24gdG8gaW5kaWNhdGUgdGhlIGpzb24sIGp1c3Qgb3V0cHV0IHBsYWluIG9sZCBqc29uIHdpdGggbm90aGluZyBlbHNlKTpcblxuICB7XG4gICAgICBkb2N1bWVudENsYXNzaWZpY2F0aW9uOiA8Q0xBU1NJRklDQVRJT04+LFxuICAgICAgcmVzdWx0OiB7XG4gICAgICAgIGVudGl0aWVzOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdHlwZTogPFRZUEUgT0YgRU5USVRZPlxuICAgICAgICAgICAgICAgIHZhbHVlOiA8VkFMVUUgT0YgRU5USVRZPlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIC4uLlxuICAgICAgICBdXG4gICAgICB9XG4gIH1cblxuICBBdHRhY2hlZCBkb2N1bWVudCBpcyBhcyBmb2xsb3dzOlxuXG4gIGA7XG5cbiAgLyoqIENvbmZpZ3VyYXRpb24gcHJvcGVydGllcyBzcGVjaWZpYyB0byBCZWRyb2NrIGRvY3VtZW50IHByb2Nlc3NpbmcgKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGJlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmdQcm9wczogQmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZ1Byb3BzO1xuICAvKiogQ3Jvc3MtcmVnaW9uIGluZmVyZW5jZSBwcmVmaXggZm9yIEJlZHJvY2sgbW9kZWwgcm91dGluZyAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY3Jvc3NSZWdpb25JbmZlcmVuY2VQcmVmaXg6IEJlZHJvY2tDcm9zc1JlZ2lvbkluZmVyZW5jZVByZWZpeDtcbiAgLyoqIFRoZSBTdGVwIEZ1bmN0aW9ucyBzdGF0ZSBtYWNoaW5lIHRoYXQgb3JjaGVzdHJhdGVzIHRoZSBkb2N1bWVudCBwcm9jZXNzaW5nIHdvcmtmbG93ICovXG4gIHJlYWRvbmx5IHN0YXRlTWFjaGluZTogU3RhdGVNYWNoaW5lO1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbmV3IEJlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmcgY29uc3RydWN0LlxuICAgKlxuICAgKiBJbml0aWFsaXplcyB0aGUgQmVkcm9jay1wb3dlcmVkIGRvY3VtZW50IHByb2Nlc3NpbmcgcGlwZWxpbmUgd2l0aCBBSSBjbGFzc2lmaWNhdGlvblxuICAgKiBhbmQgZXh0cmFjdGlvbiBjYXBhYmlsaXRpZXMuIENyZWF0ZXMgTGFtYmRhIGZ1bmN0aW9ucyB3aXRoIGFwcHJvcHJpYXRlIElBTSByb2xlc1xuICAgKiBmb3IgQmVkcm9jayBtb2RlbCBpbnZvY2F0aW9uIGFuZCBTMyBhY2Nlc3MuXG4gICAqXG4gICAqIEBwYXJhbSBzY29wZSAtIFRoZSBzY29wZSBpbiB3aGljaCB0byBkZWZpbmUgdGhpcyBjb25zdHJ1Y3RcbiAgICogQHBhcmFtIGlkIC0gVGhlIHNjb3BlZCBjb25zdHJ1Y3QgSUQuIE11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGUgc2NvcGUuXG4gICAqIEBwYXJhbSBwcm9wcyAtIENvbmZpZ3VyYXRpb24gcHJvcGVydGllcyBmb3IgdGhlIEJlZHJvY2sgZG9jdW1lbnQgcHJvY2Vzc2luZyBwaXBlbGluZVxuICAgKi9cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IEJlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmdQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCwgcHJvcHMpO1xuICAgIGlmIChwcm9wcy5uZXR3b3JrKSB7XG4gICAgICBwcm9wcy5uZXR3b3JrLmNyZWF0ZVNlcnZpY2VFbmRwb2ludCgndnBjZS1iZWRyb2NrJywgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlLkJFRFJPQ0spO1xuICAgICAgcHJvcHMubmV0d29yay5jcmVhdGVTZXJ2aWNlRW5kcG9pbnQoJ3ZwY2UtYmVkcm9jay1ydW50aW1lJywgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlLkJFRFJPQ0tfUlVOVElNRSk7XG4gICAgfVxuXG4gICAgdGhpcy5iZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nUHJvcHMgPSBwcm9wcztcbiAgICB0aGlzLmNyb3NzUmVnaW9uSW5mZXJlbmNlUHJlZml4ID0gcHJvcHMuY3Jvc3NSZWdpb25JbmZlcmVuY2VQcmVmaXggfHwgQmVkcm9ja0Nyb3NzUmVnaW9uSW5mZXJlbmNlUHJlZml4LlVTO1xuICAgIHRoaXMuc3RhdGVNYWNoaW5lID0gdGhpcy5oYW5kbGVTdGF0ZU1hY2hpbmVDcmVhdGlvbignYmVkcm9jay1kb2N1bWVudC1wcm9jZXNzaW5nLXdvcmtmbG93Jyk7XG4gIH1cblxuICAvKipcbiAgICogSW1wbGVtZW50cyB0aGUgZG9jdW1lbnQgY2xhc3NpZmljYXRpb24gc3RlcCB1c2luZyBBbWF6b24gQmVkcm9jay5cbiAgICpcbiAgICogQ3JlYXRlcyBhIExhbWJkYSBmdW5jdGlvbiB0aGF0IGludm9rZXMgdGhlIGNvbmZpZ3VyZWQgQmVkcm9jayBtb2RlbCB0byBjbGFzc2lmeVxuICAgKiB0aGUgZG9jdW1lbnQgdHlwZS4gVGhlIGZ1bmN0aW9uIHJlYWRzIHRoZSBkb2N1bWVudCBmcm9tIFMzIGFuZCBzZW5kcyBpdCB0b1xuICAgKiBCZWRyb2NrIHdpdGggdGhlIGNsYXNzaWZpY2F0aW9uIHByb21wdC5cbiAgICpcbiAgICogQHJldHVybnMgTGFtYmRhSW52b2tlIHRhc2sgY29uZmlndXJlZCBmb3IgZG9jdW1lbnQgY2xhc3NpZmljYXRpb25cbiAgICovXG4gIHByb3RlY3RlZCBjbGFzc2lmaWNhdGlvblN0ZXAoKTogRG9jdW1lbnRQcm9jZXNzaW5nU3RlcFR5cGUge1xuICAgIGNvbnN0IHByb21wdCA9IHRoaXMuYmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZ1Byb3BzLmNsYXNzaWZpY2F0aW9uUHJvbXB0IHx8IEJlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmcuREVGQVVMVF9DTEFTU0lGSUNBVElPTl9QUk9NUFQ7XG4gICAgY29uc3QgZm1Nb2RlbCA9IHRoaXMuYmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZ1Byb3BzLmNsYXNzaWZpY2F0aW9uTW9kZWxJZCB8fCBCZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nLkRFRkFVTFRfQ0xBU1NJRklDQVRJT05fTU9ERUxfSUQ7XG4gICAgY29uc3QgYWRqdXN0ZWRNb2RlbElkID0gdGhpcy5iZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nUHJvcHMudXNlQ3Jvc3NSZWdpb25JbmZlcmVuY2UgPyBgJHt0aGlzLmNyb3NzUmVnaW9uSW5mZXJlbmNlUHJlZml4fS4ke2ZtTW9kZWwubW9kZWxJZH1gIDogZm1Nb2RlbC5tb2RlbElkO1xuICAgIGNvbnN0IHJvbGUgPSB0aGlzLmdlbmVyYXRlTGFtYmRhUm9sZUZvckJlZHJvY2soZm1Nb2RlbCwgJ0NsYXNzaWZpY2F0aW9uTGFtYmRhUm9sZScpO1xuICAgIGNvbnN0IHsgcmVnaW9uLCBhY2NvdW50IH0gPSBTdGFjay5vZih0aGlzKTtcbiAgICBjb25zdCBnZW5lcmF0ZWRMb2dQZXJtaXNzaW9ucyA9IExhbWJkYUlhbVV0aWxzLmNyZWF0ZUxvZ3NQZXJtaXNzaW9ucyh7XG4gICAgICBhY2NvdW50LFxuICAgICAgZnVuY3Rpb25OYW1lOiAnYmVkcm9jay1pZHAtY2xhc3NpZmljYXRpb24nLFxuICAgICAgcmVnaW9uLFxuICAgICAgc2NvcGU6IHRoaXMsXG4gICAgfSk7XG5cbiAgICB0aGlzLmVuY3J5cHRpb25LZXkuZ3JhbnRFbmNyeXB0RGVjcnlwdChyb2xlKTtcblxuICAgIGlmICh0aGlzLmJ1Y2tldEVuY3J5cHRpb25LZXkpIHtcbiAgICAgIHRoaXMuYnVja2V0RW5jcnlwdGlvbktleS5ncmFudEVuY3J5cHREZWNyeXB0KHJvbGUpO1xuICAgIH1cblxuICAgIGNvbnN0IGJlZHJvY2tGdW5jdGlvbiA9IG5ldyBQeXRob25GdW5jdGlvbih0aGlzLCAnQmVkcm9ja0NsYXNzaWZpY2F0aW9uRnVuY3Rpb24nLCB7XG4gICAgICBmdW5jdGlvbk5hbWU6IGdlbmVyYXRlZExvZ1Blcm1pc3Npb25zLnVuaXF1ZUZ1bmN0aW9uTmFtZSxcbiAgICAgIGFyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlLlg4Nl82NCxcbiAgICAgIHJ1bnRpbWU6IERlZmF1bHRSdW50aW1lcy5QWVRIT04sXG4gICAgICBlbnRyeTogcGF0aC5qb2luKF9fZGlybmFtZSwgJ3Jlc291cmNlcy9kZWZhdWx0LWJlZHJvY2staW52b2tlJyksXG4gICAgICByb2xlLFxuICAgICAgbWVtb3J5U2l6ZTogNTEyLFxuICAgICAgdGltZW91dDogdGhpcy5iZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nUHJvcHMuc3RlcFRpbWVvdXRzIHx8IER1cmF0aW9uLm1pbnV0ZXMoNSksXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBNT0RFTF9JRDogYWRqdXN0ZWRNb2RlbElkLFxuICAgICAgICBQUk9NUFQ6IHByb21wdCxcbiAgICAgICAgSU5WT0tFX1RZUEU6ICdjbGFzc2lmaWNhdGlvbicsXG4gICAgICAgIC4uLlBvd2VydG9vbHNDb25maWcuZ2VuZXJhdGVEZWZhdWx0TGFtYmRhQ29uZmlnKFxuICAgICAgICAgIHRoaXMuYmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZ1Byb3BzLmVuYWJsZU9ic2VydmFiaWxpdHksXG4gICAgICAgICAgdGhpcy5tZXRyaWNOYW1lc3BhY2UsXG4gICAgICAgICAgdGhpcy5tZXRyaWNTZXJ2aWNlTmFtZSxcbiAgICAgICAgKSxcbiAgICAgIH0sXG4gICAgICBlbnZpcm9ubWVudEVuY3J5cHRpb246IHRoaXMuZW5jcnlwdGlvbktleSxcbiAgICAgIHZwYzogdGhpcy5iZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nUHJvcHMubmV0d29yayA/IHRoaXMuYmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZ1Byb3BzLm5ldHdvcmsudnBjIDogdW5kZWZpbmVkLFxuICAgICAgdnBjU3VibmV0czogdGhpcy5iZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nUHJvcHMubmV0d29yayA/IHRoaXMuYmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZ1Byb3BzLm5ldHdvcmsuYXBwbGljYXRpb25TdWJuZXRTZWxlY3Rpb24oKSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIGZvciAoY29uc3Qgc3RhdGVtZW50IG9mIGdlbmVyYXRlZExvZ1Blcm1pc3Npb25zLnBvbGljeVN0YXRlbWVudHMpIHtcbiAgICAgIGJlZHJvY2tGdW5jdGlvbi5yb2xlPy5hZGRUb1ByaW5jaXBhbFBvbGljeShzdGF0ZW1lbnQpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmJlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmdQcm9wcy5uZXR3b3JrKSB7XG4gICAgICBiZWRyb2NrRnVuY3Rpb24ucm9sZT8uYWRkVG9QcmluY2lwYWxQb2xpY3koTGFtYmRhSWFtVXRpbHMuZ2VuZXJhdGVMYW1iZGFWUENQZXJtaXNzaW9ucygpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IExhbWJkYUludm9rZSh0aGlzLCAnQ2xhc3NpZmljYXRpb25TdGVwJywge1xuICAgICAgbGFtYmRhRnVuY3Rpb246IGJlZHJvY2tGdW5jdGlvbixcbiAgICAgIHJlc3VsdFBhdGg6ICckLmNsYXNzaWZpY2F0aW9uUmVzdWx0JyxcbiAgICAgIHJlc3VsdFNlbGVjdG9yOiB7XG4gICAgICAgICdkb2N1bWVudENsYXNzaWZpY2F0aW9uLiQnOiAnJC5QYXlsb2FkLmRvY3VtZW50Q2xhc3NpZmljYXRpb24nLFxuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbXBsZW1lbnRzIHRoZSBkb2N1bWVudCBleHRyYWN0aW9uIHN0ZXAgdXNpbmcgQW1hem9uIEJlZHJvY2suXG4gICAqXG4gICAqIENyZWF0ZXMgYSBMYW1iZGEgZnVuY3Rpb24gdGhhdCBpbnZva2VzIHRoZSBjb25maWd1cmVkIEJlZHJvY2sgbW9kZWwgdG8gZXh0cmFjdFxuICAgKiBzdHJ1Y3R1cmVkIGRhdGEgZnJvbSB0aGUgZG9jdW1lbnQuIFVzZXMgdGhlIGNsYXNzaWZpY2F0aW9uIHJlc3VsdCBmcm9tIHRoZVxuICAgKiBwcmV2aW91cyBzdGVwIHRvIHByb3ZpZGUgY29udGV4dCBmb3IgbW9yZSBhY2N1cmF0ZSBleHRyYWN0aW9uLlxuICAgKlxuICAgKiBAcmV0dXJucyBMYW1iZGFJbnZva2UgdGFzayBjb25maWd1cmVkIGZvciBkb2N1bWVudCBleHRyYWN0aW9uXG4gICAqL1xuICBwcm90ZWN0ZWQgcHJvY2Vzc2luZ1N0ZXAoKTogRG9jdW1lbnRQcm9jZXNzaW5nU3RlcFR5cGUge1xuICAgIGNvbnN0IHByb21wdCA9IHRoaXMuYmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZ1Byb3BzLnByb2Nlc3NpbmdQcm9tcHQgfHwgQmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZy5ERUZBVUxUX1BST0NFU1NJTkdfUFJPTVBUO1xuICAgIGNvbnN0IGZtTW9kZWwgPSB0aGlzLmJlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmdQcm9wcy5wcm9jZXNzaW5nTW9kZWxJZCB8fCBCZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nLkRFRkFVTFRfUFJPQ0VTU0lOR19NT0RFTF9JRDtcbiAgICBjb25zdCBhZGp1c3RlZE1vZGVsSWQgPSB0aGlzLmJlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmdQcm9wcy51c2VDcm9zc1JlZ2lvbkluZmVyZW5jZSA/IGAke3RoaXMuY3Jvc3NSZWdpb25JbmZlcmVuY2VQcmVmaXh9LiR7Zm1Nb2RlbC5tb2RlbElkfWAgOiBmbU1vZGVsLm1vZGVsSWQ7XG4gICAgY29uc3Qgcm9sZSA9IHRoaXMuZ2VuZXJhdGVMYW1iZGFSb2xlRm9yQmVkcm9jayhmbU1vZGVsLCAnUHJvY2Vzc2luZ0xhbWJkYVJvbGUnKTtcbiAgICBjb25zdCB7IHJlZ2lvbiwgYWNjb3VudCB9ID0gU3RhY2sub2YodGhpcyk7XG5cbiAgICBjb25zdCBnZW5lcmF0ZWRMb2dQZXJtaXNzaW9ucyA9IExhbWJkYUlhbVV0aWxzLmNyZWF0ZUxvZ3NQZXJtaXNzaW9ucyh7XG4gICAgICBhY2NvdW50LFxuICAgICAgZnVuY3Rpb25OYW1lOiAnYmVkcm9jay1pZHAtcHJvY2Vzc2luZycsXG4gICAgICByZWdpb24sXG4gICAgICBzY29wZTogdGhpcyxcbiAgICB9KTtcbiAgICB0aGlzLmVuY3J5cHRpb25LZXkuZ3JhbnRFbmNyeXB0RGVjcnlwdChyb2xlKTtcbiAgICBpZiAodGhpcy5idWNrZXRFbmNyeXB0aW9uS2V5KSB7XG4gICAgICB0aGlzLmJ1Y2tldEVuY3J5cHRpb25LZXkuZ3JhbnRFbmNyeXB0RGVjcnlwdChyb2xlKTtcbiAgICB9XG4gICAgY29uc3QgYmVkcm9ja0Z1bmN0aW9uID0gbmV3IFB5dGhvbkZ1bmN0aW9uKHRoaXMsICdCZWRyb2NrRXh0cmFjdGlvbkZ1bmN0aW9uJywge1xuICAgICAgZnVuY3Rpb25OYW1lOiBnZW5lcmF0ZWRMb2dQZXJtaXNzaW9ucy51bmlxdWVGdW5jdGlvbk5hbWUsXG4gICAgICBydW50aW1lOiBEZWZhdWx0UnVudGltZXMuUFlUSE9OLFxuICAgICAgYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUuWDg2XzY0LFxuICAgICAgZW50cnk6IHBhdGguam9pbihfX2Rpcm5hbWUsICdyZXNvdXJjZXMvZGVmYXVsdC1iZWRyb2NrLWludm9rZScpLFxuICAgICAgcm9sZSxcbiAgICAgIG1lbW9yeVNpemU6IDUxMixcbiAgICAgIHRpbWVvdXQ6IHRoaXMuYmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZ1Byb3BzLnN0ZXBUaW1lb3V0cyB8fCBEdXJhdGlvbi5taW51dGVzKDUpLFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgTU9ERUxfSUQ6IGFkanVzdGVkTW9kZWxJZCxcbiAgICAgICAgUFJPTVBUOiBwcm9tcHQsXG4gICAgICAgIElOVk9LRV9UWVBFOiAncHJvY2Vzc2luZycsXG4gICAgICAgIC4uLlBvd2VydG9vbHNDb25maWcuZ2VuZXJhdGVEZWZhdWx0TGFtYmRhQ29uZmlnKFxuICAgICAgICAgIHRoaXMuYmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZ1Byb3BzLmVuYWJsZU9ic2VydmFiaWxpdHksXG4gICAgICAgICAgdGhpcy5tZXRyaWNOYW1lc3BhY2UsXG4gICAgICAgICAgdGhpcy5tZXRyaWNTZXJ2aWNlTmFtZSxcbiAgICAgICAgKSxcbiAgICAgIH0sXG4gICAgICBlbnZpcm9ubWVudEVuY3J5cHRpb246IHRoaXMuZW5jcnlwdGlvbktleSxcbiAgICAgIHZwYzogdGhpcy5iZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nUHJvcHMubmV0d29yayA/IHRoaXMuYmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZ1Byb3BzLm5ldHdvcmsudnBjIDogdW5kZWZpbmVkLFxuICAgICAgdnBjU3VibmV0czogdGhpcy5iZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nUHJvcHMubmV0d29yayA/IHRoaXMuYmVkcm9ja0RvY3VtZW50UHJvY2Vzc2luZ1Byb3BzLm5ldHdvcmsuYXBwbGljYXRpb25TdWJuZXRTZWxlY3Rpb24oKSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIGZvciAoY29uc3Qgc3RhdGVtZW50IG9mIGdlbmVyYXRlZExvZ1Blcm1pc3Npb25zLnBvbGljeVN0YXRlbWVudHMpIHtcbiAgICAgIGJlZHJvY2tGdW5jdGlvbi5yb2xlPy5hZGRUb1ByaW5jaXBhbFBvbGljeShzdGF0ZW1lbnQpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmJlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmdQcm9wcy5uZXR3b3JrKSB7XG4gICAgICBiZWRyb2NrRnVuY3Rpb24ucm9sZT8uYWRkVG9QcmluY2lwYWxQb2xpY3koTGFtYmRhSWFtVXRpbHMuZ2VuZXJhdGVMYW1iZGFWUENQZXJtaXNzaW9ucygpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IExhbWJkYUludm9rZSh0aGlzLCAnUHJvY2Vzc2luZ1N0ZXAnLCB7XG4gICAgICBsYW1iZGFGdW5jdGlvbjogYmVkcm9ja0Z1bmN0aW9uLFxuICAgICAgcmVzdWx0UGF0aDogJyQucHJvY2Vzc2luZ1Jlc3VsdCcsXG4gICAgICByZXN1bHRTZWxlY3Rvcjoge1xuICAgICAgICAnZG9jdW1lbnRDbGFzc2lmaWNhdGlvbi4kJzogJyQuUGF5bG9hZC5kb2N1bWVudENsYXNzaWZpY2F0aW9uJyxcbiAgICAgICAgJ3Jlc3VsdC4kJzogJyQuUGF5bG9hZC5yZXN1bHQnLFxuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZW5lcmF0ZUxhbWJkYVJvbGVGb3JCZWRyb2NrKGZtTW9kZWw6IEZvdW5kYXRpb25Nb2RlbElkZW50aWZpZXIsIGlkOiBzdHJpbmcpIHtcbiAgICBjb25zdCB7IHJlZ2lvbiwgYWNjb3VudCB9ID0gU3RhY2sub2YodGhpcyk7XG4gICAgcmV0dXJuIG5ldyBSb2xlKHRoaXMsIGlkLCB7XG4gICAgICBhc3N1bWVkQnk6IG5ldyBTZXJ2aWNlUHJpbmNpcGFsKCdsYW1iZGEuYW1hem9uYXdzLmNvbScpLFxuICAgICAgaW5saW5lUG9saWNpZXM6IHtcbiAgICAgICAgQmVkcm9ja0ludm9rZVBvbGljeTogbmV3IFBvbGljeURvY3VtZW50KHtcbiAgICAgICAgICBzdGF0ZW1lbnRzOiBbXG4gICAgICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgZWZmZWN0OiBFZmZlY3QuQUxMT1csXG4gICAgICAgICAgICAgIGFjdGlvbnM6IFsnczM6R2V0T2JqZWN0J10sXG4gICAgICAgICAgICAgIHJlc291cmNlczogW2Ake3RoaXMuYnVja2V0LmJ1Y2tldEFybn0vKmBdLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgZWZmZWN0OiBFZmZlY3QuQUxMT1csXG4gICAgICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAnYmVkcm9jazpJbnZva2VNb2RlbCcsXG4gICAgICAgICAgICAgICAgJ2JlZHJvY2s6SW52b2tlTW9kZWxXaXRoUmVzcG9uc2VTdHJlYW0nLFxuICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAgICAgICAgICBgYXJuOmF3czpiZWRyb2NrOio6OmZvdW5kYXRpb24tbW9kZWwvJHtmbU1vZGVsLm1vZGVsSWR9YCxcbiAgICAgICAgICAgICAgICBgYXJuOmF3czpiZWRyb2NrOiR7cmVnaW9ufToke2FjY291bnR9OmluZmVyZW5jZS1wcm9maWxlLyR7dGhpcy5jcm9zc1JlZ2lvbkluZmVyZW5jZVByZWZpeH0uJHtmbU1vZGVsLm1vZGVsSWR9YCxcbiAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0pLFxuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbXBsZW1lbnRzIHRoZSBvcHRpb25hbCBkb2N1bWVudCBlbnJpY2htZW50IHN0ZXAuXG4gICAqXG4gICAqIElmIGFuIGVucmljaG1lbnQgTGFtYmRhIGZ1bmN0aW9uIGlzIHByb3ZpZGVkIGluIHRoZSBwcm9wcywgY3JlYXRlcyBhIExhbWJkYUludm9rZVxuICAgKiB0YXNrIHRvIHBlcmZvcm0gYWRkaXRpb25hbCBwcm9jZXNzaW5nIG9uIHRoZSBleHRyYWN0ZWQgZGF0YS4gVGhpcyBzdGVwIGlzIHVzZWZ1bFxuICAgKiBmb3IgZGF0YSB2YWxpZGF0aW9uLCB0cmFuc2Zvcm1hdGlvbiwgb3IgaW50ZWdyYXRpb24gd2l0aCBleHRlcm5hbCBzeXN0ZW1zLlxuICAgKlxuICAgKiBAcmV0dXJucyBMYW1iZGFJbnZva2UgdGFzayBmb3IgZW5yaWNobWVudCwgb3IgdW5kZWZpbmVkIHRvIHNraXAgdGhpcyBzdGVwXG4gICAqL1xuICBwcm90ZWN0ZWQgZW5yaWNobWVudFN0ZXAoKTogRG9jdW1lbnRQcm9jZXNzaW5nU3RlcFR5cGUgfCB1bmRlZmluZWQge1xuICAgIGlmICghdGhpcy5iZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nUHJvcHMuZW5yaWNobWVudExhbWJkYUZ1bmN0aW9uKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIHJldHVybiBuZXcgTGFtYmRhSW52b2tlKHRoaXMsICdFbnJpY2htZW50U3RlcCcsIHtcbiAgICAgIGxhbWJkYUZ1bmN0aW9uOiB0aGlzLmJlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmdQcm9wcy5lbnJpY2htZW50TGFtYmRhRnVuY3Rpb24sXG4gICAgICByZXN1bHRQYXRoOiAnJC5lbnJpY2hlZFJlc3VsdCcsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogSW1wbGVtZW50cyB0aGUgb3B0aW9uYWwgcG9zdC1wcm9jZXNzaW5nIHN0ZXAuXG4gICAqXG4gICAqIElmIGEgcG9zdC1wcm9jZXNzaW5nIExhbWJkYSBmdW5jdGlvbiBpcyBwcm92aWRlZCBpbiB0aGUgcHJvcHMsIGNyZWF0ZXMgYSBMYW1iZGFJbnZva2VcbiAgICogdGFzayB0byBwZXJmb3JtIGZpbmFsIHByb2Nlc3Npbmcgb24gdGhlIHdvcmtmbG93IHJlc3VsdHMuIFRoaXMgc3RlcCBpcyB1c2VmdWwgZm9yXG4gICAqIGRhdGEgZm9ybWF0dGluZywgbm90aWZpY2F0aW9ucywgb3IgaW50ZWdyYXRpb24gd2l0aCBkb3duc3RyZWFtIHN5c3RlbXMuXG4gICAqXG4gICAqIEByZXR1cm5zIExhbWJkYUludm9rZSB0YXNrIGZvciBwb3N0LXByb2Nlc3NpbmcsIG9yIHVuZGVmaW5lZCB0byBza2lwIHRoaXMgc3RlcFxuICAgKi9cbiAgcHJvdGVjdGVkIHBvc3RQcm9jZXNzaW5nU3RlcCgpOiBEb2N1bWVudFByb2Nlc3NpbmdTdGVwVHlwZSB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKCF0aGlzLmJlZHJvY2tEb2N1bWVudFByb2Nlc3NpbmdQcm9wcy5wb3N0UHJvY2Vzc2luZ0xhbWJkYUZ1bmN0aW9uKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIHJldHVybiBuZXcgTGFtYmRhSW52b2tlKHRoaXMsICdQb3N0UHJvY2Vzc2luZ1N0ZXAnLCB7XG4gICAgICBsYW1iZGFGdW5jdGlvbjogdGhpcy5iZWRyb2NrRG9jdW1lbnRQcm9jZXNzaW5nUHJvcHMucG9zdFByb2Nlc3NpbmdMYW1iZGFGdW5jdGlvbixcbiAgICAgIHJlc3VsdFBhdGg6ICckLnBvc3RQcm9jZXNzZWRSZXN1bHQnLFxuICAgIH0pO1xuICB9XG59Il19
@@ -0,0 +1,3 @@
1
+ export * from './base-document-processing';
2
+ export * from './bedrock-document-processing';
3
+ export * from './agentic-document-processing';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./base-document-processing"), exports);
18
+ __exportStar(require("./bedrock-document-processing"), exports);
19
+ __exportStar(require("./agentic-document-processing"), exports);
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi91c2UtY2FzZXMvZG9jdW1lbnQtcHJvY2Vzc2luZy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsNkRBQTJDO0FBQzNDLGdFQUE4QztBQUM5QyxnRUFBOEMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tICcuL2Jhc2UtZG9jdW1lbnQtcHJvY2Vzc2luZyc7XG5leHBvcnQgKiBmcm9tICcuL2JlZHJvY2stZG9jdW1lbnQtcHJvY2Vzc2luZyc7XG5leHBvcnQgKiBmcm9tICcuL2FnZW50aWMtZG9jdW1lbnQtcHJvY2Vzc2luZyc7Il19
@@ -0,0 +1,63 @@
1
+ import json
2
+ import os
3
+ import boto3
4
+ import base64
5
+ from aws_lambda_powertools import Metrics, Tracer
6
+ from aws_lambda_powertools.metrics import MetricUnit
7
+
8
+ s3 = boto3.client('s3')
9
+ bedrock = boto3.client('bedrock-runtime')
10
+ metrics = Metrics()
11
+ tracer = Tracer()
12
+
13
+ @metrics.log_metrics
14
+ @tracer.capture_lambda_handler
15
+ def handler(event, context):
16
+ bucket = event['bucket']
17
+ key = event['key']
18
+ invoke_type = os.environ["INVOKE_TYPE"]
19
+ tracer.put_annotation(key="invoke_type", value=invoke_type)
20
+ tracer.put_annotation(key="documentId", value=event["documentId"])
21
+ metrics.add_dimension(name="invoke_type", value=invoke_type)
22
+
23
+ # Check file type
24
+ ext = key.lower().split('.')[-1]
25
+ if ext not in ['jpg', 'jpeg', 'png', 'pdf']:
26
+ raise ValueError(f"Unsupported file type: {ext}")
27
+
28
+ media_type = {'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'png': 'image/png', 'pdf': 'application/pdf'}[ext]
29
+
30
+ # Download file to /tmp
31
+ local_path = f"/tmp/{key.split('/')[-1]}"
32
+ s3.download_file(bucket, key, local_path)
33
+
34
+ # Read and encode file
35
+ with open(local_path, 'rb') as f:
36
+ file_data = base64.b64encode(f.read()).decode('utf-8')
37
+
38
+ # Format prompt if classification result exists
39
+ prompt = os.environ['PROMPT']
40
+ if 'classificationResult' in event:
41
+ classification = event['classificationResult']['documentClassification']
42
+ prompt = prompt.replace("[ACTUAL_CLASSIFICATION]", classification)
43
+
44
+ # Build content based on file type
45
+ content = [{'type': 'text', 'text': prompt}]
46
+ if ext == 'pdf':
47
+ content.append({'type': 'document', 'source': {'type': 'base64', 'media_type': media_type, 'data': file_data}})
48
+ else:
49
+ content.append({'type': 'image', 'source': {'type': 'base64', 'media_type': media_type, 'data': file_data}})
50
+
51
+ # Invoke Bedrock
52
+ response = bedrock.invoke_model(
53
+ modelId=os.environ['MODEL_ID'],
54
+ body=json.dumps({
55
+ 'anthropic_version': 'bedrock-2023-05-31',
56
+ 'max_tokens': 1000,
57
+ 'messages': [{'role': 'user', 'content': content}]
58
+ })
59
+ )
60
+
61
+ response_payload = response['body'].read()
62
+ metrics.add_metric(name="SuccessfulInvocation", unit=MetricUnit.Count, value=1)
63
+ return json.loads(json.loads(response_payload)["content"][0]["text"])
@@ -0,0 +1,4 @@
1
+ boto3>=1.26.0
2
+ aws-lambda-powertools
3
+ urllib3>=1.26.0,<2.0.0
4
+ aws-xray-sdk