From c96a70ccb309a2a7dbf34a98494f87c3ea18a4d2 Mon Sep 17 00:00:00 2001 From: David Souther Date: Thu, 18 Jan 2024 13:48:08 -0500 Subject: [PATCH 01/36] Revert "Revert "Tools: Snippet extractor and validator"" (#5967) * Revert "Revert "Tools: Snippet extractor and validator"" * Restore sdk and service yamls to where Zexii expects them --- .doc_gen/metadata/curated/sources.yaml | 4 - .github/workflows/validate.yml | 2 +- .gitignore | 2 + .tools/.gitignore | 1 + .tools/validation/doc_gen.py | 76 ++++- .tools/validation/file_utils.py | 11 +- .tools/validation/metadata.py | 265 ++++++++++-------- .tools/validation/metadata_errors.py | 70 ++--- .tools/validation/metadata_test.py | 111 ++++---- .tools/validation/metadata_validator.py | 57 ++-- .tools/validation/project_validator.py | 145 +++------- .tools/validation/project_validator_test.py | 75 +---- .../schema/curated_sources_schema.yaml | 8 - .tools/validation/sdks.py | 101 +++---- .tools/validation/sdks_test.py | 12 +- .tools/validation/services.py | 67 +++-- .tools/validation/services_test.py | 12 +- .tools/validation/snippets.py | 220 +++++++++++++++ .tools/validation/snippets_test.py | 67 +++++ .tools/validation/validate.py | 38 +-- .tools/validation/validate_test.py | 0 .tools/validation/validator_config.py | 19 +- 22 files changed, 794 insertions(+), 569 deletions(-) delete mode 100644 .doc_gen/metadata/curated/sources.yaml delete mode 100644 .tools/validation/schema/curated_sources_schema.yaml create mode 100644 .tools/validation/snippets_test.py create mode 100644 .tools/validation/validate_test.py diff --git a/.doc_gen/metadata/curated/sources.yaml b/.doc_gen/metadata/curated/sources.yaml deleted file mode 100644 index 04ace573341..00000000000 --- a/.doc_gen/metadata/curated/sources.yaml +++ /dev/null @@ -1,4 +0,0 @@ -placeholder-examples: - name: Placeholder curated examples - description: Placeholder source description until we add actual curated examples. - url: https://github.com/aws/not-a-real-repo diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 5a84fde3573..89f1cb34620 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -32,7 +32,7 @@ jobs: python3 -m pip install -r .tools/base_requirements.txt - name: Lint metadata files run: >- - yamllint --format standard -c .tools/validation/.yamllint.yaml .doc_gen/metadata .doc_gen/metadata/curated + yamllint --format standard -c .tools/validation/.yamllint.yaml .doc_gen/metadata - name: Validate metadata and repo run: >- python3 .tools/validation/validate.py --doc-gen .doc_gen diff --git a/.gitignore b/.gitignore index d2f486eb147..f56bd3d387c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,7 @@ xcuserdata # Ignore rust_dev_preview as it's no longer part of the project rust_dev_preview +# .vectors are created by the Ailly RAG process .vectors +# .snippets are created temporarily as build artifacts .snippets diff --git a/.tools/.gitignore b/.tools/.gitignore index 9f7550b1ef0..37e05af6755 100644 --- a/.tools/.gitignore +++ b/.tools/.gitignore @@ -1,2 +1,3 @@ __pycache__ .venv +ailly diff --git a/.tools/validation/doc_gen.py b/.tools/validation/doc_gen.py index 851d333dd59..8cf6750f2fe 100644 --- a/.tools/validation/doc_gen.py +++ b/.tools/validation/doc_gen.py @@ -7,35 +7,85 @@ from dataclasses import dataclass, field from pathlib import Path +# from os import glob + +from metadata import Example, parse as parse_examples from metadata_errors import MetadataErrors +from metadata_validator import validate_metadata +from project_validator import check_files, verify_sample_files from sdks import Sdk, parse as parse_sdks from services import Service, parse as parse_services -from snippets import Snippet +from snippets import Snippet, collect_snippets, validate_snippets @dataclass class DocGen: + root: Path + errors: MetadataErrors sdks: dict[str, Sdk] = field(default_factory=dict) services: dict[str, Service] = field(default_factory=dict) snippets: dict[str, Snippet] = field(default_factory=dict) + snippet_files: set[str] = field(default_factory=set) + examples: list[Example] = field(default_factory=list) + cross_blocks: set[str] = field(default_factory=set) + + def collect_snippets(self, snippets_root: Path | None): + if snippets_root is None: + snippets_root = self.root.parent.parent + snippets, errs = collect_snippets(snippets_root) + self.snippets = snippets + self.errors.extend(errs) - @staticmethod - def from_root(root: Path) -> Self | MetadataErrors: + @classmethod + def from_root(cls, root: Path) -> Self: errors = MetadataErrors() - with open(root / "sdks.yaml", encoding="utf-8") as file: + metadata = root / ".doc_gen/metadata" + + with open(metadata / "sdks.yaml", encoding="utf-8") as file: meta = yaml.safe_load(file) - parsed = parse_sdks("sdks.yaml", meta) - sdks = errors.maybe_extend(parsed) + sdks, errs = parse_sdks("sdks.yaml", meta) + errors.extend(errs) - with open(root / "services.yaml", encoding="utf-8") as file: + with open(metadata / "services.yaml", encoding="utf-8") as file: meta = yaml.safe_load(file) - parsed = parse_services("services.yaml", meta) - services = errors.maybe_extend(parsed) + services, service_errors = parse_services("services.yaml", meta) + errors.extend(service_errors) + + cross = set( + [path.name for path in (metadata.parent / "cross-content").glob("*.xml")] + ) + + doc_gen = cls( + root=root, + sdks=sdks, + services=services, + errors=errors, + cross_blocks=cross, + ) - snippets = {} + for path in metadata.glob("cross_metadata.yaml"): + with open(path) as file: + ex, errs = parse_examples( + path.name, + yaml.safe_load(file), + doc_gen.sdks, + doc_gen.services, + doc_gen.cross_blocks, + ) + doc_gen.examples.extend(ex) + errors.extend(errs) - if len(errors) > 0: - return errors + return doc_gen - return DocGen(sdks=sdks, services=services, snippets=snippets) + def validate(self, check_spdx: bool): + check_files(self.root, self.errors, check_spdx) + verify_sample_files(self.root, self.errors) + validate_metadata(self.root, self.errors) + validate_snippets( + self.examples, + self.snippets, + self.snippet_files, + self.errors, + self.root, + ) diff --git a/.tools/validation/file_utils.py b/.tools/validation/file_utils.py index bba135e5ed7..65d4fad26b9 100644 --- a/.tools/validation/file_utils.py +++ b/.tools/validation/file_utils.py @@ -3,6 +3,7 @@ import os +from shutil import rmtree from pathlib import Path from collections.abc import Generator, Callable @@ -33,8 +34,8 @@ def walk_with_gitignore( with open(root / ".gitignore", "r", encoding="utf-8") as gitignore: specs = [*specs, GitIgnoreSpec.from_lines(gitignore.readlines())] for entry in os.scandir(root): - if not match_path_to_specs(entry.path, specs): - path = Path(entry.path) + path = Path(entry.path) + if not match_path_to_specs(path, specs): if entry.is_dir(): yield from walk_with_gitignore(path, specs) else: @@ -52,3 +53,9 @@ def get_files( for path in walk_with_gitignore(root): if not skip(path): yield path + + +def clear(folder: Path): + if folder.exists(): + rmtree(folder, True) + folder.mkdir() diff --git a/.tools/validation/metadata.py b/.tools/validation/metadata.py index 28d7116cb8e..bc775591a70 100755 --- a/.tools/validation/metadata.py +++ b/.tools/validation/metadata.py @@ -3,12 +3,14 @@ # SPDX-License-Identifier: Apache-2.0 from dataclasses import dataclass, field -from typing import Optional, Self +from typing import Any, Optional, Self from os.path import splitext import metadata_errors -from doc_gen import DocGen + from metadata_errors import MetadataErrors, MetadataParseError, DuplicateItemException from metadata_validator import StringExtension +from services import Service +from sdks import Sdk @dataclass @@ -16,17 +18,19 @@ class Url: title: str url: Optional[str] - @staticmethod - def from_yaml(yaml: any) -> None | Self | MetadataParseError: + @classmethod + def from_yaml( + cls, yaml: None | dict[str, str | None] + ) -> None | Self | MetadataParseError: if yaml is None: return None - title = yaml.get("title") - url = yaml.get("url") + title = yaml.get("title", "") + url = yaml.get("url", "") if title is None: - return metadata_errors.URLMissingTitle(url=url) + return metadata_errors.URLMissingTitle(url=str(url)) - return Url(title, url) + return cls(title, url) @dataclass @@ -37,12 +41,12 @@ class Excerpt: # A path within the repo to extract the entire file as a snippet. snippet_files: list[str] = field(default_factory=list) - @staticmethod - def from_yaml(yaml: any) -> Self: + @classmethod + def from_yaml(cls, yaml: Any) -> Self: description = yaml.get("description") snippet_files = [str(file) for file in yaml.get("snippet_files", [])] snippet_tags = [str(tag) for tag in yaml.get("snippet_tags", [])] - return Excerpt(description, snippet_tags, snippet_files) + return cls(description, snippet_tags, snippet_files) @dataclass @@ -51,17 +55,23 @@ class Version: # Additional ZonBook XML to include in the tab for this sample. block_content: Optional[str] = field(default=None) # The specific code samples to include in the example. - excerpts: Optional[list[Excerpt]] = field(default=None) + excerpts: list[Excerpt] = field(default_factory=list) # Link to the source code for this example. TODO rename. github: Optional[str] = field(default=None) - add_services: dict[str, str] = field(default_factory=dict) + add_services: dict[str, list[str]] = field(default_factory=dict) # Deprecated. Replace with guide_topic list. sdkguide: Optional[str] = field(default=None) # Link to additional topic places. TODO: Overwritten by aws-doc-sdk-example when merging. more_info: list[Url] = field(default_factory=list) - @staticmethod - def from_yaml(yaml: dict[str, any], doc_gen: DocGen) -> Self | MetadataParseError: + @classmethod + def from_yaml( + cls, + yaml: dict[str, Any], + services: dict[str, Service], + cross_content_blocks: set[str], + is_action: bool, + ) -> tuple[Self, MetadataErrors]: errors = MetadataErrors() sdk_version = int(yaml.get("sdk_version", 0)) @@ -85,18 +95,15 @@ def from_yaml(yaml: dict[str, any], doc_gen: DocGen) -> Self | MetadataParseErro ) ) - excerpts = yaml.get("excerpts", []) - if len(excerpts) == 0: - excerpts = None - else: - excerpts = [Excerpt.from_yaml(excerpt) for excerpt in excerpts] + excerpts = [Excerpt.from_yaml(excerpt) for excerpt in yaml.get("excerpts", [])] - if excerpts is None and block_content is None: + if len(excerpts) == 0 and block_content is None: errors.append(metadata_errors.MissingBlockContentAndExcerpt()) - if excerpts is not None and block_content is not None: + excerpts = [] + if len(excerpts) > 0 and block_content is not None: errors.append(metadata_errors.BlockContentAndExcerptConflict()) - more_info = [] + more_info: list[Url] = [] for url in yaml.get("more_info", []): url = Url.from_yaml(url) if isinstance(url, Url): @@ -104,21 +111,24 @@ def from_yaml(yaml: dict[str, any], doc_gen: DocGen) -> Self | MetadataParseErro elif url is not None: errors.append(url) - add_services = parse_services(yaml.get("add_services", {}), errors, doc_gen) - if add_services and block_content is not None: + add_services = parse_services(yaml.get("add_services", {}), errors, services) + if add_services and is_action: errors.append(metadata_errors.APIExampleCannotAddService()) - if len(errors) > 0: - return errors - - return Version( - sdk_version, - block_content, - excerpts, - github, - add_services, - sdkguide, - more_info, + if block_content is not None and block_content not in cross_content_blocks: + errors.append(metadata_errors.MissingCrossContent(block=block_content)) + + return ( + cls( + sdk_version, + block_content, + excerpts, + github, + add_services, + sdkguide, + more_info, + ), + errors, ) @@ -127,31 +137,37 @@ class Language: name: str versions: list[Version] - @staticmethod - def from_yaml(name: str, yaml: any, doc_gen: DocGen) -> Self | MetadataErrors: + @classmethod + def from_yaml( + cls, + name: str, + yaml: Any, + sdks: dict[str, Sdk], + services: dict[str, Service], + blocks: set[str], + is_action: bool, + ) -> tuple[Self, MetadataErrors]: errors = MetadataErrors() - if name not in doc_gen.sdks: + if name not in sdks: errors.append(metadata_errors.UnknownLanguage(language=name)) - yaml_versions = yaml.get("versions") + yaml_versions: list[dict[str, Any]] | None = yaml.get("versions") if yaml_versions is None or len(yaml_versions) == 0: errors.append(metadata_errors.MissingField(field="versions")) yaml_versions = [] versions: list[Version] = [] for version in yaml_versions: - version = Version.from_yaml(version, doc_gen) - if isinstance(version, Version): - versions.append(version) - else: - for error in version: - error.language = name - errors.append(error) + version, version_errors = Version.from_yaml( + version, services, blocks, is_action + ) + errors.extend(version_errors) + versions.append(version) - if len(errors) > 0: - return errors + for error in errors: + error.language = name - return Language(name, versions) + return cls(name, versions), errors @dataclass @@ -172,82 +188,92 @@ class Example: # TODO document service_main and services. Not to be used by tributaries. Part of Cross Service. # List of services used by the examples. Lines up with those in services.yaml. service_main: Optional[str] = field(default=None) - services: dict[str, dict[str, str]] = field(default_factory=dict) + services: dict[str, list[str]] = field(default_factory=dict) synopsis_list: list[str] = field(default_factory=list) source_key: Optional[str] = field(default=None) - @staticmethod - def from_yaml(yaml: any, doc_gen: DocGen) -> Self | MetadataErrors: + @classmethod + def from_yaml( + cls, + yaml: Any, + sdks: dict[str, Sdk], + services: dict[str, Service], + blocks: set[str], + ) -> tuple[Self, MetadataErrors]: errors = MetadataErrors() title = get_with_valid_entities("title", yaml, errors) title_abbrev = get_with_valid_entities("title_abbrev", yaml, errors) synopsis = get_with_valid_entities("synopsis", yaml, errors, opt=True) - category = yaml.get("category") + category = yaml.get("category", "") source_key = yaml.get("source_key") - services = parse_services(yaml.get("services", {}), errors, doc_gen) + parsed_services = parse_services(yaml.get("services", {}), errors, services) synopsis_list = [str(syn) for syn in yaml.get("synopsis_list", [])] - guide_topic = Url.from_yaml(yaml.get("guide_topic")) if isinstance(guide_topic, MetadataParseError): errors.append(guide_topic) guide_topic = None - yaml_languages = yaml.get("languages") - languages = [] - if yaml_languages is None: - errors.append(metadata_errors.MissingField(field="languages")) - else: - for name in yaml_languages: - language = Language.from_yaml(name, yaml_languages[name], doc_gen) - if isinstance(language, Language): - languages.append(language) - else: - errors.extend(language) - service_main = yaml.get("service_main", None) - if service_main is not None and service_main not in doc_gen.services: + if service_main is not None and service_main not in services: try: errors.append(metadata_errors.UnknownService(service=service_main)) except DuplicateItemException: pass - if len(errors) > 0: - return errors - - return Example( - id="", - file="", - title=title, - title_abbrev=title_abbrev, - category=category, - guide_topic=guide_topic, - languages=languages, - service_main=service_main, - services=services, - synopsis=synopsis, - synopsis_list=synopsis_list, - source_key=source_key, + if category == "": + category = "Api" if len(parsed_services) == 1 else "Cross" + + is_action = category == "Api" + + yaml_languages = yaml.get("languages") + languages: dict[str, Language] = {} + if yaml_languages is None: + errors.append(metadata_errors.MissingField(field="languages")) + else: + for name in yaml_languages: + language, errs = Language.from_yaml( + name, yaml_languages[name], sdks, services, blocks, is_action + ) + languages[language.name] = language + errors.extend(errs) + + return ( + cls( + id="", + file="", + title=title, + title_abbrev=title_abbrev, + category=category, + guide_topic=guide_topic, + languages=languages, + service_main=service_main, + services=parsed_services, + synopsis=synopsis, + synopsis_list=synopsis_list, + source_key=source_key, + ), + errors, ) def parse_services( - yaml: any, errors: MetadataErrors, doc_gen: DocGen -) -> dict[str, dict[str, str]]: + yaml: Any, errors: MetadataErrors, known_services: dict[str, Service] +) -> dict[str, list[str]]: if yaml is None: return {} - services = {} + services: dict[str, list[str]] = {} for name in yaml: - if name not in doc_gen.services: + if name not in known_services: errors.append(metadata_errors.UnknownService(service=name)) else: - service = yaml.get(name, {}) + service: dict[str, None] | None = yaml.get(name) # While .get replaces missing with {}, `sqs: ` in yaml parses a literal `None` if service is None: service = {} # Make a copy of the dict - services[name] = dict(service) + services[name] = [*service.keys()] return services @@ -256,59 +282,59 @@ def parse_services( def get_with_valid_entities( name: str, d: dict[str, str], errors: MetadataErrors, opt: bool = False -) -> Optional[str]: +) -> str: field = d.get(name) if field is None: if not opt: errors.append(metadata_errors.MissingField(field=name)) - return None + return "" checker = StringExtension() if not checker.is_valid(field): errors.append( metadata_errors.AwsNotEntity( - field_name=name, field_value=field, check_err=checker.get_name() + field=name, value=field, check_err=checker.get_name() ) ) - return None + return "" return field -def idFormat(id: str, doc_gen: DocGen) -> bool: +def idFormat(id: str, services: dict[str, Service]) -> bool: [service, *rest] = id.split("_") if len(rest) == 0: return False - return service in doc_gen.services or service == "cross" + return service in services or service == "cross" def parse( - file: str, yaml: dict[str, any], doc_gen: DocGen -) -> list[Example] | MetadataErrors: + file: str, + yaml: dict[str, Any], + sdks: dict[str, Sdk], + services: dict[str, Service], + blocks: set[str], +) -> tuple[list[Example], MetadataErrors]: examples: list[Example] = [] errors = MetadataErrors() for id in yaml: - if not idFormat(id, doc_gen): + if not idFormat(id, services): errors.append(metadata_errors.NameFormat(file=file, id=id)) - example = Example.from_yaml(yaml[id], doc_gen) - if isinstance(example, Example): - example.file = file - example.id = id - examples.append(example) - else: - for error in example: - error.file = file - error.id = id - errors.append(error) + example, example_errors = Example.from_yaml(yaml[id], sdks, services, blocks) + for error in example_errors: + error.file = file + error.id = id + errors.extend(example_errors) + example.file = file + example.id = id + examples.append(example) - return examples if len(errors) == 0 else errors + return examples, errors -if __name__ == "__main__": +def main(): import yaml from pathlib import Path - doc_gen = DocGen() - path = ( Path(__file__).parent.parent.parent / ".doc_gen" @@ -317,5 +343,12 @@ def parse( ) with open(path) as file: meta = yaml.safe_load(file) - examples = parse(path.name, meta, doc_gen) - print(f"{examples!r}") + (examples, errors) = parse(path.name, meta, {}, {}, set()) + if len(errors) > 0: + print(f"{errors}") + else: + print(f"{examples!r}") + + +if __name__ == "__main__": + main() diff --git a/.tools/validation/metadata_errors.py b/.tools/validation/metadata_errors.py index e7c5999e130..fb63ac8393f 100644 --- a/.tools/validation/metadata_errors.py +++ b/.tools/validation/metadata_errors.py @@ -3,19 +3,20 @@ import re from dataclasses import dataclass -from typing import Optional, Iterable, TypeVar, Self +from typing import Optional, Iterator, Iterable, TypeVar, Self @dataclass class MetadataError: file: Optional[str] = None + id: Optional[str] = None def prefix(self): - prefix = f"In {self.file}, " + prefix = f"In {self.file} at {self.id}," return prefix - def message(self): - pass + def message(self) -> str: + return "" def __str__(self): return f"{self.prefix()} {self.message()}" @@ -28,28 +29,17 @@ class MetadataParseError(MetadataError): sdk_version: Optional[int] = None def prefix(self): - prefix = super().prefix() + f"example {self.id}" + prefix = super().prefix() + f" example {self.id}" if self.language: - prefix += f": {self.language}" + prefix += f" {self.language}" if self.sdk_version: - prefix += f": {self.sdk_version}" + prefix += f":{self.sdk_version}" return prefix - def message(self): - pass - def __str__(self): return f"{self.prefix()} {self.message()}" -@dataclass -class LanguageError(MetadataParseError): - language: str = "" - - def prefix(self): - return super().prefix() + f": {self.language}" - - K = TypeVar("K") @@ -59,14 +49,15 @@ def __init__(self, item: MetadataParseError): class DuplicateItemException(Exception): - def __init__(self, item: MetadataParseError): + def __init__(self, item: MetadataError): super().__init__(self, f"Already have item {item!r} in ExampleErrors") class MetadataErrors: """MyPy isn't catching list[Foo].append(list[Foo])""" - def __init__(self): + def __init__(self, no_duplicates: bool = False): + self.no_duplicates = no_duplicates self._errors: list[MetadataError] = [] def append(self, item: MetadataError): @@ -85,7 +76,7 @@ def extend(self, errors: Iterable[MetadataError]): def maybe_extend(self, maybe_errors: K | Self) -> K | None: if isinstance(maybe_errors, MetadataErrors): - self.extend(maybe_errors) + self.extend(maybe_errors._errors) return None return maybe_errors @@ -98,11 +89,14 @@ def __setitem__(self, key: int, value: MetadataError): def __len__(self) -> int: return len(self._errors) + def __iter__(self) -> Iterator[MetadataError]: + return self._errors.__iter__() + def __repr__(self) -> str: return repr(self._errors) def __str__(self) -> str: - errs = "\n".join([f"\t{err!r}" for err in self]) + errs = "\n".join([f"\t{err}" for err in self._errors]) return f"ExampleErrors with {len(self)} errors:\n{errs}" @@ -124,6 +118,14 @@ def message(self): return "name does not match the required format of 'svc_Operation', 'svc_Operation_Specialization', or 'cross_Title'" +@dataclass +class MissingCrossContent(MetadataParseError): + block: str = "" + + def message(self): + return f"missing cross content block {self.block}" + + @dataclass class FieldError(MetadataParseError): field: str = "" @@ -156,10 +158,18 @@ def message(self): return "does not contain any languages." +@dataclass +class LanguageError(MetadataParseError): + def message(self) -> str: + return "LanguageError?" + + @dataclass class UnknownLanguage(LanguageError): def message(self): - return f"contains {self.language} as a language, which is not valid." + return ( + f"contains {self.language} as a language, which is not listed in sdks.yaml." + ) @dataclass @@ -184,16 +194,14 @@ def message(self): @dataclass class SdkVersionError(LanguageError): - sdk_version: str = "" - - def prefix(self): - return super().prefix() + f": {self.sdk_version}" + def message(self) -> str: + return "SdkVersionError" @dataclass class InvalidSdkVersion(SdkVersionError): def message(self): - return "lists version {self.sdk_version} which is not listed in sdks.yaml." + return "lists version which is not listed in sdks.yaml." @dataclass @@ -209,9 +217,7 @@ class InvalidSdkGuideStart(SdkVersionError): guide: str = "" def message(self): - return ( - f"contains an sdkguide link of '{self.guide}'. Use a relative link instead and let the tool insert a 'type=documentation' attribute in the link on your behalf.", - ) + return f"contains an sdkguide link of '{self.guide}'. Use a relative link instead and let the tool insert a 'type=documentation' attribute in the link on your behalf." @dataclass @@ -256,7 +262,7 @@ def message(self): @dataclass class URLMissingTitle(SdkVersionError): - url: str = str + url: str = "" def message(self): return f"URL {self.url} is missing a title" diff --git a/.tools/validation/metadata_test.py b/.tools/validation/metadata_test.py index 41b326b8454..f8169ee5018 100644 --- a/.tools/validation/metadata_test.py +++ b/.tools/validation/metadata_test.py @@ -10,35 +10,38 @@ from pathlib import Path import metadata_errors -from metadata import parse, Example, Url, Language, Version, Excerpt, DocGen +from metadata import parse, Example, Url, Language, Version, Excerpt +from doc_gen import DocGen +from sdks import Sdk from services import Service -def load(path: Path, doc_gen: DocGen) -> list[Example] | metadata_errors.MetadataErrors: +def load( + path: Path, doc_gen: DocGen +) -> tuple[list[Example], metadata_errors.MetadataErrors]: root = Path(__file__).parent filename = root / "test_resources" / path with open(filename) as file: meta = yaml.safe_load(file) - return parse(filename.name, meta, doc_gen) + return parse(filename.name, meta, doc_gen.sdks, doc_gen.services) -DOC_GEN = DocGen( - services={ - "ses": Service(long="&SESlong;", short="&SES;", sort="ses", version=1), - "sns": Service(long="&SNSlong;", short="&SNS;", sort="sns", version=1), - "sqs": Service(long="&SQSlong;", short="&SQS;", sort="sqs", version=1), - "s3": Service(long="&S3long;", short="&S3;", sort="s3", version=1), - "autogluon": Service( - long="AutoGluon Test", short="AG Test", sort="autogluon", version=1 - ), - }, - sdks={ - "C++": Language(name="C++", versions=[]), - "Java": Language(name="Java", versions=[]), - "JavaScript": Language(name="JavaScript", versions=[]), - "PHP": Language(name="PHP", versions=[]), - }, -) +SERVICES = { + "ses": Service(long="&SESlong;", short="&SES;", sort="ses", version=1), + "sns": Service(long="&SNSlong;", short="&SNS;", sort="sns", version=1), + "sqs": Service(long="&SQSlong;", short="&SQS;", sort="sqs", version=1), + "s3": Service(long="&S3long;", short="&S3;", sort="s3", version=1), + "autogluon": Service( + long="AutoGluon Test", short="AG Test", sort="autogluon", version=1 + ), +} +SDKS = { + "C++": Sdk(name="C++", versions=[], guide="", property=""), + "Java": Sdk(name="Java", versions=[], guide="", property=""), + "JavaScript": Sdk(name="JavaScript", versions=[], guide="", property=""), + "PHP": Sdk(name="PHP", versions=[], guide="", property=""), +} +DOC_GEN = DocGen(services=SERVICES, sdks=SDKS) GOOD_SINGLE_CPP = """ sns_DeleteTopic: @@ -67,7 +70,8 @@ def load(path: Path, doc_gen: DocGen) -> list[Example] | metadata_errors.Metadat def test_parse(): meta = yaml.safe_load(GOOD_SINGLE_CPP) - parsed = parse("test_cpp.yaml", meta, DOC_GEN) + parsed, errors = parse("test_cpp.yaml", meta, SDKS, SERVICES) + assert len(errors) == 0 assert parsed == [ Example( file="test_cpp.yaml", @@ -76,12 +80,12 @@ def test_parse(): title_abbrev="Deleting a topic", synopsis="Shows how to delete an &SNS; topic.", services={ - "sns": {"Operation1": None, "Operation2": None}, - "ses": {"Operation1": None, "Operation2": None}, - "sqs": {}, + "sns": ["Operation1", "Operation2"], + "ses": ["Operation1", "Operation2"], + "sqs": [], }, - languages=[ - Language( + languages={ + "C++": Language( name="C++", versions=[ Version( @@ -97,7 +101,7 @@ def test_parse(): ) ], ) - ], + }, ) ] @@ -118,17 +122,18 @@ def test_parse(): def test_parse_cross(): meta = yaml.safe_load(CROSS_META) - actual = parse("cross.yaml", meta, DOC_GEN) + actual, errors = parse("cross.yaml", meta, SDKS, SERVICES) + assert len(errors) == 0 assert actual == [ Example( file="cross.yaml", id="cross_DeleteTopic", title="Delete Topic", title_abbrev="delete topic", - synopsis=None, - services={"sns": {}}, - languages=[ - Language( + synopsis="", + services={"sns": []}, + languages={ + "Java": Language( name="Java", versions=[ Version( @@ -136,7 +141,7 @@ def test_parse_cross(): ) ], ) - ], + }, ) ] @@ -159,7 +164,8 @@ def test_parse_cross(): def test_parse_curated(): meta = yaml.safe_load(CURATED) - actual = parse("curated.yaml", meta, DOC_GEN) + actual, errors = parse("curated.yaml", meta, SDKS, SERVICES) + assert len(errors) == 0 assert actual == [ Example( id="autogluon_tabular_with_sagemaker_pipelines", @@ -167,20 +173,21 @@ def test_parse_curated(): title="AutoGluon Tabular with SageMaker Pipelines", title_abbrev="AutoGluon Tabular with SageMaker Pipelines", source_key="amazon-sagemaker-examples", - languages=[ - Language( + languages={ + "Java": Language( name="Java", versions=[Version(sdk_version=2, block_content="block.xml")], ) - ], - services={"s3": {}}, + }, + services={"s3": []}, synopsis="use AutoGluon with SageMaker Pipelines.", ) ] def test_verify_load_successful(): - examples = load("valid_metadata.yaml", DOC_GEN) + examples, errors = load(Path("valid_metadata.yaml"), DOC_GEN) + assert len(errors) == 0 assert examples == [ Example( file="valid_metadata.yaml", @@ -192,29 +199,29 @@ def test_verify_load_successful(): guide_topic=Url(title="Test guide topic title", url="test-guide/url"), category="Usage", service_main=None, - languages=[ - Language( + languages={ + "Java": Language( name="Java", versions=[ Version( sdk_version=2, github="javav2/example_code/sns", block_content="test block", - excerpts=None, + excerpts=[], add_services={}, sdkguide=None, more_info=[], ), ], ), - Language( + "JavaScript": Language( name="JavaScript", versions=[ Version( sdk_version=3, github=None, block_content=None, - add_services={"s3": {}}, + add_services={"s3": []}, excerpts=[ Excerpt( description="Descriptive", @@ -227,7 +234,7 @@ def test_verify_load_successful(): ), ], ), - Language( + "PHP": Language( name="PHP", versions=[ Version( @@ -250,8 +257,8 @@ def test_verify_load_successful(): ) ], ), - ], - services={"sns": {}, "sqs": {}}, + }, + services={"sns": [], "sqs": []}, ) ] @@ -303,7 +310,7 @@ def test_verify_load_successful(): field="versions", file="errors_metadata.yaml", id="sqs_TestExample", - language=None, + language="Java", ), metadata_errors.MissingBlockContentAndExcerpt( file="errors_metadata.yaml", @@ -369,9 +376,11 @@ def test_verify_load_successful(): ), ], ) -def test_common_errors(filename, expected_errors): - actual = load(filename, DOC_GEN) - assert expected_errors == actual._errors +def test_common_errors( + filename: str, expected_errors: list[metadata_errors.MetadataError] +): + _, actual = load(Path(filename), DOC_GEN) + assert expected_errors == [*actual] if __name__ == "__main__": diff --git a/.tools/validation/metadata_validator.py b/.tools/validation/metadata_validator.py index 81a2d99c965..3bd4f7fcc1b 100755 --- a/.tools/validation/metadata_validator.py +++ b/.tools/validation/metadata_validator.py @@ -16,7 +16,7 @@ import yamale from dataclasses import dataclass, field from pathlib import Path -from typing import Iterable, Optional +from typing import Any, Iterable, Optional from yamale import YamaleError from yamale.validators import DefaultValidators, Validator, String @@ -27,12 +27,9 @@ class SdkVersion(Validator): """Validate that sdk version appears in sdks.yaml.""" tag = "sdk_version" - sdks = {} + sdks: dict[str, Any] = {} - def get_name(self): - return "sdk version found in sdks.yaml" - - def _is_valid(self, value): + def _is_valid(self, value: str): return value in self.sdks @@ -67,19 +64,6 @@ def _is_valid(self, value): return isdate -class SourceKey(Validator): - """Validate that curated source keys appear in curated/sources.yaml.""" - - tag = "source_key" - curated_sources: dict[str, any] = {} - - def get_name(self): - return "source key found in curated/sources.yaml" - - def _is_valid(self, value): - return value in self.curated_sources - - class ExampleId(Validator): """ Validate an example ID starts with a service ID and has underscore-separated @@ -109,7 +93,7 @@ class BlockContent(Validator): def get_name(self): return "file found in the cross-content folder" - def _is_valid(self, value): + def _is_valid(self, value: str): return value in self.block_names @@ -130,7 +114,7 @@ def __init__(self, *args, **kwargs): def get_name(self): return self.last_err - def _is_valid(self, value): + def _is_valid(self, value: str): if value == "": return True valid = True @@ -193,32 +177,29 @@ def validate_files( yamale.validate(schema, data) print(f"{meta_name.resolve()} validation success! 👍") except YamaleError as e: - errors.append(ValidateYamaleError(file=meta_name, yamale_error=e)) + errors.append(ValidateYamaleError(file=str(meta_name), yamale_error=e)) return errors -def validate_metadata(doc_gen: Path, errors: MetadataErrors): - with open(doc_gen / "metadata" / "sdks.yaml") as sdks_file: - sdks_yaml: dict[str, any] = yaml.safe_load(sdks_file) - - with open(doc_gen / "metadata" / "services.yaml") as services_file: - services_yaml = yaml.safe_load(services_file) +def validate_metadata(doc_gen_root: Path, errors: MetadataErrors) -> MetadataErrors: + with open( + Path(__file__).parent.parent.parent / ".doc_gen" / "metadata" / "sdks.yaml" + ) as sdks_file: + sdks_yaml: dict[str, Any] = yaml.safe_load(sdks_file) with open( - doc_gen / "metadata" / "curated" / "sources.yaml" - ) as curated_sources_file: - curated_sources_yaml = yaml.safe_load(curated_sources_file) + Path(__file__).parent.parent.parent / ".doc_gen" / "metadata" / "services.yaml" + ) as services_file: + services_yaml = yaml.safe_load(services_file) SdkVersion.sdks = sdks_yaml ServiceName.services = services_yaml - SourceKey.curated_sources = curated_sources_yaml ExampleId.services = services_yaml - BlockContent.block_names = os.listdir(doc_gen / "cross-content") + BlockContent.block_names = os.listdir(doc_gen_root / ".doc_gen" / "cross-content") validators = DefaultValidators.copy() validators[ServiceName.tag] = ServiceName validators[ServiceVersion.tag] = ServiceVersion - validators[SourceKey.tag] = SourceKey validators[ExampleId.tag] = ExampleId validators[BlockContent.tag] = BlockContent validators[String.tag] = StringExtension @@ -231,13 +212,11 @@ def validate_metadata(doc_gen: Path, errors: MetadataErrors): ("services_schema.yaml", "services.yaml"), # TODO: Switch between strict schema for aws-doc-sdk-examples and loose schema for tributaries ("example_strict_schema.yaml", "*_metadata.yaml"), - ("curated_sources_schema.yaml", "curated/sources.yaml"), - ("curated_example_schema.yaml", "curated/*_metadata.yaml"), ] for schema, metadata in to_validate: validate_files( schema_root / schema, - (doc_gen / "metadata").glob(metadata), + (doc_gen_root / "metadata").glob(metadata), validators, errors, ) @@ -255,9 +234,9 @@ def main(): ) args = parser.parse_args() - errors = validate_metadata(Path(args.doc_gen)) + errors = validate_metadata(Path(args.doc_gen), MetadataErrors()) - if errors == 0: + if len(errors) == 0: print("Validation succeeded! 👍👍👍") else: print("\n********************************************") diff --git a/.tools/validation/project_validator.py b/.tools/validation/project_validator.py index ffb45251046..02d73e1682b 100644 --- a/.tools/validation/project_validator.py +++ b/.tools/validation/project_validator.py @@ -21,14 +21,18 @@ import os import re -import argparse import logging import sys from dataclasses import dataclass, field from pathlib import Path from file_utils import get_files -from metadata_errors import MetadataErrors, MetadataError, DuplicateItemException +from metadata_errors import ( + MetadataErrors, + MetadataError, + MetadataParseError, + DuplicateItemException, +) from spdx import verify_spdx import validator_config @@ -54,13 +58,16 @@ def check_files(root: Path, errors: MetadataErrors, do_check_spdx: bool): verify_no_deny_list_words(file_contents, file_path, errors) verify_no_secret_keys(file_contents, file_path, errors) verify_no_secret_keys(file_contents, file_path, errors) - verify_snippet_start_end(file_contents, file_path, errors) if do_check_spdx: verify_spdx(file_contents, file_path, errors) print(f"{file_count} files scanned in {root}.\n") +def verify_spdx(a: str, b: Path, c: MetadataErrors): + pass + + def word_parts(contents: str): for word in contents.split(): # split on / for URLs, to find invalid Host names @@ -73,9 +80,12 @@ def word_parts(contents: str): class DenyListWord(MetadataError): word: str = field(default="") + def message(self) -> str: + return f"found deny list word {self.word}" + def verify_no_deny_list_words( - file_contents: str, file_location: str, errors: MetadataErrors + file_contents: str, file_location: Path, errors: MetadataErrors ) -> None: """Verify no words in the file are in the list of denied words.""" for word, part in word_parts(file_contents): @@ -89,14 +99,12 @@ def verify_no_deny_list_words( @dataclass class UnknownSampleFile(MetadataError): def message(self): - return ( - f"File {self.file} was not found in the list of expected sample files. If this is a new sample file, add it to the EXPECTED_SAMPLE_FILES list in {__package__}.{__file__}.", - ) + return f"File {self.file} was not found in the list of expected sample files. If this is a new sample file, add it to the EXPECTED_SAMPLE_FILES list in {__package__}.{__file__}." @dataclass -class InvalidSampleDirectory(MetadataError): - dir: str = field(default=-1) +class InvalidSampleDirectory(MetadataParseError): + dir: str = field(default="") def message(self): return f"must be in the {self.dir} directory." @@ -107,8 +115,8 @@ def message(self): @dataclass -class SampleFileTooLarge(MetadataError): - size_in_mb: float = field(default="") +class SampleFileTooLarge(MetadataParseError): + size_in_mb: float = field(default=-1) def message(self): return f"maximum file size is {MAX_FILE_SIZE_MB}MB, file is {self.size_in_mb}" @@ -119,36 +127,32 @@ class MissingSampleFile(MetadataError): samples_dir: str = field(default="") def message(self): - return ( - f"Expected sample file was not found in '{self.samples_dir}'. If this file was intentionally removed, remove it from the EXPECTED_SAMPLE_FILES list in {__package__}.{__file__}.", - ) + return f"Expected sample file was not found in '{self.samples_dir}'. If this file was intentionally removed, remove it from the EXPECTED_SAMPLE_FILES list in {__package__}.{__file__}." -def verify_sample_files(root_path: Path, errors: MetadataError) -> None: +def verify_sample_files(root_path: Path, errors: MetadataErrors) -> None: """Verify sample files meet the requirements and have not moved.""" - sample_files_folder = os.path.join(root_path, "resources/sample_files") + sample_files_folder = root_path / "resources/sample_files" media_folder = ".sample_media" - file_list = [] - for path, _dirs, files in os.walk(sample_files_folder, topdown=True): - for file_name in files: - file_list.append(file_name) - file_path = os.path.join(path, file_name) - ext = os.path.splitext(file_name)[1].lstrip(".") - if file_name not in validator_config.EXPECTED_SAMPLE_FILES: - errors.append(UnknownSampleFile(file=file_path)) - if ext.lower() in validator_config.MEDIA_FILE_TYPES: - if media_folder not in file_path: - errors.append( - InvalidSampleDirectory(file=file_path, dir=media_folder) - ) - size_in_mb = os.path.getsize(file_path) / ONE_MB_AS_BYTES - if size_in_mb > MAX_FILE_SIZE_MB: - errors.append(SampleFileTooLarge(file=file_path, size_in_mb=size_in_mb)) + file_list: list[str] = [] + for path in get_files(sample_files_folder): + file_list.append(path.name) + ext = path.suffix + if path.name not in validator_config.EXPECTED_SAMPLE_FILES: + errors.append(UnknownSampleFile(file=str(path))) + if ext.lower() in validator_config.MEDIA_FILE_TYPES: + if media_folder not in path: + errors.append(InvalidSampleDirectory(file=str(path), dir=media_folder)) + size_in_mb = os.path.getsize(path) / ONE_MB_AS_BYTES + if size_in_mb > MAX_FILE_SIZE_MB: + errors.append(SampleFileTooLarge(file=str(path), size_in_mb=size_in_mb)) for sample_file in validator_config.EXPECTED_SAMPLE_FILES: if sample_file not in file_list: errors.append( - MissingSampleFile(file=sample_file, samples_dir=sample_files_folder) + MissingSampleFile( + file=sample_file, samples_dir=str(sample_files_folder) + ) ) @@ -157,9 +161,7 @@ class PossibleSecretKey(MetadataError): word: str = field(default="") def message(self): - return ( - f"{len(self.word)} character string '{self.word}' might be a secret access key. If not, add it to the allow list in {__package__}.validator_config.", - ) + return f"{len(self.word)} character string '{self.word}' might be a secret access key. If not, add it to ALLOW_LIST in validator_config.py" TWENTY_LONG_KEY_REGEX = "(?<=[^A-Z0-9])[A][ACGIKNPRS][A-Z]{2}[A-Z0-9]{16}(?=[^A-Z0-9])" @@ -182,78 +184,11 @@ def verify_no_secret_keys( errors.append(PossibleSecretKey(file=str(file_location), word=word)) -@dataclass -class SnippetParseError(MetadataError): - tag: str = field(default="") - - -@dataclass -class DuplicateSnippetTagInFile(SnippetParseError): - def message(self): - return f"Duplicate tag {self.tag}" - - -@dataclass -class SnippetNoMatchingStart(SnippetParseError): - def message(self): - return f"No matching start for {self.tag}" - - -@dataclass -class SnippetNoMatchingEnd(SnippetParseError): - def message(self): - return f"No matching end for {self.tag}" - - -# TODO move this to snippets -def verify_snippet_start_end( - file_contents: str, file_location: Path, errors: MetadataErrors -): - """Scan the file contents for snippet-start and snippet-end tags and verify - that they are in matched pairs. Log errors and return the count of errors.""" - snippet_start = "snippet" + "-start:[" - snippet_end = "snippet" + "-end:[" - snippet_tags = set() - for word in file_contents.split(): - if snippet_start in word: - tag = word.split("[")[1] - if tag in snippet_tags: - errors.append(DuplicateSnippetTagInFile(file=file_location, tag=tag)) - else: - snippet_tags.add(tag) - elif snippet_end in word: - tag = word.split("[")[1] - if tag in snippet_tags: - snippet_tags.remove(tag) - else: - errors.append(SnippetNoMatchingStart(file=file_location, tag=tag)) - - for tag in snippet_tags: - errors.append(SnippetNoMatchingEnd(file=file_location, tag=tag)) - - def main(): - parser = argparse.ArgumentParser() - parser.add_argument( - "--quiet", - action="store_true", - help="Suppresses output of filenames while parsing. " "The default is False.", - ) - parser.add_argument( - "--root", - help="The root path from which to search for files " - "to check. The default is the current working " - "folder.", - ) - args = parser.parse_args() - - root_path = Path( - os.path.abspath(".") if not args.root else os.path.abspath(args.root) - ) - + root_path = Path(__file__).parent.parent.parent print("----------\n\nRun Tests\n") errors = MetadataErrors() - check_files(root_path, args.quiet, errors) + check_files(root_path, errors, True) verify_sample_files(root_path, errors) error_count = len(errors) if error_count > 0: diff --git a/.tools/validation/project_validator_test.py b/.tools/validation/project_validator_test.py index f5a1b4f61a5..5aee2b5e0b6 100644 --- a/.tools/validation/project_validator_test.py +++ b/.tools/validation/project_validator_test.py @@ -9,6 +9,7 @@ import project_validator from metadata_errors import MetadataErrors +from pathlib import Path @pytest.mark.parametrize( @@ -18,7 +19,7 @@ ("https://example.com/foo", ["https", "", "example.com", "foo"]), ], ) -def test(contents, expected_parts): +def test(contents: str, expected_parts: list[str]): """Test that the word part stemmer finds the right pieces""" actual_parts = [part for _, part in project_validator.word_parts(contents)] assert expected_parts == actual_parts @@ -38,10 +39,10 @@ def test(contents, expected_parts): ("This string has no denied words.\n" "And neither does this one.", 0), ], ) -def test_verify_no_deny_list_words(file_contents, expected_error_count): +def test_verify_no_deny_list_words(file_contents: str, expected_error_count: int): """Test that file contents that contain disallowed words are counted as errors.""" errors = MetadataErrors() - project_validator.verify_no_deny_list_words(file_contents, "location", errors) + project_validator.verify_no_deny_list_words(file_contents, Path("location"), errors) error_count = len(errors) assert error_count == expected_error_count @@ -64,75 +65,11 @@ def test_verify_no_deny_list_words(file_contents, expected_error_count): ("Something AppStreamUsageReportsCFNGlue" + "AtNotAllowed.py", 1), ], ) -def test_verify_no_secret_keys(file_contents, expected_error_count): +def test_verify_no_secret_keys(file_contents: str, expected_error_count: int): """Test that file contents that contain 20- or 40-character strings and are not in the allowed list are counted as errors.""" errors = MetadataErrors() - project_validator.verify_no_secret_keys(file_contents, "location", errors) - error_count = len(errors) - assert error_count == expected_error_count - - -@pytest.mark.parametrize( - "file_contents,expected_error_count", - [ - ( - "snippet" + "-start:[this.is.a.snippet.tag]\n" - "This is not code.\n" - "snippet" + "-end:[this.is.a.snippet.tag]", - 0, - ), - ( - "snippet" + "-start:[this.is.a.snippet.tag]\n" - "This is not code.\n" - "snippet" + "-end:[this.is.a.different.snippet.tag]", - 2, - ), - ("snippet" + "-start:[this.is.a.snippet.tag]\n" "This is not code.", 1), - ("This is not code.\n" "snippet" + "-end:[this.is.a.snippet.tag]", 1), - ( - "snippet" + "-start:[this.is.a.snippet.tag]\n" - "snippet" + "-start:[this.is.a.different.snippet.tag]\n" - "This is not code.\n" - "snippet" + "-end:[this.is.a.snippet.tag]\n" - "snippet" + "-end:[this.is.a.different.snippet.tag]\n", - 0, - ), - ( - "snippet" + "-start:[this.is.a.snippet.tag]\n" - "snippet" + "-start:[this.is.a.different.snippet.tag]\n" - "This is not code.\n" - "snippet" + "-end:[this.is.a.different.snippet.tag]\n" - "snippet" + "-end:[this.is.a.snippet.tag]\n", - 0, - ), - ( - "snippet" + "-start:[this.is.a.snippet.tag]\n" - "This is not code.\n" - "snippet" + "-end:[this.is.a.snippet.tag.with.extra.stuff]\n", - 2, - ), - ( - "snippet" + "-start:[this.is.a.snippet.tag]\n" - "snippet" + "-start:[this.is.a.snippet.tag]\n" - "This is not code.\n" - "snippet" + "-end:[this.is.a.snippet.tag]\n", - 1, - ), - ( - "snippet" + "-start:[this.is.a.snippet.tag]\n" - "This is not code.\n" - "snippet" + "-end:[this.is.a.snippet.tag]\n" - "snippet" + "-end:[this.is.a.snippet.tag]\n", - 1, - ), - ], -) -def test_verify_snippet_start_end(file_contents, expected_error_count): - """Test that various kinds of mismatched snippet-start and -end tags are - counted correctly as errors.""" - errors = MetadataErrors() - project_validator.verify_snippet_start_end(file_contents, "location", errors) + project_validator.verify_no_secret_keys(file_contents, Path("location"), errors) error_count = len(errors) assert error_count == expected_error_count diff --git a/.tools/validation/schema/curated_sources_schema.yaml b/.tools/validation/schema/curated_sources_schema.yaml deleted file mode 100644 index d214a67992f..00000000000 --- a/.tools/validation/schema/curated_sources_schema.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Yamale Schema for curated sources metadata, which is the sources.yaml file in the metadata/curated folder. - -map(include('source'), key=regex('^[-a-z0-9]+$', name='source name')) ---- -source: - name: str(upper_start=True, no_end_punc=True) - description: str(upper_start=True, end_punc=True) - url: regex('^http', name="URL") diff --git a/.tools/validation/sdks.py b/.tools/validation/sdks.py index ca8763d7ffc..a130a89e25a 100644 --- a/.tools/validation/sdks.py +++ b/.tools/validation/sdks.py @@ -1,7 +1,7 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -from typing import Self, Optional +from typing import Any, Self, Optional import metadata_errors from metadata_errors import MetadataErrors, MetadataParseError, check_mapping from dataclasses import dataclass, field @@ -19,23 +19,24 @@ class SdkApiRef: name: str link_template: Optional[str] - def from_yaml(yaml: dict[str, str] | None, errors: MetadataErrors) -> Self | None: + @classmethod + def from_yaml( + cls, yaml: dict[str, str] | None, errors: MetadataErrors + ) -> None | Self: if yaml is None: return None uid = yaml.get("uid") name = check_mapping(yaml.get("name"), "api_ref.name") link_template = yaml.get("link_template") - e = len(errors) - - if not uid: + if uid is None: errors.append(metadata_errors.MissingField(field="api_ref.uid")) + uid = "" if isinstance(name, MetadataParseError): errors.append(name) + name = "" - if e == len(errors): - return SdkApiRef(uid, name, link_template) - return None + return cls(uid, name, link_template) @dataclass @@ -56,8 +57,10 @@ class SdkVersion: bookmark: Optional[str] = field(default=None) title_override: Optional[SdkTitleOverride] = field(default=None) - @staticmethod - def from_yaml(version: int, yaml: dict[str, any]) -> Self | MetadataErrors: + @classmethod + def from_yaml( + cls, version: int, yaml: dict[str, Any] + ) -> tuple[Self, MetadataErrors]: errors = MetadataErrors() long = check_mapping(yaml.get("long"), "long") short = check_mapping(yaml.get("short"), "short") @@ -73,7 +76,7 @@ def from_yaml(version: int, yaml: dict[str, any]) -> Self | MetadataErrors: errors.append(metadata_errors.MissingField(field="expanded.long")) if not short_expanded: errors.append(metadata_errors.MissingField(field="expanded.short")) - expanded = (SdkVersionExpanded(long=long_expanded, short=short_expanded),) + expanded = SdkVersionExpanded(long=long_expanded, short=short_expanded) title_override = yaml.get("title_override") if title_override is not None: @@ -91,23 +94,25 @@ def from_yaml(version: int, yaml: dict[str, any]) -> Self | MetadataErrors: if isinstance(long, MetadataParseError): errors.append(long) + long = "" if isinstance(short, MetadataParseError): errors.append(short) + short = "" api_ref = SdkApiRef.from_yaml(yaml.get("api_ref"), errors) - if len(errors) > 0: - return errors - - return SdkVersion( - version=version, - long=long, - short=short, - expanded=expanded, - guide=guide, - api_ref=api_ref, - caveat=caveat, - bookmark=bookmark, - title_override=title_override, + return ( + cls( + version=version, + long=long, + short=short, + expanded=expanded, + guide=guide, + api_ref=api_ref, + caveat=caveat, + bookmark=bookmark, + title_override=title_override, + ), + errors, ) @@ -118,46 +123,42 @@ class Sdk: guide: str property: str - @staticmethod - def from_yaml(name: str, yaml: dict[str, any]) -> Self | MetadataErrors: + @classmethod + def from_yaml(cls, name: str, yaml: dict[str, Any]) -> tuple[Self, MetadataErrors]: errors = MetadataErrors() - property = yaml.get("property") + property = yaml.get("property", "") guide = check_mapping(yaml.get("guide"), "guide") if isinstance(guide, MetadataParseError): errors.append(guide) + guide = "" - versions = [] - sdk_versions = yaml.get("sdk", {}) + versions: list[SdkVersion] = [] + sdk_versions: None | dict[str, Any] = yaml.get("sdk") if sdk_versions is None: sdk_versions = {} for version in sdk_versions: - sdk_version = SdkVersion.from_yaml(version, sdk_versions[version]) - if isinstance(sdk_version, MetadataErrors): - errors.extend(sdk_version) - else: - versions.append(sdk_version) - - if len(errors) > 0: - return errors + (sdk_version, errs) = SdkVersion.from_yaml( + int(version), sdk_versions[version] + ) + versions.append(sdk_version) + errors.extend(errs) - return Sdk(name=name, versions=versions, guide=guide, property=property) + return cls(name=name, versions=versions, guide=guide, property=property), errors -def parse(file: str, yaml: dict[str, any]) -> dict[str, Sdk]: - sdks = {} +def parse(file: str, yaml: dict[str, Any]) -> tuple[dict[str, Sdk], MetadataErrors]: + sdks: dict[str, Sdk] = {} errors = MetadataErrors() for name in yaml: - sdk = Sdk.from_yaml(name, yaml[name]) - if isinstance(sdk, Sdk): - sdks[name] = sdk - else: - for error in sdk: - error.file = file - error.id = name - errors.extend(sdk) + sdk, errs = Sdk.from_yaml(name, yaml[name]) + sdks[name] = sdk + for error in errs: + error.file = file + error.id = name + errors.extend(errs) - return sdks if len(errors) == 0 else errors + return sdks, errors if __name__ == "__main__": @@ -167,5 +168,5 @@ def parse(file: str, yaml: dict[str, any]) -> dict[str, Sdk]: path = Path(__file__).parent.parent.parent / ".doc_gen" / "metadata" / "sdks.yaml" with open(path) as file: meta = yaml.safe_load(file) - examples = parse(path.name, meta) + examples, errors = parse(path.name, meta) print(f"{examples}") diff --git a/.tools/validation/sdks_test.py b/.tools/validation/sdks_test.py index ad94cc1e0ce..5e55d15a6ba 100644 --- a/.tools/validation/sdks_test.py +++ b/.tools/validation/sdks_test.py @@ -13,7 +13,7 @@ from sdks import parse, Sdk, SdkVersion, SdkApiRef, SdkTitleOverride -def load(path: Path) -> list[Sdk] | metadata_errors.MetadataErrors: +def load(path: str) -> tuple[dict[str, Sdk], metadata_errors.MetadataErrors]: root = Path(__file__).parent filename = root / "test_resources" / path with open(filename) as file: @@ -22,8 +22,8 @@ def load(path: Path) -> list[Sdk] | metadata_errors.MetadataErrors: def test_empty_sdks(): - examples = load("empty_sdks.yaml") - assert examples._errors == [ + _, errors = load("empty_sdks.yaml") + assert [*errors] == [ metadata_errors.MissingField( file="empty_sdks.yaml", id="C++", @@ -35,7 +35,7 @@ def test_empty_sdks(): def test_entityusage(): - actual = load("entityusage_sdks.yaml") + _, actual = load("entityusage_sdks.yaml") expected = [ metadata_errors.MappingMustBeEntity( file="entityusage_sdks.yaml", @@ -56,11 +56,11 @@ def test_entityusage(): value="CPP", ), ] - assert actual._errors == expected + assert [*actual] == expected def test_sdks(): - actual = load("sdks.yaml") + actual, _ = load("sdks.yaml") expected = { "C++": Sdk( name="C++", diff --git a/.tools/validation/services.py b/.tools/validation/services.py index ba629f02670..1c5c574df89 100644 --- a/.tools/validation/services.py +++ b/.tools/validation/services.py @@ -1,7 +1,7 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -from typing import Self, Optional +from typing import Any, Optional, Self from dataclasses import dataclass, field import metadata_errors from metadata_errors import MetadataErrors, check_mapping @@ -18,7 +18,7 @@ class Service: long: str short: str sort: str - version: str + version: int | str api_ref: Optional[str] = field(default=None) blurb: Optional[str] = field(default=None) bundle: Optional[str] = field(default=None) @@ -26,8 +26,8 @@ class Service: guide: Optional[ServiceGuide] = field(default=None) tags: dict[str, set[str]] = field(default_factory=dict) - @staticmethod - def from_yaml(name: str, yaml: dict[str, any]) -> Self | MetadataErrors: + @classmethod + def from_yaml(cls, name: str, yaml: dict[str, Any]) -> tuple[Self, MetadataErrors]: errors = MetadataErrors() long = check_mapping(yaml.get("long"), "long") @@ -37,12 +37,16 @@ def from_yaml(name: str, yaml: dict[str, any]) -> Self | MetadataErrors: if isinstance(long, metadata_errors.MetadataParseError): errors.append(long) + long = "" if isinstance(short, metadata_errors.MetadataParseError): errors.append(short) + short = "" if sort is None: errors.append(metadata_errors.MissingField(field="sort")) + sort = "" if version is None: errors.append(metadata_errors.MissingField(field="version")) + version = "0" api_ref = yaml.get("api_ref") blurb = yaml.get("blurb") @@ -63,42 +67,43 @@ def from_yaml(name: str, yaml: dict[str, any]) -> Self | MetadataErrors: for tag in tags: tags[tag] = set(tags[tag].keys()) - if len(errors) > 0: - for error in errors: - error.id = name - return errors - - return Service( - long=long, - short=short, - sort=sort, - api_ref=api_ref, - blurb=blurb, - bundle=bundle, - caveat=caveat, - guide=guide, - tags=tags, - version=version, + for error in errors: + error.id = name + + return ( + cls( + long=long, + short=short, + sort=sort, + api_ref=api_ref, + blurb=blurb, + bundle=bundle, + caveat=caveat, + guide=guide, + tags=tags, + version=version, + ), + errors, ) -def parse(filename: str, yaml: dict[str, any]) -> dict[str, Service] | MetadataErrors: +def parse( + filename: str, yaml: dict[str, Any] +) -> tuple[dict[str, Service], MetadataErrors]: errors = metadata_errors.MetadataErrors() - services = {} + services: dict[str, Service] = {} for name in yaml: meta = yaml[name] if meta is None: errors.append(metadata_errors.MissingServiceBody(file=filename, id=name)) else: - service = Service.from_yaml(name, meta) - if isinstance(service, MetadataErrors): - for error in service: - error.file = filename - errors.extend(service) - else: - services[name] = service - - return services if len(errors) == 0 else errors + service, service_errors = Service.from_yaml(name, meta) + for error in service_errors: + error.file = filename + errors.extend(service_errors) + services[name] = service + + return services, errors if __name__ == "__main__": diff --git a/.tools/validation/services_test.py b/.tools/validation/services_test.py index a3a0925b503..32dc9d05356 100644 --- a/.tools/validation/services_test.py +++ b/.tools/validation/services_test.py @@ -9,7 +9,7 @@ from services import parse, Service, ServiceGuide -def load(path: Path) -> list[Service] | metadata_errors.MetadataErrors: +def load(path: str) -> tuple[dict[str, Service], metadata_errors.MetadataErrors]: root = Path(__file__).parent filename = root / "test_resources" / path with open(filename) as file: @@ -18,15 +18,15 @@ def load(path: Path) -> list[Service] | metadata_errors.MetadataErrors: def test_empty_services(): - examples = load("empty_services.yaml") - assert examples._errors == [ + _, errs = load("empty_services.yaml") + assert [*errs] == [ metadata_errors.MissingServiceBody(file="empty_services.yaml", id="sns") ] def test_services_entity_usage(): - examples = load("entityusage_services.yaml") - assert examples._errors == [ + _, errs = load("entityusage_services.yaml") + assert [*errs] == [ metadata_errors.MappingMustBeEntity( file="entityusage_services.yaml", id="sns", field="long", value="SNSlong" ), @@ -42,7 +42,7 @@ def test_services_entity_usage(): def test_services(): - examples = load("services.yaml") + examples, _ = load("services.yaml") assert examples == { "s3": Service( short="&S3;", diff --git a/.tools/validation/snippets.py b/.tools/validation/snippets.py index 7747add02f4..b02cc96abb9 100644 --- a/.tools/validation/snippets.py +++ b/.tools/validation/snippets.py @@ -2,6 +2,17 @@ # SPDX-License-Identifier: Apache-2.0 from dataclasses import dataclass +from metadata import Example +from metadata_errors import MetadataErrors, MetadataError +from typing import Optional +from pathlib import Path +from shutil import copyfile +import validator_config + +from file_utils import get_files, clear + +SNIPPET_START = "snippet-start:[" +SNIPPET_END = "snippet-end:[" @dataclass @@ -10,3 +21,212 @@ class Snippet: file: str line_start: int line_end: int + code: str + + +@dataclass +class SnippetError(MetadataError): + line: Optional[int] = None + tag: Optional[str] = None + + def prefix(self): + return super().prefix() + f" at l{self.line} for {self.tag}: " + + +@dataclass +class DuplicateSnippetStartError(SnippetError): + def message(self): + return "duplicate snippet-start tag" + + +@dataclass +class DuplicateSnippetEndError(SnippetError): + def message(self): + return "duplicate snippet-end tag" + + +@dataclass +class MissingSnippetStartError(SnippetError): + def message(self): + return "snippet-end with no matching start" + + +@dataclass +class MissingSnippetEndError(SnippetError): + def message(self): + return "snippet-start with no matching end" + + +@dataclass +class SnippetAlreadyWritten(MetadataError): + def message(self): + return "Snippet file already exists, which means this tag is defined more than once in separate files." + + +@dataclass +class MetadataUnicodeError(MetadataError): + err: Optional[UnicodeDecodeError] = None + + def message(self): + return f" unicode error: {str(self.err)}" + + +def _tag_from_line(token: str, line: str) -> str: + tag_start = line.find(token) + len(token) + tag_end = line.find("]", tag_start) + return line[tag_start:tag_end].strip() + + +def parse_snippets( + lines: list[str], file: Path +) -> tuple[dict[str, Snippet], MetadataErrors]: + snippets: dict[str, Snippet] = {} + errors = MetadataErrors() + open_tags: set[str] = set() + for line_idx, line in enumerate(lines): + if SNIPPET_START in line: + tag = _tag_from_line(SNIPPET_START, line) + if tag in snippets: + errors.append( + DuplicateSnippetStartError(file=str(file), line=line_idx, tag=tag) + ) + else: + snippets[tag] = Snippet( + id=tag, + file=str(file), + line_start=line_idx, + line_end=-1, + code="", + ) + open_tags.add(tag) + elif SNIPPET_END in line: + tag = _tag_from_line(SNIPPET_END, line) + if tag not in snippets: + errors.append( + MissingSnippetStartError(file=str(file), line=line_idx, tag=tag) + ) + elif tag not in open_tags: + errors.append( + DuplicateSnippetEndError(file=str(file), line=line_idx, tag=tag) + ) + else: + open_tags.remove(tag) + snippets[tag].line_end = line_idx + else: + for tag in open_tags: + snippets[tag].code += line + + for tag in open_tags: + errors.append( + MissingSnippetEndError( + file=str(file), line=snippets[tag].line_start, tag=tag + ) + ) + return snippets, errors + + +def find_snippets(file: Path) -> tuple[dict[str, Snippet], MetadataErrors]: + errors = MetadataErrors() + snippets = {} + with open(file, encoding="utf-8") as snippet_file: + try: + snippets, errs = parse_snippets(snippet_file.readlines(), file) + errors.extend(errs) + except UnicodeDecodeError as err: + errors.append(MetadataUnicodeError(file=str(file), err=err)) + return snippets, errors + + +def collect_snippets(root: Path) -> tuple[dict[str, Snippet], MetadataErrors]: + snippets: dict[str, Snippet] = {} + errors = MetadataErrors() + for file in get_files(root, validator_config.skip): + snips, errs = find_snippets(file) + snippets.update(snips) + errors.extend(errs) + return snippets, errors + + +@dataclass +class MissingSnippet(MetadataError): + tag: Optional[str] = None + + def message(self): + return f"missing snippet {self.tag}" + + +@dataclass +class MissingSnippetFile(MetadataError): + snippet_file: Optional[str] = None + + def message(self): + return f"missing snippet_file {self.snippet_file}" + + +def validate_snippets( + examples: list[Example], + snippets: dict[str, Snippet], + snippet_files: set[str], + errors: MetadataErrors, + root: Path, +): + for example in examples: + for lang in example.languages: + language = example.languages[lang] + for version in language.versions: + for excerpt in version.excerpts: + for snippet_tag in excerpt.snippet_tags: + if snippet_tag not in snippets: + # Ensure all metadata snippets are found + errors.append( + MissingSnippet( + file=example.file, + id=f"{lang}:{version.sdk_version}", + tag=snippet_tag, + ) + ) + for snippet_file in excerpt.snippet_files: + if not (root / snippet_file).exists(): + # Ensure all snippet_files exist + errors.append( + MissingSnippetFile( + file=example.file, + snippet_file=snippet_file, + id=f"{lang}:{version.sdk_version}", + ) + ) + snippet_files.add(snippet_file) + + +def write_snippets(root: Path, snippets: dict[str, Snippet]): + errors = MetadataErrors() + for tag in snippets: + name = root / f"{tag}.txt" + if name.exists(): + errors.append(SnippetAlreadyWritten(file=str(name))) + else: + with open(name, "w", encoding="utf-8") as file: + file.write(snippets[tag].code) + return errors + + +def write_snippet_file(folder: Path, snippet_file: Path): + name = str(snippet_file).replace("/", ".") + dest = folder / f"{name}.txt" + if not dest.exists(): + copyfile(folder / snippet_file, dest) + + +def main(): + root = Path(__file__).parent.parent.parent + snippets, errors = collect_snippets(root) + print(f"Found {len(snippets)} snippets") + out = root / ".snippets" + clear(out) + errors.maybe_extend(write_snippets(out, snippets)) + if len(errors) > 0: + print(errors) + + +if __name__ == "__main__": + main() diff --git a/.tools/validation/snippets_test.py b/.tools/validation/snippets_test.py new file mode 100644 index 00000000000..b4436bc24e1 --- /dev/null +++ b/.tools/validation/snippets_test.py @@ -0,0 +1,67 @@ +import pytest +from pathlib import Path + +import snippets + + +@pytest.mark.parametrize( + "file_contents,expected_error_count", + [ + ( + "snippet" + "-start:[this.is.a.snippet.tag]\n" + "This is not code.\n" + "snippet" + "-end:[this.is.a.snippet.tag]", + 0, + ), + ( + "snippet" + "-start:[this.is.a.snippet.tag]\n" + "This is not code.\n" + "snippet" + "-end:[this.is.a.different.snippet.tag]", + 2, + ), + ("snippet" + "-start:[this.is.a.snippet.tag]\n" "This is not code.", 1), + ("This is not code.\n" "snippet" + "-end:[this.is.a.snippet.tag]", 1), + ( + "snippet" + "-start:[this.is.a.snippet.tag]\n" + "snippet" + "-start:[this.is.a.different.snippet.tag]\n" + "This is not code.\n" + "snippet" + "-end:[this.is.a.snippet.tag]\n" + "snippet" + "-end:[this.is.a.different.snippet.tag]\n", + 0, + ), + ( + "snippet" + "-start:[this.is.a.snippet.tag]\n" + "snippet" + "-start:[this.is.a.different.snippet.tag]\n" + "This is not code.\n" + "snippet" + "-end:[this.is.a.different.snippet.tag]\n" + "snippet" + "-end:[this.is.a.snippet.tag]\n", + 0, + ), + ( + "snippet" + "-start:[this.is.a.snippet.tag]\n" + "This is not code.\n" + "snippet" + "-end:[this.is.a.snippet.tag.with.extra.stuff]\n", + 2, + ), + ( + "snippet" + "-start:[this.is.a.snippet.tag]\n" + "snippet" + "-start:[this.is.a.snippet.tag]\n" + "This is not code.\n" + "snippet" + "-end:[this.is.a.snippet.tag]\n", + 1, + ), + ( + "snippet" + "-start:[this.is.a.snippet.tag]\n" + "This is not code.\n" + "snippet" + "-end:[this.is.a.snippet.tag]\n" + "snippet" + "-end:[this.is.a.snippet.tag]\n", + 1, + ), + ], +) +def test_verify_snippet_start_end(file_contents: str, expected_error_count: int): + """Test that various kinds of mismatched snippet-start and -end tags are + counted correctly as errors.""" + _, errors = snippets.parse_snippets(file_contents.split("\n"), Path("test")) + error_count = len(errors) + assert error_count == expected_error_count diff --git a/.tools/validation/validate.py b/.tools/validation/validate.py index c355a975fc3..e26779647f8 100755 --- a/.tools/validation/validate.py +++ b/.tools/validation/validate.py @@ -2,39 +2,22 @@ # SPDX-License-Identifier: Apache-2.0 import argparse -import yaml from pathlib import Path from sys import exit -from metadata import parse as parse_metadata -from metadata_errors import MetadataErrors -from metadata_validator import validate_metadata -from project_validator import check_files, verify_sample_files -from doc_gen import DocGen - - -def validate_zexii(metadata_path: Path, errors: MetadataErrors) -> None: - doc_gen = errors.maybe_extend(DocGen.from_root(metadata_path)) - if doc_gen is None: - return - for path in metadata_path.glob("*_metadata.yaml"): - if path.name == "cross_metadata.yaml": - continue - with open(path, encoding="utf-8") as file: - meta = yaml.safe_load(file) - errors.maybe_extend(parse_metadata(path.name, meta, doc_gen)) +from doc_gen import DocGen def main(): parser = argparse.ArgumentParser() parser.add_argument( "--root", - default=f"{Path(__file__).parent / '..' / '..'}", + default=f"{Path(__file__).parent.parent.parent}", help="The root path from which to search for files to check. The default is the root of the git repo (two up from this file).", ) parser.add_argument( "--doc-gen", - default=f"{Path(__file__).parent / '..' / '..' / '.doc_gen'}", + default=f"{Path(__file__).parent.parent.parent / '.doc_gen'}", help="The folder that contains schema and metadata files. The default is .doc_gen in the root of this repo.", required=False, ) @@ -46,19 +29,14 @@ def main(): ) args = parser.parse_args() root_path = Path(args.root).resolve() - doc_gen = Path(args.doc_gen).resolve() - - errors = MetadataErrors() - check_files(root_path, errors, args.check_spdx) - verify_sample_files(root_path, errors) - validate_metadata(doc_gen, errors) - validate_zexii(doc_gen / "metadata", errors) + doc_gen = DocGen.from_root(root=root_path) + doc_gen.collect_snippets(snippets_root=root_path) + doc_gen.validate(args.check_spdx) - error_count = len(errors) + error_count = len(doc_gen.errors) if error_count > 0: - for error in errors: - print(str(error)) + print(f"{doc_gen.errors}") print(f"{error_count} errors found, please fix them.") else: print("All checks passed, you are cleared to check in.") diff --git a/.tools/validation/validate_test.py b/.tools/validation/validate_test.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/.tools/validation/validator_config.py b/.tools/validation/validator_config.py index 867fce1646d..c20ea656b59 100644 --- a/.tools/validation/validator_config.py +++ b/.tools/validation/validator_config.py @@ -1,35 +1,40 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +from pathlib import Path from urllib.request import urlopen import json # Only files with these extensions are scanned. EXT_LOOKUP = { + ".abap": "SAP ABAP", ".c": "C", + ".cmd": "AWS-CLI", ".cpp": "C++", ".cs": "C#", ".go": "Go", ".html": "JavaScript", ".java": "Java", ".js": "JavaScript", + ".json": "JSON", + ".jsx": "JavaScript", ".kt": "Kotlin", + ".md": "Markdown", ".php": "PHP", ".py": "Python", ".rb": "Ruby", ".rs": "Rust", + ".sh": "AWS-CLI", ".swift": "Swift", ".ts": "TypeScript", - ".sh": "AWS-CLI", - ".cmd": "AWS-CLI", - ".json": "JSON", - ".yml": "YAML", + ".tsx": "TypeScript", + ".txt": "CMake", ".yaml": "YAML", - ".md": "Markdown", + ".yml": "YAML", } -def skip(path): +def skip(path: Path) -> bool: return path.suffix.lower() not in EXT_LOOKUP or path.name in IGNORE_FILES @@ -69,6 +74,7 @@ def skip(path): "crash", "dp", "dummy", + "massa", "jerry", "throat", } @@ -193,6 +199,7 @@ def skip(path): "cloudsearch/latest/developerguide/search", "cloudsearch/latest/developerguide/search", "codeartifact/latest/APIReference/Welcome", + "code/codepipeline/MyCodePipelineFunction", "codepipeline/latest/APIReference/Welcome", "datapipeline/latest/APIReference/Welcome", "imagebuilder/latest/APIReference/Welcome", From 409b9c97b53f96abbe6a0fe52b3a768dcdbd8f5d Mon Sep 17 00:00:00 2001 From: David Souther Date: Thu, 18 Jan 2024 17:39:52 -0500 Subject: [PATCH 02/36] Rust: DynamoDB Local snippet missing key details (#5911) Make local dynamodb example self contained. --- .../dynamodb/src/bin/list-tables-local.rs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/rustv1/examples/dynamodb/src/bin/list-tables-local.rs b/rustv1/examples/dynamodb/src/bin/list-tables-local.rs index 03d521d9bcf..349de2761c8 100644 --- a/rustv1/examples/dynamodb/src/bin/list-tables-local.rs +++ b/rustv1/examples/dynamodb/src/bin/list-tables-local.rs @@ -4,23 +4,33 @@ #![allow(clippy::result_large_err)] // snippet-start:[dynamodb.rust.list-tables-local] +use aws_config::BehaviorVersion; use aws_sdk_dynamodb::{Client, Error}; -use clap::Parser; -use dynamodb_code_examples::{make_config, scenario::list::list_tables, Opt}; /// Lists your tables in DynamoDB local. #[tokio::main] async fn main() -> Result<(), Error> { - let config = make_config(Opt::parse()).await?; + let config = aws_config::defaults(BehaviorVersion::latest()) + .test_credentials() + .load() + .await; let dynamodb_local_config = aws_sdk_dynamodb::config::Builder::from(&config) + // Override the endpoint in the config to use a local dynamodb server. .endpoint_url( - // 8000 is the default dynamodb port + // DynamoDB run locally uses port 8000 by default. "http://localhost:8000", ) .build(); let client = Client::from_conf(dynamodb_local_config); - list_tables(&client).await?; + + let resp = client.list_tables().send().await?; + + println!("Found {} tables", resp.table_names().len()); + for name in resp.table_names() { + println!(" {}", name); + } + Ok(()) } // snippet-end:[dynamodb.rust.list-tables-local] From 8efc02ddba0485d8971559f1cd3ee075f855da07 Mon Sep 17 00:00:00 2001 From: Dennis Traub Date: Thu, 18 Jan 2024 23:47:30 +0100 Subject: [PATCH 03/36] Fix and consolidate Bedrock example structure (#5916) Co-authored-by: Dennis Traub --- .doc_gen/metadata/bedrock-agent_metadata.yaml | 1 + .doc_gen/metadata/bedrock-runtime_metadata.yaml | 6 +++--- .doc_gen/metadata/bedrock_metadata.yaml | 2 +- .doc_gen/metadata/cross_metadata.yaml | 9 +++++---- gov2/bedrock/README.md | 2 +- javav2/example_code/bedrock/Readme.md | 2 +- kotlin/services/bedrock/README.md | 2 +- php/example_code/bedrock-runtime/README.md | 6 +++--- php/example_code/bedrock/README.md | 2 +- python/example_code/bedrock/README.md | 2 +- 10 files changed, 18 insertions(+), 16 deletions(-) diff --git a/.doc_gen/metadata/bedrock-agent_metadata.yaml b/.doc_gen/metadata/bedrock-agent_metadata.yaml index cf3486fe0de..14f65facfd7 100644 --- a/.doc_gen/metadata/bedrock-agent_metadata.yaml +++ b/.doc_gen/metadata/bedrock-agent_metadata.yaml @@ -158,6 +158,7 @@ bedrock-agent_PrepareAgent: - python.example_code.bedrock-agent.PrepareAgent services: bedrock-agent: {PrepareAgent} + bedrock-agent_GettingStartedWithBedrockAgents: title: An end-to-end example showing how to create and invoke &BR; agents using an &AWS; SDK title_abbrev: Create and invoke an agent diff --git a/.doc_gen/metadata/bedrock-runtime_metadata.yaml b/.doc_gen/metadata/bedrock-runtime_metadata.yaml index 6375dd4380f..8953de8cbe3 100644 --- a/.doc_gen/metadata/bedrock-runtime_metadata.yaml +++ b/.doc_gen/metadata/bedrock-runtime_metadata.yaml @@ -303,9 +303,9 @@ bedrock-runtime_InvokeModelWithResponseStream: bedrock-runtime: {InvokeModelWithResponseStream} bedrock-runtime_Scenario_Invoke_models: - title: Invoke multiple large-language models (LLMs) on &BR; - title_abbrev: Invoke multiple LLMs on &BR; - synopsis: invoke multiple large-language-models (LLMs) on &BR;. + title: Invoke multiple foundation models on &BR; + title_abbrev: Invoke multiple foundation models on &BR; + synopsis: invoke multiple foundation models on &BR;. synopsis_list: - Generate text with Anthropic Claude. - Generate text with AI21 Labs Jurassic-2. diff --git a/.doc_gen/metadata/bedrock_metadata.yaml b/.doc_gen/metadata/bedrock_metadata.yaml index 2c181cc98b4..fd323fbb8f4 100644 --- a/.doc_gen/metadata/bedrock_metadata.yaml +++ b/.doc_gen/metadata/bedrock_metadata.yaml @@ -50,7 +50,7 @@ bedrock_GetFoundationModel: bedrock_ListFoundationModels: title: List the available &BRlong; foundation models using an &AWS; SDK - title_abbrev: List available &BR; foundation models + title_abbrev: List &BR; foundation models synopsis: list available &BR; foundation models. category: languages: diff --git a/.doc_gen/metadata/cross_metadata.yaml b/.doc_gen/metadata/cross_metadata.yaml index 4d5991be9e1..d60d57542ce 100644 --- a/.doc_gen/metadata/cross_metadata.yaml +++ b/.doc_gen/metadata/cross_metadata.yaml @@ -737,9 +737,9 @@ cross_ResilientService: CreateLoadBalancer, CreateListener, DeleteLoadBalancer, DescribeTargetHealth} iam: {CreateInstanceProfile, DeleteInstanceProfile} cross_FMPlayground: - title: Create a sample application that offers playgrounds to interact with &BR; foundation models using an &AWS; SDK - title_abbrev: Create a playground application to interact with &BR; foundation models - synopsis: create playgrounds to interact with &BR; foundation models through different modalities. + title: A sample playground application to interact with &BR; foundation models using an &AWS; SDK + title_abbrev: A playground application to interact with foundation models on &BR; + synopsis: interact with various &BR; foundation models through different modalities. category: Scenarios languages: .NET: @@ -754,8 +754,9 @@ cross_FMPlayground: versions: - sdk_version: 3 block_content: cross_FMPlayground_Python_block.xml - service_main: bedrock-runtime + service_main: bedrock services: + bedrock: bedrock-runtime: cross_Testing: title: Example approaches for unit and integration testing with an &AWS; SDK diff --git a/gov2/bedrock/README.md b/gov2/bedrock/README.md index 274ec2090c9..dee573ec7fb 100644 --- a/gov2/bedrock/README.md +++ b/gov2/bedrock/README.md @@ -39,7 +39,7 @@ For prerequisites, see the [README](../README.md#Prerequisites) in the `gov2` fo Code excerpts that show you how to call individual service functions. -- [List available Amazon Bedrock foundation models](actions/foundation_model.go#L25) (`ListFoundationModels`) +- [List Amazon Bedrock foundation models](actions/foundation_model.go#L25) (`ListFoundationModels`) diff --git a/javav2/example_code/bedrock/Readme.md b/javav2/example_code/bedrock/Readme.md index 79b6770c708..3b4b6ab7ffe 100644 --- a/javav2/example_code/bedrock/Readme.md +++ b/javav2/example_code/bedrock/Readme.md @@ -34,7 +34,7 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `javav Code excerpts that show you how to call individual service functions. -- [List available Amazon Bedrock foundation models](src/main/java/com/example/bedrock/ListFoundationModels.java#L42) (`ListFoundationModels`) +- [List Amazon Bedrock foundation models](src/main/java/com/example/bedrock/ListFoundationModels.java#L42) (`ListFoundationModels`) diff --git a/kotlin/services/bedrock/README.md b/kotlin/services/bedrock/README.md index 3926370f45c..19f7be0a833 100644 --- a/kotlin/services/bedrock/README.md +++ b/kotlin/services/bedrock/README.md @@ -34,7 +34,7 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `kotli Code excerpts that show you how to call individual service functions. -- [List available Amazon Bedrock foundation models](src/main/kotlin/com/example/bedrock/ListFoundationModels.kt#L31) (`ListFoundationModels`) +- [List Amazon Bedrock foundation models](src/main/kotlin/com/example/bedrock/ListFoundationModels.kt#L31) (`ListFoundationModels`) diff --git a/php/example_code/bedrock-runtime/README.md b/php/example_code/bedrock-runtime/README.md index 3c9de45e584..437d099865b 100644 --- a/php/example_code/bedrock-runtime/README.md +++ b/php/example_code/bedrock-runtime/README.md @@ -51,7 +51,7 @@ Code excerpts that show you how to call individual service functions. Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. -- [Invoke multiple LLMs on Amazon Bedrock](GettingStartedWithBedrockRuntime.php) +- [Invoke multiple foundation models on Amazon Bedrock](GettingStartedWithBedrockRuntime.php) @@ -67,9 +67,9 @@ functions within the same service. -#### Invoke multiple LLMs on Amazon Bedrock +#### Invoke multiple foundation models on Amazon Bedrock -This example shows you how to invoke multiple large-language-models (LLMs) on Amazon Bedrock. +This example shows you how to invoke multiple foundation models on Amazon Bedrock. - Generate text with Anthropic Claude. - Generate text with AI21 Labs Jurassic-2. diff --git a/php/example_code/bedrock/README.md b/php/example_code/bedrock/README.md index 3b9c950cc7c..0e65203c6d9 100644 --- a/php/example_code/bedrock/README.md +++ b/php/example_code/bedrock/README.md @@ -40,7 +40,7 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `php` Code excerpts that show you how to call individual service functions. -- [List available Amazon Bedrock foundation models](BedrockService.php#L32) (`ListFoundationModels`) +- [List Amazon Bedrock foundation models](BedrockService.php#L32) (`ListFoundationModels`) diff --git a/python/example_code/bedrock/README.md b/python/example_code/bedrock/README.md index c235b81e0f8..0d65820a487 100644 --- a/python/example_code/bedrock/README.md +++ b/python/example_code/bedrock/README.md @@ -39,7 +39,7 @@ python -m pip install -r requirements.txt Code excerpts that show you how to call individual service functions. -- [List available Amazon Bedrock foundation models](bedrock_wrapper.py#L33) (`ListFoundationModels`) +- [List Amazon Bedrock foundation models](bedrock_wrapper.py#L33) (`ListFoundationModels`) From 3724a598c31a7711f578f72d42de7917c9e8a2c2 Mon Sep 17 00:00:00 2001 From: Rachel Hagerman <110480692+rlhagerm@users.noreply.github.com> Date: Thu, 18 Jan 2024 17:43:41 -0600 Subject: [PATCH 04/36] Revert "Fix and consolidate Bedrock example structure" (#5969) --- .doc_gen/metadata/bedrock-agent_metadata.yaml | 1 - .doc_gen/metadata/bedrock-runtime_metadata.yaml | 6 +++--- .doc_gen/metadata/bedrock_metadata.yaml | 2 +- .doc_gen/metadata/cross_metadata.yaml | 9 ++++----- gov2/bedrock/README.md | 2 +- javav2/example_code/bedrock/Readme.md | 2 +- kotlin/services/bedrock/README.md | 2 +- php/example_code/bedrock-runtime/README.md | 6 +++--- php/example_code/bedrock/README.md | 2 +- python/example_code/bedrock/README.md | 2 +- 10 files changed, 16 insertions(+), 18 deletions(-) diff --git a/.doc_gen/metadata/bedrock-agent_metadata.yaml b/.doc_gen/metadata/bedrock-agent_metadata.yaml index 14f65facfd7..cf3486fe0de 100644 --- a/.doc_gen/metadata/bedrock-agent_metadata.yaml +++ b/.doc_gen/metadata/bedrock-agent_metadata.yaml @@ -158,7 +158,6 @@ bedrock-agent_PrepareAgent: - python.example_code.bedrock-agent.PrepareAgent services: bedrock-agent: {PrepareAgent} - bedrock-agent_GettingStartedWithBedrockAgents: title: An end-to-end example showing how to create and invoke &BR; agents using an &AWS; SDK title_abbrev: Create and invoke an agent diff --git a/.doc_gen/metadata/bedrock-runtime_metadata.yaml b/.doc_gen/metadata/bedrock-runtime_metadata.yaml index 8953de8cbe3..6375dd4380f 100644 --- a/.doc_gen/metadata/bedrock-runtime_metadata.yaml +++ b/.doc_gen/metadata/bedrock-runtime_metadata.yaml @@ -303,9 +303,9 @@ bedrock-runtime_InvokeModelWithResponseStream: bedrock-runtime: {InvokeModelWithResponseStream} bedrock-runtime_Scenario_Invoke_models: - title: Invoke multiple foundation models on &BR; - title_abbrev: Invoke multiple foundation models on &BR; - synopsis: invoke multiple foundation models on &BR;. + title: Invoke multiple large-language models (LLMs) on &BR; + title_abbrev: Invoke multiple LLMs on &BR; + synopsis: invoke multiple large-language-models (LLMs) on &BR;. synopsis_list: - Generate text with Anthropic Claude. - Generate text with AI21 Labs Jurassic-2. diff --git a/.doc_gen/metadata/bedrock_metadata.yaml b/.doc_gen/metadata/bedrock_metadata.yaml index fd323fbb8f4..2c181cc98b4 100644 --- a/.doc_gen/metadata/bedrock_metadata.yaml +++ b/.doc_gen/metadata/bedrock_metadata.yaml @@ -50,7 +50,7 @@ bedrock_GetFoundationModel: bedrock_ListFoundationModels: title: List the available &BRlong; foundation models using an &AWS; SDK - title_abbrev: List &BR; foundation models + title_abbrev: List available &BR; foundation models synopsis: list available &BR; foundation models. category: languages: diff --git a/.doc_gen/metadata/cross_metadata.yaml b/.doc_gen/metadata/cross_metadata.yaml index d60d57542ce..4d5991be9e1 100644 --- a/.doc_gen/metadata/cross_metadata.yaml +++ b/.doc_gen/metadata/cross_metadata.yaml @@ -737,9 +737,9 @@ cross_ResilientService: CreateLoadBalancer, CreateListener, DeleteLoadBalancer, DescribeTargetHealth} iam: {CreateInstanceProfile, DeleteInstanceProfile} cross_FMPlayground: - title: A sample playground application to interact with &BR; foundation models using an &AWS; SDK - title_abbrev: A playground application to interact with foundation models on &BR; - synopsis: interact with various &BR; foundation models through different modalities. + title: Create a sample application that offers playgrounds to interact with &BR; foundation models using an &AWS; SDK + title_abbrev: Create a playground application to interact with &BR; foundation models + synopsis: create playgrounds to interact with &BR; foundation models through different modalities. category: Scenarios languages: .NET: @@ -754,9 +754,8 @@ cross_FMPlayground: versions: - sdk_version: 3 block_content: cross_FMPlayground_Python_block.xml - service_main: bedrock + service_main: bedrock-runtime services: - bedrock: bedrock-runtime: cross_Testing: title: Example approaches for unit and integration testing with an &AWS; SDK diff --git a/gov2/bedrock/README.md b/gov2/bedrock/README.md index dee573ec7fb..274ec2090c9 100644 --- a/gov2/bedrock/README.md +++ b/gov2/bedrock/README.md @@ -39,7 +39,7 @@ For prerequisites, see the [README](../README.md#Prerequisites) in the `gov2` fo Code excerpts that show you how to call individual service functions. -- [List Amazon Bedrock foundation models](actions/foundation_model.go#L25) (`ListFoundationModels`) +- [List available Amazon Bedrock foundation models](actions/foundation_model.go#L25) (`ListFoundationModels`) diff --git a/javav2/example_code/bedrock/Readme.md b/javav2/example_code/bedrock/Readme.md index 3b4b6ab7ffe..79b6770c708 100644 --- a/javav2/example_code/bedrock/Readme.md +++ b/javav2/example_code/bedrock/Readme.md @@ -34,7 +34,7 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `javav Code excerpts that show you how to call individual service functions. -- [List Amazon Bedrock foundation models](src/main/java/com/example/bedrock/ListFoundationModels.java#L42) (`ListFoundationModels`) +- [List available Amazon Bedrock foundation models](src/main/java/com/example/bedrock/ListFoundationModels.java#L42) (`ListFoundationModels`) diff --git a/kotlin/services/bedrock/README.md b/kotlin/services/bedrock/README.md index 19f7be0a833..3926370f45c 100644 --- a/kotlin/services/bedrock/README.md +++ b/kotlin/services/bedrock/README.md @@ -34,7 +34,7 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `kotli Code excerpts that show you how to call individual service functions. -- [List Amazon Bedrock foundation models](src/main/kotlin/com/example/bedrock/ListFoundationModels.kt#L31) (`ListFoundationModels`) +- [List available Amazon Bedrock foundation models](src/main/kotlin/com/example/bedrock/ListFoundationModels.kt#L31) (`ListFoundationModels`) diff --git a/php/example_code/bedrock-runtime/README.md b/php/example_code/bedrock-runtime/README.md index 437d099865b..3c9de45e584 100644 --- a/php/example_code/bedrock-runtime/README.md +++ b/php/example_code/bedrock-runtime/README.md @@ -51,7 +51,7 @@ Code excerpts that show you how to call individual service functions. Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. -- [Invoke multiple foundation models on Amazon Bedrock](GettingStartedWithBedrockRuntime.php) +- [Invoke multiple LLMs on Amazon Bedrock](GettingStartedWithBedrockRuntime.php) @@ -67,9 +67,9 @@ functions within the same service. -#### Invoke multiple foundation models on Amazon Bedrock +#### Invoke multiple LLMs on Amazon Bedrock -This example shows you how to invoke multiple foundation models on Amazon Bedrock. +This example shows you how to invoke multiple large-language-models (LLMs) on Amazon Bedrock. - Generate text with Anthropic Claude. - Generate text with AI21 Labs Jurassic-2. diff --git a/php/example_code/bedrock/README.md b/php/example_code/bedrock/README.md index 0e65203c6d9..3b9c950cc7c 100644 --- a/php/example_code/bedrock/README.md +++ b/php/example_code/bedrock/README.md @@ -40,7 +40,7 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `php` Code excerpts that show you how to call individual service functions. -- [List Amazon Bedrock foundation models](BedrockService.php#L32) (`ListFoundationModels`) +- [List available Amazon Bedrock foundation models](BedrockService.php#L32) (`ListFoundationModels`) diff --git a/python/example_code/bedrock/README.md b/python/example_code/bedrock/README.md index 0d65820a487..c235b81e0f8 100644 --- a/python/example_code/bedrock/README.md +++ b/python/example_code/bedrock/README.md @@ -39,7 +39,7 @@ python -m pip install -r requirements.txt Code excerpts that show you how to call individual service functions. -- [List Amazon Bedrock foundation models](bedrock_wrapper.py#L33) (`ListFoundationModels`) +- [List available Amazon Bedrock foundation models](bedrock_wrapper.py#L33) (`ListFoundationModels`) From e74e09efca15ce38e7b484b9b73281ea6bd2c180 Mon Sep 17 00:00:00 2001 From: Laren-AWS <57545972+Laren-AWS@users.noreply.github.com> Date: Fri, 19 Jan 2024 07:06:25 -0800 Subject: [PATCH 05/36] [Metadata] Cognito and Kinsesis metadata updates (#5935) * Update metadata and snippets from Cognito examples, per feedback. Update Kinesis Data Analytics -> Managed Apache Flink --- .../cognito-identity-provider_metadata.yaml | 16 +-- .../kinesis-analytics-v2_metadata.yaml | 50 ++-------- .doc_gen/metadata/services.yaml | 10 +- .../cognito/cognito_idp_actions.py | 4 + .../kinesis-analytics-v2/README.md | 99 +++++++++++++++++++ .../analytics_application.py | 0 .../example.sql | 0 .../kinesisanalyticsv2_demo.py | 29 ++++-- .../kinesis-analytics-v2/requirements.txt | 2 + .../kinesis-analytics-v2/test/conftest.py | 13 +++ .../test/test_analytics_application.py | 2 +- python/example_code/kinesis/README.md | 6 +- 12 files changed, 166 insertions(+), 65 deletions(-) create mode 100644 python/example_code/kinesis-analytics-v2/README.md rename python/example_code/{kinesis/analyticsv2 => kinesis-analytics-v2}/analytics_application.py (100%) rename python/example_code/{kinesis/analyticsv2 => kinesis-analytics-v2}/example.sql (100%) rename python/example_code/{kinesis => kinesis-analytics-v2}/kinesisanalyticsv2_demo.py (84%) create mode 100644 python/example_code/kinesis-analytics-v2/requirements.txt create mode 100644 python/example_code/kinesis-analytics-v2/test/conftest.py rename python/example_code/{kinesis => kinesis-analytics-v2}/test/test_analytics_application.py (99%) diff --git a/.doc_gen/metadata/cognito-identity-provider_metadata.yaml b/.doc_gen/metadata/cognito-identity-provider_metadata.yaml index a2268cab0b6..2987a16dbc0 100644 --- a/.doc_gen/metadata/cognito-identity-provider_metadata.yaml +++ b/.doc_gen/metadata/cognito-identity-provider_metadata.yaml @@ -672,9 +672,9 @@ cognito-identity-provider_ConfirmDevice: services: cognito-identity-provider: {ConfirmDevice} cognito-identity-provider_InitiateAuth: - title: Start authentication with a device tracked by &COG; using an &AWS; SDK - title_abbrev: Start authentication with a tracked device - synopsis: start authentication with a device tracked by &COG;. + title: Start authentication using an &AWS; SDK + title_abbrev: Start authentication + synopsis: start authentication with &COG;. category: languages: .NET: @@ -692,9 +692,8 @@ cognito-identity-provider_InitiateAuth: github: python/example_code/cognito sdkguide: excerpts: - - description: Sign in with a tracked device. To complete sign-in, - the client must respond correctly to Secure Remote Password (SRP) - challenges. + - description: This example shows you how to start authentication with a tracked device. To complete + sign-in, the client must respond correctly to Secure Remote Password (SRP) challenges. snippet_tags: - python.example_code.cognito-idp.helper.CognitoIdentityProviderWrapper.decl - python.example_code.cognito-idp.InitiateAuth @@ -833,7 +832,10 @@ cognito-identity-provider_Scenario_SignUpUserWithMfa: github: python/example_code/cognito sdkguide: excerpts: - - description: In addition to the previously listed steps, this example + - description: Create a class that wraps &COG; functions used in the scenario. + snippet_tags: + - python.example_code.cognito-idp.CognitoIdentityProviderWrapper.full + - description: Create a class that runs the scenario. This example also registers an MFA device to be tracked by &COG; and shows you how to sign in by using a password and information from the tracked device. This avoids the need to enter a new MFA code. diff --git a/.doc_gen/metadata/kinesis-analytics-v2_metadata.yaml b/.doc_gen/metadata/kinesis-analytics-v2_metadata.yaml index e20e91c6a6b..671b97fac43 100644 --- a/.doc_gen/metadata/kinesis-analytics-v2_metadata.yaml +++ b/.doc_gen/metadata/kinesis-analytics-v2_metadata.yaml @@ -8,7 +8,7 @@ kinesis-analytics-v2_CreateApplication: Python: versions: - sdk_version: 3 - github: python/example_code/kinesis + github: python/example_code/kinesis-analytics-v2 sdkguide: excerpts: - description: @@ -26,7 +26,7 @@ kinesis-analytics-v2_DeleteApplication: Python: versions: - sdk_version: 3 - github: python/example_code/kinesis + github: python/example_code/kinesis-analytics-v2 sdkguide: excerpts: - description: @@ -44,7 +44,7 @@ kinesis-analytics-v2_DescribeApplication: Python: versions: - sdk_version: 3 - github: python/example_code/kinesis + github: python/example_code/kinesis-analytics-v2 sdkguide: excerpts: - description: @@ -62,7 +62,7 @@ kinesis-analytics-v2_DescribeApplicationSnapshot: Python: versions: - sdk_version: 3 - github: python/example_code/kinesis + github: python/example_code/kinesis-analytics-v2 sdkguide: excerpts: - description: @@ -80,7 +80,7 @@ kinesis-analytics-v2_DiscoverInputSchema: Python: versions: - sdk_version: 3 - github: python/example_code/kinesis + github: python/example_code/kinesis-analytics-v2 sdkguide: excerpts: - description: @@ -98,7 +98,7 @@ kinesis-analytics-v2_AddApplicationInput: Python: versions: - sdk_version: 3 - github: python/example_code/kinesis + github: python/example_code/kinesis-analytics-v2 sdkguide: excerpts: - description: @@ -116,7 +116,7 @@ kinesis-analytics-v2_AddApplicationOutput: Python: versions: - sdk_version: 3 - github: python/example_code/kinesis + github: python/example_code/kinesis-analytics-v2 sdkguide: excerpts: - description: @@ -134,7 +134,7 @@ kinesis-analytics-v2_UpdateApplication: Python: versions: - sdk_version: 3 - github: python/example_code/kinesis + github: python/example_code/kinesis-analytics-v2 sdkguide: excerpts: - description: This example updates the code that runs in an existing application. @@ -152,7 +152,7 @@ kinesis-analytics-v2_StartApplication: Python: versions: - sdk_version: 3 - github: python/example_code/kinesis + github: python/example_code/kinesis-analytics-v2 sdkguide: excerpts: - description: @@ -170,7 +170,7 @@ kinesis-analytics-v2_StopApplication: Python: versions: - sdk_version: 3 - github: python/example_code/kinesis + github: python/example_code/kinesis-analytics-v2 sdkguide: excerpts: - description: @@ -183,9 +183,6 @@ kinesis-analytics-v2_DataGenerator_Anomaly: title: Generate a &AK; stream with heart rate anomalies using an &AWS; SDK title_abbrev: Generate a stream with heart rate anomalies synopsis: generate a &AK; stream with heart rate anomalies. - guide_topic: - title: "Example: Detecting data anomalies on a stream" - url: kinesisanalytics/latest/dev/app-anomaly-detection.html category: Data generator languages: Python: @@ -204,9 +201,6 @@ kinesis-analytics-v2_DataGenerator_AnomalyEx: title_abbrev: Generate a stream with blood pressure anomalies synopsis: generate a &AK; stream with blood pressure anomalies. category: Data generator - guide_topic: - title: "Example: Detecting data anomalies and getting an explanation" - url: kinesisanalytics/latest/dev/app-anomaly-detection-with-explanation.html languages: Python: versions: @@ -224,9 +218,6 @@ kinesis-analytics-v2_DataGenerator_ColumnLog: title_abbrev: Generate a stream with data in columns synopsis: generate a &AK; stream with data in columns. category: Data generator - guide_topic: - title: "Example: Split strings into multiple fields" - url: kinesisanalytics/latest/dev/examples-transforming-strings-variablecolumnlogparse.html languages: Python: versions: @@ -244,9 +235,6 @@ kinesis-analytics-v2_DataGenerator_Hotspots: title_abbrev: Generate a stream with hotspots synopsis: generate a &AK; stream with hotspots. category: Data generator - guide_topic: - title: "Example: Detecting hotspot on a stream" - url: kinesisanalytics/latest/dev/app-hotspots-detection.html languages: Python: versions: @@ -264,9 +252,6 @@ kinesis-analytics-v2_DataGenerator_Referrer: title_abbrev: Generate a stream with a referrer synopsis: generate a &AK; stream with a referrer. category: Data generator - guide_topic: - title: "Example: Extracting a portion of a stream" - url: kinesisanalytics/latest/dev/examples-transforming-strings-substring.html languages: Python: versions: @@ -284,9 +269,6 @@ kinesis-analytics-v2_DataGenerator_RegexLog: title_abbrev: Generate a stream with log entries synopsis: generate a &AK; stream with log entries. category: Data generator - guide_topic: - title: "Example: Parsing log strings based on regular expressions" - url: kinesisanalytics/latest/dev/examples-transforming-strings-regexlogparse.html languages: Python: versions: @@ -304,9 +286,6 @@ kinesis-analytics-v2_DataGenerator_Stagger: title_abbrev: Generate a stream with stagger data synopsis: generate a &AK; stream with stagger data. category: Data generator - guide_topic: - title: "Example: Stagger window" - url: kinesisanalytics/latest/dev/examples-window-stagger.html languages: Python: versions: @@ -324,9 +303,6 @@ kinesis-analytics-v2_DataGenerator_StockTicker: title_abbrev: Generate a stream with stock ticker data synopsis: generate a &AK; stream with stock ticker data. category: Data generator - guide_topic: - title: "Examples: Windows and aggregation" - url: kinesisanalytics/latest/dev/examples-window.html languages: Python: versions: @@ -344,9 +320,6 @@ kinesis-analytics-v2_DataGenerator_TwoRecordTypes: title_abbrev: Generate a stream with two data types synopsis: generate a &AK; stream with two data types. category: Data generator - guide_topic: - title: "Example: Transforming multiple data types" - url: kinesisanalytics/latest/dev/app-tworecordtypes.html languages: Python: versions: @@ -364,9 +337,6 @@ kinesis-analytics-v2_DataGenerator_WebLog: title_abbrev: Generate a stream with web log data synopsis: generate a &AK; stream with web log data. category: Data generator - guide_topic: - title: "Example: Parsing web logs" - url: kinesisanalytics/latest/dev/examples-transforming-strings-w3clogparse.html languages: Python: versions: diff --git a/.doc_gen/metadata/services.yaml b/.doc_gen/metadata/services.yaml index 2fc2c8663a9..d434b54e936 100644 --- a/.doc_gen/metadata/services.yaml +++ b/.doc_gen/metadata/services.yaml @@ -1772,15 +1772,15 @@ kinesis: kinesis-analytics-v2: long: '&AKAlong;' short: '&AKA;' - sort: Kinesis Data Analytics + sort: Managed Service for Apache Flink expanded: - long: Amazon Kinesis Data Analytics - short: Kinesis Data Analytics + long: Amazon Managed Service for Apache Flink + short: Managed Service for Apache Flink blurb: processes and analyzes streaming data using SQL or Java. guide: subtitle: Developer Guide - url: kinesisanalytics/latest/dev/what-is.html - api_ref: kinesisanalytics/latest/apiv2/Welcome.html + url: managed-flink/latest/java/what-is.html + api_ref: managed-flink/latest/apiv2/Welcome.html tags: product_categories: {'Analytics'} version: kinesisanalyticsv2-2018-05-23 diff --git a/python/example_code/cognito/cognito_idp_actions.py b/python/example_code/cognito/cognito_idp_actions.py index 6d046e4af4e..e830755c353 100644 --- a/python/example_code/cognito/cognito_idp_actions.py +++ b/python/example_code/cognito/cognito_idp_actions.py @@ -19,6 +19,7 @@ logger = logging.getLogger(__name__) +# snippet-start:[python.example_code.cognito-idp.CognitoIdentityProviderWrapper.full] # snippet-start:[python.example_code.cognito-idp.helper.CognitoIdentityProviderWrapper.decl] class CognitoIdentityProviderWrapper: """Encapsulates Amazon Cognito actions""" @@ -495,3 +496,6 @@ def sign_in_with_tracked_device( # snippet-end:[python.example_code.cognito-idp.RespondToAuthChallenge] # snippet-end:[python.example_code.cognito-idp.InitiateAuth] + + +# snippet-end:[python.example_code.cognito-idp.CognitoIdentityProviderWrapper.full] diff --git a/python/example_code/kinesis-analytics-v2/README.md b/python/example_code/kinesis-analytics-v2/README.md new file mode 100644 index 00000000000..3bffaf41739 --- /dev/null +++ b/python/example_code/kinesis-analytics-v2/README.md @@ -0,0 +1,99 @@ +# Managed Service for Apache Flink code examples for the SDK for Python + +## Overview + +Shows how to use the AWS SDK for Python (Boto3) to work with Amazon Managed Service for Apache Flink. + + + + +_Managed Service for Apache Flink processes and analyzes streaming data using SQL or Java._ + +## ⚠ Important + +* Running this code might result in charges to your AWS account. For more details, see [AWS Pricing](https://aws.amazon.com/pricing/) and [Free Tier](https://aws.amazon.com/free/). +* Running the tests might result in charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + + + + +## Code examples + +### Prerequisites + +For prerequisites, see the [README](../../README.md#Prerequisites) in the `python` folder. + +Install the packages required by these examples by running the following in a virtual environment: + +``` +python -m pip install -r requirements.txt +``` + + + + +### Single actions + +Code excerpts that show you how to call individual service functions. + +- [Add an input stream to an application](analytics_application.py#L257) (`AddApplicationInput`) +- [Add an output stream to an application](analytics_application.py#L294) (`AddApplicationOutput`) +- [Create an application](analytics_application.py#L129) (`CreateApplication`) +- [Delete an application](analytics_application.py#L158) (`DeleteApplication`) +- [Describe an application](analytics_application.py#L174) (`DescribeApplication`) +- [Describe an application snapshot](analytics_application.py#L195) (`DescribeApplicationSnapshot`) +- [Discover a data format for a stream](analytics_application.py#L226) (`DiscoverInputSchema`) +- [Start an application](analytics_application.py#L365) (`StartApplication`) +- [Stop an application](analytics_application.py#L394) (`StopApplication`) +- [Update an application](analytics_application.py#L332) (`UpdateApplication`) + + + + + +## Run the examples + +### Instructions + + + +The action examples in this section are demonstrated as part of a scenario that reads +data from an input stream, uses SQL code to transform the data, and writes it to an +output stream. Run the scenario at a command prompt with the following command: + +``` +python kinesisanalyticsv2_demo.py +``` + + + + +### Tests + +⚠ Running tests might result in charges to your AWS account. + + +To find instructions for running these tests, see the [README](../../README.md#Tests) +in the `python` folder. + + + + + + +## Additional resources + +- [Managed Service for Apache Flink Developer Guide](https://docs.aws.amazon.com/managed-flink/latest/java/what-is.html) +- [Managed Service for Apache Flink API Reference](https://docs.aws.amazon.com/managed-flink/latest/apiv2/Welcome.html) +- [SDK for Python Managed Service for Apache Flink reference](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/kinesisanalyticsv2.html) + + + + +--- + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 \ No newline at end of file diff --git a/python/example_code/kinesis/analyticsv2/analytics_application.py b/python/example_code/kinesis-analytics-v2/analytics_application.py similarity index 100% rename from python/example_code/kinesis/analyticsv2/analytics_application.py rename to python/example_code/kinesis-analytics-v2/analytics_application.py diff --git a/python/example_code/kinesis/analyticsv2/example.sql b/python/example_code/kinesis-analytics-v2/example.sql similarity index 100% rename from python/example_code/kinesis/analyticsv2/example.sql rename to python/example_code/kinesis-analytics-v2/example.sql diff --git a/python/example_code/kinesis/kinesisanalyticsv2_demo.py b/python/example_code/kinesis-analytics-v2/kinesisanalyticsv2_demo.py similarity index 84% rename from python/example_code/kinesis/kinesisanalyticsv2_demo.py rename to python/example_code/kinesis-analytics-v2/kinesisanalyticsv2_demo.py index f12c82db5ae..862a6007a1f 100644 --- a/python/example_code/kinesis/kinesisanalyticsv2_demo.py +++ b/python/example_code/kinesis-analytics-v2/kinesisanalyticsv2_demo.py @@ -4,27 +4,29 @@ """ Purpose -Shows how to use the AWS SDK for Python (Boto3) with Amazon Kinesis and version 2 of -the Amazon Kinesis Data Analytics API to create an application that reads data from -an input stream, uses SQL code to transform the data, and writes it to an output -stream. +Shows how to use the AWS SDK for Python (Boto3) with Amazon Managed Service for Apache Flink +and Amazon Kinesis to create an application that reads data from an input stream, uses +SQL code to transform the data, and writes it to an output stream. """ import logging +import os from pprint import pprint import sys import threading import time import boto3 +from botocore.exceptions import ClientError -from analyticsv2.analytics_application import KinesisAnalyticsApplicationV2 +from analytics_application import KinesisAnalyticsApplicationV2 + +sys.path.append(os.path.abspath("../kinesis")) from streams.kinesis_stream import KinesisStream from streams.dg_anomaly import generate # Add relative path to include demo_tools in this code example without need for setup. sys.path.append("../..") from demo_tools.custom_waiter import CustomWaiter, WaitState -from demo_tools.retries import exponential_retry logger = logging.getLogger(__name__) @@ -98,9 +100,16 @@ def usage_demo(): print(f"Creating application {app_name}.") # Sometimes the role is still not ready and InvalidArgumentException is raised, so # continue to retry if this happens. - app_data = exponential_retry("InvalidArgumentException")(application.create)( - app_name, role.arn - ) + app_data = None + while app_data is None: + try: + app_data = application.create(app_name, role.arn) + except ClientError as error: + if error.response["Error"]["Code"] == "InvalidArgumentException": + print("Waiting for 5 seconds to give AWS time to connect resources.") + time.sleep(5) + else: + raise pprint(app_data) print(f"Discovering schema of input stream {input_stream.name}.") input_schema = application.discover_input_schema(input_stream.arn(), role.arn) @@ -114,7 +123,7 @@ def usage_demo(): pprint(input_details) print("Uploading SQL code to the application to process the input stream.") - with open("analyticsv2/example.sql") as code_file: + with open("example.sql") as code_file: code = code_file.read() application.update_code(code) diff --git a/python/example_code/kinesis-analytics-v2/requirements.txt b/python/example_code/kinesis-analytics-v2/requirements.txt new file mode 100644 index 00000000000..621e276912d --- /dev/null +++ b/python/example_code/kinesis-analytics-v2/requirements.txt @@ -0,0 +1,2 @@ +boto3>=1.26.79 +pytest>=7.2.1 diff --git a/python/example_code/kinesis-analytics-v2/test/conftest.py b/python/example_code/kinesis-analytics-v2/test/conftest.py new file mode 100644 index 00000000000..d0236963531 --- /dev/null +++ b/python/example_code/kinesis-analytics-v2/test/conftest.py @@ -0,0 +1,13 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +Contains common test fixtures used to run unit tests. +""" + +import random +import sys + +# This is needed so Python can find test_tools on the path. +sys.path.append("../..") +from test_tools.fixtures.common import * diff --git a/python/example_code/kinesis/test/test_analytics_application.py b/python/example_code/kinesis-analytics-v2/test/test_analytics_application.py similarity index 99% rename from python/example_code/kinesis/test/test_analytics_application.py rename to python/example_code/kinesis-analytics-v2/test/test_analytics_application.py index 792f1259493..fe188154f0c 100644 --- a/python/example_code/kinesis/test/test_analytics_application.py +++ b/python/example_code/kinesis-analytics-v2/test/test_analytics_application.py @@ -10,7 +10,7 @@ from botocore.exceptions import ClientError, WaiterError import pytest -from analyticsv2.analytics_application import KinesisAnalyticsApplicationV2 +from analytics_application import KinesisAnalyticsApplicationV2 @pytest.mark.parametrize("error_code", [None, "TestException"]) diff --git a/python/example_code/kinesis/README.md b/python/example_code/kinesis/README.md index ba8564b501e..43e2eff8760 100644 --- a/python/example_code/kinesis/README.md +++ b/python/example_code/kinesis/README.md @@ -54,8 +54,10 @@ Code excerpts that show you how to call individual service functions. -Run the Kinesis Data Analytics usage demonstration at a command prompt with -the following command: +The action examples in this section are demonstrated as part of an Amazon Managed Service +for Apache Flink scenario that reads data from an input stream, uses SQL code to transform +the data, and writes it to an output stream. Run the scenario at a command prompt in +the `kinesis-analytics-v2` folder with the following command: ``` python kinesisanalyticsv2_demo.py From ad65925695d07a40cde604d9e3a564fc99ca88ba Mon Sep 17 00:00:00 2001 From: Dennis Traub Date: Fri, 19 Jan 2024 22:56:47 +0100 Subject: [PATCH 06/36] JavaScript v3: Add code examples to demonstrate the InvokeModel actions with multiple foundation models (#5930) Co-authored-by: Dennis Traub --- .../metadata/bedrock-runtime_metadata.yaml | 17 +++- .../example_code/bedrock-runtime/README.md | 94 +++++++++++++++++++ .../bedrock-runtime/actions/invoke-claude.js | 70 ++++++++++++++ .../actions/invoke-jurassic2.js | 72 ++++++++++++++ .../example_code/bedrock-runtime/package.json | 16 ++++ .../tests/invoke-model.integration.test.js | 25 +++++ .../bedrock-runtime/vite.config.js | 11 +++ javascriptv3/package.json | 1 + 8 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 javascriptv3/example_code/bedrock-runtime/README.md create mode 100644 javascriptv3/example_code/bedrock-runtime/actions/invoke-claude.js create mode 100644 javascriptv3/example_code/bedrock-runtime/actions/invoke-jurassic2.js create mode 100644 javascriptv3/example_code/bedrock-runtime/package.json create mode 100644 javascriptv3/example_code/bedrock-runtime/tests/invoke-model.integration.test.js create mode 100644 javascriptv3/example_code/bedrock-runtime/vite.config.js diff --git a/.doc_gen/metadata/bedrock-runtime_metadata.yaml b/.doc_gen/metadata/bedrock-runtime_metadata.yaml index 6375dd4380f..cd5c792ecb2 100644 --- a/.doc_gen/metadata/bedrock-runtime_metadata.yaml +++ b/.doc_gen/metadata/bedrock-runtime_metadata.yaml @@ -108,7 +108,6 @@ bedrock-runtime_InvokeClaude: title: Invoke the Anthropic Claude 2 model on &BR; for text generation title_abbrev: Text generation with Anthropic Claude 2 synopsis: invoke the Anthropic Claude 2 model on &BR; for text generation. - category: languages: Go: versions: @@ -129,6 +128,14 @@ bedrock-runtime_InvokeClaude: - description: Invoke the Anthropic Claude 2 foundation model to generate text. snippet_tags: - bedrock-runtime.java2.invoke_claude.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/bedrock-runtime + excerpts: + - description: Invoke the Anthropic Claude 2 foundation model to generate text. + snippet_files: + - javascriptv3/example_code/bedrock-runtime/actions/invoke-claude.js PHP: versions: - sdk_version: 3 @@ -190,6 +197,14 @@ bedrock-runtime_InvokeJurassic2: - description: Invoke the AI21 Labs Jurassic-2 foundation model to generate text. snippet_tags: - bedrock-runtime.java2.invoke_jurassic2.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/bedrock-runtime + excerpts: + - description: Invoke the AI21 Labs Jurassic-2 foundation model to generate text. + snippet_files: + - javascriptv3/example_code/bedrock-runtime/actions/invoke-jurassic2.js PHP: versions: - sdk_version: 3 diff --git a/javascriptv3/example_code/bedrock-runtime/README.md b/javascriptv3/example_code/bedrock-runtime/README.md new file mode 100644 index 00000000000..9f32379093a --- /dev/null +++ b/javascriptv3/example_code/bedrock-runtime/README.md @@ -0,0 +1,94 @@ +# Amazon Bedrock Runtime code examples for the SDK for JavaScript (v3) + +## Overview + +Shows how to use the AWS SDK for JavaScript (v3) to work with Amazon Bedrock Runtime. + + + + +_Amazon Bedrock Runtime is a fully managed service that makes it easy to use foundation models from third-party providers and Amazon._ + +## ⚠ Important + +* Running this code might result in charges to your AWS account. For more details, see [AWS Pricing](https://aws.amazon.com/pricing/) and [Free Tier](https://aws.amazon.com/free/). +* Running the tests might result in charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + + + + +## Code examples + +### Prerequisites + +For prerequisites, see the [README](../../README.md#Prerequisites) in the `javascriptv3` folder. + + + +> ⚠ You must request access to a model before you can use it. If you try to use the model (with the API or console) before you have requested access to it, you will receive an error message. For more information, see [Model access](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html). + + +### Single actions + +Code excerpts that show you how to call individual service functions. + +- [Text generation with AI21 Labs Jurassic-2](javascriptv3/example_code/bedrock-runtime/actions/invoke-jurassic2.js) (`InvokeModel`) +- [Text generation with Anthropic Claude 2](javascriptv3/example_code/bedrock-runtime/actions/invoke-claude.js) (`InvokeModel`) + + + + + +## Run the examples + +### Instructions + +**Note**: All code examples are written in ECMAscript 6 (ES6). For guidelines on converting to CommonJS, see +[JavaScript ES6/CommonJS syntax](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/sdk-examples-javascript-syntax.html). + +**Run a single action** + +```bash +node ./actions/ +``` + +**Run a scenario** +Most scenarios can be run with the following command: +```bash +node ./scenarios/ +``` + + + + + + +### Tests + +⚠ Running tests might result in charges to your AWS account. + + +To find instructions for running these tests, see the [README](../../README.md#Tests) +in the `javascriptv3` folder. + + + + + + +## Additional resources + +- [Amazon Bedrock Runtime User Guide](https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html) +- [Amazon Bedrock Runtime API Reference](https://docs.aws.amazon.com/bedrock/latest/APIReference/welcome.html) +- [SDK for JavaScript (v3) Amazon Bedrock Runtime reference](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/bedrock-runtime) + + + + +--- + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 \ No newline at end of file diff --git a/javascriptv3/example_code/bedrock-runtime/actions/invoke-claude.js b/javascriptv3/example_code/bedrock-runtime/actions/invoke-claude.js new file mode 100644 index 00000000000..181ea726a7b --- /dev/null +++ b/javascriptv3/example_code/bedrock-runtime/actions/invoke-claude.js @@ -0,0 +1,70 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import {fileURLToPath} from "url"; + +import {BedrockRuntimeClient, InvokeModelCommand} from "@aws-sdk/client-bedrock-runtime"; + +/** + * @typedef {Object} ResponseBody + * @property {string} completion + */ + +/** + * Invokes the Anthropic Claude 2 model to run an inference using the input + * provided in the request body. + * + * @param {string} prompt - The prompt that you want Claude to complete. + * @returns {string} The inference response (completion) from the model. + */ +export const invokeClaude = async (prompt) => { + const client = new BedrockRuntimeClient( { region: 'us-east-1' } ); + + const modelId = 'anthropic.claude-v2'; + + /* Claude requires you to enclose the prompt as follows: */ + const enclosedPrompt = `Human: ${prompt}\n\nAssistant:`; + + /* The different model providers have individual request and response formats. + * For the format, ranges, and default values for Anthropic Claude, refer to: + * https://docs.anthropic.com/claude/reference/complete_post + */ + const payload = { + prompt: enclosedPrompt, + max_tokens_to_sample: 500, + temperature: 0.5, + stop_sequences: [ '\n\nHuman:' ], + }; + + const command = new InvokeModelCommand({ + body: JSON.stringify(payload), + contentType: 'application/json', + accept: 'application/json', + modelId, + }); + + try { + const response = await client.send(command); + const decodedResponseBody = new TextDecoder().decode(response.body); + + /** @type {ResponseBody} */ + const responseBody = JSON.parse(decodedResponseBody); + + return responseBody.completion; + + } catch (err) { + console.error(err); + } +}; + +// Invoke the function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + const prompt = 'Complete the following: "Once upon a time..."'; + console.log('\nModel: Anthropic Claude v2'); + console.log(`Prompt: ${prompt}`); + + const completion = await invokeClaude(prompt); + console.log('Completion:'); + console.log(completion); + console.log('\n'); +} diff --git a/javascriptv3/example_code/bedrock-runtime/actions/invoke-jurassic2.js b/javascriptv3/example_code/bedrock-runtime/actions/invoke-jurassic2.js new file mode 100644 index 00000000000..9c1f59fe1d3 --- /dev/null +++ b/javascriptv3/example_code/bedrock-runtime/actions/invoke-jurassic2.js @@ -0,0 +1,72 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import {fileURLToPath} from "url"; + +import {BedrockRuntimeClient, InvokeModelCommand} from "@aws-sdk/client-bedrock-runtime"; + +/** + * @typedef {Object} Data + * @property {string} text + * + * @typedef {Object} Completion + * @property {Data} data + * + * @typedef {Object} ResponseBody + * @property {Completion[]} completions + */ + +/** + * Invokes the AI21 Labs Jurassic-2 large-language model to run an inference + * using the input provided in the request body. + * + * @param {string} prompt - The prompt that you want Jurassic-2 to complete. + * @returns {string} The inference response (completion) from the model. + */ +export const invokeJurassic2 = async (prompt) => { + const client = new BedrockRuntimeClient( { region: 'us-east-1' } ); + + const modelId = 'ai21.j2-mid-v1'; + + /* The different model providers have individual request and response formats. + * For the format, ranges, and default values for AI21 Labs Jurassic-2, refer to: + * https://docs.ai21.com/reference/j2-complete-ref + */ + const payload = { + prompt, + maxTokens: 500, + temperature: 0.5, + }; + + const command = new InvokeModelCommand({ + body: JSON.stringify(payload), + contentType: 'application/json', + accept: 'application/json', + modelId, + }); + + try { + const response = await client.send(command); + const decodedResponseBody = new TextDecoder().decode(response.body); + + /** @type {ResponseBody} */ + const responseBody = JSON.parse(decodedResponseBody); + + return responseBody.completions[0].data.text; + + } catch (err) { + console.error(err); + } +}; + +// Invoke the function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + const prompt = 'Complete the following: "Once upon a time..."'; + console.log('\nModel: AI21 Labs Jurassic-2'); + console.log(`Prompt: ${prompt}`); + + const completion = await invokeJurassic2(prompt); + console.log('Completion:'); + console.log(completion); + console.log('\n'); +} diff --git a/javascriptv3/example_code/bedrock-runtime/package.json b/javascriptv3/example_code/bedrock-runtime/package.json new file mode 100644 index 00000000000..ae532a4c7c1 --- /dev/null +++ b/javascriptv3/example_code/bedrock-runtime/package.json @@ -0,0 +1,16 @@ +{ + "name": "bedrock-runtime-examples", + "version": "1.0.0", + "author": "Dennis Traub ", + "license": "Apache-2.0", + "type": "module", + "scripts": { + "integration-test": "vitest run **/*.integration.test.js" + }, + "dependencies": { + "@aws-sdk/client-bedrock-runtime": "^3.489.0" + }, + "devDependencies": { + "vitest": "^1.1.3" + } +} diff --git a/javascriptv3/example_code/bedrock-runtime/tests/invoke-model.integration.test.js b/javascriptv3/example_code/bedrock-runtime/tests/invoke-model.integration.test.js new file mode 100644 index 00000000000..42a6b2dad99 --- /dev/null +++ b/javascriptv3/example_code/bedrock-runtime/tests/invoke-model.integration.test.js @@ -0,0 +1,25 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, it, expect } from "vitest"; + +import { invokeClaude } from '../actions/invoke-claude.js'; +import { invokeJurassic2 } from '../actions/invoke-jurassic2.js'; + +const TEST_PROMPT = 'Hello, this is a test prompt'; + +describe('invoke claude with test prompt', () => { + it('should return a text completion', async () => { + const response = await invokeClaude(TEST_PROMPT); + expect(typeof response).toBe('string'); + expect(response).not.toBe(''); + }) +}) + +describe('invoke jurassic-2 with test prompt', () => { + it('should return a text completion', async () => { + const response = await invokeJurassic2(TEST_PROMPT); + expect(typeof response).toBe('string'); + expect(response).not.toBe(''); + }) +}) diff --git a/javascriptv3/example_code/bedrock-runtime/vite.config.js b/javascriptv3/example_code/bedrock-runtime/vite.config.js new file mode 100644 index 00000000000..b37db909158 --- /dev/null +++ b/javascriptv3/example_code/bedrock-runtime/vite.config.js @@ -0,0 +1,11 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + testTimeout: 50000, + threads: false, + }, +}); diff --git a/javascriptv3/package.json b/javascriptv3/package.json index bcdc01c6dc7..7f662cd0ca9 100644 --- a/javascriptv3/package.json +++ b/javascriptv3/package.json @@ -19,6 +19,7 @@ "workspaces": [ "example_code/auto-scaling", "example_code/bedrock", + "example_code/bedrock-runtime", "example_code/cloudwatch", "example_code/cloudwatch-events", "example_code/cloudwatch-logs", From dcf5e6897a5f070e5be8cfc940c002c1ea5c31e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 08:42:59 -0600 Subject: [PATCH 07/36] Bump vite from 4.1.5 to 4.5.2 in /resources/clients/react/elros (#5971) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.1.5 to 4.5.2. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v4.5.2/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v4.5.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../clients/react/elros/package-lock.json | 535 +++++++----------- resources/clients/react/elros/package.json | 2 +- 2 files changed, 215 insertions(+), 322 deletions(-) diff --git a/resources/clients/react/elros/package-lock.json b/resources/clients/react/elros/package-lock.json index 62e14ec0adb..800f0769b14 100644 --- a/resources/clients/react/elros/package-lock.json +++ b/resources/clients/react/elros/package-lock.json @@ -20,7 +20,7 @@ "@types/react-dom": "^18.0.10", "@vitejs/plugin-react": "^3.1.0", "typescript": "^4.9.3", - "vite": "^4.1.5" + "vite": "^4.5.2" } }, "node_modules/@ampproject/remapping": { @@ -463,9 +463,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", - "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "cpu": [ "arm" ], @@ -479,9 +479,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", - "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "cpu": [ "arm64" ], @@ -495,9 +495,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", - "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "cpu": [ "x64" ], @@ -511,9 +511,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", - "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "cpu": [ "arm64" ], @@ -527,9 +527,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", - "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "cpu": [ "x64" ], @@ -543,9 +543,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", - "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "cpu": [ "arm64" ], @@ -559,9 +559,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", - "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "cpu": [ "x64" ], @@ -575,9 +575,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", - "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "cpu": [ "arm" ], @@ -591,9 +591,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", - "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "cpu": [ "arm64" ], @@ -607,9 +607,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", - "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "cpu": [ "ia32" ], @@ -623,9 +623,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", - "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "cpu": [ "loong64" ], @@ -639,9 +639,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", - "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "cpu": [ "mips64el" ], @@ -655,9 +655,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", - "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "cpu": [ "ppc64" ], @@ -671,9 +671,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", - "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "cpu": [ "riscv64" ], @@ -687,9 +687,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", - "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "cpu": [ "s390x" ], @@ -703,9 +703,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", - "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "cpu": [ "x64" ], @@ -719,9 +719,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", - "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "cpu": [ "x64" ], @@ -735,9 +735,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", - "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "cpu": [ "x64" ], @@ -751,9 +751,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", - "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "cpu": [ "x64" ], @@ -767,9 +767,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", - "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "cpu": [ "arm64" ], @@ -783,9 +783,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", - "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "cpu": [ "ia32" ], @@ -799,9 +799,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", - "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "cpu": [ "x64" ], @@ -1124,9 +1124,9 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", - "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "hasInstallScript": true, "bin": { @@ -1136,28 +1136,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.16.17", - "@esbuild/android-arm64": "0.16.17", - "@esbuild/android-x64": "0.16.17", - "@esbuild/darwin-arm64": "0.16.17", - "@esbuild/darwin-x64": "0.16.17", - "@esbuild/freebsd-arm64": "0.16.17", - "@esbuild/freebsd-x64": "0.16.17", - "@esbuild/linux-arm": "0.16.17", - "@esbuild/linux-arm64": "0.16.17", - "@esbuild/linux-ia32": "0.16.17", - "@esbuild/linux-loong64": "0.16.17", - "@esbuild/linux-mips64el": "0.16.17", - "@esbuild/linux-ppc64": "0.16.17", - "@esbuild/linux-riscv64": "0.16.17", - "@esbuild/linux-s390x": "0.16.17", - "@esbuild/linux-x64": "0.16.17", - "@esbuild/netbsd-x64": "0.16.17", - "@esbuild/openbsd-x64": "0.16.17", - "@esbuild/sunos-x64": "0.16.17", - "@esbuild/win32-arm64": "0.16.17", - "@esbuild/win32-ia32": "0.16.17", - "@esbuild/win32-x64": "0.16.17" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "node_modules/escalade": { @@ -1195,9 +1195,9 @@ } }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -1208,12 +1208,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -1232,18 +1226,6 @@ "node": ">=4" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -1264,18 +1246,6 @@ "url": "https://opencollective.com/immer" } }, - "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/jose": { "version": "4.13.1", "resolved": "https://registry.npmjs.org/jose/-/jose-4.13.1.tgz", @@ -1394,12 +1364,6 @@ "node": ">=0.10.0" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -1539,27 +1503,10 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/rollup": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.17.3.tgz", - "integrity": "sha512-p5LaCXiiOL/wrOkj8djsIDFmyU9ysUxcyW+EKRLHb6TKldJzXpImjcRSR+vgo09DBdofGcOoLOsRyxxG2n5/qQ==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -1610,18 +1557,6 @@ "node": ">=4" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -1725,15 +1660,14 @@ } }, "node_modules/vite": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.1.5.tgz", - "integrity": "sha512-zJ0RiVkf61kpd7O+VtU6r766xgnTaIknP/lR6sJTZq3HtVJ3HGnTo5DaJhTUtYoTyS/CQwZ6yEVdc/lrmQT7dQ==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", + "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", "dev": true, "dependencies": { - "esbuild": "^0.16.14", - "postcss": "^8.4.21", - "resolve": "^1.22.1", - "rollup": "^3.10.0" + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "bin": { "vite": "bin/vite.js" @@ -1741,12 +1675,16 @@ "engines": { "node": "^14.18.0 || >=16.0.0" }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -1759,6 +1697,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -2144,156 +2085,156 @@ } }, "@esbuild/android-arm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", - "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "dev": true, "optional": true }, "@esbuild/android-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", - "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "dev": true, "optional": true }, "@esbuild/android-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", - "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "dev": true, "optional": true }, "@esbuild/darwin-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", - "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "dev": true, "optional": true }, "@esbuild/darwin-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", - "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "dev": true, "optional": true }, "@esbuild/freebsd-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", - "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "dev": true, "optional": true }, "@esbuild/freebsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", - "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "dev": true, "optional": true }, "@esbuild/linux-arm": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", - "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "dev": true, "optional": true }, "@esbuild/linux-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", - "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "dev": true, "optional": true }, "@esbuild/linux-ia32": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", - "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "dev": true, "optional": true }, "@esbuild/linux-loong64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", - "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "dev": true, "optional": true }, "@esbuild/linux-mips64el": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", - "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "dev": true, "optional": true }, "@esbuild/linux-ppc64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", - "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "dev": true, "optional": true }, "@esbuild/linux-riscv64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", - "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "dev": true, "optional": true }, "@esbuild/linux-s390x": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", - "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "dev": true, "optional": true }, "@esbuild/linux-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", - "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "dev": true, "optional": true }, "@esbuild/netbsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", - "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "dev": true, "optional": true }, "@esbuild/openbsd-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", - "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "dev": true, "optional": true }, "@esbuild/sunos-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", - "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "dev": true, "optional": true }, "@esbuild/win32-arm64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", - "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "dev": true, "optional": true }, "@esbuild/win32-ia32": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", - "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "dev": true, "optional": true }, "@esbuild/win32-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", - "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "dev": true, "optional": true }, @@ -2536,33 +2477,33 @@ "dev": true }, "esbuild": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", - "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "requires": { - "@esbuild/android-arm": "0.16.17", - "@esbuild/android-arm64": "0.16.17", - "@esbuild/android-x64": "0.16.17", - "@esbuild/darwin-arm64": "0.16.17", - "@esbuild/darwin-x64": "0.16.17", - "@esbuild/freebsd-arm64": "0.16.17", - "@esbuild/freebsd-x64": "0.16.17", - "@esbuild/linux-arm": "0.16.17", - "@esbuild/linux-arm64": "0.16.17", - "@esbuild/linux-ia32": "0.16.17", - "@esbuild/linux-loong64": "0.16.17", - "@esbuild/linux-mips64el": "0.16.17", - "@esbuild/linux-ppc64": "0.16.17", - "@esbuild/linux-riscv64": "0.16.17", - "@esbuild/linux-s390x": "0.16.17", - "@esbuild/linux-x64": "0.16.17", - "@esbuild/netbsd-x64": "0.16.17", - "@esbuild/openbsd-x64": "0.16.17", - "@esbuild/sunos-x64": "0.16.17", - "@esbuild/win32-arm64": "0.16.17", - "@esbuild/win32-ia32": "0.16.17", - "@esbuild/win32-x64": "0.16.17" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "escalade": { @@ -2591,18 +2532,12 @@ } }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "optional": true }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -2615,15 +2550,6 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -2637,15 +2563,6 @@ "optional": true, "peer": true }, - "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, "jose": { "version": "4.13.1", "resolved": "https://registry.npmjs.org/jose/-/jose-4.13.1.tgz", @@ -2725,12 +2642,6 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -2831,21 +2742,10 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, "rollup": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.17.3.tgz", - "integrity": "sha512-p5LaCXiiOL/wrOkj8djsIDFmyU9ysUxcyW+EKRLHb6TKldJzXpImjcRSR+vgo09DBdofGcOoLOsRyxxG2n5/qQ==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -2880,12 +2780,6 @@ "has-flag": "^3.0.0" } }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -2937,16 +2831,15 @@ "requires": {} }, "vite": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.1.5.tgz", - "integrity": "sha512-zJ0RiVkf61kpd7O+VtU6r766xgnTaIknP/lR6sJTZq3HtVJ3HGnTo5DaJhTUtYoTyS/CQwZ6yEVdc/lrmQT7dQ==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", + "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", "dev": true, "requires": { - "esbuild": "^0.16.14", + "esbuild": "^0.18.10", "fsevents": "~2.3.2", - "postcss": "^8.4.21", - "resolve": "^1.22.1", - "rollup": "^3.10.0" + "postcss": "^8.4.27", + "rollup": "^3.27.1" } }, "weekstart": { diff --git a/resources/clients/react/elros/package.json b/resources/clients/react/elros/package.json index 1a3c9b43451..3e6d2b7d1c2 100644 --- a/resources/clients/react/elros/package.json +++ b/resources/clients/react/elros/package.json @@ -21,6 +21,6 @@ "@types/react-dom": "^18.0.10", "@vitejs/plugin-react": "^3.1.0", "typescript": "^4.9.3", - "vite": "^4.1.5" + "vite": "^4.5.2" } } From 2be27fc8d4ee3d594c8e7a4009f98724df177726 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 08:54:44 -0600 Subject: [PATCH 08/36] Bump vite from 4.3.9 to 4.5.2 in /applications/photo-asset-manager/elros-pam (#5973) Bump vite in /applications/photo-asset-manager/elros-pam Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.3.9 to 4.5.2. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v4.5.2/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v4.5.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../elros-pam/package-lock.json | 425 +++++++++--------- .../elros-pam/package.json | 2 +- 2 files changed, 217 insertions(+), 210 deletions(-) diff --git a/applications/photo-asset-manager/elros-pam/package-lock.json b/applications/photo-asset-manager/elros-pam/package-lock.json index 194af9351ee..f5452b77fb0 100644 --- a/applications/photo-asset-manager/elros-pam/package-lock.json +++ b/applications/photo-asset-manager/elros-pam/package-lock.json @@ -20,7 +20,7 @@ "@types/react-dom": "^18.2.4", "@vitejs/plugin-react": "^4.0.0", "typescript": "^5.1.3", - "vite": "^4.3.9" + "vite": "^4.5.2" } }, "node_modules/@ampproject/remapping": { @@ -526,9 +526,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "cpu": [ "arm" ], @@ -542,9 +542,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "cpu": [ "arm64" ], @@ -558,9 +558,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "cpu": [ "x64" ], @@ -574,9 +574,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "cpu": [ "arm64" ], @@ -590,9 +590,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "cpu": [ "x64" ], @@ -606,9 +606,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "cpu": [ "arm64" ], @@ -622,9 +622,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "cpu": [ "x64" ], @@ -638,9 +638,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "cpu": [ "arm" ], @@ -654,9 +654,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "cpu": [ "arm64" ], @@ -670,9 +670,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "cpu": [ "ia32" ], @@ -686,9 +686,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "cpu": [ "loong64" ], @@ -702,9 +702,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "cpu": [ "mips64el" ], @@ -718,9 +718,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "cpu": [ "ppc64" ], @@ -734,9 +734,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "cpu": [ "riscv64" ], @@ -750,9 +750,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "cpu": [ "s390x" ], @@ -766,9 +766,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "cpu": [ "x64" ], @@ -782,9 +782,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "cpu": [ "x64" ], @@ -798,9 +798,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "cpu": [ "x64" ], @@ -814,9 +814,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "cpu": [ "x64" ], @@ -830,9 +830,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "cpu": [ "arm64" ], @@ -846,9 +846,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "cpu": [ "ia32" ], @@ -862,9 +862,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "cpu": [ "x64" ], @@ -1238,9 +1238,9 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "hasInstallScript": true, "bin": { @@ -1250,28 +1250,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "node_modules/escalade": { @@ -1309,9 +1309,9 @@ } }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -1617,9 +1617,9 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "node_modules/rollup": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.24.0.tgz", - "integrity": "sha512-OgraHOIg2YpHQTjl0/ymWfFNBEyPucB7lmhXrQUh38qNOegxLapSPFs9sNr0qKR75awW41D93XafoR2QfhBdUQ==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -1777,14 +1777,14 @@ } }, "node_modules/vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", + "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", "dev": true, "dependencies": { - "esbuild": "^0.17.5", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "bin": { "vite": "bin/vite.js" @@ -1792,12 +1792,16 @@ "engines": { "node": "^14.18.0 || >=16.0.0" }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -1810,6 +1814,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -2244,156 +2251,156 @@ } }, "@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "dev": true, "optional": true }, "@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "dev": true, "optional": true }, "@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "dev": true, "optional": true }, "@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "dev": true, "optional": true }, "@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "dev": true, "optional": true }, "@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "dev": true, "optional": true }, "@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "dev": true, "optional": true }, "@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "dev": true, "optional": true }, "@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "dev": true, "optional": true }, "@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "dev": true, "optional": true }, "@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "dev": true, "optional": true }, "@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "dev": true, "optional": true }, "@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "dev": true, "optional": true }, "@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "dev": true, "optional": true }, "@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "dev": true, "optional": true }, "@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "dev": true, "optional": true }, "@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "dev": true, "optional": true }, "@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "dev": true, "optional": true }, "@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "dev": true, "optional": true }, "@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "dev": true, "optional": true }, "@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "dev": true, "optional": true }, "@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "dev": true, "optional": true }, @@ -2679,33 +2686,33 @@ "dev": true }, "esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "escalade": { @@ -2734,9 +2741,9 @@ } }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "optional": true }, @@ -2947,9 +2954,9 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "rollup": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.24.0.tgz", - "integrity": "sha512-OgraHOIg2YpHQTjl0/ymWfFNBEyPucB7lmhXrQUh38qNOegxLapSPFs9sNr0qKR75awW41D93XafoR2QfhBdUQ==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -3035,15 +3042,15 @@ "requires": {} }, "vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", + "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", "dev": true, "requires": { - "esbuild": "^0.17.5", + "esbuild": "^0.18.10", "fsevents": "~2.3.2", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "postcss": "^8.4.27", + "rollup": "^3.27.1" } }, "weekstart": { diff --git a/applications/photo-asset-manager/elros-pam/package.json b/applications/photo-asset-manager/elros-pam/package.json index f6244f5269a..bc8162268f4 100644 --- a/applications/photo-asset-manager/elros-pam/package.json +++ b/applications/photo-asset-manager/elros-pam/package.json @@ -21,6 +21,6 @@ "@types/react-dom": "^18.2.4", "@vitejs/plugin-react": "^4.0.0", "typescript": "^5.1.3", - "vite": "^4.3.9" + "vite": "^4.5.2" } } From 53f299433b46b444e2ddcee4f424317841a2ac90 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 09:03:07 -0600 Subject: [PATCH 09/36] Bump vite from 4.3.9 to 4.5.2 in /applications/feedback_sentiment_analyzer/client (#5974) Bump vite in /applications/feedback_sentiment_analyzer/client Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.3.9 to 4.5.2. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v4.5.2/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v4.5.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../client/package-lock.json | 421 +++++++++--------- .../client/package.json | 2 +- 2 files changed, 215 insertions(+), 208 deletions(-) diff --git a/applications/feedback_sentiment_analyzer/client/package-lock.json b/applications/feedback_sentiment_analyzer/client/package-lock.json index b52fb07f2f0..0925b8ebd20 100644 --- a/applications/feedback_sentiment_analyzer/client/package-lock.json +++ b/applications/feedback_sentiment_analyzer/client/package-lock.json @@ -20,7 +20,7 @@ "@types/react-dom": "^18.2.4", "@vitejs/plugin-react": "^4.0.1", "typescript": "^5.1.3", - "vite": "^4.3.9" + "vite": "^4.5.2" } }, "node_modules/@ampproject/remapping": { @@ -511,9 +511,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "cpu": [ "arm" ], @@ -527,9 +527,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "cpu": [ "arm64" ], @@ -543,9 +543,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "cpu": [ "x64" ], @@ -559,9 +559,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "cpu": [ "arm64" ], @@ -575,9 +575,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "cpu": [ "x64" ], @@ -591,9 +591,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "cpu": [ "arm64" ], @@ -607,9 +607,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "cpu": [ "x64" ], @@ -623,9 +623,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "cpu": [ "arm" ], @@ -639,9 +639,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "cpu": [ "arm64" ], @@ -655,9 +655,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "cpu": [ "ia32" ], @@ -671,9 +671,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "cpu": [ "loong64" ], @@ -687,9 +687,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "cpu": [ "mips64el" ], @@ -703,9 +703,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "cpu": [ "ppc64" ], @@ -719,9 +719,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "cpu": [ "riscv64" ], @@ -735,9 +735,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "cpu": [ "s390x" ], @@ -751,9 +751,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "cpu": [ "x64" ], @@ -767,9 +767,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "cpu": [ "x64" ], @@ -783,9 +783,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "cpu": [ "x64" ], @@ -799,9 +799,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "cpu": [ "x64" ], @@ -815,9 +815,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "cpu": [ "arm64" ], @@ -831,9 +831,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "cpu": [ "ia32" ], @@ -847,9 +847,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "cpu": [ "x64" ], @@ -1225,9 +1225,9 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "hasInstallScript": true, "bin": { @@ -1237,28 +1237,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "node_modules/escalade": { @@ -1285,9 +1285,9 @@ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -1566,9 +1566,9 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "node_modules/rollup": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.24.0.tgz", - "integrity": "sha512-OgraHOIg2YpHQTjl0/ymWfFNBEyPucB7lmhXrQUh38qNOegxLapSPFs9sNr0qKR75awW41D93XafoR2QfhBdUQ==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -1685,14 +1685,14 @@ } }, "node_modules/vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", + "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", "dev": true, "dependencies": { - "esbuild": "^0.17.5", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "bin": { "vite": "bin/vite.js" @@ -1700,12 +1700,16 @@ "engines": { "node": "^14.18.0 || >=16.0.0" }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -1718,6 +1722,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -2138,156 +2145,156 @@ } }, "@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "dev": true, "optional": true }, "@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "dev": true, "optional": true }, "@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "dev": true, "optional": true }, "@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "dev": true, "optional": true }, "@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "dev": true, "optional": true }, "@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "dev": true, "optional": true }, "@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "dev": true, "optional": true }, "@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "dev": true, "optional": true }, "@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "dev": true, "optional": true }, "@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "dev": true, "optional": true }, "@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "dev": true, "optional": true }, "@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "dev": true, "optional": true }, "@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "dev": true, "optional": true }, "@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "dev": true, "optional": true }, "@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "dev": true, "optional": true }, "@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "dev": true, "optional": true }, "@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "dev": true, "optional": true }, "@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "dev": true, "optional": true }, "@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "dev": true, "optional": true }, "@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "dev": true, "optional": true }, "@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "dev": true, "optional": true }, "@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "dev": true, "optional": true }, @@ -2577,33 +2584,33 @@ "dev": true }, "esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "requires": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "escalade": { @@ -2624,9 +2631,9 @@ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "optional": true }, @@ -2816,9 +2823,9 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "rollup": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.24.0.tgz", - "integrity": "sha512-OgraHOIg2YpHQTjl0/ymWfFNBEyPucB7lmhXrQUh38qNOegxLapSPFs9sNr0qKR75awW41D93XafoR2QfhBdUQ==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -2887,15 +2894,15 @@ "requires": {} }, "vite": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", - "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", + "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", "dev": true, "requires": { - "esbuild": "^0.17.5", + "esbuild": "^0.18.10", "fsevents": "~2.3.2", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "postcss": "^8.4.27", + "rollup": "^3.27.1" } }, "weekstart": { diff --git a/applications/feedback_sentiment_analyzer/client/package.json b/applications/feedback_sentiment_analyzer/client/package.json index d3fb1a684f8..0bc7b5bbb94 100644 --- a/applications/feedback_sentiment_analyzer/client/package.json +++ b/applications/feedback_sentiment_analyzer/client/package.json @@ -21,6 +21,6 @@ "@types/react-dom": "^18.2.4", "@vitejs/plugin-react": "^4.0.1", "typescript": "^5.1.3", - "vite": "^4.3.9" + "vite": "^4.5.2" } } From f2c9920740ca33cc25d2bd272b2b7da3913d4078 Mon Sep 17 00:00:00 2001 From: Dennis Traub Date: Mon, 22 Jan 2024 16:07:01 +0100 Subject: [PATCH 10/36] Workaround for doc build (#5970) --- .doc_gen/metadata/bedrock-agent_metadata.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.doc_gen/metadata/bedrock-agent_metadata.yaml b/.doc_gen/metadata/bedrock-agent_metadata.yaml index cf3486fe0de..99a98596341 100644 --- a/.doc_gen/metadata/bedrock-agent_metadata.yaml +++ b/.doc_gen/metadata/bedrock-agent_metadata.yaml @@ -193,5 +193,3 @@ bedrock-agent_GettingStartedWithBedrockAgents: ListAgentKnowledgeBases, PrepareAgent, } - bedrock-agent-runtime: - {InvokeAgent} From 69ce557150fb4a717c5fc3fd64ec5013a15fcf40 Mon Sep 17 00:00:00 2001 From: Laren-AWS <57545972+Laren-AWS@users.noreply.github.com> Date: Mon, 22 Jan 2024 09:55:25 -0800 Subject: [PATCH 11/36] [Go] Added pagination to all Go DynamoDB examples that can be paginated. (#5962) Added pagination to all Go DynamoDB examples that can be paginated. --- gov2/dynamodb/README.md | 18 +++--- gov2/dynamodb/actions/partiql.go | 35 +++++++---- gov2/dynamodb/actions/partiql_test.go | 13 ++-- gov2/dynamodb/actions/table_basics.go | 59 +++++++++++++------ .../scenarios/scenario_partiql_batch.go | 8 ++- .../scenarios/scenario_partiql_batch_test.go | 8 ++- .../scenarios/scenario_partiql_single_test.go | 10 ++-- gov2/dynamodb/stubs/partiql_stubs.go | 13 ++-- 8 files changed, 106 insertions(+), 58 deletions(-) diff --git a/gov2/dynamodb/README.md b/gov2/dynamodb/README.md index d80d48ff75d..a390eaef2fa 100644 --- a/gov2/dynamodb/README.md +++ b/gov2/dynamodb/README.md @@ -34,18 +34,18 @@ For prerequisites, see the [README](../README.md#Prerequisites) in the `gov2` fo Code excerpts that show you how to call individual service functions. - [Create a table](actions/table_basics.go#L54) (`CreateTable`) -- [Delete a table](actions/table_basics.go#L326) (`DeleteTable`) -- [Delete an item from a table](actions/table_basics.go#L311) (`DeleteItem`) -- [Get an item from a table](actions/table_basics.go#L216) (`GetItem`) +- [Delete a table](actions/table_basics.go#L347) (`DeleteTable`) +- [Delete an item from a table](actions/table_basics.go#L332) (`DeleteItem`) +- [Get an item from a table](actions/table_basics.go#L221) (`GetItem`) - [Get information about a table](actions/table_basics.go#L31) (`DescribeTable`) - [List tables](actions/table_basics.go#L99) (`ListTables`) -- [Put an item in a table](actions/table_basics.go#L116) (`PutItem`) -- [Query a table](actions/table_basics.go#L238) (`Query`) +- [Put an item in a table](actions/table_basics.go#L121) (`PutItem`) +- [Query a table](actions/table_basics.go#L243) (`Query`) - [Run a PartiQL statement](actions/partiql.go#L30) (`ExecuteStatement`) -- [Run batches of PartiQL statements](actions/partiql.go#L149) (`BatchExecuteStatement`) -- [Scan a table](actions/table_basics.go#L272) (`Scan`) -- [Update an item in a table](actions/table_basics.go#L135) (`UpdateItem`) -- [Write a batch of items](actions/table_basics.go#L172) (`BatchWriteItem`) +- [Run batches of PartiQL statements](actions/partiql.go#L164) (`BatchExecuteStatement`) +- [Scan a table](actions/table_basics.go#L285) (`Scan`) +- [Update an item in a table](actions/table_basics.go#L140) (`UpdateItem`) +- [Write a batch of items](actions/table_basics.go#L177) (`BatchWriteItem`) ### Scenarios diff --git a/gov2/dynamodb/actions/partiql.go b/gov2/dynamodb/actions/partiql.go index 631c5536b06..58e7b310ce6 100644 --- a/gov2/dynamodb/actions/partiql.go +++ b/gov2/dynamodb/actions/partiql.go @@ -81,19 +81,34 @@ func (runner PartiQLRunner) GetMovie(title string, year int) (Movie, error) { // snippet-start:[gov2.dynamodb.ExecuteStatement.Select.Projected] // GetAllMovies runs a PartiQL SELECT statement to get all movies from the DynamoDB table. +// pageSize is not typically required and is used to show how to paginate the results. // The results are projected to return only the title and rating of each movie. -func (runner PartiQLRunner) GetAllMovies() ([]map[string]interface{}, error) { +func (runner PartiQLRunner) GetAllMovies(pageSize int32) ([]map[string]interface{}, error) { var output []map[string]interface{} - response, err := runner.DynamoDbClient.ExecuteStatement(context.TODO(), &dynamodb.ExecuteStatementInput{ - Statement: aws.String( - fmt.Sprintf("SELECT title, info.rating FROM \"%v\"", runner.TableName)), - }) - if err != nil { - log.Printf("Couldn't get movies. Here's why: %v\n", err) - } else { - err = attributevalue.UnmarshalListOfMaps(response.Items, &output) + var response *dynamodb.ExecuteStatementOutput + var err error + var nextToken *string + for moreData := true; moreData; { + response, err = runner.DynamoDbClient.ExecuteStatement(context.TODO(), &dynamodb.ExecuteStatementInput{ + Statement: aws.String( + fmt.Sprintf("SELECT title, info.rating FROM \"%v\"", runner.TableName)), + Limit: aws.Int32(pageSize), + NextToken: nextToken, + }) if err != nil { - log.Printf("Couldn't unmarshal response. Here's why: %v\n", err) + log.Printf("Couldn't get movies. Here's why: %v\n", err) + moreData = false + } else { + var pageOutput []map[string]interface{} + err = attributevalue.UnmarshalListOfMaps(response.Items, &pageOutput) + if err != nil { + log.Printf("Couldn't unmarshal response. Here's why: %v\n", err) + } else { + log.Printf("Got a page of length %v.\n", len(response.Items)) + output = append(output, pageOutput...) + } + nextToken = response.NextToken + moreData = nextToken != nil } } return output, err diff --git a/gov2/dynamodb/actions/partiql_test.go b/gov2/dynamodb/actions/partiql_test.go index 1f52da5e6bd..c60d3974f53 100644 --- a/gov2/dynamodb/actions/partiql_test.go +++ b/gov2/dynamodb/actions/partiql_test.go @@ -10,6 +10,7 @@ import ( "fmt" "testing" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/dynamodb" "github.com/awsdocs/aws-doc-sdk-examples/gov2/dynamodb/stubs" "github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools" @@ -34,7 +35,7 @@ func AddMoviePartiQL(raiseErr *testtools.StubError, t *testing.T) { stubber.Add(stubs.StubExecuteStatement( fmt.Sprintf("INSERT INTO \"%v\" VALUE {'title': ?, 'year': ?, 'info': ?}", runner.TableName), - []interface{}{movie.Title, movie.Year, movie.Info}, nil, raiseErr)) + []interface{}{movie.Title, movie.Year, movie.Info}, nil, nil, nil, nil, raiseErr)) err := runner.AddMovie(movie) @@ -55,7 +56,7 @@ func GetMoviePartiQL(raiseErr *testtools.StubError, t *testing.T) { stubber.Add(stubs.StubExecuteStatement( fmt.Sprintf("SELECT * FROM \"%v\" WHERE title=? AND year=?", runner.TableName), - []interface{}{movie.Title, movie.Year}, movie, raiseErr)) + []interface{}{movie.Title, movie.Year}, nil, nil, movie, nil, raiseErr)) gotMovie, err := runner.GetMovie(movie.Title, movie.Year) @@ -81,9 +82,9 @@ func GetAllMoviesPartiQL(raiseErr *testtools.StubError, t *testing.T) { stubber.Add(stubs.StubExecuteStatement( fmt.Sprintf("SELECT title, info.rating FROM \"%v\"", runner.TableName), - nil, outProjection, raiseErr)) + nil, aws.Int32(2), nil, outProjection, nil, raiseErr)) - gotProjections, err := runner.GetAllMovies() + gotProjections, err := runner.GetAllMovies(2) testtools.VerifyError(err, raiseErr, t) if err == nil { @@ -111,7 +112,7 @@ func UpdateMoviePartiQL(raiseErr *testtools.StubError, t *testing.T) { stubber.Add(stubs.StubExecuteStatement( fmt.Sprintf("UPDATE \"%v\" SET info.rating=? WHERE title=? AND year=?", runner.TableName), - []interface{}{newRating, movie.Title, movie.Year}, movie, raiseErr)) + []interface{}{newRating, movie.Title, movie.Year}, nil, nil, movie, nil, raiseErr)) err := runner.UpdateMovie(movie, newRating) @@ -132,7 +133,7 @@ func DeleteMoviePartiQL(raiseErr *testtools.StubError, t *testing.T) { stubber.Add(stubs.StubExecuteStatement( fmt.Sprintf("DELETE FROM \"%v\" WHERE title=? AND year=?", runner.TableName), - []interface{}{movie.Title, movie.Year}, movie, raiseErr)) + []interface{}{movie.Title, movie.Year}, nil, nil, movie, nil, raiseErr)) err := runner.DeleteMovie(movie) diff --git a/gov2/dynamodb/actions/table_basics.go b/gov2/dynamodb/actions/table_basics.go index 8070e4573ce..d0d74fff648 100644 --- a/gov2/dynamodb/actions/table_basics.go +++ b/gov2/dynamodb/actions/table_basics.go @@ -101,12 +101,17 @@ func (basics TableBasics) CreateMovieTable() (*types.TableDescription, error) { // ListTables lists the DynamoDB table names for the current account. func (basics TableBasics) ListTables() ([]string, error) { var tableNames []string - tables, err := basics.DynamoDbClient.ListTables( - context.TODO(), &dynamodb.ListTablesInput{}) - if err != nil { - log.Printf("Couldn't list tables. Here's why: %v\n", err) - } else { - tableNames = tables.TableNames + var output *dynamodb.ListTablesOutput + var err error + tablePaginator := dynamodb.NewListTablesPaginator(basics.DynamoDbClient, &dynamodb.ListTablesInput{}) + for tablePaginator.HasMorePages() { + output, err = tablePaginator.NextPage(context.TODO()) + if err != nil { + log.Printf("Couldn't list tables. Here's why: %v\n", err) + break + } else { + tableNames = append(tableNames, output.TableNames...) + } } return tableNames, err } @@ -249,18 +254,26 @@ func (basics TableBasics) Query(releaseYear int) ([]Movie, error) { if err != nil { log.Printf("Couldn't build expression for query. Here's why: %v\n", err) } else { - response, err = basics.DynamoDbClient.Query(context.TODO(), &dynamodb.QueryInput{ + queryPaginator := dynamodb.NewQueryPaginator(basics.DynamoDbClient, &dynamodb.QueryInput{ TableName: aws.String(basics.TableName), ExpressionAttributeNames: expr.Names(), ExpressionAttributeValues: expr.Values(), KeyConditionExpression: expr.KeyCondition(), }) - if err != nil { - log.Printf("Couldn't query for movies released in %v. Here's why: %v\n", releaseYear, err) - } else { - err = attributevalue.UnmarshalListOfMaps(response.Items, &movies) + for queryPaginator.HasMorePages() { + response, err = queryPaginator.NextPage(context.TODO()) if err != nil { - log.Printf("Couldn't unmarshal query response. Here's why: %v\n", err) + log.Printf("Couldn't query for movies released in %v. Here's why: %v\n", releaseYear, err) + break + } else { + var moviePage []Movie + err = attributevalue.UnmarshalListOfMaps(response.Items, &moviePage) + if err != nil { + log.Printf("Couldn't unmarshal query response. Here's why: %v\n", err) + break + } else { + movies = append(movies, moviePage...) + } } } } @@ -286,20 +299,28 @@ func (basics TableBasics) Scan(startYear int, endYear int) ([]Movie, error) { if err != nil { log.Printf("Couldn't build expressions for scan. Here's why: %v\n", err) } else { - response, err = basics.DynamoDbClient.Scan(context.TODO(), &dynamodb.ScanInput{ + scanPaginator := dynamodb.NewScanPaginator(basics.DynamoDbClient, &dynamodb.ScanInput{ TableName: aws.String(basics.TableName), ExpressionAttributeNames: expr.Names(), ExpressionAttributeValues: expr.Values(), FilterExpression: expr.Filter(), ProjectionExpression: expr.Projection(), }) - if err != nil { - log.Printf("Couldn't scan for movies released between %v and %v. Here's why: %v\n", - startYear, endYear, err) - } else { - err = attributevalue.UnmarshalListOfMaps(response.Items, &movies) + for scanPaginator.HasMorePages() { + response, err = scanPaginator.NextPage(context.TODO()) if err != nil { - log.Printf("Couldn't unmarshal query response. Here's why: %v\n", err) + log.Printf("Couldn't scan for movies released between %v and %v. Here's why: %v\n", + startYear, endYear, err) + break + } else { + var moviePage []Movie + err = attributevalue.UnmarshalListOfMaps(response.Items, &moviePage) + if err != nil { + log.Printf("Couldn't unmarshal query response. Here's why: %v\n", err) + break + } else { + movies = append(movies, moviePage...) + } } } } diff --git a/gov2/dynamodb/scenarios/scenario_partiql_batch.go b/gov2/dynamodb/scenarios/scenario_partiql_batch.go index af46dab52ed..5019f79c609 100644 --- a/gov2/dynamodb/scenarios/scenario_partiql_batch.go +++ b/gov2/dynamodb/scenarios/scenario_partiql_batch.go @@ -19,8 +19,8 @@ import ( // RunPartiQLBatchScenario shows you how to use the AWS SDK for Go // to run batches of PartiQL statements to query a table that stores data about movies. // -// * Use batches of PartiQL statements to add, get, update, and delete data for -// individual movies. +// - Use batches of PartiQL statements to add, get, update, and delete data for +// individual movies. // // This example creates an Amazon DynamoDB service client from the specified sdkConfig so that // you can replace it with a mocked or stubbed config for unit testing. @@ -108,8 +108,10 @@ func RunPartiQLBatchScenario(sdkConfig aws.Config, tableName string) { log.Println(strings.Repeat("-", 88)) log.Println("Getting projected data from the table to verify our update.") - projections, err := runner.GetAllMovies() + log.Println("Using a page size of 2 to demonstrate paging.") + projections, err := runner.GetAllMovies(2) if err == nil { + log.Println("All movies:") for _, projection := range projections { log.Println(projection) } diff --git a/gov2/dynamodb/scenarios/scenario_partiql_batch_test.go b/gov2/dynamodb/scenarios/scenario_partiql_batch_test.go index 1719ba4a60b..e64c4046fe3 100644 --- a/gov2/dynamodb/scenarios/scenario_partiql_batch_test.go +++ b/gov2/dynamodb/scenarios/scenario_partiql_batch_test.go @@ -10,6 +10,7 @@ import ( "testing" "time" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" "github.com/awsdocs/aws-doc-sdk-examples/gov2/dynamodb/actions" "github.com/awsdocs/aws-doc-sdk-examples/gov2/dynamodb/stubs" @@ -53,6 +54,8 @@ func (scenTest *PartiQLBatchScenarioTest) SetupDataAndStubs() []testtools.Stub { }, } newRatings := []float64{7.7, 4.4, 1.1} + pageSize := int32(2) + pageToken := "test-token" insertStatements := make([]string, len(customMovies)) updateStatements := make([]string, len(customMovies)) @@ -89,7 +92,10 @@ func (scenTest *PartiQLBatchScenarioTest) SetupDataAndStubs() []testtools.Stub { stubList = append(stubList, stubs.StubBatchExecuteStatement(updateStatements, updateParamList, nil, nil)) stubList = append(stubList, stubs.StubExecuteStatement( fmt.Sprintf("SELECT title, info.rating FROM \"%v\"", scenTest.TableName), - nil, projectedMovies, nil)) + nil, aws.Int32(pageSize), nil, projectedMovies[0:pageSize], aws.String(pageToken), nil)) + stubList = append(stubList, stubs.StubExecuteStatement( + fmt.Sprintf("SELECT title, info.rating FROM \"%v\"", scenTest.TableName), + nil, aws.Int32(pageSize), aws.String(pageToken), projectedMovies[pageSize:len(projectedMovies)], nil, nil)) stubList = append(stubList, stubs.StubBatchExecuteStatement(deleteStatements, getDelParamList, nil, nil)) stubList = append(stubList, stubs.StubDeleteTable(scenTest.TableName, nil)) diff --git a/gov2/dynamodb/scenarios/scenario_partiql_single_test.go b/gov2/dynamodb/scenarios/scenario_partiql_single_test.go index 911b25dac38..065fc024c63 100644 --- a/gov2/dynamodb/scenarios/scenario_partiql_single_test.go +++ b/gov2/dynamodb/scenarios/scenario_partiql_single_test.go @@ -51,19 +51,19 @@ func (scenTest *PartiQLSingleScenarioTest) SetupDataAndStubs() []testtools.Stub stubList = append(stubList, stubs.StubDescribeTable(scenTest.TableName, nil)) stubList = append(stubList, stubs.StubExecuteStatement( fmt.Sprintf("INSERT INTO \"%v\" VALUE {'title': ?, 'year': ?, 'info': ?}", scenTest.TableName), - []interface{}{movie.Title, movie.Year, movie.Info}, nil, nil)) + []interface{}{movie.Title, movie.Year, movie.Info}, nil, nil, nil, nil, nil)) stubList = append(stubList, stubs.StubExecuteStatement( fmt.Sprintf("SELECT * FROM \"%v\" WHERE title=? AND year=?", scenTest.TableName), - []interface{}{movie.Title, movie.Year}, movie, nil)) + []interface{}{movie.Title, movie.Year}, nil, nil, movie, nil, nil)) stubList = append(stubList, stubs.StubExecuteStatement( fmt.Sprintf("UPDATE \"%v\" SET info.rating=? WHERE title=? AND year=?", scenTest.TableName), - []interface{}{newRating, movie.Title, movie.Year}, movie, nil)) + []interface{}{newRating, movie.Title, movie.Year}, nil, nil, movie, nil, nil)) stubList = append(stubList, stubs.StubExecuteStatement( fmt.Sprintf("SELECT * FROM \"%v\" WHERE title=? AND year=?", scenTest.TableName), - []interface{}{movie.Title, movie.Year}, movie, nil)) + []interface{}{movie.Title, movie.Year}, nil, nil, movie, nil, nil)) stubList = append(stubList, stubs.StubExecuteStatement( fmt.Sprintf("DELETE FROM \"%v\" WHERE title=? AND year=?", scenTest.TableName), - []interface{}{movie.Title, movie.Year}, movie, nil)) + []interface{}{movie.Title, movie.Year}, nil, nil, movie, nil, nil)) stubList = append(stubList, stubs.StubDeleteTable(scenTest.TableName, nil)) return stubList diff --git a/gov2/dynamodb/stubs/partiql_stubs.go b/gov2/dynamodb/stubs/partiql_stubs.go index 70b4520a94d..b294b1fc25b 100644 --- a/gov2/dynamodb/stubs/partiql_stubs.go +++ b/gov2/dynamodb/stubs/partiql_stubs.go @@ -17,8 +17,8 @@ import ( ) func StubExecuteStatement( - statement string, params []interface{}, output interface{}, - raiseErr *testtools.StubError) testtools.Stub { + statement string, params []interface{}, limit *int32, nextInputToken *string, output interface{}, + nextOutputToken *string, raiseErr *testtools.StubError) testtools.Stub { var paramAttribs []types.AttributeValue var err error if params != nil { @@ -34,12 +34,15 @@ func StubExecuteStatement( panic(err) } statementOutput.Items = append(statementOutput.Items, outputAttribs) + statementOutput.NextToken = nextOutputToken } return testtools.Stub{ OperationName: "ExecuteStatement", - Input: &dynamodb.ExecuteStatementInput{Statement: aws.String(statement), Parameters: paramAttribs}, - Output: &statementOutput, - Error: raiseErr, + Input: &dynamodb.ExecuteStatementInput{ + Statement: aws.String(statement), Parameters: paramAttribs, + Limit: limit, NextToken: nextInputToken}, + Output: &statementOutput, + Error: raiseErr, } } From 2a4138c96cd3023f3a99830041056e5484673c47 Mon Sep 17 00:00:00 2001 From: ulf5 Date: Mon, 22 Jan 2024 21:46:01 +0100 Subject: [PATCH 12/36] Rust: add empty check in delete multiple objects example for S3 (#5976) * add empty check in s3 example --- rustv1/examples/s3/src/s3-service-lib.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/rustv1/examples/s3/src/s3-service-lib.rs b/rustv1/examples/s3/src/s3-service-lib.rs index cca0cf9e651..dc084e35402 100644 --- a/rustv1/examples/s3/src/s3-service-lib.rs +++ b/rustv1/examples/s3/src/s3-service-lib.rs @@ -43,17 +43,19 @@ pub async fn delete_objects(client: &Client, bucket_name: &str) -> Result Date: Mon, 22 Jan 2024 14:52:59 -0600 Subject: [PATCH 13/36] .NET v3: Fix for bug with parameters listing and add paginator in EC2 example (#5981) * Fix for bug with parameters listing and add paginator. --------- Co-authored-by: ford prior <108086978+ford-at-aws@users.noreply.github.com> --- dotnetv3/EC2/Actions/SsmWrapper.cs | 14 ++++++-------- dotnetv3/EC2/Scenarios/EC2_Basics/EC2Basics.cs | 5 +++-- .../IAM/Scenarios/IamScenariosCommon/S3Wrapper.cs | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/dotnetv3/EC2/Actions/SsmWrapper.cs b/dotnetv3/EC2/Actions/SsmWrapper.cs index d0917e2fdb7..a2d30dd88d3 100644 --- a/dotnetv3/EC2/Actions/SsmWrapper.cs +++ b/dotnetv3/EC2/Actions/SsmWrapper.cs @@ -25,21 +25,19 @@ public async Task> GetParametersByPath(string path) { var parameters = new List(); var request = new GetParametersByPathRequest { Path = path }; - var response = await _amazonSSM.GetParametersByPathAsync(request); - // Make sure we get the whole list. - do + // Get the whole list with a paginator. + var paginatedParametersByPath = _amazonSSM.Paginators.GetParametersByPath(request); + + await foreach (var parametersPage in paginatedParametersByPath.Responses) { - parameters.AddRange(response.Parameters); - request.NextToken = response.NextToken; - response = await _amazonSSM.GetParametersByPathAsync(request); + parameters.AddRange(parametersPage.Parameters); } - while (response.NextToken is not null); // Filter out everything except items that // have "amzn2" in the name property. var paramList = - from parameter in response.Parameters + from parameter in parameters where parameter.Name.Contains("amzn2") select parameter; return paramList.ToList(); diff --git a/dotnetv3/EC2/Scenarios/EC2_Basics/EC2Basics.cs b/dotnetv3/EC2/Scenarios/EC2_Basics/EC2Basics.cs index e345a79501e..eae5ceb9b5e 100644 --- a/dotnetv3/EC2/Scenarios/EC2_Basics/EC2Basics.cs +++ b/dotnetv3/EC2/Scenarios/EC2_Basics/EC2Basics.cs @@ -35,8 +35,9 @@ static async Task Main(string[] args) var ssmMethods = new SsmWrapper(ssmClient); var uiMethods = new UiMethods(); - var keyPairName = "mvp-example-key-pair"; - var groupName = "ec2-scenario-group"; + var uniqueName = Guid.NewGuid().ToString(); + var keyPairName = "mvp-example-key-pair" + uniqueName; + var groupName = "ec2-scenario-group" + uniqueName; var groupDescription = "A security group created for the EC2 Basics scenario."; // Start the scenario. diff --git a/dotnetv3/IAM/Scenarios/IamScenariosCommon/S3Wrapper.cs b/dotnetv3/IAM/Scenarios/IamScenariosCommon/S3Wrapper.cs index 919d8a97b3b..540ed519dd7 100644 --- a/dotnetv3/IAM/Scenarios/IamScenariosCommon/S3Wrapper.cs +++ b/dotnetv3/IAM/Scenarios/IamScenariosCommon/S3Wrapper.cs @@ -27,7 +27,7 @@ public S3Wrapper(IAmazonS3 s3Service, IAmazonSecurityTokenService stsService) _stsService = stsService; } - /// + /// /// Assumes an AWS Identity and Access Management (IAM) role that allows /// Amazon S3 access for the current session. /// From b283b60ab0538cfe745bda3100c85793e5608028 Mon Sep 17 00:00:00 2001 From: Laren-AWS <57545972+Laren-AWS@users.noreply.github.com> Date: Mon, 22 Jan 2024 12:57:03 -0800 Subject: [PATCH 14/36] Update Go V1 README so it's not so cryptic and terse. (#5986) --- go/Readme.md | 72 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/go/Readme.md b/go/Readme.md index 832ed75be82..7b2bc18db8e 100644 --- a/go/Readme.md +++ b/go/Readme.md @@ -1,17 +1,65 @@ -.. Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SDK for Go V1 code examples - This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 - International License (the "License"). You may not use this file except in compliance with the - License. A copy of the License is located at http://creativecommons.org/licenses/by-nc-sa/4.0/. +## Overview - This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - either express or implied. See the License for the specific language governing permissions and - limitations under the License. +The code examples in this topic show you how to use the AWS SDK for Go V1 with AWS. +If you're looking for examples of how to use the SDK for Go V2, see the +[README for SDK for Go V2 examples](../gov2/README.md) in this repo. -###################################### -AWS SDK for Go Documentation Examples -###################################### +⚠️ AWS SDK for Go V1 will enter maintenance mode on July 31, 2024 and reach end-of-support +on July 31, 2025. For more information, see +[this announcement](https://aws.amazon.com/blogs/developer/announcing-end-of-support-for-aws-sdk-for-go-v1-on-july-31-2025/). -This is a collection of examples for the AWS SDK for Go public documentation. +The SDK for Go V1 provides a Go API for AWS infrastructure services. Using the +SDK, you can build applications on top of Amazon S3, Amazon EC2, Amazon DynamoDB, +and more. -These examples were tested using Go version 1.14 and version 1 of the AWS SDK for Go. +## Types of code examples + +* **Single-service actions** - Code examples that show you how to call individual + service functions. + +### Finding code examples + +Single-service actions are organized by AWS service. +A README in each folder lists and describes how to run the examples. + +## ⚠️ Important + +* Running this code might result in charges to your AWS account. +* Running the tests might result in charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the + minimum permissions required to perform the task. For more information, see + [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, + see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + +## Run the examples + +### Prerequisites + +* You must have an AWS account, and have your default credentials and AWS Region + configured as described in the + [AWS Tools and SDKs Shared Configuration and Credentials Reference Guide](https://docs.aws.amazon.com/credref/latest/refdocs/creds-config-files.html). +* [Go 1.14 or later](https://go.dev/doc/install) + +### Run the code + +Each example can be run separately at a command prompt. The README in each service +folder has instructions for how to run the examples. + +### Run the tests + +All tests use go test, and you can find them alongside the code in the folder for each +example. The README in each service folder has instructions for how to run the examples. + +## Additional resources + +* [AWS SDK for Go V1 Developer Guide](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/welcome.html) +* [AWS SDK for Go V1 API Reference](https://docs.aws.amazon.com/sdk-for-go/api/) + +--- + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 From 9bbae86fb034ebe8bbdc242fd40c3156de30f09f Mon Sep 17 00:00:00 2001 From: Laren-AWS <57545972+Laren-AWS@users.noreply.github.com> Date: Mon, 22 Jan 2024 13:02:50 -0800 Subject: [PATCH 15/36] [Go] Example updates: S3 CopyObject and DeleteObjects (#5972) Added copy to bucket to match the rest of the action examples. --- .doc_gen/metadata/s3_metadata.yaml | 2 +- gov2/s3/README.md | 8 ++--- gov2/s3/actions/bucket_basics.go | 22 +++++++++++- gov2/s3/actions/bucket_basics_test.go | 36 +++++++++++++++++++ gov2/s3/scenarios/scenario_presigning_test.go | 4 ++- 5 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 gov2/s3/actions/bucket_basics_test.go diff --git a/.doc_gen/metadata/s3_metadata.yaml b/.doc_gen/metadata/s3_metadata.yaml index 3e5fc295b26..2423a3b4a3e 100644 --- a/.doc_gen/metadata/s3_metadata.yaml +++ b/.doc_gen/metadata/s3_metadata.yaml @@ -210,7 +210,7 @@ s3_CopyObject: - description: snippet_tags: - gov2.s3.BucketBasics.struct - - gov2.s3.CopyObject + - gov2.s3.CopyObject.ToBucket Kotlin: versions: - sdk_version: 1 diff --git a/gov2/s3/README.md b/gov2/s3/README.md index 75730b56041..5a7edb3490e 100644 --- a/gov2/s3/README.md +++ b/gov2/s3/README.md @@ -38,14 +38,14 @@ For prerequisites, see the [README](../README.md#Prerequisites) in the `gov2` fo Code excerpts that show you how to call individual service functions. -- [Copy an object from one bucket to another](actions/bucket_basics.go#L202) (`CopyObject`) +- [Copy an object from one bucket to another](actions/bucket_basics.go#L220) (`CopyObject`) - [Create a bucket](actions/bucket_basics.go#L81) (`CreateBucket`) -- [Delete an empty bucket](actions/bucket_basics.go#L258) (`DeleteBucket`) -- [Delete multiple objects](actions/bucket_basics.go#L238) (`DeleteObjects`) +- [Delete an empty bucket](actions/bucket_basics.go#L278) (`DeleteBucket`) +- [Delete multiple objects](actions/bucket_basics.go#L256) (`DeleteObjects`) - [Determine the existence of a bucket](actions/bucket_basics.go#L51) (`HeadBucket`) - [Get an object from a bucket](actions/bucket_basics.go#L149) (`GetObject`) - [List buckets](actions/bucket_basics.go#L35) (`ListBuckets`) -- [List objects in a bucket](actions/bucket_basics.go#L220) (`ListObjectsV2`) +- [List objects in a bucket](actions/bucket_basics.go#L238) (`ListObjectsV2`) - [Upload an object to a bucket](actions/bucket_basics.go#L100) (`PutObject`) ### Scenarios diff --git a/gov2/s3/actions/bucket_basics.go b/gov2/s3/actions/bucket_basics.go index de7f66d96ef..b54ab9aa62b 100644 --- a/gov2/s3/actions/bucket_basics.go +++ b/gov2/s3/actions/bucket_basics.go @@ -217,6 +217,24 @@ func (basics BucketBasics) CopyToFolder(bucketName string, objectKey string, fol // snippet-end:[gov2.s3.CopyObject] +// snippet-start:[gov2.s3.CopyObject.ToBucket] + +// CopyToBucket copies an object in a bucket to another bucket. +func (basics BucketBasics) CopyToBucket(sourceBucket string, destinationBucket string, objectKey string) error { + _, err := basics.S3Client.CopyObject(context.TODO(), &s3.CopyObjectInput{ + Bucket: aws.String(destinationBucket), + CopySource: aws.String(fmt.Sprintf("%v/%v", sourceBucket, objectKey)), + Key: aws.String(objectKey), + }) + if err != nil { + log.Printf("Couldn't copy object from %v:%v to %v:%v. Here's why: %v\n", + sourceBucket, objectKey, destinationBucket, objectKey, err) + } + return err +} + +// snippet-end:[gov2.s3.CopyObject.ToBucket] + // snippet-start:[gov2.s3.ListObjectsV2] // ListObjects lists the objects in a bucket. @@ -243,12 +261,14 @@ func (basics BucketBasics) DeleteObjects(bucketName string, objectKeys []string) for _, key := range objectKeys { objectIds = append(objectIds, types.ObjectIdentifier{Key: aws.String(key)}) } - _, err := basics.S3Client.DeleteObjects(context.TODO(), &s3.DeleteObjectsInput{ + output, err := basics.S3Client.DeleteObjects(context.TODO(), &s3.DeleteObjectsInput{ Bucket: aws.String(bucketName), Delete: &types.Delete{Objects: objectIds}, }) if err != nil { log.Printf("Couldn't delete objects from bucket %v. Here's why: %v\n", bucketName, err) + } else { + log.Printf("Deleted %v objects.\n", len(output.Deleted)) } return err } diff --git a/gov2/s3/actions/bucket_basics_test.go b/gov2/s3/actions/bucket_basics_test.go new file mode 100644 index 00000000000..41d9e91069d --- /dev/null +++ b/gov2/s3/actions/bucket_basics_test.go @@ -0,0 +1,36 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Unit tests for action not covered by scenarios. + +package actions + +import ( + "errors" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/awsdocs/aws-doc-sdk-examples/gov2/s3/stubs" + "github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools" +) + +func enterTest() (*testtools.AwsmStubber, *BucketBasics) { + stubber := testtools.NewStubber() + basics := &BucketBasics{S3Client: s3.NewFromConfig(*stubber.SdkConfig)} + return stubber, basics +} + +func TestBucketBasics_CopyToBucket(t *testing.T) { + t.Run("NoErrors", func(t *testing.T) { CopyToBucket(nil, t) }) + t.Run("TestError", func(t *testing.T) { CopyToBucket(&testtools.StubError{Err: errors.New("TestError")}, t) }) +} + +func CopyToBucket(raiseErr *testtools.StubError, t *testing.T) { + stubber, basics := enterTest() + stubber.Add(stubs.StubCopyObject("source-bucket", "object-key", "dest-bucket", "object-key", raiseErr)) + + err := basics.CopyToBucket("source-bucket", "dest-bucket", "object-key") + + testtools.VerifyError(err, raiseErr, t) + testtools.ExitTest(stubber, t) +} diff --git a/gov2/s3/scenarios/scenario_presigning_test.go b/gov2/s3/scenarios/scenario_presigning_test.go index 9e3d18648e9..b76c6acc6f7 100644 --- a/gov2/s3/scenarios/scenario_presigning_test.go +++ b/gov2/s3/scenarios/scenario_presigning_test.go @@ -53,7 +53,9 @@ type PresigningScenarioTest struct { func (scenTest *PresigningScenarioTest) SetupDataAndStubs() []testtools.Stub { bucketName := "test-bucket-1" testConfig, err := config.LoadDefaultConfig(context.TODO()) - if err != nil {panic(err)} + if err != nil { + panic(err) + } objectKey := "doc-example-key" scenTest.TestBody = io.NopCloser(strings.NewReader("Test data!")) scenTest.Answers = []string{ From fda7e9d266486b86126778641ac1f89377e28b3e Mon Sep 17 00:00:00 2001 From: David Souther Date: Tue, 23 Jan 2024 10:42:55 -0500 Subject: [PATCH 16/36] CFN: Add resilient service rolling update mechanism (#5955) Add CFN resilient service rolling update mechanism --- .../cross-service/resilient-workflow/README.md | 16 +++++++++++----- .../resilient-workflow/resilient-service.yaml | 12 ++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/aws-cfn/cross-service/resilient-workflow/README.md b/aws-cfn/cross-service/resilient-workflow/README.md index 62e9eb3f7ad..4d494f3d10b 100644 --- a/aws-cfn/cross-service/resilient-workflow/README.md +++ b/aws-cfn/cross-service/resilient-workflow/README.md @@ -153,11 +153,11 @@ aws elbv2 describe-target-health --target-group-arn "arn:aws:elasticloadbalancin All stack outputs: -| OutputKey | OutputValue | Usage | -| --------- | ----------------------------------------- | ------------------------------------------------- | -| `LB` | The DNS Name of the primary load balancer | `curl` or Browser | +| OutputKey | OutputValue | Usage | +| --------- | ------------------------------------------ | ------------------------------------------------- | +| `LB` | The DNS Name of the primary load balancer | `curl` or Browser | | `Key` | The ID of a .pem format private key in SSM | `ssh` after downloading from SSM | -| `TGArn` | The ARN of the target group of instances | Check various additional information from the CLI | +| `TGArn` | The ARN of the target group of instances | Check various additional information from the CLI | #### Demonstrate resiliency @@ -182,6 +182,7 @@ aws cloudformation update-stack \ 1. **Initial state: healthy** — Sends requests to the endpoint to get recommendations and verify that instances are healthy. + 2. **Broken dependency** — Sets a parameter that specifies a nonexistent DynamoDB table name. This simulates a failure of the recommendation service. Requests for recommendations now return a failure code. All instances still report as healthy because they only implement shallow health checks. For this @@ -231,7 +232,8 @@ aws cloudformation update-stack \ Using the AWS Management Console, open the CloudFormation page. Navigate to the `resilience-demo` stack. Choose the `Resources` tab. Find the `DocExampleRecommendationServiceTargetGroup` line. Choose the `Physical Resource ID` link. - From this EC2 page, find the list of instances in the target group. Select one and navigate to it. Choose `Actions`, `Terminate instance`. See EC2 terminate the instance, and watch the Auto Scaling group start a new instance. + From this EC2 page, find the list of instances in the target group. Select one and navigate to it. Choose `Actions`, `Terminate instance`. + See EC2 terminate the instance, and watch the Auto Scaling group start a new instance. 7. **Fail open** — Sets the table name parameter so the recommendations service fails for all instances. Because all instances are using deep health checks, they all report as unhealthy. In this @@ -242,6 +244,10 @@ aws cloudformation update-stack \ Edit `params.json`. Add a new entry with `ParameterKey` as `SSMTableName` and `ParameterValue` as `unknown`. After updating, the service should report unhealthy but return static responses. +8. **Rolling Update** If necessary, you can trigger rolling updates to all instances by changing the Launch Template. + To change a non-functional aspect of the Launch Template, which will trigger a rolling update without needing to modify any functional configuration, change the `LaunchTemplateVersion` parameter. + This has a default value of `1.0.0`, but can be any string. Any change to this string will trigger an `AutoScalingRollingUpdate` in the `DocExampleRecommendationServiceAutoScalingGroup`. + ##### Destroy resources Use AWS CloudFormation to clean up all resources created for this example. diff --git a/aws-cfn/cross-service/resilient-workflow/resilient-service.yaml b/aws-cfn/cross-service/resilient-workflow/resilient-service.yaml index 96dd34263aa..be3b6e5a151 100644 --- a/aws-cfn/cross-service/resilient-workflow/resilient-service.yaml +++ b/aws-cfn/cross-service/resilient-workflow/resilient-service.yaml @@ -23,6 +23,9 @@ Parameters: SSMTableName: Type: String Default: "" + LaunchTemplateVersion: + Type: String + Default: "1.0.0" Conditions: EmptySSMTableName: !Equals ["", !Ref SSMTableName] @@ -197,6 +200,11 @@ Resources: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateName: doc-example-resilience-template + TagSpecifications: + - ResourceType: launch-template + Tags: + - Key: InternalVersion + Value: !Ref LaunchTemplateVersion # Increment this value & update the stack to trigger a rolling update of the group LaunchTemplateData: InstanceType: !Ref InstanceType ImageId: resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 @@ -219,6 +227,10 @@ Resources: # 4. An Auto Scaling group that starts EC2 instances, one in each of three Availability Zones. DocExampleRecommendationServiceAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup + UpdatePolicy: + AutoScalingRollingUpdate: + MaxBatchSize: 2 + MinInstancesInService: 1 Properties: AutoScalingGroupName: doc-example-resilience-group AvailabilityZones: { "Fn::GetAZs": { "Ref": "AWS::Region" } } From 403876799853745fc9be3ed0059349e77f35e064 Mon Sep 17 00:00:00 2001 From: David Souther Date: Tue, 23 Jan 2024 11:49:33 -0500 Subject: [PATCH 17/36] Rust: Per request configuration examples (#5985) Rust: Add per-operation examples for setting region, retries, and credentials --- .../src/bin/per-request-credentials.rs | 51 ++++++++++++++ .../sdk-config/src/bin/per-request-retries.rs | 61 ++++++++++++++++ .../sdk-config/src/bin/pre-request-region.rs | 70 +++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 rustv1/examples/sdk-config/src/bin/per-request-credentials.rs create mode 100644 rustv1/examples/sdk-config/src/bin/per-request-retries.rs create mode 100644 rustv1/examples/sdk-config/src/bin/pre-request-region.rs diff --git a/rustv1/examples/sdk-config/src/bin/per-request-credentials.rs b/rustv1/examples/sdk-config/src/bin/per-request-credentials.rs new file mode 100644 index 00000000000..519f5a00b2b --- /dev/null +++ b/rustv1/examples/sdk-config/src/bin/per-request-credentials.rs @@ -0,0 +1,51 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![allow(clippy::result_large_err)] + +use std::time::{Duration, SystemTime}; + +use aws_config::BehaviorVersion; +use aws_credential_types::{credential_fn::provide_credentials_fn, Credentials}; +use aws_sdk_s3::{Client, Config, Error}; + +/// Displays how many Amazon S3 buckets you have. +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing_subscriber::fmt::init(); + + let shared_config = aws_config::defaults(BehaviorVersion::latest()).load().await; + let client = Client::new(&shared_config); + + // snippet-start:[rust.per_operation_credentials] + let resp = client + .list_buckets() + .customize() + .config_override( + Config::builder().credentials_provider(provide_credentials_fn(move || { + // This snippet is for example purposes only. Production applications are responsible + // for developing secure methods to provide Credentials at this point. + let access_key_id = "access_key_id".to_string(); + let secret_access_key = "secret_access_key".to_string(); + let session_token = "session_token".to_string(); + let expires_after = SystemTime::now() + Duration::from_secs(60); + async move { + Ok(Credentials::new( + access_key_id, + secret_access_key, + Some(session_token), + Some(expires_after), + "example_provider", + )) + } + })), + ) + .send() + .await?; + // snippet-end:[rust.per_operation_credentials] + let buckets = resp.buckets(); + + println!("Found {} buckets in all regions.", buckets.len()); + + Ok(()) +} diff --git a/rustv1/examples/sdk-config/src/bin/per-request-retries.rs b/rustv1/examples/sdk-config/src/bin/per-request-retries.rs new file mode 100644 index 00000000000..5d8370ef26e --- /dev/null +++ b/rustv1/examples/sdk-config/src/bin/per-request-retries.rs @@ -0,0 +1,61 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![allow(clippy::result_large_err)] + +use aws_config::BehaviorVersion; +use aws_sdk_s3::config::retry::RetryConfig; +use aws_sdk_s3::{meta::PKG_VERSION, Client, Config, Error}; +use clap::Parser; + +#[derive(Debug, Parser)] +struct Opt { + /// The number of (re)tries. + #[structopt(short, long, default_value = "2")] + tries: u32, + + /// Whether to display additional information. + #[structopt(short, long)] + verbose: bool, +} + +/// Displays how many Amazon S3 buckets you have. +/// # Arguments +/// +/// * `[-t TRIES]` - The number of times to (re)try the request. +/// * `[-v]` - Whether to display additional information. +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing_subscriber::fmt::init(); + + let Opt { tries, verbose } = Opt::parse(); + + if verbose { + println!("S3 client version: {}", PKG_VERSION); + println!("Max retries: {}", &tries); + println!(); + } + + assert_ne!(tries, 0, "You cannot set zero retries."); + + let shared_config = aws_config::defaults(BehaviorVersion::latest()).load().await; + + // Construct an S3 client with customized retry configuration. + let client = Client::new(&shared_config); + + // snippet-start:[rust.per_operation_retry] + let resp = client + .list_buckets() + .customize() + .config_override( + Config::builder().retry_config(RetryConfig::standard().with_max_attempts(tries)), + ) + .send() + .await?; + // snippet-end:[rust.per_operation_retry] + let buckets = resp.buckets(); + + println!("Found {} buckets in all regions.", buckets.len()); + + Ok(()) +} diff --git a/rustv1/examples/sdk-config/src/bin/pre-request-region.rs b/rustv1/examples/sdk-config/src/bin/pre-request-region.rs new file mode 100644 index 00000000000..a148dd739a9 --- /dev/null +++ b/rustv1/examples/sdk-config/src/bin/pre-request-region.rs @@ -0,0 +1,70 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![allow(clippy::result_large_err)] + +use aws_config::meta::region::RegionProviderChain; +use aws_config::{BehaviorVersion, Region}; +use aws_sdk_s3::{meta::PKG_VERSION, Client, Config, Error}; +use clap::Parser; + +#[derive(Debug, Parser)] +struct Opt { + /// The AWS Region. + #[structopt(short, long)] + region: Option, + + /// Whether to display additional information. + #[structopt(short, long)] + verbose: bool, +} + +/// Displays how many Amazon S3 buckets you have. +/// # Arguments +/// +/// * `[-r REGION]` - The Region in which the client is created. +/// If not supplied, uses the value of the **AWS_REGION** environment variable. +/// If the environment variable is not set, defaults to **us-west-2**. +/// * `[-v]` - Whether to display additional information. +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing_subscriber::fmt::init(); + + let Opt { region, verbose } = Opt::parse(); + + if verbose { + println!("S3 client version: {}", PKG_VERSION); + println!( + "Region: {}", + region.as_deref().unwrap_or("not provided"), + ); + println!(); + } + + let shared_config = aws_config::defaults(BehaviorVersion::latest()).load().await; + + // Construct an S3 client with customized retry configuration. + let client = Client::new(&shared_config); + + // snippet-start:[rust.per_operation_region] + let resp = client + .list_buckets() + .customize() + .config_override( + Config::builder().region( + RegionProviderChain::first_try(region.map(Region::new)) + .or_default_provider() + .or_else(Region::new("us-west-2")) + .region() + .await, + ), + ) + .send() + .await?; + // snippet-end:[rust.per_operation_region] + let buckets = resp.buckets(); + + println!("Found {} buckets in all regions.", buckets.len()); + + Ok(()) +} From e1d90062935a266a0292b260d1a293d8cae68fc0 Mon Sep 17 00:00:00 2001 From: Scott Macdonald <57190223+scmacdon@users.noreply.github.com> Date: Tue, 23 Jan 2024 12:52:09 -0500 Subject: [PATCH 18/36] Java V2 Updated the S3 video render example (#5948) * updated the video render example --- .../create_spring_stream_app/Readme.md | 177 +++++++------ .../usecases/create_spring_stream_app/pom.xml | 8 +- .../main/java/com/example/Application.java | 8 +- .../src/main/java/com/example/Tags.java | 14 +- .../com/example/VideoStreamController.java | 16 +- .../java/com/example/VideoStreamService.java | 174 +++++++------ .../s3/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + kotlin/services/s3/gradlew | 244 ++++++++++++++++++ kotlin/services/s3/gradlew.bat | 92 +++++++ 10 files changed, 559 insertions(+), 180 deletions(-) create mode 100644 kotlin/services/s3/gradle/wrapper/gradle-wrapper.jar create mode 100644 kotlin/services/s3/gradle/wrapper/gradle-wrapper.properties create mode 100644 kotlin/services/s3/gradlew create mode 100644 kotlin/services/s3/gradlew.bat diff --git a/javav2/usecases/create_spring_stream_app/Readme.md b/javav2/usecases/create_spring_stream_app/Readme.md index 8a8fb7af6b5..5068f7463be 100644 --- a/javav2/usecases/create_spring_stream_app/Readme.md +++ b/javav2/usecases/create_spring_stream_app/Readme.md @@ -231,8 +231,8 @@ public class VideoStreamController { } // Returns the video in the bucket specified by the ID value. - @RequestMapping(value = "/{id}/stream", method = RequestMethod.GET) - public Mono> streamVideo(@PathVariable String id) { + @GetMapping("/{id}/stream") + public Mono> streamVideo(@PathVariable String id) { String fileName = id; return Mono.just(vid.getObjectBytes(bucket, fileName)); } @@ -247,13 +247,15 @@ public class VideoStreamController { The following Java code represents the **VideoStreamService** class. This class uses the Amazon S3 Java API (V2) to interact with content located in an Amazon S3 bucket. For example, the **getTags** method returns a collection of tags that are used to create the video menu. Likewise, the **getObjectBytes** reads bytes from a MP4 video. The byte array is used to create a **ResponseEntity** object. This object sets HTTP header information and the HTTP status code required to stream the video. ```java - package com.example; + package com.example; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.core.ResponseBytes; +import software.amazon.awssdk.core.ResponseInputStream; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; @@ -279,37 +281,40 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import java.io.BufferedOutputStream; import java.io.StringWriter; +import java.time.Duration; import java.util.List; import java.util.ArrayList; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.springframework.http.HttpHeaders; @Service public class VideoStreamService { - public static final String CONTENT_TYPE = "Content-Type"; - public static final String CONTENT_LENGTH = "Content-Length"; public static final String VIDEO_CONTENT = "video/"; private S3Client getClient() { return S3Client.builder() - .credentialsProvider(EnvironmentVariableCredentialsProvider.create()) - .region(Region.US_WEST_2) - .build(); + .credentialsProvider(EnvironmentVariableCredentialsProvider.create()) + .region(Region.US_WEST_2) + .build(); } // Places a new video into an Amazon S3 bucket. public void putVideo(byte[] bytes, String bucketName, String fileName, String description) { S3Client s3 = getClient(); - try { // Set the tags to apply to the object. String theTags = "name="+fileName+"&description="+description; + PutObjectRequest putOb = PutObjectRequest.builder() - .bucket(bucketName) - .key(fileName) - .tagging(theTags) - .build(); + .bucket(bucketName) + .key(fileName) + .tagging(theTags) + .build(); s3.putObject(putOb, RequestBody.fromBytes(bytes)); @@ -319,6 +324,7 @@ public class VideoStreamService { } } + // Returns a schema that describes all tags for all videos in the given bucket. public String getTags(String bucketName){ S3Client s3 = getClient(); @@ -328,88 +334,96 @@ public class VideoStreamService { .bucket(bucketName) .build(); - ListObjectsResponse res = s3.listObjects(listObjects); - List objects = res.contents(); - List keys = new ArrayList<>(); - for (S3Object myValue: objects) { - String key = myValue.key(); // We need the key to get the tags. - GetObjectTaggingRequest getTaggingRequest = GetObjectTaggingRequest.builder() - .key(key) - .bucket(bucketName) - .build(); - - GetObjectTaggingResponse tags = s3.getObjectTagging(getTaggingRequest); - List tagSet= tags.tagSet(); - for (Tag tag : tagSet) { - keys.add(tag.value()); - } - } - - List tagList = modList(keys); - return convertToString(toXml(tagList)); - - } catch (S3Exception e) { - System.err.println(e.awsErrorDetails().errorMessage()); - System.exit(1); - } + ListObjectsResponse res = s3.listObjects(listObjects); + List objects = res.contents(); + List keys = new ArrayList<>(); + for (S3Object myValue: objects) { + String key = myValue.key(); // We need the key to get the tags. + GetObjectTaggingRequest getTaggingRequest = GetObjectTaggingRequest.builder() + .key(key) + .bucket(bucketName) + .build(); + + GetObjectTaggingResponse tags = s3.getObjectTagging(getTaggingRequest); + List tagSet= tags.tagSet(); + for (Tag tag : tagSet) { + keys.add(tag.value()); + } + } + + List tagList = modList(keys); + return convertToString(toXml(tagList)); + + } catch (S3Exception e) { + System.err.println(e.awsErrorDetails().errorMessage()); + System.exit(1); + } return ""; } // Return a List where each element is a Tags object. - private List modList(List myList){ - // Get the elements from the collection. + private List modList(List myList) { int count = myList.size(); - List allTags = new ArrayList<>(); - Tags myTag ; - ArrayList keys = new ArrayList<>(); - ArrayList values = new ArrayList<>(); - - for ( int index=0; index < count; index++) { - if (index % 2 == 0) - keys.add(myList.get(index)); - else - values.add(myList.get(index)); - } - - // Create a list where each element is a Tags object. - for (int r=0; r { + Tags myTag = new Tags(); + myTag.setName(myList.get(index * 2)); + myTag.setDesc(myList.get(index * 2 + 1)); + return myTag; + }) + .collect(Collectors.toList()); } // Reads a video from a bucket and returns a ResponseEntity. - public ResponseEntity getObjectBytes (String bucketName, String keyName) { + public ResponseEntity getObjectBytes(String bucketName, String keyName) { S3Client s3 = getClient(); try { - // create a GetObjectRequest instance. - GetObjectRequest objectRequest = GetObjectRequest - .builder() - .key(keyName) - .bucket(bucketName) - .build(); + // Create an S3 object request. + GetObjectRequest objectRequest = GetObjectRequest.builder() + .bucket(bucketName) + .key(keyName) + .build(); - // get the byte[] from this AWS S3 object and return a ResponseEntity. - ResponseBytes objectBytes = s3.getObjectAsBytes(objectRequest); - return ResponseEntity.status(HttpStatus.OK) - .header(CONTENT_TYPE, VIDEO_CONTENT + "mp4") - .header(CONTENT_LENGTH, String.valueOf(objectBytes.asByteArray().length)) - .body(objectBytes.asByteArray()); + // Get the S3 object stream. + ResponseInputStream objectStream = s3.getObject(objectRequest); - } catch (S3Exception e) { - System.err.println(e.awsErrorDetails().errorMessage()); - System.exit(1); + // Set content type and length headers. + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.valueOf(VIDEO_CONTENT + "mp4")); + + // Set content length if available. + Long contentLength = objectStream.response().contentLength(); + if (contentLength != null) { + headers.setContentLength(contentLength); + } + + // Set disposition as inline to display content in the browser. + headers.setContentDispositionFormData("inline", keyName); + + // Create a StreamingResponseBody to stream the content. + StreamingResponseBody responseBody = outputStream -> { + try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) { + byte[] buffer = new byte[1024 * 1024]; + int bytesRead; + while ((bytesRead = objectStream.read(buffer)) != -1) { + bufferedOutputStream.write(buffer, 0, bytesRead); + } + bufferedOutputStream.flush(); + } finally { + objectStream.close(); + } + }; + + return new ResponseEntity<>(responseBody, headers, HttpStatus.OK); + } catch (Exception e) { + // Handle exceptions and return an appropriate ResponseEntity. + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } - return null; } - // Convert a LIST to XML data. - private Document toXml(List itemList) { + private Document toXml(List itemList) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); @@ -422,7 +436,6 @@ public class VideoStreamService { // Iterate through the list. for (Tags myItem: itemList) { - Element item = doc.createElement( "Tag" ); root.appendChild( item ); @@ -447,13 +460,14 @@ public class VideoStreamService { private String convertToString(Document xml) { try { TransformerFactory transformerFactory = getSecureTransformerFactory(); + transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); Transformer transformer = transformerFactory.newTransformer(); StreamResult result = new StreamResult(new StringWriter()); DOMSource source = new DOMSource(xml); transformer.transform(source, result); return result.getWriter().toString(); - } catch(TransformerException ex) { + } catch (TransformerException ex) { ex.printStackTrace(); } return null; @@ -469,7 +483,6 @@ public class VideoStreamService { return transformerFactory; } } - ``` ## Create the HTML file diff --git a/javav2/usecases/create_spring_stream_app/pom.xml b/javav2/usecases/create_spring_stream_app/pom.xml index 59905c63dab..7a5c8c9ef0e 100644 --- a/javav2/usecases/create_spring_stream_app/pom.xml +++ b/javav2/usecases/create_spring_stream_app/pom.xml @@ -10,21 +10,19 @@ org.springframework.boot spring-boot-starter-parent - 2.3.0.RELEASE + 2.7.4 UTF-8 - 17 - 17 - 17 + 11 software.amazon.awssdk bom - 2.21.20 + 2.20.45 pom import diff --git a/javav2/usecases/create_spring_stream_app/src/main/java/com/example/Application.java b/javav2/usecases/create_spring_stream_app/src/main/java/com/example/Application.java index f99e8919390..0ed6fd349ae 100644 --- a/javav2/usecases/create_spring_stream_app/src/main/java/com/example/Application.java +++ b/javav2/usecases/create_spring_stream_app/src/main/java/com/example/Application.java @@ -1,5 +1,7 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 +/* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 +*/ package com.example; @@ -7,7 +9,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; -@SpringBootApplication(exclude = { SecurityAutoConfiguration.class }) +@SpringBootApplication(exclude = {SecurityAutoConfiguration.class }) public class Application { public static void main(String[] args) { diff --git a/javav2/usecases/create_spring_stream_app/src/main/java/com/example/Tags.java b/javav2/usecases/create_spring_stream_app/src/main/java/com/example/Tags.java index 36c922b6872..d2587a82574 100644 --- a/javav2/usecases/create_spring_stream_app/src/main/java/com/example/Tags.java +++ b/javav2/usecases/create_spring_stream_app/src/main/java/com/example/Tags.java @@ -1,5 +1,7 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 +/* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 +*/ package com.example; @@ -9,18 +11,18 @@ public class Tags { private String description; public String getDesc() { - return this.description; + return this.description ; } - public void setDesc(String description) { + public void setDesc(String description){ this.description = description; } public String getName() { - return this.name; + return this.name ; } - public void setName(String name) { + public void setName(String name){ this.name = name; } } diff --git a/javav2/usecases/create_spring_stream_app/src/main/java/com/example/VideoStreamController.java b/javav2/usecases/create_spring_stream_app/src/main/java/com/example/VideoStreamController.java index 74f7ca8504f..52e9804b692 100644 --- a/javav2/usecases/create_spring_stream_app/src/main/java/com/example/VideoStreamController.java +++ b/javav2/usecases/create_spring_stream_app/src/main/java/com/example/VideoStreamController.java @@ -1,5 +1,7 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 +/* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 +*/ package com.example; @@ -14,6 +16,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import org.springframework.web.servlet.view.RedirectView; import reactor.core.publisher.Mono; import javax.servlet.http.HttpServletRequest; @@ -27,7 +30,8 @@ public class VideoStreamController { @Autowired VideoStreamController( - VideoStreamService vid) { + VideoStreamService vid + ) { this.vid = vid; } @@ -54,7 +58,7 @@ public String upload() { public ModelAndView singleFileUpload(@RequestParam("file") MultipartFile file, @RequestParam String description) { try { byte[] bytes = file.getBytes(); - String name = file.getOriginalFilename(); + String name = file.getOriginalFilename() ; // Put the MP4 file into an Amazon S3 bucket. vid.putVideo(bytes, bucket, name, description); @@ -74,8 +78,8 @@ public String getItems(HttpServletRequest request, HttpServletResponse response) } // Returns the video in the bucket specified by the ID value. - @RequestMapping(value = "/{id}/stream", method = RequestMethod.GET) - public Mono> streamVideo(@PathVariable String id) { + @GetMapping("/{id}/stream") + public Mono> streamVideo(@PathVariable String id) { String fileName = id; return Mono.just(vid.getObjectBytes(bucket, fileName)); } diff --git a/javav2/usecases/create_spring_stream_app/src/main/java/com/example/VideoStreamService.java b/javav2/usecases/create_spring_stream_app/src/main/java/com/example/VideoStreamService.java index c5bdeacf89b..34cacd37322 100644 --- a/javav2/usecases/create_spring_stream_app/src/main/java/com/example/VideoStreamService.java +++ b/javav2/usecases/create_spring_stream_app/src/main/java/com/example/VideoStreamService.java @@ -1,13 +1,17 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 +/* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + SPDX-License-Identifier: Apache-2.0 +*/ package com.example; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.core.ResponseBytes; +import software.amazon.awssdk.core.ResponseInputStream; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; @@ -33,23 +37,26 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import java.io.BufferedOutputStream; import java.io.StringWriter; +import java.time.Duration; import java.util.List; import java.util.ArrayList; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.springframework.http.HttpHeaders; @Service public class VideoStreamService { - public static final String CONTENT_TYPE = "Content-Type"; - public static final String CONTENT_LENGTH = "Content-Length"; public static final String VIDEO_CONTENT = "video/"; private S3Client getClient() { return S3Client.builder() - .credentialsProvider(EnvironmentVariableCredentialsProvider.create()) - .region(Region.US_WEST_2) - .build(); + .credentialsProvider(EnvironmentVariableCredentialsProvider.create()) + .region(Region.US_WEST_2) + .build(); } // Places a new video into an Amazon S3 bucket. @@ -57,13 +64,13 @@ public void putVideo(byte[] bytes, String bucketName, String fileName, String de S3Client s3 = getClient(); try { // Set the tags to apply to the object. - String theTags = "name=" + fileName + "&description=" + description; + String theTags = "name="+fileName+"&description="+description; PutObjectRequest putOb = PutObjectRequest.builder() - .bucket(bucketName) - .key(fileName) - .tagging(theTags) - .build(); + .bucket(bucketName) + .key(fileName) + .tagging(theTags) + .build(); s3.putObject(putOb, RequestBody.fromBytes(bytes)); @@ -73,27 +80,28 @@ public void putVideo(byte[] bytes, String bucketName, String fileName, String de } } + // Returns a schema that describes all tags for all videos in the given bucket. - public String getTags(String bucketName) { + public String getTags(String bucketName){ S3Client s3 = getClient(); try { ListObjectsRequest listObjects = ListObjectsRequest.builder() - .bucket(bucketName) - .build(); + .bucket(bucketName) + .build(); ListObjectsResponse res = s3.listObjects(listObjects); List objects = res.contents(); List keys = new ArrayList<>(); - for (S3Object myValue : objects) { + for (S3Object myValue: objects) { String key = myValue.key(); // We need the key to get the tags. GetObjectTaggingRequest getTaggingRequest = GetObjectTaggingRequest.builder() - .key(key) - .bucket(bucketName) - .build(); + .key(key) + .bucket(bucketName) + .build(); GetObjectTaggingResponse tags = s3.getObjectTagging(getTaggingRequest); - List tagSet = tags.tagSet(); + List tagSet= tags.tagSet(); for (Tag tag : tagSet) { keys.add(tag.value()); } @@ -111,53 +119,63 @@ public String getTags(String bucketName) { // Return a List where each element is a Tags object. private List modList(List myList) { - // Get the elements from the collection. int count = myList.size(); - List allTags = new ArrayList<>(); - Tags myTag; - ArrayList keys = new ArrayList<>(); - ArrayList values = new ArrayList<>(); - - for (int index = 0; index < count; index++) { - if (index % 2 == 0) - keys.add(myList.get(index)); - else - values.add(myList.get(index)); - } - - // Create a list where each element is a Tags object. - for (int r = 0; r < keys.size(); r++) { - myTag = new Tags(); - myTag.setName(keys.get(r)); - myTag.setDesc(values.get(r)); - allTags.add(myTag); - } - return allTags; + return IntStream.range(0, count / 2) + .mapToObj(index -> { + Tags myTag = new Tags(); + myTag.setName(myList.get(index * 2)); + myTag.setDesc(myList.get(index * 2 + 1)); + return myTag; + }) + .collect(Collectors.toList()); } + // Reads a video from a bucket and returns a ResponseEntity. - public ResponseEntity getObjectBytes(String bucketName, String keyName) { + public ResponseEntity getObjectBytes(String bucketName, String keyName) { S3Client s3 = getClient(); try { - // create a GetObjectRequest instance. - GetObjectRequest objectRequest = GetObjectRequest - .builder() - .key(keyName) - .bucket(bucketName) - .build(); + // Create an S3 object request. + GetObjectRequest objectRequest = GetObjectRequest.builder() + .bucket(bucketName) + .key(keyName) + .build(); - // get the byte[] from this AWS S3 object and return a ResponseEntity. - ResponseBytes objectBytes = s3.getObjectAsBytes(objectRequest); - return ResponseEntity.status(HttpStatus.OK) - .header(CONTENT_TYPE, VIDEO_CONTENT + "mp4") - .header(CONTENT_LENGTH, String.valueOf(objectBytes.asByteArray().length)) - .body(objectBytes.asByteArray()); + // Get the S3 object stream. + ResponseInputStream objectStream = s3.getObject(objectRequest); - } catch (S3Exception e) { - System.err.println(e.awsErrorDetails().errorMessage()); - System.exit(1); + // Set content type and length headers. + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.valueOf(VIDEO_CONTENT + "mp4")); + + // Set content length if available. + Long contentLength = objectStream.response().contentLength(); + if (contentLength != null) { + headers.setContentLength(contentLength); + } + + // Set disposition as inline to display content in the browser. + headers.setContentDispositionFormData("inline", keyName); + + // Create a StreamingResponseBody to stream the content. + StreamingResponseBody responseBody = outputStream -> { + try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) { + byte[] buffer = new byte[1024 * 1024]; + int bytesRead; + while ((bytesRead = objectStream.read(buffer)) != -1) { + bufferedOutputStream.write(buffer, 0, bytesRead); + } + bufferedOutputStream.flush(); + } finally { + objectStream.close(); + } + }; + + return new ResponseEntity<>(responseBody, headers, HttpStatus.OK); + } catch (Exception e) { + // Handle exceptions and return an appropriate ResponseEntity. + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } - return null; } // Convert a LIST to XML data. @@ -168,29 +186,28 @@ private Document toXml(List itemList) { DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.newDocument(); - // Start building the XML - Element root = doc.createElement("Tags"); - doc.appendChild(root); + // Start building the XML. + Element root = doc.createElement( "Tags" ); + doc.appendChild( root ); // Iterate through the list. - for (Tags myItem : itemList) { - - Element item = doc.createElement("Tag"); - root.appendChild(item); - - // Set Name - Element id = doc.createElement("Name"); - id.appendChild(doc.createTextNode(myItem.getName())); - item.appendChild(id); - - // Set Description - Element name = doc.createElement("Description"); - name.appendChild(doc.createTextNode(myItem.getDesc())); - item.appendChild(name); + for (Tags myItem: itemList) { + Element item = doc.createElement( "Tag" ); + root.appendChild( item ); + + // Set Name. + Element id = doc.createElement( "Name" ); + id.appendChild( doc.createTextNode(myItem.getName() ) ); + item.appendChild( id ); + + // Set Description. + Element name = doc.createElement( "Description" ); + name.appendChild( doc.createTextNode(myItem.getDesc() ) ); + item.appendChild( name ); } return doc; - } catch (ParserConfigurationException e) { + } catch(ParserConfigurationException e) { e.printStackTrace(); } return null; @@ -199,6 +216,7 @@ private Document toXml(List itemList) { private String convertToString(Document xml) { try { TransformerFactory transformerFactory = getSecureTransformerFactory(); + transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); Transformer transformer = transformerFactory.newTransformer(); StreamResult result = new StreamResult(new StringWriter()); DOMSource source = new DOMSource(xml); @@ -220,4 +238,4 @@ private static TransformerFactory getSecureTransformerFactory() { } return transformerFactory; } -} +} \ No newline at end of file diff --git a/kotlin/services/s3/gradle/wrapper/gradle-wrapper.jar b/kotlin/services/s3/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 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 literal 0 HcmV?d00001 diff --git a/kotlin/services/s3/gradle/wrapper/gradle-wrapper.properties b/kotlin/services/s3/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..42defcc94b3 --- /dev/null +++ b/kotlin/services/s3/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/kotlin/services/s3/gradlew b/kotlin/services/s3/gradlew new file mode 100644 index 00000000000..79a61d421cc --- /dev/null +++ b/kotlin/services/s3/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/kotlin/services/s3/gradlew.bat b/kotlin/services/s3/gradlew.bat new file mode 100644 index 00000000000..93e3f59f135 --- /dev/null +++ b/kotlin/services/s3/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From 3099272880f8e84583dc270ea97bcc37ae6920d4 Mon Sep 17 00:00:00 2001 From: Laren-AWS <57545972+Laren-AWS@users.noreply.github.com> Date: Tue, 23 Jan 2024 10:20:36 -0800 Subject: [PATCH 19/36] [Go] Add Movies struct to examples that use it (#5987) Add Movies struct to examples that use it so the code is more intelligible in the docs. --- .doc_gen/metadata/dynamodb_metadata.yaml | 50 +++++++++++++++++------- gov2/dynamodb/README.md | 6 +-- gov2/dynamodb/actions/movie.go | 4 ++ 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/.doc_gen/metadata/dynamodb_metadata.yaml b/.doc_gen/metadata/dynamodb_metadata.yaml index 85c44ff419e..5467f5a2a74 100644 --- a/.doc_gen/metadata/dynamodb_metadata.yaml +++ b/.doc_gen/metadata/dynamodb_metadata.yaml @@ -369,6 +369,7 @@ dynamodb_BatchWriteItem: snippet_tags: - gov2.dynamodb.TableBasics.struct - gov2.dynamodb.BatchWriteItem + - gov2.dynamodb.Movie.struct Java: versions: - sdk_version: 2 @@ -616,6 +617,7 @@ dynamodb_PutItem: snippet_tags: - gov2.dynamodb.TableBasics.struct - gov2.dynamodb.PutItem + - gov2.dynamodb.Movie.struct Kotlin: versions: - sdk_version: 1 @@ -753,6 +755,7 @@ dynamodb_GetItem: snippet_tags: - gov2.dynamodb.TableBasics.struct - gov2.dynamodb.GetItem + - gov2.dynamodb.Movie.struct Kotlin: versions: - sdk_version: 1 @@ -880,6 +883,7 @@ dynamodb_UpdateItem: snippet_tags: - gov2.dynamodb.TableBasics.struct - gov2.dynamodb.UpdateItem + - gov2.dynamodb.Movie.struct Kotlin: versions: - sdk_version: 1 @@ -999,6 +1003,7 @@ dynamodb_DeleteItem: snippet_tags: - gov2.dynamodb.TableBasics.struct - gov2.dynamodb.DeleteItem + - gov2.dynamodb.Movie.struct Kotlin: versions: - sdk_version: 1 @@ -1287,6 +1292,7 @@ dynamodb_Query: snippet_tags: - gov2.dynamodb.TableBasics.struct - gov2.dynamodb.Query + - gov2.dynamodb.Movie.struct Kotlin: versions: - sdk_version: 1 @@ -1427,6 +1433,7 @@ dynamodb_Scan: snippet_tags: - gov2.dynamodb.TableBasics.struct - gov2.dynamodb.Scan + - gov2.dynamodb.Movie.struct Kotlin: versions: - sdk_version: 1 @@ -1575,6 +1582,9 @@ dynamodb_ExecuteStatement: - description: Use a DELETE statement to delete an item. snippet_tags: - gov2.dynamodb.ExecuteStatement.Delete + - description: Define a Movie struct that is used in this example. + snippet_tags: + - gov2.dynamodb.Movie.struct JavaScript: versions: - sdk_version: 3 @@ -1694,6 +1704,9 @@ dynamodb_BatchExecuteStatement: - description: Use batches of DELETE statements to delete items. snippet_tags: - gov2.dynamodb.BatchExecuteStatement.Delete + - description: Define a Movie struct that is used in this example. + snippet_tags: + - gov2.dynamodb.Movie.struct JavaScript: versions: - sdk_version: 3 @@ -1854,14 +1867,17 @@ dynamodb_Scenario_GettingStartedMovies: - sdk_version: 2 github: gov2/dynamodb excerpts: - - description: Create a struct and methods that call &DDB; actions. - snippet_tags: - - gov2.dynamodb.TableBasics.complete - description: Run an interactive scenario to create the table and perform actions on it. snippet_tags: - gov2.dynamodb.Scenario_GettingStartedMovies + - description: Define a Movie struct that is used in this example. + snippet_tags: + - gov2.dynamodb.Movie.struct + - description: Create a struct and methods that call &DDB; actions. + snippet_tags: + - gov2.dynamodb.TableBasics.complete Kotlin: versions: - sdk_version: 1 @@ -2061,18 +2077,20 @@ dynamodb_Scenario_PartiQLSingle: - sdk_version: 2 github: gov2/dynamodb excerpts: + - description: Run a scenario that creates a table and runs PartiQL queries. + snippet_tags: + - gov2.dynamodb.Scenario_PartiQLSingle + - description: Define a Movie struct that is used in this example. + snippet_tags: + - gov2.dynamodb.Movie.struct - description: - Create a struct that is a receiver for methods that can run - PartiQL statements. + Create a struct and methods that run PartiQL statements. snippet_tags: - gov2.dynamodb.PartiQLRunner.struct - gov2.dynamodb.ExecuteStatement.Insert - gov2.dynamodb.ExecuteStatement.Select - gov2.dynamodb.ExecuteStatement.Update - gov2.dynamodb.ExecuteStatement.Delete - - description: Run a scenario that creates a table and runs PartiQL queries. - snippet_tags: - - gov2.dynamodb.Scenario_PartiQLSingle Kotlin: versions: - sdk_version: 1 @@ -2187,8 +2205,15 @@ dynamodb_Scenario_PartiQLBatch: github: gov2/dynamodb excerpts: - description: - Create a struct that is a receiver for methods that can run - PartiQL statements. + Run a scenario that creates a table and runs batches of + PartiQL queries. + snippet_tags: + - gov2.dynamodb.Scenario_PartiQLBatch + - description: Define a Movie struct that is used in this example. + snippet_tags: + - gov2.dynamodb.Movie.struct + - description: + Create a struct and methods that run PartiQL statements. snippet_tags: - gov2.dynamodb.PartiQLRunner.struct - gov2.dynamodb.BatchExecuteStatement.Insert @@ -2196,11 +2221,6 @@ dynamodb_Scenario_PartiQLBatch: - gov2.dynamodb.ExecuteStatement.Select.Projected - gov2.dynamodb.BatchExecuteStatement.Update - gov2.dynamodb.BatchExecuteStatement.Delete - - description: - Run a scenario that creates a table and runs batches of - PartiQL queries. - snippet_tags: - - gov2.dynamodb.Scenario_PartiQLBatch Kotlin: versions: - sdk_version: 1 diff --git a/gov2/dynamodb/README.md b/gov2/dynamodb/README.md index a390eaef2fa..1c58d846bcf 100644 --- a/gov2/dynamodb/README.md +++ b/gov2/dynamodb/README.md @@ -52,9 +52,9 @@ Code excerpts that show you how to call individual service functions. Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. -- [Get started with tables, items, and queries](actions/table_basics.go) -- [Query a table by using batches of PartiQL statements](actions/partiql.go) -- [Query a table using PartiQL](actions/partiql.go) +- [Get started with tables, items, and queries](scenarios/scenario_movie_table.go) +- [Query a table by using batches of PartiQL statements](scenarios/scenario_partiql_batch.go) +- [Query a table using PartiQL](scenarios/scenario_partiql_single.go) diff --git a/gov2/dynamodb/actions/movie.go b/gov2/dynamodb/actions/movie.go index 4f1607b9229..199e8dbe244 100644 --- a/gov2/dynamodb/actions/movie.go +++ b/gov2/dynamodb/actions/movie.go @@ -16,6 +16,8 @@ import ( "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" ) +// snippet-start:[gov2.dynamodb.Movie.struct] + // Movie encapsulates data about a movie. Title and Year are the composite primary key // of the movie in Amazon DynamoDB. Title is the sort key, Year is the partition key, // and Info is additional data. @@ -45,6 +47,8 @@ func (movie Movie) String() string { movie.Title, movie.Year, movie.Info["rating"], movie.Info["plot"]) } +// snippet-end:[gov2.dynamodb.Movie.struct] + // IMovieSampler defines an interface that can be used to download sample movie data // from a URL. type IMovieSampler interface { From 8f44e9c1bd4d354c97713a9643a911ebaf2ca982 Mon Sep 17 00:00:00 2001 From: Dennis Traub Date: Tue, 23 Jan 2024 20:17:47 +0100 Subject: [PATCH 20/36] Python: Fix typo in Bedrock Agents scenario comment (#5988) Fix typo in Python Bedrock Agents scenario --- .../bedrock-agent/scenario_get_started_with_agents.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/example_code/bedrock-agent/scenario_get_started_with_agents.py b/python/example_code/bedrock-agent/scenario_get_started_with_agents.py index 4c34735f7a5..3aa9c378198 100644 --- a/python/example_code/bedrock-agent/scenario_get_started_with_agents.py +++ b/python/example_code/bedrock-agent/scenario_get_started_with_agents.py @@ -94,7 +94,7 @@ def run_scenario(self): self._allow_agent_to_invoke_function() self._let_function_accept_invocations_from_agent() - # Create an action group to connects the agent with the Lambda function + # Create an action group to connect the agent with the Lambda function self._create_agent_action_group() # If the agent has been modified or any components have been added, prepare the agent again From f9f1e6721c8f8c98bb2ded440046756ea2200e84 Mon Sep 17 00:00:00 2001 From: Todd Hill <110035210+tkhill-AWS@users.noreply.github.com> Date: Tue, 23 Jan 2024 13:30:33 -0700 Subject: [PATCH 21/36] JavaV2_crossservice_Fix broken link to github code base (#5989) Fix broken link to github code base https://issues.amazon.com/issues/V1208534401 --- .doc_gen/cross-content/cross_RDSDataTracker_Java_block.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.doc_gen/cross-content/cross_RDSDataTracker_Java_block.xml b/.doc_gen/cross-content/cross_RDSDataTracker_Java_block.xml index 96098e0bc93..bcc0e361589 100644 --- a/.doc_gen/cross-content/cross_RDSDataTracker_Java_block.xml +++ b/.doc_gen/cross-content/cross_RDSDataTracker_Java_block.xml @@ -10,7 +10,7 @@ For complete source code and instructions on how to set up a Spring REST API that queries Amazon Aurora Serverless data and for use by a React application, see the full example on - GitHub. + GitHub. For complete source code and instructions on how to set up and run an example that uses the JDBC API, see the full example on From a3b438bc482d017298de0aec435f60ba27313495 Mon Sep 17 00:00:00 2001 From: Laren-AWS <57545972+Laren-AWS@users.noreply.github.com> Date: Wed, 24 Jan 2024 06:09:45 -0800 Subject: [PATCH 22/36] Update Bedrock service names to the approved ones. (#5994) * Update Bedrock service names to the approved ones. --- .doc_gen/cross-content/phrases-code-examples.ent | 8 ++------ .doc_gen/metadata/services.yaml | 12 ++++++------ .../templates/zonbook/service_chapter_template.xml | 2 +- python/example_code/bedrock-agent-runtime/README.md | 10 +++++----- python/example_code/bedrock-agent/README.md | 10 +++++----- 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/.doc_gen/cross-content/phrases-code-examples.ent b/.doc_gen/cross-content/phrases-code-examples.ent index 26b1b5eabb5..1e5b1658704 100644 --- a/.doc_gen/cross-content/phrases-code-examples.ent +++ b/.doc_gen/cross-content/phrases-code-examples.ent @@ -82,17 +82,13 @@ - - - - - - + + diff --git a/.doc_gen/metadata/services.yaml b/.doc_gen/metadata/services.yaml index d434b54e936..d47308ecd6d 100644 --- a/.doc_gen/metadata/services.yaml +++ b/.doc_gen/metadata/services.yaml @@ -289,7 +289,7 @@ bedrock: bundle: bedrock long: '&BRlong;' short: '&BR;' - sort: Bedrock + sort: Bedrock1 expanded: long: Amazon Bedrock short: Amazon Bedrock @@ -305,7 +305,7 @@ bedrock-runtime: bundle: bedrock long: '&BRRUNlong;' short: '&BRRUN;' - sort: Bedrock Runtime + sort: Bedrock2 expanded: long: Amazon Bedrock Runtime short: Amazon Bedrock Runtime @@ -321,10 +321,10 @@ bedrock-agent: bundle: bedrock long: '&BRAlong;' short: '&BRA;' - sort: Bedrock Agents + sort: Bedrock3 expanded: long: Agents for Amazon Bedrock - short: Amazon Bedrock Agents + short: Agents for Amazon Bedrock blurb: offer you the ability to build and configure autonomous agents in your application. guide: subtitle: User Guide @@ -337,10 +337,10 @@ bedrock-agent-runtime: bundle: bedrock long: '&BRARUNlong;' short: '&BRARUN;' - sort: Bedrock Agents Runtime + sort: Bedrock4 expanded: long: Agents for Amazon Bedrock Runtime - short: Amazon Bedrock Agents Runtime + short: Agents for Amazon Bedrock Runtime blurb: offers you the ability to run autonomous agents in your application. guide: subtitle: User Guide diff --git a/.doc_gen/templates/zonbook/service_chapter_template.xml b/.doc_gen/templates/zonbook/service_chapter_template.xml index 6a3f2c36d88..5bebc8d7100 100644 --- a/.doc_gen/templates/zonbook/service_chapter_template.xml +++ b/.doc_gen/templates/zonbook/service_chapter_template.xml @@ -17,7 +17,7 @@ {{- end}} {{- if .Bundle}} {{- $doc_id = printf "service_code_examples_%s" .Model }} -{{- $title_abbrev = printf "%s examples" .ServiceEntity.Short }} +{{- $title_abbrev = .ServiceEntity.Short }}
{{- else}} diff --git a/python/example_code/bedrock-agent-runtime/README.md b/python/example_code/bedrock-agent-runtime/README.md index ec12e79298a..83017041a19 100644 --- a/python/example_code/bedrock-agent-runtime/README.md +++ b/python/example_code/bedrock-agent-runtime/README.md @@ -1,4 +1,4 @@ -# Amazon Bedrock Agents Runtime code examples for the SDK for Python +# Agents for Amazon Bedrock Runtime code examples for the SDK for Python ## Overview @@ -7,7 +7,7 @@ Shows how to use the AWS SDK for Python (Boto3) to work with Agents for Amazon B -_Amazon Bedrock Agents Runtime offers you the ability to run autonomous agents in your application._ +_Agents for Amazon Bedrock Runtime offers you the ability to run autonomous agents in your application._ ## ⚠ Important @@ -69,9 +69,9 @@ in the `python` folder. ## Additional resources -- [Amazon Bedrock Agents Runtime User Guide](https://docs.aws.amazon.com/bedrock/latest/userguide/agents.html) -- [Amazon Bedrock Agents Runtime API Reference](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_Operations_Agents_for_Amazon_Bedrock_Runtime.html) -- [SDK for Python Amazon Bedrock Agents Runtime reference](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime.html) +- [Agents for Amazon Bedrock Runtime User Guide](https://docs.aws.amazon.com/bedrock/latest/userguide/agents.html) +- [Agents for Amazon Bedrock Runtime API Reference](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_Operations_Agents_for_Amazon_Bedrock_Runtime.html) +- [SDK for Python Agents for Amazon Bedrock Runtime reference](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent-runtime.html) diff --git a/python/example_code/bedrock-agent/README.md b/python/example_code/bedrock-agent/README.md index 7f5581bdb95..df7c4bc1d0c 100644 --- a/python/example_code/bedrock-agent/README.md +++ b/python/example_code/bedrock-agent/README.md @@ -1,4 +1,4 @@ -# Amazon Bedrock Agents code examples for the SDK for Python +# Agents for Amazon Bedrock code examples for the SDK for Python ## Overview @@ -7,7 +7,7 @@ Shows how to use the AWS SDK for Python (Boto3) to work with Agents for Amazon B -_Amazon Bedrock Agents offer you the ability to build and configure autonomous agents in your application._ +_Agents for Amazon Bedrock offer you the ability to build and configure autonomous agents in your application._ ## ⚠ Important @@ -110,9 +110,9 @@ in the `python` folder. ## Additional resources -- [Amazon Bedrock Agents User Guide](https://docs.aws.amazon.com/bedrock/latest/userguide/agents.html) -- [Amazon Bedrock Agents API Reference](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_Operations_Agents_for_Amazon_Bedrock.html) -- [SDK for Python Amazon Bedrock Agents reference](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent.html) +- [Agents for Amazon Bedrock User Guide](https://docs.aws.amazon.com/bedrock/latest/userguide/agents.html) +- [Agents for Amazon Bedrock API Reference](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_Operations_Agents_for_Amazon_Bedrock.html) +- [SDK for Python Agents for Amazon Bedrock reference](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/bedrock-agent.html) From 0cb6e2d15e494b29dd0721f57683c996bab9911f Mon Sep 17 00:00:00 2001 From: Dennis Traub Date: Thu, 25 Jan 2024 14:13:23 +0100 Subject: [PATCH 23/36] Python: Add prompt chaining scenario for Amazon Bedrock and AWS Step Functions (#5915) * Add prompt chaining scenario --- ..._ServerlessPromptChaining_Python_block.xml | 50 +++++++++++++++++++ .doc_gen/metadata/cross_metadata.yaml | 17 +++++++ python/example_code/bedrock/README.md | 6 +++ 3 files changed, 73 insertions(+) create mode 100644 .doc_gen/cross-content/cross_ServerlessPromptChaining_Python_block.xml diff --git a/.doc_gen/cross-content/cross_ServerlessPromptChaining_Python_block.xml b/.doc_gen/cross-content/cross_ServerlessPromptChaining_Python_block.xml new file mode 100644 index 00000000000..4f7892ba7df --- /dev/null +++ b/.doc_gen/cross-content/cross_ServerlessPromptChaining_Python_block.xml @@ -0,0 +1,50 @@ + + + %phrases-shared; + ]> + + + The Amazon Bedrock Serverless Prompt Chaining scenario demonstrates how + AWS Step Functions, + Amazon Bedrock, + and Amazon Bedrock Agents + can be used to build and orchestrate complex, serverless, and highly scalable generative AI applications. + It contains the following working examples: + + + + + Write an analysis of a given novel for a literature blog. This example illustrates a simple, sequential chain of prompts. + + + + + Generate a short story about a given topic. This example illustrates how the AI can iteratively process a list of items that it previously generated. + + + + + Create an itinerary for a weekend vacation to a given destination. This example illustrates how to parallelize multiple distinct prompts. + + + + + Pitch movie ideas to a human user acting as a movie producer. This example illustrates how to parallelize the same prompt with different inference parameters, how to backtrack to a previous step in the chain, and how to include human input as part of the workflow. + + + + + Plan a meal based on ingredients the user has at hand. This example illustrates how prompt chains can incorporate two distinct AI conversations, with two AI personas engaging in a debate with each other to improve the final outcome. + + + + + Find and summarize today's highest trending GitHub repository. This example illustrates chaining multiple AI agents that interact with external APIs. + + + + + For complete source code and instructions to set up and run, see the full project on GitHub. + + \ No newline at end of file diff --git a/.doc_gen/metadata/cross_metadata.yaml b/.doc_gen/metadata/cross_metadata.yaml index 4d5991be9e1..ef1c034f27a 100644 --- a/.doc_gen/metadata/cross_metadata.yaml +++ b/.doc_gen/metadata/cross_metadata.yaml @@ -778,3 +778,20 @@ cross_Testing: - rustv1/examples/testing/src/replay.rs services: s3: +cross_ServerlessPromptChaining: + title: Build and orchestrate generative AI applications with &BR; and &SFN; + title_abbrev: Orchestrate generative AI applications with &SFN; + synopsis: build and orchestrate generative AI applications with &BR; and &SFN;. + category: Scenarios + languages: + Python: + versions: + - sdk_version: 3 + block_content: cross_ServerlessPromptChaining_Python_block.xml + service_main: bedrock + services: + bedrock: + bedrock-runtime: + bedrock-agent: + bedrock-agent-runtime: + sfn: diff --git a/python/example_code/bedrock/README.md b/python/example_code/bedrock/README.md index c235b81e0f8..1d51b9c36f3 100644 --- a/python/example_code/bedrock/README.md +++ b/python/example_code/bedrock/README.md @@ -43,6 +43,12 @@ Code excerpts that show you how to call individual service functions. +### Scenarios + +Code examples that show you how to accomplish a specific task by calling multiple +functions within the same service. + +- [Build and orchestrate generative AI applications with AWS Step Functions](https://github.com/aws-samples/amazon-bedrock-serverless-prompt-chaining) ## Run the examples From 690de8f449b82377b870df57fce93fdac9f260bd Mon Sep 17 00:00:00 2001 From: David Souther Date: Thu, 25 Jan 2024 09:34:46 -0500 Subject: [PATCH 24/36] Create .git-blame-ignore-revs (#5996) Ignore revs in blame from SPDX Copyright Header changes --- .git-blame-ignore-revs | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000000..796629f8faf --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,3 @@ +# .git-blame-ignore-revs +# Normalize SPDX Copyright header +de7b1ee3fae2e3cd7d81a24c17345040f76b1d75 From 1ddd29cf2510932ad0ac54852a6ab703f107e870 Mon Sep 17 00:00:00 2001 From: ford prior <108086978+ford-at-aws@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:29:55 -0500 Subject: [PATCH 25/36] Tools - Update Python functions & CDK (#5995) * updates to functions --- .../producer_stack/producer_stack.py | 22 +-- .../results-bucket/consolidated-results.csv | 12 ++ .../results-bucket/results-manifest.json | 15 ++ .../sqs_lambda_to_batch_fargate/README.md | 4 +- .../test/sqs_lambda_to_batch_fargate/app.py | 2 +- .../consumer_stack/consumer_stack.py | 76 +++++----- .../lambda/export_logs.py | 136 ++++++++++++------ .../s3/scenario_getting_started.rb | 2 +- 8 files changed, 179 insertions(+), 90 deletions(-) create mode 100644 .tools/test/eventbridge_rule_with_sns_fanout/results-bucket/consolidated-results.csv create mode 100644 .tools/test/eventbridge_rule_with_sns_fanout/results-bucket/results-manifest.json diff --git a/.tools/test/eventbridge_rule_with_sns_fanout/producer_stack/producer_stack.py b/.tools/test/eventbridge_rule_with_sns_fanout/producer_stack/producer_stack.py index 5c97f7fade1..61bb8b12db2 100644 --- a/.tools/test/eventbridge_rule_with_sns_fanout/producer_stack/producer_stack.py +++ b/.tools/test/eventbridge_rule_with_sns_fanout/producer_stack/producer_stack.py @@ -16,15 +16,15 @@ def __init__(self, scope: Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) acct_config = self.get_yaml_config("../config/targets.yaml") resource_config = self.get_yaml_config("../config/resources.yaml") - topic_name = resource_config["topic_name"] - bucket_name = resource_config["bucket_name"] - topic = self.init_get_topic(topic_name) - self.sns_permissions(topic) - self.init_subscribe_permissions(topic, acct_config) - self.init_publish_permissions(topic, acct_config) - bucket = self.init_create_bucket(bucket_name) + admin_topic_name = resource_config["topic_name"] + admin_bucket_name = resource_config["bucket_name"] + admin_topic = self.init_get_topic(admin_topic_name) + self.sns_permissions(admin_topic) + self.init_subscribe_permissions(admin_topic, acct_config) + self.init_publish_permissions(admin_topic, acct_config) + bucket = self.init_create_bucket(admin_bucket_name) self.init_cross_account_log_role(acct_config, bucket) - self.init_rule(topic) + self.init_rule(admin_topic) def get_yaml_config(self, filepath): with open(filepath, "r") as file: @@ -106,7 +106,11 @@ def init_cross_account_log_role(self, target_accts, bucket): # Define policy that allows cross-account Amazon SNS and Amazon SQS access. statement = iam.PolicyStatement() statement.add_actions( - "s3:PutObject", "s3:PutObjectAcl", "s3:DeleteObject", "s3:ListBucket" + "s3:PutObject", + "s3:PutObjectAcl", + "s3:DeleteObject", + "s3:ListBucket", + "s3:GetObject", ) statement.add_resources(f"{bucket.bucket_arn}/*") statement.add_resources(bucket.bucket_arn) diff --git a/.tools/test/eventbridge_rule_with_sns_fanout/results-bucket/consolidated-results.csv b/.tools/test/eventbridge_rule_with_sns_fanout/results-bucket/consolidated-results.csv new file mode 100644 index 00000000000..246e298d326 --- /dev/null +++ b/.tools/test/eventbridge_rule_with_sns_fanout/results-bucket/consolidated-results.csv @@ -0,0 +1,12 @@ +toolname,status +ruby,FAILED +rustv1,FAILED +javascriptv3,FAILED +javav2,FAILED +cpp,FAILED +kotlin,FAILED +php,FAILED +python,FAILED +swift,FAILED +dotnetv3,FAILED +sap-abap,FAILED \ No newline at end of file diff --git a/.tools/test/eventbridge_rule_with_sns_fanout/results-bucket/results-manifest.json b/.tools/test/eventbridge_rule_with_sns_fanout/results-bucket/results-manifest.json new file mode 100644 index 00000000000..4d8c2238774 --- /dev/null +++ b/.tools/test/eventbridge_rule_with_sns_fanout/results-bucket/results-manifest.json @@ -0,0 +1,15 @@ +{ + "fileLocations": [ + { + "URIs": [ + "s3://aws-weathertop-central-log-bucket/consolidated-results.csv" + ] + } + ], + "globalUploadSettings": { + "format": "CSV", + "delimiter": ",", + "textqualifier": "'", + "containsHeader": "true" + } +} diff --git a/.tools/test/sqs_lambda_to_batch_fargate/README.md b/.tools/test/sqs_lambda_to_batch_fargate/README.md index ab90a8e9347..ab297a8de2e 100644 --- a/.tools/test/sqs_lambda_to_batch_fargate/README.md +++ b/.tools/test/sqs_lambda_to_batch_fargate/README.md @@ -18,11 +18,11 @@ Specifically, an Amazon Simple Queue Service (Amazon SQS) topic consumes message * AWS access key and secret for AWS user with permissions to create the preceding resources ### Environment variables -Before continuing, save your language name as an environment variable called `LANGUAGE_NAME`. +Before continuing, save your language name as an environment variable called `TOOL_NAME`. For example, if your language is Java, use: ``` -export LANGUAGE_NAME=javav2 +export TOOL_NAME=javav2 ``` --- diff --git a/.tools/test/sqs_lambda_to_batch_fargate/app.py b/.tools/test/sqs_lambda_to_batch_fargate/app.py index f27783b89f9..ebad49e5138 100644 --- a/.tools/test/sqs_lambda_to_batch_fargate/app.py +++ b/.tools/test/sqs_lambda_to_batch_fargate/app.py @@ -11,7 +11,7 @@ app = App() ConsumerStack( app, - f"ConsumerStack-{os.getenv('LANGUAGE_NAME').replace('_', '-')}", + f"ConsumerStack-{os.getenv('TOOL_NAME').replace('_', '-')}", env=cdk.Environment( account=os.getenv("CDK_DEFAULT_ACCOUNT"), region=os.getenv("CDK_DEFAULT_REGION") ), diff --git a/.tools/test/sqs_lambda_to_batch_fargate/consumer_stack/consumer_stack.py b/.tools/test/sqs_lambda_to_batch_fargate/consumer_stack/consumer_stack.py index c958025bcd5..cc66ec1625a 100644 --- a/.tools/test/sqs_lambda_to_batch_fargate/consumer_stack/consumer_stack.py +++ b/.tools/test/sqs_lambda_to_batch_fargate/consumer_stack/consumer_stack.py @@ -20,24 +20,24 @@ from constructs import Construct # Raises KeyError if environment variable doesn't exist. -language_name = os.environ["LANGUAGE_NAME"] +tool_name = os.environ["TOOL_NAME"] class ConsumerStack(Stack): def __init__(self, scope: Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) resource_config = self.get_yaml_config("../config/resources.yaml") - topic_name = resource_config["topic_name"] - producer_bucket_name = resource_config["bucket_name"] + admin_topic_name = resource_config["topic_name"] + admin_bucket_name = resource_config["bucket_name"] self.aws_region = resource_config["aws_region"] - self.producer_account_id = resource_config["admin_acct"] - sns_topic = self.init_get_topic(topic_name) - sqs_queue = sqs.Queue(self, f"BatchJobQueue-{language_name}") + self.admin_account_id = resource_config["admin_acct"] + sns_topic = self.init_get_topic(admin_topic_name) + sqs_queue = sqs.Queue(self, f"BatchJobQueue-{tool_name}") self.init_subscribe_sns(sqs_queue, sns_topic) job_definition, job_queue = self.init_batch_fargte() batch_function = self.init_batch_lambda(job_queue, job_definition) self.init_sqs_lambda_integration(batch_function, sqs_queue) - self.init_log_function(producer_bucket_name) + self.init_log_function(admin_bucket_name) def get_yaml_config(self, filepath): with open(filepath, "r") as file: @@ -46,7 +46,7 @@ def get_yaml_config(self, filepath): def init_get_topic(self, topic_name): external_sns_topic_arn = ( - f"arn:aws:sns:{self.aws_region}:{self.producer_account_id}:{topic_name}" + f"arn:aws:sns:{self.aws_region}:{self.admin_account_id}:{topic_name}" ) topic = sns.Topic.from_topic_arn( self, "ExternalSNSTopic", external_sns_topic_arn @@ -56,7 +56,7 @@ def init_get_topic(self, topic_name): def init_batch_fargte(self): batch_execution_role = iam.Role( self, - f"BatchExecutionRole-{language_name}", + f"BatchExecutionRole-{tool_name}", assumed_by=iam.ServicePrincipal("ecs-tasks.amazonaws.com"), inline_policies={ "BatchLoggingPolicy": iam.PolicyDocument( @@ -75,9 +75,7 @@ def init_batch_fargte(self): ) }, managed_policies=[ - iam.ManagedPolicy.from_aws_managed_policy_name( - "job-function/SystemAdministrator" - ), + iam.ManagedPolicy.from_aws_managed_policy_name("AdministratorAccess"), iam.ManagedPolicy.from_aws_managed_policy_name( "service-role/AmazonECSTaskExecutionRolePolicy" ), @@ -86,20 +84,20 @@ def init_batch_fargte(self): fargate_environment = batch_alpha.FargateComputeEnvironment( self, - f"FargateEnv-{language_name}", + f"FargateEnv-{tool_name}", vpc=ec2.Vpc.from_lookup(self, "Vpc", is_default=True), ) container_image = ecs.EcrImage.from_registry( - f"public.ecr.aws/b4v4v1s0/{language_name}:latest" + f"public.ecr.aws/b4v4v1s0/{tool_name}:latest" ) job_definition = batch_alpha.EcsJobDefinition( self, - f"JobDefinition-{language_name}", + f"JobDefinition-{tool_name}", container=batch_alpha.EcsFargateContainerDefinition( self, - f"ContainerDefinition-{language_name}", + f"ContainerDefinition-{tool_name}", image=container_image, execution_role=batch_execution_role, job_role=batch_execution_role, @@ -110,7 +108,7 @@ def init_batch_fargte(self): timeout=Duration.minutes(500), ) - job_queue = batch_alpha.JobQueue(self, f"JobQueue-{language_name}", priority=1) + job_queue = batch_alpha.JobQueue(self, f"JobQueue-{tool_name}", priority=1) job_queue.add_compute_environment(fargate_environment, 1) @@ -118,17 +116,17 @@ def init_batch_fargte(self): def init_sqs_queue(self): # Define the Amazon Simple Queue Service (Amazon SQS) queue in this account. - sqs_queue = sqs.Queue(self, f"BatchJobQueue-{language_name}") + sqs_queue = sqs.Queue(self, f"BatchJobQueue-{tool_name}") return sqs_queue def init_subscribe_sns(self, sqs_queue, sns_topic): # Create an AWS Identity and Access Management (IAM) role for the SNS topic to send messages to the SQS queue. sns_topic_role = iam.Role( self, - f"SNSTopicRole-{language_name}", + f"SNSTopicRole-{tool_name}", assumed_by=iam.ServicePrincipal("sns.amazonaws.com"), description="Allows the SNS topic to send messages to the SQS queue in this account", - role_name=f"SNSTopicRole-{language_name}", + role_name=f"SNSTopicRole-{tool_name}", ) # Policy to allow existing SNS topic to publish to new SQS queue. @@ -150,7 +148,7 @@ def init_subscribe_sns(self, sqs_queue, sns_topic): statement = iam.PolicyStatement() statement.add_resources(sqs_queue.queue_arn) statement.add_actions("sqs:*") - statement.add_arn_principal(f"arn:aws:iam::{self.producer_account_id}:root") + statement.add_arn_principal(f"arn:aws:iam::{self.admin_account_id}:root") statement.add_arn_principal(f"arn:aws:iam::{Aws.ACCOUNT_ID}:root") statement.add_condition("ArnLike", {"aws:SourceArn": sns_topic.topic_arn}) sqs_queue.add_to_resource_policy(statement) @@ -159,10 +157,10 @@ def init_batch_lambda(self, job_queue, job_definition): # Execution role for AWS Lambda function to use. execution_role = iam.Role( self, - f"BatchLambdaExecutionRole-{language_name}", + f"BatchLambdaExecutionRole-{tool_name}", assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"), description="Allows Lambda function to submit jobs to Batch", - role_name=f"BatchLambdaExecutionRole-{language_name}", + role_name=f"BatchLambdaExecutionRole-{tool_name}", ) execution_role.add_to_policy( @@ -179,16 +177,16 @@ def init_batch_lambda(self, job_queue, job_definition): # Define the Lambda function. function = _lambda.Function( self, - f"SubmitBatchJob-{language_name}", + f"SubmitBatchJob-{tool_name}", runtime=_lambda.Runtime.PYTHON_3_8, handler="submit_job.handler", role=execution_role, code=_lambda.Code.from_asset("lambda"), environment={ - "LANGUAGE_NAME": language_name, + "LANGUAGE_NAME": tool_name, "JOB_QUEUE": job_queue.job_queue_arn, "JOB_DEFINITION": job_definition.job_definition_arn, - "JOB_NAME": f"job-{language_name}", + "JOB_NAME": f"job-{tool_name}", }, ) return function @@ -215,7 +213,7 @@ def init_sqs_lambda_integration(self, function, sqs_queue): ) ) - def init_log_function(self, producer_bucket_name): + def init_log_function(self, admin_bucket_name): # S3 Bucket to store logs within this account. bucket = s3.Bucket( self, @@ -233,9 +231,14 @@ def init_log_function(self, producer_bucket_name): role_name=f"LogsLambdaExecutionRole", ) + # Update bucket permissions to allow Lambda statement = iam.PolicyStatement() statement.add_actions( - "s3:PutObject", "s3:PutObjectAcl", "s3:DeleteObject", "s3:ListBucket" + "s3:PutObject", + "s3:PutObjectAcl", + "s3:DeleteObject", + "s3:ListBucket", + "s3:GetObject", ) statement.add_resources(f"{bucket.bucket_arn}/*") statement.add_resources(bucket.bucket_arn) @@ -252,7 +255,7 @@ def init_log_function(self, producer_bucket_name): ) ) - # Grants ability to get logs from CloudWatch. + # Attach custom policy to allow Lambda to get logs from CloudWatch. execution_role.add_to_policy( statement=iam.PolicyStatement( actions=["logs:GetLogEvents", "logs:DescribeLogStreams"], @@ -260,7 +263,7 @@ def init_log_function(self, producer_bucket_name): ) ) - # Grants ability to get and put to local logs bucket. + # Attach custom policy to allow Lambda to get and put to local logs bucket. execution_role.add_to_policy( statement=iam.PolicyStatement( actions=[ @@ -277,7 +280,7 @@ def init_log_function(self, producer_bucket_name): ) ) - # Grants ability to write to cross-account log bucket. + # Attach custom policy to allow Lambda to get and put to admin logs bucket. execution_role.add_to_policy( statement=iam.PolicyStatement( actions=[ @@ -288,8 +291,8 @@ def init_log_function(self, producer_bucket_name): "s3:DeleteObject", ], resources=[ - f"arn:aws:s3:::{producer_bucket_name}/*", - f"arn:aws:s3:::{producer_bucket_name}", + f"arn:aws:s3:::{admin_bucket_name}/*", + f"arn:aws:s3:::{admin_bucket_name}", ], ) ) @@ -302,10 +305,11 @@ def init_log_function(self, producer_bucket_name): handler="export_logs.handler", role=execution_role, code=_lambda.Code.from_asset("lambda"), + timeout=Duration.seconds(60), environment={ - "LANGUAGE_NAME": language_name, - "BUCKET_NAME": bucket.bucket_name, - "PRODUCER_BUCKET_NAME": f"{producer_bucket_name}", + "TOOL_NAME": tool_name, + "LOCAL_BUCKET_NAME": bucket.bucket_name, + "ADMIN_BUCKET_NAME": f"{admin_bucket_name}", }, ) diff --git a/.tools/test/sqs_lambda_to_batch_fargate/lambda/export_logs.py b/.tools/test/sqs_lambda_to_batch_fargate/lambda/export_logs.py index 23246517984..ae4ecbbc920 100644 --- a/.tools/test/sqs_lambda_to_batch_fargate/lambda/export_logs.py +++ b/.tools/test/sqs_lambda_to_batch_fargate/lambda/export_logs.py @@ -1,26 +1,31 @@ -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 import json import logging import os -import random +import io +import csv import boto3 -s3_client = boto3.client("s3") -s3_resource = boto3.resource("s3") -logs_client = boto3.client("logs") - logger = logging.getLogger() logger.setLevel(logging.DEBUG) log_group_name = "/aws/batch/job" +s3_client = boto3.client("s3") +logs_client = boto3.client("logs") + +tool_name = os.environ["TOOL_NAME"] +admin_bucket_name = os.environ["ADMIN_BUCKET_NAME"] +local_bucket_name = os.environ["LOCAL_BUCKET_NAME"] + def handler(event, context): - logger.debug(f"BUCKET_NAME: {os.environ['BUCKET_NAME']}") + logger.debug(f"Found EnvVar - LOCAL_BUCKET_NAME: {local_bucket_name}") + logger.debug(f"Found EnvVar - ADMIN_BUCKET_NAME: {admin_bucket_name}") + logger.debug(f"Found EnvVar - TOOL_NAME: {tool_name}") logger.debug(f"INCOMING EVENT: {event}") + # Catch all non-triggering of events if "Batch Job State Change" not in event["detail-type"]: logger.info(f"Non-triggering Batch event: {event['detail-type']}") return @@ -32,16 +37,20 @@ def handler(event, context): logger.info(f"Non-triggering Batch status: STATUS: {event['detail']['status']}") return + # Put logs and results CSV to S3 try: - get_and_put_logs(event["detail"]) + for bucket in admin_bucket_name, local_bucket_name: + get_and_put_logs(event["detail"], bucket) + put_status(event["detail"]["status"], admin_bucket_name) except Exception as e: logger.error(json.dumps(f"Error: {str(e)}")) raise e -def get_and_put_logs(job_detail): +def get_and_put_logs(job_detail, bucket): """ Puts logs to a cross-account S3 bucket + :param bucket: Target bucket :param job_detail: Contains job_id and job_status """ job_id = job_detail["jobId"] @@ -73,38 +82,83 @@ def get_and_put_logs(job_detail): ) try: - # Copy logs to local and cross-account buckets - for bucket in [os.environ["PRODUCER_BUCKET_NAME"], os.environ["BUCKET_NAME"]]: - # Reset outfile - response = s3_client.list_objects_v2(Bucket=bucket, Delimiter="/") - objects = response.get("Contents", []) - for obj in objects: - key = obj["Key"] - if key.endswith("SUCCEEDED") or key.endswith("FAILED"): - s3_client.delete_object(Bucket=bucket, Key=key) - logger.info(f"Deleted: {key}") - s3_client.put_object( - Body=log_file, - Bucket=bucket, - Key=job_status, - ) - - # Put logs to cross-account bucket LATEST directory - s3_client.put_object( - Body=log_file, - Bucket=bucket, - Key=f"latest/{os.environ['LANGUAGE_NAME']}.log", - ) - # Put logs to cross-account bucket ARCHIVE - s3_client.put_object( - Body=log_file, - Bucket=bucket, - Key=f"archive/{os.environ['LANGUAGE_NAME']}/{job_detail['status']}/{log_file_name}", - ) + response = s3_client.list_objects_v2(Bucket=bucket, Delimiter="/") + objects = response.get("Contents", []) + for obj in objects: + key = obj["Key"] + if ( + key.endswith(f"SUCCEEDED") + or key.endswith(f"FAILED") + or key.endswith(f"SUCCEEDED-{tool_name}.log") + or key.endswith(f"FAILED-{tool_name}.log") + ): + s3_client.delete_object(Bucket=bucket, Key=key) + logger.info(f"Deleted: {key}") + + s3_client.put_object( + Body=log_file, + Bucket=bucket, + Key=job_status, + ) + + # Put logs to cross-account bucket LATEST directory + s3_client.put_object( + Body=log_file, + Bucket=bucket, + Key=f"latest/{job_detail['status']}-{tool_name}.log", + ) + # Put logs to cross-account bucket ARCHIVE + s3_client.put_object( + Body=log_file, + Bucket=bucket, + Key=f"archive/{tool_name}/{job_detail['status']}/{log_file_name}", + ) except Exception as e: logger.error(f"Error writing logs to S3:\n{e}") raise - logger.info( - f"Log data saved successfully: {os.environ['LANGUAGE_NAME']}/{log_file_name}" - ) + logger.info(f"Log data saved successfully: {tool_name}/{log_file_name}") + # return response + + +def put_status(status, bucket): + """ + Updates the status of the tool test run to either FAILED or SUCCEEDED + :param status: + :param bucket: + :return: + """ + key = "consolidated-results.csv" + try: + # get CSV from s3 + response = s3_client.get_object(Bucket=bucket, Key=key) + data = response["Body"].read().decode("utf-8") + except Exception as e: + logger.error(f"Error reading CSV from S3:\n{e}") + raise + + try: + # Read the CSV data into Python object. + lines = csv.reader(io.StringIO(data)) + headers = next(lines) # Skip the header row. + updated_data = [headers] + + # Update the specific record + for row in lines: + if row[0] == tool_name: + row[1] = status + updated_data.append(row) + + # Convert updated data back to CSV format. + output_buffer = io.StringIO() + writer = csv.writer(output_buffer) + writer.writerows(updated_data) + updated_csv_data = output_buffer.getvalue() + + # Upload the updated CSV to S3, overwriting the original. + s3_client.put_object(Bucket=bucket, Key=key, Body=updated_csv_data) + logger.info("Successfully updated CSV in S3.") + return + except Exception as e: + logger.error(f"Error processing and updating CSV in S3:\n{e}") + raise diff --git a/ruby/example_code/s3/scenario_getting_started.rb b/ruby/example_code/s3/scenario_getting_started.rb index 3643f410ca1..b68d81c63fa 100644 --- a/ruby/example_code/s3/scenario_getting_started.rb +++ b/ruby/example_code/s3/scenario_getting_started.rb @@ -31,7 +31,7 @@ def create_bucket bucket = @s3_resource.create_bucket( bucket: "doc-example-bucket-#{Random.uuid}", create_bucket_configuration: { - location_constraint: "us-east-2" # Note: only certain regions permitted + location_constraint: "us-east-1" # Note: only certain regions permitted } ) puts("Created demo bucket named #{bucket.name}.") From 1386b5206791279f4dc5cefc85335b4ec7c73555 Mon Sep 17 00:00:00 2001 From: Pahud Hsieh Date: Thu, 25 Jan 2024 12:43:13 -0500 Subject: [PATCH 26/36] JavaScript v3: Add code examples to demonstrate the InvokeModel actions for Llama2 Chat & Titan Text (#5990) * add bedrock-runtime js example for llama2 Co-authored-by: pahud Co-authored-by: Dennis Traub --- .../metadata/bedrock-runtime_metadata.yaml | 25 ++++++ .../example_code/bedrock-runtime/README.md | 2 + .../bedrock-runtime/actions/invoke-llama2.js | 67 ++++++++++++++ .../actions/invoke-titan-text-express-v1.js | 89 +++++++++++++++++++ .../example_code/bedrock-runtime/package.json | 3 +- .../tests/invoke-model.integration.test.js | 21 +++++ 6 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 javascriptv3/example_code/bedrock-runtime/actions/invoke-llama2.js create mode 100644 javascriptv3/example_code/bedrock-runtime/actions/invoke-titan-text-express-v1.js diff --git a/.doc_gen/metadata/bedrock-runtime_metadata.yaml b/.doc_gen/metadata/bedrock-runtime_metadata.yaml index cd5c792ecb2..9847f239b4f 100644 --- a/.doc_gen/metadata/bedrock-runtime_metadata.yaml +++ b/.doc_gen/metadata/bedrock-runtime_metadata.yaml @@ -60,6 +60,23 @@ bedrock-runtime_InvokeAmazonTitanImageGeneratorForImageGeneration: services: bedrock-runtime: {InvokeModel} +bedrock-runtime_InvokeAmazonTitanImageGeneratorForTextGeneration: + title: Invoke the Amazon Titan Text G1 model on &BR; for text generation + title_abbrev: Text generation with Amazon Titan Text G1 + synopsis: invoke the Amazon Titan Text G1 model on &BR; for text generation. + category: + languages: + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/bedrock-runtime + excerpts: + - description: Invoke the Amazon Titan Text G1 foundation model to generate text. + snippet_files: + - javascriptv3/example_code/bedrock-runtime/actions/invoke-titan-text-express-v1.js + services: + bedrock-runtime: {InvokeModel} + bedrock-runtime_InvokeStableDiffusionForImageGeneration: title: Invoke the Stability.ai Stable Diffusion XL model on &BR; for image generation title_abbrev: Image generation with Stability.ai Stable Diffusion XL @@ -257,6 +274,14 @@ bedrock-runtime_InvokeLlama2: - description: Invoke the Meta Llama 2 Chat foundation model to generate text. snippet_tags: - bedrock-runtime.java2.invoke_llama2.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/bedrock-runtime + excerpts: + - description: Invoke the Meta Llama 2 Chat foundation model to generate text. + snippet_files: + - javascriptv3/example_code/bedrock-runtime/actions/invoke-llama2.js PHP: versions: - sdk_version: 3 diff --git a/javascriptv3/example_code/bedrock-runtime/README.md b/javascriptv3/example_code/bedrock-runtime/README.md index 9f32379093a..e25394a24f1 100644 --- a/javascriptv3/example_code/bedrock-runtime/README.md +++ b/javascriptv3/example_code/bedrock-runtime/README.md @@ -35,7 +35,9 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `javas Code excerpts that show you how to call individual service functions. - [Text generation with AI21 Labs Jurassic-2](javascriptv3/example_code/bedrock-runtime/actions/invoke-jurassic2.js) (`InvokeModel`) +- [Text generation with Amazon Titan Text G1](javascriptv3/example_code/bedrock-runtime/actions/invoke-titan-text-express-v1.js) (`InvokeModel`) - [Text generation with Anthropic Claude 2](javascriptv3/example_code/bedrock-runtime/actions/invoke-claude.js) (`InvokeModel`) +- [Text generation with Meta Llama 2 Chat](javascriptv3/example_code/bedrock-runtime/actions/invoke-llama2.js) (`InvokeModel`) diff --git a/javascriptv3/example_code/bedrock-runtime/actions/invoke-llama2.js b/javascriptv3/example_code/bedrock-runtime/actions/invoke-llama2.js new file mode 100644 index 00000000000..d0907ff6386 --- /dev/null +++ b/javascriptv3/example_code/bedrock-runtime/actions/invoke-llama2.js @@ -0,0 +1,67 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import {fileURLToPath} from "url"; + +import {BedrockRuntimeClient, InvokeModelCommand} from "@aws-sdk/client-bedrock-runtime"; + +/** + * @typedef {Object} ResponseBody + * @property {generation} text + */ + +/** + * Invokes the Meta Llama 2 Chat model to run an inference + * using the input provided in the request body. + * + * @param {string} prompt - The prompt that you want Llama-2 to complete. + * @returns {string} The inference response (generation) from the model. + */ +export const invokeLlama2 = async (prompt) => { + const client = new BedrockRuntimeClient( { region: 'us-east-1' } ); + + const modelId = 'meta.llama2-13b-chat-v1'; + + /* The different model providers have individual request and response formats. + * For the format, ranges, and default values for Meta Llama 2 Chat, refer to: + * https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-meta.html + */ + const payload = { + prompt, + temperature: 0.5, + top_p: 0.9, + max_gen_len: 512, + }; + + const command = new InvokeModelCommand({ + body: JSON.stringify(payload), + contentType: 'application/json', + accept: 'application/json', + modelId, + }); + + try { + const response = await client.send(command); + const decodedResponseBody = new TextDecoder().decode(response.body); + + /** @type {ResponseBody} */ + const responseBody = JSON.parse(decodedResponseBody); + + return responseBody.generation; + + } catch (err) { + console.error(err); + } +}; + +// Invoke the function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + const prompt = 'Complete the following: "Once upon a time..."'; + console.log('\nModel: Meta Llama 2 Chat'); + console.log(`Prompt: ${prompt}`); + + const completion = await invokeLlama2(prompt); + console.log('Completion:'); + console.log(completion); + console.log('\n'); +} diff --git a/javascriptv3/example_code/bedrock-runtime/actions/invoke-titan-text-express-v1.js b/javascriptv3/example_code/bedrock-runtime/actions/invoke-titan-text-express-v1.js new file mode 100644 index 00000000000..ea00a0ebe81 --- /dev/null +++ b/javascriptv3/example_code/bedrock-runtime/actions/invoke-titan-text-express-v1.js @@ -0,0 +1,89 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import {fileURLToPath} from "url"; + +import {BedrockRuntimeClient, InvokeModelCommand} from "@aws-sdk/client-bedrock-runtime"; + +/** + * @typedef {Object} ResponseBody + * @property {Object[]} results + */ + +/** + * Invokes the Titan Text G1 - Express model to run an inference + * using the input provided in the request body. + * + * @param {string} prompt - The prompt that you want Titan Text Express to complete. + * @returns {object[]} The inference response (results) from the model. + */ +export const invokeTitanTextExpressV1 = async (prompt) => { + const client = new BedrockRuntimeClient( { region: 'us-east-1' } ); + + const modelId = 'amazon.titan-text-express-v1'; + + /* The different model providers have individual request and response formats. + * For the format, ranges, and default values for Titan text, refer to: + * https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-titan-text.html + */ + const textGenerationConfig = { + maxTokenCount: 4096, + stopSequences: [], + temperature: 0, + topP: 1, + }; + + const payload = { + inputText: prompt, + textGenerationConfig, + }; + + const command = new InvokeModelCommand({ + body: JSON.stringify(payload), + contentType: 'application/json', + accept: 'application/json', + modelId, + }); + + try { + const response = await client.send(command); + const decodedResponseBody = new TextDecoder().decode(response.body); + + /** @type {ResponseBody} */ + const responseBody = JSON.parse(decodedResponseBody); + return responseBody.results + + } catch (err) { + console.error(err); + } +}; + +// Invoke the function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + const prompt = `Meeting transcript: Miguel: Hi Brant, I want to discuss the workstream + for our new product launch Brant: Sure Miguel, is there anything in particular you want + to discuss? Miguel: Yes, I want to talk about how users enter into the product. + Brant: Ok, in that case let me add in Namita. Namita: Hey everyone + Brant: Hi Namita, Miguel wants to discuss how users enter into the product. + Miguel: its too complicated and we should remove friction. + for example, why do I need to fill out additional forms? + I also find it difficult to find where to access the product + when I first land on the landing page. Brant: I would also add that + I think there are too many steps. Namita: Ok, I can work on the + landing page to make the product more discoverable but brant + can you work on the additonal forms? Brant: Yes but I would need + to work with James from another team as he needs to unblock the sign up workflow. + Miguel can you document any other concerns so that I can discuss with James only once? + Miguel: Sure. + From the meeting transcript above, Create a list of action items for each person.`; + + console.log('\nModel: Titan Text Express v1'); + console.log(`Prompt: ${prompt}`); + + const results = await invokeTitanTextExpressV1(prompt); + console.log('Completion:'); + for (const result of results) { + console.log(result.outputText); + } + console.log('\n'); +} diff --git a/javascriptv3/example_code/bedrock-runtime/package.json b/javascriptv3/example_code/bedrock-runtime/package.json index ae532a4c7c1..9d2f3f4032d 100644 --- a/javascriptv3/example_code/bedrock-runtime/package.json +++ b/javascriptv3/example_code/bedrock-runtime/package.json @@ -11,6 +11,7 @@ "@aws-sdk/client-bedrock-runtime": "^3.489.0" }, "devDependencies": { - "vitest": "^1.1.3" + "vitest": "^1.2.1", + "zod": "^3.22.4" } } diff --git a/javascriptv3/example_code/bedrock-runtime/tests/invoke-model.integration.test.js b/javascriptv3/example_code/bedrock-runtime/tests/invoke-model.integration.test.js index 42a6b2dad99..8ce5b12c9c8 100644 --- a/javascriptv3/example_code/bedrock-runtime/tests/invoke-model.integration.test.js +++ b/javascriptv3/example_code/bedrock-runtime/tests/invoke-model.integration.test.js @@ -5,6 +5,8 @@ import { describe, it, expect } from "vitest"; import { invokeClaude } from '../actions/invoke-claude.js'; import { invokeJurassic2 } from '../actions/invoke-jurassic2.js'; +import { invokeLlama2 } from '../actions/invoke-llama2.js'; +import { invokeTitanTextExpressV1 } from "../actions/invoke-titan-text-express-v1.js"; const TEST_PROMPT = 'Hello, this is a test prompt'; @@ -23,3 +25,22 @@ describe('invoke jurassic-2 with test prompt', () => { expect(response).not.toBe(''); }) }) + +describe('invoke llama-2 with test prompt', () => { + it('should return a text completion', async () => { + const response = await invokeLlama2(TEST_PROMPT); + expect(typeof response).toBe('string'); + expect(response).not.toBe(''); + }) +}) + +describe('invoke titan-text-express-v1 with test prompt', () => { + it('should return a text completion', async () => { + const response = await invokeTitanTextExpressV1(TEST_PROMPT); + expect(typeof response).toBe('object'); + for (const result of response) { + expect(result).toHaveProperty('outputText'); + expect(result.outputText).not.toBe(''); + } + }) +}) From 5aacd30a4f5252cf2774397cda019403a3685f39 Mon Sep 17 00:00:00 2001 From: Steven Meyer <108885656+meyertst-aws@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:00:51 -0500 Subject: [PATCH 27/36] Python: Bedrock fix metadata (#6004) * Fix the service names --- .../cross_ServerlessPromptChaining_Python_block.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.doc_gen/cross-content/cross_ServerlessPromptChaining_Python_block.xml b/.doc_gen/cross-content/cross_ServerlessPromptChaining_Python_block.xml index 4f7892ba7df..111eaa6dccb 100644 --- a/.doc_gen/cross-content/cross_ServerlessPromptChaining_Python_block.xml +++ b/.doc_gen/cross-content/cross_ServerlessPromptChaining_Python_block.xml @@ -5,10 +5,10 @@ ]> - The Amazon Bedrock Serverless Prompt Chaining scenario demonstrates how - AWS Step Functions, - Amazon Bedrock, - and Amazon Bedrock Agents + The &BRlong; Serverless Prompt Chaining scenario demonstrates how + &SFNlong;, + &BRlong;, + and Agents for &BRlong; can be used to build and orchestrate complex, serverless, and highly scalable generative AI applications. It contains the following working examples: From 3d80bee2fd6c1f68685d3ff6b5dc971a48eae20d Mon Sep 17 00:00:00 2001 From: Steven Meyer <108885656+meyertst-aws@users.noreply.github.com> Date: Thu, 25 Jan 2024 19:12:10 -0500 Subject: [PATCH 28/36] Cpp: HealthImaging, text fixes (#6002) * Fixing metadata --- .doc_gen/metadata/medical-imaging_metadata.yaml | 16 ++++++++++++---- .../hello_health_imaging/README.md | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.doc_gen/metadata/medical-imaging_metadata.yaml b/.doc_gen/metadata/medical-imaging_metadata.yaml index c0e32a555f5..393c47e56ac 100644 --- a/.doc_gen/metadata/medical-imaging_metadata.yaml +++ b/.doc_gen/metadata/medical-imaging_metadata.yaml @@ -18,6 +18,7 @@ medical-imaging_Hello: versions: - sdk_version: 1 github: cpp/example_code/medical-imaging/hello_health_imaging + github_note_at_bottom: true excerpts: - description: Code for the CMakeLists.txt CMake file. snippet_tags: @@ -243,6 +244,7 @@ medical-imaging_StartDICOMImportJob: versions: - sdk_version: 1 github: cpp/example_code/medical-imaging/ + github_note_at_bottom: true excerpts: - description: snippet_tags: @@ -286,6 +288,7 @@ medical-imaging_GetDICOMImportJob: versions: - sdk_version: 1 github: cpp/example_code/medical-imaging/ + github_note_at_bottom: true excerpts: - description: snippet_tags: @@ -394,6 +397,7 @@ medical-imaging_SearchImageSets: versions: - sdk_version: 1 github: cpp/example_code/medical-imaging/ + github_note_at_bottom: true excerpts: - description: The utility function for searching image sets. snippet_tags: @@ -488,11 +492,12 @@ medical-imaging_GetImageSetMetadata: excerpts: - description: snippet_tags: - - medicalimaging.java2.get_imageset.main + - medicalimaging.java2.get_imageset_metadata.main C++: versions: - sdk_version: 1 github: cpp/example_code/medical-imaging/ + github_note_at_bottom: true excerpts: - description: Utility function to get image set metadata. snippet_tags: @@ -542,6 +547,7 @@ medical-imaging_GetImageFrame: versions: - sdk_version: 1 github: cpp/example_code/medical-imaging/ + github_note_at_bottom: true excerpts: - description: snippet_tags: @@ -708,6 +714,7 @@ medical-imaging_DeleteImageSet: versions: - sdk_version: 1 github: cpp/example_code/medical-imaging/ + github_note_at_bottom: true excerpts: - description: snippet_tags: @@ -994,7 +1001,7 @@ medical-imaging_Scenario_TaggingImageSets: medical-imaging_Scenario_ImageSetsAndFrames: title: Get started with &AHI; image sets and image frames using an &AWS; SDK title_abbrev: Get started with image sets and image frames - synopsis: get started with &AHI; image sets and image frames. + synopsis: import DICOM files and download image frames in &AHI;.The implementation is structured as a workflow command-line application. synopsis_list: - Set up resources for a DICOM import. - Import DICOM files into a data store. @@ -1008,8 +1015,9 @@ medical-imaging_Scenario_ImageSetsAndFrames: versions: - sdk_version: 1 github: cpp/example_code/medical-imaging/imaging_set_and_frames_workflow + github_note_at_bottom: true excerpts: - - description: Create a &CFN; stack with the necessary resources. + - description: Create an &CFN; stack with the necessary resources. snippet_tags: - cpp.example_code.medical-imaging.image-sets-workflow.createstack - description: Copy DICOM files to the &S3; import bucket. @@ -1028,7 +1036,7 @@ medical-imaging_Scenario_ImageSetsAndFrames: snippet_tags: - cpp.example_code.medical-imaging.image-sets-workflow.get_image_frames - cpp.example_code.medical_imaging.GetImageSetMetadata - - description: Download decode and verify image frames. + - description: Download, decode and verify image frames. snippet_tags: - cpp.example_code.medical-imaging.image-sets-workflow.download_frames - cpp.example_code.medical-imaging.image-sets-workflow.decode_and_check diff --git a/cpp/example_code/medical-imaging/hello_health_imaging/README.md b/cpp/example_code/medical-imaging/hello_health_imaging/README.md index 5e53d213fd7..8e1603099a1 100644 --- a/cpp/example_code/medical-imaging/hello_health_imaging/README.md +++ b/cpp/example_code/medical-imaging/hello_health_imaging/README.md @@ -55,7 +55,7 @@ For more information, see https://cmake.org/cmake/help/latest/manual/cmake-gener The [CMakeLists.txt](CMakeLists.txt) file contains the build settings. If your build is failing (particularly on Windows), you might need to modify this file. -The [hello_medical-imaging.cpp](hello_medical-imaging.cpp) file contains the C++ source code, including a "main" function. +The [hello_health_imaging.cpp](hello_health_imaging.cpp) file contains the C++ source code, including a "main" function. From fbff947058ee6fe5236aaf77241ccc0d758d1500 Mon Sep 17 00:00:00 2001 From: Steven Meyer <108885656+meyertst-aws@users.noreply.github.com> Date: Fri, 26 Jan 2024 10:33:39 -0500 Subject: [PATCH 29/36] Fix service name (#6009) * fixing bug that broke pipeline build for Bedrock guide --- .doc_gen/metadata/cross_metadata.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.doc_gen/metadata/cross_metadata.yaml b/.doc_gen/metadata/cross_metadata.yaml index ef1c034f27a..5b04616e112 100644 --- a/.doc_gen/metadata/cross_metadata.yaml +++ b/.doc_gen/metadata/cross_metadata.yaml @@ -791,7 +791,3 @@ cross_ServerlessPromptChaining: service_main: bedrock services: bedrock: - bedrock-runtime: - bedrock-agent: - bedrock-agent-runtime: - sfn: From 7194ce6f2778117150845b1c664b4a7aba1e49ef Mon Sep 17 00:00:00 2001 From: David Souther Date: Fri, 26 Jan 2024 11:17:59 -0500 Subject: [PATCH 30/36] Rust: Document lint and static checks. (#5998) Closes $5997 --- rustv1/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rustv1/README.md b/rustv1/README.md index 83d904940fa..769e8786cda 100644 --- a/rustv1/README.md +++ b/rustv1/README.md @@ -98,6 +98,11 @@ these examples in an isolated environment. ## Contributing +When adding or modifying Rust code examples, follow common Rust best practices. +As much as is reasonable, this means having tests that run with `cargo test`, code that has no lint errors from `cargo clippy --all-targets`, and code that has been formatted using `cargo fmt`. +These can be verified using cargo with in the example folders, or across the entire Rust code base with the `./run_all.sh` script. +The `run_all.sh` script is also used in continuous integration toolchains. + To propose a new code example to the AWS documentation team, see [CONTRIBUTING.md](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/CONTRIBUTING.md). The team prefers to create code examples that show broad scenarios rather than individual API calls. From b31156a3e9c3d1e4ab56bf798b23ae8914326461 Mon Sep 17 00:00:00 2001 From: Laren-AWS <57545972+Laren-AWS@users.noreply.github.com> Date: Mon, 29 Jan 2024 05:27:10 -0800 Subject: [PATCH 31/36] [PowerShell] Add PowerShell to sdks.yaml. (#6006) Add PowerShell to sdks.yaml. --- .doc_gen/metadata/sdks.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.doc_gen/metadata/sdks.yaml b/.doc_gen/metadata/sdks.yaml index e53d29dcef8..50ec16d5d42 100644 --- a/.doc_gen/metadata/sdks.yaml +++ b/.doc_gen/metadata/sdks.yaml @@ -143,6 +143,21 @@ PHP: uid: "SdkForPHPV3" name: "&guide-php-api;" guide: "&guide-php-dev;" +PowerShell: + property: powershell + sdk: + 4: + long: "&TWPALLlong;" + short: "&TWPALL;" + expanded: + long: "AWS Tools for PowerShell" + short: "Tools for PowerShell" + guide: "powershell/latest/userguide/pstools-welcome.html" + api_ref: + uid: "ToolsForPowerShell4" + name: "&guide-twp-ref;" + link_template: "https://docs.aws.amazon.com/powershell/latest/reference" + guide: "&guide-twp-ug;" Python: property: python sdk: From 630879dc431298bea1526887f631ffefc2879e30 Mon Sep 17 00:00:00 2001 From: Laren-AWS <57545972+Laren-AWS@users.noreply.github.com> Date: Mon, 29 Jan 2024 08:02:01 -0800 Subject: [PATCH 32/36] [Tools] Add mapped services to Go v2 SDK so that API ref links are correct. (#6013) Add mapped services to Go v2 SDK so that API ref links are correct. --- .doc_gen/metadata/sdks.yaml | 80 ++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/.doc_gen/metadata/sdks.yaml b/.doc_gen/metadata/sdks.yaml index 50ec16d5d42..524e25ef3d9 100644 --- a/.doc_gen/metadata/sdks.yaml +++ b/.doc_gen/metadata/sdks.yaml @@ -51,7 +51,85 @@ Go: api_ref: uid: "SdkForGoV2" name: "&guide-go-api;" - link_template: "https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/{{.Service}}#Client.{{.Action}}" + link_template: "https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/{{.MappedService}}#Client.{{.Action}}" + service_map: + acm-pca: acmpca + alexa-for-business: alexaforbusiness + api-gateway: apigateway + application-autoscaling: applicationautoscaling + app-mesh: appmesh + application-auto-scaling: applicationautoscaling + application-discovery-service: applicationdiscoveryservice + auto-scaling: autoscaling + auto-scaling-plans: autoscalingplans + bedrock-runtime: bedrockruntime + bedrock-agent: bedrockagent + bedrock-agent-runtime: bedrockagentruntime + cloudsearch-domain: cloudsearchdomain + cloudwatch-events: cloudwatchevents + cloudwatch-logs: cloudwatchlogs + codeguru-reviewer: codegurureviewer + codestar-connections: codestarconnections + codestar-notifications: codestarnotifications + cognito-identity: cognitoidentity + cognito-identity-provider: cognitoidentityprovider + cognito-sync: cognitosync + config-service: configservice + cost-and-usage-report-service: costandusagereportservice + cost-explorer: costexplorer + data-pipeline: datapipeline + database-migration-service: databasemigrationservice + device-farm: devicefarm + direct-connect: directconnect + directory-service: directoryservice + dynamodb-streams: dynamodbstreams + ec2-instance-connect: ec2instanceconnect + ecr-public: ecrpublic + elastic-beanstalk: elasticbeanstalk + elastic-load-balancing: elasticloadbalancing + elastic-load-balancing-v2: elasticloadbalancingv2 + elastic-transcoder: elastictranscoder + elasticsearch-service: elasticsearchservice + emr-containers: emrcontainers + global-accelerator: globalaccelerator + iot-1click-devices-service: iot1clickdevicesservice + iot-1click-projects: iot1clickprojects + iot-data-plane: iotdataplane + iot-events: iotevents + iot-events-data: ioteventsdata + iot-jobs-data-plane: iotjobsdataplane + iot-wireless: iotwireless + ivs-realtime: ivsrealtime + kinesis-analytics-v2: kinesisanalyticsv2 + license-manager: licensemanager + mediapackage-vod: mediapackagevod + mediastore-data: mediastoredata + medical-imaging: medicalimaging + migration-hub: migrationhub + payment-cryptography: paymentcryptography + payment-cryptography-data: paymentcryptographydata + personalize-runtime: personalizeruntime + personalize-events: personalizeevents + pinpoint-email: pinpointemail + pinpoint-sms-voice: pinpointsmsvoice + rds-data: rdsdata + resource-explorer-2: resourceexplorer2 + resource-groups: resourcegroups + resource-groups-tagging-api: resourcegroupstaggingapi + route-53: route53 + route-53-domains: route53domains + route53-recovery-cluster: route53recoverycluster + s3-control: s3control + secrets-manager: secretsmanager + service-catalog: servicecatalog + service-catalog-appregistry: servicecatalogappregistry + service-quotas: servicequotas + ssm-contacts: ssmcontacts + ssm-incidents: ssmincidents + storage-gateway: storagegateway + transcribe-medical: transcribemedical + vpc-lattice: vpclattice + waf-regional: wafregional guide: "&guide-go-dev;" Java: property: java From c8a42e6d0bc195a7c375a193860d027ac95a565b Mon Sep 17 00:00:00 2001 From: Dennis Traub Date: Mon, 29 Jan 2024 19:14:46 +0100 Subject: [PATCH 33/36] Fix readme generation when using snippet_files (#6008) * Bug fix: Remove redundant path from snippet_files before rendering readmes Co-authored-by: Dennis Traub --- .tools/readmes/scanner.py | 5 +- .../example_code/auto-scaling/README.md | 4 +- .../example_code/bedrock-runtime/README.md | 8 +- javascriptv3/example_code/bedrock/README.md | 6 +- .../example_code/cloudwatch-logs/README.md | 18 ++-- javascriptv3/example_code/ec2/README.md | 64 ++++++------- .../elastic-load-balancing-v2/README.md | 20 ++--- javascriptv3/example_code/iam/README.md | 90 +++++++++---------- javascriptv3/example_code/sfn/README.md | 2 +- rustv1/examples/aurora/README.md | 30 +++---- rustv1/examples/auto-scaling/README.md | 24 ++--- rustv1/examples/lambda/README.md | 16 ++-- 12 files changed, 145 insertions(+), 142 deletions(-) diff --git a/.tools/readmes/scanner.py b/.tools/readmes/scanner.py index 44092075c6a..a012a574b02 100644 --- a/.tools/readmes/scanner.py +++ b/.tools/readmes/scanner.py @@ -144,7 +144,10 @@ def snippet(self, example, sdk_ver, readme_folder, api_name): elif "snippet_files" in excerpt: snippet_files = excerpt["snippet_files"] # TODO: Find the best (or all?) snippet files, not the first. - tag_path = snippet_files[0] + full_path = snippet_files[0] + tag_path = "/".join(full_path.split("/")[3:]) + if "cross-services" in full_path: + tag_path = "../cross-services/" + tag_path elif "block_content" in ex_ver: tag_path = github if github is not None and tag_path is None: diff --git a/javascriptv3/example_code/auto-scaling/README.md b/javascriptv3/example_code/auto-scaling/README.md index 15941b0eb07..ceeef3a52a6 100644 --- a/javascriptv3/example_code/auto-scaling/README.md +++ b/javascriptv3/example_code/auto-scaling/README.md @@ -33,14 +33,14 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `javas Code excerpts that show you how to call individual service functions. -- [Attach an ELB target group to an Auto Scaling group](../cross-services/wkflw-resilient-service/steps-deploy.js#L494) (`AttachLoadBalancerTargetGroups`) +- [Attach an ELB target group to an Auto Scaling group](../cross-services/wkflw-resilient-service/steps-deploy.js#L492) (`AttachLoadBalancerTargetGroups`) ### Scenarios Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. -- [Build and manage a resilient service](javascriptv3/example_code/cross-services/wkflw-resilient-service/index.js) +- [Build and manage a resilient service](../cross-services/wkflw-resilient-service/index.js) diff --git a/javascriptv3/example_code/bedrock-runtime/README.md b/javascriptv3/example_code/bedrock-runtime/README.md index e25394a24f1..6d448b58421 100644 --- a/javascriptv3/example_code/bedrock-runtime/README.md +++ b/javascriptv3/example_code/bedrock-runtime/README.md @@ -34,10 +34,10 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `javas Code excerpts that show you how to call individual service functions. -- [Text generation with AI21 Labs Jurassic-2](javascriptv3/example_code/bedrock-runtime/actions/invoke-jurassic2.js) (`InvokeModel`) -- [Text generation with Amazon Titan Text G1](javascriptv3/example_code/bedrock-runtime/actions/invoke-titan-text-express-v1.js) (`InvokeModel`) -- [Text generation with Anthropic Claude 2](javascriptv3/example_code/bedrock-runtime/actions/invoke-claude.js) (`InvokeModel`) -- [Text generation with Meta Llama 2 Chat](javascriptv3/example_code/bedrock-runtime/actions/invoke-llama2.js) (`InvokeModel`) +- [Text generation with AI21 Labs Jurassic-2](actions/invoke-jurassic2.js) (`InvokeModel`) +- [Text generation with Amazon Titan Text G1](actions/invoke-titan-text-express-v1.js) (`InvokeModel`) +- [Text generation with Anthropic Claude 2](actions/invoke-claude.js) (`InvokeModel`) +- [Text generation with Meta Llama 2 Chat](actions/invoke-llama2.js) (`InvokeModel`) diff --git a/javascriptv3/example_code/bedrock/README.md b/javascriptv3/example_code/bedrock/README.md index bded8e5a69d..d95e1677121 100644 --- a/javascriptv3/example_code/bedrock/README.md +++ b/javascriptv3/example_code/bedrock/README.md @@ -32,15 +32,15 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `javas ### Get started -- [Hello Amazon Bedrock](javascriptv3/example_code/bedrock/hello.js) (`ListFoundationModels`) +- [Hello Amazon Bedrock](hello.js) (`ListFoundationModels`) ### Single actions Code excerpts that show you how to call individual service functions. -- [Get details about an Amazon Bedrock foundation model](javascriptv3/example_code/bedrock/actions/get-foundation-model.js) (`GetFoundationModel`) -- [List available Amazon Bedrock foundation models](javascriptv3/example_code/bedrock/actions/list-foundation-models.js) (`ListFoundationModels`) +- [Get details about an Amazon Bedrock foundation model](actions/get-foundation-model.js) (`GetFoundationModel`) +- [List available Amazon Bedrock foundation models](actions/list-foundation-models.js) (`ListFoundationModels`) diff --git a/javascriptv3/example_code/cloudwatch-logs/README.md b/javascriptv3/example_code/cloudwatch-logs/README.md index ffc05801232..ef0123b3c76 100644 --- a/javascriptv3/example_code/cloudwatch-logs/README.md +++ b/javascriptv3/example_code/cloudwatch-logs/README.md @@ -33,21 +33,21 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `javas Code excerpts that show you how to call individual service functions. -- [Create a log group](actions/create-log-group.js#L6) (`CreateLogGroup`) -- [Create a subscription filter](actions/put-subscription-filter.js#L6) (`PutSubscriptionFilter`) -- [Delete a log group](actions/delete-log-group.js#L6) (`DeleteLogGroup`) -- [Delete a subscription filter](actions/delete-subscription-filter.js#L6) (`DeleteSubscriptionFilter`) -- [Describe existing subscription filters](actions/describe-subscription-filters.js#L6) (`DescribeSubscriptionFilters`) -- [Describe log groups](actions/describe-log-groups.js#L8) (`DescribeLogGroups`) -- [Get the results of a query](scenarios/large-query/cloud-watch-query.js#L106) (`GetQueryResults`) -- [Start a query](scenarios/large-query/cloud-watch-query.js#L140) (`StartQuery`) +- [Create a log group](actions/create-log-group.js#L4) (`CreateLogGroup`) +- [Create a subscription filter](actions/put-subscription-filter.js#L4) (`PutSubscriptionFilter`) +- [Delete a log group](actions/delete-log-group.js#L4) (`DeleteLogGroup`) +- [Delete a subscription filter](actions/delete-subscription-filter.js#L4) (`DeleteSubscriptionFilter`) +- [Describe existing subscription filters](actions/describe-subscription-filters.js#L4) (`DescribeSubscriptionFilters`) +- [Describe log groups](actions/describe-log-groups.js#L6) (`DescribeLogGroups`) +- [Get the results of a query](scenarios/large-query/cloud-watch-query.js#L108) (`GetQueryResults`) +- [Start a query](scenarios/large-query/cloud-watch-query.js#L142) (`StartQuery`) ### Scenarios Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. -- [Run a large query](javascriptv3/example_code/cloudwatch-logs/scenarios/large-query/index.js) +- [Run a large query](scenarios/large-query/index.js) diff --git a/javascriptv3/example_code/ec2/README.md b/javascriptv3/example_code/ec2/README.md index 72dfa6396f1..f63e4b2cd62 100644 --- a/javascriptv3/example_code/ec2/README.md +++ b/javascriptv3/example_code/ec2/README.md @@ -7,7 +7,7 @@ Shows how to use the AWS SDK for JavaScript (v3) to work with Amazon Elastic Com -_Amazon EC2 is a web service that provides resizable computing capacity—literally, servers in Amazon's data centers—that you use to build and host your software systems._ +_Amazon EC2 is a web service that provides resizable computing capacity—literally, servers in Amazon's data centers—that you use to build and host your software systems._ ## ⚠ Important @@ -31,49 +31,49 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `javas ### Get started -- [Hello Amazon EC2](hello.js#L8) (`DescribeSecurityGroups`) +- [Hello Amazon EC2](hello.js#L6) (`DescribeSecurityGroups`) ### Single actions Code excerpts that show you how to call individual service functions. -- [Allocate an Elastic IP address](actions/allocate-address.js#L8) (`AllocateAddress`) -- [Associate an Elastic IP address with an instance](actions/associate-address.js#L8) (`AssociateAddress`) -- [Create a launch template](../cross-services/wkflw-resilient-service/steps-deploy.js#L280) (`CreateLaunchTemplate`) -- [Create a security group](actions/create-security-group.js#L8) (`CreateSecurityGroup`) -- [Create a security key pair](actions/create-key-pair.js#L8) (`CreateKeyPair`) -- [Create and run an instance](actions/run-instances.js#L8) (`RunInstances`) -- [Delete a launch template](../cross-services/wkflw-resilient-service/steps-destroy.js#L244) (`DeleteLaunchTemplate`) -- [Delete a security group](actions/delete-security-group.js#L8) (`DeleteSecurityGroup`) -- [Delete a security key pair](actions/delete-key-pair.js#L8) (`DeleteKeyPair`) -- [Describe Regions](actions/describe-regions.js#L8) (`DescribeRegions`) -- [Describe instances](actions/describe-instances.js#L8) (`DescribeInstances`) -- [Disable detailed monitoring](actions/unmonitor-instances.js#L8) (`UnmonitorInstances`) -- [Disassociate an Elastic IP address from an instance](actions/disassociate-address.js#L8) (`DisassociateAddress`) -- [Enable monitoring](actions/monitor-instances.js#L8) (`MonitorInstances`) -- [Get data about Amazon Machine Images](actions/describe-images.js#L8) (`DescribeImages`) -- [Get data about a security group](actions/describe-security-groups.js#L8) (`DescribeSecurityGroups`) -- [Get data about instance types](actions/describe-instance-types.js#L8) (`DescribeInstanceTypes`) -- [Get data about the instance profile associated with an instance](../cross-services/wkflw-resilient-service/steps-demo.js#L243) (`DescribeIamInstanceProfileAssociations`) -- [Get details about Elastic IP addresses](actions/describe-addresses.js#L8) (`DescribeAddresses`) -- [Get the default VPC](../cross-services/wkflw-resilient-service/steps-deploy.js#L359) (`DescribeVpcs`) -- [Get the default subnets for a VPC](../cross-services/wkflw-resilient-service/steps-deploy.js#L374) (`DescribeSubnets`) -- [List security key pairs](actions/describe-key-pairs.js#L8) (`DescribeKeyPairs`) -- [Reboot an instance](actions/reboot-instances.js#L8) (`RebootInstances`) -- [Release an Elastic IP address](actions/release-address.js#L8) (`ReleaseAddress`) -- [Replace the instance profile associated with an instance](../cross-services/wkflw-resilient-service/steps-demo.js#L255) (`ReplaceIamInstanceProfileAssociation`) -- [Set inbound rules for a security group](actions/authorize-security-group-ingress.js#L8) (`AuthorizeSecurityGroupIngress`) -- [Start an instance](actions/start-instances.js#L8) (`StartInstances`) -- [Stop an instance](actions/stop-instances.js#L8) (`StopInstances`) -- [Terminate an instance](actions/terminate-instances.js#L8) (`TerminateInstances`) +- [Allocate an Elastic IP address](actions/allocate-address.js#L6) (`AllocateAddress`) +- [Associate an Elastic IP address with an instance](actions/associate-address.js#L6) (`AssociateAddress`) +- [Create a launch template](../cross-services/wkflw-resilient-service/steps-deploy.js#L278) (`CreateLaunchTemplate`) +- [Create a security group](actions/create-security-group.js#L6) (`CreateSecurityGroup`) +- [Create a security key pair](actions/create-key-pair.js#L6) (`CreateKeyPair`) +- [Create and run an instance](actions/run-instances.js#L6) (`RunInstances`) +- [Delete a launch template](../cross-services/wkflw-resilient-service/steps-destroy.js#L266) (`DeleteLaunchTemplate`) +- [Delete a security group](actions/delete-security-group.js#L6) (`DeleteSecurityGroup`) +- [Delete a security key pair](actions/delete-key-pair.js#L6) (`DeleteKeyPair`) +- [Describe Regions](actions/describe-regions.js#L6) (`DescribeRegions`) +- [Describe instances](actions/describe-instances.js#L6) (`DescribeInstances`) +- [Disable detailed monitoring](actions/unmonitor-instances.js#L6) (`UnmonitorInstances`) +- [Disassociate an Elastic IP address from an instance](actions/disassociate-address.js#L6) (`DisassociateAddress`) +- [Enable monitoring](actions/monitor-instances.js#L6) (`MonitorInstances`) +- [Get data about Amazon Machine Images](actions/describe-images.js#L6) (`DescribeImages`) +- [Get data about a security group](actions/describe-security-groups.js#L6) (`DescribeSecurityGroups`) +- [Get data about instance types](actions/describe-instance-types.js#L6) (`DescribeInstanceTypes`) +- [Get data about the instance profile associated with an instance](../cross-services/wkflw-resilient-service/steps-demo.js#L241) (`DescribeIamInstanceProfileAssociations`) +- [Get details about Elastic IP addresses](actions/describe-addresses.js#L6) (`DescribeAddresses`) +- [Get the default VPC](../cross-services/wkflw-resilient-service/steps-deploy.js#L357) (`DescribeVpcs`) +- [Get the default subnets for a VPC](../cross-services/wkflw-resilient-service/steps-deploy.js#L372) (`DescribeSubnets`) +- [List security key pairs](actions/describe-key-pairs.js#L6) (`DescribeKeyPairs`) +- [Reboot an instance](actions/reboot-instances.js#L6) (`RebootInstances`) +- [Release an Elastic IP address](actions/release-address.js#L6) (`ReleaseAddress`) +- [Replace the instance profile associated with an instance](../cross-services/wkflw-resilient-service/steps-demo.js#L253) (`ReplaceIamInstanceProfileAssociation`) +- [Set inbound rules for a security group](actions/authorize-security-group-ingress.js#L6) (`AuthorizeSecurityGroupIngress`) +- [Start an instance](actions/start-instances.js#L6) (`StartInstances`) +- [Stop an instance](actions/stop-instances.js#L6) (`StopInstances`) +- [Terminate an instance](actions/terminate-instances.js#L6) (`TerminateInstances`) ### Scenarios Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. -- [Build and manage a resilient service](javascriptv3/example_code/cross-services/wkflw-resilient-service/index.js) +- [Build and manage a resilient service](../cross-services/wkflw-resilient-service/index.js) - [Get started with instances](scenarios/basic.js) diff --git a/javascriptv3/example_code/elastic-load-balancing-v2/README.md b/javascriptv3/example_code/elastic-load-balancing-v2/README.md index f435635d25c..918bdc58c84 100644 --- a/javascriptv3/example_code/elastic-load-balancing-v2/README.md +++ b/javascriptv3/example_code/elastic-load-balancing-v2/README.md @@ -31,28 +31,28 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `javas ### Get started -- [Hello Elastic Load Balancing](javascriptv3/example_code/elastic-load-balancing-v2/hello.js) (`DescribeLoadBalancers`) +- [Hello Elastic Load Balancing](hello.js) (`DescribeLoadBalancers`) ### Single actions Code excerpts that show you how to call individual service functions. -- [Create a listener for a load balancer](../cross-services/wkflw-resilient-service/steps-deploy.js#L465) (`CreateListener`) -- [Create a target group](../cross-services/wkflw-resilient-service/steps-deploy.js#L404) (`CreateTargetGroup`) -- [Create an Application Load Balancer](../cross-services/wkflw-resilient-service/steps-deploy.js#L437) (`CreateLoadBalancer`) -- [Delete a load balancer](../cross-services/wkflw-resilient-service/steps-destroy.js#L295) (`DeleteLoadBalancer`) -- [Delete a target group](../cross-services/wkflw-resilient-service/steps-destroy.js#L329) (`DeleteTargetGroup`) -- [Describe target groups](../cross-services/wkflw-resilient-service/steps-demo.js#L79) (`DescribeTargetGroups`) -- [Get the endpoint of a load balancer](javascriptv3/example_code/elastic-load-balancing-v2/hello.js) (`DescribeLoadBalancers`) -- [Get the health of a target group](../cross-services/wkflw-resilient-service/steps-demo.js#L88) (`DescribeTargetHealth`) +- [Create a listener for a load balancer](../cross-services/wkflw-resilient-service/steps-deploy.js#L463) (`CreateListener`) +- [Create a target group](../cross-services/wkflw-resilient-service/steps-deploy.js#L402) (`CreateTargetGroup`) +- [Create an Application Load Balancer](../cross-services/wkflw-resilient-service/steps-deploy.js#L435) (`CreateLoadBalancer`) +- [Delete a load balancer](../cross-services/wkflw-resilient-service/steps-destroy.js#L293) (`DeleteLoadBalancer`) +- [Delete a target group](../cross-services/wkflw-resilient-service/steps-destroy.js#L327) (`DeleteTargetGroup`) +- [Describe target groups](../cross-services/wkflw-resilient-service/steps-demo.js#L77) (`DescribeTargetGroups`) +- [Get the endpoint of a load balancer](hello.js) (`DescribeLoadBalancers`) +- [Get the health of a target group](../cross-services/wkflw-resilient-service/steps-demo.js#L86) (`DescribeTargetHealth`) ### Scenarios Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. -- [Build and manage a resilient service](javascriptv3/example_code/cross-services/wkflw-resilient-service/index.js) +- [Build and manage a resilient service](../cross-services/wkflw-resilient-service/index.js) diff --git a/javascriptv3/example_code/iam/README.md b/javascriptv3/example_code/iam/README.md index 93cfc4fc66d..d1b96ae41cf 100644 --- a/javascriptv3/example_code/iam/README.md +++ b/javascriptv3/example_code/iam/README.md @@ -31,63 +31,63 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `javas ### Get started -- [Hello IAM](hello.js#L8) (`ListPolicies`) +- [Hello IAM](hello.js#L6) (`ListPolicies`) ### Single actions Code excerpts that show you how to call individual service functions. -- [Attach a policy to a role](actions/attach-role-policy.js#L8) (`AttachRolePolicy`) -- [Attach an inline policy to a role](actions/put-role-policy.js#L8) (`PutRolePolicy`) -- [Create a SAML provider](actions/create-saml-provider.js#L8) (`CreateSAMLProvider`) -- [Create a group](actions/create-group.js#L8) (`CreateGroup`) -- [Create a policy](actions/create-policy.js#L8) (`CreatePolicy`) -- [Create a role](actions/create-role.js#L8) (`CreateRole`) -- [Create a service-linked role](actions/create-service-linked-role.js#L8) (`CreateServiceLinkedRole`) -- [Create a user](actions/create-user.js#L8) (`CreateUser`) -- [Create an access key](actions/create-access-key.js#L8) (`CreateAccessKey`) -- [Create an alias for an account](actions/create-account-alias.js#L8) (`CreateAccountAlias`) -- [Create an instance profile](../cross-services/wkflw-resilient-service/steps-demo.js#L452) (`CreateInstanceProfile`) -- [Delete SAML provider](actions/delete-saml-provider.js#L8) (`DeleteSAMLProvider`) -- [Delete a group](actions/delete-group.js#L8) (`DeleteGroup`) -- [Delete a policy](actions/delete-policy.js#L8) (`DeletePolicy`) -- [Delete a role](actions/delete-role.js#L8) (`DeleteRole`) -- [Delete a role policy](actions/delete-role-policy.js#L8) (`DeleteRolePolicy`) -- [Delete a server certificate](actions/delete-server-certificate.js#L8) (`DeleteServerCertificate`) -- [Delete a service-linked role](actions/delete-service-linked-role.js#L8) (`DeleteServiceLinkedRole`) -- [Delete a user](actions/delete-user.js#L8) (`DeleteUser`) -- [Delete an access key](actions/delete-access-key.js#L8) (`DeleteAccessKey`) -- [Delete an account alias](actions/delete-account-alias.js#L8) (`DeleteAccountAlias`) -- [Delete an instance profile](../cross-services/wkflw-resilient-service/steps-destroy.js#L215) (`DeleteInstanceProfile`) -- [Detach a policy from a role](actions/detach-role-policy.js#L8) (`DetachRolePolicy`) -- [Get a policy](actions/get-policy.js#L8) (`GetPolicy`) -- [Get a role](actions/get-role.js#L8) (`GetRole`) -- [Get a server certificate](actions/get-server-certificate.js#L8) (`GetServerCertificate`) -- [Get a service-linked role's deletion status](actions/get-service-linked-role-deletion-status.js#L8) (`GetServiceLinkedRoleDeletionStatus`) -- [Get data about the last use of an access key](actions/get-access-key-last-used.js#L8) (`GetAccessKeyLastUsed`) -- [Get the account password policy](actions/get-account-password-policy.js#L8) (`GetAccountPasswordPolicy`) -- [List SAML providers](actions/list-saml-providers.js#L8) (`ListSAMLProviders`) -- [List a user's access keys](actions/list-access-keys.js#L8) (`ListAccessKeys`) -- [List account aliases](actions/list-account-aliases.js#L8) (`ListAccountAliases`) -- [List groups](actions/list-groups.js#L8) (`ListGroups`) -- [List inline policies for a role](actions/list-role-policies.js#L8) (`ListRolePolicies`) -- [List policies](actions/list-policies.js#L8) (`ListPolicies`) -- [List policies attached to a role](actions/list-attached-role-policies.js#L8) (`ListAttachedRolePolicies`) -- [List roles](actions/list-roles.js#L8) (`ListRoles`) -- [List server certificates](actions/list-server-certificates.js#L8) (`ListServerCertificates`) -- [List users](actions/list-users.js#L8) (`ListUsers`) -- [Update a server certificate](actions/update-server-certificate.js#L8) (`UpdateServerCertificate`) -- [Update a user](actions/update-user.js#L8) (`UpdateUser`) -- [Update an access key](actions/update-access-key.js#L8) (`UpdateAccessKey`) -- [Upload a server certificate](actions/upload-server-certificate.js#L8) (`UploadServerCertificate`) +- [Attach a policy to a role](actions/attach-role-policy.js#L6) (`AttachRolePolicy`) +- [Attach an inline policy to a role](actions/put-role-policy.js#L6) (`PutRolePolicy`) +- [Create a SAML provider](actions/create-saml-provider.js#L6) (`CreateSAMLProvider`) +- [Create a group](actions/create-group.js#L6) (`CreateGroup`) +- [Create a policy](actions/create-policy.js#L6) (`CreatePolicy`) +- [Create a role](actions/create-role.js#L6) (`CreateRole`) +- [Create a service-linked role](actions/create-service-linked-role.js#L6) (`CreateServiceLinkedRole`) +- [Create a user](actions/create-user.js#L6) (`CreateUser`) +- [Create an access key](actions/create-access-key.js#L6) (`CreateAccessKey`) +- [Create an alias for an account](actions/create-account-alias.js#L6) (`CreateAccountAlias`) +- [Create an instance profile](../cross-services/wkflw-resilient-service/steps-demo.js#L450) (`CreateInstanceProfile`) +- [Delete SAML provider](actions/delete-saml-provider.js#L6) (`DeleteSAMLProvider`) +- [Delete a group](actions/delete-group.js#L6) (`DeleteGroup`) +- [Delete a policy](actions/delete-policy.js#L6) (`DeletePolicy`) +- [Delete a role](actions/delete-role.js#L6) (`DeleteRole`) +- [Delete a role policy](actions/delete-role-policy.js#L6) (`DeleteRolePolicy`) +- [Delete a server certificate](actions/delete-server-certificate.js#L6) (`DeleteServerCertificate`) +- [Delete a service-linked role](actions/delete-service-linked-role.js#L6) (`DeleteServiceLinkedRole`) +- [Delete a user](actions/delete-user.js#L6) (`DeleteUser`) +- [Delete an access key](actions/delete-access-key.js#L6) (`DeleteAccessKey`) +- [Delete an account alias](actions/delete-account-alias.js#L6) (`DeleteAccountAlias`) +- [Delete an instance profile](../cross-services/wkflw-resilient-service/steps-destroy.js#L213) (`DeleteInstanceProfile`) +- [Detach a policy from a role](actions/detach-role-policy.js#L6) (`DetachRolePolicy`) +- [Get a policy](actions/get-policy.js#L6) (`GetPolicy`) +- [Get a role](actions/get-role.js#L6) (`GetRole`) +- [Get a server certificate](actions/get-server-certificate.js#L6) (`GetServerCertificate`) +- [Get a service-linked role's deletion status](actions/get-service-linked-role-deletion-status.js#L6) (`GetServiceLinkedRoleDeletionStatus`) +- [Get data about the last use of an access key](actions/get-access-key-last-used.js#L6) (`GetAccessKeyLastUsed`) +- [Get the account password policy](actions/get-account-password-policy.js#L6) (`GetAccountPasswordPolicy`) +- [List SAML providers](actions/list-saml-providers.js#L6) (`ListSAMLProviders`) +- [List a user's access keys](actions/list-access-keys.js#L6) (`ListAccessKeys`) +- [List account aliases](actions/list-account-aliases.js#L6) (`ListAccountAliases`) +- [List groups](actions/list-groups.js#L6) (`ListGroups`) +- [List inline policies for a role](actions/list-role-policies.js#L6) (`ListRolePolicies`) +- [List policies](actions/list-policies.js#L6) (`ListPolicies`) +- [List policies attached to a role](actions/list-attached-role-policies.js#L6) (`ListAttachedRolePolicies`) +- [List roles](actions/list-roles.js#L6) (`ListRoles`) +- [List server certificates](actions/list-server-certificates.js#L6) (`ListServerCertificates`) +- [List users](actions/list-users.js#L6) (`ListUsers`) +- [Update a server certificate](actions/update-server-certificate.js#L6) (`UpdateServerCertificate`) +- [Update a user](actions/update-user.js#L6) (`UpdateUser`) +- [Update an access key](actions/update-access-key.js#L6) (`UpdateAccessKey`) +- [Upload a server certificate](actions/upload-server-certificate.js#L6) (`UploadServerCertificate`) ### Scenarios Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. -- [Build and manage a resilient service](javascriptv3/example_code/cross-services/wkflw-resilient-service/index.js) +- [Build and manage a resilient service](../cross-services/wkflw-resilient-service/index.js) - [Create a user and assume a role](scenarios/basic.js) diff --git a/javascriptv3/example_code/sfn/README.md b/javascriptv3/example_code/sfn/README.md index b294576f5c8..2f8076f1c3e 100644 --- a/javascriptv3/example_code/sfn/README.md +++ b/javascriptv3/example_code/sfn/README.md @@ -33,7 +33,7 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `javas Code excerpts that show you how to call individual service functions. -- [Start a state machine run](javascriptv3/example_code/sfn/actions/start-execution.js) (`StartExecution`) +- [Start a state machine run](actions/start-execution.js) (`StartExecution`) ### Cross-service examples diff --git a/rustv1/examples/aurora/README.md b/rustv1/examples/aurora/README.md index 8ce397d9bbd..52a2f4819f7 100644 --- a/rustv1/examples/aurora/README.md +++ b/rustv1/examples/aurora/README.md @@ -31,33 +31,33 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `rustv ### Get started -- [Hello Aurora](rustv1/examples/aurora/src/bin/hello-world.rs) (`DescribeDBClusters`) +- [Hello Aurora](src/bin/hello-world.rs) (`DescribeDBClusters`) ### Single actions Code excerpts that show you how to call individual service functions. -- [Create a DB cluster](src/aurora_scenario/mod.rs#L354) (`CreateDBCluster`) -- [Create a DB cluster parameter group](src/aurora_scenario/mod.rs#L205) (`CreateDBClusterParameterGroup`) -- [Create a DB cluster snapshot](src/aurora_scenario/mod.rs#L354) (`CreateDBClusterSnapshot`) -- [Create a DB instance in a DB cluster](src/aurora_scenario/mod.rs#L354) (`CreateDBInstance`) -- [Delete a DB cluster](src/aurora_scenario/mod.rs#L514) (`DeleteDBCluster`) -- [Delete a DB cluster parameter group](src/aurora_scenario/mod.rs#L514) (`DeleteDBClusterParameterGroup`) -- [Delete a DB instance](src/aurora_scenario/mod.rs#L514) (`DeleteDBInstance`) -- [Describe DB clusters](src/aurora_scenario/mod.rs#L354) (`DescribeDBClusters`) -- [Describe DB instances](src/aurora_scenario/mod.rs#L514) (`DescribeDBInstances`) -- [Describe database engine versions](src/aurora_scenario/mod.rs#L144) (`DescribeDBEngineVersions`) -- [Describe options for DB instances](src/aurora_scenario/mod.rs#L181) (`DescribeOrderableDBInstanceOptions`) -- [Describe parameters from a DB cluster parameter group](src/aurora_scenario/mod.rs#L288) (`DescribeDBClusterParameters`) -- [Update parameters in a DB cluster parameter group](src/aurora_scenario/mod.rs#L317) (`ModifyDBClusterParameterGroup`) +- [Create a DB cluster](src/aurora_scenario/mod.rs#L352) (`CreateDBCluster`) +- [Create a DB cluster parameter group](src/aurora_scenario/mod.rs#L203) (`CreateDBClusterParameterGroup`) +- [Create a DB cluster snapshot](src/aurora_scenario/mod.rs#L352) (`CreateDBClusterSnapshot`) +- [Create a DB instance in a DB cluster](src/aurora_scenario/mod.rs#L352) (`CreateDBInstance`) +- [Delete a DB cluster](src/aurora_scenario/mod.rs#L512) (`DeleteDBCluster`) +- [Delete a DB cluster parameter group](src/aurora_scenario/mod.rs#L512) (`DeleteDBClusterParameterGroup`) +- [Delete a DB instance](src/aurora_scenario/mod.rs#L512) (`DeleteDBInstance`) +- [Describe DB clusters](src/aurora_scenario/mod.rs#L352) (`DescribeDBClusters`) +- [Describe DB instances](src/aurora_scenario/mod.rs#L512) (`DescribeDBInstances`) +- [Describe database engine versions](src/aurora_scenario/mod.rs#L142) (`DescribeDBEngineVersions`) +- [Describe options for DB instances](src/aurora_scenario/mod.rs#L179) (`DescribeOrderableDBInstanceOptions`) +- [Describe parameters from a DB cluster parameter group](src/aurora_scenario/mod.rs#L286) (`DescribeDBClusterParameters`) +- [Update parameters in a DB cluster parameter group](src/aurora_scenario/mod.rs#L315) (`ModifyDBClusterParameterGroup`) ### Scenarios Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. -- [Get started with DB clusters](rustv1/examples/aurora/src/aurora_scenario/mod.rs) +- [Get started with DB clusters](src/aurora_scenario/mod.rs) diff --git a/rustv1/examples/auto-scaling/README.md b/rustv1/examples/auto-scaling/README.md index 8b9d97ab476..7d4b84790fc 100644 --- a/rustv1/examples/auto-scaling/README.md +++ b/rustv1/examples/auto-scaling/README.md @@ -31,30 +31,30 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `rustv ### Get started -- [Hello Auto Scaling](src/bin/list-autoscaling-groups.rs#L24) (`DescribeAutoScalingGroups`) +- [Hello Auto Scaling](src/bin/list-autoscaling-groups.rs#L22) (`DescribeAutoScalingGroups`) ### Single actions Code excerpts that show you how to call individual service functions. -- [Create a group](src/bin/create-autoscaling-group.rs#L32) (`CreateAutoScalingGroup`) -- [Delete a group](src/bin/delete-autoscaling-group.rs#L32) (`DeleteAutoScalingGroup`) -- [Disable metrics collection for a group](src/scenario.rs#L619) (`DisableMetricsCollection`) -- [Enable metrics collection for a group](src/scenario.rs#L296) (`EnableMetricsCollection`) -- [Get information about groups](src/bin/list-autoscaling-groups.rs#L24) (`DescribeAutoScalingGroups`) -- [Get information about instances](src/scenario.rs#L534) (`DescribeAutoScalingInstances`) -- [Get information about scaling activities](src/scenario.rs#L401) (`DescribeScalingActivities`) -- [Set the desired capacity of a group](src/scenario.rs#L597) (`SetDesiredCapacity`) -- [Terminate an instance in a group](src/scenario.rs#L656) (`TerminateInstanceInAutoScalingGroup`) -- [Update a group](src/bin/update-autoscaling-group.rs#L32) (`UpdateAutoScalingGroup`) +- [Create a group](src/bin/create-autoscaling-group.rs#L30) (`CreateAutoScalingGroup`) +- [Delete a group](src/bin/delete-autoscaling-group.rs#L30) (`DeleteAutoScalingGroup`) +- [Disable metrics collection for a group](src/scenario.rs#L617) (`DisableMetricsCollection`) +- [Enable metrics collection for a group](src/scenario.rs#L294) (`EnableMetricsCollection`) +- [Get information about groups](src/bin/list-autoscaling-groups.rs#L22) (`DescribeAutoScalingGroups`) +- [Get information about instances](src/scenario.rs#L532) (`DescribeAutoScalingInstances`) +- [Get information about scaling activities](src/scenario.rs#L399) (`DescribeScalingActivities`) +- [Set the desired capacity of a group](src/scenario.rs#L595) (`SetDesiredCapacity`) +- [Terminate an instance in a group](src/scenario.rs#L654) (`TerminateInstanceInAutoScalingGroup`) +- [Update a group](src/bin/update-autoscaling-group.rs#L30) (`UpdateAutoScalingGroup`) ### Scenarios Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. -- [Manage groups and instances](rustv1/examples/auto-scaling/Cargo.toml) +- [Manage groups and instances](Cargo.toml) diff --git a/rustv1/examples/lambda/README.md b/rustv1/examples/lambda/README.md index c56eb7e13d9..9453baa1d48 100644 --- a/rustv1/examples/lambda/README.md +++ b/rustv1/examples/lambda/README.md @@ -36,20 +36,20 @@ Additionally, to compile Lambda functions written in the Rust programming langua Code excerpts that show you how to call individual service functions. -- [Create a function](src/actions.rs#L233) (`CreateFunction`) -- [Delete a function](src/actions.rs#L471) (`DeleteFunction`) -- [Get a function](src/actions.rs#L379) (`GetFunction`) -- [Invoke a function](src/actions.rs#L404) (`Invoke`) -- [List functions](src/actions.rs#L392) (`ListFunctions`) -- [Update function code](src/actions.rs#L420) (`UpdateFunctionCode`) -- [Update function configuration](src/actions.rs#L446) (`UpdateFunctionConfiguration`) +- [Create a function](src/actions.rs#L231) (`CreateFunction`) +- [Delete a function](src/actions.rs#L469) (`DeleteFunction`) +- [Get a function](src/actions.rs#L377) (`GetFunction`) +- [Invoke a function](src/actions.rs#L402) (`Invoke`) +- [List functions](src/actions.rs#L390) (`ListFunctions`) +- [Update function code](src/actions.rs#L418) (`UpdateFunctionCode`) +- [Update function configuration](src/actions.rs#L444) (`UpdateFunctionConfiguration`) ### Scenarios Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. -- [Get started with functions](rustv1/examples/lambda/Cargo.toml) +- [Get started with functions](Cargo.toml) From 099dd2b84ee69cc2cf88abd7695f35989ccec9bd Mon Sep 17 00:00:00 2001 From: Dennis Traub Date: Mon, 29 Jan 2024 19:52:27 +0100 Subject: [PATCH 34/36] Fix: Typo in Bedrock Python example metadata (#6011) Fix typo in metadata Co-authored-by: Dennis Traub --- .doc_gen/metadata/bedrock-runtime_metadata.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.doc_gen/metadata/bedrock-runtime_metadata.yaml b/.doc_gen/metadata/bedrock-runtime_metadata.yaml index 9847f239b4f..f5a9ecc03d8 100644 --- a/.doc_gen/metadata/bedrock-runtime_metadata.yaml +++ b/.doc_gen/metadata/bedrock-runtime_metadata.yaml @@ -233,7 +233,7 @@ bedrock-runtime_InvokeJurassic2: Python: versions: - sdk_version: 3 - github: python/example_code/bedrockruntime + github: python/example_code/bedrock-runtime excerpts: - description: Invoke the AI21 Labs Jurassic-2 foundation model to generate text. snippet_tags: @@ -293,7 +293,7 @@ bedrock-runtime_InvokeLlama2: Python: versions: - sdk_version: 3 - github: python/example_code/bedrockruntime + github: python/example_code/bedrock-runtime excerpts: - description: Invoke the Meta Llama 2 Chat foundation model to generate text. snippet_tags: From 5c02c03d2732ee914c25e411cdfb96d18118dd51 Mon Sep 17 00:00:00 2001 From: dhiraj-thakkar <78841529+dhiraj-thakkar@users.noreply.github.com> Date: Mon, 29 Jan 2024 11:45:43 -0800 Subject: [PATCH 35/36] Update sap-abap Textract sample to parse responses (#5999) * Update sap-abap Textract sample to parse responses Co-authored-by: dhirajtx --- .abapgit.xml | 15 + .../textract/zcl_aws1_tex_actions.clas.abap | 353 ++++++++++-------- ...zcl_aws1_tex_actions.clas.testclasses.abap | 172 +++------ .../textract/zcl_aws1_tex_scenario.clas.abap | 104 +++--- ...cl_aws1_tex_scenario.clas.testclasses.abap | 28 +- 5 files changed, 320 insertions(+), 352 deletions(-) diff --git a/.abapgit.xml b/.abapgit.xml index 545b6342078..7b23657183e 100644 --- a/.abapgit.xml +++ b/.abapgit.xml @@ -5,6 +5,21 @@ E /sap-abap/ PREFIX + + /sap-abap/README.md + /sap-abap/services/bdr/README.md + /sap-abap/services/cloudwatch/README.md + /sap-abap/services/dyn/README.md + /sap-abap/services/ec2/README.md + /sap-abap/services/kinesis/README.md + /sap-abap/services/lambda/README.md + /sap-abap/services/s3/README.md + /sap-abap/services/sagemaker/README.md + /sap-abap/services/sns/README.md + /sap-abap/services/sqs/README.md + /sap-abap/services/textract/README.md + /sap-abap/services/translate/README.md + diff --git a/sap-abap/services/textract/zcl_aws1_tex_actions.clas.abap b/sap-abap/services/textract/zcl_aws1_tex_actions.clas.abap index 938d768318b..968aabaccfe 100644 --- a/sap-abap/services/textract/zcl_aws1_tex_actions.clas.abap +++ b/sap-abap/services/textract/zcl_aws1_tex_actions.clas.abap @@ -3,45 +3,44 @@ " " Reserved. " " SPDX-License-Identifier: MIT-0 " """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -class ZCL_AWS1_TEX_ACTIONS definition - public - final - create public . - -public section. - - methods ANALYZE_DOCUMENT - importing - !IV_S3OBJECT type /AWS1/TEXS3OBJECTNAME optional - !IV_S3BUCKET type /AWS1/TEXS3BUCKET optional - exporting - !OO_RESULT type ref to /AWS1/CL_TEXANALYZEDOCRESPONSE . - methods DETECT_DOCUMENT_TEXT - importing - !IV_S3OBJECT type /AWS1/TEXS3OBJECTNAME - !IV_S3BUCKET type /AWS1/TEXS3BUCKET - exporting - !OO_RESULT type ref to /AWS1/CL_TEXDETECTDOCTEXTRSP . - methods GET_DOCUMENT_ANALYSIS - importing - !IV_JOBID type /AWS1/TEXJOBID - exporting - !OO_RESULT type ref to /AWS1/CL_TEXGETDOCALYRESPONSE . - methods START_DOCUMENT_ANALYSIS - importing - !IV_S3OBJECT type /AWS1/TEXS3OBJECTNAME - !IV_S3BUCKET type /AWS1/TEXS3BUCKET - exporting - !OO_RESULT type ref to /AWS1/CL_TEXSTARTDOCALYRSP . - methods START_DOCUMENT_TEXT_DETECTION - importing - !IV_S3OBJECT type /AWS1/TEXS3OBJECTNAME - !IV_S3BUCKET type /AWS1/TEXS3BUCKET - exporting - !OO_RESULT type ref to /AWS1/CL_TEXSTARTDOCTEXTDETRSP . -protected section. -private section. +CLASS zcl_aws1_tex_actions DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + + METHODS analyze_document + IMPORTING + !iv_s3object TYPE /aws1/texs3objectname OPTIONAL + !iv_s3bucket TYPE /aws1/texs3bucket OPTIONAL + RETURNING + VALUE(oo_result) TYPE REF TO /aws1/cl_texanalyzedocresponse . + METHODS detect_document_text + IMPORTING + !iv_s3object TYPE /aws1/texs3objectname + !iv_s3bucket TYPE /aws1/texs3bucket + RETURNING + VALUE(oo_result) TYPE REF TO /aws1/cl_texdetectdoctextrsp . + METHODS get_document_analysis + IMPORTING + !iv_jobid TYPE /aws1/texjobid + RETURNING + VALUE(oo_result) TYPE REF TO /aws1/cl_texgetdocalyresponse . + METHODS start_document_analysis + IMPORTING + !iv_s3object TYPE /aws1/texs3objectname + !iv_s3bucket TYPE /aws1/texs3bucket + RETURNING + VALUE(oo_result) TYPE REF TO /aws1/cl_texstartdocalyrsp . + METHODS start_document_text_detection + IMPORTING + !iv_s3object TYPE /aws1/texs3objectname + !iv_s3bucket TYPE /aws1/texs3bucket + RETURNING + VALUE(oo_result) TYPE REF TO /aws1/cl_texstartdoctextdetrsp . + PROTECTED SECTION. + PRIVATE SECTION. ENDCLASS. @@ -51,69 +50,71 @@ CLASS ZCL_AWS1_TEX_ACTIONS IMPLEMENTATION. METHOD analyze_document. - CONSTANTS: cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. - + CONSTANTS cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. DATA(lo_session) = /aws1/cl_rt_session_aws=>create( cv_pfl ). - DATA(lo_tex) = /aws1/cl_tex_factory=>create( lo_session ). + "Textract requires endpoint region to be same as the bucket region. + "Retrieve the region name defined as a logical resource in SDK configuration. + CONSTANTS cv_lbucket TYPE string VALUE 'ZEX_TEX_BUCKET_REGION'. + DATA lv_bucket_region TYPE /aws1/rt_region_id. + lv_bucket_region = lo_session->resolve_lresource( cv_lbucket ). + DATA(lo_tex) = /aws1/cl_tex_factory=>create( + io_session = lo_session + iv_region = lv_bucket_region ). "snippet-start:[tex.abapv1.analyze_document] "Detects text and additional elements, such as forms or tables," "in a local image file or from in-memory byte data." "The image must be in PNG or JPG format." - DATA lo_document TYPE REF TO /aws1/cl_texdocument. - DATA lo_s3object TYPE REF TO /aws1/cl_texs3object. - DATA lo_featuretypes TYPE REF TO /aws1/cl_texfeaturetypes_w. - DATA lt_featuretypes TYPE /aws1/cl_texfeaturetypes_w=>tt_featuretypes. "Create ABAP objects for feature type." "Add TABLES to return information about the tables." "Add FORMS to return detected form data." "To perform both types of analysis, add TABLES and FORMS to FeatureTypes." - CREATE OBJECT lo_featuretypes EXPORTING iv_value = 'FORMS'. - INSERT lo_featuretypes INTO TABLE lt_featuretypes. - - CREATE OBJECT lo_featuretypes EXPORTING iv_value = 'TABLES'. - INSERT lo_featuretypes INTO TABLE lt_featuretypes. + DATA(lt_featuretypes) = VALUE /aws1/cl_texfeaturetypes_w=>tt_featuretypes( + ( NEW /aws1/cl_texfeaturetypes_w( iv_value = 'FORMS' ) ) + ( NEW /aws1/cl_texfeaturetypes_w( iv_value = 'TABLES' ) ) ). "Create an ABAP object for the Amazon Simple Storage Service (Amazon S3) object." - CREATE OBJECT lo_s3object - EXPORTING - iv_bucket = iv_s3bucket - iv_name = iv_s3object. + DATA(lo_s3object) = NEW /aws1/cl_texs3object( iv_bucket = iv_s3bucket + iv_name = iv_s3object ). "Create an ABAP object for the document." - CREATE OBJECT lo_document EXPORTING io_s3object = lo_s3object. + DATA(lo_document) = NEW /aws1/cl_texdocument( io_s3object = lo_s3object ). "Analyze document stored in Amazon S3." TRY. oo_result = lo_tex->analyzedocument( "oo_result is returned for testing purposes." - EXPORTING - io_document = lo_document - it_featuretypes = lt_featuretypes - ). + io_document = lo_document + it_featuretypes = lt_featuretypes ). + LOOP AT oo_result->get_blocks( ) INTO DATA(lo_block). + IF lo_block->get_text( ) = 'INGREDIENTS: POWDERED SUGAR* (CANE SUGAR,'. + MESSAGE 'Found text in the doc: ' && lo_block->get_text( ) TYPE 'I'. + ENDIF. + ENDLOOP. MESSAGE 'Analyze document completed.' TYPE 'I'. - CATCH /aws1/cx_texaccessdeniedex . + CATCH /aws1/cx_texaccessdeniedex. MESSAGE 'You do not have permission to perform this action.' TYPE 'E'. - CATCH /aws1/cx_texbaddocumentex . + CATCH /aws1/cx_texbaddocumentex. MESSAGE 'Amazon Textract is not able to read the document.' TYPE 'E'. - CATCH /aws1/cx_texdocumenttoolargeex . + CATCH /aws1/cx_texdocumenttoolargeex. MESSAGE 'The document is too large.' TYPE 'E'. - CATCH /aws1/cx_texhlquotaexceededex . + CATCH /aws1/cx_texhlquotaexceededex. MESSAGE 'Human loop quota exceeded.' TYPE 'E'. - CATCH /aws1/cx_texinternalservererr . + CATCH /aws1/cx_texinternalservererr. MESSAGE 'Internal server error.' TYPE 'E'. - CATCH /aws1/cx_texinvalidparameterex . + CATCH /aws1/cx_texinvalidparameterex. MESSAGE 'Request has non-valid parameters.' TYPE 'E'. - CATCH /aws1/cx_texinvalids3objectex . + + CATCH /aws1/cx_texinvalids3objectex. MESSAGE 'Amazon S3 object is not valid.' TYPE 'E'. - CATCH /aws1/cx_texprovthruputexcdex . + CATCH /aws1/cx_texprovthruputexcdex. MESSAGE 'Provisioned throughput exceeded limit.' TYPE 'E'. - CATCH /aws1/cx_texthrottlingex . + CATCH /aws1/cx_texthrottlingex. MESSAGE 'The request processing exceeded the limit.' TYPE 'E'. - CATCH /aws1/cx_texunsupporteddocex . + CATCH /aws1/cx_texunsupporteddocex. MESSAGE 'The document is not supported.' TYPE 'E'. ENDTRY. "snippet-end:[tex.abapv1.analyze_document] @@ -122,10 +123,18 @@ CLASS ZCL_AWS1_TEX_ACTIONS IMPLEMENTATION. METHOD detect_document_text. - CONSTANTS: cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. + CONSTANTS cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. DATA(lo_session) = /aws1/cl_rt_session_aws=>create( cv_pfl ). - DATA(lo_tex) = /aws1/cl_tex_factory=>create( lo_session ). + + "Textract requires endpoint region to be same as the bucket region. + "Retrieve the region name defined as a logical resource in SDK configuration. + CONSTANTS cv_lbucket TYPE string VALUE 'ZEX_TEX_BUCKET_REGION'. + DATA lv_bucket_region TYPE /aws1/rt_region_id. + lv_bucket_region = lo_session->resolve_lresource( cv_lbucket ). + DATA(lo_tex) = /aws1/cl_tex_factory=>create( + io_session = lo_session + iv_region = lv_bucket_region ). "snippet-start:[tex.abapv1.detect_document_text] @@ -133,39 +142,40 @@ CLASS ZCL_AWS1_TEX_ACTIONS IMPLEMENTATION. "Amazon Textract can detect lines of text and the words that make up a line of text." "The input document must be in one of the following image formats: JPEG, PNG, PDF, or TIFF." - DATA lo_document TYPE REF TO /aws1/cl_texdocument. - DATA lo_s3object TYPE REF TO /aws1/cl_texs3object. - "Create an ABAP object for the Amazon S3 object." - CREATE OBJECT lo_s3object - EXPORTING - iv_bucket = iv_s3bucket - iv_name = iv_s3object. + DATA(lo_s3object) = NEW /aws1/cl_texs3object( iv_bucket = iv_s3bucket + iv_name = iv_s3object ). "Create an ABAP object for the document." - CREATE OBJECT lo_document EXPORTING io_s3object = lo_s3object. - + DATA(lo_document) = NEW /aws1/cl_texdocument( io_s3object = lo_s3object ). "Analyze document stored in Amazon S3." TRY. oo_result = lo_tex->detectdocumenttext( io_document = lo_document ). "oo_result is returned for testing purposes." + LOOP AT oo_result->get_blocks( ) INTO DATA(lo_block). + IF lo_block->get_text( ) = 'INGREDIENTS: POWDERED SUGAR* (CANE SUGAR,'. + MESSAGE 'Found text in the doc: ' && lo_block->get_text( ) TYPE 'I'. + ENDIF. + ENDLOOP. + DATA(lo_metadata) = oo_result->get_documentmetadata( ). + MESSAGE 'The number of pages in the document is ' && lo_metadata->ask_pages( ) TYPE 'I'. MESSAGE 'Detect document text completed.' TYPE 'I'. - CATCH /aws1/cx_texaccessdeniedex . + CATCH /aws1/cx_texaccessdeniedex. MESSAGE 'You do not have permission to perform this action.' TYPE 'E'. - CATCH /aws1/cx_texbaddocumentex . + CATCH /aws1/cx_texbaddocumentex. MESSAGE 'Amazon Textract is not able to read the document.' TYPE 'E'. - CATCH /aws1/cx_texdocumenttoolargeex . + CATCH /aws1/cx_texdocumenttoolargeex. MESSAGE 'The document is too large.' TYPE 'E'. - CATCH /aws1/cx_texinternalservererr . + CATCH /aws1/cx_texinternalservererr. MESSAGE 'Internal server error.' TYPE 'E'. - CATCH /aws1/cx_texinvalidparameterex . + CATCH /aws1/cx_texinvalidparameterex. MESSAGE 'Request has non-valid parameters.' TYPE 'E'. - CATCH /aws1/cx_texinvalids3objectex . + CATCH /aws1/cx_texinvalids3objectex. MESSAGE 'Amazon S3 object is not valid.' TYPE 'E'. - CATCH /aws1/cx_texprovthruputexcdex . + CATCH /aws1/cx_texprovthruputexcdex. MESSAGE 'Provisioned throughput exceeded limit.' TYPE 'E'. - CATCH /aws1/cx_texthrottlingex . + CATCH /aws1/cx_texthrottlingex. MESSAGE 'The request processing exceeded the limit' TYPE 'E'. - CATCH /aws1/cx_texunsupporteddocex . + CATCH /aws1/cx_texunsupporteddocex. MESSAGE 'The document is not supported.' TYPE 'E'. ENDTRY. "snippet-end:[tex.abapv1.detect_document_text] @@ -174,10 +184,18 @@ CLASS ZCL_AWS1_TEX_ACTIONS IMPLEMENTATION. METHOD get_document_analysis. - CONSTANTS: cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. + CONSTANTS cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. DATA(lo_session) = /aws1/cl_rt_session_aws=>create( cv_pfl ). - DATA(lo_tex) = /aws1/cl_tex_factory=>create( lo_session ). + + "Textract requires endpoint region to be same as the bucket region. + "Retrieve the region name defined as a logical resource in SDK configuration. + CONSTANTS cv_lbucket TYPE string VALUE 'ZEX_TEX_BUCKET_REGION'. + DATA lv_bucket_region TYPE /aws1/rt_region_id. + lv_bucket_region = lo_session->resolve_lresource( cv_lbucket ). + DATA(lo_tex) = /aws1/cl_tex_factory=>create( + io_session = lo_session + iv_region = lv_bucket_region ). "snippet-start:[tex.abapv1.get_document_analysis] @@ -185,22 +203,36 @@ CLASS ZCL_AWS1_TEX_ACTIONS IMPLEMENTATION. "asynchronous operation that analyzes text in a document." TRY. oo_result = lo_tex->getdocumentanalysis( iv_jobid = iv_jobid ). "oo_result is returned for testing purposes." + WHILE oo_result->get_jobstatus( ) <> 'SUCCEEDED'. + IF sy-index = 10. + EXIT. "Maximum 300 seconds. + ENDIF. + WAIT UP TO 30 SECONDS. + oo_result = lo_tex->getdocumentanalysis( iv_jobid = iv_jobid ). + ENDWHILE. + + DATA(lt_blocks) = oo_result->get_blocks( ). + LOOP AT lt_blocks INTO DATA(lo_block). + IF lo_block->get_text( ) = 'INGREDIENTS: POWDERED SUGAR* (CANE SUGAR,'. + MESSAGE 'Found text in the doc: ' && lo_block->get_text( ) TYPE 'I'. + ENDIF. + ENDLOOP. MESSAGE 'Document analysis retrieved.' TYPE 'I'. - CATCH /aws1/cx_texaccessdeniedex . + CATCH /aws1/cx_texaccessdeniedex. MESSAGE 'You do not have permission to perform this action.' TYPE 'E'. - CATCH /aws1/cx_texinternalservererr . + CATCH /aws1/cx_texinternalservererr. MESSAGE 'Internal server error.' TYPE 'E'. - CATCH /aws1/cx_texinvalidjobidex . + CATCH /aws1/cx_texinvalidjobidex. MESSAGE 'Job ID is not valid.' TYPE 'E'. - CATCH /aws1/cx_texinvalidkmskeyex . + CATCH /aws1/cx_texinvalidkmskeyex. MESSAGE 'AWS KMS key is not valid.' TYPE 'E'. - CATCH /aws1/cx_texinvalidparameterex . + CATCH /aws1/cx_texinvalidparameterex. MESSAGE 'Request has non-valid parameters.' TYPE 'E'. - CATCH /aws1/cx_texinvalids3objectex . + CATCH /aws1/cx_texinvalids3objectex. MESSAGE 'Amazon S3 object is not valid.' TYPE 'E'. - CATCH /aws1/cx_texprovthruputexcdex . + CATCH /aws1/cx_texprovthruputexcdex. MESSAGE 'Provisioned throughput exceeded limit.' TYPE 'E'. - CATCH /aws1/cx_texthrottlingex . + CATCH /aws1/cx_texthrottlingex. MESSAGE 'The request processing exceeded the limit.' TYPE 'E'. ENDTRY. "snippet-end:[tex.abapv1.get_document_analysis] @@ -210,72 +242,69 @@ CLASS ZCL_AWS1_TEX_ACTIONS IMPLEMENTATION. METHOD start_document_analysis. - CONSTANTS: cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. + CONSTANTS cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. DATA(lo_session) = /aws1/cl_rt_session_aws=>create( cv_pfl ). - DATA(lo_tex) = /aws1/cl_tex_factory=>create( lo_session ). + + "Textract requires endpoint region to be same as the bucket region. + "Retrieve the region name defined as a logical resource in SDK configuration. + CONSTANTS cv_lbucket TYPE string VALUE 'ZEX_TEX_BUCKET_REGION'. + DATA lv_bucket_region TYPE /aws1/rt_region_id. + lv_bucket_region = lo_session->resolve_lresource( cv_lbucket ). + DATA(lo_tex) = /aws1/cl_tex_factory=>create( + io_session = lo_session + iv_region = lv_bucket_region ). "snippet-start:[tex.abapv1.start_document_analysis] "Starts the asynchronous analysis of an input document for relationships" "between detected items such as key-value pairs, tables, and selection elements." - DATA lo_documentlocation TYPE REF TO /aws1/cl_texdocumentlocation. - DATA lo_s3object TYPE REF TO /aws1/cl_texs3object. - DATA lo_featuretypes TYPE REF TO /aws1/cl_texfeaturetypes_w. - DATA lt_featuretypes TYPE /aws1/cl_texfeaturetypes_w=>tt_featuretypes. - "Create ABAP objects for feature type." "Add TABLES to return information about the tables." "Add FORMS to return detected form data." "To perform both types of analysis, add TABLES and FORMS to FeatureTypes." - CREATE OBJECT lo_featuretypes EXPORTING iv_value = 'FORMS'. - INSERT lo_featuretypes INTO TABLE lt_featuretypes. - - CREATE OBJECT lo_featuretypes EXPORTING iv_value = 'TABLES'. - INSERT lo_featuretypes INTO TABLE lt_featuretypes. - + DATA(lt_featuretypes) = VALUE /aws1/cl_texfeaturetypes_w=>tt_featuretypes( + ( NEW /aws1/cl_texfeaturetypes_w( iv_value = 'FORMS' ) ) + ( NEW /aws1/cl_texfeaturetypes_w( iv_value = 'TABLES' ) ) ). "Create an ABAP object for the Amazon S3 object." - CREATE OBJECT lo_s3object - EXPORTING - iv_bucket = iv_s3bucket - iv_name = iv_s3object. - + DATA(lo_s3object) = NEW /aws1/cl_texs3object( iv_bucket = iv_s3bucket + iv_name = iv_s3object ). "Create an ABAP object for the document." - CREATE OBJECT lo_documentlocation EXPORTING io_s3object = lo_s3object. + DATA(lo_documentlocation) = NEW /aws1/cl_texdocumentlocation( io_s3object = lo_s3object ). "Start async document analysis." TRY. oo_result = lo_tex->startdocumentanalysis( "oo_result is returned for testing purposes." - EXPORTING - io_documentlocation = lo_documentlocation - it_featuretypes = lt_featuretypes - ). + io_documentlocation = lo_documentlocation + it_featuretypes = lt_featuretypes ). + DATA(lv_jobid) = oo_result->get_jobid( ). + MESSAGE 'Document analysis started.' TYPE 'I'. - CATCH /aws1/cx_texaccessdeniedex . + CATCH /aws1/cx_texaccessdeniedex. MESSAGE 'You do not have permission to perform this action.' TYPE 'E'. - CATCH /aws1/cx_texbaddocumentex . + CATCH /aws1/cx_texbaddocumentex. MESSAGE 'Amazon Textract is not able to read the document.' TYPE 'E'. - CATCH /aws1/cx_texdocumenttoolargeex . + CATCH /aws1/cx_texdocumenttoolargeex. MESSAGE 'The document is too large.' TYPE 'E'. - CATCH /aws1/cx_texidempotentprmmis00 . + CATCH /aws1/cx_texidempotentprmmis00. MESSAGE 'Idempotent parameter mismatch exception.' TYPE 'E'. - CATCH /aws1/cx_texinternalservererr . + CATCH /aws1/cx_texinternalservererr. MESSAGE 'Internal server error.' TYPE 'E'. - CATCH /aws1/cx_texinvalidkmskeyex . + CATCH /aws1/cx_texinvalidkmskeyex. MESSAGE 'AWS KMS key is not valid.' TYPE 'E'. - CATCH /aws1/cx_texinvalidparameterex . + CATCH /aws1/cx_texinvalidparameterex. MESSAGE 'Request has non-valid parameters.' TYPE 'E'. - CATCH /aws1/cx_texinvalids3objectex . + CATCH /aws1/cx_texinvalids3objectex. MESSAGE 'Amazon S3 object is not valid.' TYPE 'E'. - CATCH /aws1/cx_texlimitexceededex . + CATCH /aws1/cx_texlimitexceededex. MESSAGE 'An Amazon Textract service limit was exceeded.' TYPE 'E'. - CATCH /aws1/cx_texprovthruputexcdex . + CATCH /aws1/cx_texprovthruputexcdex. MESSAGE 'Provisioned throughput exceeded limit.' TYPE 'E'. - CATCH /aws1/cx_texthrottlingex . + CATCH /aws1/cx_texthrottlingex. MESSAGE 'The request processing exceeded the limit.' TYPE 'E'. - CATCH /aws1/cx_texunsupporteddocex . + CATCH /aws1/cx_texunsupporteddocex. MESSAGE 'The document is not supported.' TYPE 'E'. ENDTRY. "snippet-end:[tex.abapv1.start_document_analysis] @@ -284,57 +313,57 @@ CLASS ZCL_AWS1_TEX_ACTIONS IMPLEMENTATION. METHOD start_document_text_detection. - CONSTANTS: cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. + CONSTANTS cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. DATA(lo_session) = /aws1/cl_rt_session_aws=>create( cv_pfl ). - DATA(lo_tex) = /aws1/cl_tex_factory=>create( lo_session ). + + "Textract requires endpoint region to be same as the bucket region. + "Retrieve the region name defined as a logical resource in SDK configuration. + CONSTANTS cv_lbucket TYPE string VALUE 'ZEX_TEX_BUCKET_REGION'. + DATA lv_bucket_region TYPE /aws1/rt_region_id. + lv_bucket_region = lo_session->resolve_lresource( cv_lbucket ). + DATA(lo_tex) = /aws1/cl_tex_factory=>create( + io_session = lo_session + iv_region = lv_bucket_region ). "snippet-start:[tex.abapv1.start_document_text_detection] "Starts the asynchronous detection of text in a document." "Amazon Textract can detect lines of text and the words that make up a line of text." - DATA lo_documentlocation TYPE REF TO /aws1/cl_texdocumentlocation. - DATA lo_s3object TYPE REF TO /aws1/cl_texs3object. - "Create an ABAP object for the Amazon S3 object." - CREATE OBJECT lo_s3object - EXPORTING - iv_bucket = iv_s3bucket - iv_name = iv_s3object. - + DATA(lo_s3object) = NEW /aws1/cl_texs3object( iv_bucket = iv_s3bucket + iv_name = iv_s3object ). "Create an ABAP object for the document." - CREATE OBJECT lo_documentlocation - EXPORTING - io_s3object = lo_s3object. - + DATA(lo_documentlocation) = NEW /aws1/cl_texdocumentlocation( io_s3object = lo_s3object ). "Start document analysis." TRY. - oo_result = lo_tex->startdocumenttextdetection( io_documentlocation = lo_documentlocation ). "oo_result is returned for testing purposes." + oo_result = lo_tex->startdocumenttextdetection( io_documentlocation = lo_documentlocation ). + DATA(lv_jobid) = oo_result->get_jobid( ). "oo_result is returned for testing purposes." MESSAGE 'Document analysis started.' TYPE 'I'. - CATCH /aws1/cx_texaccessdeniedex . + CATCH /aws1/cx_texaccessdeniedex. MESSAGE 'You do not have permission to perform this action.' TYPE 'E'. - CATCH /aws1/cx_texbaddocumentex . + CATCH /aws1/cx_texbaddocumentex. MESSAGE 'Amazon Textract is not able to read the document.' TYPE 'E'. - CATCH /aws1/cx_texdocumenttoolargeex . + CATCH /aws1/cx_texdocumenttoolargeex. MESSAGE 'The document is too large.' TYPE 'E'. - CATCH /aws1/cx_texidempotentprmmis00 . + CATCH /aws1/cx_texidempotentprmmis00. MESSAGE 'Idempotent parameter mismatch exception.' TYPE 'E'. - CATCH /aws1/cx_texinternalservererr . + CATCH /aws1/cx_texinternalservererr. MESSAGE 'Internal server error.' TYPE 'E'. - CATCH /aws1/cx_texinvalidkmskeyex . + CATCH /aws1/cx_texinvalidkmskeyex. MESSAGE 'AWS KMS key is not valid.' TYPE 'E'. - CATCH /aws1/cx_texinvalidparameterex . + CATCH /aws1/cx_texinvalidparameterex. MESSAGE 'Request has non-valid parameters.' TYPE 'E'. - CATCH /aws1/cx_texinvalids3objectex . + CATCH /aws1/cx_texinvalids3objectex. MESSAGE 'Amazon S3 object is not valid.' TYPE 'E'. - CATCH /aws1/cx_texlimitexceededex . + CATCH /aws1/cx_texlimitexceededex. MESSAGE 'An Amazon Textract service limit was exceeded.' TYPE 'E'. - CATCH /aws1/cx_texprovthruputexcdex . + CATCH /aws1/cx_texprovthruputexcdex. MESSAGE 'Provisioned throughput exceeded limit.' TYPE 'E'. - CATCH /aws1/cx_texthrottlingex . + CATCH /aws1/cx_texthrottlingex. MESSAGE 'The request processing exceeded the limit.' TYPE 'E'. - CATCH /aws1/cx_texunsupporteddocex . + CATCH /aws1/cx_texunsupporteddocex. MESSAGE 'The document is not supported.' TYPE 'E'. ENDTRY. "snippet-end:[tex.abapv1.start_document_text_detection] diff --git a/sap-abap/services/textract/zcl_aws1_tex_actions.clas.testclasses.abap b/sap-abap/services/textract/zcl_aws1_tex_actions.clas.testclasses.abap index 44333e9fd45..9288fea9ae7 100644 --- a/sap-abap/services/textract/zcl_aws1_tex_actions.clas.testclasses.abap +++ b/sap-abap/services/textract/zcl_aws1_tex_actions.clas.testclasses.abap @@ -16,11 +16,11 @@ CLASS ltc_zcl_aws1_tex_actions DEFINITION FOR TESTING DURATION LONG RISK LEVEL H DATA ao_tex_actions TYPE REF TO zcl_aws1_tex_actions. METHODS setup RAISING /aws1/cx_rt_generic ycx_aws1_mit_generic. - METHODS: analyze_document FOR TESTING. - METHODS: detect_document_text FOR TESTING. - METHODS: start_document_analysis FOR TESTING. - METHODS: start_document_text_detection FOR TESTING. - METHODS: get_document_analysis FOR TESTING. + METHODS analyze_document FOR TESTING. + METHODS detect_document_text FOR TESTING. + METHODS start_document_analysis FOR TESTING. + METHODS start_document_text_detection FOR TESTING. + METHODS get_document_analysis FOR TESTING. ENDCLASS. "ltc_Zcl_Aws1_Tex_Actions @@ -29,36 +29,30 @@ CLASS ltc_zcl_aws1_tex_actions IMPLEMENTATION. METHOD setup. ao_session = /aws1/cl_rt_session_aws=>create( iv_profile_id = cv_pfl ). - ao_tex = /aws1/cl_tex_factory=>create( ao_session ). + + ao_tex = /aws1/cl_tex_factory=>create( + io_session = ao_session + iv_region = 'us-east-1' ). ao_s3 = /aws1/cl_s3_factory=>create( ao_session ). ao_tex_actions = NEW zcl_aws1_tex_actions( ). ENDMETHOD. METHOD analyze_document. - DATA lv_found TYPE abap_bool VALUE abap_false. - DATA lo_output TYPE REF TO /aws1/cl_texanalyzedocresponse. - DATA lt_blocks TYPE /aws1/cl_texblock=>tt_blocklist. - DATA lo_block TYPE REF TO /aws1/cl_texblock. - "Using an image from the Public Amazon Berkeley Objects Dataset. CONSTANTS cv_bucket_name TYPE /aws1/s3_bucketname VALUE 'amazon-berkeley-objects'. CONSTANTS cv_key_name TYPE /aws1/s3_bucketname VALUE 'images/small/e0/e0feb1eb.jpg'. "Analyze document. - ao_tex_actions->analyze_document( - EXPORTING + DATA(lo_output) = ao_tex_actions->analyze_document( iv_s3object = cv_key_name - iv_s3bucket = cv_bucket_name - IMPORTING - oo_result = lo_output - ). + iv_s3bucket = cv_bucket_name ). "Validation check. - lv_found = abap_false. - lt_blocks = lo_output->get_blocks( ). + DATA(lv_found) = abap_false. + DATA(lt_blocks) = lo_output->get_blocks( ). - LOOP AT lt_blocks INTO lo_block. + LOOP AT lt_blocks INTO DATA(lo_block). IF lo_block->get_text( ) = 'INGREDIENTS: POWDERED SUGAR* (CANE SUGAR,'. lv_found = abap_true. ENDIF. @@ -66,37 +60,27 @@ CLASS ltc_zcl_aws1_tex_actions IMPLEMENTATION. cl_abap_unit_assert=>assert_true( act = lv_found - msg = |Analyze document failed| - ). + msg = |Analyze document failed| ). ENDMETHOD. METHOD detect_document_text. - DATA lv_found TYPE abap_bool VALUE abap_false. - DATA lo_output TYPE REF TO /aws1/cl_texdetectdoctextrsp. - DATA lt_blocks TYPE /aws1/cl_texblock=>tt_blocklist. - DATA lo_block TYPE REF TO /aws1/cl_texblock. - "Using an image from the Public Amazon Berkeley Objects Dataset. CONSTANTS cv_bucket_name TYPE /aws1/s3_bucketname VALUE 'amazon-berkeley-objects'. CONSTANTS cv_key_name TYPE /aws1/s3_bucketname VALUE 'images/small/e0/e0feb1eb.jpg'. "Testing. - ao_tex_actions->detect_document_text( - EXPORTING + DATA(lo_output) = ao_tex_actions->detect_document_text( iv_s3object = cv_key_name - iv_s3bucket = cv_bucket_name - IMPORTING - oo_result = lo_output - ). + iv_s3bucket = cv_bucket_name ). "Validation check. - lv_found = abap_false. - lt_blocks = lo_output->get_blocks( ). + DATA(lv_found) = abap_false. + DATA(lt_blocks) = lo_output->get_blocks( ). - LOOP AT lt_blocks INTO lo_block. + LOOP AT lt_blocks INTO DATA(lo_block). IF lo_block->get_text( ) = 'INGREDIENTS: POWDERED SUGAR* (CANE SUGAR,'. lv_found = abap_true. ENDIF. @@ -104,38 +88,25 @@ CLASS ltc_zcl_aws1_tex_actions IMPLEMENTATION. cl_abap_unit_assert=>assert_true( act = lv_found - msg = |Analyze document failed| - ). + msg = |Analyze document failed| ). ENDMETHOD. METHOD start_document_analysis. - DATA lv_found TYPE abap_bool VALUE abap_false. - DATA lo_output TYPE REF TO /aws1/cl_texstartdocalyrsp. - DATA lv_jobid TYPE /aws1/texjobid. - DATA lo_document_analysis_output TYPE REF TO /aws1/cl_texgetdocalyresponse. - DATA lo_jobstatus TYPE /aws1/texjobstatus. - DATA lt_blocks TYPE /aws1/cl_texblock=>tt_blocklist. - DATA lo_block TYPE REF TO /aws1/cl_texblock. - "Using an image from the Public Amazon Berkeley Objects Dataset. CONSTANTS cv_bucket_name TYPE /aws1/s3_bucketname VALUE 'amazon-berkeley-objects'. CONSTANTS cv_key_name TYPE /aws1/s3_bucketname VALUE 'images/small/e0/e0feb1eb.jpg'. "Testing. - ao_tex_actions->start_document_analysis( - EXPORTING + DATA(lo_output) = ao_tex_actions->start_document_analysis( iv_s3object = cv_key_name - iv_s3bucket = cv_bucket_name - IMPORTING - oo_result = lo_output - ). + iv_s3bucket = cv_bucket_name ). "Wait for job to complete. - lv_jobid = lo_output->get_jobid( ). + DATA(lv_jobid) = lo_output->get_jobid( ). - lo_document_analysis_output = ao_tex->getdocumentanalysis( iv_jobid = lv_jobid ). + DATA(lo_document_analysis_output) = ao_tex->getdocumentanalysis( iv_jobid = lv_jobid ). WHILE lo_document_analysis_output->get_jobstatus( ) <> 'SUCCEEDED'. IF sy-index = 10. EXIT. "Maximum 300 seconds. @@ -145,9 +116,9 @@ CLASS ltc_zcl_aws1_tex_actions IMPLEMENTATION. ENDWHILE. "Validation check. - lv_found = abap_false. - lt_blocks = lo_document_analysis_output->get_blocks( ). - LOOP AT lt_blocks INTO lo_block. + DATA(lv_found) = abap_false. + DATA(lt_blocks) = lo_document_analysis_output->get_blocks( ). + LOOP AT lt_blocks INTO DATA(lo_block). IF lo_block->get_text( ) = 'INGREDIENTS: POWDERED SUGAR* (CANE SUGAR,'. lv_found = abap_true. ENDIF. @@ -155,38 +126,25 @@ CLASS ltc_zcl_aws1_tex_actions IMPLEMENTATION. cl_abap_unit_assert=>assert_true( act = lv_found - msg = |Analyze document failed| - ). + msg = |Analyze document failed| ). ENDMETHOD. METHOD start_document_text_detection. - DATA lv_found TYPE abap_bool VALUE abap_false. - DATA lo_output TYPE REF TO /aws1/cl_texstartdoctextdetrsp. - DATA lv_jobid TYPE /aws1/texjobid. - DATA lo_text_detection_output TYPE REF TO /aws1/cl_texgetdoctxtdetectrsp. - DATA lo_jobstatus TYPE /aws1/texjobstatus. - DATA lt_blocks TYPE /aws1/cl_texblock=>tt_blocklist. - DATA lo_block TYPE REF TO /aws1/cl_texblock. - "Using an image from the Public Amazon Berkeley Objects Dataset. CONSTANTS cv_bucket_name TYPE /aws1/s3_bucketname VALUE 'amazon-berkeley-objects'. CONSTANTS cv_key_name TYPE /aws1/s3_bucketname VALUE 'images/small/e0/e0feb1eb.jpg'. "Testing. - ao_tex_actions->start_document_text_detection( - EXPORTING + DATA(lo_output) = ao_tex_actions->start_document_text_detection( iv_s3object = cv_key_name - iv_s3bucket = cv_bucket_name - IMPORTING - oo_result = lo_output - ). + iv_s3bucket = cv_bucket_name ). - lv_jobid = lo_output->get_jobid( ). + DATA(lv_jobid) = lo_output->get_jobid( ). "Wait for job to complete. - lo_text_detection_output = ao_tex->getdocumenttextdetection( iv_jobid = lv_jobid ). + DATA(lo_text_detection_output) = ao_tex->getdocumenttextdetection( iv_jobid = lv_jobid ). WHILE lo_text_detection_output->get_jobstatus( ) <> 'SUCCEEDED'. IF sy-index = 10. EXIT. "Maximum 300 seconds. @@ -196,9 +154,9 @@ CLASS ltc_zcl_aws1_tex_actions IMPLEMENTATION. ENDWHILE. "Validation check. - lv_found = abap_false. - lt_blocks = lo_text_detection_output->get_blocks( ). - LOOP AT lt_blocks INTO lo_block. + DATA(lv_found) = abap_false. + DATA(lt_blocks) = lo_text_detection_output->get_blocks( ). + LOOP AT lt_blocks INTO DATA(lo_block). IF lo_block->get_text( ) = 'INGREDIENTS: POWDERED SUGAR* (CANE SUGAR,'. lv_found = abap_true. ENDIF. @@ -206,74 +164,49 @@ CLASS ltc_zcl_aws1_tex_actions IMPLEMENTATION. cl_abap_unit_assert=>assert_true( act = lv_found - msg = |Analyze document failed| - ). + msg = |Analyze document failed| ). ENDMETHOD. METHOD get_document_analysis. - DATA lv_found TYPE abap_bool VALUE abap_false. - DATA lo_output TYPE REF TO /aws1/cl_texstartdocalyrsp. - DATA lv_jobid TYPE /aws1/texjobid. - DATA lo_document_analysis_output TYPE REF TO /aws1/cl_texgetdocalyresponse. - DATA lo_jobstatus TYPE /aws1/texjobstatus. - DATA lt_blocks TYPE /aws1/cl_texblock=>tt_blocklist. - DATA lo_block TYPE REF TO /aws1/cl_texblock. - DATA lo_documentlocation TYPE REF TO /aws1/cl_texdocumentlocation. - DATA lo_s3object TYPE REF TO /aws1/cl_texs3object. - DATA lo_featuretypes TYPE REF TO /aws1/cl_texfeaturetypes_w. - DATA lt_featuretypes TYPE /aws1/cl_texfeaturetypes_w=>tt_featuretypes. - "Using an image from the Public Amazon Berkeley Objects Dataset. CONSTANTS cv_bucket_name TYPE /aws1/s3_bucketname VALUE 'amazon-berkeley-objects'. CONSTANTS cv_key_name TYPE /aws1/s3_bucketname VALUE 'images/small/e0/e0feb1eb.jpg'. - CREATE OBJECT lo_featuretypes - EXPORTING - iv_value = 'FORMS'. - INSERT lo_featuretypes INTO TABLE lt_featuretypes. - - CREATE OBJECT lo_featuretypes - EXPORTING - iv_value = 'TABLES'. - INSERT lo_featuretypes INTO TABLE lt_featuretypes. + DATA(lt_featuretypes) = VALUE /aws1/cl_texfeaturetypes_w=>tt_featuretypes( + ( NEW /aws1/cl_texfeaturetypes_w( iv_value = 'FORMS' ) ) + ( NEW /aws1/cl_texfeaturetypes_w( iv_value = 'TABLES' ) ) ). "Create a ABAP object for the Amazon Simple Storage Service (Amazon S3) object. - CREATE OBJECT lo_s3object - EXPORTING - iv_bucket = cv_bucket_name - iv_name = cv_key_name. + DATA(lo_s3object) = NEW /aws1/cl_texs3object( iv_bucket = cv_bucket_name + iv_name = cv_key_name ). "Create a ABAP object for the document. - CREATE OBJECT lo_documentlocation - EXPORTING - io_s3object = lo_s3object. + DATA(lo_documentlocation) = NEW /aws1/cl_texdocumentlocation( io_s3object = lo_s3object ). "Start document analysis. - lo_output = ao_tex->startdocumentanalysis( - EXPORTING + DATA(lo_output) = ao_tex->startdocumentanalysis( io_documentlocation = lo_documentlocation - it_featuretypes = lt_featuretypes - ). + it_featuretypes = lt_featuretypes ). "Get job ID. - lv_jobid = lo_output->get_jobid( ). + DATA(lv_jobid) = lo_output->get_jobid( ). "Testing. - ao_tex_actions->get_document_analysis( EXPORTING iv_jobid = lv_jobid IMPORTING oo_result = lo_document_analysis_output ). + DATA(lo_document_analysis_output) = ao_tex_actions->get_document_analysis( lv_jobid ). WHILE lo_document_analysis_output->get_jobstatus( ) <> 'SUCCEEDED'. IF sy-index = 10. EXIT. "Maximum 300 seconds. ENDIF. WAIT UP TO 30 SECONDS. - ao_tex_actions->get_document_analysis( EXPORTING iv_jobid = lv_jobid IMPORTING oo_result = lo_document_analysis_output ). + lo_document_analysis_output = ao_tex_actions->get_document_analysis( lv_jobid ). ENDWHILE. "Validation check. - lv_found = abap_false. - lt_blocks = lo_document_analysis_output->get_blocks( ). - LOOP AT lt_blocks INTO lo_block. + DATA(lv_found) = abap_false. + DATA(lt_blocks) = lo_document_analysis_output->get_blocks( ). + LOOP AT lt_blocks INTO DATA(lo_block). IF lo_block->get_text( ) = 'INGREDIENTS: POWDERED SUGAR* (CANE SUGAR,'. lv_found = abap_true. ENDIF. @@ -281,8 +214,7 @@ CLASS ltc_zcl_aws1_tex_actions IMPLEMENTATION. cl_abap_unit_assert=>assert_true( act = lv_found - msg = |Analyze document failed| - ). + msg = |Analyze document failed| ). ENDMETHOD. diff --git a/sap-abap/services/textract/zcl_aws1_tex_scenario.clas.abap b/sap-abap/services/textract/zcl_aws1_tex_scenario.clas.abap index a0caf53a8e6..02b6e88dc7d 100644 --- a/sap-abap/services/textract/zcl_aws1_tex_scenario.clas.abap +++ b/sap-abap/services/textract/zcl_aws1_tex_scenario.clas.abap @@ -3,22 +3,21 @@ " " Reserved. " " SPDX-License-Identifier: MIT-0 " """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -class ZCL_AWS1_TEX_SCENARIO definition - public - final - create public . - -public section. - - methods GETTING_STARTED_WITH_TEX - importing - !IV_S3OBJECT type /AWS1/TEXS3OBJECTNAME - !IV_S3BUCKET type /AWS1/TEXS3BUCKET - exporting - !OO_RESULT type ref to /AWS1/CL_TEXGETDOCALYRESPONSE . -protected section. -private section. +CLASS zcl_aws1_tex_scenario DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + + METHODS getting_started_with_tex + IMPORTING + !iv_s3object TYPE /aws1/texs3objectname + !iv_s3bucket TYPE /aws1/texs3bucket + RETURNING + VALUE(oo_result) TYPE REF TO /aws1/cl_texgetdocalyresponse . + PROTECTED SECTION. + PRIVATE SECTION. ENDCLASS. @@ -28,72 +27,68 @@ CLASS ZCL_AWS1_TEX_SCENARIO IMPLEMENTATION. METHOD getting_started_with_tex. - CONSTANTS: cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. + CONSTANTS cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. DATA(lo_session) = /aws1/cl_rt_session_aws=>create( cv_pfl ). - DATA(lo_tex) = /aws1/cl_tex_factory=>create( lo_session ). + "Textract requires endpoint region to be same as the bucket region. + "Retrieve the region name defined as a logical resource in SDK configuration. + CONSTANTS cv_lbucket TYPE string VALUE 'ZEX_TEX_BUCKET_REGION'. + DATA lv_bucket_region TYPE /aws1/rt_region_id. + lv_bucket_region = lo_session->resolve_lresource( cv_lbucket ). + DATA(lo_tex) = /aws1/cl_tex_factory=>create( + io_session = lo_session + iv_region = lv_bucket_region ). " 1. Starts the asynchronous analysis. " " 2. Wait for the analysis to complete. " "snippet-start:[tex.abapv1.getting_started_with_tex] - DATA lo_documentlocation TYPE REF TO /aws1/cl_texdocumentlocation. - DATA lo_s3object TYPE REF TO /aws1/cl_texs3object. - DATA lo_featuretypes TYPE REF TO /aws1/cl_texfeaturetypes_w. - DATA lt_featuretypes TYPE /aws1/cl_texfeaturetypes_w=>tt_featuretypes. - "Create ABAP objects for feature type." "Add TABLES to return information about the tables." "Add FORMS to return detected form data." "To perform both types of analysis, add TABLES and FORMS to FeatureTypes." - CREATE OBJECT lo_featuretypes EXPORTING iv_value = 'FORMS'. - INSERT lo_featuretypes INTO TABLE lt_featuretypes. - - CREATE OBJECT lo_featuretypes EXPORTING iv_value = 'TABLES'. - INSERT lo_featuretypes INTO TABLE lt_featuretypes. + DATA(lt_featuretypes) = VALUE /aws1/cl_texfeaturetypes_w=>tt_featuretypes( + ( NEW /aws1/cl_texfeaturetypes_w( iv_value = 'FORMS' ) ) + ( NEW /aws1/cl_texfeaturetypes_w( iv_value = 'TABLES' ) ) ). "Create an ABAP object for the Amazon Simple Storage Service (Amazon S3) object." - CREATE OBJECT lo_s3object - EXPORTING - iv_bucket = iv_s3bucket - iv_name = iv_s3object. + DATA(lo_s3object) = NEW /aws1/cl_texs3object( iv_bucket = iv_s3bucket + iv_name = iv_s3object ). "Create an ABAP object for the document." - CREATE OBJECT lo_documentlocation EXPORTING io_s3object = lo_s3object. + DATA(lo_documentlocation) = NEW /aws1/cl_texdocumentlocation( io_s3object = lo_s3object ). "Start document analysis." TRY. DATA(lo_start_result) = lo_tex->startdocumentanalysis( - EXPORTING - io_documentlocation = lo_documentlocation - it_featuretypes = lt_featuretypes - ). + io_documentlocation = lo_documentlocation + it_featuretypes = lt_featuretypes ). MESSAGE 'Document analysis started.' TYPE 'I'. - CATCH /aws1/cx_texaccessdeniedex . + CATCH /aws1/cx_texaccessdeniedex. MESSAGE 'You do not have permission to perform this action.' TYPE 'E'. - CATCH /aws1/cx_texbaddocumentex . + CATCH /aws1/cx_texbaddocumentex. MESSAGE 'Amazon Textract is not able to read the document.' TYPE 'E'. - CATCH /aws1/cx_texdocumenttoolargeex . + CATCH /aws1/cx_texdocumenttoolargeex. MESSAGE 'The document is too large.' TYPE 'E'. - CATCH /aws1/cx_texidempotentprmmis00 . + CATCH /aws1/cx_texidempotentprmmis00. MESSAGE 'Idempotent parameter mismatch exception.' TYPE 'E'. - CATCH /aws1/cx_texinternalservererr . + CATCH /aws1/cx_texinternalservererr. MESSAGE 'Internal server error.' TYPE 'E'. - CATCH /aws1/cx_texinvalidkmskeyex . + CATCH /aws1/cx_texinvalidkmskeyex. MESSAGE 'AWS KMS key is not valid.' TYPE 'E'. - CATCH /aws1/cx_texinvalidparameterex . + CATCH /aws1/cx_texinvalidparameterex. MESSAGE 'Request has non-valid parameters.' TYPE 'E'. - CATCH /aws1/cx_texinvalids3objectex . + CATCH /aws1/cx_texinvalids3objectex. MESSAGE 'Amazon S3 object is not valid.' TYPE 'E'. - CATCH /aws1/cx_texlimitexceededex . + CATCH /aws1/cx_texlimitexceededex. MESSAGE 'An Amazon Textract service limit was exceeded.' TYPE 'E'. - CATCH /aws1/cx_texprovthruputexcdex . + CATCH /aws1/cx_texprovthruputexcdex. MESSAGE 'Provisioned throughput exceeded limit.' TYPE 'E'. - CATCH /aws1/cx_texthrottlingex . + CATCH /aws1/cx_texthrottlingex. MESSAGE 'The request processing exceeded the limit.' TYPE 'E'. - CATCH /aws1/cx_texunsupporteddocex . + CATCH /aws1/cx_texunsupporteddocex. MESSAGE 'The document is not supported.' TYPE 'E'. ENDTRY. @@ -101,14 +96,21 @@ CLASS ZCL_AWS1_TEX_SCENARIO IMPLEMENTATION. DATA(lv_jobid) = lo_start_result->get_jobid( ). "Wait for job to complete." - oo_result = lo_tex->getdocumentanalysis( EXPORTING iv_jobid = lv_jobid ). " oo_result is returned for testing purposes. " + oo_result = lo_tex->getdocumentanalysis( iv_jobid = lv_jobid ). " oo_result is returned for testing purposes. " WHILE oo_result->get_jobstatus( ) <> 'SUCCEEDED'. IF sy-index = 10. EXIT. "Maximum 300 seconds." ENDIF. WAIT UP TO 30 SECONDS. - oo_result = lo_tex->getdocumentanalysis( EXPORTING iv_jobid = lv_jobid ). + oo_result = lo_tex->getdocumentanalysis( iv_jobid = lv_jobid ). ENDWHILE. + + DATA(lt_blocks) = oo_result->get_blocks( ). + LOOP AT lt_blocks INTO DATA(lo_block). + IF lo_block->get_text( ) = 'INGREDIENTS: POWDERED SUGAR* (CANE SUGAR,'. + MESSAGE 'Found text in the doc: ' && lo_block->get_text( ) TYPE 'I'. + ENDIF. + ENDLOOP. "snippet-end:[tex.abapv1.getting_started_with_tex] ENDMETHOD. ENDCLASS. diff --git a/sap-abap/services/textract/zcl_aws1_tex_scenario.clas.testclasses.abap b/sap-abap/services/textract/zcl_aws1_tex_scenario.clas.testclasses.abap index 4b6a0842755..bf9faa0f4c1 100644 --- a/sap-abap/services/textract/zcl_aws1_tex_scenario.clas.testclasses.abap +++ b/sap-abap/services/textract/zcl_aws1_tex_scenario.clas.testclasses.abap @@ -8,15 +8,15 @@ CLASS ltc_zcl_aws1_tex_scenario DEFINITION FOR TESTING DURATION SHORT RISK LEVEL PRIVATE SECTION. - CONSTANTS: cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. + CONSTANTS cv_pfl TYPE /aws1/rt_profile_id VALUE 'ZCODE_DEMO'. DATA ao_tex TYPE REF TO /aws1/if_tex. DATA ao_session TYPE REF TO /aws1/cl_rt_session_base. DATA ao_tex_scenario TYPE REF TO zcl_aws1_tex_scenario. DATA lv_found TYPE abap_bool VALUE abap_false. - METHODS: setup RAISING /aws1/cx_rt_generic ycx_aws1_mit_generic. - METHODS: getting_started_with_tex FOR TESTING. + METHODS setup RAISING /aws1/cx_rt_generic ycx_aws1_mit_generic. + METHODS getting_started_with_tex FOR TESTING. ENDCLASS. "ltc_Zcl_Aws1_Tex_Scenario @@ -31,28 +31,19 @@ CLASS ltc_zcl_aws1_tex_scenario IMPLEMENTATION. METHOD getting_started_with_tex. - DATA lv_found TYPE abap_bool VALUE abap_false. - DATA lo_output TYPE REF TO /aws1/cl_texgetdocalyresponse. - DATA lt_blocks TYPE /aws1/cl_texblock=>tt_blocklist. - DATA lo_block TYPE REF TO /aws1/cl_texblock. - "Using an image from the Public Amazon Berkeley Objects Dataset. CONSTANTS cv_bucket_name TYPE /aws1/s3_bucketname VALUE 'amazon-berkeley-objects'. CONSTANTS cv_key_name TYPE /aws1/s3_bucketname VALUE 'images/small/e0/e0feb1eb.jpg'. "Analyze document. - ao_tex_scenario->getting_started_with_tex( - EXPORTING + DATA(lo_output) = ao_tex_scenario->getting_started_with_tex( iv_s3object = cv_key_name - iv_s3bucket = cv_bucket_name - IMPORTING - oo_result = lo_output - ). + iv_s3bucket = cv_bucket_name ). "Validation check. - lv_found = abap_false. - lt_blocks = lo_output->get_blocks( ). - LOOP AT lt_blocks INTO lo_block. + DATA(lv_found) = abap_false. + DATA(lt_blocks) = lo_output->get_blocks( ). + LOOP AT lt_blocks INTO DATA(lo_block). IF lo_block->get_text( ) = 'INGREDIENTS: POWDERED SUGAR* (CANE SUGAR,'. lv_found = abap_true. ENDIF. @@ -60,8 +51,7 @@ CLASS ltc_zcl_aws1_tex_scenario IMPLEMENTATION. cl_abap_unit_assert=>assert_true( act = lv_found - msg = |Analyze document failed| - ). + msg = |Analyze document failed| ). ENDMETHOD. ENDCLASS. From 3015f1a99de7bcaa744460c44a58cb7378d1515b Mon Sep 17 00:00:00 2001 From: Scott Macdonald <57190223+scmacdon@users.noreply.github.com> Date: Mon, 29 Jan 2024 15:33:46 -0500 Subject: [PATCH 36/36] Java V2 Fixed a ticket and added ListBuckets example (#6010) fixed a ticket --- .doc_gen/metadata/s3_metadata.yaml | 9 +++++ .../java/com/example/s3/GetObjectUrl.java | 3 +- .../main/java/com/example/s3/ListBuckets.java | 39 +++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 javav2/example_code/s3/src/main/java/com/example/s3/ListBuckets.java diff --git a/.doc_gen/metadata/s3_metadata.yaml b/.doc_gen/metadata/s3_metadata.yaml index 2423a3b4a3e..dca7060c5a2 100644 --- a/.doc_gen/metadata/s3_metadata.yaml +++ b/.doc_gen/metadata/s3_metadata.yaml @@ -1971,6 +1971,15 @@ s3_ListBuckets: synopsis: list S3 buckets. category: languages: + Java: + versions: + - sdk_version: 2 + github: javav2/example_code/s3 + sdkguide: + excerpts: + - description: + snippet_tags: + - s3.java2.list.buckets.main .NET: versions: - sdk_version: 3 diff --git a/javav2/example_code/s3/src/main/java/com/example/s3/GetObjectUrl.java b/javav2/example_code/s3/src/main/java/com/example/s3/GetObjectUrl.java index 76faa750e6e..a729b8374d0 100644 --- a/javav2/example_code/s3/src/main/java/com/example/s3/GetObjectUrl.java +++ b/javav2/example_code/s3/src/main/java/com/example/s3/GetObjectUrl.java @@ -1,7 +1,6 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -//* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -*SPDX-License-Identifier:Apache-2.0*/ + package com.example.s3; // snippet-start:[s3.java2.getobjecturl.main] diff --git a/javav2/example_code/s3/src/main/java/com/example/s3/ListBuckets.java b/javav2/example_code/s3/src/main/java/com/example/s3/ListBuckets.java new file mode 100644 index 00000000000..591fc4eed56 --- /dev/null +++ b/javav2/example_code/s3/src/main/java/com/example/s3/ListBuckets.java @@ -0,0 +1,39 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.s3; + +// snippet-start:[s3.java2.list.buckets.main] +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.Bucket; +import software.amazon.awssdk.services.s3.model.ListBucketsResponse; +import java.util.List; + +/** + * Before running this Java V2 code example, set up your development + * environment, including your credentials. + * + * For more information, see the following documentation topic: + * + * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html + */ +public class ListBuckets { + public static void main(String[] args) { + Region region = Region.US_EAST_1; + S3Client s3 = S3Client.builder() + .region(region) + .build(); + + listAllBuckets(s3); + + } + public static void listAllBuckets(S3Client s3) { + ListBucketsResponse response = s3.listBuckets(); + List bucketList = response.buckets(); + for (Bucket bucket: bucketList) { + System.out.println("Bucket name "+bucket.name()); + } + } +} +// snippet-end:[s3.java2.list.buckets.main] \ No newline at end of file