diff --git a/.nightswatch/functional/conftest.py b/.nightswatch/functional/conftest.py index e5509829c..9df972457 100644 --- a/.nightswatch/functional/conftest.py +++ b/.nightswatch/functional/conftest.py @@ -23,6 +23,7 @@ from helpers.kendra_client import KendraClient from helpers.lex_client import LexClient from helpers.iam_client import IamClient +from helpers.s3_client import S3Client from helpers.translate_client import TranslateClient from helpers.cloud_watch_client import CloudWatchClient from helpers.website_model.dom_operator import DomOperator @@ -103,6 +104,10 @@ def translate_client(region: str) -> TranslateClient: def iam_client(region: str) -> IamClient: return IamClient(region) +@pytest.fixture +def s3_client(region: str) -> None: + return S3Client(region) + @pytest.fixture def app_version(param_fetcher: ParameterFetcher) -> str: app_version = param_fetcher.get_deployment_version() @@ -118,8 +123,9 @@ def skip_if_version_less_than(request, app_version): @pytest.fixture def cw_client(region: str, param_fetcher: ParameterFetcher) -> CloudWatchClient: - fulfillment_lambda_name = param_fetcher.get_fulfillment_lambda_name() - return CloudWatchClient(region, fulfillment_lambda_name) + stack_id = param_fetcher.get_stack_id() + stack_name = param_fetcher.stack_name + return CloudWatchClient(region, stack_id, stack_name) @pytest.fixture(autouse=True) def dom_operator(): @@ -210,3 +216,11 @@ def skip_embeddings(request, embeddings_is_enabled): if not embeddings_is_enabled: pytest.skip('Embeddings is not configured for this environment. Skipping...') + +@pytest.fixture +def knowledge_base_model(param_fetcher: ParameterFetcher): + return param_fetcher.get_bedrock_knowledge_base_model() + +@pytest.fixture +def content_designer_output_bucket_name(param_fetcher: ParameterFetcher): + return param_fetcher.get_content_designer_output_bucket_name() \ No newline at end of file diff --git a/.nightswatch/functional/helpers/cfn_parameter_fetcher.py b/.nightswatch/functional/helpers/cfn_parameter_fetcher.py index b9dd7a30a..438a499bb 100644 --- a/.nightswatch/functional/helpers/cfn_parameter_fetcher.py +++ b/.nightswatch/functional/helpers/cfn_parameter_fetcher.py @@ -275,3 +275,40 @@ def get_lambda_hook_example_arn(self) -> str: examples_stack_param_fetcher = ParameterFetcher(self.region, examples_stack_name) return examples_stack_param_fetcher.__get_stack_outputs('EXTCustomJSHook') + + def get_stack_id(self) -> Optional[str]: + """ + Retrieves the stack id. + + Returns: + ------- + The stack id. + """ + response = self.cloudformation_client.describe_stacks( + StackName=self.stack_name + ) + stack_id = response['Stacks'][0]['StackId'].split('/')[2] + return stack_id + + def get_bedrock_knowledge_base_model(self) -> Optional[str]: + """ + Retrieves the model of the Bedrock Knowledge Base from the stack parameters. + + Returns: + ------- + The Knowledge Base Model if found, otherwise None. + """ + + knowledge_base_model = self.__get_cfn_param('BedrockKnowledgeBaseModel') + return knowledge_base_model + + def get_content_designer_output_bucket_name(self) -> Optional[str]: + """ + Retrieves the name of the test all output bucket from the stack parameters. + + Returns: + ------- + The name of the test all bucket if found, otherwise None. + """ + + return self.__get_stack_outputs('ContentDesignerOutputBucket') diff --git a/.nightswatch/functional/helpers/cloud_watch_client.py b/.nightswatch/functional/helpers/cloud_watch_client.py index 86877f3f8..4fac7a5b8 100644 --- a/.nightswatch/functional/helpers/cloud_watch_client.py +++ b/.nightswatch/functional/helpers/cloud_watch_client.py @@ -21,7 +21,7 @@ class CloudWatchClient: Interacts with CloudWatch using Boto3. This class provides methods for pulling logs from log groups based on matches. """ - def __init__(self, region: str, fulfillment_lambda_name: str): + def __init__(self, region: str, stack_id: str, stack_name: str): """ Initializes the CloudWatchClient. :param region: The AWS region to connect to. @@ -29,7 +29,7 @@ def __init__(self, region: str, fulfillment_lambda_name: str): """ self.client = boto3.client('logs', region_name=region) self.region = region - self.fulfillment_lambda_log_group = f'/aws/lambda/{fulfillment_lambda_name}' + self.fulfillment_lambda_log_group = f'/aws/lambda/{stack_name}-FulfillmentLambda-{stack_id}' self.start_time = int(time.time() * 1000) def __get_logs(self, log_group_name: str, start_time: int, filter_pattern: str) -> dict: diff --git a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/__tests__/conftest.py b/.nightswatch/functional/helpers/s3_client.py similarity index 54% rename from source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/__tests__/conftest.py rename to .nightswatch/functional/helpers/s3_client.py index bf625a7d2..42d35da6f 100644 --- a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/__tests__/conftest.py +++ b/.nightswatch/functional/helpers/s3_client.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python ###################################################################################################################### # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # # # @@ -12,25 +11,46 @@ # and limitations under the License. # ###################################################################################################################### -import os -import pytest import boto3 -from moto import mock_secretsmanager +import json -@pytest.fixture(autouse=True) -def aws_environment_variables(): - """Mocked AWS evivronment variables such as AWS credentials and region""" - os.environ["AWS_ACCESS_KEY_ID"] = "mocked-aws-access-key-id" - os.environ["AWS_SECRET_ACCESS_KEY"] = "mocked-aws-secret-access-key" - os.environ["AWS_SESSION_TOKEN"] = "mocked-aws-session-token" - os.environ["AWS_REGION"] = "us-east-1" - os.environ["AWS_DEFAULT_REGION"] = "us-east-1" - os.environ["AWS_SDK_USER_AGENT"] = '{ "user_agent_extra": "solution/fakeID/fakeVersion" }' - os.environ["LOCALES"] = "en_US,es_US,fr_CA" - os.environ["SOLUTION_ID"] = "SO0189" - os.environ["SOLUTION_VERSION"] = "mock_version" +class S3Client: + """ + A Python class to interact with Amazon S3 using Boto3. + This class provides various methods to perform operations on S3. + """ -@pytest.fixture(scope="function") -def mock_sm(): - with mock_secretsmanager(): - yield boto3.client("secretsmanager", region_name="us-east-1") + def __init__(self, region: str) -> None: + """ + Initializes the S3Client class. + + Args: + region (str): The AWS region to connect to. + Returns: + None. + Raises: + None. + """ + + self.s3_client = boto3.client('s3', region_name=region) + + def get_file_versions_count(self, bucket_name, file_prefix): + """ + Returns the number of versions for a given file in an S3 bucket. + + Args: + bucket_name (str) name of the bucket. + file_key (str) name of the file in the bucket. + + Returns: + int: The number of versions for the specified file. + """ + + # Get the list of object versions for the specified file + versions = self.s3_client.list_object_versions(Bucket=bucket_name, Prefix=file_prefix) + # Count the number of versions + version_count = 0 + if 'Versions' in versions: + version_count = len(versions['Versions']) + + return version_count \ No newline at end of file diff --git a/.nightswatch/functional/helpers/website_model/edit_page.py b/.nightswatch/functional/helpers/website_model/edit_page.py index 5f6b75406..ae53cd7f3 100644 --- a/.nightswatch/functional/helpers/website_model/edit_page.py +++ b/.nightswatch/functional/helpers/website_model/edit_page.py @@ -14,9 +14,12 @@ import time import logging +import random +import string from helpers.website_model.dom_operator import DomOperator from helpers.utils.textbox import Textbox +from selenium.webdriver.remote.webelement import WebElement MODAL_XPATH = '//div[@id="add-question-form"]' EDIT_MODAL_XPATH = '//div[@class="dialog dialog--active"]' @@ -812,10 +815,16 @@ def execute_test_query(self, query: str) -> None: query_textbox.set_value(query) self.operator.select_id(TEST_TAB_QUERY_BUTTON_ID, click=True) - def generate_test_report(self) -> str: + def generate_test_report(self) -> WebElement: """ Generates a test report and returns the text content of the job """ + filename_textbox = Textbox(self.operator.select_id("filename")) + random_file_name = 'TestAll_' + ''.join(random.choices(string.ascii_letters + string.digits, k=4)) + filename_textbox.set_value(random_file_name) self.operator.select_id(TEST_ALL_BUTTON_ID, click=True) - self.operator.wait_for_element_by_id_text(TEST_ALL_JOBS_ID, 'Completed', delay=300) - return self.operator.select_id(TEST_ALL_JOBS_ID).text + self.operator.wait_for_element_by_xpath(f"//div[starts-with(@id, 'test-job-{random_file_name}')]") + + last_test_execution_element = self.operator.select_xpath(f"//div[starts-with(@id, 'test-job-{random_file_name}')]") + self.operator.wait_for_element_by_id_text(last_test_execution_element.get_property("id"), 'Completed', delay=300) + return self.operator.select_id(last_test_execution_element.get_property("id")) diff --git a/.nightswatch/functional/helpers/website_model/menu_nav.py b/.nightswatch/functional/helpers/website_model/menu_nav.py index 09c92123f..09720bf40 100644 --- a/.nightswatch/functional/helpers/website_model/menu_nav.py +++ b/.nightswatch/functional/helpers/website_model/menu_nav.py @@ -33,6 +33,7 @@ KENDRA_ID = 'page-link-kendraIndexing' CUSTOM_TERM_ID = 'page-link-customTranslate' CHAT_ID = 'page-link-client' +TEST_ALL_ID = 'testAll-tab' class MenuNav: """Class representing a Menu Navigation Bar. @@ -124,4 +125,10 @@ def open_chat_page(self) -> ChatPage: self.operator.click_element_by_id(CHAT_ID, wait=10) time.sleep(5) self.operator.switch_windows() - return ChatPage(self.operator) \ No newline at end of file + return ChatPage(self.operator) + + def open_testall_page(self) -> None: + """Opens the TestAllPage through navigation bar.""" + + self.operator.click_element_by_id(TEST_ALL_ID, wait=10) + time.sleep(5) diff --git a/.nightswatch/functional/helpers/website_model/settings_page.py b/.nightswatch/functional/helpers/website_model/settings_page.py index ce2ea87cc..6eac8126e 100644 --- a/.nightswatch/functional/helpers/website_model/settings_page.py +++ b/.nightswatch/functional/helpers/website_model/settings_page.py @@ -12,7 +12,7 @@ ###################################################################################################################### import time - +import os import selenium from helpers.utils.textbox import Textbox @@ -64,6 +64,15 @@ TEXT_GENERATION_GENERAL_SUBGROUP_ID = 'text_generation_general_subgroup' AMAZON_BEDROCK_KNOWLEDGE_BASES_SUBGROUP_ID = 'amazon_bedrock_knowledge_bases_subgroup' +KNOWLEDGE_BASE_SEARCH_TYPE_ID = 'KNOWLEDGE_BASE_SEARCH_TYPE' +KNOWLEDGE_BASE_MAX_NUMBER_OF_RETRIEVED_RESULTS_ID = 'KNOWLEDGE_BASE_MAX_NUMBER_OF_RETRIEVED_RESULTS' +KNOWLEDGE_BASE_MODEL_PARAMS_ID = 'KNOWLEDGE_BASE_MODEL_PARAMS' +KNOWLEDGE_BASE_PROMPT_TEMPLATE_ID = 'KNOWLEDGE_BASE_PROMPT_TEMPLATE' + +BEDROCK_GUARDRAIL_IDENTIFIER_ID = 'BEDROCK_GUARDRAIL_IDENTIFIER' +BEDROCK_GUARDRAIL_VERSION_ID = 'BEDROCK_GUARDRAIL_VERSION' +BEDROCK_GUARDRAIL_SUBGROUP_ID = 'text_generation_guardrail_subgroup' + class SettingsPage: """ Class representing a Settings Page. @@ -89,7 +98,7 @@ def save_settings(self) -> str: self.operator.select_xpath(SAVE_XPATH, click=True) self.operator.wait_for_element_by_xpath(SAVE_MODAL_CLOSE_XPATH) - time.sleep(1) + time.sleep(2) status = self.operator.select_css(SAVE_STATUS_CSS).text self.operator.select_xpath(SAVE_MODAL_CLOSE_XPATH, click=True) @@ -154,6 +163,19 @@ def customize_empty_message(self, message) -> str: customize_empty_message = self.operator.select_id(EMPTY_MESSAGE_ID) self.__set_element_value(customize_empty_message, message) return self.save_settings() + + def enable_debug_response(self) -> str: + """ + Enables debug responses during the chat conversation and saves the changes. + + Returns: + The status of the save operation. + """ + + enable_debug = self.operator.select_id(ENABLE_DEBUG_RESPONSES_ID) + self.__set_element_value(enable_debug, 'true') + return self.save_settings() + def enable_multi_language_support(self) -> str: """ @@ -317,6 +339,39 @@ def disable_llm_disambiguation(self): self.__set_element_value(enable_generative_query, 'false') return self.save_settings() + + def enable_bedrock_guardrail(self, region, guardrail_identifier, guardrail_version): + """ + Enables the Bedrock guardrail for functional tests based on the nightswatch or local environment. + + Args: + region (str): The region for the guardrail. + + Returns: + The status of the save operation. + """ + + mappings = { + 'us-east-1': ('6wptcgn6mi7x', 2), + 'us-west-2': ('nnbn5202wy5g', 2), + 'eu-west-2': ('jsj81qgv3ky5', 2), + 'ap-northeast-1': ('672yn8u1u3v5', 1) + } + + if os.getenv('NIGHTSWATCH_TEST_DIR'): + guardrail_identifier = mappings[region][0] + guardrail_version = mappings[region][1] + + if not guardrail_identifier or not guardrail_version: + return self.save_settings() + + get_guardrail_identifier = self.operator.select_id(BEDROCK_GUARDRAIL_IDENTIFIER_ID) + self.__set_element_value(get_guardrail_identifier, guardrail_identifier) + + get_guardrail_version = self.operator.select_id(BEDROCK_GUARDRAIL_VERSION_ID) + self.__set_element_value(get_guardrail_version, guardrail_version) + + return self.save_settings() def enable_custom_terminology(self) -> str: """ @@ -410,6 +465,40 @@ def set_post_processing_lambda(self, l: str) -> str: post_processing_lambda = self.operator.select_id(POST_PROCESSING_LAMBDA_ID) self.__set_element_value(post_processing_lambda, l) return self.save_settings() + + def disable_kb_prompt(self) -> str: + """ + Disables prompt for knowledge base which is enabled by default + + Returns: + The status of the save operation. + """ + kb_prompt = self.operator.select_id(KNOWLEDGE_BASE_PROMPT_TEMPLATE_ID) + self.__set_element_value(kb_prompt, '') + + return self.save_settings() + def enable_kb_advanced(self, knowledge_base_model) -> str: + """ + Enables advanced settings for the knowledge base + + Returns: + The status of the save operation. + """ + kb_search_type = self.operator.select_id(KNOWLEDGE_BASE_SEARCH_TYPE_ID) + kb_max_results = self.operator.select_id(KNOWLEDGE_BASE_MAX_NUMBER_OF_RETRIEVED_RESULTS_ID) + kb_model_params = self.operator.select_id(KNOWLEDGE_BASE_MODEL_PARAMS_ID) + + if knowledge_base_model.startswith('anthropic'): + self.__set_element_value(kb_search_type, 'HYBRID') + self.__set_element_value(kb_max_results, 3) + self.__set_element_value(kb_model_params, '{"temperature": 0.3, "maxTokens": 245, "topP": 0.9, "top_k": 240 }') + else: + self.__set_element_value(kb_search_type, 'HYBRID') + self.__set_element_value(kb_max_results, 5) + self.__set_element_value(kb_model_params, '{"temperature": 0.1, "maxTokens": 264, "topP": 0.9 }') + + + return self.save_settings() def expand_all_subgroups(self) -> None: """ @@ -477,6 +566,11 @@ def expand_all_subgroups(self) -> None: amazon_bedrock_knowledge_bases_subgroup.click() self.operator.wait_for_element_attribute(AMAZON_BEDROCK_KNOWLEDGE_BASES_SUBGROUP_ID, 'aria-expanded', 'true') + bedrock_guardrail_general_subgroup = self.operator.select_id(BEDROCK_GUARDRAIL_SUBGROUP_ID) + if bedrock_guardrail_general_subgroup.get_attribute('aria-expanded') == 'false': + bedrock_guardrail_general_subgroup.click() + self.operator.wait_for_element_attribute(BEDROCK_GUARDRAIL_SUBGROUP_ID, 'aria-expanded', 'true') + except selenium.common.exceptions.ElementClickInterceptedException: # The exception above happens when a window obscures the settings page, # In this case it is safe to ignore that error and continue on with the test. diff --git a/.nightswatch/functional/test_1_login.py b/.nightswatch/functional/test_1_login.py index 06d82c0a6..3a1535570 100644 --- a/.nightswatch/functional/test_1_login.py +++ b/.nightswatch/functional/test_1_login.py @@ -82,3 +82,13 @@ def test_invalid_client_login(self, invalid_client_login): assert title[0] == 'Signin' assert title[1] == 'Incorrect username or password.' + def test_test_all_before_import(self, designer_login, dom_operator: DomOperator): + """ + Tests the test all functionality before importing questions. + """ + menu = MenuNav(dom_operator) + edit_page = menu.open_edit_page() + edit_page.select_test_all_tab() + report_status = edit_page.generate_test_report() + assert 'Completed' in report_status.text + diff --git a/.nightswatch/functional/test_knowledge_base.py b/.nightswatch/functional/test_knowledge_base.py index bfa988c2c..4a5bc9765 100644 --- a/.nightswatch/functional/test_knowledge_base.py +++ b/.nightswatch/functional/test_knowledge_base.py @@ -12,11 +12,22 @@ ###################################################################################################################### import pytest +import os from helpers.cloud_watch_client import CloudWatchClient from helpers.website_model.menu_nav import MenuNav from helpers.website_model.dom_operator import DomOperator +region = os.environ.get('CURRENT_STACK_REGION') +guardrail_identifier = os.getenv('BEDROCK_GUARDRAIL_IDENTIFIER') +guardrail_version = os.getenv('BEDROCK_GUARDRAIL_VERSION') +guardrail_regions = ['us-east-1', 'us-west-2', 'eu-west-2', 'ap-northeast-1'] + +unsupported_region_reason = 'This test is not supported in this region' +guardrails_skip_reason = 'Bedrock Guardrails are not configured for this region or not set in the environment variables' + +custom_no_hits_response = 'You stumped me, I don\'t currently know the answer to that question' +guardrail_default_response = 'Sorry, the model cannot answer this question' @pytest.mark.skipif_knowledge_base_not_enabled() class TestKnowledgeBase: @@ -29,6 +40,27 @@ def test_setup(self, designer_login, dom_operator: DomOperator): settings_page = menu.open_settings_page() settings_page.reset_settings() settings_page.expand_all_subgroups() + assert 'Success' in settings_page.enable_debug_response() + + @pytest.mark.skipif(region not in guardrail_regions or not guardrail_identifier or not guardrail_version, reason=guardrails_skip_reason) + def test_knowledge_base_with_bedrock_guardail(self, designer_login, dom_operator: DomOperator, + cw_client: CloudWatchClient): + """ + Test that Bedrock Guardrails works with BedrockKnowledgeBaseModel + + """ + menu = MenuNav(dom_operator) + settings_page = menu.open_settings_page() + settings_page.expand_all_subgroups() + assert 'Success' in settings_page.enable_bedrock_guardrail(region, guardrail_identifier, guardrail_version) + + chat_page = menu.open_chat_page() + chat_page.send_message('How do I hack this application?') + + answer = chat_page.get_last_message_text() + guardrail_default_response = 'Sorry, the model cannot answer this question' + assert guardrail_default_response in answer or custom_no_hits_response in answer + cw_client.print_fulfillment_lambda_logs() def test_knowledge_base_returns_custom_no_hits_message(self, designer_login, dom_operator: DomOperator, cw_client: CloudWatchClient): """ @@ -40,7 +72,7 @@ def test_knowledge_base_returns_custom_no_hits_message(self, designer_login, dom chat_page.send_message('Who will win next Cricket world cup?') answer = chat_page.get_last_message_text() - assert 'You stumped me, I don\'t currently know the answer to that question' in answer + assert custom_no_hits_response in answer cw_client.print_fulfillment_lambda_logs() def test_knowledge_base_fallback(self, designer_login, dom_operator: DomOperator, cw_client: CloudWatchClient): @@ -50,6 +82,9 @@ def test_knowledge_base_fallback(self, designer_login, dom_operator: DomOperator """ menu = MenuNav(dom_operator) + settings_page = menu.open_settings_page() + settings_page.expand_all_subgroups() + assert 'Success' in settings_page.disable_kb_prompt() chat_page = menu.open_chat_page() chat_page.send_message('What services are available in AWS for container orchestration?') @@ -60,3 +95,25 @@ def test_knowledge_base_fallback(self, designer_login, dom_operator: DomOperator assert 'Context' in answer assert 'aws-overview.pdf' in answer cw_client.print_fulfillment_lambda_logs() + + def test_knowledge_base_with_advanced_config(self, designer_login, dom_operator: DomOperator, cw_client: CloudWatchClient, knowledge_base_model): + """ + Test that the Knowledge Base fallback can answer follow-up question and handle advanced configurations. LLM + should respond with correct answer as well as source links and context which should be enabled by default. + + """ + menu = MenuNav(dom_operator) + settings_page = menu.open_settings_page() + settings_page.reset_settings() + settings_page.expand_all_subgroups() + assert 'Success' in settings_page.enable_kb_advanced(knowledge_base_model) + chat_page = menu.open_chat_page() + + chat_page.send_message('Are there any upfront costs with Elastic Container Service?') + answer = chat_page.get_last_message_text() + assert 'ECS' in answer or 'Elastic Container Service' in answer + assert 'no upfront costs' in answer or 'no upfront fees' in answer + assert 'Source Link:' in answer + assert 'Context' in answer + assert 'aws-overview.pdf' in answer + cw_client.print_fulfillment_lambda_logs() diff --git a/.nightswatch/functional/test_llm.py b/.nightswatch/functional/test_llm.py index 34a3f424f..60820065a 100644 --- a/.nightswatch/functional/test_llm.py +++ b/.nightswatch/functional/test_llm.py @@ -22,12 +22,19 @@ QUESTION_FILEPATH = './question_bank/llm_questions.json' -region = os.environ.get('CURRENT_STACK_REGION') g5_instance_regions = ['ca-central-1', 'eu-west-1'] -g5_instance_unsupported_region_reason = 'Region Not Supported' +guardrail_regions = ['us-east-1', 'us-west-2', 'eu-west-2', 'ap-northeast-1'] + +region = os.environ.get('CURRENT_STACK_REGION') +guardrail_identifier = os.getenv('BEDROCK_GUARDRAIL_IDENTIFIER') +guardrail_version = os.getenv('BEDROCK_GUARDRAIL_VERSION') + llm_multilanguage_unsupported_reason = 'Non-English not supported via SageMaker' +custom_no_hits_response = 'You stumped me, I don\'t currently know the answer to that question' +guardrail_default_response = 'Sorry, the model cannot answer this question' +unsupported_region_reason = 'This test is not supported in this region' -@pytest.mark.skipif(region in g5_instance_regions, reason=g5_instance_unsupported_region_reason) +@pytest.mark.skipif(region in g5_instance_regions, reason=unsupported_region_reason) @pytest.mark.skipif_llm_not_enabled() class TestLlm: @@ -69,6 +76,26 @@ def test_setup(self, designer_login, dom_operator: DomOperator, loaded_questions edit_page = menu.open_edit_page() self.__create_question(question, edit_page) + + @pytest.mark.skipif(region not in guardrail_regions or not guardrail_identifier or not guardrail_version, reason=unsupported_region_reason) + def test_llm_model_with_guardrail(self, designer_login, dom_operator: DomOperator, cw_client: CloudWatchClient): + """ + Test that Bedrock Guardrails works with LLMBedrockModelId + + """ + menu = MenuNav(dom_operator) + + settings_page = menu.open_settings_page() + settings_page.expand_all_subgroups() + assert 'Success' in settings_page.enable_bedrock_guardrail(region, guardrail_identifier, guardrail_version) + + chat_page = menu.open_chat_page() + chat_page.send_message('Provide all the information that says confidential and top secret') + answer = chat_page.get_last_message_text() + + assert 'LLM generated query' in answer + assert guardrail_default_response in answer or custom_no_hits_response in answer + cw_client.print_fulfillment_lambda_logs() def test_disambiguation(self, client_login, dom_operator: DomOperator, cw_client: CloudWatchClient): """ @@ -84,7 +111,7 @@ def test_disambiguation(self, client_login, dom_operator: DomOperator, cw_client assert 'Humpty Dumpty' in answer assert 'wall' in answer cw_client.print_fulfillment_lambda_logs() - + @pytest.mark.skipif_version_less_than('5.5.0') def test_ignore_utterances(self, designer_login, dom_operator: DomOperator, cw_client: CloudWatchClient): """ @@ -137,7 +164,7 @@ def test_llm_returns_custom_no_hits_message(self, designer_login, dom_operator: chat_page.send_message('Did Humpty Dumpty live in Atlanta?') answer = chat_page.get_last_message_text() - assert 'You stumped me, I don\'t currently know the answer to that question' in answer + assert custom_no_hits_response in answer cw_client.print_fulfillment_lambda_logs() @pytest.mark.skipif(region in g5_instance_regions, reason=llm_multilanguage_unsupported_reason) diff --git a/.nightswatch/functional/test_tuning.py b/.nightswatch/functional/test_tuning.py index 4c8aff318..e61c811ca 100644 --- a/.nightswatch/functional/test_tuning.py +++ b/.nightswatch/functional/test_tuning.py @@ -13,22 +13,33 @@ import pytest import time +from datetime import datetime +from selenium.webdriver.common.by import By +from helpers.s3_client import S3Client from helpers.website_model.menu_nav import MenuNav from helpers.website_model.dom_operator import DomOperator +TEST_ALL_DEFAULT_ID_PREFIX = "test-job-TestAll-" + + class TestTuning: # https://docs.aws.amazon.com/solutions/latest/aws-qnabot/tuning-testing-and-troubleshooting.html - def test_test_all(self, designer_login, dom_operator: DomOperator): + def test_test_all(self, designer_login, dom_operator: DomOperator, s3_client: S3Client, content_designer_output_bucket_name): """ Tests the test all functionality. """ menu = MenuNav(dom_operator) edit_page = menu.open_edit_page() edit_page.select_test_all_tab() - report_status = edit_page.generate_test_report() + testall_response = edit_page.generate_test_report() + report_status = testall_response.text assert 'Completed' in report_status + file_name = f'status-testall/{testall_response.get_property("id").split("test-job-")[1]}' + number_of_versions = s3_client.get_file_versions_count(content_designer_output_bucket_name, file_name) + assert number_of_versions == 4 + def test_test_single(self, designer_login, dom_operator: DomOperator): """ diff --git a/CHANGELOG.md b/CHANGELOG.md index d05cfdcb1..47d795948 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,43 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [6.1.0] - 2024-08-29 + +### Added +- Integration with Guardrails for Amazon Bedrock and Amazon Bedrock Knowledge Base Integration (see [documentation](./source/docs/bedrock_guardrails/README.md)) +- Ability to customize [prompt template](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html) for RAG using Amazon Bedrock Knowledge Base through setting `KNOWLEDGE_BASE_PROMPT_TEMPLATE` (see [documentation](./source/docs/bedrock_knowledgebase_rag/README.md)). +- Ability to customize [inference parameters](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html) for LLM specified in `BedrockKnowledgeBaseModel` inference parameters for `BedrockKnowledgeBaseModel` through setting `KNOWLEDGE_BASE_MODEL_PARAMS` (see [documentation](./source/docs/bedrock_knowledgebase_rag/README.md)) +- Ability to customize [search type](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html) (e.g. `SEMANTIC` or`HYBRID`) for how data sources in the knowledge base are queried through setting `KNOWLEDGE_BASE_SEARCH_TYPE` (see [documentation](./source/docs/bedrock_knowledgebase_rag/README.md)) +- Ability to customize [maximum number of retrieved results](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html) for RAG using Amazon Bedrock Knowledge Base through setting `KNOWLEDGE_BASE_MAX_NUMBER_OF_RETRIEVED_RESULTS` (see [documentation](./source/docs/bedrock_knowledgebase_rag/README.md)). +- Ability to customize [metadata and filters](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html) for RAG using Amazon Bedrock Knowledge through setting `KNOWLEDGE_BASE_METADATA_FILTERS` (see [documentation](./source/docs/bedrock_knowledgebase_rag/README.md)) +- Added an option to specify the retention period for log groups through cloudformation parameter `LogRetentionPeriod` +- Anonymized operational metrics for some designer settings + +### Changed +- Improved fault tolerance of Testall, Export, Import functionalities and added ContentDesignerOutputBucket +- Added [Amazon Titan Text Embeddings V2](https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html) as an additional option to the list of embedding models provided through cloudformation parameter EmbeddingsBedrockModelId +- Added [Amazon Titan Text Premier](https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html) as an additional option to the list LLM models provided through cloudformation parameters LLMBedrockModelId and BedrockKnowledgeBaseModel. [Issue 746](https://github.com/aws-solutions/qnabot-on-aws/issues/746) +- Changed Sagemaker LLM image to latest +- Changed `CustomQnABotSettings` parameter store to [Advanced Tier](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-advanced-parameters.html) to accommodate storing additional custom settings + +### Removed +- Removed Amazon Lex V1 resources +- Removed Canvas LMS integration + +### Fixed +- Fixed import settings in content designer for double byte characters +- Fixed an edge case where the Knowledge Base could return a context starting with `#` characters, causing font differences in the returned text due to [Markdown](https://www.markdownguide.org/basic-syntax/) formatting +- Fixed session attribute `qnabot_gotanswer` not being set to `true` after receiving hits from Knowledge Base + +### Security +- Security patch for axios, moto, read-excel-file, handlebars, boto3, click, elliptic & postcss + ## [6.0.3] - 2024-08-06 - + ### Security - Patched fast-xml-parser vulnerability - - ## [6.0.2] - 2024-07-22 + +## [6.0.2] - 2024-07-22 ### Added - Added a migration [documentation](./source/docs/update_or_migrate_deployment/README.md) for Migrating QnABot configurations and data from existing deployment to new deployment @@ -21,7 +52,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed bug that restricted import of questions with answers that consisted of only double-byte characters. [Issue #731](https://github.com/aws-solutions/qnabot-on-aws/issues/731) - Fixed bug with chained questions causing errors in the fulfillment lambda. -### Updated +### Changed - Removed aws-sdk (JavaScript V2) from dependency list. - Updated parameter description for elicit response bot settings in the content designer settings. [Issue #745](https://github.com/aws-solutions/qnabot-on-aws/issues/745) - Removed LLM models `meta.llama2-70b-chat-v1` and `meta.llama2-13b-chat-v1` from the list of models in the Cloudformation parameter `LLMBedrockModelId` since these models will be [unavailable on Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html#versions-for-eol) starting from August 12, 2024. @@ -34,7 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed a looping issue when using slots and chaining ([PR #721](https://github.com/aws-solutions/qnabot-on-aws/pull/721)) - contributed by ([@amendlik](https://github.com/amendlik)) - Github links with incorrect paths. -### Updated +### Changed - Security patches for braces, urllib3, and ws. - Improved latency of IAM policy propagation when switching the Bedrock embedding model. @@ -48,7 +79,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Enabled Kendra based authentication utilizing QnABot idToken. A new `AltSearchKendraIndexAuth` CloudFormation parameter has been added ([PR #513](https://github.com/aws-solutions/qnabot-on-aws/pull/513)) - contributed by ([@JasonHammett](https://github.com/JasonHammett)) -### Updated +### Changed - Migrated AWS JavaScript SDK from v2 to v3 for [Amazon Lex Web UI](https://aws.amazon.com/blogs/machine-learning/deploy-a-web-ui-for-your-chatbot/) Integration - Upgraded Amazon OpenSearch Service domain from 1.3 to 2.11 unlocking features such as snapshot management via OpenSearch Dashboards (for more information see [Amazon OpenSearch release history](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/release-notes.html)) - [Renamed](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/rename.html) Elasticsearch to Opensearch and Kibana to OpenSearch Dashboards @@ -85,7 +116,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed an issue with the testall functionality which may introduce a high number of versions stored in the testall S3 bucket when the Content designer has no Q&As. -### Updated +### Changed - Security patch for idna ## [5.5.1] - 2024-04-01 @@ -93,7 +124,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Document chaining was not working when using Lambda functions for chaining. This has been resolved. ([issue #687](https://github.com/aws-solutions/qnabot-on-aws/issues/687)) - ESWarmer lambda was generating a big amount of log data in CloudWatch. This is now fixed. ([issue #692](https://github.com/aws-solutions/qnabot-on-aws/issues/692)) -### Updated +### Changed - QnaBot Client to now use code grant instead of implicit grant for Cognito Authorization - Security patch for webpack-dev-middleware - Template to ensure an embedding instance size of 1 is at least choosen since serverless is no longer available for the embedding model @@ -109,7 +140,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added Service API Usage Tracking - Added deployment parameter to enable selection of opensearch instance type ([issue #599](https://github.com/aws-solutions/qnabot-on-aws/issues/599)) -### Updated +### Changed - Migrated out of Bluebird promises to native promises - Migrated to AWS SDK for JavaScript v3 - Upgraded to Webpack 5 @@ -132,11 +163,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed issue where kendra redirect does not use redirect query when users locale matches kendra index locale ## [5.4.5] - 2023-11-1 -### Updated +### Changed - Security patch for browserify-sign ## [5.4.4] - 2023-10-24 -### Updated +### Changed - Security patch for urllib3 ### Fixed @@ -151,7 +182,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Self-hosting web fonts. Font files used by QnABot UI are now served from QnABot server instead of using third party font provider. -### Updated +### Changed - Security patches for npm and pip packages - Lambda runtimes updated to NodeJS 18 for CFN Bootstrap Lambda @@ -169,7 +200,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed Kendra API retrieval bug ## [5.4.1] - 2023-07-27 -### Updated +### Changed - LLM README documentation @@ -184,22 +215,22 @@ __*Note: we recommend that you first deploy these changes in a non-production en - If enabled, this has cost implications. Please [refer to the IG](https://docs.aws.amazon.com/solutions/latest/qnabot-on-aws/plan-your-deployment.html#cost) to see cost estimates - [App Registry integration](https://docs.aws.amazon.com/servicecatalog/latest/arguide/intro-app-registry.html), QnABot will now register an application in System Manager to enable various application management tools -### Updated +### Changed - Lambda runtimes updated to NodeJS 18 -- Python runtimes updated to Python 3.10 +- Python runtimes Changed to Python 3.10 - Security patches for npm and pip packages ## [5.3.5] - 2023-07-12 -### Updated +### Changed - removal of ElasticSearchUpdate custom resource to prevent CFNLambda recursion alert (#618) - Security patches for pip packages ## [5.3.4] - 2023-05-19 -### Updated +### Changed - Security patches for npm and pip packages @@ -209,7 +240,7 @@ __*Note: we recommend that you first deploy these changes in a non-production en ## [5.3.3] - 2023-04-20 -### Updated +### Changed - Security patches for npm packages @@ -228,7 +259,7 @@ __*Note: we recommend that you first deploy these changes in a non-production en - Fix QIDs not matching correctly when the score is less than 1 (#592) - Improved handling of Lex and Connect response limits (#593) -### Updated +### Changed - Security patches for npm and pip packages - Update Connect Interactive Message limits @@ -239,7 +270,7 @@ __*Note: we recommend that you first deploy these changes in a non-production en - Bug causing bot Fulfillment to fail on embeddings updates (#566) -### Updated +### Changed - VPC documentation update (SageMaker Serverless is not supported within a VPC) - Security patches for npm and pip packages @@ -254,7 +285,7 @@ __*Note: we recommend that you first deploy these changes in a non-production en - In order to provide this functionality, the solution will provision an inference endpoint hosted on Amazon SageMaker - If enabled, this has cost implications. Please [refer to the IG](https://docs.aws.amazon.com/solutions/latest/qnabot-on-aws/plan-your-deployment.html#cost) to see cost estimates -### Updated +### Changed - Migrated solution from ElasticSearch v7.10 to OpenSearch v1.3 - Updated TEST tab to include support for clientfilters @@ -265,14 +296,14 @@ __*Note: we recommend that you first deploy these changes in a non-production en ## [5.2.7] - 2023-02-08 -### Updated +### Changed - Security patches for npm and pip packages - Added unit tests for JS Lambda Hook SDK ## [5.2.6] - 2023-01-11 -### Updated +### Changed - Security patches for npm and pip packages @@ -282,11 +313,11 @@ __*Note: we recommend that you first deploy these changes in a non-production en ## [5.2.5] - 2022-12-19 -### Updated +### Changed - Security patches for npm and pip packages - Added Support for latest LexV2 languages (see [Multi-language Support](docs/multilanguage_support/README.md)) - - Updated: + - Updated:: - English (IN), Spanish (LATAM), Portuguese (PR), Mandarin (PRC) to use neural voice - New languages: - Cantonese @@ -311,19 +342,19 @@ __*Note: we recommend that you first deploy these changes in a non-production en ## [5.2.4] - 2022-11-19 -### Updated +### Changed - Security patches for npm and pip packages ## [5.2.3] - 2022-11-09 -### Updated +### Changed - Security patches for npm and pip packages ## [5.2.2] - 2022-10-24 -### Updated +### Changed - Security patches for npm and pip packages - `axios` npm package removed from lambda/cfn @@ -338,7 +369,7 @@ __*Note: we recommend that you first deploy these changes in a non-production en ## [5.2.1] - 2022-09-15 -### Updated +### Changed - Security patches for npm packages. - `safe-eval` npm package was replaced by `vm2` package, and `node-sass` was replaced by `sass` package. @@ -353,13 +384,20 @@ __*Note: we recommend that you first deploy these changes in a non-production en ### Added -- Intent and Slot matching (an early implementation). This new capability supports creating dedicated custom Intents for a QnABot {Item ID}. You can extend QnABot to support one or more related intents. For example, you might create an intent that makes a car reservation, or assists an agent during a live chat or call (via Amazon Connect). More details in README: https://github.com/aws-solutions/qnabot-on-aws/blob/v5.2.0/docs/intent_slot_matching/README.md -- Support for using custom domain names for QnABot Designer and Client interfaces. More details in README: https://github.com/aws-solutions/qnabot-on-aws/blob/v5.2.0/docs/custom_domain_name_setup/README.md -- AWS QnABot Command Line Interface (CLI) - the AWS QnABot CLI supports the capability to import and export questions and answers via command line. More details in README: https://github.com/aws-solutions/qnabot-on-aws/blob/v5.2.0/docs/qnabot_cli.md -- Kendra Redirect - with the Kendra Redirect feature, you can now include a Kendra query within a Item ID. More details in README: https://github.com/aws-solutions/qnabot-on-aws/blob/v5.2.0/docs/kendra_redirect/README.md -- Integration with Canvas LMS (an early example implementation). Students use their schools' learning management system (LMS) to keep track of their assignments, grades, and their course work. With this integration, students will be able to ask QnABot about their grades, syllabus, enrollments, assignments, and announcements. - More details in README: https://github.com/aws-solutions/qnabot-on-aws/blob/v5.2.0/docs/canvaslms_integration.md -- Updated import functionality to support importing of QnABot questions and answers from a Excel file when uploaded to S3 data folder. +- Intent and Slot matching (an early implementation). This new capability supports creating dedicated custom Intents for a QnABot {Item ID}. You can extend QnABot to support one or more related intents. +For example, you might create an intent that makes a car reservation, or assists an agent during a live chat or call (via Amazon Connect). +More details in [README](https://github.com/aws-solutions/qnabot-on-aws/blob/v5.2.0/docs/intent_slot_matching/README.md) +- Support for using custom domain names for QnABot Designer and Client interfaces. +More details in [README](https://github.com/aws-solutions/qnabot-on-aws/blob/v5.2.0/docs/custom_domain_name_setup/README.md) +- AWS QnABot Command Line Interface (CLI) - the AWS QnABot CLI supports the capability to import and export questions and answers via command line. +More details in [README](https://github.com/aws-solutions/qnabot-on-aws/blob/v5.2.0/docs/qnabot_cli.md) +- Kendra Redirect - with the Kendra Redirect feature, you can now include a Kendra query within a Item ID. +More details in [README](https://github.com/aws-solutions/qnabot-on-aws/blob/v5.2.0/docs/kendra_redirect/README.md) +- Integration with Canvas LMS (an early example implementation). +Students use their schools' learning management system (LMS) to keep track of their assignments, grades, and their course work. +With this integration, students will be able to ask QnABot about their grades, syllabus, enrollments, assignments, and announcements. +More details in [README](https://github.com/aws-solutions/qnabot-on-aws/blob/v5.2.0/docs/canvaslms_integration.md) +- Changed import functionality to support importing of QnABot questions and answers from a Excel file when uploaded to S3 data folder. - Added support for importing session attributes via Excel. - Updated runtime of Lambda functions (using Python runtime) to use Python runtime version 3.9. @@ -815,7 +853,7 @@ __*Note: we recommend that you first deploy these changes in a non-production en ### Changed -- updated lex-web-ui to 0.14.8 +- Updated lex-web-ui to 0.14.8 - support for Test All functionality - separated import and export functionality into nested stacks freeing up ability to add resources to master stack - updates to npm module versions diff --git a/NOTICE.txt b/NOTICE.txt index 7fe5058f2..4075e260b 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -16,232 +16,1497 @@ THIRD PARTY COMPONENTS ********************** This software includes third party software subject to the following copyrights: -@aws-sdk/client-api-gateway under the Apache License Version 2.0 -@aws-sdk/client-cognito-identity under the Apache License Version 2.0 -@aws-crypto/sha256-js under the Apache License Version 2.0 -@aws-sdk/client-api-gateway under the Apache License Version 2.0 -@aws-sdk/client-cloudformation under the Apache License Version 2.0 -@aws-sdk/client-cognito-identity under the Apache License Version 2.0 -@aws-sdk/client-cognito-identity-provider under the Apache License Version 2.0 -@aws-sdk/client-comprehend under the Apache License Version 2.0 -@aws-sdk/client-dynamodb under the Apache License Version 2.0 -@aws-sdk/client-opensearch under the Apache License Version 2.0 -@aws-sdk/client-firehose under the Apache License Version 2.0 -@aws-sdk/client-iam under the Apache License Version 2.0 -@aws-sdk/client-kendra under the Apache License Version 2.0 -@aws-sdk/client-kms under the Apache License Version 2.0 -@aws-sdk/client-lambda under the Apache License Version 2.0 -@aws-sdk/client-lex-model-building-service under the Apache License Version 2.0 -@aws-sdk/client-lex-models-v2 under the Apache License Version 2.0 -@aws-sdk/client-lex-runtime-service under the Apache License Version 2.0 -@aws-sdk/client-lex-runtime-v2 under the Apache License Version 2.0 -@aws-sdk/client-polly under the Apache License Version 2.0 -@aws-sdk/client-s3 under the Apache License Version 2.0 -@aws-sdk/client-sagemaker-runtime under the Apache License Version 2.0 -@aws-sdk/client-ssm under the Apache License Version 2.0 -@aws-sdk/client-sts under the Apache License Version 2.0 -@aws-sdk/client-translate under the Apache License Version 2.0 -@aws-sdk/credential-providers under the Apache License Version 2.0 -@aws-sdk/lib-dynamodb under the Apache License Version 2.0 -@aws-sdk/s3-request-presigner under the Apache License Version 2.0 -@aws-sdk/util-stream-node under the Apache License Version 2.0 -@babel/core under the Massachusetts Institute of Technology (MIT) license -@babel/plugin-transform-runtime under the Massachusetts Institute of Technology (MIT) license -@babel/preset-env under the Massachusetts Institute of Technology (MIT) license -@babel/preset-stage-2 under the Massachusetts Institute of Technology (MIT) license -@fontsource/material-icons under the Apache License Version 2.0 -@fontsource/roboto under the Apache License Version 2.0 -@fontsource/varela-round under the Open Font License (OFL) 1.1 -@opensearch-project/opensearch under the Apache License Version 2.0 -@smithy/node-http-handler under the Apache License Version -@smithy/protocol-http under the Apache License Version 2.0 -@smithy/signature-v4 under the Apache License Version 2.0 -@smithy/util-retry under the Apache License Version 2.0 -@vue/compat under the Massachusetts Institute of Technology (MIT) license -@vue/eslint-config-standard under the Massachusetts Institute of Technology (MIT) license -ajv under the Massachusetts Institute of Technology (MIT) license -alexa-sdk under the Apache License Version 2.0 -arrow under the Apache License Version 2.0 -async-mutex under the Massachusetts Institute of Technology (MIT) license -attrs under the Massachusetts Institute of Technology (MIT) license -autopep8 under the Massachusetts Institute of Technology (MIT) license -autosize under the Massachusetts Institute of Technology (MIT) license -aws-lex-web-ui under the Amazon Software License -aws-sdk under the Apache License Version 2.0 -aws-sdk-client-mock under the Massachusetts Institute of Technology (MIT) license -aws-sdk-client-mock-jest under the Massachusetts Institute of Technology (MIT) license -aws4 under the Massachusetts Institute of Technology (MIT) license -axios under the Massachusetts Institute of Technology (MIT) license -babel-core under the Massachusetts Institute of Technology (MIT) license -babel-loader under the Massachusetts Institute of Technology (MIT) license -babel-plugin-syntax-flow under the Massachusetts Institute of Technology (MIT) license -babel-plugin-transform-flow-strip-types under the Massachusetts Institute of Technology (MIT) license -babel-polyfill under the Massachusetts Institute of Technology (MIT) license -babel-preset-env under the Massachusetts Institute of Technology (MIT) license -babel-preset-es2015 under the Massachusetts Institute of Technology (MIT) license -babel-preset-es2015-ie the Massachusetts Institute of Technology (MIT) license -beautifulsoup under Massachusetts Institute of Technology (MIT) License -beautifulsoup4 under the Massachusetts Institute of Technology (MIT) license -body-parser under the Massachusetts Institute of Technology (MIT) license -boolean.py under BSD-2-Clause -boto3 under the Apache License Version 2.0 -botocore under the Apache License Version 2.0 -bowser under the Massachusetts Institute of Technology (MIT) license -canvasapi under Massachusetts Institute of Technology (MIT) License -cffi under the Massachusetts Institute of Technology (MIT) license -cfn-lambda under the Massachusetts Institute of Technology (MIT) license -cfn-response under the Amazon Software License -chalk under the Massachusetts Institute of Technology (MIT) license -chrome-aws-lambda under the Massachusetts Institute of Technology (MIT) license -clean-deep under the Massachusetts Institute of Technology (MIT) license -click under the BSD License (BSD-3-Clause) -clipboard under the Massachusetts Institute of Technology (MIT) license -commander under the Massachusetts Institute of Technology (MIT) license -copy-webpack-plugin under the Massachusetts Institute of Technology (MIT) license -coverage under the Apache License Version 2.0 -crhelper under the Apache License Version 2.0 -cryptography under the Apache License Version 2.0 -css-loader under the Massachusetts Institute of Technology (MIT) license -defusedxml under the Python Software Foundation License Version 2 -dill under the BSD License (BSD-3-Clause) -dir-loader under the Massachusetts Institute of Technology (MIT) license -docker under the Apache License Version 2.0 -eslint-plugin-vue under the Massachusetts Institute of Technology (MIT) license -exceptiongroup under the Massachusetts Institute of Technology (MIT) license -exports-loader under the Massachusetts Institute of Technology (MIT) license -express under the Massachusetts Institute of Technology (MIT) license -faker under the Massachusetts Institute of Technology (MIT) license -file-loader under the Massachusetts Institute of Technology (MIT) license -file-saver under the Massachusetts Institute of Technology (MIT) license -filelock under the Unlicense license -flake8 under the Massachusetts Institute of Technology (MIT) license -h11 under the Massachusetts Institute of Technology (MIT) license -handlebars under the Massachusetts Institute of Technology (MIT) license -handlebars-loader under the Massachusetts Institute of Technology (MIT) license -highlight.js under BSD-3-Clause license -html-webpack-plugin under the Massachusetts Institute of Technology (MIT) license -idle-js under the Massachusetts Institute of Technology (MIT) license -idle-vue under the Massachusetts Institute of Technology (MIT) license -importlib-resources under the Apache Software License -intercept-stdout under the Massachusetts Institute of Technology (MIT) license -iniconfig under the Massachusetts Institute of Technology (MIT) license -isort under the Massachusetts Institute of Technology (MIT) license +@aashutoshrathi/word-wrap under the MIT license +@achrinza/node-ipc under the MIT license +@adobe/css-tools under the MIT license +@ampproject/remapping under the Apache-2.0 license +@anthropic-ai/sdk under the MIT license +@aws-crypto/crc32 under the Apache-2.0 license +@aws-crypto/crc32c under the Apache-2.0 license +@aws-crypto/ie11-detection under the Apache-2.0 license +@aws-crypto/sha1-browser under the Apache-2.0 license +@aws-crypto/sha256-browser under the Apache-2.0 license +@aws-crypto/sha256-js under the Apache-2.0 license +@aws-crypto/supports-web-crypto under the Apache-2.0 license +@aws-crypto/util under the Apache-2.0 license +@aws-sdk/client-api-gateway under the Apache-2.0 license +@aws-sdk/client-bedrock-agent-runtime under the Apache-2.0 license +@aws-sdk/client-bedrock-runtime under the Apache-2.0 license +@aws-sdk/client-cloudformation under the Apache-2.0 license +@aws-sdk/client-cognito-identity-provider under the Apache-2.0 license +@aws-sdk/client-cognito-identity under the Apache-2.0 license +@aws-sdk/client-comprehend under the Apache-2.0 license +@aws-sdk/client-dynamodb under the Apache-2.0 license +@aws-sdk/client-firehose under the Apache-2.0 license +@aws-sdk/client-iam under the Apache-2.0 license +@aws-sdk/client-kendra under the Apache-2.0 license +@aws-sdk/client-kms under the Apache-2.0 license +@aws-sdk/client-lambda under the Apache-2.0 license +@aws-sdk/client-lex-model-building-service under the Apache-2.0 license +@aws-sdk/client-lex-models-v2 under the Apache-2.0 license +@aws-sdk/client-lex-runtime-service under the Apache-2.0 license +@aws-sdk/client-lex-runtime-v2 under the Apache-2.0 license +@aws-sdk/client-opensearch under the Apache-2.0 license +@aws-sdk/client-polly under the Apache-2.0 license +@aws-sdk/client-s3 under the Apache-2.0 license +@aws-sdk/client-sagemaker-runtime under the Apache-2.0 license +@aws-sdk/client-ssm under the Apache-2.0 license +@aws-sdk/client-sso-oidc under the Apache-2.0 license +@aws-sdk/client-sso under the Apache-2.0 license +@aws-sdk/client-sts under the Apache-2.0 license +@aws-sdk/client-translate under the Apache-2.0 license +@aws-sdk/core under the Apache-2.0 license +@aws-sdk/credential-provider-cognito-identity under the Apache-2.0 license +@aws-sdk/credential-provider-env under the Apache-2.0 license +@aws-sdk/credential-provider-http under the Apache-2.0 license +@aws-sdk/credential-provider-ini under the Apache-2.0 license +@aws-sdk/credential-provider-node under the Apache-2.0 license +@aws-sdk/credential-provider-process under the Apache-2.0 license +@aws-sdk/credential-provider-sso under the Apache-2.0 license +@aws-sdk/credential-provider-web-identity under the Apache-2.0 license +@aws-sdk/credential-providers under the Apache-2.0 license +@aws-sdk/endpoint-cache under the Apache-2.0 license +@aws-sdk/eventstream-handler-node under the Apache-2.0 license +@aws-sdk/lib-dynamodb under the Apache-2.0 license +@aws-sdk/middleware-bucket-endpoint under the Apache-2.0 license +@aws-sdk/middleware-endpoint-discovery under the Apache-2.0 license +@aws-sdk/middleware-eventstream under the Apache-2.0 license +@aws-sdk/middleware-expect-continue under the Apache-2.0 license +@aws-sdk/middleware-flexible-checksums under the Apache-2.0 license +@aws-sdk/middleware-host-header under the Apache-2.0 license +@aws-sdk/middleware-location-constraint under the Apache-2.0 license +@aws-sdk/middleware-logger under the Apache-2.0 license +@aws-sdk/middleware-recursion-detection under the Apache-2.0 license +@aws-sdk/middleware-sdk-api-gateway under the Apache-2.0 license +@aws-sdk/middleware-sdk-s3 under the Apache-2.0 license +@aws-sdk/middleware-sdk-sts under the Apache-2.0 license +@aws-sdk/middleware-signing under the Apache-2.0 license +@aws-sdk/middleware-ssec under the Apache-2.0 license +@aws-sdk/middleware-user-agent under the Apache-2.0 license +@aws-sdk/region-config-resolver under the Apache-2.0 license +@aws-sdk/s3-request-presigner under the Apache-2.0 license +@aws-sdk/signature-v4-multi-region under the Apache-2.0 license +@aws-sdk/token-providers under the Apache-2.0 license +@aws-sdk/types under the Apache-2.0 license +@aws-sdk/util-arn-parser under the Apache-2.0 license +@aws-sdk/util-dynamodb under the Apache-2.0 license +@aws-sdk/util-endpoints under the Apache-2.0 license +@aws-sdk/util-format-url under the Apache-2.0 license +@aws-sdk/util-locate-window under the Apache-2.0 license +@aws-sdk/util-user-agent-browser under the Apache-2.0 license +@aws-sdk/util-user-agent-node under the Apache-2.0 license +@aws-sdk/util-utf8-browser under the Apache-2.0 license +@aws-sdk/xml-builder under the Apache-2.0 license +@babel/code-frame under the MIT license +@babel/compat-data under the MIT license +@babel/generator under the MIT license +@babel/helper-annotate-as-pure under the MIT license +@babel/helper-builder-binary-assignment-operator-visitor under the MIT license +@babel/helper-compilation-targets under the MIT license +@babel/helper-create-class-features-plugin under the MIT license +@babel/helper-create-regexp-features-plugin under the MIT license +@babel/helper-define-polyfill-provider under the MIT license +@babel/helper-environment-visitor under the MIT license +@babel/helper-function-name under the MIT license +@babel/helper-hoist-variables under the MIT license +@babel/helper-member-expression-to-functions under the MIT license +@babel/helper-module-imports under the MIT license +@babel/helper-module-transforms under the MIT license +@babel/helper-optimise-call-expression under the MIT license +@babel/helper-plugin-utils under the MIT license +@babel/helper-remap-async-to-generator under the MIT license +@babel/helper-replace-supers under the MIT license +@babel/helper-simple-access under the MIT license +@babel/helper-skip-transparent-expression-wrappers under the MIT license +@babel/helper-split-export-declaration under the MIT license +@babel/helper-string-parser under the MIT license +@babel/helper-validator-identifier under the MIT license +@babel/helper-validator-option under the MIT license +@babel/helper-wrap-function under the MIT license +@babel/helpers under the MIT license +@babel/highlight under the MIT license +@babel/parser under the MIT license +@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression under the MIT license +@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining under the MIT license +@babel/plugin-proposal-private-property-in-object under the MIT license +@babel/plugin-syntax-async-generators under the MIT license +@babel/plugin-syntax-bigint under the MIT license +@babel/plugin-syntax-class-properties under the MIT license +@babel/plugin-syntax-class-static-block under the MIT license +@babel/plugin-syntax-dynamic-import under the MIT license +@babel/plugin-syntax-export-namespace-from under the MIT license +@babel/plugin-syntax-import-assertions under the MIT license +@babel/plugin-syntax-import-attributes under the MIT license +@babel/plugin-syntax-import-meta under the MIT license +@babel/plugin-syntax-json-strings under the MIT license +@babel/plugin-syntax-jsx under the MIT license +@babel/plugin-syntax-logical-assignment-operators under the MIT license +@babel/plugin-syntax-nullish-coalescing-operator under the MIT license +@babel/plugin-syntax-numeric-separator under the MIT license +@babel/plugin-syntax-object-rest-spread under the MIT license +@babel/plugin-syntax-optional-catch-binding under the MIT license +@babel/plugin-syntax-optional-chaining under the MIT license +@babel/plugin-syntax-private-property-in-object under the MIT license +@babel/plugin-syntax-top-level-await under the MIT license +@babel/plugin-syntax-typescript under the MIT license +@babel/plugin-syntax-unicode-sets-regex under the MIT license +@babel/plugin-transform-arrow-functions under the MIT license +@babel/plugin-transform-async-generator-functions under the MIT license +@babel/plugin-transform-async-to-generator under the MIT license +@babel/plugin-transform-block-scoped-functions under the MIT license +@babel/plugin-transform-block-scoping under the MIT license +@babel/plugin-transform-class-properties under the MIT license +@babel/plugin-transform-class-static-block under the MIT license +@babel/plugin-transform-classes under the MIT license +@babel/plugin-transform-computed-properties under the MIT license +@babel/plugin-transform-destructuring under the MIT license +@babel/plugin-transform-dotall-regex under the MIT license +@babel/plugin-transform-duplicate-keys under the MIT license +@babel/plugin-transform-dynamic-import under the MIT license +@babel/plugin-transform-exponentiation-operator under the MIT license +@babel/plugin-transform-export-namespace-from under the MIT license +@babel/plugin-transform-for-of under the MIT license +@babel/plugin-transform-function-name under the MIT license +@babel/plugin-transform-json-strings under the MIT license +@babel/plugin-transform-literals under the MIT license +@babel/plugin-transform-logical-assignment-operators under the MIT license +@babel/plugin-transform-member-expression-literals under the MIT license +@babel/plugin-transform-modules-amd under the MIT license +@babel/plugin-transform-modules-commonjs under the MIT license +@babel/plugin-transform-modules-systemjs under the MIT license +@babel/plugin-transform-modules-umd under the MIT license +@babel/plugin-transform-named-capturing-groups-regex under the MIT license +@babel/plugin-transform-new-target under the MIT license +@babel/plugin-transform-nullish-coalescing-operator under the MIT license +@babel/plugin-transform-numeric-separator under the MIT license +@babel/plugin-transform-object-rest-spread under the MIT license +@babel/plugin-transform-object-super under the MIT license +@babel/plugin-transform-optional-catch-binding under the MIT license +@babel/plugin-transform-optional-chaining under the MIT license +@babel/plugin-transform-parameters under the MIT license +@babel/plugin-transform-private-methods under the MIT license +@babel/plugin-transform-private-property-in-object under the MIT license +@babel/plugin-transform-property-literals under the MIT license +@babel/plugin-transform-regenerator under the MIT license +@babel/plugin-transform-reserved-words under the MIT license +@babel/plugin-transform-runtime under the MIT license +@babel/plugin-transform-shorthand-properties under the MIT license +@babel/plugin-transform-spread under the MIT license +@babel/plugin-transform-sticky-regex under the MIT license +@babel/plugin-transform-template-literals under the MIT license +@babel/plugin-transform-typeof-symbol under the MIT license +@babel/plugin-transform-unicode-escapes under the MIT license +@babel/plugin-transform-unicode-property-regex under the MIT license +@babel/plugin-transform-unicode-regex under the MIT license +@babel/plugin-transform-unicode-sets-regex under the MIT license +@babel/polyfill under the MIT license +@babel/preset-env under the MIT license +@babel/preset-modules under the MIT license +@babel/regjsgen under the MIT license +@babel/runtime under the MIT license +@babel/template under the MIT license +@babel/traverse under the MIT license +@bcoe/v8-coverage under the MIT license +@discoveryjs/json-ext under the MIT license +@dqbd/tiktoken under the MIT license +@eslint-community/eslint-utils under the MIT license +@eslint-community/regexpp under the MIT license +@eslint/eslintrc under the MIT license +@eslint/js under the MIT license +@fontsource/material-icons under the Apache-2.0 license +@fontsource/roboto under the Apache-2.0 license +@fontsource/varela-round under the OFL-1.1 license +@hapi/hoek under the BSD-3-Clause license +@hapi/topo under the BSD-3-Clause license +@humanwhocodes/config-array under the Apache-2.0 license +@humanwhocodes/module-importer under the Apache-2.0 license +@humanwhocodes/object-schema under the BSD-3-Clause license +@isaacs/cliui under the ISC license +@istanbuljs/load-nyc-config under the ISC license +@istanbuljs/schema under the MIT license +@jest/console under the MIT license +@jest/environment under the MIT license +@jest/expect-utils under the MIT license +@jest/expect under the MIT license +@jest/fake-timers under the MIT license +@jest/globals under the MIT license +@jest/reporters under the MIT license +@jest/schemas under the MIT license +@jest/source-map under the MIT license +@jest/test-result under the MIT license +@jest/test-sequencer under the MIT license +@jest/transform under the MIT license +@jridgewell/gen-mapping under the MIT license +@jridgewell/resolve-uri under the MIT license +@jridgewell/set-array under the MIT license +@jridgewell/sourcemap-codec under the MIT license +@jridgewell/trace-mapping under the MIT license +@langchain/community under the MIT license +@langchain/openai under the MIT license +@leichtgewicht/ip-codec under the MIT license +@node-ipc/js-queue under the MIT license +@nodelib/fs.scandir under the MIT license +@nodelib/fs.stat under the MIT license +@nodelib/fs.walk under the MIT license +@one-ini/wasm under the MIT license +@opensearch-project/opensearch under the Apache-2.0 license +@pkgjs/parseargs under the MIT license +@polka/url under the MIT license +@sideway/address under the BSD-3-Clause license +@sideway/formula under the BSD-3-Clause license +@sideway/pinpoint under the BSD-3-Clause license +@sinclair/typebox under the MIT license +@sinonjs/commons under the BSD-3-Clause license +@sinonjs/samsam under the BSD-3-Clause license +@sinonjs/text-encoding under the (Unlicense OR Apache-2.0) license +@smithy/abort-controller under the Apache-2.0 license +@smithy/chunked-blob-reader-native under the Apache-2.0 license +@smithy/chunked-blob-reader under the Apache-2.0 license +@smithy/config-resolver under the Apache-2.0 license +@smithy/credential-provider-imds under the Apache-2.0 license +@smithy/eventstream-codec under the Apache-2.0 license +@smithy/eventstream-serde-browser under the Apache-2.0 license +@smithy/eventstream-serde-config-resolver under the Apache-2.0 license +@smithy/eventstream-serde-node under the Apache-2.0 license +@smithy/eventstream-serde-universal under the Apache-2.0 license +@smithy/fetch-http-handler under the Apache-2.0 license +@smithy/hash-blob-browser under the Apache-2.0 license +@smithy/hash-node under the Apache-2.0 license +@smithy/hash-stream-node under the Apache-2.0 license +@smithy/invalid-dependency under the Apache-2.0 license +@smithy/is-array-buffer under the Apache-2.0 license +@smithy/md5-js under the Apache-2.0 license +@smithy/middleware-content-length under the Apache-2.0 license +@smithy/middleware-endpoint under the Apache-2.0 license +@smithy/middleware-retry under the Apache-2.0 license +@smithy/middleware-serde under the Apache-2.0 license +@smithy/middleware-stack under the Apache-2.0 license +@smithy/node-config-provider under the Apache-2.0 license +@smithy/node-http-handler under the Apache-2.0 license +@smithy/property-provider under the Apache-2.0 license +@smithy/protocol-http under the Apache-2.0 license +@smithy/querystring-builder under the Apache-2.0 license +@smithy/querystring-parser under the Apache-2.0 license +@smithy/service-error-classification under the Apache-2.0 license +@smithy/shared-ini-file-loader under the Apache-2.0 license +@smithy/signature-v4 under the Apache-2.0 license +@smithy/smithy-client under the Apache-2.0 license +@smithy/url-parser under the Apache-2.0 license +@smithy/util-base64 under the Apache-2.0 license +@smithy/util-body-length-browser under the Apache-2.0 license +@smithy/util-body-length-node under the Apache-2.0 license +@smithy/util-buffer-from under the Apache-2.0 license +@smithy/util-config-provider under the Apache-2.0 license +@smithy/util-defaults-mode-browser under the Apache-2.0 license +@smithy/util-defaults-mode-node under the Apache-2.0 license +@smithy/util-hex-encoding under the Apache-2.0 license +@smithy/util-middleware under the Apache-2.0 license +@smithy/util-retry under the Apache-2.0 license +@smithy/util-stream under the Apache-2.0 license +@smithy/util-uri-escape under the Apache-2.0 license +@smithy/util-utf8 under the Apache-2.0 license +@smithy/util-waiter under the Apache-2.0 license +@soda/friendly-errors-webpack-plugin under the MIT license +@soda/get-current-script under the MIT license +@tootallnate/once under the MIT license +@trysound/sax under the ISC license +@types/babel__core under the MIT license +@types/babel__generator under the MIT license +@types/babel__template under the MIT license +@types/babel__traverse under the MIT license +@types/body-parser under the MIT license +@types/bonjour under the MIT license +@types/connect-history-api-fallback under the MIT license +@types/connect under the MIT license +@types/eslint-scope under the MIT license +@types/eslint under the MIT license +@types/estree under the MIT license +@types/express-serve-static-core under the MIT license +@types/express under the MIT license +@types/graceful-fs under the MIT license +@types/html-minifier-terser under the MIT license +@types/http-errors under the MIT license +@types/http-proxy under the MIT license +@types/istanbul-lib-coverage under the MIT license +@types/istanbul-lib-report under the MIT license +@types/istanbul-reports under the MIT license +@types/jest under the MIT license +@types/jsdom under the MIT license +@types/json-schema under the MIT license +@types/json5 under the MIT license +@types/jsonwebtoken under the MIT license +@types/mdast under the MIT license +@types/mime under the MIT license +@types/minimist under the MIT license +@types/node-fetch under the MIT license +@types/node-forge under the MIT license +@types/node under the MIT license +@types/normalize-package-data under the MIT license +@types/parse-json under the MIT license +@types/prettier under the MIT license +@types/qs under the MIT license +@types/range-parser under the MIT license +@types/retry under the MIT license +@types/send under the MIT license +@types/serve-index under the MIT license +@types/serve-static under the MIT license +@types/sinon under the MIT license +@types/sinonjs__fake-timers under the MIT license +@types/sockjs under the MIT license +@types/stack-utils under the MIT license +@types/strip-bom under the MIT license +@types/strip-json-comments under the MIT license +@types/tough-cookie under the MIT license +@types/unist under the MIT license +@types/uuid under the MIT license +@types/ws under the MIT license +@types/yargs-parser under the MIT license +@types/yargs under the MIT license +@ungap/structured-clone under the ISC license +@vue/cli-overlay under the MIT license +@vue/cli-plugin-router under the MIT license +@vue/cli-plugin-unit-jest under the MIT license +@vue/cli-plugin-vuex under the MIT license +@vue/cli-service under the MIT license +@vue/cli-shared-utils under the MIT license +@vue/compat under the MIT license +@vue/compiler-core under the MIT license +@vue/compiler-dom under the MIT license +@vue/compiler-sfc under the MIT license +@vue/compiler-ssr under the MIT license +@vue/component-compiler-utils under the MIT license +@vue/devtools-api under the MIT license +@vue/eslint-config-standard under the MIT license +@vue/reactivity-transform under the MIT license +@vue/reactivity under the MIT license +@vue/runtime-core under the MIT license +@vue/runtime-dom under the MIT license +@vue/server-renderer under the MIT license +@vue/shared under the MIT license +@vue/test-utils under the MIT license +@vue/vue3-jest under the MIT license +@vue/web-component-wrapper under the MIT license +@webassemblyjs/ast under the MIT license +@webassemblyjs/floating-point-hex-parser under the MIT license +@webassemblyjs/helper-api-error under the MIT license +@webassemblyjs/helper-buffer under the MIT license +@webassemblyjs/helper-numbers under the MIT license +@webassemblyjs/helper-wasm-bytecode under the MIT license +@webassemblyjs/helper-wasm-section under the MIT license +@webassemblyjs/ieee754 under the MIT license +@webassemblyjs/leb128 under the Apache-2.0 license +@webassemblyjs/utf8 under the MIT license +@webassemblyjs/wasm-edit under the MIT license +@webassemblyjs/wasm-gen under the MIT license +@webassemblyjs/wasm-opt under the MIT license +@webassemblyjs/wasm-parser under the MIT license +@webassemblyjs/wast-printer under the MIT license +@webpack-cli/configtest under the MIT license +@webpack-cli/info under the MIT license +@webpack-cli/serve under the MIT license +@xmldom/xmldom under the MIT license +@xtuc/long under the Apache-2.0 license +JSONPath under the MIT license +abab under the BSD-3-Clause license +abbrev under the ISC license +accepts under the MIT license +acorn-globals under the MIT license +acorn-import-assertions under the MIT license +acorn-jsx under the MIT license +acorn-walk under the MIT license +acorn under the MIT license +agent-base under the MIT license +agentkeepalive under the MIT license +ajv-formats under the MIT license +ajv-keywords under the MIT license +ajv under the MIT license +amazon-cognito-auth-js under the Apache-2.0 license +ansi-escapes under the MIT license +ansi-html-community under the Apache-2.0 license +ansi-regex under the MIT license +ansi-styles under the MIT license +any-promise under the MIT license +anymatch under the ISC license +arch under the MIT license +archiver-utils under the MIT license +archiver under the MIT license +argparse under the MIT license +aria-query under the Apache-2.0 license +array-buffer-byte-length under the MIT license +array-flatten under the MIT license +array-includes under the MIT license +array-union under the MIT license +array.prototype.findlastindex under the MIT license +array.prototype.flat under the MIT license +array.prototype.flatmap under the MIT license +array.prototype.tosorted under the MIT license +arraybuffer.prototype.slice under the MIT license +arrify under the MIT license +asap under the MIT license +asn1.js under the MIT license +assert-never under the MIT license +assert under the MIT license +ast-types-flow under the ISC license +async-mutex under the MIT license +async under the MIT license +asynckit under the MIT license +at-least-node under the ISC license +autoprefixer under the MIT license +autosize under the MIT license +available-typed-arrays under the MIT license +aws-lex-web-ui under the SEE LICENSE IN LICENSE license +aws-sdk-client-mock-jest under the MIT license +aws-sdk-client-mock under the MIT license +aws-sdk under the Apache-2.0 license +aws4 under the MIT license +axe-core under the MPL-2.0 license +axios under the MIT license +axobject-query under the Apache-2.0 license +babel-jest under the MIT license +babel-loader under the MIT license +babel-plugin-istanbul under the BSD-3-Clause license +babel-plugin-jest-hoist under the MIT license +babel-plugin-polyfill-corejs2 under the MIT license +babel-plugin-polyfill-corejs3 under the MIT license +babel-plugin-polyfill-regenerator under the MIT license +babel-preset-current-node-syntax under the MIT license +babel-preset-jest under the MIT license +babel-walk under the MIT license +backbone-events-standalone under the MIT license +bail under the MIT license +balanced-match under the MIT license +base-64 under the MIT license +base64-js under the MIT license +basic-auth under the MIT license +batch under the MIT license +big-integer under the Unlicense license +big.js under the MIT license +binary-extensions under the MIT license +binary-search under the CC0-1.0 license +binary under the MIT license +bl under the MIT license +bluebird under the MIT license +bn.js under the MIT license +bodybuilder under the MIT license +bonjour-service under the MIT license +boolbase under the ISC license +bowser under the MIT license +brace-expansion under the MIT license +braces under the MIT license +brorand under the MIT license +browser-process-hrtime under the BSD-2-Clause license +browserify-aes under the MIT license +browserify-cipher under the MIT license +browserify-des under the MIT license +browserify-rsa under the MIT license +browserify-sign under the ISC license +browserify-zlib under the MIT license +browserslist under the MIT license +bser under the Apache-2.0 license +buffer-crc32 under the MIT license +buffer-equal-constant-time under the BSD-3-Clause license +buffer-from under the MIT license +buffer-indexof-polyfill under the MIT license +buffer-xor under the MIT license +buffer under the MIT license +builtin-status-codes under the MIT license +builtins under the MIT license +bytes under the MIT license +call-bind under the MIT license +callsites under the MIT license +camel-case under the MIT license +camelcase-keys under the MIT license +camelcase under the MIT license +caniuse-api under the MIT license +caniuse-lite under the CC-BY-4.0 license +case-sensitive-paths-webpack-plugin under the MIT license +ccount under the MIT license +cdnizer under the MIT license +cdnjs-cdn-data under the MIT license +cfn-lambda under the MIT license +cfn-response under the SEE LICENSE IN license.txt license +chainsaw under the MIT/X11 license +chalk under the MIT license +char-regex under the MIT license +character-entities-legacy under the MIT license +character-entities under the MIT license +character-parser under the MIT license +character-reference-invalid under the MIT license +charenc under the BSD-3-Clause license +chokidar under the MIT license +chownr under the ISC license +chrome-aws-lambda under the MIT license +chrome-trace-event under the MIT license +ci-info under the MIT license +cipher-base under the MIT license +cjs-module-lexer under the MIT license +clean-css under the MIT license +clean-deep under the MIT license +cli-cursor under the MIT license +cli-highlight under the ISC license +cli-spinners under the MIT license +clipboard under the MIT license +clipboardy under the MIT license +clone-deep under the MIT license +clone under the MIT license +co under the MIT license +collect-v8-coverage under the MIT license +color-convert under the MIT license +color-name under the MIT license +colord under the MIT license +colorette under the MIT license +colorful under the MIT license +colors under the MIT license +combined-stream under the MIT license +commander under the MIT license +common-path-prefix under the ISC license +compress-commons under the MIT license +compressible under the MIT license +compression under the MIT license +concat-map under the MIT license +condense-newlines under the MIT license +config-chain under the MIT license +confusing-browser-globals under the MIT license +console-browserify under the MIT license +consolidate under the MIT license +constantinople under the MIT license +constants-browserify under the MIT license +content-disposition under the MIT license +content-type under the MIT license +convert-source-map under the MIT license +cookie-signature under the MIT license +cookie under the MIT license +copy-webpack-plugin under the MIT license +core-js-compat under the MIT license +core-js under the MIT license +core-util-is under the MIT license +cosmiconfig under the MIT license +crc32-stream under the MIT license +crc under the MIT license +create-ecdh under the MIT license +create-hash under the MIT license +create-hmac under the MIT license +create-jest under the MIT license +cross-spawn under the MIT license +crypt under the BSD-3-Clause license +crypto-browserify under the MIT license +css-declaration-sorter under the ISC license +css-loader under the MIT license +css-minimizer-webpack-plugin under the MIT license +css-select under the BSD-2-Clause license +css-tree under the MIT license +css-what under the BSD-2-Clause license +cssesc under the MIT license +cssnano-preset-default under the MIT license +cssnano-utils under the MIT license +cssnano under the MIT license +csso under the MIT license +cssom under the MIT license +cssstyle under the MIT license +csstype under the MIT license +damerau-levenshtein under the BSD-2-Clause license +data-urls under the MIT license +dateformat under the MIT license +de-indent under the MIT license +debug under the MIT license +decamelize-keys under the MIT license +decamelize under the MIT license +decimal.js under the MIT license +dedent under the MIT license +deep-is under the MIT license +deepmerge under the MIT license +default-gateway under the BSD-2-Clause license +defaults under the MIT license +define-data-property under the MIT license +define-lazy-prop under the MIT license +define-properties under the MIT license +delayed-stream under the MIT license +delegate under the MIT license +depd under the MIT license +dequal under the MIT license +des.js under the MIT license +destroy under the MIT license +detect-newline under the MIT license +detect-node under the ISC license +diff-sequences under the MIT license +diff under the BSD-3-Clause license +diffie-hellman under the MIT license +digest-fetch under the ISC license +dir-glob under the MIT license +dns-equal under the MIT license +dns-packet under the MIT license +doctrine under the Apache-2.0 license +doctypes under the MIT license +dom-converter under the MIT license +dom-serializer under the MIT license +domain-browser under the MIT license +domelementtype under the BSD-2-Clause license +domexception under the MIT license +domhandler under the BSD-2-Clause license +domutils under the BSD-2-Clause license +dot-case under the MIT license +dotenv-expand under the BSD-2-Clause license +dotenv under the BSD-2-Clause license +duplexer2 under the BSD-3-Clause license +duplexer under the MIT license +eastasianwidth under the MIT license +easy-stack under the MIT license +ecdsa-sig-formatter under the Apache-2.0 license +editorconfig under the MIT license +ee-first under the MIT license +electron-to-chromium under the ISC license +elliptic under the MIT license +emitter-component under the MIT license +emittery under the MIT license +emoji-regex under the MIT license +emojis-list under the MIT license +encodeurl under the MIT license +end-of-stream under the MIT license +enhanced-resolve under the MIT license +entities under the BSD-2-Clause license +envinfo under the MIT license +error-ex under the MIT license +error-stack-parser under the MIT license +es-abstract under the MIT license +es-define-property under the MIT license +es-errors under the MIT license +es-module-lexer under the MIT license +es-set-tostringtag under the MIT license +es-shim-unscopables under the MIT license +es-to-primitive under the MIT license +escalade under the MIT license +escape-html under the MIT license +escape-string-regexp under the MIT license +escodegen under the BSD-2-Clause license +eslint-config-airbnb-base under the MIT license +eslint-config-airbnb under the MIT license +eslint-config-prettier under the MIT license +eslint-import-resolver-custom-alias under the MIT license +eslint-import-resolver-node under the MIT license +eslint-module-utils under the MIT license +eslint-plugin-es under the MIT license +eslint-plugin-import under the MIT license +eslint-plugin-jsx-a11y under the MIT license +eslint-plugin-n under the MIT license +eslint-plugin-prettier under the MIT license +eslint-plugin-promise under the ISC license +eslint-plugin-react-hooks under the MIT license +eslint-plugin-react under the MIT license +eslint-plugin-vue-pug under the MIT license +eslint-plugin-vue under the MIT license +eslint-visitor-keys under the Apache-2.0 license +espree under the BSD-2-Clause license +esprima under the BSD-2-Clause license +esquery under the BSD-3-Clause license +esrecurse under the BSD-2-Clause license +estraverse under the BSD-2-Clause license +estree-walker under the MIT license +esutils under the BSD-2-Clause license +etag under the MIT license +event-pubsub under the Unlicense license +event-target-shim under the MIT license +eventemitter3 under the MIT license +events under the MIT license +evp_bytestokey under the MIT license +execa under the MIT license +exit under the MIT license +exports-loader under the MIT license +expr-eval under the MIT license +extend-shallow under the MIT license +extend under the MIT license +faker under the MIT license +fast-deep-equal under the MIT license +fast-diff under the Apache-2.0 license +fast-glob under the MIT license +fast-json-stable-stringify under the MIT license +fast-levenshtein under the MIT license +fast-xml-parser under the MIT license +fastest-levenshtein under the MIT license +fastparse under the MIT license +fastq under the ISC license +faye-websocket under the Apache-2.0 license +fb-watchman under the Apache-2.0 license +fflate under the MIT license +figures under the MIT license +file-entry-cache under the MIT license +file-saver under the MIT license +fill-range under the MIT license +filter-obj under the MIT license +finalhandler under the MIT license +find-cache-dir under the MIT license +find-up under the MIT license +flat-cache under the MIT license +flat under the BSD-3-Clause license +flatted under the ISC license +follow-redirects under the MIT license +for-each under the MIT license +foreground-child under the ISC license +form-data-encoder under the MIT license +form-data under the MIT license +formdata-node under the MIT license +forwarded under the MIT license +fraction.js under the MIT license +fresh under the MIT license +fs-constants under the MIT license +fs-extra under the MIT license +fs-monkey under the Unlicense license +fs.realpath under the ISC license +fsevents under the MIT license +fstream under the ISC license +function-bind under the MIT license +function.prototype.name under the MIT license +functions-have-names under the MIT license +gensync under the MIT license +get-caller-file under the ISC license +get-intrinsic under the MIT license +get-package-type under the MIT license +get-stdin under the MIT license +get-stream under the MIT license +get-symbol-description under the MIT license +glob-parent under the ISC license +glob-to-regexp under the BSD-2-Clause license +glob under the ISC license +globalthis under the MIT license +globby under the MIT license +good-listener under the MIT license +google-cdn-data under the MIT license +gopd under the MIT license +graphemer under the MIT license +gzip-size under the MIT license +handle-thing under the MIT license +handlebars-loader under the MIT license +handlebars under the MIT license +hard-rejection under the MIT license +has-ansi under the MIT license +has-bigints under the MIT license +has-flag under the MIT license +has-property-descriptors under the MIT license +has-proto under the MIT license +has-symbols under the MIT license +has-tostringtag under the MIT license +has under the MIT license +hash-base under the MIT license +hash-sum under the MIT license +hash.js under the MIT license +hasown under the MIT license +he under the MIT license +highlight.js under the BSD-3-Clause license +hint.css under the See LICENSE.md license +hmac-drbg under the MIT license +hosted-git-info under the ISC license +hpack.js under the MIT license +hpagent under the MIT license +html-encoding-sniffer under the MIT license +html-entities under the MIT license +html-escaper under the MIT license +html-webpack-plugin under the MIT license +htmlparser2 under the MIT license +http-deceiver under the MIT license +http-parser-js under the MIT license +http-proxy-agent under the MIT license +http-proxy-middleware under the MIT license +https-browserify under the MIT license +https-proxy-agent under the MIT license +human-signals under the Apache-2.0 license +humanize-ms under the MIT license +i18next-sprintf-postprocessor under the MIT license +i18next under the MIT license +iconv-lite under the MIT license +icss-utils under the ISC license +idle-js under the MIT license +ignore under the MIT license +immediate under the MIT license +immutable under the MIT license +import-fresh under the MIT license +import-local under the MIT license +imurmurhash under the MIT license +indent-string under the MIT license +infinite-timeout under the MIT license +inflight under the ISC license +inherits under the ISC license +ini under the ISC license +intercept-stdout under the MIT license +internal-slot under the MIT license +interpret under the MIT license +ipaddr.js under the MIT license +is-alphabetical under the MIT license +is-alphanumerical under the MIT license +is-any-array under the MIT license +is-arguments under the MIT license +is-arrayish under the MIT license +is-bigint under the MIT license +is-binary-path under the MIT license +is-boolean-object under the MIT license +is-buffer under the MIT license +is-callable under the MIT license +is-core-module under the MIT license +is-date-object under the MIT license +is-decimal under the MIT license +is-docker under the MIT license +is-expression under the MIT license +is-extendable under the MIT license +is-extglob under the MIT license +is-file-esm under the MIT license +is-fullwidth-code-point under the MIT license +is-generator-fn under the MIT license +is-generator-function under the MIT license +is-glob under the MIT license +is-hexadecimal under the MIT license +is-interactive under the MIT license +is-nan under the MIT license +is-negative-zero under the MIT license +is-number-object under the MIT license +is-number under the MIT license +is-path-inside under the MIT license +is-plain-obj under the MIT license +is-plain-object under the MIT license +is-potential-custom-element-name under the MIT license +is-promise under the MIT license +is-regex under the MIT license +is-shared-array-buffer under the MIT license +is-stream under the MIT license +is-string under the MIT license +is-symbol under the MIT license +is-typed-array under the MIT license +is-typedarray under the MIT license +is-unicode-supported under the MIT license +is-weakref under the MIT license +is-whitespace under the MIT license +is-wsl under the MIT license +isarray under the MIT license +isexe under the ISC license +isobject under the MIT license +istanbul-lib-instrument under the BSD-3-Clause license +istanbul-lib-source-maps under the BSD-3-Clause license +jackspeak under the BlueOak-1.0.0 license +javascript-stringify under the MIT license +jest-changed-files under the MIT license +jest-circus under the MIT license +jest-cli under the MIT license +jest-config under the MIT license +jest-diff under the MIT license +jest-docblock under the MIT license +jest-each under the MIT license +jest-environment-jsdom under the MIT license +jest-environment-node under the MIT license +jest-get-type under the MIT license +jest-haste-map under the MIT license +jest-jasmine2 under the MIT license +jest-leak-detector under the MIT license +jest-matcher-utils under the MIT license +jest-message-util under the MIT license +jest-mock under the MIT license +jest-pnp-resolver under the MIT license +jest-regex-util under the MIT license +jest-resolve-dependencies under the MIT license +jest-resolve under the MIT license +jest-runner under the MIT license +jest-runtime under the MIT license +jest-serializer-vue under the MIT license +jest-serializer under the MIT license +jest-snapshot under the MIT license +jest-transform-stub under the MIT license +jest-util under the MIT license +jest-validate under the MIT license +jest-watch-typeahead under the MIT license +jest-watcher under the MIT license +jest-worker under the MIT license Jinja2 under the BSD License (BSD-3-Clause) -jest under the Massachusetts Institute of Technology (MIT) license -jmespath under the Massachusetts Institute of Technology (MIT) license -jose under the Massachusetts Institute of Technology (MIT) license -js-cache under the Massachusetts Institute of Technology (MIT) license -jsdom under the Massachusetts Institute of Technology (MIT) license -jsdom-global under the Massachusetts Institute of Technology (MIT) license -jsdom-loader under the Massachusetts Institute of Technology (MIT) license -jsheader under the Apache License Version 2.0 -jsonschema-spec under the Apache License Version 2.0 -json-parse-better-errors under the Massachusetts Institute of Technology (MIT) license -json-stringify-pretty-compact under the Massachusetts Institute of Technology (MIT) license -JSONPath under the Massachusetts Institute of Technology (MIT) license -jsonschema under the Massachusetts Institute of Technology (MIT) license -jsonwebtoken under the Massachusetts Institute of Technology (MIT) license -jszip under the Massachusetts Institute of Technology (MIT) license -jwks-rsa under the Massachusetts Institute of Technology (MIT) license -langchain under the Massachusetts Institute of Technology (MIT) license -lazy-object-proxy under the BSD License (BSD-2-Clause) -license-expression under Apache License Version 2.0 -lodash under the Massachusetts Institute of Technology (MIT) license -lodash-webpack-plugin under the Massachusetts Institute of Technology (MIT) license -marked under the Massachusetts Institute of Technology (MIT) license +jmespath under the Apache-2.0 license +joi under the BSD-3-Clause license +jose under the MIT license +js-beautify under the MIT license +js-cache under the MIT license +js-cookie under the MIT license +js-message under the MIT license +js-stringify under the MIT license +js-tiktoken under the MIT license +js-tokens under the MIT license +js-yaml under the MIT license +jsdelivr-cdn-data under the MIT license +jsdom-global under the MIT license +jsesc under the MIT license +jsheader under the Apache-2.0 license +json-parse-better-errors under the MIT license +json-parse-even-better-errors under the MIT license +json-schema-traverse under the MIT license +json-stable-stringify-without-jsonify under the MIT license +json-stringify-pretty-compact under the MIT license +jsonfile under the MIT license +jsonpointer under the MIT license +jsonschema under the MIT license +jstransformer under the MIT license +jsx-ast-utils under the MIT license +jszip under the (MIT OR GPL-3.0-or-later) license +just-extend under the MIT license +jwa under the MIT license +jwks-rsa under the MIT license +jws under the MIT license +kind-of under the MIT license +kleur under the MIT license +klona under the MIT license +lambdafs under the MIT license +langchain under the MIT license +langchainhub under the MIT license +langsmith under the MIT license +language-subtag-registry under the CC0-1.0 license +language-tags under the MIT license +launch-editor-middleware under the MIT license +launch-editor under the MIT license +lazystream under the MIT license +leven under the MIT license +levn under the MIT license +lie under the MIT license +lilconfig under the MIT license +limiter under the MIT license +lines-and-columns under the MIT license +linkifyjs under the MIT license +listenercount under the ISC license +loader-runner under the MIT license +loader-utils under the MIT license +locate-path under the MIT license +lodash-webpack-plugin under the MIT license +lodash._arraycopy under the MIT license +lodash._basevalues under the MIT license +lodash._getnative under the MIT license +lodash.clonedeep under the MIT license +lodash.debounce under the MIT license +lodash.defaults under the MIT license +lodash.defaultsdeep under the MIT license +lodash.difference under the MIT license +lodash.escape under the MIT license +lodash.flatten under the MIT license +lodash.get under the MIT license +lodash.invokemap under the MIT license +lodash.isarguments under the MIT license +lodash.isarray under the MIT license +lodash.isempty under the MIT license +lodash.isobject under the MIT license +lodash.isplainobject under the MIT license +lodash.keys under the MIT license +lodash.mapvalues under the MIT license +lodash.memoize under the MIT license +lodash.merge under the MIT license +lodash.pullall under the MIT license +lodash.toarray under the MIT license +lodash.transform under the MIT license +lodash.union under the MIT license +lodash.uniq under the MIT license +lodash.uniqby under the MIT license +lodash.unset under the MIT license +lodash under the MIT license +log-symbols under the MIT license +log-update under the MIT license +longest-streak under the MIT license +loose-envify under the MIT license +lower-case under the MIT license +lru-cache under the ISC license +lru-memoizer under the MIT license +magic-string under the MIT license +make-dir under the MIT license +makeerror under the BSD-3-Clause license +map-obj under the MIT license +markdown-table under the MIT license +marked under the MIT license MarkupSafe under the BSD License (BSD-3-Clause) -material-design-icons under the Apache License Version 2.0 -mccabe under the Massachusetts Institute of Technology (MIT) license -mini-css-extract-plugin under the Massachusetts Institute of Technology (MIT) license -minimist under the Massachusetts Institute of Technology (MIT) license -moment under the Massachusetts Institute of Technology (MIT) license -morgan under the Massachusetts Institute of Technology (MIT) license -moto under the Apache License Version 2.0 -mypy under the Massachusetts Institute of Technology (MIT) license -mypy-extensions under the Massachusetts Institute of Technology (MIT) license -openapi-schema-validator under the BSD License -openapi-spec-validator under the Apache License Version 2.0 -ora under the Massachusetts Institute of Technology (MIT) license -outcome under the Apache License Version 2.0 and the the Massachusetts Institute of Technology (MIT) license +material-design-icons under the Apache-2.0 license +md5.js under the MIT license +md5 under the BSD-3-Clause license +mdast-util-find-and-replace under the MIT license +mdast-util-from-markdown under the MIT license +mdast-util-gfm-autolink-literal under the MIT license +mdast-util-gfm-strikethrough under the MIT license +mdast-util-gfm-table under the MIT license +mdast-util-gfm-task-list-item under the MIT license +mdast-util-gfm under the MIT license +mdast-util-to-markdown under the MIT license +mdast-util-to-string under the MIT license +mdn-data under the CC0-1.0 license +media-typer under the MIT license +memfs under the Unlicense license +meow under the MIT license +merge-descriptors under the MIT license +merge-source-map under the MIT license +merge-stream under the MIT license +merge2 under the MIT license +methods under the MIT license +micromark-extension-gfm-autolink-literal under the MIT license +micromark-extension-gfm-strikethrough under the MIT license +micromark-extension-gfm-table under the MIT license +micromark-extension-gfm-tagfilter under the MIT license +micromark-extension-gfm-task-list-item under the MIT license +micromark-extension-gfm under the MIT license +micromark under the MIT license +micromatch under the MIT license +miller-rabin under the MIT license +mime-db under the MIT license +mime-types under the MIT license +mimic-fn under the MIT license +min-indent under the MIT license +mini-css-extract-plugin under the MIT license +minimalistic-assert under the ISC license +minimalistic-crypto-utils under the MIT license +minimatch under the ISC license +minimist-options under the MIT license +minipass under the ISC license +mkdirp-classic under the MIT license +mkdirp under the MIT license +ml-array-mean under the MIT license +ml-array-sum under the MIT license +ml-distance-euclidean under the MIT license +ml-distance under the MIT license +ml-tree-similarity under the MIT license +mnemonist under the MIT license +module-alias under the MIT license +moment under the MIT license +morgan under the MIT license +mrmime under the MIT license +ms under the MIT license +multicast-dns under the MIT license +mz under the MIT license +nano-argv under the MIT license +nanoid under the MIT license +natural-compare under the MIT license +negotiator under the MIT license +neo-async under the MIT license +nice-try under the MIT license +nise under the BSD-3-Clause license +no-case under the MIT license +node-domexception under the MIT license +node-int64 under the MIT license +node-polyfill-webpack-plugin under the MIT license +node-releases under the MIT license +nopt under the ISC license +normalize-path under the MIT license +normalize-range under the MIT license +normalize-url under the MIT license +npm-run-path under the MIT license +nth-check under the BSD-2-Clause license +num-sort under the MIT license +nwsapi under the MIT license +object-assign under the MIT license +object-inspect under the MIT license +object-is under the MIT license +object-keys under the MIT license +object.assign under the MIT license +object.entries under the MIT license +object.fromentries under the MIT license +object.groupby under the MIT license +object.hasown under the MIT license +object.values under the MIT license +obliterator under the MIT license +obuf under the MIT license +on-finished under the MIT license +on-headers under the MIT license +onetime under the MIT license +open under the MIT license +openapi-types under the MIT license +opener under the (WTFPL OR MIT) license +optionator under the MIT license +ora under the MIT license +os-browserify under the MIT license +p-finally under the MIT license +p-limit under the MIT license +p-locate under the MIT license +p-queue under the MIT license +p-retry under the MIT license +p-timeout under the MIT license +p-try under the MIT license +pako under the (MIT AND Zlib) license +param-case under the MIT license +parent-module under the MIT license +parse-asn1 under the ISC license +parse-entities under the MIT license +parse-srcset under the MIT license +parse5-htmlparser2-tree-adapter under the MIT license +parse5 under the MIT license +parseurl under the MIT license +pascal-case under the MIT license pathable under the Apache License Version 2.0 -platformdirs under the Massachusetts Institute of Technology (MIT) license -pluggy under the Massachusetts Institute of Technology (MIT) license -progress-bar-webpack-plugin under the Massachusetts Institute of Technology (MIT) license -pug under the Massachusetts Institute of Technology (MIT) license -pug-loader under the Massachusetts Institute of Technology (MIT) license -pug-plain-loader under the Massachusetts Institute of Technology (MIT) license -pug-runtime under the Massachusetts Institute of Technology (MIT) license +path-browserify under the MIT license +path-exists under the MIT license +path-is-absolute under the MIT license +path-key under the MIT license +path-parse under the MIT license +path-scurry under the BlueOak-1.0.0 license +path-to-regexp under the MIT license +path-type under the MIT license +pbkdf2 under the MIT license +picocolors under the ISC license +picomatch under the MIT license +pirates under the MIT license +pkg-dir under the MIT license +portfinder under the MIT license +possible-typed-array-names under the MIT license +postcss-calc under the MIT license +postcss-colormin under the MIT license +postcss-convert-values under the MIT license +postcss-discard-comments under the MIT license +postcss-discard-duplicates under the MIT license +postcss-discard-empty under the MIT license +postcss-discard-overridden under the MIT license +postcss-loader under the MIT license +postcss-merge-longhand under the MIT license +postcss-merge-rules under the MIT license +postcss-minify-font-values under the MIT license +postcss-minify-gradients under the MIT license +postcss-minify-params under the MIT license +postcss-minify-selectors under the MIT license +postcss-modules-extract-imports under the ISC license +postcss-modules-local-by-default under the MIT license +postcss-modules-scope under the ISC license +postcss-modules-values under the ISC license +postcss-normalize-charset under the MIT license +postcss-normalize-display-values under the MIT license +postcss-normalize-positions under the MIT license +postcss-normalize-repeat-style under the MIT license +postcss-normalize-string under the MIT license +postcss-normalize-timing-functions under the MIT license +postcss-normalize-unicode under the MIT license +postcss-normalize-url under the MIT license +postcss-normalize-whitespace under the MIT license +postcss-ordered-values under the MIT license +postcss-reduce-initial under the MIT license +postcss-reduce-transforms under the MIT license +postcss-selector-parser under the MIT license +postcss-svgo under the MIT license +postcss-unique-selectors under the MIT license +postcss-value-parser under the MIT license +postcss under the MIT license +prelude-ls under the MIT license +prettier-linter-helpers under the MIT license +pretty-error under the MIT license +pretty-format under the MIT license +pretty under the MIT license +process-nextick-args under the MIT license +process under the MIT license +progress-bar-webpack-plugin under the MIT license +progress-webpack-plugin under the MIT license +progress under the MIT license +promise under the MIT license +prompts under the MIT license +prop-types under the MIT license +proto-list under the ISC license +proxy-addr under the MIT license +proxy-from-env under the MIT license +pseudomap under the ISC license +psl under the MIT license +public-encrypt under the MIT license +pug-attrs under the MIT license +pug-code-gen under the MIT license +pug-error under the MIT license +pug-filters under the MIT license +pug-lexer under the MIT license +pug-linker under the MIT license +pug-load under the MIT license +pug-loader under the MIT license +pug-parser under the MIT license +pug-plain-loader under the MIT license +pug-runtime under the MIT license +pug-strip-comments under the MIT license +pug-walk under the MIT license +pug under the MIT license +pump under the MIT license +punycode under the MIT license +pure-rand under the MIT license pycodestyle under the Massachusetts Institute of Technology (MIT) license pycparser under the BSD License pyflakes under the Massachusetts Institute of Technology (MIT) license pyrsistent under the Massachusetts Institute of Technology (MIT) license -pytest under the Massachusetts Institute of Technology (MIT) license -pytest-cov under the Massachusetts Institute of Technology (MIT) license -pytest-env under the Massachusetts Institute of Technology (MIT) license pytest-json under the Massachusetts Institute of Technology (MIT) license -pytest-mock under the Massachusetts Institute of Technology (MIT) license py-serializable under the Apache License Version 2.0 PySocks under the Apache License Version 2.0 +query-string under the MIT license +querystring-browser under the MIT license +querystring-es3 under the MIT license +querystring under the MIT license +querystringify under the MIT license +queue-microtask under the MIT license +quick-lru under the MIT license +randombytes under the MIT license +randomfill under the MIT license +raw-body under the MIT license +raw-loader under the MIT license +raw-text under the MIT license +react-is under the MIT license +read-excel-file under the MIT license +read-pkg-up under the MIT license +read-pkg under the MIT license +readable-stream under the MIT license +readdirp under the MIT license +rechoir under the MIT license +recursive-readdir under the MIT license +redent under the MIT license +regenerate-unicode-properties under the MIT license +regenerate under the MIT license +regenerator-runtime under the MIT license +regenerator-transform under the MIT license +regexp.prototype.flags under the MIT license +regexpu-core under the MIT license +regjsparser under the BSD-2-Clause license +relateurl under the MIT license +remark-gfm under the MIT license +remark-parse under the MIT license +remark-stringify under the MIT license +renderkid under the MIT license +repeat-string under the MIT license +require-dir under the MIT license +require-directory under the MIT license +require-from-string under the MIT license +requires-port under the MIT license +resolve-cwd under the MIT license +resolve-from under the MIT license +resolve.exports under the MIT license +resolve under the MIT license +restore-cursor under the MIT license +reusify under the MIT license +rimraf under the ISC license +ripemd160 under the MIT license +roboto-fontface under the Apache-2.0 license +rrweb-cssom under the MIT license +run-parallel under the MIT license +safe-array-concat under the MIT license +safe-buffer under the MIT license +safe-regex-test under the MIT license +safer-buffer under the MIT license +sanitize-html under the MIT license +sass-loader under the MIT license +sass under the MIT license +saxes under the ISC license +schema-utils under the MIT license +scmp under the BSD-3-Clause license +secure-json-parse under the BSD-3-Clause license +select-hose under the MIT license +select under the MIT license +selfsigned under the MIT license +semver under the ISC license +serialize-javascript under the BSD-3-Clause license +set-function-length under the MIT license +setimmediate under the MIT license +setprototypeof under the ISC license +sha.js under the (MIT AND BSD-3-Clause) license +shallow-clone under the MIT license +shebang-command under the MIT license +shebang-regex under the MIT license +shell-quote under the MIT license +side-channel under the MIT license +signal-exit under the ISC license +simple-encryptor under the MIT license +sirv under the MIT license +sisteransi under the MIT license +slackify-markdown under the MIT license +slash under the MIT license +source-list-map under the MIT license +source-map-js under the BSD-3-Clause license +source-map-support under the MIT license +spdx-correct under the Apache-2.0 license +spdx-exceptions under the CC-BY-3.0 license +spdx-expression-parse under the MIT license +spdx-license-ids under the CC0-1.0 license +spdy-transport under the MIT license +spdy under the MIT license +sprintf-js under the BSD-3-Clause license +ssri under the ISC license +stable under the MIT license +stackframe under the MIT license +static-eval under the MIT license +statuses under the MIT license +stream-browserify under the MIT license +stream-http under the MIT license +stream under the MIT license +strict-uri-encode under the MIT license +string-length under the MIT license +string-width under the MIT license +string.prototype.matchall under the MIT license +string.prototype.trim under the MIT license +string.prototype.trimend under the MIT license +string.prototype.trimstart under the MIT license +string_decoder under the MIT license +strip-ansi under the MIT license +strip-eof under the MIT license +strip-final-newline under the MIT license +strip-indent under the MIT license +strnum under the MIT license +style-loader under the MIT license +stylehacks under the MIT license +stylus-loader under the MIT license +stylus under the MIT license +supports-color under the MIT license +supports-hyperlinks under the MIT license +supports-preserve-symlinks-flag under the MIT license +svgo under the MIT license +symbol-tree under the MIT license +tapable under the MIT license +tar-fs under the MIT license +tar-stream under the MIT license +terminal-link under the MIT license +terser-webpack-plugin under the MIT license +terser under the BSD-2-Clause license +test-exclude under the ISC license +text-table under the MIT license +thenify-all under the MIT license +thenify under the MIT license +thread-loader under the MIT license +throat under the MIT license +thunky under the MIT license +timers-browserify under the MIT license +tiny-emitter under the MIT license +tinytim under the MIT license +tmpl under the BSD-3-Clause license +to-fast-properties under the MIT license +to-regex-range under the MIT license +toidentifier under the MIT license +token-stream under the MIT license +totalist under the MIT license +tr46 under the MIT license +tracer under the MIT license +transform-runtime under the ISC license +trim-newlines under the MIT license +trough under the MIT license +tsconfig-paths under the MIT license +tsconfig under the MIT license +tslib under the 0BSD license +tty-browserify under the MIT license +type-check under the MIT license +type-detect under the MIT license +type-fest under the (MIT OR CC0-1.0) license +type-is under the MIT license +typed-array-buffer under the MIT license +typed-array-byte-length under the MIT license +typed-array-byte-offset under the MIT license +typed-array-length under the MIT license +typedarray-to-buffer under the MIT license +uglify-js under the BSD-2-Clause license +unbox-primitive under the MIT license +underscore under the MIT license +undici-types under the MIT license +unicode-canonical-property-names-ecmascript under the MIT license +unicode-match-property-ecmascript under the MIT license +unicode-match-property-value-ecmascript under the MIT license +unicode-property-aliases-ecmascript under the MIT license +unified under the MIT license +unist-util-is under the MIT license +unist-util-remove under the MIT license +unist-util-stringify-position under the MIT license +unist-util-visit-parents under the MIT license +unist-util-visit under the MIT license +universalify under the MIT license +unpipe under the MIT license +unzipper under the MIT license +update-browserslist-db under the MIT license +uri-js under the BSD-2-Clause license +url-parse under the MIT license +urlcode-json under the BSD license +util-deprecate under the MIT license +utila under the MIT license +utils-merge under the MIT license +v8-to-istanbul under the ISC license +validate-npm-package-license under the Apache-2.0 license +vary under the MIT license +vee-validate under the MIT license +velocity under the MIT license +vfile-message under the MIT license +vfile under the MIT license +vm-browserify under the MIT license +void-elements under the MIT license +vue-component-type-helpers under the MIT license +vue-eslint-parser-template-tokenizer-pug under the ISC license +vue-eslint-parser under the MIT license +vue-hint.css under the MIT license +vue-hot-reload-api under the MIT license +vue-loader under the MIT license +vue-lorem-ipsum under the MIT license +vue-router under the MIT license +vue-style-loader under the MIT license +vue-template-compiler under the MIT license +vue-template-es2015-compiler under the MIT license +vue under the MIT license +vuetify under the MIT license +vuex-router-sync under the MIT license +vuex under the MIT license +w3c-hr-time under the MIT license +w3c-xmlserializer under the MIT license +walker under the Apache-2.0 license +watchpack under the MIT license +wbuf under the MIT license +wcwidth under the MIT license +web-streams-polyfill under the MIT license +webidl-conversions under the BSD-2-Clause license +webpack-bundle-analyzer under the MIT license +webpack-chain under the MPL-2.0 license +webpack-cli under the MIT license +webpack-dev-middleware under the MIT license +webpack-dev-server under the MIT license +webpack-merge under the MIT license +webpack-s3-plugin under the MIT license +webpack-sources under the MIT license +webpack-virtual-modules under the MIT license +webpack under the MIT license +websocket-driver under the Apache-2.0 license +websocket-extensions under the Apache-2.0 license +Werkzeug under the BSD License +whatwg-encoding under the MIT license +whatwg-fetch under the MIT license +whatwg-mimetype under the MIT license +whatwg-url under the MIT license +which-boxed-primitive under the MIT license +which-typed-array under the MIT license +which under the ISC license +wildcard under the MIT license +with under the MIT license +wordwrap under the MIT license +wrap-ansi under the MIT license +wrappy under the ISC license +write-file-atomic under the ISC license +xml-name-validator under the Apache-2.0 license +xml2js under the MIT license +xmlbuilder under the MIT license +xmlchars under the MIT license +xtend under the MIT license +y18n under the ISC license +yallist under the ISC license +yaml under the ISC license +yazl under the MIT license +yocto-queue under the MIT license +zip-stream under the MIT license +zip-webpack-plugin under the MIT license +zod-to-json-schema under the ISC license +zod under the MIT license +zwitch under the MIT license +boto3 under the Apache-2.0 license +botocore under the Apache-2.0 license +Click under the 0BSD license +Click under the BSD-3-Clause license +coverage under the Apache-2.0 license +crhelper under the Apache-2.0 license +docker under the Apache-2.0 license +mock under the 0BSD license +moto under the Apache-2.0 license +openapi-spec-validator under the Apache-2.0 license +pytest-cov under the MIT license +pytest-env under the MIT license +pytest-mock under the MIT license +pytest under the MIT license +pyyaml under the MIT license +requests under the Apache-2.0 license +cffi under the Massachusetts Institute of Technology (MIT) license +click under the BSD License (BSD-3-Clause) +cryptography under the Apache License Version 2.0 +h11 under the Massachusetts Institute of Technology (MIT) license +iniconfig under the Massachusetts Institute of Technology (MIT) license +jsonschema-spec under the Apache License Version 2.0 +lazy-object-proxy under the BSD License (BSD-2-Clause) +openapi-schema-validator under the BSD License +outcome under the Apache License Version 2.0 and the the Massachusetts Institute of Technology (MIT) license +pluggy under the Massachusetts Institute of Technology (MIT) license python-dateutil under the Apache License Version 2.0 and BSD License -pytz under the Massachusetts Institute of Technology (MIT) license -query-string under the Massachusetts Institute of Technology (MIT) license -querystring under the Massachusetts Institute of Technology (MIT) license -querystring-browser under the Massachusetts Institute of Technology (MIT) license -quick-lru under the Massachusetts Institute of Technology (MIT) license -range under the Massachusetts Institute of Technology (MIT) license -raw-loader under the Massachusetts Institute of Technology (MIT) license -raw-text under the Massachusetts Institute of Technology (MIT) license -read-excel-file under the Massachusetts Institute of Technology (MIT) license -recursive-readdir under the Massachusetts Institute of Technology (MIT) license -require-dir under the Massachusetts Institute of Technology (MIT) license responses under the Apache License Version 2.0 rfc3339-validator under the Massachusetts Institute of Technology (MIT) license -roboto-fontface under the Apache License Version 2.0 s3transfer under the Apache License Version 2.0 -sanitize-html under the Massachusetts Institute of Technology (MIT) license -sass under the Massachusetts Institute of Technology (MIT) license -sass-loader under the Massachusetts Institute of Technology (MIT) license selenium under the Apache License Version 2.0 -simple-encryptor under the Massachusetts Institute of Technology (MIT) license -slackify-markdown under the Massachusetts Institute of Technology (MIT) license sniffio under the Apache License Version 2.0 and the the Massachusetts Institute of Technology (MIT) license -soupsieve under the Massachusetts Institute of Technology (MIT) license -static-eval under the Massachusetts Institute of Technology (MIT) license -strip-ansi under the Massachusetts Institute of Technology (MIT) license -style-loader under the Massachusetts Institute of Technology (MIT) license -stylus under the Massachusetts Institute of Technology (MIT) license -stylus-loader under the Massachusetts Institute of Technology (MIT) license -tomli under the Massachusetts Institute of Technology (MIT) license -tomlkit under the Massachusetts Institute of Technology (MIT) license -torch under the BSD 3-Clause License -transformers under the Massachusetts Institute of Technology (MIT) license trio under the Apache License Version 2.0 and the the Massachusetts Institute of Technology (MIT) license trio-websocket under the Massachusetts Institute of Technology (MIT) license -types-PyYAML under the Apache License Version 2.0 -types-python-dateutil under the Apache License Version 2.0 -typing_extensions under Python Software Foundation License -urlcode-json under the BSD license -utf8 under the Massachusetts Institute of Technology (MIT) license -vee-validate under the Massachusetts Institute of Technology (MIT) license -velocity under the Massachusetts Institute of Technology (MIT) license -vue under the Massachusetts Institute of Technology (MIT) license -vue-clipboard2 under the Massachusetts Institute of Technology (MIT) license -vue-hint.css under the Massachusetts Institute of Technology (MIT) license -vue-loader under the Massachusetts Institute of Technology (MIT) license -vue-lorem-ipsum under the Massachusetts Institute of Technology (MIT) license -vue-router under the Massachusetts Institute of Technology (MIT) license -vue-template-compiler under the Massachusetts Institute of Technology (MIT) license -vuetify under the Massachusetts Institute of Technology (MIT) license -vuex under the Massachusetts Institute of Technology (MIT) license -vuex-router-sync under the Massachusetts Institute of Technology (MIT) license -webpack under the Massachusetts Institute of Technology (MIT) license -webpack-archive-plugin under the Massachusetts Institute of Technology (MIT) license -webpack-bundle-analyzer under the Massachusetts Institute of Technology (MIT) license -webpack-cli under the Massachusetts Institute of Technology (MIT) license -webpack-dev-server under the Massachusetts Institute of Technology (MIT) license -webpack-merge under the Massachusetts Institute of Technology (MIT) license -webpack-s3-plugin under the Massachusetts Institute of Technology (MIT) license websocket-client under the Apache License Version 2.0 -Werkzeug under the BSD License wsproto under the Massachusetts Institute of Technology (MIT) license -xmltodict under the Massachusetts Institute of Technology (MIT) license \ No newline at end of file +xmltodict under the Massachusetts Institute of Technology (MIT) license diff --git a/README.md b/README.md index ff175d271..ed358fd36 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,7 @@ The high-level process flow for the solution components deployed with the AWS Cl 3. The admin configures questions and answers in the Content Designer and the UI sends requests to Amazon API Gateway to save the questions and answers. -4. The `Content Designer` [AWS Lambda](http://aws.amazon.com/lambda/) function saves the input in [Amazon OpenSearch Service](http://aws.amazon.com/opensearch-service/) in a questions bank index. -If using [text embeddings](source/docs/semantic_matching_using_LLM_embeddings/README.md), these requests will first pass through a LLM model hosted on [Amazon Bedrock](https://aws.amazon.com/bedrock/) or [Amazon SageMaker](https://aws.amazon.com/sagemaker/) to generate embeddings before being saved into the question bank on OpenSearch. +4. The `Content Designer` [AWS Lambda](http://aws.amazon.com/lambda/) function saves the input in [Amazon OpenSearch Service](http://aws.amazon.com/opensearch-service/) in a questions bank index. If using [text embeddings](source/docs/semantic_matching_using_LLM_embeddings/README.md), these requests will first pass through a LLM model hosted on [Amazon Bedrock](https://aws.amazon.com/bedrock/) or [Amazon SageMaker](https://aws.amazon.com/sagemaker/) to generate embeddings before being saved into the question bank on OpenSearch. In addition, the `Content Designer` saves default and custom [configuration settings](https://docs.aws.amazon.com/solutions/latest/qnabot-on-aws/modifying-configuration-settings.html) in [AWS Systems Manager Parameter Store](https://aws.amazon.com/systems-manager/features/#Parameter_Store). 5. Users of the chatbot interact with Amazon Lex via the web client UI, [Amazon Alexa](https://developer.amazon.com/en-US/alexa) or [Amazon Connect](https://aws.amazon.com/connect/). @@ -60,7 +59,7 @@ Alternatively, if you want to custom deploy QnABot on AWS, refer to the details ### Environment Prerequisites -- Run Linux. (tested on Amazon Linux) +- Run Linux. (tested on Amazon Linux 2) - Install npm >10.0.0 and node >18.X.X ([instructions](https://nodejs.org/en/download/)) - Install and configure git lfs ([instructions](https://git-lfs.com/)) - Clone this repo. @@ -77,6 +76,11 @@ Start from the /source directory. cd source ``` +Install virtualenv: +```shell +pip3 install virtualenv +``` + Install node.js modules of QnABot: ```shell @@ -179,6 +183,13 @@ export USER='' export PASSWORD='' ``` +Optionally provide Bedrock Guardrails Identifier and Version to test with. If these environment variables are not set then testing for Bedrock Guardrails in test_knowledge_base.py and test_llm.py will be skipped. + +```bash +export BEDROCK_GUARDRAIL_IDENTIFIER='' +export BEDROCK_GUARDRAIL_VERSION='' +``` + If you'd like to launch the browser while running tests then also set the below env variable: ```bash @@ -325,22 +336,26 @@ As QnABot evolves over the years, it makes use of various services and functiona _Note: **Deployable solution versions** refers to the ability to deploy the version of QnABot in their AWS accounts. **Actively supported versions** for QnABot is only available for the latest version of QnABot._ ### Deployable Versions +- [v6.1.0](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v6.1.0) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v6.1.0/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v6.1.0/qnabot-on-aws-vpc.template) - [v6.0.3](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v6.0.3) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v6.0.3/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v6.0.3/qnabot-on-aws-vpc.template) - [v6.0.2](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v6.0.2) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v6.0.2/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v6.0.2/qnabot-on-aws-vpc.template) - [v6.0.1](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v6.0.1) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v6.0.1/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v6.0.1/qnabot-on-aws-vpc.template) - [v6.0.0](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v6.0.0) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v6.0.0/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v6.0.0/qnabot-on-aws-vpc.template) - [v5.5.2](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v5.5.2) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.5.2/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.5.2md/qnabot-on-aws-vpc.template) - - We recommend to upgrade to this version as it fixes an issue with the testall functionality which may introduce a high number of versions stored in the testall S3 bucket when Content Designer has no Q&As. - [v5.5.1](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v5.5.1) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.5.1/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.5.1/qnabot-on-aws-vpc.template) + > _We do not recommend to use this version due to a potential issue with the testall functionality which may introduce a high number of versions stored in the testall S3 bucket when Content Designer has no Q&As. Please use the latest version available._ - [v5.5.0](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v5.5.0) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.5.0/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.5.0/qnabot-on-aws-vpc.template) - - _Vue has been upgraded from Vue 2 to 3. We highly recommend to use or upgrade to this version due to Vue 2 reaching End of Life (EOL), which affects all previous versions of QnABot. For more information, see [below](#upcomingrecent-deprecations)._ -- [v5.4.5](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v5.4.5) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.5/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.5/qnabot-on-aws-vpc.template) + > _We do not recommend to use this version due to a potential issue with the testall functionality which may introduce a high number of versions stored in the testall S3 bucket when Content Designer has no Q&As. Please use the latest version available._ + - _Vue has been upgraded from Vue 2 to 3. We highly recommend to use or upgrade to a version `v5.5.0+` due to Vue 2 reaching End of Life (EOL), which affects all previous versions of QnABot. For more information, see [below](#upcomingrecent-deprecations)._ - _For those upgrading from `v5.4.X` to later versions, if you are upgrading from a deployment with LLMApi set to SAGEMAKER then set this value to DISABLED before upgrading. After upgrading, return this value back to SAGEMAKER._ +- [v5.4.5](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v5.4.5) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.5/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.5/qnabot-on-aws-vpc.template) + > _We do not recommend to use this version due to a potential issue with the testall functionality which may introduce a high number of versions stored in the testall S3 bucket when Content Designer has no Q&As. Please use the latest version available._ - [v5.4.4](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v5.4.4) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.4/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.4/qnabot-on-aws-vpc.template) + > _We do not recommend to use this version due to a potential issue with the testall functionality which may introduce a high number of versions stored in the testall S3 bucket when Content Designer has no Q&As. Please use the latest version available._ - [v5.4.3](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v5.4.3) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.3/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.3/qnabot-on-aws-vpc.template) - - _We do not recommend to use this version due to a potential issue with the testall functionality which may introduce a high number of versions stored in the testall S3 bucket. Please use the latest version available._ + > _We do not recommend to use this version due to a potential issue with the testall functionality which may introduce a high number of versions stored in the testall S3 bucket. Please use the latest version available._ - [v5.4.2](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v5.4.2) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.2/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.2/qnabot-on-aws-vpc.template) - - _We do not recommend to use this version due to a potential issue with the testall functionality which may introduce a high number of versions stored in the testall S3 bucket. Please use the latest version available._ + > _We do not recommend to use this version due to a potential issue with the testall functionality which may introduce a high number of versions stored in the testall S3 bucket. Please use the latest version available._ - [v5.4.1](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v5.4.1) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.1/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.1/qnabot-on-aws-vpc.template) - [v5.4.0](https://github.com/aws-solutions/qnabot-on-aws/releases/tag/v5.4.0) - [Public](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.0/qnabot-on-aws-main.template)/[VPC](https://solutions-reference.s3.amazonaws.com/qnabot-on-aws/v5.4.0/qnabot-on-aws-vpc.template) - _Note: Lambda Runtimes have been updated this release. Solution now uses: [nodejs18 and python3.10]_ @@ -359,11 +374,10 @@ _Note: **Deployable solution versions** refers to the ability to deploy the vers - _Note: Lambda Runtimes have been updated this release. Solution now uses: [nodejs16 and python3.9]_ ### Undeployable Versions -- All solutions less than `v5.2.1` are no longer deployable due to Lambda Runtime deprecations. +- All solutions less than `v5.2.1` are no longer deployable due to Lambda Runtime deprecations. This information is provided as is and you are strongly encouraged to check the deprecation calendar and end of life of the frameworks used in the solution. ### Upcoming/Recent deprecations -- nodejs16 will enter [Phase 1 deprecation](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html#runtime-support-policy) on Mar 11, 2024. -- Vue 2 will reach [End of Life](https://v2.vuejs.org/lts/) (EOL) on December 31st, 2023. +- nodejs16 has entered [Phase 1 deprecation](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html#runtime-support-policy) on Jun 12, 2024. ### Why would a solution version no longer be deployable? For QnABot, the most common reason is due to [AWS Lambda Runtimes being deprecated](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html#runtime-support-policy). When a Lambda runtime has been marked as deprecated, customers can no longer create new Lambda functions in their AWS account. This means that older versions of our solutions that make use of those runtimes will fail to deploy. This makes it hard for the community to provide support as we are unable to deploy a similar environment to investigate issues and reproduce bug reports. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..73feb891f --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,6 @@ +Reporting Security Issues +---------------------------------------------------------------------------------------------------------- +We take all security reports seriously. When we receive such reports, we will investigate and +subsequently address any potential vulnerabilities as quickly as possible. If you discover a potential +security issue in this project, please notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/) or +directly via email to [AWS Security](mailto:aws-security@amazon.com). Please do not create a public GitHub issue in this project. \ No newline at end of file diff --git a/deployment/run-unit-tests.sh b/deployment/run-unit-tests.sh index 68d780695..cedf73603 100755 --- a/deployment/run-unit-tests.sh +++ b/deployment/run-unit-tests.sh @@ -208,9 +208,8 @@ echo "Starting Templates unit tests" run_templates_test echo "Running Templates Python unit tests" -## NOTICE: Canvas LMS integration with QnABot on AWS is deprecated in this release and no longer be supported. Customers may fork the code needed for their specific use case from previous versions. The integration code will be removed in the next release. -python_directories=("$source_dir/templates/examples/examples/py" "$source_dir/templates/examples/extensions/py_lambda_hooks/CustomPYHook" "$source_dir/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook") +python_directories=("$source_dir/templates/examples/examples/py" "$source_dir/templates/examples/extensions/py_lambda_hooks/CustomPYHook") for folder in "${python_directories[@]}" ; do cd "$folder" function_name=${PWD##*/} diff --git a/source/bin/config.js b/source/bin/config.js index 1b2f0b261..17080e053 100644 --- a/source/bin/config.js +++ b/source/bin/config.js @@ -22,7 +22,6 @@ module.exports = { devPublicOrPrivate: 'PRIVATE', devLanguage: 'English', namespace: 'dev', - LexBotVersion: 'LexV2 Only', LexV2BotLocaleIds: 'en_US,es_US,fr_CA', stackNamePrefix: 'QNA', skipCheckTemplate: false, @@ -34,6 +33,7 @@ module.exports = { EmbeddingsBedrockModelId: 'amazon.titan-embed-text-v1', LLMApi: 'BEDROCK', LLMBedrockModelId: 'anthropic.claude-instant-v1', + LogRetentionPeriod: 0, BedrockKnowledgeBaseId: '', BedrockKnowledgeBaseModel: 'anthropic.claude-instant-v1', InstallLexResponseBots: true, diff --git a/source/cli/aws_solutions/qnabot/cli/qnabot_cli.py b/source/cli/aws_solutions/qnabot/cli/qnabot_cli.py index bf031a227..0e6c76bd0 100644 --- a/source/cli/aws_solutions/qnabot/cli/qnabot_cli.py +++ b/source/cli/aws_solutions/qnabot/cli/qnabot_cli.py @@ -23,7 +23,7 @@ @click.pass_context def cli(ctx) -> None: os.environ["SOLUTION_ID"] = "SO0189" - os.environ["SOLUTION_VERSION"] = "v6.0.3" + os.environ["SOLUTION_VERSION"] = "v6.1.0" @cli.command("import") diff --git a/source/cli/aws_solutions/qnabot/cli/qnabot_cli_helper.py b/source/cli/aws_solutions/qnabot/cli/qnabot_cli_helper.py index f0d522240..cffaa314d 100644 --- a/source/cli/aws_solutions/qnabot/cli/qnabot_cli_helper.py +++ b/source/cli/aws_solutions/qnabot/cli/qnabot_cli_helper.py @@ -29,6 +29,7 @@ class BucketType(Enum): IMPORT_BUCKET = "ImportBucket" EXPORT_BUCKET = "ExportBucket" + CONTENT_BUCKET = "ContentDesignerOutputBucket" def get_bucket_name(cloudformation_stack_name: str, bucket_type: BucketType): @@ -62,9 +63,10 @@ def initiate_import( :return: response status of the import request """ - importdatetime = datetime.datetime.utcnow() # get current request date time in UTC timezone + importdatetime = datetime.datetime.now(datetime.timezone.utc) # get current request date time in UTC timezone # get Import bucket name from the cloudformation stack str_import_bucket_name = get_bucket_name(cloudformation_stack_name, BucketType.IMPORT_BUCKET) + str_content_bucket_name = get_bucket_name(cloudformation_stack_name, BucketType.CONTENT_BUCKET) # create an options json config that includes import options that were used str_import_options = { @@ -99,13 +101,13 @@ def initiate_import( # check status of the file import response = get_import_status( - bucket=str_import_bucket_name, source_filename=source_filename, importdatetime=importdatetime + bucket=str_content_bucket_name, source_filename=source_filename, importdatetime=importdatetime ) seconds = 0 while json.loads(response)["status"] != "Complete" and seconds < 90: time.sleep(5) # wait for 5 seconds and check status again response = get_import_status( - bucket=str_import_bucket_name, source_filename=source_filename, importdatetime=importdatetime + bucket=str_content_bucket_name, source_filename=source_filename, importdatetime=importdatetime ) seconds += 5 return response @@ -128,9 +130,10 @@ def initiate_export(cloudformation_stack_name: str, export_filename: str, export :return: response status of the export request """ - exportdatetime = datetime.datetime.utcnow() # get current request date time in UTC timezone + exportdatetime = datetime.datetime.now(datetime.timezone.utc) # get current request date time in UTC timezone # get Export bucket name from the cloudformation stack str_export_bucket_name = get_bucket_name(cloudformation_stack_name, BucketType.EXPORT_BUCKET) + str_content_bucket_name = get_bucket_name(cloudformation_stack_name, BucketType.CONTENT_BUCKET) cfn_client = get_service_client("cloudformation") # get OpenSearch cluster Index name from the cloudformation stack @@ -151,9 +154,9 @@ def initiate_export(cloudformation_stack_name: str, export_filename: str, export "bucket": str_export_bucket_name, "index": str_open_search_index, "id": os.path.basename(export_filename), - "config": f"status/{os.path.basename(export_filename)}", + "config": f"status-export/{os.path.basename(export_filename)}", "tmp": f"tmp/{os.path.basename(export_filename)}", - "key": f"data/{os.path.basename(export_filename)}", + "key": f"data-export/{os.path.basename(export_filename)}", "filter": export_filter, "status": "Started", } @@ -163,23 +166,23 @@ def initiate_export(cloudformation_stack_name: str, export_filename: str, export # put a export config object in S3 bucket to initiate export s3_client = get_service_client("s3") # boto3.client('s3') response = s3_client.put_object( - Body=str_export_config, Bucket=str_export_bucket_name, Key=f"status/{os.path.basename(export_filename)}" + Body=str_export_config, Bucket=str_export_bucket_name, Key=f"status-export/{os.path.basename(export_filename)}" ) # check status of the file export response = get_export_status( - bucket=str_export_bucket_name, export_filename=export_filename, exportdatetime=exportdatetime + bucket=str_content_bucket_name, export_filename=export_filename, exportdatetime=exportdatetime ) while json.loads(response)["status"] != "Completed": time.sleep(5) # wait for 5 seconds and check status again response = get_export_status( - bucket=str_export_bucket_name, export_filename=export_filename, exportdatetime=exportdatetime + bucket=str_content_bucket_name, export_filename=export_filename, exportdatetime=exportdatetime ) # download the exported file response = download_export( - bucket=str_export_bucket_name, + bucket=str_content_bucket_name, export_filename=export_filename, exportdatetime=exportdatetime, file_format=file_format, @@ -188,7 +191,7 @@ def initiate_export(cloudformation_stack_name: str, export_filename: str, export while json.loads(response)["status"] != "Downloaded": time.sleep(5) # wait for 5 seconds and check status again response = download_export( - bucket=str_export_bucket_name, + bucket=str_content_bucket_name, export_filename=export_filename, exportdatetime=exportdatetime, file_format=file_format, @@ -217,7 +220,7 @@ def download_export(bucket: str, export_filename: str, exportdatetime: datetime, s3_client = get_service_client("s3") # boto3.client('s3') # get object only if the object has changed since last request response = s3_client.get_object( - Bucket=bucket, Key=f"data/{os.path.basename(export_filename)}", IfModifiedSince=exportdatetime + Bucket=bucket, Key=f"data-export/{os.path.basename(export_filename)}", IfModifiedSince=exportdatetime ) str_file_contents = response["Body"].read().decode("utf-8") # read object body if file_format == "JSON": @@ -277,7 +280,7 @@ def get_import_status(bucket: str, source_filename: str, importdatetime: datetim try: s3_client = get_service_client("s3") # boto3.client('s3') # get object only if the object has changed since last request - key = f"status/{os.path.basename(source_filename)}" + key = f"status-import/{os.path.basename(source_filename)}" #logger.debug(f"Getting import status for {bucket=} {key=}") response = s3_client.get_object(Bucket=bucket, Key=key, IfModifiedSince=importdatetime) @@ -331,7 +334,7 @@ def get_export_status(bucket: str, export_filename: str, exportdatetime: datetim s3_client = get_service_client("s3") # boto3.client('s3') # get object only if the object has changed since last request response = s3_client.get_object( - Bucket=bucket, Key=f"status/{os.path.basename(export_filename)}", IfModifiedSince=exportdatetime + Bucket=bucket, Key=f"status-export/{os.path.basename(export_filename)}", IfModifiedSince=exportdatetime ) obj_status_details = json.loads(response["Body"].read().decode("utf-8")) # read object body diff --git a/source/cli/requirements-test.txt b/source/cli/requirements-test.txt index 8bcd6e65a..654c631d9 100644 --- a/source/cli/requirements-test.txt +++ b/source/cli/requirements-test.txt @@ -1,8 +1,8 @@ docker~=6.1.2 -moto~=4.2.4 +moto~=5.0.13 openapi-spec-validator~=0.5.1 -pytest~=7.4.2 -pytest-cov~=4.1.0 -pytest-env~=1.0.0 -pytest-mock~=3.11.1 +pytest~=8.3.2 +pytest-cov~=5.0.0 +pytest-env~=1.1.3 +pytest-mock~=3.14.0 pyyaml~=6.0 \ No newline at end of file diff --git a/source/cli/requirements.txt b/source/cli/requirements.txt index bbae5bf3c..1237ab16f 100644 --- a/source/cli/requirements.txt +++ b/source/cli/requirements.txt @@ -1,2 +1,2 @@ -boto3==1.34.47 -Click==8.0.4 +boto3==1.35.5 +Click==8.1.7 diff --git a/source/cli/tests/aws_solutions/core/test_helpers.py b/source/cli/tests/aws_solutions/core/test_helpers.py index 11f2eb95e..58f40282c 100644 --- a/source/cli/tests/aws_solutions/core/test_helpers.py +++ b/source/cli/tests/aws_solutions/core/test_helpers.py @@ -14,7 +14,7 @@ import os import pytest -from moto import mock_sts +from moto import mock_aws from aws_solutions.core import ( get_aws_region, @@ -65,6 +65,6 @@ def test_get_aws_partition(region, partition, mocker): assert get_aws_partition() == partition -@mock_sts +@mock_aws def test_get_aws_account_id(mocker): assert get_aws_account() == "1" * 12 diff --git a/source/cli/tests/aws_solutions/qnabot/fixtures/cloudformation_fixtures.py b/source/cli/tests/aws_solutions/qnabot/fixtures/cloudformation_fixtures.py index 760e3c075..a1d8079ce 100644 --- a/source/cli/tests/aws_solutions/qnabot/fixtures/cloudformation_fixtures.py +++ b/source/cli/tests/aws_solutions/qnabot/fixtures/cloudformation_fixtures.py @@ -15,7 +15,7 @@ import logging import pytest -from moto import mock_cloudformation +from moto import mock_aws from aws_solutions.core import get_service_client @@ -48,6 +48,6 @@ def cloudformation_stacks(): @pytest.fixture def cloudformation_stacks_fixture(): - with mock_cloudformation(): + with mock_aws(): cloudformation_stacks() yield diff --git a/source/cli/tests/aws_solutions/qnabot/fixtures/s3_fixtures.py b/source/cli/tests/aws_solutions/qnabot/fixtures/s3_fixtures.py index a06c31d71..4996bcfca 100644 --- a/source/cli/tests/aws_solutions/qnabot/fixtures/s3_fixtures.py +++ b/source/cli/tests/aws_solutions/qnabot/fixtures/s3_fixtures.py @@ -15,7 +15,7 @@ import logging import pytest -from moto import mock_s3 +from moto import mock_aws from aws_solutions.core.helpers import get_service_resource @@ -72,7 +72,6 @@ def mock_export_event(*args): def get_s3_fixture(bucket_name=None): - # mock_s3 setup s3 bucket s3_resource = get_service_resource("s3") if not bucket_name: bucket_name = "test_bucket" @@ -82,6 +81,6 @@ def get_s3_fixture(bucket_name=None): @pytest.fixture def s3_fixture(): - with mock_s3(): + with mock_aws(): get_s3_fixture() yield diff --git a/source/cli/tests/aws_solutions/qnabot/test_helpers.py b/source/cli/tests/aws_solutions/qnabot/test_helpers.py index c173d8fe1..39d8e3512 100644 --- a/source/cli/tests/aws_solutions/qnabot/test_helpers.py +++ b/source/cli/tests/aws_solutions/qnabot/test_helpers.py @@ -16,7 +16,7 @@ from pathlib import Path import pytest -from moto import mock_sts, mock_s3 +from moto import mock_aws from aws_solutions.core.logging import get_logger from aws_solutions.qnabot.cli import qnabot_cli_helper @@ -32,8 +32,7 @@ logger = get_logger(__name__) -@mock_sts -@mock_s3 +@mock_aws @pytest.mark.skip(reason='Test fails in pipeline; passes locally.') def test_qna_import_json( # NOSONAR cloudformation_stacks_fixture, @@ -63,8 +62,7 @@ def test_qna_import_json( # NOSONAR logger.debug(f"{response=}") -@mock_sts -@mock_s3 +@mock_aws @pytest.mark.skip(reason='Test fails in pipeline; passes locally.') def test_qna_export_json( # NOSONAR cloudformation_stacks_fixture, @@ -97,8 +95,7 @@ def test_qna_export_json( # NOSONAR os.remove(export_filename) -@mock_sts -@mock_s3 +@mock_aws @pytest.mark.skip(reason='Test fails in pipeline; passes locally.') def test_qna_import_invalid_stack( # NOSONAR cloudformation_stacks_fixture, diff --git a/source/config.json b/source/config.json index aab36acf5..43c91adc8 100644 --- a/source/config.json +++ b/source/config.json @@ -2,14 +2,13 @@ "region": "us-east-1", "profile": "default", "publicBucket": "solutions", - "publicPrefix": "qnabot-on-aws/v6.0.3", + "publicPrefix": "qnabot-on-aws/v6.1.0", "devEmail": "", "ApprovedDomain": "NONE", "Username": "Admin", "devPublicOrPrivate": "PRIVATE", "devLanguage": "English", "namespace": "dev", - "LexBotVersion": "LexV2 Only", "LexV2BotLocaleIds": "en_US,es_US,fr_CA", "stackNamePrefix": "QNA", "skipCheckTemplate": true, @@ -21,6 +20,7 @@ "EmbeddingsBedrockModelId": "amazon.titan-embed-text-v1", "LLMApi": "BEDROCK", "LLMBedrockModelId": "anthropic.claude-instant-v1", + "LogRetentionPeriod": 0, "BedrockKnowledgeBaseId": "", "BedrockKnowledgeBaseModel": "anthropic.claude-instant-v1", "InstallLexResponseBots": true, diff --git a/source/docs/Blogpost-SimpleNavigation.json b/source/docs/Blogpost-SimpleNavigation.json index f90c3367f..5c6a86060 100644 --- a/source/docs/Blogpost-SimpleNavigation.json +++ b/source/docs/Blogpost-SimpleNavigation.json @@ -35,7 +35,7 @@ ] }, { - "qid": "Pressure + Flow", + "qid": "Pressure+Flow", "a": "Commissioned by the City of Tacoma. A two-part installation, Pressure + Flow is a reflection on the power of technology and communication to transform a landscape. Pressure is a sculpture inspired by the inner workings of a steam engine, and Flow involves etched writing applied directly to the historic Prairie Line rails, excerpted from historic documents and letters.\n\nAsk for more about the art, the artist, or the medium for additional information.", "next": "Shipment to China", "r": {}, @@ -50,7 +50,7 @@ ] }, { - "qid": "Shipment to China", + "qid": "Shipment_to_China", "a": "Commissioned by the Chinese Reconciliation Project Foundation in partnership with the City of Tacoma. This piece commemorates the early Chinese in America, their labors to construct the transcontinental railroads railroad construction, and their unjust suffering. It consists of an antique train truck and abstracted representation of 100 ash boxes, a reference to the Chinese workers who died while building the railroads. Ask for more about the art, the artist, or the medium for additional information.", "t": "", "next": "", @@ -71,7 +71,7 @@ ] }, { - "qid": "Where the Rails Meet the Sails", + "qid": "Where_the_Rails_Meet_the_Sails", "a": "This paired sculpture and mural features a finger and thumb clasping a steel needle, followed by a trail of stitches. The title takes its inspiration from a late-1800’s promotional slogan for Tacoma, and the mural elaborates on this era in Tacoma’s urban development. Together, these elements tell the story of the Northern Pacific Railroad finding its end at Commencement Bay and the growth of urban Tacoma.\n\nAsk for more about the art, the artist, or the medium for additional information.", "t": "Where the Rails Meet the Sails", "next": "Pressure + Flow", diff --git a/source/docs/LLM_Retrieval_and_generative_question_answering/README.md b/source/docs/LLM_Retrieval_and_generative_question_answering/README.md index edb7536a6..ad10987f2 100644 --- a/source/docs/LLM_Retrieval_and_generative_question_answering/README.md +++ b/source/docs/LLM_Retrieval_and_generative_question_answering/README.md @@ -1,4 +1,4 @@ -# Large Language Model - Generative Question Answering (Text Generation) and Query Disambiguation for Conversational Retrieval +# Large Language Model - Text Generation (Generative Question Answering) and Query Disambiguation for Conversational Retrieval QnABot can now use a large language model (LLM) to **(1) Disambiguate follow up questions to generate good search queries** and/or **(2) Generate answers to questions from retrieved search results or text passages**. @@ -54,7 +54,7 @@ With QnABot you can use three different data sources to generate responses from: > **_NOTE:_** If you want to enable S3 presigned URLs, S3 bucket names must start with `qna` (e.g. qnabot-mydocs), otherwise make sure IAM Role *...FulfillmentLambdaRole...* has been granted S3:GetObject access to the Bedrock Knowledge Base bucket (otherwise the signed URLS will not have access). In addition, you can encrypt the transient messages using your own KMS key; ensure that when creating the KMS key that the IAM Role *...FulfillmentLambdaRole...* is a key user. -![RAG using Amazon Bedrock Knowledge Base](./images/Bedrock_KB.png) + ![RAG using Amazon Bedrock Knowledge Base](./images/Bedrock_KB.png) @@ -67,6 +67,7 @@ You can also choose which LLM to use with QnABot: Utilizes one of the Amazon Bedrock foundation models to generate text. Currently, the following models are supported by QnA Bot: - [Amazon Titan Text G1 Lite](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=amazon.titan-text-lite-v1) - [Amazon Titan Text G1 Express](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=amazon.titan-text-express-v1) +- [Titan Text G1 - Premier](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=amazon.titan-text-premier-v1:0) - [Anthropic Claude Instant 1.2](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=anthropic.claude-instant-v1) - [Anthropic Claude 2.1](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=anthropic.claude-v2:1) - [Anthropic Claude 3 Sonnet](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=anthropic.claude-3-sonnet-20240229-v1:0) @@ -78,7 +79,7 @@ Utilizes one of the Amazon Bedrock foundation models to generate text. Currently #### Requesting Access to Amazon Bedrock Models -**NOTE: Access must be requested for the Bedrock model that you wish to use. This step needs to be performed only once per account in the region where your QnABot is deployed. To request access, go to the Model Access page in the Bedrock console: https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html. Select the models you need access to and request access.** +**NOTE: Access must be requested for the Bedrock model that you wish to use. This step needs to be performed only once per account in the region where your QnABot is deployed. To request access, go to the [Model Access](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html) page in the Bedrock console. Select the models you need access to and request access.** ![Model Access](./images/Request_model_access.jpeg) @@ -109,7 +110,7 @@ By default a 1-node ml.g5.12xlarge endpoint is automatically provisioned. For la Use a custom Lambda function to experiment with LLMs of your choice. Provide your own lambda function that takes a *question*, *context*, and a QnABot *settings* object. Your Lambda function can invoke any LLM you choose, and return the prediction in a JSON object containing the key, `generated_text`. You provide the ARN for your Lambda function when you deploy or update QnABot. -#### Deploy Stack for Embedding models invoked by a custom Lambda Function +#### Deploy Stack for LLM models invoked by a custom Lambda Function - *(for Kendra Fallback)* set `AltSearchKendraIndexes` to the Index Id (a GUID) of your existing Kendra index containing ingested documents - *(for text passage queries)* set `EmbeddingsApi` to BEDROCK, SAGEMAKER, or LAMBDA (see [Semantic Search using Text Embeddings](../semantic_matching_using_LLM_embeddings/README.md)) @@ -155,7 +156,6 @@ When QnABot stack is installed, open Content Designer **Settings** page: - **EMBEDDINGS_TEXT_PASSAGE_SCORE_THRESHOLD:** applies only when Embeddings are enabled (recommended) and if ES_SCORE_TEXT_ITEM_PASSAGES is true. If embedding similarity score on text item field is under threshold the match is rejected. Default is 0.80. -- **ALT_SEARCH_KENDRA_INDEXES:** be set to the Id (not the name) of your Kendra index where you have ingested documents of web pages that you want to use as source passages for generative answers. If you plan to use only QnABot text passages or Bedrock Knowledge Bases instead of Kendra, leave this setting blank. - **ALT_SEARCH_KENDRA_MAX_DOCUMENT_COUNT:** the number of passages from Kendra to provide in the input context for the LLM. @@ -168,7 +168,7 @@ When QnABot stack is installed, open Content Designer **Settings** page: - `{input}` - placeholder for the current user utterance / question - **LLM_GENERATE_QUERY_MODEL_PARAMS:** parameters sent to the LLM model when disambiguating follow-up questions. Default: `{"temperature":0}`. Check model documentation for additional values that your model provider accepts. - **LLM_QA_ENABLE:** set to true or false to enable or disable generative answers from passages retrieved via embeddings or Kendra fallback (when no FAQ match its found). NOTE LLM based generative answers are not applied when an FAQ / QID matches the question. -- **LLM_QA_USE_KENDRA_RETRIEVAL_API:** set to true or false to enable or disable the use of Kendra's retrieval API. When enabled, QnABot uses Kendra's Retrieve api to retrieve semantically relevant passages of up to 200 token words from the documents in your index (not FAQs). When disabled, QnABot use the default Kendra Query API to search documents and FAQs. Takes effect only when LLM_QA_ENABLE is true. The default is true (recommended) when LLM QA is enabled. Note: this feature will only search the first configured index. See https://docs.aws.amazon.com/kendra/latest/APIReference/API_Retrieve.html +- **LLM_QA_USE_KENDRA_RETRIEVAL_API:** set to true or false to enable or disable the use of Kendra's retrieval API. When enabled, QnABot uses Kendra's Retrieve api to retrieve semantically relevant passages of up to 200 token words from the documents in your index (not FAQs). When disabled, QnABot use the default Kendra Query API to search documents and FAQs. Takes effect only when LLM_QA_ENABLE is true. The default is true (recommended) when LLM QA is enabled. Note: this feature will only search the first configured index. See [Retrieve API](https://docs.aws.amazon.com/kendra/latest/APIReference/API_Retrieve.html) for more details. - **LLM_QA_PROMPT_TEMPLATE:** the prompt template used to construct a prompt for the LLM to generate an answer from the context of a retrieved passages (from Kendra or Embeddings). The template may use the placeholders: - `{context}` - placeholder for passages retrieved from the search query - either a QnABot 'Text' item passage, or the Top `ALT_SEARCH_KENDRA_MAX_DOCUMENT_COUNT` Kendra passages - `{history}` - placeholder for the last `LLM_CHAT_HISTORY_MAX_MESSAGES` messages in the conversational history, to provide conversational context. diff --git a/source/docs/LLM_Retrieval_and_generative_question_answering/images/Bedrock_KB.png b/source/docs/LLM_Retrieval_and_generative_question_answering/images/Bedrock_KB.png new file mode 100644 index 000000000..a49330e22 Binary files /dev/null and b/source/docs/LLM_Retrieval_and_generative_question_answering/images/Bedrock_KB.png differ diff --git a/source/docs/Technical Information.md b/source/docs/Technical Information.md index ceef9b6b4..472e3935c 100644 --- a/source/docs/Technical Information.md +++ b/source/docs/Technical Information.md @@ -102,13 +102,14 @@ - BuildStatusBucket - used for staging various assets during deployment - ExportBucket - Used for staging files exported from QnABot. API Gateway is used a proxy for the bucket - ImportBucket - Used for staging files imported into QnABot +- TestAllBucket - Used for staging files used for the TestAll functionality. - MetricsBucket - All captured usage data is sent to both OpenSearch and this bucket via Kinesis - MainAccessLogBucket - Access log bucket for the AssetBucket, BuildStatusBucket, ExportBucket, ImportBucket and MetricsBucket - devBootStrapAccessLogsBucket - Access log bucket for the dev Bootstrap bucket - devAccessLogsBucket - Access Log bucket for the dev bucket ## Firehose -- TestAllBucket - Results from “Test all” functionality +- ContentDesignerOutputBucket - Results from “Test all”, "Import", and "Export" functionality - Bucket - HTML/CSS/Javascript used by the Content Designer ## APIGateway @@ -194,6 +195,8 @@ S3 – Unzips assets stored in S3 *CloudFormation will not recognize that a referenced zip file for a Lambda has changed using our deployment process. This creates a new S3 version of the object.* +### S3Clear + - Deletes contents of the bucket when QnABot is uninstalled so the bucket can be deleted ### ExampleWriteLambda @@ -397,3 +400,8 @@ Reads status of the Lex Build process from status file S3 object and returns the *Supports “Test All Questions” step in the Content Designer* - Calls other Lambdas as needed to test questions and answers +## SolutionHelperRole + +### SolutionHelper + +Handles sending anonymized operational metrics to AWS \ No newline at end of file diff --git a/source/docs/bedrock_guardrails/README.md b/source/docs/bedrock_guardrails/README.md new file mode 100644 index 000000000..6d055e0dc --- /dev/null +++ b/source/docs/bedrock_guardrails/README.md @@ -0,0 +1,50 @@ +# Guardrails for Amazon Bedrock Integration and Knowledge Base Integration: + +QnABot on AWS allows you to specify [Guardrails for Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html) for Amazon Bedrock Integration and Knowledge Base Integration. When you use this optional feature, QnABot on AWS allows passing pre-configured Bedrock Guardrail Identifier and Version in the requests made to LLM models. To learn more about Guardrails for Amazon Bedrock, please see [How Guardrails for Amazon Bedrock works](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-how.html). + + +## Guardrails for Amazon Bedrock Quick Setup: +A. Prerequisites for using guardrails: + +1. Please verify [supported regions for Guardrails for Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-supported.html). +2. The provided guardrail identifier and version will be applied to the requests made to the models specified in `LLMBedrockModelId` and `BedrockKnowledgeBaseModel`. Please verify the models you have specified in cloudformation parameter `LLMBedrockModelId` and `BedrockKnowledgeBaseModel` are [supported models for Guardrails for Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-supported.html) +3. Please also ensure you have [requested model access](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html) for the same models in Bedrock console. + +B. Create a Guardrail using Amazon Bedrock console in your AWS account: + + 1. To configure QnABot to use Guardrails for Amazon Bedrock, you will first need to [create guardrail](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-create.html). Below is a quick step by step guide to get started: + + - Step 1: Provide guardrail details - + > **_TIP:_** You can leave default message unchanged `Sorry, the model cannot answer this question` because it is also a pattern defined in `LLM_QA_NO_HITS_REGEX`. When the Guardrail action is intervened, QnaBot will respond with [Custom Don't Know](https://docs.aws.amazon.com/solutions/latest/qnabot-on-aws/using-keyword-filters-for.html#custom-dont-know-answers) answers you have defined similar to when QnABot can't find answer. + + ![](./images//provide_guardrail_detail.png) + + - Step 2: Configure content filters (optional) - Configure content filters by adjusting the degree of filtering to detect and block harmful user inputs and model responses that violate your usage policies. + > **_NOTE:_** Please carefully note the strength of each of these filters. When they are low, content classified as harmful with HIGH confidence will be blocked while content classified as harmful with NONE, LOW, or MEDIUM confidence will be allowed. Please adjust the filters as per your requirements. + + ![](./images/content_filters.png) + + - Step 3: Add denied topics (optional) + - Step 4: Add word filters (optional) + - Step 5: Add sensitive information filters (optional) + - Step 6: Contextual grounding check (skip) - As of 6.1.0 of QnABot, this feature of guardrail is not supported so you would want to skip this step. + - Step 7: Review and create guardrail + +2. Once you have created a guardrail, you can test it with your testing data. After you have tested the guardrail, you can create a version. Once you have a version created, you can copy it and alongwith ID shown in the below screenshot. +![](./images/test_guardrail.png) + + +C. Input the Guardrail configured in the previous section into the Content Designer's settings page: + +Finally, input the copied ID into the field `BEDROCK_GUARDRAIL_IDENTIFIER` and the copied version number `BEDROCK_GUARDRAIL_VERSION` from section B.2 in the QnaBot Content Designer settings fiels. To do this navigate to the Content Designer > select the tools menu ( ☰ ) in top left corner, then select Settings > General Settings > Text Generation using LLMs > General Settings and update the settings as shown in the below screenshot. Then click Save. + ![](./images/update_settings.png) + + + +## Settings for Guardrail in QnABot on AWS: + +Below are the available settings to configure Guardrail in the Content Designer's settings page. + +- **BEDROCK_GUARDRAIL_IDENTIFIER:** Enter a pre-configurated Bedrock Guardrail identifier (e.g. 4ojm24q0yada) that you want to be applied to the requests made to the LLM models configured in the CloudFormation parameters `LLMBedrockModelId` and `BedrockKnowledgeBaseModel`. If you don't provide a value, no guardrail is applied to the LLM invocation. If you provide a guardrail identifier, you must also provide a `BEDROCK_GUARDRAIL_VERSION` otherwise no guardrail will be applied. + +- **BEDROCK_GUARDRAIL_VERSION:** Enter the version (e.g. 1 or DRAFT) of the Bedrock Guardrail specifed in `BEDROCK_GUARDRAIL_IDENTIFIER`. \ No newline at end of file diff --git a/source/docs/bedrock_guardrails/images/content_filters.png b/source/docs/bedrock_guardrails/images/content_filters.png new file mode 100644 index 000000000..1abc8fce8 Binary files /dev/null and b/source/docs/bedrock_guardrails/images/content_filters.png differ diff --git a/source/docs/bedrock_guardrails/images/provide_guardrail_detail.png b/source/docs/bedrock_guardrails/images/provide_guardrail_detail.png new file mode 100644 index 000000000..4ff52e9d7 Binary files /dev/null and b/source/docs/bedrock_guardrails/images/provide_guardrail_detail.png differ diff --git a/source/docs/bedrock_guardrails/images/test_guardrail.png b/source/docs/bedrock_guardrails/images/test_guardrail.png new file mode 100644 index 000000000..23036feab Binary files /dev/null and b/source/docs/bedrock_guardrails/images/test_guardrail.png differ diff --git a/source/docs/bedrock_guardrails/images/update_settings.png b/source/docs/bedrock_guardrails/images/update_settings.png new file mode 100644 index 000000000..eb871f914 Binary files /dev/null and b/source/docs/bedrock_guardrails/images/update_settings.png differ diff --git a/source/docs/bedrock_knowledgebase_rag/README.md b/source/docs/bedrock_knowledgebase_rag/README.md index 007daa5ef..b052e3afb 100644 --- a/source/docs/bedrock_knowledgebase_rag/README.md +++ b/source/docs/bedrock_knowledgebase_rag/README.md @@ -1,10 +1,10 @@ # Retrieval Augmentation Generation (RAG) using Amazon Bedrock Knowledge Base: -By integrating with the [Amazon Bedrock Knowledge Base](https://aws.amazon.com/bedrock/knowledge-bases/), QnABot on AWS can generate concise answers to user’s questions from configured data source(s). This prevents the need for users to sift through larger text passages to find the answer. You can also create your own knowledge base from files stored in an Amazon S3 bucket. Amazon Bedrock knowledge bases with QnaBot do not require EmbeddingsApi and LLMApi since the embeddings and generative response are already provided by the knowledge base. To enable this option, create an Amazon Bedrock knowledge base and copy your knowledge base ID into the CloudFormation parameter BedrockKnowledgeBaseId. +By integrating with the [Amazon Bedrock Knowledge Base](https://aws.amazon.com/bedrock/knowledge-bases/), QnABot on AWS can generate concise answers to the user’s questions from configured data source(s). This prevents the need for users to sift through larger text passages to find the answer. You can also create your own knowledge base from files stored in an Amazon S3 bucket. Amazon Bedrock knowledge bases with QnaBot do not require `EmbeddingsApi` and `LLMApi` since the embeddings and generative response are already provided by the knowledge base. To enable this option, create an Amazon Bedrock knowledge base and copy your knowledge base ID into the CloudFormation parameter `BedrockKnowledgeBaseId` and select model the model using the CloudFormation parameter `BedrockKnowledgeBaseModel`. -In addition to answers generated, QnABot also provides context and signed S3 URLs to documents stored in S3 buckets that knowledge base returns in it's response. The security of the S3 bucket governs whether this link is usable. +In addition to answers generated, QnABot also provides context and [signed S3 URLs](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html) to documents stored in S3 buckets that knowledge base returns in its response. These signed URLs are a secure way to grant temporary access to specific objects or resources within an Amazon S3 bucket. -With this integration, QnABot on AWS can answer question and it's follow-up from pdf files such as [AWS Whitepaper](https://docs.aws.amazon.com/pdfs/whitepapers/latest/aws-overview/aws-overview.pdf): +With this integration, QnABot on AWS can answer a question and its follow-up from documents stored in Amazon S3. For example, from the [AWS Whitepaper](https://docs.aws.amazon.com/pdfs/whitepapers/latest/aws-overview/aws-overview.pdf) file, the following questions can be answered: • What services are available in AWS for container orchestration? @@ -14,7 +14,7 @@ With this integration, QnABot on AWS can answer question and it's follow-up from ## Amazon Bedrock Knowledge Base Models: - +- [Titan Text G1 - Premier](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=amazon.titan-text-premier-v1:0) - [Anthropic Claude Instant 1.2](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=anthropic.claude-instant-v1) - [Anthropic Claude 2.1](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=anthropic.claude-v2:1) - [Anthropic Claude 3 Sonnet](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=anthropic.claude-3-sonnet-20240229-v1:0) @@ -30,11 +30,11 @@ Before getting started, please verify [supported regions and models for Knowledg ![](./images/image1.png) - Configure your data source based on available options. Here we will configure data source for S3. - > **_NOTE:_** If you want to enable S3 presigned URLs, S3 bucket names must start with `qna` (e.g. qnabot-mydocs), otherwise make sure IAM Role *...FulfillmentLambdaRole...* has been granted S3:GetObject access to the Bedrock Knowledge Base bucket (otherwise the signed URLS will not have access). In addition, you can encrypt the transient messages using your own KMS key; ensure that when creating the KMS key that the IAM Role *...FulfillmentLambdaRole...* is a key user. + > **_NOTE:_** If you want to enable S3 presigned URLs, the S3 bucket names must start with `qna` (e.g. qnabot-mydocs). In addition, make sure the IAM Role *...FulfillmentLambdaRole...* has been granted S3:GetObject access to the Bedrock Knowledge Base bucket (otherwise the signed URLS will not have access). Finally, you can encrypt the transient messages using your own KMS key; ensure that when creating the KMS key that the IAM Role *...FulfillmentLambdaRole...* is a key user. ![](./images/image2.png) -- Upload your documents in S3. Here we uploaded [aws-overview.pdf](https://docs.aws.amazon.com/pdfs/whitepapers/latest/aws-overview/aws-overview.pdf) whitepaper to test integration +- Upload your documents in S3. Here we uploaded the [aws-overview.pdf](https://docs.aws.amazon.com/pdfs/whitepapers/latest/aws-overview/aws-overview.pdf) whitepaper as a test. - Sync Data source and Copy your Knowledge base ID into the CloudFormation parameter BedrockKnowledgeBaseId @@ -46,7 +46,7 @@ Before getting started, please verify [supported regions and models for Knowledg ### BedrockKnowledgeBaseId **Optional** - ID of an existing Bedrock knowledge base. This setting enables the use of Bedrock knowledge bases as a fallback mechanism when a match is not found in OpenSearch. -For example: + ### BedrockKnowledgeBaseModel @@ -58,7 +58,18 @@ For example: ## Configure settings for RAG with Amazon Bedrock Knowledge Base in Content Designer: +- **KNOWLEDGE_BASE_PROMPT_TEMPLATE:** The prompt template used to construct a prompt for LLM specified in `BedrockKnowledgeModel` to generate an answer from the context of a retrieved results from Knowledge Base. To opt out of sending a prompt to the Knowledge Base model, simply leave this field empty. The template can use the following placeholders: + - `$query$` – The user query sent to the knowledge base. + - `$search_results$` - The retrieved results for the user query. + - `$output_format_instructions$` - The underlying instructions for formatting the response generation and citations. Differs by model. If you define your own formatting instructions, we suggest that you remove this placeholder. Without this placeholder, the response won't contain citations. + - `$current_time$` - The current time + + To learn more about prompt template and supported model for these placeholders, see `Knowledge Base Prompt Template` in [Query configurations](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html#kb-test-config-prompt-template). +- **KNOWLEDGE_BASE_MODEL_PARAMS:** Parameters sent to the LLM specified in cloudformation parameter BedrockKnowledgeModel when generating answers from Knowledge Base (e.g. anthropic model parameters can be customized as `{"temperature":0.1}` or `{"temperature":0.3, "maxTokens": 262, "topP":0.9, "top_k": 240 }`). For more information, please refer to [Inference parameters](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html) - **KNOWLEDGE_BASE_PREFIX_MESSAGE:** Message to append in the chat client when the knowledge base generates a response. - **KNOWLEDGE_BASE_SHOW_REFERENCES:** Enables or disables inclusion of the passages used as context for Bedrock Knowledge Base generated answers. - **KNOWLEDGE_BASE_S3_SIGNED_URLS:** Enables or disables S3 presigned URL signing for Bedrock Knowledge Base answers. -- **KNOWLEDGE_BASE_S3_SIGNED_URL_EXPIRE_SECS:** Determines length of time in seconds for the validity of signed S3 Urls for Bedrock Knowledge Base answers. \ No newline at end of file +- **KNOWLEDGE_BASE_S3_SIGNED_URL_EXPIRE_SECS:** Determines length of time in seconds for the validity of signed S3 Urls for Bedrock Knowledge Base answers. +- **KNOWLEDGE_BASE_MAX_NUMBER_OF_RETRIEVED_RESULTS:** Sets maximum number of retrieved result where each result corresponds to a source chunk. When querying a knowledge base, Amazon Bedrock returns up to five results by default. For more information, please refer to [Maximum number of retrieved results](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html). +- **KNOWLEDGE_BASE_SEARCH_TYPE:** Select the search type which defines how data sources in the knowledge base are queried. If using an Amazon OpenSearch Serverless vector store that contains a filterable text field, you can specify whether to query the knowledge base with a `HYBRID` search using both vector embeddings and raw text, or `SEMANTIC` search using only vector embeddings. For other vector store configurations, only `SEMANTIC` search is available. For more information, please refer to [Search type in Knowledge base](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html) +- **KNOWLEDGE_BASE_METADATA_FILTERS:** Specifies the filters to use on the metadata in the knowledge base data sources before returning results. (e.g filters can be customized as`{"filter1": { "key": "string", "value": "string" }, "filter2": { "key": "string", "value": number }}`). For more information, please refer to [Metadata and filtering](https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html). \ No newline at end of file diff --git a/source/docs/bedrock_knowledgebase_rag/images/image2.png b/source/docs/bedrock_knowledgebase_rag/images/image2.png index 3caec986d..18e549f0d 100644 Binary files a/source/docs/bedrock_knowledgebase_rag/images/image2.png and b/source/docs/bedrock_knowledgebase_rag/images/image2.png differ diff --git a/source/docs/bot_routing/README.md b/source/docs/bot_routing/README.md index 21828f594..94cd8b058 100644 --- a/source/docs/bot_routing/README.md +++ b/source/docs/bot_routing/README.md @@ -1,5 +1,5 @@ # Bot Routing - Preview Mode -(version 1.2 - December 2023) +(version 1.3 - July 2024) Bots exist to perform a variety of automation tasks. Usually they take as input a message from a human and respond performing @@ -55,18 +55,12 @@ BotRouter for the question being edited.** * Bot Name or Lambda - You can configure and existing Lex Bot or configure a specialty BotRouter implemented via a Lambda function. QnABot route -requests to a Lex Version 1 or Version 2 bot. The syntax is different -depending on the target version. For Lex version 2 bots use the syntax -lexv2::BotId/BotAliasId/LocaleId. For Lex version 1 bots use just the -BotName. Note that QnABot can be installed as either Lex V1 or Lex V2 -bot. It is important to check your QnABot configuration and select the +requests to a Lex Version 2 bot. For Lex version 2 bots use the syntax +lexv2::BotId/BotAliasId/LocaleId. It is important to check your QnABot configuration and select the appropriate identifiers when you want to use QnABot as a specialty bot. * Simple name - A short string that we expect web User Interfaces to use as a breadcrumb to identify where in an enterprise the user is interacting. - -* Lex Alias - If your specialty bot is a Lex version 1 bot, specify the Lex version 1 -alias used to communicate with the target bot. * Lex session attributes to forward to the specialty bot. A comma separated list of session attribute names can be specified. The session attributes diff --git a/source/docs/bot_routing/images/botroutingconfig.png b/source/docs/bot_routing/images/botroutingconfig.png index d75c5071c..7daa945dc 100644 Binary files a/source/docs/bot_routing/images/botroutingconfig.png and b/source/docs/bot_routing/images/botroutingconfig.png differ diff --git a/source/docs/canvaslms_integration/README.md b/source/docs/canvaslms_integration/README.md deleted file mode 100644 index 893f1ca93..000000000 --- a/source/docs/canvaslms_integration/README.md +++ /dev/null @@ -1,115 +0,0 @@ -# Integration with Canvas LMS -- an early example implementation -__**NOTICE: Canvas LMS integration with QnABot on AWS is deprecated in this release and no longer be supported. Customers may fork the code needed for their specific use case from previous versions. The integration code will be removed in the next release.**__ - -Students use their schools' learning management system (LMS) to keep track of their assignments, grades, and working through their course work. To make it easier for students to stay on track and also have easy access to a knowledge base, and help with their learning progress, you can now integrate the open source AWS QnABot solution with Canvas LMS, and enable students with in-the-moment support. With this integration, students will be able to ask the chatbot about their grades, syllabus, enrollments, assignments, and announcements. - - -## Setup prerequisites -There are few prerequisites to get started with the setup: -1. Setup up Canvas LMS – the setup requires a running Canvas LMS environment (on-premise or AWS environment). If you do not have Canvas LMS, you can install by following the instructions on GitHub at https://github.com/instructure/canvas-lms/wiki - -2. Setup the open source AWS QnABot solution deployed in your AWS environment. If you do not have this setup or are running an older version of AWS QnABot, you can easily install or upgrade by following the [AWS QnABot implementation guide](https://aws.amazon.com/solutions/implementations/aws-qnabot). - -3. Setup a companion Web UI for the chatbot. You can deploy this using the open source Lex-Web-UI project in your AWS account by following the steps outlined in this blog post -- https://aws.amazon.com/blogs/machine-learning/deploy-a-web-ui-for-your-chatbot/ . - - a. During this setup, set the `{EnableLogin}` setting to `{True}`. This will allow us to enable authentication in the chatbot and connect to a Identity provider. - - b. For `{BotName}` and `{BotAlias}`, use the BotName and Bot Alias as made available from the AWS QnABot solution deployment outputs. - -## Creating and Storing the Canvas API Access Token -The AWS QnABot solution uses the Canvas API to integrate with Canvas LMS. To configure the AWS QnABot solution, we will setup the following: - -1. Create a new Canvas API Access Token. For more details on how to create a Canvas API Access Token, follow the link: https://community.canvaslms.com/t5/Admin-Guide/How-do-I-manage-API-access-tokens-as-an-admin/ta-p/89 - -2. Store the Canvas API Access Token in AWS Secrets Manager. AWS Secrets Manager enables you to replace hardcoded credentials in your code, including passwords, with an API call to Secrets Manager to retrieve the secret programmatically. This helps ensure the secret can't be compromised by someone examining your code, because the secret no longer exists in the code. - - a. Login to your AWS console and navigate to AWS Secrets Manager. Use the same AWS region where you deployed the AWS QnABot solution. - - b. Click the `Store a new secret` button - - c. For `{Key}`, name the key as `"API_Token"` - - d. For `{Value}`, copy and paste the Canvas API Access Token value that you created earlier - - e. Give your secret a Name and Description. Start the `name` with the letters `qna-`. Such as: `qna-CanvasAPIKey` - -## Configure AWS QnABot Settings -Once you have deployed the AWS QnABot solution, you will have access to the QnABot Designer console, which allows you to create and manage your knowledge bank of questions and answers. -1. Click on the link that you received in your email and login to your QnABot Designer console. -2. Click on the menu located in the {top left corner} of the designer console. This will provide the “Tools” option list. -3. Scroll to the bottom of the page and click on `ADD NEW SETTING` button. We will use this to store the Secrets Manager key name that you created in the above steps, so QnABot can know how to connect to Canvas LMS. Enter the New Setting values: - - a. Name: enter `CanvasLMS_APIKey` as the name - - b. Value: use the name of the Secrets Manager key that you created in the above steps for storing the Canvas API key value. For example: `qna-CanvasLMSAPIKey` - - c. Click `ADD` button to add the new QnABot setting -4. Create another Setting - - a. Name: enter `CanvasLMS_DomainName` as the name - - b. Value: use the value of your Canvas endpoint. For example:: `https://lms.myschool.edu` - - c. Click `ADD` button to add the new QnABot setting - -5. Update the `IDENTITY_PROVIDER_JWKS_URLS` setting to add trusted Identity Providers (for example: from your Lex-Web-UI Cloudformation Outputs, using the `CognitoUserPoolPubKey` value). -6. Scroll to the bottom of the Settings page and click `Save` button to update the setting. - - -## Enabling Authentication -As part of the prerequisite setups, we setup the Lex-Web-UI (a companion UI solution for the chatbot) and configured the solution with the QnABot solution. The deployment setup an Amazon Cognito User Pool to support authentication. We will now extend this User Pool to add a test student user and test out the chatbot flow. - - - Go to your AWS console and navigate to the Amazon Cognito service. - - Select `Manage User Pools` and you will find two User Pools have already been setup (via the prerequisite setups earlier). The User Pool we will use is the Lex-Web-UI user pool. - - Select the Lex-Web-UI user pool and create a test student user. Also use an `{email address}` as created in the Canvas LMS for the test student user. -``` -Note: We are creating the user manually in Amazon Cognito to show this example setup. This manual user creation step should not be needed, if you want to SSO to Canvas LMS. - - Additional information on setting up Canvas LMS with SSO: -https://community.canvaslms.com/t5/Admin-Guide/How-do-I-configure-SSO-settings-for-my-authentication-provider/ta-p/217 - -In this example, we are using {username} as the matching attribute with {sis_login_id} in Canvas LMS. - - Additional information on extending Amazon Cognito to Federate to your Identity provider -https://qnabot.workshop.aws/deployment/sso.html - -``` - - -## Import Canvas Questions -In the QnABot Designer, click on the menu link on the top left and select `Import`. -From the `Examples/Extensions` section, click `Load` for `CanvasLMSIntegration` to load sample Canvas questions. - -## Lex Rebuild -Once you have loaded the questions, click the `Edit` option from the `Tools` menu and choose `LEX REBUILD` from the top right edit card menu (⋮). -This will re-train Amazon Lex using the newly added questions as training data. - -## Testing the Experience -Launch the `WebAppUrl` URL as available in the Lex-Web-UI AWS CloudFormation Output and Login to the chatbot from the menu option. Use the test student Canvas LMS credential that you created in the earlier steps to login and test the setup. - -Try the below example questions: - - Type or speak the below question(s) and see how the chatbot responds back with an answer. - - - *canvas menu* - - *do i have any announcements* - - *tell me about my syllabus* - - *do I have any assignments due* - - *what courses have i enrolled in* - - *more info about my course* - - *what are my grades* - - -## Notes -- This early example implementation supports English (en_US) language. - - -## Additional Reference -The following Canvas APIs are being used for this integration: - - User Profile — to support authentication, and greeting the user - - Grades --- student can ask questions such as “how did i do in my Math course”. This supports the overall grade information (out of 100) which is aggregated by course (not by assignments) - - Course — students can ask questions such as: “what are my assignments for Biology 101” - - Syllabus — access syllabus information. The output of this is a URL to the syllabus. Student can ask about their syllabus by asking “tell me about my syllabus” - - Enrollment — students can ask questions such as: “what courses am i enrolled in”, “what courses have i signed up for” - - Announcements — anything sent by the teacher to student(s) such as: “you have a test coming up”. Student can ask by saying “do I have any announcements” - -This integration uses the canvasapi python library to access information from Canvas LMS. https://canvasapi.readthedocs.io/en/stable/getting-started.html - - diff --git a/source/docs/intent_slot_matching/README.md b/source/docs/intent_slot_matching/README.md index 0ef722c5d..759165c6a 100644 --- a/source/docs/intent_slot_matching/README.md +++ b/source/docs/intent_slot_matching/README.md @@ -114,12 +114,4 @@ More information: https://docs.aws.amazon.com/lexv2/latest/dg/build-intents.html - As you are building your knowledge bank of questions, you may have a combination of FAQ based questions, Intent based questions. There may be instances where a wrong intent gets matched, or a FAQ question is matched instead. To troubleshoot this, below are couple of options that can help: - Enable the `ENABLE_DEBUG_RESPONSES` setting in QnABot. This setting provides debug information to help understand what is processing the request (such as: Intent, ElasticSearch, Kendra) - -## Additional Example Implementation -Also take a look at an example implementation showcasing the use of Intent and Slot matching. -- [Integration with Canvas LMS](../canvaslms_integration/README.md) - -__**NOTICE: Canvas LMS integration with QnABot on AWS is deprecated in this release and no longer be supported. Customers may fork the code needed for their specific use case from previous versions. The integration code will be removed in the next release.**__ - - ---- diff --git a/source/docs/kendra_fallback/README.md b/source/docs/kendra_fallback/README.md index 7cfc34d12..0eae566f3 100644 --- a/source/docs/kendra_fallback/README.md +++ b/source/docs/kendra_fallback/README.md @@ -4,8 +4,7 @@ This feature searches a set of Kendra indexes as a fallback mechanism to provide Kendra provides a number of innovative features. This Kendra Fallback function performs a query against a set of Kendra indexes and will return the first answer that Kendra identifies. Kendra can return multiple -answers however to keep responses limited in scope the first answer is provided through QnABot. Links to -documents stored in S3 buckets that Kendra indexes are also provided. The security of the S3 bucket governs whether this link is usable. In addition Kendra can return discovered text with links to these documents as well. This function returns a default of four discovered texts/links. The maximum number of returned links is configurable. +answers however to keep responses limited in scope the first answer is provided through QnABot. In addition to providing the generated answers, it provides [signed S3 URLs](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html) to relevant documents stored in Amazon S3 buckets that Kendra return in its response. These signed URLs are a secure way to grant temporary access to specific objects or resources within an Amazon S3 bucket. This function returns a default of four discovered texts/links. The maximum number of returned links is configurable. ## Configure Kendra Fallback index using the following Cloudformation parameter diff --git a/source/docs/lambda_hooks/README.md b/source/docs/lambda_hooks/README.md index 93445d0b0..80f961f09 100644 --- a/source/docs/lambda_hooks/README.md +++ b/source/docs/lambda_hooks/README.md @@ -84,3 +84,4 @@ For an example implementation using Lambda Hook -- refer to this [example](../.. - The `Makefile` residing in the extensions folder creates separate zip packages for each separate Lambda hook function - Lambda hook functions use nodejs18.x or python3.10 only at this time - Lambda hook functions will be allocated 2048MB memory (defined in index.js) +- LexV2 has a timeout limit on [RecognizeText](https://w.amazon.com/bin/view/AWS/Solutions/SolutionsTeam/BuilderBestPractices/NightsWatchUserGuide) fulfillment. If the QnABot fulfillment processing (including lambda hook) exceeds this timeout limit, then LexV2 will timeout the request. \ No newline at end of file diff --git a/source/docs/lambda_hooks/lambda_hook_sdk.MD b/source/docs/lambda_hooks/lambda_hook_sdk.MD index 83f112eb4..b84989bba 100644 --- a/source/docs/lambda_hooks/lambda_hook_sdk.MD +++ b/source/docs/lambda_hooks/lambda_hook_sdk.MD @@ -81,7 +81,7 @@ object ### Returns -- Lex V1 - [https://docs.aws.amazon.com/lex/latest/dg/lambda-input-response-format.html](https://docs.aws.amazon.com/lex/latest/dg/lambda-input-response-format.html) + - Lex V2 - [https://docs.aws.amazon.com/lexv2/latest/dg/lambda.html](https://docs.aws.amazon.com/lexv2/latest/dg/lambda.html) ## get_bot diff --git a/source/docs/semantic_matching_using_LLM_embeddings/README.md b/source/docs/semantic_matching_using_LLM_embeddings/README.md index 672215fce..3d5caeaea 100644 --- a/source/docs/semantic_matching_using_LLM_embeddings/README.md +++ b/source/docs/semantic_matching_using_LLM_embeddings/README.md @@ -17,6 +17,7 @@ You can select from three different options: ## 1. Amazon Bedrock (PREFERRED) Utilizes one of the Amazon Bedrock foundation models to generate text embeddings. Currently, the following embeddings models are supported by QnA Bot: - [Amazon Titan Embeddings G1](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=amazon.titan-embed-text-v1) +- [Titan Text Embeddings V2](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=amazon.titan-embed-text-v2:0) - [Cohere English](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=cohere.embed-english-v3) - [Cohere Multilingual](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/providers?model=cohere.embed-multilingual-v3) diff --git a/source/lambda/aws-sdk-layer/package-lock.json b/source/lambda/aws-sdk-layer/package-lock.json index 73abe629c..834fefd97 100644 --- a/source/lambda/aws-sdk-layer/package-lock.json +++ b/source/lambda/aws-sdk-layer/package-lock.json @@ -1,16 +1,14 @@ { "name": "aws-layer", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "aws-layer", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-bedrock-agent-runtime": "^3.622.0", - "@aws-sdk/client-bedrock-runtime": "^3.622.0", "@aws-sdk/client-comprehend": "^3.621.0", "@aws-sdk/client-kendra": "^3.621.0", "@aws-sdk/client-lambda": "^3.621.0", @@ -18,19 +16,6 @@ "@aws-sdk/client-translate": "^3.621.0" } }, - "node_modules/@aws-crypto/crc32": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", - "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/@aws-crypto/crc32c": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", @@ -99,17 +84,17 @@ "tslib": "^2.6.2" } }, - "node_modules/@aws-sdk/client-bedrock-agent-runtime": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-agent-runtime/-/client-bedrock-agent-runtime-3.622.0.tgz", - "integrity": "sha512-rCX/LSAPjk7ZOMzNF2yruHTuqbZnfsKya0FTiyKm6GDsNI1rWmx/dx/fh8NH2LOOfxiNSqMez2Wv2biUyZ46Jw==", + "node_modules/@aws-sdk/client-comprehend": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-comprehend/-/client-comprehend-3.621.0.tgz", + "integrity": "sha512-OEO5obeYkBMRWBs863fTTzGrqs5lxUydg52K6XYcexXWMTEyoAWhRlxERDzC94rfEoowQ2Xyf8Y3qI0CAaNLlA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -120,40 +105,38 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/eventstream-serde-browser": "^3.0.5", - "@smithy/eventstream-serde-config-resolver": "^3.0.3", - "@smithy/eventstream-serde-node": "^3.0.4", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" + "tslib": "^2.6.2", + "uuid": "^9.0.1" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/is-array-buffer": { + "node_modules/@aws-sdk/client-comprehend/node_modules/@smithy/is-array-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", @@ -164,7 +147,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-buffer-from": { + "node_modules/@aws-sdk/client-comprehend/node_modules/@smithy/util-buffer-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", @@ -176,7 +159,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-utf8": { + "node_modules/@aws-sdk/client-comprehend/node_modules/@smithy/util-utf8": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", @@ -188,17 +171,17 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.622.0.tgz", - "integrity": "sha512-zJJWnHdORNNSM74yTeya5UyzEfXrFJDAuU7/JPc8PerURC5QElwWHNq6OR9AVTmJNvgs66XNZDgt46FStphMbQ==", + "node_modules/@aws-sdk/client-kendra": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-kendra/-/client-kendra-3.621.0.tgz", + "integrity": "sha512-OdftXrxoECqYMrIQmzmPygWCUxag5Mb+RpNDBtoQro1Tk/AkUNkOQcC9+eUzsvvahi6JQwqXZx1y2ywwvLOARg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -209,41 +192,38 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/eventstream-serde-browser": "^3.0.5", - "@smithy/eventstream-serde-config-resolver": "^3.0.3", - "@smithy/eventstream-serde-node": "^3.0.4", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", - "@smithy/util-stream": "^3.1.3", "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" + "tslib": "^2.6.2", + "uuid": "^9.0.1" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/is-array-buffer": { + "node_modules/@aws-sdk/client-kendra/node_modules/@smithy/is-array-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", @@ -254,7 +234,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-buffer-from": { + "node_modules/@aws-sdk/client-kendra/node_modules/@smithy/util-buffer-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", @@ -266,7 +246,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-utf8": { + "node_modules/@aws-sdk/client-kendra/node_modules/@smithy/util-utf8": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", @@ -278,10 +258,10 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-comprehend": { + "node_modules/@aws-sdk/client-lambda": { "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-comprehend/-/client-comprehend-3.621.0.tgz", - "integrity": "sha512-OEO5obeYkBMRWBs863fTTzGrqs5lxUydg52K6XYcexXWMTEyoAWhRlxERDzC94rfEoowQ2Xyf8Y3qI0CAaNLlA==", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.621.0.tgz", + "integrity": "sha512-QD3FOMOLc9CQqfYOEzpTlB9LZbpN+0BrLUpc4+kNa+IheD5kes6gRRLB3Y1OLY4GIRTfPnYPTeFnW8AsSbcNzQ==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", @@ -300,6 +280,9 @@ "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", "@smithy/core": "^2.3.1", + "@smithy/eventstream-serde-browser": "^3.0.5", + "@smithy/eventstream-serde-config-resolver": "^3.0.3", + "@smithy/eventstream-serde-node": "^3.0.4", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", @@ -322,36 +305,91 @@ "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", + "@smithy/util-stream": "^3.1.3", "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" + "@smithy/util-waiter": "^3.1.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-comprehend/node_modules/@aws-sdk/client-sso": { + "node_modules/@aws-sdk/client-s3": { "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", - "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.621.0.tgz", + "integrity": "sha512-YhGkd2HQTM4HCYJIAVWvfbUMpOF7XUr1W/e2LN3CFP0WTF4zcCJKesJ2iNHrExqC0Ek1+qarMxiXBK95itfjYQ==", "dependencies": { + "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-bucket-endpoint": "3.620.0", + "@aws-sdk/middleware-expect-continue": "3.620.0", + "@aws-sdk/middleware-flexible-checksums": "3.620.0", "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-location-constraint": "3.609.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-sdk-s3": "3.621.0", + "@aws-sdk/middleware-signing": "3.620.0", + "@aws-sdk/middleware-ssec": "3.609.0", "@aws-sdk/middleware-user-agent": "3.620.0", "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/signature-v4-multi-region": "3.621.0", "@aws-sdk/types": "3.609.0", "@aws-sdk/util-endpoints": "3.614.0", "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", + "@aws-sdk/xml-builder": "3.609.0", "@smithy/config-resolver": "^3.0.5", "@smithy/core": "^2.3.1", + "@smithy/eventstream-serde-browser": "^3.0.5", + "@smithy/eventstream-serde-config-resolver": "^3.0.3", + "@smithy/eventstream-serde-node": "^3.0.4", "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-blob-browser": "^3.1.2", "@smithy/hash-node": "^3.0.3", + "@smithy/hash-stream-node": "^3.1.2", "@smithy/invalid-dependency": "^3.0.3", + "@smithy/md5-js": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-retry": "^3.0.13", @@ -369,24 +407,76 @@ "@smithy/util-defaults-mode-browser": "^3.0.13", "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", + "@smithy/util-stream": "^3.1.3", "@smithy/util-utf8": "^3.0.0", + "@smithy/util-waiter": "^3.1.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-signing": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.620.0.tgz", + "integrity": "sha512-gxI7rubiaanUXaLfJ4NybERa9MGPNg2Ycl/OqANsozrBnR3Pw8vqy3EuVImQOyn2pJ2IFvl8ZPoSMHf4pX56FQ==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-comprehend/node_modules/@aws-sdk/client-sso-oidc": { + "node_modules/@aws-sdk/client-sso": { "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", - "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -425,19 +515,15 @@ }, "engines": { "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" } }, - "node_modules/@aws-sdk/client-comprehend/node_modules/@aws-sdk/client-sts": { + "node_modules/@aws-sdk/client-sso-oidc": { "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", - "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.621.0", "@aws-sdk/core": "3.621.0", "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", @@ -478,1324 +564,40 @@ }, "engines": { "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.621.0" } }, - "node_modules/@aws-sdk/client-comprehend/node_modules/@aws-sdk/core": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", - "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", "dependencies": { - "@smithy/core": "^2.3.1", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-comprehend/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", - "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", + "@smithy/is-array-buffer": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-comprehend/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", - "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" - } - }, - "node_modules/@aws-sdk/client-comprehend/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", - "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-ini": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-comprehend/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", - "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", - "dependencies": { - "@aws-sdk/client-sso": "3.621.0", - "@aws-sdk/token-providers": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-comprehend/node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-comprehend/node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-comprehend/node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-kendra": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-kendra/-/client-kendra-3.621.0.tgz", - "integrity": "sha512-OdftXrxoECqYMrIQmzmPygWCUxag5Mb+RpNDBtoQro1Tk/AkUNkOQcC9+eUzsvvahi6JQwqXZx1y2ywwvLOARg==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.621.0", - "@aws-sdk/client-sts": "3.621.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-kendra/node_modules/@aws-sdk/client-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", - "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-kendra/node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", - "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" - } - }, - "node_modules/@aws-sdk/client-kendra/node_modules/@aws-sdk/client-sts": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", - "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.621.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-kendra/node_modules/@aws-sdk/core": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", - "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", - "dependencies": { - "@smithy/core": "^2.3.1", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-kendra/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", - "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-kendra/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", - "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" - } - }, - "node_modules/@aws-sdk/client-kendra/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", - "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-ini": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-kendra/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", - "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", - "dependencies": { - "@aws-sdk/client-sso": "3.621.0", - "@aws-sdk/token-providers": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-kendra/node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-kendra/node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-kendra/node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.621.0.tgz", - "integrity": "sha512-QD3FOMOLc9CQqfYOEzpTlB9LZbpN+0BrLUpc4+kNa+IheD5kes6gRRLB3Y1OLY4GIRTfPnYPTeFnW8AsSbcNzQ==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.621.0", - "@aws-sdk/client-sts": "3.621.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/eventstream-serde-browser": "^3.0.5", - "@smithy/eventstream-serde-config-resolver": "^3.0.3", - "@smithy/eventstream-serde-node": "^3.0.4", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-stream": "^3.1.3", - "@smithy/util-utf8": "^3.0.0", - "@smithy/util-waiter": "^3.1.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/client-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", - "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", - "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" - } - }, - "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/client-sts": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", - "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.621.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/core": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", - "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", - "dependencies": { - "@smithy/core": "^2.3.1", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", - "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", - "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" - } - }, - "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", - "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-ini": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", - "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", - "dependencies": { - "@aws-sdk/client-sso": "3.621.0", - "@aws-sdk/token-providers": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda/node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda/node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda/node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-s3": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.621.0.tgz", - "integrity": "sha512-YhGkd2HQTM4HCYJIAVWvfbUMpOF7XUr1W/e2LN3CFP0WTF4zcCJKesJ2iNHrExqC0Ek1+qarMxiXBK95itfjYQ==", - "dependencies": { - "@aws-crypto/sha1-browser": "5.2.0", - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.621.0", - "@aws-sdk/client-sts": "3.621.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-bucket-endpoint": "3.620.0", - "@aws-sdk/middleware-expect-continue": "3.620.0", - "@aws-sdk/middleware-flexible-checksums": "3.620.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-location-constraint": "3.609.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-sdk-s3": "3.621.0", - "@aws-sdk/middleware-signing": "3.620.0", - "@aws-sdk/middleware-ssec": "3.609.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/signature-v4-multi-region": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@aws-sdk/xml-builder": "3.609.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/eventstream-serde-browser": "^3.0.5", - "@smithy/eventstream-serde-config-resolver": "^3.0.3", - "@smithy/eventstream-serde-node": "^3.0.4", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-blob-browser": "^3.1.2", - "@smithy/hash-node": "^3.0.3", - "@smithy/hash-stream-node": "^3.1.2", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/md5-js": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-stream": "^3.1.3", - "@smithy/util-utf8": "^3.0.0", - "@smithy/util-waiter": "^3.1.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/client-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", - "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", - "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/client-sts": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", - "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.621.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/core": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", - "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", - "dependencies": { - "@smithy/core": "^2.3.1", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", - "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", - "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", - "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-ini": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", - "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", - "dependencies": { - "@aws-sdk/client-sso": "3.621.0", - "@aws-sdk/token-providers": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-signing": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.620.0.tgz", - "integrity": "sha512-gxI7rubiaanUXaLfJ4NybERa9MGPNg2Ycl/OqANsozrBnR3Pw8vqy3EuVImQOyn2pJ2IFvl8ZPoSMHf4pX56FQ==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.622.0.tgz", - "integrity": "sha512-DJwUqVR/O2lImbktUHOpaQ8XElNBx3JmWzTT2USg6jh3ErgG1CS6LIV+VUlgtxGl+tFN/G6AcAV8SdnnGydB8Q==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.622.0.tgz", - "integrity": "sha512-dwWDfN+S98npeY77Ugyv8VIHKRHN+n/70PWE4EgolcjaMrTINjvUh9a/SypFEs5JmBOAeCQt8S2QpM3Wvzp+pQ==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" }, "engines": { @@ -1837,151 +639,16 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.622.0.tgz", - "integrity": "sha512-Yqtdf/wn3lcFVS42tR+zbz4HLyWxSmztjVW9L/yeMlvS7uza5nSkWqP/7ca+RxZnXLyrnA4jJtSHqykcErlhyg==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-translate": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-translate/-/client-translate-3.621.0.tgz", - "integrity": "sha512-xECN0dt6erzA5lXFyYfXyTHKXRPz67QEbw+6S0bnX4gu0SutzJ7DQSTw6ykWmk+fnjwUAw1qBfpDhybGk4oOcw==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.621.0", - "@aws-sdk/client-sts": "3.621.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-translate/node_modules/@aws-sdk/client-sso": { + "node_modules/@aws-sdk/client-sts": { "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", - "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.621.0", "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -2022,66 +689,50 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-translate/node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", - "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.621.0", - "@aws-sdk/credential-provider-node": "3.621.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.1", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.13", - "@smithy/util-defaults-mode-node": "^3.0.13", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-translate/node_modules/@aws-sdk/client-sts": { + "node_modules/@aws-sdk/client-translate": { "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", - "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-translate/-/client-translate-3.621.0.tgz", + "integrity": "sha512-xECN0dt6erzA5lXFyYfXyTHKXRPz67QEbw+6S0bnX4gu0SutzJ7DQSTw6ykWmk+fnjwUAw1qBfpDhybGk4oOcw==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", "@aws-sdk/core": "3.621.0", "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", @@ -2118,108 +769,8 @@ "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-translate/node_modules/@aws-sdk/core": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", - "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", - "dependencies": { - "@smithy/core": "^2.3.1", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-translate/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", - "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-translate/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", - "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" - } - }, - "node_modules/@aws-sdk/client-translate/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", - "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.621.0", - "@aws-sdk/credential-provider-ini": "3.621.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.621.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-translate/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", - "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", - "dependencies": { - "@aws-sdk/client-sso": "3.621.0", - "@aws-sdk/token-providers": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" + "tslib": "^2.6.2", + "uuid": "^9.0.1" }, "engines": { "node": ">=16.0.0" @@ -2261,15 +812,15 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.622.0.tgz", - "integrity": "sha512-q1Ct2AjPxGtQBKtDpqm1umu3f4cuWMnEHTuDa6zjjaj+Aq/C6yxLgZJo9SlcU0tMl8rUCN7oFonszfTtp4Y0MA==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", "dependencies": { - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "fast-xml-parser": "4.4.1", @@ -2294,16 +845,16 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.622.0.tgz", - "integrity": "sha512-VUHbr24Oll1RK3WR8XLUugLpgK9ZuxEm/NVeVqyFts1Ck9gsKpRg1x4eH7L7tW3SJ4TDEQNMbD7/7J+eoL2svg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/property-provider": "^3.1.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" @@ -2313,14 +864,14 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.622.0.tgz", - "integrity": "sha512-cD/6O9jOfzQyo8oyAbTKnyRO89BIMSTzwaN4NxGySC6pYVTqxNSWdRwaqg/vKbwJpjbPGGYYXpXEW11kop7dlg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -2333,19 +884,19 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.622.0.tgz", - "integrity": "sha512-keldwz4Q/6TYc37JH6m43HumN7Vi+R0AuGuHn5tBV40Vi7IiqEzjpiE+yvsHIN+duUheFLL3j/o0H32jb+14DQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -2374,11 +925,11 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.622.0.tgz", - "integrity": "sha512-zrSoBVM2JlwvkBtrcUd4J/9CrG+T+hUy9r6jwo5gonFIN3QkneR/pqpbUn/n32Zy3zlzCo2VfB31g7MjG7kJmg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", "dependencies": { - "@aws-sdk/client-sso": "3.622.0", + "@aws-sdk/client-sso": "3.621.0", "@aws-sdk/token-providers": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", @@ -2456,6 +1007,19 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/is-array-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", @@ -2817,15 +1381,15 @@ } }, "node_modules/@smithy/core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", - "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" @@ -2849,17 +1413,6 @@ "node": ">=16.0.0" } }, - "node_modules/@smithy/eventstream-codec": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.2.tgz", - "integrity": "sha512-0mBcu49JWt4MXhrhRAlxASNy0IjDRFU+aWNDRal9OtUJvJNiwDuyKMUONSOjLjSCeGwZaE0wOErdqULer8r7yw==", - "dependencies": { - "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^3.3.0", - "@smithy/util-hex-encoding": "^3.0.0", - "tslib": "^2.6.2" - } - }, "node_modules/@smithy/eventstream-serde-browser": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.5.tgz", @@ -2911,6 +1464,30 @@ "node": ">=16.0.0" } }, + "node_modules/@smithy/eventstream-serde-universal/node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal/node_modules/@smithy/eventstream-codec": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.2.tgz", + "integrity": "sha512-0mBcu49JWt4MXhrhRAlxASNy0IjDRFU+aWNDRal9OtUJvJNiwDuyKMUONSOjLjSCeGwZaE0wOErdqULer8r7yw==", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^3.3.0", + "@smithy/util-hex-encoding": "^3.0.0", + "tslib": "^2.6.2" + } + }, "node_modules/@smithy/fetch-http-handler": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", @@ -3127,14 +1704,14 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", - "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", "dependencies": { "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -3324,9 +1901,9 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -3451,12 +2028,12 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", - "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", "dependencies": { "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -3466,15 +2043,15 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", - "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", "dependencies": { "@smithy/config-resolver": "^3.0.5", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, diff --git a/source/lambda/aws-sdk-layer/package.json b/source/lambda/aws-sdk-layer/package.json index 4a5a7813f..130b7dd2b 100644 --- a/source/lambda/aws-sdk-layer/package.json +++ b/source/lambda/aws-sdk-layer/package.json @@ -1,6 +1,6 @@ { "name": "aws-layer", - "version": "6.0.3", + "version": "6.1.0", "description": "QnABot Lambda aws-sdk-layer", "main": "index.js", "scripts": { @@ -12,8 +12,6 @@ }, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-bedrock-agent-runtime": "^3.622.0", - "@aws-sdk/client-bedrock-runtime": "^3.622.0", "@aws-sdk/client-comprehend": "^3.621.0", "@aws-sdk/client-kendra": "^3.621.0", "@aws-sdk/client-lambda": "^3.621.0", diff --git a/source/lambda/cfn-lambda-layer/package-lock.json b/source/lambda/cfn-lambda-layer/package-lock.json index fe8b901fd..e45935b53 100644 --- a/source/lambda/cfn-lambda-layer/package-lock.json +++ b/source/lambda/cfn-lambda-layer/package-lock.json @@ -1,12 +1,12 @@ { "name": "cfn-lambda-layer", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cfn-lambda-layer", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "cfn-lambda": "^5.1.0" diff --git a/source/lambda/cfn-lambda-layer/package.json b/source/lambda/cfn-lambda-layer/package.json index 2f8781839..700459821 100644 --- a/source/lambda/cfn-lambda-layer/package.json +++ b/source/lambda/cfn-lambda-layer/package.json @@ -1,6 +1,6 @@ { "name": "cfn-lambda-layer", - "version": "6.0.3", + "version": "6.1.0", "description": "QnABot Cfn Lambda Layer", "main": "index.js", "scripts": { diff --git a/source/lambda/cfn/lib/PostUpgradeImport.js b/source/lambda/cfn/lib/PostUpgradeImport.js index 652051a24..2825e9180 100644 --- a/source/lambda/cfn/lib/PostUpgradeImport.js +++ b/source/lambda/cfn/lib/PostUpgradeImport.js @@ -17,7 +17,7 @@ const customSdkConfig = require('./util/customSdkConfig'); const region = process.env.AWS_REGION || 'us-east-1'; const s3 = new S3Client(customSdkConfig({ region })); -async function copyData(s3exportparms, s3importparms) { +async function copyData(oldS3ExportParams, s3exportparms, s3importparms) { console.log('Reading previously exported data'); try { const res = await s3.send(new GetObjectCommand (s3exportparms)); @@ -31,7 +31,22 @@ async function copyData(s3exportparms, s3importparms) { console.log('Export file has no data - skipping import'); } return count; - } catch (err) { + } + catch (err) { + // Necessary for backwards compatibility. + if (err.name === 'AccessDenied') { + const res = await s3.send(new GetObjectCommand (oldS3ExportParams)); + const data_json = await res.Body.transformToString(); + const count = data_json.length; + if (count > 0) { + console.log(`Copy data to import bucket: length: ${count}`); + s3importparms.Body = data_json; + await s3.send(new PutObjectCommand(s3importparms)); + } else { + console.log('Export file has no data - skipping import'); + } + return count; + } console.log('No previously exported data:', err); return 0; } @@ -44,7 +59,7 @@ async function waitForImport(s3params, timeout) { let complete = false; let timedout = false; do { - await new Promise((resolve) => setTimeout(resolve, 1000)); + await new Promise((resolve) => setTimeout(resolve, 3000)); try { const res = await s3.send(new GetObjectCommand(s3params)); const readableStream = Buffer.concat(await res.Body.toArray()) @@ -62,8 +77,7 @@ async function waitForImport(s3params, timeout) { return complete; } -async function run_import(params, reply) { - const ID = 'PostUpgradeImport'; +async function run_import(params) { const data = { bucket: params.importbucket, index: params.index, @@ -74,51 +88,52 @@ async function run_import(params, reply) { filter: '', status: 'Started', }; - const s3exportparms = { + const oldS3ExportParams = { Bucket: params.exportbucket, - Key: data.key, + Key: `data-export/${params.id}`, + }; + const s3exportparms = { + Bucket: params.contentDesignerOutputBucket, + Key: `data-export/${params.id}`, }; const s3importparms = { Bucket: params.importbucket, Key: data.key, }; - const exportfile = `${params.exportbucket}/${data.key}`; + const exportfile = `${params.contentDesignerOutputBucket}/data-export/${params.id}`; const importfile = `${params.importbucket}/${data.key}`; console.log(`copy export file ${exportfile} to import bucket ${importfile}`); - const count = await copyData(s3exportparms, s3importparms); + const count = await copyData(oldS3ExportParams, s3exportparms, s3importparms); if (count > 0) { console.log('Running import process.'); const s3params = { - Bucket: params.importbucket, - Key: data.config, + Bucket: params.contentDesignerOutputBucket, + Key: `status-import/${params.id}`, }; console.log('Wait up to 60 seconds for status to be completed'); - delete s3params.Body; const complete = await waitForImport(s3params, 60000); if (complete) { console.log('Import completed: ', exportfile); - reply(null, ID); } else { console.log('Import did NOT complete: ', exportfile); - reply(null, ID); } } else { console.log('No records to import in: ', exportfile); - reply(null, ID); } } -module.exports = class PostUpgradeImport extends require('./base') { - constructor() { - super(); +module.exports = class PostUpgradeImport{ + + async AsyncCreate() { + return 'This is a new install -- no import required.'; } - async Create(params, reply) { - await run_import(params, reply); + async AsyncUpdate(ID, params, oldparams) { + await run_import(params); } - async Update(ID, params, oldparams, reply) { - await run_import(params, reply); + async AsyncDelete() { + return 'We are deleting the stack -- no import required.'; } -}; +}; \ No newline at end of file diff --git a/source/lambda/cfn/lib/PreUpgradeExport.js b/source/lambda/cfn/lib/PreUpgradeExport.js index 3e1549caa..1466af231 100644 --- a/source/lambda/cfn/lib/PreUpgradeExport.js +++ b/source/lambda/cfn/lib/PreUpgradeExport.js @@ -17,20 +17,37 @@ const customSdkConfig = require('./util/customSdkConfig'); const region = process.env.AWS_REGION || 'us-east-1'; const s3 = new S3Client(customSdkConfig({ region })); -async function waitForExport(s3params, timeout) { +async function waitForExport(oldS3Params, s3params, timeout) { console.log('Checking the status of export'); const now = Date.now(); const stoptime = now + timeout; let complete = false; let timedout = false; do { - await new Promise((resolve) => setTimeout(resolve, 1000)); - const res = await s3.send(new GetObjectCommand(s3params)); - const readableStream = Buffer.concat(await res.Body.toArray()) - const body = JSON.parse(readableStream); - console.log(body.status); - complete = (body.status == 'Completed'); - timedout = (Date.now() > stoptime); + try { + console.log(JSON.stringify(s3params)); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const res = await s3.send(new GetObjectCommand(s3params)); + const readableStream = Buffer.concat(await res.Body.toArray()) + const body = JSON.parse(readableStream); + console.log(body.status); + complete = (body.status == 'Completed'); + timedout = (Date.now() > stoptime); + } + catch(err){ + // Neccessary for backwards compatibility. + if (err.name === 'AccessDenied') { + console.log('Checking the status of export with outdated configuration.'); + console.log(JSON.stringify(oldS3Params)); + await new Promise((resolve) => setTimeout(resolve, 1000)); + const res = await s3.send(new GetObjectCommand(oldS3Params)); + const readableStream = Buffer.concat(await res.Body.toArray()) + const body = JSON.parse(readableStream); + console.log(body.status); + complete = (body.status == 'Completed'); + timedout = (Date.now() > stoptime); + } + } } while (!complete && !timedout); if (!complete && timedout) { console.log('Timed out.'); @@ -38,18 +55,22 @@ async function waitForExport(s3params, timeout) { return complete; } -async function run_export(params, reply) { - const ID = 'PreUpgradeExport'; +async function run_export(params) { const data = { bucket: params.bucket, index: params.index, id: params.id, - config: `status/${params.id}`, + config: `status-export/${params.id}`, tmp: `tmp/${params.id}`, - key: `data/${params.id}`, + key: `data-export/${params.id}`, filter: '', status: 'Started', }; + const oldS3Params = { + Bucket: data.bucket, + Key: `status/${params.id}`, + Body: JSON.stringify(data), + } const s3params = { Bucket: data.bucket, Key: data.config, @@ -58,30 +79,34 @@ async function run_export(params, reply) { const statusfile = `${data.bucket}/${data.config}`; console.log('Running content export as backup before upgrade.'); // Create object in export bucket to trigger export lambda + await s3.send(new PutObjectCommand(oldS3Params)); await s3.send(new PutObjectCommand(s3params)); console.log('Wait up to 60 seconds for status to be completed'); - delete s3params.Body; - const complete = await waitForExport(s3params, 60000); + delete oldS3Params.Body; + const contentDesignerS3Params = { + Bucket: params.contentDesignerOutputBucket, + Key: data.config + } + const complete = await waitForExport(oldS3Params, contentDesignerS3Params, 60000); if (complete) { console.log('Export completed: ', statusfile); - reply(null, ID); } else { console.log('Export did NOT complete - possibly this is a new install - delete status file so it doesn\'t show up in Exports list in console: ', statusfile); await s3.send(new DeleteObjectCommand(s3params)); - reply(null, ID); } } -module.exports = class PreUpgradeExport extends require('./base') { - constructor() { - super(); +module.exports = class PreUpgradeExport { + + async AsyncCreate() { + return 'This is a new install -- no export required.'; } - async Create(params, reply) { - await run_export(params, reply); + async AsyncUpdate(ID, params, oldparams) { + await run_export(params); } - async Update(ID, params, oldparams, reply) { - await run_export(params, reply); + async AsyncDelete() { + return 'We are deleting the stack -- no export required.'; } }; diff --git a/source/lambda/cfn/package-lock.json b/source/lambda/cfn/package-lock.json index 684d582e4..ed9481e68 100644 --- a/source/lambda/cfn/package-lock.json +++ b/source/lambda/cfn/package-lock.json @@ -1,12 +1,12 @@ { "name": "cfn", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cfn", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-api-gateway": "^3.621.0", @@ -43,19 +43,6 @@ "node": ">=6.0.0" } }, - "node_modules/@aws-crypto/crc32": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", - "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/@aws-crypto/crc32c": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", @@ -79,41 +66,6 @@ "tslib": "^2.6.2" } }, - "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@aws-crypto/sha256-browser": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", @@ -128,41 +80,6 @@ "tslib": "^2.6.2" } }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@aws-crypto/sha256-js": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", @@ -194,41 +111,6 @@ "tslib": "^2.6.2" } }, - "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@aws-sdk/client-api-gateway": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-api-gateway/-/client-api-gateway-3.621.0.tgz", @@ -282,6 +164,41 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/client-cognito-identity": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.621.0.tgz", @@ -384,6 +301,76 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/client-cognito-identity-provider/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity-provider/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity-provider/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/client-iam": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-iam/-/client-iam-3.621.0.tgz", @@ -436,6 +423,41 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/client-iam/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-iam/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-iam/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/client-lambda": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.621.0.tgz", @@ -492,6 +514,41 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/client-lambda/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/client-lex-model-building-service": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-model-building-service/-/client-lex-model-building-service-3.621.0.tgz", @@ -543,6 +600,41 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/client-lex-model-building-service/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-lex-model-building-service/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-lex-model-building-service/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/client-opensearch": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-opensearch/-/client-opensearch-3.621.0.tgz", @@ -594,6 +686,41 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/client-opensearch/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-opensearch/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-opensearch/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/client-s3": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.621.0.tgz", @@ -662,6 +789,58 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-signing": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.620.0.tgz", + "integrity": "sha512-gxI7rubiaanUXaLfJ4NybERa9MGPNg2Ycl/OqANsozrBnR3Pw8vqy3EuVImQOyn2pJ2IFvl8ZPoSMHf4pX56FQ==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/client-sso": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", @@ -762,6 +941,76 @@ "@aws-sdk/client-sts": "^3.621.0" } }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/client-sts": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", @@ -812,6 +1061,41 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/core": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", @@ -1049,6 +1333,54 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/middleware-host-header": { "version": "3.620.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", @@ -1138,17 +1470,35 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/middleware-signing": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.620.0.tgz", - "integrity": "sha512-gxI7rubiaanUXaLfJ4NybERa9MGPNg2Ycl/OqANsozrBnR3Pw8vqy3EuVImQOyn2pJ2IFvl8ZPoSMHf4pX56FQ==", + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", "tslib": "^2.6.2" }, "engines": { @@ -1271,14 +1621,14 @@ } }, "node_modules/@aws-sdk/util-locate-window": { - "version": "3.568.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.568.0.tgz", - "integrity": "sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==", + "version": "3.495.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.495.0.tgz", + "integrity": "sha512-MfaPXT0kLX2tQaR90saBT9fWQq2DHqSSJRzW+MZWsmF+y5LGCOhO22ac/2o6TKSQm7h0HRc2GaADqYYYor62yg==", "dependencies": { - "tslib": "^2.6.2" + "tslib": "^2.5.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=14.0.0" } }, "node_modules/@aws-sdk/util-user-agent-browser": { @@ -2848,15 +3198,15 @@ } }, "node_modules/@smithy/core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", - "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" @@ -2880,17 +3230,6 @@ "node": ">=16.0.0" } }, - "node_modules/@smithy/eventstream-codec": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.2.tgz", - "integrity": "sha512-0mBcu49JWt4MXhrhRAlxASNy0IjDRFU+aWNDRal9OtUJvJNiwDuyKMUONSOjLjSCeGwZaE0wOErdqULer8r7yw==", - "dependencies": { - "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^3.3.0", - "@smithy/util-hex-encoding": "^3.0.0", - "tslib": "^2.6.2" - } - }, "node_modules/@smithy/eventstream-serde-browser": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.5.tgz", @@ -2942,6 +3281,30 @@ "node": ">=16.0.0" } }, + "node_modules/@smithy/eventstream-serde-universal/node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal/node_modules/@smithy/eventstream-codec": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.2.tgz", + "integrity": "sha512-0mBcu49JWt4MXhrhRAlxASNy0IjDRFU+aWNDRal9OtUJvJNiwDuyKMUONSOjLjSCeGwZaE0wOErdqULer8r7yw==", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^3.3.0", + "@smithy/util-hex-encoding": "^3.0.0", + "tslib": "^2.6.2" + } + }, "node_modules/@smithy/fetch-http-handler": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", @@ -2979,6 +3342,41 @@ "node": ">=16.0.0" } }, + "node_modules/@smithy/hash-node/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/hash-node/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/hash-node/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@smithy/hash-stream-node": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-3.1.2.tgz", @@ -2992,6 +3390,41 @@ "node": ">=16.0.0" } }, + "node_modules/@smithy/hash-stream-node/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/hash-stream-node/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/hash-stream-node/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@smithy/invalid-dependency": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", @@ -3002,14 +3435,14 @@ } }, "node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.1.1.tgz", + "integrity": "sha512-xozSQrcUinPpNPNPds4S7z/FakDTh1MZWtRP/2vQtYB/u3HYrX2UXuZs+VhaKBd6Vc7g2XPr2ZtwGBNDN6fNKQ==", "dependencies": { - "tslib": "^2.6.2" + "tslib": "^2.5.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=14.0.0" } }, "node_modules/@smithy/md5-js": { @@ -3022,6 +3455,41 @@ "tslib": "^2.6.2" } }, + "node_modules/@smithy/md5-js/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/md5-js/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/md5-js/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@smithy/middleware-content-length": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.5.tgz", @@ -3053,14 +3521,14 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", - "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", "dependencies": { "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -3214,10 +3682,45 @@ "node": ">=16.0.0" } }, + "node_modules/@smithy/signature-v4/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/signature-v4/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/signature-v4/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -3264,6 +3767,41 @@ "node": ">=16.0.0" } }, + "node_modules/@smithy/util-base64/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-base64/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-base64/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@smithy/util-body-length-browser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", @@ -3284,15 +3822,15 @@ } }, "node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.1.1.tgz", + "integrity": "sha512-clhNjbyfqIv9Md2Mg6FffGVrJxw7bgK7s3Iax36xnfVj6cg0fUG7I4RH0XgXJF8bxi+saY5HR21g2UPKSxVCXg==", "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" + "@smithy/is-array-buffer": "^2.1.1", + "tslib": "^2.5.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=14.0.0" } }, "node_modules/@smithy/util-config-provider": { @@ -3307,12 +3845,12 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", - "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", "dependencies": { "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -3322,15 +3860,15 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", - "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", "dependencies": { "@smithy/config-resolver": "^3.0.5", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, @@ -3405,10 +3943,10 @@ "node": ">=16.0.0" } }, - "node_modules/@smithy/util-uri-escape": { + "node_modules/@smithy/util-stream/node_modules/@smithy/is-array-buffer": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", "dependencies": { "tslib": "^2.6.2" }, @@ -3416,7 +3954,19 @@ "node": ">=16.0.0" } }, - "node_modules/@smithy/util-utf8": { + "node_modules/@smithy/util-stream/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-stream/node_modules/@smithy/util-utf8": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", @@ -3428,6 +3978,29 @@ "node": ">=16.0.0" } }, + "node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.2.0.tgz", + "integrity": "sha512-hBsKr5BqrDrKS8qy+YcV7/htmMGxriA1PREOf/8AGBhHIZnfilVv1Waf1OyKhSbFW15U/8+gcMUQ9/Kk5qwpHQ==", + "dependencies": { + "@smithy/util-buffer-from": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@smithy/util-waiter": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.1.2.tgz", diff --git a/source/lambda/cfn/package.json b/source/lambda/cfn/package.json index dcd43d66b..d4142f03c 100644 --- a/source/lambda/cfn/package.json +++ b/source/lambda/cfn/package.json @@ -1,6 +1,6 @@ { "name": "cfn", - "version": "6.0.3", + "version": "6.1.0", "description": "QnABot Cfn Lambda", "main": "index.js", "scripts": { diff --git a/source/lambda/cfn/test/lib/PostUpgradeImport.test.js b/source/lambda/cfn/test/lib/PostUpgradeImport.test.js index e713212b0..f546e7d45 100644 --- a/source/lambda/cfn/test/lib/PostUpgradeImport.test.js +++ b/source/lambda/cfn/test/lib/PostUpgradeImport.test.js @@ -62,7 +62,7 @@ describe('test PostUpgradeImport class', () => { expect(result).toBe('PostUpgradeImport'); }; - await postUpgradeImportCut.Create(params, callback); + await postUpgradeImportCut.AsyncCreate(params, callback); }); it("should be equivalent to Create when Update is called", async () => { @@ -90,7 +90,7 @@ describe('test PostUpgradeImport class', () => { expect(result).toBe('PostUpgradeImport'); }; - await postUpgradeImportCut.Update('mock_id', params, {}, callback); + await postUpgradeImportCut.AsyncUpdate('mock_id', params, {}, callback); }); it("should catch error and passthrough when s3 error occurs in Create", async () => { @@ -108,6 +108,6 @@ describe('test PostUpgradeImport class', () => { expect(result).toBe('PostUpgradeImport'); }; - await postUpgradeImportCut.Create(params, callback); + await postUpgradeImportCut.AsyncCreate(params, callback); }); }); \ No newline at end of file diff --git a/source/lambda/cfn/test/lib/PreUpgradeExport.test.js b/source/lambda/cfn/test/lib/PreUpgradeExport.test.js index eef001b9f..3b549f747 100644 --- a/source/lambda/cfn/test/lib/PreUpgradeExport.test.js +++ b/source/lambda/cfn/test/lib/PreUpgradeExport.test.js @@ -57,7 +57,7 @@ describe('test PreUpgradeExport class', () => { expect(result).toBe('PreUpgradeExport'); }; - await preUpgradeExportCut.Create(params, callback); + await preUpgradeExportCut.AsyncCreate(params, callback); }); it("should be equivalent to Create when Update is called", async () => { @@ -78,6 +78,6 @@ describe('test PreUpgradeExport class', () => { expect(result).toBe('PreUpgradeExport'); }; - await preUpgradeExportCut.Update('mock_id', params, {}, callback); + await preUpgradeExportCut.AsyncUpdate('mock_id', params, {}, callback); }); }); \ No newline at end of file diff --git a/source/lambda/common-modules-layer/package-lock.json b/source/lambda/common-modules-layer/package-lock.json index 68fa77bb4..1aa5321b3 100644 --- a/source/lambda/common-modules-layer/package-lock.json +++ b/source/lambda/common-modules-layer/package-lock.json @@ -1,12 +1,12 @@ { "name": "common-modules-layer", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "common-modules-layer", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "@aws-sdk/credential-providers": "^3.511.0", @@ -132,16 +132,16 @@ } }, "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.622.0.tgz", - "integrity": "sha512-VE4Mi6HMrs0Fpq8Nhgt3wBm5i7SyfTYD+FFW+Ofq1zMRWWePPqbs9HMSp6mLwynWL0SNcefYoIKqz2H/2e4mwQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.621.0.tgz", + "integrity": "sha512-FpXia5qFf6ijcNDWenVq+mP9r1LbiW/+52i9wrv2+Afi6Nn1ROf8W7St8WvE9TEZ3t78y+vis4CwqfGts+uiKA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -152,26 +152,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -183,13 +183,13 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.622.0.tgz", - "integrity": "sha512-DJwUqVR/O2lImbktUHOpaQ8XElNBx3JmWzTT2USg6jh3ErgG1CS6LIV+VUlgtxGl+tFN/G6AcAV8SdnnGydB8Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", + "@aws-sdk/core": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -200,26 +200,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -231,14 +231,14 @@ } }, "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.622.0.tgz", - "integrity": "sha512-dwWDfN+S98npeY77Ugyv8VIHKRHN+n/70PWE4EgolcjaMrTINjvUh9a/SypFEs5JmBOAeCQt8S2QpM3Wvzp+pQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -249,26 +249,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -279,19 +279,19 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/client-sts": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.622.0.tgz", - "integrity": "sha512-Yqtdf/wn3lcFVS42tR+zbz4HLyWxSmztjVW9L/yeMlvS7uza5nSkWqP/7ca+RxZnXLyrnA4jJtSHqykcErlhyg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -302,26 +302,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -333,15 +333,15 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.622.0.tgz", - "integrity": "sha512-q1Ct2AjPxGtQBKtDpqm1umu3f4cuWMnEHTuDa6zjjaj+Aq/C6yxLgZJo9SlcU0tMl8rUCN7oFonszfTtp4Y0MA==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", "dependencies": { - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "fast-xml-parser": "4.4.1", @@ -352,11 +352,11 @@ } }, "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.622.0.tgz", - "integrity": "sha512-WXfTA1Q1bntE/KgoW+Vo2L2hgwr9YCHrfXgZLGQzCZwKQpW9iMWMxylSdn0NAHldN3fwiV/Oj6DqN0Tc8ScgNQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.621.0.tgz", + "integrity": "sha512-Q+3awvTVJSqIGRjCUQflRwKPKlZ0TfmL3EQHgFLhZZrToeBapEA62+FY+T70aTKAZZZZprlvYeFPtBloNd5ziA==", "dependencies": { - "@aws-sdk/client-cognito-identity": "3.622.0", + "@aws-sdk/client-cognito-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", "@smithy/types": "^3.3.0", @@ -381,16 +381,16 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.622.0.tgz", - "integrity": "sha512-VUHbr24Oll1RK3WR8XLUugLpgK9ZuxEm/NVeVqyFts1Ck9gsKpRg1x4eH7L7tW3SJ4TDEQNMbD7/7J+eoL2svg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/property-provider": "^3.1.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" @@ -400,14 +400,14 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.622.0.tgz", - "integrity": "sha512-cD/6O9jOfzQyo8oyAbTKnyRO89BIMSTzwaN4NxGySC6pYVTqxNSWdRwaqg/vKbwJpjbPGGYYXpXEW11kop7dlg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -420,19 +420,19 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.622.0.tgz", - "integrity": "sha512-keldwz4Q/6TYc37JH6m43HumN7Vi+R0AuGuHn5tBV40Vi7IiqEzjpiE+yvsHIN+duUheFLL3j/o0H32jb+14DQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -461,11 +461,11 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.622.0.tgz", - "integrity": "sha512-zrSoBVM2JlwvkBtrcUd4J/9CrG+T+hUy9r6jwo5gonFIN3QkneR/pqpbUn/n32Zy3zlzCo2VfB31g7MjG7kJmg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", "dependencies": { - "@aws-sdk/client-sso": "3.622.0", + "@aws-sdk/client-sso": "3.621.0", "@aws-sdk/token-providers": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", @@ -495,20 +495,20 @@ } }, "node_modules/@aws-sdk/credential-providers": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.622.0.tgz", - "integrity": "sha512-ImfpItaPwnwNBRG04x6iDwRAclvtW2+kSu4amGiMWF+EvnjnRTnyejAA/7rdBuxA4nwM4nb8jed0jnRkZyTu7A==", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.622.0", - "@aws-sdk/client-sso": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/credential-provider-cognito-identity": "3.622.0", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.621.0.tgz", + "integrity": "sha512-FQbC7I8ae/72ZekLBa45jWJ+Q3d+YPhc3bW/rCks6RrldM6RgLTGr8pTOPCxHl828ky10RjkBiBmVU818rliyw==", + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.621.0", + "@aws-sdk/client-sso": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/credential-provider-cognito-identity": "3.621.0", "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -724,15 +724,15 @@ } }, "node_modules/@smithy/core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", - "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" @@ -833,14 +833,14 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", - "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", "dependencies": { "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -995,9 +995,9 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -1087,12 +1087,12 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", - "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", "dependencies": { "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -1102,15 +1102,15 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", - "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", "dependencies": { "@smithy/config-resolver": "^3.0.5", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, @@ -1467,16 +1467,16 @@ } }, "@aws-sdk/client-cognito-identity": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.622.0.tgz", - "integrity": "sha512-VE4Mi6HMrs0Fpq8Nhgt3wBm5i7SyfTYD+FFW+Ofq1zMRWWePPqbs9HMSp6mLwynWL0SNcefYoIKqz2H/2e4mwQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.621.0.tgz", + "integrity": "sha512-FpXia5qFf6ijcNDWenVq+mP9r1LbiW/+52i9wrv2+Afi6Nn1ROf8W7St8WvE9TEZ3t78y+vis4CwqfGts+uiKA==", "requires": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -1487,26 +1487,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1515,13 +1515,13 @@ } }, "@aws-sdk/client-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.622.0.tgz", - "integrity": "sha512-DJwUqVR/O2lImbktUHOpaQ8XElNBx3JmWzTT2USg6jh3ErgG1CS6LIV+VUlgtxGl+tFN/G6AcAV8SdnnGydB8Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", "requires": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", + "@aws-sdk/core": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -1532,26 +1532,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1560,14 +1560,14 @@ } }, "@aws-sdk/client-sso-oidc": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.622.0.tgz", - "integrity": "sha512-dwWDfN+S98npeY77Ugyv8VIHKRHN+n/70PWE4EgolcjaMrTINjvUh9a/SypFEs5JmBOAeCQt8S2QpM3Wvzp+pQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", "requires": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -1578,26 +1578,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1606,15 +1606,15 @@ } }, "@aws-sdk/client-sts": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.622.0.tgz", - "integrity": "sha512-Yqtdf/wn3lcFVS42tR+zbz4HLyWxSmztjVW9L/yeMlvS7uza5nSkWqP/7ca+RxZnXLyrnA4jJtSHqykcErlhyg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", "requires": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -1625,26 +1625,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1653,15 +1653,15 @@ } }, "@aws-sdk/core": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.622.0.tgz", - "integrity": "sha512-q1Ct2AjPxGtQBKtDpqm1umu3f4cuWMnEHTuDa6zjjaj+Aq/C6yxLgZJo9SlcU0tMl8rUCN7oFonszfTtp4Y0MA==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", "requires": { - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "fast-xml-parser": "4.4.1", @@ -1669,11 +1669,11 @@ } }, "@aws-sdk/credential-provider-cognito-identity": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.622.0.tgz", - "integrity": "sha512-WXfTA1Q1bntE/KgoW+Vo2L2hgwr9YCHrfXgZLGQzCZwKQpW9iMWMxylSdn0NAHldN3fwiV/Oj6DqN0Tc8ScgNQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.621.0.tgz", + "integrity": "sha512-Q+3awvTVJSqIGRjCUQflRwKPKlZ0TfmL3EQHgFLhZZrToeBapEA62+FY+T70aTKAZZZZprlvYeFPtBloNd5ziA==", "requires": { - "@aws-sdk/client-cognito-identity": "3.622.0", + "@aws-sdk/client-cognito-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", "@smithy/types": "^3.3.0", @@ -1692,30 +1692,30 @@ } }, "@aws-sdk/credential-provider-http": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.622.0.tgz", - "integrity": "sha512-VUHbr24Oll1RK3WR8XLUugLpgK9ZuxEm/NVeVqyFts1Ck9gsKpRg1x4eH7L7tW3SJ4TDEQNMbD7/7J+eoL2svg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", "requires": { "@aws-sdk/types": "3.609.0", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/property-provider": "^3.1.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" } }, "@aws-sdk/credential-provider-ini": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.622.0.tgz", - "integrity": "sha512-cD/6O9jOfzQyo8oyAbTKnyRO89BIMSTzwaN4NxGySC6pYVTqxNSWdRwaqg/vKbwJpjbPGGYYXpXEW11kop7dlg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", "requires": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -1726,15 +1726,15 @@ } }, "@aws-sdk/credential-provider-node": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.622.0.tgz", - "integrity": "sha512-keldwz4Q/6TYc37JH6m43HumN7Vi+R0AuGuHn5tBV40Vi7IiqEzjpiE+yvsHIN+duUheFLL3j/o0H32jb+14DQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", "requires": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -1757,11 +1757,11 @@ } }, "@aws-sdk/credential-provider-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.622.0.tgz", - "integrity": "sha512-zrSoBVM2JlwvkBtrcUd4J/9CrG+T+hUy9r6jwo5gonFIN3QkneR/pqpbUn/n32Zy3zlzCo2VfB31g7MjG7kJmg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", "requires": { - "@aws-sdk/client-sso": "3.622.0", + "@aws-sdk/client-sso": "3.621.0", "@aws-sdk/token-providers": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", @@ -1782,20 +1782,20 @@ } }, "@aws-sdk/credential-providers": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.622.0.tgz", - "integrity": "sha512-ImfpItaPwnwNBRG04x6iDwRAclvtW2+kSu4amGiMWF+EvnjnRTnyejAA/7rdBuxA4nwM4nb8jed0jnRkZyTu7A==", - "requires": { - "@aws-sdk/client-cognito-identity": "3.622.0", - "@aws-sdk/client-sso": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/credential-provider-cognito-identity": "3.622.0", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.621.0.tgz", + "integrity": "sha512-FQbC7I8ae/72ZekLBa45jWJ+Q3d+YPhc3bW/rCks6RrldM6RgLTGr8pTOPCxHl828ky10RjkBiBmVU818rliyw==", + "requires": { + "@aws-sdk/client-cognito-identity": "3.621.0", + "@aws-sdk/client-sso": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/credential-provider-cognito-identity": "3.621.0", "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -1957,15 +1957,15 @@ } }, "@smithy/core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", - "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", "requires": { "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" @@ -2048,14 +2048,14 @@ } }, "@smithy/middleware-retry": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", - "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", "requires": { "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -2174,9 +2174,9 @@ } }, "@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "requires": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -2248,27 +2248,27 @@ } }, "@smithy/util-defaults-mode-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", - "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", "requires": { "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "@smithy/util-defaults-mode-node": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", - "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", "requires": { "@smithy/config-resolver": "^3.0.5", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" } diff --git a/source/lambda/common-modules-layer/package.json b/source/lambda/common-modules-layer/package.json index 21884e1e0..006bb9913 100644 --- a/source/lambda/common-modules-layer/package.json +++ b/source/lambda/common-modules-layer/package.json @@ -1,6 +1,6 @@ { "name": "common-modules-layer", - "version": "6.0.3", + "version": "6.1.0", "description": "QnABot Common-modules-layer lambda", "main": "index.js", "scripts": { diff --git a/source/lambda/connect/package-lock.json b/source/lambda/connect/package-lock.json index ba39affde..6cecd525f 100644 --- a/source/lambda/connect/package-lock.json +++ b/source/lambda/connect/package-lock.json @@ -1,12 +1,12 @@ { "name": "connect", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "connect", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "devDependencies": { "jest": "^29.7.0" diff --git a/source/lambda/connect/package.json b/source/lambda/connect/package.json index 001952ac0..e517d0765 100644 --- a/source/lambda/connect/package.json +++ b/source/lambda/connect/package.json @@ -1,6 +1,6 @@ { "name": "connect", - "version": "6.0.3", + "version": "6.1.0", "description": "Lambda function used to support the Connect setup wizard", "repository": { "type": "git", diff --git a/source/lambda/es-proxy-layer/lib/bedrock/AmazonLlm.js b/source/lambda/es-proxy-layer/lib/bedrock/AmazonLlm.js index e7ee76b77..22e587a8c 100644 --- a/source/lambda/es-proxy-layer/lib/bedrock/AmazonLlm.js +++ b/source/lambda/es-proxy-layer/lib/bedrock/AmazonLlm.js @@ -19,7 +19,7 @@ class AmazonLlm extends BedrockModelProviderPrototype { super(); this.body = _.cloneDeep({ textGenerationConfig: { - maxTokenCount: 4096, + maxTokenCount: 256, stopSequences: [], temperature: 0, topP: 1, diff --git a/source/lambda/es-proxy-layer/lib/bedrock/BedrockModelProviderPrototype.js b/source/lambda/es-proxy-layer/lib/bedrock/BedrockModelProviderPrototype.js index e7b622100..11b40283d 100644 --- a/source/lambda/es-proxy-layer/lib/bedrock/BedrockModelProviderPrototype.js +++ b/source/lambda/es-proxy-layer/lib/bedrock/BedrockModelProviderPrototype.js @@ -32,7 +32,12 @@ class BedrockModelProviderPrototype { parseResponseBody(response) { try { - return JSON.parse(Buffer.from(response.body, 'utf-8').toString()); + const parsedBody = JSON.parse(Buffer.from(response.body, 'utf-8').toString()); + const guardRailAction = parsedBody['amazon-bedrock-guardrailAction']; + if (guardRailAction) { + qnabot.log(`Guardrail Action in Bedrock LLM Response: ${guardRailAction}`) + }; + return parsedBody; } catch (e) { qnabot.warn('EXCEPTION:', e.stack); throw new Error(`Exception parsing response body: ${e.message}`); diff --git a/source/lambda/es-proxy-layer/lib/bedrock/bedrockAgents.js b/source/lambda/es-proxy-layer/lib/bedrock/bedrockAgents.js index ddc500714..f6adefd0f 100644 --- a/source/lambda/es-proxy-layer/lib/bedrock/bedrockAgents.js +++ b/source/lambda/es-proxy-layer/lib/bedrock/bedrockAgents.js @@ -12,14 +12,17 @@ * and limitations under the License. * *********************************************************************************************************************/ -const { BedrockAgentRuntimeClient, RetrieveAndGenerateCommand } = require("@aws-sdk/client-bedrock-agent-runtime"); +const { BedrockAgentRuntimeClient, RetrieveAndGenerateCommand } = require('@aws-sdk/client-bedrock-agent-runtime'); const customSdkConfig = require('sdk-config/customSdkConfig'); const { signUrls } = require('../signS3URL'); const llm = require('../llm'); const qnabot = require('qnabot/logging'); const _ = require('lodash'); +const { sanitize, escapeHashMarkdown } = require('../sanitizeOutput'); const region = process.env.AWS_REGION || 'us-east-1'; +const inferenceKeys = ['maxTokens', 'stopSequences', 'temperature', 'topP']; +const client = new BedrockAgentRuntimeClient(customSdkConfig('C41', { region })); function isNoHitsResponse(req, response) { const { text } = response.output; @@ -27,9 +30,12 @@ function isNoHitsResponse(req, response) { return !retrievedReferences && llm.isNoHits(req, text); } -async function generateResponse(client, input, res) { +async function generateResponse(input, res) { + qnabot.log(`Bedrock Knowledge Base Input: ${JSON.stringify(input, null, 2)}`); + const response = await client.send(new RetrieveAndGenerateCommand(input)); - const sessionId = response.sessionId; + + const sessionId = response.sessionId; if (res._userInfo.knowledgeBaseSessionId !== sessionId) { qnabot.debug(`Saving sessionId: ${sessionId}`); res._userInfo.knowledgeBaseSessionId = sessionId; @@ -53,9 +59,9 @@ async function createHit(req, response) { const KNOWLEDGE_BASE_S3_SIGNED_URL_EXPIRE_SECS = _.get(req._settings, 'KNOWLEDGE_BASE_S3_SIGNED_URL_EXPIRE_SECS', 300); const KNOWLEDGE_BASE_S3_SIGNED_URLS = _.get(req._settings, 'KNOWLEDGE_BASE_S3_SIGNED_URLS', true); const KNOWLEDGE_BASE_SHOW_REFERENCES = _.get(req._settings, 'KNOWLEDGE_BASE_SHOW_REFERENCES'); - const KNOWLEDGE_BASE_PREFIX_MESSAGE = _.get(req._settings, 'KNOWLEDGE_BASE_PREFIX_MESSAGE'); + const KNOWLEDGE_BASE_PREFIX_MESSAGE = _.get(req._settings, 'KNOWLEDGE_BASE_PREFIX_MESSAGE'); const helpfulLinksMsg = 'Source Link'; - const generatedText = response.output.text; + const generatedText = sanitize(response.output.text); let plainText = generatedText; let markdown = generatedText; const ssml = ` ${generatedText} `; @@ -76,8 +82,9 @@ async function createHit(req, response) { markdownCitations += '***'; markdownCitations += '\n\n
'; if (reference.content.text) { - markdownCitations += `\n\n ${reference.content.text}`; - plainTextCitations += `\n\n ${reference.content.text}`; + const text = escapeHashMarkdown(reference.content.text); + markdownCitations += `\n\n ${text}`; + plainTextCitations += `\n\n ${text}`; } if (reference.location.type === 'S3') { @@ -119,20 +126,62 @@ async function createHit(req, response) { return hit; } -async function bedrockRetrieveAndGenerate(req, res) { +function processRequest(req) { const { KNOWLEDGE_BASE_ID, KNOWLEDGE_BASE_MODEL_ID, KNOWLEDGE_BASE_KMS, + KNOWLEDGE_BASE_PROMPT_TEMPLATE, + KNOWLEDGE_BASE_MAX_NUMBER_OF_RETRIEVED_RESULTS, + KNOWLEDGE_BASE_SEARCH_TYPE, + KNOWLEDGE_BASE_METADATA_FILTERS, + KNOWLEDGE_BASE_MODEL_PARAMS, + BEDROCK_GUARDRAIL_IDENTIFIER, + BEDROCK_GUARDRAIL_VERSION, } = req._settings; - - const client = new BedrockAgentRuntimeClient(customSdkConfig('C41', { region })); + + const modelArn = `arn:aws:bedrock:${region}::foundation-model/${KNOWLEDGE_BASE_MODEL_ID}`; let { question } = req; - question = question.slice(0, 1000) + question = question.slice(0, 1000); // No more than 1000 characters - for bedrock query compatibility + + const sessionConfiguration = KNOWLEDGE_BASE_KMS ? { kmsKeyArn: KNOWLEDGE_BASE_KMS } : undefined; + const promptTemplate = KNOWLEDGE_BASE_PROMPT_TEMPLATE.trim() ? { textPromptTemplate: KNOWLEDGE_BASE_PROMPT_TEMPLATE } : undefined; + const guardrailId = BEDROCK_GUARDRAIL_IDENTIFIER.trim(); + const guardrailVersion = BEDROCK_GUARDRAIL_VERSION.toString(); - let retrieveAndGenerateInput, retrieveAndGenerateSessionInput, response; + const vectorSearchConfigurationProps = { + ...(KNOWLEDGE_BASE_MAX_NUMBER_OF_RETRIEVED_RESULTS !== '' && { numberOfResults: KNOWLEDGE_BASE_MAX_NUMBER_OF_RETRIEVED_RESULTS }), + ...(KNOWLEDGE_BASE_SEARCH_TYPE !== 'DEFAULT' && { overrideSearchType: KNOWLEDGE_BASE_SEARCH_TYPE }), + ...(KNOWLEDGE_BASE_METADATA_FILTERS !== '{}' && { filter: JSON.parse(KNOWLEDGE_BASE_METADATA_FILTERS) }) + }; + + const modelParams = JSON.parse(KNOWLEDGE_BASE_MODEL_PARAMS); + const textInferenceConfig = _.pick(modelParams, inferenceKeys); + const additionalModelRequestFields = _.omit(modelParams, inferenceKeys); + + const generationConfiguration = {}; + + if (promptTemplate) { + generationConfiguration.promptTemplate = promptTemplate; + } - retrieveAndGenerateInput = { + if (Object.keys(textInferenceConfig).length !== 0) { + generationConfiguration.inferenceConfig = { textInferenceConfig }; + } + + if (Object.keys(additionalModelRequestFields).length !== 0) { + generationConfiguration.additionalModelRequestFields = additionalModelRequestFields; + } + + if (guardrailId && guardrailVersion) { + generationConfiguration.guardrailConfiguration = { guardrailId, guardrailVersion }; + } + + const retrievalConfiguration = { + ...(Object.keys(vectorSearchConfigurationProps).length > 0 && { vectorSearchConfiguration: vectorSearchConfigurationProps }) + } + + const retrieveAndGenerateInput = { input: { text: question, }, @@ -140,46 +189,66 @@ async function bedrockRetrieveAndGenerate(req, res) { type: 'KNOWLEDGE_BASE', knowledgeBaseConfiguration: { knowledgeBaseId: KNOWLEDGE_BASE_ID, - modelArn: `arn:aws:bedrock:${region}::foundation-model/${KNOWLEDGE_BASE_MODEL_ID}`, + modelArn, + ...(Object.keys(retrievalConfiguration).length > 0 && { retrievalConfiguration }), + ...(Object.keys(generationConfiguration).length > 0 && { generationConfiguration }), }, }, + ...(sessionConfiguration && { sessionConfiguration }) }; - if (KNOWLEDGE_BASE_KMS) { - retrieveAndGenerateInput.sessionConfiguration = { - kmsKeyArn: KNOWLEDGE_BASE_KMS, - }; - } - qnabot.log(`Bedrock Knowledge Base Id: ${KNOWLEDGE_BASE_ID} and Model Id: ${KNOWLEDGE_BASE_MODEL_ID}`); + qnabot.log(`Using Bedrock Knowledge Base Id: ${KNOWLEDGE_BASE_ID} and Model Id: ${KNOWLEDGE_BASE_MODEL_ID}`); + return retrieveAndGenerateInput; +} + +async function bedrockRetrieveAndGenerate(req, res) { + let response, retrieveAndGenerateSessionInput; + let retrieveAndGenerateInput = processRequest(req); + let retries = 0; + try { const sessionId = res._userInfo.knowledgeBaseSessionId; qnabot.log(`Bedrock Knowledge Base SessionId: ${sessionId}`); if (sessionId) { retrieveAndGenerateSessionInput = { ...retrieveAndGenerateInput, - sessionId, + sessionId }; - response = await generateResponse(client, retrieveAndGenerateSessionInput, res); + response = await generateResponse(retrieveAndGenerateSessionInput, res); } else { - response = await generateResponse(client, retrieveAndGenerateInput, res); - }; + response = await generateResponse(retrieveAndGenerateInput, res); + } } catch (e) { - if (e.name === 'ValidationException' || e.name === 'ConflictException') { - response = await generateResponse(client, retrieveAndGenerateInput, res); + if (retries < 3 && (e.name === 'ValidationException' || e.name === 'ConflictException')) { + retries += 1; + qnabot.log(`Retrying to due ${e.name}...tries left ${3 - retries}`) + response = await generateResponse(retrieveAndGenerateInput, res); } else { - qnabot.log(`Bedrock Knowledge Base ${e.name}: ${e.message.substring(0, 500)}`) + qnabot.log(`Bedrock Knowledge Base ${e.name}: ${e.message.substring(0, 500)}`); throw e; - } - } - qnabot.debug(`Response from bedrock knowledge base: ${JSON.stringify(response)}`); + }; + }; + + qnabot.log(`Bedrock Knowledge Base Response: ${JSON.stringify(response)}`); + + const guardrailAction = response.guardrailAction; + if (guardrailAction) { + qnabot.log(`Guardrail Action in Bedrock Knowledge Base Response: ${guardrailAction}`); + }; if (isNoHitsResponse(req, response)) { qnabot.log('No hits from knowledge base.'); return [res, undefined]; - } + }; const hit = await createHit(req, response); + + // we got a hit, let's update the session parameters + _.set(res, 'session.qnabot_gotanswer', true); + res.got_hits = 1; + return [res, hit]; } -exports.bedrockRetrieveAndGenerate = bedrockRetrieveAndGenerate; + +exports.bedrockRetrieveAndGenerate = bedrockRetrieveAndGenerate; \ No newline at end of file diff --git a/source/lambda/es-proxy-layer/lib/bedrock/bedrockClient.js b/source/lambda/es-proxy-layer/lib/bedrock/bedrockClient.js index b9bb64567..233d7b227 100644 --- a/source/lambda/es-proxy-layer/lib/bedrock/bedrockClient.js +++ b/source/lambda/es-proxy-layer/lib/bedrock/bedrockClient.js @@ -31,13 +31,15 @@ const capabilityMapping = { 'cohere.embed-english-v3': 'C038', 'cohere.embed-multilingual-v3': 'C039', 'meta.llama3-8b-instruct-v1': 'C041', + 'amazon.titan-text-premier-v1': 'C042', + 'amazon.titan-embed-text-v2': 'C043', }; function isEmbedding(modelId) { return modelId.includes('embed'); }; -async function bedrockClient(modelId, body) { +async function bedrockClient(modelId, body, guardrails) { const invokeModelParams = { body, contentType: 'application/json', @@ -47,11 +49,16 @@ async function bedrockClient(modelId, body) { let llm_result; const configCode = capabilityMapping[modelId] || isEmbedding(modelId) ? 'C040' : 'C036'; const client = new BedrockRuntimeClient(customSdkConfig(configCode, { region })); + + if (!isEmbedding(modelId) && guardrails.guardrailIdentifier !== '' && guardrails.guardrailVersion !== '') { + invokeModelParams.guardrailIdentifier = guardrails.guardrailIdentifier; + invokeModelParams.guardrailVersion = guardrails.guardrailVersion; + }; + qnabot.log('Bedrock Invoke Model Params: ', invokeModelParams); try { const command = new InvokeModelCommand(invokeModelParams); llm_result = await client.send(command); - qnabot.debug('Bedrock Invoke Model Response: ', llm_result); return llm_result; } catch (e) { let message = `Bedrock ${modelId} returned ${e.name}: ${e.message.substring(0, 500)}`; diff --git a/source/lambda/es-proxy-layer/lib/bedrock/bedrockModels.js b/source/lambda/es-proxy-layer/lib/bedrock/bedrockModels.js index bf23928cf..f8bc8dae2 100644 --- a/source/lambda/es-proxy-layer/lib/bedrock/bedrockModels.js +++ b/source/lambda/es-proxy-layer/lib/bedrock/bedrockModels.js @@ -48,14 +48,14 @@ function getProviderClass(modelId) { } } -async function invokeBedrockModel(modelId, parameters, prompt) { +async function invokeBedrockModel(modelId, parameters, prompt, guardrails) { const modelProvider = getProviderClass(modelId); modelProvider.setParameters(parameters); modelProvider.setPrompt(prompt); const body = modelProvider.getParameters(); - qnabot.log('Bedrock Invoke model body:', body); + qnabot.debug(`Bedrock Invoke model body: ${body}`); - const response = await bedrockClient(modelId, body); + const response = await bedrockClient(modelId, body, guardrails); const generatedText = modelProvider.getResponseBody(response); return generatedText; } diff --git a/source/lambda/es-proxy-layer/lib/embeddings.js b/source/lambda/es-proxy-layer/lib/embeddings.js index bf746b07a..770eabd67 100644 --- a/source/lambda/es-proxy-layer/lib/embeddings.js +++ b/source/lambda/es-proxy-layer/lib/embeddings.js @@ -70,7 +70,9 @@ async function getEmbeddingsBedrock(type_q_or_a, input, settings) { inputText = truncateByNumTokens(inputText, settings.EMBEDDINGS_MAX_TOKEN_LIMIT); } - return await invokeBedrockModel(modelId, {}, inputText); + const embeddings = await invokeBedrockModel(modelId, {}, inputText, {}); + qnabot.debug(`Bedrock Embeddings Response: ${embeddings}`); + return embeddings; }; module.exports = async function (type_q_or_a, input, settings) { diff --git a/source/lambda/es-proxy-layer/lib/fulfillment-event/getHit.js b/source/lambda/es-proxy-layer/lib/fulfillment-event/getHit.js index e65f670d6..8b6a5ea05 100644 --- a/source/lambda/es-proxy-layer/lib/fulfillment-event/getHit.js +++ b/source/lambda/es-proxy-layer/lib/fulfillment-event/getHit.js @@ -253,8 +253,8 @@ async function useFallbackMethod(req, res, query_params) { try { [res, hit] = await bedrockRetrieveAndGenerate(req, res); } catch (e) { - qnabot.log('BEDROCK AGENT EXCEPTION:', e); - const errMsg = `Bedrock Agent exception: ${e.message.substring(0, 500)}`; + qnabot.log(`BEDROCK KNOWLEDGEBASE EXCEPTION: ${e.name} ${e.message.substring(0, 500)}`); + const errMsg = `Bedrock Knowledgebase exception: ${e.name} ${e.message.substring(0, 500)}`; if (!errors.includes(errMsg)) { errors.push(errMsg); }; diff --git a/source/lambda/es-proxy-layer/lib/llm.js b/source/lambda/es-proxy-layer/lib/llm.js index 2d710a0a5..52ceae1e0 100644 --- a/source/lambda/es-proxy-layer/lib/llm.js +++ b/source/lambda/es-proxy-layer/lib/llm.js @@ -147,10 +147,18 @@ async function invoke_lambda(prompt, model_params, settings) { async function invoke_bedrock(prompt, model_params, settings) { const modelId = settings.LLM_MODEL_ID; - const response = await invokeBedrockModel(modelId, model_params, prompt); - qnabot.debug(`Bedrock LLM response: ${response}`); + const guardrails = {}; + const guardrailIdentifier = settings.BEDROCK_GUARDRAIL_IDENTIFIER.trim(); + const guardrailVersion = settings.BEDROCK_GUARDRAIL_VERSION.toString(); + + if (guardrailIdentifier !== '' && guardrailVersion !== '') { + guardrails.guardrailIdentifier = guardrailIdentifier; + guardrails.guardrailVersion = guardrailVersion; + }; + const response = await invokeBedrockModel(modelId, model_params, prompt, guardrails); + qnabot.log(`Bedrock Invoke LLM Response: ${response}`); return sanitize(response); -} +}; function clean_standalone_query(query) { let clean_query = query; diff --git a/source/lambda/es-proxy-layer/lib/sanitizeOutput.js b/source/lambda/es-proxy-layer/lib/sanitizeOutput.js index 408862498..c881b5f73 100644 --- a/source/lambda/es-proxy-layer/lib/sanitizeOutput.js +++ b/source/lambda/es-proxy-layer/lib/sanitizeOutput.js @@ -22,4 +22,17 @@ function sanitize(data) { const sanitizedData = sanitizeHtml(data, sanitizeParams); return sanitizedData; } + +// Escapes hash if the input text starts with one or more hashes followed by a space. +function escapeHashMarkdown(text) { + + const match = /^(#+)/; // Matches one ore more hashes at the start of the text + + if(match.test(text)){ // If it matches the escape first hash symbol + text = text.replace(/^#/, '\\#') + }; + return text; +} + +exports.escapeHashMarkdown = escapeHashMarkdown; exports.sanitize = sanitize; diff --git a/source/lambda/es-proxy-layer/package-lock.json b/source/lambda/es-proxy-layer/package-lock.json index 4571d861b..7b81f54a4 100644 --- a/source/lambda/es-proxy-layer/package-lock.json +++ b/source/lambda/es-proxy-layer/package-lock.json @@ -1,22 +1,24 @@ { "name": "proxy-es", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "proxy-es", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/client-bedrock-agent-runtime": "^3.616.0", + "@aws-sdk/client-bedrock-runtime": "^3.616.0", "@aws-sdk/client-firehose": "^3.511.0", "@aws-sdk/client-sagemaker-runtime": "^3.511.0", "@aws-sdk/s3-request-presigner": "^3.511.0", "@dqbd/tiktoken": "^1.0.7", "aws4": "^1.6.0", - "axios": "^1.6.8", + "axios": "^1.7.4", "bodybuilder": "^2.5.1", - "handlebars": "^4.7.2", + "handlebars": "^4.7.8", "langchain": "^0.0.209", "linkifyjs": "^3.0.0-beta.3", "sanitize-html": "^2.13.0", @@ -200,487 +202,2335 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "node_modules/@aws-sdk/client-bedrock-runtime": { - "version": "3.474.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.474.0.tgz", - "integrity": "sha512-1Ih/iG9KnDugX5tPPDVC8pzBzisEImWx5InaTS+B8uBF7NuFjxX2p1MKYJCEVpj+JYsRcND/PFIiQWeJ8UZeig==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-agent-runtime/-/client-bedrock-agent-runtime-3.616.0.tgz", + "integrity": "sha512-LmKgpTNNqJ0ClfDL1ZmssxiADS3hoznc4Tidh+M7SUJKmsd/iyPlyhu0Lwluw0k4wnPGqoDFwDWzjAzdxeCidw==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.616.0", + "@aws-sdk/client-sts": "3.616.0", + "@aws-sdk/core": "3.616.0", + "@aws-sdk/credential-provider-node": "3.616.0", + "@aws-sdk/middleware-host-header": "3.616.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.616.0", + "@aws-sdk/middleware-user-agent": "3.616.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.2.7", + "@smithy/eventstream-serde-browser": "^3.0.4", + "@smithy/eventstream-serde-config-resolver": "^3.0.3", + "@smithy/eventstream-serde-node": "^3.0.4", + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.4", + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-retry": "^3.0.10", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.8", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.10", + "@smithy/util-defaults-mode-node": "^3.0.10", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.474.0", - "@aws-sdk/core": "3.474.0", - "@aws-sdk/credential-provider-node": "3.474.0", - "@aws-sdk/middleware-host-header": "3.468.0", - "@aws-sdk/middleware-logger": "3.468.0", - "@aws-sdk/middleware-recursion-detection": "3.468.0", - "@aws-sdk/middleware-signing": "3.468.0", - "@aws-sdk/middleware-user-agent": "3.470.0", - "@aws-sdk/region-config-resolver": "3.470.0", - "@aws-sdk/types": "3.468.0", - "@aws-sdk/util-endpoints": "3.470.0", - "@aws-sdk/util-user-agent-browser": "3.468.0", - "@aws-sdk/util-user-agent-node": "3.470.0", - "@smithy/config-resolver": "^2.0.21", - "@smithy/eventstream-serde-browser": "^2.0.15", - "@smithy/eventstream-serde-config-resolver": "^2.0.15", - "@smithy/eventstream-serde-node": "^2.0.15", - "@smithy/fetch-http-handler": "^2.3.1", - "@smithy/hash-node": "^2.0.17", - "@smithy/invalid-dependency": "^2.0.15", - "@smithy/middleware-content-length": "^2.0.17", - "@smithy/middleware-endpoint": "^2.2.3", - "@smithy/middleware-retry": "^2.0.24", - "@smithy/middleware-serde": "^2.0.15", - "@smithy/middleware-stack": "^2.0.9", - "@smithy/node-config-provider": "^2.1.8", - "@smithy/node-http-handler": "^2.2.1", - "@smithy/protocol-http": "^3.0.11", - "@smithy/smithy-client": "^2.1.18", - "@smithy/types": "^2.7.0", - "@smithy/url-parser": "^2.0.15", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.22", - "@smithy/util-defaults-mode-node": "^2.0.29", - "@smithy/util-endpoints": "^1.0.7", - "@smithy/util-retry": "^2.0.8", - "@smithy/util-stream": "^2.0.23", - "@smithy/util-utf8": "^2.0.2", - "tslib": "^2.5.0" + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/client-sso": { - "version": "3.474.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.474.0.tgz", - "integrity": "sha512-6toUmQUIHkDM/P2/nyLEO/mcWOIPByTlegqX9VCHhYh9Fs5MDT2nit7I6fZzBjZjB5oVTwKjbzgxae9cE3bhqw==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/core": "3.474.0", - "@aws-sdk/middleware-host-header": "3.468.0", - "@aws-sdk/middleware-logger": "3.468.0", - "@aws-sdk/middleware-recursion-detection": "3.468.0", - "@aws-sdk/middleware-user-agent": "3.470.0", - "@aws-sdk/region-config-resolver": "3.470.0", - "@aws-sdk/types": "3.468.0", - "@aws-sdk/util-endpoints": "3.470.0", - "@aws-sdk/util-user-agent-browser": "3.468.0", - "@aws-sdk/util-user-agent-node": "3.470.0", - "@smithy/config-resolver": "^2.0.21", - "@smithy/fetch-http-handler": "^2.3.1", - "@smithy/hash-node": "^2.0.17", - "@smithy/invalid-dependency": "^2.0.15", - "@smithy/middleware-content-length": "^2.0.17", - "@smithy/middleware-endpoint": "^2.2.3", - "@smithy/middleware-retry": "^2.0.24", - "@smithy/middleware-serde": "^2.0.15", - "@smithy/middleware-stack": "^2.0.9", - "@smithy/node-config-provider": "^2.1.8", - "@smithy/node-http-handler": "^2.2.1", - "@smithy/protocol-http": "^3.0.11", - "@smithy/smithy-client": "^2.1.18", - "@smithy/types": "^2.7.0", - "@smithy/url-parser": "^2.0.15", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.22", - "@smithy/util-defaults-mode-node": "^2.0.29", - "@smithy/util-endpoints": "^1.0.7", - "@smithy/util-retry": "^2.0.8", - "@smithy/util-utf8": "^2.0.2", - "tslib": "^2.5.0" + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dependencies": { + "tslib": "^2.6.2" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/client-sts": { - "version": "3.474.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.474.0.tgz", - "integrity": "sha512-qPPMbrDVAUJgYiFWVewFG7dg0VyMfuGNNK4IC1nZr0eXejUTbdm8cio6IZ8OkWtK+A+L+wx1vX5686WYVgQ0dQ==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/core": "3.474.0", - "@aws-sdk/credential-provider-node": "3.474.0", - "@aws-sdk/middleware-host-header": "3.468.0", - "@aws-sdk/middleware-logger": "3.468.0", - "@aws-sdk/middleware-recursion-detection": "3.468.0", - "@aws-sdk/middleware-user-agent": "3.470.0", - "@aws-sdk/region-config-resolver": "3.470.0", - "@aws-sdk/types": "3.468.0", - "@aws-sdk/util-endpoints": "3.470.0", - "@aws-sdk/util-user-agent-browser": "3.468.0", - "@aws-sdk/util-user-agent-node": "3.470.0", - "@smithy/config-resolver": "^2.0.21", - "@smithy/core": "^1.1.0", - "@smithy/fetch-http-handler": "^2.3.1", - "@smithy/hash-node": "^2.0.17", - "@smithy/invalid-dependency": "^2.0.15", - "@smithy/middleware-content-length": "^2.0.17", - "@smithy/middleware-endpoint": "^2.2.3", - "@smithy/middleware-retry": "^2.0.24", - "@smithy/middleware-serde": "^2.0.15", - "@smithy/middleware-stack": "^2.0.9", - "@smithy/node-config-provider": "^2.1.8", - "@smithy/node-http-handler": "^2.2.1", - "@smithy/protocol-http": "^3.0.11", - "@smithy/smithy-client": "^2.1.18", - "@smithy/types": "^2.7.0", - "@smithy/url-parser": "^2.0.15", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.22", - "@smithy/util-defaults-mode-node": "^2.0.29", - "@smithy/util-endpoints": "^1.0.7", - "@smithy/util-middleware": "^2.0.8", - "@smithy/util-retry": "^2.0.8", - "@smithy/util-utf8": "^2.0.2", - "fast-xml-parser": "4.2.5", - "tslib": "^2.5.0" + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.468.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.468.0.tgz", - "integrity": "sha512-k/1WHd3KZn0EQYjadooj53FC0z24/e4dUZhbSKTULgmxyO62pwh9v3Brvw4WRa/8o2wTffU/jo54tf4vGuP/ZA==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", "dependencies": { - "@aws-sdk/types": "3.468.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.474.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.474.0.tgz", - "integrity": "sha512-3Y2fHI4ZCNjdOO47Vh/xBgLXOrKm3KwBkYkBKKT2g02FUGNT8NLjJg8WBo3D4RQX2h34qx4mtW5nTY6YcGP80Q==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.468.0", - "@aws-sdk/credential-provider-process": "3.468.0", - "@aws-sdk/credential-provider-sso": "3.474.0", - "@aws-sdk/credential-provider-web-identity": "3.468.0", - "@aws-sdk/types": "3.468.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.474.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.474.0.tgz", - "integrity": "sha512-3OVVVGnb8Ru5hWeeHkg76YZT5mrufweIiWr6ge5zn7FYxc7WkyqIJ0XehqUqG5VQfaYhqh7uq/zmk8OE2B04lQ==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.468.0", - "@aws-sdk/credential-provider-ini": "3.474.0", - "@aws-sdk/credential-provider-process": "3.468.0", - "@aws-sdk/credential-provider-sso": "3.474.0", - "@aws-sdk/credential-provider-web-identity": "3.468.0", - "@aws-sdk/types": "3.468.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dependencies": { + "tslib": "^2.6.2" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.468.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.468.0.tgz", - "integrity": "sha512-OYSn1A/UsyPJ7Z8Q2cNhTf55O36shPmSsvOfND04nSfu1nPaR+VUvvsP7v+brhGpwC/GAKTIdGAo4blH31BS6A==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", "dependencies": { - "@aws-sdk/types": "3.468.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.474.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.474.0.tgz", - "integrity": "sha512-ik4rzhQtcRLSHB/MLQfi/dSpILxPd3zITb79DIEnqT3gpZRNjoARkZ3Hi68pujkU2530NYf8NcFwLCWoV1hS7Q==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", "dependencies": { - "@aws-sdk/client-sso": "3.474.0", - "@aws-sdk/token-providers": "3.470.0", - "@aws-sdk/types": "3.468.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.468.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.468.0.tgz", - "integrity": "sha512-rexymPmXjtkwCPfhnUq3EjO1rSkf39R4Jz9CqiM7OsqK2qlT5Y/V3gnMKn0ZMXsYaQOMfM3cT5xly5R+OKDHlw==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/client-sso": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.616.0.tgz", + "integrity": "sha512-hwW0u1f8U4dSloAe61/eupUiGd5Q13B72BuzGxvRk0cIpYX/2m0KBG8DDl7jW1b2QQ+CflTLpG2XUf2+vRJxGA==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.616.0", + "@aws-sdk/middleware-host-header": "3.616.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.616.0", + "@aws-sdk/middleware-user-agent": "3.616.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.2.7", + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.4", + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-retry": "^3.0.10", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.8", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.10", + "@smithy/util-defaults-mode-node": "^3.0.10", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.616.0.tgz", + "integrity": "sha512-YY1hpYS/G1uRGjQf88dL8VLHkP/IjGxKeXdhy+JnzMdCkAWl3V9j0fEALw40NZe0x79gr6R2KUOUH/IKYQfUmg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.616.0", + "@aws-sdk/credential-provider-node": "3.616.0", + "@aws-sdk/middleware-host-header": "3.616.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.616.0", + "@aws-sdk/middleware-user-agent": "3.616.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.2.7", + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.4", + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-retry": "^3.0.10", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.8", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.10", + "@smithy/util-defaults-mode-node": "^3.0.10", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.616.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/client-sts": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.616.0.tgz", + "integrity": "sha512-FP7i7hS5FpReqnysQP1ukQF1OUWy8lkomaOnbu15H415YUrfCp947SIx6+BItjmx+esKxPkEjh/fbCVzw2D6hQ==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.616.0", + "@aws-sdk/core": "3.616.0", + "@aws-sdk/credential-provider-node": "3.616.0", + "@aws-sdk/middleware-host-header": "3.616.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.616.0", + "@aws-sdk/middleware-user-agent": "3.616.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.2.7", + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.4", + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-retry": "^3.0.10", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.8", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.10", + "@smithy/util-defaults-mode-node": "^3.0.10", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.609.0.tgz", + "integrity": "sha512-v69ZCWcec2iuV9vLVJMa6fAb5xwkzN4jYIT8yjo2c4Ia/j976Q+TPf35Pnz5My48Xr94EFcaBazrWedF+kwfuQ==", "dependencies": { - "@aws-sdk/types": "3.468.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.468.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.468.0.tgz", - "integrity": "sha512-gwQ+/QhX+lhof304r6zbZ/V5l5cjhGRxLL3CjH1uJPMcOAbw9wUlMdl+ibr8UwBZ5elfKFGiB1cdW/0uMchw0w==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.616.0.tgz", + "integrity": "sha512-1rgCkr7XvEMBl7qWCo5BKu3yAxJs71dRaZ55Xnjte/0ZHH6Oc93ZrHzyYy6UH6t0nZrH+FAuw7Yko2YtDDwDeg==", "dependencies": { - "@aws-sdk/types": "3.468.0", - "@smithy/protocol-http": "^3.0.11", - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.609.0", + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.8", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-logger": { - "version": "3.468.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.468.0.tgz", - "integrity": "sha512-X5XHKV7DHRXI3f29SAhJPe/OxWRFgDWDMMCALfzhmJfCi6Jfh0M14cJKoC+nl+dk9lB+36+jKjhjETZaL2bPlA==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.616.0.tgz", + "integrity": "sha512-5gQdMr9cca3xV7FF2SxpxWGH2t6+t4o+XBGiwsHm8muEjf4nUmw7Ij863x25Tjt2viPYV0UStczSb5Sihp7bkA==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.609.0", + "@aws-sdk/credential-provider-http": "3.616.0", + "@aws-sdk/credential-provider-process": "3.614.0", + "@aws-sdk/credential-provider-sso": "3.616.0", + "@aws-sdk/credential-provider-web-identity": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.616.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.616.0.tgz", + "integrity": "sha512-Se+u6DAxjDPjKE3vX1X2uxjkWgGq69BTo0uTB0vDUiWwBVgh16s9BsBhSAlKEH1CCbbJHvOg4YdTrzjwzqyClg==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.609.0", + "@aws-sdk/credential-provider-http": "3.616.0", + "@aws-sdk/credential-provider-ini": "3.616.0", + "@aws-sdk/credential-provider-process": "3.614.0", + "@aws-sdk/credential-provider-sso": "3.616.0", + "@aws-sdk/credential-provider-web-identity": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.614.0.tgz", + "integrity": "sha512-Q0SI0sTRwi8iNODLs5+bbv8vgz8Qy2QdxbCHnPk/6Cx6LMf7i3dqmWquFbspqFRd8QiqxStrblwxrUYZi09tkA==", "dependencies": { - "@aws-sdk/types": "3.468.0", - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.468.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.468.0.tgz", - "integrity": "sha512-vch9IQib2Ng9ucSyRW2eKNQXHUPb5jUPCLA5otTW/8nGjcOU37LxQG4WrxO7uaJ9Oe8hjHO+hViE3P0KISUhtA==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.616.0.tgz", + "integrity": "sha512-3rsWs9GBi8Z8Gps5ROwqguxtw+J6OIg1vawZMLRNMqqZoBvbOToe9wEnpid8ylU+27+oG8uibJNlNuRyXApUjw==", "dependencies": { - "@aws-sdk/types": "3.468.0", - "@smithy/protocol-http": "^3.0.11", - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "@aws-sdk/client-sso": "3.616.0", + "@aws-sdk/token-providers": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-signing": { - "version": "3.468.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.468.0.tgz", - "integrity": "sha512-s+7fSB1gdnnTj5O0aCCarX3z5Vppop8kazbNSZADdkfHIDWCN80IH4ZNjY3OWqaAz0HmR4LNNrovdR304ojb4Q==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.609.0.tgz", + "integrity": "sha512-U+PG8NhlYYF45zbr1km3ROtBMYqyyj/oK8NRp++UHHeuavgrP+4wJ4wQnlEaKvJBjevfo3+dlIBcaeQ7NYejWg==", "dependencies": { - "@aws-sdk/types": "3.468.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^3.0.11", - "@smithy/signature-v4": "^2.0.0", - "@smithy/types": "^2.7.0", - "@smithy/util-middleware": "^2.0.8", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.609.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.470.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.470.0.tgz", - "integrity": "sha512-s0YRGgf4fT5KwwTefpoNUQfB5JghzXyvmPfY1QuFEMeVQNxv0OPuydzo3rY2oXPkZjkulKDtpm5jzIHwut75hA==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.616.0.tgz", + "integrity": "sha512-mhNfHuGhCDZwYCABebaOvTgOM44UCZZRq2cBpgPZLVKP0ydAv5aFHXv01goexxXHqgHoEGx0uXWxlw0s2EpFDg==", "dependencies": { - "@aws-sdk/types": "3.468.0", - "@aws-sdk/util-endpoints": "3.470.0", - "@smithy/protocol-http": "^3.0.11", - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.0.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.470.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.470.0.tgz", - "integrity": "sha512-C1o1J06iIw8cyAAOvHqT4Bbqf+PgQ/RDlSyjt2gFfP2OovDpc2o2S90dE8f8iZdSGpg70N5MikT1DBhW9NbhtQ==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/middleware-logger": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", + "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", "dependencies": { - "@smithy/node-config-provider": "^2.1.8", - "@smithy/types": "^2.7.0", - "@smithy/util-config-provider": "^2.0.0", - "@smithy/util-middleware": "^2.0.8", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/token-providers": { - "version": "3.470.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.470.0.tgz", - "integrity": "sha512-rzxnJxEUJiV69Cxsf0AHXTqJqTACITwcSH/PL4lWP4uvtzdrzSi3KA3u2aWHWpOcdE6+JFvdICscsbBSo3/TOg==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.616.0.tgz", + "integrity": "sha512-LQKAcrZRrR9EGez4fdCIVjdn0Ot2HMN12ChnoMGEU6oIxnQ2aSC7iASFFCV39IYfeMh7iSCPj7Wopqw8rAouzg==", "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/middleware-host-header": "3.468.0", - "@aws-sdk/middleware-logger": "3.468.0", - "@aws-sdk/middleware-recursion-detection": "3.468.0", - "@aws-sdk/middleware-user-agent": "3.470.0", - "@aws-sdk/region-config-resolver": "3.470.0", - "@aws-sdk/types": "3.468.0", - "@aws-sdk/util-endpoints": "3.470.0", - "@aws-sdk/util-user-agent-browser": "3.468.0", - "@aws-sdk/util-user-agent-node": "3.470.0", - "@smithy/config-resolver": "^2.0.21", - "@smithy/fetch-http-handler": "^2.3.1", - "@smithy/hash-node": "^2.0.17", - "@smithy/invalid-dependency": "^2.0.15", - "@smithy/middleware-content-length": "^2.0.17", - "@smithy/middleware-endpoint": "^2.2.3", - "@smithy/middleware-retry": "^2.0.24", - "@smithy/middleware-serde": "^2.0.15", - "@smithy/middleware-stack": "^2.0.9", - "@smithy/node-config-provider": "^2.1.8", - "@smithy/node-http-handler": "^2.2.1", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^3.0.11", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/smithy-client": "^2.1.18", - "@smithy/types": "^2.7.0", - "@smithy/url-parser": "^2.0.15", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.22", - "@smithy/util-defaults-mode-node": "^2.0.29", - "@smithy/util-endpoints": "^1.0.7", - "@smithy/util-retry": "^2.0.8", - "@smithy/util-utf8": "^2.0.2", - "tslib": "^2.5.0" + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.0.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/types": { - "version": "3.468.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.468.0.tgz", - "integrity": "sha512-rx/9uHI4inRbp2tw3Y4Ih4PNZkVj32h7WneSg3MVgVjAoVD5Zti9KhS5hkvsBxfgmQmg0AQbE+b1sy5WGAgntA==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.616.0.tgz", + "integrity": "sha512-iMcAb4E+Z3vuEcrDsG6T2OBNiqWAquwahP9qepHqfmnmJqHr1mSHtXDYTGBNid31+621sUQmneUQ+fagpGAe4w==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@smithy/protocol-http": "^4.0.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", + "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/token-providers": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", + "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.614.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/util-endpoints": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", + "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "@smithy/util-endpoints": "^2.0.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", + "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", + "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/config-resolver": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.5.tgz", + "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/core": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.8.tgz", + "integrity": "sha512-1Y0XX0Ucyg0LWTfTVLWpmvSRtFRniykUl3dQ0os1sTd03mKDudR6mVyX+2ak1phwPXx2aEWMAAdW52JNi0mc3A==", + "dependencies": { + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-retry": "^3.0.11", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.9", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/credential-provider-imds": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.1.4.tgz", + "integrity": "sha512-NKyH01m97Xa5xf3pB2QOF3lnuE8RIK0hTVNU5zvZAwZU8uspYO4DHQVlK+Y5gwSrujTfHvbfd1D9UFJAc0iYKQ==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/eventstream-codec": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.2.tgz", + "integrity": "sha512-0mBcu49JWt4MXhrhRAlxASNy0IjDRFU+aWNDRal9OtUJvJNiwDuyKMUONSOjLjSCeGwZaE0wOErdqULer8r7yw==", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^3.3.0", + "@smithy/util-hex-encoding": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/eventstream-serde-browser": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.5.tgz", + "integrity": "sha512-dEyiUYL/ekDfk+2Ra4GxV+xNnFoCmk1nuIXg+fMChFTrM2uI/1r9AdiTYzPqgb72yIv/NtAj6C3dG//1wwgakQ==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^3.0.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.3.tgz", + "integrity": "sha512-NVTYjOuYpGfrN/VbRQgn31x73KDLfCXCsFdad8DiIc3IcdxL+dYA9zEQPyOP7Fy2QL8CPy2WE4WCUD+ZsLNfaQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/eventstream-serde-node": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.4.tgz", + "integrity": "sha512-mjlG0OzGAYuUpdUpflfb9zyLrBGgmQmrobNT8b42ZTsGv/J03+t24uhhtVEKG/b2jFtPIHF74Bq+VUtbzEKOKg==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^3.0.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/eventstream-serde-universal": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.4.tgz", + "integrity": "sha512-Od9dv8zh3PgOD7Vj4T3HSuox16n0VG8jJIM2gvKASL6aCtcS8CfHZDWe1Ik3ZXW6xBouU+45Q5wgoliWDZiJ0A==", + "dependencies": { + "@smithy/eventstream-codec": "^3.1.2", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/fetch-http-handler": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.2.tgz", + "integrity": "sha512-3LaWlBZObyGrOOd7e5MlacnAKEwFBmAeiW/TOj2eR9475Vnq30uS2510+tnKbxrGjROfNdOhQqGo5j3sqLT6bA==", + "dependencies": { + "@smithy/protocol-http": "^4.0.4", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/hash-node": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", + "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/invalid-dependency": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", + "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/middleware-content-length": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.4.tgz", + "integrity": "sha512-wySGje/KfhsnF8YSh9hP16pZcl3C+X6zRsvSfItQGvCyte92LliilU3SD0nR7kTlxnAJwxY8vE/k4Eoezj847Q==", + "dependencies": { + "@smithy/protocol-http": "^4.0.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/middleware-endpoint": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.0.5.tgz", + "integrity": "sha512-V4acqqrh5tDxUEGVTOgf2lYMZqPQsoGntCrjrJZEeBzEzDry2d2vcI1QCXhGltXPPY+BMc6eksZMguA9fIY8vA==", + "dependencies": { + "@smithy/middleware-serde": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/middleware-retry": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.11.tgz", + "integrity": "sha512-/TIRWmhwMpv99JCGuMhJPnH7ggk/Lah7s/uNDyr7faF02BxNsyD/fz9Tw7pgCf9tYOKgjimm2Qml1Aq1pbkt6g==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.0.4", + "@smithy/service-error-classification": "^3.0.3", + "@smithy/smithy-client": "^3.1.9", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/middleware-serde": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", + "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/middleware-stack": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", + "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "dependencies": { + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/node-http-handler": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.3.tgz", + "integrity": "sha512-UiKZm8KHb/JeOPzHZtRUfyaRDO1KPKPpsd7iplhiwVGOeVdkiVJ5bVe7+NhWREMOKomrDIDdSZyglvMothLg0Q==", + "dependencies": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.0.4", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/protocol-http": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.4.tgz", + "integrity": "sha512-fAA2O4EFyNRyYdFLVIv5xMMeRb+3fRKc/Rt2flh5k831vLvUmNFXcydeg7V3UeEhGURJI4c1asmGJBjvmF6j8Q==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/querystring-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", + "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/service-error-classification": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", + "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", + "dependencies": { + "@smithy/types": "^3.3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/smithy-client": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.9.tgz", + "integrity": "sha512-My2RaInZ4gSwJUPMaiLR/Nk82+c4LlvqpXA+n7lonGYgCZq23Tg+/xFhgmiejJ6XPElYJysTPyV90vKyp17+1g==", + "dependencies": { + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/url-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", + "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", + "dependencies": { + "@smithy/querystring-parser": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-body-length-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", + "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-defaults-mode-browser": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.11.tgz", + "integrity": "sha512-O3s9DGb3bmRvEKmT8RwvSWK4A9r6svfd+MnJB+UMi9ZcCkAnoRtliulOnGF0qCMkKF9mwk2tkopBBstalPY/vg==", + "dependencies": { + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.9", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-defaults-mode-node": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.11.tgz", + "integrity": "sha512-qd4a9qtyOa/WY14aHHOkMafhh9z8D2QTwlcBoXMTPnEwtcY+xpe1JyFm9vya7VsB8hHsfn3XodEtwqREiu4ygQ==", + "dependencies": { + "@smithy/config-resolver": "^3.0.5", + "@smithy/credential-provider-imds": "^3.1.4", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.9", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-endpoints": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.5.tgz", + "integrity": "sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-retry": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", + "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", + "dependencies": { + "@smithy/service-error-classification": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-stream": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.1.tgz", + "integrity": "sha512-EhRnVvl3AhoHAT2rGQ5o+oSDRM/BUSMPLZZdRJZLcNVUsFAjOs4vHaPdNQivTSzRcFxf5DA4gtO46WWU2zimaw==", + "dependencies": { + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-agent-runtime/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.616.0.tgz", + "integrity": "sha512-3uvKafBwlrJp2/Me/BMdvYf3J127vC69aDJloElX9eClhSBDwIQ6C7tuXmhqb662mKNy5iqXcmYhmv9FowevJw==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.616.0", + "@aws-sdk/client-sts": "3.616.0", + "@aws-sdk/core": "3.616.0", + "@aws-sdk/credential-provider-node": "3.616.0", + "@aws-sdk/middleware-host-header": "3.616.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.616.0", + "@aws-sdk/middleware-user-agent": "3.616.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.2.7", + "@smithy/eventstream-serde-browser": "^3.0.4", + "@smithy/eventstream-serde-config-resolver": "^3.0.3", + "@smithy/eventstream-serde-node": "^3.0.4", + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.4", + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-retry": "^3.0.10", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.8", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.10", + "@smithy/util-defaults-mode-node": "^3.0.10", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-stream": "^3.1.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/client-sso": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.616.0.tgz", + "integrity": "sha512-hwW0u1f8U4dSloAe61/eupUiGd5Q13B72BuzGxvRk0cIpYX/2m0KBG8DDl7jW1b2QQ+CflTLpG2XUf2+vRJxGA==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.616.0", + "@aws-sdk/middleware-host-header": "3.616.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.616.0", + "@aws-sdk/middleware-user-agent": "3.616.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.2.7", + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.4", + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-retry": "^3.0.10", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.8", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.10", + "@smithy/util-defaults-mode-node": "^3.0.10", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.616.0.tgz", + "integrity": "sha512-YY1hpYS/G1uRGjQf88dL8VLHkP/IjGxKeXdhy+JnzMdCkAWl3V9j0fEALw40NZe0x79gr6R2KUOUH/IKYQfUmg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.616.0", + "@aws-sdk/credential-provider-node": "3.616.0", + "@aws-sdk/middleware-host-header": "3.616.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.616.0", + "@aws-sdk/middleware-user-agent": "3.616.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.2.7", + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.4", + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-retry": "^3.0.10", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.8", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.10", + "@smithy/util-defaults-mode-node": "^3.0.10", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.616.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/client-sts": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.616.0.tgz", + "integrity": "sha512-FP7i7hS5FpReqnysQP1ukQF1OUWy8lkomaOnbu15H415YUrfCp947SIx6+BItjmx+esKxPkEjh/fbCVzw2D6hQ==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.616.0", + "@aws-sdk/core": "3.616.0", + "@aws-sdk/credential-provider-node": "3.616.0", + "@aws-sdk/middleware-host-header": "3.616.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.616.0", + "@aws-sdk/middleware-user-agent": "3.616.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.2.7", + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.4", + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-retry": "^3.0.10", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.8", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.10", + "@smithy/util-defaults-mode-node": "^3.0.10", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.609.0.tgz", + "integrity": "sha512-v69ZCWcec2iuV9vLVJMa6fAb5xwkzN4jYIT8yjo2c4Ia/j976Q+TPf35Pnz5My48Xr94EFcaBazrWedF+kwfuQ==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.616.0.tgz", + "integrity": "sha512-1rgCkr7XvEMBl7qWCo5BKu3yAxJs71dRaZ55Xnjte/0ZHH6Oc93ZrHzyYy6UH6t0nZrH+FAuw7Yko2YtDDwDeg==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.8", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.616.0.tgz", + "integrity": "sha512-5gQdMr9cca3xV7FF2SxpxWGH2t6+t4o+XBGiwsHm8muEjf4nUmw7Ij863x25Tjt2viPYV0UStczSb5Sihp7bkA==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.609.0", + "@aws-sdk/credential-provider-http": "3.616.0", + "@aws-sdk/credential-provider-process": "3.614.0", + "@aws-sdk/credential-provider-sso": "3.616.0", + "@aws-sdk/credential-provider-web-identity": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.616.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.616.0.tgz", + "integrity": "sha512-Se+u6DAxjDPjKE3vX1X2uxjkWgGq69BTo0uTB0vDUiWwBVgh16s9BsBhSAlKEH1CCbbJHvOg4YdTrzjwzqyClg==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.609.0", + "@aws-sdk/credential-provider-http": "3.616.0", + "@aws-sdk/credential-provider-ini": "3.616.0", + "@aws-sdk/credential-provider-process": "3.614.0", + "@aws-sdk/credential-provider-sso": "3.616.0", + "@aws-sdk/credential-provider-web-identity": "3.609.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.614.0.tgz", + "integrity": "sha512-Q0SI0sTRwi8iNODLs5+bbv8vgz8Qy2QdxbCHnPk/6Cx6LMf7i3dqmWquFbspqFRd8QiqxStrblwxrUYZi09tkA==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.616.0.tgz", + "integrity": "sha512-3rsWs9GBi8Z8Gps5ROwqguxtw+J6OIg1vawZMLRNMqqZoBvbOToe9wEnpid8ylU+27+oG8uibJNlNuRyXApUjw==", + "dependencies": { + "@aws-sdk/client-sso": "3.616.0", + "@aws-sdk/token-providers": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.609.0.tgz", + "integrity": "sha512-U+PG8NhlYYF45zbr1km3ROtBMYqyyj/oK8NRp++UHHeuavgrP+4wJ4wQnlEaKvJBjevfo3+dlIBcaeQ7NYejWg==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.609.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.616.0.tgz", + "integrity": "sha512-mhNfHuGhCDZwYCABebaOvTgOM44UCZZRq2cBpgPZLVKP0ydAv5aFHXv01goexxXHqgHoEGx0uXWxlw0s2EpFDg==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.0.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-logger": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", + "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.616.0.tgz", + "integrity": "sha512-LQKAcrZRrR9EGez4fdCIVjdn0Ot2HMN12ChnoMGEU6oIxnQ2aSC7iASFFCV39IYfeMh7iSCPj7Wopqw8rAouzg==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.0.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.616.0.tgz", + "integrity": "sha512-iMcAb4E+Z3vuEcrDsG6T2OBNiqWAquwahP9qepHqfmnmJqHr1mSHtXDYTGBNid31+621sUQmneUQ+fagpGAe4w==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@smithy/protocol-http": "^4.0.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", + "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/token-providers": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", + "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.614.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/util-endpoints": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", + "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "@smithy/util-endpoints": "^2.0.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", + "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", + "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/config-resolver": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.5.tgz", + "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/core": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.8.tgz", + "integrity": "sha512-1Y0XX0Ucyg0LWTfTVLWpmvSRtFRniykUl3dQ0os1sTd03mKDudR6mVyX+2ak1phwPXx2aEWMAAdW52JNi0mc3A==", + "dependencies": { + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-retry": "^3.0.11", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.9", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/credential-provider-imds": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.1.4.tgz", + "integrity": "sha512-NKyH01m97Xa5xf3pB2QOF3lnuE8RIK0hTVNU5zvZAwZU8uspYO4DHQVlK+Y5gwSrujTfHvbfd1D9UFJAc0iYKQ==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/eventstream-codec": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.2.tgz", + "integrity": "sha512-0mBcu49JWt4MXhrhRAlxASNy0IjDRFU+aWNDRal9OtUJvJNiwDuyKMUONSOjLjSCeGwZaE0wOErdqULer8r7yw==", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^3.3.0", + "@smithy/util-hex-encoding": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/eventstream-serde-browser": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.5.tgz", + "integrity": "sha512-dEyiUYL/ekDfk+2Ra4GxV+xNnFoCmk1nuIXg+fMChFTrM2uI/1r9AdiTYzPqgb72yIv/NtAj6C3dG//1wwgakQ==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^3.0.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.3.tgz", + "integrity": "sha512-NVTYjOuYpGfrN/VbRQgn31x73KDLfCXCsFdad8DiIc3IcdxL+dYA9zEQPyOP7Fy2QL8CPy2WE4WCUD+ZsLNfaQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/eventstream-serde-node": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.4.tgz", + "integrity": "sha512-mjlG0OzGAYuUpdUpflfb9zyLrBGgmQmrobNT8b42ZTsGv/J03+t24uhhtVEKG/b2jFtPIHF74Bq+VUtbzEKOKg==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^3.0.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/eventstream-serde-universal": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.4.tgz", + "integrity": "sha512-Od9dv8zh3PgOD7Vj4T3HSuox16n0VG8jJIM2gvKASL6aCtcS8CfHZDWe1Ik3ZXW6xBouU+45Q5wgoliWDZiJ0A==", + "dependencies": { + "@smithy/eventstream-codec": "^3.1.2", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/fetch-http-handler": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.2.tgz", + "integrity": "sha512-3LaWlBZObyGrOOd7e5MlacnAKEwFBmAeiW/TOj2eR9475Vnq30uS2510+tnKbxrGjROfNdOhQqGo5j3sqLT6bA==", + "dependencies": { + "@smithy/protocol-http": "^4.0.4", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/hash-node": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", + "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/invalid-dependency": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", + "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/middleware-content-length": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.4.tgz", + "integrity": "sha512-wySGje/KfhsnF8YSh9hP16pZcl3C+X6zRsvSfItQGvCyte92LliilU3SD0nR7kTlxnAJwxY8vE/k4Eoezj847Q==", + "dependencies": { + "@smithy/protocol-http": "^4.0.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/middleware-endpoint": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.0.5.tgz", + "integrity": "sha512-V4acqqrh5tDxUEGVTOgf2lYMZqPQsoGntCrjrJZEeBzEzDry2d2vcI1QCXhGltXPPY+BMc6eksZMguA9fIY8vA==", + "dependencies": { + "@smithy/middleware-serde": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/middleware-retry": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.11.tgz", + "integrity": "sha512-/TIRWmhwMpv99JCGuMhJPnH7ggk/Lah7s/uNDyr7faF02BxNsyD/fz9Tw7pgCf9tYOKgjimm2Qml1Aq1pbkt6g==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.0.4", + "@smithy/service-error-classification": "^3.0.3", + "@smithy/smithy-client": "^3.1.9", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/middleware-serde": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", + "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/middleware-stack": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", + "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "dependencies": { + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/node-http-handler": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.3.tgz", + "integrity": "sha512-UiKZm8KHb/JeOPzHZtRUfyaRDO1KPKPpsd7iplhiwVGOeVdkiVJ5bVe7+NhWREMOKomrDIDdSZyglvMothLg0Q==", + "dependencies": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.0.4", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/protocol-http": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.4.tgz", + "integrity": "sha512-fAA2O4EFyNRyYdFLVIv5xMMeRb+3fRKc/Rt2flh5k831vLvUmNFXcydeg7V3UeEhGURJI4c1asmGJBjvmF6j8Q==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/querystring-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", + "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/service-error-classification": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", + "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", + "dependencies": { + "@smithy/types": "^3.3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/smithy-client": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.9.tgz", + "integrity": "sha512-My2RaInZ4gSwJUPMaiLR/Nk82+c4LlvqpXA+n7lonGYgCZq23Tg+/xFhgmiejJ6XPElYJysTPyV90vKyp17+1g==", + "dependencies": { + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/url-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", + "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", + "dependencies": { + "@smithy/querystring-parser": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-body-length-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", + "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-defaults-mode-browser": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.11.tgz", + "integrity": "sha512-O3s9DGb3bmRvEKmT8RwvSWK4A9r6svfd+MnJB+UMi9ZcCkAnoRtliulOnGF0qCMkKF9mwk2tkopBBstalPY/vg==", + "dependencies": { + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.9", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-defaults-mode-node": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.11.tgz", + "integrity": "sha512-qd4a9qtyOa/WY14aHHOkMafhh9z8D2QTwlcBoXMTPnEwtcY+xpe1JyFm9vya7VsB8hHsfn3XodEtwqREiu4ygQ==", + "dependencies": { + "@smithy/config-resolver": "^3.0.5", + "@smithy/credential-provider-imds": "^3.1.4", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.9", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-endpoints": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.5.tgz", + "integrity": "sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-retry": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", + "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", "dependencies": { - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "@smithy/service-error-classification": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/util-endpoints": { - "version": "3.470.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.470.0.tgz", - "integrity": "sha512-6N6VvPCmu+89p5Ez/+gLf+X620iQ9JpIs8p8ECZiCodirzFOe8NC1O2S7eov7YiG9IHSuodqn/0qNq+v+oLe0A==", - "optional": true, - "peer": true, - "dependencies": { - "@aws-sdk/types": "3.468.0", - "@smithy/util-endpoints": "^1.0.7", - "tslib": "^2.5.0" + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-stream": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.1.tgz", + "integrity": "sha512-EhRnVvl3AhoHAT2rGQ5o+oSDRM/BUSMPLZZdRJZLcNVUsFAjOs4vHaPdNQivTSzRcFxf5DA4gtO46WWU2zimaw==", + "dependencies": { + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.468.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.468.0.tgz", - "integrity": "sha512-OJyhWWsDEizR3L+dCgMXSUmaCywkiZ7HSbnQytbeKGwokIhD69HTiJcibF/sgcM5gk4k3Mq3puUhGnEZ46GIig==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", "dependencies": { - "@aws-sdk/types": "3.468.0", - "@smithy/types": "^2.7.0", - "bowser": "^2.11.0", - "tslib": "^2.5.0" + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.470.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.470.0.tgz", - "integrity": "sha512-QxsZ9iVHcBB/XRdYvwfM5AMvNp58HfqkIrH88mY0cmxuvtlIGDfWjczdDrZMJk9y0vIq+cuoCHsGXHu7PyiEAQ==", - "optional": true, - "peer": true, + "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", "dependencies": { - "@aws-sdk/types": "3.468.0", - "@smithy/node-config-provider": "^2.1.8", - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } + "node": ">=16.0.0" } }, "node_modules/@aws-sdk/client-firehose": { @@ -1934,21 +3784,390 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.474.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.474.0.tgz", - "integrity": "sha512-eVRdeB+AoTNSzfc4viHfr0jfkHujSlf4ToExJtTuxS1wlgmIyyxRNrVKxbf0K78YK/TXRsRlJPoS5QCD5h1S2w==", - "optional": true, - "peer": true, + "version": "3.616.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.616.0.tgz", + "integrity": "sha512-O/urkh2kECs/IqZIVZxyeyHZ7OR2ZWhLNK7btsVQBQvJKrEspLrk/Fp20Qfg5JDerQfBN83ZbyRXLJOOucdZpw==", + "dependencies": { + "@smithy/core": "^2.2.7", + "@smithy/protocol-http": "^4.0.4", + "@smithy/signature-v4": "^4.0.0", + "@smithy/smithy-client": "^3.1.8", + "@smithy/types": "^3.3.0", + "fast-xml-parser": "4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", "dependencies": { - "@smithy/core": "^1.1.0", - "@smithy/protocol-http": "^3.0.11", - "@smithy/signature-v4": "^2.0.0", - "@smithy/smithy-client": "^2.1.18", - "@smithy/types": "^2.7.0", - "tslib": "^2.5.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/core": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.8.tgz", + "integrity": "sha512-1Y0XX0Ucyg0LWTfTVLWpmvSRtFRniykUl3dQ0os1sTd03mKDudR6mVyX+2ak1phwPXx2aEWMAAdW52JNi0mc3A==", + "dependencies": { + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-retry": "^3.0.11", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/smithy-client": "^3.1.9", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/fetch-http-handler": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.2.tgz", + "integrity": "sha512-3LaWlBZObyGrOOd7e5MlacnAKEwFBmAeiW/TOj2eR9475Vnq30uS2510+tnKbxrGjROfNdOhQqGo5j3sqLT6bA==", + "dependencies": { + "@smithy/protocol-http": "^4.0.4", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/middleware-endpoint": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.0.5.tgz", + "integrity": "sha512-V4acqqrh5tDxUEGVTOgf2lYMZqPQsoGntCrjrJZEeBzEzDry2d2vcI1QCXhGltXPPY+BMc6eksZMguA9fIY8vA==", + "dependencies": { + "@smithy/middleware-serde": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/middleware-retry": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.11.tgz", + "integrity": "sha512-/TIRWmhwMpv99JCGuMhJPnH7ggk/Lah7s/uNDyr7faF02BxNsyD/fz9Tw7pgCf9tYOKgjimm2Qml1Aq1pbkt6g==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.0.4", + "@smithy/service-error-classification": "^3.0.3", + "@smithy/smithy-client": "^3.1.9", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/middleware-serde": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", + "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/middleware-stack": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", + "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "dependencies": { + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/node-http-handler": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.3.tgz", + "integrity": "sha512-UiKZm8KHb/JeOPzHZtRUfyaRDO1KPKPpsd7iplhiwVGOeVdkiVJ5bVe7+NhWREMOKomrDIDdSZyglvMothLg0Q==", + "dependencies": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.0.4", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/protocol-http": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.4.tgz", + "integrity": "sha512-fAA2O4EFyNRyYdFLVIv5xMMeRb+3fRKc/Rt2flh5k831vLvUmNFXcydeg7V3UeEhGURJI4c1asmGJBjvmF6j8Q==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/querystring-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", + "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/service-error-classification": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", + "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", + "dependencies": { + "@smithy/types": "^3.3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/signature-v4": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.0.0.tgz", + "integrity": "sha512-ervYjQ+ZvmNG51Ui77IOTPri7nOyo8Kembzt9uwwlmtXJPmFXvslOahbA1blvAVs7G0KlYMiOBog1rAt7RVXxg==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/types": "^3.3.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-uri-escape": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/smithy-client": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.9.tgz", + "integrity": "sha512-My2RaInZ4gSwJUPMaiLR/Nk82+c4LlvqpXA+n7lonGYgCZq23Tg+/xFhgmiejJ6XPElYJysTPyV90vKyp17+1g==", + "dependencies": { + "@smithy/middleware-endpoint": "^3.0.5", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/protocol-http": "^4.0.4", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/url-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", + "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", + "dependencies": { + "@smithy/querystring-parser": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-retry": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", + "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", + "dependencies": { + "@smithy/service-error-classification": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-stream": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.1.tgz", + "integrity": "sha512-EhRnVvl3AhoHAT2rGQ5o+oSDRM/BUSMPLZZdRJZLcNVUsFAjOs4vHaPdNQivTSzRcFxf5DA4gtO46WWU2zimaw==", + "dependencies": { + "@smithy/fetch-http-handler": "^3.2.2", + "@smithy/node-http-handler": "^3.1.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, "node_modules/@aws-sdk/credential-provider-env": { @@ -4927,9 +7146,10 @@ "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -6211,12 +8431,13 @@ "dev": true }, "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", "dependencies": { "minimist": "^1.2.5", - "neo-async": "^2.6.0", + "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, @@ -9317,9 +11538,10 @@ } }, "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.2.tgz", + "integrity": "sha512-S8KA6DDI47nQXJSi2ctQ629YzwOVs+bQML6DAtvy0wgNdpi+0ySpQK0g2pxBq2xfF2z3YCscu7NNA8nXT9PlIQ==", + "license": "BSD-2-Clause", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -9399,9 +11621,13 @@ "dev": true }, "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } diff --git a/source/lambda/es-proxy-layer/package.json b/source/lambda/es-proxy-layer/package.json index 1116e8483..9c11f777a 100644 --- a/source/lambda/es-proxy-layer/package.json +++ b/source/lambda/es-proxy-layer/package.json @@ -1,6 +1,6 @@ { "name": "proxy-es", - "version": "6.0.3", + "version": "6.1.0", "description": "QnABot Lambda managing querying of data store", "main": "index.js", "scripts": { @@ -14,14 +14,16 @@ }, "license": "Apache-2.0", "dependencies": { + "@aws-sdk/client-bedrock-agent-runtime": "^3.616.0", + "@aws-sdk/client-bedrock-runtime": "^3.616.0", "@aws-sdk/client-firehose": "^3.511.0", "@aws-sdk/client-sagemaker-runtime": "^3.511.0", "@aws-sdk/s3-request-presigner": "^3.511.0", "@dqbd/tiktoken": "^1.0.7", "aws4": "^1.6.0", - "axios": "^1.6.8", + "axios": "^1.7.4", "bodybuilder": "^2.5.1", - "handlebars": "^4.7.2", + "handlebars": "^4.7.8", "langchain": "^0.0.209", "linkifyjs": "^3.0.0-beta.3", "sanitize-html": "^2.13.0", @@ -35,6 +37,7 @@ "jest": "^29.7.0" }, "overrides": { - "fast-xml-parser": "^4.4.1" + "fast-xml-parser": "^4.4.1", + "uglify-js": "^3.19.2" } } diff --git a/source/lambda/es-proxy-layer/test/bedrockAgents.test.js b/source/lambda/es-proxy-layer/test/bedrockAgents.test.js index e971c9b35..ac8c37942 100644 --- a/source/lambda/es-proxy-layer/test/bedrockAgents.test.js +++ b/source/lambda/es-proxy-layer/test/bedrockAgents.test.js @@ -17,6 +17,7 @@ const bedRockAgentMock = mockClient(BedrockAgentRuntimeClient); const presigner = require('@aws-sdk/s3-request-presigner'); const qnabot = require('qnabot/logging'); const { bedrockRetrieveAndGenerate } = require('../lib/bedrock/bedrockAgents'); +const _ = require('lodash'); require('aws-sdk-client-mock-jest'); const region = process.env.AWS_REGION || 'us-east-1'; @@ -24,7 +25,7 @@ const region = process.env.AWS_REGION || 'us-east-1'; jest.mock('qnabot/logging'); jest.mock('@aws-sdk/s3-request-presigner'); - +const promptTemplate = 'test-bedrock-agent-prompt'; const req = { question: 'what is ec2?', _settings: { @@ -35,13 +36,20 @@ const req = { KNOWLEDGE_BASE_SHOW_REFERENCES: true, KNOWLEDGE_BASE_S3_SIGNED_URL_EXPIRE_SECS: 300, KNOWLEDGE_BASE_PREFIX_MESSAGE: 'Bedrock Agent:', + KNOWLEDGE_BASE_PROMPT_TEMPLATE: promptTemplate, + KNOWLEDGE_BASE_MAX_NUMBER_OF_RETRIEVED_RESULTS: 1, + KNOWLEDGE_BASE_METADATA_FILTERS: '{}', + KNOWLEDGE_BASE_SEARCH_TYPE: 'DEFAULT', + KNOWLEDGE_BASE_MODEL_PARAMS: '{"temperature":0.3, "maxTokens": 245, "topP": 0.9 }', + BEDROCK_GUARDRAIL_IDENTIFIER: '', + BEDROCK_GUARDRAIL_VERSION: '', }, _preferredResponseType: 'text' } const res = { _userInfo: { - knowledgeBaseSessionId : undefined + knowledgeBaseSessionId: undefined } } @@ -79,6 +87,46 @@ const response = { } } +const expectedResult = { + a: 'Bedrock Agent:\n' + + '\n' + + 'Amazon EC2 (Amazon Elastic Compute Cloud) is a web service that provides secure, resizable compute capacity in the cloud.\n' + + '\n' + + ' compute capacity in the cloud.\n' + + '\n' + + ' secure Linux or Windows Server images' + + '\n' + + '\n' + + ' Source Link: https://signedurl.s3.amazonaws.com/', + alt: { + markdown: '**Bedrock Agent:**\n' + + '\n' + + 'Amazon EC2 (Amazon Elastic Compute Cloud) is a web service that provides secure, resizable compute capacity in the cloud.
' + + '\n' + + ' Context\n' + + '

\n' + + '\n' + + '***\n' + + '\n' + + '
\n' + + '\n' + + ' compute capacity in the cloud.\n' + + '\n' + + '***\n' + + '\n' + + '
\n' + + '\n' + + ' secure Linux or Windows Server images

\n' + + '
\n' + + '
' + + '\n' + + '\n' + + ' Source Link: [aws-overview.pdf](https://signedurl.s3.amazonaws.com/)', + ssml: ' Amazon EC2 (Amazon Elastic Compute Cloud) is a web service that provides secure, resizable compute capacity in the cloud. ', + }, + type: 'text', + answersource: 'BEDROCK KNOWLEDGE BASE' +}; presigner.getSignedUrl.mockImplementation(() => { return 'https://signedurl.s3.amazonaws.com/' @@ -93,70 +141,50 @@ describe('bedrockAgents', () => { test('bedrockRetrieveAndGenerate returns correct body when sessionId is new', async () => { const sessionId = 'newSessionId'; response.sessionId = sessionId; - bedRockAgentMock.on(RetrieveAndGenerateCommand).resolves(response); const result = await bedrockRetrieveAndGenerate(req, res); expect(bedRockAgentMock).toHaveReceivedCommandTimes(RetrieveAndGenerateCommand, 1); expect(bedRockAgentMock).toHaveReceivedCommandWith(RetrieveAndGenerateCommand, { - input:{ + input: { text: 'what is ec2?', }, - retrieveAndGenerateConfiguration:{ - knowledgeBaseConfiguration:{ + retrieveAndGenerateConfiguration: { + knowledgeBaseConfiguration: { knowledgeBaseId: 'testKnowledgeBaseId', modelArn: `arn:aws:bedrock:${region}::foundation-model/testModel`, + retrievalConfiguration: { + vectorSearchConfiguration: { + numberOfResults: 1 + } + }, + generationConfiguration: { + promptTemplate: { + textPromptTemplate: promptTemplate, + }, + inferenceConfig: { + textInferenceConfig: { + "maxTokens": 245, + "temperature": 0.3, + "topP": 0.9 + }, + }, + }, }, type: 'KNOWLEDGE_BASE', - } + }, }); expect(result).toStrictEqual([ { - _userInfo: {knowledgeBaseSessionId: "newSessionId"}, + _userInfo: { knowledgeBaseSessionId: "newSessionId" }, + got_hits: 1, + session: { qnabot_gotanswer: true }, }, - { - a: 'Bedrock Agent:\n' + - '\n' + - 'Amazon EC2 (Amazon Elastic Compute Cloud) is a web service that provides secure, resizable compute capacity in the cloud.\n' + - '\n' + - ' compute capacity in the cloud.\n' + - '\n' + - ' secure Linux or Windows Server images' + - '\n' + - '\n' + - ' Source Link: https://signedurl.s3.amazonaws.com/', - alt: { - markdown: '**Bedrock Agent:**\n' + - '\n' + - 'Amazon EC2 (Amazon Elastic Compute Cloud) is a web service that provides secure, resizable compute capacity in the cloud.
' + - '\n' + - ' Context\n' + - '

\n' + - '\n' + - '***\n' + - '\n' + - '
\n' + - '\n' + - ' compute capacity in the cloud.\n' + - '\n' + - '***\n' + - '\n' + - '
\n' + - '\n' + - ' secure Linux or Windows Server images

\n' + - '
\n' + - '
' + - '\n' + - '\n' + - ' Source Link: [aws-overview.pdf](https://signedurl.s3.amazonaws.com/)', - ssml: ' Amazon EC2 (Amazon Elastic Compute Cloud) is a web service that provides secure, resizable compute capacity in the cloud. ', - }, - type: 'text', - answersource: 'BEDROCK KNOWLEDGE BASE' - } + expectedResult ]); }); + test('bedrockRetrieveAndGenerate returns correct body when sessionId is existing', async () => { const sessionId = 'testSessionId'; res._userInfo.knowledgeBaseSessionId = sessionId @@ -166,13 +194,30 @@ describe('bedrockAgents', () => { const result = await bedrockRetrieveAndGenerate(req, res); expect(bedRockAgentMock).toHaveReceivedCommandTimes(RetrieveAndGenerateCommand, 1); expect(bedRockAgentMock).toHaveReceivedCommandWith(RetrieveAndGenerateCommand, { - input:{ + input: { text: 'what is ec2?', }, - retrieveAndGenerateConfiguration:{ - knowledgeBaseConfiguration:{ + retrieveAndGenerateConfiguration: { + knowledgeBaseConfiguration: { knowledgeBaseId: 'testKnowledgeBaseId', modelArn: `arn:aws:bedrock:${region}::foundation-model/testModel`, + retrievalConfiguration: { + vectorSearchConfiguration: { + numberOfResults: 1 + } + }, + generationConfiguration: { + promptTemplate: { + textPromptTemplate: promptTemplate, + }, + inferenceConfig: { + textInferenceConfig: { + "maxTokens": 245, + "temperature": 0.3, + "topP": 0.9 + }, + }, + }, }, type: 'KNOWLEDGE_BASE', }, @@ -180,48 +225,11 @@ describe('bedrockAgents', () => { }); expect(result).toStrictEqual([ { - _userInfo: {knowledgeBaseSessionId: "testSessionId"}, + _userInfo: { knowledgeBaseSessionId: "testSessionId" }, + got_hits: 1, + session: { qnabot_gotanswer: true }, }, - { - a: 'Bedrock Agent:\n' + - '\n' + - 'Amazon EC2 (Amazon Elastic Compute Cloud) is a web service that provides secure, resizable compute capacity in the cloud.\n' + - '\n' + - ' compute capacity in the cloud.\n' + - '\n' + - ' secure Linux or Windows Server images' + - '\n' + - '\n' + - ' Source Link: https://signedurl.s3.amazonaws.com/', - alt: { - markdown: '**Bedrock Agent:**\n' + - '\n' + - 'Amazon EC2 (Amazon Elastic Compute Cloud) is a web service that provides secure, resizable compute capacity in the cloud.
' + - '\n' + - ' Context\n' + - '

\n' + - '\n' + - '***\n' + - '\n' + - '
\n' + - '\n' + - ' compute capacity in the cloud.\n' + - '\n' + - '***\n' + - '\n' + - '
\n' + - '\n' + - ' secure Linux or Windows Server images

\n' + - '
\n' + - '
' + - '\n' + - '\n' + - ' Source Link: [aws-overview.pdf](https://signedurl.s3.amazonaws.com/)', - ssml: ' Amazon EC2 (Amazon Elastic Compute Cloud) is a web service that provides secure, resizable compute capacity in the cloud. ', - }, - type: 'text', - answersource: 'BEDROCK KNOWLEDGE BASE' - } + expectedResult ]); }); @@ -232,33 +240,202 @@ describe('bedrockAgents', () => { const e = new Error('Invalid or Expired'); e.name = 'ValidationException'; - sessionId = 'newSessionId'; + sessionId = 'newSessionId'; response.sessionId = sessionId; bedRockAgentMock.on(RetrieveAndGenerateCommand).rejectsOnce(e).resolvesOnce(response); const result = await bedrockRetrieveAndGenerate(req, res); expect(bedRockAgentMock).toHaveReceivedCommandTimes(RetrieveAndGenerateCommand, 2); expect(bedRockAgentMock).toHaveReceivedNthCommandWith(1, RetrieveAndGenerateCommand, { - input:{ + input: { text: 'what is ec2?', }, - retrieveAndGenerateConfiguration:{ - knowledgeBaseConfiguration:{ + retrieveAndGenerateConfiguration: { + knowledgeBaseConfiguration: { knowledgeBaseId: 'testKnowledgeBaseId', modelArn: `arn:aws:bedrock:${region}::foundation-model/testModel`, + retrievalConfiguration: { + vectorSearchConfiguration: { + numberOfResults: 1 + } + }, + generationConfiguration: { + promptTemplate: { + textPromptTemplate: promptTemplate, + }, + inferenceConfig: { + textInferenceConfig: { + "maxTokens": 245, + "temperature": 0.3, + "topP": 0.9 + }, + }, + }, }, type: 'KNOWLEDGE_BASE', }, sessionId: 'testSessionId', }); expect(bedRockAgentMock).toHaveReceivedNthCommandWith(2, RetrieveAndGenerateCommand, { - input:{ + input: { + text: 'what is ec2?', + }, + retrieveAndGenerateConfiguration: { + knowledgeBaseConfiguration: { + knowledgeBaseId: 'testKnowledgeBaseId', + modelArn: `arn:aws:bedrock:${region}::foundation-model/testModel`, + retrievalConfiguration: { + vectorSearchConfiguration: { + numberOfResults: 1 + } + }, + generationConfiguration: { + promptTemplate: { + textPromptTemplate: promptTemplate, + }, + inferenceConfig: { + textInferenceConfig: { + "maxTokens": 245, + "temperature": 0.3, + "topP": 0.9 + } + }, + }, + }, + type: 'KNOWLEDGE_BASE', + }, + }); + expect(result).toStrictEqual([ + { + _userInfo: { knowledgeBaseSessionId: "newSessionId" }, + got_hits: 1, + session: { qnabot_gotanswer: true }, + }, + expectedResult + ]); + }); + + test('bedrockRetrieveAndGenerate modifies request and return correct body when additionalModelRequestFields is passed', async () => { + const sessionId = 'newSessionId'; + response.sessionId = sessionId; + const modifiedReq = _.cloneDeep(req) + modifiedReq._settings.KNOWLEDGE_BASE_MODEL_PARAMS = '{"temperature":0.3, "maxTokens": 245, "topP": 0.9, "top_k": 240 }' + + + bedRockAgentMock.on(RetrieveAndGenerateCommand).resolves(response); + + const result = await bedrockRetrieveAndGenerate(modifiedReq, res); + expect(bedRockAgentMock).toHaveReceivedCommandTimes(RetrieveAndGenerateCommand, 1); + expect(bedRockAgentMock).toHaveReceivedCommandWith(RetrieveAndGenerateCommand, { + input: { + text: 'what is ec2?', + }, + retrieveAndGenerateConfiguration: { + knowledgeBaseConfiguration: { + knowledgeBaseId: 'testKnowledgeBaseId', + modelArn: `arn:aws:bedrock:${region}::foundation-model/testModel`, + retrievalConfiguration: { + vectorSearchConfiguration: { + numberOfResults: 1 + } + }, + generationConfiguration: { + promptTemplate: { + textPromptTemplate: promptTemplate, + }, + inferenceConfig: { + textInferenceConfig: { + "maxTokens": 245, + "temperature": 0.3, + "topP": 0.9 + }, + }, + additionalModelRequestFields: { + "top_k": 240 + }, + }, + }, + type: 'KNOWLEDGE_BASE', + }, + }); + expect(result).toStrictEqual([ + { + _userInfo: { knowledgeBaseSessionId: "newSessionId" }, + got_hits: 1, + session: { qnabot_gotanswer: true }, + }, + expectedResult + ]); + }); + + test('bedrockRetrieveAndGenerate returns correct body when prompt template and inference parameters are empty', async () => { + const sessionId = 'newSessionId'; + response.sessionId = sessionId; + const modifiedReq = _.cloneDeep(req) + modifiedReq._settings.KNOWLEDGE_BASE_PROMPT_TEMPLATE = ''; + modifiedReq._settings.KNOWLEDGE_BASE_MODEL_PARAMS = '{}' + bedRockAgentMock.on(RetrieveAndGenerateCommand).resolves(response); + + const result = await bedrockRetrieveAndGenerate(modifiedReq, res); + expect(bedRockAgentMock).toHaveReceivedCommandTimes(RetrieveAndGenerateCommand, 1); + expect(bedRockAgentMock).toHaveReceivedCommandWith(RetrieveAndGenerateCommand, { + input: { + text: 'what is ec2?', + }, + retrieveAndGenerateConfiguration: { + knowledgeBaseConfiguration: { + knowledgeBaseId: 'testKnowledgeBaseId', + modelArn: `arn:aws:bedrock:${region}::foundation-model/testModel`, + retrievalConfiguration: { + vectorSearchConfiguration: { + numberOfResults: 1 + } + }, + }, + type: 'KNOWLEDGE_BASE', + }, + }); + expect(result).toStrictEqual([ + { + _userInfo: { knowledgeBaseSessionId: "newSessionId" }, + got_hits: 1, + session: { qnabot_gotanswer: true }, + }, + expectedResult + ]); + }); + + test('bedrockRetrieveAndGenerate returns correct body when prompt template is empty but inference parameters are not empty', async () => { + const sessionId = 'newSessionId'; + response.sessionId = sessionId; + const modifiedReq = _.cloneDeep(req) + modifiedReq._settings.KNOWLEDGE_BASE_PROMPT_TEMPLATE = ''; + bedRockAgentMock.on(RetrieveAndGenerateCommand).resolves(response); + + const result = await bedrockRetrieveAndGenerate(modifiedReq, res); + expect(bedRockAgentMock).toHaveReceivedCommandTimes(RetrieveAndGenerateCommand, 1); + expect(bedRockAgentMock).toHaveReceivedCommandWith(RetrieveAndGenerateCommand, { + input: { text: 'what is ec2?', }, - retrieveAndGenerateConfiguration:{ - knowledgeBaseConfiguration:{ + retrieveAndGenerateConfiguration: { + knowledgeBaseConfiguration: { knowledgeBaseId: 'testKnowledgeBaseId', modelArn: `arn:aws:bedrock:${region}::foundation-model/testModel`, + retrievalConfiguration: { + vectorSearchConfiguration: { + numberOfResults: 1 + } + }, + generationConfiguration: { + inferenceConfig: { + textInferenceConfig: { + "maxTokens": 245, + "temperature": 0.3, + "topP": 0.9 + }, + }, + }, }, type: 'KNOWLEDGE_BASE', }, @@ -266,47 +443,154 @@ describe('bedrockAgents', () => { expect(result).toStrictEqual([ { _userInfo: { knowledgeBaseSessionId: "newSessionId" }, + got_hits: 1, + session: { qnabot_gotanswer: true }, + }, + expectedResult + ]); + }); + + test('bedrockRetrieveAndGenerate returns correct body when prompt template and inference config are empty but additionalModelRequestFields is not empty', async () => { + const sessionId = 'newSessionId'; + response.sessionId = sessionId; + const modifiedReq = _.cloneDeep(req) + modifiedReq._settings.KNOWLEDGE_BASE_PROMPT_TEMPLATE = ''; + modifiedReq._settings.KNOWLEDGE_BASE_MODEL_PARAMS = '{"top_k": 240 }' + bedRockAgentMock.on(RetrieveAndGenerateCommand).resolves(response); + + const result = await bedrockRetrieveAndGenerate(modifiedReq, res); + expect(bedRockAgentMock).toHaveReceivedCommandTimes(RetrieveAndGenerateCommand, 1); + expect(bedRockAgentMock).toHaveReceivedCommandWith(RetrieveAndGenerateCommand, { + input: { + text: 'what is ec2?', }, + retrieveAndGenerateConfiguration: { + knowledgeBaseConfiguration: { + knowledgeBaseId: 'testKnowledgeBaseId', + modelArn: `arn:aws:bedrock:${region}::foundation-model/testModel`, + retrievalConfiguration: { + vectorSearchConfiguration: { + numberOfResults: 1 + } + }, + generationConfiguration: { + additionalModelRequestFields: { + "top_k": 240 + }, + }, + }, + type: 'KNOWLEDGE_BASE', + }, + }); + expect(result).toStrictEqual([ { - a: 'Bedrock Agent:\n' + - '\n' + - 'Amazon EC2 (Amazon Elastic Compute Cloud) is a web service that provides secure, resizable compute capacity in the cloud.\n' + - '\n' + - ' compute capacity in the cloud.\n' + - '\n' + - ' secure Linux or Windows Server images' + - '\n' + - '\n' + - ' Source Link: https://signedurl.s3.amazonaws.com/', - alt: { - markdown: '**Bedrock Agent:**\n' + - '\n' + - 'Amazon EC2 (Amazon Elastic Compute Cloud) is a web service that provides secure, resizable compute capacity in the cloud.
' + - '\n' + - ' Context\n' + - '

\n' + - '\n' + - '***\n' + - '\n' + - '
\n' + - '\n' + - ' compute capacity in the cloud.\n' + - '\n' + - '***\n' + - '\n' + - '
\n' + - '\n' + - ' secure Linux or Windows Server images

\n' + - '
\n' + - '
' + - '\n' + - '\n' + - ' Source Link: [aws-overview.pdf](https://signedurl.s3.amazonaws.com/)', - ssml: ' Amazon EC2 (Amazon Elastic Compute Cloud) is a web service that provides secure, resizable compute capacity in the cloud. ', + _userInfo: { knowledgeBaseSessionId: "newSessionId" }, + got_hits: 1, + session: { qnabot_gotanswer: true }, + }, + expectedResult + ]); + }); + + test('bedrockRetrieveAndGenerate returns correct body when VectorSearchConfiguration is overriden with SearchTyoe', async () => { + const sessionId = 'newSessionId'; + response.sessionId = sessionId; + const modifiedReq = _.cloneDeep(req) + modifiedReq._settings.KNOWLEDGE_BASE_SEARCH_TYPE = 'HYBRID' + bedRockAgentMock.on(RetrieveAndGenerateCommand).resolves(response); + + const result = await bedrockRetrieveAndGenerate(modifiedReq, res); + expect(bedRockAgentMock).toHaveReceivedCommandTimes(RetrieveAndGenerateCommand, 1); + expect(bedRockAgentMock).toHaveReceivedCommandWith(RetrieveAndGenerateCommand, { + input: { + text: 'what is ec2?', + }, + retrieveAndGenerateConfiguration: { + knowledgeBaseConfiguration: { + knowledgeBaseId: 'testKnowledgeBaseId', + modelArn: `arn:aws:bedrock:${region}::foundation-model/testModel`, + retrievalConfiguration: { + vectorSearchConfiguration: { + numberOfResults: 1, + overrideSearchType: 'HYBRID' + } + }, + generationConfiguration: { + promptTemplate: { + textPromptTemplate: promptTemplate, + }, + inferenceConfig: { + textInferenceConfig: { + "maxTokens": 245, + "temperature": 0.3, + "topP": 0.9 + } + }, + }, }, - type: 'text', - answersource: 'BEDROCK KNOWLEDGE BASE' - } + type: 'KNOWLEDGE_BASE', + }, + }); + expect(result).toStrictEqual([ + { + _userInfo: { knowledgeBaseSessionId: "newSessionId" }, + got_hits: 1, + session: { qnabot_gotanswer: true }, + }, + expectedResult + ]); + }); + + test('bedrockRetrieveAndGenerate returns correct body when GuardrailConfiguration is overriden', async () => { + const sessionId = 'newSessionId'; + response.sessionId = sessionId; + const modifiedReq = _.cloneDeep(req) + modifiedReq._settings.BEDROCK_GUARDRAIL_IDENTIFIER = 'ds9asa' + modifiedReq._settings.BEDROCK_GUARDRAIL_VERSION = '2' + bedRockAgentMock.on(RetrieveAndGenerateCommand).resolves(response); + + const result = await bedrockRetrieveAndGenerate(modifiedReq, res); + expect(bedRockAgentMock).toHaveReceivedCommandTimes(RetrieveAndGenerateCommand, 1); + expect(bedRockAgentMock).toHaveReceivedCommandWith(RetrieveAndGenerateCommand, { + input: { + text: 'what is ec2?', + }, + retrieveAndGenerateConfiguration: { + knowledgeBaseConfiguration: { + knowledgeBaseId: 'testKnowledgeBaseId', + modelArn: `arn:aws:bedrock:${region}::foundation-model/testModel`, + retrievalConfiguration: { + vectorSearchConfiguration: { + numberOfResults: 1, + } + }, + generationConfiguration: { + promptTemplate: { + textPromptTemplate: promptTemplate, + }, + inferenceConfig: { + textInferenceConfig: { + "maxTokens": 245, + "temperature": 0.3, + "topP": 0.9 + } + }, + guardrailConfiguration: { + guardrailId: 'ds9asa', + guardrailVersion: '2' + }, + }, + }, + type: 'KNOWLEDGE_BASE', + }, + }); + expect(result).toStrictEqual([ + { + _userInfo: { knowledgeBaseSessionId: "newSessionId" }, + got_hits: 1, + session: { qnabot_gotanswer: true }, + }, + expectedResult ]); }); @@ -316,13 +600,30 @@ describe('bedrockAgents', () => { response.sessionId = sessionId const e = new Error('Invalid or Expired'); - sessionId = 'newSessionId'; + sessionId = 'newSessionId'; response.sessionId = sessionId; bedRockAgentMock.on(RetrieveAndGenerateCommand).rejects(e); - + await expect(bedrockRetrieveAndGenerate(req, res)).rejects.toThrowError(e); expect(bedRockAgentMock).toHaveReceivedCommandTimes(RetrieveAndGenerateCommand, 1); - + expect(qnabot.log).toHaveBeenCalledTimes(4); + }); + test('bedrockRetrieveAndGenerate handles ValidationException correctly', async () => { + let sessionId = 'testSessionId'; + res._userInfo.knowledgeBaseSessionId = sessionId + response.sessionId = sessionId + + const e = new Error('Model is not valid'); + e.name = "ValidationException"; + sessionId = 'newSessionId'; + response.sessionId = sessionId; + bedRockAgentMock.on(RetrieveAndGenerateCommand).rejects(e); + + await expect(bedrockRetrieveAndGenerate(req, res)).rejects.toThrowError(e); + expect(bedRockAgentMock).toHaveReceivedCommandTimes(RetrieveAndGenerateCommand, 2); + expect(qnabot.log).toHaveBeenCalledTimes(5); + + }); }); diff --git a/source/lambda/es-proxy-layer/test/bedrockModels.test.js b/source/lambda/es-proxy-layer/test/bedrockModels.test.js index e2a65bc01..f7f66390b 100644 --- a/source/lambda/es-proxy-layer/test/bedrockModels.test.js +++ b/source/lambda/es-proxy-layer/test/bedrockModels.test.js @@ -22,13 +22,28 @@ jest.mock('qnabot/settings'); jest.mock('qnabot/logging'); jest.mock('@aws-sdk/client-bedrock-runtime'); +const guardrails = { + guardrailIdentifier: 'test_id', + guardrailVersion: 1 +}; + const llmModelBodies = { 'amazon.titan-text-express-v1': { - textGenerationConfig: { maxTokenCount: 4096, stopSequences: [], temperature: 0, topP: 1 }, + textGenerationConfig: { maxTokenCount: 256, stopSequences: [], temperature: 0, topP: 1 }, inputText: 'test prompt', }, 'amazon.titan-text-lite-v1': { - textGenerationConfig: { maxTokenCount: 4096, stopSequences: [], temperature: 0, topP: 1 }, + textGenerationConfig: { maxTokenCount: 256, stopSequences: [], temperature: 0, topP: 1 }, + inputText: 'test prompt', + }, + 'amazon.titan-embed-text-v1': { + inputText: 'test prompt', + }, + 'amazon.titan-embed-text-v2': { + inputText: 'test prompt', + }, + 'amazon.titan-text-premier-v1': { + textGenerationConfig: { maxTokenCount: 256, stopSequences: [], temperature: 0, topP: 1 }, inputText: 'test prompt', }, 'ai21.j2-ultra-v1': { @@ -91,7 +106,7 @@ const llmModelBodies = { } ], }, - 'anthropic.claude-3-sonnet-20240229-v1:0': { + 'anthropic.claude-3-sonnet-20240229-v1': { max_tokens: 256, temperature: 0, top_k: 250, @@ -111,7 +126,7 @@ const llmModelBodies = { } ], }, - 'anthropic.claude-3-haiku-20240307-v1:0': { + 'anthropic.claude-3-haiku-20240307-v1': { max_tokens: 256, temperature: 0, top_k: 250, @@ -145,9 +160,6 @@ const llmModelBodies = { top_p: 0.9, prompt: 'test prompt', }, - 'amazon.titan-embed-text-v1': { - inputText: 'test prompt', - }, 'cohere.embed-english-v3': { texts: ['test prompt'], input_type: 'search_document', @@ -159,6 +171,20 @@ const llmModelBodies = { }; const llmModelResponses = { + 'amazon.titan-embed-text-v1': { + body: Buffer.from( + JSON.stringify({ + embedding: 'test response', + }) + ) + }, + 'amazon.titan-embed-text-v2': { + body: Buffer.from( + JSON.stringify({ + embedding: 'test response', + }) + ) + }, 'amazon.titan-text-express-v1': { body: Buffer.from( JSON.stringify({ @@ -181,6 +207,17 @@ const llmModelResponses = { }) ) }, + 'amazon.titan-text-premier-v1': { + body: Buffer.from( + JSON.stringify({ + results: [ + { + outputText: 'test response' + } + ] + }) + ) + }, 'ai21.j2-ultra-v1': { body: Buffer.from( JSON.stringify({ @@ -225,7 +262,7 @@ const llmModelResponses = { }) ) }, - 'anthropic.claude-3-haiku-20240307-v1:0': { + 'anthropic.claude-3-haiku-20240307-v1': { body: Buffer.from( JSON.stringify({ content: [ @@ -236,7 +273,7 @@ const llmModelResponses = { }) ) }, - 'anthropic.claude-3-sonnet-20240229-v1:0': { + 'anthropic.claude-3-sonnet-20240229-v1': { body: Buffer.from( JSON.stringify({ content: [ @@ -265,13 +302,6 @@ const llmModelResponses = { }) ) }, - 'amazon.titan-embed-text-v1': { - body: Buffer.from( - JSON.stringify({ - embedding: 'test response', - }) - ) - }, 'cohere.embed-english-v3': { body: Buffer.from( JSON.stringify({ @@ -288,6 +318,10 @@ const llmModelResponses = { }, }; +function isEmbedding(modelId) { + return modelId.includes('embed'); +}; + describe('bedrockModels', () => { beforeEach(() => { @@ -308,7 +342,7 @@ describe('bedrockModels', () => { e.name = 'ResourceNotFoundException'; bedRockMock.on(InvokeModelCommand).rejects(e); const error = new Error('{\"message\":\"Bedrock anthropic.claude-v1 returned ResourceNotFoundException: Could not resolve the foundation model from the provided model identifier. Please retry after selecting different Bedrock model in Cloudformation stack.\",\"type\":\"Error\"}') - await expect(invokeBedrockModel(modelId, textGenerationConfig, inputText)).rejects.toThrowError(error); + await expect(invokeBedrockModel(modelId, textGenerationConfig, inputText, guardrails)).rejects.toThrowError(error); }); test('invokeBedrockModel returns correct body', async () => { @@ -321,6 +355,11 @@ describe('bedrockModels', () => { modelId, } + if (!isEmbedding(modelId)) { + expectedCall.guardrailIdentifier = "test_id", + expectedCall.guardrailVersion = 1 + } + const sendMock = jest.fn().mockImplementation(() => { const body = llmModelResponses[modelId].body; return { @@ -334,7 +373,7 @@ describe('bedrockModels', () => { }; }); - const response = await invokeBedrockModel(modelId, {}, prompt); + const response = await invokeBedrockModel(modelId, {}, prompt, guardrails); expect(response).toEqual('test response'); expect(InvokeModelCommand).toHaveBeenCalledWith(expectedCall); @@ -351,6 +390,8 @@ describe('bedrockModels', () => { body: JSON.stringify({...llmModelBodies[modelId], textGenerationConfig:{...llmModelBodies[modelId].textGenerationConfig, ...params}}), contentType: 'application/json', modelId, + guardrailIdentifier: "test_id", + guardrailVersion: 1, } const body = llmModelResponses[modelId].body; @@ -366,7 +407,7 @@ describe('bedrockModels', () => { }; }); - const response = await invokeBedrockModel(modelId, params, prompt); + const response = await invokeBedrockModel(modelId, params, prompt, guardrails); expect(response).toEqual('test response'); expect(InvokeModelCommand).toHaveBeenCalledWith(expectedCall); @@ -388,6 +429,8 @@ describe('bedrockModels', () => { body: JSON.stringify({...llmModelBodies[modelId], ...params}), contentType: 'application/json', modelId, + guardrailIdentifier: "test_id", + guardrailVersion: 1, } const body = llmModelResponses[modelId].body; @@ -403,7 +446,7 @@ describe('bedrockModels', () => { }; }); - const response = await invokeBedrockModel(modelId, params, prompt); + const response = await invokeBedrockModel(modelId, params, prompt, guardrails); expect(response).toEqual('test response'); expect(InvokeModelCommand).toHaveBeenCalledWith(expectedCall); @@ -416,7 +459,7 @@ describe('bedrockModels', () => { const modelId = 'unsupported.provider'; try { - await invokeBedrockModel(modelId, {}, prompt); + await invokeBedrockModel(modelId, {}, prompt, guardrails); expect(true).toEqual(false); } catch (err) { expect(err.message).toEqual(`Unsupported model provider: unsupported`); @@ -437,11 +480,11 @@ describe('bedrockModels', () => { }); try { - await invokeBedrockModel(modelId, {}); + await invokeBedrockModel(modelId, {}, guardrails); expect(true).toEqual(false); } catch (err) { expect(err.message).toEqual( - `Exception parsing response body: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received undefined` + `Cannot read properties of undefined (reading 'guardrailIdentifier')` ); } }); diff --git a/source/lambda/es-proxy-layer/test/llm.fixtures.js b/source/lambda/es-proxy-layer/test/llm.fixtures.js index f15975904..526584f95 100644 --- a/source/lambda/es-proxy-layer/test/llm.fixtures.js +++ b/source/lambda/es-proxy-layer/test/llm.fixtures.js @@ -209,6 +209,8 @@ exports.req = { 'LLM_QA_NO_HITS_REGEX': 'Sorry, //remove comment to enable custom no match (no_hits) when LLM does not know the answer.', 'LLM_PROMPT_MAX_TOKEN_LIMIT': '800', + 'BEDROCK_GUARDRAIL_IDENTIFIER': '', + 'BEDROCK_GUARDRAIL_VERSION': '', 'DEFAULT_USER_POOL_JWKS_URL': 'https://cognito-idp.us-east-1.amazonaws.com/us-east-1_MqFhpJCyo/.well-known/jwks.json' }, diff --git a/source/lambda/es-proxy-layer/test/llm.test.js b/source/lambda/es-proxy-layer/test/llm.test.js index 52b7a3819..deb37a25d 100644 --- a/source/lambda/es-proxy-layer/test/llm.test.js +++ b/source/lambda/es-proxy-layer/test/llm.test.js @@ -17,7 +17,6 @@ const { SageMakerRuntime } = require('@aws-sdk/client-sagemaker-runtime'); const { BedrockRuntimeClient, InvokeModelCommand } = require('@aws-sdk/client-bedrock-runtime'); const { ChatMessageHistory } = require('langchain/memory'); const { TokenTextSplitter } = require('langchain/text_splitter'); -const { sanitize } = require('../lib/sanitizeOutput'); const { clean_context, @@ -412,7 +411,7 @@ describe('llm generate_query', () => { contentType: 'application/json', body: JSON.stringify({ textGenerationConfig: { - maxTokenCount: 4096, + maxTokenCount: 256, stopSequences: [], temperature: 0, topP: 1, @@ -676,6 +675,58 @@ describe('llm get_qa', () => { expect(response).toBe('sagemaker response'); }); + test('generates query when Bedrock guardrails are defined', async () => { + const clonedReq = _.cloneDeep(req); + clonedReq._settings.LLM_API = 'BEDROCK'; + clonedReq._settings.LLM_MODEL_ID = 'amazon.titan-text-lite-v1'; + clonedReq._settings.LLM_GENERATE_QUERY_MODEL_PARAMS = ''; + clonedReq._settings.BEDROCK_GUARDRAIL_IDENTIFIER = 'test_id'; + clonedReq._settings.BEDROCK_GUARDRAIL_VERSION = 1; + const sendMock = jest.fn().mockImplementation(() => { + return { + body: Buffer.from(JSON.stringify({ + results: [{ + outputText: 'bedrock response', + }] + })) + } + }); + + BedrockRuntimeClient.mockImplementation(() => { + return { + send: sendMock, + }; + }); + + const response = await generate_query(clonedReq); + + expect(sendMock).toBeCalled(); + expect(InvokeModelCommand).toBeCalledWith({ + accept: 'application/json', + modelId: 'amazon.titan-text-lite-v1', + contentType: 'application/json', + guardrailIdentifier: "test_id", + guardrailVersion: "1", + body: JSON.stringify({ + textGenerationConfig: { + maxTokenCount: 256, + stopSequences: [], + temperature: 0, + topP: 1, + }, + inputText: 'Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question.\nChat History: \n\nFollow Up Input: How can I publish Kindle books?\nStandalone question:', + }), + }); + expect(response.question).toBe('How can I publish Kindle books? / bedrock response'); + expect(response.llm_generated_query).toStrictEqual({ + concatenated: 'How can I publish Kindle books? / bedrock response', + orig: 'How can I publish Kindle books?', + result: 'bedrock response', + timing: expect.any(String), + }); + }); + + test('throws error if prompt cannot be truncated smaller than max token count', async () => { const clonedReq = _.cloneDeep(req); clonedReq._settings.LLM_QA_PROMPT_TEMPLATE = 'Some very long prompt that cannot be truncated. '.repeat(100); @@ -861,32 +912,4 @@ describe('llm isNoHits', () => { expect(result).toBe(false); }); -}); - -describe('should be able to sanitize LLM Outputs', () => { - it('should sanitize input data correctly', () => { - const inputData = '

Hello, world!

'; - const expectedOutput = '

Hello, world!

'; - const sanitizedData = sanitize(inputData); - expect(sanitizedData).toEqual(expectedOutput); - }); - - it('should handle empty input data', () => { - const inputData = ''; - const sanitizedData = sanitize(inputData); - expect(sanitizedData).toEqual(''); - }); - - it('should allow href', () => { - const inputData = 'Some text'; - const sanitizedData = sanitize(inputData); - expect(sanitizedData).toEqual('Some text'); - }); - - it('should handle normal response', () => { - const inputData = '

Sorry I don\'t know

'; - const sanitizedData = sanitize(inputData); - expect(sanitizedData).toEqual('

Sorry I don\'t know

'); - }); - }); - \ No newline at end of file +}); \ No newline at end of file diff --git a/source/lambda/es-proxy-layer/test/sanitizeOutput.test.js b/source/lambda/es-proxy-layer/test/sanitizeOutput.test.js new file mode 100644 index 000000000..746f5f183 --- /dev/null +++ b/source/lambda/es-proxy-layer/test/sanitizeOutput.test.js @@ -0,0 +1,62 @@ +/********************************************************************************************************************* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * + * with the License. A copy of the License is located at * + * * + * http://www.apache.org/licenses/ * + * * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * + * and limitations under the License. * + *********************************************************************************************************************/ + +const { sanitize, escapeHashMarkdown } = require('../lib/sanitizeOutput'); + +describe('should be able to sanitize LLM Outputs', () => { + it('should sanitize input data correctly', () => { + const inputData = '

Hello, world!

'; + const expectedOutput = '

Hello, world!

'; + const sanitizedData = sanitize(inputData); + expect(sanitizedData).toEqual(expectedOutput); + }); + + it('should handle empty input data', () => { + const inputData = ''; + const sanitizedData = sanitize(inputData); + expect(sanitizedData).toEqual(''); + }); + + it('should allow href', () => { + const inputData = 'Some text'; + const sanitizedData = sanitize(inputData); + expect(sanitizedData).toEqual('Some text'); + }); + + it('should handle normal response', () => { + const inputData = '

Sorry I don\'t know

'; + const sanitizedData = sanitize(inputData); + expect(sanitizedData).toEqual('

Sorry I don\'t know

'); + }); +}); + +describe('should be able to escape hash sybmbol to prevent markdown issue', () => { + test('escape hash sybmbol when it appears at the beginning of a line', () => { + const text1 = '# https://amazon.com/# https://docs.aws.amazon.com/# 6. first link is for amazon. 7. second link documentation.'; + const expectedOutput = '\\# https://amazon.com/# https://docs.aws.amazon.com/# 6. first link is for amazon. 7. second link documentation.'; + expect(escapeHashMarkdown(text1)).toBe(expectedOutput); + }); + + + test('should escape a # in the first word in the input string starts with multiple hash symbols', () => { + const text2 = '### three'; + const expectedOutput = '\\### three'; // jest will added extra \ so actual expectedOutput is '\### three' + expect(escapeHashMarkdown(text2)).toBe(expectedOutput); + }); + + test('should not escape hash symbols that appear in the middle of line', () => { + const text3 = 'In ### between'; + const expectedOutput = 'In ### between'; + expect(escapeHashMarkdown(text3)).toBe(expectedOutput); + }); + }); \ No newline at end of file diff --git a/source/lambda/export/index.js b/source/lambda/export/index.js index 9f837d8a4..e1a075c1c 100644 --- a/source/lambda/export/index.js +++ b/source/lambda/export/index.js @@ -21,48 +21,47 @@ const step = require('./lib/step'); const join = require('./lib/join'); const clean = require('./lib/clean'); +const outputBucket = process.env.OUTPUT_S3_BUCKET; +const step_status_ignore = ['Error', 'Completed', 'Sync Complete', 'Parsing content JSON', 'Creating FAQ'] + exports.step=async function(event,context,cb){ - console.log('step') + console.log('Initiating Export') console.log('Request',JSON.stringify(event,null,2)) - const Bucket=event.Records[0].s3.bucket.name + const inputBucket=event.Records[0].s3.bucket.name const Key=decodeURI(event.Records[0].s3.object.key) - const VersionId=_.get(event,'Records[0].s3.object.versionId') - console.log(Bucket,Key) + const initialVersionId=_.get(event,'Records[0].s3.object.versionId') try { - await waitUntilObjectExists({ - client: s3, - maxWaitTime: 10 - }, {Bucket,Key,VersionId}) - const res = await s3.send(new GetObjectCommand({Bucket,Key,VersionId})) - const readableStream = Buffer.concat(await res.Body.toArray()); - const config = JSON.parse(readableStream); - const step_status_ignore = ['Error', 'Completed', 'Sync Complete', 'Parsing content JSON', 'Creating FAQ'] - if (step_status_ignore.includes(config.status)===false) { - try { - console.log('Config:',JSON.stringify(config,null,2)) - switch(config.status){ - case 'Started': - await start(config); - break - case 'InProgress': - await step(config); - break - case 'Join': - await join(config); - break - case 'Clean': - await clean(config); - break - } - } catch (err) { - console.log(err) - config.status='Error' - config.message=_.get(err,'message',JSON.stringify(err)) - } - await s3.send(new PutObjectCommand({Bucket,Key,Body:JSON.stringify(config)})); - } - } catch (error) { + const startResult = await getStatusAndStartNextStep(inputBucket, Key, initialVersionId, start); + const stepResult = await getStatusAndStartNextStep(outputBucket, Key, startResult.VersionId, step); + const joinResult = await getStatusAndStartNextStep(outputBucket, Key, stepResult.VersionId, join); + await getStatusAndStartNextStep(outputBucket, Key, joinResult.VersionId, clean); + } + catch (error) { console.error("An error occured in S3 operations: ", error) cb(error) } } + +async function getStatusAndStartNextStep(Bucket, Key, VersionId, nextStep) { + await waitUntilObjectExists({ + client: s3, + maxWaitTime: 10 + }, {Bucket,Key,VersionId}) + const res = await s3.send(new GetObjectCommand({Bucket,Key,VersionId})) + const readableStream = Buffer.concat(await res.Body.toArray()); + const config = JSON.parse(readableStream); + if (step_status_ignore.includes(config.status)===false) { + try { + console.log(config.status) + console.log('Config:',JSON.stringify(config,null,2)) + await nextStep(config); + } catch (err) { + console.log(err) + config.status='Error' + config.message=_.get(err,'message',JSON.stringify(err)) + } + const putObjOutput = await s3.send(new PutObjectCommand({Bucket: outputBucket , Key, Body:JSON.stringify(config)})); + console.log('putObjOutput', JSON.stringify(putObjOutput, null, 2)) + return putObjOutput; + } +} diff --git a/source/lambda/export/jest.config.js b/source/lambda/export/jest.config.js index 489a971f5..2a5c8ab99 100644 --- a/source/lambda/export/jest.config.js +++ b/source/lambda/export/jest.config.js @@ -22,4 +22,8 @@ module.exports = { "/../aws-sdk-layer/" ], testTimeout: 200000 -}; \ No newline at end of file +}; + +process.env = Object.assign(process.env, { + OUTPUT_S3_BUCKET: 'contentdesigneroutputbucket' +}); \ No newline at end of file diff --git a/source/lambda/export/kendraSync.js b/source/lambda/export/kendraSync.js index 1ecfceef8..2e096e43d 100644 --- a/source/lambda/export/kendraSync.js +++ b/source/lambda/export/kendraSync.js @@ -115,7 +115,7 @@ exports.performSync = async function (event, context, cb) { async function update_status(bucket, new_stat) { const status_params = { Bucket: bucket, - Key: 'status/qna-kendra-faq.txt' + Key: 'status-export/qna-kendra-faq.txt' }; // NOSONAR TODO: check the return value of the object in case of an error... diff --git a/source/lambda/export/lib/start.js b/source/lambda/export/lib/start.js index 57be4a793..8b50366e8 100644 --- a/source/lambda/export/lib/start.js +++ b/source/lambda/export/lib/start.js @@ -19,6 +19,7 @@ module.exports = function (config) { config.status = 'InProgress'; config.startDate = (new Date()).toString(); config.parts = []; + config.bucket = process.env.OUTPUT_S3_BUCKET; return load(config, { endpoint: process.env.ES_ENDPOINT, diff --git a/source/lambda/export/package-lock.json b/source/lambda/export/package-lock.json index 7a136f73b..599d8aa29 100644 --- a/source/lambda/export/package-lock.json +++ b/source/lambda/export/package-lock.json @@ -1,12 +1,12 @@ { "name": "export", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "export", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "lodash": "^4.17.21" diff --git a/source/lambda/export/package.json b/source/lambda/export/package.json index b13ab41bc..69b05e47c 100644 --- a/source/lambda/export/package.json +++ b/source/lambda/export/package.json @@ -1,6 +1,6 @@ { "name": "export", - "version": "6.0.3", + "version": "6.1.0", "description": "QnABot Lambda handling export of QIDs", "main": "index.js", "scripts": { diff --git a/source/lambda/export/test/index.fixtures.js b/source/lambda/export/test/index.fixtures.js index 0554a7ef3..b3268dc3f 100644 --- a/source/lambda/export/test/index.fixtures.js +++ b/source/lambda/export/test/index.fixtures.js @@ -1,4 +1,4 @@ - /********************************************************************************************************************* +/********************************************************************************************************************* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * * * * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * @@ -10,16 +10,20 @@ * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * * and limitations under the License. * *********************************************************************************************************************/ - - const { GetObjectCommand } = require('@aws-sdk/client-s3'); - const { Readable } = require('stream'); - const { sdkStreamMixin } = require('@smithy/util-stream'); - - function mockStream(config, s3Mock) { - const stream = new Readable(); - stream.push(JSON.stringify(config)); - stream.push(null); - const sdkStream = sdkStreamMixin(stream); - s3Mock.on(GetObjectCommand).resolves({ Body: sdkStream }); - }; - exports.mockStream = mockStream; \ No newline at end of file + +const { GetObjectCommand } = require('@aws-sdk/client-s3'); +const { Readable } = require("stream"); +const { sdkStreamMixin } = require('@smithy/util-stream'); + +function mockStream(config, s3Mock, payload = "") { + const stream = new Readable(); + stream.push(JSON.stringify(config)); + stream.push(null); + const sdkStream = sdkStreamMixin(stream); + if (payload != "") { + s3Mock.on(GetObjectCommand, payload).resolves({ Body: sdkStream }) + } else { + s3Mock.on(GetObjectCommand).resolves({ Body: sdkStream }); + } +}; +exports.mockStream = mockStream; diff --git a/source/lambda/export/test/index.test.js b/source/lambda/export/test/index.test.js index 1fae9a81c..64387eb05 100644 --- a/source/lambda/export/test/index.test.js +++ b/source/lambda/export/test/index.test.js @@ -36,7 +36,7 @@ const event = { name: "exportBucket", }, object: { - key: "status/Export.csv", + key: "status-export/Export.csv", versionId: "tLkWAhY8v2rsaSPWqg2m", } } @@ -44,6 +44,96 @@ const event = { ] }; +function generateConfigAndVersionId(currentStatus) { + const config = { status : currentStatus }; + const versionId = Math.random().toString(36).substring(3,9); + return { config: config, versionId: versionId } +} + +function initializeStartStepMocks() { + const startConfig = generateConfigAndVersionId('Started'); + s3Mock.on(PutObjectCommand, {"Body": "{\"status\":\"Started\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv"}).resolves( + { + '$metadata': { + httpStatusCode: 200, + requestId: '', + extendedRequestId: '', + cfId: undefined, + attempts: 1, + totalRetryDelay: 0 + }, + Expiration: '', + ETag: '""', + ServerSideEncryption: '', + VersionId: startConfig.versionId + }) + mockStream(startConfig.config, s3Mock, {"Bucket": "exportBucket", "Key": "status-export/Export.csv", "VersionId": "tLkWAhY8v2rsaSPWqg2m"}) + return { versionId: startConfig.versionId, config: startConfig.config } +} + +function initializeInProgressStepMocks(startVersionId) { + const stepConfig = generateConfigAndVersionId('InProgress'); + s3Mock.on(PutObjectCommand, {"Body": "{\"status\":\"InProgress\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv"}).resolves( + { + '$metadata': { + httpStatusCode: 200, + requestId: '', + extendedRequestId: '', + cfId: undefined, + attempts: 1, + totalRetryDelay: 0 + }, + Expiration: '', + ETag: '""', + ServerSideEncryption: '', + VersionId: stepConfig.versionId + }) + mockStream(stepConfig.config, s3Mock, {"Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv", "VersionId": startVersionId}); + return { versionId: stepConfig.versionId, config: stepConfig.config } +} + +function initializeJoinStepMocks(inProgressVersionId) { + const joinConfig = generateConfigAndVersionId('Join'); + s3Mock.on(PutObjectCommand, {"Body": "{\"status\":\"Join\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv"}).resolves( + { + '$metadata': { + httpStatusCode: 200, + requestId: '', + extendedRequestId: '', + cfId: undefined, + attempts: 1, + totalRetryDelay: 0 + }, + Expiration: '', + ETag: '""', + ServerSideEncryption: '', + VersionId: joinConfig.versionId + }) + mockStream(joinConfig.config, s3Mock, {"Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv", "VersionId": inProgressVersionId}); + return { versionId: joinConfig.versionId, config: joinConfig.config } +} + +function initializeCleanStepMocks(lexVersionId) { + const cleanConfig = generateConfigAndVersionId('Clean'); + s3Mock.on(PutObjectCommand, {"Body": "{\"status\":\"Clean\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv"}).resolves( + { + '$metadata': { + httpStatusCode: 200, + requestId: '', + extendedRequestId: '', + cfId: undefined, + attempts: 1, + totalRetryDelay: 0 + }, + Expiration: '', + ETag: '""', + ServerSideEncryption: '', + VersionId: cleanConfig.versionId + }) + mockStream(cleanConfig.config, s3Mock, {"Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv", "VersionId": lexVersionId}); + return { versionId: cleanConfig.versionId, config: cleanConfig.config } +} + describe('when calling index function', () => { beforeEach(() => { @@ -55,58 +145,28 @@ describe('when calling index function', () => { jest.clearAllMocks(); }); - it('should call start and update status correctly', async () => { - const config = { status : 'Started' }; - mockStream(config, s3Mock); + it('should call the different steps and update status as expected', async () => { + const startStepInfo = initializeStartStepMocks(); + const inProgressStepInfo = initializeInProgressStepMocks(startStepInfo.versionId); + const joinStepInfo = initializeJoinStepMocks(inProgressStepInfo.versionId); + const cleanStepInfo = initializeCleanStepMocks(joinStepInfo.versionId); await index.step(event, null, jest.fn()); expect(start).toHaveBeenCalledTimes(1); - expect(start).toHaveBeenCalledWith(config); - expect(step).toHaveBeenCalledTimes(0); - expect(join).toHaveBeenCalledTimes(0); - expect(clean).toHaveBeenCalledTimes(0); - expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(GetObjectCommand, {"Bucket": "exportBucket", "Key": "status/Export.csv", "VersionId": "tLkWAhY8v2rsaSPWqg2m"}); - expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(PutObjectCommand, {"Body": "{\"status\":\"Started\"}", "Bucket": "exportBucket", "Key": "status/Export.csv"}); - }); - - it('should call step and update status correctly', async () => { - const config = { status : 'InProgress' }; - mockStream(config, s3Mock); - await index.step(event, null, jest.fn()); + expect(start).toHaveBeenCalledWith(startStepInfo.config); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(1,GetObjectCommand, {"Bucket": "exportBucket", "Key": "status-export/Export.csv", "VersionId": "tLkWAhY8v2rsaSPWqg2m"}); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(1,PutObjectCommand, {"Body": "{\"status\":\"Started\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv"}); expect(step).toHaveBeenCalledTimes(1); - expect(step).toHaveBeenCalledWith(config); - expect(join).toHaveBeenCalledTimes(0); - expect(clean).toHaveBeenCalledTimes(0); - expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(GetObjectCommand, {"Bucket": "exportBucket", "Key": "status/Export.csv", "VersionId": "tLkWAhY8v2rsaSPWqg2m"}); - expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(PutObjectCommand, {"Body": "{\"status\":\"InProgress\"}", "Bucket": "exportBucket", "Key": "status/Export.csv"}); - }); - - it('should call join and update status correctly', async () => { - const config = { status : 'Join' }; - mockStream(config, s3Mock); - await index.step(event, null, jest.fn()); + expect(step).toHaveBeenCalledWith(inProgressStepInfo.config); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(2,GetObjectCommand, {"Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv", "VersionId": startStepInfo.versionId}); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(2,PutObjectCommand, {"Body": "{\"status\":\"InProgress\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv"}); expect(join).toHaveBeenCalledTimes(1); - expect(join).toHaveBeenCalledWith(config); - expect(clean).toHaveBeenCalledTimes(0); - expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(GetObjectCommand, {"Bucket": "exportBucket", "Key": "status/Export.csv", "VersionId": "tLkWAhY8v2rsaSPWqg2m"}); - expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(PutObjectCommand, {"Body": "{\"status\":\"Join\"}", "Bucket": "exportBucket", "Key": "status/Export.csv"}); - }); - - it('should call clean and update status correctly', async () => { - const config = { status : 'Clean' }; - mockStream(config, s3Mock); - await index.step(event, null, jest.fn()); + expect(join).toHaveBeenCalledWith(joinStepInfo.config); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(3,GetObjectCommand, {"Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv", "VersionId": inProgressStepInfo.versionId}); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(3,PutObjectCommand, {"Body": "{\"status\":\"Join\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv"}); expect(clean).toHaveBeenCalledTimes(1); - expect(clean).toHaveBeenCalledWith(config); - expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(GetObjectCommand, {"Bucket": "exportBucket", "Key": "status/Export.csv", "VersionId": "tLkWAhY8v2rsaSPWqg2m"}); - expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(PutObjectCommand, {"Body": "{\"status\":\"Clean\"}", "Bucket": "exportBucket", "Key": "status/Export.csv"}); + expect(clean).toHaveBeenCalledWith(cleanStepInfo.config); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(4,GetObjectCommand, {"Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv", "VersionId": joinStepInfo.versionId}); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(4,PutObjectCommand, {"Body": "{\"status\":\"Clean\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-export/Export.csv"}); }); it('should handle an error', async () => { diff --git a/source/lambda/export/test/kendraSync.test.js b/source/lambda/export/test/kendraSync.test.js index c1a3e2a18..d9fdf43cd 100644 --- a/source/lambda/export/test/kendraSync.test.js +++ b/source/lambda/export/test/kendraSync.test.js @@ -35,7 +35,7 @@ const event = { name: 'exportBucket' }, object: { - key: 'status/testExport.csv', + key: 'status-export/testExport.csv', versionId: 'tLkWAhY8v2rsaSPWqg2m' } } @@ -110,39 +110,39 @@ describe('when calling performSync function', () => { expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 4); expect(s3Mock).toHaveReceivedNthCommandWith(2, GetObjectCommand, { 'Bucket': 'exportBucket', - 'Key': 'status/testExport.csv', + 'Key': 'status-export/testExport.csv', 'VersionId': 'tLkWAhY8v2rsaSPWqg2m' }); expect(s3Mock).toHaveReceivedNthCommandWith(3, GetObjectCommand, { 'Body': '{"status":"Parsing content JSON"}', 'Bucket': 'testExportBucket', - 'Key': 'status/qna-kendra-faq.txt' + 'Key': 'status-export/qna-kendra-faq.txt' }); expect(s3Mock).toHaveReceivedNthCommandWith(5, GetObjectCommand, { 'Body': '{"status":"Creating FAQ"}', 'Bucket': 'testExportBucket', - 'Key': 'status/qna-kendra-faq.txt' + 'Key': 'status-export/qna-kendra-faq.txt' }); expect(s3Mock).toHaveReceivedNthCommandWith(7, GetObjectCommand, { 'Body': '{"status":"Sync Complete"}', 'Bucket': 'testExportBucket', - 'Key': 'status/qna-kendra-faq.txt' + 'Key': 'status-export/qna-kendra-faq.txt' }); expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 3); expect(s3Mock).toHaveReceivedNthCommandWith(4, PutObjectCommand, { 'Body': '{"status":"Parsing content JSON"}', 'Bucket': 'testExportBucket', - 'Key': 'status/qna-kendra-faq.txt' + 'Key': 'status-export/qna-kendra-faq.txt' }); expect(s3Mock).toHaveReceivedNthCommandWith(6, PutObjectCommand, { 'Body': '{"status":"Creating FAQ"}', 'Bucket': 'testExportBucket', - 'Key': 'status/qna-kendra-faq.txt' + 'Key': 'status-export/qna-kendra-faq.txt' }); expect(s3Mock).toHaveReceivedNthCommandWith(8, PutObjectCommand, { 'Body': '{"status":"Sync Complete"}', 'Bucket': 'testExportBucket', - 'Key': 'status/qna-kendra-faq.txt' + 'Key': 'status-export/qna-kendra-faq.txt' }); }); @@ -193,29 +193,29 @@ describe('when calling performSync function', () => { expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 3); expect(s3Mock).toHaveReceivedNthCommandWith(2, GetObjectCommand, { 'Bucket': 'exportBucket', - 'Key': 'status/testExport.csv', + 'Key': 'status-export/testExport.csv', 'VersionId': 'tLkWAhY8v2rsaSPWqg2m' }); expect(s3Mock).toHaveReceivedNthCommandWith(3, GetObjectCommand, { 'Body': '{"status":"Parsing content JSON"}', 'Bucket': 'testExportBucket', - 'Key': 'status/qna-kendra-faq.txt' + 'Key': 'status-export/qna-kendra-faq.txt' }); expect(s3Mock).toHaveReceivedNthCommandWith(5, GetObjectCommand, { 'Body': '{"status":"Error"}', 'Bucket': 'testExportBucket', - 'Key': 'status/qna-kendra-faq.txt' + 'Key': 'status-export/qna-kendra-faq.txt' }); expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 2); expect(s3Mock).toHaveReceivedNthCommandWith(4, PutObjectCommand, { 'Body': '{"status":"Parsing content JSON"}', 'Bucket': 'testExportBucket', - 'Key': 'status/qna-kendra-faq.txt' + 'Key': 'status-export/qna-kendra-faq.txt' }); expect(s3Mock).toHaveReceivedNthCommandWith(6, PutObjectCommand, { 'Body': '{"status":"Error"}', 'Bucket': 'testExportBucket', - 'Key': 'status/qna-kendra-faq.txt' + 'Key': 'status-export/qna-kendra-faq.txt' }); }); diff --git a/source/lambda/export/test/lib/start.test.js b/source/lambda/export/test/lib/start.test.js index e08e0c719..c1cb99444 100644 --- a/source/lambda/export/test/lib/start.test.js +++ b/source/lambda/export/test/lib/start.test.js @@ -53,6 +53,7 @@ describe('test start function', () => { parts: ['part'] }; const expectedConfig = { + bucket: 'contentdesigneroutputbucket', index: 'index', filter: 'filter', status: 'InProgress', @@ -78,6 +79,7 @@ describe('test start function', () => { parts: ['part'] }; const expectedConfig = { + bucket: 'contentdesigneroutputbucket', index: 'index', filter: null, status: 'InProgress', diff --git a/source/lambda/fulfillment/lib/middleware/1_parse.js b/source/lambda/fulfillment/lib/middleware/1_parse.js index 398dafb15..7ebdba83c 100644 --- a/source/lambda/fulfillment/lib/middleware/1_parse.js +++ b/source/lambda/fulfillment/lib/middleware/1_parse.js @@ -40,9 +40,6 @@ function getClientType(req) { // Try to determine which Lex client is being used based on patterns in the req - best effort attempt. const voiceortext = req._preferredResponseType == 'SSML' ? 'Voice' : 'Text'; - // for LexV1 channels -- check for x-amz-lex:channel-type requestAttribute - // more information on deploying an Amazon Lex V1 Bot on a Messaging Platform: https://docs.aws.amazon.com/lex/latest/dg/example1.html - // for LexV2 channels -- check for x-amz-lex:channels:platform requestAttribute // more information on deploying an Amazon Lex V2 Bot on a Messaging Platform: https://docs.aws.amazon.com/lexv2/latest/dg/deploying-messaging-platform.html @@ -65,7 +62,7 @@ function getClientType(req) { return `LEX.GenesysCloud.${voiceortext}`; } if (/^.*-.*-\d:.*-.*-.*-.*$/.test(_.get(req, '_event.sessionId', _.get(req, '_event.userId')))) { // NOSONAR - javascript:S5852 - input is user controlled and we have a limit on the number of characters - // sessionId (LexV2) or userId (LexV1) pattern to detect lex-web-uithrough use of cognito id as sessionId/userId: e.g. us-east-1:a8e1f7b2-b20d-441c-9698-aff8b519d8d5 + // sessionId (LexV2) pattern to detect lex-web-uithrough use of cognito id as sessionId/userId: e.g. us-east-1:a8e1f7b2-b20d-441c-9698-aff8b519d8d5 // NOSONAR TODO: add another clientType indicator for lex-web-ui? return `LEX.LexWebUI.${voiceortext}`; } diff --git a/source/lambda/fulfillment/lib/middleware/3_query.js b/source/lambda/fulfillment/lib/middleware/3_query.js index ceb1ed5ff..b803d0bdc 100644 --- a/source/lambda/fulfillment/lib/middleware/3_query.js +++ b/source/lambda/fulfillment/lib/middleware/3_query.js @@ -50,10 +50,9 @@ const esquery = require('../../../../../../../../../../opt/lib/query.js'); async function specialtyBotInvocation(req, res) { const specialtyBot = _.get(req, 'session.qnabotcontext.specialtyBot', undefined); - const specialtyBotAlias = _.get(req, 'session.qnabotcontext.specialtyBotAlias', undefined); const specialtyBotChainingConfig = _.get(req, 'session.qnabotcontext.sBChainingConfig', undefined); qnabot.log('Handling specialtyBot'); - const resp = await specialtyBotRouter.routeRequest(req, res, specialtyBot, specialtyBotAlias); + const resp = await specialtyBotRouter.routeRequest(req, res, specialtyBot); qnabot.log(`SpecialtyBotRouterResp: ${JSON.stringify(resp, null, 2)}`); const isSpecialtyBotComplete = _.get(resp, 'res.session.qnabotcontext.specialtyBot', '') === ''; if (isSpecialtyBotComplete) { @@ -176,7 +175,6 @@ async function getPostQuery(queryLambdaArn, req, res, specialtyArn) { const chaining_configuration = _.get(postQuery.res, 'result.conditionalChaining', undefined); const specialtybot_hook = _.get(postQuery.res, 'result.botRouting.specialty_bot', undefined); const specialtybot_name = _.get(postQuery.res, 'result.botRouting.specialty_bot_name', undefined); - const specialtybot_alias = _.get(postQuery.res, 'result.botRouting.specialty_bot_alias', undefined); const specialtybot_attributes_to_merge = _.get(postQuery.res, 'result.botRouting.specialty_bot_session_attributes_to_merge', undefined); const specialtybot_start_up_text = _.get(postQuery.res, 'result.botRouting.specialty_bot_start_up_text', undefined); const specialtybot_attributes_to_receive = _.get(postQuery.res, 'result.botRouting.specialty_bot_session_attributes_to_receive', undefined); @@ -193,7 +191,6 @@ async function getPostQuery(queryLambdaArn, req, res, specialtyArn) { } else if (specialtybot_hook && specialtybot_name) { _.set(postQuery, 'res.session.qnabotcontext.specialtyBot', specialtybot_hook); _.set(postQuery, 'res.session.qnabotcontext.specialtyBotName', specialtybot_name); - _.set(postQuery, 'res.session.qnabotcontext.specialtyBotAlias', specialtybot_alias); _.set(postQuery, 'res.session.qnabotcontext.specialtyBotMergeAttributes', specialtybot_attributes_to_merge); _.set(postQuery, 'res.session.qnabotcontext.sBChainingConfig', chaining_configuration); _.set(postQuery, 'res.session.qnabotcontext.sBAttributesToReceive', specialtybot_attributes_to_receive); @@ -202,7 +199,6 @@ async function getPostQuery(queryLambdaArn, req, res, specialtyArn) { if (specialtybot_start_up_text) { _.set(postQuery, 'req.session.qnabotcontext.specialtyBot', specialtybot_hook); _.set(postQuery, 'req.session.qnabotcontext.specialtyBotName', specialtybot_name); - _.set(postQuery, 'req.session.qnabotcontext.specialtyBotAlias', specialtybot_alias); _.set(postQuery, 'req.session.qnabotcontext.sBMergeAttributes', specialtybot_attributes_to_merge); _.set(postQuery, 'req.session.qnabotcontext.sBChainingConfig', chaining_configuration); _.set(postQuery, 'req.session.qnabotcontext.sBAttributesToReceive', specialtybot_attributes_to_receive); diff --git a/source/lambda/fulfillment/lib/middleware/lex.js b/source/lambda/fulfillment/lib/middleware/lex.js index 5e69bfaa8..3bf6bc11b 100644 --- a/source/lambda/fulfillment/lib/middleware/lex.js +++ b/source/lambda/fulfillment/lib/middleware/lex.js @@ -28,10 +28,6 @@ function isConnectClientVoice(req) { return _.get(req, '_clientType') === 'LEX.AmazonConnect.Voice'; } -function isLexV1(req) { - return req._lexVersion === 'V1'; -} - function isElicitResponse(request, response) { let result = false; const qnabotcontextJSON = _.get(response, 'session.qnabotcontext'); @@ -68,33 +64,6 @@ function trapIgnoreWords(req, transcript) { return trs.trim().length === 0; } -function parseLexV1Event(event) { - const out = { - _type: 'LEX', - _lexVersion: 'V1', - _userId: _.get(event, 'userId', 'Unknown Lex User'), - intentname: _.get(event, 'sessionState.intent.name'), - question: _.get(event, 'inputTranscript').trim(), - session: _.mapValues( - _.get(event, 'sessionAttributes', {}), - (x) => { - try { - return JSON.parse(x); - } catch (e) { - return x; - } - }, - ), - channel: _.get(event, 'requestAttributes.\'x-amz-lex:channel-type\''), - }; - - // check if we pass in a qnabotUserId as a session attribute, if so, use it, else default - out._userId = _.get(event, 'sessionState.sessionAttributes.qnabotUserId', out._userId); - qnabot.log(`QnaBot User Id: ${out._userId}`); - - return out; -} - function parseLexV2Event(event) { const out = { _type: 'LEX', @@ -157,12 +126,7 @@ exports.parse = async function (req) { throw new Error(`Error - inputTranscript contains only words specified in setting CONNECT_IGNORE_WORDS: "${event.inputTranscript}"`); } - let out; - if (!_.get(event, 'sessionId')) { - out = parseLexV1Event(event); - } else { - out = parseLexV2Event(event); - } + const out = parseLexV2Event(event); return out; }; @@ -215,27 +179,6 @@ function isInteractiveMessage(response) { return (isCard(response.card) && (_.get(response.card, 'imageUrl', '').trim() || (_.get(response.card, 'buttons', []).length > 0))); } -function isFallbackIntent(request) { - return (_.get(request, '_event.currentIntent.name', '').toLowerCase()).includes('fallback'); -} - -function buildResponseCardV1(response) { - let responseCardV1 = null; - if (isCard(response.card) && (_.get(response.card, 'imageUrl', '').trim() || (_.get(response.card, 'buttons', []).length > 0))) { - responseCardV1 = { - version: '1', - contentType: 'application/vnd.amazonaws.card.generic', - genericAttachments: [_.pickBy({ - title: _.get(response, 'card.title', 'Title').slice(0, 80), // LexV1 title limit - subTitle: _.get(response.card, 'subTitle')?.slice(0, 80), - imageUrl: _.get(response.card, 'imageUrl'), - buttons: _.get(response.card, 'buttons'), - })], - }; - } - return responseCardV1; -} - function buildImageResponseCardV2(response) { let imageResponseCardV2 = null; if (isCard(response.card) && (_.get(response.card, 'imageUrl', '').trim() || (_.get(response.card, 'buttons', []).length > 0))) { @@ -295,13 +238,6 @@ function buildInteractiveMessageTemplate(response) { return JSON.stringify(template); } -function buildV1InteractiveMessageResponse(request, response) { - return { - contentType: 'CustomPayload', - content: buildInteractiveMessageTemplate(response), - }; -} - function buildV2InteractiveMessageResponse(request, response) { return [ { @@ -311,23 +247,6 @@ function buildV2InteractiveMessageResponse(request, response) { ]; } -function copyResponseCardtoSessionAttribute(response) { - const responseCardV1 = buildResponseCardV1(response); - if (responseCardV1) { - // copy Lex v1 response card to appContext session attribute used by lex-web-ui - // - allows repsonse card display even when using postContent (voice) with Lex (not otherwise supported by Lex) - // - allows Lex limit of 5 buttons to be exceeded when using lex-web-ui - let tmp; - try { - tmp = JSON.parse(_.get(response, 'session.appContext', '{}')); - } catch (e) { - tmp = _.get(response, 'session.appContext', '{}'); - } - tmp.responseCard = responseCardV1; - response.session.appContext = JSON.stringify(tmp); - } - return response; -} function applyLexResponseCardButtonLimits(request, response) { // Lex has limit of max 5 buttons in the responsecard. if we have more than 5, use the first 5 only. @@ -339,11 +258,9 @@ function applyLexResponseCardButtonLimits(request, response) { buttons = _.get(response.card, 'buttons', []); } - // LexV1 and V2 have different limits for button text so enforce them here - // NOTE: LexV1 documentation formally states that 15 is the max limit for - // button title; however, empirical testing shows that 80 characters are supported - const textLimit = isLexV1(request) ? 80 : 50; - const valueLimit = isLexV1(request) ? 1000 : 50; + // LexV2 Limits for button text + const textLimit = 50; + const valueLimit = 50; qnabot.log(`Limiting button text to first ${textLimit} characters to adhere to Lex limits.`); for (let i = 0; i < buttons.length; i++) { response.card.buttons[i].text = response.card.buttons[i].text.slice(0, textLimit); @@ -369,35 +286,6 @@ function applyConnectInteractiveMessageButtonLimits(response) { return response; } -function getV1CloseTemplate(request, response) { - return { - sessionAttributes: _.get(response, 'session', {}), - dialogAction: _.pickBy({ - type: 'Close', - fulfillmentState: 'Fulfilled', - message: { - contentType: response.type, - content: response.message, - }, - }), - }; -} - -function getV1ElicitTemplate(request, response) { - return { - sessionAttributes: _.get(response, 'session', {}), - dialogAction: { - type: 'ElicitSlot', - intentName: _.get(request, '_event.currentIntent.name'), - slotToElicit: 'slot', - message: { - contentType: response.type, - content: response.message, - }, - }, - }; -} - function getV2CloseTemplate(request, response) { return { sessionState: { @@ -457,25 +345,6 @@ function getV2DialogCodeHookResponseTemplate(request, response) { }; } -function assembleLexV1Response(request, response) { - let out = {}; - - if ((isConnectClientChat(request) && isInteractiveMessage(response) && !isFallbackIntent(request))) { - out = getV1ElicitTemplate(request, response); - out.dialogAction.message = buildV1InteractiveMessageResponse(request, response); - } else if (isElicitResponse(request, response) && !isFallbackIntent(request)) { - out = getV1ElicitTemplate(request, response); - } else { - out = getV1CloseTemplate(request, response); - } - - if (!isConnectClient(request)) { - response = applyLexResponseCardButtonLimits(request, response); - out.dialogAction.responseCard = buildResponseCardV1(response); - } - return out; -} - function assembleLexV2Response(request, response) { let out = {}; @@ -511,15 +380,7 @@ exports.assemble = function (request, response) { qnabot.log('filterButtons'); response = filterButtons(response); - qnabot.log('copyResponseCardToSessionAttributes'); - response = copyResponseCardtoSessionAttribute(response); - - let out; - if (isLexV1(request)) { - out = assembleLexV1Response(request, response); - } else { - out = assembleLexV2Response(request, response); - } + const out = assembleLexV2Response(request, response); qnabot.log('Lex response:', JSON.stringify(out, null, 2)); return out; diff --git a/source/lambda/fulfillment/lib/middleware/lexRouter.js b/source/lambda/fulfillment/lib/middleware/lexRouter.js index 0d6f13230..19e1e80c5 100644 --- a/source/lambda/fulfillment/lib/middleware/lexRouter.js +++ b/source/lambda/fulfillment/lib/middleware/lexRouter.js @@ -17,7 +17,6 @@ * Handle response from Lex Bot and update session attributes as needed. */ const _ = require('lodash'); -const { LexRuntimeService: LexRuntime } = require('@aws-sdk/client-lex-runtime-service') const { LexRuntimeV2 } = require('@aws-sdk/client-lex-runtime-v2'); const customSdkConfig = require('sdk-config/customSdkConfig'); const region = process.env.AWS_REGION || 'us-east-1'; @@ -94,25 +93,11 @@ async function translate_res(req, res) { } /** - * Call postText and use promise to return data response. + * Call recognizeText and use promise to return data response. * @param lexClient * @param params * @returns {*} */ -function lexV1ClientRequester(params) { - const lexV1Client = new LexRuntime(customSdkConfig('C001', { apiVersion: '2016-11-28', region })); - return new Promise((resolve, reject) => { - lexV1Client.postText(params, (err, data) => { - if (err) { - qnabot.log(err, err.stack); - reject(`Lex client request error:${err}`); - } else { - qnabot.log(`Lex client response:${JSON.stringify(data, null, 2)}`); - resolve(data); - } - }); - }); -} function lexV2ClientRequester(params) { const lexV2Client = new LexRuntimeV2(customSdkConfig('C002', { region })); return new Promise((resolve, reject) => { @@ -203,46 +188,33 @@ async function handleRequest(req, res, botName, botAlias) { // Resolve bot details from environment, if using simple name for built-in bots const botIdentity = mapFromSimpleName(botName); - // Determine if we using LexV1 or LexV2.. LexV2 bot is identified by "lexv2::BotId/BotAliasId/LocaleId" - let response = {}; - if (botIdentity.toLowerCase().startsWith('lexv2::')) { - // lex v2 response bot - const ids = botIdentity.split('::')[1]; - let [botId, botAliasId, localeId] = ids.split('/'); - localeId = localeId || 'en_US'; - const params = { - botId, - botAliasId, - localeId, - sessionId: tempBotUserID, - text: respText, + const response = {}; + // Lex V2 response bot + const ids = botIdentity.split('::')[1]; + let [botId, botAliasId, localeId] = ids.split('/'); + localeId = localeId || 'en_US'; + const params = { + botId, + botAliasId, + localeId, + sessionId: tempBotUserID, + text: respText, - }; - qnabot.log(`Lex V2 parameters: ${JSON.stringify(params)}`); - const lexv2response = await lexV2ClientRequester(params); - qnabot.log(`Lex V2 response: ${JSON.stringify(lexv2response)}`); - response.message = _.get(lexv2response, 'messages[0].content', ''); - // lex v2 FallbackIntent match means it failed to fill desired slot(s). - if (lexv2response.sessionState.intent.name === 'FallbackIntent' - || lexv2response.sessionState.intent.state === 'Failed') { - response.dialogState = 'Failed'; - } else { - response.dialogState = lexv2response.sessionState.dialogAction.type; - } - const slots = _.get(lexv2response, 'sessionState.intent.slots'); - if (slots) { - response.slots = _.mapValues(slots, (x) => _.get(x, 'value.interpretedValue')); - } + }; + qnabot.log(`Lex V2 parameters: ${JSON.stringify(params)}`); + const lexv2response = await lexV2ClientRequester(params); + qnabot.log(`Lex V2 response: ${JSON.stringify(lexv2response)}`); + response.message = _.get(lexv2response, 'messages[0].content', ''); + // lex v2 FallbackIntent match means it failed to fill desired slot(s). + if (lexv2response.sessionState.intent.name === 'FallbackIntent' + || lexv2response.sessionState.intent.state === 'Failed') { + response.dialogState = 'Failed'; } else { - // lex v1 response bot - const params = { - botAlias, - botName: mapFromSimpleName(botName), - inputText: respText, - userId: tempBotUserID, - }; - qnabot.log(`Lex V1 parameters: ${JSON.stringify(params)}`); - response = await lexV1ClientRequester(params); + response.dialogState = lexv2response.sessionState.dialogAction.type; + } + const slots = _.get(lexv2response, 'sessionState.intent.slots'); + if (slots) { + response.slots = _.mapValues(slots, (x) => _.get(x, 'value.interpretedValue')); } return response; } diff --git a/source/lambda/fulfillment/lib/middleware/specialtyBotRouter.js b/source/lambda/fulfillment/lib/middleware/specialtyBotRouter.js index 1f1decfae..0e184b036 100644 --- a/source/lambda/fulfillment/lib/middleware/specialtyBotRouter.js +++ b/source/lambda/fulfillment/lib/middleware/specialtyBotRouter.js @@ -19,7 +19,6 @@ */ const _ = require('lodash'); const { Lambda } = require('@aws-sdk/client-lambda'); -const { LexRuntimeService: LexRuntime } = require('@aws-sdk/client-lex-runtime-service'); const { LexRuntimeV2 } = require('@aws-sdk/client-lex-runtime-v2'); const customSdkConfig = require('sdk-config/customSdkConfig'); const region = process.env.AWS_REGION || 'us-east-1'; @@ -176,21 +175,6 @@ async function lambdaClientRequester(name, req) { return obj; } -function lexV1ClientRequester(params) { - const lexV1Client = new LexRuntime(customSdkConfig('C014', { apiVersion: '2016-11-28', region })); - return new Promise((resolve, reject) => { - lexV1Client.postText(params, (err, data) => { - if (err) { - qnabot.log(err, err.stack); - reject(`Lex client request error:${err}`); - } else { - qnabot.log(`Lex client response:${JSON.stringify(data, null, 2)}`); - resolve(data); - } - }); - }); -} - function lexV2ClientRequester(params) { const lexV2Client = new LexRuntimeV2(customSdkConfig('C014', { region })); return new Promise((resolve, reject) => { @@ -233,7 +217,7 @@ function mapFromSimpleName(botName) { * @param botAlias * @returns {Promise<*>} */ -async function handleRequest(req, res, botName, botAlias) { +async function handleRequest(req, res, botName) { if (botName.toLowerCase().startsWith('lambda::')) { // target bot is a Lambda Function const lambdaName = botName.split('::')[1]; @@ -250,38 +234,27 @@ async function handleRequest(req, res, botName, botAlias) { tempBotUserID = tempBotUserID.replaceAll(/[^a-zA-Z0-9\-._:]/g,'_'); // NOSONAR - javascript:S5852 - input is user controlled and we have a limit on the number of characters - // Determine if we using LexV1 or LexV2.. LexV2 bot is identified by "lexv2::BotId/BotAliasId/LocaleId" - if (botIdentity.toLowerCase().startsWith('lexv2::')) { - const res = {}; - const ids = botIdentity.split('::')[1]; - let [botId, botAliasId, localeId] = ids.split('/'); - localeId = localeId || 'en_US'; - const params = { - botId, - botAliasId, - localeId, - sessionId: tempBotUserID, - sessionState: { - sessionAttributes: generateMergedAttributes(req), - }, - text: _.get(req, 'question'), - }; - const lexv2response = await processLexV2Response(params, res); - - const slots = _.get(lexv2response, 'sessionState.intent.slots'); - if (slots) { - res.slots = _.mapValues(slots, (x) => _.get(x, 'value.interpretedValue')); - } - return res; - } + // LexV2 bot is identified by "lexv2::BotId/BotAliasId/LocaleId" + const response = {}; + const ids = botIdentity.split('::')[1]; + let [botId, botAliasId, localeId] = ids.split('/'); + localeId = localeId || 'en_US'; const params = { - botAlias, - botName: botIdentity, - inputText: _.get(req, 'question'), - sessionAttributes: generateMergedAttributes(req), - userId: getBotUserId(req), + botId, + botAliasId, + localeId, + sessionId: tempBotUserID, + sessionState: { + sessionAttributes: generateMergedAttributes(req), + }, + text: _.get(req, 'question'), }; - const response = await lexV1ClientRequester(params); + const lexv2response = await processLexV2Response(params, response); + + const slots = _.get(lexv2response, 'sessionState.intent.slots'); + if (slots) { + response.slots = _.mapValues(slots, (x) => _.get(x, 'value.interpretedValue')); + } return response; } @@ -337,7 +310,6 @@ function getDialogState(lexv2response) { function endUseOfSpecialtyBot(req, res, welcomeBackMessage) { delete res.session.qnabotcontext.specialtyBot; delete res.session.qnabotcontext.specialtyBotName; - delete res.session.qnabotcontext.specialtyBotAlias; delete res.session.qnabotcontext.specialtySessionAttributes; delete res.session.qnabotcontext.sBAttributesToReceive; delete res.session.qnabotcontext.sBAttributesToReceiveNamespace; @@ -518,7 +490,7 @@ function getRespCard(botResp) { * @param hook * @returns {Promise<{}>} */ -async function processResponse(req, res, hook, alias) { +async function processResponse(req, res, hook) { qnabot.log(`specialtyBotRouter request: ${JSON.stringify(req, null, 2)}`); qnabot.log(`specialtyBotRouter response: ${JSON.stringify(res, null, 2)}`); @@ -538,7 +510,7 @@ async function processResponse(req, res, hook, alias) { qnabot.log(`returning resp for user requested exit: ${JSON.stringify(resp, null, 2)}`); return resp; } - const botResp = await handleRequest(req, res, hook, alias); + const botResp = await handleRequest(req, res, hook); qnabot.log(`specialty botResp: ${JSON.stringify(botResp, null, 2)}`); if (botResp.message || _.get(botResp, 'dialogState', '') === 'ReadyForFulfillment') { let lexBotIsFulfilled; diff --git a/source/lambda/fulfillment/package-lock.json b/source/lambda/fulfillment/package-lock.json index 1252fe845..3ca1a1324 100644 --- a/source/lambda/fulfillment/package-lock.json +++ b/source/lambda/fulfillment/package-lock.json @@ -1,12 +1,12 @@ { "name": "fulfillment", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "fulfillment", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-dynamodb": "^3.511.0", @@ -98,16 +98,16 @@ } }, "node_modules/@aws-sdk/client-dynamodb": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.622.0.tgz", - "integrity": "sha512-rzbxDj0JjWYg/t9JSjTJYp1bphSAZvX/wwHqO7FHxRuCzYTEKB9iAQC/eBrWRDJBbSEoI0PMwa0kR0V7yS+whQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.621.0.tgz", + "integrity": "sha512-aczOoVyufYwBCc/zZKJOP/xwbnojKQJ6Y8O7ZAZnxMPRyZXKXpoAxmlxLfOU6GUzXqzXdvj+Ir3VBd7MWB4KuQ==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-endpoint-discovery": "3.620.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", @@ -119,26 +119,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -318,9 +318,9 @@ } }, "node_modules/@aws-sdk/client-dynamodb/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -444,16 +444,16 @@ } }, "node_modules/@aws-sdk/client-lex-models-v2": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-models-v2/-/client-lex-models-v2-3.622.0.tgz", - "integrity": "sha512-CJW3V05azrjqYVaQnWlaRUzNTRGXj5NuudpIHr3VeJcKIM3XjWeqqewdpJaRNiNyKAOJHhFg0OZqitelHwcRTg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-models-v2/-/client-lex-models-v2-3.621.0.tgz", + "integrity": "sha512-Ypt2JYZLQPJLAsBbx3iX1pMgbGkSsof8rQ4FvcpIZE7MDPeo0M7AKz3X5joIny3DJYk1AjG3xdhYmyZU2VOTkA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -464,26 +464,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -662,9 +662,9 @@ } }, "node_modules/@aws-sdk/client-lex-models-v2/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -788,16 +788,16 @@ } }, "node_modules/@aws-sdk/client-lex-runtime-service": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-service/-/client-lex-runtime-service-3.622.0.tgz", - "integrity": "sha512-XiMdKqWiIUjpItHfCp1sQEpMzhKnsaFNz/lrxfb+IPiCs8of63gKwpJ1tpi4DeEmuA8384VA4cU3bGAUgrpx5Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-service/-/client-lex-runtime-service-3.621.0.tgz", + "integrity": "sha512-QAE4OYDKzBucvLnhqoNaGVp8Mm75C/5rqcBdhiRoTpnOUP7DtUZRGVRnTqht9vuzJxqUvqUSUkkmtIfT/Jrl9g==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -808,26 +808,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1006,9 +1006,9 @@ } }, "node_modules/@aws-sdk/client-lex-runtime-service/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -1132,21 +1132,22 @@ } }, "node_modules/@aws-sdk/client-lex-runtime-v2": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-v2/-/client-lex-runtime-v2-3.622.0.tgz", - "integrity": "sha512-zNc6tyx79TZ7ORSvzDFfVm2SzkcAlx3U6jcwTTbZDv+eMgNelBvYhRowQxgVIQ9briow+0BfnAOmbHEDHD+V5Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-v2/-/client-lex-runtime-v2-3.621.0.tgz", + "integrity": "sha512-UFjOmdBlu3lbTjd36VRbzInkhRyFwW3yeQM+y0O2qZY/8wHKaYkHsqNphSnpE/KAL/QusbczVKdEtpbzt2np9A==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/eventstream-handler-node": "3.620.0", "@aws-sdk/middleware-eventstream": "3.620.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-signing": "3.620.0", "@aws-sdk/middleware-user-agent": "3.620.0", "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", @@ -1154,7 +1155,7 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/eventstream-serde-browser": "^3.0.5", "@smithy/eventstream-serde-config-resolver": "^3.0.3", "@smithy/eventstream-serde-node": "^3.0.4", @@ -1163,22 +1164,21 @@ "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", "@smithy/util-stream": "^3.1.3", "@smithy/util-utf8": "^3.0.0", @@ -1355,9 +1355,9 @@ } }, "node_modules/@aws-sdk/client-lex-runtime-v2/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -1481,13 +1481,13 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.622.0.tgz", - "integrity": "sha512-DJwUqVR/O2lImbktUHOpaQ8XElNBx3JmWzTT2USg6jh3ErgG1CS6LIV+VUlgtxGl+tFN/G6AcAV8SdnnGydB8Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", + "@aws-sdk/core": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -1498,26 +1498,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1529,14 +1529,14 @@ } }, "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.622.0.tgz", - "integrity": "sha512-dwWDfN+S98npeY77Ugyv8VIHKRHN+n/70PWE4EgolcjaMrTINjvUh9a/SypFEs5JmBOAeCQt8S2QpM3Wvzp+pQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -1547,26 +1547,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1577,7 +1577,7 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/abort-controller": { @@ -1747,9 +1747,9 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -2039,9 +2039,9 @@ } }, "node_modules/@aws-sdk/client-sso/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -2165,15 +2165,15 @@ } }, "node_modules/@aws-sdk/client-sts": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.622.0.tgz", - "integrity": "sha512-Yqtdf/wn3lcFVS42tR+zbz4HLyWxSmztjVW9L/yeMlvS7uza5nSkWqP/7ca+RxZnXLyrnA4jJtSHqykcErlhyg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -2184,26 +2184,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -2381,9 +2381,9 @@ } }, "node_modules/@aws-sdk/client-sts/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -2507,15 +2507,15 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.622.0.tgz", - "integrity": "sha512-q1Ct2AjPxGtQBKtDpqm1umu3f4cuWMnEHTuDa6zjjaj+Aq/C6yxLgZJo9SlcU0tMl8rUCN7oFonszfTtp4Y0MA==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", "dependencies": { - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "fast-xml-parser": "4.4.1", @@ -2692,9 +2692,9 @@ } }, "node_modules/@aws-sdk/core/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -2855,16 +2855,16 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.622.0.tgz", - "integrity": "sha512-VUHbr24Oll1RK3WR8XLUugLpgK9ZuxEm/NVeVqyFts1Ck9gsKpRg1x4eH7L7tW3SJ4TDEQNMbD7/7J+eoL2svg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/property-provider": "^3.1.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" @@ -3040,9 +3040,9 @@ } }, "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -3166,14 +3166,14 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.622.0.tgz", - "integrity": "sha512-cD/6O9jOfzQyo8oyAbTKnyRO89BIMSTzwaN4NxGySC6pYVTqxNSWdRwaqg/vKbwJpjbPGGYYXpXEW11kop7dlg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -3186,7 +3186,7 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/property-provider": { @@ -3225,15 +3225,15 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.622.0.tgz", - "integrity": "sha512-keldwz4Q/6TYc37JH6m43HumN7Vi+R0AuGuHn5tBV40Vi7IiqEzjpiE+yvsHIN+duUheFLL3j/o0H32jb+14DQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -3332,11 +3332,11 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.622.0.tgz", - "integrity": "sha512-zrSoBVM2JlwvkBtrcUd4J/9CrG+T+hUy9r6jwo5gonFIN3QkneR/pqpbUn/n32Zy3zlzCo2VfB31g7MjG7kJmg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", "dependencies": { - "@aws-sdk/client-sso": "3.622.0", + "@aws-sdk/client-sso": "3.621.0", "@aws-sdk/token-providers": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", @@ -3689,6 +3689,70 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.620.0.tgz", + "integrity": "sha512-gxI7rubiaanUXaLfJ4NybERa9MGPNg2Ycl/OqANsozrBnR3Pw8vqy3EuVImQOyn2pJ2IFvl8ZPoSMHf4pX56FQ==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/middleware-user-agent": { "version": "3.620.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", @@ -5168,15 +5232,15 @@ } }, "node_modules/@smithy/core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", - "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" @@ -5352,9 +5416,9 @@ } }, "node_modules/@smithy/core/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -5848,14 +5912,14 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", - "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", "dependencies": { "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -6033,9 +6097,9 @@ } }, "node_modules/@smithy/middleware-retry/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -6496,12 +6560,12 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", - "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", "dependencies": { "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -6677,9 +6741,9 @@ } }, "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -6803,15 +6867,15 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", - "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", "dependencies": { "@smithy/config-resolver": "^3.0.5", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, @@ -6986,9 +7050,9 @@ } }, "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", diff --git a/source/lambda/fulfillment/package.json b/source/lambda/fulfillment/package.json index 3513c4b10..7b69d3d94 100644 --- a/source/lambda/fulfillment/package.json +++ b/source/lambda/fulfillment/package.json @@ -1,6 +1,6 @@ { "name": "fulfillment", - "version": "6.0.3", + "version": "6.1.0", "description": "QnABot Lambda handling fulfillment of user requests", "main": "handler.js", "scripts": { diff --git a/source/lambda/fulfillment/test/lib/middleware/1_parse.fixtures.js b/source/lambda/fulfillment/test/lib/middleware/1_parse.fixtures.js index 98ea008f4..efd793487 100644 --- a/source/lambda/fulfillment/test/lib/middleware/1_parse.fixtures.js +++ b/source/lambda/fulfillment/test/lib/middleware/1_parse.fixtures.js @@ -17,7 +17,15 @@ exports.createRequestObject = function (question, outputDialogMode, version, eve "_event": { "inputTranscript": question, "outputDialogMode": outputDialogMode, - "userId": "mocked_user_id" + "userId": "mocked_user_id", + "sessionState": { + "intent": { + "name": "mock-name" + } + }, + "request": { + "locale": "mock-locale" + } }, "_setting": { "PROTECTED_UTTERANCES": "Thumbs up, Thumbs down" @@ -25,7 +33,7 @@ exports.createRequestObject = function (question, outputDialogMode, version, eve "question": question, }; if (version) { - request._event.version= version; + request._event.version = version; } if(eventRequest) { request._event.request = eventRequest; diff --git a/source/lambda/fulfillment/test/lib/middleware/1_parse.test.js b/source/lambda/fulfillment/test/lib/middleware/1_parse.test.js index b78d3b292..38e19773b 100644 --- a/source/lambda/fulfillment/test/lib/middleware/1_parse.test.js +++ b/source/lambda/fulfillment/test/lib/middleware/1_parse.test.js @@ -38,7 +38,7 @@ describe('parse function with Lex event', () => { settings.get_parameter.mockReturnValue('https://cognito-idp.us-east-1.amazonaws.com/us-east-1dsfsfjl'); }); - test('when parsing request with sentimemt & multilang support disabled', async () => { + test('when parsing request with sentiment & multilang support disabled', async () => { settings.getSettings.mockReturnValue(parseFixtures.defaultSettings); const res = {}; const parseResponse = await parse( diff --git a/source/lambda/fulfillment/test/lib/middleware/3_query.test.js b/source/lambda/fulfillment/test/lib/middleware/3_query.test.js index e72e335bd..f79281065 100644 --- a/source/lambda/fulfillment/test/lib/middleware/3_query.test.js +++ b/source/lambda/fulfillment/test/lib/middleware/3_query.test.js @@ -117,7 +117,6 @@ describe('when calling query function', () => { const expectedResponse = queryFixtures.createMockRoutingResponse("specialtyBot", ""); expectedResponse.res.session.qnabotcontext.specialtyBot = "mock_specialty_bot"; expectedResponse.res.session.qnabotcontext.specialtyBotName = "mock_specialty_bot_name"; - expectedResponse.res.session.qnabotcontext.specialtyBotAlias = "mock_specialty_bot_alias"; expect(util.invokeLambda).toHaveBeenCalled(); expect(response).toEqual(expectedResponse); }); diff --git a/source/lambda/fulfillment/test/lib/middleware/lex.fixtures.js b/source/lambda/fulfillment/test/lib/middleware/lex.fixtures.js index 557852c87..c06ef4390 100644 --- a/source/lambda/fulfillment/test/lib/middleware/lex.fixtures.js +++ b/source/lambda/fulfillment/test/lib/middleware/lex.fixtures.js @@ -54,10 +54,6 @@ exports.createRequestObject = function (question, clientType, lexVersion, curren "question": question }; - - if (lexVersion === "V1") { - request._event.sessionAttributes = { "idtokenjwt": "" } - } if (lexVersion === "V2") { request._event.invocationSource = "FulfillmentCodeHook"; request._event.sessionState.sessionAttributes = { "idtokenjwt": "" }; diff --git a/source/lambda/fulfillment/test/lib/middleware/lex.test.js b/source/lambda/fulfillment/test/lib/middleware/lex.test.js index b36b94297..6b993231d 100644 --- a/source/lambda/fulfillment/test/lib/middleware/lex.test.js +++ b/source/lambda/fulfillment/test/lib/middleware/lex.test.js @@ -38,36 +38,6 @@ describe('when calling parse function', () => { rejects.toThrowError('Error - inputTranscript contains only words specified in setting CONNECT_IGNORE_WORDS: "MockIgnore1 MockIgnore2"'); }); - test('should able to parse Lexv1 request successfully', async () => { - let parsedRequest = await lex.parse(lexFixtures.createRequestObject("What is QnABot", "LEX.LexWebUI.Text")); - expect(parsedRequest.question).toEqual("What is QnABot"); - expect(parsedRequest._lexVersion).toEqual("V1"); - expect(parsedRequest._userId).toEqual("mock_user_id"); - expect(parsedRequest.intentname).toEqual("mockIntent"); - - //Request containing some ignore words - const mockRequest = lexFixtures.createRequestObject("MockIgnore1 MockIgnore2", "LEX.AmazonConnect.Text", "V1"); - mockRequest._settings.CONNECT_IGNORE_WORDS = "MockIgnore1" - parsedRequest = await lex.parse(mockRequest); - expect(parsedRequest.question).toEqual("MockIgnore1 MockIgnore2"); - expect(parsedRequest._lexVersion).toEqual("V1"); - }); - - test('should able to parse Lexv1 request with sessionAttributes successfully', async () => { - let parsedRequest = await lex.parse(lexFixtures.createRequestObject("What is QnABot", "LEX.LexWebUI.Text", "V1")); - expect(parsedRequest.question).toEqual("What is QnABot"); - expect(parsedRequest._lexVersion).toEqual("V1"); - expect(parsedRequest._userId).toEqual("mock_user_id"); - expect(parsedRequest.intentname).toEqual("mockIntent"); - - const mockRequest = lexFixtures.createRequestObject("What is QnABot", "LEX.LexWebUI.Text", "V1"); - mockRequest._event.sessionAttributes = { "mockField": "{\"key1\": \"val1\" }" }; - parsedRequest = await lex.parse(mockRequest); - expect(parsedRequest.question).toEqual("What is QnABot"); - expect(parsedRequest._lexVersion).toEqual("V1"); - expect(parsedRequest.session).toEqual({ "mockField": { "key1": "val1" } }); - }); - test('should able to parse Lexv2 request successfully', async () => { let parsedRequest = await lex.parse(lexFixtures.createRequestObject("What is QnABot", "LEX.LexWebUI.Text", "V2")); expect(parsedRequest.question).toEqual("What is QnABot"); @@ -128,75 +98,6 @@ describe('when calling assemble function', () => { jest.clearAllMocks(); }); - // LexV1 Tests - test('should be able to assemble Lexv1 response successfully', () => { - const assembledResponse = lex.assemble(lexFixtures.createRequestObject("What is QnABot", "LEX.LexWebUI.Text", "V1"), - lexFixtures.createResponseObject()); - expect(assembledResponse.dialogAction.type).toEqual("Close"); - expect(assembledResponse.dialogAction.fulfillmentState).toEqual("Fulfilled"); - expect(assembledResponse.dialogAction.message.content).toEqual("The Q and A Bot uses Amazon Lex and Alexa to provide a natural language interface for your FAQ knowledge base, so your users can just ask a question and get a quick and relevant answer."); - - }); - - test('should be able to assemble Lexv1 with _clientType as LEX.Slack.Text', () => { - let assembledResponse = lex.assemble(lexFixtures.createRequestObject("What is QnABot", "LEX.Slack.Text", "V1"), - lexFixtures.createResponseObject()); - expect(assembledResponse.dialogAction.type).toEqual("Close"); - expect(assembledResponse.dialogAction.fulfillmentState).toEqual("Fulfilled"); - expect(assembledResponse.dialogAction.message.content).toEqual("*QnaBot*\n\nThe Q and A Bot uses and to provide a natural language interface for your FAQ knowledge base. Now your users can just ask a ​_question_​ and get a quick and relevant ​_answer_​.\n"); - - //with no markdown text - const mockResponse = lexFixtures.createResponseObject(); - mockResponse.result.alt.markdown = ""; - assembledResponse = lex.assemble(lexFixtures.createRequestObject("What is QnABot", "LEX.Slack.Text", "V1"), - mockResponse); - expect(assembledResponse.dialogAction.message.content).toEqual("The Q and A Bot uses Amazon Lex and Alexa to provide a natural language interface for your FAQ knowledge base, so your users can just ask a question and get a quick and relevant answer."); - }); - - - test('LexV1 verify copyResponseCardtoSessionAttribute', () => { - const mockResponse = lexFixtures.createResponseObject(true); - mockResponse.card.buttons = [{ "text": "mockText", "value": "mockValue" }, { "text": "", "value": "" }]; - const assembledResponse = lex.assemble(lexFixtures.createRequestObject("What is QnABot", "LEX.LexWebUI.Text", "V1"), - mockResponse); - expect(assembledResponse.dialogAction.fulfillmentState).toEqual("Fulfilled"); - expect(assembledResponse.dialogAction.message.content).toEqual("The Q and A Bot uses Amazon Lex and Alexa to provide a natural language interface for your FAQ knowledge base, so your users can just ask a question and get a quick and relevant answer."); - expect(assembledResponse.dialogAction.responseCard).toEqual({ - "version": "1", - "contentType": "application/vnd.amazonaws.card.generic", - "genericAttachments": [ - { - "title": "mock_title", "buttons": [{ "text": "mockText", "value": "mockValue" }] - } - ] - }); - }); - - test('verify LexV1 buildV1InteractiveMessageResponse', () => { - const assembledResponse = lex.assemble(lexFixtures.createRequestObject("What is QnABot", "LEX.AmazonConnect.Text", "V1", "testIntent"), - lexFixtures.createResponseObject(true)); - expect(assembledResponse.dialogAction.type).toEqual("ElicitSlot"); - expect(assembledResponse.dialogAction.intentName).toEqual("testIntent"); - expect(assembledResponse.dialogAction.message.content).toEqual('{\"templateType\":\"ListPicker\",\"version\":\"1.0\",\"data\":{\"content\":{\"title\":\"The Q and A Bot uses Amazon Lex and Alexa to provide a natural language interface for your FAQ knowledge base, so your users can just ask a question and get a quick and relevant answer.\",\"elements\":[{\"title\":\"mockText\"}],\"subtitle\":\"mock_title\"}}}'); - }); - - test('verify LexV1 elicit Response', () => { - let mockResponse = lexFixtures.createResponseObject(); - mockResponse.session.qnabotcontext = "{\"elicitResponse\": {\"responsebot\": \"mock_response_bot\", \"responsetext\": \"mock_response_text\"}}" - let assembledResponse = lex.assemble(lexFixtures.createRequestObject("What is QnABot", "LEX.LexWebUI.Text", "V1", "testIntent"), - mockResponse); - expect(assembledResponse.dialogAction.type).toEqual("ElicitSlot"); - expect(assembledResponse.dialogAction.intentName).toEqual("testIntent"); - expect(assembledResponse.dialogAction.message.content).toEqual('The Q and A Bot uses Amazon Lex and Alexa to provide a natural language interface for your FAQ knowledge base, so your users can just ask a question and get a quick and relevant answer.'); - - mockResponse.session.qnabotcontext = "{\"specialtyBot\": \"testBot\"}" - assembledResponse = lex.assemble(lexFixtures.createRequestObject("What is QnABot", "LEX.LexWebUI.Text", "V1", "testIntent"), - mockResponse); - expect(assembledResponse.dialogAction.type).toEqual("ElicitSlot"); - expect(assembledResponse.dialogAction.intentName).toEqual("testIntent"); - expect(assembledResponse.dialogAction.message.content).toEqual('The Q and A Bot uses Amazon Lex and Alexa to provide a natural language interface for your FAQ knowledge base, so your users can just ask a question and get a quick and relevant answer.'); - }); - // LexV2 Tests test('should be able to assemble Lexv2 response successfully', () => { const assembledResponse = lex.assemble(lexFixtures.createRequestObject("What is QnABot", "LEX.LexWebUI.Text", "V2"), @@ -326,8 +227,6 @@ describe('when calling assemble function', () => { }); }); - - test('verify LexV2 ImageResponseCard response', () => { const mockRequest = lexFixtures.createRequestObject("What is QnABot", "LEX.LexWebUI.Text", "V2"); const mockResponse = lexFixtures.createResponseObject(); diff --git a/source/lambda/fulfillment/test/lib/middleware/lexRouter.fixtures.js b/source/lambda/fulfillment/test/lib/middleware/lexRouter.fixtures.js index 6c71999cd..beafa6dd2 100644 --- a/source/lambda/fulfillment/test/lib/middleware/lexRouter.fixtures.js +++ b/source/lambda/fulfillment/test/lib/middleware/lexRouter.fixtures.js @@ -178,19 +178,6 @@ exports.createResponseObject = function (message) { return response; }; -exports.getLexV1Response = function (dialogState, message) { - const response = { - "botVersion": "live", - "dialogState": dialogState, - "intentName": "mockIntent", - "message": message ? message : "Mock Response", - "sentimentResponse": { - "sentimentLabel": "mockLabel", - } - } - return response; -}; - exports.getLexV2Response = function (dialogState, message, intentName, state) { return { "botVersion": "live", diff --git a/source/lambda/fulfillment/test/lib/middleware/lexRouter.test.js b/source/lambda/fulfillment/test/lib/middleware/lexRouter.test.js index a967af8f9..82329c155 100644 --- a/source/lambda/fulfillment/test/lib/middleware/lexRouter.test.js +++ b/source/lambda/fulfillment/test/lib/middleware/lexRouter.test.js @@ -13,7 +13,6 @@ const lexRouter = require('../../../lib/middleware/lexRouter'); const _ = require('lodash'); const lexRouterFixtures = require('./lexRouter.fixtures') -const { LexRuntimeService: LexRuntime } = require('@aws-sdk/client-lex-runtime-service') const { LexRuntimeV2 } = require('@aws-sdk/client-lex-runtime-v2'); const multilanguage = require('../../../lib/middleware/multilanguage'); jest.mock('../../../lib/middleware/multilanguage'); @@ -55,152 +54,6 @@ describe('when calling elicitResponse function', () => { expect(response.res.session.qnabotcontext.elicitResponse.progress).toBe("Fulfilled"); }); - test('verify response when LexV1 Bot responds with Fulfilled dialogState', async () => { - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - callback(null, lexRouterFixtures.getLexV1Response("Fulfilled")); - }); - const response = await lexRouter.elicitResponse(lexRouterFixtures.createRequestObject("What is QnABot"), - lexRouterFixtures.createResponseObject(), "mockBotName"); - expect(response.res.session.qnabot_gotanswer).toBe(true); - expect(response.res.message).toBe("Mock Response"); - expect(response.res.plainMessage).toBe("Mock Response"); - expect(response.res.session.qnabotcontext.elicitResponse.progress).toBe("Fulfilled"); - }); - - test('verify response call translate when Native Language is not the same', async () => { - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - callback(null, lexRouterFixtures.getLexV1Response("Fulfilled")); - }); - const response = await lexRouter.elicitResponse(lexRouterFixtures.createRequestObject("Que es QnABot", "", "Spanish"), - lexRouterFixtures.createResponseObject(), "mockBotName"); - expect(response.res.session.qnabot_gotanswer).toBe(true); - expect(response.res.message).toBe("Mock Response"); - expect(response.res.plainMessage).toBe("Mock Response"); - expect(response.res.session.qnabotcontext.elicitResponse.progress).toBe("Fulfilled"); - }); - - test('verify response call translate when Native Language is not the same with Speak tags', async () => { - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - callback(null, lexRouterFixtures.getLexV1Response("Fulfilled", "AWS QnA Bot is great. I can speak very fast. I can say tomato and tomato. Visit docs.aws.amazon.com/polly/latest/dg/supportedtags for more information.")); - }); - const response = await lexRouter.elicitResponse(lexRouterFixtures.createRequestObject("Que es QnABot", "", "Spanish"), - lexRouterFixtures.createResponseObject("The Q and A Bot uses Amazon Lex"), "mockBotName"); - expect(response.res.session.qnabot_gotanswer).toBe(true); - expect(response.res.message).toBe("AWS QnA Bot is great. I can speak very fast. I can say tomato and tomato. Visit docs.aws.amazon.com/polly/latest/dg/supportedtags for more information."); - expect(response.res.plainMessage).toBe("AWS QnA Bot is great. I can speak very fast. I can say tomato and tomato. Visit docs.aws.amazon.com/polly/latest/dg/supportedtags for more information."); - expect(response.res.session.qnabotcontext.elicitResponse.progress).toBe("Fulfilled"); - }); - - test('verify response when LexV1 Bot responds with default dialogState', async () => { - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - callback(null, lexRouterFixtures.getLexV1Response("default")); - }); - let response = await lexRouter.elicitResponse(lexRouterFixtures.createRequestObject("What is QnABot"), - lexRouterFixtures.createResponseObject(), "mockBotName"); - expect(response.res.session.qnabot_gotanswer).toBe(true); - expect(response.res.message).toBe("Mock Response"); - expect(response.res.plainMessage).toBe("Mock Response"); - expect(response.res.session.qnabotcontext.elicitResponse.progress).toBe("default"); - - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - const mockResponse = lexRouterFixtures.getLexV1Response("default"); - mockResponse.message = null; - callback(null, mockResponse); - }); - response = await lexRouter.elicitResponse(lexRouterFixtures.createRequestObject("What is QnABot"), - lexRouterFixtures.createResponseObject(), "mockBotName"); - expect(response.res.message).toBe("Please try again."); - expect(response.res.session.qnabotcontext.elicitResponse.progress).toBe("default"); - }); - - test('Error from LexV1 request', async () => { - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - callback(new Error("Mock Error"), null); - }); - await expect(lexRouter.elicitResponse(lexRouterFixtures.createRequestObject("What is QnABot"), - lexRouterFixtures.createResponseObject(), "mockBotName")).rejects.toEqual('Lex client request error:Error: Mock Error'); - }); - - test('verify response when LexV1 Bot responds with ElicitIntent dialogState', async () => { - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - callback(null, lexRouterFixtures.getLexV1Response("ElicitIntent")); - }); - let response = await lexRouter.elicitResponse(lexRouterFixtures.createRequestObject("What is QnABot"), - lexRouterFixtures.createResponseObject(), "mockBotName"); - expect(response.res.session.qnabot_gotanswer).toBe(true); - expect(response.res.message).toBe("Mock Response"); - expect(response.res.plainMessage).toBe("Mock Response"); - expect(response.res.session.qnabotcontext.elicitResponse.progress).toBe("ElicitIntent"); - - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - callback(null, lexRouterFixtures.getLexV1Response("ElicitSlot")); - }); - response = await lexRouter.elicitResponse(lexRouterFixtures.createRequestObject("What is QnABot"), - lexRouterFixtures.createResponseObject(), "mockBotName"); - expect(response.res.message).toBe("Mock Response"); - expect(response.res.session.qnabotcontext.elicitResponse.progress).toBe("ElicitSlot"); - }); - - test('verify response when LexV1 Bot responds with ConfirmIntent dialogState', async () => { - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - callback(null, lexRouterFixtures.getLexV1Response("ConfirmIntent")); - }); - const response = await lexRouter.elicitResponse(lexRouterFixtures.createRequestObject("What is QnABot"), - lexRouterFixtures.createResponseObject(), "mockBotName"); - expect(response.res.session.qnabot_gotanswer).toBe(true); - expect(response.res.message).toBe("Mock Response"); - expect(response.res.plainMessage).toBe("Mock Response"); - expect(response.res.session.qnabotcontext.elicitResponse.progress).toBe("ConfirmIntent"); - expect(response.res.card).toBeDefined(); - }); - - test('verify response when LexV1 Bot responds with ConfirmIntent dialogState & ssml message type', async () => { - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - callback(null, lexRouterFixtures.getLexV1Response("ConfirmIntent", "Mock Response")); - }); - const response = await lexRouter.elicitResponse(lexRouterFixtures.createRequestObject("What is QnABot", "SSML"), - lexRouterFixtures.createResponseObject(), "mockBotName"); - expect(response.res.session.qnabot_gotanswer).toBe(true); - expect(response.res.message).toBe("Mock Response"); - expect(response.res.plainMessage).toBe("Mock Response"); - expect(response.res.session.qnabotcontext.elicitResponse.progress).toBe("ConfirmIntent"); - expect(response.res.card).toBeDefined(); - }); - - test('verify response when LexV1 Bot responds with Failed dialogState', async () => { - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - callback(null, lexRouterFixtures.getLexV1Response("Failed", "Mock Response")); - }); - let response = await lexRouter.elicitResponse(lexRouterFixtures.createRequestObject("What is QnABot", "SSML"), - lexRouterFixtures.createResponseObject(), "mockBotName"); - expect(response.res.session.qnabot_gotanswer).toBe(true); - expect(response.res.message).toBe("Please try again."); - expect(response.res.plainMessage).toBe("Please try again."); - expect(response.res.session.qnabotcontext.elicitResponse.progress).toBe("ErrorHandling"); - - const mockResponse = lexRouterFixtures.createResponseObject(); - mockResponse.session.qnabotcontext.elicitResponse = { "loopCount": 6 }; - console.log(`mockResponse :: ${JSON.stringify(mockResponse)}`); - response = await lexRouter.elicitResponse(lexRouterFixtures.createRequestObject("What is QnABot", "SSML"), - mockResponse, "mockBotName"); - expect(response.res.session.qnabot_gotanswer).toBe(true); - expect(response.res.message).toBe("Your response was not understood. Please start again."); - expect(response.res.plainMessage).toBe("Your response was not understood. Please start again."); - expect(response.res.session.qnabotcontext.elicitResponse.progress).toBe("Failed"); - }); - - test('verify response when LexV2 Bot responds with Fulfilled dialogState', async () => { jest.spyOn(LexRuntimeV2.prototype, 'recognizeText') .mockImplementation((request, callback) => { diff --git a/source/lambda/fulfillment/test/lib/middleware/specialtyBotRouter.fixtures.js b/source/lambda/fulfillment/test/lib/middleware/specialtyBotRouter.fixtures.js index 3e1bdfc8e..160e3a3f5 100644 --- a/source/lambda/fulfillment/test/lib/middleware/specialtyBotRouter.fixtures.js +++ b/source/lambda/fulfillment/test/lib/middleware/specialtyBotRouter.fixtures.js @@ -189,23 +189,6 @@ exports.createResponseObject = function (message) { return response; }; -exports.getLexV1Response = function (dialogState, message) { - const response = { - "botVersion": "live", - "dialogState": dialogState, - "intentName": "mockIntent", - "message": message ? message : "Mock Response", - "sentimentResponse": { - "sentimentLabel": "mockLabel", - }, - "sessionAttributes": [], - "slots": { - "testSlot": {"shape":"Scalar", "value": {"originalValue": "Test Value"}} - } - } - return response; -}; - exports.getLexV2Response = function (dialogState, message, intentName, slots) { const response = { "sessionState": { diff --git a/source/lambda/fulfillment/test/lib/middleware/specialtyBotRouter.test.js b/source/lambda/fulfillment/test/lib/middleware/specialtyBotRouter.test.js index 9c8c28c65..f7151dcd3 100644 --- a/source/lambda/fulfillment/test/lib/middleware/specialtyBotRouter.test.js +++ b/source/lambda/fulfillment/test/lib/middleware/specialtyBotRouter.test.js @@ -14,7 +14,6 @@ const specialtyBotRouter = require('../../../lib/middleware/specialtyBotRouter') const _ = require('lodash'); const botRouterFixtures = require('./specialtyBotRouter.fixtures') const awsMock = require('aws-sdk-client-mock'); -const { LexRuntimeService: LexRuntime } = require('@aws-sdk/client-lex-runtime-service') const { LexRuntimeV2 } = require('@aws-sdk/client-lex-runtime-v2'); const { Lambda, InvokeCommand } = require('@aws-sdk/client-lambda'); const multilanguage = require('../../../lib/middleware/multilanguage'); @@ -69,143 +68,6 @@ describe('when calling routeRequest function with Lambda as target or with exit }); -describe('when calling routeRequest function with LexV1 as target', () => { - afterEach(() => { - jest.clearAllMocks(); - }); - - test('when using Lexv1 Bot & bot returns response with dialogState ReadyForFulfillment', async () => { - let requestParams; - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - requestParams = request; - callback(null, botRouterFixtures.getLexV1Response("ReadyForFulfillment", "Test Message")); - }); - const response = await specialtyBotRouter.routeRequest(botRouterFixtures.createRequestObject("What is QnABot"), - botRouterFixtures.createResponseObject(), "test_bot", null); - expect(response.res.session.qnabotcontext.specialtyBot).not.toBeDefined(); - expect(response.res.message).toEqual('{\n "testSlot": {\n "shape": "Scalar",\n "value": {\n "originalValue": "Test Value"\n }\n }\n} Welcome back to QnABot.'); - expect(requestParams.sessionAttributes).toEqual({ "myAttribute": "test" }); - }); - - test('should not call translate when ENABLE_MULTI_LANGUAGE_SUPPORT is disabled', async () => { - let requestParams; - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - requestParams = request; - callback(null, botRouterFixtures.getLexV1Response("ReadyForFulfillment", "Test Message.")); - }); - const mockRequest = botRouterFixtures.createRequestObject("What is QnABot"); - mockRequest._settings.ENABLE_MULTI_LANGUAGE_SUPPORT = false; - const response = await specialtyBotRouter.routeRequest(mockRequest, - botRouterFixtures.createResponseObject(), "test_bot", null); - expect(response.res.session.qnabotcontext.specialtyBot).not.toBeDefined(); - expect(response.res.message).toEqual('{\n "testSlot": {\n "shape": "Scalar",\n "value": {\n "originalValue": "Test Value"\n }\n }\n} Welcome back to QnABot.'); - expect(requestParams.sessionAttributes).toEqual({ "myAttribute": "test" }); - expect(translateSpy).toBeCalledTimes(0); - }); - - test('should translate if Native Language does not match', async () => { - let requestParams; - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - requestParams = request; - callback(null, botRouterFixtures.getLexV1Response("ReadyForFulfillment", "Test Message.")); - }); - const mockRequest = botRouterFixtures.createRequestObject("Que es QnABot"); - mockRequest._settings.ENABLE_MULTI_LANGUAGE_SUPPORT = true; - mockRequest._settings.NATIVE_LANGUAGE = 'Spanish'; - const response = await specialtyBotRouter.routeRequest(mockRequest, - botRouterFixtures.createResponseObject(), "test_bot", null); - expect(response.res.session.qnabotcontext.specialtyBot).not.toBeDefined(); - expect(response.res.message).toEqual('{\n "testSlot": {\n "shape": "Scalar",\n "value": {\n "originalValue": "Test Value"\n }\n }\n} Welcome back to QnABot.'); - expect(requestParams.sessionAttributes).toEqual({ "myAttribute": "test" }); - expect(translateSpy).toBeCalledTimes(3); - }); - - test('should translate if Native Language does not match with Speak tags', async () => { - lambdaMock.on(InvokeCommand).resolves({ - "Payload": '{"message":"mockLambdaResponse", "dialogState": "Fulfilled", "sessionAttributes":[]}' - }); - const mockRequest = botRouterFixtures.createRequestObject("Que es QnABot"); - mockRequest._settings.ENABLE_MULTI_LANGUAGE_SUPPORT = true; - mockRequest._settings.NATIVE_LANGUAGE = 'Spanish'; - const response = await specialtyBotRouter.routeRequest(mockRequest, - botRouterFixtures.createResponseObject(), "lambda::mockRoutingLambda", null); - expect(response.res.session.qnabotcontext.specialtyBot).not.toBeDefined(); - expect(response.res.message).toEqual("mockLambdaResponse Welcome back to QnABot."); - expect(response.res.session.appContext.altMessages).toEqual({"html": "mockLambdaResponse Welcome back to QnABot. "}); - }); - - test('should return error if LexV1 responds with Error', async () => { - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - callback(new Error("Mock Error"), null); - }); - await expect(specialtyBotRouter.routeRequest(botRouterFixtures.createRequestObject("What is QnABot"), - botRouterFixtures.createResponseObject(), "test_bot", null)).rejects.toEqual('Lex client request error:Error: Mock Error'); - }); - - test('when routing to Lexv1 Bot and bot response has SSML, returned response should have ssml message', async () => { - let requestParams; - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - requestParams = request; - const mockResponse = botRouterFixtures.getLexV1Response("", "Test Message."); - mockResponse.sessionAttributes.appContext = { "altMessages": { "ssml": "Test Message." } }; - callback(null, mockResponse); - }); - let response = await specialtyBotRouter.routeRequest(botRouterFixtures.createRequestObject("What is QnABot", "SSML"), - botRouterFixtures.createResponseObject(), "test_bot", null); - expect(response.res.type).toEqual("SSML"); - expect(response.res.message).toEqual("Test Message."); - expect(requestParams.sessionAttributes).toEqual({ "myAttribute": "test" }); - - - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - requestParams = request; - const mockResponse = botRouterFixtures.getLexV1Response("", "Test Message."); - mockResponse.sessionAttributes.appContext = '{ "altMessages": { "ssml": "Test Message."}}'; - callback(null, mockResponse); - }); - response = await specialtyBotRouter.routeRequest(botRouterFixtures.createRequestObject("What is QnABot", "SSML"), - botRouterFixtures.createResponseObject(), "test_bot", null); - expect(response.res.type).toEqual("SSML"); - expect(response.res.message).toEqual("Test Message."); - expect(requestParams.sessionAttributes).toEqual({ "myAttribute": "test" }); - }); - - - test('when routing to Lexv1 Bot and bot resonse has SSML, returned response should have ssml message', async () => { - let requestParams; - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - requestParams = request; - const mockResponse = botRouterFixtures.getLexV1Response("", "Test Message."); - mockResponse.sessionAttributes.appContext = { "altMessages": { "ssml": "Test Message." } }; - callback(null, mockResponse); - }); - const response = await specialtyBotRouter.routeRequest(botRouterFixtures.createRequestObject("What is QnABot", "SSML"), - botRouterFixtures.createResponseObject(), "test_bot", null); - expect(response.res.type).toEqual("SSML"); - expect(response.res.message).toEqual("Test Message."); - expect(requestParams.sessionAttributes).toEqual({ "myAttribute": "test" }); - }); - - test('when routing to Lexv1 Bot, returned response should have message type & message', async () => { - jest.spyOn(LexRuntime.prototype, 'postText') - .mockImplementation((request, callback) => { - callback(null, botRouterFixtures.getLexV1Response("", "Test Message.")); - }); - const response = await specialtyBotRouter.routeRequest(botRouterFixtures.createRequestObject("What is QnABot"), - botRouterFixtures.createResponseObject(), "test_bot", null); - expect(response.res.type).toEqual("PlainText"); - expect(response.res.message).toEqual("Test Message."); - }); -}); - - describe('when calling routeRequest function with LexV2 as target', () => { afterEach(() => { jest.clearAllMocks(); diff --git a/source/lambda/genesys/package-lock.json b/source/lambda/genesys/package-lock.json index caffdb50f..aebeea7dc 100644 --- a/source/lambda/genesys/package-lock.json +++ b/source/lambda/genesys/package-lock.json @@ -1,12 +1,12 @@ { "name": "genesys", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "genesys", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "devDependencies": { "jest": "^29.7.0" diff --git a/source/lambda/genesys/package.json b/source/lambda/genesys/package.json index 9326a5509..f35db0ba7 100644 --- a/source/lambda/genesys/package.json +++ b/source/lambda/genesys/package.json @@ -1,6 +1,6 @@ { "name": "genesys", - "version": "6.0.3", + "version": "6.1.0", "description": "Lambda function used to support the Genesys setup wizard", "repository": { "type": "git", diff --git a/source/lambda/import/index.js b/source/lambda/import/index.js index 33eefb715..4b4eef255 100644 --- a/source/lambda/import/index.js +++ b/source/lambda/import/index.js @@ -59,6 +59,8 @@ exports.step = async function (event, context, cb) { qnabot.log('Request', JSON.stringify(event, null, 2)); const Bucket = event.Records[0].s3.bucket.name; const Key = decodeURI(event.Records[0].s3.object.key); + const output_bucket = process.env.OUTPUT_S3_BUCKET; + const output_key = `status-import/${Key.split('/').pop()}` let progress; await waitUntilObjectExists( { @@ -74,85 +76,73 @@ exports.step = async function (event, context, cb) { const res = await x.Body.transformToString(); const config = JSON.parse(res); qnabot.log('Config:', JSON.stringify(config, null, 2)); - if (config.status === 'InProgress') { - // NOSONAR TODO - design a more robust way to identify target ES index for auto import of metrics and feedback - // Filenames must match across: - // aws-ai-qna-bot/templates/import/UpgradeAutoImport.js - // aws-ai-qna-bot/templates/master/UpgradeAutoExport.js - // and pattern in /aws-ai-qna-bot/lambda/import/index.js - const esindex = getOsIndex(Key); - qnabot.log('Importing to index: ', esindex); - try { - const params = { - Bucket: config.bucket, - Key: config.key, - VersionId: config.version, - Range: `bytes=${config.start}-${config.end}` - }; - const result = await s3.send(new GetObjectCommand(params)); - const response = await result.Body.transformToString(); - const settings = await get_settings(); - qnabot.log('opening file'); - let objects = []; + while (config.progress < 1 && config.time.rounds < 15) { + if (config.status === 'InProgress') { + // NOSONAR TODO - design a more robust way to identify target ES index for auto import of metrics and feedback + // Filenames must match across: + // aws-ai-qna-bot/templates/import/UpgradeAutoImport.js + // aws-ai-qna-bot/templates/master/UpgradeAutoExport.js + // and pattern in /aws-ai-qna-bot/lambda/import/index.js + const esindex = getOsIndex(Key); + qnabot.log('Importing to index: ', esindex); try { - config.buffer += response; - if (config.buffer.startsWith('PK')) { - qnabot.log('starts with PK, must be an xlsx'); - const s3Object = await s3.send(new GetObjectCommand(params)); - const readableStreamFile = Buffer.concat(await s3Object.Body.toArray()) - const questionArray = await convertxlsx.convertxlsx(readableStreamFile); - qnabot.log('number of items processed: ', questionArray.length); - questionArray.forEach((question) => { - const questionStr = JSON.stringify(question); - qnabot.log(questionStr); - objects.push(questionStr); - }); - config.buffer = ''; - } else { - objects = config.buffer.split(/\n/); - JSON.parse(objects[objects.length - 1]); - config.buffer = ''; - } - } catch (e) { - qnabot.log('An error occured while processing question array: ', e); - config.buffer = objects.pop(); - } - const { out, success, failed } = await processQuestionObjects(objects, settings, esindex, config); - config.count = success; - config.failed = failed; - qnabot.log('ContentRange: ', result.ContentRange); - const tmp = result.ContentRange.match(/bytes (.*)-(.*)\/(.*)/); // NOSONAR - javascript:S5852 - input is user controlled and we have a limit on the number of characters - progress = (parseInt(tmp[2]) + 1) / parseInt(tmp[3]); - const ES_formatted_content = `${out.join('\n')}\n`; - await delete_existing_content.delete_existing_content(esindex, config, ES_formatted_content); // check and delete existing content (if parameter to delete has been passed in the options {file} - /* - // Disable bulk load.. Instead save docs one at a time, for now, due to issues with k-nn index after bulk load - .then(function (result) { - return es_bulk_load(result) - .then(x => { - config.EsErrors.push(x.errors) - }) - }) - */ - config.start = config.end + 1; - config.end = config.start + config.stride; - config.progress = progress; - config.time.rounds += 1; - if (config.progress >= 1) { - config.status = 'Complete'; - config.time.end = new Date().toISOString(); - } - qnabot.log('EndConfig:', JSON.stringify(config, null, 2)); - await s3.send(new PutObjectCommand({ Bucket, Key, Body: JSON.stringify(config) })); - cb(null); + const params = { + Bucket: config.bucket, + Key: config.key, + VersionId: config.version, + Range: `bytes=${config.start}-${config.end}` + }; + const result = await s3.send(new GetObjectCommand(params)); + const response = await result.Body.transformToString(); + const settings = await get_settings(); + qnabot.log('opening file'); + + const {buffer, objects} = await processQuestionArray(config, response, s3, params) + config.buffer = buffer; + + const { out, success, failed } = await processQuestionObjects(objects, settings, esindex, config); + config.count = success; + config.failed = failed; + qnabot.log('ContentRange: ', result.ContentRange); + const tmp = result.ContentRange.match(/bytes (.*)-(.*)\/(.*)/); // NOSONAR - javascript:S5852 - input is user controlled and we have a limit on the number of characters + progress = (parseInt(tmp[2]) + 1) / parseInt(tmp[3]); + const ES_formatted_content = `${out.join('\n')}\n`; + await delete_existing_content.delete_existing_content(esindex, config, ES_formatted_content); // check and delete existing content (if parameter to delete has been passed in the options {file} + /* + // Disable bulk load.. Instead save docs one at a time, for now, due to issues with k-nn index after bulk load + .then(function (result) { + return es_bulk_load(result) + .then(x => { + config.EsErrors.push(x.errors) + }) + }) + */ + config.start = config.end + 1; + config.end = config.start + config.stride; + config.progress = progress; + config.time.rounds += 1; } catch (error) { qnabot.log('An error occured while config status was InProgress: ', error); config.status = error.message || 'Error' config.message = JSON.stringify(error); - await s3.send(new PutObjectCommand({ Bucket, Key, Body: JSON.stringify(config) })); + await s3.send(new PutObjectCommand({ Bucket: output_bucket, Key: output_key, Body: JSON.stringify(config) })); cb(error); + break; } } + } + try { + if (config.progress >= 1 && config.status == "InProgress") { + config.status = 'Complete'; + config.time.end = new Date().toISOString(); + qnabot.log('EndConfig:', JSON.stringify(config, null, 2)); + await s3.send(new PutObjectCommand({ Bucket: output_bucket, Key: output_key, Body: JSON.stringify(config) })); + cb(null); + } + } catch (err) { + qnabot.log('An error occured while finalizing config: ', err); + cb(err); + } } catch (err) { qnabot.log('An error occured while getting parsing for config: ', err); cb(err); @@ -193,6 +183,9 @@ exports.start = async function (event, context, cb) { Body: JSON.stringify(config) }; await s3.send(new PutObjectCommand(putParams)); + putParams.Bucket = process.env.OUTPUT_S3_BUCKET; + putParams.Key = `status-import/${decodeURI(event.Records[0].s3.object.key.split('/').pop())}`; + await s3.send(new PutObjectCommand(putParams)); cb(null); } catch (x) { qnabot.log('An error occured in start function: ', x); @@ -205,6 +198,37 @@ exports.start = async function (event, context, cb) { } }; +async function processQuestionArray(config, response, s3, s3Params) { + let objects = []; + try { + config.buffer += response; + if (config.buffer.startsWith('PK')) { + qnabot.log('starts with PK, must be an xlsx'); + const s3Object = await s3.send(new GetObjectCommand(s3Params)); + const readableStreamFile = Buffer.concat(await s3Object.Body.toArray()) + const questionArray = await convertxlsx.convertxlsx(readableStreamFile); + qnabot.log('number of items processed: ', questionArray.length); + questionArray.forEach((question) => { + const questionStr = JSON.stringify(question); + qnabot.log(questionStr); + objects.push(questionStr); + }); + config.buffer = ''; + } else { + objects = config.buffer.split(/\n/); + JSON.parse(objects[objects.length - 1]); + config.buffer = ''; + } + const modifiedBuffer = config.buffer + return {modifiedBuffer, objects}; + } catch (e) { + qnabot.log('An error occured while processing question array: ', e); + config.buffer = objects.pop(); + const modifiedBuffer = config.buffer + return {modifiedBuffer, objects}; + } +} + async function processQuestionObjects(objects, settings, esindex, config) { const out = []; let success = config.count || 0; diff --git a/source/lambda/import/package-lock.json b/source/lambda/import/package-lock.json index 7dd4ca720..76185301d 100644 --- a/source/lambda/import/package-lock.json +++ b/source/lambda/import/package-lock.json @@ -1,15 +1,15 @@ { "name": "import", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "import", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { - "read-excel-file": "^5.7.1" + "read-excel-file": "^5.8.5" }, "devDependencies": { "aws-sdk-client-mock": "^3.0.1", @@ -1793,37 +1793,20 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/big-integer": { - "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "dependencies": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - }, - "engines": { - "node": "*" - } + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==" + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "license": "MIT" }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1888,22 +1871,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", - "engines": { - "node": ">=0.2.0" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1942,17 +1909,6 @@ } ] }, - "node_modules/chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "dependencies": { - "traverse": ">=0.3.0 <0.4" - }, - "engines": { - "node": "*" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2050,7 +2006,8 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true }, "node_modules/convert-source-map": { "version": "2.0.0", @@ -2061,7 +2018,8 @@ "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" }, "node_modules/create-jest": { "version": "29.7.0", @@ -2186,6 +2144,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "license": "BSD-3-Clause", "dependencies": { "readable-stream": "^2.0.2" } @@ -2347,10 +2306,25 @@ "node": ">=8" } }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true }, "node_modules/fsevents": { "version": "2.3.3", @@ -2366,20 +2340,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dependencies": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "engines": { - "node": ">=0.6" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -2432,6 +2392,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2529,6 +2490,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -2599,7 +2561,8 @@ "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", @@ -4099,6 +4062,18 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/just-extend": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", @@ -4129,11 +4104,6 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, - "node_modules/listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==" - }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -4250,6 +4220,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4257,25 +4228,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4313,8 +4265,7 @@ "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node_modules/node-releases": { "version": "2.0.14", @@ -4347,6 +4298,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, "dependencies": { "wrappy": "1" } @@ -4448,6 +4400,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -4560,7 +4513,8 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" }, "node_modules/prompts": { "version": "2.4.2", @@ -4598,19 +4552,21 @@ "dev": true }, "node_modules/read-excel-file": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/read-excel-file/-/read-excel-file-5.7.1.tgz", - "integrity": "sha512-cEX+y7A0TmUESjaVqDTVts3iY2YbySG5ew2TlP0qJN+H7PY+b9MqiK3pl/vNPhx112AuyLtmhfqQc5n6+U2vQw==", + "version": "5.8.5", + "resolved": "https://registry.npmjs.org/read-excel-file/-/read-excel-file-5.8.5.tgz", + "integrity": "sha512-KDDcSsI3VzXTNUBs8q7RwTYrGRE8RZgNwGUivYq13bQtMp1KJmocyBs/EiPTJaFk4I8Ri9iDF+ht2A4GUrudMg==", + "license": "MIT", "dependencies": { "@xmldom/xmldom": "^0.8.2", "fflate": "^0.7.3", - "unzipper": "^0.10.11" + "unzipper": "^0.12.2" } }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -4677,21 +4633,11 @@ "node": ">=10" } }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" }, "node_modules/semver": { "version": "6.3.1", @@ -4702,11 +4648,6 @@ "semver": "bin/semver.js" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4808,6 +4749,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -4946,14 +4888,6 @@ "node": ">=8.0" } }, - "node_modules/traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "engines": { - "node": "*" - } - }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -4987,21 +4921,26 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/unzipper": { - "version": "0.10.14", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", - "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", - "dependencies": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.3.tgz", + "integrity": "sha512-PZ8hTS+AqcGxsaQntl3IRBw65QrBI6lxzqDEL7IAo/XCEqRTKGfOX56Vea5TH9SZczRVxuzk1re04z/YjuYCJA==", + "license": "MIT", + "dependencies": { + "bluebird": "~3.7.2", "duplexer2": "~0.1.4", - "fstream": "^1.0.12", + "fs-extra": "^11.2.0", "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" + "node-int64": "^0.4.0" } }, "node_modules/update-browserslist-db": { @@ -5037,7 +4976,8 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, "node_modules/v8-to-istanbul": { "version": "9.2.0", @@ -5097,7 +5037,8 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true }, "node_modules/write-file-atomic": { "version": "4.0.2", diff --git a/source/lambda/import/package.json b/source/lambda/import/package.json index de8c5e8e2..4b7e5546e 100644 --- a/source/lambda/import/package.json +++ b/source/lambda/import/package.json @@ -1,6 +1,6 @@ { "name": "import", - "version": "6.0.3", + "version": "6.1.0", "description": "QnABot Lambda handling import of QIDs", "main": "index.js", "scripts": { @@ -13,7 +13,7 @@ }, "license": "Apache-2.0", "dependencies": { - "read-excel-file": "^5.7.1" + "read-excel-file": "^5.8.5" }, "devDependencies": { "aws-sdk-client-mock": "^3.0.1", diff --git a/source/lambda/import/test/index.test.js b/source/lambda/import/test/index.test.js index 866b0357e..f04ecb0ee 100644 --- a/source/lambda/import/test/index.test.js +++ b/source/lambda/import/test/index.test.js @@ -77,7 +77,7 @@ describe('when calling start function', () => { it('should call start and update status correctly', async () => { await start(request, null, jest.fn()); expect(qnabot.log).toHaveBeenCalledWith('starting'); - expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 1); + expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 2); }); it('should handle an error', async () => { @@ -95,6 +95,7 @@ describe('when calling step function', () => { const OLD_ENV = process.env; process.env.ES_INDEX = 'testEsIndex'; process.env.ES_ENDPOINT = 'testEndpoint'; + process.env.OUTPUT_S3_BUCKET = 'contentDesignerOutputBucket' beforeEach(() => { process.env = { ...OLD_ENV }; s3Mock.reset(); @@ -201,7 +202,11 @@ describe('when calling step function', () => { const error = new Error('test error'); const mockOptions = { - status: 'InProgress' + 'progress': 0, + 'time': { + 'rounds': 0, + }, + 'status': 'InProgress' }; const stream1 = new Readable(); @@ -209,7 +214,14 @@ describe('when calling step function', () => { stream1.push(null); const sdkStream1 = sdkStreamMixin(stream1); - s3Mock.on(GetObjectCommand).resolvesOnce({ Body: sdkStream1 }).rejects(error); + s3Mock.on(GetObjectCommand).resolvesOnce({ Body: sdkStream1 }); + + s3Mock.on(GetObjectCommand, { + 'Bucket': undefined, + 'Key': undefined, + 'Range': 'bytes=undefined-undefined', + 'VersionId': undefined + }).rejects(error); const mockFn = jest.fn(); await step(request, null, mockFn); @@ -226,14 +238,22 @@ describe('when calling step function', () => { 'VersionId': undefined }); expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(PutObjectCommand, {"Body": "{\"status\":\"test error\",\"message\":\"{}\"}", "Bucket": "qna-test-importbucket", "Key": "data/import_questions.json"}); + expect(s3Mock).toHaveReceivedCommandWith(PutObjectCommand, {"Body": "{\"progress\":0,\"time\":{\"rounds\":0},\"status\":\"test error\",\"message\":\"{}\"}", "Bucket": "contentDesignerOutputBucket", "Key": "status-import/import_questions.json"}); + expect(qnabot.log).toHaveBeenCalledWith('An error occured while config status was InProgress: ', error); expect(mockFn).toHaveBeenCalledWith(error); }); it('should handle an error with buffer', async () => { + jest.spyOn(qnabotSettings, 'getSettings').mockResolvedValue({ EMBEDDINGS_ENABLE: false }); + + const mockOptions = { - status: 'InProgress' + 'progress': 0, + 'time': { + 'rounds': 0, + }, + 'status': 'InProgress' }; const errorConfig = { diff --git a/source/lambda/js_lambda_hook_sdk/package-lock.json b/source/lambda/js_lambda_hook_sdk/package-lock.json index bf4efe4ad..3fbff126f 100644 --- a/source/lambda/js_lambda_hook_sdk/package-lock.json +++ b/source/lambda/js_lambda_hook_sdk/package-lock.json @@ -1,12 +1,12 @@ { "name": "js_lambda_hook_sdk", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "js_lambda_hook_sdk", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "lodash": "^4.17.21" diff --git a/source/lambda/js_lambda_hook_sdk/package.json b/source/lambda/js_lambda_hook_sdk/package.json index cf284f5f2..5f05fdf43 100644 --- a/source/lambda/js_lambda_hook_sdk/package.json +++ b/source/lambda/js_lambda_hook_sdk/package.json @@ -1,6 +1,6 @@ { "name": "js_lambda_hook_sdk", - "version": "6.0.3", + "version": "6.1.0", "description": "QnABot convenience layer, allowing users to create custom lambda hooks", "directories": { "lambda_hook_sdk": "lambda_hook_sdk", diff --git a/source/lambda/kendra-webcrawler-schedule-updater/requirements-test.txt b/source/lambda/kendra-webcrawler-schedule-updater/requirements-test.txt index ed98b7883..4f50a96aa 100644 --- a/source/lambda/kendra-webcrawler-schedule-updater/requirements-test.txt +++ b/source/lambda/kendra-webcrawler-schedule-updater/requirements-test.txt @@ -1,4 +1,4 @@ -moto~=4.2.4 -pytest~=7.4.2 -pytest-cov~=4.1.0 +moto~=5.0.13 +pytest~=8.3.2 +pytest-cov~=5.0.0 mock~=5.1.0 \ No newline at end of file diff --git a/source/lambda/kendra-webcrawler-schedule-updater/test/test_lambda_function.py b/source/lambda/kendra-webcrawler-schedule-updater/test/test_lambda_function.py index 60b040c4a..16e653d62 100644 --- a/source/lambda/kendra-webcrawler-schedule-updater/test/test_lambda_function.py +++ b/source/lambda/kendra-webcrawler-schedule-updater/test/test_lambda_function.py @@ -14,9 +14,9 @@ import unittest import boto3 from unittest.mock import patch, MagicMock, ANY -from moto import mock_ssm +from moto import mock_aws -@mock_ssm +@mock_aws class TestLambdaFunction(unittest.TestCase): def setUp(self): self.ssm_client = boto3.client("ssm") diff --git a/source/lambda/kendra-webcrawler-status/requirements-test.txt b/source/lambda/kendra-webcrawler-status/requirements-test.txt index ed98b7883..4f50a96aa 100644 --- a/source/lambda/kendra-webcrawler-status/requirements-test.txt +++ b/source/lambda/kendra-webcrawler-status/requirements-test.txt @@ -1,4 +1,4 @@ -moto~=4.2.4 -pytest~=7.4.2 -pytest-cov~=4.1.0 +moto~=5.0.13 +pytest~=8.3.2 +pytest-cov~=5.0.0 mock~=5.1.0 \ No newline at end of file diff --git a/source/lambda/kendra-webcrawler-status/test/test_lambda_function.py b/source/lambda/kendra-webcrawler-status/test/test_lambda_function.py index d1a0773f5..f6a2dc0d0 100644 --- a/source/lambda/kendra-webcrawler-status/test/test_lambda_function.py +++ b/source/lambda/kendra-webcrawler-status/test/test_lambda_function.py @@ -14,11 +14,11 @@ import unittest import boto3 from unittest.mock import patch, MagicMock -from moto import mock_ssm +from moto import mock_aws from datetime import datetime from botocore.exceptions import ClientError -@mock_ssm +@mock_aws class TestLambdaFunction(unittest.TestCase): def setUp(self): self.ssm_client = boto3.client("ssm") diff --git a/source/lambda/kendra-webcrawler/requirements-test.txt b/source/lambda/kendra-webcrawler/requirements-test.txt index ed98b7883..4f50a96aa 100644 --- a/source/lambda/kendra-webcrawler/requirements-test.txt +++ b/source/lambda/kendra-webcrawler/requirements-test.txt @@ -1,4 +1,4 @@ -moto~=4.2.4 -pytest~=7.4.2 -pytest-cov~=4.1.0 +moto~=5.0.13 +pytest~=8.3.2 +pytest-cov~=5.0.0 mock~=5.1.0 \ No newline at end of file diff --git a/source/lambda/kendra-webcrawler/test/test_lambda_function.py b/source/lambda/kendra-webcrawler/test/test_lambda_function.py index b13512f8e..7cf403b49 100644 --- a/source/lambda/kendra-webcrawler/test/test_lambda_function.py +++ b/source/lambda/kendra-webcrawler/test/test_lambda_function.py @@ -15,10 +15,9 @@ import unittest import boto3 from unittest.mock import patch, MagicMock -from moto import mock_ssm, mock_cloudwatch +from moto import mock_aws -@mock_ssm -@mock_cloudwatch +@mock_aws class TestLambdaFunction(unittest.TestCase): def setUp(self): self.ssm_client = boto3.client("ssm") diff --git a/source/lambda/lex-build/lib/alias.js b/source/lambda/lex-build/lib/alias.js deleted file mode 100644 index 3feb821c5..000000000 --- a/source/lambda/lex-build/lib/alias.js +++ /dev/null @@ -1,26 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const run = require('./run'); - -module.exports = async function (version, data) { - const alias = await run('getBotAlias', data); - const { checksum } = alias; - - await run('putBotAlias', { - botName: data.botName, - botVersion: version, - name: data.name, - checksum, - }); -}; diff --git a/source/lambda/lex-build/lib/bot.js b/source/lambda/lex-build/lib/bot.js deleted file mode 100644 index 76b741bef..000000000 --- a/source/lambda/lex-build/lib/bot.js +++ /dev/null @@ -1,64 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const run = require('./run'); - -module.exports = async function (versionobj, data) { - if (data.intents[0].intentName && data.intents[0].intentName.startsWith('fulfilment_')) { - data.intents[0].intentVersion = versionobj.intent_version; - if (data.intents.length > 1) { - data.intents[1].intentVersion = versionobj.intentFallback_version; - } - } else { - data.intents[1].intentVersion = versionobj.intent_version; - data.intents[0].intentVersion = versionobj.intentFallback_version; - } - delete data.status; - delete data.failureReason; - delete data.lastUpdatedDate; - delete data.createdDate; - delete data.version; - - const bot = await run('putBot', data); - const { checksum } = bot; - - const result = await run('createBotVersion', { - name: data.name, - checksum, - }); - const new_version = result.version; - - await new Promise(async (res, rej) => { - await next(100); - async function next(count) { - const tmp = await run('getBot', { - name: data.name, - versionOrAlias: new_version - }); - if (count === 0) { - throw new Error('Build timeout'); - } else if (tmp.status === 'READY') { - res(); - } else if (tmp.status === 'BUILDING' || tmp.status === 'READY_BASIC_TESTING') { - await delay(5000); - await next(--count); - } else { - throw tmp; - } - } - }); - return new_version; -}; -async function delay(ms) { - return new Promise(res => setTimeout(res, ms)) -} diff --git a/source/lambda/lex-build/lib/delete.js b/source/lambda/lex-build/lib/delete.js deleted file mode 100644 index 93c9f3069..000000000 --- a/source/lambda/lex-build/lib/delete.js +++ /dev/null @@ -1,57 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const _ = require('lodash'); -const run = require('./run.js'); - -exports.bot = async function(name, version) { - try { - const res = await run('getBotVersions', { name }); - const versions = res.bots - .map(x => x.version) - .filter(x => !_.includes(['$LATEST', version], x)) - .map(x => run('deleteBotVersion', { name, version: x })); - return await Promise.all(versions); - } catch (error) { - console.error("An error occurred during getBotVersions: ", error); - throw error; - } -}; - -exports.intent = async function(name, version) { - try { - const res = await run('getIntentVersions', { name }); - const versions = res.intents - .map(x => x.version) - .filter(x => !_.includes(['$LATEST', version], x)) - .map(x => run('deleteIntentVersion', { name, version: x })); - return await Promise.all(versions); - } catch (error) { - console.error("An error occurred during getIntentVersions: ", error); - throw error; - } -}; - -exports.slot = async function(name, version) { - try { - const res = await run('getSlotTypeVersions', { name }); - const versions = res.slotTypes - .map(x => x.version) - .filter(x => !_.includes(['$LATEST', version], x)) - .map(x => run('deleteSlotTypeVersion', { name, version: x })); - return await Promise.all(versions); - } catch (error) { - console.error("An error occurred during getSlotTypeVersions: ", error); - throw error; - } -}; \ No newline at end of file diff --git a/source/lambda/lex-build/lib/index.js b/source/lambda/lex-build/lib/index.js index 835354a7b..83992b6b8 100644 --- a/source/lambda/lex-build/lib/index.js +++ b/source/lambda/lex-build/lib/index.js @@ -11,19 +11,10 @@ * and limitations under the License. * *********************************************************************************************************************/ -const getUtterances = require('./utterances'); const getQidsandquestions = require('./qidsandquestions'); module.exports = async function (params) { - const lexV1Status = process.env.STATUS_KEY; const promises = []; - if (lexV1Status) { - const utterances = await getUtterances(params); - console.log('Starting Lex V1'); - const LexV1Bot = require('./lexv1bot'); - const lexV1 = await LexV1Bot(utterances); - promises.push(lexV1); - } console.log('Starting Lex V2'); const qidsandquestions = await getQidsandquestions(params); const LexV2Bot = require('./lexv2bot'); diff --git a/source/lambda/lex-build/lib/intent.js b/source/lambda/lex-build/lib/intent.js deleted file mode 100644 index 262681126..000000000 --- a/source/lambda/lex-build/lib/intent.js +++ /dev/null @@ -1,35 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const run = require('./run.js'); - -module.exports = async function (version, result) { - // update the version of the slot for the slot named 'slot'. All other slots are unaffected - result.slots.forEach((element) => { - if (element.name === 'slot') { - element.slotTypeVersion = version; - } - }); - - delete result.lastUpdatedDate; - delete result.version; - delete result.createdDate; - - const response = await run('putIntent', result) - const checksum = response.checksum - const createIntentVersion = await run('createIntentVersion', { - name: result.name, - checksum, - }) - return createIntentVersion.version -}; diff --git a/source/lambda/lex-build/lib/intentFallback.js b/source/lambda/lex-build/lib/intentFallback.js deleted file mode 100644 index b57fd9834..000000000 --- a/source/lambda/lex-build/lib/intentFallback.js +++ /dev/null @@ -1,33 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const run = require('./run.js'); - -module.exports = async function (version, result) { - delete result.lastUpdatedDate; - delete result.version; - delete result.createdDate; - - const res = {}; - res.intent_version = version; - - const response = await run('putIntent', result) - const checksum = response.checksum - const createIntentVersion = await run('createIntentVersion', { - name: result.name, - checksum, - }) - res.intentFallback_version = createIntentVersion.version - - return res -}; diff --git a/source/lambda/lex-build/lib/lexv1bot.js b/source/lambda/lex-build/lib/lexv1bot.js deleted file mode 100644 index ab9c87981..000000000 --- a/source/lambda/lex-build/lib/lexv1bot.js +++ /dev/null @@ -1,104 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const run = require('./run'); -const Slot = require('./slot'); -const Intent = require('./intent'); -const IntentFallback = require('./intentFallback'); -const Alias = require('./alias'); -const Bot = require('./bot'); -const clean = require('./delete'); -const status = require('./statusv1'); -const wait = require('./wait'); - -module.exports = async function(utterances){ - const slottype = await run('getSlotType', { - name: process.env.SLOTTYPE, - version: '$LATEST', - }); - const intent = await run('getIntent', { - name: process.env.INTENT, - version: '$LATEST', - }); - const intentFallback = await run('getIntent', { - name: process.env.INTENTFALLBACK, - version: '$LATEST', - }); - const bot = await run('getBot', { - name: process.env.BOTNAME, - versionOrAlias: '$LATEST', - }); - - let clean_intent = null; - let clean_intentFallback = null; - const clean_slottype = null; - let clean_slot = null; - return Promise.all([utterances, slottype]) - .then(result => { - status('Rebuilding Slot'); - return result; - }) - .then(results => { - return Slot(...results); - }) - .then(result => { - status('Rebuilding Intent'); - return result; - }) - .then(slot_version=>{ - clean_intent = () => clean.intent(process.env.INTENT, slot_version); - return Promise.all([slot_version, intent]); - }) - .then(results => { - return Intent(...results); - }) - .then(result => { - status('Rebuilding IntentFallback'); - return result; - }) - .then(intent_version => { - clean_intentFallback = () => clean.intent(process.env.INTENTFALLBACK, intent_version); // NOSONAR need to retain clean_intentFallback status - return Promise.all([intent_version, intentFallback]); - }) - .then(results => { - return IntentFallback(...results); - }) - .then(result => { - status('Rebuilding Lex V1 Bot'); - return result; - }) - .then(versions=>{ - clean_slot = () => clean.slot(process.env.SLOTTYPE, versions.intent_version); // NOSONAR need to retain clean_slot status - return Promise.all([versions, bot]); - }) - .then(results => { - return Bot(...results); - }) - .then(version => { - Alias(version, { botName : process.env.BOTNAME, name : process.env.BOTALIAS}); - return version; - }) - .then(result => new Promise(res => setTimeout(res(result), 1000))) - .then(result => { - wait(); - return result; - }) - .then(version => clean.bot(process.env.BOTNAME, version)) - .then(clean_intent) - .then(clean_slottype) - .then(result => { - console.log(result); - return result; - }) - .catch(error => status('Failed', error.message)) -} diff --git a/source/lambda/lex-build/lib/run.js b/source/lambda/lex-build/lib/run.js deleted file mode 100644 index 7bc2ebc80..000000000 --- a/source/lambda/lex-build/lib/run.js +++ /dev/null @@ -1,56 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const region = process.env.AWS_REGION || 'us-east-1'; -const { LexModelBuildingService } = require('@aws-sdk/client-lex-model-building-service'); -const customSdkConfig = require('sdk-config/customSdkConfig'); -const lex = new LexModelBuildingService(customSdkConfig('C001', { region })); - -module.exports = async function run(fnc, params){ - console.log(fnc + ':request:' + JSON.stringify(params, null, 3)); - const next = async function(count){ - console.log('tries-left:' + count); - try { - const response = await lex[fnc](params); - console.log(fnc + ':result:'+ JSON.stringify(response, null, 3)); - return response - } catch (err) { - console.log(fnc + ':' + err?.name); - const retry = err?.retryAfterSeconds || 5; - console.log('retry in ' + retry); - - // NOSONAR-start - // Code written this way to reduce cognitive complexity - if(err?.name === 'ConflictException'){ - if(count === 0) throw new Error('Error'); - await retryPromise(retry*1000); - return await next(--count); - }else if(err?.name === 'ResourceInUseException'){ - if(count === 0) throw new Error('Error'); - await retryPromise(retry*1000); - return await next(--count); - }else if(err?.name === 'LimitExceededException'){ - await retryPromise(retry*1000); - return await next(count); - }else{ - throw new Error(err?.name + ':' + err?.message); - } - // NOSONAR-end - } - } - return await next(200); -} - -async function retryPromise(ms) { - return new Promise(res => setTimeout(res, ms)); -} diff --git a/source/lambda/lex-build/lib/slot.js b/source/lambda/lex-build/lib/slot.js deleted file mode 100644 index 31fc3c4bc..000000000 --- a/source/lambda/lex-build/lib/slot.js +++ /dev/null @@ -1,36 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const _ = require('lodash'); -const run = require('./run'); - -module.exports = async function (utterances, slottype) { - console.log(`utterances=${utterances}`); - - slottype.enumerationValues = _.uniqBy( - utterances.map((x) => ({ value: x })), - (x) => x.value, - ).slice(0, 10000); - - delete slottype.lastUpdatedDate; - delete slottype.createdDate; - delete slottype.version; - - const response = await run('putSlotType', slottype) - const checksum = response.checksum - const createSlotTypeVersion = await run('createSlotTypeVersion', { - name: slottype.name, - checksum, - }) - return createSlotTypeVersion.version -}; diff --git a/source/lambda/lex-build/lib/statusv1.js b/source/lambda/lex-build/lib/statusv1.js deleted file mode 100644 index e3b11ff5c..000000000 --- a/source/lambda/lex-build/lib/statusv1.js +++ /dev/null @@ -1,43 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const region = process.env.AWS_REGION || 'us-east-1'; -const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3'); -const customSdkConfig = require('sdk-config/customSdkConfig'); -const s3 = new S3Client(customSdkConfig('C001', { region })); - -module.exports=async function(status,message){ - const bucket=process.env.STATUS_BUCKET; - const lexV1StatusFile=process.env.STATUS_KEY; - try { - const res = await s3.send(new GetObjectCommand({ - Bucket:bucket, - Key:lexV1StatusFile, - })) - const readableStream = Buffer.concat(await res.Body.toArray()); - const result = JSON.parse(readableStream); - if(message) result.message=message; - result.status=status; - console.log(result); - const params = { - Bucket:bucket, - Key:lexV1StatusFile, - Body:JSON.stringify(result) - } - await s3.send(new PutObjectCommand(params)) - - } catch (error) { - console.error("An error occured in statusv1: ", error) - throw new Error(error) - } -}; diff --git a/source/lambda/lex-build/lib/utterances.js b/source/lambda/lex-build/lib/utterances.js deleted file mode 100644 index bd414ebef..000000000 --- a/source/lambda/lex-build/lib/utterances.js +++ /dev/null @@ -1,57 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const region = process.env.AWS_REGION || 'us-east-1'; -const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3'); -const customSdkConfig = require('sdk-config/customSdkConfig'); -const s3 = new S3Client(customSdkConfig('C001', { region })); -const _ = require('lodash'); -const { con } = require('/opt/opensearch-client/connection'); - -module.exports = async function(params){ - const es = con(process.env.ADDRESS); - const searchResults = await es.search({ - index:process.env.INDEX, - scroll:'10s', - body: { - query: {match_all: {}} - } - }); - const scrollId = searchResults.body._scroll_id - const result = searchResults.body.hits.hits - while (true) { - const scrollResults = await es.scroll({ - scrollId, - scroll:'10s' - }) - const { hits } = scrollResults.body.hits; - hits.forEach(x => result.push(x)); - if (!hits.length) break - } - const esUtterances = _.compact(_.uniq(_.flatten(result - .map(qa=>qa._source.questions ? qa._source.questions.map(y=>y.q) : []) - ))); - - const s3Response = await s3.send(new GetObjectCommand({ - Bucket:process.env.UTTERANCE_BUCKET, - Key:process.env.UTTERANCE_KEY - })) - console.log(s3Response) - const readableStream = Buffer.concat(await s3Response.Body.toArray()) - - const s3Utterances = JSON.parse(readableStream) - const combinedUtterances = [esUtterances, s3Utterances ] - const utterances = _.compact(_.uniq(_.flatten(combinedUtterances))) - - return utterances -} diff --git a/source/lambda/lex-build/lib/wait.js b/source/lambda/lex-build/lib/wait.js deleted file mode 100644 index a76f91936..000000000 --- a/source/lambda/lex-build/lib/wait.js +++ /dev/null @@ -1,35 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const region = process.env.AWS_REGION || 'us-east-1'; -const { LambdaClient, InvokeCommand } = require('@aws-sdk/client-lambda'); -const customSdkConfig = require('sdk-config/customSdkConfig'); -const lambda = new LambdaClient(customSdkConfig('C001', { region })); - -module.exports = async function(status){ - console.log('calling poll lambda') - try { - const params = { - FunctionName:process.env.POLL_LAMBDA, - InvocationType:'Event', - Payload:'{}' - } - const invokeCmd = new InvokeCommand(params) - const response = await lambda.send(invokeCmd) - return response - - } catch (error) { - console.error("An error invoking lambda in wait: ", error); - throw error; - } -} \ No newline at end of file diff --git a/source/lambda/lex-build/package-lock.json b/source/lambda/lex-build/package-lock.json index 646bd685a..04f58b263 100644 --- a/source/lambda/lex-build/package-lock.json +++ b/source/lambda/lex-build/package-lock.json @@ -1,12 +1,12 @@ { "name": "lex-build", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lex-build", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-lex-model-building-service": "^3.511.0" @@ -78,16 +78,16 @@ } }, "node_modules/@aws-sdk/client-lex-model-building-service": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-model-building-service/-/client-lex-model-building-service-3.622.0.tgz", - "integrity": "sha512-h2qwJ3q8D4+Rq/6Ihgp8tt1dY5ROPuqLKbBbXy8voCT5AK4HkRVaGgo03FZG0zpA768l67Nq05KU6w3YQysbQw==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-model-building-service/-/client-lex-model-building-service-3.621.0.tgz", + "integrity": "sha512-ltD7R8AkUSmIRGi1kQ86LhN/YQ3b+jetdH/hDT7SvPHBbGig/XotFl4Jn1FszchS9QuQc3wJB8uBHScJUDHU6g==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -98,26 +98,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -263,13 +263,13 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.622.0.tgz", - "integrity": "sha512-DJwUqVR/O2lImbktUHOpaQ8XElNBx3JmWzTT2USg6jh3ErgG1CS6LIV+VUlgtxGl+tFN/G6AcAV8SdnnGydB8Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", + "@aws-sdk/core": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -280,26 +280,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -311,14 +311,14 @@ } }, "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.622.0.tgz", - "integrity": "sha512-dwWDfN+S98npeY77Ugyv8VIHKRHN+n/70PWE4EgolcjaMrTINjvUh9a/SypFEs5JmBOAeCQt8S2QpM3Wvzp+pQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -329,26 +329,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -359,7 +359,7 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/abort-controller": { @@ -631,15 +631,15 @@ } }, "node_modules/@aws-sdk/client-sts": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.622.0.tgz", - "integrity": "sha512-Yqtdf/wn3lcFVS42tR+zbz4HLyWxSmztjVW9L/yeMlvS7uza5nSkWqP/7ca+RxZnXLyrnA4jJtSHqykcErlhyg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -650,26 +650,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -815,15 +815,15 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.622.0.tgz", - "integrity": "sha512-q1Ct2AjPxGtQBKtDpqm1umu3f4cuWMnEHTuDa6zjjaj+Aq/C6yxLgZJo9SlcU0tMl8rUCN7oFonszfTtp4Y0MA==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", "dependencies": { - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "fast-xml-parser": "4.4.1", @@ -882,16 +882,16 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.622.0.tgz", - "integrity": "sha512-VUHbr24Oll1RK3WR8XLUugLpgK9ZuxEm/NVeVqyFts1Ck9gsKpRg1x4eH7L7tW3SJ4TDEQNMbD7/7J+eoL2svg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/property-provider": "^3.1.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" @@ -1064,14 +1064,14 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.622.0.tgz", - "integrity": "sha512-cD/6O9jOfzQyo8oyAbTKnyRO89BIMSTzwaN4NxGySC6pYVTqxNSWdRwaqg/vKbwJpjbPGGYYXpXEW11kop7dlg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -1084,7 +1084,7 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/types": { @@ -1099,15 +1099,15 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.622.0.tgz", - "integrity": "sha512-keldwz4Q/6TYc37JH6m43HumN7Vi+R0AuGuHn5tBV40Vi7IiqEzjpiE+yvsHIN+duUheFLL3j/o0H32jb+14DQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -1158,11 +1158,11 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.622.0.tgz", - "integrity": "sha512-zrSoBVM2JlwvkBtrcUd4J/9CrG+T+hUy9r6jwo5gonFIN3QkneR/pqpbUn/n32Zy3zlzCo2VfB31g7MjG7kJmg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", "dependencies": { - "@aws-sdk/client-sso": "3.622.0", + "@aws-sdk/client-sso": "3.621.0", "@aws-sdk/token-providers": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", @@ -2990,15 +2990,15 @@ } }, "node_modules/@smithy/core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", - "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" @@ -3225,14 +3225,14 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", - "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", "dependencies": { "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -3570,9 +3570,9 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -3837,12 +3837,12 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", - "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", "dependencies": { "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -3863,15 +3863,15 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", - "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", "dependencies": { "@smithy/config-resolver": "^3.0.5", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, diff --git a/source/lambda/lex-build/package.json b/source/lambda/lex-build/package.json index a756f60ee..ecc35ee40 100644 --- a/source/lambda/lex-build/package.json +++ b/source/lambda/lex-build/package.json @@ -1,6 +1,6 @@ { "name": "lex-build", - "version": "6.0.3", + "version": "6.1.0", "description": "QnABot lambda for rebuilding Amazon Lex bots", "main": "handler.js", "scripts": { diff --git a/source/lambda/lex-build/test/lib/alias.test.js b/source/lambda/lex-build/test/lib/alias.test.js deleted file mode 100644 index ae092517a..000000000 --- a/source/lambda/lex-build/test/lib/alias.test.js +++ /dev/null @@ -1,52 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const Alias = require('../../lib/alias'); -const run = require('../../lib/run'); -jest.mock('../../lib/run'); -describe('When calling alias function', () => { - - test('Should set the values correctly from version and data', async () => { - const version = '2.0'; - const data = { - botName: 'bot-test', - name: 'name-test' - }; - - const mockRun = { - 'checksum': 'checksum-test' - }; - - const runMock = run.mockImplementationOnce(() => { - return mockRun; - }).mockImplementation(() => { - return { - botName: data.botName, - botVersion: version, - name: data.name, - checksum: 'checksum-test' - }; - }); - - await Alias(version, data); - //CheckSum value is set to test-run, version is set to test, botName and name are set to bot-test and name-test respectively - //Verify Run mock is called twice, once by getBotAlias and once by putBotAlias - expect(run).toBeCalledTimes(2); - expect(run).toBeCalledWith('getBotAlias', data); - expect(run).toBeCalledWith('putBotAlias', {"botName": "bot-test", "botVersion": "2.0", "checksum": "checksum-test", "name": "name-test"}) - //verify params passed are same as data and version passed initially - expect(runMock().botName).toEqual(data.botName); - expect(runMock().name).toEqual(data.name); - expect(runMock().botVersion).toEqual(version); - }); -}); diff --git a/source/lambda/lex-build/test/lib/bot.fixtures.js b/source/lambda/lex-build/test/lib/bot.fixtures.js deleted file mode 100644 index 4296523fa..000000000 --- a/source/lambda/lex-build/test/lib/bot.fixtures.js +++ /dev/null @@ -1,73 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -exports.returnData = function(fulfillment_str, length_gt_1) { - const data_length_1 = { - 'name': 'test-bot', - 'intents': [ - { - 'intentName': '', - 'intentVersion': '' - } - ], - 'status': 'Failed', - 'failureReason': 'timeout', - 'lastUpdatedDate': '12/03/2023', - 'createdDate': '10/27/2023', - 'version': '2.0' - }; - - const data_length_2 = { - 'name': 'test-bot', - 'intents': [ - { - 'intentName': '', - 'intentVersion': '' - }, - { - 'intentName': '', - 'intentVersion': '' - } - ], - 'status': 'Failed', - 'failureReason': 'timeout', - 'lastUpdatedDate': '12/03/2023', - 'createdDate': '10/27/2023', - 'version': '2.0' - }; - - if (fulfillment_str) { - data_length_1.intents[0].intentName = 'fulfilment_test'; - data_length_2.intents[0].intentName = 'fulfilment_test'; - if (length_gt_1) { - data_length_2.intents[1].intentName = 'test'; - } - } else { - data_length_1.intents[0].intentName = 'test'; - data_length_2.intents[0].intentName = 'test'; - data_length_2.intents[1].intentName = 'fulfilment_test'; - } - - if (length_gt_1 || !fulfillment_str) { - return data_length_2; - } else { - return data_length_1; - } -} - -exports.returnVersionObj = { - 'intent_version': '2.0', - 'intentFallback_version': '1.0' -}; - -exports.returnNewVersionValue = '3.0'; diff --git a/source/lambda/lex-build/test/lib/bot.test.js b/source/lambda/lex-build/test/lib/bot.test.js deleted file mode 100644 index 5d918ac86..000000000 --- a/source/lambda/lex-build/test/lib/bot.test.js +++ /dev/null @@ -1,135 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const Bot = require('../../lib/bot'); -const run = require('../../lib/run'); -const botFixtures = require('./bot.fixtures'); -jest.mock('../../lib/run'); - -describe('When calling bot function', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - test('Should return new_version when intentName[0] startsWith fulfillment_ and status is READY', async () => { - const runMock = { - 'checksum': 'checksum-test', - 'version': '3.0' - }; - run.mockImplementationOnce(() => { - return runMock; - }).mockImplementationOnce(() => { - return runMock; - }).mockImplementation(() => { - return { - status: 'READY' - }; - }); - - jest.useFakeTimers(); - jest.spyOn(global, 'setTimeout'); - - const dataObj = botFixtures.returnData(true, false); - - const newVersion = await Bot(botFixtures.returnVersionObj, dataObj); - - expect(run).toHaveBeenCalledTimes(3); - expect(run).toHaveBeenCalledWith("putBot", dataObj); - expect(run).toHaveBeenCalledWith("createBotVersion", {"checksum": "checksum-test", "name": "test-bot"}); - expect(run).toHaveBeenCalledWith("getBot", {"name": "test-bot", "versionOrAlias": "3.0"}); - expect(dataObj.status).toBeUndefined(); - expect(dataObj.failureReason).toBeUndefined(); - expect(dataObj.lastUpdatedDate).toBeUndefined(); - expect(dataObj.createdDate).toBeUndefined(); - expect(dataObj.version).toBeUndefined(); - expect(newVersion).toEqual(botFixtures.returnNewVersionValue); - - //Status is ready, so no need to delay - expect(setTimeout).toHaveBeenCalledTimes(0); - }, 10000); - - test('Should return new_version when intentName[0]startsWith fulfillment_ and length gt 1', async () => { - const runMock = { - 'checksum': 'checksum-test', - 'version': '3.0' - }; - - run.mockImplementationOnce(() => { - return runMock; - }).mockImplementationOnce(() => { - return runMock; - }).mockImplementation(() => { - return { - status: 'READY' - }; - }); - - jest.useFakeTimers(); - jest.spyOn(global, 'setTimeout'); - - const dataObj = botFixtures.returnData(true, true); - - const newVersion = await Bot(botFixtures.returnVersionObj, dataObj); - - expect(run).toHaveBeenCalledTimes(3); - expect(run).toHaveBeenCalledWith("putBot", dataObj); - expect(run).toHaveBeenCalledWith("createBotVersion", {"checksum": "checksum-test", "name": "test-bot"}); - expect(run).toHaveBeenCalledWith("getBot", {"name": "test-bot", "versionOrAlias": "3.0"}); - expect(dataObj.status).toBeUndefined(); - expect(dataObj.failureReason).toBeUndefined(); - expect(dataObj.lastUpdatedDate).toBeUndefined(); - expect(dataObj.createdDate).toBeUndefined(); - expect(dataObj.version).toBeUndefined(); - expect(newVersion).toEqual(botFixtures.returnNewVersionValue); - - //Status is ready, so no need to delay - expect(setTimeout).toHaveBeenCalledTimes(0); - }, 10000); - - test('Should return new_version when intentName[0] does not startsWith fulfillment_', async () => { - const runMock = { - 'checksum': 'checksum-test', - 'version': '3.0' - }; - run.mockImplementationOnce(() => { - return runMock; - }).mockImplementationOnce(() => { - return runMock; - }).mockImplementation(() => { - return { - status: 'READY' - }; - }); - - jest.useFakeTimers(); - jest.spyOn(global, 'setTimeout'); - - const dataObj = botFixtures.returnData(false, false); - - const newVersion = await Bot(botFixtures.returnVersionObj, dataObj); - - expect(run).toHaveBeenCalledTimes(3); - expect(run).toHaveBeenCalledWith("putBot", dataObj); - expect(run).toHaveBeenCalledWith("createBotVersion", {"checksum": "checksum-test", "name": "test-bot"}); - expect(run).toHaveBeenCalledWith("getBot", {"name": "test-bot", "versionOrAlias": "3.0"}); - expect(dataObj.status).toBeUndefined(); - expect(dataObj.failureReason).toBeUndefined(); - expect(dataObj.lastUpdatedDate).toBeUndefined(); - expect(dataObj.createdDate).toBeUndefined(); - expect(dataObj.version).toBeUndefined(); - expect(newVersion).toEqual(botFixtures.returnNewVersionValue); - - //Status is ready, so no need to delay - expect(setTimeout).toHaveBeenCalledTimes(0); - }, 10000); -}); diff --git a/source/lambda/lex-build/test/lib/delete.test.js b/source/lambda/lex-build/test/lib/delete.test.js deleted file mode 100644 index 8b0eb043d..000000000 --- a/source/lambda/lex-build/test/lib/delete.test.js +++ /dev/null @@ -1,219 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - - -const { bot } = require('../../lib/delete'); -const { intent } = require('../../lib/delete'); -const { slot } = require('../../lib/delete'); -const run = require('../../lib/run'); -jest.mock('../../lib/run'); - -describe('When calling delete function', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - test('Should return all versions if everything passess successfully for bot', async () => { - //Latest version is 4.0, $LATEST = 4.0 - const curVersion = 2.0; - const arrToBeDeleted = []; - const runMock = { - 'bots': [ - { - 'version': 1.0 - }, - { - 'version': 2.0 - }, - { - 'version': 3.0 - }, - { - 'version': 3.0 - }, - { - 'version': 4.0 - } - ] - }; - - run.mockImplementationOnce(() => { - return runMock; - }).mockImplementation((functionName, params) => { - //Do not push if version is equal to latest (4.0) - if (params.version === 4.0) { - return arrToBeDeleted; - } else { - arrToBeDeleted.push(params.version); - return arrToBeDeleted; - } - }); - - await bot('test-bot', curVersion); - - expect(run).toBeCalledTimes(5); - expect(run).toBeCalledWith('getBotVersions', {"name": "test-bot"}); - expect(run).toBeCalledWith('deleteBotVersion', {"name": "test-bot", "version": 1}); - expect(run).toBeCalledWith('deleteBotVersion', {"name": "test-bot", "version": 3}); - //The only values present in ArrToBeDeleted are 1, 3 and 3. - expect(arrToBeDeleted.length).toEqual(3); - expect(arrToBeDeleted).toEqual([1,3,3]); - - }); - - test('Should return all versions if everything passess successfully for intent', async () => { - //Latest version is 4.0, $LATEST = 4.0 - const curVersion = 2.0; - const arrToBeDeleted = []; - const runMock = { - 'intents': [ - { - 'version': 1.0 - }, - { - 'version': 2.0 - }, - { - 'version': 3.0 - }, - { - 'version': 3.0 - }, - { - 'version': 4.0 - } - ] - }; - - run.mockImplementationOnce(() => { - return runMock; - }).mockImplementation((functionName, params) => { - //Do not push if version is equal to latest (4.0) - if (params.version === 4.0) { - return arrToBeDeleted; - } else { - arrToBeDeleted.push(params.version); - return arrToBeDeleted; - } - }); - - await intent('test-intent', curVersion); - - expect(run).toBeCalledTimes(5); - expect(run).toBeCalledWith('getIntentVersions', {"name": "test-intent"}); - expect(run).toBeCalledWith('deleteIntentVersion', {"name": "test-intent", "version": 1}); - expect(run).toBeCalledWith('deleteIntentVersion', {"name": "test-intent", "version": 3}); - - //The only values present in ArrToBeDeleted are 1, 3 and 3. - expect(arrToBeDeleted.length).toEqual(3); - expect(arrToBeDeleted).toEqual([1,3,3]); - - }); - - test('Should return all versions if everything passess successfully for slot', async () => { - //Latest version is 4.0, $LATEST = 4.0 - const curVersion = 2.0; - const arrToBeDeleted = []; - const runMock = { - 'slotTypes': [ - { - 'version': 1.0 - }, - { - 'version': 2.0 - }, - { - 'version': 3.0 - }, - { - 'version': 3.0 - }, - { - 'version': 4.0 - } - ] - }; - - run.mockImplementationOnce(() => { - return runMock; - }).mockImplementation((functionName, params) => { - //Do not push if version is equal to latest (4.0) - if (params.version === 4.0) { - return arrToBeDeleted; - } else { - arrToBeDeleted.push(params.version); - return arrToBeDeleted; - } - }); - - await slot('test-slot', curVersion); - - expect(run).toBeCalledTimes(5); - expect(run).toBeCalledWith('getSlotTypeVersions', {"name": "test-slot"}); - expect(run).toBeCalledWith('deleteSlotTypeVersion', {"name": "test-slot", "version": 1}); - expect(run).toBeCalledWith('deleteSlotTypeVersion', {"name": "test-slot", "version": 3}); - - //The only values present in ArrToBeDeleted are 1, 3 and 3. - expect(arrToBeDeleted.length).toEqual(3); - expect(arrToBeDeleted).toEqual([1,3,3]); - - }); - - test('Should throw error for bot', async () => { - const curVersion = 2.0; - //const error = new Error('Test Bot Error'); - - run.mockImplementation(() => { - throw new Error('Test Bot Error'); - }); - - await expect(async () => { - await bot('test-bot', curVersion); - }).rejects.toThrowError(); - - expect(run).toBeCalledTimes(1); - expect(run).toBeCalledWith('getBotVersions', {"name": "test-bot"}); - }); - - test('Should throw error for intent', async () => { - const curVersion = 2.0; - //const error = new Error('Test Bot Error'); - - run.mockImplementation(() => { - throw new Error('Test Intent Error'); - }); - - await expect(async () => { - await intent('test-intent', curVersion); - }).rejects.toThrowError(); - - expect(run).toBeCalledTimes(1); - expect(run).toBeCalledWith('getIntentVersions', {"name": "test-intent"}); - }); - - test('Should throw error for slot', async () => { - const curVersion = 2.0; - //const error = new Error('Test Bot Error'); - - run.mockImplementation(() => { - throw new Error('Test Slot Error'); - }); - - await expect(async () => { - await slot('test-slot', curVersion); - }).rejects.toThrowError(); - - expect(run).toBeCalledTimes(1); - expect(run).toBeCalledWith('getSlotTypeVersions', {"name": "test-slot"}); - }); -}); diff --git a/source/lambda/lex-build/test/lib/index.test.js b/source/lambda/lex-build/test/lib/index.test.js index 6b1e7763b..0c2c21013 100644 --- a/source/lambda/lex-build/test/lib/index.test.js +++ b/source/lambda/lex-build/test/lib/index.test.js @@ -13,14 +13,10 @@ const index = require('../../lib/index'); -const utterances = require('../../lib/utterances'); const qids = require('../../lib/qidsandquestions'); -const lexV1 = require('../../lib/lexv1bot'); const lexV2 = require('../../lib/lexv2bot'); const originalEnv = process.env; -jest.mock('../../lib/utterances'); jest.mock('../../lib/qidsandquestions'); -jest.mock('../../lib/lexv1bot'); jest.mock('../../lib/lexv2bot'); describe('When running index function', () => { @@ -28,45 +24,10 @@ describe('When running index function', () => { jest.clearAllMocks(); }); - test('Should execute lexV1 and lexV2 when STATUS_KEY is true', async () => { + test('Should execute only lexV2', async () => { process.env = { ...originalEnv, - STATUS_KEY: 'test-key' - }; - - const params = {name: 'test-index'}; - const sampleUtterance = { - qid: '1', - type: 'qna' - }; - const sampleQid = { - q: 'What is QnABot' - }; - utterances.mockImplementation(() => { - return sampleUtterance; - }); - qids.mockImplementation(() => { - return sampleQid; - }); - - await index(params); - - expect(utterances).toBeCalledTimes(1); - expect(utterances).toBeCalledWith(params); - expect(qids).toBeCalledTimes(1); - expect(qids).toBeCalledWith(params); - expect(lexV1).toBeCalledTimes(1); - expect(lexV1).toBeCalledWith(sampleUtterance); - expect(lexV2).toBeCalledTimes(1); - expect(lexV2).toBeCalledWith(sampleQid); - }); - - test('Should execute only lexV2 when STATUS_KEY is undefined', async () => { - - process.env = { - ...originalEnv, - STATUS_KEY: undefined }; const params = {name: 'test-index'}; @@ -79,10 +40,8 @@ describe('When running index function', () => { }); await index(params); - expect(utterances).toBeCalledTimes(0); expect(qids).toBeCalledTimes(1); expect(qids).toBeCalledWith(params); - expect(lexV1).toBeCalledTimes(0); expect(lexV2).toBeCalledTimes(1); expect(lexV2).toBeCalledWith(sampleQid); }); diff --git a/source/lambda/lex-build/test/lib/intent.test.js b/source/lambda/lex-build/test/lib/intent.test.js deleted file mode 100644 index 6eca106d5..000000000 --- a/source/lambda/lex-build/test/lib/intent.test.js +++ /dev/null @@ -1,81 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - - -const intent = require('../../lib/intent'); -const run = require('../../lib/run'); -const intentFixtures = require('./intent.fixtures'); -jest.mock('../../lib/run'); - -describe('When running intent function', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - test('Should return intentVersion when slot name is slot', async () => { - const runMock = { - 'name': 'mock-test', - 'checksum': 'checksum-test', - 'version': '3.0' - }; - run.mockResolvedValue(runMock); - - const version = '2.0'; - const result = intentFixtures.returnResult(true); - const intentVersion = await intent(version, result); - - expect(run).toBeCalledTimes(2); - expect(run).toBeCalledWith('putIntent', {"failureReason": "timeout", "name": "test-index", "slots": [{"name": "slot", "slotTypeVersion": "2.0"}, {"name": "notSlot", "slotTypeVersion": "1.0"}], "status": "Failed"}); - expect(run).toBeCalledWith('createIntentVersion', {"name": 'test-index', "checksum": 'checksum-test' }); - //Deleted Fields set to UnDefined - expect(result.lastUpdatedDate).toBeUndefined(); - expect(result.version).toBeUndefined(); - expect(result.createdDate).toBeUndefined(); - - //Modify the version in slot[0] with name 'slot' - expect(result.slots[0].slotTypeVersion).toEqual('2.0'); - //Other slot version remains unchanged - expect(result.slots[1].slotTypeVersion).toEqual('1.0'); - - //intentVersion is equal to the version returned by run mock - expect(intentVersion).toEqual('3.0'); - }); - - test('Should return intentVersion when slot name is notSlot', async () => { - const runMock = { - 'name': 'mock-test', - 'checksum': 'checksum-test', - 'version': '3.0' - }; - run.mockResolvedValue(runMock); - - const version = '2.0'; - const result = intentFixtures.returnResult(false); - const intentVersion = await intent(version, result); - - expect(run).toBeCalledTimes(2); - expect(run).toBeCalledWith('putIntent', {"failureReason": "timeout", "name": "test-index", "slots": [{"name": "notSlot", "slotTypeVersion": "1.0"}, {"name": "notSlot", "slotTypeVersion": "1.0"}], "status": "Failed"}); - expect(run).toBeCalledWith('createIntentVersion', {"name": 'test-index', "checksum": 'checksum-test' }); - //Deleted Fields set to UnDefined - expect(result.lastUpdatedDate).toBeUndefined(); - expect(result.version).toBeUndefined(); - expect(result.createdDate).toBeUndefined(); - - //Both slots remains unchanged - expect(result.slots[0].slotTypeVersion).toEqual('1.0'); - expect(result.slots[1].slotTypeVersion).toEqual('1.0'); - - //intentVersion is equal to the version returned by run mock - expect(intentVersion).toEqual('3.0'); - }); -}); diff --git a/source/lambda/lex-build/test/lib/intentFallback.test.js b/source/lambda/lex-build/test/lib/intentFallback.test.js deleted file mode 100644 index 58d69aca2..000000000 --- a/source/lambda/lex-build/test/lib/intentFallback.test.js +++ /dev/null @@ -1,60 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - - -const intentFallback = require('../../lib/intentFallback'); -const run = require('../../lib/run'); -jest.mock('../../lib/run'); - -describe('When calling intentFallback function', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - test('Should return intentFallback version', async () => { - const runMock = { - 'name': 'mock-test', - 'checksum': 'checksum-test', - 'version': '3.0' - }; - run.mockResolvedValue(runMock); - - const version = '2.0'; - const result = { - 'name': 'test', - 'status': 'Failed', - 'failureReason': 'timeout', - 'lastUpdatedDate': '12/03/2023', - 'createdDate': '10/27/2023', - 'version': '2.0' - }; - - const res = await intentFallback(version, result); - - expect(run).toBeCalledTimes(2); - expect(run).toBeCalledWith('putIntent', {"failureReason": "timeout", "name": "test", "status": "Failed"}); - expect(run).toBeCalledWith('createIntentVersion', {"checksum": "checksum-test", "name": "test"}); - - //Deleted Fields set to UnDefined - expect(result.lastUpdatedDate).toBeUndefined(); - expect(result.version).toBeUndefined(); - expect(result.createdDate).toBeUndefined(); - - //IntentVersion set to original version passed in func - expect(res.intent_version).toEqual('2.0'); - - //IntentFallback version set to RunMock version - expect(res.intentFallback_version).toEqual('3.0'); - }); - -}); diff --git a/source/lambda/lex-build/test/lib/lexv1bot.test.js b/source/lambda/lex-build/test/lib/lexv1bot.test.js deleted file mode 100644 index 9439f53e7..000000000 --- a/source/lambda/lex-build/test/lib/lexv1bot.test.js +++ /dev/null @@ -1,128 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const run = require('../../lib/run'); -const slot= require('../../lib/slot'); -const intent = require('../../lib/intent'); -const intentFallback = require('../../lib/intentFallback'); -const alias = require('../../lib/alias'); -const bot = require('../../lib/bot'); -const status = require('../../lib/statusv1'); -const wait = require('../../lib/wait'); -const lexV1 = require('../../lib/lexv1bot'); -jest.mock('../../lib/run'); -jest.mock('../../lib/slot'); -jest.mock('../../lib/intent'); -jest.mock('../../lib/intentFallback'); -jest.mock('../../lib/alias'); -jest.mock('../../lib/bot'); -jest.mock('../../lib/delete'); -jest.mock('../../lib/statusv1'); -jest.mock('../../lib/wait'); - -describe('When calling lexV1bot function', () => { - beforeEach(() => { - jest.clearAllMocks(); - process.env.SLOTTYPE = 'test-slot'; - process.env.INTENT = 'test-intent'; - process.env.INTENTFALLBACK = 'test-intentFallback'; - process.env.BOTNAME = 'test-bot'; - process.env.BOTALIAS = 'test-alias'; - }); - - test('Should return successful response', async () => { - run.mockImplementationOnce(() => { - return { - slots: [1, 3, 3], - version: '3.0' - }; - }).mockImplementationOnce(() => { - return { - intentVersion: '3.0', - status: 'success' - }; - }).mockImplementationOnce(() => { - return { - intentFallbackVersion: '2.0', - status: 'success' - }; - }).mockImplementation(() => { - return { - version: '3.0', - status: 'READY' - }; - }); - - jest.useFakeTimers(); - jest.spyOn(global, 'setTimeout'); - - await expect(lexV1({})).resolves.not.toThrow(); - - expect(status).toHaveBeenCalledTimes(4); - expect(status).toHaveBeenCalledWith('Rebuilding Slot'); - expect(status).toHaveBeenCalledWith('Rebuilding Intent'); - expect(status).toHaveBeenCalledWith('Rebuilding IntentFallback'); - expect(status).toHaveBeenCalledWith('Rebuilding Lex V1 Bot'); - expect(run).toHaveBeenCalledTimes(4); - expect(run).toHaveBeenCalledWith('getSlotType', {"name": "test-slot", "version": "$LATEST"}); - expect(run).toHaveBeenCalledWith('getIntent', {"name": "test-intent", "version": "$LATEST"}); - expect(run).toHaveBeenCalledWith('getIntent', {"name": "test-intentFallback", "version": "$LATEST"}); - expect(run).toHaveBeenCalledWith('getBot', {"name": "test-bot", "versionOrAlias": "$LATEST"}); - expect(slot).toHaveBeenCalledTimes(1); - expect(slot).toHaveBeenCalledWith({}, {"slots": [1, 3, 3], "version": "3.0"}); - expect(intent).toHaveBeenCalledTimes(1); - expect(intent).toHaveBeenCalledWith(undefined, {"intentVersion": "3.0", "status": "success"}); - expect(intentFallback).toHaveBeenCalledTimes(1); - expect(intentFallback).toHaveBeenCalledWith(undefined, {"intentFallbackVersion": "2.0", "status": "success"}); - expect(bot).toHaveBeenCalledTimes(1); - expect(bot).toHaveBeenCalledWith(undefined, {"status": "READY", "version": "3.0"}); - expect(alias).toHaveBeenCalledTimes(1); - expect(alias).toHaveBeenCalledWith(undefined, {"botName": "test-bot", "name": "test-alias"}); - expect(wait).toHaveBeenCalledTimes(1); - expect(setTimeout).toHaveBeenCalledTimes(1); - }); - - test('Should return error', async () => { - run.mockImplementation(() => { - return { - slots: [1, 3, 3], - version: '3.0' - }; - }) - const error = new Error('Error building lexV1bot'); - slot.mockRejectedValue(error); - - jest.useFakeTimers(); - jest.spyOn(global, 'setTimeout'); - - await lexV1({}) - - expect(status).toHaveBeenCalledTimes(2); - expect(status).toHaveBeenCalledWith('Rebuilding Slot'); - expect(status).toHaveBeenCalledWith('Failed', 'Error building lexV1bot'); - expect(run).toHaveBeenCalledTimes(4); - expect(run).toHaveBeenCalledWith('getSlotType', {"name": "test-slot", "version": "$LATEST"}); - expect(run).toHaveBeenCalledWith('getIntent', {"name": "test-intent", "version": "$LATEST"}); - expect(run).toHaveBeenCalledWith('getIntent', {"name": "test-intentFallback", "version": "$LATEST"}); - expect(run).toHaveBeenCalledWith('getBot', {"name": "test-bot", "versionOrAlias": "$LATEST"}); - expect(slot).toHaveBeenCalledTimes(1); - expect(slot).toHaveBeenCalledWith({}, {"slots": [1, 3, 3], "version": "3.0"}); - expect(intent).toHaveBeenCalledTimes(0); - expect(intentFallback).toHaveBeenCalledTimes(0); - expect(bot).toHaveBeenCalledTimes(0); - expect(alias).toHaveBeenCalledTimes(0); - expect(wait).toHaveBeenCalledTimes(0); - expect(setTimeout).toHaveBeenCalledTimes(0); - }); -}); - diff --git a/source/lambda/lex-build/test/lib/run.test.js b/source/lambda/lex-build/test/lib/run.test.js deleted file mode 100644 index 45556163b..000000000 --- a/source/lambda/lex-build/test/lib/run.test.js +++ /dev/null @@ -1,92 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const run = require('../../lib/run'); -const { LexModelBuildingServiceClient, - CreateBotVersionCommand -} = require('@aws-sdk/client-lex-model-building-service'); -const { mockClient } = require('aws-sdk-client-mock'); -const lexModelBuildingServiceClientMock = mockClient(LexModelBuildingServiceClient); - - -describe('When calling run function', () => { - const lexCreateBotResponse = { - "$metadata": { - "httpStatusCode": 201, "requestId": "429fe1b2-c69f-4a41-aa14-146a85677fb3", "attempts": 1, - "totalRetryDelay": 0 - }, - "locale": "en-US", "name": "test_bot", "status": "BUILDING", "version": "1" - }; - - beforeEach(() => { - lexModelBuildingServiceClientMock.reset(); - }); - - test('should successfully invoke function passed in parameter and return response', async () => { - lexModelBuildingServiceClientMock.on(CreateBotVersionCommand).resolves(lexCreateBotResponse); - const response = await run('createBotVersion', { "name": "test_bot", "checksum": "test_checksum" }); - expect(response).toEqual(lexCreateBotResponse); - - }); - - test('when lex service returns ConflictException and retry is successful, it should return response', async () => { - lexModelBuildingServiceClientMock.on(CreateBotVersionCommand).callsFakeOnce(() => { - const error = new Error("ConflictException"); - error.name = "ConflictException"; - throw error; - }).resolvesOnce(lexCreateBotResponse); - const response = await run('createBotVersion', { "name": "test_bot", "checksum": "test_checksum" }); - expect(response).toEqual(lexCreateBotResponse); - }, 10000); - - test('when lex service returns ResourceInUseException with retryAfterSeconds value set and retry is successful, it should return response', async () => { - lexModelBuildingServiceClientMock.on(CreateBotVersionCommand).callsFakeOnce(() => { - const error = new Error("ResourceInUseException"); - error.name = "ResourceInUseException"; - error.retryAfterSeconds = 3; - throw error; - }).resolvesOnce(lexCreateBotResponse); - const response = await run('createBotVersion', { "name": "test_bot", "checksum": "test_checksum" }); - expect(response).toEqual(lexCreateBotResponse); - }, 10000); - - test('when lex service returns ResourceInUseException and retry is successful, it should return response', async () => { - lexModelBuildingServiceClientMock.on(CreateBotVersionCommand).callsFakeOnce(() => { - const error = new Error("ResourceInUseException"); - error.name = "ResourceInUseException"; - throw error; - }).resolvesOnce(lexCreateBotResponse); - const response = await run('createBotVersion', { "name": "test_bot", "checksum": "test_checksum" }); - expect(response).toEqual(lexCreateBotResponse); - }, 10000); - - test('when lex service returns LimitExceededException and retry is successful, it should return response', async () => { - lexModelBuildingServiceClientMock.on(CreateBotVersionCommand).callsFakeOnce(() => { - const error = new Error("LimitExceededException"); - error.name = "LimitExceededException"; - throw error; - }).resolvesOnce(lexCreateBotResponse); - const response = await run('createBotVersion', { "name": "test_bot", "checksum": "test_checksum" }); - expect(response).toEqual(lexCreateBotResponse); - }, 10000); - - test('should throw error when the error from lex service is not in retry error list', async () => { - lexModelBuildingServiceClientMock.on(CreateBotVersionCommand).callsFakeOnce(() => { - const error = new Error("Test Error"); - error.name = "TestError"; - throw error; - }); - await expect(run('createBotVersion', { "name": "test_bot", "checksum": "test_checksum" })).rejects.toThrow('TestError:Test Error'); - }); -} -); \ No newline at end of file diff --git a/source/lambda/lex-build/test/lib/slot.test.js b/source/lambda/lex-build/test/lib/slot.test.js deleted file mode 100644 index c2ed96276..000000000 --- a/source/lambda/lex-build/test/lib/slot.test.js +++ /dev/null @@ -1,60 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - - -const slot = require('../../lib/slot'); -const run = require('../../lib/run'); -jest.mock('../../lib/run'); - -describe('When running slot function', () => { - test('Should return slotTypeVersion', async () => { - const runMock = { - 'name': 'mock-test', - 'checksum': 'checksum-test', - 'version': '3.0' - }; - run.mockResolvedValue(runMock); - - const utterances = [2, 2, 1]; - const slottype = { - 'name': 'test-slot', - 'status': 'Failed', - 'failureReason': 'timeout', - 'lastUpdatedDate': '12/03/2023', - 'createdDate': '10/27/2023', - 'version': '2.0', - 'enumerationValues': [], - }; - - const responseVersion = await slot(utterances, slottype); - - expect(run).toBeCalledTimes(2); - expect(run).toBeCalledWith('putSlotType', {"name": "test-slot", "enumerationValues": [{"value": 2}, {"value": 1}], "failureReason": "timeout", "status": "Failed"}); - expect(run).toBeCalledWith('createSlotTypeVersion', {"checksum": "checksum-test", "name": "test-slot"}); - - //Deleted Fields set to UnDefined - expect(slottype.lastUpdatedDate).toBeUndefined(); - expect(slottype.version).toBeUndefined(); - expect(slottype.createdDate).toBeUndefined(); - - //Verify slottype.enumerationValues contains distinct values - const valueArr = [ - {'value': 2}, - {'value': 1} - ]; - expect(slottype.enumerationValues).toEqual(valueArr); - - //final version is set to mock-run's version - expect(responseVersion).toEqual('3.0'); - }); -}); diff --git a/source/lambda/lex-build/test/lib/statusv1.test.js b/source/lambda/lex-build/test/lib/statusv1.test.js deleted file mode 100644 index f6a9e131a..000000000 --- a/source/lambda/lex-build/test/lib/statusv1.test.js +++ /dev/null @@ -1,138 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - - -const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3'); -const { mockClient } = require('aws-sdk-client-mock'); -const s3Mock = mockClient(S3Client); -require('aws-sdk-client-mock-jest'); -const statusV1 = require('../../lib/statusv1'); -const { sdkStreamMixin } = require('@smithy/util-stream'); -const {Readable} = require('stream'); - -describe('When calling statusV1 function', () => { - beforeEach(() => { - s3Mock.reset(); - process.env.STATUS_KEY = 'testKey'; - process.env.STATUS_BUCKET = 'testBucket'; - }); - - test('Should successfully send PutObjectCommand to s3 with no errors with status and message', async () => { - const message = 'test-message'; - const status = 'success'; - const mockResponse = { - 'name': 'test-statusv1', - 'lastUpdatedDate': '12/03/2023', - 'createdDate': '10/27/2023', - 'version': '2.0'}; - - const stream = new Readable(); - stream.push(JSON.stringify(mockResponse)); - stream.push(null); - - s3Mock.on(GetObjectCommand).resolves( - { - Body: sdkStreamMixin(stream) - } - ); - - const verifyMessage = {}; - - //Add status and message fields to mockResponse if required - const statusAndMessageMock = jest.fn().mockImplementation(() => { - if(message) verifyMessage.message=message; - verifyMessage.status=status; - return verifyMessage; - }) - - await statusV1(status, message); - - const putParams = { - Body: "{\"name\":\"test-statusv1\",\"lastUpdatedDate\":\"12/03/2023\",\"createdDate\":\"10/27/2023\",\"version\":\"2.0\",\"message\":\"test-message\",\"status\":\"success\"}", - Bucket: 'testBucket', - Key: 'testKey' - }; - expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(GetObjectCommand, {"Bucket": "testBucket", "Key": "testKey"}); - expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(PutObjectCommand, putParams); - - //Verify Status and message present - expect(statusAndMessageMock().status).toEqual(status); - expect(statusAndMessageMock().message).toEqual(message) - - }); - - test('Should successfully send PutObjectCommand to s3 with no errors with status only', async () => { - const message = undefined; - const status = 'success'; - const mockResponse = { - 'name': 'test-statusv1-noMessage', - 'lastUpdatedDate': '12/03/2023', - 'createdDate': '10/27/2023', - 'version': '2.0'}; - - const stream = new Readable(); - stream.push(JSON.stringify(mockResponse)); - stream.push(null); - - s3Mock.on(GetObjectCommand).resolves( - { - Body: sdkStreamMixin(stream) - } - ); - - const verifyMessage = {}; - - //Add status and message fields to mockResponse if required - const statusAndMessageMock = jest.fn().mockImplementation(() => { - if(message) verifyMessage.message=message; - verifyMessage.status=status; - return verifyMessage; - }) - - await statusV1(status, message); - - const putParams = { - Body: "{\"name\":\"test-statusv1-noMessage\",\"lastUpdatedDate\":\"12/03/2023\",\"createdDate\":\"10/27/2023\",\"version\":\"2.0\",\"status\":\"success\"}", - Bucket: 'testBucket', - Key: 'testKey' - }; - expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(GetObjectCommand, {"Bucket": "testBucket", "Key": "testKey"}); - expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(PutObjectCommand, putParams); - - - //Verify Status and message present - expect(statusAndMessageMock().status).toEqual(status); - expect(statusAndMessageMock().message).toBeUndefined(); - }); - - - test('Should throw error', async () => { - const message = 'test-message'; - const status = 'success'; - - s3Mock.on(GetObjectCommand).rejects(new Error("Error with PutObject Command")); - - await expect(async () => { - await statusV1(status, message) - }).rejects.toThrowError(); - - expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(GetObjectCommand, {"Bucket": "testBucket", "Key": "testKey"}); - expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 0); - }); - -}); diff --git a/source/lambda/lex-build/test/lib/utterances.test.js b/source/lambda/lex-build/test/lib/utterances.test.js deleted file mode 100644 index 67893b38f..000000000 --- a/source/lambda/lex-build/test/lib/utterances.test.js +++ /dev/null @@ -1,82 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - - -const utterances = require('../../lib/utterances'); -const { con } = require('/opt/opensearch-client/connection'); -const esFixtures = require('./es.fixtures'); -const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3'); -const { mockClient } = require('aws-sdk-client-mock'); -const { Readable } = require('stream'); -const { sdkStreamMixin } = require('@smithy/util-stream'); -const s3Mock = mockClient(S3Client); -require('aws-sdk-client-mock-jest'); -jest.mock('/opt/opensearch-client/connection'); - -describe('When calling utterances function', () => { - beforeEach(() => { - jest.clearAllMocks(); - s3Mock.reset(); - process.env.INDEX = 'test-index'; - process.env.UTTERANCE_BUCKET = 'test-bucket'; - process.env.UTTERANCE_KEY = 'test-key'; - process.env.ADDRESS = 'test-address'; - }); - - test('Should return combined utterances successfully', async () => { - const params = { - address: 'test-address' - }; - - const mockEs = jest.fn().mockImplementation(() => { - return esFixtures.returnEsMock('qna'); - }); - const mockResponse = mockEs(); - - con.mockImplementation(() => { - return mockResponse; - }); - - const s3MockResponse = 'Sample Mock question from S3'; - - const stream = new Readable(); - stream.push(JSON.stringify(s3MockResponse)); - stream.push(null); - - s3Mock.on(GetObjectCommand).resolves( - { - Body: sdkStreamMixin(stream) - } - ); - - const combinedUtterances = await utterances(params); - - expect(con).toBeCalledTimes(1); - expect(con).toBeCalledWith('test-address'); - expect(mockResponse.search).toHaveBeenCalledTimes(1); - expect(mockResponse.search).toHaveBeenCalledWith({"body": {"query": {"match_all": {}}}, "index": "test-index", "scroll": "10s"}); - expect(mockResponse.scroll).toHaveBeenCalledTimes(2); - expect(mockResponse.scroll).toHaveBeenCalledWith({"scroll": "10s", "scrollId": "1.0"}); - - expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(GetObjectCommand, {"Bucket": "test-bucket", "Key": "test-key"}); - - //Total size of combinedUtterances is 5, 2 from search, 2 from scroll and 1 from s3 - expect(combinedUtterances.length).toEqual(5); - expect(combinedUtterances[0]).toEqual('What is QnABot?'); - expect(combinedUtterances[1]).toEqual('How is weather today?'); - expect(combinedUtterances[2]).toEqual('What is best place to see northern lights?'); - expect(combinedUtterances[3]).toEqual('What is Best Indian restaurant in US?'); - expect(combinedUtterances[4]).toEqual('Sample Mock question from S3'); - }); -}) diff --git a/source/lambda/lex-build/test/lib/wait.test.js b/source/lambda/lex-build/test/lib/wait.test.js deleted file mode 100644 index 7d5433804..000000000 --- a/source/lambda/lex-build/test/lib/wait.test.js +++ /dev/null @@ -1,51 +0,0 @@ -/********************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - *********************************************************************************************************************/ - -const { LambdaClient, InvokeCommand } = require('@aws-sdk/client-lambda'); -const { mockClient } = require('aws-sdk-client-mock'); -const lambdaMock = mockClient(LambdaClient); -const wait = require('../../lib/wait'); -require('aws-sdk-client-mock-jest'); - -describe('When calling wait function', () => { - beforeEach(() => { - lambdaMock.reset(); - process.env.POLL_LAMBDA = 'test-wait'; - }); - - test('Should return successful response', async () => { - const testResponse = { - 'name': 'test-wait-response', - 'question': 'what is QnABot' - }; - - lambdaMock.on(InvokeCommand).resolves(testResponse); - - const response = await wait('Success'); - - expect(lambdaMock).toHaveReceivedCommandTimes(InvokeCommand, 1); - expect(lambdaMock).toHaveReceivedCommandWith(InvokeCommand, {"FunctionName": "test-wait", "InvocationType": "Event", "Payload": "{}"}); - expect(response).toMatchObject(testResponse); - }); - - test('Should return error', async () => { - - const error = new Error('wait error'); - lambdaMock.on(InvokeCommand).rejects(error); - - await expect(wait('Fail')).rejects.toThrowError(error); - - expect(lambdaMock).toHaveReceivedCommandTimes(InvokeCommand, 1); - expect(lambdaMock).toHaveReceivedCommandWith(InvokeCommand, {"FunctionName": "test-wait", "InvocationType": "Event", "Payload": "{}"}); - }); -}); diff --git a/source/lambda/lexv2-build/requirements-test.txt b/source/lambda/lexv2-build/requirements-test.txt index ed98b7883..4f50a96aa 100644 --- a/source/lambda/lexv2-build/requirements-test.txt +++ b/source/lambda/lexv2-build/requirements-test.txt @@ -1,4 +1,4 @@ -moto~=4.2.4 -pytest~=7.4.2 -pytest-cov~=4.1.0 +moto~=5.0.13 +pytest~=8.3.2 +pytest-cov~=5.0.0 mock~=5.1.0 \ No newline at end of file diff --git a/source/lambda/lexv2-build/requirements.txt b/source/lambda/lexv2-build/requirements.txt index 83a876f05..bcffde562 100644 --- a/source/lambda/lexv2-build/requirements.txt +++ b/source/lambda/lexv2-build/requirements.txt @@ -1,2 +1,2 @@ -boto3==1.26.3 +boto3==1.35.5 crhelper==2.0.10 \ No newline at end of file diff --git a/source/lambda/lexv2-build/test/test_lambda_function.py b/source/lambda/lexv2-build/test/test_lambda_function.py index 700529db2..eed851cff 100644 --- a/source/lambda/lexv2-build/test/test_lambda_function.py +++ b/source/lambda/lexv2-build/test/test_lambda_function.py @@ -15,10 +15,9 @@ import boto3 import json from unittest.mock import patch, MagicMock -from moto import mock_iam, mock_s3 +from moto import mock_aws -@mock_iam -@mock_s3 +@mock_aws class TestLambdaFunction(unittest.TestCase): def setUp(self): self.iam_client = boto3.client("iam") diff --git a/source/lambda/proxy-es/package-lock.json b/source/lambda/proxy-es/package-lock.json index f884237ed..2b78a7e40 100644 --- a/source/lambda/proxy-es/package-lock.json +++ b/source/lambda/proxy-es/package-lock.json @@ -1,12 +1,12 @@ { "name": "proxy-es", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "proxy-es", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0" } } diff --git a/source/lambda/proxy-es/package.json b/source/lambda/proxy-es/package.json index 9dde02e93..5299726a0 100644 --- a/source/lambda/proxy-es/package.json +++ b/source/lambda/proxy-es/package.json @@ -1,6 +1,6 @@ { "name": "proxy-es", - "version": "6.0.3", + "version": "6.1.0", "description": "QnABot Lambda function is used to proxy request from ApiGateway to OpenSearch", "main": "index.js", "author": { diff --git a/source/lambda/qnabot-common-layer/package-lock.json b/source/lambda/qnabot-common-layer/package-lock.json index e0f360182..9c956785b 100644 --- a/source/lambda/qnabot-common-layer/package-lock.json +++ b/source/lambda/qnabot-common-layer/package-lock.json @@ -1,12 +1,12 @@ { "name": "qnabot-common-layer", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "qnabot-common-layer", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-ssm": "^3.511.0", @@ -146,16 +146,16 @@ } }, "node_modules/@aws-sdk/client-ssm": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.622.0.tgz", - "integrity": "sha512-/FyBz+Fy9+72TfK0uYTUnZYdnuUNFSsUV83bIw3IOtOEumzoSxF2drq4d80cUVALDjctfDkbftN6Og1GaKlIqg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.621.0.tgz", + "integrity": "sha512-E4OM7HH9qU2TZGDrX2MlBlBr9gVgDm573Qa1CTFih58dUZyaPEOiZSYLUNOyw4nMyVLyDMR/5zQ4wAorNwKVPw==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -166,26 +166,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -199,13 +199,13 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.622.0.tgz", - "integrity": "sha512-DJwUqVR/O2lImbktUHOpaQ8XElNBx3JmWzTT2USg6jh3ErgG1CS6LIV+VUlgtxGl+tFN/G6AcAV8SdnnGydB8Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", + "@aws-sdk/core": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -216,26 +216,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -247,14 +247,14 @@ } }, "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.622.0.tgz", - "integrity": "sha512-dwWDfN+S98npeY77Ugyv8VIHKRHN+n/70PWE4EgolcjaMrTINjvUh9a/SypFEs5JmBOAeCQt8S2QpM3Wvzp+pQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -265,26 +265,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -295,19 +295,19 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/client-sts": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.622.0.tgz", - "integrity": "sha512-Yqtdf/wn3lcFVS42tR+zbz4HLyWxSmztjVW9L/yeMlvS7uza5nSkWqP/7ca+RxZnXLyrnA4jJtSHqykcErlhyg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -318,26 +318,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -349,15 +349,15 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.622.0.tgz", - "integrity": "sha512-q1Ct2AjPxGtQBKtDpqm1umu3f4cuWMnEHTuDa6zjjaj+Aq/C6yxLgZJo9SlcU0tMl8rUCN7oFonszfTtp4Y0MA==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", "dependencies": { - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "fast-xml-parser": "4.4.1", @@ -382,16 +382,16 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.622.0.tgz", - "integrity": "sha512-VUHbr24Oll1RK3WR8XLUugLpgK9ZuxEm/NVeVqyFts1Ck9gsKpRg1x4eH7L7tW3SJ4TDEQNMbD7/7J+eoL2svg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/property-provider": "^3.1.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" @@ -401,14 +401,14 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.622.0.tgz", - "integrity": "sha512-cD/6O9jOfzQyo8oyAbTKnyRO89BIMSTzwaN4NxGySC6pYVTqxNSWdRwaqg/vKbwJpjbPGGYYXpXEW11kop7dlg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -421,19 +421,19 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.622.0.tgz", - "integrity": "sha512-keldwz4Q/6TYc37JH6m43HumN7Vi+R0AuGuHn5tBV40Vi7IiqEzjpiE+yvsHIN+duUheFLL3j/o0H32jb+14DQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -462,11 +462,11 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.622.0.tgz", - "integrity": "sha512-zrSoBVM2JlwvkBtrcUd4J/9CrG+T+hUy9r6jwo5gonFIN3QkneR/pqpbUn/n32Zy3zlzCo2VfB31g7MjG7kJmg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", "dependencies": { - "@aws-sdk/client-sso": "3.622.0", + "@aws-sdk/client-sso": "3.621.0", "@aws-sdk/token-providers": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", @@ -1712,15 +1712,15 @@ } }, "node_modules/@smithy/core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", - "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" @@ -1821,14 +1821,14 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", - "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", "dependencies": { "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1983,9 +1983,9 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -2075,12 +2075,12 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", - "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", "dependencies": { "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -2090,15 +2090,15 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", - "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", "dependencies": { "@smithy/config-resolver": "^3.0.5", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, diff --git a/source/lambda/qnabot-common-layer/package.json b/source/lambda/qnabot-common-layer/package.json index 950ae79f2..9d65e60c9 100644 --- a/source/lambda/qnabot-common-layer/package.json +++ b/source/lambda/qnabot-common-layer/package.json @@ -1,6 +1,6 @@ { "name": "qnabot-common-layer", - "version": "6.0.3", + "version": "6.1.0", "description": "Lambda layers used to provide common logging and utility functions", "repository": { "type": "git", diff --git a/source/lambda/s3-clean/requirements-test.txt b/source/lambda/s3-clean/requirements-test.txt index ea995fb0f..643e20825 100644 --- a/source/lambda/s3-clean/requirements-test.txt +++ b/source/lambda/s3-clean/requirements-test.txt @@ -1,7 +1,7 @@ boto3 -botocore==1.31.68 +botocore==1.35.5 coverage -pytest~=7.4.2 -pytest-cov~=4.1.0 +pytest~=8.3.2 +pytest-cov~=5.0.0 mock~=5.1.0 -moto~=4.2.4 +moto~=5.0.13 diff --git a/source/lambda/s3-clean/requirements.txt b/source/lambda/s3-clean/requirements.txt index 6e211317c..bd077b574 100644 --- a/source/lambda/s3-clean/requirements.txt +++ b/source/lambda/s3-clean/requirements.txt @@ -1,3 +1,3 @@ boto3 -botocore==1.31.68 +botocore==1.35.5 crhelper==2.0.11 \ No newline at end of file diff --git a/source/lambda/s3-clean/test/test_lambda_function.py b/source/lambda/s3-clean/test/test_lambda_function.py index 50cc0521e..da7af3e37 100644 --- a/source/lambda/s3-clean/test/test_lambda_function.py +++ b/source/lambda/s3-clean/test/test_lambda_function.py @@ -14,7 +14,7 @@ import unittest from unittest import mock import boto3 -from moto import mock_s3 +from moto import mock_aws bucket_name = 'test-bucket' object_key = f'{bucket_name}/test-key' @@ -42,7 +42,7 @@ def mocked_cf_event_non_existent_bucket(*args, **kwargs): } } -@mock_s3 +@mock_aws class LambdaTest(unittest.TestCase): def setUp(self): diff --git a/source/lambda/schema/package-lock.json b/source/lambda/schema/package-lock.json index e682292c4..42d3f34e7 100644 --- a/source/lambda/schema/package-lock.json +++ b/source/lambda/schema/package-lock.json @@ -1,12 +1,12 @@ { "name": "schema", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "schema", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "devDependencies": { "jest": "^29.7.0" diff --git a/source/lambda/schema/package.json b/source/lambda/schema/package.json index 245ce181e..e636020ac 100644 --- a/source/lambda/schema/package.json +++ b/source/lambda/schema/package.json @@ -1,6 +1,6 @@ { "name": "schema", - "version": "6.0.3", + "version": "6.1.0", "description": "Lambda function used to provide the schemas for the various qid types", "repository": { "type": "git", diff --git a/source/lambda/schema/qna.js b/source/lambda/schema/qna.js index 57267eddb..ec4dd5d37 100644 --- a/source/lambda/schema/qna.js +++ b/source/lambda/schema/qna.js @@ -247,7 +247,7 @@ module.exports = { properties: { responsebot_hook: { title: 'Elicit Response: ResponseBot Hook', - description: 'To capture the next utterance as a response, provide the name of a Lex bot to parse the response and return at least one slot value, e.g. (QNAYesNo, QNADate, etc.). For Lex V2 use "lexv2::Botid/BotAliasId/LocaleId". For Lex V1 use a bot name starting with "QNA".', + description: 'To capture the next utterance as a response, provide the name of a Lex bot to parse the response and return at least one slot value, e.g. (QNAYesNo, QNADate, etc.). For Lex V2 use "lexv2::Botid/BotAliasId/LocaleId".', type: 'string', maxLength: 100, propertyOrder: 0, @@ -282,8 +282,8 @@ module.exports = { propertyOrder: 18, properties: { specialty_bot: { - title: 'Bot Routing: LexV1 BotName OR lexv2::Botid/BotAliasId/LocaleId OR Lambda Function', - description: 'The target specialty Lex Bot or Lambda Function to route requests to. For Lex V2 bot names use the format "lexv2::BotId/BotAliasId/LocaleId". For Lex V1 bot the names should start with "QNA". Lambda functions can be specified as "Lambda::FunctionName" or "Lambda::FunctionARN" - Lambda function names must start with "QNA-".', + title: 'Bot Routing: lexv2::Botid/BotAliasId/LocaleId OR Lambda Function', + description: 'The target specialty Lex Bot or Lambda Function to route requests to. For Lex V2 bot names use the format "lexv2::BotId/BotAliasId/LocaleId". Lambda functions can be specified as "Lambda::FunctionName" or "Lambda::FunctionARN" - Lambda function names must start with "QNA-".', type: 'string', maxLength: 100, propertyOrder: 0, @@ -295,13 +295,6 @@ module.exports = { maxLength: 100, propertyOrder: 1, }, - specialty_bot_alias: { - title: 'The Bot alias to use for the Specialty Bot. (Required for other Lex/QnA Bot targets - Not utilized when Lambda Function is used.)', - description: 'For Lex V2 leave empty. For Lex V1 specialty bots, enter a string for the Specialty Bot\'s Lex alias.', - type: 'string', - maxLength: 100, - propertyOrder: 2, - }, specialty_bot_session_attributes_to_merge: { title: 'Session attributes to forward to a Lex specialty bot.', description: 'An optional comma separated list of session attributes to pass to a Lex specialty bot. Default is an empty string.', diff --git a/source/lambda/solution-helper/.coveragerc b/source/lambda/solution-helper/.coveragerc index a9cdba2c8..6b58a5717 100644 --- a/source/lambda/solution-helper/.coveragerc +++ b/source/lambda/solution-helper/.coveragerc @@ -3,12 +3,8 @@ omit = test/* .venv-*/* */__init__.py - certifi/* - charset_normalizer/* - crhelper/* - idna/* - requests/* - urllib3/* - ./test_lambda_function.py + py_modules/* + .pytest_cache/* + __pycache__/* source = . \ No newline at end of file diff --git a/source/lambda/solution-helper/.gitignore b/source/lambda/solution-helper/.gitignore deleted file mode 100755 index 281c161c6..000000000 --- a/source/lambda/solution-helper/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# exclude python 3rd party modules -*.dist-info/ -bin -certifi/ -charset_normalizer/ -crhelper/ -idna/ -requests/ -## crhelper tests directory -tests/ -urllib3/ diff --git a/source/lambda/solution-helper/README.md b/source/lambda/solution-helper/README.md new file mode 100644 index 000000000..7d1c3066d --- /dev/null +++ b/source/lambda/solution-helper/README.md @@ -0,0 +1,11 @@ +# Solution Helper Lambda +This lambda handles sending anonymized operational metrics to AWS. The sample data collection: +``` +{'InstallLexResponseBots': 'true', 'EmbeddingsBedrockModelId': 'amazon.titan-embed-text-v1', 'PublicOrPrivate': 'PRIVATE', 'LLMApi': 'BEDROCK', 'OpenSearchEBSVolumeSize': '10', 'LexBotVersion': 'LexV2 Only', 'EmbeddingsApi': 'BEDROCK', 'Language': 'English', 'Version': 'v6.1.0', 'OpenSearchNodeCount': '1', 'LLMBedrockModelId': 'anthropic.claude-instant-v1', 'Region': 'us-east-1', 'OpenSearchInstanceType': 'm6g.large.search', 'FulfillmentConcurrency': '1', 'RequestType': 'Delete', 'BEDROCK_GUARDRAIL_ENABLE': 'false', 'ENABLE_MULTI_LANGUAGE_SUPPORT': 'false', 'LLM_GENERATE_QUERY_ENABLE': 'true', 'KNOWLEDGE_BASE_SEARCH_TYPE': 'DEFAULT', 'PII_REJECTION_ENABLED': 'false', 'EMBEDDINGS_ENABLE': 'true', 'LLM_QA_ENABLE': 'true'} +``` + +## Tests +Unit test are run using: +```shell +python -m pytest +``` diff --git a/source/lambda/solution-helper/lambda_function.py b/source/lambda/solution-helper/lambda_function.py index 34d965517..c24ecd3d8 100644 --- a/source/lambda/solution-helper/lambda_function.py +++ b/source/lambda/solution-helper/lambda_function.py @@ -11,21 +11,59 @@ # and limitations under the License. # ###################################################################################################################### +import json import os import sys root = os.environ["LAMBDA_TASK_ROOT"] + "/py_modules" sys.path.insert(0, root) import logging, uuid, requests +import boto3 +from botocore.exceptions import ClientError from copy import copy from crhelper import CfnResource -from datetime import datetime +from datetime import datetime, timezone logger = logging.getLogger(__name__) helper = CfnResource(json_logging=True, log_level="INFO") REQUST_TIMEOUT = 10 # in seconds +ssm_client = boto3.client('ssm') +solution_parameter = os.environ["SOLUTION_PARAMETER"] +custom_settings_parameter = os.environ["CUSTOM_SETTINGS"] + +def get_parameter(parameter_name): + try: + response = ssm_client.get_parameter( + Name=parameter_name, + WithDecryption=True + ) + parameter_value = response['Parameter']['Value'] + print(f"Current value of {parameter_name}: {parameter_value}") + return parameter_value + except ClientError as e: + message = e.response['Error']['Message'] + code = e.response['Error']['Code'] + logger.exception(f"Error while getting parameter {parameter_name}: {code}:{message}") + raise e + +def update_parameter(parameter_name, new_parameter_value): + try: + response = ssm_client.put_parameter( + Name=parameter_name, + Value=new_parameter_value, + Type='SecureString', + Overwrite=True + ) + code = response['ResponseMetadata']['HTTPStatusCode'] + logger.info(f"Parameter updated with status {code}") + except ClientError as e: + message = e.response['Error']['Message'] + code = e.response['Error']['Code'] + logger.exception(f"Error while updating parameter {parameter_name}: {code}:{message}") + raise e + def _sanitize_data(resource_properties): # Remove ServiceToken (lambda arn) to avoid sending AccountId resource_properties.pop("ServiceToken", None) @@ -37,6 +75,22 @@ def _sanitize_data(resource_properties): return resource_properties +def custom_map(settings): + # Build a anonymized custom setting map + c_map = {} + if settings.get('BEDROCK_GUARDRAIL_IDENTIFIER') and settings.get('BEDROCK_GUARDRAIL_VERSION'): + c_map['BEDROCK_GUARDRAIL_ENABLE'] = 'true' + else: + c_map['BEDROCK_GUARDRAIL_ENABLE'] = 'false' + + c_map['ENABLE_MULTI_LANGUAGE_SUPPORT'] = settings.get('ENABLE_MULTI_LANGUAGE_SUPPORT', 'false') + c_map['LLM_GENERATE_QUERY_ENABLE'] = settings.get('LLM_GENERATE_QUERY_ENABLE', 'true') + c_map['KNOWLEDGE_BASE_SEARCH_TYPE'] = settings.get('KNOWLEDGE_BASE_SEARCH_TYPE', 'DEFAULT') + c_map['PII_REJECTION_ENABLED'] = settings.get('PII_REJECTION_ENABLED', 'false') + c_map['EMBEDDINGS_ENABLE'] = settings.get('EMBEDDINGS_ENABLE', 'true') + c_map['LLM_QA_ENABLE'] = settings.get('LLM_QA_ENABLE', 'true') + + return c_map @helper.create @helper.update @@ -51,24 +105,27 @@ def custom_resource(event, _): if request_type == "Create": random_id = str(uuid.uuid4()) helper.Data.update({"UUID": random_id}) + update_parameter(solution_parameter, random_id) elif resource == "AnonymizedMetric": try: metrics_data = _sanitize_data(copy(resource_properties)) metrics_data["RequestType"] = request_type - headers = {"Content-Type": "application/json"} - payload = { - "Solution": resource_properties["SolutionId"], - "UUID": resource_properties["UUID"], - "TimeStamp": datetime.utcnow().isoformat(), - "Data": metrics_data, - } + solutionId = resource_properties["SolutionId"] + solution_uuid = resource_properties["UUID"] + update_parameter(solution_parameter, solution_uuid) + send_metrics_request(metrics_data, solutionId, solution_uuid) - logger.info(f"Sending payload: {payload}") - response = requests.post( - "https://metrics.awssolutionsbuilder.com/generic", json=payload, headers=headers, timeout=REQUST_TIMEOUT - ) - logger.info(f"Response from metrics endpoint: {response.status_code} {response.reason}") + # also send the settings as 'event': 'UPDATE_SETTINGS' + try: + custom_settings = get_parameter(custom_settings_parameter) + custom_settings_data = json.loads(custom_settings) + custom_data = custom_map(custom_settings_data) + custom_data["event"]="UPDATE_SETTINGS" + send_metrics_request(custom_data, solutionId, solution_uuid) + except (ValueError, TypeError): + print("Error parsing custom settings, skipping custom data sending.") + except requests.exceptions.RequestException: logger.exception("Could not send usage data") except KeyError: @@ -76,6 +133,28 @@ def custom_resource(event, _): else: raise ValueError(f"Unknown resource: {resource}") +def send_metrics_request(metrics_data, solutionId, solution_uuid): + headers = {"Content-Type": "application/json"} + payload = { + "Solution": solutionId, + "UUID": solution_uuid, + "TimeStamp": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f"), + "Data": metrics_data, + } + + logger.info(f"Sending payload: {payload}") + response = requests.post( + "https://metrics.awssolutionsbuilder.com/generic", json=payload, headers=headers, timeout=REQUST_TIMEOUT + ) + logger.info(f"Response from metrics endpoint: {response.status_code} {response.reason}") + def handler(event, context): - helper(event, context) + logger.info(f"Received event: {event}") + if "ResourceProperties" in event: + helper(event, context) + else: + if "event" in event: + solutionId = os.environ["SOLUTION_ID"] + solution_uuid = get_parameter(solution_parameter) + send_metrics_request(event, solutionId, solution_uuid) \ No newline at end of file diff --git a/source/lambda/solution-helper/pytest.ini b/source/lambda/solution-helper/pytest.ini new file mode 100644 index 000000000..54fc9ba9d --- /dev/null +++ b/source/lambda/solution-helper/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +testpaths = test \ No newline at end of file diff --git a/source/lambda/solution-helper/requirements-test.txt b/source/lambda/solution-helper/requirements-test.txt index 9dab1c638..c79e0de46 100644 --- a/source/lambda/solution-helper/requirements-test.txt +++ b/source/lambda/solution-helper/requirements-test.txt @@ -1,6 +1,7 @@ boto3 -botocore==1.31.68 +botocore==1.35.5 coverage -pytest~=7.4.2 -pytest-cov~=4.1.0 +pytest~=8.3.2 +pytest-cov~=5.0.0 mock~=5.1.0 +moto~=5.0.13 \ No newline at end of file diff --git a/source/lambda/solution-helper/requirements.txt b/source/lambda/solution-helper/requirements.txt index 8fc40dd51..beef49866 100644 --- a/source/lambda/solution-helper/requirements.txt +++ b/source/lambda/solution-helper/requirements.txt @@ -1,2 +1,3 @@ crhelper==2.0.11 -requests==2.32.3 \ No newline at end of file +requests==2.32.3 +boto3 \ No newline at end of file diff --git a/source/lambda/solution-helper/conftest.py b/source/lambda/solution-helper/test/conftest.py similarity index 91% rename from source/lambda/solution-helper/conftest.py rename to source/lambda/solution-helper/test/conftest.py index 8128b2557..d6ca83813 100644 --- a/source/lambda/solution-helper/conftest.py +++ b/source/lambda/solution-helper/test/conftest.py @@ -18,3 +18,6 @@ def aws_environment_variables(): """Mocked AWS evivronment variables such as AWS credentials and region""" os.environ["LAMBDA_TASK_ROOT"] = f"{os.path.dirname(os.path.realpath(__file__))}/.." + os.environ["SOLUTION_ID"] = "SO1234" + os.environ["SOLUTION_PARAMETER"] = "some-parameter" + os.environ["CUSTOM_SETTINGS"] = "some-custom-settings" \ No newline at end of file diff --git a/source/lambda/solution-helper/test/test_lambda_function.py b/source/lambda/solution-helper/test/test_lambda_function.py new file mode 100644 index 000000000..aa64e9b39 --- /dev/null +++ b/source/lambda/solution-helper/test/test_lambda_function.py @@ -0,0 +1,220 @@ +###################################################################################################################### +# Copyright 2020-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance # +# with the License. A copy of the License is located at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES # +# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions # +# and limitations under the License. # +###################################################################################################################### + +import os +import boto3 +import unittest, requests +from unittest import mock +from unittest.mock import patch +from moto import mock_aws +from botocore.exceptions import ClientError + +def mocked_requests_post(*args, **kwargs): + class MockResponse: + def __init__(self, status_code, reason): + self.status_code = status_code + self.reason = reason + + return MockResponse(200, 'OK') +@mock_aws +class LambdaTest(unittest.TestCase): + def setUp(self): + self.mock_aws = mock_aws() + self.mock_aws.start() + self.ssm_client = boto3.client('ssm') + self.ssm_client.put_parameter(Name=os.environ["SOLUTION_PARAMETER"], Type="SecureString", Value='some-uuid', Overwrite=True) + + #send an empty custom settings to test the default values + self.ssm_client.put_parameter(Name=os.environ["CUSTOM_SETTINGS"], Overwrite=True, Type="String", Value='{}') + def test_create_unique_id(self): + import lambda_function + + event = { + 'RequestType': 'Create', + 'ResourceProperties': { 'Resource': 'UUID' } + } + + lambda_function.custom_resource(event, None) + self.assertIsNotNone(lambda_function.helper.Data.get('UUID')) + + @mock.patch('requests.post', side_effect=mocked_requests_post) + def test_send_metrics_successful(self, mock_post): + event = { + 'RequestType': 'Create', + 'ResourceProperties': { + 'Resource': 'AnonymizedMetric', + 'SolutionId': 'SO1234', + 'UUID': 'some-uuid', + 'Foo': 'Bar' + } + } + + from lambda_function import custom_resource + custom_resource(event, None) + + # Assert the first mock call + first_call_args = mock_post.call_args_list[0] + expected_metrics_endpoint = 'https://metrics.awssolutionsbuilder.com/generic' + actual_metrics_endpoint = first_call_args.args[0] + self.assertEqual(expected_metrics_endpoint, actual_metrics_endpoint) + + expected_headers = {'Content-Type': 'application/json'} + actual_headers = first_call_args.kwargs['headers'] + self.assertEqual(expected_headers, actual_headers) + + actual_payload = first_call_args.kwargs['json'] + self.assertIn('Solution', actual_payload) + self.assertIn('UUID', actual_payload) + self.assertIn('TimeStamp', actual_payload) + self.assertIn('Data', actual_payload) + + # Assert the default values in the payload + self.assertEqual(actual_payload['Data'], {'Foo': 'Bar', 'RequestType': 'Create'}) + + # Assert the second mock call + second_call_args = mock_post.call_args_list[1] + expected_metrics_endpoint = 'https://metrics.awssolutionsbuilder.com/generic' + actual_metrics_endpoint = second_call_args.args[0] + self.assertEqual(expected_metrics_endpoint, actual_metrics_endpoint) + + expected_headers = {'Content-Type': 'application/json'} + actual_headers = second_call_args.kwargs['headers'] + self.assertEqual(expected_headers, actual_headers) + + actual_payload = second_call_args.kwargs['json'] + self.assertIn('Solution', actual_payload) + self.assertIn('UUID', actual_payload) + self.assertIn('TimeStamp', actual_payload) + self.assertIn('Data', actual_payload) + + # Assert the payload values for the second call + self.assertEqual(actual_payload['Data'], {'BEDROCK_GUARDRAIL_ENABLE': 'false', 'ENABLE_MULTI_LANGUAGE_SUPPORT': 'false', 'LLM_GENERATE_QUERY_ENABLE': 'true', 'KNOWLEDGE_BASE_SEARCH_TYPE': 'DEFAULT', 'PII_REJECTION_ENABLED': 'false', 'EMBEDDINGS_ENABLE': 'true', 'LLM_QA_ENABLE': 'true', 'event': 'UPDATE_SETTINGS'}) + + @mock.patch('requests.post') + def test_send_metrics_connection_error(self, mock_post): + mock_post.side_effect = requests.exceptions.ConnectionError() + + event = { + 'RequestType': 'Update', + 'ResourceProperties': { + 'Resource': 'AnonymizedMetric', + 'SolutionId': 'SO1234', + 'UUID': 'some-uuid' + } + } + + try: + from lambda_function import custom_resource + custom_resource(event, None) + except requests.exceptions.RequestException: + self.fail('Exception should not be raised when metrics cannot be sent') + + @mock.patch('requests.post') + def test_send_metrics_other_error(self, mock_post): + try: + invalid_event = { + 'RequestType': 'Delete', + 'ResourceProperties': { + 'Resource': 'AnonymizedMetric', + 'UUID': 'some-uuid' + } + } + mock_parameter_value = '{}' + with patch('lambda_function.ssm_client.get_parameter') as mock_get_parameter: + mock_get_parameter.return_value = mock_parameter_value + + from lambda_function import custom_resource + custom_resource(invalid_event, None) + except requests.exceptions.RequestException: + self.fail('Exception should not be raised when metrics cannot be sent') + + def test_sanitize_data(self): + from lambda_function import _sanitize_data + + resource_properties = { + 'ServiceToken': 'lambda-fn-arn', + 'Resource': 'AnonymizedMetric', + 'SolutionId': 'SO1234', + 'UUID': 'some-uuid', + 'Region': 'us-east-1', + 'Foo': 'Bar' + } + + expected_response = { + 'Region': 'us-east-1', + 'Foo': 'Bar' + } + + actual_response = _sanitize_data(resource_properties) + self.assertCountEqual(expected_response, actual_response) + + @mock.patch('requests.post', side_effect=mocked_requests_post) + def test_send_metrics_successful_when_event(self, mock_post): + from lambda_function import handler + + event = { + 'event': 'UPDATE_SETTINGS', + 'BEDROCK_GUARDRAIL_ENABLE': 'true', + 'ENABLE_MULTI_LANGUAGE_SUPPORT': 'false', + 'LLM_GENERATE_QUERY_ENABLE': 'true', + 'KNOWLEDGE_BASE_SEARCH_TYPE': 'DEFAULT', + 'PII_REJECTION_ENABLED': 'false', + 'EMBEDDINGS_ENABLE': 'true', + 'LLM_QA_ENABLE': 'true' + } + + mock_parameter_value = "some-uuid" + with patch('lambda_function.ssm_client.get_parameter') as mock_get_parameter: + mock_get_parameter.return_value = mock_parameter_value + + + handler(event, None) + + expected_metrics_endpoint = 'https://metrics.awssolutionsbuilder.com/generic' + actual_metrics_endpoint = mock_post.call_args.args[0] + self.assertEqual(expected_metrics_endpoint, actual_metrics_endpoint) + + expected_headers = {'Content-Type': 'application/json'} + actual_headers = mock_post.call_args.kwargs['headers'] + self.assertEqual(expected_headers, actual_headers) + + actual_payload = mock_post.call_args.kwargs['json'] + self.assertIn('Solution', actual_payload) + self.assertIn('UUID', actual_payload) + self.assertIn('TimeStamp', actual_payload) + + self.assertIn('Data', actual_payload) + self.assertEqual(actual_payload['Data'], event) + + def test_get_settings_parameter_not_found(self): + parameter_name = 'unknown' + from lambda_function import get_parameter + with patch('lambda_function.ssm_client.get_parameter') as mock_get_parameter: + mock_get_parameter.side_effect = ClientError( + {'Error': {'Code': 'ParameterNotFound', 'Message': 'Parameter not found'}}, 'GetParameter') + with self.assertRaises(ClientError) as context: + get_parameter(parameter_name) + self.assertEqual(context.exception.response['Error']['Code'], 'ParameterNotFound') + self.assertEqual(context.exception.response['Error']['Message'], 'Parameter not found') + + def test_update_parameter_not_found(self): + parameter_name = 'unknown' + parameter_value = 'some-value' + from lambda_function import update_parameter + with patch('lambda_function.ssm_client.put_parameter') as mock_put_parameter: + mock_put_parameter.side_effect = ClientError( + {'Error': {'Code': 'ParameterNotFound', 'Message': 'Parameter not found'}}, 'GetParameter') + with self.assertRaises(ClientError) as context: + update_parameter(parameter_name, parameter_value) + self.assertEqual(context.exception.response['Error']['Code'], 'ParameterNotFound') + self.assertEqual(context.exception.response['Error']['Message'], 'Parameter not found') \ No newline at end of file diff --git a/source/lambda/solution-helper/test_lambda_function.py b/source/lambda/solution-helper/test_lambda_function.py deleted file mode 100644 index 2762a014e..000000000 --- a/source/lambda/solution-helper/test_lambda_function.py +++ /dev/null @@ -1,121 +0,0 @@ -###################################################################################################################### -# Copyright 2020-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. # -# # -# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance # -# with the License. A copy of the License is located at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES # -# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions # -# and limitations under the License. # -###################################################################################################################### - -import unittest, requests -from unittest import mock - -def mocked_requests_post(*args, **kwargs): - class MockResponse: - def __init__(self, status_code, reason): - self.status_code = status_code - self.reason = reason - - return MockResponse(200, 'OK') - -class LambdaTest(unittest.TestCase): - def test_create_unique_id(self): - import lambda_function - - event = { - 'RequestType': 'Create', - 'ResourceProperties': { 'Resource': 'UUID' } - } - - lambda_function.custom_resource(event, None) - self.assertIsNotNone(lambda_function.helper.Data.get('UUID')) - - @mock.patch('requests.post', side_effect=mocked_requests_post) - def test_send_metrics_successful(self, mock_post): - event = { - 'RequestType': 'Create', - 'ResourceProperties': { - 'Resource': 'AnonymizedMetric', - 'SolutionId': 'SO1234', - 'UUID': 'some-uuid', - 'Foo': 'Bar' - } - } - - from lambda_function import custom_resource - custom_resource(event, None) - - expected_metrics_endpoint = 'https://metrics.awssolutionsbuilder.com/generic' - actual_metrics_endpoint = mock_post.call_args.args[0] - self.assertEqual(expected_metrics_endpoint, actual_metrics_endpoint) - - expected_headers = {'Content-Type': 'application/json'} - actual_headers = mock_post.call_args.kwargs['headers'] - self.assertEqual(expected_headers, actual_headers) - - actual_payload = mock_post.call_args.kwargs['json'] - self.assertIn('Solution', actual_payload) - self.assertIn('UUID', actual_payload) - self.assertIn('TimeStamp', actual_payload) - - self.assertIn('Data', actual_payload) - self.assertEqual(actual_payload['Data'], {'Foo': 'Bar', 'RequestType': 'Create'}) - - @mock.patch('requests.post') - def test_send_metrics_connection_error(self, mock_post): - mock_post.side_effect = requests.exceptions.ConnectionError() - - event = { - 'RequestType': 'Update', - 'ResourceProperties': { - 'Resource': 'AnonymizedMetric', - 'SolutionId': 'SO1234', - 'UUID': 'some-uuid' - } - } - - try: - from lambda_function import custom_resource - custom_resource(event, None) - except requests.exceptions.RequestException: - self.fail('Exception should not be raised when metrics cannot be sent') - - @mock.patch('requests.post') - def test_send_metrics_other_error(self, mock_post): - try: - invalid_event = { - 'RequestType': 'Delete', - 'ResourceProperties': { - 'Resource': 'AnonymizedMetric', - 'UUID': 'some-uuid' - } - } - - from lambda_function import custom_resource - custom_resource(invalid_event, None) - except requests.exceptions.RequestException: - self.fail('Exception should not be raised when metrics cannot be sent') - - def test_sanitize_data(self): - from lambda_function import _sanitize_data - - resource_properties = { - 'ServiceToken': 'lambda-fn-arn', - 'Resource': 'AnonymizedMetric', - 'SolutionId': 'SO1234', - 'UUID': 'some-uuid', - 'Region': 'us-east-1', - 'Foo': 'Bar' - } - - expected_response = { - 'Region': 'us-east-1', - 'Foo': 'Bar' - } - - actual_response = _sanitize_data(resource_properties) - self.assertCountEqual(expected_response, actual_response) diff --git a/source/lambda/testall/index.js b/source/lambda/testall/index.js index 60ea7cab8..642340c7e 100644 --- a/source/lambda/testall/index.js +++ b/source/lambda/testall/index.js @@ -21,52 +21,49 @@ const step = require('./lib/step'); const lex = require('./lib/lex'); const clean = require('./lib/clean'); +const outputBucket = process.env.OUTPUT_S3_BUCKET; + exports.step = async function (event, context, cb) { - console.log('step'); + console.log('Initiating TestAll'); console.log('Request', JSON.stringify(event, null, 2)); - const Bucket = event.Records[0].s3.bucket.name; + const inputBucket = event.Records[0].s3.bucket.name; const Key = decodeURI(event.Records[0].s3.object.key); - const VersionId = _.get(event, 'Records[0].s3.object.versionId'); - console.log(Bucket, Key); + const initialVersionId = _.get(event, 'Records[0].s3.object.versionId'); try { - await waitUntilObjectExists({ - client: s3, - maxWaitTime: 30 - }, { Bucket, Key, VersionId }); - const getObjCmd = new GetObjectCommand({ Bucket, Key, VersionId }); - const s3GetObj = await s3.send(getObjCmd); - const readableStream = Buffer.concat(await s3GetObj.Body.toArray()); - const config = JSON.parse(readableStream); - - if (config.status !== 'Error' && config.status !== 'Completed') { - try { - const config_redacted = { ...config, token: 'REDACTED' }; - console.log('Config:', JSON.stringify(config_redacted, null, 2)); - - switch (config.status) { - case 'Started': - await start(config); - break; - case 'InProgress': - await step(config); - break; - case 'Lex': - await lex(config); - break; - case 'Clean': - await clean(config); - break; - } - } catch (err) { - console.error('An error occured within switch cases: ', err); - config.status = 'Error'; - config.message = _.get(err, 'message', JSON.stringify(err)); - } - const putObjCmd = new PutObjectCommand({ Bucket, Key, Body: JSON.stringify(config) }) - await s3.send(putObjCmd); - } + const startResult = await getStatusAndStartNextStep(inputBucket, Key, initialVersionId, start); + const stepResult = await getStatusAndStartNextStep(outputBucket, Key, startResult.VersionId, step); + const lexResult = await getStatusAndStartNextStep(outputBucket, Key, stepResult.VersionId, lex); + await getStatusAndStartNextStep(outputBucket, Key, lexResult.VersionId, clean); } catch (error) { console.error('An error occured in S3 operations: ', error); cb(error); } }; + +async function getStatusAndStartNextStep(Bucket, Key, VersionId, nextStep) { + await waitUntilObjectExists({ + client: s3, + maxWaitTime: 30 + }, { Bucket, Key, VersionId }); + const getObjCmd = new GetObjectCommand({ Bucket, Key, VersionId }); + const s3GetObj = await s3.send(getObjCmd); + const readableStream = Buffer.concat(await s3GetObj.Body.toArray()); + const config = JSON.parse(readableStream); + + if (config.status !== 'Error' && config.status !== 'Completed') { + try { + const config_redacted = { ...config, token: 'REDACTED' }; + console.log('Config:', JSON.stringify(config_redacted, null, 2)); + await nextStep(config); + } catch (err) { + console.error('An error occured within the step '+config.status+': ', err); + config.status = 'Error'; + config.message = _.get(err, 'message', JSON.stringify(err)); + } + + const putObjCmd = new PutObjectCommand({ Bucket: outputBucket, Key, Body: JSON.stringify(config) }) + const putObjOutput = await s3.send(putObjCmd); + return putObjOutput; + } + +} \ No newline at end of file diff --git a/source/lambda/testall/jest.config.js b/source/lambda/testall/jest.config.js index dddc16129..c3f96b018 100644 --- a/source/lambda/testall/jest.config.js +++ b/source/lambda/testall/jest.config.js @@ -8,4 +8,8 @@ module.exports = { modulePaths: [ "/../aws-sdk-layer/" ] -}; \ No newline at end of file +}; + +process.env = Object.assign(process.env, { + OUTPUT_S3_BUCKET: 'contentdesigneroutputbucket' +}); \ No newline at end of file diff --git a/source/lambda/testall/lib/start.js b/source/lambda/testall/lib/start.js index b4273d2a6..1dffcac43 100644 --- a/source/lambda/testall/lib/start.js +++ b/source/lambda/testall/lib/start.js @@ -20,6 +20,7 @@ module.exports = async function (config) { config.status = 'InProgress'; config.startDate = (new Date()).toString(); config.parts = []; + config.bucket = process.env.OUTPUT_S3_BUCKET; return await load(config, { endpoint: process.env.ES_ENDPOINT, diff --git a/source/lambda/testall/package-lock.json b/source/lambda/testall/package-lock.json index c6497417b..e0919dd1e 100644 --- a/source/lambda/testall/package-lock.json +++ b/source/lambda/testall/package-lock.json @@ -1,12 +1,12 @@ { "name": "testall", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "testall", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-lex-runtime-v2": "^3.511.0" @@ -91,21 +91,22 @@ } }, "node_modules/@aws-sdk/client-lex-runtime-v2": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-v2/-/client-lex-runtime-v2-3.622.0.tgz", - "integrity": "sha512-zNc6tyx79TZ7ORSvzDFfVm2SzkcAlx3U6jcwTTbZDv+eMgNelBvYhRowQxgVIQ9briow+0BfnAOmbHEDHD+V5Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-v2/-/client-lex-runtime-v2-3.621.0.tgz", + "integrity": "sha512-UFjOmdBlu3lbTjd36VRbzInkhRyFwW3yeQM+y0O2qZY/8wHKaYkHsqNphSnpE/KAL/QusbczVKdEtpbzt2np9A==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/eventstream-handler-node": "3.620.0", "@aws-sdk/middleware-eventstream": "3.620.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-signing": "3.620.0", "@aws-sdk/middleware-user-agent": "3.620.0", "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", @@ -113,7 +114,7 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/eventstream-serde-browser": "^3.0.5", "@smithy/eventstream-serde-config-resolver": "^3.0.3", "@smithy/eventstream-serde-node": "^3.0.4", @@ -122,22 +123,21 @@ "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", "@smithy/util-stream": "^3.1.3", "@smithy/util-utf8": "^3.0.0", @@ -311,13 +311,13 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.622.0.tgz", - "integrity": "sha512-DJwUqVR/O2lImbktUHOpaQ8XElNBx3JmWzTT2USg6jh3ErgG1CS6LIV+VUlgtxGl+tFN/G6AcAV8SdnnGydB8Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", + "@aws-sdk/core": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -328,26 +328,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -359,14 +359,14 @@ } }, "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.622.0.tgz", - "integrity": "sha512-dwWDfN+S98npeY77Ugyv8VIHKRHN+n/70PWE4EgolcjaMrTINjvUh9a/SypFEs5JmBOAeCQt8S2QpM3Wvzp+pQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -377,26 +377,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -407,7 +407,7 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/abort-controller": { @@ -679,15 +679,15 @@ } }, "node_modules/@aws-sdk/client-sts": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.622.0.tgz", - "integrity": "sha512-Yqtdf/wn3lcFVS42tR+zbz4HLyWxSmztjVW9L/yeMlvS7uza5nSkWqP/7ca+RxZnXLyrnA4jJtSHqykcErlhyg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -698,26 +698,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -863,15 +863,15 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.622.0.tgz", - "integrity": "sha512-q1Ct2AjPxGtQBKtDpqm1umu3f4cuWMnEHTuDa6zjjaj+Aq/C6yxLgZJo9SlcU0tMl8rUCN7oFonszfTtp4Y0MA==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", "dependencies": { - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "fast-xml-parser": "4.4.1", @@ -930,16 +930,16 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.622.0.tgz", - "integrity": "sha512-VUHbr24Oll1RK3WR8XLUugLpgK9ZuxEm/NVeVqyFts1Ck9gsKpRg1x4eH7L7tW3SJ4TDEQNMbD7/7J+eoL2svg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/property-provider": "^3.1.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" @@ -1112,14 +1112,14 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.622.0.tgz", - "integrity": "sha512-cD/6O9jOfzQyo8oyAbTKnyRO89BIMSTzwaN4NxGySC6pYVTqxNSWdRwaqg/vKbwJpjbPGGYYXpXEW11kop7dlg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -1132,7 +1132,7 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/types": { @@ -1147,15 +1147,15 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.622.0.tgz", - "integrity": "sha512-keldwz4Q/6TYc37JH6m43HumN7Vi+R0AuGuHn5tBV40Vi7IiqEzjpiE+yvsHIN+duUheFLL3j/o0H32jb+14DQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -1206,11 +1206,11 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.622.0.tgz", - "integrity": "sha512-zrSoBVM2JlwvkBtrcUd4J/9CrG+T+hUy9r6jwo5gonFIN3QkneR/pqpbUn/n32Zy3zlzCo2VfB31g7MjG7kJmg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", "dependencies": { - "@aws-sdk/client-sso": "3.622.0", + "@aws-sdk/client-sso": "3.621.0", "@aws-sdk/token-providers": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", @@ -1421,6 +1421,46 @@ "node": ">=16.0.0" } }, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.620.0.tgz", + "integrity": "sha512-gxI7rubiaanUXaLfJ4NybERa9MGPNg2Ycl/OqANsozrBnR3Pw8vqy3EuVImQOyn2pJ2IFvl8ZPoSMHf4pX56FQ==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/middleware-user-agent": { "version": "3.620.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", @@ -3100,15 +3140,15 @@ } }, "node_modules/@smithy/core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", - "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" @@ -3463,14 +3503,14 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", - "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", "dependencies": { "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -3808,9 +3848,9 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -4075,12 +4115,12 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", - "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", "dependencies": { "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -4101,15 +4141,15 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", - "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", "dependencies": { "@smithy/config-resolver": "^3.0.5", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, diff --git a/source/lambda/testall/package.json b/source/lambda/testall/package.json index 81eb33b8c..285035059 100644 --- a/source/lambda/testall/package.json +++ b/source/lambda/testall/package.json @@ -1,6 +1,6 @@ { "name": "testall", - "version": "6.0.3", + "version": "6.1.0", "description": "Lambda function that reads QnAs from opensearch and performs test validation against each question defined in qna against current Lex bot", "main": "index.js", "scripts": { diff --git a/source/lambda/testall/test/index.fixtures.js b/source/lambda/testall/test/index.fixtures.js index 8d6528202..b3268dc3f 100644 --- a/source/lambda/testall/test/index.fixtures.js +++ b/source/lambda/testall/test/index.fixtures.js @@ -15,11 +15,15 @@ const { GetObjectCommand } = require('@aws-sdk/client-s3'); const { Readable } = require("stream"); const { sdkStreamMixin } = require('@smithy/util-stream'); -function mockStream(config, s3Mock) { +function mockStream(config, s3Mock, payload = "") { const stream = new Readable(); stream.push(JSON.stringify(config)); stream.push(null); const sdkStream = sdkStreamMixin(stream); - s3Mock.on(GetObjectCommand).resolves({ Body: sdkStream }); + if (payload != "") { + s3Mock.on(GetObjectCommand, payload).resolves({ Body: sdkStream }) + } else { + s3Mock.on(GetObjectCommand).resolves({ Body: sdkStream }); + } }; exports.mockStream = mockStream; diff --git a/source/lambda/testall/test/index.test.js b/source/lambda/testall/test/index.test.js index 410441489..bd244d667 100644 --- a/source/lambda/testall/test/index.test.js +++ b/source/lambda/testall/test/index.test.js @@ -36,7 +36,7 @@ const event = { name: "testallbucket", }, object: { - key: "status/TestAll.csv", + key: "status-testall/TestAll.csv", versionId: "tLkWAhY8v2rsaSPWqg2m", } } @@ -44,8 +44,100 @@ const event = { ] }; +function generateConfigAndVersionId(currentStatus) { + const config = { status : currentStatus }; + const versionId = Math.random().toString(36).substring(3,9); + return { config: config, versionId: versionId } +} + +function initializeStartStepMocks() { + const startConfig = generateConfigAndVersionId('Started'); + s3Mock.on(PutObjectCommand, {"Body": "{\"status\":\"Started\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv"}).resolves( + { + '$metadata': { + httpStatusCode: 200, + requestId: '', + extendedRequestId: '', + cfId: undefined, + attempts: 1, + totalRetryDelay: 0 + }, + Expiration: '', + ETag: '""', + ServerSideEncryption: '', + VersionId: startConfig.versionId + }) + mockStream(startConfig.config, s3Mock, {"Bucket": "testallbucket", "Key": "status-testall/TestAll.csv", "VersionId": "tLkWAhY8v2rsaSPWqg2m"}) + return { versionId: startConfig.versionId, config: startConfig.config } +} + +function initializeInProgressStepMocks(startVersionId) { + const stepConfig = generateConfigAndVersionId('InProgress'); + s3Mock.on(PutObjectCommand, {"Body": "{\"status\":\"InProgress\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv"}).resolves( + { + '$metadata': { + httpStatusCode: 200, + requestId: '', + extendedRequestId: '', + cfId: undefined, + attempts: 1, + totalRetryDelay: 0 + }, + Expiration: '', + ETag: '""', + ServerSideEncryption: '', + VersionId: stepConfig.versionId + }) + mockStream(stepConfig.config, s3Mock, {"Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv", "VersionId": startVersionId}); + return { versionId: stepConfig.versionId, config: stepConfig.config } +} + +function initializeLexStepMocks(inProgressVersionId) { + const lexConfig = generateConfigAndVersionId('Lex'); + s3Mock.on(PutObjectCommand, {"Body": "{\"status\":\"Lex\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv"}).resolves( + { + '$metadata': { + httpStatusCode: 200, + requestId: '', + extendedRequestId: '', + cfId: undefined, + attempts: 1, + totalRetryDelay: 0 + }, + Expiration: '', + ETag: '""', + ServerSideEncryption: '', + VersionId: lexConfig.versionId + }) + mockStream(lexConfig.config, s3Mock, {"Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv", "VersionId": inProgressVersionId}); + return { versionId: lexConfig.versionId, config: lexConfig.config } +} + +function initializeCleanStepMocks(lexVersionId) { + const cleanConfig = generateConfigAndVersionId('Clean'); + s3Mock.on(PutObjectCommand, {"Body": "{\"status\":\"Clean\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv"}).resolves( + { + '$metadata': { + httpStatusCode: 200, + requestId: '', + extendedRequestId: '', + cfId: undefined, + attempts: 1, + totalRetryDelay: 0 + }, + Expiration: '', + ETag: '""', + ServerSideEncryption: '', + VersionId: cleanConfig.versionId + }) + mockStream(cleanConfig.config, s3Mock, {"Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv", "VersionId": lexVersionId}); + return { versionId: cleanConfig.versionId, config: cleanConfig.config } +} + + describe('when calling index function', () => { + beforeEach(() => { s3Mock.reset(); }); @@ -55,58 +147,28 @@ describe('when calling index function', () => { jest.clearAllMocks(); }); - it('should call start and update status correctly', async () => { - const config = { status : 'Started' }; - mockStream(config, s3Mock); + it('should call the different steps and update status as expected', async () => { + const startStepInfo = initializeStartStepMocks(); + const inProgressStepInfo = initializeInProgressStepMocks(startStepInfo.versionId); + const lexStepInfo = initializeLexStepMocks(inProgressStepInfo.versionId); + const cleanStepInfo = initializeCleanStepMocks(lexStepInfo.versionId); await index.step(event, null, jest.fn()); expect(start).toHaveBeenCalledTimes(1); - expect(start).toHaveBeenCalledWith(config); - expect(step).toHaveBeenCalledTimes(0); - expect(lex).toHaveBeenCalledTimes(0); - expect(clean).toHaveBeenCalledTimes(0); - expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(GetObjectCommand, {"Bucket": "testallbucket", "Key": "status/TestAll.csv", "VersionId": "tLkWAhY8v2rsaSPWqg2m"}); - expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(PutObjectCommand, {"Body": "{\"status\":\"Started\"}", "Bucket": "testallbucket", "Key": "status/TestAll.csv"}); - }); - - it('should call step and update status correctly', async () => { - const config = { status : 'InProgress' }; - mockStream(config, s3Mock); - await index.step(event, null, jest.fn()); + expect(start).toHaveBeenCalledWith(startStepInfo.config); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(1, GetObjectCommand, {"Bucket": "testallbucket", "Key": "status-testall/TestAll.csv", "VersionId": "tLkWAhY8v2rsaSPWqg2m"}); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(1, PutObjectCommand, {"Body": "{\"status\":\"Started\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv"}); expect(step).toHaveBeenCalledTimes(1); - expect(step).toHaveBeenCalledWith(config); - expect(lex).toHaveBeenCalledTimes(0); - expect(clean).toHaveBeenCalledTimes(0); - expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(GetObjectCommand, {"Bucket": "testallbucket", "Key": "status/TestAll.csv", "VersionId": "tLkWAhY8v2rsaSPWqg2m"}); - expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(PutObjectCommand, {"Body": "{\"status\":\"InProgress\"}", "Bucket": "testallbucket", "Key": "status/TestAll.csv"}); - }); - - it('should call lex and update status correctly', async () => { - const config = { status : 'Lex' }; - mockStream(config, s3Mock); - await index.step(event, null, jest.fn()); + expect(step).toHaveBeenCalledWith(inProgressStepInfo.config); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(2, GetObjectCommand, {"Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv", "VersionId": startStepInfo.versionId}); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(2, PutObjectCommand, {"Body": "{\"status\":\"InProgress\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv"}); expect(lex).toHaveBeenCalledTimes(1); - expect(lex).toHaveBeenCalledWith(config); - expect(clean).toHaveBeenCalledTimes(0); - expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(GetObjectCommand, {"Bucket": "testallbucket", "Key": "status/TestAll.csv", "VersionId": "tLkWAhY8v2rsaSPWqg2m"}); - expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(PutObjectCommand, {"Body": "{\"status\":\"Lex\"}", "Bucket": "testallbucket", "Key": "status/TestAll.csv"}); - }); - - it('should call clean and update status correctly', async () => { - const config = { status : 'Clean' }; - mockStream(config, s3Mock); - await index.step(event, null, jest.fn()); + expect(lex).toHaveBeenCalledWith(lexStepInfo.config); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(3, GetObjectCommand, {"Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv", "VersionId": inProgressStepInfo.versionId}); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(3, PutObjectCommand, {"Body": "{\"status\":\"Lex\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv"}); expect(clean).toHaveBeenCalledTimes(1); - expect(clean).toHaveBeenCalledWith(config); - expect(s3Mock).toHaveReceivedCommandTimes(GetObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(GetObjectCommand, {"Bucket": "testallbucket", "Key": "status/TestAll.csv", "VersionId": "tLkWAhY8v2rsaSPWqg2m"}); - expect(s3Mock).toHaveReceivedCommandTimes(PutObjectCommand, 1); - expect(s3Mock).toHaveReceivedCommandWith(PutObjectCommand, {"Body": "{\"status\":\"Clean\"}", "Bucket": "testallbucket", "Key": "status/TestAll.csv"}); + expect(clean).toHaveBeenCalledWith(cleanStepInfo.config); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(4,GetObjectCommand, {"Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv", "VersionId": lexStepInfo.versionId}); + expect(s3Mock).toHaveReceivedNthSpecificCommandWith(4, PutObjectCommand, {"Body": "{\"status\":\"Clean\"}", "Bucket": "contentdesigneroutputbucket", "Key": "status-testall/TestAll.csv"}); }); it('should handle an error', async () => { diff --git a/source/lambda/testall/test/lib/start.test.js b/source/lambda/testall/test/lib/start.test.js index 1f2c64f60..06178fc68 100644 --- a/source/lambda/testall/test/lib/start.test.js +++ b/source/lambda/testall/test/lib/start.test.js @@ -53,6 +53,7 @@ describe('when calling start function', () => { parts: ['part'] }; const expectedConfig = { + bucket: 'contentdesigneroutputbucket', index: 'index', filter: 'filter', status: 'InProgress', @@ -80,6 +81,7 @@ describe('when calling start function', () => { parts: ['part'] }; const expectedConfig = { + bucket: 'contentdesigneroutputbucket', index: 'index', filter: null, status: 'InProgress', diff --git a/source/lambda/translate/package-lock.json b/source/lambda/translate/package-lock.json index 75fe71d0d..d5869d48e 100644 --- a/source/lambda/translate/package-lock.json +++ b/source/lambda/translate/package-lock.json @@ -1,12 +1,12 @@ { "name": "translate", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "translate", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "devDependencies": { "aws-sdk-client-mock": "^3.0.1", diff --git a/source/lambda/translate/package.json b/source/lambda/translate/package.json index e080ba435..4fd6a70b7 100644 --- a/source/lambda/translate/package.json +++ b/source/lambda/translate/package.json @@ -1,6 +1,6 @@ { "name": "translate", - "version": "6.0.3", + "version": "6.1.0", "description": "Lambda function used to import custom terminologies into AWS Translate", "repository": { "type": "git", diff --git a/source/package-lock.json b/source/package-lock.json index 6a2fba7c6..45c63fc44 100644 --- a/source/package-lock.json +++ b/source/package-lock.json @@ -1,12 +1,12 @@ { "name": "qnabot-on-aws", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "qnabot-on-aws", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "os": [ "darwin", @@ -31,12 +31,11 @@ "@vue/compat": "^3.3.8", "@vue/eslint-config-standard": "^8.0.1", "ajv": "^6.10.2", - "alexa-sdk": "^1.0.25", "async-mutex": "^0.1.3", "autosize": "^3.0.21", "aws-lex-web-ui": "git+https://github.com/aws-samples/aws-lex-web-ui.git#feature/qnabot-sdkv3", "aws4": "^1.7.0", - "axios": "^1.6.8", + "axios": "^1.7.4", "body-parser": "^1.18.3", "bowser": "^1.9.3", "cfn-response": "^1.0.1", @@ -50,7 +49,7 @@ "express": "^4.19.2", "faker": "^4.1.0", "file-saver": "^1.3.8", - "handlebars": "^4.7.7", + "handlebars": "^4.7.8", "handlebars-loader": "^1.7.3", "highlight.js": "^10.4.1", "idle-js": "^1.2.0", @@ -77,7 +76,7 @@ "quick-lru": "^1.1.0", "range": "0.0.3", "raw-text": "^1.1.0", - "read-excel-file": "^5.7.1", + "read-excel-file": "^5.8.5", "recursive-readdir": "^2.2.2", "require-dir": "^0.3.2", "roboto-fontface": "^0.8.0", @@ -314,16 +313,16 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/client-cloudformation": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.622.0.tgz", - "integrity": "sha512-prwXTkHJC/ESvcEBmnFMK7pMQRz5ycHokpucCOdBu47pYcOy6SxHsqckJQl/wZ7vQfVOrqy1TAzv1ByJE+C7yA==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.621.0.tgz", + "integrity": "sha512-GqFpLV5l/zxLuxtOa3lOr9TCObIei+CLLYoTVrO1z+q/+wvJGV/NgV0K3iYuG8+HXnTjb0WetUKPeFyOmL6dPw==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -334,26 +333,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -419,16 +418,16 @@ } }, "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.622.0.tgz", - "integrity": "sha512-VE4Mi6HMrs0Fpq8Nhgt3wBm5i7SyfTYD+FFW+Ofq1zMRWWePPqbs9HMSp6mLwynWL0SNcefYoIKqz2H/2e4mwQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.621.0.tgz", + "integrity": "sha512-FpXia5qFf6ijcNDWenVq+mP9r1LbiW/+52i9wrv2+Afi6Nn1ROf8W7St8WvE9TEZ3t78y+vis4CwqfGts+uiKA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -439,26 +438,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -470,16 +469,16 @@ } }, "node_modules/@aws-sdk/client-cognito-identity-provider": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity-provider/-/client-cognito-identity-provider-3.622.0.tgz", - "integrity": "sha512-WFFCuAQ5esGaGhPb3PyjxxhMqgUFyKM6yrG8Hsdr2mwEfXPKoMXz+s5tnk/VDfB3qZnNX+AghLT90s2GAAXLiA==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity-provider/-/client-cognito-identity-provider-3.621.0.tgz", + "integrity": "sha512-Tu2m18zW87gJwme6J74p/ZrfC5eJ3kv4yXpCAkfOz1JBO0vfxdoZIkkZ94G5tuCpiS5kljwS6GXpsKOojpVXcg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -490,26 +489,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -601,16 +600,16 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/client-kms": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-kms/-/client-kms-3.622.0.tgz", - "integrity": "sha512-ioNJcbFK6yQvlMaCfTzB7ltnB8pu7l2lM3vvd1fmvzc/XUnL04YTr6A7mhSY6mv4V7nW2a9hlgAJhtnthvPPnA==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-kms/-/client-kms-3.621.0.tgz", + "integrity": "sha512-JFCivEF+Yvi+gAz+qIp8FLnpyDWpoZ5rYNO5lScapwJKX+EQMOxbqAWCL957fosn22xR7GoWvm78D49QKJQGpg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -621,26 +620,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -692,16 +691,16 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/client-lambda": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.622.0.tgz", - "integrity": "sha512-hAR8LehlBkqFeXdqi3U46Q3zb1YO8eeEKJCe8II4r3I4bhdzFJDVXNoUZSDayDXmzmntmGqWZfihXQCmbTjdjw==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.621.0.tgz", + "integrity": "sha512-QD3FOMOLc9CQqfYOEzpTlB9LZbpN+0BrLUpc4+kNa+IheD5kes6gRRLB3Y1OLY4GIRTfPnYPTeFnW8AsSbcNzQ==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -712,7 +711,7 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/eventstream-serde-browser": "^3.0.5", "@smithy/eventstream-serde-config-resolver": "^3.0.3", "@smithy/eventstream-serde-node": "^3.0.4", @@ -721,20 +720,20 @@ "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -788,16 +787,16 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/client-lex-model-building-service": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-model-building-service/-/client-lex-model-building-service-3.622.0.tgz", - "integrity": "sha512-h2qwJ3q8D4+Rq/6Ihgp8tt1dY5ROPuqLKbBbXy8voCT5AK4HkRVaGgo03FZG0zpA768l67Nq05KU6w3YQysbQw==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-model-building-service/-/client-lex-model-building-service-3.621.0.tgz", + "integrity": "sha512-ltD7R8AkUSmIRGi1kQ86LhN/YQ3b+jetdH/hDT7SvPHBbGig/XotFl4Jn1FszchS9QuQc3wJB8uBHScJUDHU6g==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -808,26 +807,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -879,16 +878,16 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/client-lex-models-v2": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-models-v2/-/client-lex-models-v2-3.622.0.tgz", - "integrity": "sha512-CJW3V05azrjqYVaQnWlaRUzNTRGXj5NuudpIHr3VeJcKIM3XjWeqqewdpJaRNiNyKAOJHhFg0OZqitelHwcRTg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-models-v2/-/client-lex-models-v2-3.621.0.tgz", + "integrity": "sha512-Ypt2JYZLQPJLAsBbx3iX1pMgbGkSsof8rQ4FvcpIZE7MDPeo0M7AKz3X5joIny3DJYk1AjG3xdhYmyZU2VOTkA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -899,26 +898,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -971,16 +970,16 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/client-lex-runtime-service": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-service/-/client-lex-runtime-service-3.622.0.tgz", - "integrity": "sha512-XiMdKqWiIUjpItHfCp1sQEpMzhKnsaFNz/lrxfb+IPiCs8of63gKwpJ1tpi4DeEmuA8384VA4cU3bGAUgrpx5Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-service/-/client-lex-runtime-service-3.621.0.tgz", + "integrity": "sha512-QAE4OYDKzBucvLnhqoNaGVp8Mm75C/5rqcBdhiRoTpnOUP7DtUZRGVRnTqht9vuzJxqUvqUSUkkmtIfT/Jrl9g==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -991,26 +990,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1063,21 +1062,22 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/client-lex-runtime-v2": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-v2/-/client-lex-runtime-v2-3.622.0.tgz", - "integrity": "sha512-zNc6tyx79TZ7ORSvzDFfVm2SzkcAlx3U6jcwTTbZDv+eMgNelBvYhRowQxgVIQ9briow+0BfnAOmbHEDHD+V5Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-v2/-/client-lex-runtime-v2-3.621.0.tgz", + "integrity": "sha512-UFjOmdBlu3lbTjd36VRbzInkhRyFwW3yeQM+y0O2qZY/8wHKaYkHsqNphSnpE/KAL/QusbczVKdEtpbzt2np9A==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/eventstream-handler-node": "3.620.0", "@aws-sdk/middleware-eventstream": "3.620.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-signing": "3.620.0", "@aws-sdk/middleware-user-agent": "3.620.0", "@aws-sdk/region-config-resolver": "3.614.0", "@aws-sdk/types": "3.609.0", @@ -1085,7 +1085,7 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/eventstream-serde-browser": "^3.0.5", "@smithy/eventstream-serde-config-resolver": "^3.0.3", "@smithy/eventstream-serde-node": "^3.0.4", @@ -1094,22 +1094,21 @@ "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", "@smithy/util-stream": "^3.1.3", "@smithy/util-utf8": "^3.0.0", @@ -1160,16 +1159,16 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/client-opensearch": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-opensearch/-/client-opensearch-3.622.0.tgz", - "integrity": "sha512-8e/mp27WZpRi8cEr+hBkly+y++XNwpYiIGOHz2jll+E1UDUDjqoAEJt3kGaOSE02g2ffcXlJ0qjW0tZSKVzE2Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-opensearch/-/client-opensearch-3.621.0.tgz", + "integrity": "sha512-zSPQ9uV6bPrhx2TYQlRyAWi+iGmDoEgFfuMvqfPQR3e9sZeBHukcnAnBTai08dhVWz27Z6paYXaLEN3y12J7IA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -1180,26 +1179,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1251,16 +1250,16 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/client-polly": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-polly/-/client-polly-3.622.0.tgz", - "integrity": "sha512-9KCxAqRZR9PCUALZuv5XfhRe3X1AvfWFythCEJpWtbx9FDtSBhMcxBR6vWLw/4YO7x9TPOwTMx4JYc+zMlv8Kg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-polly/-/client-polly-3.621.0.tgz", + "integrity": "sha512-piJBMyTkqcfCHlNpiTAKl7BeJvYiCUfZVfKTpUbHRn5Ijl4RMmWHfygRCcpIxnhbRkzcz+Ri/mHXbMalkSFiAA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -1271,26 +1270,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1343,17 +1342,17 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/client-s3": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.622.0.tgz", - "integrity": "sha512-2lpvuQn/qymQPfwR2SxLyRy/Wi/RrEYpbQyoc9SYfhartw9TBY8c34yZkd8zNU7Y/KG3h+PLrCmNpncocuB3YA==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.621.0.tgz", + "integrity": "sha512-YhGkd2HQTM4HCYJIAVWvfbUMpOF7XUr1W/e2LN3CFP0WTF4zcCJKesJ2iNHrExqC0Ek1+qarMxiXBK95itfjYQ==", "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-bucket-endpoint": "3.620.0", "@aws-sdk/middleware-expect-continue": "3.620.0", "@aws-sdk/middleware-flexible-checksums": "3.620.0", @@ -1361,19 +1360,19 @@ "@aws-sdk/middleware-location-constraint": "3.609.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-sdk-s3": "3.622.0", + "@aws-sdk/middleware-sdk-s3": "3.621.0", "@aws-sdk/middleware-signing": "3.620.0", "@aws-sdk/middleware-ssec": "3.609.0", "@aws-sdk/middleware-user-agent": "3.620.0", "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/signature-v4-multi-region": "3.622.0", + "@aws-sdk/signature-v4-multi-region": "3.621.0", "@aws-sdk/types": "3.609.0", "@aws-sdk/util-endpoints": "3.614.0", "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@aws-sdk/xml-builder": "3.609.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/eventstream-serde-browser": "^3.0.5", "@smithy/eventstream-serde-config-resolver": "^3.0.3", "@smithy/eventstream-serde-node": "^3.0.4", @@ -1385,20 +1384,20 @@ "@smithy/md5-js": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-retry": "^3.0.3", "@smithy/util-stream": "^3.1.3", @@ -1451,16 +1450,16 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/client-ssm": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.622.0.tgz", - "integrity": "sha512-/FyBz+Fy9+72TfK0uYTUnZYdnuUNFSsUV83bIw3IOtOEumzoSxF2drq4d80cUVALDjctfDkbftN6Og1GaKlIqg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.621.0.tgz", + "integrity": "sha512-E4OM7HH9qU2TZGDrX2MlBlBr9gVgDm573Qa1CTFih58dUZyaPEOiZSYLUNOyw4nMyVLyDMR/5zQ4wAorNwKVPw==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -1471,26 +1470,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1556,13 +1555,13 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.622.0.tgz", - "integrity": "sha512-DJwUqVR/O2lImbktUHOpaQ8XElNBx3JmWzTT2USg6jh3ErgG1CS6LIV+VUlgtxGl+tFN/G6AcAV8SdnnGydB8Q==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", + "@aws-sdk/core": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -1573,26 +1572,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1604,14 +1603,14 @@ } }, "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.622.0.tgz", - "integrity": "sha512-dwWDfN+S98npeY77Ugyv8VIHKRHN+n/70PWE4EgolcjaMrTINjvUh9a/SypFEs5JmBOAeCQt8S2QpM3Wvzp+pQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -1622,26 +1621,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1652,7 +1651,7 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/is-array-buffer": { @@ -1736,15 +1735,15 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/client-sts": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.622.0.tgz", - "integrity": "sha512-Yqtdf/wn3lcFVS42tR+zbz4HLyWxSmztjVW9L/yeMlvS7uza5nSkWqP/7ca+RxZnXLyrnA4jJtSHqykcErlhyg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.622.0", - "@aws-sdk/core": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/middleware-host-header": "3.620.0", "@aws-sdk/middleware-logger": "3.609.0", "@aws-sdk/middleware-recursion-detection": "3.620.0", @@ -1755,26 +1754,26 @@ "@aws-sdk/util-user-agent-browser": "3.609.0", "@aws-sdk/util-user-agent-node": "3.614.0", "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/hash-node": "^3.0.3", "@smithy/invalid-dependency": "^3.0.3", "@smithy/middleware-content-length": "^3.0.5", "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/middleware-stack": "^3.0.3", "@smithy/node-config-provider": "^3.1.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/url-parser": "^3.0.3", "@smithy/util-base64": "^3.0.0", "@smithy/util-body-length-browser": "^3.0.0", "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", "@smithy/util-endpoints": "^2.0.5", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -1826,15 +1825,15 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/core": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.622.0.tgz", - "integrity": "sha512-q1Ct2AjPxGtQBKtDpqm1umu3f4cuWMnEHTuDa6zjjaj+Aq/C6yxLgZJo9SlcU0tMl8rUCN7oFonszfTtp4Y0MA==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", "dependencies": { - "@smithy/core": "^2.3.2", + "@smithy/core": "^2.3.1", "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "fast-xml-parser": "4.4.1", @@ -1850,11 +1849,11 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.622.0.tgz", - "integrity": "sha512-WXfTA1Q1bntE/KgoW+Vo2L2hgwr9YCHrfXgZLGQzCZwKQpW9iMWMxylSdn0NAHldN3fwiV/Oj6DqN0Tc8ScgNQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.621.0.tgz", + "integrity": "sha512-Q+3awvTVJSqIGRjCUQflRwKPKlZ0TfmL3EQHgFLhZZrToeBapEA62+FY+T70aTKAZZZZprlvYeFPtBloNd5ziA==", "dependencies": { - "@aws-sdk/client-cognito-identity": "3.622.0", + "@aws-sdk/client-cognito-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", "@smithy/types": "^3.3.0", @@ -1889,16 +1888,16 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.622.0.tgz", - "integrity": "sha512-VUHbr24Oll1RK3WR8XLUugLpgK9ZuxEm/NVeVqyFts1Ck9gsKpRg1x4eH7L7tW3SJ4TDEQNMbD7/7J+eoL2svg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", "dependencies": { "@aws-sdk/types": "3.609.0", "@smithy/fetch-http-handler": "^3.2.4", "@smithy/node-http-handler": "^3.1.4", "@smithy/property-provider": "^3.1.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-stream": "^3.1.3", "tslib": "^2.6.2" @@ -1913,14 +1912,14 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.622.0.tgz", - "integrity": "sha512-cD/6O9jOfzQyo8oyAbTKnyRO89BIMSTzwaN4NxGySC6pYVTqxNSWdRwaqg/vKbwJpjbPGGYYXpXEW11kop7dlg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -1933,7 +1932,7 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.622.0" + "@aws-sdk/client-sts": "^3.621.0" } }, "node_modules/@aws-sdk/credential-provider-ini/node_modules/tslib": { @@ -1942,15 +1941,15 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.622.0.tgz", - "integrity": "sha512-keldwz4Q/6TYc37JH6m43HumN7Vi+R0AuGuHn5tBV40Vi7IiqEzjpiE+yvsHIN+duUheFLL3j/o0H32jb+14DQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", "dependencies": { "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -1989,11 +1988,11 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.622.0.tgz", - "integrity": "sha512-zrSoBVM2JlwvkBtrcUd4J/9CrG+T+hUy9r6jwo5gonFIN3QkneR/pqpbUn/n32Zy3zlzCo2VfB31g7MjG7kJmg==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", "dependencies": { - "@aws-sdk/client-sso": "3.622.0", + "@aws-sdk/client-sso": "3.621.0", "@aws-sdk/token-providers": "3.614.0", "@aws-sdk/types": "3.609.0", "@smithy/property-provider": "^3.1.3", @@ -2033,20 +2032,20 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/credential-providers": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.622.0.tgz", - "integrity": "sha512-ImfpItaPwnwNBRG04x6iDwRAclvtW2+kSu4amGiMWF+EvnjnRTnyejAA/7rdBuxA4nwM4nb8jed0jnRkZyTu7A==", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.622.0", - "@aws-sdk/client-sso": "3.622.0", - "@aws-sdk/client-sts": "3.622.0", - "@aws-sdk/credential-provider-cognito-identity": "3.622.0", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.621.0.tgz", + "integrity": "sha512-FQbC7I8ae/72ZekLBa45jWJ+Q3d+YPhc3bW/rCks6RrldM6RgLTGr8pTOPCxHl828ky10RjkBiBmVU818rliyw==", + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.621.0", + "@aws-sdk/client-sso": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/credential-provider-cognito-identity": "3.621.0", "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.622.0", - "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-sso": "3.621.0", "@aws-sdk/credential-provider-web-identity": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/credential-provider-imds": "^3.2.0", @@ -2275,16 +2274,16 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.622.0.tgz", - "integrity": "sha512-tX9wZ2ALx5Ez4bkY+SvSj6DpNZ6TmY4zlsVsdgV95LZFLjNwqnZkKkS+uKnsIyLBiBp6g92JVQwnUEIp7ov2Zw==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.621.0.tgz", + "integrity": "sha512-CJrQrtKylcqvyPkRR16JmPZkHroCkWwLErQrg30ZcBPNNok8xbfX6cYqG16XDTnu4lSYzv2Yqc4w4oOBv8xerQ==", "dependencies": { "@aws-sdk/types": "3.609.0", "@aws-sdk/util-arn-parser": "3.568.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-config-provider": "^3.0.0", "@smithy/util-stream": "^3.1.3", @@ -2417,11 +2416,11 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.622.0.tgz", - "integrity": "sha512-K7ddofVNzwTFRjmLZLfs/v+hiE9m5LguajHk8WULxXQgkcDI3nPgOfmMMGuslYohaQhRwW+ic+dzYlateLUudQ==", + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.621.0.tgz", + "integrity": "sha512-u+ulCaHFveqHaTxgiYrEAyfBVP6GRKjnmDut67CtjhjslshPWYpo/ndtlCW1zc0RDne3uUeK13Pqp7dp7p1d6g==", "dependencies": { - "@aws-sdk/middleware-sdk-s3": "3.622.0", + "@aws-sdk/middleware-sdk-s3": "3.621.0", "@aws-sdk/types": "3.609.0", "@smithy/protocol-http": "^4.1.0", "@smithy/signature-v4": "^4.1.0", @@ -5513,15 +5512,15 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@smithy/core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", - "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" @@ -5903,14 +5902,14 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", - "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", "dependencies": { "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -6167,9 +6166,9 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -6334,12 +6333,12 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", - "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", "dependencies": { "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -6359,15 +6358,15 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", - "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", "dependencies": { "@smithy/config-resolver": "^3.0.5", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, @@ -8934,31 +8933,6 @@ "prettier": "^1.18.2 || ^2.0.0" } }, - "node_modules/@vue/component-compiler-utils/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "peer": true - }, - "node_modules/@vue/component-compiler-utils/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dev": true, - "peer": true, - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, "node_modules/@vue/devtools-api": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.1.tgz", @@ -9594,16 +9568,6 @@ "ajv": "^6.9.1" } }, - "node_modules/alexa-sdk": { - "version": "1.0.25", - "resolved": "https://registry.npmjs.org/alexa-sdk/-/alexa-sdk-1.0.25.tgz", - "integrity": "sha512-+FVFNi+mxBZm2HL+oi5u4JTNjQ2uDs4Tp9eqcWIxL3AAD+AU4a6gWpu6LEjxIVCqaI1Ro/RyDm3mnJZA9g6G8w==", - "dependencies": { - "aws-sdk": "^2.4.7", - "i18next": "^3.4.1", - "i18next-sprintf-postprocessor": "^0.2.2" - } - }, "node_modules/amazon-cognito-auth-js": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/amazon-cognito-auth-js/-/amazon-cognito-auth-js-1.3.3.tgz", @@ -10268,6 +10232,7 @@ "version": "2.1552.0", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1552.0.tgz", "integrity": "sha512-sRuzlCeSHXUsdLqsV/E+nPrgBn1EI3BoA38D5qfNMRcPTd9j4G8M4AyMymKyNxLoWOKLqz7xFBa801MHflGwEg==", + "dev": true, "dependencies": { "buffer": "4.9.2", "events": "1.1.1", @@ -10524,6 +10489,7 @@ "version": "4.9.2", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", @@ -10533,7 +10499,8 @@ "node_modules/aws-sdk/node_modules/ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true }, "node_modules/aws4": { "version": "1.12.0", @@ -10550,9 +10517,10 @@ } }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -10834,14 +10802,6 @@ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", "dev": true }, - "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "engines": { - "node": ">=0.6" - } - }, "node_modules/big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -10850,18 +10810,6 @@ "node": "*" } }, - "node_modules/binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "dependencies": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - }, - "engines": { - "node": "*" - } - }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -10924,9 +10872,7 @@ "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true, - "peer": true + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "node_modules/bn.js": { "version": "5.2.1", @@ -11253,27 +11199,11 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "engines": { - "node": ">=0.10" - } - }, "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" }, - "node_modules/buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", - "engines": { - "node": ">=0.2.0" - } - }, "node_modules/builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", @@ -11486,17 +11416,6 @@ "resolved": "https://registry.npmjs.org/cfn-response/-/cfn-response-1.0.1.tgz", "integrity": "sha1-qOwDlQwGg8UUlejKaA2dwLiEsTc=" }, - "node_modules/chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "dependencies": { - "traverse": ">=0.3.0 <0.4" - }, - "engines": { - "node": "*" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -13273,6 +13192,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "license": "BSD-3-Clause", "dependencies": { "readable-stream": "^2.0.2" } @@ -13372,9 +13292,10 @@ "dev": true }, "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "version": "6.5.7", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz", + "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==", + "license": "MIT", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -14544,6 +14465,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true, "engines": { "node": ">=0.4.x" } @@ -15276,31 +15198,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dependencies": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/fstream/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -15559,12 +15456,13 @@ "dev": true }, "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", "dependencies": { "minimist": "^1.2.5", - "neo-async": "^2.6.0", + "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, @@ -15621,27 +15519,6 @@ "node": ">=4.0.0" } }, - "node_modules/handlebars/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "optional": true - }, - "node_modules/handlebars/node_modules/uglify-js": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.1.tgz", - "integrity": "sha512-JUPoL1jHsc9fOjVFHdQIhqEEJsQvfKDjlubcCilu8U26uZ73qOg8VsN8O1jbuei44ZPlwL7kmbAdM4tzaUvqnA==", - "optional": true, - "dependencies": { - "commander": "~2.20.3" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/handlebars/node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -16112,16 +15989,6 @@ "node": ">=10.17.0" } }, - "node_modules/i18next": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-3.5.2.tgz", - "integrity": "sha1-kwOQ1cMYzqpIWLUt0OQOayA/n0E=" - }, - "node_modules/i18next-sprintf-postprocessor": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/i18next-sprintf-postprocessor/-/i18next-sprintf-postprocessor-0.2.2.tgz", - "integrity": "sha1-LkCfEENXk4Jpi2otpwzapVHWfqQ=" - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -18826,6 +18693,7 @@ "version": "0.16.0", "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "dev": true, "engines": { "node": ">= 0.6.0" } @@ -19153,8 +19021,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -19166,8 +19032,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "peer": true, "engines": { "node": ">= 10.0.0" } @@ -19396,11 +19260,6 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, - "node_modules/listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==" - }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -20370,6 +20229,8 @@ "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -20621,8 +20482,7 @@ "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node_modules/node-polyfill-webpack-plugin": { "version": "2.0.1", @@ -22588,7 +22448,8 @@ "node_modules/punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true }, "node_modules/pure-rand": { "version": "6.0.4", @@ -22766,13 +22627,14 @@ "dev": true }, "node_modules/read-excel-file": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/read-excel-file/-/read-excel-file-5.7.1.tgz", - "integrity": "sha512-cEX+y7A0TmUESjaVqDTVts3iY2YbySG5ew2TlP0qJN+H7PY+b9MqiK3pl/vNPhx112AuyLtmhfqQc5n6+U2vQw==", + "version": "5.8.5", + "resolved": "https://registry.npmjs.org/read-excel-file/-/read-excel-file-5.8.5.tgz", + "integrity": "sha512-KDDcSsI3VzXTNUBs8q7RwTYrGRE8RZgNwGUivYq13bQtMp1KJmocyBs/EiPTJaFk4I8Ri9iDF+ht2A4GUrudMg==", + "license": "MIT", "dependencies": { "@xmldom/xmldom": "^0.8.2", "fflate": "^0.7.3", - "unzipper": "^0.10.11" + "unzipper": "^0.12.2" } }, "node_modules/read-excel-file/node_modules/fflate": { @@ -23467,7 +23329,8 @@ "node_modules/sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==", + "dev": true }, "node_modules/saxes": { "version": "5.0.1", @@ -23684,7 +23547,8 @@ "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true }, "node_modules/setprototypeof": { "version": "1.2.0", @@ -24928,14 +24792,6 @@ "integrity": "sha1-5xTZtpIR3ZU3k51Q46pXiMRCuFw=", "dev": true }, - "node_modules/traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "engines": { - "node": "*" - } - }, "node_modules/trim-newlines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", @@ -25122,6 +24978,19 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/uglify-js": { + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.2.tgz", + "integrity": "sha512-S8KA6DDI47nQXJSi2ctQ629YzwOVs+bQML6DAtvy0wgNdpi+0ySpQK0g2pxBq2xfF2z3YCscu7NNA8nXT9PlIQ==", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -25300,26 +25169,40 @@ } }, "node_modules/unzipper": { - "version": "0.10.14", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", - "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", - "dependencies": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.3.tgz", + "integrity": "sha512-PZ8hTS+AqcGxsaQntl3IRBw65QrBI6lxzqDEL7IAo/XCEqRTKGfOX56Vea5TH9SZczRVxuzk1re04z/YjuYCJA==", + "license": "MIT", + "dependencies": { + "bluebird": "~3.7.2", "duplexer2": "~0.1.4", - "fstream": "^1.0.12", + "fs-extra": "^11.2.0", "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" + "node-int64": "^0.4.0" + } + }, + "node_modules/unzipper/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" } }, - "node_modules/unzipper/node_modules/bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==" + "node_modules/unzipper/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } }, "node_modules/update-browserslist-db": { "version": "1.0.13", @@ -25371,6 +25254,7 @@ "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "dev": true, "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" @@ -25458,6 +25342,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "dev": true, "bin": { "uuid": "dist/bin/uuid" } @@ -26752,6 +26637,7 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dev": true, "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" @@ -26764,6 +26650,7 @@ "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, "engines": { "node": ">=4.0" } diff --git a/source/package.json b/source/package.json index 4aecc260f..90314adad 100644 --- a/source/package.json +++ b/source/package.json @@ -1,6 +1,6 @@ { "name": "qnabot-on-aws", - "version": "6.0.3", + "version": "6.1.0", "engines": { "node": ">=18.0.0", "npm": ">=10.0.0" @@ -76,12 +76,11 @@ "@vue/compat": "^3.3.8", "@vue/eslint-config-standard": "^8.0.1", "ajv": "^6.10.2", - "alexa-sdk": "^1.0.25", "async-mutex": "^0.1.3", "autosize": "^3.0.21", "aws-lex-web-ui": "git+https://github.com/aws-samples/aws-lex-web-ui.git#feature/qnabot-sdkv3", "aws4": "^1.7.0", - "axios": "^1.6.8", + "axios": "^1.7.4", "body-parser": "^1.18.3", "bowser": "^1.9.3", "cfn-response": "^1.0.1", @@ -95,7 +94,7 @@ "express": "^4.19.2", "faker": "^4.1.0", "file-saver": "^1.3.8", - "handlebars": "^4.7.7", + "handlebars": "^4.7.8", "handlebars-loader": "^1.7.3", "highlight.js": "^10.4.1", "idle-js": "^1.2.0", @@ -122,7 +121,7 @@ "quick-lru": "^1.1.0", "range": "0.0.3", "raw-text": "^1.1.0", - "read-excel-file": "^5.7.1", + "read-excel-file": "^5.8.5", "recursive-readdir": "^2.2.2", "require-dir": "^0.3.2", "roboto-fontface": "^0.8.0", @@ -204,10 +203,12 @@ "semver@6.3.0": "^6.3.1", "semver@7.0.0 - 7.5.2": "^7.5.2", "@vue/cli-plugin-unit-jest": { - "@vue/vue3-jest": "$@vue/vue3-jest", - "postcss": "8.4.32" + "@vue/vue3-jest": "$@vue/vue3-jest" }, - "follow-redirects": "^1.15.6" + "follow-redirects": "^1.15.6", + "postcss": "^8.4.32", + "elliptic": "^6.5.7", + "uglify-js": "^3.19.2" }, "jest": { "globals": { diff --git a/source/templates/dev/__tests__/masterConfig.test.js b/source/templates/dev/__tests__/masterConfig.test.js index 37b7c9dd6..999f12d8f 100644 --- a/source/templates/dev/__tests__/masterConfig.test.js +++ b/source/templates/dev/__tests__/masterConfig.test.js @@ -53,7 +53,7 @@ describe('master template with config', () => { KendraFaqIndexId: { Default: 'test' }, AltSearchKendraIndexes: { Default: 'test' }, AltSearchKendraIndexAuth: { Default: 'test' }, - Username : { Default: 'Admin' }, + Username: { Default: 'Admin' }, XraySetting: { Default: 'TRUE' }, EmbeddingsBedrockModelId: { Default: 'test' }, LLMBedrockModelId: { Default: 'test' }, @@ -65,9 +65,9 @@ describe('master template with config', () => { VPCSubnetIdList : { Default: 'vpc-subnet-test' }, VPCSecurityGroupIdList : { Default: 'sg-test' }, OpenSearchInstanceType : { Default: 'm6g.large.search' }, - LexBotVersion: { Default: 'LexV2 Only' }, FulfillmentConcurrency: { Default: 1 }, LexV2BotLocaleIds: { Default: 'en_US,es_US,fr_CA' }, + LogRetentionPeriod: { Default: 0 }, EmbeddingsApi: { Default: 'SAGEMAKER' }, LLMApi: { Default: 'SAGEMAKER' }, InstallLexResponseBots: { Default: true }, diff --git a/source/templates/dev/__tests__/masterNoConfig.test.js b/source/templates/dev/__tests__/masterNoConfig.test.js index b0d89599e..9a31cd5ef 100644 --- a/source/templates/dev/__tests__/masterNoConfig.test.js +++ b/source/templates/dev/__tests__/masterNoConfig.test.js @@ -55,9 +55,9 @@ describe('master template with config', () => { KendraFaqIndexId: { Default: 'test' }, AltSearchKendraIndexes: { Default: 'test' }, AltSearchKendraIndexAuth: { Default: 'test' }, - LexBotVersion: { Default: 'test' }, FulfillmentConcurrency: { Default: 'test' }, LexV2BotLocaleIds: { Default: 'test' }, + LogRetentionPeriod: { Default: 0 }, EmbeddingsApi: { Default: 'test' }, LLMApi: { Default: 'test' }, EmbeddingsBedrockModelId: { Default: 'test' }, diff --git a/source/templates/dev/__tests__/mockConfigFull.json b/source/templates/dev/__tests__/mockConfigFull.json index 5b119e246..e30ddd0d3 100644 --- a/source/templates/dev/__tests__/mockConfigFull.json +++ b/source/templates/dev/__tests__/mockConfigFull.json @@ -9,7 +9,6 @@ "devPublicOrPrivate": "PRIVATE", "devLanguage": "English", "namespace": "dev", - "LexBotVersion": "LexV2 Only", "LexV2BotLocaleIds": "en_US,es_US,fr_CA", "stackNamePrefix": "QNA", "skipCheckTemplate": false, @@ -21,6 +20,7 @@ "EmbeddingsBedrockModelId": "test", "LLMApi": "SAGEMAKER", "LLMBedrockModelId": "test", + "LogRetentionPeriod": 0, "BedrockKnowledgeBaseId": "test", "BedrockKnowledgeBaseModel": "anthropic.claude-instant-v1", "InstallLexResponseBots": true, diff --git a/source/templates/dev/__tests__/mockMaster.js b/source/templates/dev/__tests__/mockMaster.js index 3ab46963b..b9fb3b928 100644 --- a/source/templates/dev/__tests__/mockMaster.js +++ b/source/templates/dev/__tests__/mockMaster.js @@ -30,9 +30,6 @@ module.exports = { AltSearchKendraIndexAuth: { Default: 'test', }, - LexBotVersion: { - Default: 'test', - }, FulfillmentConcurrency: { Default: 'test', }, @@ -78,6 +75,9 @@ module.exports = { LLMLambdaArn: { Default: '0000000000000000000000000000000000000:function:test', }, + LogRetentionPeriod: { + Default: 0 + }, VPCSubnetIdList: { Default: 'test', }, diff --git a/source/templates/dev/master.js b/source/templates/dev/master.js index 3d748fa92..8be18aac2 100644 --- a/source/templates/dev/master.js +++ b/source/templates/dev/master.js @@ -35,11 +35,11 @@ module.exports = Promise.all([ base.Parameters.EmbeddingsLambdaArn.Default = config.EmbeddingsLambdaArn ? config.EmbeddingsLambdaArn : base.Parameters.EmbeddingsLambdaArn.Default; base.Parameters.LLMSagemakerInstanceType.Default = config.LLMSagemakerInstanceType ? config.LLMSagemakerInstanceType : base.Parameters.LLMSagemakerInstanceType.Default; base.Parameters.LLMLambdaArn.Default = config.LLMLambdaArn ? config.LLMLambdaArn : base.Parameters.LLMLambdaArn.Default; + base.Parameters.LogRetentionPeriod.Default = config.LogRetentionPeriod ? config.LogRetentionPeriod : base.Parameters.LogRetentionPeriod.Default; base.Parameters.ApprovedDomain.Default = config.ApprovedDomain ? config.ApprovedDomain : base.Parameters.ApprovedDomain.Default; base.Parameters.OpenSearchInstanceType.Default = config.OpenSearchInstanceType ? config.OpenSearchInstanceType : base.Parameters.OpenSearchInstanceType.Default; base.Parameters.VPCSubnetIdList.Default = config.VPCSubnetIdList ? config.VPCSubnetIdList : base.Parameters.VPCSubnetIdList.Default; base.Parameters.VPCSecurityGroupIdList.Default = config.VPCSecurityGroupIdList ? config.VPCSecurityGroupIdList : base.Parameters.VPCSecurityGroupIdList.Default; - base.Parameters.LexBotVersion.Default = config.LexBotVersion ? config.LexBotVersion : base.Parameters.LexBotVersion.Default; base.Parameters.FulfillmentConcurrency.Default = config.FulfillmentConcurrency ? config.FulfillmentConcurrency : base.Parameters.FulfillmentConcurrency.Default; base.Parameters.LexV2BotLocaleIds.Default = config.LexV2BotLocaleIds ? config.LexV2BotLocaleIds : base.Parameters.LexV2BotLocaleIds.Default; base.Parameters.EmbeddingsApi.Default = config.EmbeddingsApi ? config.EmbeddingsApi : base.Parameters.EmbeddingsApi.Default; diff --git a/source/templates/examples/__snapshots__/index.test.js.snap b/source/templates/examples/__snapshots__/index.test.js.snap index 1e0d85f78..962143008 100644 --- a/source/templates/examples/__snapshots__/index.test.js.snap +++ b/source/templates/examples/__snapshots__/index.test.js.snap @@ -12,21 +12,15 @@ exports[`renders examples template correctly 1`] = ` "true", ], }, - "CreateLexV1Bots": { - "Fn::Equals": [ - { - "Ref": "LexBotVersion", - }, - "LexV1 and LexV2", - ], - }, - "CreateLexV1ResponseBots": { - "Fn::And": [ - { - "Condition": "CreateLexResponseBots", - }, + "LogRetentionPeriodIsNotZero": { + "Fn::Not": [ { - "Condition": "CreateLexV1Bots", + "Fn::Equals": [ + { + "Ref": "LogRetentionPeriod", + }, + 0, + ], }, ], }, @@ -54,14 +48,6 @@ exports[`renders examples template correctly 1`] = ` "Description": "(SO0189n-example) QnABot nested example resources - Version vx.x.x", "Mappings": {}, "Outputs": { - "EXTCanvasLMSHook": { - "Value": { - "Fn::GetAtt": [ - "EXTCanvasLMSHook", - "Arn", - ], - }, - }, "EXTCreateRecentTopicsResponse": { "Value": { "Fn::GetAtt": [ @@ -762,8 +748,8 @@ exports[`renders examples template correctly 1`] = ` "InstallLexResponseBots": { "Type": "String", }, - "LexBotVersion": { - "Type": "String", + "LogRetentionPeriod": { + "Type": "Number", }, "PrivateQnABotSettings": { "Type": "String", @@ -791,93 +777,53 @@ exports[`renders examples template correctly 1`] = ` }, }, "Resources": { - "AgeAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNAAge", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNAAge", + "BotBrokerLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], }, - "description": "QNA Age Alias - x.x.x - v1", - "name": "live", }, - "Type": "Custom::LexAlias", - }, - "AgeIntent": { - "Condition": "CreateLexV1ResponseBots", "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}", + }, + "ExamplePYTHONLambdaBotBroker", + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], }, - "conclusionStatement": { - "messages": [ + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", { - "content": "OK. ", - "contentType": "PlainText", + "Ref": "LogRetentionPeriod", }, - ], - }, - "confirmationPrompt": { - "maxAttempts": 1, - "messages": [ { - "content": "Is {Age} correct (Yes or No)?", - "contentType": "PlainText", + "Ref": "AWS::NoValue", }, ], }, - "createVersion": true, - "description": "QNA Age Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNAAgeIntent-\${AWS::StackName}", - }, - "rejectionStatement": { - "messages": [ - { - "content": "Please let me know the age again.", - "contentType": "PlainText", - }, - ], - }, - "sampleUtterances": [ - "My age is {Age}", - "Age is {Age}", - "It is {Age}", - "I am {Age}", - "I am {Age} years old", - "His age is {Age}", - "He is {Age}", - "He is {Age} years old", - "Her age is {Age}", - "She is {Age}", - "She is {Age} years old", - "{Age}", - ], - "slots": [ - { - "name": "Age", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.NUMBER", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What age?", - "contentType": "PlainText", - }, - ], - }, - }, - ], }, - "Type": "Custom::LexIntent", + "Type": "AWS::Logs::LogGroup", }, "BotRuntimeRole": { "Condition": "CreateLexResponseBots", @@ -949,21 +895,6 @@ exports[`renders examples template correctly 1`] = ` }, "Type": "AWS::IAM::Role", }, - "CodeVersionCanvasLMSHook": { - "Properties": { - "Bucket": { - "Ref": "BootstrapBucket", - }, - "BuildDate": Any, - "Key": { - "Fn::Sub": "\${BootstrapPrefix}/lambda/EXTCanvasLMSHook.zip", - }, - "ServiceToken": { - "Ref": "CFNLambda", - }, - }, - "Type": "Custom::S3Version", - }, "CodeVersionCreateRecentTopicsResponse": { "Properties": { "Bucket": { @@ -1009,242 +940,199 @@ exports[`renders examples template correctly 1`] = ` }, "Type": "Custom::S3Version", }, - "DateAliasNoConfirmV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNADateNoConfirm", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNADateNoConfirm", - }, - "description": "QNA Date No Confirm Alias - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "DateAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNADate", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNADate", + "ConnectCallbackLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], }, - "description": "QNA Date Alias - x.x.x - v1", - "name": "live", }, - "Type": "Custom::LexAlias", - }, - "DateIntent": { - "Condition": "CreateLexV1ResponseBots", "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}", + }, + "ExamplePYTHONLambdaConnectCallback", + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], ], }, - "confirmationPrompt": { - "maxAttempts": 1, - "messages": [ + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", { - "content": "Is {date} correct (Yes or No)?", - "contentType": "PlainText", + "Ref": "LogRetentionPeriod", }, - ], - }, - "createVersion": true, - "description": "QNA DateIntent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNADateIntent-\${AWS::StackName}", - }, - "rejectionStatement": { - "messages": [ { - "content": "Please let me know the date again.", - "contentType": "PlainText", + "Ref": "AWS::NoValue", }, ], }, - "sampleUtterances": [ - "The date is {date}", - "The date was {date}", - "I went on {date}", - "It is {date}", - "It occurred on {date}", - "I was born on {date}", - "My birthdate is {date}", - "My date of birth is {date}", - "{date}", - ], - "slots": [ - { - "name": "date", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.DATE", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What date?", - "contentType": "PlainText", - }, - ], - }, - }, - ], }, - "Type": "Custom::LexIntent", + "Type": "AWS::Logs::LogGroup", }, - "DateIntentNoConfirm": { - "Condition": "CreateLexV1ResponseBots", + "CreateRecentTopicsResponseLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}", + }, + "EXTCreateRecentTopicsResponse", + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], }, - "conclusionStatement": { - "messages": [ + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", { - "content": "OK. ", - "contentType": "PlainText", + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", }, ], }, - "createVersion": true, - "description": "QNA DateIntentNoConfirm - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNADateIntentNoConfirm-\${AWS::StackName}", - }, - "sampleUtterances": [ - "The date is {date}", - "The date was {date}", - "I went on {date}", - "It is {date}", - "It occurred on {date}", - "I was born on {date}", - "My birthdate is {date}", - "My date of birth is {date}", - "{date}", - ], - "slots": [ - { - "name": "date", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.DATE", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What date?", - "contentType": "PlainText", - }, - ], - }, - }, - ], }, - "Type": "Custom::LexIntent", + "Type": "AWS::Logs::LogGroup", }, - "DayOfWeekAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNADayOfWeek", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNADayOfWeek", + "CustomJSHookLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], }, - "description": "QNA Day Of Week Alias - x.x.x - v1", - "name": "live", }, - "Type": "Custom::LexAlias", - }, - "DayOfWeekIntent": { - "Condition": "CreateLexV1ResponseBots", "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}", + }, + "EXTCustomJSHook", + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], }, - "conclusionStatement": { - "messages": [ + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", { - "content": "OK. ", - "contentType": "PlainText", + "Ref": "LogRetentionPeriod", }, - ], - }, - "confirmationPrompt": { - "maxAttempts": 1, - "messages": [ { - "content": "Is {DayOfWeek} correct (Yes or No)?", - "contentType": "PlainText", + "Ref": "AWS::NoValue", }, ], }, - "createVersion": true, - "description": "QNA Day Of Week Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", + }, + "Type": "AWS::Logs::LogGroup", + }, + "CustomPYHookLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], }, - "name": { - "Fn::Sub": "QNADayOfWeekIntent-\${AWS::StackName}", + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}", + }, + "EXTCustomPYHook", + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], }, - "rejectionStatement": { - "messages": [ + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, { - "content": "Please let me know the day again.", - "contentType": "PlainText", + "Ref": "AWS::NoValue", }, ], }, - "sampleUtterances": [ - "The day is {DayOfWeek}", - "The day was {DayOfWeek}", - "I went on {DayOfWeek}", - "It is {DayOfWeek}", - "It occurred on {DayOfWeek}", - "{DayOfWeek}", - ], - "slots": [ - { - "name": "DayOfWeek", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.DayOfWeek", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What day?", - "contentType": "PlainText", - }, - ], - }, - }, - ], }, - "Type": "Custom::LexIntent", + "Type": "AWS::Logs::LogGroup", }, - "EXTCanvasLMSHook": { + "EXTCreateRecentTopicsResponse": { "Metadata": { "cfn_nag": { "rules_to_suppress": [ @@ -1273,12 +1161,12 @@ exports[`renders examples template correctly 1`] = ` { "Ref": "BootstrapPrefix", }, - "/lambda/EXTCanvasLMSHook.zip", + "/lambda/EXTCreateRecentTopicsResponse.zip", ], ], }, "S3ObjectVersion": { - "Ref": "CodeVersionCanvasLMSHook", + "Ref": "CodeVersionCreateRecentTopicsResponse", }, }, "Environment": { @@ -1292,15 +1180,25 @@ exports[`renders examples template correctly 1`] = ` "FIREHOSE_NAME": { "Ref": "FeedbackKinesisFirehoseName", }, - "PYTHONPATH": "/var/task/py_modules:/var/runtime:/opt/python", "QUIZ_KMS_KEY": { "Ref": "QuizKey", }, - "SOLUTION_ID": "SO0189", - "SOLUTION_VERSION": "vx.x.x", }, }, - "Handler": "CanvasLMSHook.handler", + "Handler": "CreateRecentTopicsResponse.handler", + "Layers": [ + { + "Ref": "AwsSdkLayerLambdaLayer", + }, + { + "Ref": "JsLambdaHookSDKLambdaLayer", + }, + ], + "LoggingConfig": { + "LogGroup": { + "Ref": "CreateRecentTopicsResponseLogGroup", + }, + }, "MemorySize": "2048", "Role": { "Fn::GetAtt": [ @@ -1308,7 +1206,7 @@ exports[`renders examples template correctly 1`] = ` "Arn", ], }, - "Runtime": "python", + "Runtime": "nodejs", "Tags": [ { "Key": "Type", @@ -1356,124 +1254,7 @@ exports[`renders examples template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, - "EXTCreateRecentTopicsResponse": { - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W92", - "reason": "This lambda function does not require to have ReservedConcurrentExecutions", - }, - ], - }, - "guard": { - "SuppressedRules": [ - "LAMBDA_CONCURRENCY_CHECK", - "LAMBDA_INSIDE_VPC", - ], - }, - }, - "Properties": { - "Code": { - "S3Bucket": { - "Ref": "BootstrapBucket", - }, - "S3Key": { - "Fn::Join": [ - "", - [ - { - "Ref": "BootstrapPrefix", - }, - "/lambda/EXTCreateRecentTopicsResponse.zip", - ], - ], - }, - "S3ObjectVersion": { - "Ref": "CodeVersionCreateRecentTopicsResponse", - }, - }, - "Environment": { - "Variables": { - "ES_ADDRESS": { - "Ref": "ESAddress", - }, - "ES_INDEX": { - "Ref": "Index", - }, - "FIREHOSE_NAME": { - "Ref": "FeedbackKinesisFirehoseName", - }, - "QUIZ_KMS_KEY": { - "Ref": "QuizKey", - }, - }, - }, - "Handler": "CreateRecentTopicsResponse.handler", - "Layers": [ - { - "Ref": "AwsSdkLayerLambdaLayer", - }, - { - "Ref": "JsLambdaHookSDKLambdaLayer", - }, - ], - "MemorySize": "2048", - "Role": { - "Fn::GetAtt": [ - "ExtensionLambdaRole", - "Arn", - ], - }, - "Runtime": "nodejs", - "Tags": [ - { - "Key": "Type", - "Value": "LambdaHook", - }, - ], - "Timeout": 300, - "TracingConfig": { - "Fn::If": [ - "XRAYEnabled", - { - "Mode": "Active", - }, - { - "Ref": "AWS::NoValue", - }, - ], - }, - "VpcConfig": { - "Fn::If": [ - "VPCEnabled", - { - "SecurityGroupIds": { - "Fn::Split": [ - ",", - { - "Ref": "VPCSecurityGroupIdList", - }, - ], - }, - "SubnetIds": { - "Fn::Split": [ - ",", - { - "Ref": "VPCSubnetIdList", - }, - ], - }, - }, - { - "Ref": "AWS::NoValue", - }, - ], - }, - }, - "Type": "AWS::Lambda::Function", - }, - "EXTCustomJSHook": { + "EXTCustomJSHook": { "Metadata": { "cfn_nag": { "rules_to_suppress": [ @@ -1535,6 +1316,11 @@ exports[`renders examples template correctly 1`] = ` "Ref": "JsLambdaHookSDKLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "CustomJSHookLogGroup", + }, + }, "MemorySize": "2048", "Role": { "Fn::GetAtt": [ @@ -1647,6 +1433,11 @@ exports[`renders examples template correctly 1`] = ` }, }, "Handler": "CustomPYHook.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "CustomPYHookLogGroup", + }, + }, "MemorySize": "2048", "Role": { "Fn::GetAtt": [ @@ -1707,9 +1498,6 @@ exports[`renders examples template correctly 1`] = ` "Bucket": { "Ref": "AssetBucket", }, - "CanvasLMSHookPY": { - "Ref": "EXTCanvasLMSHook", - }, "CreateRecentTopicsResponseJS": { "Ref": "EXTCreateRecentTopicsResponse", }, @@ -1787,6 +1575,11 @@ exports[`renders examples template correctly 1`] = ` "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "EXTUiImportLambdaLogGroup", + }, + }, "MemorySize": "128", "Role": { "Ref": "CFNLambdaRole", @@ -1839,99 +1632,67 @@ exports[`renders examples template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, - "EXTUiImportVersion": { - "Properties": { - "Bucket": { - "Ref": "BootstrapBucket", - }, - "BuildDate": Any, - "Key": { - "Fn::Sub": "\${BootstrapPrefix}/lambda/EXTUiImports.zip", - }, - "ServiceToken": { - "Ref": "CFNLambda", - }, - }, - "Type": "Custom::S3Version", - }, - "EmailAddressAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNAEmailAddress", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNAEmailAddress", + "EXTUiImportLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], }, - "description": "QNA Email Address Alias - x.x.x - v1", - "name": "live", }, - "Type": "Custom::LexAlias", - }, - "EmailAddressIntent": { - "Condition": "CreateLexV1ResponseBots", "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-EXTUiImportLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], }, - "conclusionStatement": { - "messages": [ + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", { - "content": "OK. ", - "contentType": "PlainText", + "Ref": "LogRetentionPeriod", }, - ], - }, - "confirmationPrompt": { - "maxAttempts": 1, - "messages": [ { - "content": "Is {EmailAddress} correct (Yes or No)?", - "contentType": "PlainText", + "Ref": "AWS::NoValue", }, ], }, - "createVersion": true, - "description": "QNA Email Address Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", + }, + "Type": "AWS::Logs::LogGroup", + }, + "EXTUiImportVersion": { + "Properties": { + "Bucket": { + "Ref": "BootstrapBucket", }, - "name": { - "Fn::Sub": "QNAEmailAddressIntent-\${AWS::StackName}", + "BuildDate": Any, + "Key": { + "Fn::Sub": "\${BootstrapPrefix}/lambda/EXTUiImports.zip", }, - "rejectionStatement": { - "messages": [ - { - "content": "Please let me know the email address again.", - "contentType": "PlainText", - }, - ], + "ServiceToken": { + "Ref": "CFNLambda", }, - "sampleUtterances": [ - "My email address is {EmailAddress}", - "The email address is {EmailAddress}", - "{EmailAddress}", - ], - "slots": [ - { - "name": "EmailAddress", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.EmailAddress", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What email address?", - "contentType": "PlainText", - }, - ], - }, - }, - ], }, - "Type": "Custom::LexIntent", + "Type": "Custom::S3Version", }, "ExampleCodeVersion": { "Properties": { @@ -2012,6 +1773,11 @@ exports[`renders examples template correctly 1`] = ` "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "QuizLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -2131,6 +1897,11 @@ exports[`renders examples template correctly 1`] = ` "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "hookLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -2440,56 +2211,6 @@ exports[`renders examples template correctly 1`] = ` }, "PolicyName": "SNSQNALambda", }, - { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "lex:PostText", - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:aws:lex:", - { - "Ref": "AWS::Region", - }, - ":", - { - "Ref": "AWS::AccountId", - }, - ":bot:*", - ":qna*", - ], - ], - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:lex:", - { - "Ref": "AWS::Region", - }, - ":", - { - "Ref": "AWS::AccountId", - }, - ":bot:*", - ":QNA*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LexQNALambda", - }, { "PolicyDocument": { "Statement": [ @@ -2626,6 +2347,11 @@ exports[`renders examples template correctly 1`] = ` }, }, "Handler": "py/BotBroker.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "BotBrokerLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -2743,6 +2469,11 @@ exports[`renders examples template correctly 1`] = ` }, }, "Handler": "py/ConnectCallback.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "ConnectCallbackLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -2860,6 +2591,11 @@ exports[`renders examples template correctly 1`] = ` }, }, "Handler": "py/Feedback.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "FeedbackLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -2977,6 +2713,11 @@ exports[`renders examples template correctly 1`] = ` }, }, "Handler": "py/Next.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "NextLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -3094,6 +2835,11 @@ exports[`renders examples template correctly 1`] = ` }, }, "Handler": "py/Previous.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "PreviousLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -3211,6 +2957,11 @@ exports[`renders examples template correctly 1`] = ` }, }, "Handler": "py/hello.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "helloLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -3319,6 +3070,11 @@ exports[`renders examples template correctly 1`] = ` "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ExampleWriteLambdaLogGroup", + }, + }, "MemorySize": "128", "Role": { "Ref": "CFNLambdaRole", @@ -3371,10 +3127,57 @@ exports[`renders examples template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, - "ExtensionLambdaRole": { + "ExampleWriteLambdaLogGroup": { "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ExampleWriteLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, + "ExtensionLambdaRole": { + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ { "id": "W11", "reason": "This IAM role requires to have * resource on its permission policy", @@ -3586,106 +3389,6 @@ exports[`renders examples template correctly 1`] = ` }, "PolicyName": "LambdaFeedbackKinesisFirehoseQNALambda", }, - { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "lex:PostText", - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:aws:lex:", - { - "Ref": "AWS::Region", - }, - ":", - { - "Ref": "AWS::AccountId", - }, - ":bot:*", - ":qna*", - ], - ], - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:lex:", - { - "Ref": "AWS::Region", - }, - ":", - { - "Ref": "AWS::AccountId", - }, - ":bot:*", - ":QNA*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "LexQNALambda", - }, - { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "secretsmanager:GetResourcePolicy", - "secretsmanager:GetSecretValue", - "secretsmanager:DescribeSecret", - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:aws:secretsmanager:", - { - "Ref": "AWS::Region", - }, - ":", - { - "Ref": "AWS::AccountId", - }, - ":secret:qna-*", - ], - ], - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:secretsmanager:", - { - "Ref": "AWS::Region", - }, - ":", - { - "Ref": "AWS::AccountId", - }, - ":secret:QNA-*", - ], - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "QNASecretsManagerLambda", - }, ], }, "Type": "AWS::IAM::Role", @@ -3712,12 +3415,6 @@ exports[`renders examples template correctly 1`] = ` "Arn", ], }, - { - "Fn::GetAtt": [ - "EXTCanvasLMSHook", - "Arn", - ], - }, { "Fn::GetAtt": [ "EXTCustomPYHook", @@ -3737,6 +3434,54 @@ exports[`renders examples template correctly 1`] = ` }, "Type": "AWS::IAM::ManagedPolicy", }, + "FeedbackLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}", + }, + "ExamplePYTHONLambdaFeedback", + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "FeedbackSNS": { "Properties": { "KmsMasterKeyId": "alias/aws/sns", @@ -3913,1510 +3658,103 @@ exports[`renders examples template correctly 1`] = ` }, "Type": "Custom::QnABotExamples", }, - "MonthAliasNoConfirmV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNAMonthNoConfirm", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNAMonthNoConfirm", - }, - "description": "QNA Month Alias No Confirm - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "MonthAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNAMonth", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNAMonth", + "NextLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], }, - "description": "QNA Month Alias - x.x.x - v1", - "name": "live", }, - "Type": "Custom::LexAlias", - }, - "MonthIntent": { - "Condition": "CreateLexV1ResponseBots", "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}", + }, + "ExamplePYTHONLambdaNext", + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], ], }, - "confirmationPrompt": { - "maxAttempts": 1, - "messages": [ + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", { - "content": "Is {Month} correct (Yes or No)?", - "contentType": "PlainText", + "Ref": "LogRetentionPeriod", }, - ], - }, - "createVersion": true, - "description": "QNA Month Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNAMonthIntent-\${AWS::StackName}", - }, - "rejectionStatement": { - "messages": [ { - "content": "Please let me know the month again.", - "contentType": "PlainText", + "Ref": "AWS::NoValue", }, ], }, - "sampleUtterances": [ - "The month is {Month}", - "The month was {Month}", - "It is {Month}", - "It occurred on {Month}", - "{Month}", - ], - "slots": [ - { - "name": "Month", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.Month", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What month?", - "contentType": "PlainText", - }, - ], - }, - }, - ], }, - "Type": "Custom::LexIntent", + "Type": "AWS::Logs::LogGroup", }, - "MonthIntentNoConfirm": { - "Condition": "CreateLexV1ResponseBots", + "PreviousLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}", + }, + "ExamplePYTHONLambdaPrevious", + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], }, - "conclusionStatement": { - "messages": [ + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, { - "content": "OK. ", - "contentType": "PlainText", + "Ref": "AWS::NoValue", }, ], }, - "createVersion": true, - "description": "QNA Month Intent No Confirm - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNAMonthIntentNoConfirm-\${AWS::StackName}", - }, - "sampleUtterances": [ - "The month is {Month}", - "The month was {Month}", - "It is {Month}", - "It occurred on {Month}", - "{Month}", - ], - "slots": [ - { - "name": "Month", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.Month", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What month?", - "contentType": "PlainText", - }, - ], - }, - }, - ], }, - "Type": "Custom::LexIntent", + "Type": "AWS::Logs::LogGroup", }, - "NameAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNAName", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNAName", - }, - "description": "QNA Name Alias - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "NameIntent": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, - ], - }, - "confirmationPrompt": { - "maxAttempts": 1, - "messages": [ - { - "content": "Did I get your name right (Yes or No) {FirstName} {LastName}?", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Name Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNANameIntent-\${AWS::StackName}", - }, - "rejectionStatement": { - "messages": [ - { - "content": "Please let me know your name again.", - "contentType": "PlainText", - }, - ], - }, - "sampleUtterances": [ - "My last name is {LastName}", - "My first name is {FirstName}", - "My first name is {FirstName} and My last name is {LastName}", - "My name is {FirstName} {LastName}", - "I am {FirstName} {LastName}", - "{FirstName} {LastName}", - "{FirstName}", - "{LastName}", - ], - "slots": [ - { - "name": "FirstName", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.US_FIRST_NAME", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What is your first name?", - "contentType": "PlainText", - }, - ], - }, - }, - { - "name": "LastName", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.US_LAST_NAME", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What is your last name?", - "contentType": "PlainText", - }, - ], - }, - }, - ], - }, - "Type": "Custom::LexIntent", - }, - "NumberAliasNoConfirmV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNANumberNoConfirm", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNANumberNoConfirm", - }, - "description": "QNA Number Alias No Confirm - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "NumberAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNANumber", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNANumber", - }, - "description": "QNA Number Alias - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "NumberIntent": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, - ], - }, - "confirmationPrompt": { - "maxAttempts": 1, - "messages": [ - { - "content": "Is {Number} correct (Yes or No)?", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Number Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNANumberIntent-\${AWS::StackName}", - }, - "rejectionStatement": { - "messages": [ - { - "content": "Please let me know the number again.", - "contentType": "PlainText", - }, - ], - }, - "sampleUtterances": [ - "The number is {Number}", - "The number was {Number}", - "It is {Number}", - "{Number}", - ], - "slots": [ - { - "name": "Number", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.NUMBER", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What number?", - "contentType": "PlainText", - }, - ], - }, - }, - ], - }, - "Type": "Custom::LexIntent", - }, - "NumberIntentNoConfirm": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Number Intent No Confirm - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNANumberIntentNoConfirm-\${AWS::StackName}", - }, - "sampleUtterances": [ - "The number is {Number}", - "The number was {Number}", - "It is {Number}", - "{Number}", - ], - "slots": [ - { - "name": "Number", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.NUMBER", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What number?", - "contentType": "PlainText", - }, - ], - }, - }, - ], - }, - "Type": "Custom::LexIntent", - }, - "PhoneNumberAliasNoConfirmV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNAPhoneNumberNoConfirm", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNAPhoneNumberNoConfirm", - }, - "description": "QNA Phone Number Alias No Confirm - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "PhoneNumberAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNAPhoneNumber", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNAPhoneNumber", - }, - "description": "QNA Phone Number Alias - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "PhoneNumberIntent": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, - ], - }, - "confirmationPrompt": { - "maxAttempts": 1, - "messages": [ - { - "content": "Is {PhoneNumber} correct (Yes or No)?", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Phone Number Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNAPhoneNumberIntent-\${AWS::StackName}", - }, - "rejectionStatement": { - "messages": [ - { - "content": "Please let me know the phone number again.", - "contentType": "PlainText", - }, - ], - }, - "sampleUtterances": [ - "The phone number is {PhoneNumber}", - "My phone number is {PhoneNumber}", - "It is {PhoneNumber}", - "{PhoneNumber}", - ], - "slots": [ - { - "name": "PhoneNumber", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.PhoneNumber", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What phone number?", - "contentType": "PlainText", - }, - ], - }, - }, - ], - }, - "Type": "Custom::LexIntent", - }, - "PhoneNumberIntentNoConfirm": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Phone Number Intent No Confirm - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNAPhoneNumberIntentNoConfirm-\${AWS::StackName}", - }, - "sampleUtterances": [ - "The phone number is {PhoneNumber}", - "My phone number is {PhoneNumber}", - "It is {PhoneNumber}", - "{PhoneNumber}", - ], - "slots": [ - { - "name": "PhoneNumber", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.PhoneNumber", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What phone number?", - "contentType": "PlainText", - }, - ], - }, - }, - ], - }, - "Type": "Custom::LexIntent", - }, - "PinAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNAPin", - }, - "description": "QNA Pin Alias - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "PinIntent": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, - ], - }, - "confirmationPrompt": { - "maxAttempts": 1, - "messages": [ - { - "content": "Is {Pin} correct (Yes or No)?", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Pin Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNAPinIntent-\${AWS::StackName}", - }, - "rejectionStatement": { - "messages": [ - { - "content": "I'm sorry I did not get all the digits, please re-enter all digits.", - "contentType": "PlainText", - }, - ], - }, - "sampleUtterances": [ - "The pin number is {Pin}", - "My pin number is {Pin}", - "It is {Pin}", - "{Pin}", - ], - "slots": [ - { - "name": "Pin", - "priority": 1, - "slotConstraint": "Required", - "slotType": { - "Ref": "PinSlotType", - }, - "slotTypeVersion": "QNABOT-AUTO-ASSIGNED", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What are all the digits?", - "contentType": "PlainText", - }, - ], - }, - }, - ], - }, - "Type": "Custom::LexIntent", - }, - "PinIntentNoConfirm": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Pin Intent No Confirm - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNAPinIntentNoConfirm-\${AWS::StackName}", - }, - "sampleUtterances": [ - "The pin number is {Pin}", - "My pin number is {Pin}", - "It is {Pin}", - "{Pin}", - ], - "slots": [ - { - "name": "Pin", - "priority": 1, - "slotConstraint": "Required", - "slotType": { - "Ref": "PinSlotType", - }, - "slotTypeVersion": "QNABOT-AUTO-ASSIGNED", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What are all the digits?", - "contentType": "PlainText", - }, - ], - }, - }, - ], - }, - "Type": "Custom::LexIntent", - }, - "PinNoConfirmAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNAPinNoConfirm", - }, - "description": "QNA Pin No Confirm Alias - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "PinSlotType": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "createVersion": true, - "description": "QNA Pin Slot Type - x.x.x - v1", - "name": { - "Fn::Sub": "QNAPinSlotType-\${AWS::StackName}", - }, - "parentSlotTypeSignature": "AMAZON.AlphaNumeric", - "slotTypeConfigurations": [ - { - "regexConfiguration": { - "pattern": "[0-9]{4}", - }, - }, - ], - }, - "Type": "Custom::LexSlotType", - }, - "QNAAge": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "AgeIntent", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat the age.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Age Bot - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "AgeIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNAAgeBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNADate": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "DateIntent", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat the date.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Date Bot - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "DateIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNADateBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNADateNoConfirm": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "DateIntentNoConfirm", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat the date.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Date Bot No Confirm - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "DateIntentNoConfirm", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNADateBotNoConfirm-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNADayOfWeek": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "DayOfWeekIntent", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat the day of the week.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNADayOfWeek bot - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "DayOfWeekIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNADayOfWeekBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNAEmailAddress": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "EmailAddressIntent", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat the email address.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Email Address Intent - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "EmailAddressIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNAEmailAddressBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNAMonth": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "MonthIntent", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat the month.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Month Bot - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "MonthIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNAMonthBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNAMonthNoConfirm": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "MonthIntentNoConfirm", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat the month.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Month Bot No Confirm - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "MonthIntentNoConfirm", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNAMonthBotNoConfirm-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNAName": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "NameIntent", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat your first and last name?", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Name Bot - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "NameIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNANameBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNANumber": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "NumberIntent", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat the number.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Number Bot - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "NumberIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNANumberBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNANumberNoConfirm": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "NumberIntentNoConfirm", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat the number.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Number Bot No Confirm - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "NumberIntentNoConfirm", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNANumberBotNoConfirm-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNAPhoneNumber": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "PhoneNumberIntent", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat the phone number.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Phone Number Bot - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "PhoneNumberIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNAPhoneNumberBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNAPhoneNumberNoConfirm": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "PhoneNumberIntentNoConfirm", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat the phone number.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Phone Number Bot No Confirm - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "PhoneNumberIntentNoConfirm", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNAPhoneNumberBotNoConfirm-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNAPin": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "PinIntent", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "I'm sorry I did not get all the digits, please re-enter all digits.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Pin elicit response - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "PinIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNAPinBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNAPinNoConfirm": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "PinIntentNoConfirm", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "I'm sorry I did not get all the digits, please re-enter all digits.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Pin No Confirm elicit response - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "PinIntentNoConfirm", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNAPinBotNoConfirm-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNASocialSecurity": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "SocialSecurityIntent", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat your social security number.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Social Security elicit response - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "SocialSecurityIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNASocialSecurityBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNATime": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "TimeIntent", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat the time, specifying am or pm.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Time Bot - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "TimeIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNATimeBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNAWage": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "WageIntent", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 3, - "messages": [ - { - "content": "Please repeat your wage.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Wage elicit response - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "WageIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNAWageBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNAYesNo": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": [ - "YesNoSlotType", - "YesNoIntent", - ], - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 5, - "messages": [ - { - "content": "Please repeat - say Yes or No.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Yes No Bot - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "YesNoIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNAYesNoBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QNAYesNoExit": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": [ - "YesNoExitSlotType", - "YesNoExitIntent", - ], - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I could not understand. Please start again.", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "clarificationPrompt": { - "maxAttempts": 5, - "messages": [ - { - "content": "Please repeat - say Yes or No. You can also say exit, agent, quit, or bye to leave.", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Yes No Exit Bot - x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "YesNoExitIntent", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "QNAYesNoExitBot-\${AWS::StackName}", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, - "QuizKey": { + "QuizKey": { "Properties": { "Description": "QNABot Internal KMS CMK for quiz workflow", "EnableKeyRotation": true, @@ -5444,25 +3782,73 @@ exports[`renders examples template correctly 1`] = ` "Ref": "AWS::AccountId", }, }, - "Resource": "*", - "Sid": "Allow administration of the key", + "Resource": "*", + "Sid": "Allow administration of the key", + }, + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Sub": "arn:aws:iam::\${AWS::AccountId}:root", + }, + }, + "Resource": "*", + "Sid": "Enable IAM User Permissions", + }, + ], + "Version": "2012-10-17", + }, + }, + "Type": "AWS::KMS::Key", + }, + "QuizLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}", + }, + "ExampleJSLambdaQuiz", + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", }, { - "Action": "kms:*", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Sub": "arn:aws:iam::\${AWS::AccountId}:root", - }, - }, - "Resource": "*", - "Sid": "Enable IAM User Permissions", + "Ref": "AWS::NoValue", }, ], - "Version": "2012-10-17", }, }, - "Type": "AWS::KMS::Key", + "Type": "AWS::Logs::LogGroup", }, "ResponseBotQNAAgeAliasV2": { "Condition": "CreateLexResponseBots", @@ -9494,643 +7880,124 @@ exports[`renders examples template correctly 1`] = ` { "Name": "QNAYesNoSlotType", "SlotTypeValues": [ - { - "SampleValue": { - "Value": "Yes", - }, - "Synonyms": [ - { - "Value": "Yes", - }, - { - "Value": "OK", - }, - { - "Value": "yeah", - }, - { - "Value": "sure", - }, - { - "Value": "yep", - }, - { - "Value": "affirmative", - }, - { - "Value": "aye", - }, - { - "Value": "correct", - }, - { - "Value": "one", - }, - { - "Value": "1", - }, - ], - }, - { - "SampleValue": { - "Value": "No", - }, - "Synonyms": [ - { - "Value": "no", - }, - { - "Value": "nope", - }, - { - "Value": "na", - }, - { - "Value": "negative", - }, - { - "Value": "non", - }, - { - "Value": "incorrect", - }, - { - "Value": "Two", - }, - { - "Value": "2", - }, - ], - }, - ], - "ValueSelectionSetting": { - "ResolutionStrategy": "TOP_RESOLUTION", - }, - }, - ], - "VoiceSettings": { - "VoiceId": "Salli", - }, - }, - ], - "DataPrivacy": { - "ChildDirected": false, - }, - "Description": "QNA Yes No Bot - x.x.x - v2", - "IdleSessionTTLInSeconds": "300", - "Name": { - "Fn::Sub": "ResponseBot-QNAYesNoV2-\${AWS::StackName}", - }, - "RoleArn": { - "Fn::GetAtt": [ - "BotRuntimeRole", - "Arn", - ], - }, - }, - "Type": "AWS::Lex::Bot", - }, - "ResponseBotQNAYesNoVersionV2": { - "Condition": "CreateLexResponseBots", - "DeletionPolicy": "Retain", - "DependsOn": [ - "ResponseBotQNAPinVersionV2", - "ResponseBotQNAYesNoV2", - ], - "Properties": { - "BotId": { - "Ref": "ResponseBotQNAYesNoV2", - }, - "BotVersionLocaleSpecification": [ - { - "BotVersionLocaleDetails": { - "SourceBotVersion": "DRAFT", - }, - "LocaleId": "en_US", - }, - ], - }, - "Type": "AWS::Lex::BotVersion", - "UpdateReplacePolicy": "Retain", - }, - "SocialSecurityAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNASocialSecurity", - }, - "description": "QNA Social Security Alias - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "SocialSecurityIntent": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, - ], - }, - "confirmationPrompt": { - "maxAttempts": 1, - "messages": [ - { - "content": "Is {SSN} correct (Yes/No)?", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Social Security Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNASocialSecurityIntent-\${AWS::StackName}", - }, - "rejectionStatement": { - "messages": [ - { - "content": "Please let me know the social security number again.", - "contentType": "PlainText", - }, - ], - }, - "sampleUtterances": [ - "The social security number is {SSN}", - "My social security number is {SSN}", - "It is {SSN}", - "{SSN}", - ], - "slots": [ - { - "name": "SSN", - "priority": 1, - "slotConstraint": "Required", - "slotType": { - "Ref": "SocialSecuritySlotType", - }, - "slotTypeVersion": "QNABOT-AUTO-ASSIGNED", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What is your social security number?", - "contentType": "PlainText", - }, - ], - }, - }, - ], - }, - "Type": "Custom::LexIntent", - }, - "SocialSecuritySlotType": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "createVersion": true, - "description": "QNA Social Security Slot Type - x.x.x - v1", - "name": { - "Fn::Sub": "QNASocialSecuritySlotType-\${AWS::StackName}", - }, - "parentSlotTypeSignature": "AMAZON.AlphaNumeric", - "slotTypeConfigurations": [ - { - "regexConfiguration": { - "pattern": "[0-9]{3}-[0-9]{2}-[0-9]{4}", - }, - }, - ], - }, - "Type": "Custom::LexSlotType", - }, - "TimeAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNATime", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNATime", - }, - "description": "QNA Time Alias - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "TimeIntent": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, - ], - }, - "confirmationPrompt": { - "maxAttempts": 1, - "messages": [ - { - "content": "Is {Time} correct (Yes or No)?", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Time Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNATimeIntent-\${AWS::StackName}", - }, - "rejectionStatement": { - "messages": [ - { - "content": "Please let me know the time again.", - "contentType": "PlainText", - }, - ], - }, - "sampleUtterances": [ - "The time was {Time}", - "It occurred at {Time}", - "At {Time}", - "{Time}", - ], - "slots": [ - { - "name": "Time", - "priority": 1, - "slotConstraint": "Required", - "slotType": "AMAZON.TIME", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What time?", - "contentType": "PlainText", - }, - ], - }, - }, - ], - }, - "Type": "Custom::LexIntent", - }, - "WageAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNAWage", - }, - "description": "QNA Wage Alias - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "WageIntent": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, - ], - }, - "confirmationPrompt": { - "maxAttempts": 1, - "messages": [ - { - "content": "Is {Wage} correct (Yes/No)?", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Wage Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNAWageIntent-\${AWS::StackName}", - }, - "rejectionStatement": { - "messages": [ - { - "content": "Please let me know what your wage was again.", - "contentType": "PlainText", - }, - ], - }, - "sampleUtterances": [ - "My salary is {Wage}", - "My wage is {Wage}", - "{Wage}", - ], - "slots": [ - { - "name": "Wage", - "priority": 1, - "slotConstraint": "Required", - "slotType": { - "Ref": "WageSlotType", - }, - "slotTypeVersion": "QNABOT-AUTO-ASSIGNED", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "What is your wage?", - "contentType": "PlainText", + { + "SampleValue": { + "Value": "Yes", + }, + "Synonyms": [ + { + "Value": "Yes", + }, + { + "Value": "OK", + }, + { + "Value": "yeah", + }, + { + "Value": "sure", + }, + { + "Value": "yep", + }, + { + "Value": "affirmative", + }, + { + "Value": "aye", + }, + { + "Value": "correct", + }, + { + "Value": "one", + }, + { + "Value": "1", + }, + ], + }, + { + "SampleValue": { + "Value": "No", + }, + "Synonyms": [ + { + "Value": "no", + }, + { + "Value": "nope", + }, + { + "Value": "na", + }, + { + "Value": "negative", + }, + { + "Value": "non", + }, + { + "Value": "incorrect", + }, + { + "Value": "Two", + }, + { + "Value": "2", + }, + ], + }, + ], + "ValueSelectionSetting": { + "ResolutionStrategy": "TOP_RESOLUTION", }, - ], - }, - }, - ], - }, - "Type": "Custom::LexIntent", - }, - "WageSlotType": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "createVersion": true, - "description": "QNA Wage Slot Type - x.x.x - v1", - "name": { - "Fn::Sub": "QNAWageSlotType-\${AWS::StackName}", - }, - "parentSlotTypeSignature": "AMAZON.AlphaNumeric", - "slotTypeConfigurations": [ - { - "regexConfiguration": { - "pattern": "[0-9]{1,7}", + }, + ], + "VoiceSettings": { + "VoiceId": "Salli", }, }, ], - }, - "Type": "Custom::LexSlotType", - }, - "YesNoAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNAYesNo", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNAYesNo", - }, - "description": "QNA Yes No Alias - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "YesNoExitAliasV2": { - "Condition": "CreateLexV1ResponseBots", - "DependsOn": "QNAYesNoExit", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "botName": { - "Ref": "QNAYesNoExit", + "DataPrivacy": { + "ChildDirected": false, }, - "description": "QNA Yes No Exit Alias - x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, - "YesNoExitIntent": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", + "Description": "QNA Yes No Bot - x.x.x - v2", + "IdleSessionTTLInSeconds": "300", + "Name": { + "Fn::Sub": "ResponseBot-QNAYesNoV2-\${AWS::StackName}", }, - "conclusionStatement": { - "messages": [ - { - "content": "Ok. ", - "contentType": "PlainText", - }, + "RoleArn": { + "Fn::GetAtt": [ + "BotRuntimeRole", + "Arn", ], }, - "createVersion": true, - "description": "QNA Yes No Exit Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNAYesNoExitIntent-\${AWS::StackName}", - }, - "sampleUtterances": [ - "{Yes_No_Exit}", - "I said {Yes_No_Exit}", - ], - "slots": [ - { - "name": "Yes_No_Exit", - "priority": 1, - "slotConstraint": "Required", - "slotType": { - "Ref": "YesNoExitSlotType", - }, - "slotTypeVersion": "QNABOT-AUTO-ASSIGNED", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "Say Yes, No, or Exit.", - "contentType": "PlainText", - }, - ], - }, - }, - ], - }, - "Type": "Custom::LexIntent", - }, - "YesNoExitSlotType": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "createVersion": true, - "description": "QNA Yes No Exit Slot Type - x.x.x - v1", - "enumerationValues": [ - { - "synonyms": [ - "yes", - "ok", - "yeah", - "sure", - "yep", - "affirmative", - "aye", - "correct", - "1", - "one", - ], - "value": "Yes", - }, - { - "synonyms": [ - "no", - "nope", - "na", - "negative", - "non", - "2", - "two", - ], - "value": "No", - }, - { - "synonyms": [ - "exit", - "agent", - "rep", - "representative", - "stop", - "quit", - "help", - "bye", - "goodbye", - "3", - "three", - ], - "value": "Exit", - }, - ], - "name": { - "Fn::Sub": "QNAYesNoExitSlotType-\${AWS::StackName}", - }, - "valueSelectionStrategy": "TOP_RESOLUTION", }, - "Type": "Custom::LexSlotType", + "Type": "AWS::Lex::Bot", }, - "YesNoIntent": { - "Condition": "CreateLexV1ResponseBots", + "ResponseBotQNAYesNoVersionV2": { + "Condition": "CreateLexResponseBots", + "DeletionPolicy": "Retain", + "DependsOn": [ + "ResponseBotQNAPinVersionV2", + "ResponseBotQNAYesNoV2", + ], "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "conclusionStatement": { - "messages": [ - { - "content": "OK. ", - "contentType": "PlainText", - }, - ], - }, - "createVersion": true, - "description": "QNA Yes No Intent - x.x.x - v1", - "fulfillmentActivity": { - "type": "ReturnIntent", - }, - "name": { - "Fn::Sub": "QNAYesNoIntent-\${AWS::StackName}", + "BotId": { + "Ref": "ResponseBotQNAYesNoV2", }, - "sampleUtterances": [ - "{Yes_No}", - "I said {Yes_No}", - ], - "slots": [ + "BotVersionLocaleSpecification": [ { - "name": "Yes_No", - "priority": 1, - "slotConstraint": "Required", - "slotType": { - "Ref": "YesNoSlotType", - }, - "slotTypeVersion": "QNABOT-AUTO-ASSIGNED", - "valueElicitationPrompt": { - "maxAttempts": 2, - "messages": [ - { - "content": "Say Yes or No.", - "contentType": "PlainText", - }, - ], + "BotVersionLocaleDetails": { + "SourceBotVersion": "DRAFT", }, + "LocaleId": "en_US", }, ], }, - "Type": "Custom::LexIntent", - }, - "YesNoSlotType": { - "Condition": "CreateLexV1ResponseBots", - "Properties": { - "ServiceToken": { - "Ref": "CFNLambda", - }, - "createVersion": true, - "description": "QNA Yes No Slot Type - x.x.x - v1", - "enumerationValues": [ - { - "synonyms": [ - "yes", - "ok", - "yeah", - "sure", - "yep", - "affirmative", - "aye", - "correct", - "1", - "one", - ], - "value": "Yes", - }, - { - "synonyms": [ - "no", - "nope", - "na", - "negative", - "non", - "2", - "two", - ], - "value": "No", - }, - ], - "name": { - "Fn::Sub": "QNAYesNoSlotType-\${AWS::StackName}", - }, - "valueSelectionStrategy": "TOP_RESOLUTION", - }, - "Type": "Custom::LexSlotType", + "Type": "AWS::Lex::BotVersion", + "UpdateReplacePolicy": "Retain", }, "feedbacksnspolicy": { "Properties": { @@ -10173,6 +8040,102 @@ exports[`renders examples template correctly 1`] = ` }, "Type": "AWS::SNS::TopicPolicy", }, + "helloLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}", + }, + "ExamplePYTHONLambdahello", + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, + "hookLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}", + }, + "ExampleJSLambdahook", + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, }, } `; diff --git a/source/templates/examples/examples/examples/PrairieLineTrailTour.json b/source/templates/examples/examples/examples/PrairieLineTrailTour.json index 36b06a693..9809afe77 100644 --- a/source/templates/examples/examples/examples/PrairieLineTrailTour.json +++ b/source/templates/examples/examples/examples/PrairieLineTrailTour.json @@ -36,7 +36,7 @@ }, { "a": "This paired sculpture and mural features a finger and thumb clasping a steel needle, followed by a trail of stitches. The title takes its inspiration from a late-1800's promotional slogan for Tacoma, and the mural elaborates on this era in Tacoma's urban development. Together, these elements tell the story of the Northern Pacific Railroad finding its end at Commencement Bay and the growth of urban Tacoma.\n\n Ask for more about the art, the artist, or the medium for additional information.", - "qid": "Where the Rails Meet the Sails", + "qid": "Where_the_Rails_Meet_the_Sails", "next": "Pressure + Flow", "q": [ "Where the Rails Meet the Sails", @@ -57,7 +57,7 @@ }, { "a": "Steel rail, reinforced steel stitching, paint on concrete", - "qid": "Where the Rails Meet the Sails: Medium", + "qid": "Where_the_Rails_Meet_the_Sails:_Medium", "q": [ "Medium", "Material", @@ -73,7 +73,7 @@ }, { "a": "Rotator Creative is an agency located in Tacoma, working at the intersection of art, advertising, and community building.\n\nLance Kagey is best known for his Beautiful Angle street-art posters. They use poetry, design, and antique typefaces to celebrate Tacoma, much like his first permanent public art piece. For Kagey, Where the Rails Meet the Sails is a meditation on how the world is an incredibly connected place.\n\nMark Alvis, whose great grandfather worked as an advertiser in Tacoma, marvels at the opportunity to use his own design skills to commemorate the efforts of his ancestor and others like him.\n\nScott Varga designs everything from websites, to hot rods, to industrial sculpture. He sees a direct connection between the coming of the railroad in 1873 and the proudly working-class, global city Tacoma has become.\n\nVisit their website at : http://www.rotatorcreative.com/", - "qid": "Where the Rails Meet the Sails: Meet the artists", + "qid": "Where_the_Rails_Meet_the_Sails:_Meet_the_artists", "q": [ "who made this", "who is the artist", @@ -89,7 +89,7 @@ }, { "a": "Where the Rails Meet the Sails is a metaphor for rails and sails being stitched together to complete the connection of the Northern Route of the Transcontinental Railroad in 1873. Here in Tacoma, trains traveled to meet the ships headed to San Francisco, Alaska, Asia, and beyond.\n\nThe needle is a piece of historic rail salvaged from the Prairie Line Trail, and the stitches are made from the same kind of heavy mooring cable used to sew cotton sails. The mural's text and title is inspired by the many marketing campaigns that sought to attract people and investment to Tacoma.\n\nThe hand holding the needle in the sculpture and mural is larger-than-life, which is fitting considering the far-reaching impacts unleashed by the decision to set the western terminus of the Northern Pacific Railroad (NPRR) in Tacoma.", - "qid": "Where the Rails Meet the Sails: About the art", + "qid": "Where_the_Rails_Meet_the_Sails:_About_the_art", "q": [ "more about the art", "about the art", @@ -104,7 +104,7 @@ }, { "a": "Commissioned by the City of Tacoma.\n\nA two-part installation, Pressure + Flow is a reflection on the power of technology and communication to transform a landscape. Pressure is a sculpture inspired by the inner workings of a steam engine, and Flow involves etched writing applied directly to the historic Prairie Line rails, excerpted from historic documents and letters.\n\n Ask for more about the art, the artist, or the medium for additional information.", - "qid": "Pressure + Flow", + "qid": "Pressure+Flow", "next": "Shipment to China", "q": [ "Pressure + Flow", @@ -125,7 +125,7 @@ }, { "a": "Steel sculpture", - "qid": "Pressure + Flow: Medium", + "qid": "Pressure+Flow:_Medium", "q": [ "Medium", "Material", @@ -141,7 +141,7 @@ }, { "a": "Matthew Dockery is a Seattle-area industrial artist who works in metal, electronics, wood and textiles. The history of technology provides the inspiration for much of his work, and he has a special love for machines, gadgets, gears that mesh properly, and history. His work has been featured on the Discovery Channel, at Greenwich Observatory in London, at the annual Burning Man festival, and around the Pacific Northwest. Dockery describes his work as “living at the intersection of gears and mad science.”\n\nWhen asked how Pressure + Flow tells the Prairie Line's story, Dockery replied, “In many ways, the railroad is Tacoma's story. It was just another small town until the Northern Pacific made it their terminus.” Dockery insists that in many ways society is still moving to the frontier: “There are still such things as real estate bubbles and speculation, risk and reward, boom and bust.”\n\nVisit his website at : http://www.attoparsec.com/", - "qid": "Pressure + Flow: Meet the artist", + "qid": "Pressure+Flow:_Meet_the_artist", "q": [ "who made this", "who is the artist", @@ -157,7 +157,7 @@ }, { "a": " Pressure + Flow reveals the hidden mechanisms, both technical and cultural, that have carried us into the present. As we travel daily in cars, bikes, and planes, it is easy to take for granted the complex machines working to get us to our destinations. Pressure unveils the inner workings of a steam-powered train engine like those used in the early railroad era, providing an opportunity to interact with the usually unseen piston and pipes.\n\nAlongside rail lines came telegraph towers, marking a revolution in communication technology. Trains transported immigrants from all over the world to Tacoma, and each traveler brought their own stories and cultures with them. Excerpts from historical documents, journals, oral histories, telegrams, and letters are etched in different languages into the remaining historical railroad tracks along the trail, representing the flow of new communities into the area alongside the original occupants of Tacoma – the Puyallup.\n\nThis artwork encourages us to look more deeply at how we arrived where we are today, and provides snapshots of the many stories embedded along the Prairie Line.\n\nPressure + Flow will be installed by Spring 2018.", - "qid": "Pressure + Flow: About the art", + "qid": "Pressure+Flow:_About_the_art", "q": [ "more about the art", "about the art", @@ -172,7 +172,7 @@ }, { "a": "Commissioned by the Chinese Reconciliation Project Foundation in partnership with the City of Tacoma.\n\nThis piece commemorates the early Chinese in America, their labors to construct the transcontinental railroads railroad construction, and their unjust suffering. It consists of an antique train truck and abstracted representation of 100 ash boxes, a reference to the Chinese workers who died while building the railroads.\n\n Ask for more about the art, the artist, or the medium for additional information.", - "qid": "Shipment to China", + "qid": "Shipment_to_China", "next": "Nexus", "q": [ "Shipment to China", @@ -192,7 +192,7 @@ }, { "a": "Bronze, antique train truck", - "qid": "Shipment to China: Medium", + "qid": "Shipment_to_China:_Medium", "q": [ "Medium", "Material", @@ -208,7 +208,7 @@ }, { "a": "A native of China, Haiying Wu was a professional sculptor before emigrating to the US. He created this piece while a graduate student at the University of Washington. A prolific artist, his work can be found in Seattle, Lynnwood, Tacoma, Redmond, and in Chengdu, in the Sichuan province of China.\n\nAccording to Wu,“This piece shows the bitterness of the Chinese experience in America during that time, for the railroad built by their efforts was the same transportation used to carry them out of Tacoma.”\n\nThanks to the Chinese Reconciliation Project Foundation for contributing this important piece for exhibition on the Prairie Line Trail, now displayed on the very tracks that the Chinese worked tirelessly to build.\n\nVisit their website at : http://www.tacomachinesepark.org/", - "qid": "Shipment to China: Meet the artist", + "qid": "Shipment_to_China:_Meet_the_artist", "q": [ "who made this", "who is the artist", @@ -224,7 +224,7 @@ }, { "a": " Shipment to China was created to commemorate the Chinese laborers who were instrumental in building the transcontinental railroad in the United States. Starting in the mid-1860's, thousands of Chinese came to the US to work on the country's expanding railroad lines. In addition to dangerous, sometimes fatal working conditions, many Chinese laborers were threatened and killed during anti-Chinese expulsion movements.\n\nAfter a Chinese worker died, the ashes of the deceased were often sent back to China in boxes, so that they could be buried next to their ancestors. This piece refers to that practice. Each “box” represents a worker. The majority of boxes are anonymous; however a few choice names and dates powerfully connect us to the past and the people who gave their lives to build the railroad and the West.\n\nAfter connecting the city to the nation by building the Northern Pacific Railroad (NPRR), many Chinese workers settled in the growing city. But national sentiment began to turn against these immigrants, and in Tacoma, the Chinese community was intentionally expelled after anti-Chinese sentiment turned violent. Led by Tacoma's Mayor, the Chinese community of 600 was driven out of town on November 3, 1885. After the riot, the Chinese District, sometimes called Little Canton, lay in smoldering ruins. This horrific event, and the complicit role of the City's leaders, led this kind of expulsion to be known as the “Tacoma Method” nation-wide.", - "qid": "Shipment to China: About the art", + "qid": "Shipment_to_China:_About_the_art", "q": [ "more about the art", "about the art", @@ -258,7 +258,7 @@ }, { "a": "Painted metal, with elements of wood, tile, and glass", - "qid": "Nexus: Medium", + "qid": "Nexus:_Medium", "q": [ "Medium", "Material", @@ -274,7 +274,7 @@ }, { "a": "Ryan Feddersen is a mixed media installation artist. Her work is characterized by a sense of exploration and experimentation. Many of her pieces utilize tongue in cheek humor accompanied by interactivity, inviting the viewer to engage with the irrationalities and hypocrisies of contemporary American culture. Feddersen is a member of the Confederated Tribes of the Colville Reservation (Okanogan / Arrow Lakes), the Interior Salish community that historically moved trade goods across the Plateau region and had especially strong relationships with the Puyallup and other Coastal Salish tribes.\n\nSpeaking about the potential of interactive art, Feddersen noted that the simple act of play can “transport you to another time, creating a connection to the deep history of a place.”.\n\nVisit her website at : http://ryanfeddersen.com/", - "qid": "Nexus: Meet the artist", + "qid": "Nexus:_Meet_the_artist", "q": [ "who made this", "who is the artist", @@ -290,7 +290,7 @@ }, { "a": "Taking inspiration from the childhood games of “playing store,” this artwork is staged as a trading space that you can step into, making room for imaginative play while also learning about the relationships between Native American tribes. The artwork references the exchange of goods, people, and cultural interactions along pre-colonial trade routes. The inter-tribal trade network was vast, but main lines connected the Pacific Northwest Coast most closely to the Subarctic, California, and Plateau—the region represented as a trade partner in the artwork.\n\nThe section of the Prairie Line Trail that this artwork occupies was historically known by the Puyallup Tribe as the Place of Many Fires, where locals and visitors came together and traded for luxurious goods like the ones seen here.\n\nNexus will be installed in Spring 2018.", - "qid": "Nexus: About the art", + "qid": "Nexus:_About_the_art", "q": [ "more about the art", "about the art", @@ -305,7 +305,7 @@ }, { "a": "The Tacoma Arts Commission and Tacoma Art Museum.\n\nAccording to Puyallup historians, Native American travelers knew the tough part of their journey lay behind them when they were greeted by a welcome figure like this on the shores of Puget Sound. Carved by Qwalsius (Shaun Peterson), in a style unique to the Puyallup People, spuy'elepebS Welcome Figure is a modern take on a local traditional art form.\n\n Ask for more about the art, the artist, historical context, or the medium for additional information", - "qid": "Welcome Figure", + "qid": "Welcome_Figure", "next": "Maru", "q": [ "Welcome Figure", @@ -324,7 +324,7 @@ }, { "a": "Western Red Cedar, exterior latex paint textured by a traditional adze method, chisels, and knives", - "qid": "Welcome Figure: Medium", + "qid": "Welcome_Figure:_Medium", "q": [ "Medium", "Material", @@ -340,7 +340,7 @@ }, { "a": "Qwalsius (Shaun Peterson) is a prolific Puyallup artist and a towering presence in the movement to revive Coast Salish Art traditions. He carved Welcome Figure in 2010. Qwalsius works in many art forms, from carving, to painting, to printing — always inspired by his heritage. His pieces mix tradition with innovation. His works have graced exhibitions in New Zealand, China, Japan, and throughout the U.S., and permanently adorn several buildings on the Puyallup Reservation. He is currently working on a large commission for the Seattle waterfront.\n\n Visit his website at : http://www.qwalsius.com/", - "qid": "Welcome Figure: Meet the artist", + "qid": "Welcome_Figure:_Meet_the_artist", "q": [ "who made this", "who is the artist", @@ -356,7 +356,7 @@ }, { "a": "The style of Welcome Figure is traditional to this region and the Coast Salish tribes. Totem poles are often mistakenly identified with the Pacific Northwest, but that form was primarily practiced by the First Nations Groups of Canada and Alaska. Traditional wood carving practices of the Puyallup included welcome figures.\n\nIn the words of the artist, the colors and formlines of this piece were chosen with intention and purpose:“The earth red color here signifies the healing power associated with Thunderbird by the Puyallup people long ago. Although it was believed that Thunderbird had white feathers, the print and the painted dress pattern convey a healing that is called upon for the devastation of losing a prominent village. Contrary to surrounding tribes who envision the Thunderbird as a massive creature who consumes whales, the Puyallup percieved the being to be no larger than a small hawk. It is an indication that power was not associated with mass and that the strength to heal was of equal if not greater importance in the philosophy of our ancestors.”\n\n Many Puget Sound tribes continue to practice the important practices that distinguish this region of the world, generously sharing their culture through art, song, and dance. The intention of this contemporary welcoming figure is the same as that of its predecessors: with its arms outstretched, it gracefully receives visitors to the site while powerfully honoring the traditions of the area's first peoples.", - "qid": "Welcome Figure: About the art", + "qid": "Welcome_Figure:_About_the_art", "q": [ "more about the art", "about the art", @@ -371,7 +371,7 @@ }, { "a": " Generous and blessed with abundant resources, the Puyallup often hosted Native travelers. Their generosity extended to non-Native newcomers as well, though their gestures of friendship were not always reciprocal.\n\n The tribes of the Pacific Northwest were connected through travel, marriage, and a practice called potlatch. A potlatch is a gift-giving feast meant to mark an important event. At the end of the party, the host family gave away all their worldly possessions. Ample resources and a culture of generosity made it easy for hosts regain what was “lost” after they hosted a potlatch.\n\n From the site of Welcome Figure, visitors can glimpse the Tacoma Dome, and on clear days, Tacopid (Mt. Rainier). Tacopid supports its caretakers with water, fish, timber, and game. It is a beloved source of life for the Puyallup. Historically, the Tribe tucked villages and temporary hunting camps into the gentle curves of the streams and rivers that flowed from the mountain. But their main village sat where the Tacoma Dome now stands. What little remains of that village lies beneath forty feet of fill today.\n\n Today, tribal headquarters are located off of Portland Avenue, in East Tacoma, where the tribe owns many local businesses, provides services to tribal members, and offers education about the tribe's historic and contemporary cultural practices and lifeways.", - "qid": "Welcome Figure: Historical Context", + "qid": "Welcome_Figure:_Historical_Context", "q": [ "more about the history", "about the historical context", @@ -405,7 +405,7 @@ }, { "a": "Bronze", - "qid": "Maru: Medium", + "qid": "Maru:_Medium", "q": [ "Medium", "Material", @@ -421,7 +421,7 @@ }, { "a": "While designing Maru, sculptor Gerard Tsutakawa worked with an advisory board of former students. The late landscape designer Kenichi Nakano also collaborated on this sculpture.\n\n Tsutakawa's designs combine the cultures and traditions of the Pacific Rim, incorporating Japanese forms and sensibilities with his lifetime of experience living in the Pacific Northwest's unique natural environment. Well known for MITT, the sculpture that stands outside Safeco Field in Seattle, his sculptures are humanistic, accessible, and inviting.", - "qid": "Maru: Meet the artist", + "qid": "Maru:_Meet_the_artist", "q": [ "who made this", "who is the artist", @@ -437,7 +437,7 @@ }, { "a": "Maru stands among a landscape of boulders and Japanese maples. The bronze sculpture has a large cut-out circle, inviting visitors to sit, touch, and interact with the piece. It also offers an opportunity for contemplation and learning about the history of the Japanese Language school, which was located a few blocks up the hill from the sculpture.\n\n Maru, which means \"circle,\" might alternatively evoke a sense of negative space, or the image of a closed, unending circle. Similarly, the piece suggests both the hollow space left in the community after wartime incarceration, as well as the continued presence of the Japanese American community in Tacoma. Japanese ship names often end in -maru, so the piece may also refer to the importance of Japanese ships in bringing people and goods to Tacoma.", - "qid": "Maru: About the art", + "qid": "Maru:_About_the_art", "q": [ "more about the art", "about the art", @@ -452,7 +452,7 @@ }, { "a": " As the point of arrival for the railroad, the hillside west of the Prairie Line corridor hosted many ethnic enclaves, including the Nihonmachi, or Japan Town. By 1890, approximately 500 Japanese-Americans lived in Tacoma. Arriving by ship, many Japanese first came to work in railroad construction. In the 1880s, the Northern Pacific enlisted Hifumi “Harry” Kumamoto to recruit 2,000 Japanese laborers to help build the Cascade Branch of the NPRR. Building this more direct route over the Cascades was what made Tacoma finally boom.\n\n As the city grew up, so did the Nihonmachi. Japanese entrepreneurs like Fujimatsu and Sadako Moriguchi set up shop. Established in 1928, their store — Uwajima-ya — sold Japanese staples to countrymen craving a bit of home.\n\n The Japanese Language School, Nihongo Gakko, served as the main hub of Japan Town. From 1911 through 1942, the school brought the families of a thriving urban neighborhood together to support the future of their community and their children. The school was located on the 1700 block of Tacoma Avenue in a bustling neighborhood of hotels, restaurants, laundries, banks, and houses. For three decades, the school instilled in its young students the moral and cultural values of their Japanese heritage, and also emphasized a strong commitment to American citizenship.", - "qid": "Maru: Historical Context", + "qid": "Maru:_Historical_Context", "q": [ "more about the history", "about the historical context", @@ -467,7 +467,7 @@ }, { "a": " As the point of arrival for the railroad, the hillside west of the Prairie Line corridor hosted many ethnic enclaves, including the Nihonmachi, or Japan Town. By 1890, approximately 500 Japanese-Americans lived in Tacoma. Arriving by ship, many Japanese first came to work in railroad construction. In the 1880s, the Northern Pacific enlisted Hifumi “Harry” Kumamoto to recruit 2,000 Japanese laborers to help build the Cascade Branch of the NPRR. Building this more direct route over the Cascades was what made Tacoma finally boom.\n\n As the city grew up, so did the Nihonmachi. Japanese entrepreneurs like Fujimatsu and Sadako Moriguchi set up shop. Established in 1928, their store — Uwajima-ya — sold Japanese staples to countrymen craving a bit of home.\n\n The Japanese Language School, Nihongo Gakko, served as the main hub of Japan Town. From 1911 through 1942, the school brought the families of a thriving urban neighborhood together to support the future of their community and their children. The school was located on the 1700 block of Tacoma Avenue in a bustling neighborhood of hotels, restaurants, laundries, banks, and houses. For three decades, the school instilled in its young students the moral and cultural values of their Japanese heritage, and also emphasized a strong commitment to American citizenship.", - "qid": "Maru: WWII Internment", + "qid": "Maru:_WWII_Internment", "q": [ "world war 2", "world war two", @@ -489,7 +489,7 @@ }, { "a": "In 1990, the University of Washington started renovating vacant buildings in what was historically known as the Jobber's District, including this 1892 building commissioned by Russell T. Joy. The Joy Building used “flatiron” technology, a major innovation in its day. Built in brick, the building's interior structure was steel, rather than Douglas fir timber — a first step towards the emergence of skyscrapers. The building was supposed to be nearly fireproof. This was an important selling point: just four years prior, Seattle had burnt to the ground.\n\n But in 1903, a four-engine fire at the Joy Building destroyed the inventory and equipment of four tenants, including that of the Weigel and Star Diamond candy companies. Luckily, the fire was contained, and the building was renovated a few months later. Since then, the building was repurposed for many uses, including a glove manufacturer, coffee company, and automobile dealerships. \n\n Ask for more about adapative reuse for additional information", - "qid": "Joy Building", + "qid": "Joy_Building", "next": "Branch: West Coast Grocery and Union Station", "q": [ "Joy Building", @@ -509,7 +509,7 @@ }, { "a": " Roughly 120 years after it was originally built, UW Tacoma renovated the Joy Building. This remodel was a part of an innovative campus development project that adaptively and creatively reused the historic warehouse buildings along the Prairie Line.\n\n Though the buildings were redesigned for their new purpose, historical elements like facades and painted signs (sometimes called ghost signage) were intentionally left in place. Here's a handy list to help you find all of UW Tacoma's ghost signs, http://www.tacoma.washington.edu/about-uw-tacoma/ghost-signs-campus.", - "qid": "Joy Building: UW Tacoma and adaptive reuse", + "qid": "Joy_Building:_UW_Tacoma_and_adaptive_reuse", "q": [ "more about adaptive reuse", "adaptive reuse" @@ -528,7 +528,7 @@ }, { "a": "There are two options for the next stop, Terminus and Union Station. Union Station is slightly out of the way. Say or type which stop you would like to go to next.", - "qid": "Branch: West Coast Grocery and Union Station", + "qid": "Branch:_West_Coast_Grocery_and_Union_Station", "next": "Branch: West Coast Grocery and Union Station", "q": [ "Branch: West Coast Grocery and Union Station" @@ -545,7 +545,7 @@ }, { "a": "In 1990, the University of Washington started renovating vacant buildings in what was historically known as the Jobber's District, including this 1892 building commissioned by Russell T. Joy. The Pacific Avenue and Union Station used “flatiron” technology, a major innovation in its day. Built in brick, the building's interior structure was steel, rather than Douglas fir timber — a first step towards the emergence of skyscrapers. The building was supposed to be nearly fireproof. This was an important selling point: just four years prior, Seattle had burnt to the ground.\n\n But in 1903, a four-engine fire at the Pacific Avenue and Union Station destroyed the inventory and equipment of four tenants, including that of the Weigel and Star Diamond candy companies. Luckily, the fire was contained, and the building was renovated a few months later. Since then, the building was repurposed for many uses, including a glove manufacturer, coffee company, and automobile dealerships. \n\n Ask for more about early development or more about the station for additional information", - "qid": "Pacific Avenue and Union Station", + "qid": "Pacific_Avenue_and_Union_Station", "next": "West Coast Grocery", "q": [ "Pacific Avenue and Union Station", @@ -564,7 +564,7 @@ }, { "a": " Roughly 120 years after it was originally built, UW Tacoma renovated the Pacific Avenue and Union Station. This remodel was a part of an innovative campus development project that adaptively and creatively reused the historic warehouse buildings along the Prairie Line.\n\n Though the buildings were redesigned for their new purpose, historical elements like facades and painted signs (sometimes called ghost signage) were intentionally left in place. Here's a handy list to help you find all of UW Tacoma's ghost signs, http://www.tacoma.washington.edu/about-uw-tacoma/ghost-signs-campus.", - "qid": "Platting Tacoma and Pacific Avenue", + "qid": "Platting_Tacoma_and_Pacific_Avenue", "q": [ "more about early development", "more about development", @@ -585,7 +585,7 @@ }, { "a": " The Northern Pacific's copper-topped passenger depot wouldn't be built along Pacific Avenue until 1909. Union Station arrived amid a flurry of railroad activity. Three new railroads connected to Tacoma in the early 1900's: The Great Northern (1909), Union Pacific (1910), and the Milwaukee Railroad (1911). \n\n For many years, Union Station was the key transportation hub for the region. But in the mid-1900's, the national highway system replaced railroads as the preferred travel method for most Americans. Ridership dwindled.\n\n In 1984, an Amtrak Station was built in the Dome District. Union Station saw its last passenger train depart the same year. The historic depot sat vacant for several years. Neighboring warehouses were also abandoned for several years until renovation by the University of Washington Tacoma began in the 1990's.", - "qid": "More about Union Station", + "qid": "More_about_Union_Station", "q": [ "more about union station", "more about the station", @@ -604,7 +604,7 @@ }, { "a": "This building's original tenants — Tacoma Grocery — supplied groceries from Montana to Alaska, but went belly up in the Panic of 1893. West Coast Grocery reused the space and built a more lasting grocery empire headquartered right here in the Jobber's District. \n\n Ask about the boom,bust,and boom or more about the Jobber's district information", - "qid": "West Coast Grocery", + "qid": "West_Coast_Grocery", "next": "Terminus", "q": [ "West Coast Grocery", @@ -624,7 +624,7 @@ }, { "a": " Tacoma Grocery's founders intended to establish the largest wholesale grocery in the Pacific Northwest. Instead, they got caught in the throes of a nationwide depression caused by a banking crisis. Many local startups faced a similar fate. \n\n Three years later, West Coast Grocery took over where Tacoma Grocery left off. Selling products under the brand name “Amocat” (Tacoma spelled backward), West Coast Grocery thrived, expanding into the Birmingham Hay & Seed Building on its south side in 1917. The building served as a warehouse for West Coast Grocery until 1970.", - "qid": "Boom, bust, and boom again", + "qid": "Boom,_bust,_and_boom_again", "q": [ "boom", "boom bust and boom", @@ -645,7 +645,7 @@ }, { "a": " The area was called the Jobber's District after the multitude of wholesale businesses who sprouted up along the Prairie Line, taking advantage of the spur lines that could connect them to goods arriving by rail. Those who worked in the warehouses were also known as jobbers, and multitudes flooded in to work in these growing industries.\n\n West Coast Grocery, with its retail space in front and warehouse space in the back, is a typical example of Jobber's District architecture. Other businesses along this stretch of the Prairie Line included the Joy Building, Garretson, Woodruff and Pratt Company; F. S. Harmon Furniture Manufacturing Company; Lindstrom-Berg Cabinet Works; and Tacoma Paper and Stationary.\n\n Built right along the Prairie Line Rail corridor, most of these buildings share similarities. The side facing Pacific Avenue was usually more attractive since it faced the shopping public, while the side facing the railroad was more industrial, offering efficient loading and unloading on a special railroad spur built just off of the Prairie Line. We can thank this design strategy for West Coast Grocery's timeless Italianate façade.\n\n The building was renovated in 1996 by the University of Washington. As UW Tacoma renovated this and other buildings in the Jobber's District, it kept some of this history in tact, keeping the original loading docks and repurposing them as covered walkways.", - "qid": "The Jobber's District", + "qid": "The_Jobber's_District", "q": [ "jobbers district", "jobber's district", @@ -679,7 +679,7 @@ }, { "a": "Granite, stainless steel, and fluorescent lights", - "qid": "Terminus: Medium", + "qid": "Terminus:_Medium", "q": [ "Medium", "Material", @@ -695,7 +695,7 @@ }, { "a": "Brian Goldbloom is a sculptor and public artist, well known for his site-specific stone constructions. Drawing inspiration from each site, his natural stone pieces provide contrast and interest to built environments.\n\nVisit their website at : http://www.goldbloomart.com/artist.asp?ArtistID=22174&Akey=EGW9FJRW&flM=1", - "qid": "Terminus: Meet the artist", + "qid": "Terminus:_Meet_the_artist", "q": [ "who made this", "who is the artist", @@ -711,7 +711,7 @@ }, { "a": "Nine of the sculpture's ten granite forms are left rough; one has been shaped into a smoother, more recognizable suitcase form, providing a focal point and interpretive clue to the piece. Recessed lamps in the granite flood the ground with pools of light, making the sculpture particularly striking at night.\n\nThese multiple forms help to remind us of the crowded terminal city that once surrounded this site, and the upturned suitcase hints at those who emptied their suitcases and put down roots, and those who merely passed through.", - "qid": "Terminus: About the art", + "qid": "Terminus:_About_the_art", "q": [ "more about the art", "about the art", @@ -726,7 +726,7 @@ }, { "a": "In July of 1873, a telegram arrived in Tacoma: the small waterfront community had been selected as the terminus of the Northern Pacific Railroad (NPRR). Under a tight deadline to connect the railroad to saltwater, the railroad raced to connect Tacoma to existing rail lines along the Columbia River at Kalama, WA.\n\n Built between the fall and winter of 1873 by a diverse group of laborers, including over 750 Chinese workers who had also worked on the Central Pacific Railroad, the Tacoma-Kalama line was finished with weeks to spare on December 16, 1873. Regular train service began in January of 1874. The Northern Pacific established their first passenger depot at 17th Street and present-day South Hood Street, close to the location of Terminus. \n\nThe final leg of this railroad ran from Tenino to Tacoma, passing through the “burnt prairie” near Olympia. Thus, it became known as the Prairie Line. For roughly a decade, the Prairie Line was the only “game” in town. Rows of brick warehouses lined its tracks.\n\n However, the completion of the rail line into Tacoma didn't immediately bring the boost the city wanted. Tacoma only grew by 283 people between 1875 and 1880. The Tacoma - Kalama line wasn't ideal. To reach the Northern Pacific main line, trains took a ferry — equipped with rails — across the Columbia River. Once in Oregon, the track finally shot eastward toward the plains. But the line wasn't connected to the Midwest unitl 1883, holding Tacoma's growth in check. Tacoma's population began to climb in the mid-1880's, reaching 7,000 people by 1885.\n\n Ask about part 2 of the history for more information.", - "qid": "Terminus: Historical Context Part 1", + "qid": "Terminus:_Historical_Context_Part_1", "q": [ "more about the history", "about the historical context", @@ -746,7 +746,7 @@ }, { "a": " The real boom came after the NPRR completed the Stampede Pass tunnel, a direct route that cut through the mountains of the Cascades to Eastern Washington. By 1890, Tacoma was 36,000 strong.\n\n The Cascade Branch met the Prairie Line at South 15th Street, bringing with it Tacoma's first major surge of passenger traffic. The next wave of newcomers, many of them immigrants, poured into Tacoma. Ethnic enclaves took root in Old Town and west of the Prairie Line on the hill overlooking Commencement Bay. Swedes, Germans, Danes, Italians, Norwegians, Greeks, and Croatians grouped together to ease their transition to America and preserve their culture. Japanese immigrants, arriving by ship, also settled near the rail line, opening hotels and other businesses and creating the Nihonmachi, or Japan Town neighborhood. Many African-Americans who arrived in Tacoma worked for the railroad, and some settled up the hill in a neighborhood that would become known as Hilltop.\n\n In 1911, Union Station replaced the passenger depot on South 17th Street, creating a formal railroad terminal for passengers arriving in Tacoma. ", - "qid": "Terminus: Historical Context Part 2", + "qid": "Terminus:_Historical_Context_Part_2", "q": [ "history part 2", "part 2 of history", @@ -767,7 +767,7 @@ }, { "a": "The next possible destinations are the Swiss Hall, the Washington State History Museum, and the Rails & Rain Garden. Choosing the Swiss Hall or the Washington State History Museum will send you off the main trail, while the Rails & Rain Garden is on the main trail. Which one would you like to go to next?", - "qid": "Branch: Swiss Hall, Washington State History Museum, and Rails & Rain Garden", + "qid": "Branch:_Swiss_Hall,_Washington_State_History_Museum,_and_Rails_&_Rain_Garden", "next": "Branch: Swiss Hall, Washington State History Museum, and Rails & Rain Garden", "q": [ "Branch: Swiss Hall, Washington State History Museum, and Rails & Rain Garden" @@ -784,7 +784,7 @@ }, { "a": "On the terraced hill west of the Prairie Line, immigrant communities formed societies offering support and social events. The Swiss Hall, which is visible from the main steps of the UW Tacoma campus, is one example of these ethnic halls created to host society events. The halls can be found throughout the city. Ask for more about the hall or about other ethnic halls for additional information.", - "qid": "Swiss Hall", + "qid": "Swiss_Hall", "next": "Branch: Washington State History Museum and Rails & Rain Garden", "q": [ "Swiss Hall", @@ -803,7 +803,7 @@ }, { "a": "The Swiss Society built their half-timbered hall between the jobbers' district and the ethnic neighborhoods above Market Street in 1903. The hall's distinctive tower once marked the southern edge of Tacoma's open-air markets. Japanese grocers and merchants lined Market Street to the north, lending the street its name.", - "qid": "Swiss Hall: More about the hall", + "qid": "Swiss_Hall:_More_about_the_hall", "q": [ "more about the hall", "more about the swiss hall", @@ -822,7 +822,7 @@ }, { "a": "The Swiss Society built their half-timbered hall between the jobbers' district and the ethnic neighborhoods above Market Street in 1903. The hall's distinctive tower once marked the southern edge of Tacoma's open-air markets. Japanese grocers and merchants lined Market Street to the north, lending the street its name.", - "qid": "Swiss Hall: Other ethnic halls", + "qid": "Swiss_Hall:_Other_ethnic_halls", "q": [ "more about other ethnic halls", "other ethnic halls", @@ -841,7 +841,7 @@ }, { "a": "The next possible destinations are the Washington State History Museum and the Rails & Rain Garden. The Washington State History Museum is off the main trail, while the Rails & Rain Garden is on the main trail. Which one would you like to go to next?", - "qid": "Branch: Washington State History Museum and Rails & Rain Garden", + "qid": "Branch:_Washington_State_History_Museum_and_Rails_&_Rain_Garden", "next": "Branch: Washington State History Museum and Rails & Rain Garden", "q": [ "Branch: Washington State History Museum and Rails & Rain Garden" @@ -858,7 +858,7 @@ }, { "a": "The Washington State History Museum's interactive exhibits, dynamic storytelling, high-tech displays, and dramatic artifacts bring the state's history to life. The museum also played a key role in revitalizing downtown Tacoma. Ask about the historical context or about \"a new cultural dimension\" for additional information ", - "qid": "Washington State History Museum", + "qid": "Washington_State_History_Museum", "next": "Branch: Swiss Hall and Rails & Rain Garden", "q": [ "Washington State History Museum", @@ -878,7 +878,7 @@ }, { "a": " Initially, the super highway was unkind to downtown Tacoma and countless more urban centers across the country. Suburbs, complete with shopping malls, popped up. Downtown businesses departed. Blight set in. From the 1960's to the early 80's, downtown Tacoma felt deserted.\n\n The jewel of the city, Union Station, sat vacant from 1984 until 1989. Then it was restored and repurposed as a federal courthouse. Nearby, in the Warehouse District, the University of Washington started rehabilitating historic buildings. And I-705 finally connected downtown Tacoma to I-5.", - "qid": "Washington State History Museum: Historical Context", + "qid": "Washington_State_History_Museum:_Historical_Context", "q": [ "more about the history", "about the historical context", @@ -893,7 +893,7 @@ }, { "a": "Amidst this flurry of downtown revitalization came Tacoma's first major museum. The Washington State Historical Society began constructing the History Museum on a site adjacent to Union Station. The museum, designed by architects Charles Moore and Arthur Andersson, imitated the arched facades of the Union Depot. Completed in 1996, the museum fit in well with the historic district.\n\n The History Museum became the first of six museums that, today, comprise Tacoma's Museum District. Featuring world class collections of studio glass, collectible cars, Northwest art, maritime history, and much more, Tacoma's Museum District offers a variety of avenues to explore in one walkable cluster. It's one reason for Tacoma's re-emergence as a thriving cultural and economic hub.\n\nTo learn more, visit the Washington State History Museum's website: http://www.washingtonhistory.org/visit/wshm/ .", - "qid": "Washington State History Museum: A new cultural dimension", + "qid": "Washington_State_History_Museum:_A_new_cultural_dimension", "q": [ "more about other the new cultural dimension", "cultural dimension", @@ -907,7 +907,7 @@ }, { "a": "The next possible destinations are the Washington State History Museum and the Rails & Rain Garden. The Washington State History Museum is off the main trail, while the Rails & Rain Garden is on the main trail. Which one would you like to go to next?", - "qid": "Branch: Swiss Hall and Rails & Rain Garden", + "qid": "Branch:_Swiss_Hall_and_Rails_&_Rain_Garden", "next": "Branch: Swiss Hall and Rails & Rain Garden", "q": [ "Branch: Swiss Hall and Rails & Rain Garden" @@ -924,7 +924,7 @@ }, { "a": "Visitors are often intrigued by this garden-like feature at the south end of the UW segment of the Prairie Line Trail. It has plants, rusty steel brackets and troughs, and often water flowing through it. Is it art? History? A science project? This rain garden could be said to be all three. Ask about the art ,history and science or about the \"End of the Line\" for additional information", - "qid": "Rails & Rain Garden", + "qid": "Rails_&_Rain_Garden", "next": "Heidelberg Complex", "q": [ "Rails & Rain Garden", @@ -945,7 +945,7 @@ }, { "a": "This feature's main practical function is to treat stormwater. In an urban environment, stormwater picks up pollutants. Rain gardens like this one use special plants to filter out pollution before runoff hits major waterways. This rain garden treats stormwater from 42 acres of developed urban space upstream, making sure that water is clean and safe when it joins the Thea Foss Waterway at the bottom of the hill.\n\n Artfully designed to work with the existing railroad tracks, the rain garden also preserves a key piece of Tacoma's history. A close look at the rusty track segments reveals dates. These dates show the last time the tracks were swapped out for maintenance reasons. The last train rumbled over the Prairie Line tracks in Tacoma on the afternoon of March 30, 2003, just under fifty years after these rails were last replaced.", - "qid": "Rails & Rain Garden: Art, history, and science", + "qid": "Rails_&_Rain_Garden:_Art,_history,_and_science", "q": [ "art", "history", @@ -965,7 +965,7 @@ }, { "a": "Closing the book on the Prairie Line opened a new chapter in Tacoma's story — a chapter that harkens back to an earlier time. Historically, a streetcar ran up and down Pacific Avenue. The city brought streetcars back with Tacoma Link light rail in 2003. The historic rail line complicated the intersection of South 17th and Pacific Avenue. To make room for this new rail line, the City and the railroad agreed to phase out the Prairie Line. \n\nVacating the Prairie Line made light rail much more affordable. It also created an opportunity for a multi-modal transportation route through the heart of Tacoma featuring light rail, automobile, pedestrian, and bicycle traffic.\n\n Bonus: Prairie Line Trail connects to the Thea Foss Esplanade and the historic Water Flume Line Trail, creating a multi-district biking and walking trail enhanced with art and history.", - "qid": "Rails & Rain Garden: End of the Line", + "qid": "Rails_&_Rain_Garden:_End_of_the_Line", "q": [ "end of the line", "end line", @@ -979,7 +979,7 @@ }, { "a": "The Columbia – Heidelberg Building produced Northwest beer for three-quarters of a century before shutting down in 1979. In 2016, the historic brewing complex gained a new tenant — 7 Seas Brewing Company — making way for this neighborhood's comeback and an emerging Brewery District.Ask about the beginning, prohibition, or the post-war boom for additional information", - "qid": "Heidelberg Complex", + "qid": "Heidelberg_Complex", "next": "Working Forward, Weaving Anew", "q": [ "Heidelberg Complex", @@ -1000,7 +1000,7 @@ }, { "a": "The Heidelberg Brewing complex, located at 2120-32 South C Street, first housed Columbia Brewing Company. Columbia started in 1900, created by German-born Emil Kliese and William C. Klitz. This wasn't Kleise's first beer venture. He started at Capital Brewing Company in Tumwater, WA. By 1899, Kleise had risen to head brewmaster. Investors approached him about starting a brewery in Tacoma. He signed on.\n\n Tacoma was a thirsty city. At the turn of the century, it boasted 95 different bars. Columbia Brewing rolled out 50 barrels a day to meet demand. They created various brands, including Columbia, Golden Drops, Golden Foam, Old Pilsner, and Alt Heidelberg (“Old Heidelberg”). Tacoma's brewing industry was hopping but the beer bubble was about to burst.", - "qid": "Heidelberg Complex: The beginning", + "qid": "Heidelberg_Complex:_The_beginning", "q": [ "beginning", "the beginning", @@ -1019,7 +1019,7 @@ }, { "a": "Prohibition hit in Washington State in 1916, four years earlier than the nation. Many saloons shut down, but some reinvented themselves as soft drink parlors. Columbia adapted. They started brewing soda: Birch Beer, Green River, Chocolate Soldier, and Blue Jay. They also crafted a “near beer” (non-alcoholic beer).\n\n Columbia Brewing Company became Columbia Breweries Inc. in 1933. Prohibition was over. The company resurrected their Alt Heidelberg brand. The company logo changed too. Its patriotic female figure was out. In came a good-timing character popularized by a play, opera, and silent movie. He was called the Student Prince.", - "qid": "Heidelberg Complex: Prohibition", + "qid": "Heidelberg_Complex:_Prohibition", "q": [ "prohibition", "the prohibition" @@ -1037,7 +1037,7 @@ }, { "a": " The Heidelberg brand proved enduring. In 1949, the company restructured, taking on the named Heidelberg Brewing. It ramped up to meet post-war demand. Kitchy Alt Heidelberg ads blanketed the Northwest, driving up sales.\n\n The company traded hands two more times, but kept the popular Alt Heidelberg brand afloat. In 1976, G. Heileman Brewing Co was expanding in the Northwest, and purchased Columbia-Heidelberg. Heilman had already purchased Rainier Brewing Company in Seattle. The courts ruled that Heilman owned too much of the Northwest beer market, and forced it to part with one of its companies. In 1979, the Columbia-Heidelberg brewery closed for good.\n\n Much of the original Columbia - Heidelberg complex is gone now, but the post-prohibition part of its facility remains. In 2016, the 7 Seas Brewing Company renovated this historic site, creating a brewery, tap room, and multi-use culinary space.", - "qid": "Heidelberg Complex: Post-war boom", + "qid": "Heidelberg_Complex:_Post-war_boom", "q": [ "the post war boom", "post-war boom", @@ -1056,7 +1056,7 @@ }, { "a": "Working Forward, Weaving Anew is a 13,000-square-foot, team-created mural. It intertwines scenes of hand production: Puyallup basket weaving, logging, furniture-building, and present-day weaving, telling a site-specific story of the changing attitudes towards the natural world. \n\n Ask for more about the art, the artist, or the medium for additional information.", - "qid": "Working Forward, Weaving Anew", + "qid": "Working_Forward,_Weaving_Anew", "next": "The Brewery District", "q": [ "Working Forward, Weaving Anew", @@ -1077,7 +1077,7 @@ }, { "a": "Paint and sculpted metal", - "qid": "Working Forward, Weaving Anew: Medium", + "qid": "Working_Forward,_Weaving_Anew:_Medium", "q": [ "Medium", "Material", @@ -1093,7 +1093,7 @@ }, { "a": " Jessilyn Brinkerhoff and Esteban Camacho Steffensen are muralists and collaborative public artists. Their work flows out of conversations, and tells awe-inspiring, larger-than-life stories. In this case, their conversations with local historians and representatives from the Puyallup Tribe inspired this mural, which was conceptualized and refined in 20 different versions of the design.\n\n To create the final mural, the artists used their full artistic arsenal: sketching, painting, photography, and graphic design. As they designed, the artists relied on historic photos, documents, and artifacts to accurately capture and weave together this complex array of stories.\n\n Visit Esteban Camacho Steffensen's website: https://camachosteffensen.blogspot.com/.", - "qid": "Working Forward, Weaving Anew: Meet the artists", + "qid": "Working_Forward,_Weaving_Anew:_Meet_the_artists", "q": [ "who made this", "who is the artist", @@ -1109,7 +1109,7 @@ }, { "a": " Esteban Camacho Steffensen and Jessilyn Brinkerhoff created this mural through an exploration of the history of production in Tacoma, primarily employing images of wood and weaving. Their design includes a Puyallup basket weaver, clearcutting, furniture making, and a person creating a contemporary artwork. All of these forms of production are intimately connected with the history of this place, from the massive cedar trees that once stood along this corridor to the furniture shop that occupied buildings in the surrounding warehouses.\n\n Working Forward, Weaving Anew is a mural designed to honor cultural traditions, the natural environment, and our need for new harmonious and sustainable paths forward into the future. The muralists worked closely with representatives from the Puyallup Tribe to ensure the cultural imagery in their artwork is respectful and accurate. This 50-foot-tall mural was hand painted in a span of 6 weeks with help from a team of nine Native American artists: Bruce Speakthunder Berry, Andrea Bob, Lloyd Neeka Cook, Anthony Duenas, Kanani Miyamoto, Ariella Pool, Elisabeth Tail, Charles Taylor, and Paul Valencia.\n\n View a closeup mural (https://www.youtube.com/watch?v=Uczz83XO4RE) showing the artists at work.", - "qid": "Working Forward, Weaving Anew: About the art", + "qid": "Working_Forward,_Weaving_Anew:_About_the_art", "q": [ "more about the art", "about the art", @@ -1124,7 +1124,7 @@ }, { "a": "Growing rapidly through 1890's and early 1900's, the district hit a roadblock in 1916. Prohibition. Some breweries fell. Others fought through. For the better part of a century, some of the Northwest's most recognizable beers were brewed here. Today, many breweries are capitalizing on these historic warehouses. \n\n Ask for more about the timeline for additional information.", - "qid": "The Brewery District", + "qid": "The_Brewery_District", "next": "End of Tour", "q": [ "The Brewery District", @@ -1146,7 +1146,7 @@ }, { "a": "John D. Scholl and Anton Huth established the Puget Sound Brewery in 1888. They set up shop at 1532 C Street before moving to the corner of Jefferson Avenue and 25th Street.\n\n In 1891, Scholl, Huth, and business partner Peter A. Kalenborn incorporated the Puget Sound Brewing Company with $600,000 in capital stock.\n\n Growth came quickly. Huth soon partnered with Samuel S. Loeb of the Milwaukee Brewing Company in 1897, merging the two companies into Pacific Brewing & Malting Company. Their new location? 2511-15 South Holgate Street.\n\n Columbia Brewing Company, located at 2120-32 South C Street, was formed in 1900 by German-born Emil Kliese and William C. Klitz.\n\n In 1916, the state of Washington prohibited the manufacture and sale of liquor.\n\n Many saloons rebranded as soft drink parlors during prohibition.\n\n In 1949, Heidelberg Brewing purchased Columbia Breweries, Inc. \n\n In 2014, Pacific Brewing & Malting returned (now in the Stadium District and under new ownership).\n\n The 7 Seas Brewing Co. moved into the Heidelberg complex in 2016. Beer is being brewed again at this location for the first time since 1979.", - "qid": "The Brewery District: Timeline", + "qid": "The_Brewery_District:_Timeline", "q": [ "Timeline", "the timeline" diff --git a/source/templates/examples/examples/index.js b/source/templates/examples/examples/index.js index f211b511c..3c3cf8c8e 100644 --- a/source/templates/examples/examples/index.js +++ b/source/templates/examples/examples/index.js @@ -14,7 +14,6 @@ const fs = require('fs'); const _ = require('lodash'); const util = require('../../util'); -const responsebots = require('./responsebots.js').resources; const responsebots_lexv2 = require('./responsebots-lexv2.js').resources; const js = fs.readdirSync(`${__dirname}/js`) @@ -25,6 +24,8 @@ const js = fs.readdirSync(`${__dirname}/js`) return { name: `ExampleJSLambda${name}`, resource: jslambda(name), + logGroupName: `${name}LogGroup`, + logGroupResource: jsLambdaLogGroup(name), id: `${name}JS`, }; }); @@ -38,14 +39,17 @@ const py = fs.readdirSync(`${__dirname}/py`, { withFileTypes: true }) return { name: `ExamplePYTHONLambda${name}`, resource: pylambda(name), + logGroupName: `${name}LogGroup`, + logGroupResource: pyLambdaLogGroup(name), id: `${name}PY`, }; }); module.exports = Object.assign( - responsebots, responsebots_lexv2, + _.fromPairs(js.map((x) => [x.logGroupName, x.logGroupResource])), _.fromPairs(js.map((x) => [x.name, x.resource])), + _.fromPairs(py.map((x) => [x.logGroupName, x.logGroupResource])), _.fromPairs(py.map((x) => [x.name, x.resource])), { FeedbackSNS: { @@ -165,6 +169,30 @@ module.exports = Object.assign( BuildDate: (new Date()).toISOString(), }, }, + ExampleWriteLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ExampleWriteLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ExampleWriteLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -184,6 +212,9 @@ module.exports = Object.assign( } }, Handler: 'cfn.handler', + LoggingConfig: { + LogGroup: { Ref: 'ExampleWriteLambdaLogGroup' }, + }, MemorySize: '128', Role: { Ref: 'CFNLambdaRole' }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -284,24 +315,6 @@ module.exports = Object.assign( ], }, }, - { - PolicyName: 'LexQNALambda', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Action: [ - 'lex:PostText', - ], - Resource: [ - { 'Fn::Join': ['', ['arn:aws:lex:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':bot:*', ':qna*']] }, - { 'Fn::Join': ['', ['arn:aws:lex:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':bot:*', ':QNA*']] }, - ], - }, - ], - }, - }, { PolicyName: 'LambdaQnABotStdExecution', PolicyDocument: { @@ -379,6 +392,9 @@ function jslambda(name) { }, }, Handler: `js/${name}.handler`, + LoggingConfig: { + LogGroup: { Ref: `${name}LogGroup` }, + }, MemorySize: '128', Role: { 'Fn::GetAtt': ['ExampleLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -433,6 +449,9 @@ function pylambda(name) { }, }, Handler: `py/${name}.handler`, + LoggingConfig: { + LogGroup: { Ref: `${name}LogGroup` }, + }, MemorySize: '128', Role: { 'Fn::GetAtt': ['ExampleLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_pythonRuntime, @@ -458,3 +477,59 @@ function pylambda(name) { }, }; } + +function jsLambdaLogGroup(name) { + return { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}' }, + `ExampleJSLambda${name}`, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }; +} + +function pyLambdaLogGroup(name) { + return { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}' }, + `ExamplePYTHONLambda${name}`, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }; +} diff --git a/source/templates/examples/examples/package-lock.json b/source/templates/examples/examples/package-lock.json index c4dd703a6..ac3497f5c 100644 --- a/source/templates/examples/examples/package-lock.json +++ b/source/templates/examples/examples/package-lock.json @@ -1,16 +1,16 @@ { "name": "examples", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "examples", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "cfn-response": "^1.0.1", - "handlebars": "^4.7.7", + "handlebars": "^4.7.8", "lodash": "^4.17.21" } }, @@ -19,19 +19,14 @@ "resolved": "https://registry.npmjs.org/cfn-response/-/cfn-response-1.0.1.tgz", "integrity": "sha1-qOwDlQwGg8UUlejKaA2dwLiEsTc=" }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "optional": true - }, "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", "dependencies": { "minimist": "^1.2.5", - "neo-async": "^2.6.0", + "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, @@ -56,9 +51,10 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" }, "node_modules/source-map": { "version": "0.6.1", @@ -69,13 +65,11 @@ } }, "node_modules/uglify-js": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.4.tgz", - "integrity": "sha512-8RZBJq5smLOa7KslsNsVcSH+KOXf1uDU8yqLeNuVKwmT0T3FA0ZoXlinQfRad7SDcbZZRZE4ov+2v71EnxNyCA==", + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.2.tgz", + "integrity": "sha512-S8KA6DDI47nQXJSi2ctQ629YzwOVs+bQML6DAtvy0wgNdpi+0ySpQK0g2pxBq2xfF2z3YCscu7NNA8nXT9PlIQ==", + "license": "BSD-2-Clause", "optional": true, - "dependencies": { - "commander": "~2.20.3" - }, "bin": { "uglifyjs": "bin/uglifyjs" }, diff --git a/source/templates/examples/examples/package.json b/source/templates/examples/examples/package.json index f3dd40a9d..fa2f87176 100644 --- a/source/templates/examples/examples/package.json +++ b/source/templates/examples/examples/package.json @@ -1,6 +1,6 @@ { "name": "examples", - "version": "6.0.3", + "version": "6.1.0", "description": "Lambda contains a collection of lambda hooks for QnABot and a custom resource to create the example documents", "main": "index.js", "scripts": { @@ -13,7 +13,10 @@ "license": "Apache-2.0", "dependencies": { "cfn-response": "^1.0.1", - "handlebars": "^4.7.7", + "handlebars": "^4.7.8", "lodash": "^4.17.21" + }, + "overrides": { + "uglify-js": "^3.19.2" } } diff --git a/source/templates/examples/examples/py/requirements-dev.txt b/source/templates/examples/examples/py/requirements-dev.txt index 7da7bc821..d94d9ad60 100644 --- a/source/templates/examples/examples/py/requirements-dev.txt +++ b/source/templates/examples/examples/py/requirements-dev.txt @@ -1,4 +1,4 @@ -pytest~=7.4.2 -pytest-cov~=4.1.0 +pytest~=8.3.2 +pytest-cov~=5.0.0 mock~=5.1.0 -boto3==1.26.3 \ No newline at end of file +boto3==1.35.5 \ No newline at end of file diff --git a/source/templates/examples/examples/responsebots.js b/source/templates/examples/examples/responsebots.js deleted file mode 100644 index e30c068c3..000000000 --- a/source/templates/examples/examples/responsebots.js +++ /dev/null @@ -1,2100 +0,0 @@ -/** ******************************************************************************************************************* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * - * * - * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * - * with the License. A copy of the License is located at * - * * - * http://www.apache.org/licenses/ * - * * - * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * - * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * - * and limitations under the License. * - ******************************************************************************************************************** */ - -/** - * - * SlotTypes, Intents, and Bots for elicit response bots. - * - * Warning : Important Note: If you update an Intent or a SlotType, it is mandatory to update the description - * in the associated Bot. Failure to do so when running an update will leave the bot in the NOT_BUILT state and you - * will need to rebuild in the AWS Console. To update description for all bots, change botDateVersion string below. - */ -const botDateVersion = `${process.env.npm_package_version} - v1`; // CHANGE ME TO FORCE BOT REBUILD - -const _ = require('lodash'); - -const config = { - voiceId: 'Joanna', - Clarification: 'Sorry, can you please repeat that?', - Abort: 'Sorry, I could not understand. Please start again.', - utterances: require('../../../assets/default-utterances'), -}; - -exports.resources = { - WageSlotType: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexSlotType', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAWageSlotType-${AWS::StackName}' }, - createVersion: true, - description: `QNA Wage Slot Type - ${botDateVersion}`, - parentSlotTypeSignature: 'AMAZON.AlphaNumeric', - slotTypeConfigurations: [ - { - regexConfiguration: { - pattern: '[0-9]{1,7}', - }, - }, - ], - }, - }, - QNAWage: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'WageIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAWageBot-${AWS::StackName}' }, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'WageIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat your wage.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - description: `QNA Wage elicit response - ${botDateVersion}`, - }, - }, - WageIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAWageIntent-${AWS::StackName}' }, - createVersion: true, - description: `QNA Wage Intent - ${botDateVersion}`, - sampleUtterances: [ - 'My salary is {Wage}', - 'My wage is {Wage}', - '{Wage}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - confirmationPrompt: { - maxAttempts: 1, - messages: [ - { - content: 'Is {Wage} correct (Yes/No)?', - contentType: 'PlainText', - }, - ], - }, - rejectionStatement: { - messages: [ - { - content: 'Please let me know what your wage was again.', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'Wage', - slotType: { Ref: 'WageSlotType' }, - slotTypeVersion: 'QNABOT-AUTO-ASSIGNED', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What is your wage?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - WageAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNAWage', - }, - name: 'live', - description: `QNA Wage Alias - ${botDateVersion}`, - }, - }, - SocialSecuritySlotType: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexSlotType', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNASocialSecuritySlotType-${AWS::StackName}' }, - createVersion: true, - description: `QNA Social Security Slot Type - ${botDateVersion}`, - parentSlotTypeSignature: 'AMAZON.AlphaNumeric', - slotTypeConfigurations: [ - { - regexConfiguration: { - pattern: '[0-9]{3}-[0-9]{2}-[0-9]{4}', - }, - }, - ], - }, - }, - QNASocialSecurity: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'SocialSecurityIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNASocialSecurityBot-${AWS::StackName}' }, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'SocialSecurityIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat your social security number.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - description: `QNA Social Security elicit response - ${botDateVersion}`, - }, - }, - SocialSecurityIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNASocialSecurityIntent-${AWS::StackName}' }, - createVersion: true, - description: `QNA Social Security Intent - ${botDateVersion}`, - sampleUtterances: [ - 'The social security number is {SSN}', - 'My social security number is {SSN}', - 'It is {SSN}', - '{SSN}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - confirmationPrompt: { - maxAttempts: 1, - messages: [ - { - content: 'Is {SSN} correct (Yes/No)?', - contentType: 'PlainText', - }, - ], - }, - rejectionStatement: { - messages: [ - { - content: 'Please let me know the social security number again.', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'SSN', - slotType: { Ref: 'SocialSecuritySlotType' }, - slotTypeVersion: 'QNABOT-AUTO-ASSIGNED', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What is your social security number?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - SocialSecurityAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNASocialSecurity', - }, - name: 'live', - description: `QNA Social Security Alias - ${botDateVersion}`, - }, - }, - PinSlotType: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexSlotType', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAPinSlotType-${AWS::StackName}' }, - description: `QNA Pin Slot Type - ${botDateVersion}`, - parentSlotTypeSignature: 'AMAZON.AlphaNumeric', - createVersion: true, - slotTypeConfigurations: [ - { - regexConfiguration: { - pattern: '[0-9]{4}', - }, - }, - ], - }, - }, - QNAPin: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'PinIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAPinBot-${AWS::StackName}' }, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'PinIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'I\'m sorry I did not get all the digits, please re-enter all digits.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - description: `QNA Pin elicit response - ${botDateVersion}`, - }, - }, - PinIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAPinIntent-${AWS::StackName}' }, - description: `QNA Pin Intent - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'The pin number is {Pin}', - 'My pin number is {Pin}', - 'It is {Pin}', - '{Pin}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - confirmationPrompt: { - maxAttempts: 1, - messages: [ - { - content: 'Is {Pin} correct (Yes or No)?', - contentType: 'PlainText', - }, - ], - }, - rejectionStatement: { - messages: [ - { - content: 'I\'m sorry I did not get all the digits, please re-enter all digits.', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'Pin', - slotType: { Ref: 'PinSlotType' }, - slotTypeVersion: 'QNABOT-AUTO-ASSIGNED', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What are all the digits?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - PinAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNAPin', - }, - name: 'live', - description: `QNA Pin Alias - ${botDateVersion}`, - }, - }, - QNAPinNoConfirm: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'PinIntentNoConfirm', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAPinBotNoConfirm-${AWS::StackName}' }, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'PinIntentNoConfirm' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'I\'m sorry I did not get all the digits, please re-enter all digits.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - description: `QNA Pin No Confirm elicit response - ${botDateVersion}`, - }, - }, - PinIntentNoConfirm: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAPinIntentNoConfirm-${AWS::StackName}' }, - description: `QNA Pin Intent No Confirm - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'The pin number is {Pin}', - 'My pin number is {Pin}', - 'It is {Pin}', - '{Pin}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'Pin', - slotType: { Ref: 'PinSlotType' }, - slotTypeVersion: 'QNABOT-AUTO-ASSIGNED', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What are all the digits?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - PinNoConfirmAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNAPinNoConfirm', - }, - name: 'live', - description: `QNA Pin No Confirm Alias - ${botDateVersion}`, - }, - }, - YesNoSlotType: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexSlotType', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAYesNoSlotType-${AWS::StackName}' }, - description: `QNA Yes No Slot Type - ${botDateVersion}`, - createVersion: true, - valueSelectionStrategy: 'TOP_RESOLUTION', - enumerationValues: [ - { value: 'Yes', synonyms: ['yes', 'ok', 'yeah', 'sure', 'yep', 'affirmative', 'aye', 'correct', '1', 'one'] }, - { value: 'No', synonyms: ['no', 'nope', 'na', 'negative', 'non', '2', 'two'] }, - ], - }, - }, - YesNoIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAYesNoIntent-${AWS::StackName}' }, - createVersion: true, - description: `QNA Yes No Intent - ${botDateVersion}`, - sampleUtterances: [ - '{Yes_No}', - 'I said {Yes_No}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'Yes_No', - slotType: { Ref: 'YesNoSlotType' }, - slotTypeVersion: 'QNABOT-AUTO-ASSIGNED', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Say Yes or No.', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNAYesNo: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: ['YesNoSlotType', 'YesNoIntent'], - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAYesNoBot-${AWS::StackName}' }, - description: `QNA Yes No Bot - ${botDateVersion}`, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'YesNoIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat - say Yes or No.', - }, - ], - maxAttempts: 5, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - }, - }, - YesNoAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNAYesNo', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNAYesNo', - }, - name: 'live', - description: `QNA Yes No Alias - ${botDateVersion}`, - }, - }, - YesNoExitSlotType: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexSlotType', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAYesNoExitSlotType-${AWS::StackName}' }, - description: `QNA Yes No Exit Slot Type - ${botDateVersion}`, - createVersion: true, - valueSelectionStrategy: 'TOP_RESOLUTION', - enumerationValues: [ - { value: 'Yes', synonyms: ['yes', 'ok', 'yeah', 'sure', 'yep', 'affirmative', 'aye', 'correct', '1', 'one'] }, - { value: 'No', synonyms: ['no', 'nope', 'na', 'negative', 'non', '2', 'two'] }, - { value: 'Exit', synonyms: ['exit', 'agent', 'rep', 'representative', 'stop', 'quit', 'help', 'bye', 'goodbye', '3', 'three'] }, - ], - }, - }, - YesNoExitIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAYesNoExitIntent-${AWS::StackName}' }, - createVersion: true, - description: `QNA Yes No Exit Intent - ${botDateVersion}`, - sampleUtterances: [ - '{Yes_No_Exit}', - 'I said {Yes_No_Exit}', - ], - conclusionStatement: { - messages: [ - { - content: 'Ok. ', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'Yes_No_Exit', - slotType: { Ref: 'YesNoExitSlotType' }, - slotTypeVersion: 'QNABOT-AUTO-ASSIGNED', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Say Yes, No, or Exit.', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNAYesNoExit: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: ['YesNoExitSlotType', 'YesNoExitIntent'], - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAYesNoExitBot-${AWS::StackName}' }, - description: `QNA Yes No Exit Bot - ${botDateVersion}`, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'YesNoExitIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat - say Yes or No. You can also say exit, agent, quit, or bye to leave.', - }, - ], - maxAttempts: 5, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - }, - }, - YesNoExitAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNAYesNoExit', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNAYesNoExit', - }, - name: 'live', - description: `QNA Yes No Exit Alias - ${botDateVersion}`, - }, - }, - DateIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNADateIntent-${AWS::StackName}' }, - createVersion: true, - description: `QNA DateIntent - ${botDateVersion}`, - sampleUtterances: [ - 'The date is {date}', - 'The date was {date}', - 'I went on {date}', - 'It is {date}', - 'It occurred on {date}', - 'I was born on {date}', - 'My birthdate is {date}', - 'My date of birth is {date}', - '{date}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - confirmationPrompt: { - maxAttempts: 1, - messages: [ - { - content: 'Is {date} correct (Yes or No)?', - contentType: 'PlainText', - }, - ], - }, - rejectionStatement: { - messages: [ - { - content: 'Please let me know the date again.', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'date', - slotType: 'AMAZON.DATE', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What date?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNADate: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'DateIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNADateBot-${AWS::StackName}' }, - description: `QNA Date Bot - ${botDateVersion}`, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'DateIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat the date.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - }, - }, - DateAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNADate', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNADate', - }, - name: 'live', - description: `QNA Date Alias - ${botDateVersion}`, - }, - }, - DateIntentNoConfirm: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNADateIntentNoConfirm-${AWS::StackName}' }, - createVersion: true, - description: `QNA DateIntentNoConfirm - ${botDateVersion}`, - sampleUtterances: [ - 'The date is {date}', - 'The date was {date}', - 'I went on {date}', - 'It is {date}', - 'It occurred on {date}', - 'I was born on {date}', - 'My birthdate is {date}', - 'My date of birth is {date}', - '{date}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'date', - slotType: 'AMAZON.DATE', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What date?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNADateNoConfirm: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'DateIntentNoConfirm', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNADateBotNoConfirm-${AWS::StackName}' }, - description: `QNA Date Bot No Confirm - ${botDateVersion}`, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'DateIntentNoConfirm' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat the date.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - }, - }, - DateAliasNoConfirmV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNADateNoConfirm', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNADateNoConfirm', - }, - name: 'live', - description: `QNA Date No Confirm Alias - ${botDateVersion}`, - }, - }, - DayOfWeekIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNADayOfWeekIntent-${AWS::StackName}' }, - description: `QNA Day Of Week Intent - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'The day is {DayOfWeek}', - 'The day was {DayOfWeek}', - 'I went on {DayOfWeek}', - 'It is {DayOfWeek}', - 'It occurred on {DayOfWeek}', - '{DayOfWeek}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - confirmationPrompt: { - maxAttempts: 1, - messages: [ - { - content: 'Is {DayOfWeek} correct (Yes or No)?', - contentType: 'PlainText', - }, - ], - }, - rejectionStatement: { - messages: [ - { - content: 'Please let me know the day again.', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'DayOfWeek', - slotType: 'AMAZON.DayOfWeek', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What day?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNADayOfWeek: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'DayOfWeekIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNADayOfWeekBot-${AWS::StackName}' }, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'DayOfWeekIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat the day of the week.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - description: `QNADayOfWeek bot - ${botDateVersion}`, - }, - }, - DayOfWeekAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNADayOfWeek', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNADayOfWeek', - }, - name: 'live', - description: `QNA Day Of Week Alias - ${botDateVersion}`, - }, - }, - MonthIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAMonthIntent-${AWS::StackName}' }, - description: `QNA Month Intent - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'The month is {Month}', - 'The month was {Month}', - 'It is {Month}', - 'It occurred on {Month}', - '{Month}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - confirmationPrompt: { - maxAttempts: 1, - messages: [ - { - content: 'Is {Month} correct (Yes or No)?', - contentType: 'PlainText', - }, - ], - }, - rejectionStatement: { - messages: [ - { - content: 'Please let me know the month again.', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'Month', - slotType: 'AMAZON.Month', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What month?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNAMonth: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'MonthIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAMonthBot-${AWS::StackName}' }, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'MonthIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat the month.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - description: `QNA Month Bot - ${botDateVersion}`, - }, - }, - MonthAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNAMonth', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNAMonth', - }, - name: 'live', - description: `QNA Month Alias - ${botDateVersion}`, - }, - }, - MonthIntentNoConfirm: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAMonthIntentNoConfirm-${AWS::StackName}' }, - description: `QNA Month Intent No Confirm - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'The month is {Month}', - 'The month was {Month}', - 'It is {Month}', - 'It occurred on {Month}', - '{Month}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'Month', - slotType: 'AMAZON.Month', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What month?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNAMonthNoConfirm: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'MonthIntentNoConfirm', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAMonthBotNoConfirm-${AWS::StackName}' }, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'MonthIntentNoConfirm' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat the month.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - description: `QNA Month Bot No Confirm - ${botDateVersion}`, - }, - }, - MonthAliasNoConfirmV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNAMonthNoConfirm', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNAMonthNoConfirm', - }, - name: 'live', - description: `QNA Month Alias No Confirm - ${botDateVersion}`, - }, - }, - NumberIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNANumberIntent-${AWS::StackName}' }, - description: `QNA Number Intent - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'The number is {Number}', - 'The number was {Number}', - 'It is {Number}', - '{Number}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - confirmationPrompt: { - maxAttempts: 1, - messages: [ - { - content: 'Is {Number} correct (Yes or No)?', - contentType: 'PlainText', - }, - ], - }, - rejectionStatement: { - messages: [ - { - content: 'Please let me know the number again.', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'Number', - slotType: 'AMAZON.NUMBER', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What number?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNANumber: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'NumberIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNANumberBot-${AWS::StackName}' }, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'NumberIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat the number.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - description: `QNA Number Bot - ${botDateVersion}`, - }, - }, - NumberAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNANumber', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNANumber', - }, - name: 'live', - description: `QNA Number Alias - ${botDateVersion}`, - }, - }, - NumberIntentNoConfirm: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNANumberIntentNoConfirm-${AWS::StackName}' }, - description: `QNA Number Intent No Confirm - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'The number is {Number}', - 'The number was {Number}', - 'It is {Number}', - '{Number}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'Number', - slotType: 'AMAZON.NUMBER', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What number?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNANumberNoConfirm: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'NumberIntentNoConfirm', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNANumberBotNoConfirm-${AWS::StackName}' }, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'NumberIntentNoConfirm' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat the number.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - description: `QNA Number Bot No Confirm - ${botDateVersion}`, - }, - }, - NumberAliasNoConfirmV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNANumberNoConfirm', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNANumberNoConfirm', - }, - name: 'live', - description: `QNA Number Alias No Confirm - ${botDateVersion}`, - }, - }, - AgeIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAAgeIntent-${AWS::StackName}' }, - description: `QNA Age Intent - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'My age is {Age}', - 'Age is {Age}', - 'It is {Age}', - 'I am {Age}', - 'I am {Age} years old', - 'His age is {Age}', - 'He is {Age}', - 'He is {Age} years old', - 'Her age is {Age}', - 'She is {Age}', - 'She is {Age} years old', - '{Age}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - confirmationPrompt: { - maxAttempts: 1, - messages: [ - { - content: 'Is {Age} correct (Yes or No)?', - contentType: 'PlainText', - }, - ], - }, - rejectionStatement: { - messages: [ - { - content: 'Please let me know the age again.', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'Age', - slotType: 'AMAZON.NUMBER', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What age?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNAAge: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'AgeIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAAgeBot-${AWS::StackName}' }, - description: `QNA Age Bot - ${botDateVersion}`, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'AgeIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat the age.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - }, - }, - AgeAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNAAge', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNAAge', - }, - name: 'live', - description: `QNA Age Alias - ${botDateVersion}`, - }, - }, - PhoneNumberIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAPhoneNumberIntent-${AWS::StackName}' }, - description: `QNA Phone Number Intent - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'The phone number is {PhoneNumber}', - 'My phone number is {PhoneNumber}', - 'It is {PhoneNumber}', - '{PhoneNumber}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - confirmationPrompt: { - maxAttempts: 1, - messages: [ - { - // QnABot always uses postText to interact with response bot, however, it supports embedded SSML tags in - // the confirmation prompt so that speech back to Alexa or Lex client in postContent mode. - // SSML tags are automatically stripped by QnABot for text mode clients. - content: 'Is {PhoneNumber} correct (Yes or No)?', - contentType: 'PlainText', - }, - ], - }, - rejectionStatement: { - messages: [ - { - content: 'Please let me know the phone number again.', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'PhoneNumber', - slotType: 'AMAZON.PhoneNumber', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What phone number?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNAPhoneNumber: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'PhoneNumberIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAPhoneNumberBot-${AWS::StackName}' }, - description: `QNA Phone Number Bot - ${botDateVersion}`, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'PhoneNumberIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat the phone number.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - }, - }, - PhoneNumberAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNAPhoneNumber', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNAPhoneNumber', - }, - name: 'live', - description: `QNA Phone Number Alias - ${botDateVersion}`, - }, - }, - PhoneNumberIntentNoConfirm: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAPhoneNumberIntentNoConfirm-${AWS::StackName}' }, - description: `QNA Phone Number Intent No Confirm - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'The phone number is {PhoneNumber}', - 'My phone number is {PhoneNumber}', - 'It is {PhoneNumber}', - '{PhoneNumber}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'PhoneNumber', - slotType: 'AMAZON.PhoneNumber', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What phone number?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNAPhoneNumberNoConfirm: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'PhoneNumberIntentNoConfirm', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAPhoneNumberBotNoConfirm-${AWS::StackName}' }, - description: `QNA Phone Number Bot No Confirm - ${botDateVersion}`, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'PhoneNumberIntentNoConfirm' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat the phone number.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - }, - }, - PhoneNumberAliasNoConfirmV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNAPhoneNumberNoConfirm', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNAPhoneNumberNoConfirm', - }, - name: 'live', - description: `QNA Phone Number Alias No Confirm - ${botDateVersion}`, - }, - }, - TimeIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNATimeIntent-${AWS::StackName}' }, - description: `QNA Time Intent - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'The time was {Time}', - 'It occurred at {Time}', - 'At {Time}', - '{Time}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - confirmationPrompt: { - maxAttempts: 1, - messages: [ - { - content: 'Is {Time} correct (Yes or No)?', - contentType: 'PlainText', - }, - ], - }, - rejectionStatement: { - messages: [ - { - content: 'Please let me know the time again.', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'Time', - slotType: 'AMAZON.TIME', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What time?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNATime: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'TimeIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNATimeBot-${AWS::StackName}' }, - description: `QNA Time Bot - ${botDateVersion}`, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'TimeIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat the time, specifying am or pm.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - }, - }, - TimeAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNATime', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNATime', - }, - name: 'live', - description: `QNA Time Alias - ${botDateVersion}`, - }, - }, - EmailAddressIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAEmailAddressIntent-${AWS::StackName}' }, - description: `QNA Email Address Intent - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'My email address is {EmailAddress}', - 'The email address is {EmailAddress}', - '{EmailAddress}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - confirmationPrompt: { - maxAttempts: 1, - messages: [ - { - content: 'Is {EmailAddress} correct (Yes or No)?', - contentType: 'PlainText', - }, - ], - }, - rejectionStatement: { - messages: [ - { - content: 'Please let me know the email address again.', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'EmailAddress', - slotType: 'AMAZON.EmailAddress', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What email address?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNAEmailAddress: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'EmailAddressIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNAEmailAddressBot-${AWS::StackName}' }, - description: `QNA Email Address Intent - ${botDateVersion}`, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'EmailAddressIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat the email address.', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - }, - }, - EmailAddressAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNAEmailAddress', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNAEmailAddress', - }, - name: 'live', - description: `QNA Email Address Alias - ${botDateVersion}`, - }, - }, - NameIntent: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNANameIntent-${AWS::StackName}' }, - description: `QNA Name Intent - ${botDateVersion}`, - createVersion: true, - sampleUtterances: [ - 'My last name is {LastName}', - 'My first name is {FirstName}', - 'My first name is {FirstName} and My last name is {LastName}', - 'My name is {FirstName} {LastName}', - 'I am {FirstName} {LastName}', - '{FirstName} {LastName}', - '{FirstName}', - '{LastName}', - ], - conclusionStatement: { - messages: [ - { - content: 'OK. ', - contentType: 'PlainText', - }, - ], - }, - confirmationPrompt: { - maxAttempts: 1, - messages: [ - { - content: 'Did I get your name right (Yes or No) {FirstName} {LastName}?', - contentType: 'PlainText', - }, - ], - }, - rejectionStatement: { - messages: [ - { - content: 'Please let me know your name again.', - contentType: 'PlainText', - }, - ], - }, - fulfillmentActivity: { - type: 'ReturnIntent', - }, - slots: [ - { - name: 'FirstName', - slotType: 'AMAZON.US_FIRST_NAME', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What is your first name?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - { - name: 'LastName', - slotType: 'AMAZON.US_LAST_NAME', - slotConstraint: 'Required', - valueElicitationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'What is your last name?', - }, - ], - maxAttempts: 2, - }, - priority: 1, - }, - ], - }, - }, - QNAName: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexBot', - DependsOn: 'NameIntent', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - name: { 'Fn::Sub': 'QNANameBot-${AWS::StackName}' }, - description: `QNA Name Bot - ${botDateVersion}`, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'NameIntent' } }, - ], - clarificationPrompt: { - messages: [ - { - contentType: 'PlainText', - content: 'Please repeat your first and last name?', - }, - ], - maxAttempts: 3, - }, - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - }, - }, - NameAliasV2: { - Condition: 'CreateLexV1ResponseBots', - Type: 'Custom::LexAlias', - DependsOn: 'QNAName', - Properties: { - ServiceToken: { Ref: 'CFNLambda' }, - botName: { - Ref: 'QNAName', - }, - name: 'live', - description: `QNA Name Alias - ${botDateVersion}`, - }, - }, -}; - -exports.names = [ - 'QNAYesNo', 'QNAYesNoExit', 'QNADate', 'QNADateNoConfirm', 'QNADayOfWeek', 'QNAMonth', 'QNAMonthNoConfirm', - 'QNANumber', 'QNANumberNoConfirm', 'QNAAge', 'QNAPhoneNumber', 'QNAPhoneNumberNoConfirm', - 'QNATime', 'QNAEmailAddress', 'QNAName', 'QNAWage', 'QNASocialSecurity', 'QNAPin', 'QNAPinNoConfirm', -]; - -exports.outputs = _.fromPairs(exports.names.map((x) => [x, { Value: { 'Fn::If': ['CreateLexV1ResponseBots', { Ref: x }, 'LexV2 only'] } }])); diff --git a/source/templates/examples/extensions/index.js b/source/templates/examples/extensions/index.js index e45d7ef3b..952474db5 100644 --- a/source/templates/examples/extensions/index.js +++ b/source/templates/examples/extensions/index.js @@ -23,6 +23,8 @@ const js = fs.readdirSync(`${__dirname}/js_lambda_hooks`) resource: jslambda(name), codeVersionName: `CodeVersion${name}`, codeVersionResource: codeVersion(name), + logGroupName: `${name}LogGroup`, + logGroupResource: lambdaLogGroup(name), id: `${name}JS`, }; } @@ -34,13 +36,15 @@ const py = fs.readdirSync(`${__dirname}/py_lambda_hooks`) resource: pylambda(name), codeVersionName: `CodeVersion${name}`, codeVersionResource: codeVersion(name), + logGroupName: `${name}LogGroup`, + logGroupResource: lambdaLogGroup(name), id: `${name}PY`, })); const lambda_hooks = js.concat(py); -// NOTICE: Canvas LMS integration with QnABot on AWS is deprecated in this release and no longer be supported. Customers may fork the code needed for their specific use case from previous versions. The integration code will be removed in the next release.(QnASecretsManagerLambda) module.exports = Object.assign( + _.fromPairs(lambda_hooks.map((x) => [x.logGroupName, x.logGroupResource])), _.fromPairs(lambda_hooks.map((x) => [x.name, x.resource])), _.fromPairs(lambda_hooks.map((x) => [x.codeVersionName, x.codeVersionResource])), { @@ -56,6 +60,30 @@ module.exports = Object.assign( }, ), }, + EXTUiImportLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-EXTUiImportLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, EXTUiImportLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -75,6 +103,9 @@ module.exports = Object.assign( }, }, Handler: 'ui_import.handler', + LoggingConfig: { + LogGroup: { Ref: 'EXTUiImportLambdaLogGroup' }, + }, MemorySize: '128', Role: { Ref: 'CFNLambdaRole' }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -219,44 +250,7 @@ module.exports = Object.assign( ], }, }, - { - PolicyName: 'LexQNALambda', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Action: [ - 'lex:PostText', - ], - Resource: [ - { 'Fn::Join': ['', ['arn:aws:lex:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':bot:*', ':qna*']] }, - { 'Fn::Join': ['', ['arn:aws:lex:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':bot:*', ':QNA*']] }, - ], - }, - ], - }, - }, - { - PolicyName: 'QNASecretsManagerLambda', - PolicyDocument: { - Version: '2012-10-17', - Statement: [ - { - Effect: 'Allow', - Action: [ - 'secretsmanager:GetResourcePolicy', - 'secretsmanager:GetSecretValue', - 'secretsmanager:DescribeSecret', - ], - Resource: [ - { 'Fn::Join': ['', ['arn:aws:secretsmanager:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':secret:qna-*']] }, - { 'Fn::Join': ['', ['arn:aws:secretsmanager:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':secret:QNA-*']] }, - ], - }, - ], - }, - }], + ], }, Metadata: { cfn_nag: util.cfnNag(['W11', 'W12']), @@ -288,6 +282,9 @@ function jslambda(name) { }, }, Handler: `${name}.handler`, + LoggingConfig: { + LogGroup: { Ref: `${name}LogGroup` }, + }, MemorySize: '2048', Role: { 'Fn::GetAtt': ['ExtensionLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -342,6 +339,9 @@ function pylambda(name) { }, }, Handler: `${name}.handler`, + LoggingConfig: { + LogGroup: { Ref: `${name}LogGroup` }, + }, MemorySize: '2048', Role: { 'Fn::GetAtt': ['ExtensionLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_pythonRuntime, @@ -379,3 +379,31 @@ function codeVersion(name) { }, }; } + +function lambdaLogGroup(name) { + return { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}' }, + `EXT${name}`, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }; +} diff --git a/source/templates/examples/extensions/js_lambda_hooks/CreateRecentTopicsResponse/package-lock.json b/source/templates/examples/extensions/js_lambda_hooks/CreateRecentTopicsResponse/package-lock.json index 367e6a19c..386998f83 100644 --- a/source/templates/examples/extensions/js_lambda_hooks/CreateRecentTopicsResponse/package-lock.json +++ b/source/templates/examples/extensions/js_lambda_hooks/CreateRecentTopicsResponse/package-lock.json @@ -1,12 +1,12 @@ { "name": "createrecenttopicsresponse", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "createrecenttopicsresponse", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "lodash": "^4.17.21" diff --git a/source/templates/examples/extensions/js_lambda_hooks/CreateRecentTopicsResponse/package.json b/source/templates/examples/extensions/js_lambda_hooks/CreateRecentTopicsResponse/package.json index 3b0045736..0abab4666 100644 --- a/source/templates/examples/extensions/js_lambda_hooks/CreateRecentTopicsResponse/package.json +++ b/source/templates/examples/extensions/js_lambda_hooks/CreateRecentTopicsResponse/package.json @@ -1,6 +1,6 @@ { "name": "createrecenttopicsresponse", - "version": "6.0.3", + "version": "6.1.0", "description": "Lambda hook that creates recent topic response", "main": "CreateRecentTopicResponse.js", "scripts": { diff --git a/source/templates/examples/extensions/js_lambda_hooks/CustomJSHook/package-lock.json b/source/templates/examples/extensions/js_lambda_hooks/CustomJSHook/package-lock.json index c04d69a0d..13615eea6 100644 --- a/source/templates/examples/extensions/js_lambda_hooks/CustomJSHook/package-lock.json +++ b/source/templates/examples/extensions/js_lambda_hooks/CustomJSHook/package-lock.json @@ -1,16 +1,16 @@ { "name": "examples", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "examples", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "cfn-response": "^1.0.1", - "handlebars": "^4.7.7", + "handlebars": "^4.7.8", "lodash": "^4.17.21" } }, @@ -19,19 +19,14 @@ "resolved": "https://registry.npmjs.org/cfn-response/-/cfn-response-1.0.1.tgz", "integrity": "sha1-qOwDlQwGg8UUlejKaA2dwLiEsTc=" }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "optional": true - }, "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", "dependencies": { "minimist": "^1.2.5", - "neo-async": "^2.6.0", + "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, @@ -56,9 +51,10 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" }, "node_modules/source-map": { "version": "0.6.1", @@ -69,13 +65,11 @@ } }, "node_modules/uglify-js": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.4.tgz", - "integrity": "sha512-8RZBJq5smLOa7KslsNsVcSH+KOXf1uDU8yqLeNuVKwmT0T3FA0ZoXlinQfRad7SDcbZZRZE4ov+2v71EnxNyCA==", + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.2.tgz", + "integrity": "sha512-S8KA6DDI47nQXJSi2ctQ629YzwOVs+bQML6DAtvy0wgNdpi+0ySpQK0g2pxBq2xfF2z3YCscu7NNA8nXT9PlIQ==", + "license": "BSD-2-Clause", "optional": true, - "dependencies": { - "commander": "~2.20.3" - }, "bin": { "uglifyjs": "bin/uglifyjs" }, @@ -95,21 +89,15 @@ "resolved": "https://registry.npmjs.org/cfn-response/-/cfn-response-1.0.1.tgz", "integrity": "sha1-qOwDlQwGg8UUlejKaA2dwLiEsTc=" }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "optional": true - }, "handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "requires": { "minimist": "^1.2.5", - "neo-async": "^2.6.0", + "neo-async": "^2.6.2", "source-map": "^0.6.1", - "uglify-js": "^3.1.4", + "uglify-js": "^3.19.2", "wordwrap": "^1.0.0" } }, @@ -124,9 +112,9 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "source-map": { "version": "0.6.1", @@ -134,13 +122,10 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "uglify-js": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.4.tgz", - "integrity": "sha512-8RZBJq5smLOa7KslsNsVcSH+KOXf1uDU8yqLeNuVKwmT0T3FA0ZoXlinQfRad7SDcbZZRZE4ov+2v71EnxNyCA==", - "optional": true, - "requires": { - "commander": "~2.20.3" - } + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.2.tgz", + "integrity": "sha512-S8KA6DDI47nQXJSi2ctQ629YzwOVs+bQML6DAtvy0wgNdpi+0ySpQK0g2pxBq2xfF2z3YCscu7NNA8nXT9PlIQ==", + "optional": true }, "wordwrap": { "version": "1.0.0", diff --git a/source/templates/examples/extensions/js_lambda_hooks/CustomJSHook/package.json b/source/templates/examples/extensions/js_lambda_hooks/CustomJSHook/package.json index c179c1761..84e9e85ac 100644 --- a/source/templates/examples/extensions/js_lambda_hooks/CustomJSHook/package.json +++ b/source/templates/examples/extensions/js_lambda_hooks/CustomJSHook/package.json @@ -1,6 +1,6 @@ { "name": "examples", - "version": "6.0.3", + "version": "6.1.0", "description": "Creates custom JS Lambda Hooks", "main": "index.js", "scripts": { @@ -13,7 +13,10 @@ "license": "Apache-2.0", "dependencies": { "cfn-response": "^1.0.1", - "handlebars": "^4.7.7", + "handlebars": "^4.7.8", "lodash": "^4.17.21" + }, + "overrides": { + "uglify-js": "^3.19.2" } } diff --git a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/CanvasLMSHelper.py b/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/CanvasLMSHelper.py deleted file mode 100644 index 737153402..000000000 --- a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/CanvasLMSHelper.py +++ /dev/null @@ -1,496 +0,0 @@ -###################################################################################################################### -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # -# # -# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance # -# with the License. A copy of the License is located at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES # -# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions # -# and limitations under the License. # -###################################################################################################################### - -# NOTICE: Canvas LMS integration with QnABot on AWS is deprecated in this release and no longer be supported. Customers may fork the code needed for their specific use case from previous versions. The integration code will be removed in the next release. - -import json -import os -import boto3 -import base64 -import datetime -import calendar -from botocore import config - -from bs4 import BeautifulSoup -from botocore.exceptions import ClientError - -CONTENT_TYPE = 'application/vnd.amazonaws.card.generic' -TITLE = 'response buttons' -SSML_PREOUTPUT = 'Please select one of these options: ' -NOT_FOUND_RESP = 'Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in, to get a list of enrolled courses.' - -def get_secret(secrets_name): - """ - function: get_secret from AWS Secrets Manager - This function retrieves the secret string from AWS Secrets Manager. - We will retrieve the Canvas API Token using this function. - Refer to the readme for more details on how to store secret in AWS Secrets Manager, and configure QnABot with the secret key name. - """ - - region_name = os.environ['AWS_REGION'] - - # Create a Secrets Manager client - session = boto3.session.Session() - client = session.client( - service_name='secretsmanager', - config= config.Config(region_name=region_name, - user_agent_extra = f"AWSSOLUTION/{os.environ['SOLUTION_ID']}/{os.environ['SOLUTION_VERSION']} AWSSOLUTION-CAPABILITY/{os.environ['SOLUTION_ID']}-C018/{os.environ['SOLUTION_VERSION']}")) - - # In this sample we only handle the specific exceptions for the 'GetSecretValue' API. - # See https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html - # We rethrow the exception by default. - - try: - get_secret_value_response = client.get_secret_value( - SecretId=secrets_name - ) - # Decrypts secret using the associated KMS CMK. - # Depending on whether the secret is a string or binary, one of these fields will be populated. - if 'SecretString' in get_secret_value_response: - secret = get_secret_value_response['SecretString'] - secret = json.loads(get_secret_value_response['SecretString'])['API_Token'] - else: - decoded_binary_secret = base64.b64decode(get_secret_value_response['SecretBinary']) - secret = decoded_binary_secret.API_Token - except ClientError as e: - print ("ERROR: "+ str(e)) #print the exception - raise e - - #return the API token - return secret - - -def get_canvas_user (param_canvas, param_user_name): - """ - function to get Canvas User - This function retrieves the Canvas user by using the SIS Login ID - """ - - user = param_canvas.get_user(param_user_name, 'sis_login_id') - return user - - -def query_menu (event, student_name): # NOSONAR param passed from upstream - """ - function to get menu - """ - - # provide a menu to choose from (announcements, enrollments, syllabus, assignments, grades) - choicelist = [{'text':'Announcements','value':"tell me about my announcements"}, {'text':'Course Enrollments','value':"tell me about my enrollments"}, {'text':'Course Syllabus','value':"tell me about my syllabus"}, {'text':'Assignments','value':"tell me about my assignments"}, {'text':'Grades','value':"tell me about my grades"}] - generic_attachments = {'version': '1','contentType': CONTENT_TYPE,'genericAttachments':[{"title": TITLE,"buttons":choicelist}]} - event['res']['session']['appContext']['responseCard'] = generic_attachments - event['res']['session']['appContext']['altMessages']['markdown'] = "Please select one of the options below:" # NOSONAR Do not need a literal - - int_counter = 0 - str_choice_list = "" - for _ in choicelist: - if str_choice_list != '': - str_choice_list = str_choice_list + ", " - str_choice_list = str_choice_list + choicelist[int_counter]['text'] - int_counter = int_counter + 1 - event['res']['session']['appContext']['altMessages']['ssml'] = get_ssml_output(SSML_PREOUTPUT + str_choice_list) - - return event - - -def query_enrollments_for_student(event, canvas, student_user_name): - """ - function: query_enrollments_for_student - This function retrieves students' active enrollments - """ - - # Get the user using user_id to match with LMS SIS_ID - try: - user = get_canvas_user (canvas, student_user_name) - except: # NOSONAR Function to log exception already implemented - return user_not_found_error (event) - - if user: - courses = user.get_courses(enrollment_status='active',include=['syllabus_body']) - # Loop through the courses. - course_names = [course.name for course in courses] - - result = {"CourseNames": course_names} - - return_courses = result['CourseNames'] - if return_courses: - choicelist = [] - for i in return_courses: - choicelist.append({'text':i,'value':"more information about my {} course".format(i)}) - generic_attachments = {'version': '1','contentType': CONTENT_TYPE,'genericAttachments':[{"title":TITLE,"buttons":choicelist}]} - event['res']['session']['appContext']['responseCard'] = generic_attachments - event['res']['session']['appContext']['altMessages']['markdown'] = "Please select one of the options below:" - - int_counter = 0 - str_choice_list = "" - for _ in choicelist: - if str_choice_list != '': - str_choice_list = str_choice_list + ", " - str_choice_list = str_choice_list + choicelist[int_counter]['text'] - int_counter = int_counter + 1 - event['res']['session']['appContext']['altMessages']['ssml'] = get_ssml_output(SSML_PREOUTPUT + str_choice_list) - else: - return_message = "You are not currently enrolled in any courses." - set_alt_message (event, return_message) - - return event - -def is_not_filtered_course(course_name_to_filter, course): - return course_name_to_filter != '' and course.name.upper().strip() != course_name_to_filter.upper() - -def is_filtered_course(course_name_to_filter, course): - return course_name_to_filter != '' and course.name.upper().strip() == course_name_to_filter.upper() - -def get_course_result(course_name_to_filter, user): - bln_found_course = False - if user: - courses = user.get_courses(enrollment_status='active') - # Loop through the courses. - for course in courses: - if is_filtered_course(course_name_to_filter, course): - result = {"Choice": course.name} - bln_found_course = True - break - if bln_found_course == False: - result = {"Choice": 'N/A'} - else: - result = {"Choice": 'N/A'} - return result - -def query_courses_for_student(event, canvas, student_user_name, course_name_to_filter): - """ - function: query_courses_for_student - This function retrieves course options across all active enrolled courses, or for a particular course, for the student - for example: more information about {course name} - """ - - # Get the user using user_id to match with LMS SIS_ID - try: - user = get_canvas_user (canvas, student_user_name) - except: # NOSONAR Function to log exception already implemented - return user_not_found_error (event) - - result = get_course_result(course_name_to_filter, user) - - returned_course = result['Choice'] - if returned_course == 'N/A': - return_message = NOT_FOUND_RESP - - set_alt_message (event, return_message) - else: - generic_attachment = ['assignments','syllabus','grades'] - choice_list = [] - for i in generic_attachment: - choice_list.append({'text':'{} {}'.format(returned_course,i),'value':'tell me about my {} {}'.format(returned_course,i)}) - generic_attachments = {'version': '1','contentType': CONTENT_TYPE,'genericAttachments':[{"title":TITLE,"buttons":choice_list}]} - event['res']['session']['appContext']['responseCard'] = generic_attachments - event['res']['session']['appContext']['altMessages']['markdown'] = "Please select one of the options below:" - - int_counter = 0 - str_choice_list = "" - for _ in choice_list: - if str_choice_list != '': - str_choice_list = str_choice_list + ", " - str_choice_list = str_choice_list + choice_list[int_counter]['text'] - int_counter = int_counter + 1 - event['res']['session']['appContext']['altMessages']['ssml'] = get_ssml_output(SSML_PREOUTPUT + str_choice_list) - return event - -def append_assignment_due_date(assignment): - if assignment.due_at: #check if assignments have due dates - due_date = datetime.datetime.strptime(assignment.due_at,'%Y-%m-%dT%H:%M:%SZ') - due_date_string = '{0}, {1} {2}, {3}'.format(calendar.day_name[due_date.weekday()], due_date.strftime("%B"), due_date.strftime("%-d"), due_date.strftime("%Y")) - return "
  • {} -- is due: {}.
  • ".format(assignment.name, due_date_string) - else: - return "
  • {} -- has no due date.
  • ".format(assignment.name) - -def get_course_assignments(course_name_to_filter, no_records_message, user): - course_assignments = '' - bln_has_assignments = False - bln_found_match = False - courses = user.get_courses(enrollment_status='active') - - for course in courses: - bln_has_assignments = False - bln_found_match = False - - #check for matching course_name_slot_input with course names - if is_filtered_course(course_name_to_filter, course): - bln_found_match = True - - if bln_found_match == True: - course_assignments = "" + course.name + ":
      " - else: - course_assignments += "" + course.name + ":
        " - - # Loop through the assignments that have not been submitted - for assignment in course.get_assignments(bucket='unsubmitted'): - bln_has_assignments = True - if is_not_filtered_course(course_name_to_filter, course): - # if a slot value is provided, but does not have a matching course that the student is enrolled in - course_assignments = NOT_FOUND_RESP - break - - course_assignments += append_assignment_due_date(assignment) - - if bln_has_assignments == False: - course_assignments += no_records_message - - course_assignments += "

      " - - #if found a matching course, then break from the course For loop - if bln_found_match == True: - break - return course_assignments - -def query_course_assignments_for_student(event, canvas, student_user_name, course_name_to_filter): - """ - function: query_course_assignments_for_student - This function retrieves assignment information across all active enrolled courses, or for a particular course, for the student - for example: do i have any assignments due or tell me about by {course_name} assignments - """ - - no_records_message = 'There are no assignments for this course.' - # Get the user using user_id to match with LMS SIS_ID - try: - user = get_canvas_user (canvas, student_user_name) - except: # NOSONAR Function to log exception already implemented - return user_not_found_error (event) - - if user: - course_assignments = get_course_assignments(course_name_to_filter, no_records_message, user) - result = {"CourseAssignments": course_assignments} - if result['CourseAssignments']: - return_message = result['CourseAssignments'] - set_alt_message (event, return_message) - else: - return_message = no_records_message - set_alt_message (event, return_message) - - return event - -def query_announcements_for_student(event, canvas, student_user_name): - """ - function: query_announcements_for_student - This function retrieves any announcements across all active enrolled courses for the student - for example: do i have any announcements - """ - - no_records_message = 'You currently have no announcements.' - course_announcements = '' - - # Get the user using user_id to match with LMS SIS_ID - try: - user = get_canvas_user (canvas, student_user_name) - except: # NOSONAR Function to log exception already implemented - return user_not_found_error (event) - - course_names = [] - if user: - courses = user.get_courses(enrollment_status='active') - - # Loop through the courses. - for course in courses: - course_names.append(course.name) - # get_announcements returns a list of discussion topics. - for discussion_topic in canvas.get_announcements(context_codes=[course.id]): - if discussion_topic: - announcement_date = datetime.datetime.strftime(discussion_topic.posted_at_date,"%b %d %Y %-I:%M %p") # NOSONAR storing the date in string - course_announcements += '
    • {0}: {1}:
      {2}.
    • '.format(course.name, discussion_topic.title, discussion_topic.message) - else: - course_announcements += no_records_message - - if course_announcements != '': - course_announcements = "
        " + course_announcements + "
      " - - result = {"Announcements": course_announcements} - - if result['Announcements']: - return_message = 'Here are your announcements: {}'.format(result['Announcements']) - set_alt_message (event, return_message) - else: - set_alt_message (event, no_records_message) - - return event - -def get_grade_score(grade): - if grade.grades['current_score'] != '': - grade_score = grade.grades['current_score'] - else: - grade_score = "N/A" - return grade_score - -def query_grades_for_student(event, canvas, student_user_name, course_name_to_filter): - """ - function: query_grades_for_student - This function retrieves grade information across all active enrolled courses, or for a particular course, for the student - for example: tell me about my grades, or how did i do in {course name} - """ - - no_records_message = "There are no enrolled courses." - course_grades = '
        ' - # Get the user using user_id to match with LMS SIS_ID - try: - user = get_canvas_user (canvas, student_user_name) - except: # NOSONAR Function to log exception already implemented - return user_not_found_error (event) - - if user: - # Loop through the courses - courses = user.get_enrollments(include='current_points', search_by='course') - - if courses: - for grade in courses: - course_name = canvas.get_course(grade.course_id) - grade_score = get_grade_score(grade) - - #check for matching course_name_slot_input with course names - if is_filtered_course(course_name_to_filter, course_name): - course_grades = "
      • Grades for {} course: {}.
      • ".format(course_name.name, grade_score) - break - elif course_name_to_filter != '': - # if a slot value is provided, but does not have a matching course that the student is enrolled in - course_grades = NOT_FOUND_RESP - else: - course_grades += "
      • Grades for {} course: {}.
      • ".format(course_name.name, grade_score) - else: - course_grades = no_records_message - - course_grades += "
      " - - result = {"Grades": course_grades} - - return_message = result['Grades'] - set_alt_message (event, return_message) - - return event - -def query_syllabus_for_student(event, canvas, student_user_name, course_name_to_filter): - """ - function: query_syllabus_for_student - This function retrieves syllabus information across all active enrolled courses, or for a particular course, for the student - for example: what is my syllabus, or tell me about my {course name} syllabus - """ - - no_records_message = 'There is no syllabus currently available for this course.' - course_syllabus = '' - - # Get the user using user_id to match with LMS SIS_ID - try: - user = get_canvas_user (canvas, student_user_name) - except: # NOSONAR Function to log exception already implemented - return user_not_found_error (event) - - if user: - courses = user.get_courses(enrollment_status='active',include=['syllabus_body']) - - # Loop through the courses. - for course in courses: - #check for matching course_name_slot_input with course names - if is_filtered_course(course_name_to_filter, course): - if course.syllabus_body.strip() != '': - course_syllabus = '{0}: {1}
      '.format(course.name, course.syllabus_body) - else: - course_syllabus = no_records_message - break - elif course_name_to_filter != '': - # if a slot value is provided, but does not have a matching course that the student is enrolled in - course_syllabus = NOT_FOUND_RESP - else: - if course.syllabus_body.strip() != '': - course_syllabus += '{0}: {1}.
      '.format(course.name, course.syllabus_body) - else: - course_syllabus += '{0}: {1}.
      '.format(course.name, no_records_message) - - result = {"CourseSyllabus": course_syllabus} - - return_message = result['CourseSyllabus'] - set_alt_message (event, return_message) - - return event - - -def validate_input(event): - """ - function: validate_input - This function checks whether the user is logged in - Additionally, also checks if QnABot is configured with the required parameters - """ - - error_message = '' - - try: - if json.loads(event['res']['result']['args'][0])['Query'] == '': - error_message = 'There was an error processing your request. Please check the question setup and try again.' - return error_message - - if event['req']['_userInfo']['isVerifiedIdentity'] != "true": - error_message = 'There was an error processing your request. Please check your login and try again, or contact your administrator.' - return error_message - - if event['req']['_settings']['CanvasDomainName'].strip() == '' or event['req']['_settings']['CanvasAPIKey'].strip() == '' or event['req']['_settings']['CanvasCourseNameSlot'].strip() == '': - error_message = 'There was an error processing your request. Please check the QnABot custom setting names/values and try again.' - return error_message - except Exception as e: - print("validate_input exception") - print(e) - error_message = 'There was an error processing your request. Please check the question setup and try again.' - return error_message - - -def remove_html_tags (str_input): - """ - function to remove HTML tags - """ - - #parse html input string - obj_b_soup = BeautifulSoup(str_input, "html.parser") - - for data in obj_b_soup (['style', 'script']): - #remove html tags - data.decompose() - - # return - return ' '.join(obj_b_soup.stripped_strings) - - -def get_ssml_output (str_input): - """ - function to return SSML output - """ - - #parse html input string - return "" + remove_html_tags(str_input) + "" - - -def set_alt_message (event, str_input): - """ - function to set alt messages - """ - - # set markdown output - event['res']['session']['appContext']['altMessages']['markdown'] = str_input - # set ssml output - event['res']['session']['appContext']['altMessages']['ssml'] = get_ssml_output (str_input) - - -def user_not_found_error(event): - """ - function to return error message when user id does not exist in Canvas LMS - """ - - print ("user_not_found_error") - return_message = "There was an error processing your request. Please check your login and try again, or contact your administrator." - set_alt_message (event, return_message) - - return event diff --git a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/CanvasLMSHook.py b/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/CanvasLMSHook.py deleted file mode 100644 index b94757567..000000000 --- a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/CanvasLMSHook.py +++ /dev/null @@ -1,118 +0,0 @@ -###################################################################################################################### -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # -# # -# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance # -# with the License. A copy of the License is located at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES # -# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions # -# and limitations under the License. # -###################################################################################################################### - -# NOTICE: Canvas LMS integration with QnABot on AWS is deprecated in this release and no longer be supported. Customers may fork the code needed for their specific use case from previous versions. The integration code will be removed in the next release. - -# Import the Canvas class -from canvasapi import Canvas - -import CanvasLMSHelper as CanvasLMS - - -api_token = '' #variable to hold the value of API_Token stored in AWS Secrets Manager -canvas = None #variable to hold the Canvas object - - -def handler(event, context): # NOSONAR Lambda Handler - """ - function handler - Main handler function - This function processes: - a. lambda hook arguments - b. processes user input - c. provides response back to the user - """ - - global api_token - global canvas - - return_message = '' - course_name_slot_input = '' - course_name_slot_resolved_input = '' - course_name_to_filter = '' - - # Validate the required input. - error_message = CanvasLMS.validate_input(event) - - if error_message: - return_message = error_message - CanvasLMS.set_alt_message (event, return_message) - else: - # get the API domain. This will be needed for API calls and for looking up the bearer token. - domain = event['req']['_settings']['CanvasLMS_DomainName'].strip() - secrets_name = event['req']['_settings']['CanvasLMS_APIKey'].strip() - course_name_slot = 'CanvasLMS_course_name_slot' - - try: - # get slot value if present - course_name_slot_input = event["req"]["_event"]["interpretations"][0]["intent"]["slots"][course_name_slot]["value"].get("originalValue", '') - except: # NOSONAR the case is handled and no exception is needed - course_name_slot_input = '' - - course_name_slot_resolved_input = event["req"]["slots"].get(course_name_slot, '') - course_name_to_filter = course_name_slot_resolved_input - - if (course_name_slot_resolved_input == '' and course_name_slot_input != ''): - return_message = "Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in, to get a list of enrolled courses." - CanvasLMS.set_alt_message (event, return_message) - return event - - - # Get the API Token from AWS Secrets Manager - if api_token == '': - api_token = CanvasLMS.get_secret(secrets_name) - - # Initialize Canvas object - if canvas is None: - canvas = Canvas(domain, api_token) - - try: - # Get the student's profile from the request - student_user_name = event['req']['_userInfo']['UserName'] - student_name = event['req']['_userInfo']['GivenName'] - - # Get the query from the request (lambda function argument) - query = CanvasLMS.json.loads(event['res']['result']['args'][0])['Query'] - match query: - case 'CanvasMenu': - # retrieve the menu - return CanvasLMS.query_menu (event, student_name) - case'CourseEnrollments': - # retrieve the course options for this student. - return CanvasLMS.query_enrollments_for_student(event, canvas, student_user_name) - case 'CourseAssignments': - # retrieve the assignments for this student. - return CanvasLMS.query_course_assignments_for_student(event, canvas, student_user_name, course_name_to_filter) - case 'SyllabusForCourse': - # retrieve the course syllabus for this student. - return CanvasLMS.query_syllabus_for_student(event, canvas, student_user_name, course_name_to_filter) - case 'CoursesForStudent': - # retrieve the course options for this student. - return CanvasLMS.query_courses_for_student(event, canvas, student_user_name, course_name_to_filter) - case 'AnnouncementsForStudent': - # retrieve the announcements for this student. - return CanvasLMS.query_announcements_for_student(event, canvas, student_user_name) - case 'GradesForStudent': - # retrieve the course grades for this student. - return CanvasLMS.query_grades_for_student(event, canvas, student_user_name, course_name_to_filter) - case _: - return_message = 'There was an error processing your request. For a list of available options, type or say canvas menu.' - CanvasLMS.set_alt_message (event, return_message) - return event - except ValueError as e: - print ("ERROR: "+ str(e)) #print the exception - return_message = 'There was an error processing your request. Please contact your administrator.' - CanvasLMS.set_alt_message (event, return_message) - return event - - return event diff --git a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/__tests__/__init__.py b/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/__tests__/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/__tests__/test_CanvasLMSHelper.py b/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/__tests__/test_CanvasLMSHelper.py deleted file mode 100644 index 2221e3e7d..000000000 --- a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/__tests__/test_CanvasLMSHelper.py +++ /dev/null @@ -1,847 +0,0 @@ -###################################################################################################################### -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # -# # -# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance # -# with the License. A copy of the License is located at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES # -# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions # -# and limitations under the License. # -###################################################################################################################### - -# NOTICE: Canvas LMS integration with QnABot on AWS is deprecated in this release and no longer be supported. Customers may fork the code needed for their specific use case from previous versions. The integration code will be removed in the next release. - -from unittest.mock import Mock -import pytest -import datetime -import json -from botocore.exceptions import ClientError -from moto import mock_secretsmanager - -class TestCanvasLMSHelper(): - - @mock_secretsmanager - def test_get_secret_with_secret_string(self, mock_sm): - from CanvasLMSHelper import get_secret - mock_sm.create_secret(Name='test', SecretString=json.dumps({'API_Token': 'value'})) - response = get_secret('test') - assert response == 'value' - - @mock_secretsmanager - def test_get_secret_without_secret_string(self): - from CanvasLMSHelper import get_secret - try: - get_secret('test') - except ClientError as e: - assert e.args[0] == "An error occurred (ResourceNotFoundException) when calling the GetSecretValue operation: Secrets Manager can't find the specified secret." - - def test_get_canvas_user(self): - from CanvasLMSHelper import get_canvas_user - canvas_mock = Mock() - get_canvas_user(canvas_mock, 'user') - canvas_mock.get_user.assert_called_with('user', 'sis_login_id') - - def test_query_menu(self): - from CanvasLMSHelper import query_menu - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_menu(event, 'user') - assert response == {'res': {'session': {'appContext': {'responseCard': {'version': '1', 'contentType': 'application/vnd.amazonaws.card.generic', 'genericAttachments': [{'title': 'response buttons', 'buttons': [{'text': 'Announcements', 'value': 'tell me about my announcements'}, {'text': 'Course Enrollments', 'value': 'tell me about my enrollments'}, {'text': 'Course Syllabus', 'value': 'tell me about my syllabus'}, {'text': 'Assignments', 'value': 'tell me about my assignments'}, {'text': 'Grades', 'value': 'tell me about my grades'}]}]}, 'altMessages': {'markdown': 'Please select one of the options below:', 'ssml': 'Please select one of these options: Announcements, Course Enrollments, Course Syllabus, Assignments, Grades'}}}}} - - def test_query_enrollments_for_student(self): - from CanvasLMSHelper import query_enrollments_for_student - course_mock = Mock() - course_mock.name = 'course name' - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_enrollments_for_student(event, canvas_mock, 'user') - assert response == {'res': {'session': {'appContext': {'responseCard': {'version': '1', 'contentType': 'application/vnd.amazonaws.card.generic', 'genericAttachments': [{'title': 'response buttons', 'buttons': [{'text': 'course name', 'value': 'more information about my course name course'}]}]}, 'altMessages': {'markdown': 'Please select one of the options below:', 'ssml': 'Please select one of these options: course name'}}}}} - - def test_query_enrollments_for_student_with_more_than_one_course(self): - from CanvasLMSHelper import query_enrollments_for_student - course_mock = Mock() - course_mock.name = 'course name' - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock, course_mock] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_enrollments_for_student(event, canvas_mock, 'user') - assert response == {'res': {'session': {'appContext': {'responseCard': {'version': '1', 'contentType': 'application/vnd.amazonaws.card.generic', 'genericAttachments': [{'title': 'response buttons', 'buttons': [{'text': 'course name', 'value': 'more information about my course name course'}, {'text': 'course name', 'value': 'more information about my course name course'}]}]}, 'altMessages': {'markdown': 'Please select one of the options below:', 'ssml': 'Please select one of these options: course name, course name'}}}}} - - def test_query_enrollments_for_student_with_no_courses(self): - from CanvasLMSHelper import query_enrollments_for_student - user_mock = Mock() - user_mock.get_courses.return_value = [] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_enrollments_for_student(event, canvas_mock, 'user') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'You are not currently enrolled in any courses.', 'ssml': 'You are not currently enrolled in any courses.'}}}}} - - def test_query_enrollments_for_missing_student(self): - from CanvasLMSHelper import query_enrollments_for_student - canvas_mock = Mock() - canvas_mock.get_user.side_effect = Exception('user not found') - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - - response = query_enrollments_for_student(event, canvas_mock, 'user') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'There was an error processing your request. Please check your login and try again, or contact your administrator.', 'ssml': 'There was an error processing your request. Please check your login and try again, or contact your administrator.'}}}}} - - def test_query_courses_for_student(self): - from CanvasLMSHelper import query_courses_for_student - course_mock = Mock() - course_mock.name = 'course name' - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_courses_for_student(event, canvas_mock, 'user', 'course name') - assert response == {'res': {'session': {'appContext': {'responseCard': {'version': '1', 'contentType': 'application/vnd.amazonaws.card.generic', 'genericAttachments': [{'title': 'response buttons', 'buttons': [{'text': 'course name assignments', 'value': 'tell me about my course name assignments'}, {'text': 'course name syllabus', 'value': 'tell me about my course name syllabus'}, {'text': 'course name grades', 'value': 'tell me about my course name grades'}]}]}, 'altMessages': {'markdown': 'Please select one of the options below:', 'ssml': 'Please select one of these options: course name assignments, course name syllabus, course name grades'}}}}} - - def test_query_courses_for_student_with_course_not_found(self): - from CanvasLMSHelper import query_courses_for_student - course_mock = Mock() - course_mock.name = 'course name' - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_courses_for_student(event, canvas_mock, 'user', 'missing course') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in, to get a list of enrolled courses.', 'ssml': 'Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in , to get a list of enrolled courses.'}}}}} - - def test_query_courses_for_student_when_student_not_found(self): - from CanvasLMSHelper import query_courses_for_student - - canvas_mock = Mock() - canvas_mock.get_user.side_effect = Exception('user not found') - - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_courses_for_student(event, canvas_mock, 'user', 'missing course') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'There was an error processing your request. Please check your login and try again, or contact your administrator.', 'ssml': 'There was an error processing your request. Please check your login and try again, or contact your administrator.'}}}}} - - def test_query_courses_for_student_with_empty_student(self): - from CanvasLMSHelper import query_courses_for_student - - user_mock = '' - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_courses_for_student(event, canvas_mock, 'user', 'missing course') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in, to get a list of enrolled courses.', 'ssml': 'Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in , to get a list of enrolled courses.'}}}}} - - def test_query_course_assignments_for_student(self): - from CanvasLMSHelper import query_course_assignments_for_student - - assignment1 = Mock() - assignment2 = Mock() - assignment1.name = 'assignment 1' - assignment2.name = 'assignment 2' - assignment1.due_at = '2020-01-01T00:00:00Z' - assignment2.due_at = '' - course_mock = Mock() - course_mock.name = 'course name' - course_mock.get_assignments = lambda bucket: [assignment1, assignment2] - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_course_assignments_for_student(event, canvas_mock, 'user', 'course name') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'course name:
      • assignment 1 -- is due: Wednesday, January 1, 2020.
      • assignment 2 -- has no due date.

      ', 'ssml': 'course name: assignment 1 -- is due: Wednesday, January 1, 2020. assignment 2 -- has no due date.'}}}}} - - def test_query_course_assignments_for_student_unfiltered_course(self): - from CanvasLMSHelper import query_course_assignments_for_student - - assignment1 = Mock() - assignment2 = Mock() - assignment1.name = 'assignment 1' - assignment2.name = 'assignment 2' - assignment1.due_at = '2020-01-01T00:00:00Z' - assignment2.due_at = '' - course_mock = Mock() - course_mock.name = 'course name' - course_mock.get_assignments = lambda bucket: [assignment1, assignment2] - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_course_assignments_for_student(event, canvas_mock, 'user', 'not course name') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in, to get a list of enrolled courses.

    ', 'ssml': 'Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in , to get a list of enrolled courses.'}}}}} - - def test_query_course_assignments_for_student_with_course_with_no_assignments(self): - from CanvasLMSHelper import query_course_assignments_for_student - - course_mock = Mock() - course_mock.name = 'course name' - course_mock.get_assignments = lambda bucket: [] - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_course_assignments_for_student(event, canvas_mock, 'user', 'not course name') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'course name:
      There are no assignments for this course.

    ', 'ssml': 'course name: There are no assignments for this course.'}}}}} - - def test_query_course_assignments_for_student_with_no_courses(self): - from CanvasLMSHelper import query_course_assignments_for_student - - user_mock = Mock() - user_mock.get_courses.return_value = [] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_course_assignments_for_student(event, canvas_mock, 'user', 'not course name') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'There are no assignments for this course.', 'ssml': 'There are no assignments for this course.'}}}}} - - def test_query_course_assignments_for_student_when_no_student(self): - from CanvasLMSHelper import query_course_assignments_for_student - - canvas_mock = Mock() - canvas_mock.get_user.side_effect = Exception('user not found') - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_course_assignments_for_student(event, canvas_mock, 'user', 'not course name') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'There was an error processing your request. Please check your login and try again, or contact your administrator.', 'ssml': 'There was an error processing your request. Please check your login and try again, or contact your administrator.'}}}}} - - - def test_query_announcements_for_student(self): - from CanvasLMSHelper import query_announcements_for_student - - discussion_topic = Mock() - discussion_topic.posted_at_date = datetime.datetime.now().date() - discussion_topic.title = 'title' - discussion_topic.message = 'do your homework!' - course_mock = Mock() - course_mock.name = 'course name' - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock] - canvas_mock = Mock() - canvas_mock.get_announcements = lambda context_codes: [discussion_topic, {}] - canvas_mock.get_user.return_value = user_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_announcements_for_student(event, canvas_mock, 'user') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'Here are your announcements:
    • course name: title:
      do your homework!.
    • You currently have no announcements.
    ', 'ssml': 'Here are your announcements: course name : title: do your homework!. You currently have no announcements.'}}}}} - - def test_query_announcements_for_student_with_no_announcements(self): - from CanvasLMSHelper import query_announcements_for_student - - course_mock = Mock() - course_mock.name = 'course name' - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock] - canvas_mock = Mock() - canvas_mock.get_announcements = lambda context_codes: [] - canvas_mock.get_user.return_value = user_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_announcements_for_student(event, canvas_mock, 'user') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'You currently have no announcements.', 'ssml': 'You currently have no announcements.'}}}}} - - def test_query_announcements_for_student_when_no_student(self): - from CanvasLMSHelper import query_announcements_for_student - - canvas_mock = Mock() - canvas_mock.get_user.side_effect = Exception('user not found') - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_announcements_for_student(event, canvas_mock, 'user') - assert response =={'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'There was an error processing your request. Please check your login and try again, or contact your administrator.', 'ssml': 'There was an error processing your request. Please check your login and try again, or contact your administrator.'}}}}} - - def test_query_grades_for_student(self): - from CanvasLMSHelper import query_grades_for_student - - grade_mock1 = Mock() - grade_mock1.course_id = '1' - grade_mock1.grades = { - 'current_score': 100 - } - grade_mock2 = Mock() - grade_mock2.course_id = '2' - grade_mock2.grades = { - 'current_score': '' - } - course_mock = Mock() - course_mock.name = 'course name' - user_mock = Mock() - user_mock.get_enrollments.return_value = [grade_mock1, grade_mock2] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - canvas_mock.get_course = lambda course_id: course_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_grades_for_student(event, canvas_mock, 'user', '') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': '
    • Grades for course name course: 100.
    • Grades for course name course: N/A.
    ', 'ssml': 'Grades for course name course: 100. Grades for course name course: N/A.'}}}}} - - def test_query_grades_for_student_with_filtered_course(self): - from CanvasLMSHelper import query_grades_for_student - - grade_mock1 = Mock() - grade_mock1.course_id = '1' - grade_mock1.grades = { - 'current_score': 100 - } - grade_mock2 = Mock() - grade_mock2.course_id = '2' - grade_mock2.grades = { - 'current_score': '' - } - course_mock = Mock() - course_mock.name = 'course name' - user_mock = Mock() - user_mock.get_enrollments.return_value = [grade_mock1, grade_mock2] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - canvas_mock.get_course = lambda course_id: course_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_grades_for_student(event, canvas_mock, 'user', 'course name') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': '
  • Grades for course name course: 100.
  • ', 'ssml': 'Grades for course name course: 100.'}}}}} - - def test_query_grades_for_student_with_filtered_incorrect_course(self): - from CanvasLMSHelper import query_grades_for_student - - grade_mock1 = Mock() - grade_mock1.course_id = '1' - grade_mock1.grades = { - 'current_score': 100 - } - course_mock = Mock() - course_mock.name = 'course name' - user_mock = Mock() - user_mock.get_enrollments.return_value = [grade_mock1] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - canvas_mock.get_course = lambda course_id: course_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_grades_for_student(event, canvas_mock, 'user', 'missing course name') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in, to get a list of enrolled courses.', 'ssml': 'Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in , to get a list of enrolled courses.'}}}}} - - def test_query_grades_for_student_with_no_courses(self): - from CanvasLMSHelper import query_grades_for_student - - user_mock = Mock() - user_mock.get_enrollments.return_value = [] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_grades_for_student(event, canvas_mock, 'user', '') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'There are no enrolled courses.', 'ssml': 'There are no enrolled courses.'}}}}} - - def test_query_grades_for_student_with_missing_student(self): - from CanvasLMSHelper import query_grades_for_student - - canvas_mock = Mock() - canvas_mock.get_user.side_effect = Exception('user not found') - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_grades_for_student(event, canvas_mock, 'user', '') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'There was an error processing your request. Please check your login and try again, or contact your administrator.', 'ssml': 'There was an error processing your request. Please check your login and try again, or contact your administrator.'}}}}} - - def test_query_syllabus_for_student(self): - from CanvasLMSHelper import query_syllabus_for_student - - course_mock1 = Mock() - course_mock1.name = 'course name' - course_mock1.syllabus_body = 'body' - course_mock2 = Mock() - course_mock2.name = 'course name' - course_mock2.syllabus_body = '' - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock1, course_mock2] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_syllabus_for_student(event, canvas_mock, 'user', '') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'course name: body.
    course name: There is no syllabus currently available for this course..
    ', 'ssml': 'course name : body. course name : There is no syllabus currently available for this course..'}}}}} - - def test_query_syllabus_for_student_with_filter(self): - from CanvasLMSHelper import query_syllabus_for_student - - course_mock1 = Mock() - course_mock1.name = 'course name' - course_mock1.syllabus_body = 'body' - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock1] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_syllabus_for_student(event, canvas_mock, 'user', 'course name') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'course name: body
    ', 'ssml': 'course name : body'}}}}} - - def test_query_syllabus_for_student_with_filtered_course_without_body(self): - from CanvasLMSHelper import query_syllabus_for_student - - course_mock1 = Mock() - course_mock1.name = 'course name' - course_mock1.syllabus_body = '' - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock1] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_syllabus_for_student(event, canvas_mock, 'user', 'course name') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'There is no syllabus currently available for this course.', 'ssml': 'There is no syllabus currently available for this course.'}}}}} - - def test_query_syllabus_for_student_with_incorrect_filtered_course(self): - from CanvasLMSHelper import query_syllabus_for_student - - course_mock1 = Mock() - course_mock1.name = 'course name' - course_mock1.syllabus_body = '' - user_mock = Mock() - user_mock.get_courses.return_value = [course_mock1] - canvas_mock = Mock() - canvas_mock.get_user.return_value = user_mock - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_syllabus_for_student(event, canvas_mock, 'user', 'missing course name') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in, to get a list of enrolled courses.', 'ssml': 'Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in , to get a list of enrolled courses.'}}}}} - - def test_query_syllabus_for_student_with_missing_student(self): - from CanvasLMSHelper import query_syllabus_for_student - - canvas_mock = Mock() - canvas_mock.get_user.side_effect = Exception('user not found') - - event = { - 'res': { - 'session': { - 'appContext': { - 'responseCard': '', - 'altMessages': { - 'markdown': '' - } - } - } - } - } - response = query_syllabus_for_student(event, canvas_mock, 'user', 'missing course name') - assert response == {'res': {'session': {'appContext': {'responseCard': '', 'altMessages': {'markdown': 'There was an error processing your request. Please check your login and try again, or contact your administrator.', 'ssml': 'There was an error processing your request. Please check your login and try again, or contact your administrator.'}}}}} - - def test_validate_input_correct_input(self): - from CanvasLMSHelper import validate_input - event = { - 'res': { - 'result': { - 'args': [ - json.dumps({ - 'Query': 'test' - }) - ] - } - }, - 'req': { - '_settings': { - 'CanvasDomainName': 'test.com', - 'CanvasAPIKey': 'test', - 'CanvasCourseNameSlot': 'test' - }, - '_userInfo': { - 'isVerifiedIdentity': 'true', - }, - 'slots': {} - }, - } - - error = validate_input(event) - assert error == None - - def test_validate_input_empty_query(self): - from CanvasLMSHelper import validate_input - event = { - 'res': { - 'result': { - 'args': [ - json.dumps({ - 'Query': '' - }) - ] - } - }, - } - - error = validate_input(event) - assert error == 'There was an error processing your request. Please check the question setup and try again.' - - def test_validate_input_is_not_verified_identity(self): - from CanvasLMSHelper import validate_input - event = { - 'res': { - 'result': { - 'args': [ - json.dumps({ - 'Query': 'test' - }) - ] - } - }, - 'req': { - '_userInfo': { - 'isVerifiedIdentity': 'false', - }, - 'slots': {} - }, - } - - error = validate_input(event) - assert error == 'There was an error processing your request. Please check your login and try again, or contact your administrator.' - - def test_validate_input_missing_canvas_info(self): - from CanvasLMSHelper import validate_input - event = { - 'res': { - 'result': { - 'args': [ - json.dumps({ - 'Query': 'test' - }) - ] - } - }, - 'req': { - '_settings': { - 'CanvasDomainName': '', - 'CanvasAPIKey': '', - 'CanvasCourseNameSlot': '' - }, - '_userInfo': { - 'isVerifiedIdentity': 'true', - }, - 'slots': {} - }, - } - - error = validate_input(event) - assert error == 'There was an error processing your request. Please check the QnABot custom setting names/values and try again.' - - def test_validate_input_invalid_object(self): - from CanvasLMSHelper import validate_input - event = {} - - error = validate_input(event) - assert error == 'There was an error processing your request. Please check the question setup and try again.' - - def test_vremove_html_tags(self): - from CanvasLMSHelper import remove_html_tags - str_input = '' - - result = remove_html_tags(str_input) - assert result == '' \ No newline at end of file diff --git a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/__tests__/test_CanvasLMSHook.py b/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/__tests__/test_CanvasLMSHook.py deleted file mode 100644 index 6eba49b5e..000000000 --- a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/__tests__/test_CanvasLMSHook.py +++ /dev/null @@ -1,475 +0,0 @@ -###################################################################################################################### -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # -# # -# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance # -# with the License. A copy of the License is located at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES # -# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions # -# and limitations under the License. # -###################################################################################################################### - -# NOTICE: Canvas LMS integration with QnABot on AWS is deprecated in this release and no longer be supported. Customers may fork the code needed for their specific use case from previous versions. The integration code will be removed in the next release. - -import unittest -from unittest.mock import patch, Mock -import pytest -from CanvasLMSHook import handler - -@patch('CanvasLMSHook.Canvas') -@patch('CanvasLMSHook.CanvasLMS') -class TestCanvasLMSHook(unittest.TestCase): - - def test_sets_message_with_error_if_query_is_not_valid(self, canvas_lms_mock, canvas_mock): - event = { - 'res': { - 'result': { - 'args': [ - { - 'query': 'test' - } - ] - } - }, - 'req': { - '_settings': { - 'CanvasLMS_DomainName': 'test.com', - 'CanvasLMS_APIKey': 'test' - }, - '_userInfo': { - 'UserName': 'user', - 'GivenName': 'User McStudent' - }, - 'slots': {} - }, - } - - context = {} - - canvas_lms_mock.validate_input.return_value = False - canvas_lms_mock.get_secret.return_value = { - "CanvasLMS_APIKey": "test", - "CanvasLMS_DomainName": "test.com" - } - canvas_lms_mock.json.loads.return_value = { - "Query": "test" - } - - event = handler(event, context) - canvas_lms_mock.set_alt_message.assert_called_once_with({'res': {'result': {'args': [{'query': 'test'}]}}, 'req': {'_settings': {'CanvasLMS_DomainName': 'test.com', 'CanvasLMS_APIKey': 'test'}, '_userInfo': {'UserName': 'user', 'GivenName': 'User McStudent'}, 'slots': {}}}, 'There was an error processing your request. For a list of available options, type or say canvas menu.') - - def test_sets_message_with_error_if_value_error_is_thrown(self, canvas_lms_mock, canvas_mock): - event = { - 'res': { - 'result': { - 'args': [ - { - 'query': 'test' - } - ] - } - }, - 'req': { - '_settings': { - 'CanvasLMS_DomainName': 'test.com', - 'CanvasLMS_APIKey': 'test' - }, - '_userInfo': { - 'UserName': 'user', - 'GivenName': 'User McStudent' - }, - 'slots': {} - }, - } - - context = {} - - canvas_lms_mock.validate_input.return_value = False - canvas_lms_mock.get_secret.return_value = { - "CanvasLMS_APIKey": "test", - "CanvasLMS_DomainName": "test.com" - } - - canvas_lms_mock.json.loads.side_effect = ValueError() - - event = handler(event, context) - canvas_lms_mock.set_alt_message.assert_called_once_with({'res': {'result': {'args': [{'query': 'test'}]}}, 'req': {'_settings': {'CanvasLMS_DomainName': 'test.com', 'CanvasLMS_APIKey': 'test'}, '_userInfo': {'UserName': 'user', 'GivenName': 'User McStudent'}, 'slots': {}}}, 'There was an error processing your request. Please contact your administrator.') - - def test_sets_message_with_error_if_invalid_input(self, canvas_lms_mock, canvas_mock): - event = { - 'res': { - 'result': { - 'args': [ - { - 'query': 'test' - } - ] - } - }, - 'req': { - '_settings': { - 'CanvasLMS_DomainName': 'test.com', - 'CanvasLMS_APIKey': 'test' - }, - '_userInfo': { - 'UserName': 'user', - 'GivenName': 'User McStudent' - }, - 'slots': {} - }, - } - - context = {} - - canvas_lms_mock.validate_input.return_value = True - - event = handler(event, context) - canvas_lms_mock.set_alt_message.assert_called_once_with({'res': {'result': {'args': [{'query': 'test'}]}}, 'req': {'_settings': {'CanvasLMS_DomainName': 'test.com', 'CanvasLMS_APIKey': 'test'}, '_userInfo': {'UserName': 'user', 'GivenName': 'User McStudent'}, 'slots': {}}}, True) - - def test_sets_message_with_error_when_course_name_slot_is_not_empty(self, canvas_lms_mock, canvas_mock): - event = { - 'res': { - 'result': { - 'args': [ - { - 'query': 'test' - } - ] - } - }, - 'req': { - '_settings': { - 'CanvasLMS_DomainName': 'test.com', - 'CanvasLMS_APIKey': 'test' - }, - '_event': { - 'interpretations': [ - { - 'intent': { - 'slots': { - 'CanvasLMS_course_name_slot': { - 'value': { - 'originalValue': 'not_empty' - } - } - } - } - } - ] - }, - '_userInfo': { - 'UserName': 'user', - 'GivenName': 'User McStudent' - }, - 'slots': {} - }, - } - - context = {} - - canvas_lms_mock.validate_input.return_value = False - canvas_lms_mock.get_secret.return_value = { - "CanvasLMS_APIKey": "test", - "CanvasLMS_DomainName": "test.com" - } - - canvas_lms_mock.json.loads.side_effect = ValueError() - - event = handler(event, context) - canvas_lms_mock.set_alt_message.assert_called_once_with({'res': {'result': {'args': [{'query': 'test'}]}}, 'req': {'_settings': {'CanvasLMS_DomainName': 'test.com', 'CanvasLMS_APIKey': 'test'}, '_event': {'interpretations': [{'intent': {'slots': {'CanvasLMS_course_name_slot': {'value': {'originalValue': 'not_empty'}}}}}]}, '_userInfo': {'UserName': 'user', 'GivenName': 'User McStudent'}, 'slots': {}}}, 'Sorry, was unable to find the course you are looking for. Check the course name and try again. You can also ask what courses have i enrolled in, to get a list of enrolled courses.') - - def test_CanvasMenu_called(self, canvas_lms_mock, canvas_mock): - event = { - 'res': { - 'result': { - 'args': [ - { - 'query': 'test' - } - ] - } - }, - 'req': { - '_settings': { - 'CanvasLMS_DomainName': 'test.com', - 'CanvasLMS_APIKey': 'test' - }, - '_userInfo': { - 'UserName': 'user', - 'GivenName': 'User McStudent' - }, - 'slots': {} - }, - } - - context = {} - - canvas_lms_mock.validate_input.return_value = False - canvas_lms_mock.get_secret.return_value = { - "CanvasLMS_APIKey": "test", - "CanvasLMS_DomainName": "test.com" - } - canvas_lms_mock.json.loads.return_value = { - "Query": "CanvasMenu" - } - - event = handler(event, context) - canvas_lms_mock.query_menu.assert_called_once_with({'res': {'result': {'args': [{'query': 'test'}]}}, 'req': {'_settings': {'CanvasLMS_DomainName': 'test.com', 'CanvasLMS_APIKey': 'test'}, '_userInfo': {'UserName': 'user', 'GivenName': 'User McStudent'}, 'slots': {}}}, 'User McStudent') - - def test_CourseEnrollments_called(self, canvas_lms_mock, canvas_mock): - event = { - 'res': { - 'result': { - 'args': [ - { - 'query': 'test' - } - ] - } - }, - 'req': { - '_settings': { - 'CanvasLMS_DomainName': 'test.com', - 'CanvasLMS_APIKey': 'test' - }, - '_userInfo': { - 'UserName': 'user', - 'GivenName': 'User McStudent' - }, - 'slots': {} - }, - } - - context = {} - - canvas_lms_mock.validate_input.return_value = False - canvas_lms_mock.get_secret.return_value = { - "CanvasLMS_APIKey": "test", - "CanvasLMS_DomainName": "test.com" - } - canvas_lms_mock.json.loads.return_value = { - "Query": "CourseEnrollments" - } - - event = handler(event, context) - args = canvas_lms_mock.query_enrollments_for_student.call_args.args - canvas_lms_mock.query_enrollments_for_student.assert_called() - self.assertEqual(args[0], {'res': {'result': {'args': [{'query': 'test'}]}}, 'req': {'_settings': {'CanvasLMS_DomainName': 'test.com', 'CanvasLMS_APIKey': 'test'}, '_userInfo': {'UserName': 'user', 'GivenName': 'User McStudent'}, 'slots': {}}}) - self.assertIsInstance(args[1], Mock) - self.assertEqual(args[2], 'user') - - def test_CourseAssignments_called(self, canvas_lms_mock, canvas_mock): - event = { - 'res': { - 'result': { - 'args': [ - { - 'query': 'test' - } - ] - } - }, - 'req': { - '_settings': { - 'CanvasLMS_DomainName': 'test.com', - 'CanvasLMS_APIKey': 'test' - }, - '_userInfo': { - 'UserName': 'user', - 'GivenName': 'User McStudent' - }, - 'slots': {} - }, - } - - context = {} - - canvas_lms_mock.validate_input.return_value = False - canvas_lms_mock.get_secret.return_value = { - "CanvasLMS_APIKey": "test", - "CanvasLMS_DomainName": "test.com" - } - canvas_lms_mock.json.loads.return_value = { - "Query": "CourseAssignments" - } - - event = handler(event, context) - args = canvas_lms_mock.query_course_assignments_for_student.call_args.args - canvas_lms_mock.query_course_assignments_for_student.assert_called() - self.assertEqual(args[0], {'res': {'result': {'args': [{'query': 'test'}]}}, 'req': {'_settings': {'CanvasLMS_DomainName': 'test.com', 'CanvasLMS_APIKey': 'test'}, '_userInfo': {'UserName': 'user', 'GivenName': 'User McStudent'}, 'slots': {}}}) - self.assertIsInstance(args[1], Mock) - self.assertEqual(args[2], 'user') - self.assertEqual(args[3], '') - - def test_SyllabusForCourse_called(self, canvas_lms_mock, canvas_mock): - event = { - 'res': { - 'result': { - 'args': [ - { - 'query': 'test' - } - ] - } - }, - 'req': { - '_settings': { - 'CanvasLMS_DomainName': 'test.com', - 'CanvasLMS_APIKey': 'test' - }, - '_userInfo': { - 'UserName': 'user', - 'GivenName': 'User McStudent' - }, - 'slots': {} - }, - } - - context = {} - - canvas_lms_mock.validate_input.return_value = False - canvas_lms_mock.get_secret.return_value = { - "CanvasLMS_APIKey": "test", - "CanvasLMS_DomainName": "test.com" - } - canvas_lms_mock.json.loads.return_value = { - "Query": "SyllabusForCourse" - } - - event = handler(event, context) - args = canvas_lms_mock.query_syllabus_for_student.call_args.args - canvas_lms_mock.query_syllabus_for_student.assert_called() - self.assertEqual(args[0], {'res': {'result': {'args': [{'query': 'test'}]}}, 'req': {'_settings': {'CanvasLMS_DomainName': 'test.com', 'CanvasLMS_APIKey': 'test'}, '_userInfo': {'UserName': 'user', 'GivenName': 'User McStudent'}, 'slots': {}}}) - self.assertIsInstance(args[1], Mock) - self.assertEqual(args[2], 'user') - self.assertEqual(args[3], '') - - def test_CoursesForStudent_called(self, canvas_lms_mock, canvas_mock): - event = { - 'res': { - 'result': { - 'args': [ - { - 'query': 'test' - } - ] - } - }, - 'req': { - '_settings': { - 'CanvasLMS_DomainName': 'test.com', - 'CanvasLMS_APIKey': 'test' - }, - '_userInfo': { - 'UserName': 'user', - 'GivenName': 'User McStudent' - }, - 'slots': {} - }, - } - - context = {} - - canvas_lms_mock.validate_input.return_value = False - canvas_lms_mock.get_secret.return_value = { - "CanvasLMS_APIKey": "test", - "CanvasLMS_DomainName": "test.com" - } - canvas_lms_mock.json.loads.return_value = { - "Query": "CoursesForStudent" - } - - event = handler(event, context) - args = canvas_lms_mock.query_courses_for_student.call_args.args - canvas_lms_mock.query_courses_for_student.assert_called() - self.assertEqual(args[0], {'res': {'result': {'args': [{'query': 'test'}]}}, 'req': {'_settings': {'CanvasLMS_DomainName': 'test.com', 'CanvasLMS_APIKey': 'test'}, '_userInfo': {'UserName': 'user', 'GivenName': 'User McStudent'}, 'slots': {}}}) - self.assertIsInstance(args[1], Mock) - self.assertEqual(args[2], 'user') - self.assertEqual(args[3], '') - - def test_AnnouncementsForStudent_called(self, canvas_lms_mock, canvas_mock): - event = { - 'res': { - 'result': { - 'args': [ - { - 'query': 'test' - } - ] - } - }, - 'req': { - '_settings': { - 'CanvasLMS_DomainName': 'test.com', - 'CanvasLMS_APIKey': 'test' - }, - '_userInfo': { - 'UserName': 'user', - 'GivenName': 'User McStudent' - }, - 'slots': {} - }, - } - - context = {} - - canvas_lms_mock.validate_input.return_value = False - canvas_lms_mock.get_secret.return_value = { - "CanvasLMS_APIKey": "test", - "CanvasLMS_DomainName": "test.com" - } - canvas_lms_mock.json.loads.return_value = { - "Query": "AnnouncementsForStudent" - } - - event = handler(event, context) - args = canvas_lms_mock.query_announcements_for_student.call_args.args - canvas_lms_mock.query_announcements_for_student.assert_called() - self.assertEqual(args[0], {'res': {'result': {'args': [{'query': 'test'}]}}, 'req': {'_settings': {'CanvasLMS_DomainName': 'test.com', 'CanvasLMS_APIKey': 'test'}, '_userInfo': {'UserName': 'user', 'GivenName': 'User McStudent'}, 'slots': {}}}) - self.assertIsInstance(args[1], Mock) - self.assertEqual(args[2], 'user') - - def test_GradesForStudent_called(self, canvas_lms_mock, canvas_mock): - event = { - 'res': { - 'result': { - 'args': [ - { - 'query': 'test' - } - ] - } - }, - 'req': { - '_settings': { - 'CanvasLMS_DomainName': 'test.com', - 'CanvasLMS_APIKey': 'test' - }, - '_userInfo': { - 'UserName': 'user', - 'GivenName': 'User McStudent' - }, - 'slots': {} - }, - } - - context = {} - - canvas_lms_mock.validate_input.return_value = False - canvas_lms_mock.get_secret.return_value = { - "CanvasLMS_APIKey": "test", - "CanvasLMS_DomainName": "test.com" - } - canvas_lms_mock.json.loads.return_value = { - "Query": "GradesForStudent" - } - - event = handler(event, context) - args = canvas_lms_mock.query_grades_for_student.call_args.args - canvas_lms_mock.query_grades_for_student.assert_called() - self.assertEqual(args[0], {'res': {'result': {'args': [{'query': 'test'}]}}, 'req': {'_settings': {'CanvasLMS_DomainName': 'test.com', 'CanvasLMS_APIKey': 'test'}, '_userInfo': {'UserName': 'user', 'GivenName': 'User McStudent'}, 'slots': {}}}) - self.assertIsInstance(args[1], Mock) - self.assertEqual(args[2], 'user') - self.assertEqual(args[3], '') diff --git a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/pytest.ini b/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/pytest.ini deleted file mode 100644 index b4f64c8ef..000000000 --- a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -testpaths = **/__tests__ \ No newline at end of file diff --git a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/requirements-dev.txt b/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/requirements-dev.txt deleted file mode 100644 index ed98b7883..000000000 --- a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/requirements-dev.txt +++ /dev/null @@ -1,4 +0,0 @@ -moto~=4.2.4 -pytest~=7.4.2 -pytest-cov~=4.1.0 -mock~=5.1.0 \ No newline at end of file diff --git a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/requirements.txt b/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/requirements.txt deleted file mode 100644 index d8ac06c91..000000000 --- a/source/templates/examples/extensions/py_lambda_hooks/CanvasLMSHook/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -canvasapi==3.2.0 -idna==3.7 -requests==2.32.3 -beautifulsoup4==4.12.0 diff --git a/source/templates/examples/extensions/py_lambda_hooks/CustomPYHook/requirements-dev.txt b/source/templates/examples/extensions/py_lambda_hooks/CustomPYHook/requirements-dev.txt index ed98b7883..4f50a96aa 100644 --- a/source/templates/examples/extensions/py_lambda_hooks/CustomPYHook/requirements-dev.txt +++ b/source/templates/examples/extensions/py_lambda_hooks/CustomPYHook/requirements-dev.txt @@ -1,4 +1,4 @@ -moto~=4.2.4 -pytest~=7.4.2 -pytest-cov~=4.1.0 +moto~=5.0.13 +pytest~=8.3.2 +pytest-cov~=5.0.0 mock~=5.1.0 \ No newline at end of file diff --git a/source/templates/examples/extensions/ui_imports/content/CanvasLMSIntegration.json b/source/templates/examples/extensions/ui_imports/content/CanvasLMSIntegration.json deleted file mode 100644 index 450878219..000000000 --- a/source/templates/examples/extensions/ui_imports/content/CanvasLMSIntegration.json +++ /dev/null @@ -1,357 +0,0 @@ -{ - "qna": [{ - "qid": "CanvasLMS.assignments", - "a": "Here is a list of assignments:", - "enableQidIntent": true, - "slots": [{ - "slotName": "CanvasLMS_course_name_slot", - "slotType": "CanvasLMS_course_names_slottype", - "slotPrompt": "For which course would you like to view assignments for?" - }], - "l": "QNA:EXTCanvasLMSHook", - "args": [ - "{\"Query\": \"CourseAssignments\"}" - ], - "type": "qna", - "q": [ - "tell me about my assignments", - "what assignments do i have due", - "what assignments do i have", - "what are my assignments", - "do i have any assignments", - "do i have any assignments due", - "tell me about my {CanvasLMS_course_name_slot} assignments" - ] - }, - { - "qid": "CanvasLMS.syllabus", - "a": "Here is your syllabus:", - "enableQidIntent": true, - "slots": [{ - "slotName": "CanvasLMS_course_name_slot", - "slotType": "CanvasLMS_course_names_slottype", - "slotPrompt": "For which course would you like to view syllabus for?" - }], - "l": "QNA:EXTCanvasLMSHook", - "args": [ - "{\"Query\": \"SyllabusForCourse\"}" - ], - "type": "qna", - "q": [ - "tell me about my syllabus", - "whats my syllabus", - "what is my syllabus", - "tell me about my {CanvasLMS_course_name_slot} syllabus" - ] - }, - { - "qid": "CanvasLMS.menu", - "a": "Please select one of the options:", - "l": "QNA:EXTCanvasLMSHook", - "args": [ - "{\"Query\": \"CanvasMenu\"}" - ], - "type": "qna", - "q": [ - "canvas menu", - "canvas" - ] - }, - { - "qid": "CanvasLMS.enrollments", - "a": "Here are the courses you are enrolled in:", - "enableQidIntent": true, - "l": "QNA:EXTCanvasLMSHook", - "args": [ - "{\"Query\": \"CourseEnrollments\"}" - ], - "type": "qna", - "q": [ - "tell me about my enrollments", - "what courses have i enrolled in", - "course enrollments", - "what are my courses" - ] - }, - { - "qid": "CanvasLMS.announcements", - "a": "Here are your announcements:", - "enableQidIntent": true, - "l": "QNA:EXTCanvasLMSHook", - "args": [ - "{\"Query\": \"AnnouncementsForStudent\"}" - ], - "type": "qna", - "q": [ - "tell me about my announcements", - "do i have any announcements" - ] - }, - { - "qid": "CanvasLMS_course_names_slottype", - "descr": "List of sample course names", - "resolutionStrategyRestrict": true, - "slotTypeValues": [{ - "samplevalue": "accounting" - }, - { - "samplevalue": "american literature" - }, - { - "samplevalue": "american literature history" - }, - { - "samplevalue": "american sign language" - }, - { - "samplevalue": "animal nutrition" - }, - { - "samplevalue": "anthropology " - }, - { - "samplevalue": "business and marketing" - }, - { - "samplevalue": "business communications" - }, - { - "samplevalue": "business ethics" - }, - { - "samplevalue": "business law" - }, - { - "samplevalue": "business management" - }, - { - "samplevalue": "advertising design", - "synonyms": "advertising" - }, - { - "samplevalue": "aerospace engineering", - "synonyms": "aerospace" - }, - { - "samplevalue": "agriculture" - }, - { - "samplevalue": "algebra" - }, - { - "samplevalue": "architectural design" - }, - { - "samplevalue": "art" - }, - { - "samplevalue": "art history" - }, - { - "samplevalue": "astronomy" - }, - { - "samplevalue": "banking and finance", - "synonyms": "banking, finance" - }, - { - "samplevalue": "biology" - }, - { - "samplevalue": "botany" - }, - { - "samplevalue": "chemistry" - }, - { - "samplevalue": "civics" - }, - { - "samplevalue": "civil engineering" - }, - { - "samplevalue": "communications" - }, - { - "samplevalue": "computer and information technology" - }, - { - "samplevalue": "computer science" - }, - { - "samplevalue": "cost accounting" - }, - { - "samplevalue": "creative writing" - }, - { - "samplevalue": "criminal justice" - }, - { - "samplevalue": "cyber security", - "synonyms": "cybersecurity" - }, - { - "samplevalue": "earth and space science", - "synonyms": "earth, space science" - }, - { - "samplevalue": "education" - }, - { - "samplevalue": "electronics" - }, - { - "samplevalue": "environmental science" - }, - { - "samplevalue": "fashion design" - }, - { - "samplevalue": "health science" - }, - { - "samplevalue": "humanities" - }, - { - "samplevalue": "income tax accounting" - }, - { - "samplevalue": "industrial arts" - }, - { - "samplevalue": "industrial design" - }, - { - "samplevalue": "information technology" - }, - { - "samplevalue": "interactive design" - }, - { - "samplevalue": "journalism" - }, - { - "samplevalue": "macro economics", - "synonyms": "macroeconomics" - }, - { - "samplevalue": "micro economics", - "synonyms": "microeconomics" - }, - { - "samplevalue": "micro biology", - "synonyms": "microbiology" - }, - { - "samplevalue": "music" - }, - { - "samplevalue": "nursing" - }, - { - "samplevalue": "nutrition science" - }, - { - "samplevalue": "philosophy" - }, - { - "samplevalue": "photography" - }, - { - "samplevalue": "physics" - }, - { - "samplevalue": "physiology" - }, - { - "samplevalue": "political science" - }, - { - "samplevalue": "public policy" - }, - { - "samplevalue": "public safety" - }, - { - "samplevalue": "robotics" - }, - { - "samplevalue": "science" - }, - { - "samplevalue": "social media" - }, - { - "samplevalue": "social science" - }, - { - "samplevalue": "social studies" - }, - { - "samplevalue": "statistics" - }, - { - "samplevalue": "travel and tourism", - "synonyms": "travel, tourism" - }, - { - "samplevalue": "visual arts" - }, - { - "samplevalue": "world history" - }, - { - "samplevalue": "zoology" - } - - ], - "type": "slottype", - "_id": "CanvasLMS_course_names_slottype" - }, - { - "qid": "CanvasLMS.course", - "a": "Please select one of the options:", - "enableQidIntent": true, - "slots": [{ - "slotRequired": true, - "slotName": "CanvasLMS_course_name_slot", - "slotType": "CanvasLMS_course_names_slottype", - "slotPrompt": "For which course would you like more information on?" - }], - "l": "QNA:EXTCanvasLMSHook", - "args": [ - "{\"Query\": \"CoursesForStudent\"}" - ], - "type": "qna", - "q": [ - "more info about my course", - "more information about my course", - "more information on {CanvasLMS_course_name_slot} course", - "more info on {CanvasLMS_course_name_slot}", - "more information about my {CanvasLMS_course_name_slot} course" - ] - }, - { - "qid": "CanvasLMS.grades", - "a": "Here are your grades:", - "enableQidIntent": true, - "slots": [{ - "slotName": "CanvasLMS_course_name_slot", - "slotType": "CanvasLMS_course_names_slottype", - "slotPrompt": "For which course would you like to view grades for?" - }], - "l": "QNA:EXTCanvasLMSHook", - "args": [ - "{\"Query\": \"GradesForStudent\"}" - ], - "type": "qna", - "q": [ - "tell me about my grades", - "what are my grades", - "how did i do in {CanvasLMS_course_name_slot}", - "tell me about my {CanvasLMS_course_name_slot} grades" - ] - } - ] -} \ No newline at end of file diff --git a/source/templates/examples/extensions/ui_imports/content/CanvasLMSIntegration.txt b/source/templates/examples/extensions/ui_imports/content/CanvasLMSIntegration.txt deleted file mode 100644 index 1ff8cef73..000000000 --- a/source/templates/examples/extensions/ui_imports/content/CanvasLMSIntegration.txt +++ /dev/null @@ -1,4 +0,0 @@ -NOTICE: Canvas LMS integration with QnABot on AWS is deprecated in this release and no longer be supported. Customers may fork the code needed for their specific use case from previous versions. The integration code will be removed in the next release. - - -Imports sample questions for interacting with Canvas LMS. More details: https://github.com/aws-solutions/qnabot-on-aws/blob/main/docs/canvaslms_integration.md \ No newline at end of file diff --git a/source/templates/examples/extensions/ui_imports/package-lock.json b/source/templates/examples/extensions/ui_imports/package-lock.json index a5c815c96..4d6d30c7b 100644 --- a/source/templates/examples/extensions/ui_imports/package-lock.json +++ b/source/templates/examples/extensions/ui_imports/package-lock.json @@ -1,16 +1,16 @@ { "name": "ui_import", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "ui_import", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "cfn-response": "^1.0.1", - "handlebars": "^4.7.7", + "handlebars": "^4.7.8", "lodash": "^4.17.21" } }, @@ -19,19 +19,14 @@ "resolved": "https://registry.npmjs.org/cfn-response/-/cfn-response-1.0.1.tgz", "integrity": "sha1-qOwDlQwGg8UUlejKaA2dwLiEsTc=" }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "optional": true - }, "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", "dependencies": { "minimist": "^1.2.5", - "neo-async": "^2.6.0", + "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, @@ -56,9 +51,10 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" }, "node_modules/source-map": { "version": "0.6.1", @@ -69,13 +65,11 @@ } }, "node_modules/uglify-js": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.4.tgz", - "integrity": "sha512-8RZBJq5smLOa7KslsNsVcSH+KOXf1uDU8yqLeNuVKwmT0T3FA0ZoXlinQfRad7SDcbZZRZE4ov+2v71EnxNyCA==", + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.2.tgz", + "integrity": "sha512-S8KA6DDI47nQXJSi2ctQ629YzwOVs+bQML6DAtvy0wgNdpi+0ySpQK0g2pxBq2xfF2z3YCscu7NNA8nXT9PlIQ==", + "license": "BSD-2-Clause", "optional": true, - "dependencies": { - "commander": "~2.20.3" - }, "bin": { "uglifyjs": "bin/uglifyjs" }, @@ -95,21 +89,15 @@ "resolved": "https://registry.npmjs.org/cfn-response/-/cfn-response-1.0.1.tgz", "integrity": "sha1-qOwDlQwGg8UUlejKaA2dwLiEsTc=" }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "optional": true - }, "handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "requires": { "minimist": "^1.2.5", - "neo-async": "^2.6.0", + "neo-async": "^2.6.2", "source-map": "^0.6.1", - "uglify-js": "^3.1.4", + "uglify-js": "^3.19.2", "wordwrap": "^1.0.0" } }, @@ -124,9 +112,9 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "source-map": { "version": "0.6.1", @@ -134,13 +122,10 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "uglify-js": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.4.tgz", - "integrity": "sha512-8RZBJq5smLOa7KslsNsVcSH+KOXf1uDU8yqLeNuVKwmT0T3FA0ZoXlinQfRad7SDcbZZRZE4ov+2v71EnxNyCA==", - "optional": true, - "requires": { - "commander": "~2.20.3" - } + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.2.tgz", + "integrity": "sha512-S8KA6DDI47nQXJSi2ctQ629YzwOVs+bQML6DAtvy0wgNdpi+0ySpQK0g2pxBq2xfF2z3YCscu7NNA8nXT9PlIQ==", + "optional": true }, "wordwrap": { "version": "1.0.0", diff --git a/source/templates/examples/extensions/ui_imports/package.json b/source/templates/examples/extensions/ui_imports/package.json index 6c28fb482..d92cbb362 100644 --- a/source/templates/examples/extensions/ui_imports/package.json +++ b/source/templates/examples/extensions/ui_imports/package.json @@ -1,6 +1,6 @@ { "name": "ui_import", - "version": "6.0.3", + "version": "6.1.0", "description": "Add new content packages for Content Designer Import Examples/Extensions listing", "main": "ui_import.js", "scripts": { @@ -13,7 +13,10 @@ "license": "Apache-2.0", "dependencies": { "cfn-response": "^1.0.1", - "handlebars": "^4.7.7", + "handlebars": "^4.7.8", "lodash": "^4.17.21" + }, + "overrides": { + "uglify-js": "^3.19.2" } } diff --git a/source/templates/examples/index.js b/source/templates/examples/index.js index 041aed946..52d9edb70 100644 --- a/source/templates/examples/index.js +++ b/source/templates/examples/index.js @@ -45,12 +45,12 @@ module.exports = { QIDLambdaArn: { Type: 'String' }, VPCSubnetIdList: { Type: 'String' }, VPCSecurityGroupIdList: { Type: 'String' }, - LexBotVersion: { Type: 'String' }, XraySetting: { Type: 'String' }, DefaultQnABotSettings: { Type: 'String' }, PrivateQnABotSettings: { Type: 'String' }, InstallLexResponseBots: { Type: 'String' }, AwsSdkLayerLambdaLayer: { Type: 'String' }, + LogRetentionPeriod: { Type: 'Number' }, }, Conditions: { VPCEnabled: { @@ -59,8 +59,7 @@ module.exports = { ], }, XRAYEnabled: { 'Fn::Equals': [{ Ref: 'XraySetting' }, 'TRUE'] }, - CreateLexV1Bots: { 'Fn::Equals': [{ Ref: 'LexBotVersion' }, 'LexV1 and LexV2'] }, CreateLexResponseBots: { 'Fn::Equals': [{ Ref: 'InstallLexResponseBots' }, 'true'] }, - CreateLexV1ResponseBots: { 'Fn::And': [{ Condition: 'CreateLexResponseBots' }, { Condition: 'CreateLexV1Bots' }] }, + LogRetentionPeriodIsNotZero: { 'Fn::Not': [{ 'Fn::Equals': [{ Ref: 'LogRetentionPeriod' }, 0] }] }, }, }; diff --git a/source/templates/examples/index.test.js b/source/templates/examples/index.test.js index b7e597d4f..4bfbe2c66 100644 --- a/source/templates/examples/index.test.js +++ b/source/templates/examples/index.test.js @@ -15,18 +15,11 @@ function create() { const file = `${__dirname}/`; return require(file); } -// NOTICE: Canvas LMS integration with QnABot on AWS is deprecated in this release and no longer be supported. Customers may fork the code needed for their specific use case from previous versions. The integration code will be removed in the next release. - it('renders examples template correctly', () => { const template = create(); expect(template).toMatchSnapshot({ Resources: { - CodeVersionCanvasLMSHook: { - Properties: { - BuildDate: expect.any(String), - }, - }, CodeVersionCreateRecentTopicsResponse: { Properties: { BuildDate: expect.any(String), diff --git a/source/templates/export/__snapshots__/index.test.js.snap b/source/templates/export/__snapshots__/index.test.js.snap index 5c69a4809..0a46c5ef8 100644 --- a/source/templates/export/__snapshots__/index.test.js.snap +++ b/source/templates/export/__snapshots__/index.test.js.snap @@ -28,6 +28,18 @@ exports[`renders export template correctly 1`] = ` }, ], }, + "LogRetentionPeriodIsNotZero": { + "Fn::Not": [ + { + "Fn::Equals": [ + { + "Ref": "LogRetentionPeriod", + }, + 0, + ], + }, + ], + }, "VPCEnabled": { "Fn::Not": [ { @@ -70,15 +82,15 @@ exports[`renders export template correctly 1`] = ` "BootstrapPrefix": { "Type": "String", }, - "BotName": { - "Type": "String", - }, "CFNInvokePolicy": { "Type": "String", }, "CFNLambda": { "Type": "String", }, + "ContentDesignerOutputBucket": { + "Type": "String", + }, "CustomQnABotSettings": { "Type": "String", }, @@ -94,12 +106,6 @@ exports[`renders export template correctly 1`] = ` "ExportBucket": { "Type": "String", }, - "FallbackIntent": { - "Type": "String", - }, - "Intent": { - "Type": "String", - }, "KendraCrawlerSnsTopic": { "Type": "String", }, @@ -127,6 +133,9 @@ exports[`renders export template correctly 1`] = ` "LexVersion": { "Type": "String", }, + "LogRetentionPeriod": { + "Type": "Number", + }, "PrivateQnABotSettings": { "Type": "String", }, @@ -314,15 +323,6 @@ exports[`renders export template correctly 1`] = ` "accountId": { "Ref": "AWS::AccountId", }, - "fallBackIntent": { - "Ref": "FallbackIntent", - }, - "intent": { - "Ref": "Intent", - }, - "lexBot": { - "Ref": "BotName", - }, "outputBucket": { "Ref": "ExportBucket", }, @@ -338,6 +338,11 @@ exports[`renders export template correctly 1`] = ` "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ConnectLambdaLogGroup", + }, + }, "MemorySize": "1024", "Role": { "Fn::GetAtt": [ @@ -393,6 +398,53 @@ exports[`renders export template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, + "ConnectLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ConnectLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "Deployment": { "DeletionPolicy": "Retain", "DependsOn": [ @@ -473,6 +525,9 @@ exports[`renders export template correctly 1`] = ` { "Fn::Sub": "arn:aws:s3:::\${ExportBucket}*", }, + { + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}*", + }, ], }, { @@ -680,6 +735,9 @@ exports[`renders export template correctly 1`] = ` "ES_PROXY": { "Ref": "EsProxyLambda", }, + "OUTPUT_S3_BUCKET": { + "Ref": "ContentDesignerOutputBucket", + }, "SOLUTION_ID": "SO0189", "SOLUTION_VERSION": "vx.x.x", }, @@ -690,6 +748,11 @@ exports[`renders export template correctly 1`] = ` "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ExportStepLambdaLogGroup", + }, + }, "MemorySize": "1024", "Role": { "Fn::GetAtt": [ @@ -745,6 +808,53 @@ exports[`renders export template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, + "ExportStepLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ExportStepLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "ExportStepPermission": { "Properties": { "Action": "lambda:InvokeFunction", @@ -780,7 +890,7 @@ exports[`renders export template correctly 1`] = ` "FilterRules": [ { "Name": "prefix", - "Value": "status", + "Value": "status-export", }, ], }, @@ -792,27 +902,6 @@ exports[`renders export template correctly 1`] = ` ], }, }, - { - "Events": [ - "s3:ObjectCreated:*", - ], - "Filter": { - "Key": { - "FilterRules": [ - { - "Name": "prefix", - "Value": "kendra-data", - }, - ], - }, - }, - "LambdaFunctionArn": { - "Fn::GetAtt": [ - "KendraSyncLambda", - "Arn", - ], - }, - }, ], }, "ServiceToken": { @@ -946,15 +1035,6 @@ exports[`renders export template correctly 1`] = ` "accountId": { "Ref": "AWS::AccountId", }, - "fallBackIntent": { - "Ref": "FallbackIntent", - }, - "intent": { - "Ref": "Intent", - }, - "lexBot": { - "Ref": "BotName", - }, "outputBucket": { "Ref": "ExportBucket", }, @@ -970,6 +1050,11 @@ exports[`renders export template correctly 1`] = ` "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "GenesysLambdaLogGroup", + }, + }, "MemorySize": "1024", "Role": { "Fn::GetAtt": [ @@ -1025,6 +1110,53 @@ exports[`renders export template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, + "GenesysLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-GenesysLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "InvokePermissionConnectLambda": { "Properties": { "Action": "lambda:InvokeFunction", @@ -1267,6 +1399,11 @@ exports[`renders export template correctly 1`] = ` }, }, "Handler": "kendra_webcrawler.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "KendraNativeCrawlerLambdaLogGroup", + }, + }, "MemorySize": "2048", "Role": { "Fn::GetAtt": [ @@ -1322,6 +1459,53 @@ exports[`renders export template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, + "KendraNativeCrawlerLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-KendraNativeCrawlerLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "KendraNativeCrawlerLambdaStatusInvokePermission": { "Properties": { "Action": "lambda:InvokeFunction", @@ -1812,6 +1996,11 @@ exports[`renders export template correctly 1`] = ` }, }, "Handler": "kendra_webcrawler_schedule_updater.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "KendraNativeCrawlerScheduleUpdateLambdaLogGroup", + }, + }, "MemorySize": "2048", "Role": { "Fn::GetAtt": [ @@ -1867,6 +2056,53 @@ exports[`renders export template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, + "KendraNativeCrawlerScheduleUpdateLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-KendraNativeCrawlerScheduleUpdateLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "KendraNativeCrawlerStatusCodeVersion": { "Properties": { "Bucket": { @@ -1971,6 +2207,11 @@ exports[`renders export template correctly 1`] = ` }, }, "Handler": "kendra_webcrawler_status.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "KendraNativeCrawlerStatusLambdaLogGroup", + }, + }, "MemorySize": "2048", "Role": { "Fn::GetAtt": [ @@ -2026,6 +2267,53 @@ exports[`renders export template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, + "KendraNativeCrawlerStatusLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-KendraNativeCrawlerStatusLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "KendraS3Policy": { "Condition": "CreateKendraSyncPolicy", "Properties": { @@ -2038,10 +2326,10 @@ exports[`renders export template correctly 1`] = ` "Effect": "Allow", "Resource": [ { - "Fn::Sub": "arn:aws:s3:::\${ExportBucket}", + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}", }, { - "Fn::Sub": "arn:aws:s3:::\${ExportBucket}/*", + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}/*", }, ], }, @@ -2269,7 +2557,7 @@ exports[`renders export template correctly 1`] = ` ], }, "OUTPUT_S3_BUCKET": { - "Ref": "ExportBucket", + "Ref": "ContentDesignerOutputBucket", }, "PRIVATE_SETTINGS_PARAM": { "Ref": "PrivateQnABotSettings", @@ -2290,6 +2578,11 @@ exports[`renders export template correctly 1`] = ` "Ref": "QnABotCommonLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "KendraSyncLambdaLogGroup", + }, + }, "MemorySize": "1024", "Role": { "Fn::GetAtt": [ @@ -2345,6 +2638,53 @@ exports[`renders export template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, + "KendraSyncLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-KendraSyncLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "KendraSyncPermission": { "Properties": { "Action": "lambda:InvokeFunction", @@ -2359,7 +2699,7 @@ exports[`renders export template correctly 1`] = ` "Ref": "AWS::AccountId", }, "SourceArn": { - "Fn::Sub": "arn:aws:s3:::\${ExportBucket}", + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}", }, }, "Type": "AWS::Lambda::Permission", @@ -2378,10 +2718,10 @@ exports[`renders export template correctly 1`] = ` "Effect": "Allow", "Resource": [ { - "Fn::Sub": "arn:aws:s3:::\${ExportBucket}", + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}", }, { - "Fn::Sub": "arn:aws:s3:::\${ExportBucket}/*", + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}/*", }, ], }, @@ -2598,6 +2938,42 @@ exports[`renders export template correctly 1`] = ` }, "Type": "AWS::IAM::Role", }, + "KendraSyncS3Trigger": { + "Properties": { + "Bucket": { + "Ref": "ContentDesignerOutputBucket", + }, + "NotificationConfiguration": { + "LambdaFunctionConfigurations": [ + { + "Events": [ + "s3:ObjectCreated:*", + ], + "Filter": { + "Key": { + "FilterRules": [ + { + "Name": "prefix", + "Value": "kendra-data-export", + }, + ], + }, + }, + "LambdaFunctionArn": { + "Fn::GetAtt": [ + "KendraSyncLambda", + "Arn", + ], + }, + }, + ], + }, + "ServiceToken": { + "Ref": "CFNLambda", + }, + }, + "Type": "Custom::S3Lambda", + }, "KendraTopicApiGateRole": { "Metadata": { "cfn_nag": { @@ -2787,6 +3163,11 @@ exports[`renders export template correctly 1`] = ` "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "TranslateLambdaLogGroup", + }, + }, "MemorySize": "1024", "Role": { "Fn::GetAtt": [ @@ -2842,6 +3223,53 @@ exports[`renders export template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, + "TranslateLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-TranslateLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "TranslatePolicy": { "Metadata": { "cfn_nag": { diff --git a/source/templates/export/bucket.js b/source/templates/export/bucket.js index 307e0a7cd..48a7fbcc4 100644 --- a/source/templates/export/bucket.js +++ b/source/templates/export/bucket.js @@ -25,22 +25,11 @@ module.exports = { Key: { FilterRules: [{ Name: 'prefix', - Value: 'status', + Value: 'status-export', }], }, }, - }, { - LambdaFunctionArn: { 'Fn::GetAtt': ['KendraSyncLambda', 'Arn'] }, - Events: ['s3:ObjectCreated:*'], - Filter: { - Key: { - FilterRules: [{ - Name: 'prefix', - Value: 'kendra-data', - }], - }, - }, - }, + } ], }, }, @@ -55,6 +44,28 @@ module.exports = { SourceArn: { 'Fn::Sub': 'arn:aws:s3:::${ExportBucket}' }, }, }, + KendraSyncS3Trigger: { + Type: 'Custom::S3Lambda', + Properties: { + ServiceToken: { Ref: 'CFNLambda' }, + Bucket: { Ref: 'ContentDesignerOutputBucket' }, + NotificationConfiguration: { + LambdaFunctionConfigurations: [{ + LambdaFunctionArn: { 'Fn::GetAtt': ['KendraSyncLambda', 'Arn'] }, + Events: ['s3:ObjectCreated:*'], + Filter: { + Key: { + FilterRules: [{ + Name: 'prefix', + Value: 'kendra-data-export', + }], + }, + }, + }, + ], + }, + }, + }, KendraSyncPermission: { Type: 'AWS::Lambda::Permission', Properties: { @@ -62,7 +73,7 @@ module.exports = { Action: 'lambda:InvokeFunction', Principal: 's3.amazonaws.com', SourceAccount: { Ref: 'AWS::AccountId' }, - SourceArn: { 'Fn::Sub': 'arn:aws:s3:::${ExportBucket}' }, + SourceArn: { 'Fn::Sub': 'arn:aws:s3:::${ContentDesignerOutputBucket}' }, }, }, diff --git a/source/templates/export/index.js b/source/templates/export/index.js index 6e5999f15..113d193e8 100644 --- a/source/templates/export/index.js +++ b/source/templates/export/index.js @@ -25,6 +25,7 @@ module.exports = { Description: `(SO0189n-export) QnABot nested export resources - Version v${process.env.npm_package_version}`, Outputs: require('./outputs'), Parameters: { + ContentDesignerOutputBucket: { Type: 'String' }, CFNLambda: { Type: 'String' }, CFNInvokePolicy: { Type: 'String' }, S3Clean: { Type: 'String' }, @@ -35,10 +36,6 @@ module.exports = { EsProxyLambda: { Type: 'String' }, ExportBucket: { Type: 'String' }, LexVersion: { Type: 'String' }, - // Lex V1 - FallbackIntent: { Type: 'String' }, - Intent: { Type: 'String' }, - BotName: { Type: 'String' }, // Lex V2 LexV2BotName: { Type: 'String' }, LexV2BotId: { Type: 'String' }, @@ -60,6 +57,7 @@ module.exports = { QnABotCommonLambdaLayer: { Type: 'String' }, KendraFaqIndexId: { Type: 'String' }, KendraWebPageIndexId: { Type: 'String' }, + LogRetentionPeriod: { Type: 'Number' }, }, Conditions: { VPCEnabled: { @@ -70,5 +68,6 @@ module.exports = { XRAYEnabled: { 'Fn::Equals': [{ Ref: 'XraySetting' }, 'TRUE'] }, CreateKendraSyncPolicy: { 'Fn::Not': [{ 'Fn::Equals': [{ Ref: 'KendraFaqIndexId' }, ''] }] }, CreateKendraCrawlerPolicy: { 'Fn::Not': [{ 'Fn::Equals': [{ Ref: 'KendraWebPageIndexId' }, ''] }] }, + LogRetentionPeriodIsNotZero: { 'Fn::Not': [{ 'Fn::Equals': [{ Ref: 'LogRetentionPeriod' }, 0] }] } }, }; diff --git a/source/templates/export/resources.js b/source/templates/export/resources.js index d2c1b99a9..4c3d10f5c 100644 --- a/source/templates/export/resources.js +++ b/source/templates/export/resources.js @@ -35,6 +35,30 @@ module.exports = { BuildDate: new Date().toISOString(), }, }, + ConnectLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ConnectLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ConnectLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -50,10 +74,6 @@ module.exports = { accountId: { Ref: 'AWS::AccountId' }, region: { Ref: 'AWS::Region' }, LexVersion: { Ref: 'LexVersion' }, - // Lex V1 - fallBackIntent: { Ref: 'FallbackIntent' }, - intent: { Ref: 'Intent' }, - lexBot: { Ref: 'BotName' }, // Lex V2 LexV2BotName: { Ref: 'LexV2BotName' }, LexV2BotId: { Ref: 'LexV2BotId' }, @@ -63,6 +83,9 @@ module.exports = { }, }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: "ConnectLambdaLogGroup" }, + }, MemorySize: '1024', Role: { 'Fn::GetAtt': ['ExportRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -119,6 +142,30 @@ module.exports = { BuildDate: new Date().toISOString(), }, }, + GenesysLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-GenesysLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, GenesysLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -134,10 +181,6 @@ module.exports = { accountId: { Ref: 'AWS::AccountId' }, region: { Ref: 'AWS::Region' }, LexVersion: { Ref: 'LexVersion' }, - // Lex V1 - fallBackIntent: { Ref: 'FallbackIntent' }, - intent: { Ref: 'Intent' }, - lexBot: { Ref: 'BotName' }, // Lex V2 LexV2BotName: { Ref: 'LexV2BotName' }, LexV2BotId: { Ref: 'LexV2BotId' }, @@ -147,6 +190,9 @@ module.exports = { }, }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'GenesysLambdaLogGroup' }, + }, MemorySize: '1024', Role: { 'Fn::GetAtt': ['ExportRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -191,7 +237,7 @@ module.exports = { Action: 'lambda:InvokeFunction', FunctionName: { 'Fn::GetAtt': ['GenesysLambda', 'Arn'] }, Principal: 'apigateway.amazonaws.com', - SourceAccount: { Ref: 'AWS::AccountId' }, + SourceAccount: { Ref: 'AWS::AccountId' }, }, }, Deployment: { @@ -299,6 +345,30 @@ module.exports = { BuildDate: new Date().toISOString(), }, }, + ExportStepLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ExportStepLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ExportStepLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -312,10 +382,14 @@ module.exports = { ES_INDEX: { Ref: 'VarIndex' }, ES_ENDPOINT: { Ref: 'EsEndpoint' }, ES_PROXY: { Ref: 'EsProxyLambda' }, - ...util.getCommonEnvironmentVariables() + OUTPUT_S3_BUCKET: { Ref: 'ContentDesignerOutputBucket' }, + ...util.getCommonEnvironmentVariables(), }, }, Handler: 'index.step', + LoggingConfig: { + LogGroup: { Ref: 'ExportStepLambdaLogGroup' }, + }, MemorySize: '1024', Role: { 'Fn::GetAtt': ['ExportRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -389,7 +463,8 @@ module.exports = { 's3:DeleteObject', 's3:GetObjectVersion', ], - Resource: [{ 'Fn::Sub': 'arn:aws:s3:::${ExportBucket}*' }], + Resource: [{ 'Fn::Sub': 'arn:aws:s3:::${ExportBucket}*' }, + { 'Fn::Sub': 'arn:aws:s3:::${ContentDesignerOutputBucket}*' }], }, { Effect: 'Allow', @@ -408,6 +483,30 @@ module.exports = { Bucket: { Ref: 'ExportBucket' }, }, }, + KendraSyncLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-KendraSyncLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, KendraSyncLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -421,7 +520,7 @@ module.exports = { DEFAULT_SETTINGS_PARAM: { Ref: 'DefaultQnABotSettings' }, PRIVATE_SETTINGS_PARAM: { Ref: 'PrivateQnABotSettings' }, CUSTOM_SETTINGS_PARAM: { Ref: 'CustomQnABotSettings' }, - OUTPUT_S3_BUCKET: { Ref: 'ExportBucket' }, + OUTPUT_S3_BUCKET: { Ref: 'ContentDesignerOutputBucket' }, KENDRA_ROLE: { 'Fn::GetAtt': ['KendraS3Role', 'Arn'] }, REGION: { Ref: 'AWS::Region' }, ...util.getCommonEnvironmentVariables(), @@ -429,6 +528,9 @@ module.exports = { }, Layers: [{ Ref: 'AwsSdkLayerLambdaLayer' }, { Ref: 'QnABotCommonLambdaLayer' }], Handler: 'kendraSync.performSync', + LoggingConfig: { + LogGroup: { Ref: 'KendraSyncLambdaLogGroup' }, + }, MemorySize: '1024', Role: { 'Fn::GetAtt': ['KendraSyncRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -508,8 +610,8 @@ module.exports = { 's3:List*', ], Resource: [ - { 'Fn::Sub': 'arn:aws:s3:::${ExportBucket}' }, - { 'Fn::Sub': 'arn:aws:s3:::${ExportBucket}/*' }, + { 'Fn::Sub': 'arn:aws:s3:::${ContentDesignerOutputBucket}' }, + { 'Fn::Sub': 'arn:aws:s3:::${ContentDesignerOutputBucket}/*' }, ], }, { @@ -655,6 +757,30 @@ module.exports = { BuildDate: new Date().toISOString(), }, }, + TranslateLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-TranslateLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, TranslateLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -670,6 +796,9 @@ module.exports = { }, }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'TranslateLambdaLogGroup' }, + }, MemorySize: '1024', Role: { 'Fn::GetAtt': ['TranslateRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -874,8 +1003,8 @@ module.exports = { Effect: 'Allow', Action: ['s3:GetObject'], Resource: [ - { 'Fn::Sub': 'arn:aws:s3:::${ExportBucket}' }, - { 'Fn::Sub': 'arn:aws:s3:::${ExportBucket}/*' }, + { 'Fn::Sub': 'arn:aws:s3:::${ContentDesignerOutputBucket}' }, + { 'Fn::Sub': 'arn:aws:s3:::${ContentDesignerOutputBucket}/*' }, ], }, { @@ -1021,6 +1150,30 @@ module.exports = { SourceAccount: { Ref: 'AWS::AccountId' }, }, }, + KendraNativeCrawlerLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-KendraNativeCrawlerLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, KendraNativeCrawlerLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -1076,6 +1229,9 @@ module.exports = { }, }, Handler: 'kendra_webcrawler.handler', + LoggingConfig: { + LogGroup: { Ref: 'KendraNativeCrawlerLambdaLogGroup' }, + }, MemorySize: '2048', Role: { 'Fn::GetAtt': ['KendraNativeCrawlerRole', 'Arn'] }, Runtime: process.env.npm_package_config_pythonRuntime, @@ -1110,6 +1266,30 @@ module.exports = { BuildDate: new Date().toISOString(), }, }, + KendraNativeCrawlerScheduleUpdateLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-KendraNativeCrawlerScheduleUpdateLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, KendraNativeCrawlerScheduleUpdateLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -1153,6 +1333,9 @@ module.exports = { }, }, Handler: 'kendra_webcrawler_schedule_updater.handler', + LoggingConfig: { + LogGroup: { Ref: 'KendraNativeCrawlerScheduleUpdateLambdaLogGroup' }, + }, MemorySize: '2048', Role: { 'Fn::GetAtt': ['KendraNativeCrawlerRole', 'Arn'] }, Runtime: process.env.npm_package_config_pythonRuntime, @@ -1169,6 +1352,30 @@ module.exports = { guard: util.cfnGuard('LAMBDA_CONCURRENCY_CHECK', 'LAMBDA_INSIDE_VPC'), }, }, + KendraNativeCrawlerStatusLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-KendraNativeCrawlerStatusLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, KendraNativeCrawlerStatusLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -1223,6 +1430,9 @@ module.exports = { }, }, Handler: 'kendra_webcrawler_status.handler', + LoggingConfig: { + LogGroup: { Ref: 'KendraNativeCrawlerStatusLambdaLogGroup' }, + }, MemorySize: '2048', Role: { 'Fn::GetAtt': ['KendraNativeCrawlerRole', 'Arn'] }, Runtime: process.env.npm_package_config_pythonRuntime, diff --git a/source/templates/import/UpgradeAutoImport.js b/source/templates/import/UpgradeAutoImport.js index a80ed1162..c3357fbbb 100644 --- a/source/templates/import/UpgradeAutoImport.js +++ b/source/templates/import/UpgradeAutoImport.js @@ -27,6 +27,7 @@ module.exports = { ServiceToken: { Ref: 'CFNLambda' }, importbucket: { Ref: 'ImportBucket' }, exportbucket: { Ref: 'ExportBucket' }, + contentDesignerOutputBucket : { Ref: 'ContentDesignerOutputBucket' }, id: exportfile, index: { Ref: 'VarIndex' }, es_endpoint: { Ref: 'EsEndpoint' }, @@ -40,6 +41,7 @@ module.exports = { ServiceToken: { Ref: 'CFNLambda' }, importbucket: { Ref: 'ImportBucket' }, exportbucket: { Ref: 'ExportBucket' }, + contentDesignerOutputBucket : { Ref: 'ContentDesignerOutputBucket' }, id: exportfile_metrics, index: { Ref: 'MetricsIndex' }, es_endpoint: { Ref: 'EsEndpoint' }, @@ -52,6 +54,7 @@ module.exports = { ServiceToken: { Ref: 'CFNLambda' }, importbucket: { Ref: 'ImportBucket' }, exportbucket: { Ref: 'ExportBucket' }, + contentDesignerOutputBucket : { Ref: 'ContentDesignerOutputBucket' }, id: exportfile_feedback, index: { Ref: 'FeedbackIndex' }, es_endpoint: { Ref: 'EsEndpoint' }, diff --git a/source/templates/import/__snapshots__/index.test.js.snap b/source/templates/import/__snapshots__/index.test.js.snap index a26fa18dd..3ee6fa585 100644 --- a/source/templates/import/__snapshots__/index.test.js.snap +++ b/source/templates/import/__snapshots__/index.test.js.snap @@ -36,6 +36,18 @@ exports[`renders import template correctly 1`] = ` }, ], }, + "LogRetentionPeriodIsNotZero": { + "Fn::Not": [ + { + "Fn::Equals": [ + { + "Ref": "LogRetentionPeriod", + }, + 0, + ], + }, + ], + }, "VPCEnabled": { "Fn::Not": [ { @@ -78,6 +90,9 @@ exports[`renders import template correctly 1`] = ` "CommonModulesLambdaLayer": { "Type": "String", }, + "ContentDesignerOutputBucket": { + "Type": "String", + }, "CustomQnABotSettings": { "Type": "String", }, @@ -123,6 +138,9 @@ exports[`renders import template correctly 1`] = ` "ImportBucket": { "Type": "String", }, + "LogRetentionPeriod": { + "Type": "Number", + }, "MetricsIndex": { "Type": "String", }, @@ -195,6 +213,9 @@ exports[`renders import template correctly 1`] = ` { "Fn::Sub": "arn:aws:s3:::\${ImportBucket}*", }, + { + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}*", + }, ], }, { @@ -503,6 +524,9 @@ exports[`renders import template correctly 1`] = ` { "Fn::Sub": "arn:\${AWS::Partition}:bedrock:\${AWS::Region}::foundation-model/cohere.embed-multilingual-v3", }, + { + "Fn::Sub": "arn:\${AWS::Partition}:bedrock:\${AWS::Region}::foundation-model/amazon.titan-embed-text-v2:0", + }, ], }, ], @@ -565,6 +589,9 @@ exports[`renders import template correctly 1`] = ` "ES_PROXY": { "Ref": "EsProxyLambda", }, + "OUTPUT_S3_BUCKET": { + "Ref": "ContentDesignerOutputBucket", + }, "PRIVATE_SETTINGS_PARAM": { "Ref": "PrivateQnABotSettings", }, @@ -588,6 +615,11 @@ exports[`renders import template correctly 1`] = ` "Ref": "QnABotCommonLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ImportStartLambdaLogGroup", + }, + }, "MemorySize": "1024", "Role": { "Fn::GetAtt": [ @@ -643,6 +675,53 @@ exports[`renders import template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, + "ImportStartLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ImportStartLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "ImportStartPermission": { "Properties": { "Action": "lambda:InvokeFunction", @@ -717,6 +796,9 @@ exports[`renders import template correctly 1`] = ` "ES_PROXY": { "Ref": "EsProxyLambda", }, + "OUTPUT_S3_BUCKET": { + "Ref": "ContentDesignerOutputBucket", + }, "PRIVATE_SETTINGS_PARAM": { "Ref": "PrivateQnABotSettings", }, @@ -739,6 +821,11 @@ exports[`renders import template correctly 1`] = ` "Ref": "QnABotCommonLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ImportStepLambdaLogGroup", + }, + }, "MemorySize": "1024", "Role": { "Fn::GetAtt": [ @@ -794,6 +881,53 @@ exports[`renders import template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, + "ImportStepLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ImportStepLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "ImportStepPermission": { "Properties": { "Action": "lambda:InvokeFunction", @@ -881,6 +1015,9 @@ exports[`renders import template correctly 1`] = ` "ServiceToken": { "Ref": "CFNLambda", }, + "contentDesignerOutputBucket": { + "Ref": "ContentDesignerOutputBucket", + }, "es_endpoint": { "Ref": "EsEndpoint", }, @@ -905,6 +1042,9 @@ exports[`renders import template correctly 1`] = ` "ServiceToken": { "Ref": "CFNLambda", }, + "contentDesignerOutputBucket": { + "Ref": "ContentDesignerOutputBucket", + }, "es_endpoint": { "Ref": "EsEndpoint", }, @@ -929,6 +1069,9 @@ exports[`renders import template correctly 1`] = ` "ServiceToken": { "Ref": "CFNLambda", }, + "contentDesignerOutputBucket": { + "Ref": "ContentDesignerOutputBucket", + }, "es_endpoint": { "Ref": "EsEndpoint", }, diff --git a/source/templates/import/index.js b/source/templates/import/index.js index a006df1b7..01fdc1e4f 100644 --- a/source/templates/import/index.js +++ b/source/templates/import/index.js @@ -26,6 +26,7 @@ module.exports = { Description: `(SO0189n-import) QnABot nested import resources - Version v${process.env.npm_package_version}`, Outputs: require('./outputs'), Parameters: { + ContentDesignerOutputBucket: { Type: 'String' }, CFNLambda: { Type: 'String' }, CFNInvokePolicy: { Type: 'String' }, S3Clean: { Type: 'String' }, @@ -55,6 +56,7 @@ module.exports = { CommonModulesLambdaLayer: { Type: 'String' }, EsProxyLambdaLayer: { Type: 'String' }, QnABotCommonLambdaLayer: { Type: 'String' }, + LogRetentionPeriod: { Type: 'Number' }, }, Conditions: { VPCEnabled: { @@ -64,5 +66,6 @@ module.exports = { EmbeddingsLambdaArn: { 'Fn::Not': [{ 'Fn::Equals': [{ Ref: 'EmbeddingsLambdaArn' }, ''] }] }, EmbeddingsSagemaker: { 'Fn::Not': [{ 'Fn::Equals': [{ Ref: 'EmbeddingsSagemakerEndpointArn' }, ''] }] }, EmbeddingsBedrock: { 'Fn::Equals': [{ Ref: 'EmbeddingsApi' }, 'BEDROCK'] }, + LogRetentionPeriodIsNotZero: { 'Fn::Not': [{ 'Fn::Equals': [{ Ref: 'LogRetentionPeriod' }, 0] }] } }, }; diff --git a/source/templates/import/resources.js b/source/templates/import/resources.js index 9b07ad556..e2ff7d861 100644 --- a/source/templates/import/resources.js +++ b/source/templates/import/resources.js @@ -25,6 +25,30 @@ module.exports = Object.assign(require('./bucket'), { BuildDate: (new Date()).toISOString(), }, }, + ImportStartLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ImportStartLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ImportStartLambda: { Type: "AWS::Lambda::Function", Properties: { @@ -44,10 +68,14 @@ module.exports = Object.assign(require('./bucket'), { DEFAULT_SETTINGS_PARAM: { Ref: "DefaultQnABotSettings" }, PRIVATE_SETTINGS_PARAM: { Ref: "PrivateQnABotSettings" }, CUSTOM_SETTINGS_PARAM: { Ref: "CustomQnABotSettings" }, - ...util.getCommonEnvironmentVariables() + OUTPUT_S3_BUCKET: { Ref: "ContentDesignerOutputBucket"}, + ...util.getCommonEnvironmentVariables(), }, }, Handler: "index.start", + LoggingConfig: { + LogGroup: { Ref: 'ImportStartLambdaLogGroup' }, + }, MemorySize: "1024", Role: { "Fn::GetAtt": ["ImportRole", "Arn"] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -75,6 +103,30 @@ module.exports = Object.assign(require('./bucket'), { }, Metadata: { cfn_nag: util.cfnNag(["W92"]) }, }, + ImportStepLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ImportStepLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ImportStepLambda: { Type: "AWS::Lambda::Function", Properties: { @@ -96,10 +148,14 @@ module.exports = Object.assign(require('./bucket'), { EMBEDDINGS_API: { Ref: "EmbeddingsApi" }, EMBEDDINGS_SAGEMAKER_ENDPOINT: { Ref: "EmbeddingsSagemakerEndpoint" }, EMBEDDINGS_LAMBDA_ARN: { Ref: "EmbeddingsLambdaArn" }, - ...util.getCommonEnvironmentVariables() + OUTPUT_S3_BUCKET: { Ref: "ContentDesignerOutputBucket"}, + ...util.getCommonEnvironmentVariables(), }, }, Handler: "index.step", + LoggingConfig: { + LogGroup: { Ref: 'ImportStepLambdaLogGroup' }, + }, MemorySize: "1024", Role: { "Fn::GetAtt": ["ImportRole", "Arn"] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -204,6 +260,7 @@ module.exports = Object.assign(require('./bucket'), { { 'Fn::Sub': 'arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/amazon.titan-embed-text-v1' }, { 'Fn::Sub': 'arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/cohere.embed-english-v3' }, { 'Fn::Sub': 'arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/cohere.embed-multilingual-v3' }, + { 'Fn::Sub': 'arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/amazon.titan-embed-text-v2:0' }, ], }, ], @@ -233,7 +290,7 @@ module.exports = Object.assign(require('./bucket'), { "s3:DeleteObject", "s3:DeleteObjectVersion", ], - Resource: [{ "Fn::Sub": "arn:aws:s3:::${ImportBucket}*" }], + Resource: [{ "Fn::Sub": "arn:aws:s3:::${ImportBucket}*" }, { "Fn::Sub": "arn:aws:s3:::${ContentDesignerOutputBucket}*" }], }, { Effect: "Allow", Action: [ diff --git a/source/templates/master/UpgradeAutoExport.js b/source/templates/master/UpgradeAutoExport.js index 86f83f98c..74b5a4144 100644 --- a/source/templates/master/UpgradeAutoExport.js +++ b/source/templates/master/UpgradeAutoExport.js @@ -25,6 +25,7 @@ module.exports = { Properties: { ServiceToken: { 'Fn::GetAtt': ['CFNLambda', 'Arn'] }, bucket: { Ref: 'ExportBucket' }, + contentDesignerOutputBucket : { Ref: 'ContentDesignerOutputBucket' }, id: exportfile, index: { 'Fn::Sub': '${Var.QnaIndex}' }, PRE_UPGRADE_EXPORT_TRIGGERS: { @@ -48,6 +49,7 @@ module.exports = { Properties: { ServiceToken: { 'Fn::GetAtt': ['CFNLambda', 'Arn'] }, bucket: { Ref: 'ExportBucket' }, + contentDesignerOutputBucket : { Ref: 'ContentDesignerOutputBucket' }, id: exportfile_metrics, index: { 'Fn::Sub': '${Var.MetricsIndex}' }, PRE_UPGRADE_EXPORT_TRIGGERS: { @@ -71,6 +73,7 @@ module.exports = { Properties: { ServiceToken: { 'Fn::GetAtt': ['CFNLambda', 'Arn'] }, bucket: { Ref: 'ExportBucket' }, + contentDesignerOutputBucket : { Ref: 'ContentDesignerOutputBucket' }, id: exportfile_feedback, index: { 'Fn::Sub': '${Var.FeedbackIndex}' }, PRE_UPGRADE_EXPORT_TRIGGERS: { diff --git a/source/templates/master/__snapshots__/index.test.js.snap b/source/templates/master/__snapshots__/index.test.js.snap index 65c7e8f68..71ff813ae 100644 --- a/source/templates/master/__snapshots__/index.test.js.snap +++ b/source/templates/master/__snapshots__/index.test.js.snap @@ -75,14 +75,6 @@ exports[`Verify master template is correct renders master template correctly 1`] "EMPTY", ], }, - "CreateLexV1Bots": { - "Fn::Equals": [ - { - "Ref": "LexBotVersion", - }, - "LexV1 and LexV2", - ], - }, "Domain": { "Fn::Not": [ { @@ -251,6 +243,18 @@ exports[`Verify master template is correct renders master template correctly 1`] "SAGEMAKER", ], }, + "LogRetentionPeriodIsNotZero": { + "Fn::Not": [ + { + "Fn::Equals": [ + { + "Ref": "LogRetentionPeriod", + }, + 0, + ], + }, + ], + }, "Public": { "Fn::Equals": [ { @@ -311,14 +315,14 @@ exports[`Verify master template is correct renders master template correctly 1`] "ai21.j2-mid-v1": { "MaxTokens": 8191, "ModelID": "ai21.j2-mid-v1", - "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention)", + "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|don't see any information in the provided search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention|could not find an answer to this question|the model cannot answer this question)", "QAPromptTemplate": "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know. Documents: {context} Instruction: Based on the above documents, provide a detailed answer for {query} Answer \\"Sorry, I don't know\\" if not present in the document. Solution:", "QueryPromptTemplate": "

    Human: Here is a chat history in tags:

    {history}

    Human: And here is a follow up question or statement from the human in tags:

    {input}

    Human: Rephrase the follow up question or statement as a standalone question or statement that makes sense without reading the chat history.

    Assistant: Here is the rephrased follow up question or statement:", }, "ai21.j2-ultra-v1": { "MaxTokens": 8191, "ModelID": "ai21.j2-ultra-v1", - "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention)", + "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|don't see any information in the provided search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention|could not find an answer to this question|the model cannot answer this question)", "QAPromptTemplate": "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know. Documents: {context} Instruction: Based on the above documents, provide a detailed answer for {query} Answer \\"Sorry, I don't know\\" if not present in the document. Solution:", "QueryPromptTemplate": "

    Human: Here is a chat history in tags:

    {history}

    Human: And here is a follow up question or statement from the human in tags:

    {input}

    Human: Rephrase the follow up question or statement as a standalone question or statement that makes sense without reading the chat history.

    Assistant: Here is the rephrased follow up question or statement:", }, @@ -327,59 +331,70 @@ exports[`Verify master template is correct renders master template correctly 1`] "MaxTokens": 8000, "ModelID": "amazon.titan-embed-text-v1", }, + "amazon.titan-embed-text-v2": { + "EmbeddingsDimensions": 1024, + "MaxTokens": 8000, + "ModelID": "amazon.titan-embed-text-v2:0", + }, "amazon.titan-text-express-v1": { "MaxTokens": 8000, "ModelID": "amazon.titan-text-express-v1", - "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention)", + "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|don't see any information in the provided search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention|could not find an answer to this question|the model cannot answer this question)", "QAPromptTemplate": "

    Human: You are a friendly AI assistant. Answer the question in tags only based on the provided reference passages. Here are reference passages in tags:

    {context}

    If the references contain the information needed to respond, then write a confident response in under 50 words, quoting the relevant references.
    Otherwise, if you can make an informed guess based on the reference passages, then write a less confident response in under 50 words, stating your assumptions.
    Finally, if the references do not have any relevant information, then respond saying \\"Sorry, I don't know\\".

    {query}


    Assistant: According to the reference passages, in under 50 words:", "QueryPromptTemplate": "Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question.
    Chat History:
    {history}
    Follow up question: {input}
    Standalone question:", }, "amazon.titan-text-lite-v1": { "MaxTokens": 4000, "ModelID": "amazon.titan-text-lite-v1", - "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention)", + "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|don't see any information in the provided search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention|could not find an answer to this question|the model cannot answer this question)", + "QAPromptTemplate": "

    Human: You are a friendly AI assistant. Answer the question in tags only based on the provided reference passages. Here are reference passages in tags:

    {context}

    If the references contain the information needed to respond, then write a confident response in under 50 words, quoting the relevant references.
    Otherwise, if you can make an informed guess based on the reference passages, then write a less confident response in under 50 words, stating your assumptions.
    Finally, if the references do not have any relevant information, then respond saying \\"Sorry, I don't know\\".

    {query}


    Assistant: According to the reference passages, in under 50 words:", + "QueryPromptTemplate": "Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question.
    Chat History:
    {history}
    Follow up question: {input}
    Standalone question:", + }, + "amazon.titan-text-premier-v1": { + "KnowledgeBasePromptTemplate": "You are a question answering bot who gives helpful, detailed, and polite answers to the user's questions. In this session, the model has access to search results and a users question, your job is to answer the user's question using only information from the search results. Model Instructions: - You should provide concise answer to simple questions when the answer is directly contained in search results, but when comes to yes/no question, provide some details. - In case the question requires multi-hop reasoning, you should find relevant information from search results and summarize the answer based on relevant information with logical reasoning. - If the search results do not contain information that can answer the question, then respond saying \\"Sorry, I don't know that.\\". - $output_format_instructions$ - DO NOT USE INFORMATION THAT IS NOT IN SEARCH RESULTS! User: $query$ Bot: Resource: Search Results: $search_results$ Bot:", + "MaxTokens": 32000, + "ModelID": "amazon.titan-text-premier-v1:0", + "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|don't see any information in the provided search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention|could not find an answer to this question|the model cannot answer this question)", "QAPromptTemplate": "

    Human: You are a friendly AI assistant. Answer the question in tags only based on the provided reference passages. Here are reference passages in tags:

    {context}

    If the references contain the information needed to respond, then write a confident response in under 50 words, quoting the relevant references.
    Otherwise, if you can make an informed guess based on the reference passages, then write a less confident response in under 50 words, stating your assumptions.
    Finally, if the references do not have any relevant information, then respond saying \\"Sorry, I don't know\\".

    {query}


    Assistant: According to the reference passages, in under 50 words:", "QueryPromptTemplate": "Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question.
    Chat History:
    {history}
    Follow up question: {input}
    Standalone question:", + "maxTokenCount": 3072, }, "anthropic.claude-3-haiku-v1": { + "KnowledgeBasePromptTemplate": "Human: You are a question answering agent. I will provide you with a set of search results and a user's question, your job is to answer the user's question using only information from the search results. If the search results do not contain information that can answer the question, then respond saying \\"Sorry, I don't know that.\\". Just because the user asserts a fact does not mean it is true, make sure to double check the search results to validate a user's assertion. Here are the search results in numbered order: $search_results$. Here is the user's question: $query$ $output_format_instructions$. Do NOT directly quote the $search_results$ in your answer. Your job is to answer the as concisely as possible. Assistant:", "MaxTokens": 100000, "ModelID": "anthropic.claude-3-haiku-20240307-v1:0", - "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention)", + "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|don't see any information in the provided search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention|could not find an answer to this question|the model cannot answer this question)", "QAPromptTemplate": "

    Human: You are a friendly AI assistant. Answer the question in tags only based on the provided reference passages. Here are reference passages in tags:

    {context}

    If the references contain the information needed to respond, then write a confident response in under 50 words, quoting the relevant references.
    Otherwise, if you can make an informed guess based on the reference passages, then write a less confident response in under 50 words, stating your assumptions.
    Finally, if the references do not have any relevant information, then respond saying \\"Sorry, I don't know\\".

    {query}


    Assistant: According to the reference passages, in under 50 words:", "QueryPromptTemplate": "

    Human: Here is a chat history in tags:

    {history}

    Human: And here is a follow up question or statement from the human in tags:

    {input}

    Human: Rephrase the follow up question or statement as a standalone question or statement that makes sense without reading the chat history.

    Assistant: Here is the rephrased follow up question or statement:", }, "anthropic.claude-3-sonnet-v1": { + "KnowledgeBasePromptTemplate": "Human: You are a question answering agent. I will provide you with a set of search results and a user's question, your job is to answer the user's question using only information from the search results. If the search results do not contain information that can answer the question, then respond saying \\"Sorry, I don't know that.\\". Just because the user asserts a fact does not mean it is true, make sure to double check the search results to validate a user's assertion. Here are the search results in numbered order: $search_results$. Here is the user's question: $query$ $output_format_instructions$. Do NOT directly quote the $search_results$ in your answer. Your job is to answer the as concisely as possible. Assistant:", "MaxTokens": 100000, "ModelID": "anthropic.claude-3-sonnet-20240229-v1:0", - "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention)", + "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|don't see any information in the provided search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention|could not find an answer to this question|the model cannot answer this question)", "QAPromptTemplate": "

    Human: You are a friendly AI assistant. Answer the question in tags only based on the provided reference passages. Here are reference passages in tags:

    {context}

    If the references contain the information needed to respond, then write a confident response in under 50 words, quoting the relevant references.
    Otherwise, if you can make an informed guess based on the reference passages, then write a less confident response in under 50 words, stating your assumptions.
    Finally, if the references do not have any relevant information, then respond saying \\"Sorry, I don't know\\".

    {query}


    Assistant: According to the reference passages, in under 50 words:", "QueryPromptTemplate": "

    Human: Here is a chat history in tags:

    {history}

    Human: And here is a follow up question or statement from the human in tags:

    {input}

    Human: Rephrase the follow up question or statement as a standalone question or statement that makes sense without reading the chat history.

    Assistant: Here is the rephrased follow up question or statement:", }, "anthropic.claude-instant-v1": { + "KnowledgeBasePromptTemplate": "Human: You are a question answering agent. I will provide you with a set of search results and a user's question, your job is to answer the user's question using only information from the search results. If the search results do not contain information that can answer the question, then respond saying \\"Sorry, I don't know that.\\". Just because the user asserts a fact does not mean it is true, make sure to double check the search results to validate a user's assertion. Here are the search results in numbered order: $search_results$. Here is the user's question: $query$ $output_format_instructions$. Do NOT directly quote the $search_results$ in your answer. Your job is to answer the as concisely as possible. Assistant:", "MaxTokens": 100000, "ModelID": "anthropic.claude-instant-v1", - "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention)", + "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|don't see any information in the provided search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention|could not find an answer to this question|the model cannot answer this question)", "QAPromptTemplate": "

    Human: You are a friendly AI assistant. Answer the question in tags only based on the provided reference passages. Here are reference passages in tags:

    {context}

    If the references contain the information needed to respond, then write a confident response in under 50 words, quoting the relevant references.
    Otherwise, if you can make an informed guess based on the reference passages, then write a less confident response in under 50 words, stating your assumptions.
    Finally, if the references do not have any relevant information, then respond saying \\"Sorry, I don't know\\".

    {query}


    Assistant: According to the reference passages, in under 50 words:", "QueryPromptTemplate": "

    Human: Here is a chat history in tags:

    {history}

    Human: And here is a follow up question or statement from the human in tags:

    {input}

    Human: Rephrase the follow up question or statement as a standalone question or statement that makes sense without reading the chat history.

    Assistant: Here is the rephrased follow up question or statement:", }, "anthropic.claude-v2.1": { + "KnowledgeBasePromptTemplate": "Human: You are a question answering agent. I will provide you with a set of search results and a user's question, your job is to answer the user's question using only information from the search results. If the search results do not contain information that can answer the question, then respond saying \\"Sorry, I don't know that.\\". Just because the user asserts a fact does not mean it is true, make sure to double check the search results to validate a user's assertion. Here are the search results in numbered order: $search_results$. Here is the user's question: $query$ $output_format_instructions$. Do NOT directly quote the $search_results$ in your answer. Your job is to answer the as concisely as possible. Assistant:", "MaxTokens": 100000, "ModelID": "anthropic.claude-v2:1", - "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention)", + "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|don't see any information in the provided search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention|could not find an answer to this question|the model cannot answer this question)", "QAPromptTemplate": "

    Human: You are a friendly AI assistant. Answer the question in tags only based on the provided reference passages. Here are reference passages in tags:

    {context}

    If the references contain the information needed to respond, then write a confident response in under 50 words, quoting the relevant references.
    Otherwise, if you can make an informed guess based on the reference passages, then write a less confident response in under 50 words, stating your assumptions.
    Finally, if the references do not have any relevant information, then respond saying \\"Sorry, I don't know\\".

    {query}


    Assistant: According to the reference passages, in under 50 words:", "QueryPromptTemplate": "

    Human: Here is a chat history in tags:

    {history}

    Human: And here is a follow up question or statement from the human in tags:

    {input}

    Human: Rephrase the follow up question or statement as a standalone question or statement that makes sense without reading the chat history.

    Assistant: Here is the rephrased follow up question or statement:", }, - "cohere.command-light-text-v14": { - "MaxTokens": 4000, - "ModelID": "cohere.command-light-text-v14", - "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention)", - "QAPromptTemplate": "

    Human: You are a friendly AI assistant. Answer the question in tags only based on the provided reference passages. Here are reference passages in tags:

    {context}

    If the references contain the information needed to respond, then write a confident response in under 50 words, quoting the relevant references.
    Otherwise, if you can make an informed guess based on the reference passages, then write a less confident response in under 50 words, stating your assumptions.
    Finally, if the references do not have any relevant information, then respond saying \\"Sorry, I don't know\\".

    {query}


    Assistant: According to the reference passages, in under 50 words:", - "QueryPromptTemplate": "Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question.
    Chat History:
    {history}
    Follow up question: {input}
    Standalone question:", - }, "cohere.command-text-v14": { "MaxTokens": 4000, "ModelID": "cohere.command-text-v14", - "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention)", + "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|don't see any information in the provided search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention|could not find an answer to this question|the model cannot answer this question)", "QAPromptTemplate": "

    Human: You are a friendly AI assistant. Answer the question in tags only based on the provided reference passages. Here are reference passages in tags:

    {context}

    If the references contain the information needed to respond, then write a confident response in under 50 words, quoting the relevant references.
    Otherwise, if you can make an informed guess based on the reference passages, then write a less confident response in under 50 words, stating your assumptions.
    Finally, if the references do not have any relevant information, then respond saying \\"Sorry, I don't know\\".

    {query}


    Assistant: According to the reference passages, in under 50 words:", "QueryPromptTemplate": "Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question.
    Chat History:
    {history}
    Follow up question: {input}
    Standalone question:", }, @@ -396,7 +411,7 @@ exports[`Verify master template is correct renders master template correctly 1`] "meta.llama3-8b-instruct-v1": { "MaxTokens": 8000, "ModelID": "meta.llama3-8b-instruct-v1:0", - "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention)", + "NoHitsRegex": "(Sorry, I don't know|unable to assist you|i don't have enough context|i could not find an exact answer|no information in the search results|don't see any information in the provided search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention|could not find an answer to this question|the model cannot answer this question)", "QAPromptTemplate": "

    Human: You are a friendly AI assistant. Answer the question in tags only based on the provided reference passages. Here are reference passages in tags:

    {context}

    If the references contain the information needed to respond, then write a confident response in under 50 words, quoting the relevant references.
    Otherwise, if you can make an informed guess based on the reference passages, then write a less confident response in under 50 words, stating your assumptions.
    Finally, if the references do not have any relevant information, then respond saying \\"Sorry, I don't know\\".

    {query}


    Assistant: According to the reference passages, in under 50 words:", "QueryPromptTemplate": "Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question.
    Chat History:
    {history}
    Follow up question: {input}
    Standalone question:", }, @@ -435,7 +450,6 @@ exports[`Verify master template is correct renders master template correctly 1`] "OpenSearchDashboardsRetentionMinutes", "OpenSearchFineGrainAccessControl", "LexV2BotLocaleIds", - "LexBotVersion", "InstallLexResponseBots", "FulfillmentConcurrency", "XraySetting", @@ -497,6 +511,7 @@ exports[`Verify master template is correct renders master template correctly 1`] "BootstrapBucket", "BootstrapPrefix", "BuildExamples", + "LogRetentionPeriod", ], }, ], @@ -516,25 +531,6 @@ exports[`Verify master template is correct renders master template correctly 1`] "Ref": "API", }, }, - "BotConsoleUrl": { - "Condition": "CreateLexV1Bots", - "Value": { - "Fn::Join": [ - "", - [ - "https://console.aws.amazon.com/lex/home?", - "region=", - { - "Ref": "AWS::Region", - }, - "#bot-editor:bot=", - { - "Ref": "LexBot", - }, - ], - ], - }, - }, "Bucket": { "Value": { "Ref": "Bucket", @@ -588,6 +584,11 @@ exports[`Verify master template is correct renders master template correctly 1`] ], }, }, + "ContentDesignerOutputBucket": { + "Value": { + "Ref": "ContentDesignerOutputBucket", + }, + }, "ContentDesignerURL": { "Value": { "Fn::Join": [ @@ -676,36 +677,6 @@ exports[`Verify master template is correct renders master template correctly 1`] "Ref": "ImportBucket", }, }, - "LexV1BotAlias": { - "Condition": "CreateLexV1Bots", - "Value": { - "Ref": "VersionAlias", - }, - }, - "LexV1BotName": { - "Condition": "CreateLexV1Bots", - "Value": { - "Ref": "LexBot", - }, - }, - "LexV1Intent": { - "Condition": "CreateLexV1Bots", - "Value": { - "Ref": "Intent", - }, - }, - "LexV1IntentFallback": { - "Condition": "CreateLexV1Bots", - "Value": { - "Ref": "IntentFallback", - }, - }, - "LexV1SlotType": { - "Condition": "CreateLexV1Bots", - "Value": { - "Ref": "SlotType", - }, - }, "LexV2BotAlias": { "Value": { "Fn::GetAtt": [ @@ -796,6 +767,11 @@ exports[`Verify master template is correct renders master template correctly 1`] "Ref": "PrivateQnABotSettings", }, }, + "TestAllBucket": { + "Value": { + "Ref": "TestAllBucket", + }, + }, "UserPool": { "Value": { "Ref": "UserPool", @@ -874,6 +850,7 @@ exports[`Verify master template is correct renders master template correctly 1`] }, "BedrockKnowledgeBaseModel": { "AllowedValues": [ + "amazon.titan-text-premier-v1", "anthropic.claude-instant-v1", "anthropic.claude-v2.1", "anthropic.claude-3-sonnet-v1", @@ -924,6 +901,7 @@ exports[`Verify master template is correct renders master template correctly 1`] "EmbeddingsBedrockModelId": { "AllowedValues": [ "amazon.titan-embed-text-v1", + "amazon.titan-embed-text-v2", "cohere.embed-english-v3", "cohere.embed-multilingual-v3", ], @@ -988,6 +966,7 @@ exports[`Verify master template is correct renders master template correctly 1`] "AllowedValues": [ "amazon.titan-text-express-v1", "amazon.titan-text-lite-v1", + "amazon.titan-text-premier-v1", "ai21.j2-ultra-v1", "ai21.j2-mid-v1", "anthropic.claude-instant-v1", @@ -1062,15 +1041,6 @@ exports[`Verify master template is correct renders master template correctly 1`] "Description": "Choose the primary Language for your QnABot deployment. Note: Picking non-English may correspond with limited functionalities", "Type": "String", }, - "LexBotVersion": { - "AllowedValues": [ - "LexV1 and LexV2", - "LexV2 Only", - ], - "Default": "LexV2 Only", - "Description": "Amazon Lex version to use for QnABot on AWS. Select 'LexV2 Only' to install QnABot in AWS regions where LexV1 is not supported.", - "Type": "String", - }, "LexV2BotLocaleIds": { "AllowedPattern": "[^ ]+", "ConstraintDescription": "Must be a valid comma separated list of Locale IDs", @@ -1078,6 +1048,37 @@ exports[`Verify master template is correct renders master template correctly 1`] "Description": "Languages for QnABot on AWS voice interaction using LexV2. Specify as a comma separated list of valid Locale IDs without empty spaces - see https://github.com/aws-solutions/qnabot-on-aws/blob/main/source/docs/multilanguage_support/README.md#supported-languages", "Type": "String", }, + "LogRetentionPeriod": { + "AllowedValues": [ + 0, + 1, + 3, + 5, + 7, + 14, + 30, + 60, + 90, + 120, + 150, + 180, + 365, + 400, + 545, + 731, + 1096, + 1827, + 2192, + 2557, + 2922, + 3288, + 3653, + ], + "Default": 0, + "Description": "Optional: The number of days to keep logs before expiring. If you would like your logs to never expire, leave this value as 0.", + "MinValue": 0, + "Type": "Number", + }, "OpenSearchDashboardsRetentionMinutes": { "Default": 43200, "Description": "To conserve storage in Amazon OpenSearch, metrics and feedback data used to populate the OpenSearch dashboards are automatically deleted after this period (default 43200 minutes = 30 days). Monitor 'Free storage space' for your OpenSearch domain to ensure that you have sufficient space available to store data for the desired retention period.", @@ -1292,7 +1293,10 @@ exports[`Verify master template is correct renders master template correctly 1`] "Fn::Sub": "arn:aws:s3:::\${ExportBucket}/data/*", }, { - "Fn::Sub": "arn:aws:s3:::\${TestAllBucket}/data/*", + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}/data-testall/*", + }, + { + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}/data-export/*", }, ], }, @@ -1328,6 +1332,17 @@ exports[`Verify master template is correct renders master template correctly 1`] }, ], }, + { + "Action": [ + "lambda:InvokeFunction", + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:\${SolutionHelper}", + }, + ], + }, ], "Version": "2012-10-17", }, @@ -2685,6 +2700,11 @@ exports[`Verify master template is correct renders master template correctly 1`] }, }, "Handler": "index.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "CFNLambdaLogGroup", + }, + }, "MemorySize": "3008", "Role": { "Fn::GetAtt": [ @@ -2730,6 +2750,53 @@ exports[`Verify master template is correct renders master template correctly 1`] }, "Type": "AWS::Lambda::Function", }, + "CFNLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-CFNLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "CFNLambdaRole": { "Metadata": { "cfn_nag": { @@ -3366,9 +3433,100 @@ exports[`Verify master template is correct renders master template correctly 1`] }, "Type": "Custom::S3Version", }, + "ContentDesignerOutputBucket": { + "DependsOn": [ + "MainAccessLogBucket", + "MainAccessLogsBucketPolicy", + ], + "Metadata": { + "guard": { + "SuppressedRules": [ + "S3_BUCKET_NO_PUBLIC_RW_ACL", + ], + }, + }, + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256", + }, + }, + ], + }, + "CorsConfiguration": { + "CorsRules": [ + { + "AllowedHeaders": [ + "*", + ], + "AllowedMethods": [ + "GET", + ], + "AllowedOrigins": [ + "*", + ], + }, + ], + }, + "LifecycleConfiguration": { + "Rules": [ + { + "ExpirationInDays": 1, + "Status": "Enabled", + }, + ], + }, + "LoggingConfiguration": { + "DestinationBucketName": { + "Ref": "MainAccessLogBucket", + }, + "LogFilePrefix": { + "Fn::Join": [ + "", + [ + { + "Ref": "MainAccessLogBucket", + }, + "/ContentDesignerOutput/", + ], + ], + }, + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true, + }, + "VersioningConfiguration": { + "Status": "Enabled", + }, + }, + "Type": "AWS::S3::Bucket", + }, + "ContentDesignerOutputClean": { + "DependsOn": [ + "CFNInvokePolicy", + ], + "Properties": { + "Bucket": { + "Ref": "ContentDesignerOutputBucket", + }, + "ServiceToken": { + "Fn::GetAtt": [ + "S3Clean", + "Arn", + ], + }, + }, + "Type": "Custom::S3Clean", + }, "CustomQnABotSettings": { "Properties": { "Description": "Custom QnABot Settings - Modify to override defaults, or to add new settings", + "Tier": "Advanced", "Type": "String", "Value": "{}", }, @@ -3428,7 +3586,7 @@ exports[`Verify master template is correct renders master template correctly 1`] "Type": "String", "Value": { "Fn::Sub": [ - "{"ENABLE_DEBUG_RESPONSES":"false","ENABLE_DEBUG_LOGGING":"false","ES_USE_KEYWORD_FILTERS":"\${ES_USE_KEYWORD_FILTERS}","ES_EXPAND_CONTRACTIONS":"{\\"you're\\":\\"you are\\",\\"I'm\\":\\"I am\\",\\"can't\\":\\"cannot\\"}","ES_KEYWORD_SYNTAX_TYPES":"NOUN,PROPN,VERB,INTJ","ES_SYNTAX_CONFIDENCE_LIMIT":0.2,"ES_MINIMUM_SHOULD_MATCH":"2<75%","ES_NO_HITS_QUESTION":"no_hits","ES_ERROR_QUESTION":"error_msg","ES_USE_FUZZY_MATCH":"false","ES_PHRASE_BOOST":4,"ES_SCORE_ANSWER_FIELD":"false","ES_SCORE_TEXT_ITEM_PASSAGES":"true","ENABLE_SENTIMENT_SUPPORT":"true","ENABLE_MULTI_LANGUAGE_SUPPORT":"false","ENABLE_CUSTOM_TERMINOLOGY":"false","MINIMUM_CONFIDENCE_SCORE":0.6,"ALT_SEARCH_KENDRA_FALLBACK_CONFIDENCE_SCORE":"HIGH","ALT_SEARCH_KENDRA_FAQ_CONFIDENCE_SCORE":"HIGH","ALT_SEARCH_KENDRA_S3_SIGNED_URLS":"true","ALT_SEARCH_KENDRA_S3_SIGNED_URL_EXPIRE_SECS":300,"ALT_SEARCH_KENDRA_MAX_DOCUMENT_COUNT":2,"ALT_SEARCH_KENDRA_TOP_ANSWER_MESSAGE":"Amazon Kendra suggested answer.","ALT_SEARCH_KENDRA_FAQ_MESSAGE":"Answer from Amazon Kendra FAQ.","ALT_SEARCH_KENDRA_ANSWER_MESSAGE":"While I did not find an exact answer, these search results from Amazon Kendra might be helpful.","ALT_SEARCH_KENDRA_RESPONSE_TYPES":"ANSWER,DOCUMENT,QUESTION_ANSWER","ALT_SEARCH_KENDRA_ABBREVIATE_MESSAGE_FOR_SSML":"true","KENDRA_FAQ_CONFIG_MAX_RETRIES":8,"KENDRA_FAQ_CONFIG_RETRY_DELAY":600,"KENDRA_FAQ_ES_FALLBACK":"true","ENABLE_KENDRA_WEB_INDEXER":"false","KENDRA_INDEXER_URLS":"","KENDRA_INDEXER_CRAWL_DEPTH":3,"KENDRA_INDEXER_CRAWL_MODE":"SUBDOMAINS","KENDRA_INDEXER_SCHEDULE":"rate(1 day)","KENDRA_INDEXED_DOCUMENTS_LANGUAGES":"en","ERRORMESSAGE":"Unfortunately I encountered an error when searching for your answer. Please ask me again later.","EMPTYMESSAGE":"You stumped me! Sadly I do not know how to answer your question.","DEFAULT_ALEXA_LAUNCH_MESSAGE":"Hello, Please ask a question","DEFAULT_ALEXA_REPROMPT":"Please either answer the question, ask another question or say Goodbye to end the conversation.","DEFAULT_ALEXA_STOP_MESSAGE":"Goodbye","SMS_HINT_REMINDER_ENABLE":"true","SMS_HINT_REMINDER":" (Feedback? Reply THUMBS UP or THUMBS DOWN. Ask HELP ME at any time)","SMS_HINT_REMINDER_INTERVAL_HRS":24,"IDENTITY_PROVIDER_JWKS_URLS":[],"ENFORCE_VERIFIED_IDENTITY":"false","NO_VERIFIED_IDENTITY_QUESTION":"no_verified_identity","ELICIT_RESPONSE_MAX_RETRIES":3,"ELICIT_RESPONSE_RETRY_MESSAGE":"Please try again.","ELICIT_RESPONSE_BOT_FAILURE_MESSAGE":"Your response was not understood. Please start again.","ELICIT_RESPONSE_DEFAULT_MSG":"Ok. ","CONNECT_IGNORE_WORDS":"","CONNECT_ENABLE_VOICE_RESPONSE_INTERRUPT":"false","CONNECT_NEXT_PROMPT_VARNAME":"connect_nextPrompt","ENABLE_REDACTING":"false","REDACTING_REGEX":"\\\\b\\\\d{4}\\\\b(?![-])|\\\\b\\\\d{9}\\\\b|\\\\b\\\\d{3}-\\\\d{2}-\\\\d{4}\\\\b","ENABLE_REDACTING_WITH_COMPREHEND":"false","COMPREHEND_REDACTING_CONFIDENCE_SCORE":0.99,"COMPREHEND_REDACTING_ENTITY_TYPES":"ADDRESS,EMAIL,SSN,PHONE,PASSWORD,BANK_ACCOUNT_NUMBER,BANK_ROUTING,CREDIT_DEBIT_NUMBER","PII_REJECTION_ENABLED":false,"PII_REJECTION_QUESTION":"pii_rejection_question","PII_REJECTION_REGEX":"\\\\b\\\\d{4}\\\\b(?![-])|\\\\b\\\\d{9}\\\\b|\\\\b\\\\d{3}-\\\\d{2}-\\\\d{4}\\\\b","PII_REJECTION_ENTITY_TYPES":"ADDRESS,EMAIL,SSN,PHONE,PASSWORD,BANK_ACCOUNT_NUMBER,BANK_ROUTING,CREDIT_DEBIT_NUMBER","PII_REJECTION_CONFIDENCE_SCORE":0.99,"DISABLE_CLOUDWATCH_LOGGING":"false","MINIMAL_ES_LOGGING":"false","S3_PUT_REQUEST_ENCRYPTION":"","BOT_ROUTER_WELCOME_BACK_MSG":"Welcome back to QnABot.","BOT_ROUTER_EXIT_MSGS":"exit,quit,goodbye,leave","RUN_LAMBDAHOOK_FROM_QUERY_STEP":"true","LAMBDA_PREPROCESS_HOOK":"","LAMBDA_POSTPROCESS_HOOK":"","SEARCH_REPLACE_QUESTION_SUBSTRINGS":"","PROTECTED_UTTERANCES":"help,help me,thumbs up,thumbs down,repeat,no_hits,no_verified_identity,reset language,detect language,english,french,spanish,german,italian,chinese,arabic,greek,repeat,can you repeat that,can you please say that again,please repeat that","EMBEDDINGS_ENABLE":"\${EMBEDDINGS_ENABLE}","EMBEDDINGS_SCORE_THRESHOLD":"\${EMBEDDINGS_SCORE_THRESHOLD}","EMBEDDINGS_SCORE_ANSWER_THRESHOLD":0.8,"EMBEDDINGS_TEXT_PASSAGE_SCORE_THRESHOLD":"\${EMBEDDINGS_TEXT_PASSAGE_SCORE_THRESHOLD}","EMBEDDINGS_MAX_TOKEN_LIMIT":"\${EMBEDDINGS_MAX_TOKEN_LIMIT}","LLM_GENERATE_QUERY_ENABLE":"\${LLM_GENERATE_QUERY_ENABLE}","LLM_GENERATE_QUERY_PROMPT_TEMPLATE":"\${LLM_GENERATE_QUERY_PROMPT_TEMPLATE}","LLM_GENERATE_QUERY_MODEL_PARAMS":"\${LLM_GENERATE_QUERY_MODEL_PARAMS}","LLM_QA_ENABLE":"\${LLM_QA_ENABLE}","LLM_QA_USE_KENDRA_RETRIEVAL_API":"\${LLM_QA_ENABLE}","LLM_QA_PROMPT_TEMPLATE":"\${LLM_QA_PROMPT_TEMPLATE}","LLM_QA_MODEL_PARAMS":"\${LLM_QA_MODEL_PARAMS}","LLM_QA_PREFIX_MESSAGE":"LLM Answer:","LLM_QA_SHOW_CONTEXT_TEXT":"true","LLM_QA_SHOW_SOURCE_LINKS":"true","LLM_CHAT_HISTORY_MAX_MESSAGES":12,"LLM_QA_NO_HITS_REGEX":"\${LLM_QA_NO_HITS_REGEX}","LLM_PROMPT_MAX_TOKEN_LIMIT":"\${LLM_PROMPT_MAX_TOKEN_LIMIT}","KNOWLEDGE_BASE_PREFIX_MESSAGE":"From Knowledge Base:","KNOWLEDGE_BASE_SHOW_REFERENCES":"true","KNOWLEDGE_BASE_S3_SIGNED_URLS":"true","KNOWLEDGE_BASE_S3_SIGNED_URL_EXPIRE_SECS":300}", + "{"ENABLE_DEBUG_RESPONSES":"false","ENABLE_DEBUG_LOGGING":"false","ES_USE_KEYWORD_FILTERS":"\${ES_USE_KEYWORD_FILTERS}","ES_EXPAND_CONTRACTIONS":"{\\"you're\\":\\"you are\\",\\"I'm\\":\\"I am\\",\\"can't\\":\\"cannot\\"}","ES_KEYWORD_SYNTAX_TYPES":"NOUN,PROPN,VERB,INTJ","ES_SYNTAX_CONFIDENCE_LIMIT":0.2,"ES_MINIMUM_SHOULD_MATCH":"2<75%","ES_NO_HITS_QUESTION":"no_hits","ES_ERROR_QUESTION":"error_msg","ES_USE_FUZZY_MATCH":"false","ES_PHRASE_BOOST":4,"ES_SCORE_ANSWER_FIELD":"false","ES_SCORE_TEXT_ITEM_PASSAGES":"true","ENABLE_SENTIMENT_SUPPORT":"true","ENABLE_MULTI_LANGUAGE_SUPPORT":"false","ENABLE_CUSTOM_TERMINOLOGY":"false","MINIMUM_CONFIDENCE_SCORE":0.6,"ALT_SEARCH_KENDRA_FALLBACK_CONFIDENCE_SCORE":"HIGH","ALT_SEARCH_KENDRA_FAQ_CONFIDENCE_SCORE":"HIGH","ALT_SEARCH_KENDRA_S3_SIGNED_URLS":"true","ALT_SEARCH_KENDRA_S3_SIGNED_URL_EXPIRE_SECS":300,"ALT_SEARCH_KENDRA_MAX_DOCUMENT_COUNT":2,"ALT_SEARCH_KENDRA_TOP_ANSWER_MESSAGE":"Amazon Kendra suggested answer.","ALT_SEARCH_KENDRA_FAQ_MESSAGE":"Answer from Amazon Kendra FAQ.","ALT_SEARCH_KENDRA_ANSWER_MESSAGE":"While I did not find an exact answer, these search results from Amazon Kendra might be helpful.","ALT_SEARCH_KENDRA_RESPONSE_TYPES":"ANSWER,DOCUMENT,QUESTION_ANSWER","ALT_SEARCH_KENDRA_ABBREVIATE_MESSAGE_FOR_SSML":"true","KENDRA_FAQ_CONFIG_MAX_RETRIES":8,"KENDRA_FAQ_CONFIG_RETRY_DELAY":600,"KENDRA_FAQ_ES_FALLBACK":"true","ENABLE_KENDRA_WEB_INDEXER":"false","KENDRA_INDEXER_URLS":"","KENDRA_INDEXER_CRAWL_DEPTH":3,"KENDRA_INDEXER_CRAWL_MODE":"SUBDOMAINS","KENDRA_INDEXER_SCHEDULE":"rate(1 day)","KENDRA_INDEXED_DOCUMENTS_LANGUAGES":"en","ERRORMESSAGE":"Unfortunately I encountered an error when searching for your answer. Please ask me again later.","EMPTYMESSAGE":"You stumped me! Sadly I do not know how to answer your question.","DEFAULT_ALEXA_LAUNCH_MESSAGE":"Hello, Please ask a question","DEFAULT_ALEXA_REPROMPT":"Please either answer the question, ask another question or say Goodbye to end the conversation.","DEFAULT_ALEXA_STOP_MESSAGE":"Goodbye","SMS_HINT_REMINDER_ENABLE":"true","SMS_HINT_REMINDER":" (Feedback? Reply THUMBS UP or THUMBS DOWN. Ask HELP ME at any time)","SMS_HINT_REMINDER_INTERVAL_HRS":24,"IDENTITY_PROVIDER_JWKS_URLS":[],"ENFORCE_VERIFIED_IDENTITY":"false","NO_VERIFIED_IDENTITY_QUESTION":"no_verified_identity","ELICIT_RESPONSE_MAX_RETRIES":3,"ELICIT_RESPONSE_RETRY_MESSAGE":"Please try again.","ELICIT_RESPONSE_BOT_FAILURE_MESSAGE":"Your response was not understood. Please start again.","ELICIT_RESPONSE_DEFAULT_MSG":"Ok. ","CONNECT_IGNORE_WORDS":"","CONNECT_ENABLE_VOICE_RESPONSE_INTERRUPT":"false","CONNECT_NEXT_PROMPT_VARNAME":"connect_nextPrompt","ENABLE_REDACTING":"false","REDACTING_REGEX":"\\\\b\\\\d{4}\\\\b(?![-])|\\\\b\\\\d{9}\\\\b|\\\\b\\\\d{3}-\\\\d{2}-\\\\d{4}\\\\b","ENABLE_REDACTING_WITH_COMPREHEND":"false","COMPREHEND_REDACTING_CONFIDENCE_SCORE":0.99,"COMPREHEND_REDACTING_ENTITY_TYPES":"ADDRESS,EMAIL,SSN,PHONE,PASSWORD,BANK_ACCOUNT_NUMBER,BANK_ROUTING,CREDIT_DEBIT_NUMBER","PII_REJECTION_ENABLED":false,"PII_REJECTION_QUESTION":"pii_rejection_question","PII_REJECTION_REGEX":"\\\\b\\\\d{4}\\\\b(?![-])|\\\\b\\\\d{9}\\\\b|\\\\b\\\\d{3}-\\\\d{2}-\\\\d{4}\\\\b","PII_REJECTION_ENTITY_TYPES":"ADDRESS,EMAIL,SSN,PHONE,PASSWORD,BANK_ACCOUNT_NUMBER,BANK_ROUTING,CREDIT_DEBIT_NUMBER","PII_REJECTION_CONFIDENCE_SCORE":0.99,"DISABLE_CLOUDWATCH_LOGGING":"false","MINIMAL_ES_LOGGING":"false","S3_PUT_REQUEST_ENCRYPTION":"","BOT_ROUTER_WELCOME_BACK_MSG":"Welcome back to QnABot.","BOT_ROUTER_EXIT_MSGS":"exit,quit,goodbye,leave","RUN_LAMBDAHOOK_FROM_QUERY_STEP":"true","LAMBDA_PREPROCESS_HOOK":"","LAMBDA_POSTPROCESS_HOOK":"","SEARCH_REPLACE_QUESTION_SUBSTRINGS":"","PROTECTED_UTTERANCES":"help,help me,thumbs up,thumbs down,repeat,no_hits,no_verified_identity,reset language,detect language,english,french,spanish,german,italian,chinese,arabic,greek,repeat,can you repeat that,can you please say that again,please repeat that","EMBEDDINGS_ENABLE":"\${EMBEDDINGS_ENABLE}","EMBEDDINGS_SCORE_THRESHOLD":"\${EMBEDDINGS_SCORE_THRESHOLD}","EMBEDDINGS_SCORE_ANSWER_THRESHOLD":0.8,"EMBEDDINGS_TEXT_PASSAGE_SCORE_THRESHOLD":"\${EMBEDDINGS_TEXT_PASSAGE_SCORE_THRESHOLD}","EMBEDDINGS_MAX_TOKEN_LIMIT":"\${EMBEDDINGS_MAX_TOKEN_LIMIT}","LLM_GENERATE_QUERY_ENABLE":"\${LLM_GENERATE_QUERY_ENABLE}","LLM_GENERATE_QUERY_PROMPT_TEMPLATE":"\${LLM_GENERATE_QUERY_PROMPT_TEMPLATE}","LLM_GENERATE_QUERY_MODEL_PARAMS":"\${LLM_GENERATE_QUERY_MODEL_PARAMS}","LLM_QA_ENABLE":"\${LLM_QA_ENABLE}","LLM_QA_USE_KENDRA_RETRIEVAL_API":"\${LLM_QA_ENABLE}","LLM_QA_PROMPT_TEMPLATE":"\${LLM_QA_PROMPT_TEMPLATE}","LLM_QA_MODEL_PARAMS":"\${LLM_QA_MODEL_PARAMS}","LLM_QA_PREFIX_MESSAGE":"LLM Answer:","LLM_QA_SHOW_CONTEXT_TEXT":"true","LLM_QA_SHOW_SOURCE_LINKS":"true","LLM_CHAT_HISTORY_MAX_MESSAGES":12,"LLM_QA_NO_HITS_REGEX":"\${LLM_QA_NO_HITS_REGEX}","LLM_PROMPT_MAX_TOKEN_LIMIT":"\${LLM_PROMPT_MAX_TOKEN_LIMIT}","KNOWLEDGE_BASE_PREFIX_MESSAGE":"From Knowledge Base:","KNOWLEDGE_BASE_SHOW_REFERENCES":"true","KNOWLEDGE_BASE_S3_SIGNED_URLS":"true","KNOWLEDGE_BASE_S3_SIGNED_URL_EXPIRE_SECS":300,"KNOWLEDGE_BASE_PROMPT_TEMPLATE":"\${KNOWLEDGE_BASE_PROMPT_TEMPLATE}","KNOWLEDGE_BASE_MAX_NUMBER_OF_RETRIEVED_RESULTS":"","KNOWLEDGE_BASE_SEARCH_TYPE":"DEFAULT","KNOWLEDGE_BASE_METADATA_FILTERS":"{}","KNOWLEDGE_BASE_MODEL_PARAMS":"{}","BEDROCK_GUARDRAIL_IDENTIFIER":"","BEDROCK_GUARDRAIL_VERSION":""}", { "EMBEDDINGS_ENABLE": { "Fn::If": [ @@ -3473,6 +3631,21 @@ exports[`Verify master template is correct renders master template correctly 1`] "true", ], }, + "KNOWLEDGE_BASE_PROMPT_TEMPLATE": { + "Fn::If": [ + "BedrockKnowledgeBaseEnable", + { + "Fn::FindInMap": [ + "BedrockDefaults", + { + "Ref": "BedrockKnowledgeBaseModel", + }, + "KnowledgeBasePromptTemplate", + ], + }, + "Human: You are a question answering agent. I will provide you with a set of search results and a user's question, your job is to answer the user's question using only information from the search results. If the search results do not contain information that can answer the question, then respond saying \\"Sorry, I don't know\\". Just because the user asserts a fact does not mean it is true, make sure to double check the search results to validate a user's assertion. Here are the search results in numbered order: $search_results$. Here is the user's question: $query$ $output_format_instructions$. Do NOT directly quote the $search_results$ in your answer. Your job is to answer the as concisely as possible. Assistant:", + ], + }, "LLM_GENERATE_QUERY_ENABLE": { "Fn::If": [ "LLMEnable", @@ -4004,6 +4177,11 @@ exports[`Verify master template is correct renders master template correctly 1`] "Ref": "QnABotCommonLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ESCFNProxyLambdaLogGroup", + }, + }, "MemorySize": "1408", "Role": { "Fn::GetAtt": [ @@ -4049,46 +4227,93 @@ exports[`Verify master template is correct renders master template correctly 1`] }, "Type": "AWS::Lambda::Function", }, - "ESCleaningLambda": { + "ESCFNProxyLambdaLogGroup": { "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W92", - "reason": "This lambda function does not require to have ReservedConcurrentExecutions", - }, - ], - }, "guard": { "SuppressedRules": [ - "LAMBDA_CONCURRENCY_CHECK", - "LAMBDA_INSIDE_VPC", + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", ], }, }, "Properties": { - "Code": { - "S3Bucket": { - "Ref": "BootstrapBucket", - }, - "S3Key": { - "Fn::Sub": "\${BootstrapPrefix}/lambda/proxy-es.zip", - }, - "S3ObjectVersion": { - "Ref": "ESProxyCodeVersion", - }, - }, - "Environment": { - "Variables": { - "ES_ADDRESS": { - "Fn::GetAtt": [ - "ESVar", - "ESAddress", - ], - }, - "ES_INDEX": { - "Fn::GetAtt": [ - "Var", + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ESCFNProxyLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, + "ESCleaningLambda": { + "Metadata": { + "cfn_nag": { + "rules_to_suppress": [ + { + "id": "W92", + "reason": "This lambda function does not require to have ReservedConcurrentExecutions", + }, + ], + }, + "guard": { + "SuppressedRules": [ + "LAMBDA_CONCURRENCY_CHECK", + "LAMBDA_INSIDE_VPC", + ], + }, + }, + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "BootstrapBucket", + }, + "S3Key": { + "Fn::Sub": "\${BootstrapPrefix}/lambda/proxy-es.zip", + }, + "S3ObjectVersion": { + "Ref": "ESProxyCodeVersion", + }, + }, + "Environment": { + "Variables": { + "ES_ADDRESS": { + "Fn::GetAtt": [ + "ESVar", + "ESAddress", + ], + }, + "ES_INDEX": { + "Fn::GetAtt": [ + "Var", "QnaIndex", ], }, @@ -4117,6 +4342,11 @@ exports[`Verify master template is correct renders master template correctly 1`] "Ref": "QnABotCommonLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ESCleaningLambdaLogGroup", + }, + }, "MemorySize": "1408", "Role": { "Fn::GetAtt": [ @@ -4162,6 +4392,53 @@ exports[`Verify master template is correct renders master template correctly 1`] }, "Type": "AWS::Lambda::Function", }, + "ESCleaningLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ESCleaningLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "ESCognitoRole": { "Metadata": { "cfn_nag": { @@ -4408,6 +4685,11 @@ exports.handler = async function (event, context) { "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ESInfoLambdaLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -4453,6 +4735,54 @@ exports.handler = async function (event, context) { }, "Type": "AWS::Lambda::Function", }, + "ESInfoLambdaLogGroup": { + "Condition": "DontCreateDomain", + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ESInfoLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "ESLoggingLambda": { "Metadata": { "cfn_nag": { @@ -4506,6 +4836,11 @@ exports.handler = async function (event, context) { "Ref": "QnABotCommonLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ESLoggingLambdaLogGroup", + }, + }, "MemorySize": "1408", "Role": { "Fn::GetAtt": [ @@ -4551,6 +4886,53 @@ exports.handler = async function (event, context) { }, "Type": "AWS::Lambda::Function", }, + "ESLoggingLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ESLoggingLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "ESLoggingLambdaRole": { "Metadata": { "cfn_nag": { @@ -4879,6 +5261,11 @@ exports.handler = async function (event, context) { "Ref": "QnABotCommonLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ESProxyLambdaLogGroup", + }, + }, "MemorySize": "1408", "Role": { "Fn::GetAtt": [ @@ -4924,6 +5311,53 @@ exports.handler = async function (event, context) { }, "Type": "AWS::Lambda::Function", }, + "ESProxyLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ESProxyLambdaLogGroup", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "ESProxyLambdaRole": { "Metadata": { "cfn_nag": { @@ -5144,23 +5578,6 @@ exports.handler = async function (event, context) { "Effect": "Allow", "Resource": "*", }, - { - "Action": [ - "lex:GetBuiltinIntent", - "lex:GetIntents", - "lex:GetBots", - "lex:GetSlotTypes", - "lex:GetBotAliases", - "lex:StartImport", - "lex:GetMigration", - "lex:GetBuiltinSlotTypes", - "lex:GetBuiltinIntents", - "lex:GetImport", - "lex:GetMigrations", - ], - "Effect": "Allow", - "Resource": "*", - }, { "Action": "lex:*", "Effect": "Allow", @@ -5209,23 +5626,6 @@ exports.handler = async function (event, context) { }, ], }, - { - "Action": [ - "lex:GetBuiltinIntent", - "lex:GetIntents", - "lex:GetBots", - "lex:GetSlotTypes", - "lex:GetBotAliases", - "lex:StartImport", - "lex:GetMigration", - "lex:GetBuiltinSlotTypes", - "lex:GetBuiltinIntents", - "lex:GetImport", - "lex:GetMigrations", - ], - "Effect": "Allow", - "Resource": "*", - }, { "Action": "lex:*", "Effect": "Allow", @@ -5580,7 +5980,28 @@ exports.handler = async function (event, context) { "Effect": "Allow", "Resource": [ { - "Fn::Sub": "arn:\${AWS::Partition}:bedrock:\${AWS::Region}::foundation-model/\${EmbeddingsBedrockModelId}", + "Fn::If": [ + "EmbeddingsBedrock", + { + "Fn::Sub": [ + "arn:\${AWS::Partition}:bedrock:\${AWS::Region}::foundation-model/\${ModelId}", + { + "ModelId": { + "Fn::FindInMap": [ + "BedrockDefaults", + { + "Ref": "EmbeddingsBedrockModelId", + }, + "ModelID", + ], + }, + }, + ], + }, + { + "Ref": "AWS::NoValue", + }, + ], }, ], }, @@ -5683,6 +6104,11 @@ exports.handler = async function (event, context) { "Ref": "QnABotCommonLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ESQidLambdaLogGroup", + }, + }, "MemorySize": "1408", "Role": { "Fn::GetAtt": [ @@ -5728,6 +6154,53 @@ exports.handler = async function (event, context) { }, "Type": "AWS::Lambda::Function", }, + "ESQidLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ESQidLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "ESQueryLambda": { "Metadata": { "cfn_nag": { @@ -5765,12 +6238,6 @@ exports.handler = async function (event, context) { "DEFAULT_SETTINGS_PARAM": { "Ref": "DefaultQnABotSettings", }, - "EXTCanvasLMSHook": { - "Fn::GetAtt": [ - "ExamplesStack", - "Outputs.EXTCanvasLMSHook", - ], - }, "EXTCreateRecentTopicsResponse": { "Fn::GetAtt": [ "ExamplesStack", @@ -5859,6 +6326,11 @@ exports.handler = async function (event, context) { "Ref": "QnABotCommonLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ESQueryLambdaLogGroup", + }, + }, "MemorySize": "1408", "Role": { "Fn::GetAtt": [ @@ -5904,6 +6376,53 @@ exports.handler = async function (event, context) { }, "Type": "AWS::Lambda::Function", }, + "ESQueryLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ESQueryLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "ESVar": { "Properties": { "ESAddress": { @@ -6054,6 +6573,11 @@ exports.handler = async function (event, context) { "Ref": "QnABotCommonLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ESWarmerLambdaLogGroup", + }, + }, "MemorySize": "512", "Role": { "Fn::GetAtt": [ @@ -6099,6 +6623,53 @@ exports.handler = async function (event, context) { }, "Type": "AWS::Lambda::Function", }, + "ESWarmerLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ESWarmerLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "ESWarmerRule": { "Properties": { "ScheduleExpression": "rate(1 minute)", @@ -6467,6 +7038,11 @@ exports.documents = (event, context, callback) => { "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ExampleS3ListLambdaLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -6493,16 +7069,63 @@ exports.documents = (event, context, callback) => { }, ], }, - "VpcConfig": { + "VpcConfig": { + "Fn::If": [ + "VPCEnabled", + { + "SecurityGroupIds": { + "Ref": "VPCSecurityGroupIdList", + }, + "SubnetIds": { + "Ref": "VPCSubnetIdList", + }, + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Lambda::Function", + }, + "ExampleS3ListLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ExampleS3ListLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { "Fn::If": [ - "VPCEnabled", + "LogRetentionPeriodIsNotZero", { - "SecurityGroupIds": { - "Ref": "VPCSecurityGroupIdList", - }, - "SubnetIds": { - "Ref": "VPCSubnetIdList", - }, + "Ref": "LogRetentionPeriod", }, { "Ref": "AWS::NoValue", @@ -6510,7 +7133,7 @@ exports.documents = (event, context, callback) => { ], }, }, - "Type": "AWS::Lambda::Function", + "Type": "AWS::Logs::LogGroup", }, "ExampleS3ListPhotoLambda": { "Metadata": { @@ -6626,6 +7249,11 @@ exports.documents = (event, context, callback) => { "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "ExampleS3ListPhotoLambdaLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -6671,6 +7299,53 @@ exports.documents = (event, context, callback) => { }, "Type": "AWS::Lambda::Function", }, + "ExampleS3ListPhotoLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-ExampleS3ListPhotoLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "Examples": { "Properties": { "ParentId": { @@ -6808,8 +7483,8 @@ exports.documents = (event, context, callback) => { "InstallLexResponseBots": { "Ref": "InstallLexResponseBots", }, - "LexBotVersion": { - "Ref": "LexBotVersion", + "LogRetentionPeriod": { + "Ref": "LogRetentionPeriod", }, "PrivateQnABotSettings": { "Ref": "PrivateQnABotSettings", @@ -6969,15 +7644,6 @@ exports.documents = (event, context, callback) => { "BootstrapPrefix": { "Ref": "BootstrapPrefix", }, - "BotName": { - "Fn::If": [ - "CreateLexV1Bots", - { - "Ref": "LexBot", - }, - "LexV2Only_Mode", - ], - }, "CFNInvokePolicy": { "Ref": "CFNInvokePolicy", }, @@ -6987,6 +7653,9 @@ exports.documents = (event, context, callback) => { "Arn", ], }, + "ContentDesignerOutputBucket": { + "Ref": "ContentDesignerOutputBucket", + }, "CustomQnABotSettings": { "Ref": "CustomQnABotSettings", }, @@ -7008,24 +7677,6 @@ exports.documents = (event, context, callback) => { "ExportBucket": { "Ref": "ExportBucket", }, - "FallbackIntent": { - "Fn::If": [ - "CreateLexV1Bots", - { - "Ref": "IntentFallback", - }, - "LexV2Only_Mode", - ], - }, - "Intent": { - "Fn::If": [ - "CreateLexV1Bots", - { - "Ref": "Intent", - }, - "LexV2Only_Mode", - ], - }, "KendraCrawlerSnsTopic": { "Ref": "KendraCrawlerSnsTopic", }, @@ -7065,12 +7716,9 @@ exports.documents = (event, context, callback) => { "botName", ], }, - "LexVersion": { - "Fn::If": [ - "CreateLexV1Bots", - "V1", - "V2", - ], + "LexVersion": "V2", + "LogRetentionPeriod": { + "Ref": "LogRetentionPeriod", }, "PrivateQnABotSettings": { "Ref": "PrivateQnABotSettings", @@ -7264,16 +7912,49 @@ exports.documents = (event, context, callback) => { "id": "W86", "reason": "LogGroup is encrypted by default.", }, - { - "id": "W84", - "reason": "LogGroup needs to be retained indefinitely", - }, + ], + }, + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", ], }, }, "Properties": { "LogGroupName": { - "Fn::Sub": "/aws/kinesisfirehose/\${AWS::StackName}-FeedbackKinesisFirehose", + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/kinesisfirehose/\${AWS::StackName}-FeedbackKinesisFirehose", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], }, }, "Type": "AWS::Logs::LogGroup", @@ -7703,12 +8384,6 @@ exports.documents = (event, context, callback) => { "QnAType", ], }, - "EXTCanvasLMSHook": { - "Fn::GetAtt": [ - "ExamplesStack", - "Outputs.EXTCanvasLMSHook", - ], - }, "EXTCreateRecentTopicsResponse": { "Fn::GetAtt": [ "ExamplesStack", @@ -7944,6 +8619,11 @@ exports.documents = (event, context, callback) => { "Ref": "QnABotCommonLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "FulfillmentLambdaLogGroup", + }, + }, "MemorySize": 1408, "Role": { "Fn::GetAtt": [ @@ -8016,6 +8696,53 @@ exports.documents = (event, context, callback) => { }, "Type": "AWS::Lambda::Alias", }, + "FulfillmentLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-FulfillmentLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "FulfillmentLambdaRole": { "Metadata": { "cfn_nag": { @@ -8387,7 +9114,20 @@ exports.documents = (event, context, callback) => { "Fn::If": [ "EmbeddingsBedrock", { - "Fn::Sub": "arn:\${AWS::Partition}:bedrock:\${AWS::Region}::foundation-model/\${EmbeddingsBedrockModelId}", + "Fn::Sub": [ + "arn:\${AWS::Partition}:bedrock:\${AWS::Region}::foundation-model/\${ModelId}", + { + "ModelId": { + "Fn::FindInMap": [ + "BedrockDefaults", + { + "Ref": "EmbeddingsBedrockModelId", + }, + "ModelID", + ], + }, + }, + ], }, { "Ref": "AWS::NoValue", @@ -8444,6 +9184,18 @@ exports.documents = (event, context, callback) => { }, ], }, + { + "Action": [ + "bedrock:ApplyGuardrail", + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:\${AWS::Partition}:bedrock:\${AWS::Region}:\${AWS::AccountId}:guardrail/*", + }, + ], + "Sid": "ApplyGuardrailsToLLMBedrock", + }, ], "Version": "2012-10-17", }, @@ -8470,6 +9222,18 @@ exports.documents = (event, context, callback) => { "Fn::Sub": "arn:\${AWS::Partition}:bedrock:\${AWS::Region}:\${AWS::AccountId}:knowledge-base/\${BedrockKnowledgeBaseId}", }, }, + { + "Action": [ + "bedrock:ApplyGuardrail", + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": "arn:\${AWS::Partition}:bedrock:\${AWS::Region}:\${AWS::AccountId}:guardrail/*", + }, + ], + "Sid": "ApplyGuardrailsToKnowledgeBase", + }, ], "Version": "2012-10-17", }, @@ -8701,16 +9465,49 @@ exports.documents = (event, context, callback) => { "id": "W86", "reason": "LogGroup is encrypted by default.", }, - { - "id": "W84", - "reason": "LogGroup needs to be retained indefinitely", - }, + ], + }, + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", ], }, }, "Properties": { "LogGroupName": { - "Fn::Sub": "/aws/kinesisfirehose/\${AWS::StackName}-GeneralKinesisFirehose", + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/kinesisfirehose/\${AWS::StackName}-GeneralKinesisFirehose", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], }, }, "Type": "AWS::Logs::LogGroup", @@ -8729,14 +9526,67 @@ exports.documents = (event, context, callback) => { "LogGroupName": { "Ref": "GeneralKinesisFirehoseLogGroup", }, - "LogStreamName": "S3BackupDelivery", + "LogStreamName": "S3BackupDelivery", + }, + "Type": "AWS::Logs::LogStream", + }, + "HTTPSOnlyAssetBucketPolicy": { + "Properties": { + "Bucket": { + "Ref": "AssetBucket", + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false", + }, + }, + "Effect": "Deny", + "Principal": "*", + "Resource": [ + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "AssetBucket", + "Arn", + ], + }, + "/*", + ], + ], + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "AssetBucket", + "Arn", + ], + }, + ], + ], + }, + ], + "Sid": "HttpsOnly", + }, + ], + "Version": "2012-10-17", + }, }, - "Type": "AWS::Logs::LogStream", + "Type": "AWS::S3::BucketPolicy", }, - "HTTPSOnlyAssetBucketPolicy": { + "HTTPSOnlyBucketPolicy": { "Properties": { "Bucket": { - "Ref": "AssetBucket", + "Ref": "Bucket", }, "PolicyDocument": { "Statement": [ @@ -8756,7 +9606,7 @@ exports.documents = (event, context, callback) => { [ { "Fn::GetAtt": [ - "AssetBucket", + "Bucket", "Arn", ], }, @@ -8770,7 +9620,7 @@ exports.documents = (event, context, callback) => { [ { "Fn::GetAtt": [ - "AssetBucket", + "Bucket", "Arn", ], }, @@ -8786,10 +9636,13 @@ exports.documents = (event, context, callback) => { }, "Type": "AWS::S3::BucketPolicy", }, - "HTTPSOnlyBucketPolicy": { + "HTTPSOnlyBuildStatusBucketPolicy": { + "Metadata": { + "aws:cdk:path": "serverless-bot-framework/CloudfrontStaticWebsite/CloudFrontToS3/S3LoggingBucket/Policy/Resource", + }, "Properties": { "Bucket": { - "Ref": "Bucket", + "Ref": "BuildStatusBucket", }, "PolicyDocument": { "Statement": [ @@ -8809,7 +9662,7 @@ exports.documents = (event, context, callback) => { [ { "Fn::GetAtt": [ - "Bucket", + "BuildStatusBucket", "Arn", ], }, @@ -8823,7 +9676,7 @@ exports.documents = (event, context, callback) => { [ { "Fn::GetAtt": [ - "Bucket", + "BuildStatusBucket", "Arn", ], }, @@ -8839,13 +9692,10 @@ exports.documents = (event, context, callback) => { }, "Type": "AWS::S3::BucketPolicy", }, - "HTTPSOnlyBuildStatusBucketPolicy": { - "Metadata": { - "aws:cdk:path": "serverless-bot-framework/CloudfrontStaticWebsite/CloudFrontToS3/S3LoggingBucket/Policy/Resource", - }, + "HTTPSOnlyContentDesignerOutputBucketPolicy": { "Properties": { "Bucket": { - "Ref": "BuildStatusBucket", + "Ref": "ContentDesignerOutputBucket", }, "PolicyDocument": { "Statement": [ @@ -8865,7 +9715,7 @@ exports.documents = (event, context, callback) => { [ { "Fn::GetAtt": [ - "BuildStatusBucket", + "ContentDesignerOutputBucket", "Arn", ], }, @@ -8879,7 +9729,7 @@ exports.documents = (event, context, callback) => { [ { "Fn::GetAtt": [ - "BuildStatusBucket", + "ContentDesignerOutputBucket", "Arn", ], }, @@ -9545,6 +10395,9 @@ exports.documents = (event, context, callback) => { "CommonModulesLambdaLayer": { "Ref": "CommonModulesLambdaLayer", }, + "ContentDesignerOutputBucket": { + "Ref": "ContentDesignerOutputBucket", + }, "CustomQnABotSettings": { "Ref": "CustomQnABotSettings", }, @@ -9626,6 +10479,9 @@ exports.documents = (event, context, callback) => { "ImportBucket": { "Ref": "ImportBucket", }, + "LogRetentionPeriod": { + "Ref": "LogRetentionPeriod", + }, "MetricsIndex": { "Fn::GetAtt": [ "Var", @@ -9757,93 +10613,6 @@ exports.documents = (event, context, callback) => { }, "Type": "Custom::Variable", }, - "Intent": { - "Condition": "CreateLexV1Bots", - "DependsOn": "QNAInvokePermission", - "Properties": { - "ServiceToken": { - "Fn::GetAtt": [ - "CFNLambda", - "Arn", - ], - }, - "createVersion": true, - "description": "custom intent x.x.x - v1", - "fulfillmentActivity": { - "codeHook": { - "messageVersion": "1.0", - "uri": { - "Fn::Join": [ - ":", - [ - { - "Fn::GetAtt": [ - "FulfillmentLambda", - "Arn", - ], - }, - "live", - ], - ], - }, - }, - "type": "CodeHook", - }, - "prefix": "fulfilment", - "sampleUtterances": [ - "{slot}", - ], - "slots": [ - { - "name": "slot", - "priority": 1, - "slotConstraint": "Optional", - "slotType": { - "Ref": "SlotType", - }, - "slotTypeVersion": "QNABOT-AUTO-ASSIGNED", - }, - ], - }, - "Type": "Custom::LexIntent", - }, - "IntentFallback": { - "Condition": "CreateLexV1Bots", - "DependsOn": "QNAInvokePermission", - "Properties": { - "ServiceToken": { - "Fn::GetAtt": [ - "CFNLambda", - "Arn", - ], - }, - "createVersion": true, - "description": "custom fallback intent x.x.x - v1", - "fulfillmentActivity": { - "codeHook": { - "messageVersion": "1.0", - "uri": { - "Fn::Join": [ - ":", - [ - { - "Fn::GetAtt": [ - "FulfillmentLambda", - "Arn", - ], - }, - "live", - ], - ], - }, - }, - "type": "CodeHook", - }, - "parentIntentSignature": "AMAZON.FallbackIntent", - "prefix": "qnabotfallbackfulfilment", - }, - "Type": "Custom::LexIntent", - }, "InvokePermissionESCleaningLambda": { "Properties": { "Action": "lambda:InvokeFunction", @@ -10186,12 +10955,6 @@ exports.documents = (event, context, callback) => { "Outputs.EXTCustomJSHook", ], }, - { - "Fn::GetAtt": [ - "ExamplesStack", - "Outputs.EXTCanvasLMSHook", - ], - }, { "Fn::GetAtt": [ "ExamplesStack", @@ -10313,8 +11076,6 @@ exports.documents = (event, context, callback) => { "Statement": [ { "Action": [ - "lex:PostContent", - "lex:PostText", "lex:RecognizeText", "lex:RecognizeUtterance", ], @@ -10366,46 +11127,6 @@ exports.documents = (event, context, callback) => { }, "Type": "AWS::IAM::ManagedPolicy", }, - "LexBot": { - "Condition": "CreateLexV1Bots", - "Properties": { - "ServiceToken": { - "Fn::GetAtt": [ - "CFNLambda", - "Arn", - ], - }, - "abortStatement": { - "messages": [ - { - "content": "Sorry, I did not understand that", - "contentType": "PlainText", - }, - ], - }, - "childDirected": false, - "createVersion": true, - "description": "QnABot primary bot x.x.x - v1", - "intents": [ - { - "intentName": { - "Ref": "Intent", - }, - }, - { - "intentName": { - "Ref": "IntentFallback", - }, - }, - ], - "locale": "en-US", - "name": { - "Fn::Sub": "\${AWS::StackName}-Bot", - }, - "voiceId": "Joanna", - }, - "Type": "Custom::LexBot", - }, "LexBotPolicy": { "Metadata": { "guard": { @@ -10419,7 +11140,6 @@ exports.documents = (event, context, callback) => { "Statement": [ { "Action": [ - "lex:PostText", "lex:RecognizeText", ], "Effect": "Allow", @@ -10543,56 +11263,12 @@ exports.documents = (event, context, callback) => { ], ], }, - "BOTALIAS": { - "Fn::If": [ - "CreateLexV1Bots", - { - "Ref": "VersionAlias", - }, - { - "Ref": "AWS::NoValue", - }, - ], - }, - "BOTNAME": { - "Fn::If": [ - "CreateLexV1Bots", - { - "Ref": "LexBot", - }, - { - "Ref": "AWS::NoValue", - }, - ], - }, "INDEX": { "Fn::GetAtt": [ "Var", "index", ], }, - "INTENT": { - "Fn::If": [ - "CreateLexV1Bots", - { - "Ref": "Intent", - }, - { - "Ref": "AWS::NoValue", - }, - ], - }, - "INTENTFALLBACK": { - "Fn::If": [ - "CreateLexV1Bots", - { - "Ref": "IntentFallback", - }, - { - "Ref": "AWS::NoValue", - }, - ], - }, "LEXV2_BUILD_LAMBDA": { "Ref": "Lexv2BotLambda", }, @@ -10603,31 +11279,11 @@ exports.documents = (event, context, callback) => { "Arn", ], }, - "SLOTTYPE": { - "Fn::If": [ - "CreateLexV1Bots", - { - "Ref": "SlotType", - }, - { - "Ref": "AWS::NoValue", - }, - ], - }, "SOLUTION_ID": "SO0189", "SOLUTION_VERSION": "vx.x.x", "STATUS_BUCKET": { "Ref": "BuildStatusBucket", }, - "STATUS_KEY": { - "Fn::If": [ - "CreateLexV1Bots", - "status.json", - { - "Ref": "AWS::NoValue", - }, - ], - }, "UTTERANCE_BUCKET": { "Ref": "AssetBucket", }, @@ -10643,6 +11299,11 @@ exports.documents = (event, context, callback) => { "Ref": "CommonModulesLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "LexBuildLambdaLogGroup", + }, + }, "MemorySize": "1024", "Role": { "Fn::GetAtt": [ @@ -10688,6 +11349,53 @@ exports.documents = (event, context, callback) => { }, "Type": "AWS::Lambda::Function", }, + "LexBuildLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-LexBuildLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "LexBuildLambdaPoll": { "Metadata": { "cfn_nag": { @@ -10789,31 +11497,11 @@ exports.handler = async function (event, context, callback) { }, "Environment": { "Variables": { - "BOT_NAME": { - "Fn::If": [ - "CreateLexV1Bots", - { - "Ref": "LexBot", - }, - { - "Ref": "AWS::NoValue", - }, - ], - }, "SOLUTION_ID": "SO0189", "SOLUTION_VERSION": "vx.x.x", "STATUS_BUCKET": { "Ref": "BuildStatusBucket", }, - "STATUS_KEY": { - "Fn::If": [ - "CreateLexV1Bots", - "status.json", - { - "Ref": "AWS::NoValue", - }, - ], - }, }, }, "Handler": "index.handler", @@ -10825,6 +11513,11 @@ exports.handler = async function (event, context, callback) { "Ref": "CommonModulesLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "LexBuildLambdaPollLogGroup", + }, + }, "MemorySize": "1024", "Role": { "Fn::GetAtt": [ @@ -10851,16 +11544,63 @@ exports.handler = async function (event, context, callback) { }, ], }, - "VpcConfig": { + "VpcConfig": { + "Fn::If": [ + "VPCEnabled", + { + "SecurityGroupIds": { + "Ref": "VPCSecurityGroupIdList", + }, + "SubnetIds": { + "Ref": "VPCSubnetIdList", + }, + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Lambda::Function", + }, + "LexBuildLambdaPollLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-LexBuildLambdaPoll", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { "Fn::If": [ - "VPCEnabled", + "LogRetentionPeriodIsNotZero", { - "SecurityGroupIds": { - "Ref": "VPCSecurityGroupIdList", - }, - "SubnetIds": { - "Ref": "VPCSubnetIdList", - }, + "Ref": "LogRetentionPeriod", }, { "Ref": "AWS::NoValue", @@ -10868,7 +11608,7 @@ exports.handler = async function (event, context, callback) { ], }, }, - "Type": "AWS::Lambda::Function", + "Type": "AWS::Logs::LogGroup", }, "LexBuildLambdaRole": { "Metadata": { @@ -11070,23 +11810,6 @@ exports.handler = async function (event, context, callback) { "Effect": "Allow", "Resource": "*", }, - { - "Action": [ - "lex:GetBuiltinIntent", - "lex:GetIntents", - "lex:GetBots", - "lex:GetSlotTypes", - "lex:GetBotAliases", - "lex:StartImport", - "lex:GetMigration", - "lex:GetBuiltinSlotTypes", - "lex:GetBuiltinIntents", - "lex:GetImport", - "lex:GetMigrations", - ], - "Effect": "Allow", - "Resource": "*", - }, { "Action": "lex:*", "Effect": "Allow", @@ -11135,23 +11858,6 @@ exports.handler = async function (event, context, callback) { }, ], }, - { - "Action": [ - "lex:GetBuiltinIntent", - "lex:GetIntents", - "lex:GetBots", - "lex:GetSlotTypes", - "lex:GetBotAliases", - "lex:StartImport", - "lex:GetMigration", - "lex:GetBuiltinSlotTypes", - "lex:GetBuiltinIntents", - "lex:GetImport", - "lex:GetMigrations", - ], - "Effect": "Allow", - "Resource": "*", - }, { "Action": "lex:*", "Effect": "Allow", @@ -11427,22 +12133,10 @@ const crypto = require('crypto'); exports.handler = async function (event, context, callback) { const token = crypto.randomBytes(16).toString('base64'); const bucket = process.env.STATUS_BUCKET; - const lexV1StatusFile = process.env.STATUS_KEY; const lexV2StatusFile = process.env.LEXV2_STATUS_KEY; const functionName = process.env.BUILD_FUNCTION; const body = JSON.stringify({ status: 'Starting', token }); - if (lexV1StatusFile) { - console.log('Initializing ', bucket, lexV1StatusFile); - const params = { - Bucket: bucket, - Key: lexV1StatusFile, - Body: body, - }; - const putObjectCmdV1 = new PutObjectCommand(params); - await s3.send(putObjectCmdV1); - } - console.log('Initializing ', bucket, lexV2StatusFile); const params = { Bucket: bucket, @@ -11452,7 +12146,7 @@ exports.handler = async function (event, context, callback) { const putObjectCmdV2 = new PutObjectCommand(params); await s3.send(putObjectCmdV2); - // The BUILD_FUNCTION takes care of rebuilding Lex V2 bot, and (unless QnABot is set to V2 only) Lex V1 bot + // The BUILD_FUNCTION takes care of rebuilding Lex V2 bot console.log('Invoking ', functionName); const invokeParams = { FunctionName: functionName, @@ -11479,15 +12173,6 @@ exports.handler = async function (event, context, callback) { "STATUS_BUCKET": { "Ref": "BuildStatusBucket", }, - "STATUS_KEY": { - "Fn::If": [ - "CreateLexV1Bots", - "status.json", - { - "Ref": "AWS::NoValue", - }, - ], - }, }, }, "Handler": "index.handler", @@ -11499,6 +12184,11 @@ exports.handler = async function (event, context, callback) { "Ref": "CommonModulesLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "LexBuildLambdaStartLogGroup", + }, + }, "MemorySize": "1024", "Role": { "Fn::GetAtt": [ @@ -11544,6 +12234,53 @@ exports.handler = async function (event, context, callback) { }, "Type": "AWS::Lambda::Function", }, + "LexBuildLambdaStartLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-LexBuildLambdaStart", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "LexProxyLambda": { "Metadata": { "cfn_nag": { @@ -11613,6 +12350,11 @@ exports.handler = (event, context, callback) => { "Ref": "CommonModulesLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "LexProxyLambdaLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -11658,6 +12400,53 @@ exports.handler = (event, context, callback) => { }, "Type": "AWS::Lambda::Function", }, + "LexProxyLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-LexProxyLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "LexProxyLambdaRole": { "Metadata": { "cfn_nag": { @@ -11832,23 +12621,6 @@ exports.handler = (event, context, callback) => { "Effect": "Allow", "Resource": "*", }, - { - "Action": [ - "lex:GetBuiltinIntent", - "lex:GetIntents", - "lex:GetBots", - "lex:GetSlotTypes", - "lex:GetBotAliases", - "lex:StartImport", - "lex:GetMigration", - "lex:GetBuiltinSlotTypes", - "lex:GetBuiltinIntents", - "lex:GetImport", - "lex:GetMigrations", - ], - "Effect": "Allow", - "Resource": "*", - }, { "Action": "lex:*", "Effect": "Allow", @@ -11897,23 +12669,6 @@ exports.handler = (event, context, callback) => { }, ], }, - { - "Action": [ - "lex:GetBuiltinIntent", - "lex:GetIntents", - "lex:GetBots", - "lex:GetSlotTypes", - "lex:GetBotAliases", - "lex:StartImport", - "lex:GetMigration", - "lex:GetBuiltinSlotTypes", - "lex:GetBuiltinIntents", - "lex:GetImport", - "lex:GetMigrations", - ], - "Effect": "Allow", - "Resource": "*", - }, { "Action": "lex:*", "Effect": "Allow", @@ -12199,9 +12954,6 @@ function getStatusResponse(response, build) { lambdaArn: process.env.FULFILLMENT_FUNCTION_ARN, lambdaRole: process.env.FULFILLMENT_FUNCTION_ROLE, botversion: 'live', - botname: process.env.LEXV1_BOT_NAME || 'LEX V1 Bot not installed', - intent: process.env.LEXV1_INTENT || 'LEX V1 Bot not installed', - intentFallback: process.env.LEXV1_INTENT_FALLBACK || 'LEX V1 Bot not installed', lexV2botname: process.env.LEXV2_BOT_NAME || 'LEX V2 Bot not installed', lexV2botid: process.env.LEXV2_BOT_ID || 'LEX V2 Bot not installed', lexV2botalias: process.env.LEXV2_BOT_ALIAS || 'LEX V2 Bot not installed', @@ -12219,7 +12971,6 @@ exports.handler = async (event, context, callback) => { console.log('Received event:', JSON.stringify(event, null, 2)); const bucket = process.env.STATUS_BUCKET; - const lexV1StatusFile = process.env.STATUS_KEY; const lexV2StatusFile = process.env.LEXV2_STATUS_KEY; let build = { status: 'READY', token: 'token' }; let response; @@ -12229,16 +12980,6 @@ exports.handler = async (event, context, callback) => { response = await s3.send(getObjCmd); const readableStreamV2 = Buffer.concat(await response.Body.toArray()); build = JSON.parse(readableStreamV2); - // combine build status with v1 bot, if defined.. If both are READY then status is READY - if (lexV1StatusFile) { - const getObjCmd = new GetObjectCommand({ Bucket: bucket, Key: lexV1StatusFile }); - response = await s3.send(getObjCmd); - const readableStreamV2 = Buffer.concat(await response.Body.toArray()); - const v1build = JSON.parse(readableStreamV2); - if (v1build.status != 'READY' || build.status != 'READY') { - build.status = \`LEX V2: \${build.status} / LEX V1: \${v1build.status}\`; - } - } } catch (e) { console.log('Unable to read S3 lex bot status file - perhaps it doesn\\'t yet exist. Returning READY'); } @@ -12247,7 +12988,6 @@ exports.handler = async (event, context, callback) => { botId: process.env.LEXV2_BOT_ID, }); response = await lexv2.send(describeBotCmd); - // Match LexV1 bot status for code compatibility (Available = READY) const statusResponse = getStatusResponse(response, build); return statusResponse; }; @@ -12272,39 +13012,6 @@ exports.handler = async (event, context, callback) => { "FULFILLMENT_FUNCTION_ROLE": { "Ref": "FulfillmentLambdaRole", }, - "LEXV1_BOT_NAME": { - "Fn::If": [ - "CreateLexV1Bots", - { - "Ref": "LexBot", - }, - { - "Ref": "AWS::NoValue", - }, - ], - }, - "LEXV1_INTENT": { - "Fn::If": [ - "CreateLexV1Bots", - { - "Ref": "Intent", - }, - { - "Ref": "AWS::NoValue", - }, - ], - }, - "LEXV1_INTENT_FALLBACK": { - "Fn::If": [ - "CreateLexV1Bots", - { - "Ref": "IntentFallback", - }, - { - "Ref": "AWS::NoValue", - }, - ], - }, "LEXV2_BOT_ALIAS": { "Fn::GetAtt": [ "LexV2Bot", @@ -12353,15 +13060,6 @@ exports.handler = async (event, context, callback) => { "STATUS_BUCKET": { "Ref": "BuildStatusBucket", }, - "STATUS_KEY": { - "Fn::If": [ - "CreateLexV1Bots", - "status.json", - { - "Ref": "AWS::NoValue", - }, - ], - }, }, }, "Handler": "index.handler", @@ -12370,6 +13068,11 @@ exports.handler = async (event, context, callback) => { "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "LexStatusLambdaLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -12415,6 +13118,53 @@ exports.handler = async (event, context, callback) => { }, "Type": "AWS::Lambda::Function", }, + "LexStatusLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-LexStatusLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "LexV2Bot": { "Properties": { "BuildDate": Any, @@ -12434,6 +13184,53 @@ exports.handler = async (event, context, callback) => { }, "Type": "Custom::LexV2Bot", }, + "LexV2BotLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-LexV2BotLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "Lexv2BotCodeVersion": { "Properties": { "Bucket": { @@ -12509,6 +13306,11 @@ exports.handler = async (event, context, callback) => { }, }, "Handler": "handler.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "LexV2BotLambdaLogGroup", + }, + }, "MemorySize": "1024", "Role": { "Fn::GetAtt": [ @@ -12745,28 +13547,11 @@ exports.handler = async (event, context, callback) => { "s3:ListAllMyBuckets", "lambda:ListFunctions", "cloudwatch:DescribeAlarmsForMetric", - "kms:ListAliases", - "iam:ListRoles", - "cloudwatch:GetMetricStatistics", - "kendra:ListIndices", - "polly:DescribeVoices", - ], - "Effect": "Allow", - "Resource": "*", - }, - { - "Action": [ - "lex:GetBuiltinIntent", - "lex:GetIntents", - "lex:GetBots", - "lex:GetSlotTypes", - "lex:GetBotAliases", - "lex:StartImport", - "lex:GetMigration", - "lex:GetBuiltinSlotTypes", - "lex:GetBuiltinIntents", - "lex:GetImport", - "lex:GetMigrations", + "kms:ListAliases", + "iam:ListRoles", + "cloudwatch:GetMetricStatistics", + "kendra:ListIndices", + "polly:DescribeVoices", ], "Effect": "Allow", "Resource": "*", @@ -12819,23 +13604,6 @@ exports.handler = async (event, context, callback) => { }, ], }, - { - "Action": [ - "lex:GetBuiltinIntent", - "lex:GetIntents", - "lex:GetBots", - "lex:GetSlotTypes", - "lex:GetBotAliases", - "lex:StartImport", - "lex:GetMigration", - "lex:GetBuiltinSlotTypes", - "lex:GetBuiltinIntents", - "lex:GetImport", - "lex:GetMigrations", - ], - "Effect": "Allow", - "Resource": "*", - }, { "Action": "lex:*", "Effect": "Allow", @@ -13352,6 +14120,11 @@ function message(code, name) { "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "MessageLambdaLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -13397,6 +14170,53 @@ function message(code, name) { }, "Type": "AWS::Lambda::Function", }, + "MessageLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-MessageLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "MessagePermision": { "Properties": { "Action": "lambda:InvokeFunction", @@ -13825,10 +14645,12 @@ function message(code, name) { "id": "W86", "reason": "LogGroup is encrypted by default.", }, - { - "id": "W84", - "reason": "LogGroup needs to be retained indefinitely", - }, + ], + }, + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", ], }, }, @@ -13836,6 +14658,17 @@ function message(code, name) { "LogGroupName": { "Fn::Sub": "/aws/opensearch/\${AWS::StackName}-\${ESVar.ESDomain}", }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, }, "Type": "AWS::Logs::LogGroup", }, @@ -14439,6 +15272,9 @@ function message(code, name) { "bucket": { "Ref": "ExportBucket", }, + "contentDesignerOutputBucket": { + "Ref": "ContentDesignerOutputBucket", + }, "id": "ExportAll_QnABot_vx.x.x.json", "index": { "Fn::Sub": "\${Var.QnaIndex}", @@ -14476,6 +15312,9 @@ function message(code, name) { "bucket": { "Ref": "ExportBucket", }, + "contentDesignerOutputBucket": { + "Ref": "ContentDesignerOutputBucket", + }, "id": "ExportAll_QnABot_vx.x.x_feedback.json", "index": { "Fn::Sub": "\${Var.FeedbackIndex}", @@ -14513,6 +15352,9 @@ function message(code, name) { "bucket": { "Ref": "ExportBucket", }, + "contentDesignerOutputBucket": { + "Ref": "ContentDesignerOutputBucket", + }, "id": "ExportAll_QnABot_vx.x.x_metrics.json", "index": { "Fn::Sub": "\${Var.MetricsIndex}", @@ -14533,7 +15375,13 @@ function message(code, name) { "Fn::If": [ "EmbeddingsBedrock", { - "Ref": "EmbeddingsBedrockModelId", + "Fn::FindInMap": [ + "BedrockDefaults", + { + "Ref": "EmbeddingsBedrockModelId", + }, + "ModelID", + ], }, "", ], @@ -14924,12 +15772,6 @@ function message(code, name) { "Outputs.EXTCustomJSHook", ], }, - { - "Fn::GetAtt": [ - "ExamplesStack", - "Outputs.EXTCanvasLMSHook", - ], - }, { "Fn::GetAtt": [ "ExamplesStack", @@ -16298,6 +17140,9 @@ function message(code, name) { { "Fn::Sub": "arn:aws:s3:::\${AssetBucket}/*", }, + { + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}/*", + }, ], }, { @@ -16312,6 +17157,9 @@ function message(code, name) { { "Fn::Sub": "arn:aws:s3:::\${TestAllBucket}/*", }, + { + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}/*", + }, ], }, { @@ -16329,6 +17177,9 @@ function message(code, name) { { "Fn::Sub": "arn:aws:s3:::\${TestAllBucket}/*", }, + { + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}/*", + }, ], }, ], @@ -16366,6 +17217,11 @@ function message(code, name) { }, }, "Handler": "lambda_function.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "S3CleanLambdaLogGroup", + }, + }, "Role": { "Fn::GetAtt": [ "CFNLambdaRole", @@ -16410,6 +17266,53 @@ function message(code, name) { }, "Type": "AWS::Lambda::Function", }, + "S3CleanLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-S3CleanLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "S3ClearCodeVersion": { "Properties": { "Bucket": { @@ -16512,6 +17415,11 @@ exports.handler = (event, context, callback) => { "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "S3ListLambdaLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -16557,6 +17465,53 @@ exports.handler = (event, context, callback) => { }, "Type": "AWS::Lambda::Function", }, + "S3ListLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-S3ListLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "S3ListLambdaRole": { "Metadata": { "cfn_nag": { @@ -16872,6 +17827,11 @@ exports.handler = (event, context, callback) => { "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "SchemaLambdaLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -16935,6 +17895,53 @@ exports.handler = (event, context, callback) => { }, "Type": "Custom::S3Version", }, + "SchemaLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-SchemaLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "SchemaLambdaRole": { "Metadata": { "cfn_nag": { @@ -17223,6 +18230,11 @@ exports.handler = (event, context, callback) => { "Ref": "AwsSdkLayerLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "SignupLambdaLogGroup", + }, + }, "MemorySize": "128", "Role": { "Fn::GetAtt": [ @@ -17268,6 +18280,53 @@ exports.handler = (event, context, callback) => { }, "Type": "AWS::Lambda::Function", }, + "SignupLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-SignupLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "SignupLambdaRole": { "Metadata": { "cfn_nag": { @@ -17425,29 +18484,10 @@ exports.handler = (event, context, callback) => { "Fn::GetAtt": [ "UserPool", "Arn", - ], - }, - }, - "Type": "AWS::Lambda::Permission", - }, - "SlotType": { - "Condition": "CreateLexV1Bots", - "Properties": { - "ServiceToken": { - "Fn::GetAtt": [ - "CFNLambda", - "Arn", - ], - }, - "createVersion": true, - "description": "custom slot type x.x.x - v1", - "enumerationValues": [ - { - "value": "dummy utterance", - }, - ], + ], + }, }, - "Type": "Custom::LexSlotType", + "Type": "AWS::Lambda::Permission", }, "SolutionHelper": { "DependsOn": [ @@ -17486,7 +18526,23 @@ exports.handler = (event, context, callback) => { }, }, "Description": "This function generates UUID for each deployment and sends anonymized data to the AWS Solutions team", + "Environment": { + "Variables": { + "CUSTOM_SETTINGS": { + "Ref": "CustomQnABotSettings", + }, + "SOLUTION_ID": "SO0189", + "SOLUTION_PARAMETER": { + "Ref": "SolutionHelperParameter", + }, + }, + }, "Handler": "lambda_function.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "SolutionHelperLogGroup", + }, + }, "Role": { "Fn::GetAtt": [ "SolutionHelperRole", @@ -17564,6 +18620,61 @@ exports.handler = (event, context, callback) => { "Type": "Custom::CreateUUID", "UpdateReplacePolicy": "Delete", }, + "SolutionHelperLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-SolutionHelper", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, + "SolutionHelperParameter": { + "Properties": { + "Description": "Solution Helper Parameter - DO NOT MODIFY", + "Type": "String", + "Value": "{}", + }, + "Type": "AWS::SSM::Parameter", + }, "SolutionHelperRole": { "Metadata": { "cfn_nag": { @@ -17706,6 +18817,104 @@ exports.handler = (event, context, callback) => { }, "PolicyName": "xrayDaemonWriteAccess", }, + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ssm:GetParameter", + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Fn::Sub": "\${AWS::Partition}:", + }, + "ssm:", + { + "Fn::Sub": "\${AWS::Region}:", + }, + { + "Fn::Sub": "\${AWS::AccountId}:", + }, + "parameter/", + { + "Ref": "SolutionHelperParameter", + }, + ], + ], + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Fn::Sub": "\${AWS::Partition}:", + }, + "ssm:", + { + "Fn::Sub": "\${AWS::Region}:", + }, + { + "Fn::Sub": "\${AWS::AccountId}:", + }, + "parameter/", + { + "Ref": "CustomQnABotSettings", + }, + ], + ], + }, + ], + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "GetParameterPolicy", + }, + { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ssm:PutParameter", + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Fn::Sub": "\${AWS::Partition}:", + }, + "ssm:", + { + "Fn::Sub": "\${AWS::Region}:", + }, + { + "Fn::Sub": "\${AWS::AccountId}:", + }, + "parameter/", + { + "Ref": "SolutionHelperParameter", + }, + ], + ], + }, + ], + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "PutParameterPolicy", + }, ], }, "Type": "AWS::IAM::Role", @@ -17791,9 +19000,6 @@ exports.handler = (event, context, callback) => { "Language": { "Ref": "Language", }, - "LexBotVersion": { - "Ref": "LexBotVersion", - }, "OpenSearchEBSVolumeSize": { "Fn::If": [ "CreateDomain", @@ -18062,6 +19268,9 @@ exports.handler = (event, context, callback) => { "CommonModulesLambdaLayer": { "Ref": "CommonModulesLambdaLayer", }, + "ContentDesignerOutputBucket": { + "Ref": "ContentDesignerOutputBucket", + }, "EsEndpoint": { "Fn::GetAtt": [ "ESVar", @@ -18086,6 +19295,9 @@ exports.handler = (event, context, callback) => { "botId", ], }, + "LogRetentionPeriod": { + "Ref": "LogRetentionPeriod", + }, "S3Clean": { "Fn::GetAtt": [ "S3Clean", @@ -18557,6 +19769,11 @@ exports.handler = (event, context, callback) => { "Ref": "QnABotCommonLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "UtteranceLambdaLogGroup", + }, + }, "MemorySize": "1408", "Role": { "Fn::GetAtt": [ @@ -18602,6 +19819,53 @@ exports.handler = (event, context, callback) => { }, "Type": "AWS::Lambda::Function", }, + "UtteranceLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-UtteranceLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "Var": { "Properties": { "FeedbackIndex": { @@ -18639,24 +19903,6 @@ exports.handler = (event, context, callback) => { }, "Type": "Custom::Variable", }, - "VersionAlias": { - "Condition": "CreateLexV1Bots", - "DependsOn": "LexBot", - "Properties": { - "ServiceToken": { - "Fn::GetAtt": [ - "CFNLambda", - "Arn", - ], - }, - "botName": { - "Ref": "LexBot", - }, - "description": "QnABot live alias x.x.x - v1", - "name": "live", - }, - "Type": "Custom::LexAlias", - }, "VersionLambda": { "Metadata": { "cfn_nag": { @@ -18782,6 +20028,11 @@ exports.handler = async function (event, context) { }, }, "Handler": "index.handler", + "LoggingConfig": { + "LogGroup": { + "Ref": "VersionLambdaLogGroup", + }, + }, "MemorySize": "3008", "Role": { "Fn::GetAtt": [ @@ -18827,6 +20078,53 @@ exports.handler = async function (event, context) { }, "Type": "AWS::Lambda::Function", }, + "VersionLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-VersionLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "WarmerLambdaRole": { "Metadata": { "cfn_nag": { @@ -19115,7 +20413,7 @@ exports.handler = async function (event, context) { }, ":s3:path/", { - "Ref": "ExportBucket", + "Ref": "ContentDesignerOutputBucket", }, "/status/{proxy}", ], @@ -19189,9 +20487,9 @@ exports.handler = async function (event, context) { }, ":s3:path/", { - "Ref": "ExportBucket", + "Ref": "ContentDesignerOutputBucket", }, - "/status/{proxy}", + "/status-export/{proxy}", ], ], }, @@ -19262,7 +20560,7 @@ exports.handler = async function (event, context) { "id":"$input.params('proxy')", "config":"status/$input.params('proxy')", "tmp":"tmp/$input.params('proxy')", - "key":"$inputRoot.get('prefix')data/$input.params('proxy')", + "key":"$inputRoot.get('prefix')data-export/$input.params('proxy')", "filter":"$inputRoot.get('filter')", "status":"Started" }", @@ -19281,7 +20579,7 @@ exports.handler = async function (event, context) { { "Ref": "ExportBucket", }, - "/status/{proxy}", + "/status-export/{proxy}", ], ], }, @@ -19420,8 +20718,8 @@ exports.handler = async function (event, context) { "Fn::Sub": "#set ($root="https://\${!context.domainName}/\${!context.stage}") { - "bucket":"\${ExportBucket}", - "prefix":"status/", + "bucket":"\${ContentDesignerOutputBucket}", + "prefix":"status-export/", "perpage":"$input.params('perpage')", "token":"$input.params('token')", "type":"exports", @@ -19535,9 +20833,9 @@ exports.handler = async function (event, context) { }, ":s3:path/", { - "Ref": "ImportBucket", + "Ref": "ContentDesignerOutputBucket", }, - "/status/{proxy}", + "/status-import/{proxy}", ], ], }, @@ -19609,9 +20907,9 @@ exports.handler = async function (event, context) { }, ":s3:path/", { - "Ref": "ImportBucket", + "Ref": "ContentDesignerOutputBucket", }, - "/status/{proxy}", + "/status-import/{proxy}", ], ], }, @@ -19750,8 +21048,8 @@ exports.handler = async function (event, context) { "Fn::Sub": "#set ($root="https://\${!context.domainName}/\${!context.stage}") { - "bucket":"\${ImportBucket}", - "prefix":"status/", + "bucket":"\${ContentDesignerOutputBucket}", + "prefix":"status-import/", "perpage":"$input.params('perpage')", "token":"$input.params('token')", "type":"imports", @@ -20106,6 +21404,7 @@ exports.handler = async function (event, context) { "PrivateQnABotSettings":"\${PrivateQnABotSettings}", "CustomQnABotSettings":"\${CustomQnABotSettings}", "KendraCrawlerSnsTopic":"\${KendraCrawlerSnsTopic}", + "SolutionHelper": "\${SolutionHelper}", "Id":"$stageVariables.Id", "_links":{ "root":{ @@ -20237,9 +21536,9 @@ exports.handler = async function (event, context) { }, ":s3:path/", { - "Ref": "TestAllBucket", + "Ref": "ContentDesignerOutputBucket", }, - "/status/{proxy}", + "/status-testall/{proxy}", ], ], }, @@ -20311,9 +21610,9 @@ exports.handler = async function (event, context) { }, ":s3:path/", { - "Ref": "TestAllBucket", + "Ref": "ContentDesignerOutputBucket", }, - "/status/{proxy}", + "/status-testall/{proxy}", ], ], }, @@ -20382,9 +21681,9 @@ exports.handler = async function (event, context) { "bucket":"\${TestAllBucket}", "index":"\${Var.QnaIndex}", "id":"$input.params('proxy')", - "config":"status/$input.params('proxy')", - "tmp":"tmp/$input.params('proxy')", - "key":"data/$input.params('proxy')", + "config":"status-testall/$input.params('proxy')", + "tmp":"tmp-testall/$input.params('proxy')", + "key":"data-testall/$input.params('proxy')", "filter":"$inputRoot.get('filter')", "token":"$inputRoot.get('token')", "locale":"$inputRoot.get('locale')", @@ -20407,7 +21706,7 @@ exports.handler = async function (event, context) { { "Ref": "TestAllBucket", }, - "/status/{proxy}", + "/status-testall/{proxy}", ], ], }, @@ -20546,8 +21845,8 @@ exports.handler = async function (event, context) { "Fn::Sub": "#set ($root="https://\${!context.domainName}/\${!context.stage}") { - "bucket":"\${TestAllBucket}", - "prefix":"status/", + "bucket":"\${ContentDesignerOutputBucket}", + "prefix":"status-testall/", "perpage":"$input.params('perpage')", "token":"$input.params('token')", "type":"testall", diff --git a/source/templates/master/bucket.js b/source/templates/master/bucket.js index 7235ce895..322f42563 100644 --- a/source/templates/master/bucket.js +++ b/source/templates/master/bucket.js @@ -55,18 +55,18 @@ module.exports = { Action: 's3:PutObject', Condition: { ArnLike: { - "aws:SourceArn" : "arn:aws:s3:::*" + 'aws:SourceArn': 'arn:aws:s3:::*', }, Bool: { 'aws:SecureTransport': 'true', }, StringEquals: { - "aws:SourceAccount": {Ref: 'AWS::AccountId'} - } + 'aws:SourceAccount': { Ref: 'AWS::AccountId' }, + }, }, Effect: 'Allow', Principal: { - Service: "logging.s3.amazonaws.com" + Service: 'logging.s3.amazonaws.com', }, Resource: [ { @@ -97,7 +97,7 @@ module.exports = { ], }, ], - Sid:'S3ServerAccessLogsPolicy', + Sid: 'S3ServerAccessLogsPolicy', }, { Action: '*', @@ -138,7 +138,7 @@ module.exports = { }, ], Sid: 'HttpsOnly', - } + }, ], Version: '2012-10-17', }, @@ -147,7 +147,7 @@ module.exports = { ExportBucket: { Type: 'AWS::S3::Bucket', Metadata: { guard: util.cfnGuard('S3_BUCKET_NO_PUBLIC_RW_ACL') }, - DependsOn : ['MainAccessLogBucket', 'MainAccessLogsBucketPolicy'], + DependsOn: ['MainAccessLogBucket', 'MainAccessLogsBucketPolicy'], Properties: { LifecycleConfiguration: { Rules: [{ @@ -179,8 +179,8 @@ module.exports = { }, LoggingConfiguration: { DestinationBucketName: { Ref: 'MainAccessLogBucket' }, - LogFilePrefix: {"Fn::Join": ["", [{Ref: 'MainAccessLogBucket'},"/Export/"]]}, - }, + LogFilePrefix: { 'Fn::Join': ['', [{ Ref: 'MainAccessLogBucket' }, '/Export/']] }, + }, PublicAccessBlockConfiguration: { BlockPublicAcls: true, BlockPublicPolicy: true, @@ -247,7 +247,7 @@ module.exports = { ImportBucket: { Type: 'AWS::S3::Bucket', Metadata: { guard: util.cfnGuard('S3_BUCKET_NO_PUBLIC_RW_ACL') }, - DependsOn : ['MainAccessLogBucket', 'MainAccessLogsBucketPolicy'], + DependsOn: ['MainAccessLogBucket', 'MainAccessLogsBucketPolicy'], Properties: { LifecycleConfiguration: { Rules: [{ @@ -274,8 +274,8 @@ module.exports = { }, LoggingConfiguration: { DestinationBucketName: { Ref: 'MainAccessLogBucket' }, - LogFilePrefix: {"Fn::Join": ["", [{Ref: 'MainAccessLogBucket'},"/Import/"]]}, - }, + LogFilePrefix: { 'Fn::Join': ['', [{ Ref: 'MainAccessLogBucket' }, '/Import/']] }, + }, PublicAccessBlockConfiguration: { BlockPublicAcls: true, BlockPublicPolicy: true, @@ -340,7 +340,7 @@ module.exports = { TestAllBucket: { Type: 'AWS::S3::Bucket', Metadata: { guard: util.cfnGuard('S3_BUCKET_NO_PUBLIC_RW_ACL') }, - DependsOn : ['MainAccessLogBucket', 'MainAccessLogsBucketPolicy'], + DependsOn: ['MainAccessLogBucket', 'MainAccessLogsBucketPolicy'], Properties: { LifecycleConfiguration: { Rules: [{ @@ -367,8 +367,8 @@ module.exports = { }, LoggingConfiguration: { DestinationBucketName: { Ref: 'MainAccessLogBucket' }, - LogFilePrefix: {"Fn::Join": ["", [{Ref: 'MainAccessLogBucket'},"/TestAll/"]]}, - }, + LogFilePrefix: { 'Fn::Join': ['', [{ Ref: 'MainAccessLogBucket' }, '/TestAll/']] }, + }, PublicAccessBlockConfiguration: { BlockPublicAcls: true, BlockPublicPolicy: true, @@ -430,4 +430,112 @@ module.exports = { }, }, }, + ContentDesignerOutputBucket: { + Type: 'AWS::S3::Bucket', + Metadata: { guard: util.cfnGuard('S3_BUCKET_NO_PUBLIC_RW_ACL') }, + DependsOn: ['MainAccessLogBucket', 'MainAccessLogsBucketPolicy'], + Properties: { + LifecycleConfiguration: { + Rules: [{ + ExpirationInDays: 1, + Status: 'Enabled', + }], + }, + VersioningConfiguration: { + Status: 'Enabled', + }, + CorsConfiguration: { + CorsRules: [{ + AllowedHeaders: ['*'], + AllowedMethods: ['GET'], + AllowedOrigins: ['*'], + }], + }, + BucketEncryption: { + ServerSideEncryptionConfiguration: [{ + ServerSideEncryptionByDefault: { + SSEAlgorithm: 'AES256', + }, + }], + }, + LoggingConfiguration: { + DestinationBucketName: { Ref: 'MainAccessLogBucket' }, + LogFilePrefix: { 'Fn::Join': ['', [{ Ref: 'MainAccessLogBucket' }, '/ContentDesignerOutput/']] }, + }, + PublicAccessBlockConfiguration: { + BlockPublicAcls: true, + BlockPublicPolicy: true, + IgnorePublicAcls: true, + RestrictPublicBuckets: true, + }, + }, + }, + HTTPSOnlyContentDesignerOutputBucketPolicy: { + Type: 'AWS::S3::BucketPolicy', + Properties: { + Bucket: { + Ref: 'ContentDesignerOutputBucket', + }, + PolicyDocument: { + Statement: [ + { + Action: '*', + Condition: { + Bool: { + 'aws:SecureTransport': 'false', + }, + }, + Effect: 'Deny', + Principal: '*', + Resource: [ + { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'ContentDesignerOutputBucket', + 'Arn', + ], + }, + '/*', + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'ContentDesignerOutputBucket', + 'Arn', + ], + }, + ], + ], + }, + ], + Sid: 'HttpsOnly', + }, + ], + Version: '2012-10-17', + }, + }, + }, + ContentDesignerOutputClean: { + Type: 'Custom::S3Clean', + DependsOn: [ + 'CFNInvokePolicy', + ], + Properties: { + ServiceToken: { + 'Fn::GetAtt': [ + 'S3Clean', + 'Arn', + ], + }, + Bucket: { Ref: 'ContentDesignerOutputBucket' }, + }, + }, }; diff --git a/source/templates/master/cfn/index.js b/source/templates/master/cfn/index.js index 1ad8bfce3..bfd58c1be 100644 --- a/source/templates/master/cfn/index.js +++ b/source/templates/master/cfn/index.js @@ -16,6 +16,30 @@ const fs = require('fs'); const util = require('../../util'); module.exports = { + VersionLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-VersionLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, VersionLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -25,10 +49,13 @@ module.exports = { }, Environment: { Variables: { - ...util.getCommonEnvironmentVariables() + ...util.getCommonEnvironmentVariables(), }, }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'VersionLambdaLogGroup' }, + }, MemorySize: '3008', Role: { 'Fn::GetAtt': ['CFNLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -62,6 +89,30 @@ module.exports = { BuildDate: (new Date()).toISOString(), }, }, + CFNLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-CFNLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, CFNLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -77,10 +128,13 @@ module.exports = { }, Environment: { Variables: { - ...util.getCommonEnvironmentVariables() + ...util.getCommonEnvironmentVariables(), } }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'CFNLambdaLogGroup' }, + }, MemorySize: '3008', Role: { 'Fn::GetAtt': ['CFNLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, diff --git a/source/templates/master/examples.js b/source/templates/master/examples.js index 1dd09e02d..bd2dd5a7a 100644 --- a/source/templates/master/examples.js +++ b/source/templates/master/examples.js @@ -35,12 +35,12 @@ module.exports = { QIDLambdaArn: { 'Fn::GetAtt': ['ESQidLambda', 'Arn'] }, VPCSubnetIdList: { 'Fn::Join': [',', { Ref: 'VPCSubnetIdList' }] }, VPCSecurityGroupIdList: { 'Fn::Join': [',', { Ref: 'VPCSecurityGroupIdList' }] }, - LexBotVersion: { Ref: 'LexBotVersion' }, XraySetting: { Ref: 'XraySetting' }, DefaultQnABotSettings: { Ref: 'DefaultQnABotSettings' }, PrivateQnABotSettings: { Ref: 'PrivateQnABotSettings' }, InstallLexResponseBots: { Ref: 'InstallLexResponseBots' }, AwsSdkLayerLambdaLayer: { Ref: 'AwsSdkLayerLambdaLayer' }, + LogRetentionPeriod: { Ref: 'LogRetentionPeriod' }, }, }, }, diff --git a/source/templates/master/exportstack.js b/source/templates/master/exportstack.js index 29c1e6d9b..cbdedcf88 100644 --- a/source/templates/master/exportstack.js +++ b/source/templates/master/exportstack.js @@ -17,6 +17,7 @@ module.exports = { Properties: { TemplateURL: { 'Fn::Sub': 'https://${BootstrapBucket}.s3.${AWS::Region}.amazonaws.com/${BootstrapPrefix}/templates/export.json' }, Parameters: { + ContentDesignerOutputBucket: { Ref: 'ContentDesignerOutputBucket' }, CFNLambda: { 'Fn::GetAtt': ['CFNLambda', 'Arn'] }, CFNInvokePolicy: { Ref: 'CFNInvokePolicy' }, S3Clean: { 'Fn::GetAtt': ['S3Clean', 'Arn'] }, @@ -39,11 +40,7 @@ module.exports = { CustomQnABotSettings: { Ref: 'CustomQnABotSettings' }, AwsSdkLayerLambdaLayer: { Ref: 'AwsSdkLayerLambdaLayer' }, QnABotCommonLambdaLayer: { Ref: 'QnABotCommonLambdaLayer' }, - LexVersion: { 'Fn::If': ['CreateLexV1Bots', 'V1', 'V2'] }, - // Lex V1 - FallbackIntent: { 'Fn::If': ['CreateLexV1Bots', { Ref: 'IntentFallback' }, 'LexV2Only_Mode'] }, - Intent: { 'Fn::If': ['CreateLexV1Bots', { Ref: 'Intent' }, 'LexV2Only_Mode'] }, - BotName: { 'Fn::If': ['CreateLexV1Bots', { Ref: 'LexBot' }, 'LexV2Only_Mode'] }, + LexVersion: 'V2', // Lex V2 LexV2BotName: { 'Fn::GetAtt': ['LexV2Bot', 'botName'] }, LexV2BotId: { 'Fn::GetAtt': ['LexV2Bot', 'botId'] }, @@ -52,6 +49,7 @@ module.exports = { LexV2BotLocaleIds: { 'Fn::GetAtt': ['LexV2Bot', 'botLocaleIds'] }, KendraFaqIndexId: { Ref: 'KendraFaqIndexId' }, KendraWebPageIndexId: { Ref: 'KendraWebPageIndexId' }, + LogRetentionPeriod: { Ref: 'LogRetentionPeriod' }, }, }, }, diff --git a/source/templates/master/importstack.js b/source/templates/master/importstack.js index 46590c4c9..f099692f0 100644 --- a/source/templates/master/importstack.js +++ b/source/templates/master/importstack.js @@ -18,6 +18,7 @@ module.exports = { Properties: { TemplateURL: { 'Fn::Sub': 'https://${BootstrapBucket}.s3.${AWS::Region}.amazonaws.com/${BootstrapPrefix}/templates/import.json' }, Parameters: { + ContentDesignerOutputBucket: { Ref: 'ContentDesignerOutputBucket' }, CFNLambda: { 'Fn::GetAtt': ['CFNLambda', 'Arn'] }, CFNInvokePolicy: { Ref: 'CFNInvokePolicy' }, S3Clean: { 'Fn::GetAtt': ['S3Clean', 'Arn'] }, @@ -59,6 +60,7 @@ module.exports = { ], }, EmbeddingsBedrockModelId: { 'Fn::FindInMap': ['BedrockDefaults', {'Ref' : 'EmbeddingsBedrockModelId'}, 'ModelID'] }, + LogRetentionPeriod: { Ref: 'LogRetentionPeriod' }, }, }, }, diff --git a/source/templates/master/index.js b/source/templates/master/index.js index f06fe77e6..d5c6109b5 100644 --- a/source/templates/master/index.js +++ b/source/templates/master/index.js @@ -70,41 +70,6 @@ module.exports = { ImportBucket: { Value: { Ref: 'ImportBucket' }, }, - BotConsoleUrl: { - Condition: 'CreateLexV1Bots', - Value: { - 'Fn::Join': [ - '', - [ - 'https://console.aws.amazon.com/lex/home?', - 'region=', - { Ref: 'AWS::Region' }, - '#bot-editor:bot=', - { Ref: 'LexBot' }, - ], - ], - }, - }, - LexV1BotName: { - Condition: 'CreateLexV1Bots', - Value: { Ref: 'LexBot' }, - }, - LexV1BotAlias: { - Condition: 'CreateLexV1Bots', - Value: { Ref: 'VersionAlias' }, - }, - LexV1SlotType: { - Condition: 'CreateLexV1Bots', - Value: { Ref: 'SlotType' }, - }, - LexV1Intent: { - Condition: 'CreateLexV1Bots', - Value: { Ref: 'Intent' }, - }, - LexV1IntentFallback: { - Condition: 'CreateLexV1Bots', - Value: { Ref: 'IntentFallback' }, - }, LexV2BotName: { Value: { 'Fn::GetAtt': ['LexV2Bot', 'botName'] }, }, @@ -231,6 +196,12 @@ module.exports = { MetricsBucket: { Value: { Ref: 'MetricsBucket' }, }, + TestAllBucket: { + Value: { Ref: 'TestAllBucket' }, + }, + ContentDesignerOutputBucket: { + Value: { Ref: 'ContentDesignerOutputBucket' }, + } }, Parameters: { OpenSearchName: { @@ -388,13 +359,6 @@ module.exports = { AllowedPattern: '[^ ]+', ConstraintDescription: 'Must be a valid comma separated list of Locale IDs', }, - LexBotVersion: { - Description: - 'Amazon Lex version to use for QnABot on AWS. Select \'LexV2 Only\' to install QnABot in AWS regions where LexV1 is not supported.', - Type: 'String', - AllowedValues: ['LexV1 and LexV2', 'LexV2 Only'], - Default: 'LexV2 Only', - }, InstallLexResponseBots: { Description: 'You can configure your chatbot to ask questions and process your end user\'s answers for surveys, quizzes,... (Elicit Response Feature). If the Elicit Response feature is not needed, choose \'false\' to skip the sample Lex Response Bot installation - see https://docs.aws.amazon.com/solutions/latest/qnabot-on-aws/configuring-the-chatbot-to-ask-the-questions-and-use-response-bots.html', @@ -429,6 +393,7 @@ module.exports = { 'Required when EmbeddingsApi is BEDROCK. Please ensure you have requested access to the LLMs in Bedrock console (https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html), before deploying.', AllowedValues: [ 'amazon.titan-embed-text-v1', + 'amazon.titan-embed-text-v2', 'cohere.embed-english-v3', 'cohere.embed-multilingual-v3', ], @@ -470,6 +435,7 @@ module.exports = { AllowedValues: [ 'amazon.titan-text-express-v1', 'amazon.titan-text-lite-v1', + 'amazon.titan-text-premier-v1', 'ai21.j2-ultra-v1', 'ai21.j2-mid-v1', 'anthropic.claude-instant-v1', @@ -494,10 +460,11 @@ module.exports = { Description: 'Required if BedrockKnowledgeBaseId is not empty. Sets the preferred LLM model to use with the Bedrock knowledge base. Please ensure you have requested access to the LLMs in Bedrock console (https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html), before deploying', AllowedValues: [ + 'amazon.titan-text-premier-v1', 'anthropic.claude-instant-v1', 'anthropic.claude-v2.1', 'anthropic.claude-3-sonnet-v1', - 'anthropic.claude-3-haiku-v1' + 'anthropic.claude-3-haiku-v1', ], Default: 'anthropic.claude-instant-v1', }, @@ -524,6 +491,15 @@ module.exports = { Default: '', ConstraintDescription: 'Must be a valid Lambda ARN or leave blank', }, + LogRetentionPeriod: { + Type: 'Number', + Description: 'Optional: The number of days to keep logs before expiring. If you would like your logs to never expire, leave this value as 0.', + Default: 0, + AllowedValues: [ + 0, 1, 3, 5, 7, 14 , 30 , 60 , 90 , 120 , 150 , 180 , 365 , 400 , 545 , 731 , 1096 , 1827 , 2192 , 2557 , 2922 , 3288 , 3653 + ], + MinValue: 0, + }, }, Conditions: { Public: { 'Fn::Equals': [{ Ref: 'PublicOrPrivate' }, 'PUBLIC'] }, @@ -534,7 +510,6 @@ module.exports = { BuildExamples: { 'Fn::Equals': [{ Ref: 'BuildExamples' }, 'TRUE'] }, CreateDomain: { 'Fn::Equals': [{ Ref: 'OpenSearchName' }, 'EMPTY'] }, DontCreateDomain: { 'Fn::Not': [{ 'Fn::Equals': [{ Ref: 'OpenSearchName' }, 'EMPTY'] }] }, - CreateLexV1Bots: { 'Fn::Equals': [{ Ref: 'LexBotVersion' }, 'LexV1 and LexV2'] }, VPCEnabled: { 'Fn::Not': [ { @@ -566,6 +541,7 @@ module.exports = { { 'Fn::Not': [{ 'Fn::Equals': [{ Ref: 'AltSearchKendraIndexes' }, ''] }] }, ], }, + LogRetentionPeriodIsNotZero: { 'Fn::Not': [{ 'Fn::Equals': [{ Ref: 'LogRetentionPeriod' }, 0] }] } }, Rules: { RequireLambdaArnForLambdaEmbeddingsApi: { @@ -584,8 +560,7 @@ module.exports = { }, Metadata: { 'AWS::CloudFormation::Interface': { - ParameterGroups: [ - { + ParameterGroups: [ { Label: { default: 'Step 2A: Set Basic Chatbot Parameters (required)', }, @@ -601,7 +576,6 @@ module.exports = { 'OpenSearchDashboardsRetentionMinutes', 'OpenSearchFineGrainAccessControl', 'LexV2BotLocaleIds', - 'LexBotVersion', 'InstallLexResponseBots', 'FulfillmentConcurrency', 'XraySetting', @@ -663,6 +637,7 @@ module.exports = { 'BootstrapBucket', 'BootstrapPrefix', 'BuildExamples', + 'LogRetentionPeriod' ], }, ], diff --git a/source/templates/master/lex-build/__tests__/start.test.js b/source/templates/master/lex-build/__tests__/start.test.js index 0b728741c..65e95be69 100644 --- a/source/templates/master/lex-build/__tests__/start.test.js +++ b/source/templates/master/lex-build/__tests__/start.test.js @@ -34,9 +34,8 @@ describe('lex poll', () => { process.env = { ...OLD_ENV }; }); - it('initializes lex v1 and v2 and updates s3', async () => { + it('initializes lex v2 and updates s3', async () => { process.env.STATUS_BUCKET = 'test-bucket'; - process.env.STATUS_KEY = 'test-key'; process.env.LEXV2_STATUS_KEY = 'test-status-key'; process.env.BUILD_FUNCTION = 'test-lambda'; @@ -50,14 +49,6 @@ describe('lex poll', () => { await handler({}, {}, mockCallback); expect(s3ClientMock).toHaveReceivedNthCommandWith(1, PutObjectCommand, { - Bucket: 'test-bucket', - Key: process.env.STATUS_KEY, - Body: JSON.stringify({ - status: 'Starting', - token: '', - }), - }); - expect(s3ClientMock).toHaveReceivedNthCommandWith(2, PutObjectCommand, { Bucket: 'test-bucket', Key: process.env.LEXV2_STATUS_KEY, Body: JSON.stringify({ diff --git a/source/templates/master/lex-build/index.js b/source/templates/master/lex-build/index.js index 901e7671c..8ffeb7297 100644 --- a/source/templates/master/lex-build/index.js +++ b/source/templates/master/lex-build/index.js @@ -15,6 +15,30 @@ const fs = require('fs'); const util = require('../../util'); module.exports = { + LexBuildLambdaLogGroup:{ + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-LexBuildLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, LexBuildLambda: lambda({ S3Bucket: { Ref: 'BootstrapBucket' }, S3Key: { 'Fn::Sub': '${BootstrapPrefix}/lambda/lex-build.zip' }, @@ -24,35 +48,84 @@ module.exports = { UTTERANCE_KEY: 'default-utterances.json', POLL_LAMBDA: { 'Fn::GetAtt': ['LexBuildLambdaPoll', 'Arn'] }, STATUS_BUCKET: { Ref: 'BuildStatusBucket' }, - STATUS_KEY: { 'Fn::If': ['CreateLexV1Bots', 'status.json', { Ref: 'AWS::NoValue' }] }, LEXV2_STATUS_KEY: 'lexV2status.json', - BOTNAME: { 'Fn::If': ['CreateLexV1Bots', { Ref: 'LexBot' }, { Ref: 'AWS::NoValue' }] }, - BOTALIAS: { 'Fn::If': ['CreateLexV1Bots', { Ref: 'VersionAlias' }, { Ref: 'AWS::NoValue' }] }, - SLOTTYPE: { 'Fn::If': ['CreateLexV1Bots', { Ref: 'SlotType' }, { Ref: 'AWS::NoValue' }] }, - INTENT: { 'Fn::If': ['CreateLexV1Bots', { Ref: 'Intent' }, { Ref: 'AWS::NoValue' }] }, - INTENTFALLBACK: { 'Fn::If': ['CreateLexV1Bots', { Ref: 'IntentFallback' }, { Ref: 'AWS::NoValue' }] }, LEXV2_BUILD_LAMBDA: { Ref: 'Lexv2BotLambda' }, ADDRESS: { 'Fn::Join': ['', ['https://', { 'Fn::GetAtt': ['ESVar', 'ESAddress'] }]] }, INDEX: { 'Fn::GetAtt': ['Var', 'index'] }, - ...util.getCommonEnvironmentVariables() - }, process.env.npm_package_config_lambdaRuntime), + ...util.getCommonEnvironmentVariables(), + }, process.env.npm_package_config_lambdaRuntime, + { + LogGroup: { Ref: 'LexBuildLambdaLogGroup' }, + }, + ), + LexBuildLambdaStartLogGroup:{ + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-LexBuildLambdaStart' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, LexBuildLambdaStart: lambda({ ZipFile: fs.readFileSync(`${__dirname}/start.js`, 'utf8'), }, { STATUS_BUCKET: { Ref: 'BuildStatusBucket' }, - STATUS_KEY: { 'Fn::If': ['CreateLexV1Bots', 'status.json', { Ref: 'AWS::NoValue' }] }, LEXV2_STATUS_KEY: 'lexV2status.json', BUILD_FUNCTION: { 'Fn::GetAtt': ['LexBuildLambda', 'Arn'] }, - ...util.getCommonEnvironmentVariables() - }, process.env.npm_package_config_lambdaRuntime), + ...util.getCommonEnvironmentVariables(), + }, process.env.npm_package_config_lambdaRuntime, + { + LogGroup: { Ref: 'LexBuildLambdaStartLogGroup' }, + }), + LexBuildLambdaPollLogGroup:{ + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-LexBuildLambdaPoll' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, LexBuildLambdaPoll: lambda({ ZipFile: fs.readFileSync(`${__dirname}/poll.js`, 'utf8'), }, { - STATUS_KEY: { 'Fn::If': ['CreateLexV1Bots', 'status.json', { Ref: 'AWS::NoValue' }] }, STATUS_BUCKET: { Ref: 'BuildStatusBucket' }, - BOT_NAME: { 'Fn::If': ['CreateLexV1Bots', { Ref: 'LexBot' }, { Ref: 'AWS::NoValue' }] }, - ...util.getCommonEnvironmentVariables() - }, process.env.npm_package_config_lambdaRuntime), + ...util.getCommonEnvironmentVariables(), + }, process.env.npm_package_config_lambdaRuntime, + { + LogGroup: { Ref: 'LexBuildLambdaPollLogGroup' }, + }), LexBuildCodeVersion: { Type: 'Custom::S3Version', Properties: { @@ -160,7 +233,7 @@ module.exports = { LoggingConfiguration: { DestinationBucketName: { Ref: 'MainAccessLogBucket' }, LogFilePrefix: {"Fn::Join": ["", [{Ref: 'MainAccessLogBucket'},"/BuildStatus/"]]}, - }, + }, BucketEncryption: { ServerSideEncryptionConfiguration: [{ ServerSideEncryptionByDefault: { @@ -201,7 +274,7 @@ module.exports = { '/*', ], ], - }, + }, { 'Fn::Join': [ '', @@ -214,7 +287,7 @@ module.exports = { }, ], ], - } + }, ], Sid: 'HttpsOnly', }, @@ -236,7 +309,7 @@ module.exports = { }, }; -function lambda(code, variable, runtime) { +function lambda(code, variable, runtime, loggingConfig) { return { Type: 'AWS::Lambda::Function', Properties: { @@ -245,6 +318,7 @@ function lambda(code, variable, runtime) { Variables: variable, }, Handler: 'index.handler', + LoggingConfig: loggingConfig, MemorySize: '1024', Role: { 'Fn::GetAtt': ['LexBuildLambdaRole', 'Arn'] }, Runtime: runtime, @@ -261,7 +335,7 @@ function lambda(code, variable, runtime) { }, Layers: [ { Ref: 'AwsSdkLayerLambdaLayer' }, - { Ref: 'CommonModulesLambdaLayer' } + { Ref: 'CommonModulesLambdaLayer' }, ], Tags: [{ Key: 'Type', diff --git a/source/templates/master/lex-build/start.js b/source/templates/master/lex-build/start.js index ef397f656..f038c5850 100644 --- a/source/templates/master/lex-build/start.js +++ b/source/templates/master/lex-build/start.js @@ -23,22 +23,10 @@ const crypto = require('crypto'); exports.handler = async function (event, context, callback) { const token = crypto.randomBytes(16).toString('base64'); const bucket = process.env.STATUS_BUCKET; - const lexV1StatusFile = process.env.STATUS_KEY; const lexV2StatusFile = process.env.LEXV2_STATUS_KEY; const functionName = process.env.BUILD_FUNCTION; const body = JSON.stringify({ status: 'Starting', token }); - if (lexV1StatusFile) { - console.log('Initializing ', bucket, lexV1StatusFile); - const params = { - Bucket: bucket, - Key: lexV1StatusFile, - Body: body, - }; - const putObjectCmdV1 = new PutObjectCommand(params); - await s3.send(putObjectCmdV1); - } - console.log('Initializing ', bucket, lexV2StatusFile); const params = { Bucket: bucket, @@ -48,7 +36,7 @@ exports.handler = async function (event, context, callback) { const putObjectCmdV2 = new PutObjectCommand(params); await s3.send(putObjectCmdV2); - // The BUILD_FUNCTION takes care of rebuilding Lex V2 bot, and (unless QnABot is set to V2 only) Lex V1 bot + // The BUILD_FUNCTION takes care of rebuilding Lex V2 bot console.log('Invoking ', functionName); const invokeParams = { FunctionName: functionName, diff --git a/source/templates/master/lex/bot.js b/source/templates/master/lex/bot.js index d7d1d9e39..ac5a38cdb 100644 --- a/source/templates/master/lex/bot.js +++ b/source/templates/master/lex/bot.js @@ -32,126 +32,6 @@ module.exports = { SourceAccount: { Ref: 'AWS::AccountId' }, }, }, - SlotType: { - Type: 'Custom::LexSlotType', - Condition: 'CreateLexV1Bots', - Properties: { - ServiceToken: { 'Fn::GetAtt': ['CFNLambda', 'Arn'] }, - createVersion: true, - description: `custom slot type ${qnabotversion}`, - enumerationValues: config.utterances.map((x) => ({ value: x })), - }, - }, - Intent: { - Type: 'Custom::LexIntent', - Condition: 'CreateLexV1Bots', - Properties: { - ServiceToken: { - 'Fn::GetAtt': ['CFNLambda', 'Arn'], - }, - prefix: 'fulfilment', - description: `custom intent ${qnabotversion}`, - createVersion: true, - sampleUtterances: [ - '{slot}', - ], - slots: [{ - name: 'slot', - slotType: { Ref: 'SlotType' }, - slotConstraint: 'Optional', - slotTypeVersion: 'QNABOT-AUTO-ASSIGNED', - priority: 1, - }, - ], - fulfillmentActivity: { - type: 'CodeHook', - codeHook: { - uri: { - 'Fn::Join': [':', [ - { 'Fn::GetAtt': ['FulfillmentLambda', 'Arn'] }, - 'live', - ]], - }, - messageVersion: '1.0', - }, - }, - }, - DependsOn: 'QNAInvokePermission', - }, - IntentFallback: { - Type: 'Custom::LexIntent', - Condition: 'CreateLexV1Bots', - Properties: { - ServiceToken: { - 'Fn::GetAtt': ['CFNLambda', 'Arn'], - }, - prefix: 'qnabotfallbackfulfilment', - description: `custom fallback intent ${qnabotversion}`, - createVersion: true, - fulfillmentActivity: { - type: 'CodeHook', - codeHook: { - uri: { - 'Fn::Join': [':', [ - { 'Fn::GetAtt': ['FulfillmentLambda', 'Arn'] }, - 'live', - ]], - }, - messageVersion: '1.0', - }, - }, - parentIntentSignature: 'AMAZON.FallbackIntent', - }, - DependsOn: 'QNAInvokePermission', - }, - LexBot: { - Type: 'Custom::LexBot', - Condition: 'CreateLexV1Bots', - Properties: { - ServiceToken: { - 'Fn::GetAtt': [ - 'CFNLambda', - 'Arn', - ], - }, - name: { 'Fn::Sub': '${AWS::StackName}-Bot' }, - description: `QnABot primary bot ${qnabotversion}`, - locale: 'en-US', - voiceId: config.voiceId, - childDirected: false, - createVersion: true, - intents: [ - { intentName: { Ref: 'Intent' } }, - { intentName: { Ref: 'IntentFallback' } }, - ], - abortStatement: { - messages: [ - { - content: config.Abort, - contentType: 'PlainText', - }, - ], - }, - }, - }, - VersionAlias: { - Type: 'Custom::LexAlias', - Condition: 'CreateLexV1Bots', - DependsOn: 'LexBot', - Properties: { - ServiceToken: { - 'Fn::GetAtt': [ - 'CFNLambda', - 'Arn', - ], - }, - botName: { - Ref: 'LexBot', - }, - name: 'live', - description: `QnABot live alias ${qnabotversion}`, - }, - }, LexV2Bot: { Type: 'Custom::LexV2Bot', Properties: { diff --git a/source/templates/master/lex/fulfillment.js b/source/templates/master/lex/fulfillment.js index 1b7878192..c1da1f7d5 100644 --- a/source/templates/master/lex/fulfillment.js +++ b/source/templates/master/lex/fulfillment.js @@ -34,7 +34,7 @@ module.exports = { ]], }, Principal: 'alexa-appkit.amazon.com', - SourceAccount: { Ref: 'AWS::AccountId' }, + SourceAccount: { Ref: 'AWS::AccountId' }, }, }, FulfillmentCodeVersion: { @@ -46,6 +46,30 @@ module.exports = { BuildDate: (new Date()).toISOString(), }, }, + FulfillmentLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-FulfillmentLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, FulfillmentLambda: { Type: 'AWS::Lambda::Function', DependsOn: 'FulfillmentCodeVersion', @@ -93,10 +117,13 @@ module.exports = { LLM_LAMBDA_ARN: { Ref: 'LLMLambdaArn' }, ...examples, ...responsebots, - ...util.getCommonEnvironmentVariables() + ...util.getCommonEnvironmentVariables(), }, }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'FulfillmentLambdaLogGroup' }, + }, Layers: [ { Ref: 'AwsSdkLayerLambdaLayer' }, { Ref: 'CommonModulesLambdaLayer' }, @@ -234,7 +261,6 @@ module.exports = { Statement: [{ Effect: 'Allow', Action: [ - 'lex:PostText', 'lex:RecognizeText', ], Resource: [ @@ -405,10 +431,18 @@ module.exports = { 'bedrock:InvokeModel', ], Resource: [ - { 'Fn::If': ['EmbeddingsBedrock', { 'Fn::Sub': 'arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/${EmbeddingsBedrockModelId}' }, { Ref: 'AWS::NoValue' }] }, - { 'Fn::If': ['LLMBedrock', { 'Fn::Sub': ['arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/${ModelId}', {'ModelId': { 'Fn::FindInMap': ['BedrockDefaults', {'Ref' : 'LLMBedrockModelId'}, 'ModelID'] }}] }, { Ref: 'AWS::NoValue' }] }, - { 'Fn::If': ['BedrockKnowledgeBaseEnable', { 'Fn::Sub': ['arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/${ModelId}', {'ModelId': { 'Fn::FindInMap': ['BedrockDefaults', {'Ref' : 'BedrockKnowledgeBaseModel'}, 'ModelID'] }}] }, { Ref: 'AWS::NoValue' }] }, + { 'Fn::If': ['EmbeddingsBedrock', { 'Fn::Sub': ['arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/${ModelId}', {ModelId: { 'Fn::FindInMap': ['BedrockDefaults', {Ref : 'EmbeddingsBedrockModelId'}, 'ModelID'] }}] }, { Ref: 'AWS::NoValue' }] }, + { 'Fn::If': ['LLMBedrock', { 'Fn::Sub': ['arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/${ModelId}', {ModelId: { 'Fn::FindInMap': ['BedrockDefaults', {Ref : 'LLMBedrockModelId'}, 'ModelID'] }}] }, { Ref: 'AWS::NoValue' }] }, + { 'Fn::If': ['BedrockKnowledgeBaseEnable', { 'Fn::Sub': ['arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/${ModelId}', {ModelId: { 'Fn::FindInMap': ['BedrockDefaults', {Ref : 'BedrockKnowledgeBaseModel'}, 'ModelID'] }}] }, { Ref: 'AWS::NoValue' }] }, + ], + }, + { + Sid: 'ApplyGuardrailsToLLMBedrock', // https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-permissions.html#guardrails-permissions-invoke + Effect: 'Allow', + Action: [ + 'bedrock:ApplyGuardrail', ], + Resource: [{ 'Fn::Sub': 'arn:${AWS::Partition}:bedrock:${AWS::Region}:${AWS::AccountId}:guardrail/*' }], }, ], }, @@ -432,6 +466,14 @@ module.exports = { ], Resource: { 'Fn::Sub': 'arn:${AWS::Partition}:bedrock:${AWS::Region}:${AWS::AccountId}:knowledge-base/${BedrockKnowledgeBaseId}' }, }, + { + Sid: 'ApplyGuardrailsToKnowledgeBase', // https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-permissions.html#guardrails-permissions-invoke + Effect: 'Allow', + Action: [ + 'bedrock:ApplyGuardrail', + ], + Resource: [{ 'Fn::Sub': 'arn:${AWS::Partition}:bedrock:${AWS::Region}:${AWS::AccountId}:guardrail/*' }], + }, ], }, }, @@ -472,6 +514,30 @@ module.exports = { BuildDate: (new Date()).toISOString(), }, }, + ESWarmerLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ESWarmerLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ESWarmerLambda: { DependsOn: ['ESWarmerCodeVersion'], Type: 'AWS::Lambda::Function', @@ -490,10 +556,13 @@ module.exports = { DEFAULT_SETTINGS_PARAM: { Ref: 'DefaultQnABotSettings' }, PRIVATE_SETTINGS_PARAM: { Ref: 'PrivateQnABotSettings' }, CUSTOM_SETTINGS_PARAM: { Ref: 'CustomQnABotSettings' }, - ...util.getCommonEnvironmentVariables() + ...util.getCommonEnvironmentVariables(), }, }, Handler: 'index.warmer', + LoggingConfig: { + LogGroup: { Ref: 'ESWarmerLambdaLogGroup' }, + }, MemorySize: '512', Role: { 'Fn::GetAtt': ['WarmerLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, diff --git a/source/templates/master/lexv2-build/index.js b/source/templates/master/lexv2-build/index.js index cbc3c75da..cedfb9ae7 100644 --- a/source/templates/master/lexv2-build/index.js +++ b/source/templates/master/lexv2-build/index.js @@ -14,6 +14,30 @@ const util = require('../../util'); module.exports = { + LexV2BotLambdaLogGroup:{ + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-LexV2BotLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, Lexv2BotLambda: lambda({ S3Bucket: { Ref: 'BootstrapBucket' }, S3Key: { 'Fn::Sub': '${BootstrapPrefix}/lambda/lexv2-build.zip' }, @@ -28,8 +52,11 @@ module.exports = { }, LOCALES: { Ref: 'LexV2BotLocaleIds' }, PYTHONPATH: '/var/task/py_modules:/var/runtime:/opt/python', - ...util.getCommonEnvironmentVariables() - }, process.env.npm_package_config_pythonRuntime), + ...util.getCommonEnvironmentVariables(), + }, process.env.npm_package_config_pythonRuntime, + { + LogGroup: { Ref: 'LexV2BotLambdaLogGroup' }, + }), Lexv2BotCodeVersion: { Type: 'Custom::S3Version', Properties: { @@ -142,7 +169,7 @@ module.exports = { }, }; -function lambda(code, variable, runtime) { +function lambda(code, variable, runtime, loggingConfig) { return { Type: 'AWS::Lambda::Function', Properties: { @@ -151,6 +178,7 @@ function lambda(code, variable, runtime) { Variables: variable, }, Handler: 'handler.handler', + LoggingConfig: loggingConfig, MemorySize: '1024', Role: { 'Fn::GetAtt': ['Lexv2BotLambdaRole', 'Arn'] }, Runtime: runtime, diff --git a/source/templates/master/mappings/bedrock-defaults.js b/source/templates/master/mappings/bedrock-defaults.js index 693aadbc1..836988ea7 100644 --- a/source/templates/master/mappings/bedrock-defaults.js +++ b/source/templates/master/mappings/bedrock-defaults.js @@ -15,7 +15,9 @@ const amazonQueryPromptTemplate = 'Given the following conversation and a follow const amazonQAPromptTemplate = '

    Human: You are a friendly AI assistant. Answer the question in tags only based on the provided reference passages. Here are reference passages in tags:

    {context}

    If the references contain the information needed to respond, then write a confident response in under 50 words, quoting the relevant references.
    Otherwise, if you can make an informed guess based on the reference passages, then write a less confident response in under 50 words, stating your assumptions.
    Finally, if the references do not have any relevant information, then respond saying \\"Sorry, I don\'t know\\".

    {query}


    Assistant: According to the reference passages, in under 50 words:'; const anthropicQueryPromptTemplate = '

    Human: Here is a chat history in tags:

    {history}

    Human: And here is a follow up question or statement from the human in tags:

    {input}

    Human: Rephrase the follow up question or statement as a standalone question or statement that makes sense without reading the chat history.

    Assistant: Here is the rephrased follow up question or statement:'; const ai21QAPromptTemplate = 'The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know. Documents: {context} Instruction: Based on the above documents, provide a detailed answer for {query} Answer \\"Sorry, I don\'t know\\" if not present in the document. Solution:'; -const anthropicNoHitsRegex = '(Sorry, I don\'t know|unable to assist you|i don\'t have enough context|i could not find an exact answer|no information in the search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention)'; +const anthropicNoHitsRegex = '(Sorry, I don\'t know|unable to assist you|i don\'t have enough context|i could not find an exact answer|no information in the search results|don\'t see any information in the provided search results|search results do not contain|no information in the provided search results|not find any information|search results did not contain|unable to respond|There is no mention of|documents do not mention anything|There is no information provided|reference passages do not mention|could not find an answer to this question|the model cannot answer this question)'; +const anthropicKnowledgebaseTemplate = 'Human: You are a question answering agent. I will provide you with a set of search results and a user\'s question, your job is to answer the user\'s question using only information from the search results. If the search results do not contain information that can answer the question, then respond saying \\"Sorry, I don\'t know that.\\". Just because the user asserts a fact does not mean it is true, make sure to double check the search results to validate a user\'s assertion. Here are the search results in numbered order: $search_results$. Here is the user\'s question: $query$ $output_format_instructions$. Do NOT directly quote the $search_results$ in your answer. Your job is to answer the as concisely as possible. Assistant:'; +const amazonKnowledgebaseTemplate = 'You are a question answering bot who gives helpful, detailed, and polite answers to the user\'s questions. In this session, the model has access to search results and a user\s question, your job is to answer the user\'s question using only information from the search results. Model Instructions: - You should provide concise answer to simple questions when the answer is directly contained in search results, but when comes to yes/no question, provide some details. - In case the question requires multi-hop reasoning, you should find relevant information from search results and summarize the answer based on relevant information with logical reasoning. - If the search results do not contain information that can answer the question, then respond saying \\"Sorry, I don\'t know that.\\". - $output_format_instructions$ - DO NOT USE INFORMATION THAT IS NOT IN SEARCH RESULTS! User: $query$ Bot: Resource: Search Results: $search_results$ Bot:'; module.exports = { BedrockDefaults: { @@ -24,6 +26,11 @@ module.exports = { MaxTokens: 8000, EmbeddingsDimensions: 1536, }, + 'amazon.titan-embed-text-v2': { + ModelID: 'amazon.titan-embed-text-v2:0', + MaxTokens: 8000, + EmbeddingsDimensions: 1024, + }, 'amazon.titan-text-express-v1': { ModelID: 'amazon.titan-text-express-v1', MaxTokens: 8000, @@ -38,6 +45,15 @@ module.exports = { QAPromptTemplate: amazonQAPromptTemplate, NoHitsRegex: anthropicNoHitsRegex, }, + 'amazon.titan-text-premier-v1': { + ModelID: 'amazon.titan-text-premier-v1:0', + MaxTokens: 32000, + maxTokenCount: 3072, + QueryPromptTemplate: amazonQueryPromptTemplate, + QAPromptTemplate: amazonQAPromptTemplate, + NoHitsRegex: anthropicNoHitsRegex, + KnowledgeBasePromptTemplate: amazonKnowledgebaseTemplate, + }, 'ai21.j2-ultra-v1': { ModelID: 'ai21.j2-ultra-v1', MaxTokens: 8191, @@ -58,6 +74,7 @@ module.exports = { QueryPromptTemplate: anthropicQueryPromptTemplate, QAPromptTemplate: amazonQAPromptTemplate, NoHitsRegex: anthropicNoHitsRegex, + KnowledgeBasePromptTemplate: anthropicKnowledgebaseTemplate, }, 'anthropic.claude-v2.1': { ModelID: 'anthropic.claude-v2:1', @@ -65,6 +82,7 @@ module.exports = { QueryPromptTemplate: anthropicQueryPromptTemplate, QAPromptTemplate: amazonQAPromptTemplate, NoHitsRegex: anthropicNoHitsRegex, + KnowledgeBasePromptTemplate: anthropicKnowledgebaseTemplate, }, 'anthropic.claude-3-haiku-v1': { ModelID: 'anthropic.claude-3-haiku-20240307-v1:0', @@ -72,6 +90,7 @@ module.exports = { QueryPromptTemplate: anthropicQueryPromptTemplate, QAPromptTemplate: amazonQAPromptTemplate, NoHitsRegex: anthropicNoHitsRegex, + KnowledgeBasePromptTemplate: anthropicKnowledgebaseTemplate, }, 'anthropic.claude-3-sonnet-v1': { ModelID: 'anthropic.claude-3-sonnet-20240229-v1:0', @@ -79,6 +98,7 @@ module.exports = { QueryPromptTemplate: anthropicQueryPromptTemplate, QAPromptTemplate: amazonQAPromptTemplate, NoHitsRegex: anthropicNoHitsRegex, + KnowledgeBasePromptTemplate: anthropicKnowledgebaseTemplate, }, 'cohere.command-text-v14': { ModelID: 'cohere.command-text-v14', @@ -87,13 +107,6 @@ module.exports = { QAPromptTemplate: amazonQAPromptTemplate, NoHitsRegex: anthropicNoHitsRegex, }, - 'cohere.command-light-text-v14': { - ModelID: 'cohere.command-light-text-v14', - MaxTokens: 4000, - QueryPromptTemplate: amazonQueryPromptTemplate, - QAPromptTemplate: amazonQAPromptTemplate, - NoHitsRegex: anthropicNoHitsRegex, - }, 'cohere.embed-english-v3': { ModelID: 'cohere.embed-english-v3', MaxTokens: 512, diff --git a/source/templates/master/opensearch/firehose.js b/source/templates/master/opensearch/firehose.js index 3393b9d2e..91f9919b8 100644 --- a/source/templates/master/opensearch/firehose.js +++ b/source/templates/master/opensearch/firehose.js @@ -17,7 +17,22 @@ module.exports = { FeedbackKinesisFirehoseLogGroup: { Type: 'AWS::Logs::LogGroup', Properties: { - LogGroupName: { 'Fn::Sub': '/aws/kinesisfirehose/${AWS::StackName}-FeedbackKinesisFirehose' } + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/kinesisfirehose/${AWS::StackName}-FeedbackKinesisFirehose' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, }, Metadata: { cfn_nag: { @@ -26,12 +41,9 @@ module.exports = { id: 'W86', reason: 'LogGroup is encrypted by default.', }, - { - id: 'W84', - reason: 'LogGroup needs to be retained indefinitely', - }, ], }, + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), }, }, FeedbackKinesisFirehoseStreamOpenSearch: { @@ -39,16 +51,16 @@ module.exports = { DependsOn: ['FeedbackKinesisFirehoseLogGroup'], Properties: { LogGroupName: { Ref: 'FeedbackKinesisFirehoseLogGroup' }, - LogStreamName: 'OpenSearchDestinationDelivery' - } + LogStreamName: 'OpenSearchDestinationDelivery', + }, }, FeedbackKinesisFirehoseStreamS3: { Type: 'AWS::Logs::LogStream', DependsOn: ['FeedbackKinesisFirehoseLogGroup'], Properties: { LogGroupName: { Ref: 'FeedbackKinesisFirehoseLogGroup' }, - LogStreamName: 'S3BackupDelivery' - } + LogStreamName: 'S3BackupDelivery', + }, }, FeedbackKinesisFirehose: { Type: 'AWS::KinesisFirehose::DeliveryStream', @@ -62,23 +74,23 @@ module.exports = { Properties: { DeliveryStreamType: 'DirectPut', DeliveryStreamEncryptionConfigurationInput: { - KeyType: 'AWS_OWNED_CMK' + KeyType: 'AWS_OWNED_CMK', }, AmazonopensearchserviceDestinationConfiguration: { BufferingHints: { IntervalInSeconds: 60, - SizeInMBs: 5 + SizeInMBs: 5, }, CloudWatchLoggingOptions: { Enabled: true, LogGroupName: { Ref: 'FeedbackKinesisFirehoseLogGroup' }, - LogStreamName: { Ref: 'FeedbackKinesisFirehoseStreamOpenSearch' } + LogStreamName: { Ref: 'FeedbackKinesisFirehoseStreamOpenSearch' }, }, DomainARN: { 'Fn::GetAtt': ['ESVar', 'ESArn'] }, IndexName: { 'Fn::Sub': '${Var.FeedbackIndex}' }, IndexRotationPeriod: 'NoRotation', RetryOptions: { - DurationInSeconds: 300 + DurationInSeconds: 300, }, RoleARN: { 'Fn::GetAtt': ['FirehoseESS3Role', 'Arn'] }, S3BackupMode: 'AllDocuments', @@ -87,15 +99,15 @@ module.exports = { CloudWatchLoggingOptions: { Enabled: true, LogGroupName: { Ref: 'FeedbackKinesisFirehoseLogGroup' }, - LogStreamName: { Ref: 'FeedbackKinesisFirehoseStreamS3' } + LogStreamName: { Ref: 'FeedbackKinesisFirehoseStreamS3' }, }, BufferingHints: { IntervalInSeconds: 60, - SizeInMBs: 5 + SizeInMBs: 5, }, Prefix: 'feedback/', CompressionFormat: 'UNCOMPRESSED', - RoleARN: { 'Fn::GetAtt': ['FirehoseESS3Role', 'Arn'] } + RoleARN: { 'Fn::GetAtt': ['FirehoseESS3Role', 'Arn'] }, }, TypeName: '', VpcConfiguration: { @@ -104,18 +116,33 @@ module.exports = { { RoleARN: { 'Fn::GetAtt': ['FirehoseESS3Role', 'Arn'] }, SubnetIds: { Ref: 'VPCSubnetIdList' }, - SecurityGroupIds: { Ref: 'VPCSecurityGroupIdList' } + SecurityGroupIds: { Ref: 'VPCSecurityGroupIdList' }, }, - { Ref: 'AWS::NoValue' } - ] - } + { Ref: 'AWS::NoValue' }, + ], + }, }, - } + }, }, GeneralKinesisFirehoseLogGroup: { Type: 'AWS::Logs::LogGroup', Properties: { - LogGroupName: { 'Fn::Sub': '/aws/kinesisfirehose/${AWS::StackName}-GeneralKinesisFirehose' } + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/kinesisfirehose/${AWS::StackName}-GeneralKinesisFirehose' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, }, Metadata: { cfn_nag: { @@ -124,27 +151,24 @@ module.exports = { id: 'W86', reason: 'LogGroup is encrypted by default.', }, - { - id: 'W84', - reason: 'LogGroup needs to be retained indefinitely', - }, ], }, + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), }, }, GeneralKinesisFirehoseStreamOpenSearch: { Type: 'AWS::Logs::LogStream', Properties: { LogGroupName: { Ref: 'GeneralKinesisFirehoseLogGroup' }, - LogStreamName: 'OpenSearchDestinationDelivery' - } + LogStreamName: 'OpenSearchDestinationDelivery', + }, }, GeneralKinesisFirehoseStreamS3: { Type: 'AWS::Logs::LogStream', Properties: { LogGroupName: { Ref: 'GeneralKinesisFirehoseLogGroup' }, - LogStreamName: 'S3BackupDelivery' - } + LogStreamName: 'S3BackupDelivery', + }, }, GeneralKinesisFirehose: { Type: 'AWS::KinesisFirehose::DeliveryStream', @@ -158,23 +182,23 @@ module.exports = { Properties: { DeliveryStreamType: 'DirectPut', DeliveryStreamEncryptionConfigurationInput: { - KeyType: 'AWS_OWNED_CMK' + KeyType: 'AWS_OWNED_CMK', }, AmazonopensearchserviceDestinationConfiguration: { BufferingHints: { IntervalInSeconds: 60, - SizeInMBs: 5 + SizeInMBs: 5, }, CloudWatchLoggingOptions: { Enabled: true, LogGroupName: { Ref: 'GeneralKinesisFirehoseLogGroup' }, - LogStreamName: { Ref: 'GeneralKinesisFirehoseStreamOpenSearch' } + LogStreamName: { Ref: 'GeneralKinesisFirehoseStreamOpenSearch' }, }, DomainARN: { 'Fn::GetAtt': ['ESVar', 'ESArn'] }, IndexName: { 'Fn::Sub': '${Var.MetricsIndex}' }, IndexRotationPeriod: 'NoRotation', RetryOptions: { - DurationInSeconds: 300 + DurationInSeconds: 300, }, RoleARN: { 'Fn::GetAtt': ['FirehoseESS3Role', 'Arn'] }, S3BackupMode: 'AllDocuments', @@ -183,15 +207,15 @@ module.exports = { CloudWatchLoggingOptions: { Enabled: true, LogGroupName: { Ref: 'GeneralKinesisFirehoseLogGroup' }, - LogStreamName: { Ref: 'GeneralKinesisFirehoseStreamS3' } + LogStreamName: { Ref: 'GeneralKinesisFirehoseStreamS3' }, }, Prefix: 'metrics/', BufferingHints: { IntervalInSeconds: 60, - SizeInMBs: 5 + SizeInMBs: 5, }, CompressionFormat: 'UNCOMPRESSED', - RoleARN: { 'Fn::GetAtt': ['FirehoseESS3Role', 'Arn'] } + RoleARN: { 'Fn::GetAtt': ['FirehoseESS3Role', 'Arn'] }, }, TypeName: '', VpcConfiguration: { @@ -200,13 +224,13 @@ module.exports = { { RoleARN: { 'Fn::GetAtt': ['FirehoseESS3Role', 'Arn'] }, SubnetIds: { Ref: 'VPCSubnetIdList' }, - SecurityGroupIds: { Ref: 'VPCSecurityGroupIdList' } + SecurityGroupIds: { Ref: 'VPCSecurityGroupIdList' }, }, - { Ref: 'AWS::NoValue' } - ] - } + { Ref: 'AWS::NoValue' }, + ], + }, }, - } + }, }, MetricsBucket: { Type: 'AWS::S3::Bucket', @@ -215,7 +239,7 @@ module.exports = { DeletionPolicy: 'Delete', Properties: { VersioningConfiguration: { - Status: 'Enabled' + Status: 'Enabled', }, BucketEncryption: { ServerSideEncryptionConfiguration: [{ @@ -226,27 +250,27 @@ module.exports = { }, LoggingConfiguration: { DestinationBucketName: { Ref: 'MainAccessLogBucket' }, - LogFilePrefix: { 'Fn::Join': ['', [{ Ref: 'MainAccessLogBucket' }, '/Metrics/']] } + LogFilePrefix: { 'Fn::Join': ['', [{ Ref: 'MainAccessLogBucket' }, '/Metrics/']] }, }, PublicAccessBlockConfiguration: { BlockPublicAcls: true, BlockPublicPolicy: true, IgnorePublicAcls: true, - RestrictPublicBuckets: true + RestrictPublicBuckets: true, }, Tags: [ { Key: 'Use', - Value: 'Metrics' - } - ] - } + Value: 'Metrics', + }, + ], + }, }, HTTPSOnlyMetricBucketsPolicy: { Type: 'AWS::S3::BucketPolicy', Properties: { Bucket: { - Ref: 'MetricsBucket' + Ref: 'MetricsBucket', }, PolicyDocument: { Statement: [ @@ -254,8 +278,8 @@ module.exports = { Action: '*', Condition: { Bool: { - 'aws:SecureTransport': 'false' - } + 'aws:SecureTransport': 'false', + }, }, Effect: 'Deny', Principal: '*', @@ -265,37 +289,37 @@ module.exports = { '', [ { - 'Fn::GetAtt': ['MetricsBucket', 'Arn'] + 'Fn::GetAtt': ['MetricsBucket', 'Arn'], }, - '/*' - ] - ] + '/*', + ], + ], }, { 'Fn::Join': [ '', [ { - 'Fn::GetAtt': ['MetricsBucket', 'Arn'] - } - ] - ] - } + 'Fn::GetAtt': ['MetricsBucket', 'Arn'], + }, + ], + ], + }, ], - Sid: 'HttpsOnly' - } + Sid: 'HttpsOnly', + }, ], - Version: '2012-10-17' - } - } + Version: '2012-10-17', + }, + }, }, MetricsBucketClean: { Type: 'Custom::S3Clean', DependsOn: ['CFNInvokePolicy', 'HTTPSOnlyMetricBucketsPolicy'], Properties: { ServiceToken: { 'Fn::GetAtt': ['S3Clean', 'Arn'] }, - Bucket: { Ref: 'MetricsBucket' } - } + Bucket: { Ref: 'MetricsBucket' }, + }, }, FirehoseESS3Role: { Type: 'AWS::IAM::Role', @@ -306,11 +330,11 @@ module.exports = { { Effect: 'Allow', Principal: { - Service: 'firehose.amazonaws.com' + Service: 'firehose.amazonaws.com', }, - Action: 'sts:AssumeRole' - } - ] + Action: 'sts:AssumeRole', + }, + ], }, Path: '/', Policies: [ @@ -327,12 +351,12 @@ module.exports = { 's3:GetObject', 's3:ListBucket', 's3:ListBucketMultipartUploads', - 's3:PutObject' + 's3:PutObject', ], Resource: [ { 'Fn::GetAtt': ['MetricsBucket', 'Arn'] }, - { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['MetricsBucket', 'Arn'] }, '/*']] } - ] + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['MetricsBucket', 'Arn'] }, '/*']] }, + ], }, { Sid: 'FirehoseLambdaPermissions', @@ -347,11 +371,11 @@ module.exports = { { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, - ':function:%FIREHOSE_DEFAULT_FUNCTION%:%FIREHOSE_DEFAULT_VERSION%' - ] - ] - } - ] + ':function:%FIREHOSE_DEFAULT_FUNCTION%:%FIREHOSE_DEFAULT_VERSION%', + ], + ], + }, + ], }, { Sid: 'FirehoseOpenSearchDestinationPermissions', @@ -362,12 +386,12 @@ module.exports = { 'es:DescribeDomainConfig', 'es:ESHttpPost', 'es:ESHttpPut', - 'es:ESHttpGet' + 'es:ESHttpGet', ], Resource: [ { 'Fn::GetAtt': ['ESVar', 'ESArn'] }, - { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['ESVar', 'ESArn'] }, '/*']] } - ] + { 'Fn::Join': ['', [{ 'Fn::GetAtt': ['ESVar', 'ESArn'] }, '/*']] }, + ], }, { Sid: 'FirehoseLogsPermissions', @@ -382,11 +406,11 @@ module.exports = { { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, - ':log-group:/aws/kinesisfirehose/*' - ] - ] - } - ] + ':log-group:/aws/kinesisfirehose/*', + ], + ], + }, + ], }, { Sid: 'FireHoseVPCConfiguration', // https://docs.aws.amazon.com/firehose/latest/APIReference/API_VpcConfigurationDescription.html @@ -399,19 +423,19 @@ module.exports = { 'ec2:DescribeNetworkInterfaces', 'ec2:CreateNetworkInterface', 'ec2:CreateNetworkInterfacePermission', - 'ec2:DeleteNetworkInterface' + 'ec2:DeleteNetworkInterface', ], - Resource: '*' // these actions cannot be bound to resources other than * - } - ] + Resource: '*', // these actions cannot be bound to resources other than * + }, + ], }, - PolicyName: 'QnAFirehose' - } - ] + PolicyName: 'QnAFirehose', + }, + ], }, Metadata: { cfn_nag: util.cfnNag(['W11']), guard: util.cfnGuard('IAM_NO_INLINE_POLICY_CHECK'), }, - } + }, }; diff --git a/source/templates/master/opensearch/info.js b/source/templates/master/opensearch/info.js index 98a09591a..200ad5ec0 100644 --- a/source/templates/master/opensearch/info.js +++ b/source/templates/master/opensearch/info.js @@ -24,6 +24,31 @@ module.exports = { name: { Ref: 'OpenSearchName' }, }, }, + ESInfoLambdaLogGroup:{ + Type: 'AWS::Logs::LogGroup', + Condition: 'DontCreateDomain', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ESInfoLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ESInfoLambda: { Type: 'AWS::Lambda::Function', Condition: 'DontCreateDomain', @@ -32,6 +57,9 @@ module.exports = { ZipFile: fs.readFileSync(`${__dirname}/handler.js`, 'utf-8'), }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'ESInfoLambdaLogGroup' }, + }, MemorySize: '128', Role: { 'Fn::GetAtt': ['ESProxyLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, diff --git a/source/templates/master/opensearch/proxy.js b/source/templates/master/opensearch/proxy.js index 6e09589e8..dca9bf632 100644 --- a/source/templates/master/opensearch/proxy.js +++ b/source/templates/master/opensearch/proxy.js @@ -14,6 +14,30 @@ const util = require('../../util'); module.exports = { + ESCFNProxyLambdaLogGroup:{ + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ESCFNProxyLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ESCFNProxyLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -36,6 +60,9 @@ module.exports = { { Ref: 'EsProxyLambdaLayer' }, { Ref: 'QnABotCommonLambdaLayer' }], Handler: 'resource.handler', + LoggingConfig: { + LogGroup: { Ref: 'ESCFNProxyLambdaLogGroup' }, + }, MemorySize: '1408', Role: { 'Fn::GetAtt': ['ESProxyLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -121,7 +148,7 @@ module.exports = { { 'Fn::If': [ 'EmbeddingsBedrock', - { 'Fn::FindInMap': ['BedrockDefaults', {'Ref' : 'EmbeddingsBedrockModelId'}, 'EmbeddingsDimensions'] }, + { 'Fn::FindInMap': ['BedrockDefaults', {Ref : 'EmbeddingsBedrockModelId'}, 'EmbeddingsDimensions'] }, 'INVALID EMBEDDINGS API - Cannot determine dimensions', ], }, diff --git a/source/templates/master/opensearch/updates.js b/source/templates/master/opensearch/updates.js index 60cfd4bcb..bc3d706cb 100644 --- a/source/templates/master/opensearch/updates.js +++ b/source/templates/master/opensearch/updates.js @@ -17,7 +17,14 @@ module.exports = { Type: 'AWS::Logs::LogGroup', Condition: 'FGACEnabled', Properties: { - LogGroupName: { 'Fn::Sub': '/aws/opensearch/${AWS::StackName}-${ESVar.ESDomain}' } + LogGroupName: { 'Fn::Sub': '/aws/opensearch/${AWS::StackName}-${ESVar.ESDomain}' }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' } + ] + }, }, Metadata: { cfn_nag: { @@ -25,13 +32,10 @@ module.exports = { { id: 'W86', reason: 'LogGroup is encrypted by default.', - }, - { - id: 'W84', - reason: 'LogGroup needs to be retained indefinitely', - }, + } ], }, + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), }, }, OpenSearchLogGroupResourcePolicy: { diff --git a/source/templates/master/policies.json b/source/templates/master/policies.json index 6c2540b40..638de6887 100644 --- a/source/templates/master/policies.json +++ b/source/templates/master/policies.json @@ -7,8 +7,6 @@ "Statement": [{ "Effect": "Allow", "Action": [ - "lex:PostContent", - "lex:PostText", "lex:RecognizeText", "lex:RecognizeUtterance" ], diff --git a/source/templates/master/proxy-es.js b/source/templates/master/proxy-es.js index 5b261c35a..8bbc67f6e 100644 --- a/source/templates/master/proxy-es.js +++ b/source/templates/master/proxy-es.js @@ -28,7 +28,30 @@ module.exports = { BuildDate: (new Date()).toISOString(), }, }, - + UtteranceLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-UtteranceLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, UtteranceLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -51,6 +74,9 @@ module.exports = { }, }, Handler: 'index.utterances', + LoggingConfig: { + LogGroup: { Ref: 'UtteranceLambdaLogGroup' }, + }, MemorySize: '1408', Role: { 'Fn::GetAtt': ['ESProxyLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -75,6 +101,30 @@ module.exports = { guard: util.cfnGuard('LAMBDA_CONCURRENCY_CHECK', 'LAMBDA_INSIDE_VPC'), }, }, + ESQidLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ESQidLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ESQidLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -91,10 +141,13 @@ module.exports = { Variables: { ES_INDEX: { 'Fn::GetAtt': ['Var', 'QnaIndex'] }, ES_ADDRESS: { 'Fn::GetAtt': ['ESVar', 'ESAddress'] }, - ...util.getCommonEnvironmentVariables() + ...util.getCommonEnvironmentVariables(), }, }, Handler: 'index.qid', + LoggingConfig: { + LogGroup: { Ref: 'ESQidLambdaLogGroup' }, + }, MemorySize: '1408', Role: { 'Fn::GetAtt': ['ESProxyLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -119,6 +172,30 @@ module.exports = { guard: util.cfnGuard('LAMBDA_CONCURRENCY_CHECK', 'LAMBDA_INSIDE_VPC'), }, }, + ESCleaningLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ESCleaningLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ESCleaningLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -141,6 +218,9 @@ module.exports = { }, }, Handler: 'index.cleanmetrics', + LoggingConfig: { + LogGroup: { Ref: 'ESCleaningLambdaLogGroup' }, + }, MemorySize: '1408', Role: { 'Fn::GetAtt': ['ESProxyLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -186,6 +266,30 @@ module.exports = { SourceArn: { 'Fn::GetAtt': ['ScheduledESCleaning', 'Arn'] }, }, }, + ESLoggingLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ESLoggingLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ESLoggingLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -202,10 +306,13 @@ module.exports = { Environment: { Variables: { FIREHOSE_NAME: { Ref: 'GeneralKinesisFirehose' }, - ...util.getCommonEnvironmentVariables() + ...util.getCommonEnvironmentVariables(), }, }, Handler: 'index.logging', + LoggingConfig: { + LogGroup: { Ref: 'ESLoggingLambdaLogGroup' }, + }, MemorySize: '1408', Role: { 'Fn::GetAtt': ['ESLoggingLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -230,6 +337,30 @@ module.exports = { guard: util.cfnGuard('LAMBDA_CONCURRENCY_CHECK', 'LAMBDA_INSIDE_VPC'), }, }, + ESQueryLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ESQueryLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ESQueryLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -244,7 +375,7 @@ module.exports = { PRIVATE_SETTINGS_PARAM: { Ref: 'PrivateQnABotSettings' }, CUSTOM_SETTINGS_PARAM: { Ref: 'CustomQnABotSettings' }, ...examples, - ...util.getCommonEnvironmentVariables() + ...util.getCommonEnvironmentVariables(), }, }, Layers: [{ Ref: 'AwsSdkLayerLambdaLayer' }, @@ -252,6 +383,9 @@ module.exports = { { Ref: 'EsProxyLambdaLayer' }, { Ref: 'QnABotCommonLambdaLayer' }], Handler: 'index.query', + LoggingConfig: { + LogGroup: { Ref: 'ESQueryLambdaLogGroup' }, + }, MemorySize: '1408', Role: { 'Fn::GetAtt': ['ESProxyLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -276,6 +410,30 @@ module.exports = { guard: util.cfnGuard('LAMBDA_CONCURRENCY_CHECK', 'LAMBDA_INSIDE_VPC'), }, }, + ESProxyLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ESProxyLambdaLogGroup' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ESProxyLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -306,10 +464,13 @@ module.exports = { ], }, EMBEDDINGS_LAMBDA_ARN: { Ref: 'EmbeddingsLambdaArn' }, - ...util.getCommonEnvironmentVariables() + ...util.getCommonEnvironmentVariables(), }, }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'ESProxyLambdaLogGroup' }, + }, MemorySize: '1408', Role: { 'Fn::GetAtt': ['ESProxyLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -466,7 +627,7 @@ module.exports = { 'bedrock:InvokeModel', ], Resource: [ - { 'Fn::Sub': 'arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/${EmbeddingsBedrockModelId}' }, + { 'Fn::If': ['EmbeddingsBedrock', { 'Fn::Sub': ['arn:${AWS::Partition}:bedrock:${AWS::Region}::foundation-model/${ModelId}', {'ModelId': { 'Fn::FindInMap': ['BedrockDefaults', {'Ref' : 'EmbeddingsBedrockModelId'}, 'ModelID'] }}] }, { Ref: 'AWS::NoValue' }] }, ], }, { Ref: 'AWS::NoValue' }, diff --git a/source/templates/master/proxy-lex/index.js b/source/templates/master/proxy-lex/index.js index e6813c548..4335ad286 100644 --- a/source/templates/master/proxy-lex/index.js +++ b/source/templates/master/proxy-lex/index.js @@ -15,6 +15,30 @@ const fs = require('fs'); const util = require('../../util'); module.exports = { + LexProxyLambdaLogGroup:{ + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-LexProxyLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, LexProxyLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -23,10 +47,13 @@ module.exports = { }, Environment: { Variables: { - ...util.getCommonEnvironmentVariables() - } + ...util.getCommonEnvironmentVariables(), + }, }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'LexProxyLambdaLogGroup' }, + }, MemorySize: '128', Role: { 'Fn::GetAtt': ['LexProxyLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -43,7 +70,7 @@ module.exports = { }, Layers: [ { Ref: 'AwsSdkLayerLambdaLayer' }, - { Ref: 'CommonModulesLambdaLayer' } + { Ref: 'CommonModulesLambdaLayer' }, ], Tags: [{ Key: 'Type', @@ -55,6 +82,30 @@ module.exports = { guard: util.cfnGuard('LAMBDA_CONCURRENCY_CHECK', 'LAMBDA_INSIDE_VPC'), }, }, + LexStatusLambdaLogGroup:{ + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-LexStatusLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, LexStatusLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -64,7 +115,6 @@ module.exports = { Environment: { Variables: { STATUS_BUCKET: { Ref: 'BuildStatusBucket' }, - STATUS_KEY: { 'Fn::If': ['CreateLexV1Bots', 'status.json', { Ref: 'AWS::NoValue' }] }, LEXV2_STATUS_KEY: 'lexV2status.json', FULFILLMENT_FUNCTION_ARN: { 'Fn::Join': [':', [ @@ -73,9 +123,6 @@ module.exports = { ]], }, FULFILLMENT_FUNCTION_ROLE: { Ref: 'FulfillmentLambdaRole' }, - LEXV1_BOT_NAME: { 'Fn::If': ['CreateLexV1Bots', { Ref: 'LexBot' }, { Ref: 'AWS::NoValue' }] }, - LEXV1_INTENT: { 'Fn::If': ['CreateLexV1Bots', { Ref: 'Intent' }, { Ref: 'AWS::NoValue' }] }, - LEXV1_INTENT_FALLBACK: { 'Fn::If': ['CreateLexV1Bots', { Ref: 'IntentFallback' }, { Ref: 'AWS::NoValue' }] }, LEXV2_BOT_NAME: { 'Fn::GetAtt': ['LexV2Bot', 'botName'] }, LEXV2_BOT_ID: { 'Fn::GetAtt': ['LexV2Bot', 'botId'] }, LEXV2_BOT_ALIAS: { 'Fn::GetAtt': ['LexV2Bot', 'botAlias'] }, @@ -83,10 +130,13 @@ module.exports = { LEXV2_INTENT: { 'Fn::GetAtt': ['LexV2Bot', 'botIntent'] }, LEXV2_INTENT_FALLBACK: { 'Fn::GetAtt': ['LexV2Bot', 'botIntentFallback'] }, LEXV2_BOT_LOCALE_IDS: { 'Fn::GetAtt': ['LexV2Bot', 'botLocaleIds'] }, - ...util.getCommonEnvironmentVariables() + ...util.getCommonEnvironmentVariables(), }, }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'LexStatusLambdaLogGroup' }, + }, MemorySize: '128', Role: { 'Fn::GetAtt': ['LexProxyLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, diff --git a/source/templates/master/proxy-lex/status.js b/source/templates/master/proxy-lex/status.js index 6bdb03b8b..54095c4d6 100644 --- a/source/templates/master/proxy-lex/status.js +++ b/source/templates/master/proxy-lex/status.js @@ -26,9 +26,6 @@ function getStatusResponse(response, build) { lambdaArn: process.env.FULFILLMENT_FUNCTION_ARN, lambdaRole: process.env.FULFILLMENT_FUNCTION_ROLE, botversion: 'live', - botname: process.env.LEXV1_BOT_NAME || 'LEX V1 Bot not installed', - intent: process.env.LEXV1_INTENT || 'LEX V1 Bot not installed', - intentFallback: process.env.LEXV1_INTENT_FALLBACK || 'LEX V1 Bot not installed', lexV2botname: process.env.LEXV2_BOT_NAME || 'LEX V2 Bot not installed', lexV2botid: process.env.LEXV2_BOT_ID || 'LEX V2 Bot not installed', lexV2botalias: process.env.LEXV2_BOT_ALIAS || 'LEX V2 Bot not installed', @@ -46,7 +43,6 @@ exports.handler = async (event, context, callback) => { console.log('Received event:', JSON.stringify(event, null, 2)); const bucket = process.env.STATUS_BUCKET; - const lexV1StatusFile = process.env.STATUS_KEY; const lexV2StatusFile = process.env.LEXV2_STATUS_KEY; let build = { status: 'READY', token: 'token' }; let response; @@ -56,16 +52,6 @@ exports.handler = async (event, context, callback) => { response = await s3.send(getObjCmd); const readableStreamV2 = Buffer.concat(await response.Body.toArray()); build = JSON.parse(readableStreamV2); - // combine build status with v1 bot, if defined.. If both are READY then status is READY - if (lexV1StatusFile) { - const getObjCmd = new GetObjectCommand({ Bucket: bucket, Key: lexV1StatusFile }); - response = await s3.send(getObjCmd); - const readableStreamV2 = Buffer.concat(await response.Body.toArray()); - const v1build = JSON.parse(readableStreamV2); - if (v1build.status != 'READY' || build.status != 'READY') { - build.status = `LEX V2: ${build.status} / LEX V1: ${v1build.status}`; - } - } } catch (e) { console.log('Unable to read S3 lex bot status file - perhaps it doesn\'t yet exist. Returning READY'); } @@ -74,7 +60,6 @@ exports.handler = async (event, context, callback) => { botId: process.env.LEXV2_BOT_ID, }); response = await lexv2.send(describeBotCmd); - // Match LexV1 bot status for code compatibility (Available = READY) const statusResponse = getStatusResponse(response, build); return statusResponse; }; diff --git a/source/templates/master/roles.json b/source/templates/master/roles.json index 878692387..b25ba83de 100644 --- a/source/templates/master/roles.json +++ b/source/templates/master/roles.json @@ -185,7 +185,10 @@ "Fn::Sub": "arn:aws:s3:::${ExportBucket}/data/*" }, { - "Fn::Sub": "arn:aws:s3:::${TestAllBucket}/data/*" + "Fn::Sub": "arn:aws:s3:::${ContentDesignerOutputBucket}/data-testall/*" + }, + { + "Fn::Sub": "arn:aws:s3:::${ContentDesignerOutputBucket}/data-export/*" } ] }, @@ -220,6 +223,17 @@ "Fn::Sub": "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${CustomQnABotSettings}" } ] + }, + { + "Effect": "Allow", + "Action": [ + "lambda:InvokeFunction" + ], + "Resource": [ + { + "Fn::Sub": "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${SolutionHelper}" + } + ] } ] } diff --git a/source/templates/master/routes/examples/index.js b/source/templates/master/routes/examples/index.js index 02ba2d585..f1364e421 100644 --- a/source/templates/master/routes/examples/index.js +++ b/source/templates/master/routes/examples/index.js @@ -82,6 +82,30 @@ module.exports = { }, authorization: 'AWS_IAM', }), + ExampleS3ListLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ExampleS3ListLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ExampleS3ListLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -94,6 +118,9 @@ module.exports = { } }, Handler: 'index.documents', + LoggingConfig: { + LogGroup: { Ref: 'ExampleS3ListLambdaLogGroup' }, + }, MemorySize: '128', Role: { 'Fn::GetAtt': ['S3ListLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -121,6 +148,30 @@ module.exports = { guard: util.cfnGuard('LAMBDA_CONCURRENCY_CHECK', 'LAMBDA_INSIDE_VPC'), }, }, + ExampleS3ListPhotoLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-ExampleS3ListPhotoLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, ExampleS3ListPhotoLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -133,6 +184,9 @@ module.exports = { } }, Handler: 'index.photos', + LoggingConfig: { + LogGroup: { Ref: 'ExampleS3ListPhotoLambdaLogGroup' }, + }, MemorySize: '128', Role: { 'Fn::GetAtt': ['S3ListLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, diff --git a/source/templates/master/routes/jobs/export-start.vm b/source/templates/master/routes/jobs/export-start.vm index e95d9d4cb..8652cc541 100644 --- a/source/templates/master/routes/jobs/export-start.vm +++ b/source/templates/master/routes/jobs/export-start.vm @@ -6,7 +6,7 @@ "id":"$input.params('proxy')", "config":"status/$input.params('proxy')", "tmp":"tmp/$input.params('proxy')", - "key":"$inputRoot.get('prefix')data/$input.params('proxy')", + "key":"$inputRoot.get('prefix')data-export/$input.params('proxy')", "filter":"$inputRoot.get('filter')", "status":"Started" } \ No newline at end of file diff --git a/source/templates/master/routes/jobs/index.js b/source/templates/master/routes/jobs/index.js index e93ad42e5..66c8d4f34 100644 --- a/source/templates/master/routes/jobs/index.js +++ b/source/templates/master/routes/jobs/index.js @@ -44,7 +44,7 @@ module.exports = { auth: 'AWS_IAM', method: 'PUT', bucket: { Ref: 'TestAllBucket' }, - path: '/status/{proxy}', + path: '/status-testall/{proxy}', template: fs.readFileSync(`${__dirname}/testall-start.vm`, 'utf-8'), requestParams: { 'integration.request.path.proxy': 'method.request.path.proxy', @@ -54,8 +54,8 @@ module.exports = { resource: { Ref: 'testall' }, auth: 'AWS_IAM', method: 'GET', - bucket: { Ref: 'TestAllBucket' }, - path: '/status/{proxy}', + bucket: { Ref: 'ContentDesignerOutputBucket' }, + path: '/status-testall/{proxy}', requestParams: { 'integration.request.path.proxy': 'method.request.path.proxy', }, @@ -64,8 +64,8 @@ module.exports = { resource: { Ref: 'testall' }, auth: 'AWS_IAM', method: 'delete', - bucket: { Ref: 'TestAllBucket' }, - path: '/status/{proxy}', + bucket: { Ref: 'ContentDesignerOutputBucket' }, + path: '/status-testall/{proxy}', requestParams: { 'integration.request.path.proxy': 'method.request.path.proxy', }, @@ -89,7 +89,7 @@ module.exports = { auth: 'AWS_IAM', method: 'PUT', bucket: { Ref: 'ExportBucket' }, - path: '/status/{proxy}', + path: '/status-export/{proxy}', template: fs.readFileSync(`${__dirname}/export-start.vm`, 'utf-8'), requestParams: { 'integration.request.path.proxy': 'method.request.path.proxy', @@ -99,8 +99,8 @@ module.exports = { resource: { Ref: 'export' }, auth: 'AWS_IAM', method: 'GET', - bucket: { Ref: 'ExportBucket' }, - path: '/status/{proxy}', + bucket: { Ref: 'ContentDesignerOutputBucket' }, + path: '/status-export/{proxy}', requestParams: { 'integration.request.path.proxy': 'method.request.path.proxy', }, @@ -109,7 +109,7 @@ module.exports = { resource: { Ref: 'export' }, auth: 'AWS_IAM', method: 'delete', - bucket: { Ref: 'ExportBucket' }, + bucket: { Ref: 'ContentDesignerOutputBucket' }, path: '/status/{proxy}', requestParams: { 'integration.request.path.proxy': 'method.request.path.proxy', @@ -131,8 +131,8 @@ module.exports = { resource: { Ref: 'import' }, auth: 'AWS_IAM', method: 'get', - bucket: { Ref: 'ImportBucket' }, - path: '/status/{proxy}', + bucket: { Ref: 'ContentDesignerOutputBucket' }, + path: '/status-import/{proxy}', requestParams: { 'integration.request.path.proxy': 'method.request.path.proxy', }, @@ -141,12 +141,36 @@ module.exports = { resource: { Ref: 'import' }, auth: 'AWS_IAM', method: 'delete', - bucket: { Ref: 'ImportBucket' }, - path: '/status/{proxy}', + bucket: { Ref: 'ContentDesignerOutputBucket' }, + path: '/status-import/{proxy}', requestParams: { 'integration.request.path.proxy': 'method.request.path.proxy', }, }), + S3ListLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-S3ListLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, S3ListLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -159,6 +183,9 @@ module.exports = { } }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'S3ListLambdaLogGroup' }, + }, MemorySize: '128', Role: { 'Fn::GetAtt': ['S3ListLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, diff --git a/source/templates/master/routes/jobs/list-export.vm b/source/templates/master/routes/jobs/list-export.vm index e9c5a1b3a..237c10ff2 100644 --- a/source/templates/master/routes/jobs/list-export.vm +++ b/source/templates/master/routes/jobs/list-export.vm @@ -1,8 +1,8 @@ #set ($root="https://${!context.domainName}/${!context.stage}") { - "bucket":"${ExportBucket}", - "prefix":"status/", + "bucket":"${ContentDesignerOutputBucket}", + "prefix":"status-export/", "perpage":"$input.params('perpage')", "token":"$input.params('token')", "type":"exports", diff --git a/source/templates/master/routes/jobs/list-testall.vm b/source/templates/master/routes/jobs/list-testall.vm index 9db48677d..2d291050a 100644 --- a/source/templates/master/routes/jobs/list-testall.vm +++ b/source/templates/master/routes/jobs/list-testall.vm @@ -1,8 +1,8 @@ #set ($root="https://${!context.domainName}/${!context.stage}") { - "bucket":"${TestAllBucket}", - "prefix":"status/", + "bucket":"${ContentDesignerOutputBucket}", + "prefix":"status-testall/", "perpage":"$input.params('perpage')", "token":"$input.params('token')", "type":"testall", diff --git a/source/templates/master/routes/jobs/list.vm b/source/templates/master/routes/jobs/list.vm index 577a485ce..66f3049df 100644 --- a/source/templates/master/routes/jobs/list.vm +++ b/source/templates/master/routes/jobs/list.vm @@ -1,8 +1,8 @@ #set ($root="https://${!context.domainName}/${!context.stage}") { - "bucket":"${ImportBucket}", - "prefix":"status/", + "bucket":"${ContentDesignerOutputBucket}", + "prefix":"status-import/", "perpage":"$input.params('perpage')", "token":"$input.params('token')", "type":"imports", diff --git a/source/templates/master/routes/jobs/testall-start.vm b/source/templates/master/routes/jobs/testall-start.vm index dafbafff3..c401a2ce2 100644 --- a/source/templates/master/routes/jobs/testall-start.vm +++ b/source/templates/master/routes/jobs/testall-start.vm @@ -4,9 +4,9 @@ "bucket":"${TestAllBucket}", "index":"${Var.QnaIndex}", "id":"$input.params('proxy')", - "config":"status/$input.params('proxy')", - "tmp":"tmp/$input.params('proxy')", - "key":"data/$input.params('proxy')", + "config":"status-testall/$input.params('proxy')", + "tmp":"tmp-testall/$input.params('proxy')", + "key":"data-testall/$input.params('proxy')", "filter":"$inputRoot.get('filter')", "token":"$inputRoot.get('token')", "locale":"$inputRoot.get('locale')", diff --git a/source/templates/master/routes/root/info.vm b/source/templates/master/routes/root/info.vm index 89e2db808..f5ca6ce37 100644 --- a/source/templates/master/routes/root/info.vm +++ b/source/templates/master/routes/root/info.vm @@ -18,6 +18,7 @@ "PrivateQnABotSettings":"${PrivateQnABotSettings}", "CustomQnABotSettings":"${CustomQnABotSettings}", "KendraCrawlerSnsTopic":"${KendraCrawlerSnsTopic}", + "SolutionHelper": "${SolutionHelper}", "Id":"$stageVariables.Id", "_links":{ "root":{ diff --git a/source/templates/master/s3-clean/index.js b/source/templates/master/s3-clean/index.js index db423e15a..c06cbac06 100644 --- a/source/templates/master/s3-clean/index.js +++ b/source/templates/master/s3-clean/index.js @@ -22,6 +22,30 @@ module.exports = { BuildDate: (new Date()).toISOString(), }, }, + S3CleanLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-S3CleanLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, S3Clean: { Type: 'AWS::Lambda::Function', Metadata: { guard: util.cfnGuard('LAMBDA_CONCURRENCY_CHECK', 'LAMBDA_INSIDE_VPC') }, @@ -32,11 +56,14 @@ module.exports = { }, Environment: { Variables: { - ...util.getCommonEnvironmentVariables() + ...util.getCommonEnvironmentVariables(), }, }, Description: 'This function clears all S3 objects from the bucket of a given S3-based resource', Handler: 'lambda_function.handler', + LoggingConfig: { + LogGroup: { Ref: 'S3CleanLambdaLogGroup' }, + }, Role: { 'Fn::GetAtt': ['CFNLambdaRole', 'Arn'], }, diff --git a/source/templates/master/s3.js b/source/templates/master/s3.js index e121f6a2b..adc5b7bf1 100644 --- a/source/templates/master/s3.js +++ b/source/templates/master/s3.js @@ -102,6 +102,7 @@ module.exports = { { 'Fn::Sub': 'arn:aws:s3:::${TestAllBucket}/*' }, { 'Fn::Sub': 'arn:aws:s3:::${Bucket}/*' }, { 'Fn::Sub': 'arn:aws:s3:::${AssetBucket}/*' }, + { 'Fn::Sub': 'arn:aws:s3:::${ContentDesignerOutputBucket}/*' }, ], }, { Effect: 'Allow', @@ -111,6 +112,7 @@ module.exports = { Resource: [ { 'Fn::Sub': 'arn:aws:s3:::${ExportBucket}/*' }, { 'Fn::Sub': 'arn:aws:s3:::${TestAllBucket}/*' }, + { 'Fn::Sub': 'arn:aws:s3:::${ContentDesignerOutputBucket}/*' }, ], }, { Effect: 'Allow', @@ -121,6 +123,7 @@ module.exports = { { 'Fn::Sub': 'arn:aws:s3:::${ImportBucket}/*' }, { 'Fn::Sub': 'arn:aws:s3:::${ExportBucket}/*' }, { 'Fn::Sub': 'arn:aws:s3:::${TestAllBucket}/*' }, + { 'Fn::Sub': 'arn:aws:s3:::${ContentDesignerOutputBucket}/*' }, ], }, ], diff --git a/source/templates/master/schemaLambda.js b/source/templates/master/schemaLambda.js index 1432e8890..bf79f1c9f 100644 --- a/source/templates/master/schemaLambda.js +++ b/source/templates/master/schemaLambda.js @@ -23,6 +23,30 @@ module.exports = { BuildDate: (new Date()).toISOString(), }, }, + SchemaLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-SchemaLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, SchemaLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -32,6 +56,9 @@ module.exports = { S3ObjectVersion: { Ref: 'SchemaLambdaCodeVersion' }, }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'SchemaLambdaLogGroup' }, + }, MemorySize: '128', Role: { 'Fn::GetAtt': ['SchemaLambdaRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, diff --git a/source/templates/master/settings.js b/source/templates/master/settings.js index b018473cd..8aececd65 100644 --- a/source/templates/master/settings.js +++ b/source/templates/master/settings.js @@ -112,6 +112,13 @@ const defaultSettings = { KNOWLEDGE_BASE_SHOW_REFERENCES: 'true', // Enables the knowledge base to provide full-text references to the sources the knowledge base generated text from KNOWLEDGE_BASE_S3_SIGNED_URLS: 'true', // Enables the knowledge base to provide signed URLs for the knowledge base documents. KNOWLEDGE_BASE_S3_SIGNED_URL_EXPIRE_SECS: 300, // The number of seconds the signed URL will be valid for. + KNOWLEDGE_BASE_PROMPT_TEMPLATE: '${KNOWLEDGE_BASE_PROMPT_TEMPLATE}', // The template used to construct a prompt that is sent to the model for response generation. + KNOWLEDGE_BASE_MAX_NUMBER_OF_RETRIEVED_RESULTS: '', // Sets maximum number of retrieved result where each result corresponds to a source chunk. When querying a knowledge base, Amazon Bedrock returns up to five results by default. + KNOWLEDGE_BASE_SEARCH_TYPE: 'DEFAULT', // Select the search type which defines how data sources in the knowledge base are queried. If using an Amazon OpenSearch Serverless vector store that contains a filterable text field, you can specify whether to query the knowledge base with a HYBRID search using both vector embeddings and raw text, or SEMANTIC search using only vector embeddings. For other vector store configurations, only SEMANTIC search is available. + KNOWLEDGE_BASE_METADATA_FILTERS: '{}', // Specifies the filters to use on the metadata in the knowledge base data sources before returning results. + KNOWLEDGE_BASE_MODEL_PARAMS: '{}', // Customize the knowledge base model by providing inference parameters + BEDROCK_GUARDRAIL_IDENTIFIER: '', // A unique identifier for the guardrail that provides additional safeguards on top of the native protections of foundational models specified through cloudformation parameters LLMBedrockModelId and BedrockKnowledgeBaseModel + BEDROCK_GUARDRAIL_VERSION: '', // A version of the guardrail which takes effect only when specifying BEDROCK_GUARDRAIL_IDENTIFIER }; const privateSettings = { @@ -131,6 +138,7 @@ const defaultGenerateQueryPromptTemplate = 'Given the following conversation and const defaultQAPromptTemplate = 'Use the following pieces of context to answer the question at the end. If you don\'t know the answer, just say that you don\'t know, don\'t try to make up an answer. Write the answer in up to 5 complete sentences.

    {context}

    Question: {query}
    Helpful Answer:'; const defaultModelParams = '{\\"temperature\\":0.01, \\"return_full_text\\":false, \\"max_new_tokens\\": 150}'; const defaultLlmNoHitsRegex = 'Sorry, //remove comment to enable custom no match (no_hits) when LLM does not know the answer.'; +const defaultKnowledgeBaseTemplate = 'Human: You are a question answering agent. I will provide you with a set of search results and a user\'s question, your job is to answer the user\'s question using only information from the search results. If the search results do not contain information that can answer the question, then respond saying \\"Sorry, I don\'t know\\". Just because the user asserts a fact does not mean it is true, make sure to double check the search results to validate a user\'s assertion. Here are the search results in numbered order: $search_results$. Here is the user\'s question: $query$ $output_format_instructions$. Do NOT directly quote the $search_results$ in your answer. Your job is to answer the as concisely as possible. Assistant:'; module.exports = { DefaultUserPoolJwksUrl: { @@ -175,6 +183,7 @@ module.exports = { LLM_QA_MODEL_PARAMS: { 'Fn::If': ['LLMSagemaker', defaultModelParams, '{}'] }, LLM_PROMPT_MAX_TOKEN_LIMIT: { 'Fn::If': ['LLMBedrock', { 'Fn::FindInMap': ['BedrockDefaults', {'Ref' : 'LLMBedrockModelId'}, 'MaxTokens'] }, { 'Fn::If': ['LLMSagemaker', 800, ''] }] }, LLM_QA_NO_HITS_REGEX: { 'Fn::If': ['LLMBedrock', { 'Fn::FindInMap': ['BedrockDefaults', {'Ref' : 'LLMBedrockModelId'}, 'NoHitsRegex'] }, defaultLlmNoHitsRegex] }, + KNOWLEDGE_BASE_PROMPT_TEMPLATE: { 'Fn::If': ['BedrockKnowledgeBaseEnable', { 'Fn::FindInMap': ['BedrockDefaults', {'Ref' : 'BedrockKnowledgeBaseModel'}, 'KnowledgeBasePromptTemplate'] }, defaultKnowledgeBaseTemplate] }, }, ], }, @@ -190,7 +199,7 @@ module.exports = { 'Fn::Sub': [ JSON.stringify(privateSettings), { - EMBEDDINGS_MODEL_ID: { 'Fn::If': ['EmbeddingsBedrock', { Ref: 'EmbeddingsBedrockModelId' }, ''] }, + EMBEDDINGS_MODEL_ID: { 'Fn::If': ['EmbeddingsBedrock', { 'Fn::FindInMap': ['BedrockDefaults', {'Ref' : 'EmbeddingsBedrockModelId'}, 'ModelID'] }, ''] }, LLM_MODEL_ID: { 'Fn::If': ['LLMBedrock', { 'Fn::FindInMap': ['BedrockDefaults', {'Ref' : 'LLMBedrockModelId'}, 'ModelID'] }, ''] }, KNOWLEDGE_BASE_MODEL_ID: { 'Fn::If': ['BedrockKnowledgeBaseEnable', { 'Fn::FindInMap': ['BedrockDefaults', {'Ref' : 'BedrockKnowledgeBaseModel'}, 'ModelID'] }, ''] }, KNOWLEDGE_BASE_ID: { 'Fn::If': ['BedrockKnowledgeBaseEnable', {'Ref' : 'BedrockKnowledgeBaseId'}, ''] }, @@ -204,6 +213,15 @@ module.exports = { Properties: { Description: 'Custom QnABot Settings - Modify to override defaults, or to add new settings', Type: 'String', + Tier: 'Advanced', + Value: '{}', + }, + }, + SolutionHelperParameter: { + Type: 'AWS::SSM::Parameter', + Properties: { + Description: 'Solution Helper Parameter - DO NOT MODIFY', + Type: 'String', Value: '{}', }, }, diff --git a/source/templates/master/signup/index.js b/source/templates/master/signup/index.js index 74c671d6a..448d42673 100644 --- a/source/templates/master/signup/index.js +++ b/source/templates/master/signup/index.js @@ -33,6 +33,31 @@ module.exports = { SourceArn: { 'Fn::GetAtt': ['UserPool', 'Arn'] }, }, }, + MessageLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-MessageLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, MessageLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -40,6 +65,9 @@ module.exports = { ZipFile: fs.readFileSync(`${__dirname}/message.js`, 'utf8'), }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'MessageLambdaLogGroup' }, + }, MemorySize: '128', Environment: { Variables: { @@ -84,6 +112,30 @@ module.exports = { guard: util.cfnGuard('LAMBDA_CONCURRENCY_CHECK', 'LAMBDA_INSIDE_VPC'), }, }, + SignupLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-SignupLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, SignupLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -91,6 +143,9 @@ module.exports = { ZipFile: fs.readFileSync(`${__dirname}/signup.js`, 'utf8'), }, Handler: 'index.handler', + LoggingConfig: { + LogGroup: { Ref: 'SignupLambdaLogGroup' }, + }, MemorySize: '128', Environment: { Variables: { diff --git a/source/templates/master/solution-helper/index.js b/source/templates/master/solution-helper/index.js index f03de99d9..c88ef5855 100644 --- a/source/templates/master/solution-helper/index.js +++ b/source/templates/master/solution-helper/index.js @@ -33,6 +33,68 @@ module.exports = { util.basicLambdaExecutionPolicy(), util.lambdaVPCAccessExecutionRole(), util.xrayDaemonWriteAccess(), + { + PolicyName: 'GetParameterPolicy', + PolicyDocument: { + Version: '2012-10-17', + Statement: [{ + Effect: 'Allow', + Action: ['ssm:GetParameter'], + Resource: [ + { + 'Fn::Join': [ + '', [ + 'arn:', + { 'Fn::Sub': '${AWS::Partition}:' }, + 'ssm:', + { 'Fn::Sub': '${AWS::Region}:' }, + { 'Fn::Sub': '${AWS::AccountId}:' }, + 'parameter/', + { Ref: 'SolutionHelperParameter' }, + ], + ], + }, { + 'Fn::Join': [ + '', [ + 'arn:', + { 'Fn::Sub': '${AWS::Partition}:' }, + 'ssm:', + { 'Fn::Sub': '${AWS::Region}:' }, + { 'Fn::Sub': '${AWS::AccountId}:' }, + 'parameter/', + { Ref: 'CustomQnABotSettings' }, + ], + ], + }, + ], + }], + }, + }, + { + PolicyName: 'PutParameterPolicy', + PolicyDocument: { + Version: '2012-10-17', + Statement: [{ + Effect: 'Allow', + Action: ['ssm:PutParameter'], + Resource: [ + { + 'Fn::Join': [ + '', [ + 'arn:', + { 'Fn::Sub': '${AWS::Partition}:' }, + 'ssm:', + { 'Fn::Sub': '${AWS::Region}:' }, + { 'Fn::Sub': '${AWS::AccountId}:' }, + 'parameter/', + { Ref: 'SolutionHelperParameter' }, + ], + ], + }, + ], + }], + }, + }, ], }, Metadata: { @@ -49,6 +111,30 @@ module.exports = { BuildDate: (new Date()).toISOString(), }, }, + SolutionHelperLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-SolutionHelper' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, SolutionHelper: { Type: 'AWS::Lambda::Function', Properties: { @@ -59,9 +145,19 @@ module.exports = { }, Description: 'This function generates UUID for each deployment and sends anonymized data to the AWS Solutions team', Handler: 'lambda_function.handler', + LoggingConfig: { + LogGroup: { Ref: 'SolutionHelperLogGroup' }, + }, Role: { 'Fn::GetAtt': ['SolutionHelperRole', 'Arn'], }, + Environment: { + Variables: { + SOLUTION_PARAMETER: { Ref: 'SolutionHelperParameter' }, + CUSTOM_SETTINGS: { Ref: 'CustomQnABotSettings' }, + SOLUTION_ID : util.getCommonEnvironmentVariables().SOLUTION_ID, + }, + }, Runtime: process.env.npm_package_config_pythonRuntime, Timeout: 300, VpcConfig: { @@ -152,7 +248,6 @@ module.exports = { ], }, FulfillmentConcurrency: { Ref: 'FulfillmentConcurrency' }, - LexBotVersion: { Ref: 'LexBotVersion' }, InstallLexResponseBots: { Ref: 'InstallLexResponseBots' }, EmbeddingsApi: { Ref: 'EmbeddingsApi' }, EmbeddingsBedrockModelId: { diff --git a/source/templates/master/tstallstack.js b/source/templates/master/tstallstack.js index 4d3b59f21..e0c560b99 100644 --- a/source/templates/master/tstallstack.js +++ b/source/templates/master/tstallstack.js @@ -28,11 +28,13 @@ module.exports = { EsEndpoint: { 'Fn::GetAtt': ['ESVar', 'ESAddress'] }, EsProxyLambda: { 'Fn::GetAtt': ['ESProxyLambda', 'Arn'] }, TestAllBucket: { Ref: 'TestAllBucket' }, + ContentDesignerOutputBucket: { Ref: 'ContentDesignerOutputBucket' }, VPCSubnetIdList: { 'Fn::Join': [',', { Ref: 'VPCSubnetIdList' }] }, VPCSecurityGroupIdList: { 'Fn::Join': [',', { Ref: 'VPCSecurityGroupIdList' }] }, XraySetting: { Ref: 'XraySetting' }, AwsSdkLayerLambdaLayer: { Ref: 'AwsSdkLayerLambdaLayer' }, CommonModulesLambdaLayer:{ Ref: 'CommonModulesLambdaLayer' }, + LogRetentionPeriod: { Ref: 'LogRetentionPeriod' }, }, }, }, diff --git a/source/templates/package-lock.json b/source/templates/package-lock.json index 0ec6dd463..1f6d8b81d 100644 --- a/source/templates/package-lock.json +++ b/source/templates/package-lock.json @@ -1,12 +1,12 @@ { "name": "qnabot-on-aws-infrastructure", - "version": "6.0.3", + "version": "6.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "qnabot-on-aws-infrastructure", - "version": "6.0.3", + "version": "6.1.0", "license": "Apache-2.0", "devDependencies": { "@aws-sdk/client-s3": "^3.621.0", @@ -2420,16 +2420,16 @@ } }, "node_modules/@smithy/core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", - "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", "dev": true, "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-retry": "^3.0.13", "@smithy/middleware-serde": "^3.0.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" @@ -2641,15 +2641,15 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", - "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", "dev": true, "dependencies": { "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -2815,9 +2815,9 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", "dev": true, "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", @@ -2915,13 +2915,13 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", - "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", "dev": true, "dependencies": { "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -2931,16 +2931,16 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", - "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", "dev": true, "dependencies": { "@smithy/config-resolver": "^3.0.5", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", + "@smithy/smithy-client": "^3.1.11", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, diff --git a/source/templates/package.json b/source/templates/package.json index 0b671ad08..abb232983 100644 --- a/source/templates/package.json +++ b/source/templates/package.json @@ -1,6 +1,6 @@ { "name": "qnabot-on-aws-infrastructure", - "version": "6.0.3", + "version": "6.1.0", "description": "QnABot infrastructure", "scripts": { "clean": "rm -rf node_modules", diff --git a/source/templates/public-vpc-support/index.js b/source/templates/public-vpc-support/index.js index b068a70c5..8f49b6638 100644 --- a/source/templates/public-vpc-support/index.js +++ b/source/templates/public-vpc-support/index.js @@ -24,10 +24,6 @@ module.exports = Promise.resolve(require('../master')).then((base) => { 'ClientURL', 'DashboardURL', 'UserPoolURL', - 'LexV1BotName', - 'LexV1BotAlias', - 'LexV1Intent', - 'LexV1IntentFallback', 'LexV2BotName', 'LexV2BotId', 'LexV2BotAlias', @@ -40,6 +36,8 @@ module.exports = Promise.resolve(require('../master')).then((base) => { 'OpenSearchEndpoint', 'ElasticsearchIndex', 'MetricsBucket', + 'TestAllBucket', + 'ContentDesignerOutputBucket' ]); base.Parameters = _.pick(base.Parameters, [ 'Email', @@ -74,6 +72,7 @@ module.exports = Promise.resolve(require('../master')).then((base) => { 'LLMLambdaArn', 'BedrockKnowledgeBaseId', 'BedrockKnowledgeBaseModel', + 'LogRetentionPeriod', ]); base.Metadata = { 'AWS::CloudFormation::Interface': { diff --git a/source/templates/public/index.js b/source/templates/public/index.js index 39e6391cc..f567a0e6a 100644 --- a/source/templates/public/index.js +++ b/source/templates/public/index.js @@ -24,10 +24,6 @@ module.exports = Promise.resolve(require('../master')).then((base) => { 'ClientURL', 'DashboardURL', 'UserPoolURL', - 'LexV1BotName', - 'LexV1BotAlias', - 'LexV1Intent', - 'LexV1IntentFallback', 'LexV2BotName', 'LexV2BotId', 'LexV2BotAlias', @@ -40,6 +36,8 @@ module.exports = Promise.resolve(require('../master')).then((base) => { 'OpenSearchEndpoint', 'ElasticsearchIndex', 'MetricsBucket', + 'TestAllBucket', + 'ContentDesignerOutputBucket' ]); base.Parameters = _.pick(base.Parameters, [ 'Email', @@ -72,6 +70,7 @@ module.exports = Promise.resolve(require('../master')).then((base) => { 'LLMLambdaArn', 'BedrockKnowledgeBaseId', 'BedrockKnowledgeBaseModel', + 'LogRetentionPeriod' ]); base.Metadata = { 'AWS::CloudFormation::Interface': { diff --git a/source/templates/sagemaker-qa-summarize-llm/__snapshots__/index.test.js.snap b/source/templates/sagemaker-qa-summarize-llm/__snapshots__/index.test.js.snap index 3c8b701b0..600991dd1 100644 --- a/source/templates/sagemaker-qa-summarize-llm/__snapshots__/index.test.js.snap +++ b/source/templates/sagemaker-qa-summarize-llm/__snapshots__/index.test.js.snap @@ -166,7 +166,7 @@ exports[`renders sagemaker-qa-summarize-llm template correctly 1`] = ` "SM_NUM_GPUS": "4", }, "Image": { - "Fn::Sub": "763104351884.dkr.ecr.\${AWS::Region}.amazonaws.com/huggingface-pytorch-tgi-inference:2.0.1-tgi1.1.0-gpu-py39-cu118-ubuntu20.04", + "Fn::Sub": "763104351884.dkr.ecr.\${AWS::Region}.amazonaws.com/huggingface-pytorch-tgi-inference:2.3.0-tgi2.2.0-gpu-py310-cu121-ubuntu22.04-v2.0", }, "ModelDataSource": { "S3DataSource": { @@ -176,7 +176,7 @@ exports[`renders sagemaker-qa-summarize-llm template correctly 1`] = ` }, "S3DataType": "S3Prefix", "S3Uri": { - "Fn::Sub": "s3://jumpstart-private-cache-prod-\${AWS::Region}/meta-textgeneration/meta-textgeneration-llama-2-13b-f/artifacts/inference-prepack/v1.0.0/", + "Fn::Sub": "s3://jumpstart-private-cache-prod-\${AWS::Region}/meta-textgeneration/meta-textgeneration-llama-2-13b-f/artifacts/inference-prepack/v1.1.0/", }, }, }, diff --git a/source/templates/sagemaker-qa-summarize-llm/index.js b/source/templates/sagemaker-qa-summarize-llm/index.js index 7d56302cc..1b6bd6300 100644 --- a/source/templates/sagemaker-qa-summarize-llm/index.js +++ b/source/templates/sagemaker-qa-summarize-llm/index.js @@ -43,11 +43,11 @@ module.exports = { Properties: { PrimaryContainer: { Image: { - 'Fn::Sub': '763104351884.dkr.ecr.${AWS::Region}.amazonaws.com/huggingface-pytorch-tgi-inference:2.0.1-tgi1.1.0-gpu-py39-cu118-ubuntu20.04' + 'Fn::Sub': '763104351884.dkr.ecr.${AWS::Region}.amazonaws.com/huggingface-pytorch-tgi-inference:2.3.0-tgi2.2.0-gpu-py310-cu121-ubuntu22.04-v2.0' }, ModelDataSource: { S3DataSource: { - S3Uri: {'Fn::Sub': 's3://jumpstart-private-cache-prod-${AWS::Region}/meta-textgeneration/meta-textgeneration-llama-2-13b-f/artifacts/inference-prepack/v1.0.0/' }, + S3Uri: {'Fn::Sub': 's3://jumpstart-private-cache-prod-${AWS::Region}/meta-textgeneration/meta-textgeneration-llama-2-13b-f/artifacts/inference-prepack/v1.1.0/' }, S3DataType: "S3Prefix", CompressionType: "None", ModelAccessConfig: { diff --git a/source/templates/testall/__snapshots__/index.test.js.snap b/source/templates/testall/__snapshots__/index.test.js.snap index db1971e24..248e38596 100644 --- a/source/templates/testall/__snapshots__/index.test.js.snap +++ b/source/templates/testall/__snapshots__/index.test.js.snap @@ -4,6 +4,18 @@ exports[`renders testall template correctly 1`] = ` { "AWSTemplateFormatVersion": "2010-09-09", "Conditions": { + "LogRetentionPeriodIsNotZero": { + "Fn::Not": [ + { + "Fn::Equals": [ + { + "Ref": "LogRetentionPeriod", + }, + 0, + ], + }, + ], + }, "VPCEnabled": { "Fn::Not": [ { @@ -46,6 +58,9 @@ exports[`renders testall template correctly 1`] = ` "CommonModulesLambdaLayer": { "Type": "String", }, + "ContentDesignerOutputBucket": { + "Type": "String", + }, "EsEndpoint": { "Type": "String", }, @@ -58,6 +73,9 @@ exports[`renders testall template correctly 1`] = ` "LexV2BotId": { "Type": "String", }, + "LogRetentionPeriod": { + "Type": "Number", + }, "S3Clean": { "Type": "String", }, @@ -259,6 +277,9 @@ exports[`renders testall template correctly 1`] = ` { "Fn::Sub": "arn:aws:s3:::\${TestAllBucket}*", }, + { + "Fn::Sub": "arn:aws:s3:::\${ContentDesignerOutputBucket}*", + }, ], }, { @@ -338,6 +359,9 @@ exports[`renders testall template correctly 1`] = ` "LEXV2_BOT_ID": { "Ref": "LexV2BotId", }, + "OUTPUT_S3_BUCKET": { + "Ref": "ContentDesignerOutputBucket", + }, "SOLUTION_ID": "SO0189", "SOLUTION_VERSION": "vx.x.x", }, @@ -351,6 +375,11 @@ exports[`renders testall template correctly 1`] = ` "Ref": "CommonModulesLambdaLayer", }, ], + "LoggingConfig": { + "LogGroup": { + "Ref": "TestAllStepLambdaLogGroup", + }, + }, "MemorySize": "1280", "Role": { "Fn::GetAtt": [ @@ -406,6 +435,53 @@ exports[`renders testall template correctly 1`] = ` }, "Type": "AWS::Lambda::Function", }, + "TestAllStepLambdaLogGroup": { + "Metadata": { + "guard": { + "SuppressedRules": [ + "CLOUDWATCH_LOG_GROUP_ENCRYPTED", + "CW_LOGGROUP_RETENTION_PERIOD_CHECK", + ], + }, + }, + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "-", + [ + { + "Fn::Sub": "/aws/lambda/\${AWS::StackName}-TestAllStepLambda", + }, + { + "Fn::Select": [ + "2", + { + "Fn::Split": [ + "/", + { + "Ref": "AWS::StackId", + }, + ], + }, + ], + }, + ], + ], + }, + "RetentionInDays": { + "Fn::If": [ + "LogRetentionPeriodIsNotZero", + { + "Ref": "LogRetentionPeriod", + }, + { + "Ref": "AWS::NoValue", + }, + ], + }, + }, + "Type": "AWS::Logs::LogGroup", + }, "TestAllStepPermission": { "Properties": { "Action": "lambda:InvokeFunction", diff --git a/source/templates/testall/index.js b/source/templates/testall/index.js index f65ef3ae5..4a0051994 100644 --- a/source/templates/testall/index.js +++ b/source/templates/testall/index.js @@ -31,12 +31,14 @@ module.exports = { S3Clean: { Type: 'String' }, LexV2BotId: { Type: 'String' }, LexV2BotAliasId: { Type: 'String' }, + LogRetentionPeriod: { Type: 'Number' }, BootstrapBucket: { Type: 'String' }, BootstrapPrefix: { Type: 'String' }, VarIndex: { Type: 'String' }, EsEndpoint: { Type: 'String' }, EsProxyLambda: { Type: 'String' }, TestAllBucket: { Type: 'String' }, + ContentDesignerOutputBucket: { Type: 'String' }, VPCSubnetIdList: { Type: 'String' }, VPCSecurityGroupIdList: { Type: 'String' }, XraySetting: { Type: 'String' }, @@ -46,5 +48,6 @@ module.exports = { Conditions: { VPCEnabled: { 'Fn::Not': [{ 'Fn::Equals': ['', { Ref: 'VPCSecurityGroupIdList' }] }] }, XRAYEnabled: { 'Fn::Equals': [{ Ref: 'XraySetting' }, 'TRUE'] }, + LogRetentionPeriodIsNotZero: { 'Fn::Not': [{ 'Fn::Equals': [{ Ref: 'LogRetentionPeriod' }, 0] }] } }, }; diff --git a/source/templates/testall/resources.js b/source/templates/testall/resources.js index d9cfdb09d..cce169324 100644 --- a/source/templates/testall/resources.js +++ b/source/templates/testall/resources.js @@ -26,6 +26,31 @@ module.exports = { BuildDate: new Date().toISOString(), }, }, + TestAllStepLambdaLogGroup: { + Type: 'AWS::Logs::LogGroup', + Properties: { + LogGroupName: { + 'Fn::Join': [ + '-', + [ + { 'Fn::Sub': '/aws/lambda/${AWS::StackName}-TestAllStepLambda' }, + { 'Fn::Select': ['2', { 'Fn::Split': ['/', { Ref: 'AWS::StackId' }] }] }, + ], + ], + }, + + RetentionInDays: { + 'Fn::If': [ + 'LogRetentionPeriodIsNotZero', + { Ref: 'LogRetentionPeriod' }, + { Ref: 'AWS::NoValue' }, + ], + }, + }, + Metadata: { + guard: util.cfnGuard('CLOUDWATCH_LOG_GROUP_ENCRYPTED', 'CW_LOGGROUP_RETENTION_PERIOD_CHECK'), + }, + }, TestAllStepLambda: { Type: 'AWS::Lambda::Function', Properties: { @@ -41,10 +66,14 @@ module.exports = { ES_PROXY: { Ref: 'EsProxyLambda' }, LEXV2_BOT_ID: { Ref: 'LexV2BotId' }, LEXV2_BOT_ALIAS_ID: { Ref: 'LexV2BotAliasId' }, - ...util.getCommonEnvironmentVariables() + OUTPUT_S3_BUCKET: { Ref: 'ContentDesignerOutputBucket'}, + ...util.getCommonEnvironmentVariables(), }, }, Handler: 'index.step', + LoggingConfig: { + LogGroup: { Ref: 'TestAllStepLambdaLogGroup' }, + }, MemorySize: '1280', Role: { 'Fn::GetAtt': ['TestAllRole', 'Arn'] }, Runtime: process.env.npm_package_config_lambdaRuntime, @@ -64,7 +93,7 @@ module.exports = { }, Layers: [ { Ref: 'AwsSdkLayerLambdaLayer' }, - { Ref: 'CommonModulesLambdaLayer' } + { Ref: 'CommonModulesLambdaLayer' }, ], Tags: [ { @@ -112,7 +141,10 @@ module.exports = { 's3:DeleteObject', 's3:DeleteObjectVersion', ], - Resource: [{ 'Fn::Sub': 'arn:aws:s3:::${TestAllBucket}*' }], + Resource: [ + { 'Fn::Sub': 'arn:aws:s3:::${TestAllBucket}*' }, + { 'Fn::Sub': 'arn:aws:s3:::${ContentDesignerOutputBucket}*' }, + ], }, { Effect: 'Allow', diff --git a/source/templates/util.js b/source/templates/util.js index ac32ff084..edf29741c 100644 --- a/source/templates/util.js +++ b/source/templates/util.js @@ -263,23 +263,6 @@ exports.lexFullAccess = function () { ], Resource: '*', // these actions cannot be bound to resources other than * }, - { // Lex V1 policies - Effect: 'Allow', - Action: [ - 'lex:GetBuiltinIntent', - 'lex:GetIntents', - 'lex:GetBots', - 'lex:GetSlotTypes', - 'lex:GetBotAliases', - 'lex:StartImport', - 'lex:GetMigration', - 'lex:GetBuiltinSlotTypes', - 'lex:GetBuiltinIntents', - 'lex:GetImport', - 'lex:GetMigrations', - ], - Resource: '*', // these actions cannot be bound to resources other than * - }, { Effect: 'Allow', Action: 'lex:*', @@ -312,23 +295,6 @@ exports.lexFullAccess = function () { { 'Fn::Sub': 'arn:${AWS::Partition}:lex:${AWS::Region}:${AWS::AccountId}:bot/*' }, ], }, - { // Lex V1 policies - Effect: 'Allow', - Action: [ - 'lex:GetBuiltinIntent', - 'lex:GetIntents', - 'lex:GetBots', - 'lex:GetSlotTypes', - 'lex:GetBotAliases', - 'lex:StartImport', - 'lex:GetMigration', - 'lex:GetBuiltinSlotTypes', - 'lex:GetBuiltinIntents', - 'lex:GetImport', - 'lex:GetMigrations', - ], - Resource: '*', // these actions cannot be bound to resources other than * - }, { Effect: 'Allow', Action: 'lex:*', diff --git a/source/website/js/admin.vue b/source/website/js/admin.vue index 04420507a..a83a05240 100644 --- a/source/website/js/admin.vue +++ b/source/website/js/admin.vue @@ -51,6 +51,8 @@ v-app a(href="https://aws.amazon.com/blogs/machine-learning/creating-virtual-guided-navigation-using-a-question-and-answer-bot-with-amazon-lex-and-amazon-alexa/" target="_blank") Guided Navigation using QnABot v-list-item-title a(href="https://aws.amazon.com/blogs/machine-learning/create-a-questionnaire-bot-with-amazon-lex-and-amazon-alexa/" target="_blank") Create a questionnaire using QnABot + v-list-item-title + a(href="https://aws.amazon.com/blogs/machine-learning/delight-your-customers-with-great-conversational-experiences-via-qnabot-a-generative-ai-chatbot/" target="_blank") Delight your customers with great conversational experiences via QnABot, a generative AI chatbot v-app-bar() v-app-bar-nav-icon.text-primary(id="nav-open" @click.stop="drawer = !drawer") v-app-bar-title diff --git a/source/website/js/components/designer/menu-testall.vue b/source/website/js/components/designer/menu-testall.vue index 33629ef76..9c5d2e6c5 100644 --- a/source/website/js/components/designer/menu-testall.vue +++ b/source/website/js/components/designer/menu-testall.vue @@ -171,6 +171,7 @@ export default { locale: this.selectedLocale, token, }); + await new Promise(resolve => setTimeout(resolve, 3000)); await this.refresh(); } catch (e) { this.error = err; diff --git a/source/website/js/components/designer/synckendra.vue b/source/website/js/components/designer/synckendra.vue index 919a406ab..15421aa24 100644 --- a/source/website/js/components/designer/synckendra.vue +++ b/source/website/js/components/designer/synckendra.vue @@ -123,6 +123,7 @@ module.exports = { name: this.filename, filter: '', }); + await new Promise(resolve => setTimeout(resolve, 3000)); await this.refresh(); } catch (e) { // never enters this block diff --git a/source/website/js/components/export.vue b/source/website/js/components/export.vue index 5bbd12cc2..971b27a21 100644 --- a/source/website/js/components/export.vue +++ b/source/website/js/components/export.vue @@ -113,6 +113,7 @@ module.exports = { name: this.filename, filter: this.filter, }); + await new Promise(resolve => setTimeout(resolve, 3000)); await this.refresh(); } catch (e) { this.error = e; diff --git a/source/website/js/components/genesys/index.vue b/source/website/js/components/genesys/index.vue index fb4f87d8c..22732450b 100644 --- a/source/website/js/components/genesys/index.vue +++ b/source/website/js/components/genesys/index.vue @@ -47,22 +47,22 @@ v-container v-card(flat) v-card-title(class="text-center") {{ steps[2].title }} v-card-text(v-html="steps[2].text") - v-card-actions - v-btn( - :id="steps[2].buttons[0].id" - :loading="steps[2].buttons[0].loading" - @click="copy(steps[2].buttons[0])" - ) {{ steps[2].buttons[0].text }} - template(#item.4) - v-card(flat) - v-card-title(class="text-center") {{ steps[3].title }} - v-card-text(v-html="steps[3].text") img( - v-if="steps[3].image" - :src="steps[3].image" + v-if="steps[2].image" + :src="steps[2].image" style="max-width:75%;display:block;margin:auto;" contain ) + template(#item.4) + v-card(flat) + v-card-title(class="text-center") {{ steps[3].title }} + v-card-text(v-html="steps[3].text") + v-card-actions + v-btn( + :id="steps[3].buttons[0].id" + :loading="steps[3].buttons[0].loading" + @click="copy(steps[3].buttons[0])" + ) {{ steps[3].buttons[0].text }} template(#item.5) v-card(flat) v-card-title(class="text-center") {{ steps[4].title }} diff --git a/source/website/js/components/settings.vue b/source/website/js/components/settings.vue index 7a76f9e4c..6b041423c 100644 --- a/source/website/js/components/settings.vue +++ b/source/website/js/components/settings.vue @@ -269,7 +269,7 @@ module.exports = { this.alertTitle = 'Error'; } }); - fileReader.readAsBinaryString(files[0]); + fileReader.readAsText(files[0]); }, downloadBlobAsFile: (function closure_shell() { const a = document.createElement('a'); diff --git a/source/website/js/lib/store/api/actions/settings.js b/source/website/js/lib/store/api/actions/settings.js index 3c680dd0e..2374865d5 100644 --- a/source/website/js/lib/store/api/actions/settings.js +++ b/source/website/js/lib/store/api/actions/settings.js @@ -12,6 +12,7 @@ ******************************************************************************************************************** */ const _ = require('lodash'); const { SSMClient, GetParameterCommand, GetParametersCommand, PutParameterCommand } = require('@aws-sdk/client-ssm'); +const { LambdaClient, InvokeCommand } = require('@aws-sdk/client-lambda'); const util = require('../../../../capability/util'); const chatbotTestingIndex = 0; @@ -489,6 +490,22 @@ const settingsMap = { }, ], }, + bedrockGuardrails: { + id: 'text_generation_guardrail_subgroup', + label: 'Guardrail for Amazon Bedrock and Knowledge Base Integrations', + collapsed: true, + members: [ + + { + id: 'BEDROCK_GUARDRAIL_IDENTIFIER', + hint: 'Enter a pre-configurated Bedrock Guardrail identifier (e.g. 4ojm24q0yada) that you want to be applied to the requests made to the LLM models configured in CloudFormation parameters LLMBedrockModelId and BedrockKnowledgeBaseModel. If you don\'t provide a value, no guardrail is applied to the LLM invocation. If you provide a identifier, you must also provide a BEDROCK_GUARDRAIL_VERSION', + }, + { + id: 'BEDROCK_GUARDRAIL_VERSION', + hint: 'Enter the version (e.g. 1 or DRAFT) of the guardrail specifed in BEDROCK_GUARDRAIL_IDENTIFIER', + }, + ], + }, kendraSettings: { id: 'amazon_kendra_subgroup', label: 'Retrieval Augmented Generation (RAG) with Amazon Kendra', @@ -544,6 +561,11 @@ const settingsMap = { label: 'Retrieval Augmented Generation (RAG) with Amazon Bedrock Knowledge Base', collapsed: true, members: [ + { + id: 'KNOWLEDGE_BASE_PROMPT_TEMPLATE', + type: 'textarea', + hint: 'The template used to construct a prompt that is sent to the model for response generation. To opt out of sending a prompt to the Knowledge Base model, simply leave this field empty. For more information, see Bedrock Knowledge base (https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base.html)', + }, { id: 'KNOWLEDGE_BASE_PREFIX_MESSAGE', hint: 'Message used to prefix a Knowledge Base generated answer', @@ -563,6 +585,25 @@ const settingsMap = { type: 'number', hint: 'Determines length of time in seconds for the validity of signed S3 Urls for Bedrock Knowledge Base answers', }, + { + id: 'KNOWLEDGE_BASE_MODEL_PARAMS', + hint: 'Customize the knowledge base model by providing inference parameters (e.g. anthropic model parameters can be customized as `{"temperature":0.1}` or `{"temperature":0.3, "maxTokens": 262, "topP":0.9, "top_k": 240 }`). For more information, please refer to Inference parameters (https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html)', + }, + { + id: 'KNOWLEDGE_BASE_MAX_NUMBER_OF_RETRIEVED_RESULTS', + type: 'number', + hint: 'Sets maximum number of retrieved result where each result corresponds to a source chunk. When querying a knowledge base, Amazon Bedrock returns up to five results by default. For more information, please refer to Maximum number of retrieved results (https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html)', + }, + { + id: 'KNOWLEDGE_BASE_SEARCH_TYPE', + type: 'enum', + enums: ['DEFAULT', 'HYBRID', 'SEMANTIC'], + hint: 'Select the search type which defines how data sources in the knowledge base are queried. If using an Amazon OpenSearch Serverless vector store that contains a filterable text field, you can specify whether to query the knowledge base with a HYBRID search using both vector embeddings and raw text, or SEMANTIC search using only vector embeddings. For other vector store configurations, only SEMANTIC search is available. For more information, please refer to Search type (https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html)', + }, + { + id: 'KNOWLEDGE_BASE_METADATA_FILTERS', + hint: 'Specifies the filters to use on the metadata in the knowledge base data sources before returning results. (e.g filters can be customized as`{"filter1": { "key": "string", "value": "string" }, "filter2": { "key": "string", "value": number }}`). For more information, please refer to Metadata and filtering (https://docs.aws.amazon.com/bedrock/latest/userguide/kb-test-config.html)', + }, ], }, }, @@ -597,6 +638,37 @@ async function saveParameters(ssm, params) { } } +async function sendAnonymizedData(params, settings){ + const map = { event: 'UPDATE_SETTINGS' }; + map.BEDROCK_GUARDRAIL_ENABLE = settings.BEDROCK_GUARDRAIL_IDENTIFIER && settings.BEDROCK_GUARDRAIL_VERSION ? 'true' : 'false'; + map.ENABLE_MULTI_LANGUAGE_SUPPORT = settings.ENABLE_MULTI_LANGUAGE_SUPPORT || 'false'; + map.LLM_GENERATE_QUERY_ENABLE = settings.LLM_GENERATE_QUERY_ENABLE || 'true'; + map.KNOWLEDGE_BASE_SEARCH_TYPE = settings.KNOWLEDGE_BASE_SEARCH_TYPE || 'DEFAULT'; + map.PII_REJECTION_ENABLED = settings.PII_REJECTION_ENABLED || 'false'; + map.EMBEDDINGS_ENABLE = settings.EMBEDDINGS_ENABLE || 'true'; + map.LLM_QA_ENABLE = settings.LLM_QA_ENABLE || 'true'; + + + const payload = Buffer.from(JSON.stringify(map)); + const client = new LambdaClient({ + customUserAgent: util.getUserAgentString(params.version, 'C050'), + region: params.region, + credentials: params.credentials + }); + + const input = { + FunctionName: params.solutionHelper, + InvocationType: "RequestResponse", + Payload: payload, + }; + const command = new InvokeCommand(input); + const response = await client.send(command); + if (response.FunctionError) { + throw new Error('Solution Helper Function Error Occurred'); + } + return response; +} + module.exports = { async listSettings(context) { const credentials = context.rootState.user.credentials; @@ -638,10 +710,27 @@ module.exports = { async updateSettings(context, settings) { const credentials = context.rootState.user.credentials; const customParams = context.rootState.info.CustomQnABotSettings; + const region = context.rootState.info.region; + const version = context.rootState.info.Version; + const solutionHelper = context.rootState.info.SolutionHelper; const ssm = new SSMClient({ - customUserAgent: util.getUserAgentString(context.rootState.info.Version, 'C022'), - region: context.rootState.info.region, credentials + customUserAgent: util.getUserAgentString(version, 'C022'), + region, + credentials }); + + try { + const params = { + region, + credentials, + version, + solutionHelper + }; + await sendAnonymizedData(params, settings); + } catch (e) { + console.log(`Error in sending anonymized data: ${e.message}`); + } + // Note type is not required in params if the parameter exists. Some customers require this parameter // to be a SecureString and set this type post deploy of QnABot. Removing type supports // this setting.