diff --git a/backend/compact-connect/docs/devops/STAFF_USER_MFA_RECOVERY.md b/backend/compact-connect/docs/devops/STAFF_USER_MFA_RECOVERY.md index 65fa9453c..e9d36965f 100644 --- a/backend/compact-connect/docs/devops/STAFF_USER_MFA_RECOVERY.md +++ b/backend/compact-connect/docs/devops/STAFF_USER_MFA_RECOVERY.md @@ -41,9 +41,8 @@ Before beginning this procedure, ensure you have: ### Step 2: Archive the DynamoDB Record -In the DynamoDB console, if you change the partition key (pk) value of a existing DynamoDB item, it automatically deletes the old record with the old pk and creates a new one with the new pk, effectively archiving the user record. Perform the following steps: +In the DynamoDB console, perform the following steps: -1. **Create the Archived Record** - In the DynamoDB table, find the existing staff user record and select it to open the 'Edit item' view. - **Add a new field**: `archivedDate` = current date (yyyy-mm-dd format) - **Add a new field**: `archivedReason` = "MFA recovery - user lost access to MFA device" diff --git a/backend/compact-connect/lambdas/nodejs/package.json b/backend/compact-connect/lambdas/nodejs/package.json index 31c941213..54a7d170b 100644 --- a/backend/compact-connect/lambdas/nodejs/package.json +++ b/backend/compact-connect/lambdas/nodejs/package.json @@ -4,7 +4,7 @@ "type": "commonjs", "description": "NodeJS lambdas for CompactConnect", "resolutions": { - "fast-xml-parser": "5.7.0", + "fast-xml-parser": "5.7.3", "postcss": "8.5.10" }, "scripts": { @@ -45,9 +45,9 @@ }, "dependencies": { "@aws-lambda-powertools/logger": "^2.32.0", - "@aws-sdk/client-dynamodb": "^3.1029.0", - "@aws-sdk/client-s3": "^3.1029.0", - "@aws-sdk/client-sesv2": "^3.1029.0", + "@aws-sdk/client-dynamodb": "^3.1045.0", + "@aws-sdk/client-s3": "^3.1045.0", + "@aws-sdk/client-sesv2": "^3.1045.0", "@aws-sdk/util-dynamodb": "^3.996.2", "@csg-org/email-builder": "^0.0.13", "nodemailer": "^8.0.5", diff --git a/backend/compact-connect/lambdas/nodejs/yarn.lock b/backend/compact-connect/lambdas/nodejs/yarn.lock index 6e5212abb..adc98e9c0 100644 --- a/backend/compact-connect/lambdas/nodejs/yarn.lock +++ b/backend/compact-connect/lambdas/nodejs/yarn.lock @@ -85,177 +85,178 @@ "@aws-lambda-powertools/commons" "2.32.0" "@aws/lambda-invoke-store" "0.2.4" -"@aws-sdk/client-dynamodb@^3.1029.0": - version "3.1029.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1029.0.tgz#2123c4db1ce683e807c931b5a9910567c8ac1cb8" - integrity sha512-5y5BMzg2O8yHBmDfKVnqFCtg7JqpDeMVnRqtccuNZmuG9AjXQD3WeGqxaUPAYrnek3l5fIBGB0PRwoSuelguYw== +"@aws-sdk/client-dynamodb@^3.1045.0": + version "3.1045.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1045.0.tgz#d497a132068b081f6189626a86bea9cdf3d71df0" + integrity sha512-TxZmhpziFxWD3pdXGbuwntKOX5OkW14yvCITYsRz+QDM5EUL4cIygu2xRGHiKDvKmb3QUOA4yKetAQcIMLe2zw== dependencies: "@aws-crypto/sha256-browser" "5.2.0" "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/core" "^3.973.27" - "@aws-sdk/credential-provider-node" "^3.972.30" - "@aws-sdk/dynamodb-codec" "^3.972.28" - "@aws-sdk/middleware-endpoint-discovery" "^3.972.10" - "@aws-sdk/middleware-host-header" "^3.972.9" - "@aws-sdk/middleware-logger" "^3.972.9" - "@aws-sdk/middleware-recursion-detection" "^3.972.10" - "@aws-sdk/middleware-user-agent" "^3.972.29" - "@aws-sdk/region-config-resolver" "^3.972.11" - "@aws-sdk/types" "^3.973.7" - "@aws-sdk/util-endpoints" "^3.996.6" - "@aws-sdk/util-user-agent-browser" "^3.972.9" - "@aws-sdk/util-user-agent-node" "^3.973.15" - "@smithy/config-resolver" "^4.4.14" - "@smithy/core" "^3.23.14" - "@smithy/fetch-http-handler" "^5.3.16" - "@smithy/hash-node" "^4.2.13" - "@smithy/invalid-dependency" "^4.2.13" - "@smithy/middleware-content-length" "^4.2.13" - "@smithy/middleware-endpoint" "^4.4.29" - "@smithy/middleware-retry" "^4.5.0" - "@smithy/middleware-serde" "^4.2.17" - "@smithy/middleware-stack" "^4.2.13" - "@smithy/node-config-provider" "^4.3.13" - "@smithy/node-http-handler" "^4.5.2" - "@smithy/protocol-http" "^5.3.13" - "@smithy/smithy-client" "^4.12.9" - "@smithy/types" "^4.14.0" - "@smithy/url-parser" "^4.2.13" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/credential-provider-node" "^3.972.39" + "@aws-sdk/dynamodb-codec" "^3.973.8" + "@aws-sdk/middleware-endpoint-discovery" "^3.972.11" + "@aws-sdk/middleware-host-header" "^3.972.10" + "@aws-sdk/middleware-logger" "^3.972.10" + "@aws-sdk/middleware-recursion-detection" "^3.972.11" + "@aws-sdk/middleware-user-agent" "^3.972.38" + "@aws-sdk/region-config-resolver" "^3.972.13" + "@aws-sdk/types" "^3.973.8" + "@aws-sdk/util-endpoints" "^3.996.8" + "@aws-sdk/util-user-agent-browser" "^3.972.10" + "@aws-sdk/util-user-agent-node" "^3.973.24" + "@smithy/config-resolver" "^4.4.17" + "@smithy/core" "^3.23.17" + "@smithy/fetch-http-handler" "^5.3.17" + "@smithy/hash-node" "^4.2.14" + "@smithy/invalid-dependency" "^4.2.14" + "@smithy/middleware-content-length" "^4.2.14" + "@smithy/middleware-endpoint" "^4.4.32" + "@smithy/middleware-retry" "^4.5.7" + "@smithy/middleware-serde" "^4.2.20" + "@smithy/middleware-stack" "^4.2.14" + "@smithy/node-config-provider" "^4.3.14" + "@smithy/node-http-handler" "^4.6.1" + "@smithy/protocol-http" "^5.3.14" + "@smithy/smithy-client" "^4.12.13" + "@smithy/types" "^4.14.1" + "@smithy/url-parser" "^4.2.14" "@smithy/util-base64" "^4.3.2" "@smithy/util-body-length-browser" "^4.2.2" "@smithy/util-body-length-node" "^4.2.3" - "@smithy/util-defaults-mode-browser" "^4.3.45" - "@smithy/util-defaults-mode-node" "^4.2.49" - "@smithy/util-endpoints" "^3.3.4" - "@smithy/util-middleware" "^4.2.13" - "@smithy/util-retry" "^4.3.0" + "@smithy/util-defaults-mode-browser" "^4.3.49" + "@smithy/util-defaults-mode-node" "^4.2.54" + "@smithy/util-endpoints" "^3.4.2" + "@smithy/util-middleware" "^4.2.14" + "@smithy/util-retry" "^4.3.6" "@smithy/util-utf8" "^4.2.2" - "@smithy/util-waiter" "^4.2.15" + "@smithy/util-waiter" "^4.3.0" tslib "^2.6.2" -"@aws-sdk/client-s3@^3.1029.0": - version "3.1029.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.1029.0.tgz#7f4dd14b6fd7b0734735a3641f1261c37238e4ea" - integrity sha512-OuA8RZTxsAaHDcI25j2NGLMaYFI2WpJdDzK3uLmVBmaHwjQKQZOUDVVBcln8pNo3IgkY+HRSJhRR4/xlM//UyQ== +"@aws-sdk/client-s3@^3.1045.0": + version "3.1045.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.1045.0.tgz#d41b6d49f0554d3f67a41866dfa6de0e6b8f1a94" + integrity sha512-fsuO3Y6t+3Ro9Bsg41DKj4Sfy53CGSrhnMldNplWmG8Tx0UbYk+YDa4RD1hVlJpERw4JBmPkl0+J9qlxMh1pcA== dependencies: "@aws-crypto/sha1-browser" "5.2.0" "@aws-crypto/sha256-browser" "5.2.0" "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/core" "^3.973.27" - "@aws-sdk/credential-provider-node" "^3.972.30" - "@aws-sdk/middleware-bucket-endpoint" "^3.972.9" - "@aws-sdk/middleware-expect-continue" "^3.972.9" - "@aws-sdk/middleware-flexible-checksums" "^3.974.7" - "@aws-sdk/middleware-host-header" "^3.972.9" - "@aws-sdk/middleware-location-constraint" "^3.972.9" - "@aws-sdk/middleware-logger" "^3.972.9" - "@aws-sdk/middleware-recursion-detection" "^3.972.10" - "@aws-sdk/middleware-sdk-s3" "^3.972.28" - "@aws-sdk/middleware-ssec" "^3.972.9" - "@aws-sdk/middleware-user-agent" "^3.972.29" - "@aws-sdk/region-config-resolver" "^3.972.11" - "@aws-sdk/signature-v4-multi-region" "^3.996.16" - "@aws-sdk/types" "^3.973.7" - "@aws-sdk/util-endpoints" "^3.996.6" - "@aws-sdk/util-user-agent-browser" "^3.972.9" - "@aws-sdk/util-user-agent-node" "^3.973.15" - "@smithy/config-resolver" "^4.4.14" - "@smithy/core" "^3.23.14" - "@smithy/eventstream-serde-browser" "^4.2.13" - "@smithy/eventstream-serde-config-resolver" "^4.3.13" - "@smithy/eventstream-serde-node" "^4.2.13" - "@smithy/fetch-http-handler" "^5.3.16" - "@smithy/hash-blob-browser" "^4.2.14" - "@smithy/hash-node" "^4.2.13" - "@smithy/hash-stream-node" "^4.2.13" - "@smithy/invalid-dependency" "^4.2.13" - "@smithy/md5-js" "^4.2.13" - "@smithy/middleware-content-length" "^4.2.13" - "@smithy/middleware-endpoint" "^4.4.29" - "@smithy/middleware-retry" "^4.5.0" - "@smithy/middleware-serde" "^4.2.17" - "@smithy/middleware-stack" "^4.2.13" - "@smithy/node-config-provider" "^4.3.13" - "@smithy/node-http-handler" "^4.5.2" - "@smithy/protocol-http" "^5.3.13" - "@smithy/smithy-client" "^4.12.9" - "@smithy/types" "^4.14.0" - "@smithy/url-parser" "^4.2.13" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/credential-provider-node" "^3.972.39" + "@aws-sdk/middleware-bucket-endpoint" "^3.972.10" + "@aws-sdk/middleware-expect-continue" "^3.972.10" + "@aws-sdk/middleware-flexible-checksums" "^3.974.16" + "@aws-sdk/middleware-host-header" "^3.972.10" + "@aws-sdk/middleware-location-constraint" "^3.972.10" + "@aws-sdk/middleware-logger" "^3.972.10" + "@aws-sdk/middleware-recursion-detection" "^3.972.11" + "@aws-sdk/middleware-sdk-s3" "^3.972.37" + "@aws-sdk/middleware-ssec" "^3.972.10" + "@aws-sdk/middleware-user-agent" "^3.972.38" + "@aws-sdk/region-config-resolver" "^3.972.13" + "@aws-sdk/signature-v4-multi-region" "^3.996.25" + "@aws-sdk/types" "^3.973.8" + "@aws-sdk/util-endpoints" "^3.996.8" + "@aws-sdk/util-user-agent-browser" "^3.972.10" + "@aws-sdk/util-user-agent-node" "^3.973.24" + "@smithy/config-resolver" "^4.4.17" + "@smithy/core" "^3.23.17" + "@smithy/eventstream-serde-browser" "^4.2.14" + "@smithy/eventstream-serde-config-resolver" "^4.3.14" + "@smithy/eventstream-serde-node" "^4.2.14" + "@smithy/fetch-http-handler" "^5.3.17" + "@smithy/hash-blob-browser" "^4.2.15" + "@smithy/hash-node" "^4.2.14" + "@smithy/hash-stream-node" "^4.2.14" + "@smithy/invalid-dependency" "^4.2.14" + "@smithy/md5-js" "^4.2.14" + "@smithy/middleware-content-length" "^4.2.14" + "@smithy/middleware-endpoint" "^4.4.32" + "@smithy/middleware-retry" "^4.5.7" + "@smithy/middleware-serde" "^4.2.20" + "@smithy/middleware-stack" "^4.2.14" + "@smithy/node-config-provider" "^4.3.14" + "@smithy/node-http-handler" "^4.6.1" + "@smithy/protocol-http" "^5.3.14" + "@smithy/smithy-client" "^4.12.13" + "@smithy/types" "^4.14.1" + "@smithy/url-parser" "^4.2.14" "@smithy/util-base64" "^4.3.2" "@smithy/util-body-length-browser" "^4.2.2" "@smithy/util-body-length-node" "^4.2.3" - "@smithy/util-defaults-mode-browser" "^4.3.45" - "@smithy/util-defaults-mode-node" "^4.2.49" - "@smithy/util-endpoints" "^3.3.4" - "@smithy/util-middleware" "^4.2.13" - "@smithy/util-retry" "^4.3.0" - "@smithy/util-stream" "^4.5.22" + "@smithy/util-defaults-mode-browser" "^4.3.49" + "@smithy/util-defaults-mode-node" "^4.2.54" + "@smithy/util-endpoints" "^3.4.2" + "@smithy/util-middleware" "^4.2.14" + "@smithy/util-retry" "^4.3.6" + "@smithy/util-stream" "^4.5.25" "@smithy/util-utf8" "^4.2.2" - "@smithy/util-waiter" "^4.2.15" + "@smithy/util-waiter" "^4.3.0" tslib "^2.6.2" -"@aws-sdk/client-sesv2@^3.1029.0": - version "3.1029.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sesv2/-/client-sesv2-3.1029.0.tgz#f3a3ce8f41720a2041325eef06e620b4f4d7e1e3" - integrity sha512-ZL2E13IaLQjevcL9nHqT7Jf8EeYfDhgwNyuOh1bp/2ECga+0BzJaHKiASZdvBCZHV+cCDqH3SiGKePUMOxakYA== +"@aws-sdk/client-sesv2@^3.1045.0": + version "3.1045.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sesv2/-/client-sesv2-3.1045.0.tgz#5793588298dd648cf0d5f3baddc8e9bea4e0c9dd" + integrity sha512-Ae6oKWTod06687mIdKPnHPG5tolx/g68tqIbySMoWCs56OmRqn+7JiS3pOlpQeqjhbJlukfrXbsTMgZcXO9cSQ== dependencies: "@aws-crypto/sha256-browser" "5.2.0" "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/core" "^3.973.27" - "@aws-sdk/credential-provider-node" "^3.972.30" - "@aws-sdk/middleware-host-header" "^3.972.9" - "@aws-sdk/middleware-logger" "^3.972.9" - "@aws-sdk/middleware-recursion-detection" "^3.972.10" - "@aws-sdk/middleware-user-agent" "^3.972.29" - "@aws-sdk/region-config-resolver" "^3.972.11" - "@aws-sdk/signature-v4-multi-region" "^3.996.16" - "@aws-sdk/types" "^3.973.7" - "@aws-sdk/util-endpoints" "^3.996.6" - "@aws-sdk/util-user-agent-browser" "^3.972.9" - "@aws-sdk/util-user-agent-node" "^3.973.15" - "@smithy/config-resolver" "^4.4.14" - "@smithy/core" "^3.23.14" - "@smithy/fetch-http-handler" "^5.3.16" - "@smithy/hash-node" "^4.2.13" - "@smithy/invalid-dependency" "^4.2.13" - "@smithy/middleware-content-length" "^4.2.13" - "@smithy/middleware-endpoint" "^4.4.29" - "@smithy/middleware-retry" "^4.5.0" - "@smithy/middleware-serde" "^4.2.17" - "@smithy/middleware-stack" "^4.2.13" - "@smithy/node-config-provider" "^4.3.13" - "@smithy/node-http-handler" "^4.5.2" - "@smithy/protocol-http" "^5.3.13" - "@smithy/smithy-client" "^4.12.9" - "@smithy/types" "^4.14.0" - "@smithy/url-parser" "^4.2.13" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/credential-provider-node" "^3.972.39" + "@aws-sdk/middleware-host-header" "^3.972.10" + "@aws-sdk/middleware-logger" "^3.972.10" + "@aws-sdk/middleware-recursion-detection" "^3.972.11" + "@aws-sdk/middleware-user-agent" "^3.972.38" + "@aws-sdk/region-config-resolver" "^3.972.13" + "@aws-sdk/signature-v4-multi-region" "^3.996.25" + "@aws-sdk/types" "^3.973.8" + "@aws-sdk/util-endpoints" "^3.996.8" + "@aws-sdk/util-user-agent-browser" "^3.972.10" + "@aws-sdk/util-user-agent-node" "^3.973.24" + "@smithy/config-resolver" "^4.4.17" + "@smithy/core" "^3.23.17" + "@smithy/fetch-http-handler" "^5.3.17" + "@smithy/hash-node" "^4.2.14" + "@smithy/invalid-dependency" "^4.2.14" + "@smithy/middleware-content-length" "^4.2.14" + "@smithy/middleware-endpoint" "^4.4.32" + "@smithy/middleware-retry" "^4.5.7" + "@smithy/middleware-serde" "^4.2.20" + "@smithy/middleware-stack" "^4.2.14" + "@smithy/node-config-provider" "^4.3.14" + "@smithy/node-http-handler" "^4.6.1" + "@smithy/protocol-http" "^5.3.14" + "@smithy/smithy-client" "^4.12.13" + "@smithy/types" "^4.14.1" + "@smithy/url-parser" "^4.2.14" "@smithy/util-base64" "^4.3.2" "@smithy/util-body-length-browser" "^4.2.2" "@smithy/util-body-length-node" "^4.2.3" - "@smithy/util-defaults-mode-browser" "^4.3.45" - "@smithy/util-defaults-mode-node" "^4.2.49" - "@smithy/util-endpoints" "^3.3.4" - "@smithy/util-middleware" "^4.2.13" - "@smithy/util-retry" "^4.3.0" + "@smithy/util-defaults-mode-browser" "^4.3.49" + "@smithy/util-defaults-mode-node" "^4.2.54" + "@smithy/util-endpoints" "^3.4.2" + "@smithy/util-middleware" "^4.2.14" + "@smithy/util-retry" "^4.3.6" "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@aws-sdk/core@^3.973.27", "@aws-sdk/core@^3.974.1": - version "3.974.1" - resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.974.1.tgz#69e812e056501060a44bb1e844e66a1932c44c83" - integrity sha512-gy/gffKz0zaHDaqRiLCdIvgHmaAL/HXuAtMcBP7euYSFx4BsbsdlfmUBJag+Gqe62z6/XuloKyQyaiH+kS3Vrg== +"@aws-sdk/core@^3.974.8": + version "3.974.8" + resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.974.8.tgz#cdd51195a31322f1e429e66919eb18da8944c081" + integrity sha512-njR2qoG6ZuB0kvAS2FyICsFZJ6gmCcf2X/7JcD14sUvGDm26wiZ5BrA6LOiUxKFEF+IVe7kdroxyE00YlkiYsw== dependencies: "@aws-sdk/types" "^3.973.8" - "@aws-sdk/xml-builder" "^3.972.18" - "@smithy/core" "^3.23.15" + "@aws-sdk/xml-builder" "^3.972.22" + "@smithy/core" "^3.23.17" "@smithy/node-config-provider" "^4.3.14" "@smithy/property-provider" "^4.2.14" "@smithy/protocol-http" "^5.3.14" "@smithy/signature-v4" "^5.3.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" "@smithy/util-base64" "^4.3.2" "@smithy/util-middleware" "^4.2.14" + "@smithy/util-retry" "^4.3.6" "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" @@ -267,46 +268,46 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-env@^3.972.27": - version "3.972.27" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.27.tgz#296091d01fbad87b56730e4af6c847b5951490a9" - integrity sha512-xfUt2CUZDC+Tf16A6roD1b4pk/nrXdkoLY3TEhv198AXDtBo5xUJP1zd0e8SmuKLN4PpIBX96OizZbmMlcI6oQ== +"@aws-sdk/credential-provider-env@^3.972.34": + version "3.972.34" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.34.tgz#9d420adf02e7604094a641ae613a353aa86e1b83" + integrity sha512-XT0jtf8Fw9JE6ppsQeoNnZRiG+jqRixMT1v1ZR17G60UvVdsQmTG8nbEyHuEPfMxDXEhfdARaM/XiEhca4lGHQ== dependencies: - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/types" "^3.973.8" "@smithy/property-provider" "^4.2.14" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-http@^3.972.29": - version "3.972.29" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.29.tgz#31c4b731bd3200155a03b58e5e6e2fabd2793adf" - integrity sha512-hjNeYb6oLyHgMihra83ie0J/T2y9om3cy1qC90h9DRgvYXEoN4BCFf8bHguZjKhXunnv7YkmZRuYL5Mkk77eCA== +"@aws-sdk/credential-provider-http@^3.972.36": + version "3.972.36" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.36.tgz#842268559da2ffc5855cde1e90e7302d53639c08" + integrity sha512-DPoGWfy7J7RKxvbf5kOKIGQkD2ek3dbKgzKIGrnLuvZBz5myU+Im/H6pmc14QcnFbqHMqxvtWSgRDSJW3qXLQg== dependencies: - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/types" "^3.973.8" "@smithy/fetch-http-handler" "^5.3.17" - "@smithy/node-http-handler" "^4.5.3" + "@smithy/node-http-handler" "^4.6.1" "@smithy/property-provider" "^4.2.14" "@smithy/protocol-http" "^5.3.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" - "@smithy/util-stream" "^4.5.23" + "@smithy/util-stream" "^4.5.25" tslib "^2.6.2" -"@aws-sdk/credential-provider-ini@^3.972.31": - version "3.972.31" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.31.tgz#e6fe3aa4952edb730007545fc3d944362a111edb" - integrity sha512-PuQ7e8WYzAPpzvFcajxf8c0LqSzakVHVlKw8M0oubk8Kf347YOCCqT1seQrHs5AdZuIh2RD9LX4O+Xa5ImEBfQ== - dependencies: - "@aws-sdk/core" "^3.974.1" - "@aws-sdk/credential-provider-env" "^3.972.27" - "@aws-sdk/credential-provider-http" "^3.972.29" - "@aws-sdk/credential-provider-login" "^3.972.31" - "@aws-sdk/credential-provider-process" "^3.972.27" - "@aws-sdk/credential-provider-sso" "^3.972.31" - "@aws-sdk/credential-provider-web-identity" "^3.972.31" - "@aws-sdk/nested-clients" "^3.996.21" +"@aws-sdk/credential-provider-ini@^3.972.38": + version "3.972.38" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.38.tgz#e20955fdfe4a88149b20dc7e25a517542e1dfd9f" + integrity sha512-oDzUBu2MGJFgoar05sPMCwSrhw44ASyccrHzj66vO69OZqi7I6hZZxXfuPLC8OCzW7C+sU+bI73XHij41yekgQ== + dependencies: + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/credential-provider-env" "^3.972.34" + "@aws-sdk/credential-provider-http" "^3.972.36" + "@aws-sdk/credential-provider-login" "^3.972.38" + "@aws-sdk/credential-provider-process" "^3.972.34" + "@aws-sdk/credential-provider-sso" "^3.972.38" + "@aws-sdk/credential-provider-web-identity" "^3.972.38" + "@aws-sdk/nested-clients" "^3.997.6" "@aws-sdk/types" "^3.973.8" "@smithy/credential-provider-imds" "^4.2.14" "@smithy/property-provider" "^4.2.14" @@ -314,13 +315,13 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-login@^3.972.31": - version "3.972.31" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.31.tgz#7a71981679dc44e5d13862a171d5ec9d2bf6e80a" - integrity sha512-bBmWDmtSpmLOZR6a0kmowBcVL1hiL8Vlap/RXeMpFd7JbWl87YcwqL6T9LH/0oBVEZXu1dUZAtojgSuZgMO5xw== +"@aws-sdk/credential-provider-login@^3.972.38": + version "3.972.38" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.38.tgz#278437712c02a3ad1785f70c93b4f591cb3f6491" + integrity sha512-g1NosS8qe4OF++G2UFCM5ovSkgipC7YYor5KCWatG0UoMSO5YFj9C8muePlyVmOBV/WTI16Jo3/s1NUo/o1Bww== dependencies: - "@aws-sdk/core" "^3.974.1" - "@aws-sdk/nested-clients" "^3.996.21" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/nested-clients" "^3.997.6" "@aws-sdk/types" "^3.973.8" "@smithy/property-provider" "^4.2.14" "@smithy/protocol-http" "^5.3.14" @@ -328,17 +329,17 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-node@^3.972.30": - version "3.972.32" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.32.tgz#28466df983be1a6d9de50f431e7e8021af18ceba" - integrity sha512-9aj0x9hGYUondBZSD0XkksAdHhOKttFw4BWpLCeggeg40qSJxGrAP++g0GCm0VqWc1WtC/NRFiAVzPCy56vmog== - dependencies: - "@aws-sdk/credential-provider-env" "^3.972.27" - "@aws-sdk/credential-provider-http" "^3.972.29" - "@aws-sdk/credential-provider-ini" "^3.972.31" - "@aws-sdk/credential-provider-process" "^3.972.27" - "@aws-sdk/credential-provider-sso" "^3.972.31" - "@aws-sdk/credential-provider-web-identity" "^3.972.31" +"@aws-sdk/credential-provider-node@^3.972.39": + version "3.972.39" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.39.tgz#71f87848b7615dda4f31a57b113be9666e4bbd1a" + integrity sha512-HEswDQyxUtadoZ/bJsPPENHg7R0Lzym5LuMksJeHvqhCOpP+rtkDLKI4/ZChH4w3cf5kG8n6bZuI8PzajoiqMg== + dependencies: + "@aws-sdk/credential-provider-env" "^3.972.34" + "@aws-sdk/credential-provider-http" "^3.972.36" + "@aws-sdk/credential-provider-ini" "^3.972.38" + "@aws-sdk/credential-provider-process" "^3.972.34" + "@aws-sdk/credential-provider-sso" "^3.972.38" + "@aws-sdk/credential-provider-web-identity" "^3.972.38" "@aws-sdk/types" "^3.973.8" "@smithy/credential-provider-imds" "^4.2.14" "@smithy/property-provider" "^4.2.14" @@ -346,52 +347,52 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-process@^3.972.27": - version "3.972.27" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.27.tgz#24ae20a1af5c0ab63872f3672696889694c7fa2e" - integrity sha512-1CZvfb1WzudWWIFAVQkd1OI/T1RxPcSvNWzNsb2BMBVsBJzBtB8dV5f2nymHVU4UqwxipdVt/DAbgdDRf33JDg== +"@aws-sdk/credential-provider-process@^3.972.34": + version "3.972.34" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.34.tgz#c964275be1a528ac73ade6d98c309fb6b7cdfb68" + integrity sha512-T3IFs4EVmVi1dVN5RciFnklCANSzvrQd/VuHY9ThHSQmYkTogjcGkoJEr+oNUPQZnso52183088NqysMPji1/Q== dependencies: - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/types" "^3.973.8" "@smithy/property-provider" "^4.2.14" "@smithy/shared-ini-file-loader" "^4.4.9" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-sso@^3.972.31": - version "3.972.31" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.31.tgz#6a5506d65397323740f930ba000aab7622f9be71" - integrity sha512-x8Mx18S48XMl9bEEpYwmXDTvjWGPIfDadReN37Lc099/DUrlL4Zs9T9rwwggo6DkKS1aev6v+MTUx7JTa87TZQ== +"@aws-sdk/credential-provider-sso@^3.972.38": + version "3.972.38" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.38.tgz#ec754bfecb2426a3307e19ef7e6c6b6438a327c6" + integrity sha512-5ZxG+t0+3Q3QPh8KEjX6syskhgNf7I0MN7oGioTf6Lm1NTjfP7sIcYGNsthXC2qR8vcD3edNZwCr2ovfSSWuRA== dependencies: - "@aws-sdk/core" "^3.974.1" - "@aws-sdk/nested-clients" "^3.996.21" - "@aws-sdk/token-providers" "3.1032.0" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/nested-clients" "^3.997.6" + "@aws-sdk/token-providers" "3.1041.0" "@aws-sdk/types" "^3.973.8" "@smithy/property-provider" "^4.2.14" "@smithy/shared-ini-file-loader" "^4.4.9" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-web-identity@^3.972.31": - version "3.972.31" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.31.tgz#e431eceb97dfc53ca4c890bf87f909fa8550c246" - integrity sha512-zfuNMIkGfjYsHis9qytYf74Bcmq6Ji9Xwf4w53baRCI/b2otTwZv3SW1uRiJ5Di7999QzRGhHZ96+eUeo3gSOA== +"@aws-sdk/credential-provider-web-identity@^3.972.38": + version "3.972.38" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.38.tgz#149951ef6e12db5292118e8ed5d95133c24ad719" + integrity sha512-lYHFF30DGI20jZcYX8cm6Ns0V7f1dDN6g/MBDLTyD/5iw+bXs3yBr2iAiHDkx4RFU5JgsnZvCHYKiRVPRdmOgw== dependencies: - "@aws-sdk/core" "^3.974.1" - "@aws-sdk/nested-clients" "^3.996.21" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/nested-clients" "^3.997.6" "@aws-sdk/types" "^3.973.8" "@smithy/property-provider" "^4.2.14" "@smithy/shared-ini-file-loader" "^4.4.9" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/dynamodb-codec@^3.972.28": - version "3.973.1" - resolved "https://registry.yarnpkg.com/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.973.1.tgz#1adf2ee3887b5ca0fe07d232e349c60fac0a78bc" - integrity sha512-BuxJyHW+fnuGLFZ84z5txzlfKXLVbf3hmWH4wQ9q5a/P6O5slNg6j2eUE2kQMYWt3A3PheUR4tgRBUC7j9i/nQ== +"@aws-sdk/dynamodb-codec@^3.973.8": + version "3.973.8" + resolved "https://registry.yarnpkg.com/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.973.8.tgz#e2f0a451eef83a0163e73625fdf7fd1e5b8c110d" + integrity sha512-dYQ/cQqHZd23hcl8oEGwPphTqyGnmvf2HrVmz4J90Q5Bv89oJjlwcBcifiiTvApqsVpx7Pr0IebMpkYwWJvZlQ== dependencies: - "@aws-sdk/core" "^3.974.1" - "@smithy/core" "^3.23.15" + "@aws-sdk/core" "^3.974.8" + "@smithy/core" "^3.23.17" "@smithy/types" "^4.14.1" "@smithy/util-base64" "^4.3.2" tslib "^2.6.2" @@ -404,7 +405,7 @@ mnemonist "0.38.3" tslib "^2.6.2" -"@aws-sdk/middleware-bucket-endpoint@^3.972.9": +"@aws-sdk/middleware-bucket-endpoint@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.10.tgz#d26aa88b441d6d1b6e9275ffdc61e0fbfb55a513" integrity sha512-Vbc2frZH7wXlMNd+ZZSXUEs/l1Sv8Jj4zUnIfwrYF5lwaLdXHZ9xx4U3rjUcaye3HRhFVc+E5DbBxpRAbB16BA== @@ -417,7 +418,7 @@ "@smithy/util-config-provider" "^4.2.2" tslib "^2.6.2" -"@aws-sdk/middleware-endpoint-discovery@^3.972.10": +"@aws-sdk/middleware-endpoint-discovery@^3.972.11": version "3.972.11" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.972.11.tgz#6f1e38f4638272e01b8a32cc91853e79a650db8a" integrity sha512-vXARCZVFQHdsd6qPPZyC/hh+5x2XsCYKqUQDCqnUlpGpChMpDojOOacQWdLJ+FFXKN8X3cmLOGrtgx/zysCKqQ== @@ -429,7 +430,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-expect-continue@^3.972.9": +"@aws-sdk/middleware-expect-continue@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.10.tgz#b685287951156a5d093cfdd37364894c6a8c966c" integrity sha512-2Yn0f1Qiq/DjxYR3wfI3LokXnjOhFM7Ssn4LTdFDIxRMCE6I32MAsVnhPX1cUZsuVA9tiZtwwhlSLAtFGxAZlQ== @@ -439,15 +440,15 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-flexible-checksums@^3.974.7": - version "3.974.9" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.9.tgz#28e3e6c51a6ebdcdbd09725e910a6cb67fbc51f4" - integrity sha512-ye6xVuMEQ5NCT+yQOryGYsuCXnOwu7iGFGzV+qpXZOWtqXIAAaFostapxj6RCubw36rekVwmdB2lcspFuyNfYQ== +"@aws-sdk/middleware-flexible-checksums@^3.974.16": + version "3.974.16" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.16.tgz#89b78cb0ad389aba7d12d060f46017e1fa3784a9" + integrity sha512-6ru8doI0/XzszqLIPXf0E/V7HhAw1Pu94010XCKYtBUfD0LxF0BuOzrUf8OQGR6j2o6wgKTHUniOmndQycHwCA== dependencies: "@aws-crypto/crc32" "5.2.0" "@aws-crypto/crc32c" "5.2.0" "@aws-crypto/util" "5.2.0" - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/crc64-nvme" "^3.972.7" "@aws-sdk/types" "^3.973.8" "@smithy/is-array-buffer" "^4.2.2" @@ -455,11 +456,11 @@ "@smithy/protocol-http" "^5.3.14" "@smithy/types" "^4.14.1" "@smithy/util-middleware" "^4.2.14" - "@smithy/util-stream" "^4.5.23" + "@smithy/util-stream" "^4.5.25" "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@aws-sdk/middleware-host-header@^3.972.10", "@aws-sdk/middleware-host-header@^3.972.9": +"@aws-sdk/middleware-host-header@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.10.tgz#e63b91959ce46948d789582351b2a44c4876e924" integrity sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg== @@ -469,7 +470,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-location-constraint@^3.972.9": +"@aws-sdk/middleware-location-constraint@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.10.tgz#5265ea472f735c50b016bb5d1b46c7a616653733" integrity sha512-rI3NZvJcEvjoD0+0PI0iUAwlPw2IlSlhyvgBK/3WkKJQE/YiKFedd9dMN2lVacdNxPNhxL/jzQaKQdrGtQagjQ== @@ -478,7 +479,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-logger@^3.972.10", "@aws-sdk/middleware-logger@^3.972.9": +"@aws-sdk/middleware-logger@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.972.10.tgz#d92b3374dcaddd523930bdff441207946343c270" integrity sha512-OOuGvvz1Dm20SjZo5oEBePFqxt5nf8AwkNDSyUHvD9/bfNASmstcYxFAHUowy4n6Io7mWUZ04JURZwSBvyQanQ== @@ -487,7 +488,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-recursion-detection@^3.972.10", "@aws-sdk/middleware-recursion-detection@^3.972.11": +"@aws-sdk/middleware-recursion-detection@^3.972.11": version "3.972.11" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.11.tgz#5659982a34fa58c69cbd358c2987c32aefd2bd91" integrity sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ== @@ -498,27 +499,27 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-sdk-s3@^3.972.28", "@aws-sdk/middleware-sdk-s3@^3.972.30": - version "3.972.30" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.30.tgz#cd54439bd298cf16d7aece7bf7afeccc03547b27" - integrity sha512-hoQRxjJu4tt3gEOQin21rJKotClJC+x7AmCh9ylRct1DJeaNI/BRlFxMbuhJe54bG6xANPagSs0my8K30QyV9g== +"@aws-sdk/middleware-sdk-s3@^3.972.37": + version "3.972.37" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.37.tgz#82ef4953cddd3373d2942d07a5d2baf443bbf3ea" + integrity sha512-Km7M+i8DrLArVzrid1gfxeGhYHBd3uxvE77g0s5a52zPSVosxzQBnJ0gwWb6NIp/DOk8gsBMhi7V+cpJG0ndTA== dependencies: - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/types" "^3.973.8" "@aws-sdk/util-arn-parser" "^3.972.3" - "@smithy/core" "^3.23.15" + "@smithy/core" "^3.23.17" "@smithy/node-config-provider" "^4.3.14" "@smithy/protocol-http" "^5.3.14" "@smithy/signature-v4" "^5.3.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" "@smithy/util-config-provider" "^4.2.2" "@smithy/util-middleware" "^4.2.14" - "@smithy/util-stream" "^4.5.23" + "@smithy/util-stream" "^4.5.25" "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@aws-sdk/middleware-ssec@^3.972.9": +"@aws-sdk/middleware-ssec@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.10.tgz#46b5c030c0116f51110e18042ad3cf863ab5c81c" integrity sha512-Gli9A0u8EVVb+5bFDGS/QbSVg28w/wpEidg1ggVcSj65BDTdGR6punsOcVjqdiu1i42WHWo51MCvARPIIz9juw== @@ -527,101 +528,102 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-user-agent@^3.972.29", "@aws-sdk/middleware-user-agent@^3.972.31": - version "3.972.31" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.31.tgz#691b8cbc8c96d70993a8cf52035e503f9e607e03" - integrity sha512-L+hXN2HDomlIsWSHW5DVD7ppccCeRnlHXZ5uHG34ePTjF5bm0I1fmrJLbUGiW97xRXWryit5cjdP4Sx2FwiGog== +"@aws-sdk/middleware-user-agent@^3.972.38": + version "3.972.38" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.38.tgz#626d9a2499f5a6398a4db917abeeaac14b54c6cb" + integrity sha512-iz+B29TXcAZsJpwB+AwG/TTGA5l/VnmMZ2UxtiySOZjI6gCdmviXPwdgzcmuazMy16rXoPY4mYCGe7zdNKfx5A== dependencies: - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/types" "^3.973.8" - "@aws-sdk/util-endpoints" "^3.996.7" - "@smithy/core" "^3.23.15" + "@aws-sdk/util-endpoints" "^3.996.8" + "@smithy/core" "^3.23.17" "@smithy/protocol-http" "^5.3.14" "@smithy/types" "^4.14.1" - "@smithy/util-retry" "^4.3.2" + "@smithy/util-retry" "^4.3.6" tslib "^2.6.2" -"@aws-sdk/nested-clients@^3.996.21": - version "3.996.21" - resolved "https://registry.yarnpkg.com/@aws-sdk/nested-clients/-/nested-clients-3.996.21.tgz#60148799e399fc002bc6b2b3e09d0024609ab153" - integrity sha512-Me3d/ua2lb2G0bQfFmvCeQQp3+nN6GSPqMxDmi/IQlQ8CrlpQ5C0JJHpz2AnOUkEFI0lBNrAL3Vnt29l44ndkA== +"@aws-sdk/nested-clients@^3.997.6": + version "3.997.6" + resolved "https://registry.yarnpkg.com/@aws-sdk/nested-clients/-/nested-clients-3.997.6.tgz#17433cfac2160ec620a14cbff9d2b33675712cae" + integrity sha512-WBDnqatJl+kGObpfmfSxqnXeYTu3Me8wx8WCtvoxX3pfWrrTv8I4WTMSSs7PZqcRcVh8WeUKMgGFjMG+52SR1w== dependencies: "@aws-crypto/sha256-browser" "5.2.0" "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/middleware-host-header" "^3.972.10" "@aws-sdk/middleware-logger" "^3.972.10" "@aws-sdk/middleware-recursion-detection" "^3.972.11" - "@aws-sdk/middleware-user-agent" "^3.972.31" - "@aws-sdk/region-config-resolver" "^3.972.12" + "@aws-sdk/middleware-user-agent" "^3.972.38" + "@aws-sdk/region-config-resolver" "^3.972.13" + "@aws-sdk/signature-v4-multi-region" "^3.996.25" "@aws-sdk/types" "^3.973.8" - "@aws-sdk/util-endpoints" "^3.996.7" + "@aws-sdk/util-endpoints" "^3.996.8" "@aws-sdk/util-user-agent-browser" "^3.972.10" - "@aws-sdk/util-user-agent-node" "^3.973.17" - "@smithy/config-resolver" "^4.4.16" - "@smithy/core" "^3.23.15" + "@aws-sdk/util-user-agent-node" "^3.973.24" + "@smithy/config-resolver" "^4.4.17" + "@smithy/core" "^3.23.17" "@smithy/fetch-http-handler" "^5.3.17" "@smithy/hash-node" "^4.2.14" "@smithy/invalid-dependency" "^4.2.14" "@smithy/middleware-content-length" "^4.2.14" - "@smithy/middleware-endpoint" "^4.4.30" - "@smithy/middleware-retry" "^4.5.3" - "@smithy/middleware-serde" "^4.2.18" + "@smithy/middleware-endpoint" "^4.4.32" + "@smithy/middleware-retry" "^4.5.7" + "@smithy/middleware-serde" "^4.2.20" "@smithy/middleware-stack" "^4.2.14" "@smithy/node-config-provider" "^4.3.14" - "@smithy/node-http-handler" "^4.5.3" + "@smithy/node-http-handler" "^4.6.1" "@smithy/protocol-http" "^5.3.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" "@smithy/url-parser" "^4.2.14" "@smithy/util-base64" "^4.3.2" "@smithy/util-body-length-browser" "^4.2.2" "@smithy/util-body-length-node" "^4.2.3" - "@smithy/util-defaults-mode-browser" "^4.3.47" - "@smithy/util-defaults-mode-node" "^4.2.52" - "@smithy/util-endpoints" "^3.4.1" + "@smithy/util-defaults-mode-browser" "^4.3.49" + "@smithy/util-defaults-mode-node" "^4.2.54" + "@smithy/util-endpoints" "^3.4.2" "@smithy/util-middleware" "^4.2.14" - "@smithy/util-retry" "^4.3.2" + "@smithy/util-retry" "^4.3.6" "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@aws-sdk/region-config-resolver@^3.972.11", "@aws-sdk/region-config-resolver@^3.972.12": - version "3.972.12" - resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.12.tgz#4156ce4fd065719cd87bdf376c23e3e0b97a6408" - integrity sha512-QQI43Mxd53nBij0pm8HXC+t4IOC6gnhhZfzxE0OATQyO6QfPV4e+aTIRRuAJKA6Nig/cR8eLwPryqYTX9ZrjAQ== +"@aws-sdk/region-config-resolver@^3.972.13": + version "3.972.13" + resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.13.tgz#bd32748c2d41b62be838fec76c4b87d4370939c6" + integrity sha512-CvJ2ZIjK/jVD/lbOpowBVElJyC1YxLTIJ13yM0AEo0t2v7swOzGjSA6lJGH+DwZXQhcjUjoYwc8bVYCX5MDr1A== dependencies: "@aws-sdk/types" "^3.973.8" - "@smithy/config-resolver" "^4.4.16" + "@smithy/config-resolver" "^4.4.17" "@smithy/node-config-provider" "^4.3.14" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/signature-v4-multi-region@^3.996.16": - version "3.996.18" - resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.18.tgz#9043a9060aa41d27fa4a8b795b796bd7b6628c73" - integrity sha512-4KT8UXRmvNAP5zKq9UI1MIwbnmSChZncBt89RKu/skMqZSSWGkBZTAJsZ+no+txfmF3kVaUFv31CTBZkQ5BJpQ== +"@aws-sdk/signature-v4-multi-region@^3.996.25": + version "3.996.25" + resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.25.tgz#b50651b7e4f9c82482416caa9953ad17645d4a2d" + integrity sha512-+CMIt3e1VzlklAECmG+DtP1sV8iKq25FuA0OKpnJ4KA0kxUtd7CgClY7/RU6VzJBQwbN4EJ9Ue6plvqx1qGadw== dependencies: - "@aws-sdk/middleware-sdk-s3" "^3.972.30" + "@aws-sdk/middleware-sdk-s3" "^3.972.37" "@aws-sdk/types" "^3.973.8" "@smithy/protocol-http" "^5.3.14" "@smithy/signature-v4" "^5.3.14" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/token-providers@3.1032.0": - version "3.1032.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.1032.0.tgz#fda2fa76aedbebbc525a0b2ce6bff1e0ed638b3f" - integrity sha512-n+PU8Z+gll7p3wDrH+Wo6fkt8sPrVnq30YYM6Ryga95oJlEneNMEbDHj0iqjMX3V7gaGdJo/hJWyPo4lscP+mA== +"@aws-sdk/token-providers@3.1041.0": + version "3.1041.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.1041.0.tgz#f3f068010780fc85fc4a7faa6a080cfb8afd73a4" + integrity sha512-Th7kPI6YPtvJUcdznooXJMy+9rQWjmEF81LxaJssngBzuysK4a/x+l8kjm1zb7nYsUPbndnBdUnwng/3PLvtGw== dependencies: - "@aws-sdk/core" "^3.974.1" - "@aws-sdk/nested-clients" "^3.996.21" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/nested-clients" "^3.997.6" "@aws-sdk/types" "^3.973.8" "@smithy/property-provider" "^4.2.14" "@smithy/shared-ini-file-loader" "^4.4.9" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/types@^3.222.0", "@aws-sdk/types@^3.973.7", "@aws-sdk/types@^3.973.8": +"@aws-sdk/types@^3.222.0", "@aws-sdk/types@^3.973.8": version "3.973.8" resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.973.8.tgz#7352cb74a5f8bae1218eee63e714cf94302911c5" integrity sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw== @@ -643,15 +645,15 @@ dependencies: tslib "^2.6.2" -"@aws-sdk/util-endpoints@^3.996.6", "@aws-sdk/util-endpoints@^3.996.7": - version "3.996.7" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.996.7.tgz#febfca74a3e54d697333c4e89a0890629bb2332b" - integrity sha512-ty4LQxN1QC+YhUP28NfEgZDEGXkyqOQy+BDriBozqHsrYO4JMgiPhfizqOGF7P+euBTZ5Ez6SKlLAMCLo8tzmw== +"@aws-sdk/util-endpoints@^3.996.8": + version "3.996.8" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.996.8.tgz#ad5c4f09b93482c0861d49d8a025edc2b0d2f5ec" + integrity sha512-oOZHcRDihk5iEe5V25NVWg45b3qEA8OpHWVdU/XQh8Zj4heVPAJqWvMphQnU7LkufmUo10EpvFPZuQMiFLJK3g== dependencies: "@aws-sdk/types" "^3.973.8" "@smithy/types" "^4.14.1" "@smithy/url-parser" "^4.2.14" - "@smithy/util-endpoints" "^3.4.1" + "@smithy/util-endpoints" "^3.4.2" tslib "^2.6.2" "@aws-sdk/util-locate-window@^3.0.0": @@ -661,7 +663,7 @@ dependencies: tslib "^2.6.2" -"@aws-sdk/util-user-agent-browser@^3.972.10", "@aws-sdk/util-user-agent-browser@^3.972.9": +"@aws-sdk/util-user-agent-browser@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.10.tgz#e29be10389db9db12b2d8246ad247a89038f4c60" integrity sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g== @@ -671,25 +673,26 @@ bowser "^2.11.0" tslib "^2.6.2" -"@aws-sdk/util-user-agent-node@^3.973.15", "@aws-sdk/util-user-agent-node@^3.973.17": - version "3.973.17" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.17.tgz#aec872d774478078d72f35e851d98dacb665933e" - integrity sha512-utF5qjjbuJQuU9VdCkWl7L87sr93cApsrD+uxGfUnlafX8iyEzJrb7EZnufjThURZVTOtelRMXrblWxpefElUg== +"@aws-sdk/util-user-agent-node@^3.973.24": + version "3.973.24" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.24.tgz#cf44a63b92adfecaeb8cb9f948b390456310566a" + integrity sha512-ZWwlkjcIp7cEL8ZfTpTAPNkwx25p7xol0xlKoWVVf22+nsjwmLcHYtTPjIV1cSpmB/b6DaK4cb1fSkvCXHgRdw== dependencies: - "@aws-sdk/middleware-user-agent" "^3.972.31" + "@aws-sdk/middleware-user-agent" "^3.972.38" "@aws-sdk/types" "^3.973.8" "@smithy/node-config-provider" "^4.3.14" "@smithy/types" "^4.14.1" "@smithy/util-config-provider" "^4.2.2" tslib "^2.6.2" -"@aws-sdk/xml-builder@^3.972.18": - version "3.972.18" - resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.972.18.tgz#2620fff23f5f20b25cf5d0ef4d4d1ffc12d741a5" - integrity sha512-BMDNVG1ETXRhl1tnisQiYBef3RShJ1kfZA7x7afivTFMLirfHNTb6U71K569HNXhSXbQZsweHvSDZ6euBw8hPA== +"@aws-sdk/xml-builder@^3.972.22": + version "3.972.22" + resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.972.22.tgz#1e44ca9fd9c3fdc3d9af9540ced024f34cfc60b2" + integrity sha512-PMYKKtJd70IsSG0yHrdAbxBr+ZWBKLvzFZfD3/urxgf6hXVMzuU5M+3MJ5G67RpOmLBu1fAUN65SbWuKUCOlAA== dependencies: + "@nodable/entities" "2.1.0" "@smithy/types" "^4.14.1" - fast-xml-parser "5.5.8" + fast-xml-parser "5.7.2" tslib "^2.6.2" "@aws/lambda-invoke-store@0.2.4", "@aws/lambda-invoke-store@^0.2.2": @@ -1699,7 +1702,7 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@nodable/entities@^2.1.0": +"@nodable/entities@2.1.0", "@nodable/entities@^2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@nodable/entities/-/entities-2.1.0.tgz#f543e5c6446720d4cf9e498a83019dd159973bc2" integrity sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA== @@ -1775,22 +1778,22 @@ dependencies: tslib "^2.6.2" -"@smithy/config-resolver@^4.4.14", "@smithy/config-resolver@^4.4.16": - version "4.4.16" - resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-4.4.16.tgz#95652ffb2f29fc6c659fbe8f51d27170862c30ac" - integrity sha512-GFlGPNLZKrGfqWpqVb31z7hvYCA9ZscfX1buYnvvMGcRYsQQnhH+4uN6mWWflcD5jB4OXP/LBrdpukEdjl41tg== +"@smithy/config-resolver@^4.4.17": + version "4.4.17" + resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-4.4.17.tgz#5bd7ccf461e126c79072ce84c6b0f3d00b3409bc" + integrity sha512-TzDZcAnhTyAHbXVxWZo7/tEcrIeFq20IBk8So3OLOetWpR8EwY/yEqBMBFaJMeyEiREDq4NfEl+qO3OAUD+vbQ== dependencies: "@smithy/node-config-provider" "^4.3.14" "@smithy/types" "^4.14.1" "@smithy/util-config-provider" "^4.2.2" - "@smithy/util-endpoints" "^3.4.1" + "@smithy/util-endpoints" "^3.4.2" "@smithy/util-middleware" "^4.2.14" tslib "^2.6.2" -"@smithy/core@^3.23.14", "@smithy/core@^3.23.15": - version "3.23.15" - resolved "https://registry.yarnpkg.com/@smithy/core/-/core-3.23.15.tgz#fdce4411531d4df07f275e96b6fe116583195c84" - integrity sha512-E7GVCgsQttzfujEZb6Qep005wWf4xiL4x06apFEtzQMWYBPggZh/0cnOxPficw5cuK/YjjkehKoIN4YUaSh0UQ== +"@smithy/core@^3.23.17": + version "3.23.17" + resolved "https://registry.yarnpkg.com/@smithy/core/-/core-3.23.17.tgz#23d02277c8d6d30a1605afd756696265e48ed67e" + integrity sha512-x7BlLbUFL8NWCGjMF9C+1N5cVCxcPa7g6Tv9B4A2luWx3be3oU8hQ96wIwxe/s7OhIzvoJH73HAUSg5JXVlEtQ== dependencies: "@smithy/protocol-http" "^5.3.14" "@smithy/types" "^4.14.1" @@ -1798,7 +1801,7 @@ "@smithy/util-base64" "^4.3.2" "@smithy/util-body-length-browser" "^4.2.2" "@smithy/util-middleware" "^4.2.14" - "@smithy/util-stream" "^4.5.23" + "@smithy/util-stream" "^4.5.25" "@smithy/util-utf8" "^4.2.2" "@smithy/uuid" "^1.1.2" tslib "^2.6.2" @@ -1824,7 +1827,7 @@ "@smithy/util-hex-encoding" "^4.2.2" tslib "^2.6.2" -"@smithy/eventstream-serde-browser@^4.2.13": +"@smithy/eventstream-serde-browser@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.14.tgz#b483667ea358975afb2170cd2618b9aa53a0fb29" integrity sha512-8IelTCtTctWRbb+0Dcy+C0aICh1qa0qWXqgjcXDmMuCvPJRnv26hiDZoAau2ILOniki65mCPKqOQs/BaWvO4CQ== @@ -1833,7 +1836,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/eventstream-serde-config-resolver@^4.3.13": +"@smithy/eventstream-serde-config-resolver@^4.3.14": version "4.3.14" resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.14.tgz#2eb23acad43414b9bc0b43f34ae9afbd5464e484" integrity sha512-sqHiHpYRYo3FJlaIxD1J8PhbcmJAm7IuM16mVnwSkCToD7g00IBZzKuiLNMGmftULmEUX6/UAz8/NN5uMP8bVA== @@ -1841,7 +1844,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/eventstream-serde-node@^4.2.13": +"@smithy/eventstream-serde-node@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.14.tgz#402c2a3b0437b7ac9747090a38a60d3642813490" integrity sha512-Ht/8BuGlKfFTy0H3+8eEu0vdpwGztCnaLLXtpXNdQqiR7Hj4vFScU3T436vRAjATglOIPjJXronY+1WxxNLSiw== @@ -1859,7 +1862,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/fetch-http-handler@^5.3.16", "@smithy/fetch-http-handler@^5.3.17": +"@smithy/fetch-http-handler@^5.3.17": version "5.3.17" resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.17.tgz#bf13a4b03eb8afe101775fef59a1758f8fb5cd4b" integrity sha512-bXOvQzaSm6MnmLaWA1elgfQcAtN4UP3vXqV97bHuoOrHQOJiLT3ds6o9eo5bqd0TJfRFpzdGnDQdW3FACiAVdw== @@ -1870,7 +1873,7 @@ "@smithy/util-base64" "^4.3.2" tslib "^2.6.2" -"@smithy/hash-blob-browser@^4.2.14": +"@smithy/hash-blob-browser@^4.2.15": version "4.2.15" resolved "https://registry.yarnpkg.com/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.15.tgz#1323f9717cad352b3e18065b738387bb9684f993" integrity sha512-0PJ4Al3fg2nM4qKrAIxyNcApgqHAXcBkN8FeizOz69z0rb26uZ6lMESYtxegaTlXB5Hj84JfwMPavMrwDMjucA== @@ -1880,7 +1883,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/hash-node@^4.2.13", "@smithy/hash-node@^4.2.14": +"@smithy/hash-node@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-4.2.14.tgz#e3ed33dc614e26fff5f043e097750c6931b48592" integrity sha512-8ZBDY2DD4wr+GGjTpPtiglEsqr0lUP+KHqgZcWczFf6qeZ/YRjMIOoQWVQlmwu7EtxKTd8YXD8lblmYcpBIA1g== @@ -1890,7 +1893,7 @@ "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@smithy/hash-stream-node@^4.2.13": +"@smithy/hash-stream-node@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/hash-stream-node/-/hash-stream-node-4.2.14.tgz#98bc14e79e2be852d04ff6cbfe4b0babe48fb10d" integrity sha512-tw4GANWkZPb6+BdD4Fgucqzey2+r73Z/GRo9zklsCdwrnxxumUV83ZIaBDdudV4Ylazw3EPTiJZhpX42105ruQ== @@ -1899,7 +1902,7 @@ "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@smithy/invalid-dependency@^4.2.13", "@smithy/invalid-dependency@^4.2.14": +"@smithy/invalid-dependency@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-4.2.14.tgz#a52766f9d4299abcd9d6cd23b5a76f34fc59c7a0" integrity sha512-c21qJiTSb25xvvOp+H2TNZzPCngrvl5vIPqPB8zQ/DmJF4QWXO19x1dWfMJZ6wZuuWUPPm0gV8C0cU3+ifcWuw== @@ -1921,7 +1924,7 @@ dependencies: tslib "^2.6.2" -"@smithy/md5-js@^4.2.13": +"@smithy/md5-js@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/md5-js/-/md5-js-4.2.14.tgz#c066572ec84def147af24e55a402c44d0d7dcd7b" integrity sha512-V2v0vx+h0iUSNG1Alt+GNBMSLGCrl9iVsdd+Ap67HPM9PN479x12V8LkuMoKImNZxn3MXeuyUjls+/7ZACZghA== @@ -1930,7 +1933,7 @@ "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@smithy/middleware-content-length@^4.2.13", "@smithy/middleware-content-length@^4.2.14": +"@smithy/middleware-content-length@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-4.2.14.tgz#d8b17f94c4d8f9c3b7992f1db84d3299c83efe78" integrity sha512-xhHq7fX4/3lv5NHxLUk3OeEvl0xZ+Ek3qIbWaCL4f9JwgDZEclPBElljaZCAItdGPQl/kSM4LPMOpy1MYgprpw== @@ -1939,13 +1942,13 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/middleware-endpoint@^4.4.29", "@smithy/middleware-endpoint@^4.4.30": - version "4.4.30" - resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.30.tgz#4f7a301ae414b743ef23384245c531891c317163" - integrity sha512-qS2XqhKeXmdZ4nEQ4cOxIczSP/Y91wPAHYuRwmWDCh975B7/57uxsm5d6sisnUThn2u2FwzMdJNM7AbO1YPsPg== +"@smithy/middleware-endpoint@^4.4.32": + version "4.4.32" + resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.32.tgz#4c7dcf06b637b40dfcc53d3b18d1a784a747c530" + integrity sha512-ZZkgyjnJppiZbIm6Qbx92pbXYi1uzenIvGhBSCDlc7NwuAkiqSgS75j1czAD25ZLs2FjMjYy1q7gyRVWG6JA0Q== dependencies: - "@smithy/core" "^3.23.15" - "@smithy/middleware-serde" "^4.2.18" + "@smithy/core" "^3.23.17" + "@smithy/middleware-serde" "^4.2.20" "@smithy/node-config-provider" "^4.3.14" "@smithy/shared-ini-file-loader" "^4.4.9" "@smithy/types" "^4.14.1" @@ -1953,33 +1956,33 @@ "@smithy/util-middleware" "^4.2.14" tslib "^2.6.2" -"@smithy/middleware-retry@^4.5.0", "@smithy/middleware-retry@^4.5.3": - version "4.5.3" - resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-4.5.3.tgz#66e74235d0d8f73728cc9a7ca91672d0543936e9" - integrity sha512-TE8dJNi6JuxzGSxMCVd3i9IEWDndCl3bmluLsBNDWok8olgj65OfkndMhl9SZ7m14c+C5SQn/PcUmrDl57rSFw== +"@smithy/middleware-retry@^4.5.7": + version "4.5.7" + resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-4.5.7.tgz#a2da0c472d631ee408ff566186c99571b3efb70b" + integrity sha512-bRt6ZImqVSeTk39Nm81K20ObIiAZ3WefY7G6+iz/0tZjs4dgRRjvRX2sgsH+zi6iDCRR/aQvQofLKxxz4rPBZg== dependencies: - "@smithy/core" "^3.23.15" + "@smithy/core" "^3.23.17" "@smithy/node-config-provider" "^4.3.14" "@smithy/protocol-http" "^5.3.14" - "@smithy/service-error-classification" "^4.2.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/service-error-classification" "^4.3.1" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" "@smithy/util-middleware" "^4.2.14" - "@smithy/util-retry" "^4.3.2" + "@smithy/util-retry" "^4.3.6" "@smithy/uuid" "^1.1.2" tslib "^2.6.2" -"@smithy/middleware-serde@^4.2.17", "@smithy/middleware-serde@^4.2.18": - version "4.2.18" - resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-4.2.18.tgz#6fc65092a2eed7354cc2288bb20693c9ff424018" - integrity sha512-M6CSgnp3v4tYz9ynj2JHbA60woBZcGqEwNjTKjBsNHPV26R1ZX52+0wW8WsZU18q45jD0tw2wL22S17Ze9LpEw== +"@smithy/middleware-serde@^4.2.20": + version "4.2.20" + resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-4.2.20.tgz#76862c8f9b39b08501539440a2e6bca7a77de508" + integrity sha512-Lx9JMO9vArPtiChE3wbEZ5akMIDQpWQtlu90lhACQmNOXcGXRbaDywMHDzuDZ2OkZzP+9wQfZi3YJT9F67zTQQ== dependencies: - "@smithy/core" "^3.23.15" + "@smithy/core" "^3.23.17" "@smithy/protocol-http" "^5.3.14" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/middleware-stack@^4.2.13", "@smithy/middleware-stack@^4.2.14": +"@smithy/middleware-stack@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-4.2.14.tgz#23a4cf643ccdbde52c8780fe5cc080611efef1c7" integrity sha512-2dvkUKLuFdKsCRmOE4Mn63co0Djtsm+JMh0bYZQupN1pJwMeE8FmQmRLLzzEMN0dnNi7CDCYYH8F0EVwWiPBeA== @@ -1987,7 +1990,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/node-config-provider@^4.3.13", "@smithy/node-config-provider@^4.3.14": +"@smithy/node-config-provider@^4.3.14": version "4.3.14" resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-4.3.14.tgz#8ca13b86b6123cbb0425d669bd847fcd333ca4bd" integrity sha512-S+gFjyo/weSVL0P1b9Ts8C/CwIfNCgUPikk3sl6QVsfE/uUuO+QsF+NsE/JkpvWqqyz1wg7HFdiaZuj5CoBMRg== @@ -1997,10 +2000,10 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/node-http-handler@^4.5.2", "@smithy/node-http-handler@^4.5.3": - version "4.5.3" - resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-4.5.3.tgz#a0f7263fb8ecb0fd5dea03f770ec99d3a4c4efdc" - integrity sha512-lc5jFL++x17sPhIwMWJ3YOnqmSjw/2Po6VLDlUIXvxVWRuJwRXnJ4jOBBLB0cfI5BB5ehIl02Fxr1PDvk/kxDw== +"@smithy/node-http-handler@^4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-4.6.1.tgz#cb25b9445e46294a6f0dfb1566dbf2a1a19510af" + integrity sha512-iB+orM4x3xrr57X3YaXazfKnntl0LHlZB1kcXSGzMV1Tt0+YwEjGlbjk/44qEGtBzXAz6yFDzkYTKSV6Pj2HUg== dependencies: "@smithy/protocol-http" "^5.3.14" "@smithy/querystring-builder" "^4.2.14" @@ -2015,7 +2018,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/protocol-http@^5.3.13", "@smithy/protocol-http@^5.3.14": +"@smithy/protocol-http@^5.3.14": version "5.3.14" resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-5.3.14.tgz#ed1e65cdb0fffb7fd00dce997c04baa236f180cc" integrity sha512-dN5F8kHx8RNU0r+pCwNmFZyz6ChjMkzShy/zup6MtkRmmix4vZzJdW+di7x//b1LiynIev88FM18ie+wwPcQtQ== @@ -2040,10 +2043,10 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/service-error-classification@^4.2.14": - version "4.2.14" - resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-4.2.14.tgz#b9d3df0cb6f6f7fab87ddf5a348ca70f0b61585f" - integrity sha512-vVimoUnGxlx4eLLQbZImdOZFOe+Zh+5ACntv8VxZuGP72LdWu5GV3oEmCahSEReBgRJoWjypFkrehSj7BWx1HQ== +"@smithy/service-error-classification@^4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-4.3.1.tgz#5303d4fc3c3eea0f79c3b88cb4436498a31e9f12" + integrity sha512-aUQuDGh760ts/8MU+APjIZhlLPKhIIfqyzZaJikLEIMrdxFvxuLYD0WxWzaYWpmLbQlXDe9p7EWM3HsBe0K6Gw== dependencies: "@smithy/types" "^4.14.1" @@ -2069,27 +2072,27 @@ "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@smithy/smithy-client@^4.12.11", "@smithy/smithy-client@^4.12.9": - version "4.12.11" - resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-4.12.11.tgz#547dd901c7674e8c39c9558348b864f0222d2a8f" - integrity sha512-wzz/Wa1CH/Tlhxh0s4DQPEcXSxSVfJ59AZcUh9Gu0c6JTlKuwGf4o/3P2TExv0VbtPFt8odIBG+eQGK2+vTECg== +"@smithy/smithy-client@^4.12.13": + version "4.12.13" + resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-4.12.13.tgz#dec184a1d2d5027370ae1582bddbdbc068c97da5" + integrity sha512-y/Pcj1V9+qG98gyu1gvftHB7rDpdh+7kIBIggs55yGm3JdtBV8GT8IFF3a1qxZ79QnaJHX9GXzvBG6tAd+czJA== dependencies: - "@smithy/core" "^3.23.15" - "@smithy/middleware-endpoint" "^4.4.30" + "@smithy/core" "^3.23.17" + "@smithy/middleware-endpoint" "^4.4.32" "@smithy/middleware-stack" "^4.2.14" "@smithy/protocol-http" "^5.3.14" "@smithy/types" "^4.14.1" - "@smithy/util-stream" "^4.5.23" + "@smithy/util-stream" "^4.5.25" tslib "^2.6.2" -"@smithy/types@^4.14.0", "@smithy/types@^4.14.1": +"@smithy/types@^4.14.1": version "4.14.1" resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.14.1.tgz#aba92b4cdb406f2a2b062e82f1e3728d809a7c23" integrity sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg== dependencies: tslib "^2.6.2" -"@smithy/url-parser@^4.2.13", "@smithy/url-parser@^4.2.14": +"@smithy/url-parser@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-4.2.14.tgz#349a442a62eb5907533f204b73a010618198b073" integrity sha512-p06BiBigJ8bTA3MgnOfCtDUWnAMY0YfedO/GRpmc7p+wg3KW8vbXy1xwSu5ASy0wV7rRYtlfZOIKH4XqfhjSQQ== @@ -2144,33 +2147,33 @@ dependencies: tslib "^2.6.2" -"@smithy/util-defaults-mode-browser@^4.3.45", "@smithy/util-defaults-mode-browser@^4.3.47": - version "4.3.47" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.47.tgz#1fc43bae2e50b49f78fe095a7c71a8b4d0519a0c" - integrity sha512-zlIuXai3/SHjQUQ8y3g/woLvrH573SK2wNjcDaHu5e9VOcC0JwM1MI0Sq0GZJyN3BwSUneIhpjZ18nsiz5AtQw== +"@smithy/util-defaults-mode-browser@^4.3.49": + version "4.3.49" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.49.tgz#926ce84bf65e56307f25cce7a13b427d33442939" + integrity sha512-a5bNrdiONYB/qE2BuKegvUMd/+ZDwdg4vsNuuSzYE8qs2EYAdK9CynL+Rzn29PbPiUqoz/cbpRbcLzD5lEevHw== dependencies: "@smithy/property-provider" "^4.2.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/util-defaults-mode-node@^4.2.49", "@smithy/util-defaults-mode-node@^4.2.52": - version "4.2.52" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.52.tgz#8ee1f267d764c3d540c0c3a091c3d9b703194991" - integrity sha512-cQBz8g68Vnw1W2meXlkb3D/hXJU+Taiyj9P8qLJtjREEV9/Td65xi4A/H1sRQ8EIgX5qbZbvdYPKygKLholZ3w== +"@smithy/util-defaults-mode-node@^4.2.54": + version "4.2.54" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.54.tgz#32c4ea9f8a8c74ef9fe0ca5e3d6a10df0327f87e" + integrity sha512-g1cvrJvOnzeJgEdf7AE4luI7gp6L8weE0y9a9wQUSGtjb8QRHDbCJYuE4Sy0SD9N8RrnNPFsPltAz/OSoBR9Zw== dependencies: - "@smithy/config-resolver" "^4.4.16" + "@smithy/config-resolver" "^4.4.17" "@smithy/credential-provider-imds" "^4.2.14" "@smithy/node-config-provider" "^4.3.14" "@smithy/property-provider" "^4.2.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/util-endpoints@^3.3.4", "@smithy/util-endpoints@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-3.4.1.tgz#01ef5aaa699a635073da3e63cc7f15beb4d1abf9" - integrity sha512-wMxNDZJrgS5mQV9oxCs4TWl5767VMgOfqfZ3JHyCkMtGC2ykW9iPqMvFur695Otcc5yxLG8OKO/80tsQBxrhXg== +"@smithy/util-endpoints@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-3.4.2.tgz#ee59c42d039a642b6c6eb2d38e0ae3db6fc48e97" + integrity sha512-a55Tr+3OKld4TTtnT+RhKOQHyPxm3j/xL4OR83WBUhLJaKDS9dnJ7arRMOp3t31dcLhApwG9bgvrRXBHlLdIkg== dependencies: "@smithy/node-config-provider" "^4.3.14" "@smithy/types" "^4.14.1" @@ -2183,7 +2186,7 @@ dependencies: tslib "^2.6.2" -"@smithy/util-middleware@^4.2.13", "@smithy/util-middleware@^4.2.14": +"@smithy/util-middleware@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-4.2.14.tgz#9985dd82b4036db2d03835229b9b0c63d2bb85fa" integrity sha512-1Su2vj9RYNDEv/V+2E+jXkkwGsgR7dc4sfHn9Z7ruzQHJIEni9zzw5CauvRXlFJfmgcqYP8fWa0dkh2Q2YaQyw== @@ -2191,22 +2194,22 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/util-retry@^4.3.0", "@smithy/util-retry@^4.3.2": - version "4.3.2" - resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-4.3.2.tgz#5f73ca1300a39b413f0e764128fe6c473ed31b9b" - integrity sha512-2+KTsJEwTi63NUv4uR9IQ+IFT1yu6Rf6JuoBK2WKaaJ/TRvOiOVGcXAsEqX/TQN2thR9yII21kPUJq1UV/WI2A== +"@smithy/util-retry@^4.3.6": + version "4.3.8" + resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-4.3.8.tgz#7f904ed8e5bad2b5f2e6aa1e193db2b46b2c57df" + integrity sha512-LUIxbTBi+OpvXpg91poGA6BdyoleMDLnfXjVDqyi2RvZmTveY5loE/FgYUBCR5LU2BThW2SoZRh8dTIIy38IPw== dependencies: - "@smithy/service-error-classification" "^4.2.14" + "@smithy/service-error-classification" "^4.3.1" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/util-stream@^4.5.22", "@smithy/util-stream@^4.5.23": - version "4.5.23" - resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-4.5.23.tgz#dc7535580bcc7117126e3ae26dfc937a83b434fb" - integrity sha512-N6on1+ngJ3RznZOnDWNveIwnTSlqxNnXuNAh7ez889ZZaRdXoNRTXKgmYOLe6dB0gCmAVtuRScE1hymQFl4hpg== +"@smithy/util-stream@^4.5.25": + version "4.5.25" + resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-4.5.25.tgz#f48385a284151c7e099395af4e5fb0978fffe4ff" + integrity sha512-/PFpG4k8Ze8Ei+mMKj3oiPICYekthuzePZMgZbCqMiXIHHf4n2aZ4Ps0aSRShycFTGuj/J6XldmC0x0DwednIA== dependencies: "@smithy/fetch-http-handler" "^5.3.17" - "@smithy/node-http-handler" "^4.5.3" + "@smithy/node-http-handler" "^4.6.1" "@smithy/types" "^4.14.1" "@smithy/util-base64" "^4.3.2" "@smithy/util-buffer-from" "^4.2.2" @@ -2237,10 +2240,10 @@ "@smithy/util-buffer-from" "^4.2.2" tslib "^2.6.2" -"@smithy/util-waiter@^4.2.15": - version "4.2.16" - resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-4.2.16.tgz#eae1be0810cd243898fdcf22c83a1ec59fe63610" - integrity sha512-GtclrKoZ3Lt7jPQ7aTIYKfjY92OgceScftVnkTsG8e1KV8rkvZgN+ny6YSRhd9hxB8rZtwVbmln7NTvE5O3GmQ== +"@smithy/util-waiter@^4.3.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-4.3.0.tgz#6122ce27939edb5550d1d6c7c8d506323f3a17f7" + integrity sha512-JyjYmLAfS+pdxF92o4yLgEoy0zhayKTw73FU1aofLWwLcJw7iSqIY2exGmMTrl/lmZugP5p/zxdFSippJDfKWA== dependencies: "@smithy/types" "^4.14.1" tslib "^2.6.2" @@ -3429,20 +3432,21 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fast-xml-builder@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/fast-xml-builder/-/fast-xml-builder-1.1.5.tgz#50188e1452a5fa095f415d3e63dcac0a1dbcbf11" - integrity sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA== +fast-xml-builder@^1.1.7: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz#abd2363145a7625d9789ad96da375fabe3cff28c" + integrity sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q== dependencies: - path-expression-matcher "^1.1.3" + path-expression-matcher "^1.5.0" + xml-naming "^0.1.0" -fast-xml-parser@5.5.8, fast-xml-parser@5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-5.7.0.tgz#b93e49a3d62a8824c5212d8fa099ac2e548d548a" - integrity sha512-MTcrUoRQ1GSQ9iG3QJzBGquYYYeA7piZaJoIWbPFGbRn6Jj6z7xgoAyi4DrZX4y2ZIQQBF59gc/zmvvejjgoFQ== +fast-xml-parser@5.7.2, fast-xml-parser@5.7.3: + version "5.7.3" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-5.7.3.tgz#309b04b08d835defc62ab657a0bb340c0e0fbe6a" + integrity sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg== dependencies: "@nodable/entities" "^2.1.0" - fast-xml-builder "^1.1.5" + fast-xml-builder "^1.1.7" path-expression-matcher "^1.5.0" strnum "^2.2.3" @@ -4689,11 +4693,6 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -path-expression-matcher@^1.1.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/path-expression-matcher/-/path-expression-matcher-1.2.0.tgz#9bdae3787f43b0857b0269e9caaa586c12c8abee" - integrity sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ== - path-expression-matcher@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz#3b98545dc88ffebb593e2d8458d0929da9275f4a" @@ -5387,6 +5386,11 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" +xml-naming@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/xml-naming/-/xml-naming-0.1.0.tgz#8ab7106c5b8d23caa2fabac1cadf17136379fbd8" + integrity sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" diff --git a/backend/compact-connect/lambdas/python/cognito-backup/requirements-dev.txt b/backend/compact-connect/lambdas/python/cognito-backup/requirements-dev.txt index 767452093..5f7003c6d 100644 --- a/backend/compact-connect/lambdas/python/cognito-backup/requirements-dev.txt +++ b/backend/compact-connect/lambdas/python/cognito-backup/requirements-dev.txt @@ -77,7 +77,7 @@ six==1.17.0 # via python-dateutil typing-extensions==4.15.0 # via aws-lambda-powertools -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # requests diff --git a/backend/compact-connect/lambdas/python/common/requirements-dev.txt b/backend/compact-connect/lambdas/python/common/requirements-dev.txt index 5d525168d..dfca9adb2 100644 --- a/backend/compact-connect/lambdas/python/common/requirements-dev.txt +++ b/backend/compact-connect/lambdas/python/common/requirements-dev.txt @@ -177,7 +177,7 @@ typing-inspection==0.4.2 # via # pydantic # pydantic-settings -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/compact-connect/lambdas/python/common/requirements.txt b/backend/compact-connect/lambdas/python/common/requirements.txt index 64e51baf4..d73dc3d5a 100644 --- a/backend/compact-connect/lambdas/python/common/requirements.txt +++ b/backend/compact-connect/lambdas/python/common/requirements.txt @@ -47,7 +47,7 @@ six==1.17.0 # via python-dateutil typing-extensions==4.15.0 # via aws-lambda-powertools -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # requests diff --git a/backend/compact-connect/lambdas/python/compact-configuration/requirements-dev.txt b/backend/compact-connect/lambdas/python/compact-configuration/requirements-dev.txt index 5febd7fe0..fd6c74d7d 100644 --- a/backend/compact-connect/lambdas/python/compact-configuration/requirements-dev.txt +++ b/backend/compact-connect/lambdas/python/compact-configuration/requirements-dev.txt @@ -58,7 +58,7 @@ s3transfer==0.16.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/compact-connect/lambdas/python/custom-resources/requirements-dev.txt b/backend/compact-connect/lambdas/python/custom-resources/requirements-dev.txt index 95d67726d..193158100 100644 --- a/backend/compact-connect/lambdas/python/custom-resources/requirements-dev.txt +++ b/backend/compact-connect/lambdas/python/custom-resources/requirements-dev.txt @@ -58,7 +58,7 @@ s3transfer==0.16.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/compact-connect/lambdas/python/data-events/requirements-dev.txt b/backend/compact-connect/lambdas/python/data-events/requirements-dev.txt index 73018a252..29aee1caf 100644 --- a/backend/compact-connect/lambdas/python/data-events/requirements-dev.txt +++ b/backend/compact-connect/lambdas/python/data-events/requirements-dev.txt @@ -58,7 +58,7 @@ s3transfer==0.16.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/compact-connect/lambdas/python/disaster-recovery/requirements-dev.txt b/backend/compact-connect/lambdas/python/disaster-recovery/requirements-dev.txt index 341ca2d7c..1f5dc76eb 100644 --- a/backend/compact-connect/lambdas/python/disaster-recovery/requirements-dev.txt +++ b/backend/compact-connect/lambdas/python/disaster-recovery/requirements-dev.txt @@ -58,7 +58,7 @@ s3transfer==0.16.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/compact-connect/lambdas/python/feature-flag/requirements-dev.txt b/backend/compact-connect/lambdas/python/feature-flag/requirements-dev.txt index afdd04ddf..49a7ffd2c 100644 --- a/backend/compact-connect/lambdas/python/feature-flag/requirements-dev.txt +++ b/backend/compact-connect/lambdas/python/feature-flag/requirements-dev.txt @@ -56,7 +56,7 @@ s3transfer==0.16.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/compact-connect/lambdas/python/feature-flag/requirements.txt b/backend/compact-connect/lambdas/python/feature-flag/requirements.txt index 0bcf16a28..1b8a3684e 100644 --- a/backend/compact-connect/lambdas/python/feature-flag/requirements.txt +++ b/backend/compact-connect/lambdas/python/feature-flag/requirements.txt @@ -16,5 +16,5 @@ statsig-python-core==0.19.1 # via -r requirements.in typing-extensions==4.15.0 # via statsig-python-core -urllib3==2.6.3 +urllib3==2.7.0 # via requests diff --git a/backend/compact-connect/lambdas/python/provider-data-v1/requirements-dev.txt b/backend/compact-connect/lambdas/python/provider-data-v1/requirements-dev.txt index 107ddd44f..ffb24944e 100644 --- a/backend/compact-connect/lambdas/python/provider-data-v1/requirements-dev.txt +++ b/backend/compact-connect/lambdas/python/provider-data-v1/requirements-dev.txt @@ -60,7 +60,7 @@ s3transfer==0.16.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/compact-connect/lambdas/python/purchases/requirements-dev.in b/backend/compact-connect/lambdas/python/purchases/requirements-dev.in index 5b44d6ab1..b921f8320 100644 --- a/backend/compact-connect/lambdas/python/purchases/requirements-dev.in +++ b/backend/compact-connect/lambdas/python/purchases/requirements-dev.in @@ -14,4 +14,4 @@ boto3>=1.34.33, <2 cryptography>=46, <47 marshmallow>=4.3.0, <5.0.0 requests>=2.31.0, <3.0.0 -urllib3>=2.6.3, <3 +urllib3>=2.7.0, <3 diff --git a/backend/compact-connect/lambdas/python/purchases/requirements-dev.txt b/backend/compact-connect/lambdas/python/purchases/requirements-dev.txt index 54487e277..658108d4b 100644 --- a/backend/compact-connect/lambdas/python/purchases/requirements-dev.txt +++ b/backend/compact-connect/lambdas/python/purchases/requirements-dev.txt @@ -161,7 +161,7 @@ tomli-w==1.2.0 # via pip-audit typing-extensions==4.15.0 # via aws-lambda-powertools -urllib3==2.6.3 +urllib3==2.7.0 # via # -r purchases/requirements-dev.in # botocore diff --git a/backend/compact-connect/lambdas/python/purchases/requirements.in b/backend/compact-connect/lambdas/python/purchases/requirements.in index f19cff7a1..15b94eb8c 100644 --- a/backend/compact-connect/lambdas/python/purchases/requirements.in +++ b/backend/compact-connect/lambdas/python/purchases/requirements.in @@ -1,4 +1,4 @@ # common requirements are managed in the common-python requirements.in file authorizenet>=1.1.6, <2 # explicitly setting this transitive dependency to pick vulnerability patch -urllib3>=2.6.3, <3 +urllib3>=2.7.0, <3 diff --git a/backend/compact-connect/lambdas/python/purchases/requirements.txt b/backend/compact-connect/lambdas/python/purchases/requirements.txt index e921e9e66..3f9e73536 100644 --- a/backend/compact-connect/lambdas/python/purchases/requirements.txt +++ b/backend/compact-connect/lambdas/python/purchases/requirements.txt @@ -18,7 +18,7 @@ pyxb-x==1.2.6.3 # via authorizenet requests==2.33.1 # via authorizenet -urllib3==2.6.3 +urllib3==2.7.0 # via # -r requirements.in # requests diff --git a/backend/compact-connect/lambdas/python/search/requirements-dev.txt b/backend/compact-connect/lambdas/python/search/requirements-dev.txt index 2b1485be2..c8e6e7a75 100644 --- a/backend/compact-connect/lambdas/python/search/requirements-dev.txt +++ b/backend/compact-connect/lambdas/python/search/requirements-dev.txt @@ -56,7 +56,7 @@ s3transfer==0.16.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/compact-connect/lambdas/python/search/requirements.txt b/backend/compact-connect/lambdas/python/search/requirements.txt index 1df821788..7c40b5b0f 100644 --- a/backend/compact-connect/lambdas/python/search/requirements.txt +++ b/backend/compact-connect/lambdas/python/search/requirements.txt @@ -30,7 +30,7 @@ six==1.17.0 # via python-dateutil typing-extensions==4.15.0 # via grpcio -urllib3==2.6.3 +urllib3==2.7.0 # via # opensearch-py # requests diff --git a/backend/compact-connect/lambdas/python/staff-user-pre-token/requirements-dev.txt b/backend/compact-connect/lambdas/python/staff-user-pre-token/requirements-dev.txt index 1f881ca6b..cf042a623 100644 --- a/backend/compact-connect/lambdas/python/staff-user-pre-token/requirements-dev.txt +++ b/backend/compact-connect/lambdas/python/staff-user-pre-token/requirements-dev.txt @@ -58,7 +58,7 @@ s3transfer==0.16.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/compact-connect/lambdas/python/staff-users/requirements-dev.txt b/backend/compact-connect/lambdas/python/staff-users/requirements-dev.txt index 6d5b0c844..0a8e043bf 100644 --- a/backend/compact-connect/lambdas/python/staff-users/requirements-dev.txt +++ b/backend/compact-connect/lambdas/python/staff-users/requirements-dev.txt @@ -64,7 +64,7 @@ s3transfer==0.16.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/compact-connect/requirements-dev.txt b/backend/compact-connect/requirements-dev.txt index f59ff80a9..68670cae3 100644 --- a/backend/compact-connect/requirements-dev.txt +++ b/backend/compact-connect/requirements-dev.txt @@ -97,7 +97,7 @@ tomli==2.4.1 # via pip-audit tomli-w==1.2.0 # via pip-audit -urllib3==2.6.3 +urllib3==2.7.0 # via requests wheel==0.46.3 # via pip-tools diff --git a/backend/compact-connect/tests/smoke/compact_configuration_smoke_tests.py b/backend/compact-connect/tests/smoke/compact_configuration_smoke_tests.py index 8cf7e3a79..6e9086964 100644 --- a/backend/compact-connect/tests/smoke/compact_configuration_smoke_tests.py +++ b/backend/compact-connect/tests/smoke/compact_configuration_smoke_tests.py @@ -103,7 +103,7 @@ def test_active_member_jurisdictions(): print(f'Successfully verified active member jurisdictions for compact {compact}') -def test_compact_configuration(): +def test_compact_configuration(compact: str = None): """ Test that a compact admin can update and retrieve compact configuration. @@ -112,8 +112,9 @@ def test_compact_configuration(): """ print('Testing compact configuration...') + if compact is None: + compact = COMPACTS[0] # Use the first compact for testing # Create a test compact admin user - compact = COMPACTS[0] # Use the first compact for testing test_email = f'test-compact-admin-{compact}@ccSmokeTestFakeEmail.com' permissions = {'actions': {'admin'}, 'jurisdictions': {}} @@ -222,7 +223,9 @@ def test_compact_configuration(): delete_test_staff_user(test_email, user_sub, compact) -def test_jurisdiction_configuration(jurisdiction: str = 'ne', recreate_compact_config: bool = False): +def test_jurisdiction_configuration( + compact: str = None, jurisdiction: str = 'ne', recreate_compact_config: bool = False +): """ Test that a state admin can update and retrieve jurisdiction configuration. @@ -232,7 +235,8 @@ def test_jurisdiction_configuration(jurisdiction: str = 'ne', recreate_compact_c print('Testing jurisdiction configuration...') # Create a test state admin user with compact admin permissions for simplicity - compact = COMPACTS[0] # Use the first compact for testing + if compact is None: + compact = COMPACTS[0] # Use the first compact for testing test_email = f'test-state-admin-{jurisdiction}@ccSmokeTestFakeEmail.com' permissions = {'actions': {'admin'}, 'jurisdictions': {jurisdiction: {'admin'}}} diff --git a/backend/compact-connect/tests/smoke/purchasing_privileges_smoke_tests.py b/backend/compact-connect/tests/smoke/purchasing_privileges_smoke_tests.py index 26c7a0387..b127df188 100644 --- a/backend/compact-connect/tests/smoke/purchasing_privileges_smoke_tests.py +++ b/backend/compact-connect/tests/smoke/purchasing_privileges_smoke_tests.py @@ -35,10 +35,12 @@ def _generate_post_body(attestations_from_system, license_type): def test_purchase_privilege_options(): """Test the GET /v1/purchases/privileges/options endpoint.""" + original_provider_data = call_provider_users_me_endpoint() + compact = original_provider_data.get('compact') # First, ensure we have known configuration by calling the configuration tests # These will set up the configurations and return them for verification - compact_config = test_compact_configuration() - jurisdiction_config = test_jurisdiction_configuration() + compact_config = test_compact_configuration(compact=compact) + jurisdiction_config = test_jurisdiction_configuration(compact=compact) # Now test the purchase privilege options endpoint headers = get_provider_user_auth_headers_cached() diff --git a/backend/cosmetology-app/docs/api-specification/latest-oas30.json b/backend/cosmetology-app/docs/api-specification/latest-oas30.json index 70ed01a4b..19ef8897d 100644 --- a/backend/cosmetology-app/docs/api-specification/latest-oas30.json +++ b/backend/cosmetology-app/docs/api-specification/latest-oas30.json @@ -2,11 +2,14 @@ "openapi": "3.0.1", "info": { "title": "StateApi", - "version": "2026-03-13T17:32:08Z" + "version": "2026-02-16T16:53:09Z" }, "servers": [ { - "url": "https://state-api.beta.compactconnect.org" + "url": "https://state-api.beta.compactconnect.org", + "x-amazon-apigateway-endpoint-configuration": { + "disableExecuteApiEndpoint": true + } } ], "paths": { @@ -42,7 +45,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboStateLyTv9k6jxTZK" + "$ref": "#/components/schemas/TestSStateGpk4PxFv8Eew" } } }, @@ -54,7 +57,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboStateDr9HAH5blAWv" + "$ref": "#/components/schemas/TestSStatevE5TiToQrRwN" } } } @@ -64,7 +67,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboStatexWoPOpVnKEI9" + "$ref": "#/components/schemas/TestSState2d1wqb3JR6OX" } } } @@ -72,7 +75,7 @@ }, "security": [ { - "SandboxStateAPIStackStateApiStateAuthAuthorizer7F83A6D3": [ + "TestBackendCosmetologyTestStateAPIStackStateApiStateAuthAuthorizerBD69FBB7": [ "cosm/write", "al/cosm.write", "az/cosm.write", @@ -123,7 +126,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboStateMW9czXwgYk67" + "$ref": "#/components/schemas/TestSState4LF6rLqTTc6G" } } } @@ -131,7 +134,7 @@ }, "security": [ { - "SandboxStateAPIStackStateApiStateAuthAuthorizer7F83A6D3": [ + "TestBackendCosmetologyTestStateAPIStackStateApiStateAuthAuthorizerBD69FBB7": [ "cosm/write", "al/cosm.write", "az/cosm.write", @@ -151,31 +154,45 @@ }, "components": { "schemas": { - "SandboStateDr9HAH5blAWv": { + "TestSState4LF6rLqTTc6G": { + "required": [ + "upload" + ], "type": "object", "properties": { - "message": { - "type": "string", - "description": "Message indicating success or failure" - }, - "errors": { + "upload": { + "required": [ + "fields", + "url" + ], "type": "object", - "additionalProperties": { - "type": "object", - "additionalProperties": { - "type": "array", - "description": "List of error messages for a field", - "items": { + "properties": { + "fields": { + "type": "object", + "additionalProperties": { "type": "string" } }, - "description": "Errors for a specific record" - }, - "description": "Validation errors by record index" + "url": { + "type": "string" + } + } + } + } + }, + "TestSState2d1wqb3JR6OX": { + "required": [ + "message" + ], + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A message about the request" } } }, - "SandboStateLyTv9k6jxTZK": { + "TestSStateGpk4PxFv8Eew": { "maxItems": 100, "type": "array", "items": { @@ -312,47 +329,33 @@ "additionalProperties": false } }, - "SandboStateMW9czXwgYk67": { - "required": [ - "upload" - ], + "TestSStatevE5TiToQrRwN": { "type": "object", "properties": { - "upload": { - "required": [ - "fields", - "url" - ], + "message": { + "type": "string", + "description": "Message indicating success or failure" + }, + "errors": { "type": "object", - "properties": { - "fields": { - "type": "object", - "additionalProperties": { + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "array", + "description": "List of error messages for a field", + "items": { "type": "string" } }, - "url": { - "type": "string" - } - } - } - } - }, - "SandboStatexWoPOpVnKEI9": { - "required": [ - "message" - ], - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "A message about the request" + "description": "Errors for a specific record" + }, + "description": "Validation errors by record index" } } } }, "securitySchemes": { - "SandboxStateAPIStackStateApiStateAuthAuthorizer7F83A6D3": { + "TestBackendCosmetologyTestStateAPIStackStateApiStateAuthAuthorizerBD69FBB7": { "type": "apiKey", "name": "Authorization", "in": "header", diff --git a/backend/cosmetology-app/docs/internal/api-specification/latest-oas30.json b/backend/cosmetology-app/docs/internal/api-specification/latest-oas30.json index 03af68b85..aaeaab743 100644 --- a/backend/cosmetology-app/docs/internal/api-specification/latest-oas30.json +++ b/backend/cosmetology-app/docs/internal/api-specification/latest-oas30.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "LicenseApi", - "version": "2026-04-28T15:48:19Z" + "version": "2026-05-11T21:56:12Z" }, "servers": [ { @@ -4338,6 +4338,7 @@ "compact", "familyName", "givenName", + "licenseEligibility", "licenseJurisdiction", "licenseNumber", "licenseType", @@ -4349,6 +4350,14 @@ "type": "string", "description": "License type or profession designation for this license row" }, + "licenseEligibility": { + "type": "string", + "description": "Whether the license is eligible for compact participation in public search results", + "enum": [ + "eligible", + "ineligible" + ] + }, "licenseJurisdiction": { "type": "string", "enum": [ diff --git a/backend/cosmetology-app/docs/internal/postman/postman-collection.json b/backend/cosmetology-app/docs/internal/postman/postman-collection.json index ee716a6c8..8c9b76ac6 100644 --- a/backend/cosmetology-app/docs/internal/postman/postman-collection.json +++ b/backend/cosmetology-app/docs/internal/postman/postman-collection.json @@ -10,7 +10,7 @@ "type": "bearer" }, "info": { - "_postman_id": "ac8375b9-db52-469b-9342-96248d04542f", + "_postman_id": "56bf1d02-7d0b-4b0b-bd1d-d438c768b790", "description": { "content": "", "type": "text/plain" @@ -401,7 +401,7 @@ "item": [ { "event": [], - "id": "1ebbe4bb-f974-4785-a1ce-9d34e1a38b2e", + "id": "68cdf48f-7cd3-4dcc-af6a-4e32f78aeaac", "name": "/v1/compacts/:compact", "protocolProfileBehavior": { "disableBodyPruning": true @@ -444,7 +444,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"compactAbbr\": \"\",\n \"compactAdverseActionsNotificationEmails\": [\n \"\",\n \"\"\n ],\n \"compactName\": \"\",\n \"compactOperationsTeamEmails\": [\n \"\",\n \"\"\n ],\n \"configuredStates\": [\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"md\"\n },\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"wa\"\n }\n ],\n \"licenseeRegistrationEnabled\": \"\"\n}", + "body": "{\n \"compactAbbr\": \"\",\n \"compactAdverseActionsNotificationEmails\": [\n \"\",\n \"\"\n ],\n \"compactName\": \"\",\n \"compactOperationsTeamEmails\": [\n \"\",\n \"\"\n ],\n \"configuredStates\": [\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"ky\"\n },\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"oh\"\n }\n ],\n \"licenseeRegistrationEnabled\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -453,7 +453,7 @@ "value": "application/json" } ], - "id": "3a02ceb1-e8a4-4378-995c-3106e3d3ab6d", + "id": "0c6f4fa0-a5fd-4e4c-8786-a3ac43d77468", "name": "200 response", "originalRequest": { "body": {}, @@ -491,7 +491,7 @@ }, { "event": [], - "id": "065f3d04-c199-4c03-bb44-220589b8dd4e", + "id": "a5e31b50-829b-4066-8ff4-ed11e2bc4294", "name": "/v1/compacts/:compact", "protocolProfileBehavior": { "disableBodyPruning": true @@ -505,7 +505,7 @@ "language": "json" } }, - "raw": "{\n \"compactAdverseActionsNotificationEmails\": [\n \"\"\n ],\n \"compactOperationsTeamEmails\": [\n \"\"\n ],\n \"configuredStates\": [\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"co\"\n },\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"az\"\n }\n ],\n \"licenseeRegistrationEnabled\": \"\"\n}" + "raw": "{\n \"compactAdverseActionsNotificationEmails\": [\n \"\"\n ],\n \"compactOperationsTeamEmails\": [\n \"\"\n ],\n \"configuredStates\": [\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"co\"\n },\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"tn\"\n }\n ],\n \"licenseeRegistrationEnabled\": \"\"\n}" }, "description": {}, "header": [ @@ -556,7 +556,7 @@ "value": "application/json" } ], - "id": "b2b941d9-c3a2-45dc-8d0d-534b8cf60422", + "id": "cedfee38-f89a-4ccc-a9c7-d93b9a090e23", "name": "200 response", "originalRequest": { "body": { @@ -567,7 +567,7 @@ "language": "json" } }, - "raw": "{\n \"compactAdverseActionsNotificationEmails\": [\n \"\"\n ],\n \"compactOperationsTeamEmails\": [\n \"\"\n ],\n \"configuredStates\": [\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"co\"\n },\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"az\"\n }\n ],\n \"licenseeRegistrationEnabled\": \"\"\n}" + "raw": "{\n \"compactAdverseActionsNotificationEmails\": [\n \"\"\n ],\n \"compactOperationsTeamEmails\": [\n \"\"\n ],\n \"configuredStates\": [\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"co\"\n },\n {\n \"isLive\": \"\",\n \"postalAbbreviation\": \"tn\"\n }\n ],\n \"licenseeRegistrationEnabled\": \"\"\n}" }, "header": [ { @@ -610,7 +610,7 @@ "item": [ { "event": [], - "id": "8f56f2f1-82c7-4f9f-b35f-9dcf3de6f115", + "id": "f03e30cb-9ff8-49fa-8bd7-518c9e29272e", "name": "/v1/compacts/:compact/jurisdictions", "protocolProfileBehavior": { "disableBodyPruning": true @@ -663,7 +663,7 @@ "value": "application/json" } ], - "id": "95fbcf95-1684-43ae-923c-5f3743cf6244", + "id": "85c75263-dbc7-4f45-8a6b-04e1fa28fb09", "name": "200 response", "originalRequest": { "body": {}, @@ -705,7 +705,7 @@ "item": [ { "event": [], - "id": "3413a3b0-cf0d-4c19-9cf2-f658240e7e87", + "id": "df1929c4-50ae-4e9a-8c4d-6c32b332333a", "name": "/v1/compacts/:compact/jurisdictions/:jurisdiction", "protocolProfileBehavior": { "disableBodyPruning": true @@ -769,7 +769,7 @@ "value": "application/json" } ], - "id": "316582a0-e609-45e5-9708-2115942c2b4d", + "id": "06c70a4c-1955-4596-b366-96343a6ad510", "name": "200 response", "originalRequest": { "body": {}, @@ -809,7 +809,7 @@ }, { "event": [], - "id": "f9ce288d-da28-46ac-ac92-9d49e56219c0", + "id": "f2ff9f0c-b166-463c-8848-6acc6ebd633c", "name": "/v1/compacts/:compact/jurisdictions/:jurisdiction", "protocolProfileBehavior": { "disableBodyPruning": true @@ -886,7 +886,7 @@ "value": "application/json" } ], - "id": "df6fec71-216d-4872-a9f7-67eefd4ce8ef", + "id": "4a2c1911-5ae3-42de-93cb-ae6093acc10e", "name": "200 response", "originalRequest": { "body": { @@ -970,7 +970,7 @@ } } ], - "id": "26fa5130-19a5-44ec-848e-be174ce2a8bf", + "id": "faf04e77-94e1-49b9-ac88-9b4155648393", "name": "/v1/compacts/:compact/jurisdictions/:jurisdiction/licenses/bulk-upload", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1027,7 +1027,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"upload\": {\n \"fields\": {\n \"nullad\": \"\",\n \"veniam9fd\": \"\",\n \"sunt_5\": \"\"\n },\n \"url\": \"\"\n }\n}", + "body": "{\n \"upload\": {\n \"fields\": {\n \"est_2\": \"\"\n },\n \"url\": \"\"\n }\n}", "code": 200, "cookie": [], "header": [ @@ -1036,7 +1036,7 @@ "value": "application/json" } ], - "id": "28717351-5663-4d20-ad70-d9dd364b93e5", + "id": "2609a867-310e-4063-b759-f069fddcd787", "name": "200 response", "originalRequest": { "body": {}, @@ -1096,7 +1096,7 @@ "item": [ { "event": [], - "id": "632a61a5-7490-4e69-a151-b7c77d37755a", + "id": "eab0da7b-6d1a-452c-ba80-62afa885cc5d", "name": "/v1/compacts/:compact/providers/query", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1110,7 +1110,7 @@ "language": "json" } }, - "raw": "{\n \"query\": {\n \"providerId\": \"d02a383a-0174-4cdd-b4fa-0b1c8d37949b\",\n \"jurisdiction\": \"az\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"descending\"\n }\n}" + "raw": "{\n \"query\": {\n \"providerId\": \"4d3ac645-b43a-4b5b-8d04-6848afa184dd\",\n \"jurisdiction\": \"az\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"descending\"\n }\n}" }, "description": {}, "header": [ @@ -1154,7 +1154,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"pagination\": {\n \"prevLastKey\": {},\n \"lastKey\": {},\n \"pageSize\": \"\"\n },\n \"providers\": [\n {\n \"birthMonthDay\": \"19-07\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"2549-11-02\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseJurisdiction\": \"az\",\n \"licenseStatus\": \"inactive\",\n \"providerId\": \"99e05d9a-5716-46e6-8569-1e685d78606d\",\n \"type\": \"provider\",\n \"dateOfBirth\": \"2055-04-07\",\n \"suffix\": \"\",\n \"ssnLastFour\": \"1748\",\n \"middleName\": \"\"\n },\n {\n \"birthMonthDay\": \"13-01\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"1166-06-30\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseJurisdiction\": \"al\",\n \"licenseStatus\": \"inactive\",\n \"providerId\": \"1ad662bb-8227-4275-aced-0ddeca3776af\",\n \"type\": \"provider\",\n \"dateOfBirth\": \"1694-03-29\",\n \"suffix\": \"\",\n \"ssnLastFour\": \"7199\",\n \"middleName\": \"\"\n }\n ],\n \"sorting\": {\n \"key\": \"familyName\",\n \"direction\": \"ascending\"\n }\n}", + "body": "{\n \"pagination\": {\n \"prevLastKey\": {},\n \"lastKey\": {},\n \"pageSize\": \"\"\n },\n \"providers\": [\n {\n \"birthMonthDay\": \"17-33\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1069-12-09\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseJurisdiction\": \"va\",\n \"licenseStatus\": \"active\",\n \"providerId\": \"e3f87b9e-3722-4ad6-b5bd-e9b1b781a439\",\n \"type\": \"provider\",\n \"dateOfBirth\": \"2002-07-13\",\n \"suffix\": \"\",\n \"ssnLastFour\": \"6991\",\n \"middleName\": \"\"\n },\n {\n \"birthMonthDay\": \"00-05\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"1484-09-07\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseJurisdiction\": \"oh\",\n \"licenseStatus\": \"inactive\",\n \"providerId\": \"46b57d10-344d-465b-b614-ced78affa0aa\",\n \"type\": \"provider\",\n \"dateOfBirth\": \"2999-12-15\",\n \"suffix\": \"\",\n \"ssnLastFour\": \"1060\",\n \"middleName\": \"\"\n }\n ],\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"ascending\"\n }\n}", "code": 200, "cookie": [], "header": [ @@ -1163,7 +1163,7 @@ "value": "application/json" } ], - "id": "5c03d6df-64b9-4585-b2c6-cf5eb78de99a", + "id": "eecb4a66-7473-4b31-8036-914db268d739", "name": "200 response", "originalRequest": { "body": { @@ -1174,7 +1174,7 @@ "language": "json" } }, - "raw": "{\n \"query\": {\n \"providerId\": \"d02a383a-0174-4cdd-b4fa-0b1c8d37949b\",\n \"jurisdiction\": \"az\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"descending\"\n }\n}" + "raw": "{\n \"query\": {\n \"providerId\": \"4d3ac645-b43a-4b5b-8d04-6848afa184dd\",\n \"jurisdiction\": \"az\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"descending\"\n }\n}" }, "header": [ { @@ -1222,7 +1222,7 @@ "item": [ { "event": [], - "id": "2e40b78a-ca98-46ed-b9c7-62a6166956f6", + "id": "dfcc7cf8-c5da-4de4-81e2-72be3d503ed6", "name": "/v1/compacts/:compact/providers/:providerId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1277,7 +1277,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2472-12-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1092-04-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"33cd4e3a-0ae6-4fd9-b15e-b4397f379efb\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"1500-11-23\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2053-02-05\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2299-10-24\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"5e30b385-0a0c-4244-afb2-56d47fcca5d4\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"consumer harm\"\n ],\n \"effectiveLiftDate\": \"1542-06-03\",\n \"liftingUser\": \"\"\n }\n ],\n \"birthMonthDay\": \"18-11\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2501-05-01\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"ks\",\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"2420-04-06\",\n \"dateOfIssuance\": \"1910-03-27\",\n \"dateOfRenewal\": \"2933-12-22\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"va\",\n \"previous\": {\n \"dateOfExpiration\": \"2298-01-15\",\n \"dateOfIssuance\": \"2012-01-30\",\n \"dateOfRenewal\": \"1719-10-29\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"2321-05-31\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+2153693116487\",\n \"licenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"deactivation\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"eligible\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1698-06-05\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"2935-11-07\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"2239-11-31\",\n \"phoneNumber\": \"+351252570452647\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"2272-11-23\",\n \"licenseStatus\": \"active\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"ks\",\n \"previous\": {\n \"dateOfExpiration\": \"1750-02-31\",\n \"dateOfIssuance\": \"1244-09-30\",\n \"dateOfRenewal\": \"1458-10-21\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1267-08-29\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+4873870690\",\n \"licenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"deactivation\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1082-11-08\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"2800-03-15\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"1560-07-05\",\n \"phoneNumber\": \"+79605126\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"1599-03-04\",\n \"licenseStatus\": \"active\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n }\n ],\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"ks\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseStatus\": \"inactive\",\n \"licenseType\": \"esthetician\",\n \"middleName\": \"\",\n \"providerId\": \"5799538c-8282-4b40-83aa-9e5e3bf4ed6e\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"providerId\": \"c218d210-27d1-4a09-8f60-937cc5d9da1a\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"6c8a3c26-49ef-4baa-b721-d4fec6186c7d\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"licenseNumber\": \"\",\n \"investigationStatus\": \"underInvestigation\",\n \"dateOfBirth\": \"1272-02-18\",\n \"ssnLastFour\": \"4860\",\n \"phoneNumber\": \"+443831153\",\n \"licenseStatusName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2410-11-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2966-11-06\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"1957f993-c906-44ab-b922-20689424301a\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"consumer harm\"\n ],\n \"effectiveLiftDate\": \"2337-12-06\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1890-03-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1202-04-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"97e14c28-cf86-491e-9160-b964ac99b681\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"2995-02-27\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1620-01-09\",\n \"dateOfIssuance\": \"1518-10-27\",\n \"dateOfRenewal\": \"1409-03-31\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"ky\",\n \"previous\": {\n \"dateOfExpiration\": \"2687-08-02\",\n \"dateOfIssuance\": \"1800-02-08\",\n \"dateOfRenewal\": \"2182-11-26\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1374-06-05\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+866770080011785\",\n \"licenseStatus\": \"inactive\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"issuance\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"eligible\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2357-07-22\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"2814-11-08\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"2463-05-31\",\n \"phoneNumber\": \"+90394720412714\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"1560-05-30\",\n \"licenseStatus\": \"inactive\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"az\",\n \"previous\": {\n \"dateOfExpiration\": \"2038-09-31\",\n \"dateOfIssuance\": \"2765-09-05\",\n \"dateOfRenewal\": \"2187-08-16\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1325-02-08\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+438228315\",\n \"licenseStatus\": \"inactive\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"deactivation\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1757-06-30\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"1053-11-31\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"1863-10-30\",\n \"phoneNumber\": \"+739439911111475\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"2745-02-29\",\n \"licenseStatus\": \"active\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n }\n ],\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"ks\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"cosmetologist\",\n \"middleName\": \"\",\n \"providerId\": \"af4e6827-c801-41d7-828c-9389db2537c4\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"providerId\": \"5630fde6-f62a-4cb9-a036-6cc61830b3e9\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"providerId\": \"3226ec6c-fe28-4a5e-9a44-c0d120a6f722\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"licenseNumber\": \"\",\n \"investigationStatus\": \"underInvestigation\",\n \"dateOfBirth\": \"1784-10-16\",\n \"ssnLastFour\": \"6968\",\n \"phoneNumber\": \"+598881251843826\",\n \"licenseStatusName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1643-03-12\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1215-07-16\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"b2a0bd6c-79da-48e0-834e-5fb75532902e\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"fraud\"\n ],\n \"effectiveLiftDate\": \"2226-11-24\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1289-12-12\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1702-11-09\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"a1e8c323-be9e-482c-9472-f3f00ee09590\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"fraud\"\n ],\n \"effectiveLiftDate\": \"2438-08-02\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"privileges\": [\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"2622-10-06\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"co\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1567-10-04\",\n \"licenseJurisdiction\": \"tn\",\n \"compact\": \"cosm\",\n \"providerId\": \"73d3fb6f-f3da-46c4-8d73-5c5253ff0e45\",\n \"jurisdiction\": \"al\",\n \"type\": \"privilege\",\n \"status\": \"inactive\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"encumbrance\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"active\",\n \"dateOfExpiration\": \"1500-10-10\",\n \"licenseJurisdiction\": \"wa\",\n \"compact\": \"cosm\",\n \"providerId\": \"bf35acb6-f5af-4068-9b89-f356df4327c3\",\n \"jurisdiction\": \"az\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"inactive\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"va\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1355-02-30\",\n \"licenseJurisdiction\": \"oh\",\n \"compact\": \"cosm\",\n \"providerId\": \"c0b4c15f-b8d1-4cd3-a3f8-67a9c00a7997\",\n \"jurisdiction\": \"co\",\n \"type\": \"privilege\",\n \"status\": \"inactive\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"licenseDeactivation\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"inactive\",\n \"dateOfExpiration\": \"1518-05-15\",\n \"licenseJurisdiction\": \"oh\",\n \"compact\": \"cosm\",\n \"providerId\": \"0b9acd36-849b-4315-b9d0-062b523b83cc\",\n \"jurisdiction\": \"al\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"inactive\"\n }\n }\n ],\n \"jurisdiction\": \"md\",\n \"licenseJurisdiction\": \"tn\",\n \"licenseType\": \"cosmetologist\",\n \"providerId\": \"9fc874d7-ff28-46bd-8632-4aab533d2f75\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"providerId\": \"20cffd60-f5a7-455a-8be0-f0066dc24870\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"providerId\": \"860d7047-48bb-448b-8616-66b96d843098\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1206-12-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1396-10-25\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"acccfcad-80df-4aeb-a83a-b9c680d54f25\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"2864-10-31\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2142-10-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2427-10-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"22f22d7d-e6b8-4614-b7fd-1d950cc6268f\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"consumer harm\"\n ],\n \"effectiveLiftDate\": \"2046-07-04\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1917-05-30\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"al\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1626-09-30\",\n \"licenseJurisdiction\": \"al\",\n \"compact\": \"cosm\",\n \"providerId\": \"fe15a3cf-fef0-417e-b4ae-114717e03a80\",\n \"jurisdiction\": \"wa\",\n \"type\": \"privilege\",\n \"status\": \"inactive\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"lifting_encumbrance\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"active\",\n \"dateOfExpiration\": \"2414-01-04\",\n \"licenseJurisdiction\": \"tn\",\n \"compact\": \"cosm\",\n \"providerId\": \"96224980-aec3-4455-8c42-fdc0f0eb01c9\",\n \"jurisdiction\": \"co\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"inactive\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"ks\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"2835-03-31\",\n \"licenseJurisdiction\": \"az\",\n \"compact\": \"cosm\",\n \"providerId\": \"1561e91b-96db-471d-88f2-af2b1abd0e05\",\n \"jurisdiction\": \"az\",\n \"type\": \"privilege\",\n \"status\": \"inactive\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"expiration\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"inactive\",\n \"dateOfExpiration\": \"1227-04-30\",\n \"licenseJurisdiction\": \"co\",\n \"compact\": \"cosm\",\n \"providerId\": \"01a97a37-120f-4970-b7d7-31e2a5e7b948\",\n \"jurisdiction\": \"al\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"inactive\"\n }\n }\n ],\n \"jurisdiction\": \"al\",\n \"licenseJurisdiction\": \"ky\",\n \"licenseType\": \"cosmetologist\",\n \"providerId\": \"635eb57f-480b-4f8f-88f1-1a8a55eec766\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"aae151a5-5b8a-4cfc-b6f1-d0fd5c81ca7a\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"eb1c2287-1391-4e40-b1be-7d764bb15db2\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2620-07-20\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2405-11-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"78cd57c0-7fe3-45d2-a077-fbdf7bb5f4c6\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"consumer harm\"\n ],\n \"effectiveLiftDate\": \"1416-11-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2713-02-18\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1135-12-27\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"1bf4d4a7-dbdd-4699-9448-449fbc7512ce\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"2692-05-24\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"providerId\": \"4c42f96d-1a2c-4007-beab-eb73d0459239\",\n \"type\": \"provider\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2054-08-02\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"ssnLastFour\": \"5052\",\n \"licenseStatus\": \"inactive\",\n \"middleName\": \"\"\n}", + "body": "{\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1704-11-24\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1022-10-03\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"10ed510d-dc0c-4786-982a-8f1455fdbc7c\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"2902-08-12\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2282-03-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1278-12-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"738f6916-a2d4-4cc6-a958-3149b367d73e\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"consumer harm\"\n ],\n \"effectiveLiftDate\": \"2034-11-11\",\n \"liftingUser\": \"\"\n }\n ],\n \"birthMonthDay\": \"02-17\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1319-11-30\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"az\",\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"2896-10-30\",\n \"dateOfIssuance\": \"1132-05-08\",\n \"dateOfRenewal\": \"2793-09-12\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"al\",\n \"previous\": {\n \"dateOfExpiration\": \"1636-12-14\",\n \"dateOfIssuance\": \"2792-11-01\",\n \"dateOfRenewal\": \"2253-10-25\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2462-11-31\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+945365259726997\",\n \"licenseStatus\": \"inactive\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"issuance\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1425-05-05\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"2974-12-05\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"1104-11-05\",\n \"phoneNumber\": \"+5382331736425\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"2102-02-31\",\n \"licenseStatus\": \"active\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"az\",\n \"previous\": {\n \"dateOfExpiration\": \"2330-11-21\",\n \"dateOfIssuance\": \"2331-05-05\",\n \"dateOfRenewal\": \"2354-05-24\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1165-11-19\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+18967348\",\n \"licenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"licenseDeactivation\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"2551-10-31\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"2064-08-08\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"2303-01-08\",\n \"phoneNumber\": \"+129540280865927\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"2440-11-11\",\n \"licenseStatus\": \"inactive\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n }\n ],\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"va\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseStatus\": \"inactive\",\n \"licenseType\": \"esthetician\",\n \"middleName\": \"\",\n \"providerId\": \"ae61e900-0b46-493a-aa01-d4f2c2c52108\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"dafe7762-702d-4546-bded-1c17a39c6798\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"540737f1-e520-4ba3-a990-7437f1d85bad\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"licenseNumber\": \"\",\n \"investigationStatus\": \"underInvestigation\",\n \"dateOfBirth\": \"1643-12-24\",\n \"ssnLastFour\": \"9281\",\n \"phoneNumber\": \"+84009236542\",\n \"licenseStatusName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2164-09-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2797-12-06\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"d9d8499a-1f5c-4237-852a-4ca7dc9770ad\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"consumer harm\"\n ],\n \"effectiveLiftDate\": \"1975-12-28\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2205-04-11\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2283-02-01\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"7c767061-1812-459f-a808-0e2a2dd06c47\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"consumer harm\"\n ],\n \"effectiveLiftDate\": \"2577-10-31\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"1500-05-30\",\n \"dateOfIssuance\": \"1440-11-10\",\n \"dateOfRenewal\": \"1482-11-30\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"md\",\n \"previous\": {\n \"dateOfExpiration\": \"2810-10-28\",\n \"dateOfIssuance\": \"2039-09-05\",\n \"dateOfRenewal\": \"1259-08-09\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1227-02-30\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+64672574598\",\n \"licenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"licenseDeactivation\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2975-01-30\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"2793-08-06\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"2855-10-13\",\n \"phoneNumber\": \"+963925673992567\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"2755-08-31\",\n \"licenseStatus\": \"inactive\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"az\",\n \"previous\": {\n \"dateOfExpiration\": \"2065-05-27\",\n \"dateOfIssuance\": \"2833-11-09\",\n \"dateOfRenewal\": \"2722-09-12\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"middleName\": \"\",\n \"homeAddressStreet2\": \"\",\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1933-10-05\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+134240923517135\",\n \"licenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatusName\": \"\"\n },\n \"type\": \"licenseUpdate\",\n \"updateType\": \"lifting_encumbrance\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"homeAddressStreet2\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"givenName\": \"\",\n \"homeAddressStreet1\": \"\",\n \"compactEligibility\": \"eligible\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"2959-11-24\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"suffix\": \"\",\n \"dateOfIssuance\": \"2337-07-08\",\n \"emailAddress\": \"\",\n \"dateOfExpiration\": \"2784-06-03\",\n \"phoneNumber\": \"+419715888481085\",\n \"homeAddressState\": \"\",\n \"dateOfRenewal\": \"1072-11-26\",\n \"licenseStatus\": \"inactive\",\n \"familyName\": \"\",\n \"homeAddressCity\": \"\",\n \"licenseNumber\": \"\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n }\n ],\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"va\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"cosmetologist\",\n \"middleName\": \"\",\n \"providerId\": \"3efdca4f-ce9e-4131-aaa5-3c297b20b883\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"providerId\": \"c161a9b0-decf-4f81-9afe-870c8ea33188\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"providerId\": \"8e3092fd-3c68-43d6-b45d-33ae966a9237\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"licenseNumber\": \"\",\n \"investigationStatus\": \"underInvestigation\",\n \"dateOfBirth\": \"2074-12-03\",\n \"ssnLastFour\": \"3747\",\n \"phoneNumber\": \"+61351667777\",\n \"licenseStatusName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1932-11-08\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2639-03-01\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"8e048e34-5113-4a95-b879-45e74e92f405\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"1774-08-26\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1380-09-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1397-04-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"f48aff8a-e316-43b7-b2b0-b6781c5ccd03\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"1079-10-12\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"privileges\": [\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"2132-01-05\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"al\",\n \"previous\": {\n \"administratorSetStatus\": \"inactive\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1007-03-30\",\n \"licenseJurisdiction\": \"al\",\n \"compact\": \"cosm\",\n \"providerId\": \"717a0322-8ff9-4c4f-a991-be019c784fa7\",\n \"jurisdiction\": \"wa\",\n \"type\": \"privilege\",\n \"status\": \"active\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"licenseDeactivation\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"inactive\",\n \"dateOfExpiration\": \"1245-10-30\",\n \"licenseJurisdiction\": \"az\",\n \"compact\": \"cosm\",\n \"providerId\": \"d8b49e12-c262-4cb7-889e-42ab6e01c5af\",\n \"jurisdiction\": \"al\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"active\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"az\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"2796-07-13\",\n \"licenseJurisdiction\": \"wa\",\n \"compact\": \"cosm\",\n \"providerId\": \"92071240-f158-4ee4-86ce-d4037f664eb6\",\n \"jurisdiction\": \"ky\",\n \"type\": \"privilege\",\n \"status\": \"active\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"deactivation\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"inactive\",\n \"dateOfExpiration\": \"1066-12-08\",\n \"licenseJurisdiction\": \"ks\",\n \"compact\": \"cosm\",\n \"providerId\": \"9b120a0f-3c7d-4953-882c-502c123e3756\",\n \"jurisdiction\": \"ks\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"active\"\n }\n }\n ],\n \"jurisdiction\": \"co\",\n \"licenseJurisdiction\": \"ks\",\n \"licenseType\": \"cosmetologist\",\n \"providerId\": \"28817ef4-78db-49d5-85bc-956d06d83b39\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"928a25f0-13e3-4e92-863f-9ee2d4720636\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"providerId\": \"f7ebef49-0486-4534-8d77-8a44f1092383\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1376-11-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1331-11-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"b3ba6720-ee2b-4b24-8999-2314926229f1\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"2544-10-04\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2762-06-02\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2516-11-27\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"e3f3a4c9-0e49-4e3e-9229-fea602ec79f8\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"1096-07-28\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"2641-12-14\",\n \"history\": [\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"co\",\n \"previous\": {\n \"administratorSetStatus\": \"active\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1548-11-17\",\n \"licenseJurisdiction\": \"oh\",\n \"compact\": \"cosm\",\n \"providerId\": \"464113a8-78b3-4149-9f8e-628cc5355a75\",\n \"jurisdiction\": \"oh\",\n \"type\": \"privilege\",\n \"status\": \"active\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"other\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"esthetician\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"inactive\",\n \"dateOfExpiration\": \"1798-05-30\",\n \"licenseJurisdiction\": \"al\",\n \"compact\": \"cosm\",\n \"providerId\": \"2b63e61d-f8fd-4598-9065-9c266af243d9\",\n \"jurisdiction\": \"oh\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"inactive\"\n }\n },\n {\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"jurisdiction\": \"wa\",\n \"previous\": {\n \"administratorSetStatus\": \"inactive\",\n \"compactTransactionId\": \"\",\n \"dateOfExpiration\": \"1267-01-31\",\n \"licenseJurisdiction\": \"md\",\n \"compact\": \"cosm\",\n \"providerId\": \"d9d723c8-ab7b-4133-9eab-7488cc0c3364\",\n \"jurisdiction\": \"md\",\n \"type\": \"privilege\",\n \"status\": \"active\"\n },\n \"type\": \"privilegeUpdate\",\n \"updateType\": \"encumbrance\",\n \"removedValues\": [\n \"\",\n \"\"\n ],\n \"licenseType\": \"cosmetologist\",\n \"updatedValues\": {\n \"administratorSetStatus\": \"inactive\",\n \"dateOfExpiration\": \"2726-07-13\",\n \"licenseJurisdiction\": \"ky\",\n \"compact\": \"cosm\",\n \"providerId\": \"3f0c93d6-fbf7-4c7c-aacd-3ff53e9f3b55\",\n \"jurisdiction\": \"ky\",\n \"type\": \"privilege\",\n \"compactTransactionId\": \"\",\n \"status\": \"active\"\n }\n }\n ],\n \"jurisdiction\": \"al\",\n \"licenseJurisdiction\": \"wa\",\n \"licenseType\": \"esthetician\",\n \"providerId\": \"78e40573-28b0-4e8c-80c0-43369c131a14\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"7370c1ad-02c8-4c3b-b9f1-9cce95d1fba2\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"providerId\": \"04cf1a5d-fcc5-42c4-98e8-d65393cf4a4e\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"adverseActions\": [\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1097-10-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1180-12-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"da629e25-a820-416d-a54c-f579dc9b0557\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"fraud\"\n ],\n \"effectiveLiftDate\": \"1706-12-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2383-06-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2098-04-15\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"d48a1e3c-4efb-476b-8572-929c5ad666e6\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"1137-12-20\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"providerId\": \"f9be7248-5ace-485f-b46e-635d1c052d80\",\n \"type\": \"provider\",\n \"compactEligibility\": \"ineligible\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"dateOfBirth\": \"1703-04-11\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"suffix\": \"\",\n \"ssnLastFour\": \"2985\",\n \"licenseStatus\": \"active\",\n \"middleName\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -1286,7 +1286,7 @@ "value": "application/json" } ], - "id": "667b06b7-de55-40e8-a21e-c63d5d9443b6", + "id": "999d5cc3-d268-40c2-90e5-d0bac445fbb8", "name": "200 response", "originalRequest": { "body": {}, @@ -1344,7 +1344,7 @@ "item": [ { "event": [], - "id": "27c80f06-0fed-4c63-bfd6-01cab86aad85", + "id": "ca7b080a-2bce-4ca7-b22e-7ddaebf2f080", "name": "/v1/compacts/:compact/providers/:providerId/licenses/jurisdiction/:jurisdiction/licenseType/:licenseType/encumbrance", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1358,7 +1358,7 @@ "language": "json" } }, - "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"fraud\"\n ],\n \"encumbranceEffectiveDate\": \"2830-08-11\",\n \"encumbranceType\": \"revocation\"\n}" + "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"fraud\"\n ],\n \"encumbranceEffectiveDate\": \"1968-01-31\",\n \"encumbranceType\": \"surrender of license\"\n}" }, "description": {}, "header": [ @@ -1447,7 +1447,7 @@ "value": "application/json" } ], - "id": "53dc25e2-9cd8-4d80-8a7f-dd6dcd2682bf", + "id": "edb48f26-4d3d-46cc-87dd-58a2d2ad8fda", "name": "200 response", "originalRequest": { "body": { @@ -1458,7 +1458,7 @@ "language": "json" } }, - "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"fraud\"\n ],\n \"encumbranceEffectiveDate\": \"2830-08-11\",\n \"encumbranceType\": \"revocation\"\n}" + "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"fraud\"\n ],\n \"encumbranceEffectiveDate\": \"1968-01-31\",\n \"encumbranceType\": \"surrender of license\"\n}" }, "header": [ { @@ -1509,7 +1509,7 @@ "item": [ { "event": [], - "id": "d705f96c-81d0-49fc-ae0b-9f4afc7d35dc", + "id": "4fe6d742-e13c-4209-ad59-d2160e5414db", "name": "/v1/compacts/:compact/providers/:providerId/licenses/jurisdiction/:jurisdiction/licenseType/:licenseType/encumbrance/:encumbranceId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1523,7 +1523,7 @@ "language": "json" } }, - "raw": "{\n \"effectiveLiftDate\": \"1209-10-31\"\n}" + "raw": "{\n \"effectiveLiftDate\": \"2122-07-31\"\n}" }, "description": {}, "header": [ @@ -1623,7 +1623,7 @@ "value": "application/json" } ], - "id": "24fa9350-47a6-4264-acb9-3db815bb5eed", + "id": "dcd53473-fa87-4ede-91a4-078a78316542", "name": "200 response", "originalRequest": { "body": { @@ -1634,7 +1634,7 @@ "language": "json" } }, - "raw": "{\n \"effectiveLiftDate\": \"1209-10-31\"\n}" + "raw": "{\n \"effectiveLiftDate\": \"2122-07-31\"\n}" }, "header": [ { @@ -1692,7 +1692,7 @@ "item": [ { "event": [], - "id": "2b52498f-6722-4b5b-8f98-dd17f2b029a1", + "id": "0d16004b-e025-44fc-8e1f-405dff9f8ef7", "name": "/v1/compacts/:compact/providers/:providerId/licenses/jurisdiction/:jurisdiction/licenseType/:licenseType/investigation", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1795,7 +1795,7 @@ "value": "application/json" } ], - "id": "74b1ae79-fbc7-44c6-85cc-f5c530f538e5", + "id": "49192cb7-ce70-416c-b3d5-d44dad6d13a5", "name": "200 response", "originalRequest": { "body": { @@ -1857,7 +1857,7 @@ "item": [ { "event": [], - "id": "b5b13c2e-588f-4924-8ab8-bad0464faa9a", + "id": "99c7dfae-c084-400c-8bc9-65301e1fb884", "name": "/v1/compacts/:compact/providers/:providerId/licenses/jurisdiction/:jurisdiction/licenseType/:licenseType/investigation/:investigationId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -1871,7 +1871,7 @@ "language": "json" } }, - "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"other\"\n ],\n \"encumbranceEffectiveDate\": \"2848-12-03\",\n \"encumbranceType\": \"revocation\"\n }\n}" + "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"consumer harm\"\n ],\n \"encumbranceEffectiveDate\": \"2044-11-30\",\n \"encumbranceType\": \"suspension\"\n }\n}" }, "description": {}, "header": [ @@ -1971,7 +1971,7 @@ "value": "application/json" } ], - "id": "cfd3ba5b-5a77-492c-afd3-7160e1faa70d", + "id": "a44d3b21-3a43-4aa7-81cd-5e4fb6cfcc0e", "name": "200 response", "originalRequest": { "body": { @@ -1982,7 +1982,7 @@ "language": "json" } }, - "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"other\"\n ],\n \"encumbranceEffectiveDate\": \"2848-12-03\",\n \"encumbranceType\": \"revocation\"\n }\n}" + "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"consumer harm\"\n ],\n \"encumbranceEffectiveDate\": \"2044-11-30\",\n \"encumbranceType\": \"suspension\"\n }\n}" }, "header": [ { @@ -2070,7 +2070,7 @@ "item": [ { "event": [], - "id": "97163bd0-511f-476f-b3cc-5458ec4df27a", + "id": "3ffbd841-54b4-48a6-b492-641fd2b0469d", "name": "/v1/compacts/:compact/providers/:providerId/privileges/jurisdiction/:jurisdiction/licenseType/:licenseType/encumbrance", "protocolProfileBehavior": { "disableBodyPruning": true @@ -2084,7 +2084,7 @@ "language": "json" } }, - "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"fraud\"\n ],\n \"encumbranceEffectiveDate\": \"2830-08-11\",\n \"encumbranceType\": \"revocation\"\n}" + "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"fraud\"\n ],\n \"encumbranceEffectiveDate\": \"1968-01-31\",\n \"encumbranceType\": \"surrender of license\"\n}" }, "description": {}, "header": [ @@ -2173,7 +2173,7 @@ "value": "application/json" } ], - "id": "7a19d86d-f7b3-4dfb-b1c4-41b167f596c3", + "id": "dcb4c1ba-f090-4a87-8757-635c16610763", "name": "200 response", "originalRequest": { "body": { @@ -2184,7 +2184,7 @@ "language": "json" } }, - "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"fraud\"\n ],\n \"encumbranceEffectiveDate\": \"2830-08-11\",\n \"encumbranceType\": \"revocation\"\n}" + "raw": "{\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"fraud\"\n ],\n \"encumbranceEffectiveDate\": \"1968-01-31\",\n \"encumbranceType\": \"surrender of license\"\n}" }, "header": [ { @@ -2235,7 +2235,7 @@ "item": [ { "event": [], - "id": "213d94c9-ded3-40a1-948e-53d950c31ba8", + "id": "4d611100-ee45-4867-8256-91edf2fc918c", "name": "/v1/compacts/:compact/providers/:providerId/privileges/jurisdiction/:jurisdiction/licenseType/:licenseType/encumbrance/:encumbranceId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -2249,7 +2249,7 @@ "language": "json" } }, - "raw": "{\n \"effectiveLiftDate\": \"1209-10-31\"\n}" + "raw": "{\n \"effectiveLiftDate\": \"2122-07-31\"\n}" }, "description": {}, "header": [ @@ -2349,7 +2349,7 @@ "value": "application/json" } ], - "id": "a6c491c7-e29e-4132-9164-facdb2f7bb23", + "id": "a7cb906d-70d7-481f-99cc-e6fe2c02eba7", "name": "200 response", "originalRequest": { "body": { @@ -2360,7 +2360,7 @@ "language": "json" } }, - "raw": "{\n \"effectiveLiftDate\": \"1209-10-31\"\n}" + "raw": "{\n \"effectiveLiftDate\": \"2122-07-31\"\n}" }, "header": [ { @@ -2418,7 +2418,7 @@ "item": [ { "event": [], - "id": "10d17740-7a12-4a4d-908b-66802ec35668", + "id": "267f553f-e2de-4533-8d28-4fa66717b4ae", "name": "/v1/compacts/:compact/providers/:providerId/privileges/jurisdiction/:jurisdiction/licenseType/:licenseType/investigation", "protocolProfileBehavior": { "disableBodyPruning": true @@ -2521,7 +2521,7 @@ "value": "application/json" } ], - "id": "910c2a5a-2020-424f-b67b-46266de42ee4", + "id": "1dc68a74-87db-46de-b302-0fd21f55f20f", "name": "200 response", "originalRequest": { "body": { @@ -2583,7 +2583,7 @@ "item": [ { "event": [], - "id": "d6c38e7a-7ee8-40d1-8e85-fd9f9bfe046c", + "id": "b26d34d6-168d-4319-8435-d4574eadb833", "name": "/v1/compacts/:compact/providers/:providerId/privileges/jurisdiction/:jurisdiction/licenseType/:licenseType/investigation/:investigationId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -2597,7 +2597,7 @@ "language": "json" } }, - "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"other\"\n ],\n \"encumbranceEffectiveDate\": \"2848-12-03\",\n \"encumbranceType\": \"revocation\"\n }\n}" + "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"consumer harm\"\n ],\n \"encumbranceEffectiveDate\": \"2044-11-30\",\n \"encumbranceType\": \"suspension\"\n }\n}" }, "description": {}, "header": [ @@ -2697,7 +2697,7 @@ "value": "application/json" } ], - "id": "34df120a-8e60-45ff-bfd6-773eb3514a60", + "id": "74f3b10b-973e-4577-8d98-b8c30256ad49", "name": "200 response", "originalRequest": { "body": { @@ -2708,7 +2708,7 @@ "language": "json" } }, - "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"other\"\n ],\n \"encumbranceEffectiveDate\": \"2848-12-03\",\n \"encumbranceType\": \"revocation\"\n }\n}" + "raw": "{\n \"action\": \"close\",\n \"encumbrance\": {\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"consumer harm\"\n ],\n \"encumbranceEffectiveDate\": \"2044-11-30\",\n \"encumbranceType\": \"suspension\"\n }\n}" }, "header": [ { @@ -2787,7 +2787,7 @@ "item": [ { "event": [], - "id": "4684bef3-a4d4-48c1-a025-d52d918d6a82", + "id": "a0f18bc4-8880-4824-a337-03c8e5e9cc0c", "name": "/v1/compacts/:compact/staff-users", "protocolProfileBehavior": { "disableBodyPruning": true @@ -2831,7 +2831,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"pagination\": {\n \"prevLastKey\": {},\n \"lastKey\": {},\n \"pageSize\": \"\"\n },\n \"users\": [\n {\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"eud2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"laboris5\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"aliqua_d2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"irure0a3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"sed_3_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"nulla_53\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"inactive\",\n \"userId\": \"\"\n },\n {\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"esse_a\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"laborum_52\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"dolore_c0\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"temporb\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"id567\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"et_0\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"qui_4f\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"in3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"inactive\",\n \"userId\": \"\"\n }\n ]\n}", + "body": "{\n \"pagination\": {\n \"prevLastKey\": {},\n \"lastKey\": {},\n \"pageSize\": \"\"\n },\n \"users\": [\n {\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"auteb\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"qui_21\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"incididunt434\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"dolor58\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"idb17\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"in74\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"in62\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"quis_17\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"in_cfa\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n },\n {\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"et_cad\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"voluptate_ea3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"in_e8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"dolore2f\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"ipsum_9\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"voluptate_c61\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"inactive\",\n \"userId\": \"\"\n }\n ]\n}", "code": 200, "cookie": [], "header": [ @@ -2849,7 +2849,7 @@ "value": "" } ], - "id": "6d132ca8-65b2-47b7-9c33-d3dc6a5899b8", + "id": "df3a2238-9981-471a-89bd-02afe5da2f7b", "name": "200 response", "originalRequest": { "body": {}, @@ -2888,7 +2888,7 @@ }, { "event": [], - "id": "4be2161c-3e39-4a37-91c4-23bc9451626b", + "id": "81473fa2-b810-48c1-9456-992dd3db3409", "name": "/v1/compacts/:compact/staff-users", "protocolProfileBehavior": { "disableBodyPruning": true @@ -2902,7 +2902,7 @@ "language": "json" } }, - "raw": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"nulla5f3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"eiusmod5\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n }\n}" + "raw": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"aute__\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"dolore980\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"ad2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"nostrud3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"aliquip91\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"dolored1\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"est_00\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n }\n}" }, "description": {}, "header": [ @@ -2945,7 +2945,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"non_c8e\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"proidentadf\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"in_2a3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"sint_8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"est_0_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"laborum6f0\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"utbfd\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"tempor8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", + "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"exa7a\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"dolore_bb7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"ad2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"officiad\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"elit391\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"magna_b7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"dolore671\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"aliqua__5\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"dolorc\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"sede00\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"consectetur_ea\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -2963,7 +2963,7 @@ "value": "" } ], - "id": "95d6cb6c-eb21-4e67-9d89-6814e3f717fc", + "id": "3636f965-1f4d-46b8-9147-8fd2f734e1e6", "name": "200 response", "originalRequest": { "body": { @@ -2974,7 +2974,7 @@ "language": "json" } }, - "raw": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"nulla5f3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"eiusmod5\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n }\n}" + "raw": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"aute__\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"dolore980\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"ad2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"nostrud3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"aliquip91\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"dolored1\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"est_00\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n }\n}" }, "header": [ { @@ -3018,7 +3018,7 @@ "item": [ { "event": [], - "id": "634ccbb2-58fd-4ed1-8b42-49bb33073177", + "id": "b292449c-e000-43cc-9a90-30f4b7c181ca", "name": "/v1/compacts/:compact/staff-users/:userId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3073,7 +3073,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"non_c8e\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"proidentadf\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"in_2a3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"sint_8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"est_0_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"laborum6f0\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"utbfd\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"tempor8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", + "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"exa7a\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"dolore_bb7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"ad2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"officiad\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"elit391\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"magna_b7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"dolore671\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"aliqua__5\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"dolorc\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"sede00\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"consectetur_ea\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -3091,7 +3091,7 @@ "value": "" } ], - "id": "b25ee9de-c254-40ed-9b32-259c7e011f36", + "id": "ec465621-d8b8-4807-b8cb-24aa2e2352b7", "name": "200 response", "originalRequest": { "body": {}, @@ -3138,7 +3138,7 @@ "value": "application/json" } ], - "id": "6f8607dd-7774-47b5-bb08-d3d916adf81e", + "id": "daddd514-5918-4d44-bfab-57c2fe2792fd", "name": "404 response", "originalRequest": { "body": {}, @@ -3178,7 +3178,7 @@ }, { "event": [], - "id": "36d7d4d5-6c2c-4137-8c2f-5570a7ba3294", + "id": "adbb1078-e800-439c-9b7d-79d047e2dbed", "name": "/v1/compacts/:compact/staff-users/:userId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3242,7 +3242,7 @@ "value": "application/json" } ], - "id": "3222f6e6-5b9b-4935-9a82-8323b8ec7c88", + "id": "d6dc4851-2005-4c34-aee3-7ab77090300d", "name": "200 response", "originalRequest": { "body": {}, @@ -3289,7 +3289,7 @@ "value": "application/json" } ], - "id": "724e468b-6e50-4264-ad90-c001a24e9a66", + "id": "29272061-367b-4319-8ca1-40ff0432ab8a", "name": "404 response", "originalRequest": { "body": {}, @@ -3329,7 +3329,7 @@ }, { "event": [], - "id": "b0305f97-7758-47fa-b42b-02b663cc45c0", + "id": "130f1ebd-5fc2-4299-a34b-6ccfb6037caf", "name": "/v1/compacts/:compact/staff-users/:userId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3343,7 +3343,7 @@ "language": "json" } }, - "raw": "{\n \"permissions\": {\n \"ut2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"Excepteur99\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"cupidatata3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"dolor_4_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"ullamco_ab\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"do_4\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"velit_4\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"ut_e26\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n }\n}" + "raw": "{\n \"permissions\": {\n \"mollit02f\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"eu_c\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"fugiat9f\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"eu_5c\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"sint_007\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n }\n}" }, "description": {}, "header": [ @@ -3397,7 +3397,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"non_c8e\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"proidentadf\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"in_2a3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"sint_8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"est_0_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"laborum6f0\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"utbfd\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"tempor8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", + "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"exa7a\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"dolore_bb7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"ad2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"officiad\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"elit391\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"magna_b7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"dolore671\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"aliqua__5\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"dolorc\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"sede00\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"consectetur_ea\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -3415,7 +3415,7 @@ "value": "" } ], - "id": "b15b3532-8280-43f8-99a5-0b17c6daa1c9", + "id": "aa23c905-1c9a-4b76-a807-8650022433be", "name": "200 response", "originalRequest": { "body": { @@ -3426,7 +3426,7 @@ "language": "json" } }, - "raw": "{\n \"permissions\": {\n \"ut2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"Excepteur99\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"cupidatata3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"dolor_4_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"ullamco_ab\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"do_4\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"velit_4\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"ut_e26\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n }\n}" + "raw": "{\n \"permissions\": {\n \"mollit02f\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"eu_c\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"fugiat9f\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"eu_5c\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"sint_007\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n }\n}" }, "header": [ { @@ -3475,7 +3475,7 @@ "value": "application/json" } ], - "id": "24f6e35b-7f08-4e5f-9d76-5ef2359ed57d", + "id": "bdb7f3fa-8f36-4cda-b2a2-12c0b1816e28", "name": "404 response", "originalRequest": { "body": { @@ -3486,7 +3486,7 @@ "language": "json" } }, - "raw": "{\n \"permissions\": {\n \"ut2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"Excepteur99\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"cupidatata3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"dolor_4_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"ullamco_ab\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"do_4\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"velit_4\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"ut_e26\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n }\n}" + "raw": "{\n \"permissions\": {\n \"mollit02f\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"eu_c\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"fugiat9f\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"eu_5c\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"sint_007\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n }\n}" }, "header": [ { @@ -3531,7 +3531,7 @@ "item": [ { "event": [], - "id": "e7b88313-eeb9-4549-8d85-e96aea8d0069", + "id": "1a6f77b0-b795-4c2e-a980-e55303909905", "name": "/v1/compacts/:compact/staff-users/:userId/reinvite", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3596,7 +3596,7 @@ "value": "application/json" } ], - "id": "a0f999a8-904c-4472-9fa6-ccea7c396828", + "id": "0dd9aa1c-4f72-483b-af70-d387710a4653", "name": "200 response", "originalRequest": { "body": {}, @@ -3644,7 +3644,7 @@ "value": "application/json" } ], - "id": "12daddec-6586-431d-ac9f-4e2b59d05238", + "id": "e4bc3418-7a1e-4426-b33c-daca588d6100", "name": "404 response", "originalRequest": { "body": {}, @@ -3709,7 +3709,7 @@ "item": [ { "event": [], - "id": "6d87b2cc-0c26-42fb-a938-52db599c340e", + "id": "fda98b88-10b5-45cb-bc90-f9f31c5499bd", "name": "/v1/flags/:flagId/check", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3726,7 +3726,7 @@ "language": "json" } }, - "raw": "{\n \"context\": {\n \"userId\": \"\",\n \"customAttributes\": {\n \"magna_56\": \"\",\n \"in_20\": \"\",\n \"Excepteur5\": \"\",\n \"anime\": \"\"\n }\n }\n}" + "raw": "{\n \"context\": {\n \"userId\": \"\",\n \"customAttributes\": {\n \"sed_5c3\": \"\",\n \"adipisicing_0\": \"\",\n \"animd3\": \"\",\n \"dolore5\": \"\",\n \"nostrud_7\": \"\"\n }\n }\n}" }, "description": {}, "header": [ @@ -3778,7 +3778,7 @@ "value": "application/json" } ], - "id": "aca887a5-f508-4f5c-9576-f56d982d6e73", + "id": "749ea113-1dbe-4291-abcb-e98163071bc5", "name": "200 response", "originalRequest": { "body": { @@ -3789,7 +3789,7 @@ "language": "json" } }, - "raw": "{\n \"context\": {\n \"userId\": \"\",\n \"customAttributes\": {\n \"magna_56\": \"\",\n \"in_20\": \"\",\n \"Excepteur5\": \"\",\n \"anime\": \"\"\n }\n }\n}" + "raw": "{\n \"context\": {\n \"userId\": \"\",\n \"customAttributes\": {\n \"sed_5c3\": \"\",\n \"adipisicing_0\": \"\",\n \"animd3\": \"\",\n \"dolore5\": \"\",\n \"nostrud_7\": \"\"\n }\n }\n}" }, "header": [ { @@ -3843,7 +3843,7 @@ "item": [ { "event": [], - "id": "7ea490a7-1f67-448b-b1ba-f48a3bda8fe8", + "id": "db05bb1d-1621-429b-ac5f-6714c3afd221", "name": "/v1/public/compacts/:compact/jurisdictions", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3900,7 +3900,7 @@ "value": "application/json" } ], - "id": "3df20685-6c7a-4cf8-907a-be5b206bd84f", + "id": "af03627e-4ae8-4120-b1df-ce4560e79d2d", "name": "200 response", "originalRequest": { "body": {}, @@ -3941,7 +3941,7 @@ "item": [ { "event": [], - "id": "fc06a259-8ad1-4356-843b-2d46bd31f9c8", + "id": "aa1dfd2c-2c5b-4126-aca6-b0b8e98052ff", "name": "/v1/public/compacts/:compact/providers/query", "protocolProfileBehavior": { "disableBodyPruning": true @@ -3958,7 +3958,7 @@ "language": "json" } }, - "raw": "{\n \"query\": {\n \"providerId\": \"d02a383a-0174-4cdd-b4fa-0b1c8d37949b\",\n \"jurisdiction\": \"az\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"descending\"\n }\n}" + "raw": "{\n \"query\": {\n \"providerId\": \"4d3ac645-b43a-4b5b-8d04-6848afa184dd\",\n \"jurisdiction\": \"az\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"descending\"\n }\n}" }, "description": {}, "header": [ @@ -4003,7 +4003,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"pagination\": {\n \"prevLastKey\": {},\n \"lastKey\": {},\n \"pageSize\": \"\"\n },\n \"providers\": [\n {\n \"compact\": \"cosm\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"az\",\n \"licenseNumber\": \"\",\n \"licenseType\": \"\",\n \"providerId\": \"1d2b2f8a-1f82-49f2-b2a4-d45e1571be6d\"\n },\n {\n \"compact\": \"cosm\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"tn\",\n \"licenseNumber\": \"\",\n \"licenseType\": \"\",\n \"providerId\": \"1b639584-9ab9-41ae-97ec-f00106e68b0a\"\n }\n ],\n \"query\": {\n \"providerId\": \"affb525b-577f-4598-b76a-8f0aa23ef846\",\n \"jurisdiction\": \"co\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"ascending\"\n }\n}", + "body": "{\n \"pagination\": {\n \"prevLastKey\": {},\n \"lastKey\": {},\n \"pageSize\": \"\"\n },\n \"providers\": [\n {\n \"compact\": \"cosm\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseEligibility\": \"eligible\",\n \"licenseJurisdiction\": \"wa\",\n \"licenseNumber\": \"\",\n \"licenseType\": \"\",\n \"providerId\": \"69c540cf-1b63-4ed2-962a-240ee3a02271\"\n },\n {\n \"compact\": \"cosm\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseEligibility\": \"eligible\",\n \"licenseJurisdiction\": \"al\",\n \"licenseNumber\": \"\",\n \"licenseType\": \"\",\n \"providerId\": \"7fc1ff84-7ae1-4a38-bb6f-37a7a66d779a\"\n }\n ],\n \"query\": {\n \"providerId\": \"41f57d7c-dd36-4be8-82f2-429348a9ee6b\",\n \"jurisdiction\": \"va\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"sorting\": {\n \"key\": \"familyName\",\n \"direction\": \"ascending\"\n }\n}", "code": 200, "cookie": [], "header": [ @@ -4012,7 +4012,7 @@ "value": "application/json" } ], - "id": "589bc47e-18d3-4ceb-93b4-0211581a954c", + "id": "b8459001-1f3d-4b6b-b8f4-e175eda9df36", "name": "200 response", "originalRequest": { "body": { @@ -4023,7 +4023,7 @@ "language": "json" } }, - "raw": "{\n \"query\": {\n \"providerId\": \"d02a383a-0174-4cdd-b4fa-0b1c8d37949b\",\n \"jurisdiction\": \"az\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"descending\"\n }\n}" + "raw": "{\n \"query\": {\n \"providerId\": \"4d3ac645-b43a-4b5b-8d04-6848afa184dd\",\n \"jurisdiction\": \"az\",\n \"givenName\": \"\",\n \"familyName\": \"\",\n \"licenseNumber\": \"\"\n },\n \"pagination\": {\n \"lastKey\": \"\",\n \"pageSize\": \"\"\n },\n \"sorting\": {\n \"key\": \"dateOfUpdate\",\n \"direction\": \"descending\"\n }\n}" }, "header": [ { @@ -4064,7 +4064,7 @@ "item": [ { "event": [], - "id": "8bb8df8c-bd53-4dff-a092-3221679dff0e", + "id": "119f5aae-3585-4272-955a-9d8213f1467b", "name": "/v1/public/compacts/:compact/providers/:providerId", "protocolProfileBehavior": { "disableBodyPruning": true @@ -4123,7 +4123,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"tn\",\n \"providerId\": \"9fa5506b-47c2-4cf5-8eef-a7293710475b\",\n \"type\": \"provider\",\n \"privileges\": [\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1189-08-06\",\n \"jurisdiction\": \"ks\",\n \"licenseJurisdiction\": \"wa\",\n \"licenseType\": \"esthetician\",\n \"providerId\": \"8dabc2ba-b74e-475b-962f-4caeae8665bd\",\n \"status\": \"active\",\n \"type\": \"privilege\"\n },\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1718-05-19\",\n \"jurisdiction\": \"wa\",\n \"licenseJurisdiction\": \"tn\",\n \"licenseType\": \"cosmetologist\",\n \"providerId\": \"d637db02-84b5-458d-b39c-ae6e82723740\",\n \"status\": \"active\",\n \"type\": \"privilege\"\n }\n ],\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"2367-02-26\",\n \"jurisdiction\": \"ky\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"cosmetologist\",\n \"type\": \"license\"\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"1717-11-31\",\n \"jurisdiction\": \"md\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"type\": \"license\"\n }\n ],\n \"middleName\": \"\",\n \"suffix\": \"\"\n}", + "body": "{\n \"compact\": \"cosm\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"licenseJurisdiction\": \"al\",\n \"providerId\": \"538c4dde-65b9-47e3-be4f-1f785335fbc2\",\n \"type\": \"provider\",\n \"privileges\": [\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2149-12-09\",\n \"jurisdiction\": \"md\",\n \"licenseJurisdiction\": \"tn\",\n \"licenseType\": \"esthetician\",\n \"providerId\": \"37d67147-12c8-4ace-b1f9-dcda9ad436fd\",\n \"status\": \"active\",\n \"type\": \"privilege\"\n },\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1651-11-15\",\n \"jurisdiction\": \"co\",\n \"licenseJurisdiction\": \"tn\",\n \"licenseType\": \"cosmetologist\",\n \"providerId\": \"e3d31465-7766-46a8-af20-82a398cfab02\",\n \"status\": \"inactive\",\n \"type\": \"privilege\"\n }\n ],\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1944-11-30\",\n \"jurisdiction\": \"md\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"type\": \"license\"\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"2388-09-27\",\n \"jurisdiction\": \"al\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"cosmetologist\",\n \"type\": \"license\"\n }\n ],\n \"middleName\": \"\",\n \"suffix\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -4132,7 +4132,7 @@ "value": "application/json" } ], - "id": "05cf7b33-b77e-41dd-9b4b-6893c966da1e", + "id": "3a4dc02a-3913-4516-b1e8-c03b443589bf", "name": "200 response", "originalRequest": { "body": {}, @@ -4183,7 +4183,7 @@ "item": [ { "event": [], - "id": "0168e76f-0277-4763-98f4-372bb9e4e5f6", + "id": "55d7b4b5-c5f2-46f3-837d-c85dfa75d29b", "name": "/v1/public/jurisdictions/live", "protocolProfileBehavior": { "disableBodyPruning": true @@ -4229,7 +4229,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"adipisicingd\": [\n \"ky\",\n \"al\"\n ],\n \"anim_c1a\": [\n \"tn\",\n \"wa\"\n ],\n \"inda_\": [\n \"oh\",\n \"ks\"\n ]\n}", + "body": "{\n \"sed3e\": [\n \"md\",\n \"wa\"\n ],\n \"est_8__\": [\n \"ks\",\n \"ky\"\n ],\n \"sunt8bb\": [\n \"az\",\n \"oh\"\n ]\n}", "code": 200, "cookie": [], "header": [ @@ -4238,7 +4238,7 @@ "value": "application/json" } ], - "id": "a5737f01-733d-421d-ad3f-86c8a70836f9", + "id": "8fa34e72-2336-4ddc-8e0c-61da5d26473e", "name": "200 response", "originalRequest": { "body": {}, @@ -4294,7 +4294,7 @@ "item": [ { "event": [], - "id": "2079833b-681e-4b23-95bf-4691cc193046", + "id": "ee6b9034-05f4-4d93-8e6d-200505d733e3", "name": "/v1/staff-users/me", "protocolProfileBehavior": { "disableBodyPruning": true @@ -4326,7 +4326,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"non_c8e\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"proidentadf\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"in_2a3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"sint_8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"est_0_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"laborum6f0\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"utbfd\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"tempor8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", + "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"exa7a\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"dolore_bb7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"ad2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"officiad\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"elit391\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"magna_b7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"dolore671\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"aliqua__5\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"dolorc\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"sede00\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"consectetur_ea\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -4344,7 +4344,7 @@ "value": "" } ], - "id": "5121b21c-f6fb-43be-831a-c9ccb38f6e23", + "id": "77c410b0-8dfe-4a7e-9f3c-230239f8b9a8", "name": "200 response", "originalRequest": { "body": {}, @@ -4389,7 +4389,7 @@ "value": "application/json" } ], - "id": "a887a5ab-6df1-49b2-bc06-21e70e9aa9d2", + "id": "6b33fac8-04ff-4d58-a141-2e49b5229e77", "name": "404 response", "originalRequest": { "body": {}, @@ -4427,7 +4427,7 @@ }, { "event": [], - "id": "bbed9d6f-bb0e-4b84-8415-b830c9166b31", + "id": "81f67ebf-e4cc-4099-a7d9-dbd9e4e1bf33", "name": "/v1/staff-users/me", "protocolProfileBehavior": { "disableBodyPruning": true @@ -4472,7 +4472,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"non_c8e\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"proidentadf\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"in_2a3\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"sint_8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"est_0_\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"laborum6f0\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"utbfd\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"tempor8\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", + "body": "{\n \"attributes\": {\n \"email\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\"\n },\n \"permissions\": {\n \"exa7a\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"dolore_bb7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"ad2\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"officiad\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"elit391\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"magna_b7\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"dolore671\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"aliqua__5\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n },\n \"dolorc\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n },\n \"sede00\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\"\n },\n \"jurisdictions\": {\n \"consectetur_ea\": {\n \"actions\": {\n \"readPrivate\": \"\",\n \"admin\": \"\",\n \"write\": \"\"\n }\n }\n }\n }\n },\n \"status\": \"active\",\n \"userId\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -4490,7 +4490,7 @@ "value": "" } ], - "id": "2ed3526e-6882-4a90-aefe-996825d58feb", + "id": "34fddfbc-4d3b-4d43-9927-9556500c959f", "name": "200 response", "originalRequest": { "body": { @@ -4548,7 +4548,7 @@ "value": "application/json" } ], - "id": "2387d9f2-20c6-4aab-a1f4-3875b8e2ceb1", + "id": "07da24a7-cb4a-4b43-993e-0e321a15a849", "name": "404 response", "originalRequest": { "body": { diff --git a/backend/cosmetology-app/docs/postman/postman-collection.json b/backend/cosmetology-app/docs/postman/postman-collection.json index 0ce52dede..c6328c0c6 100644 --- a/backend/cosmetology-app/docs/postman/postman-collection.json +++ b/backend/cosmetology-app/docs/postman/postman-collection.json @@ -10,7 +10,7 @@ "type": "bearer" }, "info": { - "_postman_id": "e444fd71-91b5-46e4-bcac-fe1bb2ddf12a", + "_postman_id": "aa3254dc-cc8c-4d01-a794-29804caee5aa", "description": { "content": "", "type": "text/plain" @@ -410,7 +410,7 @@ "item": [ { "event": [], - "id": "ae4dd3d5-9625-4003-b70c-6e0b1e0896d4", + "id": "950dbc5d-759c-46e3-9db1-ae172063583e", "name": "/v1/compacts/:compact/jurisdictions/:jurisdiction/licenses", "protocolProfileBehavior": { "disableBodyPruning": true @@ -424,7 +424,7 @@ "language": "json" } }, - "raw": "[\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2047-09-31\",\n \"dateOfExpiration\": \"2778-12-30\",\n \"dateOfIssuance\": \"1961-10-22\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"cosmetologist\",\n \"ssn\": \"776-14-8717\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+375005223091\",\n \"dateOfRenewal\": \"1874-11-30\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n },\n {\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1822-04-31\",\n \"dateOfExpiration\": \"2511-11-31\",\n \"dateOfIssuance\": \"2096-09-28\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"551-66-3213\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+2352984283\",\n \"dateOfRenewal\": \"2319-11-05\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n]" + "raw": "[\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2159-10-07\",\n \"dateOfExpiration\": \"1122-03-03\",\n \"dateOfIssuance\": \"1692-10-30\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"172-51-9536\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+25906623\",\n \"dateOfRenewal\": \"1987-09-27\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n },\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2188-08-31\",\n \"dateOfExpiration\": \"2548-02-08\",\n \"dateOfIssuance\": \"2942-06-30\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"058-01-7527\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+4163553436\",\n \"dateOfRenewal\": \"2585-11-02\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n]" }, "description": {}, "header": [ @@ -488,7 +488,7 @@ "value": "application/json" } ], - "id": "3dc7d85f-73ff-4370-be60-47ab18257e0c", + "id": "16298898-f09f-429b-8fdc-70c26ca237f9", "name": "200 response", "originalRequest": { "body": { @@ -499,7 +499,7 @@ "language": "json" } }, - "raw": "[\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2047-09-31\",\n \"dateOfExpiration\": \"2778-12-30\",\n \"dateOfIssuance\": \"1961-10-22\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"cosmetologist\",\n \"ssn\": \"776-14-8717\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+375005223091\",\n \"dateOfRenewal\": \"1874-11-30\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n },\n {\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1822-04-31\",\n \"dateOfExpiration\": \"2511-11-31\",\n \"dateOfIssuance\": \"2096-09-28\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"551-66-3213\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+2352984283\",\n \"dateOfRenewal\": \"2319-11-05\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n]" + "raw": "[\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2159-10-07\",\n \"dateOfExpiration\": \"1122-03-03\",\n \"dateOfIssuance\": \"1692-10-30\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"172-51-9536\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+25906623\",\n \"dateOfRenewal\": \"1987-09-27\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n },\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2188-08-31\",\n \"dateOfExpiration\": \"2548-02-08\",\n \"dateOfIssuance\": \"2942-06-30\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"058-01-7527\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+4163553436\",\n \"dateOfRenewal\": \"2585-11-02\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n]" }, "header": [ { @@ -540,7 +540,7 @@ }, { "_postman_previewlanguage": "json", - "body": "{\n \"message\": \"\",\n \"errors\": {\n \"ullamco9\": {\n \"laboris6fd\": [\n \"\",\n \"\"\n ]\n }\n }\n}", + "body": "{\n \"message\": \"\",\n \"errors\": {\n \"nulla76a\": {\n \"tempor_1\": [\n \"\",\n \"\"\n ]\n }\n }\n}", "code": 400, "cookie": [], "header": [ @@ -549,7 +549,7 @@ "value": "application/json" } ], - "id": "9209a379-9a94-4192-b60e-141d660e1b6a", + "id": "de4d86f6-3083-42ec-a2cd-1f5531148be5", "name": "400 response", "originalRequest": { "body": { @@ -560,7 +560,7 @@ "language": "json" } }, - "raw": "[\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2047-09-31\",\n \"dateOfExpiration\": \"2778-12-30\",\n \"dateOfIssuance\": \"1961-10-22\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"cosmetologist\",\n \"ssn\": \"776-14-8717\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+375005223091\",\n \"dateOfRenewal\": \"1874-11-30\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n },\n {\n \"compactEligibility\": \"ineligible\",\n \"dateOfBirth\": \"1822-04-31\",\n \"dateOfExpiration\": \"2511-11-31\",\n \"dateOfIssuance\": \"2096-09-28\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"551-66-3213\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+2352984283\",\n \"dateOfRenewal\": \"2319-11-05\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n]" + "raw": "[\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2159-10-07\",\n \"dateOfExpiration\": \"1122-03-03\",\n \"dateOfIssuance\": \"1692-10-30\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"172-51-9536\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+25906623\",\n \"dateOfRenewal\": \"1987-09-27\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n },\n {\n \"compactEligibility\": \"eligible\",\n \"dateOfBirth\": \"2188-08-31\",\n \"dateOfExpiration\": \"2548-02-08\",\n \"dateOfIssuance\": \"2942-06-30\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"esthetician\",\n \"ssn\": \"058-01-7527\",\n \"homeAddressStreet2\": \"\",\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"phoneNumber\": \"+4163553436\",\n \"dateOfRenewal\": \"2585-11-02\",\n \"middleName\": \"\",\n \"licenseStatusName\": \"\"\n }\n]" }, "header": [ { @@ -631,7 +631,7 @@ } } ], - "id": "94302ab8-108f-40dd-a5bb-01d1e6042939", + "id": "e2d7115d-bc92-4c6e-b6d1-396eecee8832", "name": "/v1/compacts/:compact/jurisdictions/:jurisdiction/licenses/bulk-upload", "protocolProfileBehavior": { "disableBodyPruning": true @@ -688,7 +688,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"upload\": {\n \"fields\": {\n \"ut_9c\": \"\",\n \"non_8f\": \"\"\n },\n \"url\": \"\"\n }\n}", + "body": "{\n \"upload\": {\n \"fields\": {\n \"velitd2\": \"\",\n \"quis_b\": \"\"\n },\n \"url\": \"\"\n }\n}", "code": 200, "cookie": [], "header": [ @@ -697,7 +697,7 @@ "value": "application/json" } ], - "id": "d149ce75-f3ec-4640-a52e-95c04db4d14e", + "id": "55a4e48a-b54d-48a3-bd95-2dc7ec625e63", "name": "200 response", "originalRequest": { "body": {}, diff --git a/backend/cosmetology-app/docs/search-internal/api-specification/latest-oas30.json b/backend/cosmetology-app/docs/search-internal/api-specification/latest-oas30.json index 14e44fe22..c6a545456 100644 --- a/backend/cosmetology-app/docs/search-internal/api-specification/latest-oas30.json +++ b/backend/cosmetology-app/docs/search-internal/api-specification/latest-oas30.json @@ -2,11 +2,14 @@ "openapi": "3.0.1", "info": { "title": "SearchApi", - "version": "2026-03-13T19:50:46Z" + "version": "2026-04-17T19:42:45Z" }, "servers": [ { - "url": "https://search.beta.compactconnect.org" + "url": "https://search.beta.compactconnect.org", + "x-amazon-apigateway-endpoint-configuration": { + "disableExecuteApiEndpoint": true + } } ], "paths": { @@ -34,7 +37,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboSearc6bIbGbp1agwX" + "$ref": "#/components/schemas/TestSSearch7KTSu0MG6ez" } } }, @@ -46,7 +49,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SandboSearce1qe0F7F8UqP" + "$ref": "#/components/schemas/TestSSearcCrqH7R9Q0ysc" } } } @@ -54,7 +57,7 @@ }, "security": [ { - "SandboxSearchAPIStackSearchApiStaffUsersPoolAuthorizer469875BC": [ + "TestBackendCosmetologyTestSearchAPIStackSearchApiStaffUsersPoolAuthorizer02E7F51B": [ "cosm/readGeneral" ] } @@ -64,7 +67,7 @@ }, "components": { "schemas": { - "SandboSearce1qe0F7F8UqP": { + "TestSSearcCrqH7R9Q0ysc": { "required": [ "providers", "total" @@ -287,7 +290,12 @@ "clinicalPrivilegeActionCategories": { "type": "array", "items": { - "type": "string" + "type": "string", + "enum": [ + "fraud", + "consumer harm", + "other" + ] } }, "compact": { @@ -706,7 +714,12 @@ "clinicalPrivilegeActionCategories": { "type": "array", "items": { - "type": "string" + "type": "string", + "enum": [ + "fraud", + "consumer harm", + "other" + ] } }, "compact": { @@ -834,7 +847,7 @@ } } }, - "SandboSearc6bIbGbp1agwX": { + "TestSSearch7KTSu0MG6ez": { "required": [ "query" ], @@ -871,7 +884,7 @@ } }, "securitySchemes": { - "SandboxSearchAPIStackSearchApiStaffUsersPoolAuthorizer469875BC": { + "TestBackendCosmetologyTestSearchAPIStackSearchApiStaffUsersPoolAuthorizer02E7F51B": { "type": "apiKey", "name": "Authorization", "in": "header", diff --git a/backend/cosmetology-app/docs/search-internal/postman/postman-collection.json b/backend/cosmetology-app/docs/search-internal/postman/postman-collection.json index 39b9dd8b9..9975537a2 100644 --- a/backend/cosmetology-app/docs/search-internal/postman/postman-collection.json +++ b/backend/cosmetology-app/docs/search-internal/postman/postman-collection.json @@ -10,7 +10,7 @@ "type": "bearer" }, "info": { - "_postman_id": "1369ff3a-aabc-4f1d-bfde-c195fb7e91e7", + "_postman_id": "109c916e-8844-4045-a72f-985c936f7236", "description": { "content": "", "type": "text/plain" @@ -407,7 +407,7 @@ "item": [ { "event": [], - "id": "02ee167c-b449-48bc-ba9b-05599c65e9f6", + "id": "9a224db1-0801-49dc-bc77-c227ec4ae5d6", "name": "/v1/compacts/:compact/providers/search", "protocolProfileBehavior": { "disableBodyPruning": true @@ -465,7 +465,7 @@ "response": [ { "_postman_previewlanguage": "json", - "body": "{\n \"providers\": [\n {\n \"birthMonthDay\": \"16-02\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseJurisdiction\": \"co\",\n \"licenseStatus\": \"active\",\n \"providerId\": \"983077ef-81b6-4e94-a38d-9ecfda81b86a\",\n \"type\": \"provider\",\n \"privileges\": [\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2707-10-31\",\n \"jurisdiction\": \"al\",\n \"licenseJurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"eaa19666-0c94-40e4-a15b-db3ed72c3bb3\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"providerId\": \"c45c1eed-682f-40cf-9586-62f4d524c01c\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"998f10c3-8571-4c5d-b26c-ba6934198c2b\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2034-07-13\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1515-10-28\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"3f479d09-990a-4d9a-b7ba-41df74b00041\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2271-10-09\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1699-10-22\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2676-02-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"5cbf3e2c-da58-4ee0-b7ce-07dec8207bd6\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2681-04-18\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2987-06-31\",\n \"jurisdiction\": \"co\",\n \"licenseJurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"eae111bd-d3b8-448d-b01d-cc797b006fc0\",\n \"status\": \"inactive\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"providerId\": \"e160d703-de3b-49c7-be24-331f6f3c000b\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"providerId\": \"7fbcb526-c2ec-4d3c-8fd6-3c72870b61d1\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1170-02-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2792-01-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"9afcaf64-67b0-418d-af53-c8096d813948\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2220-01-05\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1220-12-21\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2085-06-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"3cea388c-d4dc-45a1-9c48-caecd5433902\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2664-05-20\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"suffix\": \"\",\n \"currentHomeJurisdiction\": \"md\",\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"1635-05-30\",\n \"dateOfIssuance\": \"2279-12-06\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"va\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"\",\n \"providerId\": \"f5ecbfb0-8245-4dce-bc5c-8e8c3fb720e3\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"1caf7375-85f8-40d4-9d88-1d5bc6478576\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"providerId\": \"39eb05fc-2aca-4c31-ba27-24d53ab319f6\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"2768-02-20\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+17859210533\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2973-11-06\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2861-07-13\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"e88c198f-5081-42f4-8f26-fa6e0d3640d0\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2162-03-10\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2915-10-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2600-09-07\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"5b0a05f2-b595-44d2-9735-1691df5f2068\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2740-12-31\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"1447-08-30\",\n \"dateOfIssuance\": \"2140-11-30\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"az\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"\",\n \"providerId\": \"2a06657c-43d8-4e1f-8cf0-d661da262204\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"providerId\": \"8de6cacb-65ea-46b8-9349-f540f70e66ab\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"f66dbdd5-ddbe-4e23-846c-c3b36082da8f\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"1091-11-01\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+266910525245\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1801-03-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1899-03-29\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"05c59b30-09dc-484c-a37e-e238db0aa2e1\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1399-02-08\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1949-02-06\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2961-12-29\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"d5c72dd2-df42-47e5-9d12-f2a4b0cf4d33\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2645-06-06\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"middleName\": \"\",\n \"compactConnectRegisteredEmailAddress\": \"\"\n },\n {\n \"birthMonthDay\": \"11-31\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseJurisdiction\": \"al\",\n \"licenseStatus\": \"inactive\",\n \"providerId\": \"3c413612-aff7-422f-9ae3-cac05b1d837f\",\n \"type\": \"provider\",\n \"privileges\": [\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2530-12-06\",\n \"jurisdiction\": \"md\",\n \"licenseJurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"d9498e8c-9005-4782-b574-6e6cf0e44011\",\n \"status\": \"inactive\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"providerId\": \"76bb1feb-1b15-434e-935d-9be37563997b\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"providerId\": \"064865aa-71b0-4e48-a07a-6c9a8bbdbd76\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1336-06-14\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1196-02-22\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"06dbbb61-3f81-4f45-b6fc-82443c4f419e\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1791-11-14\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1113-10-04\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1083-12-02\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"8d84550a-baec-4842-a5f8-3d1399b7afda\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2292-10-11\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1226-12-06\",\n \"jurisdiction\": \"md\",\n \"licenseJurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"providerId\": \"492f0fcd-f0f4-457f-b8da-7a7ee442bcac\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"7599e0cf-2c34-4f9b-875c-5ab0ca531c4d\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"e2057bce-3488-4ecc-83df-aec735abc462\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1411-09-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1107-02-07\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"088ed538-7672-4dd8-a192-d08bb7129261\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1999-09-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2451-12-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2938-12-01\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"612dae37-a887-4877-9ee1-c7f9da7e17cf\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1943-03-30\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"suffix\": \"\",\n \"currentHomeJurisdiction\": \"al\",\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1630-06-11\",\n \"dateOfIssuance\": \"2424-03-03\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"md\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"inactive\",\n \"licenseType\": \"\",\n \"providerId\": \"ac33c991-d600-490c-bfca-5f2caac4f117\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"providerId\": \"11cc1dae-f66d-45dd-92a2-fdf7eed8bd86\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"cac6a717-28ed-4398-8e70-bdb956bf8ee3\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"2872-03-09\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+2087609290\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1858-12-25\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1711-12-28\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"346a41e7-21f9-40f3-aa0a-8e6d8693d732\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1776-11-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1142-03-06\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2399-11-12\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"4f9c5550-7026-4660-ad1c-bb825f4fe36d\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2138-02-26\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"1870-01-08\",\n \"dateOfIssuance\": \"2155-09-20\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"ks\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"inactive\",\n \"licenseType\": \"\",\n \"providerId\": \"bd51940e-807e-435d-b9fc-00bd6ad6f7bb\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"providerId\": \"9cb66796-f7f0-4340-9a03-93b2c4b14093\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"04350816-776b-4cf7-bfbe-48a5d17f5432\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"1601-11-31\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+9770350103011\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2894-11-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1672-10-07\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"f1476062-ec15-46b2-a931-50b4cd7cfbf0\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"1514-10-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1782-07-01\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1686-05-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"c59cfdee-1dde-4280-9b69-5f7747e9cfa1\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"\",\n \"\"\n ],\n \"effectiveLiftDate\": \"2431-12-31\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"middleName\": \"\",\n \"compactConnectRegisteredEmailAddress\": \"\"\n }\n ],\n \"total\": {\n \"value\": \"\",\n \"relation\": \"eq\"\n },\n \"lastSort\": \"\"\n}", + "body": "{\n \"providers\": [\n {\n \"birthMonthDay\": \"13-27\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseJurisdiction\": \"oh\",\n \"licenseStatus\": \"inactive\",\n \"providerId\": \"18bebbfa-e8ca-4869-98c4-ffff83095cc5\",\n \"type\": \"provider\",\n \"privileges\": [\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1056-09-29\",\n \"jurisdiction\": \"wa\",\n \"licenseJurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"3d05da9b-c1f5-4592-97f8-3ad8c1146499\",\n \"status\": \"inactive\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"providerId\": \"5b6e2c5d-32fb-45d7-9470-0f8b5f305a85\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"db5e051a-9bde-4174-af6a-414a45ee680d\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1994-10-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1317-12-01\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"e22dc06c-faec-4961-835f-3dd6af6fee8b\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"1740-02-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2731-11-23\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1810-01-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"b0b0b419-b41d-4927-9587-8f0592b35abf\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"consumer harm\"\n ],\n \"effectiveLiftDate\": \"1536-11-16\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"2833-10-15\",\n \"jurisdiction\": \"tn\",\n \"licenseJurisdiction\": \"co\",\n \"licenseType\": \"\",\n \"providerId\": \"4e64bdce-d338-42db-814f-ab46e53e11a0\",\n \"status\": \"inactive\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"85b4ee0a-e8a0-4e16-b5b7-86ecdd686b38\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"cffb7fe0-9bec-4b44-ac08-56091fce440a\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2290-01-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1055-10-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"04dcfddc-ff19-40c7-8380-036f041c076a\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"other\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"1323-12-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1122-05-09\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2752-08-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"d479b788-5309-4b30-9716-89ada3964fd3\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"2600-12-16\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"suffix\": \"\",\n \"currentHomeJurisdiction\": \"co\",\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"1164-01-21\",\n \"dateOfIssuance\": \"2025-10-04\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"va\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"\",\n \"providerId\": \"ee1923a7-7899-4847-be5d-7b5793f64864\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"providerId\": \"b3387c78-bb50-4ba6-9706-dc83e7ba9156\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"3c3bc16f-ad2d-4494-aa23-54b5e3c2146f\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"2273-06-31\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+80837827816\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1327-12-21\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1923-11-01\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"1fa7c5ef-ceb2-452c-ba75-f01d08b36332\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"1979-10-31\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1566-03-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1493-10-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"d9793eb4-5bfe-4c79-940b-3955a567f473\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"fraud\"\n ],\n \"effectiveLiftDate\": \"2231-10-17\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"2933-03-12\",\n \"dateOfIssuance\": \"1248-12-31\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"ks\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"inactive\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"\",\n \"providerId\": \"eefd95b6-9870-4dcc-a988-ffa28375aeea\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ky\",\n \"licenseType\": \"\",\n \"providerId\": \"6ad74b74-6abd-4fc7-b1cd-0290e10fc256\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"bbf87366-cc78-450d-9d95-3079573becb1\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"1790-01-10\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+05715949804\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1762-12-16\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2890-11-30\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"al\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"03a1be0c-1e4b-46c4-bb8d-df0ac470eeb0\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"consumer harm\"\n ],\n \"effectiveLiftDate\": \"1315-03-31\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1410-09-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1082-07-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"e1001d2f-644d-4413-af38-6aefbb9228bf\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"2107-10-19\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"middleName\": \"\",\n \"compactConnectRegisteredEmailAddress\": \"\"\n },\n {\n \"birthMonthDay\": \"13-15\",\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseJurisdiction\": \"al\",\n \"licenseStatus\": \"inactive\",\n \"providerId\": \"02c384d9-c7c1-4bf1-8402-ad53128eb4b7\",\n \"type\": \"provider\",\n \"privileges\": [\n {\n \"administratorSetStatus\": \"inactive\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1863-12-30\",\n \"jurisdiction\": \"wa\",\n \"licenseJurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"39e9cb58-baf9-4897-b8bb-cc2956c2696d\",\n \"status\": \"inactive\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"providerId\": \"3eccb946-d179-4d02-a028-ceb13b435e1c\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"providerId\": \"642dd70a-e6a1-462d-ac58-8a668bf05e2c\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2935-08-17\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2301-11-31\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"ded9577f-5f97-4204-91ab-0cbfed4e2fcc\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"fraud\"\n ],\n \"effectiveLiftDate\": \"2088-06-17\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1620-12-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2898-04-20\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"b216230a-42ce-46b0-9ffb-dfc0a3ba10e6\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"1344-12-07\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"administratorSetStatus\": \"active\",\n \"compact\": \"cosm\",\n \"dateOfExpiration\": \"1799-11-12\",\n \"jurisdiction\": \"md\",\n \"licenseJurisdiction\": \"wa\",\n \"licenseType\": \"\",\n \"providerId\": \"e6efe045-71ac-4c62-a85c-c383af048d75\",\n \"status\": \"active\",\n \"type\": \"privilege\",\n \"investigationStatus\": \"underInvestigation\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"8c28f233-25a3-445a-afce-8581dfcb0735\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"providerId\": \"07fd36be-4b66-4fdb-88a7-8ad918918b5f\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"compactTransactionId\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1818-10-08\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1090-12-08\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"d83df1f7-0b05-4c21-9f4b-4db4da8f3bec\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"1059-10-30\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2981-06-31\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1499-09-05\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"va\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"3793e448-9c55-4c58-ba1d-a492b5900424\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"1432-03-20\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"suffix\": \"\",\n \"currentHomeJurisdiction\": \"wa\",\n \"licenses\": [\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"ineligible\",\n \"dateOfExpiration\": \"1990-01-31\",\n \"dateOfIssuance\": \"2640-06-31\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"tn\",\n \"jurisdictionUploadedCompactEligibility\": \"ineligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"\",\n \"providerId\": \"e72a1eb4-db31-4daf-84a5-752965792065\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"ks\",\n \"licenseType\": \"\",\n \"providerId\": \"653ae65b-5170-4ef7-b736-0851ff1b5479\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"az\",\n \"licenseType\": \"\",\n \"providerId\": \"798235ed-c128-4919-b444-f7b762408915\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"1967-02-31\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+5188469175\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1073-08-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2221-05-16\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"fd50f39a-bfaa-4d5f-a864-d443a901b86c\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"fraud\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"2482-12-06\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"2747-12-24\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1309-03-27\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"5650de1a-c7b7-4045-ab5a-b6e9555dd0f0\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"other\"\n ],\n \"effectiveLiftDate\": \"1738-03-31\",\n \"liftingUser\": \"\"\n }\n ]\n },\n {\n \"compact\": \"cosm\",\n \"compactEligibility\": \"eligible\",\n \"dateOfExpiration\": \"2929-10-11\",\n \"dateOfIssuance\": \"1314-05-07\",\n \"dateOfUpdate\": \"\",\n \"familyName\": \"\",\n \"givenName\": \"\",\n \"homeAddressCity\": \"\",\n \"homeAddressPostalCode\": \"\",\n \"homeAddressState\": \"\",\n \"homeAddressStreet1\": \"\",\n \"jurisdiction\": \"co\",\n \"jurisdictionUploadedCompactEligibility\": \"eligible\",\n \"jurisdictionUploadedLicenseStatus\": \"active\",\n \"licenseNumber\": \"\",\n \"licenseStatus\": \"active\",\n \"licenseType\": \"\",\n \"providerId\": \"beb6d699-b726-4189-9bfd-9c7f37021a65\",\n \"type\": \"license-home\",\n \"homeAddressStreet2\": \"\",\n \"investigations\": [\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"tn\",\n \"licenseType\": \"\",\n \"providerId\": \"842380bf-3c7d-4310-b691-2552f329bc7b\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n },\n {\n \"compact\": \"cosm\",\n \"creationDate\": \"\",\n \"dateOfUpdate\": \"\",\n \"investigationId\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"providerId\": \"dae71a10-e40d-4a8b-a266-7a01c1f4b542\",\n \"submittingUser\": \"\",\n \"type\": \"investigation\"\n }\n ],\n \"suffix\": \"\",\n \"emailAddress\": \"\",\n \"dateOfRenewal\": \"1033-12-05\",\n \"investigationStatus\": \"underInvestigation\",\n \"phoneNumber\": \"+0657366487662\",\n \"licenseStatusName\": \"\",\n \"middleName\": \"\",\n \"adverseActions\": [\n {\n \"actionAgainst\": \"privilege\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1480-11-30\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"2751-08-08\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"md\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"2bedc81f-1a98-4753-b168-393787bad1e2\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"fraud\"\n ],\n \"effectiveLiftDate\": \"1058-01-01\",\n \"liftingUser\": \"\"\n },\n {\n \"actionAgainst\": \"license\",\n \"adverseActionId\": \"\",\n \"compact\": \"cosm\",\n \"creationDate\": \"1999-06-11\",\n \"dateOfUpdate\": \"\",\n \"effectiveStartDate\": \"1422-12-10\",\n \"encumbranceType\": \"\",\n \"jurisdiction\": \"oh\",\n \"licenseType\": \"\",\n \"licenseTypeAbbreviation\": \"\",\n \"providerId\": \"a470dc2b-802b-4d7b-b858-4a286213d4b5\",\n \"submittingUser\": \"\",\n \"type\": \"adverseAction\",\n \"clinicalPrivilegeActionCategories\": [\n \"consumer harm\",\n \"consumer harm\"\n ],\n \"effectiveLiftDate\": \"1438-12-03\",\n \"liftingUser\": \"\"\n }\n ]\n }\n ],\n \"middleName\": \"\",\n \"compactConnectRegisteredEmailAddress\": \"\"\n }\n ],\n \"total\": {\n \"value\": \"\",\n \"relation\": \"eq\"\n },\n \"lastSort\": \"\"\n}", "code": 200, "cookie": [], "header": [ @@ -474,7 +474,7 @@ "value": "application/json" } ], - "id": "9646725c-fe05-4bce-9b1f-3dadb5c4929b", + "id": "383ab925-b14e-427a-8d2b-3ccbfcd51e17", "name": "200 response", "originalRequest": { "body": { diff --git a/backend/cosmetology-app/lambdas/nodejs/email-notification-service/lambda.ts b/backend/cosmetology-app/lambdas/nodejs/email-notification-service/lambda.ts index 03efc991e..a10b98571 100644 --- a/backend/cosmetology-app/lambdas/nodejs/email-notification-service/lambda.ts +++ b/backend/cosmetology-app/lambdas/nodejs/email-notification-service/lambda.ts @@ -7,7 +7,7 @@ import { Context } from 'aws-lambda'; import { EnvironmentVariablesService } from '../lib/environment-variables-service'; import { CompactConfigurationClient } from '../lib/compact-configuration-client'; import { JurisdictionClient } from '../lib/jurisdiction-client'; -import { EncumbranceNotificationService, InvestigationNotificationService } from '../lib/email'; +import { EmailNotificationService, EncumbranceNotificationService, InvestigationNotificationService } from '../lib/email'; import { EmailNotificationEvent, EmailNotificationResponse } from '../lib/models/email-notification-service-event'; const environmentVariables = new EnvironmentVariablesService(); @@ -19,6 +19,7 @@ interface LambdaProperties { } export class Lambda implements LambdaInterface { + private readonly emailService: EmailNotificationService; private readonly encumbranceService: EncumbranceNotificationService; private readonly investigationService: InvestigationNotificationService; @@ -40,6 +41,13 @@ export class Lambda implements LambdaInterface { jurisdictionClient: jurisdictionClient }); + this.emailService = new EmailNotificationService({ + logger: logger, + sesClient: props.sesClient, + compactConfigurationClient: compactConfigurationClient, + jurisdictionClient: jurisdictionClient + }); + this.investigationService = new InvestigationNotificationService({ logger: logger, sesClient: props.sesClient, @@ -319,6 +327,27 @@ export class Lambda implements LambdaInterface { event.templateVariables.licenseType ); break; + case 'homeJurisdictionChangeNotification': + if (!event.jurisdiction) { + throw new Error('Missing required jurisdiction field for home jurisdiction change notification template.'); + } + if (!event.templateVariables?.providerFirstName + || !event.templateVariables?.providerLastName + || !event.templateVariables?.providerId + || !event.templateVariables?.previousJurisdiction + || !event.templateVariables?.newJurisdiction) { + throw new Error('Missing required template variables for home jurisdiction change notification template.'); + } + await this.emailService.sendHomeJurisdictionChangeStateNotificationEmail( + event.compact, + event.jurisdiction, + event.templateVariables.providerFirstName, + event.templateVariables.providerLastName, + event.templateVariables.providerId, + event.templateVariables.previousJurisdiction, + event.templateVariables.newJurisdiction + ); + break; default: logger.info('Unsupported email template provided', { template: event.template }); throw new Error(`Unsupported email template: ${event.template}`); diff --git a/backend/cosmetology-app/lambdas/nodejs/lib/email/base-email-service.ts b/backend/cosmetology-app/lambdas/nodejs/lib/email/base-email-service.ts index d4b7bf99e..7f7689658 100644 --- a/backend/cosmetology-app/lambdas/nodejs/lib/email/base-email-service.ts +++ b/backend/cosmetology-app/lambdas/nodejs/lib/email/base-email-service.ts @@ -367,201 +367,6 @@ export abstract class BaseEmailService { report['root']['data']['childrenIds'].push(blockId); } - protected insertTuple(report: TReaderDocument, keyText: string, valueText: string) { - const containerBlockId = `block-${crypto.randomUUID()}`; - const keyBlockId = `block-${crypto.randomUUID()}`; - const valueBlockId = `block-${crypto.randomUUID()}`; - - - report[keyBlockId] = { - 'type': 'Text', - 'data': { - 'style': { - 'fontWeight': 'bold', - 'padding': { - 'top': 16, - 'bottom': 0, - 'right': 12, - 'left': 24 - } - }, - 'props': { - 'text': keyText - } - } - }; - - report[valueBlockId] = { - 'type': 'Text', - 'data': { - 'style': { - 'color': '#525252', - 'fontSize': 14, - 'fontWeight': 'normal', - 'padding': { - 'top': 0, - 'bottom': 0, - 'right': 24, - 'left': 24 - } - }, - 'props': { - 'text': valueText - } - } - }; - - report[containerBlockId] = { - 'type': 'Container', - 'data': { - 'style': { - 'padding': { - 'top': 0, - 'bottom': 0, - 'right': 72, - 'left': 76 - } - }, - 'props': { - 'childrenIds': [ - keyBlockId, - valueBlockId - ] - } - } - }; - - report['root']['data']['childrenIds'].push(containerBlockId); - } - - protected insertTwoColumnTable(report: TReaderDocument, title: string, rows: { left: string, right: string }[]) { - const titleBlockId = `block-${crypto.randomUUID()}`; - - - report[titleBlockId] = { - 'type': 'Text', - 'data': { - 'style': { - 'fontWeight': 'bold', - 'padding': { - 'top': 24, - 'bottom': 16, - 'right': 24, - 'left': 68 - } - }, - 'props': { - 'text': title - } - } - }; - - report['root']['data']['childrenIds'].push(titleBlockId); - - rows.forEach((row) => { - this.insertTwoColumnRow(report, row.left, row.right, false, 6); - }); - } - - protected insertTwoColumnRow( - report: TReaderDocument, - leftContent: string, - rightContent: string, - isBold: boolean, - bottomPadding: number - ) { - const containerId = `block-${crypto.randomUUID()}`; - const leftCellId = `block-${crypto.randomUUID()}`; - const rightCellId = `block-${crypto.randomUUID()}`; - - report[leftCellId] = { - 'type': 'Text', - 'data': { - 'style': { - 'fontWeight': 'normal', - 'textAlign': 'left', - 'padding': { - 'top': 0, - 'bottom': 0, - 'right': 24, - 'left': 24 - } - }, - 'props': { - 'text': leftContent - } - } - }; - - report[rightCellId] = { - 'type': 'Text', - 'data': { - 'style': { - 'fontWeight': 'normal', - 'textAlign': 'right', - 'padding': { - 'top': 0, - 'bottom': 0, - 'right': 24, - 'left': 24 - } - }, - 'props': { - 'text': rightContent - } - } - }; - - report[containerId] = { - 'type': 'ColumnsContainer', - 'data': { - 'style': { - 'padding': { - 'top': 0, - 'bottom': bottomPadding || 6, - 'right': 44, - 'left': 44 - } - }, - 'props': { - 'fixedWidths': [ - null, - null, - null - ], - 'columnsCount': 2, - 'columnsGap': 10, - 'columns': [ - { - 'childrenIds': [ - leftCellId - ] - }, - { - 'childrenIds': [ - rightCellId - ] - }, - { - 'childrenIds': [] - } - ] - } - } - }; - - if ( - isBold - && report[leftCellId]['data']['style'] - && report[rightCellId]['data']['style'] - ) { - report[leftCellId]['data']['style']['fontWeight'] = 'bold'; - report[rightCellId]['data']['style']['fontWeight'] = 'bold'; - } - - report['root']['data']['childrenIds'].push(containerId); - } - protected insertFooter(report: TReaderDocument) { const blockId = `block-footer`; diff --git a/backend/cosmetology-app/lambdas/nodejs/lib/email/email-notification-service.ts b/backend/cosmetology-app/lambdas/nodejs/lib/email/email-notification-service.ts new file mode 100644 index 000000000..ea1543e8e --- /dev/null +++ b/backend/cosmetology-app/lambdas/nodejs/lib/email/email-notification-service.ts @@ -0,0 +1,80 @@ +import { BaseEmailService } from './base-email-service'; +import { EnvironmentVariablesService } from '../environment-variables-service'; +import { RecipientType } from '../models/email-notification-service-event'; + +const environmentVariableService = new EnvironmentVariablesService(); + +/** + * Email service for handling email notifications + */ +export class EmailNotificationService extends BaseEmailService { + + private async getJurisdictionRecipients( + compact: string, + jurisdiction: string, + recipientType: RecipientType + ): Promise { + + const jurisdictionConfig = await this.jurisdictionClient.getJurisdictionConfiguration(compact, jurisdiction); + + switch (recipientType) { + case 'JURISDICTION_OPERATIONS_TEAM': + return jurisdictionConfig.jurisdictionOperationsTeamEmails; + default: + throw new Error(`Unsupported recipient type for compact configuration: ${recipientType}`); + } + } + + /** + * Sends a notification email to a jurisdiction operations team when a practitioner's home state license changes + * @param compact - The compact name + * @param jurisdiction - The jurisdiction to notify + * @param providerFirstName - The provider's first name + * @param providerLastName - The provider's last name + * @param providerId - The provider's ID + * @param previousJurisdiction - The previous home jurisdiction + * @param newJurisdiction - The new home jurisdiction + */ + public async sendHomeJurisdictionChangeStateNotificationEmail( + compact: string, + jurisdiction: string, + providerFirstName: string, + providerLastName: string, + providerId: string, + previousJurisdiction: string, + newJurisdiction: string + ): Promise { + this.logger.info('Sending home jurisdiction change state notification email', { + compact: compact, + jurisdiction: jurisdiction + }); + + const recipients = await this.getJurisdictionRecipients( + compact, + jurisdiction, + 'JURISDICTION_OPERATIONS_TEAM' + ); + + if (recipients.length === 0) { + throw new Error(`No recipients found for jurisdiction ${jurisdiction} in compact ${compact}`); + } + + const formattedPreviousJurisdiction = previousJurisdiction.toUpperCase(); + const formattedNewJurisdiction = newJurisdiction.toUpperCase(); + + const compactConfig = await this.compactConfigurationClient.getCompactConfiguration(compact); + const report = this.getNewEmailTemplate(); + const subject = `Practitioner Home State Change - ${compactConfig.compactName}`; + const bodyText = `This is to notify you that ${providerFirstName} ${providerLastName} has changed their home state from ${formattedPreviousJurisdiction} to ${formattedNewJurisdiction}.\n\n` + + `Provider Details: ${environmentVariableService.getUiBasePathUrl()}/${compact}/Licensing/${providerId}\n\n` + + 'If the above link does not work, you can copy and paste the url into a browser tab, where you are already logged in.'; + + this.insertHeader(report, subject); + this.insertBody(report, bodyText, 'center', true); + this.insertFooter(report); + + const htmlContent = this.renderTemplate(report); + + await this.sendEmail({ htmlContent, subject, recipients, errorMessage: 'Unable to send home jurisdiction change state notification email' }); + } +} diff --git a/backend/cosmetology-app/lambdas/nodejs/lib/email/index.ts b/backend/cosmetology-app/lambdas/nodejs/lib/email/index.ts index 001ba8e05..6f9d5a2c5 100644 --- a/backend/cosmetology-app/lambdas/nodejs/lib/email/index.ts +++ b/backend/cosmetology-app/lambdas/nodejs/lib/email/index.ts @@ -3,3 +3,4 @@ export { EncumbranceNotificationService } from './encumbrance-notification-servi export { InvestigationNotificationService } from './investigation-notification-service'; export { IngestEventEmailService } from './ingest-event-email-service'; export { EnvironmentBannerService } from './environment-banner-service'; +export { EmailNotificationService } from './email-notification-service'; \ No newline at end of file diff --git a/backend/cosmetology-app/lambdas/nodejs/package.json b/backend/cosmetology-app/lambdas/nodejs/package.json index 31c941213..54a7d170b 100644 --- a/backend/cosmetology-app/lambdas/nodejs/package.json +++ b/backend/cosmetology-app/lambdas/nodejs/package.json @@ -4,7 +4,7 @@ "type": "commonjs", "description": "NodeJS lambdas for CompactConnect", "resolutions": { - "fast-xml-parser": "5.7.0", + "fast-xml-parser": "5.7.3", "postcss": "8.5.10" }, "scripts": { @@ -45,9 +45,9 @@ }, "dependencies": { "@aws-lambda-powertools/logger": "^2.32.0", - "@aws-sdk/client-dynamodb": "^3.1029.0", - "@aws-sdk/client-s3": "^3.1029.0", - "@aws-sdk/client-sesv2": "^3.1029.0", + "@aws-sdk/client-dynamodb": "^3.1045.0", + "@aws-sdk/client-s3": "^3.1045.0", + "@aws-sdk/client-sesv2": "^3.1045.0", "@aws-sdk/util-dynamodb": "^3.996.2", "@csg-org/email-builder": "^0.0.13", "nodemailer": "^8.0.5", diff --git a/backend/cosmetology-app/lambdas/nodejs/tests/email-notification-service.test.ts b/backend/cosmetology-app/lambdas/nodejs/tests/email-notification-service.test.ts index 73857a4a6..d06fc9774 100644 --- a/backend/cosmetology-app/lambdas/nodejs/tests/email-notification-service.test.ts +++ b/backend/cosmetology-app/lambdas/nodejs/tests/email-notification-service.test.ts @@ -1077,4 +1077,95 @@ describe('EmailNotificationServiceLambda', () => { .toThrow('Missing required template variables for privilegeInvestigationClosedStateNotification template.'); }); }); + + describe('Home Jurisdiction Change New State Notification', () => { + const SAMPLE_HOME_JURISDICTION_CHANGE_NEW_STATE_NOTIFICATION_EVENT: EmailNotificationEvent = { + template: 'homeJurisdictionChangeNotification', + recipientType: 'JURISDICTION_OPERATIONS_TEAM', + compact: 'cosm', + jurisdiction: 'tx', + templateVariables: { + providerFirstName: 'John', + providerLastName: 'Doe', + providerId: 'provider-123', + previousJurisdiction: 'tx', + newJurisdiction: 'oh' + } + }; + + it('should successfully send home jurisdiction change notification email', async () => { + const mockTxJurisdictionConfig = { + 'pk': { S: 'cosm#CONFIGURATION' }, + 'sk': { S: 'cosm#JURISDICTION#tx' }, + 'jurisdictionName': { S: 'Texas' }, + 'jurisdictionOperationsTeamEmails': { L: [{ S: 'tx-ops@example.com' }]}, + 'type': { S: 'jurisdiction' } + }; + + mockDynamoDBClient.on(GetItemCommand).callsFake((input) => { + const sk = input.Key.sk.S; + + if (sk === 'cosm#JURISDICTION#tx') { + return Promise.resolve({ Item: mockTxJurisdictionConfig }); + } + if (sk === 'cosm#CONFIGURATION') { + return Promise.resolve({ Item: SAMPLE_COMPACT_CONFIGURATION }); + } + return Promise.resolve({}); + }); + + const response = await lambda.handler( + SAMPLE_HOME_JURISDICTION_CHANGE_NEW_STATE_NOTIFICATION_EVENT, + {} as any + ); + + expect(response).toEqual({ + message: 'Email message sent' + }); + + expect(mockDynamoDBClient).toHaveReceivedCommand(GetItemCommand); + expect(mockSESClient).toHaveReceivedCommandWith(SendEmailCommand, { + Destination: { + ToAddresses: ['tx-ops@example.com'] + }, + Content: { + Simple: { + Body: { + Html: { + Charset: 'UTF-8', + Data: expect.stringContaining('') + } + }, + Subject: { + Charset: 'UTF-8', + Data: 'Practitioner Home State Change - Audiology and Speech Language Pathology' + } + } + }, + FromEmailAddress: 'CompactConnect ' + }); + + const emailCall = mockSESClient.commandCalls(SendEmailCommand)[0]; + const htmlContent = emailCall.args[0].input.Content?.Simple?.Body?.Html?.Data; + + expect(htmlContent).toBeDefined(); + expect(htmlContent).toContain( + 'This is to notify you that John Doe has changed their home state from TX to OH.' + ); + expect(htmlContent).toContain( + 'https://app.test.compactconnect.org/cosm/Licensing/provider-123' + ); + }); + + it('should throw error when required template variables are missing', async () => { + const eventWithMissingVariables: EmailNotificationEvent = { + ...SAMPLE_HOME_JURISDICTION_CHANGE_NEW_STATE_NOTIFICATION_EVENT, + templateVariables: {} + }; + + await expect(lambda.handler(eventWithMissingVariables, {} as any)) + .rejects + .toThrow('Missing required template variables for home jurisdiction change notification template.'); + }); + }); }); diff --git a/backend/cosmetology-app/lambdas/nodejs/yarn.lock b/backend/cosmetology-app/lambdas/nodejs/yarn.lock index 6e5212abb..85817b5cf 100644 --- a/backend/cosmetology-app/lambdas/nodejs/yarn.lock +++ b/backend/cosmetology-app/lambdas/nodejs/yarn.lock @@ -85,177 +85,178 @@ "@aws-lambda-powertools/commons" "2.32.0" "@aws/lambda-invoke-store" "0.2.4" -"@aws-sdk/client-dynamodb@^3.1029.0": - version "3.1029.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1029.0.tgz#2123c4db1ce683e807c931b5a9910567c8ac1cb8" - integrity sha512-5y5BMzg2O8yHBmDfKVnqFCtg7JqpDeMVnRqtccuNZmuG9AjXQD3WeGqxaUPAYrnek3l5fIBGB0PRwoSuelguYw== +"@aws-sdk/client-dynamodb@^3.1045.0": + version "3.1045.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1045.0.tgz#d497a132068b081f6189626a86bea9cdf3d71df0" + integrity sha512-TxZmhpziFxWD3pdXGbuwntKOX5OkW14yvCITYsRz+QDM5EUL4cIygu2xRGHiKDvKmb3QUOA4yKetAQcIMLe2zw== dependencies: "@aws-crypto/sha256-browser" "5.2.0" "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/core" "^3.973.27" - "@aws-sdk/credential-provider-node" "^3.972.30" - "@aws-sdk/dynamodb-codec" "^3.972.28" - "@aws-sdk/middleware-endpoint-discovery" "^3.972.10" - "@aws-sdk/middleware-host-header" "^3.972.9" - "@aws-sdk/middleware-logger" "^3.972.9" - "@aws-sdk/middleware-recursion-detection" "^3.972.10" - "@aws-sdk/middleware-user-agent" "^3.972.29" - "@aws-sdk/region-config-resolver" "^3.972.11" - "@aws-sdk/types" "^3.973.7" - "@aws-sdk/util-endpoints" "^3.996.6" - "@aws-sdk/util-user-agent-browser" "^3.972.9" - "@aws-sdk/util-user-agent-node" "^3.973.15" - "@smithy/config-resolver" "^4.4.14" - "@smithy/core" "^3.23.14" - "@smithy/fetch-http-handler" "^5.3.16" - "@smithy/hash-node" "^4.2.13" - "@smithy/invalid-dependency" "^4.2.13" - "@smithy/middleware-content-length" "^4.2.13" - "@smithy/middleware-endpoint" "^4.4.29" - "@smithy/middleware-retry" "^4.5.0" - "@smithy/middleware-serde" "^4.2.17" - "@smithy/middleware-stack" "^4.2.13" - "@smithy/node-config-provider" "^4.3.13" - "@smithy/node-http-handler" "^4.5.2" - "@smithy/protocol-http" "^5.3.13" - "@smithy/smithy-client" "^4.12.9" - "@smithy/types" "^4.14.0" - "@smithy/url-parser" "^4.2.13" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/credential-provider-node" "^3.972.39" + "@aws-sdk/dynamodb-codec" "^3.973.8" + "@aws-sdk/middleware-endpoint-discovery" "^3.972.11" + "@aws-sdk/middleware-host-header" "^3.972.10" + "@aws-sdk/middleware-logger" "^3.972.10" + "@aws-sdk/middleware-recursion-detection" "^3.972.11" + "@aws-sdk/middleware-user-agent" "^3.972.38" + "@aws-sdk/region-config-resolver" "^3.972.13" + "@aws-sdk/types" "^3.973.8" + "@aws-sdk/util-endpoints" "^3.996.8" + "@aws-sdk/util-user-agent-browser" "^3.972.10" + "@aws-sdk/util-user-agent-node" "^3.973.24" + "@smithy/config-resolver" "^4.4.17" + "@smithy/core" "^3.23.17" + "@smithy/fetch-http-handler" "^5.3.17" + "@smithy/hash-node" "^4.2.14" + "@smithy/invalid-dependency" "^4.2.14" + "@smithy/middleware-content-length" "^4.2.14" + "@smithy/middleware-endpoint" "^4.4.32" + "@smithy/middleware-retry" "^4.5.7" + "@smithy/middleware-serde" "^4.2.20" + "@smithy/middleware-stack" "^4.2.14" + "@smithy/node-config-provider" "^4.3.14" + "@smithy/node-http-handler" "^4.6.1" + "@smithy/protocol-http" "^5.3.14" + "@smithy/smithy-client" "^4.12.13" + "@smithy/types" "^4.14.1" + "@smithy/url-parser" "^4.2.14" "@smithy/util-base64" "^4.3.2" "@smithy/util-body-length-browser" "^4.2.2" "@smithy/util-body-length-node" "^4.2.3" - "@smithy/util-defaults-mode-browser" "^4.3.45" - "@smithy/util-defaults-mode-node" "^4.2.49" - "@smithy/util-endpoints" "^3.3.4" - "@smithy/util-middleware" "^4.2.13" - "@smithy/util-retry" "^4.3.0" + "@smithy/util-defaults-mode-browser" "^4.3.49" + "@smithy/util-defaults-mode-node" "^4.2.54" + "@smithy/util-endpoints" "^3.4.2" + "@smithy/util-middleware" "^4.2.14" + "@smithy/util-retry" "^4.3.6" "@smithy/util-utf8" "^4.2.2" - "@smithy/util-waiter" "^4.2.15" + "@smithy/util-waiter" "^4.3.0" tslib "^2.6.2" -"@aws-sdk/client-s3@^3.1029.0": - version "3.1029.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.1029.0.tgz#7f4dd14b6fd7b0734735a3641f1261c37238e4ea" - integrity sha512-OuA8RZTxsAaHDcI25j2NGLMaYFI2WpJdDzK3uLmVBmaHwjQKQZOUDVVBcln8pNo3IgkY+HRSJhRR4/xlM//UyQ== +"@aws-sdk/client-s3@^3.1045.0": + version "3.1045.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.1045.0.tgz#d41b6d49f0554d3f67a41866dfa6de0e6b8f1a94" + integrity sha512-fsuO3Y6t+3Ro9Bsg41DKj4Sfy53CGSrhnMldNplWmG8Tx0UbYk+YDa4RD1hVlJpERw4JBmPkl0+J9qlxMh1pcA== dependencies: "@aws-crypto/sha1-browser" "5.2.0" "@aws-crypto/sha256-browser" "5.2.0" "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/core" "^3.973.27" - "@aws-sdk/credential-provider-node" "^3.972.30" - "@aws-sdk/middleware-bucket-endpoint" "^3.972.9" - "@aws-sdk/middleware-expect-continue" "^3.972.9" - "@aws-sdk/middleware-flexible-checksums" "^3.974.7" - "@aws-sdk/middleware-host-header" "^3.972.9" - "@aws-sdk/middleware-location-constraint" "^3.972.9" - "@aws-sdk/middleware-logger" "^3.972.9" - "@aws-sdk/middleware-recursion-detection" "^3.972.10" - "@aws-sdk/middleware-sdk-s3" "^3.972.28" - "@aws-sdk/middleware-ssec" "^3.972.9" - "@aws-sdk/middleware-user-agent" "^3.972.29" - "@aws-sdk/region-config-resolver" "^3.972.11" - "@aws-sdk/signature-v4-multi-region" "^3.996.16" - "@aws-sdk/types" "^3.973.7" - "@aws-sdk/util-endpoints" "^3.996.6" - "@aws-sdk/util-user-agent-browser" "^3.972.9" - "@aws-sdk/util-user-agent-node" "^3.973.15" - "@smithy/config-resolver" "^4.4.14" - "@smithy/core" "^3.23.14" - "@smithy/eventstream-serde-browser" "^4.2.13" - "@smithy/eventstream-serde-config-resolver" "^4.3.13" - "@smithy/eventstream-serde-node" "^4.2.13" - "@smithy/fetch-http-handler" "^5.3.16" - "@smithy/hash-blob-browser" "^4.2.14" - "@smithy/hash-node" "^4.2.13" - "@smithy/hash-stream-node" "^4.2.13" - "@smithy/invalid-dependency" "^4.2.13" - "@smithy/md5-js" "^4.2.13" - "@smithy/middleware-content-length" "^4.2.13" - "@smithy/middleware-endpoint" "^4.4.29" - "@smithy/middleware-retry" "^4.5.0" - "@smithy/middleware-serde" "^4.2.17" - "@smithy/middleware-stack" "^4.2.13" - "@smithy/node-config-provider" "^4.3.13" - "@smithy/node-http-handler" "^4.5.2" - "@smithy/protocol-http" "^5.3.13" - "@smithy/smithy-client" "^4.12.9" - "@smithy/types" "^4.14.0" - "@smithy/url-parser" "^4.2.13" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/credential-provider-node" "^3.972.39" + "@aws-sdk/middleware-bucket-endpoint" "^3.972.10" + "@aws-sdk/middleware-expect-continue" "^3.972.10" + "@aws-sdk/middleware-flexible-checksums" "^3.974.16" + "@aws-sdk/middleware-host-header" "^3.972.10" + "@aws-sdk/middleware-location-constraint" "^3.972.10" + "@aws-sdk/middleware-logger" "^3.972.10" + "@aws-sdk/middleware-recursion-detection" "^3.972.11" + "@aws-sdk/middleware-sdk-s3" "^3.972.37" + "@aws-sdk/middleware-ssec" "^3.972.10" + "@aws-sdk/middleware-user-agent" "^3.972.38" + "@aws-sdk/region-config-resolver" "^3.972.13" + "@aws-sdk/signature-v4-multi-region" "^3.996.25" + "@aws-sdk/types" "^3.973.8" + "@aws-sdk/util-endpoints" "^3.996.8" + "@aws-sdk/util-user-agent-browser" "^3.972.10" + "@aws-sdk/util-user-agent-node" "^3.973.24" + "@smithy/config-resolver" "^4.4.17" + "@smithy/core" "^3.23.17" + "@smithy/eventstream-serde-browser" "^4.2.14" + "@smithy/eventstream-serde-config-resolver" "^4.3.14" + "@smithy/eventstream-serde-node" "^4.2.14" + "@smithy/fetch-http-handler" "^5.3.17" + "@smithy/hash-blob-browser" "^4.2.15" + "@smithy/hash-node" "^4.2.14" + "@smithy/hash-stream-node" "^4.2.14" + "@smithy/invalid-dependency" "^4.2.14" + "@smithy/md5-js" "^4.2.14" + "@smithy/middleware-content-length" "^4.2.14" + "@smithy/middleware-endpoint" "^4.4.32" + "@smithy/middleware-retry" "^4.5.7" + "@smithy/middleware-serde" "^4.2.20" + "@smithy/middleware-stack" "^4.2.14" + "@smithy/node-config-provider" "^4.3.14" + "@smithy/node-http-handler" "^4.6.1" + "@smithy/protocol-http" "^5.3.14" + "@smithy/smithy-client" "^4.12.13" + "@smithy/types" "^4.14.1" + "@smithy/url-parser" "^4.2.14" "@smithy/util-base64" "^4.3.2" "@smithy/util-body-length-browser" "^4.2.2" "@smithy/util-body-length-node" "^4.2.3" - "@smithy/util-defaults-mode-browser" "^4.3.45" - "@smithy/util-defaults-mode-node" "^4.2.49" - "@smithy/util-endpoints" "^3.3.4" - "@smithy/util-middleware" "^4.2.13" - "@smithy/util-retry" "^4.3.0" - "@smithy/util-stream" "^4.5.22" + "@smithy/util-defaults-mode-browser" "^4.3.49" + "@smithy/util-defaults-mode-node" "^4.2.54" + "@smithy/util-endpoints" "^3.4.2" + "@smithy/util-middleware" "^4.2.14" + "@smithy/util-retry" "^4.3.6" + "@smithy/util-stream" "^4.5.25" "@smithy/util-utf8" "^4.2.2" - "@smithy/util-waiter" "^4.2.15" + "@smithy/util-waiter" "^4.3.0" tslib "^2.6.2" -"@aws-sdk/client-sesv2@^3.1029.0": - version "3.1029.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sesv2/-/client-sesv2-3.1029.0.tgz#f3a3ce8f41720a2041325eef06e620b4f4d7e1e3" - integrity sha512-ZL2E13IaLQjevcL9nHqT7Jf8EeYfDhgwNyuOh1bp/2ECga+0BzJaHKiASZdvBCZHV+cCDqH3SiGKePUMOxakYA== +"@aws-sdk/client-sesv2@^3.1045.0": + version "3.1045.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sesv2/-/client-sesv2-3.1045.0.tgz#5793588298dd648cf0d5f3baddc8e9bea4e0c9dd" + integrity sha512-Ae6oKWTod06687mIdKPnHPG5tolx/g68tqIbySMoWCs56OmRqn+7JiS3pOlpQeqjhbJlukfrXbsTMgZcXO9cSQ== dependencies: "@aws-crypto/sha256-browser" "5.2.0" "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/core" "^3.973.27" - "@aws-sdk/credential-provider-node" "^3.972.30" - "@aws-sdk/middleware-host-header" "^3.972.9" - "@aws-sdk/middleware-logger" "^3.972.9" - "@aws-sdk/middleware-recursion-detection" "^3.972.10" - "@aws-sdk/middleware-user-agent" "^3.972.29" - "@aws-sdk/region-config-resolver" "^3.972.11" - "@aws-sdk/signature-v4-multi-region" "^3.996.16" - "@aws-sdk/types" "^3.973.7" - "@aws-sdk/util-endpoints" "^3.996.6" - "@aws-sdk/util-user-agent-browser" "^3.972.9" - "@aws-sdk/util-user-agent-node" "^3.973.15" - "@smithy/config-resolver" "^4.4.14" - "@smithy/core" "^3.23.14" - "@smithy/fetch-http-handler" "^5.3.16" - "@smithy/hash-node" "^4.2.13" - "@smithy/invalid-dependency" "^4.2.13" - "@smithy/middleware-content-length" "^4.2.13" - "@smithy/middleware-endpoint" "^4.4.29" - "@smithy/middleware-retry" "^4.5.0" - "@smithy/middleware-serde" "^4.2.17" - "@smithy/middleware-stack" "^4.2.13" - "@smithy/node-config-provider" "^4.3.13" - "@smithy/node-http-handler" "^4.5.2" - "@smithy/protocol-http" "^5.3.13" - "@smithy/smithy-client" "^4.12.9" - "@smithy/types" "^4.14.0" - "@smithy/url-parser" "^4.2.13" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/credential-provider-node" "^3.972.39" + "@aws-sdk/middleware-host-header" "^3.972.10" + "@aws-sdk/middleware-logger" "^3.972.10" + "@aws-sdk/middleware-recursion-detection" "^3.972.11" + "@aws-sdk/middleware-user-agent" "^3.972.38" + "@aws-sdk/region-config-resolver" "^3.972.13" + "@aws-sdk/signature-v4-multi-region" "^3.996.25" + "@aws-sdk/types" "^3.973.8" + "@aws-sdk/util-endpoints" "^3.996.8" + "@aws-sdk/util-user-agent-browser" "^3.972.10" + "@aws-sdk/util-user-agent-node" "^3.973.24" + "@smithy/config-resolver" "^4.4.17" + "@smithy/core" "^3.23.17" + "@smithy/fetch-http-handler" "^5.3.17" + "@smithy/hash-node" "^4.2.14" + "@smithy/invalid-dependency" "^4.2.14" + "@smithy/middleware-content-length" "^4.2.14" + "@smithy/middleware-endpoint" "^4.4.32" + "@smithy/middleware-retry" "^4.5.7" + "@smithy/middleware-serde" "^4.2.20" + "@smithy/middleware-stack" "^4.2.14" + "@smithy/node-config-provider" "^4.3.14" + "@smithy/node-http-handler" "^4.6.1" + "@smithy/protocol-http" "^5.3.14" + "@smithy/smithy-client" "^4.12.13" + "@smithy/types" "^4.14.1" + "@smithy/url-parser" "^4.2.14" "@smithy/util-base64" "^4.3.2" "@smithy/util-body-length-browser" "^4.2.2" "@smithy/util-body-length-node" "^4.2.3" - "@smithy/util-defaults-mode-browser" "^4.3.45" - "@smithy/util-defaults-mode-node" "^4.2.49" - "@smithy/util-endpoints" "^3.3.4" - "@smithy/util-middleware" "^4.2.13" - "@smithy/util-retry" "^4.3.0" + "@smithy/util-defaults-mode-browser" "^4.3.49" + "@smithy/util-defaults-mode-node" "^4.2.54" + "@smithy/util-endpoints" "^3.4.2" + "@smithy/util-middleware" "^4.2.14" + "@smithy/util-retry" "^4.3.6" "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@aws-sdk/core@^3.973.27", "@aws-sdk/core@^3.974.1": - version "3.974.1" - resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.974.1.tgz#69e812e056501060a44bb1e844e66a1932c44c83" - integrity sha512-gy/gffKz0zaHDaqRiLCdIvgHmaAL/HXuAtMcBP7euYSFx4BsbsdlfmUBJag+Gqe62z6/XuloKyQyaiH+kS3Vrg== +"@aws-sdk/core@^3.974.8": + version "3.974.8" + resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.974.8.tgz#cdd51195a31322f1e429e66919eb18da8944c081" + integrity sha512-njR2qoG6ZuB0kvAS2FyICsFZJ6gmCcf2X/7JcD14sUvGDm26wiZ5BrA6LOiUxKFEF+IVe7kdroxyE00YlkiYsw== dependencies: "@aws-sdk/types" "^3.973.8" - "@aws-sdk/xml-builder" "^3.972.18" - "@smithy/core" "^3.23.15" + "@aws-sdk/xml-builder" "^3.972.22" + "@smithy/core" "^3.23.17" "@smithy/node-config-provider" "^4.3.14" "@smithy/property-provider" "^4.2.14" "@smithy/protocol-http" "^5.3.14" "@smithy/signature-v4" "^5.3.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" "@smithy/util-base64" "^4.3.2" "@smithy/util-middleware" "^4.2.14" + "@smithy/util-retry" "^4.3.6" "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" @@ -267,46 +268,46 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-env@^3.972.27": - version "3.972.27" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.27.tgz#296091d01fbad87b56730e4af6c847b5951490a9" - integrity sha512-xfUt2CUZDC+Tf16A6roD1b4pk/nrXdkoLY3TEhv198AXDtBo5xUJP1zd0e8SmuKLN4PpIBX96OizZbmMlcI6oQ== +"@aws-sdk/credential-provider-env@^3.972.34": + version "3.972.34" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.34.tgz#9d420adf02e7604094a641ae613a353aa86e1b83" + integrity sha512-XT0jtf8Fw9JE6ppsQeoNnZRiG+jqRixMT1v1ZR17G60UvVdsQmTG8nbEyHuEPfMxDXEhfdARaM/XiEhca4lGHQ== dependencies: - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/types" "^3.973.8" "@smithy/property-provider" "^4.2.14" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-http@^3.972.29": - version "3.972.29" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.29.tgz#31c4b731bd3200155a03b58e5e6e2fabd2793adf" - integrity sha512-hjNeYb6oLyHgMihra83ie0J/T2y9om3cy1qC90h9DRgvYXEoN4BCFf8bHguZjKhXunnv7YkmZRuYL5Mkk77eCA== +"@aws-sdk/credential-provider-http@^3.972.36": + version "3.972.36" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.36.tgz#842268559da2ffc5855cde1e90e7302d53639c08" + integrity sha512-DPoGWfy7J7RKxvbf5kOKIGQkD2ek3dbKgzKIGrnLuvZBz5myU+Im/H6pmc14QcnFbqHMqxvtWSgRDSJW3qXLQg== dependencies: - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/types" "^3.973.8" "@smithy/fetch-http-handler" "^5.3.17" - "@smithy/node-http-handler" "^4.5.3" + "@smithy/node-http-handler" "^4.6.1" "@smithy/property-provider" "^4.2.14" "@smithy/protocol-http" "^5.3.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" - "@smithy/util-stream" "^4.5.23" + "@smithy/util-stream" "^4.5.25" tslib "^2.6.2" -"@aws-sdk/credential-provider-ini@^3.972.31": - version "3.972.31" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.31.tgz#e6fe3aa4952edb730007545fc3d944362a111edb" - integrity sha512-PuQ7e8WYzAPpzvFcajxf8c0LqSzakVHVlKw8M0oubk8Kf347YOCCqT1seQrHs5AdZuIh2RD9LX4O+Xa5ImEBfQ== - dependencies: - "@aws-sdk/core" "^3.974.1" - "@aws-sdk/credential-provider-env" "^3.972.27" - "@aws-sdk/credential-provider-http" "^3.972.29" - "@aws-sdk/credential-provider-login" "^3.972.31" - "@aws-sdk/credential-provider-process" "^3.972.27" - "@aws-sdk/credential-provider-sso" "^3.972.31" - "@aws-sdk/credential-provider-web-identity" "^3.972.31" - "@aws-sdk/nested-clients" "^3.996.21" +"@aws-sdk/credential-provider-ini@^3.972.38": + version "3.972.38" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.38.tgz#e20955fdfe4a88149b20dc7e25a517542e1dfd9f" + integrity sha512-oDzUBu2MGJFgoar05sPMCwSrhw44ASyccrHzj66vO69OZqi7I6hZZxXfuPLC8OCzW7C+sU+bI73XHij41yekgQ== + dependencies: + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/credential-provider-env" "^3.972.34" + "@aws-sdk/credential-provider-http" "^3.972.36" + "@aws-sdk/credential-provider-login" "^3.972.38" + "@aws-sdk/credential-provider-process" "^3.972.34" + "@aws-sdk/credential-provider-sso" "^3.972.38" + "@aws-sdk/credential-provider-web-identity" "^3.972.38" + "@aws-sdk/nested-clients" "^3.997.6" "@aws-sdk/types" "^3.973.8" "@smithy/credential-provider-imds" "^4.2.14" "@smithy/property-provider" "^4.2.14" @@ -314,13 +315,13 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-login@^3.972.31": - version "3.972.31" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.31.tgz#7a71981679dc44e5d13862a171d5ec9d2bf6e80a" - integrity sha512-bBmWDmtSpmLOZR6a0kmowBcVL1hiL8Vlap/RXeMpFd7JbWl87YcwqL6T9LH/0oBVEZXu1dUZAtojgSuZgMO5xw== +"@aws-sdk/credential-provider-login@^3.972.38": + version "3.972.38" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.38.tgz#278437712c02a3ad1785f70c93b4f591cb3f6491" + integrity sha512-g1NosS8qe4OF++G2UFCM5ovSkgipC7YYor5KCWatG0UoMSO5YFj9C8muePlyVmOBV/WTI16Jo3/s1NUo/o1Bww== dependencies: - "@aws-sdk/core" "^3.974.1" - "@aws-sdk/nested-clients" "^3.996.21" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/nested-clients" "^3.997.6" "@aws-sdk/types" "^3.973.8" "@smithy/property-provider" "^4.2.14" "@smithy/protocol-http" "^5.3.14" @@ -328,17 +329,17 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-node@^3.972.30": - version "3.972.32" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.32.tgz#28466df983be1a6d9de50f431e7e8021af18ceba" - integrity sha512-9aj0x9hGYUondBZSD0XkksAdHhOKttFw4BWpLCeggeg40qSJxGrAP++g0GCm0VqWc1WtC/NRFiAVzPCy56vmog== - dependencies: - "@aws-sdk/credential-provider-env" "^3.972.27" - "@aws-sdk/credential-provider-http" "^3.972.29" - "@aws-sdk/credential-provider-ini" "^3.972.31" - "@aws-sdk/credential-provider-process" "^3.972.27" - "@aws-sdk/credential-provider-sso" "^3.972.31" - "@aws-sdk/credential-provider-web-identity" "^3.972.31" +"@aws-sdk/credential-provider-node@^3.972.39": + version "3.972.39" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.39.tgz#71f87848b7615dda4f31a57b113be9666e4bbd1a" + integrity sha512-HEswDQyxUtadoZ/bJsPPENHg7R0Lzym5LuMksJeHvqhCOpP+rtkDLKI4/ZChH4w3cf5kG8n6bZuI8PzajoiqMg== + dependencies: + "@aws-sdk/credential-provider-env" "^3.972.34" + "@aws-sdk/credential-provider-http" "^3.972.36" + "@aws-sdk/credential-provider-ini" "^3.972.38" + "@aws-sdk/credential-provider-process" "^3.972.34" + "@aws-sdk/credential-provider-sso" "^3.972.38" + "@aws-sdk/credential-provider-web-identity" "^3.972.38" "@aws-sdk/types" "^3.973.8" "@smithy/credential-provider-imds" "^4.2.14" "@smithy/property-provider" "^4.2.14" @@ -346,52 +347,52 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-process@^3.972.27": - version "3.972.27" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.27.tgz#24ae20a1af5c0ab63872f3672696889694c7fa2e" - integrity sha512-1CZvfb1WzudWWIFAVQkd1OI/T1RxPcSvNWzNsb2BMBVsBJzBtB8dV5f2nymHVU4UqwxipdVt/DAbgdDRf33JDg== +"@aws-sdk/credential-provider-process@^3.972.34": + version "3.972.34" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.34.tgz#c964275be1a528ac73ade6d98c309fb6b7cdfb68" + integrity sha512-T3IFs4EVmVi1dVN5RciFnklCANSzvrQd/VuHY9ThHSQmYkTogjcGkoJEr+oNUPQZnso52183088NqysMPji1/Q== dependencies: - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/types" "^3.973.8" "@smithy/property-provider" "^4.2.14" "@smithy/shared-ini-file-loader" "^4.4.9" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-sso@^3.972.31": - version "3.972.31" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.31.tgz#6a5506d65397323740f930ba000aab7622f9be71" - integrity sha512-x8Mx18S48XMl9bEEpYwmXDTvjWGPIfDadReN37Lc099/DUrlL4Zs9T9rwwggo6DkKS1aev6v+MTUx7JTa87TZQ== +"@aws-sdk/credential-provider-sso@^3.972.38": + version "3.972.38" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.38.tgz#ec754bfecb2426a3307e19ef7e6c6b6438a327c6" + integrity sha512-5ZxG+t0+3Q3QPh8KEjX6syskhgNf7I0MN7oGioTf6Lm1NTjfP7sIcYGNsthXC2qR8vcD3edNZwCr2ovfSSWuRA== dependencies: - "@aws-sdk/core" "^3.974.1" - "@aws-sdk/nested-clients" "^3.996.21" - "@aws-sdk/token-providers" "3.1032.0" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/nested-clients" "^3.997.6" + "@aws-sdk/token-providers" "3.1041.0" "@aws-sdk/types" "^3.973.8" "@smithy/property-provider" "^4.2.14" "@smithy/shared-ini-file-loader" "^4.4.9" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/credential-provider-web-identity@^3.972.31": - version "3.972.31" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.31.tgz#e431eceb97dfc53ca4c890bf87f909fa8550c246" - integrity sha512-zfuNMIkGfjYsHis9qytYf74Bcmq6Ji9Xwf4w53baRCI/b2otTwZv3SW1uRiJ5Di7999QzRGhHZ96+eUeo3gSOA== +"@aws-sdk/credential-provider-web-identity@^3.972.38": + version "3.972.38" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.38.tgz#149951ef6e12db5292118e8ed5d95133c24ad719" + integrity sha512-lYHFF30DGI20jZcYX8cm6Ns0V7f1dDN6g/MBDLTyD/5iw+bXs3yBr2iAiHDkx4RFU5JgsnZvCHYKiRVPRdmOgw== dependencies: - "@aws-sdk/core" "^3.974.1" - "@aws-sdk/nested-clients" "^3.996.21" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/nested-clients" "^3.997.6" "@aws-sdk/types" "^3.973.8" "@smithy/property-provider" "^4.2.14" "@smithy/shared-ini-file-loader" "^4.4.9" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/dynamodb-codec@^3.972.28": - version "3.973.1" - resolved "https://registry.yarnpkg.com/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.973.1.tgz#1adf2ee3887b5ca0fe07d232e349c60fac0a78bc" - integrity sha512-BuxJyHW+fnuGLFZ84z5txzlfKXLVbf3hmWH4wQ9q5a/P6O5slNg6j2eUE2kQMYWt3A3PheUR4tgRBUC7j9i/nQ== +"@aws-sdk/dynamodb-codec@^3.973.8": + version "3.973.8" + resolved "https://registry.yarnpkg.com/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.973.8.tgz#e2f0a451eef83a0163e73625fdf7fd1e5b8c110d" + integrity sha512-dYQ/cQqHZd23hcl8oEGwPphTqyGnmvf2HrVmz4J90Q5Bv89oJjlwcBcifiiTvApqsVpx7Pr0IebMpkYwWJvZlQ== dependencies: - "@aws-sdk/core" "^3.974.1" - "@smithy/core" "^3.23.15" + "@aws-sdk/core" "^3.974.8" + "@smithy/core" "^3.23.17" "@smithy/types" "^4.14.1" "@smithy/util-base64" "^4.3.2" tslib "^2.6.2" @@ -404,7 +405,7 @@ mnemonist "0.38.3" tslib "^2.6.2" -"@aws-sdk/middleware-bucket-endpoint@^3.972.9": +"@aws-sdk/middleware-bucket-endpoint@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.10.tgz#d26aa88b441d6d1b6e9275ffdc61e0fbfb55a513" integrity sha512-Vbc2frZH7wXlMNd+ZZSXUEs/l1Sv8Jj4zUnIfwrYF5lwaLdXHZ9xx4U3rjUcaye3HRhFVc+E5DbBxpRAbB16BA== @@ -417,7 +418,7 @@ "@smithy/util-config-provider" "^4.2.2" tslib "^2.6.2" -"@aws-sdk/middleware-endpoint-discovery@^3.972.10": +"@aws-sdk/middleware-endpoint-discovery@^3.972.11": version "3.972.11" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.972.11.tgz#6f1e38f4638272e01b8a32cc91853e79a650db8a" integrity sha512-vXARCZVFQHdsd6qPPZyC/hh+5x2XsCYKqUQDCqnUlpGpChMpDojOOacQWdLJ+FFXKN8X3cmLOGrtgx/zysCKqQ== @@ -429,7 +430,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-expect-continue@^3.972.9": +"@aws-sdk/middleware-expect-continue@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.10.tgz#b685287951156a5d093cfdd37364894c6a8c966c" integrity sha512-2Yn0f1Qiq/DjxYR3wfI3LokXnjOhFM7Ssn4LTdFDIxRMCE6I32MAsVnhPX1cUZsuVA9tiZtwwhlSLAtFGxAZlQ== @@ -439,15 +440,15 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-flexible-checksums@^3.974.7": - version "3.974.9" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.9.tgz#28e3e6c51a6ebdcdbd09725e910a6cb67fbc51f4" - integrity sha512-ye6xVuMEQ5NCT+yQOryGYsuCXnOwu7iGFGzV+qpXZOWtqXIAAaFostapxj6RCubw36rekVwmdB2lcspFuyNfYQ== +"@aws-sdk/middleware-flexible-checksums@^3.974.16": + version "3.974.16" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.16.tgz#89b78cb0ad389aba7d12d060f46017e1fa3784a9" + integrity sha512-6ru8doI0/XzszqLIPXf0E/V7HhAw1Pu94010XCKYtBUfD0LxF0BuOzrUf8OQGR6j2o6wgKTHUniOmndQycHwCA== dependencies: "@aws-crypto/crc32" "5.2.0" "@aws-crypto/crc32c" "5.2.0" "@aws-crypto/util" "5.2.0" - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/crc64-nvme" "^3.972.7" "@aws-sdk/types" "^3.973.8" "@smithy/is-array-buffer" "^4.2.2" @@ -455,11 +456,11 @@ "@smithy/protocol-http" "^5.3.14" "@smithy/types" "^4.14.1" "@smithy/util-middleware" "^4.2.14" - "@smithy/util-stream" "^4.5.23" + "@smithy/util-stream" "^4.5.25" "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@aws-sdk/middleware-host-header@^3.972.10", "@aws-sdk/middleware-host-header@^3.972.9": +"@aws-sdk/middleware-host-header@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.10.tgz#e63b91959ce46948d789582351b2a44c4876e924" integrity sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg== @@ -469,7 +470,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-location-constraint@^3.972.9": +"@aws-sdk/middleware-location-constraint@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.10.tgz#5265ea472f735c50b016bb5d1b46c7a616653733" integrity sha512-rI3NZvJcEvjoD0+0PI0iUAwlPw2IlSlhyvgBK/3WkKJQE/YiKFedd9dMN2lVacdNxPNhxL/jzQaKQdrGtQagjQ== @@ -478,7 +479,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-logger@^3.972.10", "@aws-sdk/middleware-logger@^3.972.9": +"@aws-sdk/middleware-logger@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.972.10.tgz#d92b3374dcaddd523930bdff441207946343c270" integrity sha512-OOuGvvz1Dm20SjZo5oEBePFqxt5nf8AwkNDSyUHvD9/bfNASmstcYxFAHUowy4n6Io7mWUZ04JURZwSBvyQanQ== @@ -487,7 +488,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-recursion-detection@^3.972.10", "@aws-sdk/middleware-recursion-detection@^3.972.11": +"@aws-sdk/middleware-recursion-detection@^3.972.11": version "3.972.11" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.11.tgz#5659982a34fa58c69cbd358c2987c32aefd2bd91" integrity sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ== @@ -498,27 +499,27 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-sdk-s3@^3.972.28", "@aws-sdk/middleware-sdk-s3@^3.972.30": - version "3.972.30" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.30.tgz#cd54439bd298cf16d7aece7bf7afeccc03547b27" - integrity sha512-hoQRxjJu4tt3gEOQin21rJKotClJC+x7AmCh9ylRct1DJeaNI/BRlFxMbuhJe54bG6xANPagSs0my8K30QyV9g== +"@aws-sdk/middleware-sdk-s3@^3.972.37": + version "3.972.37" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.37.tgz#82ef4953cddd3373d2942d07a5d2baf443bbf3ea" + integrity sha512-Km7M+i8DrLArVzrid1gfxeGhYHBd3uxvE77g0s5a52zPSVosxzQBnJ0gwWb6NIp/DOk8gsBMhi7V+cpJG0ndTA== dependencies: - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/types" "^3.973.8" "@aws-sdk/util-arn-parser" "^3.972.3" - "@smithy/core" "^3.23.15" + "@smithy/core" "^3.23.17" "@smithy/node-config-provider" "^4.3.14" "@smithy/protocol-http" "^5.3.14" "@smithy/signature-v4" "^5.3.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" "@smithy/util-config-provider" "^4.2.2" "@smithy/util-middleware" "^4.2.14" - "@smithy/util-stream" "^4.5.23" + "@smithy/util-stream" "^4.5.25" "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@aws-sdk/middleware-ssec@^3.972.9": +"@aws-sdk/middleware-ssec@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.10.tgz#46b5c030c0116f51110e18042ad3cf863ab5c81c" integrity sha512-Gli9A0u8EVVb+5bFDGS/QbSVg28w/wpEidg1ggVcSj65BDTdGR6punsOcVjqdiu1i42WHWo51MCvARPIIz9juw== @@ -527,101 +528,102 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/middleware-user-agent@^3.972.29", "@aws-sdk/middleware-user-agent@^3.972.31": - version "3.972.31" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.31.tgz#691b8cbc8c96d70993a8cf52035e503f9e607e03" - integrity sha512-L+hXN2HDomlIsWSHW5DVD7ppccCeRnlHXZ5uHG34ePTjF5bm0I1fmrJLbUGiW97xRXWryit5cjdP4Sx2FwiGog== +"@aws-sdk/middleware-user-agent@^3.972.38": + version "3.972.38" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.38.tgz#626d9a2499f5a6398a4db917abeeaac14b54c6cb" + integrity sha512-iz+B29TXcAZsJpwB+AwG/TTGA5l/VnmMZ2UxtiySOZjI6gCdmviXPwdgzcmuazMy16rXoPY4mYCGe7zdNKfx5A== dependencies: - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/types" "^3.973.8" - "@aws-sdk/util-endpoints" "^3.996.7" - "@smithy/core" "^3.23.15" + "@aws-sdk/util-endpoints" "^3.996.8" + "@smithy/core" "^3.23.17" "@smithy/protocol-http" "^5.3.14" "@smithy/types" "^4.14.1" - "@smithy/util-retry" "^4.3.2" + "@smithy/util-retry" "^4.3.6" tslib "^2.6.2" -"@aws-sdk/nested-clients@^3.996.21": - version "3.996.21" - resolved "https://registry.yarnpkg.com/@aws-sdk/nested-clients/-/nested-clients-3.996.21.tgz#60148799e399fc002bc6b2b3e09d0024609ab153" - integrity sha512-Me3d/ua2lb2G0bQfFmvCeQQp3+nN6GSPqMxDmi/IQlQ8CrlpQ5C0JJHpz2AnOUkEFI0lBNrAL3Vnt29l44ndkA== +"@aws-sdk/nested-clients@^3.997.6": + version "3.997.6" + resolved "https://registry.yarnpkg.com/@aws-sdk/nested-clients/-/nested-clients-3.997.6.tgz#17433cfac2160ec620a14cbff9d2b33675712cae" + integrity sha512-WBDnqatJl+kGObpfmfSxqnXeYTu3Me8wx8WCtvoxX3pfWrrTv8I4WTMSSs7PZqcRcVh8WeUKMgGFjMG+52SR1w== dependencies: "@aws-crypto/sha256-browser" "5.2.0" "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/core" "^3.974.1" + "@aws-sdk/core" "^3.974.8" "@aws-sdk/middleware-host-header" "^3.972.10" "@aws-sdk/middleware-logger" "^3.972.10" "@aws-sdk/middleware-recursion-detection" "^3.972.11" - "@aws-sdk/middleware-user-agent" "^3.972.31" - "@aws-sdk/region-config-resolver" "^3.972.12" + "@aws-sdk/middleware-user-agent" "^3.972.38" + "@aws-sdk/region-config-resolver" "^3.972.13" + "@aws-sdk/signature-v4-multi-region" "^3.996.25" "@aws-sdk/types" "^3.973.8" - "@aws-sdk/util-endpoints" "^3.996.7" + "@aws-sdk/util-endpoints" "^3.996.8" "@aws-sdk/util-user-agent-browser" "^3.972.10" - "@aws-sdk/util-user-agent-node" "^3.973.17" - "@smithy/config-resolver" "^4.4.16" - "@smithy/core" "^3.23.15" + "@aws-sdk/util-user-agent-node" "^3.973.24" + "@smithy/config-resolver" "^4.4.17" + "@smithy/core" "^3.23.17" "@smithy/fetch-http-handler" "^5.3.17" "@smithy/hash-node" "^4.2.14" "@smithy/invalid-dependency" "^4.2.14" "@smithy/middleware-content-length" "^4.2.14" - "@smithy/middleware-endpoint" "^4.4.30" - "@smithy/middleware-retry" "^4.5.3" - "@smithy/middleware-serde" "^4.2.18" + "@smithy/middleware-endpoint" "^4.4.32" + "@smithy/middleware-retry" "^4.5.7" + "@smithy/middleware-serde" "^4.2.20" "@smithy/middleware-stack" "^4.2.14" "@smithy/node-config-provider" "^4.3.14" - "@smithy/node-http-handler" "^4.5.3" + "@smithy/node-http-handler" "^4.6.1" "@smithy/protocol-http" "^5.3.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" "@smithy/url-parser" "^4.2.14" "@smithy/util-base64" "^4.3.2" "@smithy/util-body-length-browser" "^4.2.2" "@smithy/util-body-length-node" "^4.2.3" - "@smithy/util-defaults-mode-browser" "^4.3.47" - "@smithy/util-defaults-mode-node" "^4.2.52" - "@smithy/util-endpoints" "^3.4.1" + "@smithy/util-defaults-mode-browser" "^4.3.49" + "@smithy/util-defaults-mode-node" "^4.2.54" + "@smithy/util-endpoints" "^3.4.2" "@smithy/util-middleware" "^4.2.14" - "@smithy/util-retry" "^4.3.2" + "@smithy/util-retry" "^4.3.6" "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@aws-sdk/region-config-resolver@^3.972.11", "@aws-sdk/region-config-resolver@^3.972.12": - version "3.972.12" - resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.12.tgz#4156ce4fd065719cd87bdf376c23e3e0b97a6408" - integrity sha512-QQI43Mxd53nBij0pm8HXC+t4IOC6gnhhZfzxE0OATQyO6QfPV4e+aTIRRuAJKA6Nig/cR8eLwPryqYTX9ZrjAQ== +"@aws-sdk/region-config-resolver@^3.972.13": + version "3.972.13" + resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.13.tgz#bd32748c2d41b62be838fec76c4b87d4370939c6" + integrity sha512-CvJ2ZIjK/jVD/lbOpowBVElJyC1YxLTIJ13yM0AEo0t2v7swOzGjSA6lJGH+DwZXQhcjUjoYwc8bVYCX5MDr1A== dependencies: "@aws-sdk/types" "^3.973.8" - "@smithy/config-resolver" "^4.4.16" + "@smithy/config-resolver" "^4.4.17" "@smithy/node-config-provider" "^4.3.14" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/signature-v4-multi-region@^3.996.16": - version "3.996.18" - resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.18.tgz#9043a9060aa41d27fa4a8b795b796bd7b6628c73" - integrity sha512-4KT8UXRmvNAP5zKq9UI1MIwbnmSChZncBt89RKu/skMqZSSWGkBZTAJsZ+no+txfmF3kVaUFv31CTBZkQ5BJpQ== +"@aws-sdk/signature-v4-multi-region@^3.996.25": + version "3.996.25" + resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.25.tgz#b50651b7e4f9c82482416caa9953ad17645d4a2d" + integrity sha512-+CMIt3e1VzlklAECmG+DtP1sV8iKq25FuA0OKpnJ4KA0kxUtd7CgClY7/RU6VzJBQwbN4EJ9Ue6plvqx1qGadw== dependencies: - "@aws-sdk/middleware-sdk-s3" "^3.972.30" + "@aws-sdk/middleware-sdk-s3" "^3.972.37" "@aws-sdk/types" "^3.973.8" "@smithy/protocol-http" "^5.3.14" "@smithy/signature-v4" "^5.3.14" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/token-providers@3.1032.0": - version "3.1032.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.1032.0.tgz#fda2fa76aedbebbc525a0b2ce6bff1e0ed638b3f" - integrity sha512-n+PU8Z+gll7p3wDrH+Wo6fkt8sPrVnq30YYM6Ryga95oJlEneNMEbDHj0iqjMX3V7gaGdJo/hJWyPo4lscP+mA== +"@aws-sdk/token-providers@3.1041.0": + version "3.1041.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.1041.0.tgz#f3f068010780fc85fc4a7faa6a080cfb8afd73a4" + integrity sha512-Th7kPI6YPtvJUcdznooXJMy+9rQWjmEF81LxaJssngBzuysK4a/x+l8kjm1zb7nYsUPbndnBdUnwng/3PLvtGw== dependencies: - "@aws-sdk/core" "^3.974.1" - "@aws-sdk/nested-clients" "^3.996.21" + "@aws-sdk/core" "^3.974.8" + "@aws-sdk/nested-clients" "^3.997.6" "@aws-sdk/types" "^3.973.8" "@smithy/property-provider" "^4.2.14" "@smithy/shared-ini-file-loader" "^4.4.9" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@aws-sdk/types@^3.222.0", "@aws-sdk/types@^3.973.7", "@aws-sdk/types@^3.973.8": +"@aws-sdk/types@^3.222.0", "@aws-sdk/types@^3.973.8": version "3.973.8" resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.973.8.tgz#7352cb74a5f8bae1218eee63e714cf94302911c5" integrity sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw== @@ -643,15 +645,15 @@ dependencies: tslib "^2.6.2" -"@aws-sdk/util-endpoints@^3.996.6", "@aws-sdk/util-endpoints@^3.996.7": - version "3.996.7" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.996.7.tgz#febfca74a3e54d697333c4e89a0890629bb2332b" - integrity sha512-ty4LQxN1QC+YhUP28NfEgZDEGXkyqOQy+BDriBozqHsrYO4JMgiPhfizqOGF7P+euBTZ5Ez6SKlLAMCLo8tzmw== +"@aws-sdk/util-endpoints@^3.996.8": + version "3.996.8" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.996.8.tgz#ad5c4f09b93482c0861d49d8a025edc2b0d2f5ec" + integrity sha512-oOZHcRDihk5iEe5V25NVWg45b3qEA8OpHWVdU/XQh8Zj4heVPAJqWvMphQnU7LkufmUo10EpvFPZuQMiFLJK3g== dependencies: "@aws-sdk/types" "^3.973.8" "@smithy/types" "^4.14.1" "@smithy/url-parser" "^4.2.14" - "@smithy/util-endpoints" "^3.4.1" + "@smithy/util-endpoints" "^3.4.2" tslib "^2.6.2" "@aws-sdk/util-locate-window@^3.0.0": @@ -661,7 +663,7 @@ dependencies: tslib "^2.6.2" -"@aws-sdk/util-user-agent-browser@^3.972.10", "@aws-sdk/util-user-agent-browser@^3.972.9": +"@aws-sdk/util-user-agent-browser@^3.972.10": version "3.972.10" resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.10.tgz#e29be10389db9db12b2d8246ad247a89038f4c60" integrity sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g== @@ -671,25 +673,26 @@ bowser "^2.11.0" tslib "^2.6.2" -"@aws-sdk/util-user-agent-node@^3.973.15", "@aws-sdk/util-user-agent-node@^3.973.17": - version "3.973.17" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.17.tgz#aec872d774478078d72f35e851d98dacb665933e" - integrity sha512-utF5qjjbuJQuU9VdCkWl7L87sr93cApsrD+uxGfUnlafX8iyEzJrb7EZnufjThURZVTOtelRMXrblWxpefElUg== +"@aws-sdk/util-user-agent-node@^3.973.24": + version "3.973.24" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.24.tgz#cf44a63b92adfecaeb8cb9f948b390456310566a" + integrity sha512-ZWwlkjcIp7cEL8ZfTpTAPNkwx25p7xol0xlKoWVVf22+nsjwmLcHYtTPjIV1cSpmB/b6DaK4cb1fSkvCXHgRdw== dependencies: - "@aws-sdk/middleware-user-agent" "^3.972.31" + "@aws-sdk/middleware-user-agent" "^3.972.38" "@aws-sdk/types" "^3.973.8" "@smithy/node-config-provider" "^4.3.14" "@smithy/types" "^4.14.1" "@smithy/util-config-provider" "^4.2.2" tslib "^2.6.2" -"@aws-sdk/xml-builder@^3.972.18": - version "3.972.18" - resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.972.18.tgz#2620fff23f5f20b25cf5d0ef4d4d1ffc12d741a5" - integrity sha512-BMDNVG1ETXRhl1tnisQiYBef3RShJ1kfZA7x7afivTFMLirfHNTb6U71K569HNXhSXbQZsweHvSDZ6euBw8hPA== +"@aws-sdk/xml-builder@^3.972.22": + version "3.972.22" + resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.972.22.tgz#1e44ca9fd9c3fdc3d9af9540ced024f34cfc60b2" + integrity sha512-PMYKKtJd70IsSG0yHrdAbxBr+ZWBKLvzFZfD3/urxgf6hXVMzuU5M+3MJ5G67RpOmLBu1fAUN65SbWuKUCOlAA== dependencies: + "@nodable/entities" "2.1.0" "@smithy/types" "^4.14.1" - fast-xml-parser "5.5.8" + fast-xml-parser "5.7.2" tslib "^2.6.2" "@aws/lambda-invoke-store@0.2.4", "@aws/lambda-invoke-store@^0.2.2": @@ -1699,7 +1702,7 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@nodable/entities@^2.1.0": +"@nodable/entities@2.1.0", "@nodable/entities@^2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@nodable/entities/-/entities-2.1.0.tgz#f543e5c6446720d4cf9e498a83019dd159973bc2" integrity sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA== @@ -1775,22 +1778,22 @@ dependencies: tslib "^2.6.2" -"@smithy/config-resolver@^4.4.14", "@smithy/config-resolver@^4.4.16": - version "4.4.16" - resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-4.4.16.tgz#95652ffb2f29fc6c659fbe8f51d27170862c30ac" - integrity sha512-GFlGPNLZKrGfqWpqVb31z7hvYCA9ZscfX1buYnvvMGcRYsQQnhH+4uN6mWWflcD5jB4OXP/LBrdpukEdjl41tg== +"@smithy/config-resolver@^4.4.17": + version "4.4.17" + resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-4.4.17.tgz#5bd7ccf461e126c79072ce84c6b0f3d00b3409bc" + integrity sha512-TzDZcAnhTyAHbXVxWZo7/tEcrIeFq20IBk8So3OLOetWpR8EwY/yEqBMBFaJMeyEiREDq4NfEl+qO3OAUD+vbQ== dependencies: "@smithy/node-config-provider" "^4.3.14" "@smithy/types" "^4.14.1" "@smithy/util-config-provider" "^4.2.2" - "@smithy/util-endpoints" "^3.4.1" + "@smithy/util-endpoints" "^3.4.2" "@smithy/util-middleware" "^4.2.14" tslib "^2.6.2" -"@smithy/core@^3.23.14", "@smithy/core@^3.23.15": - version "3.23.15" - resolved "https://registry.yarnpkg.com/@smithy/core/-/core-3.23.15.tgz#fdce4411531d4df07f275e96b6fe116583195c84" - integrity sha512-E7GVCgsQttzfujEZb6Qep005wWf4xiL4x06apFEtzQMWYBPggZh/0cnOxPficw5cuK/YjjkehKoIN4YUaSh0UQ== +"@smithy/core@^3.23.17": + version "3.23.17" + resolved "https://registry.yarnpkg.com/@smithy/core/-/core-3.23.17.tgz#23d02277c8d6d30a1605afd756696265e48ed67e" + integrity sha512-x7BlLbUFL8NWCGjMF9C+1N5cVCxcPa7g6Tv9B4A2luWx3be3oU8hQ96wIwxe/s7OhIzvoJH73HAUSg5JXVlEtQ== dependencies: "@smithy/protocol-http" "^5.3.14" "@smithy/types" "^4.14.1" @@ -1798,7 +1801,7 @@ "@smithy/util-base64" "^4.3.2" "@smithy/util-body-length-browser" "^4.2.2" "@smithy/util-middleware" "^4.2.14" - "@smithy/util-stream" "^4.5.23" + "@smithy/util-stream" "^4.5.25" "@smithy/util-utf8" "^4.2.2" "@smithy/uuid" "^1.1.2" tslib "^2.6.2" @@ -1824,7 +1827,7 @@ "@smithy/util-hex-encoding" "^4.2.2" tslib "^2.6.2" -"@smithy/eventstream-serde-browser@^4.2.13": +"@smithy/eventstream-serde-browser@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.14.tgz#b483667ea358975afb2170cd2618b9aa53a0fb29" integrity sha512-8IelTCtTctWRbb+0Dcy+C0aICh1qa0qWXqgjcXDmMuCvPJRnv26hiDZoAau2ILOniki65mCPKqOQs/BaWvO4CQ== @@ -1833,7 +1836,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/eventstream-serde-config-resolver@^4.3.13": +"@smithy/eventstream-serde-config-resolver@^4.3.14": version "4.3.14" resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.14.tgz#2eb23acad43414b9bc0b43f34ae9afbd5464e484" integrity sha512-sqHiHpYRYo3FJlaIxD1J8PhbcmJAm7IuM16mVnwSkCToD7g00IBZzKuiLNMGmftULmEUX6/UAz8/NN5uMP8bVA== @@ -1841,7 +1844,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/eventstream-serde-node@^4.2.13": +"@smithy/eventstream-serde-node@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.14.tgz#402c2a3b0437b7ac9747090a38a60d3642813490" integrity sha512-Ht/8BuGlKfFTy0H3+8eEu0vdpwGztCnaLLXtpXNdQqiR7Hj4vFScU3T436vRAjATglOIPjJXronY+1WxxNLSiw== @@ -1859,7 +1862,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/fetch-http-handler@^5.3.16", "@smithy/fetch-http-handler@^5.3.17": +"@smithy/fetch-http-handler@^5.3.17": version "5.3.17" resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.17.tgz#bf13a4b03eb8afe101775fef59a1758f8fb5cd4b" integrity sha512-bXOvQzaSm6MnmLaWA1elgfQcAtN4UP3vXqV97bHuoOrHQOJiLT3ds6o9eo5bqd0TJfRFpzdGnDQdW3FACiAVdw== @@ -1870,7 +1873,7 @@ "@smithy/util-base64" "^4.3.2" tslib "^2.6.2" -"@smithy/hash-blob-browser@^4.2.14": +"@smithy/hash-blob-browser@^4.2.15": version "4.2.15" resolved "https://registry.yarnpkg.com/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.15.tgz#1323f9717cad352b3e18065b738387bb9684f993" integrity sha512-0PJ4Al3fg2nM4qKrAIxyNcApgqHAXcBkN8FeizOz69z0rb26uZ6lMESYtxegaTlXB5Hj84JfwMPavMrwDMjucA== @@ -1880,7 +1883,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/hash-node@^4.2.13", "@smithy/hash-node@^4.2.14": +"@smithy/hash-node@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-4.2.14.tgz#e3ed33dc614e26fff5f043e097750c6931b48592" integrity sha512-8ZBDY2DD4wr+GGjTpPtiglEsqr0lUP+KHqgZcWczFf6qeZ/YRjMIOoQWVQlmwu7EtxKTd8YXD8lblmYcpBIA1g== @@ -1890,7 +1893,7 @@ "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@smithy/hash-stream-node@^4.2.13": +"@smithy/hash-stream-node@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/hash-stream-node/-/hash-stream-node-4.2.14.tgz#98bc14e79e2be852d04ff6cbfe4b0babe48fb10d" integrity sha512-tw4GANWkZPb6+BdD4Fgucqzey2+r73Z/GRo9zklsCdwrnxxumUV83ZIaBDdudV4Ylazw3EPTiJZhpX42105ruQ== @@ -1899,7 +1902,7 @@ "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@smithy/invalid-dependency@^4.2.13", "@smithy/invalid-dependency@^4.2.14": +"@smithy/invalid-dependency@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-4.2.14.tgz#a52766f9d4299abcd9d6cd23b5a76f34fc59c7a0" integrity sha512-c21qJiTSb25xvvOp+H2TNZzPCngrvl5vIPqPB8zQ/DmJF4QWXO19x1dWfMJZ6wZuuWUPPm0gV8C0cU3+ifcWuw== @@ -1921,7 +1924,7 @@ dependencies: tslib "^2.6.2" -"@smithy/md5-js@^4.2.13": +"@smithy/md5-js@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/md5-js/-/md5-js-4.2.14.tgz#c066572ec84def147af24e55a402c44d0d7dcd7b" integrity sha512-V2v0vx+h0iUSNG1Alt+GNBMSLGCrl9iVsdd+Ap67HPM9PN479x12V8LkuMoKImNZxn3MXeuyUjls+/7ZACZghA== @@ -1930,7 +1933,7 @@ "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@smithy/middleware-content-length@^4.2.13", "@smithy/middleware-content-length@^4.2.14": +"@smithy/middleware-content-length@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-4.2.14.tgz#d8b17f94c4d8f9c3b7992f1db84d3299c83efe78" integrity sha512-xhHq7fX4/3lv5NHxLUk3OeEvl0xZ+Ek3qIbWaCL4f9JwgDZEclPBElljaZCAItdGPQl/kSM4LPMOpy1MYgprpw== @@ -1939,13 +1942,13 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/middleware-endpoint@^4.4.29", "@smithy/middleware-endpoint@^4.4.30": - version "4.4.30" - resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.30.tgz#4f7a301ae414b743ef23384245c531891c317163" - integrity sha512-qS2XqhKeXmdZ4nEQ4cOxIczSP/Y91wPAHYuRwmWDCh975B7/57uxsm5d6sisnUThn2u2FwzMdJNM7AbO1YPsPg== +"@smithy/middleware-endpoint@^4.4.32": + version "4.4.32" + resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.32.tgz#4c7dcf06b637b40dfcc53d3b18d1a784a747c530" + integrity sha512-ZZkgyjnJppiZbIm6Qbx92pbXYi1uzenIvGhBSCDlc7NwuAkiqSgS75j1czAD25ZLs2FjMjYy1q7gyRVWG6JA0Q== dependencies: - "@smithy/core" "^3.23.15" - "@smithy/middleware-serde" "^4.2.18" + "@smithy/core" "^3.23.17" + "@smithy/middleware-serde" "^4.2.20" "@smithy/node-config-provider" "^4.3.14" "@smithy/shared-ini-file-loader" "^4.4.9" "@smithy/types" "^4.14.1" @@ -1953,33 +1956,33 @@ "@smithy/util-middleware" "^4.2.14" tslib "^2.6.2" -"@smithy/middleware-retry@^4.5.0", "@smithy/middleware-retry@^4.5.3": - version "4.5.3" - resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-4.5.3.tgz#66e74235d0d8f73728cc9a7ca91672d0543936e9" - integrity sha512-TE8dJNi6JuxzGSxMCVd3i9IEWDndCl3bmluLsBNDWok8olgj65OfkndMhl9SZ7m14c+C5SQn/PcUmrDl57rSFw== +"@smithy/middleware-retry@^4.5.7": + version "4.5.7" + resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-4.5.7.tgz#a2da0c472d631ee408ff566186c99571b3efb70b" + integrity sha512-bRt6ZImqVSeTk39Nm81K20ObIiAZ3WefY7G6+iz/0tZjs4dgRRjvRX2sgsH+zi6iDCRR/aQvQofLKxxz4rPBZg== dependencies: - "@smithy/core" "^3.23.15" + "@smithy/core" "^3.23.17" "@smithy/node-config-provider" "^4.3.14" "@smithy/protocol-http" "^5.3.14" - "@smithy/service-error-classification" "^4.2.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/service-error-classification" "^4.3.1" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" "@smithy/util-middleware" "^4.2.14" - "@smithy/util-retry" "^4.3.2" + "@smithy/util-retry" "^4.3.6" "@smithy/uuid" "^1.1.2" tslib "^2.6.2" -"@smithy/middleware-serde@^4.2.17", "@smithy/middleware-serde@^4.2.18": - version "4.2.18" - resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-4.2.18.tgz#6fc65092a2eed7354cc2288bb20693c9ff424018" - integrity sha512-M6CSgnp3v4tYz9ynj2JHbA60woBZcGqEwNjTKjBsNHPV26R1ZX52+0wW8WsZU18q45jD0tw2wL22S17Ze9LpEw== +"@smithy/middleware-serde@^4.2.20": + version "4.2.20" + resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-4.2.20.tgz#76862c8f9b39b08501539440a2e6bca7a77de508" + integrity sha512-Lx9JMO9vArPtiChE3wbEZ5akMIDQpWQtlu90lhACQmNOXcGXRbaDywMHDzuDZ2OkZzP+9wQfZi3YJT9F67zTQQ== dependencies: - "@smithy/core" "^3.23.15" + "@smithy/core" "^3.23.17" "@smithy/protocol-http" "^5.3.14" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/middleware-stack@^4.2.13", "@smithy/middleware-stack@^4.2.14": +"@smithy/middleware-stack@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-4.2.14.tgz#23a4cf643ccdbde52c8780fe5cc080611efef1c7" integrity sha512-2dvkUKLuFdKsCRmOE4Mn63co0Djtsm+JMh0bYZQupN1pJwMeE8FmQmRLLzzEMN0dnNi7CDCYYH8F0EVwWiPBeA== @@ -1987,7 +1990,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/node-config-provider@^4.3.13", "@smithy/node-config-provider@^4.3.14": +"@smithy/node-config-provider@^4.3.14": version "4.3.14" resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-4.3.14.tgz#8ca13b86b6123cbb0425d669bd847fcd333ca4bd" integrity sha512-S+gFjyo/weSVL0P1b9Ts8C/CwIfNCgUPikk3sl6QVsfE/uUuO+QsF+NsE/JkpvWqqyz1wg7HFdiaZuj5CoBMRg== @@ -1997,10 +2000,10 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/node-http-handler@^4.5.2", "@smithy/node-http-handler@^4.5.3": - version "4.5.3" - resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-4.5.3.tgz#a0f7263fb8ecb0fd5dea03f770ec99d3a4c4efdc" - integrity sha512-lc5jFL++x17sPhIwMWJ3YOnqmSjw/2Po6VLDlUIXvxVWRuJwRXnJ4jOBBLB0cfI5BB5ehIl02Fxr1PDvk/kxDw== +"@smithy/node-http-handler@^4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-4.6.1.tgz#cb25b9445e46294a6f0dfb1566dbf2a1a19510af" + integrity sha512-iB+orM4x3xrr57X3YaXazfKnntl0LHlZB1kcXSGzMV1Tt0+YwEjGlbjk/44qEGtBzXAz6yFDzkYTKSV6Pj2HUg== dependencies: "@smithy/protocol-http" "^5.3.14" "@smithy/querystring-builder" "^4.2.14" @@ -2015,7 +2018,7 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/protocol-http@^5.3.13", "@smithy/protocol-http@^5.3.14": +"@smithy/protocol-http@^5.3.14": version "5.3.14" resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-5.3.14.tgz#ed1e65cdb0fffb7fd00dce997c04baa236f180cc" integrity sha512-dN5F8kHx8RNU0r+pCwNmFZyz6ChjMkzShy/zup6MtkRmmix4vZzJdW+di7x//b1LiynIev88FM18ie+wwPcQtQ== @@ -2040,10 +2043,10 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/service-error-classification@^4.2.14": - version "4.2.14" - resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-4.2.14.tgz#b9d3df0cb6f6f7fab87ddf5a348ca70f0b61585f" - integrity sha512-vVimoUnGxlx4eLLQbZImdOZFOe+Zh+5ACntv8VxZuGP72LdWu5GV3oEmCahSEReBgRJoWjypFkrehSj7BWx1HQ== +"@smithy/service-error-classification@^4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-4.3.1.tgz#5303d4fc3c3eea0f79c3b88cb4436498a31e9f12" + integrity sha512-aUQuDGh760ts/8MU+APjIZhlLPKhIIfqyzZaJikLEIMrdxFvxuLYD0WxWzaYWpmLbQlXDe9p7EWM3HsBe0K6Gw== dependencies: "@smithy/types" "^4.14.1" @@ -2069,27 +2072,27 @@ "@smithy/util-utf8" "^4.2.2" tslib "^2.6.2" -"@smithy/smithy-client@^4.12.11", "@smithy/smithy-client@^4.12.9": - version "4.12.11" - resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-4.12.11.tgz#547dd901c7674e8c39c9558348b864f0222d2a8f" - integrity sha512-wzz/Wa1CH/Tlhxh0s4DQPEcXSxSVfJ59AZcUh9Gu0c6JTlKuwGf4o/3P2TExv0VbtPFt8odIBG+eQGK2+vTECg== +"@smithy/smithy-client@^4.12.13": + version "4.12.13" + resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-4.12.13.tgz#dec184a1d2d5027370ae1582bddbdbc068c97da5" + integrity sha512-y/Pcj1V9+qG98gyu1gvftHB7rDpdh+7kIBIggs55yGm3JdtBV8GT8IFF3a1qxZ79QnaJHX9GXzvBG6tAd+czJA== dependencies: - "@smithy/core" "^3.23.15" - "@smithy/middleware-endpoint" "^4.4.30" + "@smithy/core" "^3.23.17" + "@smithy/middleware-endpoint" "^4.4.32" "@smithy/middleware-stack" "^4.2.14" "@smithy/protocol-http" "^5.3.14" "@smithy/types" "^4.14.1" - "@smithy/util-stream" "^4.5.23" + "@smithy/util-stream" "^4.5.25" tslib "^2.6.2" -"@smithy/types@^4.14.0", "@smithy/types@^4.14.1": +"@smithy/types@^4.14.1": version "4.14.1" resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.14.1.tgz#aba92b4cdb406f2a2b062e82f1e3728d809a7c23" integrity sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg== dependencies: tslib "^2.6.2" -"@smithy/url-parser@^4.2.13", "@smithy/url-parser@^4.2.14": +"@smithy/url-parser@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-4.2.14.tgz#349a442a62eb5907533f204b73a010618198b073" integrity sha512-p06BiBigJ8bTA3MgnOfCtDUWnAMY0YfedO/GRpmc7p+wg3KW8vbXy1xwSu5ASy0wV7rRYtlfZOIKH4XqfhjSQQ== @@ -2144,33 +2147,33 @@ dependencies: tslib "^2.6.2" -"@smithy/util-defaults-mode-browser@^4.3.45", "@smithy/util-defaults-mode-browser@^4.3.47": - version "4.3.47" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.47.tgz#1fc43bae2e50b49f78fe095a7c71a8b4d0519a0c" - integrity sha512-zlIuXai3/SHjQUQ8y3g/woLvrH573SK2wNjcDaHu5e9VOcC0JwM1MI0Sq0GZJyN3BwSUneIhpjZ18nsiz5AtQw== +"@smithy/util-defaults-mode-browser@^4.3.49": + version "4.3.49" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.49.tgz#926ce84bf65e56307f25cce7a13b427d33442939" + integrity sha512-a5bNrdiONYB/qE2BuKegvUMd/+ZDwdg4vsNuuSzYE8qs2EYAdK9CynL+Rzn29PbPiUqoz/cbpRbcLzD5lEevHw== dependencies: "@smithy/property-provider" "^4.2.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/util-defaults-mode-node@^4.2.49", "@smithy/util-defaults-mode-node@^4.2.52": - version "4.2.52" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.52.tgz#8ee1f267d764c3d540c0c3a091c3d9b703194991" - integrity sha512-cQBz8g68Vnw1W2meXlkb3D/hXJU+Taiyj9P8qLJtjREEV9/Td65xi4A/H1sRQ8EIgX5qbZbvdYPKygKLholZ3w== +"@smithy/util-defaults-mode-node@^4.2.54": + version "4.2.54" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.54.tgz#32c4ea9f8a8c74ef9fe0ca5e3d6a10df0327f87e" + integrity sha512-g1cvrJvOnzeJgEdf7AE4luI7gp6L8weE0y9a9wQUSGtjb8QRHDbCJYuE4Sy0SD9N8RrnNPFsPltAz/OSoBR9Zw== dependencies: - "@smithy/config-resolver" "^4.4.16" + "@smithy/config-resolver" "^4.4.17" "@smithy/credential-provider-imds" "^4.2.14" "@smithy/node-config-provider" "^4.3.14" "@smithy/property-provider" "^4.2.14" - "@smithy/smithy-client" "^4.12.11" + "@smithy/smithy-client" "^4.12.13" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/util-endpoints@^3.3.4", "@smithy/util-endpoints@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-3.4.1.tgz#01ef5aaa699a635073da3e63cc7f15beb4d1abf9" - integrity sha512-wMxNDZJrgS5mQV9oxCs4TWl5767VMgOfqfZ3JHyCkMtGC2ykW9iPqMvFur695Otcc5yxLG8OKO/80tsQBxrhXg== +"@smithy/util-endpoints@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-3.4.2.tgz#ee59c42d039a642b6c6eb2d38e0ae3db6fc48e97" + integrity sha512-a55Tr+3OKld4TTtnT+RhKOQHyPxm3j/xL4OR83WBUhLJaKDS9dnJ7arRMOp3t31dcLhApwG9bgvrRXBHlLdIkg== dependencies: "@smithy/node-config-provider" "^4.3.14" "@smithy/types" "^4.14.1" @@ -2183,7 +2186,7 @@ dependencies: tslib "^2.6.2" -"@smithy/util-middleware@^4.2.13", "@smithy/util-middleware@^4.2.14": +"@smithy/util-middleware@^4.2.14": version "4.2.14" resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-4.2.14.tgz#9985dd82b4036db2d03835229b9b0c63d2bb85fa" integrity sha512-1Su2vj9RYNDEv/V+2E+jXkkwGsgR7dc4sfHn9Z7ruzQHJIEni9zzw5CauvRXlFJfmgcqYP8fWa0dkh2Q2YaQyw== @@ -2191,22 +2194,22 @@ "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/util-retry@^4.3.0", "@smithy/util-retry@^4.3.2": - version "4.3.2" - resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-4.3.2.tgz#5f73ca1300a39b413f0e764128fe6c473ed31b9b" - integrity sha512-2+KTsJEwTi63NUv4uR9IQ+IFT1yu6Rf6JuoBK2WKaaJ/TRvOiOVGcXAsEqX/TQN2thR9yII21kPUJq1UV/WI2A== +"@smithy/util-retry@^4.3.6": + version "4.3.8" + resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-4.3.8.tgz#7f904ed8e5bad2b5f2e6aa1e193db2b46b2c57df" + integrity sha512-LUIxbTBi+OpvXpg91poGA6BdyoleMDLnfXjVDqyi2RvZmTveY5loE/FgYUBCR5LU2BThW2SoZRh8dTIIy38IPw== dependencies: - "@smithy/service-error-classification" "^4.2.14" + "@smithy/service-error-classification" "^4.3.1" "@smithy/types" "^4.14.1" tslib "^2.6.2" -"@smithy/util-stream@^4.5.22", "@smithy/util-stream@^4.5.23": - version "4.5.23" - resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-4.5.23.tgz#dc7535580bcc7117126e3ae26dfc937a83b434fb" - integrity sha512-N6on1+ngJ3RznZOnDWNveIwnTSlqxNnXuNAh7ez889ZZaRdXoNRTXKgmYOLe6dB0gCmAVtuRScE1hymQFl4hpg== +"@smithy/util-stream@^4.5.25": + version "4.5.25" + resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-4.5.25.tgz#f48385a284151c7e099395af4e5fb0978fffe4ff" + integrity sha512-/PFpG4k8Ze8Ei+mMKj3oiPICYekthuzePZMgZbCqMiXIHHf4n2aZ4Ps0aSRShycFTGuj/J6XldmC0x0DwednIA== dependencies: "@smithy/fetch-http-handler" "^5.3.17" - "@smithy/node-http-handler" "^4.5.3" + "@smithy/node-http-handler" "^4.6.1" "@smithy/types" "^4.14.1" "@smithy/util-base64" "^4.3.2" "@smithy/util-buffer-from" "^4.2.2" @@ -2237,10 +2240,10 @@ "@smithy/util-buffer-from" "^4.2.2" tslib "^2.6.2" -"@smithy/util-waiter@^4.2.15": - version "4.2.16" - resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-4.2.16.tgz#eae1be0810cd243898fdcf22c83a1ec59fe63610" - integrity sha512-GtclrKoZ3Lt7jPQ7aTIYKfjY92OgceScftVnkTsG8e1KV8rkvZgN+ny6YSRhd9hxB8rZtwVbmln7NTvE5O3GmQ== +"@smithy/util-waiter@^4.3.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-4.3.0.tgz#6122ce27939edb5550d1d6c7c8d506323f3a17f7" + integrity sha512-JyjYmLAfS+pdxF92o4yLgEoy0zhayKTw73FU1aofLWwLcJw7iSqIY2exGmMTrl/lmZugP5p/zxdFSippJDfKWA== dependencies: "@smithy/types" "^4.14.1" tslib "^2.6.2" @@ -3429,20 +3432,21 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fast-xml-builder@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/fast-xml-builder/-/fast-xml-builder-1.1.5.tgz#50188e1452a5fa095f415d3e63dcac0a1dbcbf11" - integrity sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA== +fast-xml-builder@1.2.0, fast-xml-builder@^1.1.7: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz#abd2363145a7625d9789ad96da375fabe3cff28c" + integrity sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q== dependencies: - path-expression-matcher "^1.1.3" + path-expression-matcher "^1.5.0" + xml-naming "^0.1.0" -fast-xml-parser@5.5.8, fast-xml-parser@5.7.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-5.7.0.tgz#b93e49a3d62a8824c5212d8fa099ac2e548d548a" - integrity sha512-MTcrUoRQ1GSQ9iG3QJzBGquYYYeA7piZaJoIWbPFGbRn6Jj6z7xgoAyi4DrZX4y2ZIQQBF59gc/zmvvejjgoFQ== +fast-xml-parser@5.7.2, fast-xml-parser@5.7.3: + version "5.7.3" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-5.7.3.tgz#309b04b08d835defc62ab657a0bb340c0e0fbe6a" + integrity sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg== dependencies: "@nodable/entities" "^2.1.0" - fast-xml-builder "^1.1.5" + fast-xml-builder "^1.1.7" path-expression-matcher "^1.5.0" strnum "^2.2.3" @@ -4689,11 +4693,6 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -path-expression-matcher@^1.1.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/path-expression-matcher/-/path-expression-matcher-1.2.0.tgz#9bdae3787f43b0857b0269e9caaa586c12c8abee" - integrity sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ== - path-expression-matcher@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz#3b98545dc88ffebb593e2d8458d0929da9275f4a" @@ -5387,6 +5386,11 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" +xml-naming@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/xml-naming/-/xml-naming-0.1.0.tgz#8ab7106c5b8d23caa2fabac1cadf17136379fbd8" + integrity sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" diff --git a/backend/cosmetology-app/lambdas/python/cognito-backup/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/cognito-backup/requirements-dev.txt index 36dabc6d8..1dc758bd4 100644 --- a/backend/cosmetology-app/lambdas/python/cognito-backup/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/cognito-backup/requirements-dev.txt @@ -4,48 +4,44 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/cognito-backup/requirements-dev.in # -aws-lambda-powertools==3.28.0 - # via -r cognito-backup/requirements-dev.in -boto3==1.42.89 +aws-lambda-powertools==3.29.0 + # via -r lambdas/python/cognito-backup/requirements-dev.in +boto3==1.43.7 # via - # -r cognito-backup/requirements-dev.in + # -r lambdas/python/cognito-backup/requirements-dev.in # moto -botocore==1.42.90 +botocore==1.43.7 # via - # -r cognito-backup/requirements-dev.in + # -r lambdas/python/cognito-backup/requirements-dev.in # boto3 # moto # s3transfer -certifi==2026.2.25 +certifi==2026.4.22 # via requests cffi==2.0.0 # via cryptography charset-normalizer==3.4.7 # via requests -cryptography==46.0.7 +cryptography==48.0.0 # via # joserfc # moto -idna==3.11 +idna==3.15 # via requests iniconfig==2.3.0 # via pytest -jinja2==3.1.6 - # via moto jmespath==1.1.0 # via # aws-lambda-powertools # boto3 # botocore -joserfc==1.6.4 +joserfc==1.6.5 # via moto markupsafe==3.0.3 - # via - # jinja2 - # werkzeug -moto[cognitoidp,s3]==5.1.22 - # via -r cognito-backup/requirements-dev.in -packaging==26.1 + # via werkzeug +moto[cognitoidp,s3]==5.2.1 + # via -r lambdas/python/cognito-backup/requirements-dev.in +packaging==26.2 # via pytest pluggy==1.6.0 # via pytest @@ -56,28 +52,26 @@ pycparser==3.0 pygments==2.20.0 # via pytest pytest==9.0.3 - # via -r cognito-backup/requirements-dev.in + # via -r lambdas/python/cognito-backup/requirements-dev.in python-dateutil==2.9.0.post0 - # via - # botocore - # moto + # via botocore pyyaml==6.0.3 # via # moto # responses -requests==2.33.1 +requests==2.34.1 # via # moto # responses responses==0.26.0 # via moto -s3transfer==0.16.0 +s3transfer==0.17.0 # via boto3 six==1.17.0 # via python-dateutil typing-extensions==4.15.0 # via aws-lambda-powertools -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # requests diff --git a/backend/cosmetology-app/lambdas/python/cognito-backup/requirements.txt b/backend/cosmetology-app/lambdas/python/cognito-backup/requirements.txt index fe5c2c1db..d568b1cf0 100644 --- a/backend/cosmetology-app/lambdas/python/cognito-backup/requirements.txt +++ b/backend/cosmetology-app/lambdas/python/cognito-backup/requirements.txt @@ -4,13 +4,13 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/cognito-backup/requirements.in # -aws-lambda-powertools==3.28.0 - # via -r cognito-backup/requirements.in -boto3==1.42.89 - # via -r cognito-backup/requirements.in -botocore==1.42.90 +aws-lambda-powertools==3.29.0 + # via -r lambdas/python/cognito-backup/requirements.in +boto3==1.43.7 + # via -r lambdas/python/cognito-backup/requirements.in +botocore==1.43.7 # via - # -r cognito-backup/requirements.in + # -r lambdas/python/cognito-backup/requirements.in # boto3 # s3transfer jmespath==1.1.0 @@ -20,11 +20,11 @@ jmespath==1.1.0 # botocore python-dateutil==2.9.0.post0 # via botocore -s3transfer==0.16.0 +s3transfer==0.17.0 # via boto3 six==1.17.0 # via python-dateutil typing-extensions==4.15.0 # via aws-lambda-powertools -urllib3==2.6.3 +urllib3==2.7.0 # via botocore diff --git a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/provider_record_util.py b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/provider_record_util.py index 73c287e58..f7e70260f 100644 --- a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/provider_record_util.py +++ b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/provider_record_util.py @@ -41,6 +41,21 @@ class ProviderRecordType(StrEnum): ] +def _license_sort_key(license_record: dict | LicenseData) -> tuple: + """ + Sort key for license records: by date of renewal if present, else date of issuance; + use date of issuance as tiebreaker. Works with both dict and LicenseData so the same + ordering is used in find_best_license (dicts) and find_best_license_in_current_known_licenses (LicenseData). + """ + if isinstance(license_record, dict): + effective_date = license_record.get('dateOfRenewal') or license_record['dateOfIssuance'] + date_of_issuance = license_record['dateOfIssuance'] + else: + effective_date = license_record.dateOfRenewal or license_record.dateOfIssuance + date_of_issuance = license_record.dateOfIssuance + return effective_date, date_of_issuance + + class ProviderRecordUtility: """ A class for housing official logic for how to handle provider records without making database queries. @@ -75,47 +90,16 @@ def get_provider_record(provider_records: Iterable[dict]) -> dict | None: return provider_records[0] if provider_records else None @classmethod - def _license_sort_key(cls, license_record: dict | LicenseData) -> tuple: - """ - Sort key for license records: by date of renewal if present, else date of issuance; - use date of issuance as tiebreaker. Works with both dict and LicenseData so the same - ordering is used in find_best_license (dicts) and find_best_license_in_current_known_licenses (LicenseData). - """ - if isinstance(license_record, dict): - effective_date = license_record.get('dateOfRenewal') or license_record['dateOfIssuance'] - date_of_issuance = license_record['dateOfIssuance'] - else: - effective_date = license_record.dateOfRenewal or license_record.dateOfIssuance - date_of_issuance = license_record.dateOfIssuance - return (effective_date, date_of_issuance) - - @classmethod - def find_best_license(cls, license_records: Iterable[dict], home_jurisdiction: str | None = None) -> dict: + def find_most_recently_issued_or_renewed_license(cls, license_records: Iterable[dict]) -> dict: """ - Find the best license from a collection of licenses. - This selects the license renewed or issued most recently. Sort by date of renewal if present, otherwise date of issuance; use date of issuance as tiebreaker. Compact eligibility and active status are not considered. - 1. If home jurisdiction is selected, only consider licenses from that jurisdiction - 2. Return the single license with the latest (renewal date or issuance date) - :param license_records: An iterable of license records - :param home_jurisdiction: The home jurisdiction selection :return: The best license record """ - # If the provider's home jurisdiction was selected, we only consider licenses from that jurisdiction - # Unless the provider does not have any licenses in that jurisdiction - # (ie they moved to a non-member jurisdiction) - if home_jurisdiction is not None: - license_records_in_jurisdiction = cls.get_records_of_type( - license_records, ProviderRecordType.LICENSE, _filter=lambda x: x['jurisdiction'] == home_jurisdiction - ) - if license_records_in_jurisdiction: - license_records = license_records_in_jurisdiction - - latest_licenses = sorted(license_records, key=cls._license_sort_key, reverse=True) + latest_licenses = sorted(license_records, key=_license_sort_key, reverse=True) if not latest_licenses: raise CCInternalException('No licenses found') @@ -389,6 +373,30 @@ def get_provider_record(self) -> ProviderData: raise CCInternalException('No provider record found for user.') return self._provider_records[0] + @staticmethod + def _sort_licenses_by_most_recent(licenses: list[LicenseData]) -> list[LicenseData]: + return sorted( + licenses, + key=_license_sort_key, + reverse=True, + ) + + def find_most_recent_licenses_for_each_license_type(self) -> list[LicenseData]: + """ + For each license type, find the most recent license for the provider. + + :return: A list of LicenseData objects, one for each license type the provider holds. + """ + most_recent_licenses: list[LicenseData] = [] + by_type: dict[str, list] = {} + for lic in self._license_records: + by_type.setdefault(lic.licenseType, []).append(lic) + for _lt, licenses in by_type.items(): + sorted_licenses = self._sort_licenses_by_most_recent(licenses) + most_recent_licenses.append(sorted_licenses[0]) + + return most_recent_licenses + def find_best_license_in_current_known_licenses( self, jurisdiction: str | None = None, @@ -417,11 +425,7 @@ def find_best_license_in_current_known_licenses( if not license_records: raise CCNotFoundException('No licenses found') - sorted_licenses = sorted( - license_records, - key=ProviderRecordUtility._license_sort_key, # noqa: SLF001 - reverse=True, - ) + sorted_licenses = self._sort_licenses_by_most_recent(license_records) return sorted_licenses[0] def generate_privileges_for_provider(self, include_inactive_privileges: bool = False) -> list[dict]: @@ -462,7 +466,7 @@ def generate_privileges_for_provider(self, include_inactive_privileges: bool = F for _lt, licenses in by_type.items(): sorted_licenses = sorted( licenses, - key=ProviderRecordUtility._license_sort_key, # noqa: SLF001 + key=_license_sort_key, reverse=True, ) most_recent_license = sorted_licenses[0] @@ -566,18 +570,26 @@ def get_update_records_for_license( and (filter_condition is None or filter_condition(record)) ] - def generate_api_response_object(self) -> dict: + def generate_api_response_object(self, is_public_response: bool = False) -> dict: """ Assemble a list of provider records into a single object used by the provider details api. + :param is_public_response: If True, licenses that are not the most recent license for a type + will not be included in the response. :return: A single provider record matching our provider details api schema. """ provider = self.get_provider_record().to_dict() licenses = [] privileges = [] + if is_public_response: + # only include the most recent license for each license type in the public response + license_records = self.find_most_recent_licenses_for_each_license_type() + else: + license_records = self.get_license_records() + # Build licenses dict with investigations and adverseActions - for license_record in self._license_records: + for license_record in license_records: license_dict = license_record.to_dict() license_dict['adverseActions'] = [ rec.to_dict() @@ -606,9 +618,10 @@ def generate_opensearch_documents(self) -> list[dict]: """ Generate one OpenSearch document per license for this provider. - Each document contains the full provider-level fields, a single license in the `licenses` - array, and privileges only if that license is the home license for its type. This enables - 1:1 mapping between OpenSearch documents and license records for native pagination. + Each document contains the full provider-level fields (including top-level `adverseActions` + for the provider), a single license in the `licenses` array, and privileges only if that license + is the home license for its type. This enables 1:1 mapping between OpenSearch documents and license + records for native pagination. Privileges are always included for home license documents — including when the license is ineligible — so that adverse actions and investigations remain linked to privilege records. @@ -623,24 +636,15 @@ def generate_opensearch_documents(self) -> list[dict]: provider_dict = self.get_provider_record().to_dict() all_privileges = self.generate_privileges_for_provider(include_inactive_privileges=True) - # Determine the home license for each license type using the same sort logic - # as generate_privileges_for_provider, so privilege assignment is consistent. - by_type: dict[str, list] = {} - for lic in self._license_records: - by_type.setdefault(lic.licenseType, []).append(lic) - - home_licenses: set[tuple[str, str]] = set() - for _lt, licenses in by_type.items(): - sorted_licenses = sorted( - licenses, - key=ProviderRecordUtility._license_sort_key, # noqa: SLF001 - reverse=True, - ) - home = sorted_licenses[0] - home_licenses.add((home.jurisdiction.lower(), home.licenseType)) + # Determine the most recent (aka home) license for each license type + most_recent_licenses = { + (most_recent_license_for_type.jurisdiction.lower(), most_recent_license_for_type.licenseType) + for most_recent_license_for_type in self.find_most_recent_licenses_for_each_license_type() + } documents = [] - for license_record in self._license_records: + adverse_actions = [rec.to_dict() for rec in self.get_adverse_action_records()] + for license_record in self.get_license_records(): license_dict = license_record.to_dict() license_dict['adverseActions'] = [ rec.to_dict() @@ -655,14 +659,21 @@ def generate_opensearch_documents(self) -> list[dict]: ) ] - is_home = (license_record.jurisdiction.lower(), license_record.licenseType) in home_licenses + is_most_recent_license_for_type = ( + license_record.jurisdiction.lower(), + license_record.licenseType, + ) in most_recent_licenses license_privileges = ( - [p for p in all_privileges if p['licenseType'] == license_record.licenseType] if is_home else [] + [p for p in all_privileges if p['licenseType'] == license_record.licenseType] + if is_most_recent_license_for_type + else [] ) + license_dict['mostRecentLicenseForType'] = is_most_recent_license_for_type doc = dict(provider_dict) doc['licenses'] = [license_dict] doc['privileges'] = license_privileges + doc['adverseActions'] = adverse_actions documents.append(doc) return documents diff --git a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/data_event/api.py b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/data_event/api.py index 006edb86b..4df727eae 100644 --- a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/data_event/api.py +++ b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/data_event/api.py @@ -42,3 +42,9 @@ class LicenseRevertDetailSchema(DataEventDetailBaseSchema): startTime = AwareDateTime(required=True, allow_none=False) endTime = AwareDateTime(required=True, allow_none=False) rollbackExecutionName = String(required=True, allow_none=False) + + +class HomeJurisdictionChangeEventDetailSchema(DataEventDetailBaseSchema): + providerId = UUID(required=True, allow_none=False) + licenseType = String(required=True, allow_none=False) + formerHomeJurisdiction = Jurisdiction(required=True, allow_none=False) diff --git a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/license/api.py b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/license/api.py index 568e76032..0dd849d82 100644 --- a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/license/api.py +++ b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/license/api.py @@ -6,7 +6,7 @@ from datetime import date from marshmallow import ValidationError, pre_load, validates_schema -from marshmallow.fields import Date, Email, List, Nested, Raw, String +from marshmallow.fields import Boolean, Date, Email, List, Nested, Raw, String from marshmallow.validate import Length from cc_common.config import config @@ -39,7 +39,7 @@ class LicenseExpirationStatusMixin: @pre_load def correct_expired_license_status(self, in_data, **kwargs): - """Set licenseStatus to inactive if the license has expired.""" + """Correct licenseStatus and compactEligibility if the license has expired.""" if in_data.get('licenseStatus') != ActiveInactiveStatus.ACTIVE: # Already inactive, no correction needed return in_data @@ -54,9 +54,10 @@ def correct_expired_license_status(self, in_data, **kwargs): else: expiration_date = date_of_expiration - # If expired, correct the status to inactive + # If expired, correct the status to inactive and eligibility to ineligible if expiration_date < config.expiration_resolution_date: in_data['licenseStatus'] = ActiveInactiveStatus.INACTIVE + in_data['compactEligibility'] = CompactEligibilityStatus.INELIGIBLE return in_data @@ -238,11 +239,17 @@ class LicenseOpenSearchDocumentSchema(LicenseGeneralResponseSchema): authorized staff users to search providers by date of birth. This schema is used only for indexing into OpenSearch, not for API responses. + Additionally, this schema includes the mostRecentLicenseForType field to indicate + the most recent license for the provider for a specific license type. This + allows for filtering public search results by the most recent licenses for + the provider. + Serialization direction: Python -> load() -> OpenSearch document """ dateOfBirth = Raw(required=False, allow_none=False) + mostRecentLicenseForType = Boolean(required=False, allow_none=False, load_default=False) class LicensePublicResponseSchema(LicenseExpirationStatusMixin, ForgivingSchema): diff --git a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/provider/api.py b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/provider/api.py index e8b8bedb9..e62ab1e65 100644 --- a/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/provider/api.py +++ b/backend/cosmetology-app/lambdas/python/common/cc_common/data_model/schema/provider/api.py @@ -211,6 +211,7 @@ class PublicLicenseSearchResponseSchema(ForgivingSchema): compact = Compact(required=True, allow_none=False) licenseType = String(required=True, allow_none=False) licenseNumber = String(required=True, allow_none=False, validate=Length(1, 100)) + licenseEligibility = CompactEligibility(required=True, allow_none=False) class QueryProvidersRequestSchema(CCRequestSchema): diff --git a/backend/cosmetology-app/lambdas/python/common/cc_common/email_service_client.py b/backend/cosmetology-app/lambdas/python/common/cc_common/email_service_client.py index 755a130b9..10cc4feea 100644 --- a/backend/cosmetology-app/lambdas/python/common/cc_common/email_service_client.py +++ b/backend/cosmetology-app/lambdas/python/common/cc_common/email_service_client.py @@ -37,6 +37,20 @@ class InvestigationNotificationTemplateVariables: provider_id: UUID +@dataclass +class HomeJurisdictionChangeNotificationTemplateVariables: + """ + Template variables for license home state change notification emails. + """ + + provider_first_name: str + provider_last_name: str + former_jurisdiction: str + current_jurisdiction: str + license_type: str + provider_id: UUID + + class JurisdictionNotificationMethod(Protocol): """Protocol for Jurisdiction encumbrance notification methods.""" @@ -358,3 +372,37 @@ def send_privilege_investigation_closed_state_notification_email( }, } return self._invoke_lambda(payload) + + def send_provider_home_state_change_email( + self, + *, + compact: str, + jurisdiction: str, + template_variables: HomeJurisdictionChangeNotificationTemplateVariables, + ) -> dict[str, str]: + """ + Send a license home state change notification email to a state. + + :param compact: Compact name + :param jurisdiction: Jurisdiction to notify + :param template_variables: Template variables for the email + :return: Response from the email notification service + """ + if template_variables.provider_id is None: + raise ValueError('provider_id must be provided for state notifications') + + payload = { + 'compact': compact, + 'jurisdiction': jurisdiction, + 'template': 'homeJurisdictionChangeNotification', + 'recipientType': 'JURISDICTION_OPERATIONS_TEAM', + 'templateVariables': { + 'providerFirstName': template_variables.provider_first_name, + 'providerLastName': template_variables.provider_last_name, + 'providerId': str(template_variables.provider_id), + 'previousJurisdiction': template_variables.former_jurisdiction, + 'newJurisdiction': template_variables.current_jurisdiction, + 'licenseType': template_variables.license_type, + }, + } + return self._invoke_lambda(payload) diff --git a/backend/cosmetology-app/lambdas/python/common/cc_common/event_bus_client.py b/backend/cosmetology-app/lambdas/python/common/cc_common/event_bus_client.py index 03349c3ad..f9f19cd36 100644 --- a/backend/cosmetology-app/lambdas/python/common/cc_common/event_bus_client.py +++ b/backend/cosmetology-app/lambdas/python/common/cc_common/event_bus_client.py @@ -8,6 +8,7 @@ from cc_common.data_model.schema.common import InvestigationAgainstEnum from cc_common.data_model.schema.data_event.api import ( EncumbranceEventDetailSchema, + HomeJurisdictionChangeEventDetailSchema, InvestigationEventDetailSchema, LicenseDeactivationDetailSchema, LicenseRevertDetailSchema, @@ -82,6 +83,45 @@ def generate_license_deactivation_event( 'EventBusName': config.event_bus_name, } + def generate_home_jurisdiction_change_event( + self, + source: str, + compact: str, + jurisdiction: str, + provider_id: UUID, + license_type: str, + former_home_jurisdiction: str, + ) -> dict: + """ + Generate a home jurisdiction change event entry for use with batch writers. + + :param source: The source of the event + :param compact: The compact abbreviation + :param jurisdiction: The new jurisdiction that uploaded the license + :param provider_id: The provider's unique identifier + :param license_type: The type of license + :param former_home_jurisdiction: The former home jurisdiction of the provider + :returns: Event entry dict that can be used with EventBatchWriter + """ + event_detail = { + 'eventTime': config.current_standard_datetime.isoformat(), + 'compact': compact, + 'jurisdiction': jurisdiction, + 'providerId': str(provider_id), + 'licenseType': license_type, + 'formerHomeJurisdiction': former_home_jurisdiction, + } + + home_jurisdiction_change_schema = HomeJurisdictionChangeEventDetailSchema() + loaded_detail = home_jurisdiction_change_schema.load(event_detail) + + return { + 'Source': source, + 'DetailType': 'provider.homeStateChange', + 'Detail': json.dumps(loaded_detail, cls=ResponseEncoder), + 'EventBusName': config.event_bus_name, + } + def publish_license_encumbrance_event( self, source: str, diff --git a/backend/cosmetology-app/lambdas/python/common/requirements-dev.in b/backend/cosmetology-app/lambdas/python/common/requirements-dev.in index 1f0533a76..1bc9e5c36 100644 --- a/backend/cosmetology-app/lambdas/python/common/requirements-dev.in +++ b/backend/cosmetology-app/lambdas/python/common/requirements-dev.in @@ -3,4 +3,4 @@ attrs>=25.4,<26 moto[all]>=5.0.12, <6 boto3-stubs[full] Faker>=40, <41 -cryptography>=46, <47 +cryptography>=48, <49 diff --git a/backend/cosmetology-app/lambdas/python/common/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/common/requirements-dev.txt index a30103cc2..199aa276f 100644 --- a/backend/cosmetology-app/lambdas/python/common/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/common/requirements-dev.txt @@ -10,24 +10,22 @@ antlr4-python3-runtime==4.13.2 # via moto attrs==25.4.0 # via - # -r common/requirements-dev.in + # -r lambdas/python/common/requirements-dev.in # jsonschema # referencing -aws-sam-translator==1.103.0 - # via - # cfn-lint - # moto +aws-sam-translator==1.109.0 + # via cfn-lint aws-xray-sdk==2.15.0 # via moto -boto3==1.42.89 +boto3==1.43.7 # via # aws-sam-translator # moto -boto3-stubs[full]==1.42.90 - # via -r common/requirements-dev.in -boto3-stubs-full==1.42.90 +boto3-stubs[full]==1.43.7 + # via -r lambdas/python/common/requirements-dev.in +boto3-stubs-full==1.43.7 # via boto3-stubs -botocore==1.42.90 +botocore==1.43.7 # via # aws-xray-sdk # boto3 @@ -35,34 +33,32 @@ botocore==1.42.90 # s3transfer botocore-stubs==1.42.41 # via boto3-stubs -certifi==2026.2.25 +certifi==2026.4.22 # via requests cffi==2.0.0 # via cryptography -cfn-lint==1.41.0 +cfn-lint==1.51.0 # via moto charset-normalizer==3.4.7 # via requests -cryptography==46.0.7 +cryptography==48.0.0 # via - # -r common/requirements-dev.in + # -r lambdas/python/common/requirements-dev.in # joserfc # moto docker==7.1.0 # via moto -faker==40.13.0 - # via -r common/requirements-dev.in +faker==40.15.0 + # via -r lambdas/python/common/requirements-dev.in graphql-core==3.2.8 # via moto -idna==3.11 +idna==3.15 # via requests -jinja2==3.1.6 - # via moto jmespath==1.1.0 # via # boto3 # botocore -joserfc==1.6.4 +joserfc==1.6.5 # via moto jsonpatch==1.33 # via cfn-lint @@ -70,13 +66,13 @@ jsonpath-ng==1.8.0 # via moto jsonpointer==3.1.1 # via jsonpatch -jsonschema==4.24.1 +jsonschema==4.26.0 # via # aws-sam-translator # moto # openapi-schema-validator # openapi-spec-validator -jsonschema-path==0.4.5 +jsonschema-path==0.4.6 # via openapi-spec-validator jsonschema-specifications==2025.9.1 # via @@ -85,11 +81,9 @@ jsonschema-specifications==2025.9.1 lazy-object-proxy==1.12.0 # via openapi-spec-validator markupsafe==3.0.3 - # via - # jinja2 - # werkzeug -moto[all]==5.1.22 - # via -r common/requirements-dev.in + # via werkzeug +moto[all]==5.2.1 + # via -r lambdas/python/common/requirements-dev.in mpmath==1.3.0 # via sympy multipart==1.3.1 @@ -98,7 +92,7 @@ networkx==3.6.1 # via cfn-lint openapi-schema-validator==0.8.1 # via openapi-spec-validator -openapi-spec-validator==0.8.4 +openapi-spec-validator==0.8.5 # via moto pathable==0.5.0 # via jsonschema-path @@ -106,25 +100,22 @@ py-partiql-parser==0.6.3 # via moto pycparser==3.0 # via cffi -pydantic==2.12.4 +pydantic==2.12.5 # via # aws-sam-translator - # moto # openapi-schema-validator # openapi-spec-validator # pydantic-settings pydantic-core==2.41.5 # via pydantic -pydantic-settings==2.13.1 +pydantic-settings==2.14.1 # via # openapi-schema-validator # openapi-spec-validator pyparsing==3.3.2 # via moto python-dateutil==2.9.0.post0 - # via - # botocore - # moto + # via botocore python-dotenv==1.2.2 # via pydantic-settings pyyaml==6.0.3 @@ -139,9 +130,9 @@ referencing==0.37.0 # jsonschema-path # jsonschema-specifications # openapi-schema-validator -regex==2026.4.4 +regex==2026.5.9 # via cfn-lint -requests==2.33.1 +requests==2.34.1 # via # docker # moto @@ -154,7 +145,7 @@ rpds-py==0.30.0 # via # jsonschema # referencing -s3transfer==0.16.0 +s3transfer==0.17.0 # via boto3 six==1.17.0 # via @@ -177,7 +168,7 @@ typing-inspection==0.4.2 # via # pydantic # pydantic-settings -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/cosmetology-app/lambdas/python/common/requirements.in b/backend/cosmetology-app/lambdas/python/common/requirements.in index bb9c2f281..dc017c3ab 100644 --- a/backend/cosmetology-app/lambdas/python/common/requirements.in +++ b/backend/cosmetology-app/lambdas/python/common/requirements.in @@ -1,6 +1,6 @@ argon2-cffi>=25.1.0, <26.0.0 aws-lambda-powertools>=3.5.0, <4 boto3>=1.34.33, <2 -cryptography>=46, <47 +cryptography>=48, <49 marshmallow>=4.3.0, <5.0.0 requests>=2.31.0, <3.0.0 diff --git a/backend/cosmetology-app/lambdas/python/common/requirements.txt b/backend/cosmetology-app/lambdas/python/common/requirements.txt index 6d5ad6fbe..358ba0f18 100644 --- a/backend/cosmetology-app/lambdas/python/common/requirements.txt +++ b/backend/cosmetology-app/lambdas/python/common/requirements.txt @@ -5,18 +5,18 @@ # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/common/requirements.in # argon2-cffi==25.1.0 - # via -r common/requirements.in + # via -r lambdas/python/common/requirements.in argon2-cffi-bindings==25.1.0 # via argon2-cffi -aws-lambda-powertools==3.28.0 - # via -r common/requirements.in -boto3==1.42.89 - # via -r common/requirements.in -botocore==1.42.90 +aws-lambda-powertools==3.29.0 + # via -r lambdas/python/common/requirements.in +boto3==1.43.7 + # via -r lambdas/python/common/requirements.in +botocore==1.43.7 # via # boto3 # s3transfer -certifi==2026.2.25 +certifi==2026.4.22 # via requests cffi==2.0.0 # via @@ -24,9 +24,9 @@ cffi==2.0.0 # cryptography charset-normalizer==3.4.7 # via requests -cryptography==46.0.7 - # via -r common/requirements.in -idna==3.11 +cryptography==48.0.0 + # via -r lambdas/python/common/requirements.in +idna==3.15 # via requests jmespath==1.1.0 # via @@ -34,20 +34,20 @@ jmespath==1.1.0 # boto3 # botocore marshmallow==4.3.0 - # via -r common/requirements.in + # via -r lambdas/python/common/requirements.in pycparser==3.0 # via cffi python-dateutil==2.9.0.post0 # via botocore -requests==2.33.1 - # via -r common/requirements.in -s3transfer==0.16.0 +requests==2.34.1 + # via -r lambdas/python/common/requirements.in +s3transfer==0.17.0 # via boto3 six==1.17.0 # via python-dateutil typing-extensions==4.15.0 # via aws-lambda-powertools -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # requests diff --git a/backend/cosmetology-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.py b/backend/cosmetology-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.py index afbe6baf7..3ebf0df25 100644 --- a/backend/cosmetology-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.py +++ b/backend/cosmetology-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.py @@ -329,6 +329,7 @@ def _make_license_data(self, *, license_status='active', date_of_expiration='210 'homeAddressPostalCode': '43215', 'licenseNumber': 'LIC12345', 'dateOfBirth': '1985-06-06', + 'mostRecentLicenseForType': True, } def test_includes_date_of_birth(self): diff --git a/backend/cosmetology-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.py b/backend/cosmetology-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.py index d045cbafe..937386ad8 100644 --- a/backend/cosmetology-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.py +++ b/backend/cosmetology-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.py @@ -49,6 +49,7 @@ def _make_provider_data_with_license(self): 'homeAddressState': 'OH', 'homeAddressPostalCode': '43215', 'dateOfBirth': '1985-06-06', + 'mostRecentLicenseForType': True, } ], 'privileges': [], diff --git a/backend/cosmetology-app/lambdas/python/common/tests/unit/test_email_service_client.py b/backend/cosmetology-app/lambdas/python/common/tests/unit/test_email_service_client.py index 520b1868a..d52888daf 100644 --- a/backend/cosmetology-app/lambdas/python/common/tests/unit/test_email_service_client.py +++ b/backend/cosmetology-app/lambdas/python/common/tests/unit/test_email_service_client.py @@ -1,7 +1,16 @@ +import json +from unittest.mock import MagicMock +from uuid import UUID + from cc_common.config import logger from tests import TstLambdas +TEST_COMPACT = 'cosm' +TEST_FORMER_JURISDICTION = 'tn' +TEST_NEW_JURISDICTION = 'oh' +TEST_PROVIDER_ID = UUID('12345678-1234-5678-1234-567812345678') + class TestEmailServiceClient(TstLambdas): def _generate_test_model(self, mock_lambda_client): @@ -17,3 +26,43 @@ def _generate_test_model(self, mock_lambda_client): return EmailServiceClient( lambda_client=mock_lambda_client, email_notification_service_lambda_name='test-lambda-name', logger=logger ) + + def test_send_provider_home_state_change_email_should_invoke_lambda_client_with_expected_parameters(self): + from cc_common.email_service_client import HomeJurisdictionChangeNotificationTemplateVariables + + mock_lambda_client = MagicMock() + test_model = self._generate_test_model(mock_lambda_client) + + test_model.send_provider_home_state_change_email( + compact=TEST_COMPACT, + jurisdiction=TEST_FORMER_JURISDICTION, + template_variables=HomeJurisdictionChangeNotificationTemplateVariables( + provider_first_name='Jane', + provider_last_name='Smith', + former_jurisdiction=TEST_FORMER_JURISDICTION, + current_jurisdiction=TEST_NEW_JURISDICTION, + license_type='Cosmetologist', + provider_id=TEST_PROVIDER_ID, + ), + ) + + mock_lambda_client.invoke.assert_called_once_with( + FunctionName='test-lambda-name', + InvocationType='RequestResponse', + Payload=json.dumps( + { + 'compact': TEST_COMPACT, + 'jurisdiction': TEST_FORMER_JURISDICTION, + 'template': 'homeJurisdictionChangeNotification', + 'recipientType': 'JURISDICTION_OPERATIONS_TEAM', + 'templateVariables': { + 'providerFirstName': 'Jane', + 'providerLastName': 'Smith', + 'providerId': str(TEST_PROVIDER_ID), + 'previousJurisdiction': TEST_FORMER_JURISDICTION, + 'newJurisdiction': TEST_NEW_JURISDICTION, + 'licenseType': 'Cosmetologist', + }, + } + ), + ) diff --git a/backend/cosmetology-app/lambdas/python/common/tests/unit/test_provider_record_util.py b/backend/cosmetology-app/lambdas/python/common/tests/unit/test_provider_record_util.py index c7748c4f1..def14f631 100644 --- a/backend/cosmetology-app/lambdas/python/common/tests/unit/test_provider_record_util.py +++ b/backend/cosmetology-app/lambdas/python/common/tests/unit/test_provider_record_util.py @@ -466,18 +466,6 @@ def setUp(self): 'adverseActions': [], } - def test_find_best_license_with_home_jurisdiction(self): - """Test that find_best_license correctly filters by home jurisdiction when specified.""" - from cc_common.data_model.provider_record_util import ProviderRecordUtility - - licenses = [ - {**self.base_license, 'jurisdiction': 'oh', 'dateOfIssuance': '2024-02-01'}, - {**self.base_license, 'jurisdiction': 'ky', 'dateOfIssuance': '2024-01-01'}, - ] - - best_license = ProviderRecordUtility.find_best_license(licenses, home_jurisdiction='ky') - self.assertEqual(best_license['jurisdiction'], 'ky') - def test_find_best_license_date_of_issuance_preferred_when_no_renewal(self): """Test that find_best_license selects by most recent issuance.""" from cc_common.data_model.provider_record_util import ProviderRecordUtility @@ -496,7 +484,7 @@ def test_find_best_license_date_of_issuance_preferred_when_no_renewal(self): }, ] - best_license = ProviderRecordUtility.find_best_license(licenses) + best_license = ProviderRecordUtility.find_most_recently_issued_or_renewed_license(licenses) self.assertEqual(best_license['dateOfIssuance'], '2024-02-01') self.assertEqual(best_license['compactEligibility'], CompactEligibilityStatus.INELIGIBLE) @@ -523,7 +511,7 @@ def test_latest_renewed_license_selected_even_when_inactive(self): }, ] - best_license = ProviderRecordUtility.find_best_license(licenses) + best_license = ProviderRecordUtility.find_most_recently_issued_or_renewed_license(licenses) self.assertEqual(best_license['dateOfRenewal'], '2024-06-01') self.assertEqual(best_license['licenseStatus'], ActiveInactiveStatus.INACTIVE) self.assertEqual(best_license['compactEligibility'], CompactEligibilityStatus.INELIGIBLE) @@ -534,7 +522,7 @@ def test_find_best_license_raises_exception_when_no_licenses(self): from cc_common.exceptions import CCInternalException with self.assertRaises(CCInternalException): - ProviderRecordUtility.find_best_license([]) + ProviderRecordUtility.find_most_recently_issued_or_renewed_license([]) def test_find_best_license_complex_scenario(self): """With multiple licenses, the one with the most recent issuance is selected regardless of status.""" @@ -563,7 +551,7 @@ def test_find_best_license_complex_scenario(self): }, ] - best_license = ProviderRecordUtility.find_best_license(licenses) + best_license = ProviderRecordUtility.find_most_recently_issued_or_renewed_license(licenses) self.assertEqual(best_license['dateOfIssuance'], '2024-03-01') self.assertEqual(best_license['compactEligibility'], CompactEligibilityStatus.INELIGIBLE) @@ -730,6 +718,7 @@ def test_single_license_returns_one_document(self): 'licenseStatusName': 'DEFINITELY_A_HUMAN', 'licenseType': 'cosmetologist', 'middleName': 'Gunnar', + 'mostRecentLicenseForType': True, 'phoneNumber': '+13213214321', 'providerId': UUID('89a6377e-c3a5-40e5-bca5-317ec854c570'), 'ssnLastFour': '1234', @@ -765,6 +754,7 @@ def test_single_license_returns_one_document(self): 'type': 'privilege', }, ], + 'adverseActions': [], 'providerId': UUID('89a6377e-c3a5-40e5-bca5-317ec854c570'), 'ssnLastFour': '1234', 'type': 'provider', @@ -843,6 +833,7 @@ def test_two_licenses_different_types_returns_two_documents(self): 'licenseStatusName': 'DEFINITELY_A_HUMAN', 'licenseType': 'cosmetologist', 'middleName': 'Gunnar', + 'mostRecentLicenseForType': True, 'phoneNumber': '+13213214321', 'providerId': UUID('89a6377e-c3a5-40e5-bca5-317ec854c570'), 'ssnLastFour': '1234', @@ -878,6 +869,7 @@ def test_two_licenses_different_types_returns_two_documents(self): 'type': 'privilege', }, ], + 'adverseActions': [], 'providerId': UUID('89a6377e-c3a5-40e5-bca5-317ec854c570'), 'ssnLastFour': '1234', 'type': 'provider', @@ -922,6 +914,7 @@ def test_two_licenses_different_types_returns_two_documents(self): 'licenseStatusName': 'DEFINITELY_A_HUMAN', 'licenseType': 'esthetician', 'middleName': 'Gunnar', + 'mostRecentLicenseForType': True, 'phoneNumber': '+13213214321', 'providerId': UUID('89a6377e-c3a5-40e5-bca5-317ec854c570'), 'ssnLastFour': '1234', @@ -958,6 +951,7 @@ def test_two_licenses_different_types_returns_two_documents(self): 'type': 'privilege', }, ], + 'adverseActions': [], 'providerId': UUID('89a6377e-c3a5-40e5-bca5-317ec854c570'), 'ssnLastFour': '1234', 'type': 'provider', @@ -966,6 +960,56 @@ def test_two_licenses_different_types_returns_two_documents(self): docs, ) + def test_three_licenses_two_same_type_one_other_sets_most_recent_per_type(self): + """Two cosmetologist licenses + one esthetician: each type's most recent license shows + mostRecentLicenseForType true.""" + from cc_common.data_model.provider_record_util import ProviderUserRecords + from cc_common.data_model.schema.common import CompactEligibilityStatus + + records = self._make_provider_records( + license_overrides_list=[ + { + 'jurisdiction': 'ky', + 'licenseType': 'cosmetologist', + 'licenseNumber': 'KY-COS-OLDER', + 'dateOfExpiration': date(2026, 4, 4), + 'dateOfIssuance': date(2005, 1, 1), + 'dateOfRenewal': date(2010, 6, 1), + 'compactEligibility': CompactEligibilityStatus.ELIGIBLE, + 'jurisdictionUploadedCompactEligibility': CompactEligibilityStatus.ELIGIBLE, + }, + { + 'jurisdiction': 'oh', + 'licenseType': 'cosmetologist', + 'dateOfExpiration': date(2026, 4, 4), + 'compactEligibility': CompactEligibilityStatus.ELIGIBLE, + 'jurisdictionUploadedCompactEligibility': CompactEligibilityStatus.ELIGIBLE, + }, + { + 'jurisdiction': 'al', + 'licenseType': 'esthetician', + 'licenseNumber': 'AL-EST-ONLY', + 'dateOfExpiration': date(2026, 4, 4), + 'compactEligibility': CompactEligibilityStatus.ELIGIBLE, + 'jurisdictionUploadedCompactEligibility': CompactEligibilityStatus.ELIGIBLE, + }, + ] + ) + with self._patch_config_for_privilege_generation(): + provider_user_records = ProviderUserRecords(records) + docs = provider_user_records.generate_opensearch_documents() + + self.assertEqual(3, len(docs)) + by_jurisdiction_and_type = { + (d['licenses'][0]['jurisdiction'], d['licenses'][0]['licenseType']): d['licenses'][0][ + 'mostRecentLicenseForType' + ] + for d in docs + } + self.assertFalse(by_jurisdiction_and_type[('ky', 'cosmetologist')]) + self.assertTrue(by_jurisdiction_and_type[('oh', 'cosmetologist')]) + self.assertTrue(by_jurisdiction_and_type[('al', 'esthetician')]) + def test_privileges_assigned_only_to_home_license_document(self): """Privileges are only on the document whose license is the home license for its type.""" from cc_common.data_model.provider_record_util import ProviderUserRecords @@ -1036,6 +1080,7 @@ def test_privileges_assigned_only_to_home_license_document(self): 'licenseStatusName': 'DEFINITELY_A_HUMAN', 'licenseType': 'cosmetologist', 'middleName': 'Gunnar', + 'mostRecentLicenseForType': False, 'phoneNumber': '+13213214321', 'providerId': UUID('89a6377e-c3a5-40e5-bca5-317ec854c570'), 'ssnLastFour': '1234', @@ -1044,6 +1089,7 @@ def test_privileges_assigned_only_to_home_license_document(self): ], 'middleName': 'Gunnar', 'privileges': [], + 'adverseActions': [], 'providerId': UUID('89a6377e-c3a5-40e5-bca5-317ec854c570'), 'ssnLastFour': '1234', 'type': 'provider', @@ -1088,6 +1134,7 @@ def test_privileges_assigned_only_to_home_license_document(self): 'licenseStatusName': 'DEFINITELY_A_HUMAN', 'licenseType': 'cosmetologist', 'middleName': 'Gunnar', + 'mostRecentLicenseForType': True, 'phoneNumber': '+13213214321', 'providerId': UUID('89a6377e-c3a5-40e5-bca5-317ec854c570'), 'ssnLastFour': '1234', @@ -1123,6 +1170,7 @@ def test_privileges_assigned_only_to_home_license_document(self): 'type': 'privilege', }, ], + 'adverseActions': [], 'providerId': UUID('89a6377e-c3a5-40e5-bca5-317ec854c570'), 'ssnLastFour': '1234', 'type': 'provider', @@ -1167,7 +1215,7 @@ def test_multiple_types_privileges_on_correct_home_licenses(self): self.assertGreater(len(esth_privs), 0) def test_license_adverse_actions_included(self): - """Each document includes adverse actions specific to its license.""" + """Each document nests license-targeted adverse actions under that license and duplicates them at top level.""" from cc_common.data_model.provider_record_util import ProviderUserRecords from cc_common.data_model.schema.common import CompactEligibilityStatus @@ -1196,6 +1244,44 @@ def test_license_adverse_actions_included(self): self.assertEqual(1, len(docs)) self.assertEqual(1, len(docs[0]['licenses'][0]['adverseActions'])) + self.assertEqual(1, len(docs[0]['adverseActions'])) + + def test_privilege_adverse_actions_included_in_top_level_adverse_actions(self): + """Privilege-targeted adverse actions are in top-level adverseActions (aggregated list)""" + from cc_common.data_model.provider_record_util import ProviderUserRecords + from cc_common.data_model.schema.common import CompactEligibilityStatus + from common_test.test_data_generator import TestDataGenerator + + privilege_aa = TestDataGenerator.generate_default_adverse_action( + value_overrides={ + 'jurisdiction': 'al', + 'licenseTypeAbbreviation': 'cos', + 'licenseType': 'cosmetologist', + 'actionAgainst': 'privilege', + 'effectiveStartDate': date(2025, 5, 15), + } + ) + records = self._make_provider_records( + license_overrides_list=[ + { + 'jurisdiction': 'oh', + 'licenseType': 'cosmetologist', + 'dateOfExpiration': date(2026, 4, 4), + 'compactEligibility': CompactEligibilityStatus.ELIGIBLE, + } + ], + extra_records=[privilege_aa.serialize_to_database_record()], + ) + with self._patch_config_for_privilege_generation(): + provider_user_records = ProviderUserRecords(records) + all_aa = provider_user_records.get_adverse_action_records() + self.assertEqual(1, len(all_aa)) + self.assertEqual('privilege', all_aa[0].actionAgainst) + docs = provider_user_records.generate_opensearch_documents() + + self.assertEqual(1, len(docs)) + self.assertEqual([], docs[0]['licenses'][0]['adverseActions']) + self.assertEqual([privilege_aa.to_dict()], docs[0]['adverseActions']) def test_no_licenses_returns_empty_list(self): """Provider with no license records produces an empty list.""" diff --git a/backend/cosmetology-app/lambdas/python/compact-configuration/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/compact-configuration/requirements-dev.txt index 3bd349ea8..734805476 100644 --- a/backend/cosmetology-app/lambdas/python/compact-configuration/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/compact-configuration/requirements-dev.txt @@ -4,61 +4,55 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/compact-configuration/requirements-dev.in # -boto3==1.42.89 +boto3==1.43.7 # via moto -botocore==1.42.90 +botocore==1.43.7 # via # boto3 # moto # s3transfer -certifi==2026.2.25 +certifi==2026.4.22 # via requests cffi==2.0.0 # via cryptography charset-normalizer==3.4.7 # via requests -cryptography==46.0.7 +cryptography==48.0.0 # via moto docker==7.1.0 # via moto -idna==3.11 +idna==3.15 # via requests -jinja2==3.1.6 - # via moto jmespath==1.1.0 # via # boto3 # botocore markupsafe==3.0.3 - # via - # jinja2 - # werkzeug -moto[dynamodb,s3]==5.1.22 - # via -r compact-configuration/requirements-dev.in + # via werkzeug +moto[dynamodb,s3]==5.2.1 + # via -r lambdas/python/compact-configuration/requirements-dev.in py-partiql-parser==0.6.3 # via moto pycparser==3.0 # via cffi python-dateutil==2.9.0.post0 - # via - # botocore - # moto + # via botocore pyyaml==6.0.3 # via # moto # responses -requests==2.33.1 +requests==2.34.1 # via # docker # moto # responses responses==0.26.0 # via moto -s3transfer==0.16.0 +s3transfer==0.17.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/cosmetology-app/lambdas/python/custom-resources/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/custom-resources/requirements-dev.txt index dd0a62ac8..e5e4a38e9 100644 --- a/backend/cosmetology-app/lambdas/python/custom-resources/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/custom-resources/requirements-dev.txt @@ -4,61 +4,55 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/custom-resources/requirements-dev.in # -boto3==1.42.89 +boto3==1.43.7 # via moto -botocore==1.42.90 +botocore==1.43.7 # via # boto3 # moto # s3transfer -certifi==2026.2.25 +certifi==2026.4.22 # via requests cffi==2.0.0 # via cryptography charset-normalizer==3.4.7 # via requests -cryptography==46.0.7 +cryptography==48.0.0 # via moto docker==7.1.0 # via moto -idna==3.11 +idna==3.15 # via requests -jinja2==3.1.6 - # via moto jmespath==1.1.0 # via # boto3 # botocore markupsafe==3.0.3 - # via - # jinja2 - # werkzeug -moto[dynamodb,s3]==5.1.22 - # via -r custom-resources/requirements-dev.in + # via werkzeug +moto[dynamodb,s3]==5.2.1 + # via -r lambdas/python/custom-resources/requirements-dev.in py-partiql-parser==0.6.3 # via moto pycparser==3.0 # via cffi python-dateutil==2.9.0.post0 - # via - # botocore - # moto + # via botocore pyyaml==6.0.3 # via # moto # responses -requests==2.33.1 +requests==2.34.1 # via # docker # moto # responses responses==0.26.0 # via moto -s3transfer==0.16.0 +s3transfer==0.17.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/cosmetology-app/lambdas/python/data-events/handlers/encumbrance_events.py b/backend/cosmetology-app/lambdas/python/data-events/handlers/encumbrance_events.py index e81dd8ed8..30d836cdb 100644 --- a/backend/cosmetology-app/lambdas/python/data-events/handlers/encumbrance_events.py +++ b/backend/cosmetology-app/lambdas/python/data-events/handlers/encumbrance_events.py @@ -242,8 +242,8 @@ def privilege_encumbrance_notification_listener(message: dict, tracker: Notifica # Get license type name from abbreviation (lookup once at the top) license_type_name = _get_license_type_name(compact, license_type_abbreviation) - # Get provider records to gather notification targets and provider information - provider_records, provider_record = _get_provider_records(compact, provider_id) + # Get top level provider record to gather provider information + provider_record = config.data_client.get_provider_top_level_record(compact=compact, provider_id=provider_id) # State Notifications # Send notification to the state where the privilege is encumbered @@ -432,8 +432,8 @@ def license_encumbrance_notification_listener(message: dict, tracker: Notificati # Get license type name from abbreviation (lookup once at the top) license_type_name = _get_license_type_name(compact, license_type_abbreviation) - # Get provider records to gather notification targets and provider information - provider_records, provider_record = _get_provider_records(compact, provider_id) + # Get top level provider record to gather provider information + provider_record = config.data_client.get_provider_top_level_record(compact=compact, provider_id=provider_id) # State Notifications # Send notification to the state where the license is encumbered diff --git a/backend/cosmetology-app/lambdas/python/data-events/handlers/home_state_change_events.py b/backend/cosmetology-app/lambdas/python/data-events/handlers/home_state_change_events.py new file mode 100644 index 000000000..35d9065b6 --- /dev/null +++ b/backend/cosmetology-app/lambdas/python/data-events/handlers/home_state_change_events.py @@ -0,0 +1,55 @@ +from cc_common.config import config, logger +from cc_common.data_model.schema.data_event.api import HomeJurisdictionChangeEventDetailSchema +from cc_common.email_service_client import HomeJurisdictionChangeNotificationTemplateVariables +from cc_common.utils import sqs_handler + + +@sqs_handler +def home_state_change_notification_listener(message: dict): + """ + Handle home state change events by sending notifications. + + For the Cosmetology compact, the home state for a practitioner is determined by + which license was issued or renewed most recently. If another home state uploads + or renews a license record for that same practitioner with a more recent date, + that state becomes the new home state for that practitioner, and this notification + listener is triggered. + """ + detail_schema = HomeJurisdictionChangeEventDetailSchema() + detail = detail_schema.load(message['detail']) + + compact = detail['compact'] + provider_id = detail['providerId'] + jurisdiction = detail['jurisdiction'] + former_home_jurisdiction = detail['formerHomeJurisdiction'] + license_type = detail['licenseType'] + event_time = detail['eventTime'] + + with logger.append_context_keys( + compact=compact, + provider_id=provider_id, + jurisdiction=jurisdiction, + license_type=license_type, + event_time=event_time, + ): + logger.info('Processing provider home state change event') + + # Get top level provider record to gather provider information + provider_record = config.data_client.get_provider_top_level_record(compact=compact, provider_id=provider_id) + + # Send notification to former state + config.email_service_client.send_provider_home_state_change_email( + compact=compact, + # in the case of cosmetology, we only send the email notification to the former state. + jurisdiction=former_home_jurisdiction, + template_variables=HomeJurisdictionChangeNotificationTemplateVariables( + provider_first_name=provider_record.givenName, + provider_last_name=provider_record.familyName, + former_jurisdiction=former_home_jurisdiction, + current_jurisdiction=jurisdiction, + license_type=license_type, + provider_id=provider_id, + ), + ) + + logger.info('Successfully processed home state change event') diff --git a/backend/cosmetology-app/lambdas/python/data-events/handlers/investigation_events.py b/backend/cosmetology-app/lambdas/python/data-events/handlers/investigation_events.py index 59ff56f22..579011e6e 100644 --- a/backend/cosmetology-app/lambdas/python/data-events/handlers/investigation_events.py +++ b/backend/cosmetology-app/lambdas/python/data-events/handlers/investigation_events.py @@ -2,7 +2,6 @@ from uuid import UUID from cc_common.config import config, logger -from cc_common.data_model.provider_record_util import ProviderUserRecords from cc_common.data_model.schema.data_event.api import InvestigationEventDetailSchema from cc_common.data_model.schema.provider import ProviderData from cc_common.email_service_client import InvestigationNotificationTemplateVariables @@ -19,27 +18,6 @@ def __call__( ) -> dict[str, Any]: ... -def _get_provider_records(compact: str, provider_id: str) -> tuple[ProviderUserRecords, ProviderData]: - """ - Retrieve and validate provider records for notification processing. - - :param compact: The compact identifier - :param provider_id: The provider ID - :return: Tuple of (provider_records, provider_record) - :raises Exception: If provider records cannot be retrieved - """ - try: - provider_records = config.data_client.get_provider_user_records( - compact=compact, - provider_id=provider_id, - ) - provider_record = provider_records.get_provider_record() - return provider_records, provider_record - except Exception as e: - logger.error('Failed to retrieve provider records for notification', exception=str(e)) - raise - - def _send_primary_state_notification( notification_method: JurisdictionNotificationMethod, notification_type: str, @@ -164,8 +142,8 @@ def license_investigation_notification_listener(message: dict): # Get license type name from abbreviation (lookup once at the top) license_type_name = LicenseUtility.get_license_type_by_abbreviation(compact, license_type_abbreviation).name - # Get provider records to gather notification targets and provider information - provider_records, provider_record = _get_provider_records(compact, provider_id) + # Get top level provider record to gather provider information + provider_record = config.data_client.get_provider_top_level_record(compact=compact, provider_id=provider_id) # State Notifications # Note: We do NOT send notifications to providers for investigations @@ -231,8 +209,8 @@ def license_investigation_closed_notification_listener(message: dict): # Get license type name from abbreviation (lookup once at the top) license_type_name = LicenseUtility.get_license_type_by_abbreviation(compact, license_type_abbreviation).name - # Get provider records to gather notification targets and provider information - provider_records, provider_record = _get_provider_records(compact, provider_id) + # Get top level provider record to gather provider information + provider_record = config.data_client.get_provider_top_level_record(compact=compact, provider_id=provider_id) # State Notifications # Note: We do NOT send notifications to providers for investigations @@ -292,8 +270,8 @@ def privilege_investigation_notification_listener(message: dict): # Get license type name from abbreviation (lookup once at the top) license_type_name = LicenseUtility.get_license_type_by_abbreviation(compact, license_type_abbreviation).name - # Get provider records to gather notification targets and provider information - provider_records, provider_record = _get_provider_records(compact, provider_id) + # Get top level provider record to gather provider information + provider_record = config.data_client.get_provider_top_level_record(compact=compact, provider_id=provider_id) # State Notifications # Note: We do NOT send notifications to providers for investigations @@ -359,11 +337,10 @@ def privilege_investigation_closed_notification_listener(message: dict): # Get license type name from abbreviation (lookup once at the top) license_type_name = LicenseUtility.get_license_type_by_abbreviation(compact, license_type_abbreviation).name - # Get provider records to gather notification targets and provider information - provider_records, provider_record = _get_provider_records(compact, provider_id) + # Get top level provider record to gather provider information + provider_record = config.data_client.get_provider_top_level_record(compact=compact, provider_id=provider_id) # State Notifications - # Note: We do NOT send notifications to providers for investigations # Send notification to the state where the privilege investigation was closed _send_primary_state_notification( config.email_service_client.send_privilege_investigation_closed_state_notification_email, diff --git a/backend/cosmetology-app/lambdas/python/data-events/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/data-events/requirements-dev.txt index 84af3711c..4b10e789c 100644 --- a/backend/cosmetology-app/lambdas/python/data-events/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/data-events/requirements-dev.txt @@ -4,61 +4,55 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/data-events/requirements-dev.in # -boto3==1.42.89 +boto3==1.43.7 # via moto -botocore==1.42.90 +botocore==1.43.7 # via # boto3 # moto # s3transfer -certifi==2026.2.25 +certifi==2026.4.22 # via requests cffi==2.0.0 # via cryptography charset-normalizer==3.4.7 # via requests -cryptography==46.0.7 +cryptography==48.0.0 # via moto docker==7.1.0 # via moto -idna==3.11 +idna==3.15 # via requests -jinja2==3.1.6 - # via moto jmespath==1.1.0 # via # boto3 # botocore markupsafe==3.0.3 - # via - # jinja2 - # werkzeug -moto[dynamodb,s3]==5.1.22 - # via -r data-events/requirements-dev.in + # via werkzeug +moto[dynamodb,s3]==5.2.1 + # via -r lambdas/python/data-events/requirements-dev.in py-partiql-parser==0.6.3 # via moto pycparser==3.0 # via cffi python-dateutil==2.9.0.post0 - # via - # botocore - # moto + # via botocore pyyaml==6.0.3 # via # moto # responses -requests==2.33.1 +requests==2.34.1 # via # docker # moto # responses responses==0.26.0 # via moto -s3transfer==0.16.0 +s3transfer==0.17.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/cosmetology-app/lambdas/python/data-events/tests/function/test_home_state_change_events.py b/backend/cosmetology-app/lambdas/python/data-events/tests/function/test_home_state_change_events.py new file mode 100644 index 000000000..fe190d48e --- /dev/null +++ b/backend/cosmetology-app/lambdas/python/data-events/tests/function/test_home_state_change_events.py @@ -0,0 +1,91 @@ +import json +from datetime import datetime +from unittest.mock import patch +from uuid import UUID + +from common_test.test_constants import ( + DEFAULT_COMPACT, + DEFAULT_DATE_OF_UPDATE_TIMESTAMP, + DEFAULT_LICENSE_JURISDICTION, + DEFAULT_LICENSE_TYPE, + DEFAULT_PROVIDER_ID, +) +from moto import mock_aws + +from . import TstFunction + +TEST_FORMER_LICENSE_JURISDICTION = 'az' + + +@mock_aws +@patch('cc_common.config._Config.current_standard_datetime', datetime.fromisoformat(DEFAULT_DATE_OF_UPDATE_TIMESTAMP)) +class TestHomeStateChangeEvents(TstFunction): + """Test suite for investigation event handlers.""" + + def _generate_license_home_state_change_message(self, message_overrides=None): + """Generate a test SQS message for license home state change events.""" + message = { + 'detail': { + 'compact': DEFAULT_COMPACT, + 'providerId': DEFAULT_PROVIDER_ID, + 'jurisdiction': DEFAULT_LICENSE_JURISDICTION, + 'licenseType': DEFAULT_LICENSE_TYPE, + 'eventTime': DEFAULT_DATE_OF_UPDATE_TIMESTAMP, + 'formerHomeJurisdiction': TEST_FORMER_LICENSE_JURISDICTION, + } + } + if message_overrides: + message['detail'].update(message_overrides) + return message + + def _create_sqs_event(self, message): + """Create a proper SQS event structure with the message in the body.""" + return {'Records': [{'messageId': '123', 'body': json.dumps(message)}]} + + @patch('cc_common.email_service_client.EmailServiceClient.send_provider_home_state_change_email') + def test_license_homes_state_change_listener_sends_notification_to_former_state(self, mock_state_email): + """Test that license home state change listener sends an email notification to the former state.""" + from cc_common.email_service_client import HomeJurisdictionChangeNotificationTemplateVariables + from handlers.home_state_change_events import home_state_change_notification_listener + + # Set up test data with registered provider + self.test_data_generator.put_default_provider_record_in_provider_table() + + # Add the license for the former home state + self.test_data_generator.put_default_license_record_in_provider_table( + value_overrides={'jurisdiction': TEST_FORMER_LICENSE_JURISDICTION} + ) + # Add license for the current home state + self.test_data_generator.put_default_license_record_in_provider_table() + + message = self._generate_license_home_state_change_message() + event = self._create_sqs_event(message) + + # Execute the handler + result = home_state_change_notification_listener(event, self.mock_context) + + # Should succeed with no batch failures + self.assertEqual({'batchItemFailures': []}, result) + + expected_template_variables = HomeJurisdictionChangeNotificationTemplateVariables( + provider_first_name='Björk', + provider_last_name='Guðmundsdóttir', + former_jurisdiction=TEST_FORMER_LICENSE_JURISDICTION, + current_jurisdiction=DEFAULT_LICENSE_JURISDICTION, + license_type=DEFAULT_LICENSE_TYPE, + provider_id=UUID(DEFAULT_PROVIDER_ID), + ) + expected_state_call = [ + { + 'compact': DEFAULT_COMPACT, + # we only send to the former home state + 'jurisdiction': TEST_FORMER_LICENSE_JURISDICTION, + 'template_variables': expected_template_variables, + }, + ] + + # Verify state notification was sent + self.assertEqual(1, mock_state_email.call_count) + actual_state_calls = [call.kwargs for call in mock_state_email.call_args_list] + + self.assertEqual(expected_state_call, actual_state_calls) diff --git a/backend/cosmetology-app/lambdas/python/data-events/tests/function/test_investigation_events.py b/backend/cosmetology-app/lambdas/python/data-events/tests/function/test_investigation_events.py index 30207e018..75bb79612 100644 --- a/backend/cosmetology-app/lambdas/python/data-events/tests/function/test_investigation_events.py +++ b/backend/cosmetology-app/lambdas/python/data-events/tests/function/test_investigation_events.py @@ -94,8 +94,8 @@ def _create_sqs_event(self, message): return {'Records': [{'messageId': '123', 'body': json.dumps(message)}]} @patch('cc_common.email_service_client.EmailServiceClient.send_license_investigation_state_notification_email') - def test_license_investigation_listener_processes_event_with_registered_provider(self, mock_state_email): - """Test that license investigation listener processes events for registered providers.""" + def test_license_investigation_listener_processes_event_with_provider(self, mock_state_email): + """Test that license investigation listener processes events for provider.""" from cc_common.email_service_client import InvestigationNotificationTemplateVariables from handlers.investigation_events import license_investigation_notification_listener @@ -158,8 +158,8 @@ def test_license_investigation_listener_processes_event_with_registered_provider @patch( 'cc_common.email_service_client.EmailServiceClient.send_license_investigation_closed_state_notification_email' ) - def test_license_investigation_closed_listener_processes_event_with_registered_provider(self, mock_state_email): - """Test that license investigation closed listener processes events for registered providers.""" + def test_license_investigation_closed_listener_processes_event_with_provider(self, mock_state_email): + """Test that license investigation closed listener processes events for provider.""" from cc_common.email_service_client import InvestigationNotificationTemplateVariables from handlers.investigation_events import license_investigation_closed_notification_listener @@ -219,8 +219,8 @@ def test_license_investigation_closed_listener_processes_event_with_registered_p self.assertEqual(expected_state_calls_sorted, actual_state_calls_sorted) @patch('cc_common.email_service_client.EmailServiceClient.send_privilege_investigation_state_notification_email') - def test_privilege_investigation_listener_processes_event_with_registered_provider(self, mock_state_email): - """Test that privilege investigation listener processes events for registered providers.""" + def test_privilege_investigation_listener_processes_event_with_provider(self, mock_state_email): + """Test that privilege investigation listener processes events for provider.""" from cc_common.email_service_client import InvestigationNotificationTemplateVariables from handlers.investigation_events import privilege_investigation_notification_listener @@ -280,8 +280,8 @@ def test_privilege_investigation_listener_processes_event_with_registered_provid @patch( 'cc_common.email_service_client.EmailServiceClient.send_privilege_investigation_closed_state_notification_email' ) - def test_privilege_investigation_closed_listener_processes_event_with_registered_provider(self, mock_state_email): - """Test that privilege investigation closed listener processes events for registered providers.""" + def test_privilege_investigation_closed_listener_processes_event_with_provider(self, mock_state_email): + """Test that privilege investigation closed listener processes events for provider.""" from cc_common.email_service_client import InvestigationNotificationTemplateVariables from handlers.investigation_events import privilege_investigation_closed_notification_listener diff --git a/backend/cosmetology-app/lambdas/python/disaster-recovery/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/disaster-recovery/requirements-dev.txt index 7a9765c02..8336576cc 100644 --- a/backend/cosmetology-app/lambdas/python/disaster-recovery/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/disaster-recovery/requirements-dev.txt @@ -4,61 +4,55 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/disaster-recovery/requirements-dev.in # -boto3==1.42.89 +boto3==1.43.7 # via moto -botocore==1.42.90 +botocore==1.43.7 # via # boto3 # moto # s3transfer -certifi==2026.2.25 +certifi==2026.4.22 # via requests cffi==2.0.0 # via cryptography charset-normalizer==3.4.7 # via requests -cryptography==46.0.7 +cryptography==48.0.0 # via moto docker==7.1.0 # via moto -idna==3.11 +idna==3.15 # via requests -jinja2==3.1.6 - # via moto jmespath==1.1.0 # via # boto3 # botocore markupsafe==3.0.3 - # via - # jinja2 - # werkzeug -moto[dynamodb,s3]==5.1.22 - # via -r disaster-recovery/requirements-dev.in + # via werkzeug +moto[dynamodb,s3]==5.2.1 + # via -r lambdas/python/disaster-recovery/requirements-dev.in py-partiql-parser==0.6.3 # via moto pycparser==3.0 # via cffi python-dateutil==2.9.0.post0 - # via - # botocore - # moto + # via botocore pyyaml==6.0.3 # via # moto # responses -requests==2.33.1 +requests==2.34.1 # via # docker # moto # responses responses==0.26.0 # via moto -s3transfer==0.16.0 +s3transfer==0.17.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/cosmetology-app/lambdas/python/feature-flag/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/feature-flag/requirements-dev.txt index 280846e04..49a7ffd2c 100644 --- a/backend/cosmetology-app/lambdas/python/feature-flag/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/feature-flag/requirements-dev.txt @@ -56,7 +56,7 @@ s3transfer==0.16.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.5.0 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/cosmetology-app/lambdas/python/feature-flag/requirements.txt b/backend/cosmetology-app/lambdas/python/feature-flag/requirements.txt index f20f193c3..1b8a3684e 100644 --- a/backend/cosmetology-app/lambdas/python/feature-flag/requirements.txt +++ b/backend/cosmetology-app/lambdas/python/feature-flag/requirements.txt @@ -16,5 +16,5 @@ statsig-python-core==0.19.1 # via -r requirements.in typing-extensions==4.15.0 # via statsig-python-core -urllib3==2.5.0 +urllib3==2.7.0 # via requests diff --git a/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/__init__.py b/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/__init__.py index 8939ee726..43e1ee52d 100644 --- a/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/__init__.py +++ b/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/__init__.py @@ -4,18 +4,20 @@ @logger_inject_kwargs(logger, 'compact', 'provider_id') -def get_provider_information(compact: str, provider_id: str) -> dict: +def get_provider_information(compact: str, provider_id: str, is_public_response: bool = False) -> dict: """Common method to get provider information by compact and provider id. - Currently, this is used by staff-users to get information for a specific provider, - provider-users to get their own information, and the public lookup api to get a filtered response. + Currently, this is used by staff-users to get information for a specific provider + and the public lookup api to get a filtered response. :param compact: Compact the provider belongs to. :param provider_id: The provider's unique identifier. + :param is_public_response: If True, licenses that are not the most recent license for a type will + not be included in the response. :return: Provider profile information. """ # Collect all main provider records and privilege update records, which are included in tier one. provider_user_records = config.data_client.get_provider_user_records( compact=compact, provider_id=provider_id, include_update_tier=UpdateTierEnum.TIER_ONE ) - return provider_user_records.generate_api_response_object() + return provider_user_records.generate_api_response_object(is_public_response=is_public_response) diff --git a/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/ingest.py b/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/ingest.py index dbd30e470..58e449f4c 100644 --- a/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/ingest.py +++ b/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/ingest.py @@ -125,6 +125,7 @@ def ingest_license_message(message: dict): consistent_read=True, ) provider_records = provider_data['items'] + license_records = ProviderRecordUtility.get_records_of_type( provider_records, ProviderRecordType.LICENSE, @@ -134,7 +135,7 @@ def ingest_license_message(message: dict): licenses_organized.setdefault(record['jurisdiction'], {}) licenses_organized[record['jurisdiction']][record['licenseType']] = record - # Get the home jurisdiction selection, if it exists + # Parse the top level provider record into a data class instance current_provider_record = ProviderData.create_new( ProviderRecordUtility.get_provider_record(provider_records) ) @@ -184,17 +185,40 @@ def ingest_license_message(message: dict): for license_record in jurisdiction_licenses.values() ] - best_license = ProviderRecordUtility.find_best_license( + best_license = ProviderRecordUtility.find_most_recently_issued_or_renewed_license( license_records=licenses_flattened, ) if best_license is posted_license_record: logger.info('Updating provider data') + # If this posted license is the most recent issued/renewed license for the provider, + # and it's from a different jurisdiction, send a home jurisdiction change notification event + # to notify the former home jurisdiction. + if ( + current_provider_record + and current_provider_record.licenseJurisdiction != best_license['jurisdiction'] + ): + logger.info( + 'New home state license detected. Sending home state change notification.', + previous_home_jurisdiction=current_provider_record.licenseJurisdiction, + new_home_jurisdiction=jurisdiction, + ) + home_jurisdiction_change_event = config.event_bus_client.generate_home_jurisdiction_change_event( + source='org.compactconnect.provider-data', + compact=compact, + jurisdiction=jurisdiction, + provider_id=current_provider_record.providerId, + license_type=posted_license_record['licenseType'], + former_home_jurisdiction=current_provider_record.licenseJurisdiction, + ) + data_events.append(home_jurisdiction_change_event) + + # Update our top level provider record with data from the posted license provider_record = ProviderRecordUtility.populate_provider_record( current_provider_record=current_provider_record, license_record=posted_license_record ) - # Update our provider data + dynamo_transactions.append( { 'Put': { @@ -206,6 +230,7 @@ def ingest_license_message(message: dict): # Write the records together as a transaction that succeeds or fails as one, to ensure consistency config.dynamodb_client.transact_write_items(TransactItems=dynamo_transactions) + # We'll save our events until after the transaction is written, to ensure consistency with EventBatchWriter(config.events_client) as event_writer: for event in data_events: diff --git a/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/public_lookup.py b/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/public_lookup.py index 9fa6abd8f..2d4706054 100644 --- a/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/public_lookup.py +++ b/backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/public_lookup.py @@ -22,7 +22,9 @@ def public_get_provider(event: dict, context: LambdaContext): # noqa: ARG001 un raise CCInvalidRequestException('Missing required field') from e with logger.append_context_keys(compact=compact, provider_id=provider_id): - provider_information = get_provider_information(compact=compact, provider_id=provider_id) + provider_information = get_provider_information( + compact=compact, provider_id=provider_id, is_public_response=True + ) public_schema = ProviderPublicResponseSchema() return public_schema.load(provider_information) diff --git a/backend/cosmetology-app/lambdas/python/provider-data-v1/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/provider-data-v1/requirements-dev.txt index 48adc79de..4c65d1dc2 100644 --- a/backend/cosmetology-app/lambdas/python/provider-data-v1/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/provider-data-v1/requirements-dev.txt @@ -4,63 +4,57 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/provider-data-v1/requirements-dev.in # -boto3==1.42.89 +boto3==1.43.7 # via moto -botocore==1.42.90 +botocore==1.43.7 # via # boto3 # moto # s3transfer -certifi==2026.2.25 +certifi==2026.4.22 # via requests cffi==2.0.0 # via cryptography charset-normalizer==3.4.7 # via requests -cryptography==46.0.7 +cryptography==48.0.0 # via moto docker==7.1.0 # via moto -faker==40.13.0 - # via -r provider-data-v1/requirements-dev.in -idna==3.11 +faker==40.15.0 + # via -r lambdas/python/provider-data-v1/requirements-dev.in +idna==3.15 # via requests -jinja2==3.1.6 - # via moto jmespath==1.1.0 # via # boto3 # botocore markupsafe==3.0.3 - # via - # jinja2 - # werkzeug -moto[dynamodb,s3]==5.1.22 - # via -r provider-data-v1/requirements-dev.in + # via werkzeug +moto[dynamodb,s3]==5.2.1 + # via -r lambdas/python/provider-data-v1/requirements-dev.in py-partiql-parser==0.6.3 # via moto pycparser==3.0 # via cffi python-dateutil==2.9.0.post0 - # via - # botocore - # moto + # via botocore pyyaml==6.0.3 # via # moto # responses -requests==2.33.1 +requests==2.34.1 # via # docker # moto # responses responses==0.26.0 # via moto -s3transfer==0.16.0 +s3transfer==0.17.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/cosmetology-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.py b/backend/cosmetology-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.py index 6cba9cbb3..95b85c995 100644 --- a/backend/cosmetology-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.py +++ b/backend/cosmetology-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.py @@ -1,6 +1,6 @@ import json from datetime import date, datetime -from unittest.mock import patch +from unittest.mock import MagicMock, patch from moto import mock_aws @@ -657,3 +657,151 @@ def test_multiple_license_types_different_jurisdictions(self): self.assertEqual('ky', provider_data['licenseJurisdiction']) self.assertEqual('Audrey', provider_data['givenName']) self.assertEqual('Guðmundsdóttir', provider_data['familyName']) + + def test_same_license_types_different_jurisdictions_triggers_home_jurisdiction_change_event_bridge_notification( + self, + ): + """ + Same license type (cosmetologist) in two jurisdictions: a newer issuance from KY replaces OH as the best + cosmetologist license and ingest emits ``provider.homeStateChange`` with former OH and new KY. + """ + import handlers.ingest as ingest_handler + from handlers.ingest import ingest_license_message + + provider_id = self._with_ingested_license() + provider_data_after_first_license = self._get_provider_via_api(provider_id) + + # Verify the first license was ingested correctly + self.assertEqual(1, len(provider_data_after_first_license['licenses'])) + self.assertEqual('cosmetologist', provider_data_after_first_license['licenses'][0]['licenseType']) + self.assertEqual('oh', provider_data_after_first_license['licenseJurisdiction']) + self.assertEqual('Björk', provider_data_after_first_license['givenName']) + + with open('../common/tests/resources/ingest/event-bridge-message.json') as f: + message = json.load(f) + + # Same license type as OH, but KY upload with a newer issuance date → new “home” license jurisdiction for type + message['detail'].update( + { + 'licenseType': 'cosmetologist', + 'jurisdiction': 'ky', + 'dateOfIssuance': '2020-06-06', + 'licenseNumber': 'B0608337260', + 'givenName': 'Audrey', + } + ) + + mock_put_events = MagicMock(return_value={'FailedEntryCount': 0, 'Entries': [{'EventId': 'evt-1'}]}) + # Patch the EventBridge client bound on this lambda's config (setUp replaces the global singleton each test). + with patch.object(ingest_handler.config.events_client, 'put_events', mock_put_events): + event = {'Records': [{'messageId': '456', 'body': json.dumps(message)}]} + resp = ingest_license_message(event, self.mock_context) + self.assertEqual({'batchItemFailures': []}, resp) + + mock_put_events.assert_called_once() + entries = mock_put_events.call_args.kwargs['Entries'] + self.assertEqual(1, len(entries)) + home_change_entry = entries[0] + self.assertEqual( + { + 'Detail': json.dumps( + { + 'compact': 'cosm', + 'jurisdiction': 'ky', + 'eventTime': '2024-11-08T23:59:59+00:00', + 'providerId': '89a6377e-c3a5-40e5-bca5-317ec854c570', + 'licenseType': 'cosmetologist', + 'formerHomeJurisdiction': 'oh', + } + ), + 'DetailType': 'provider.homeStateChange', + 'EventBusName': 'license-data-events', + 'Source': 'org.compactconnect.provider-data', + }, + home_change_entry, + ) + + provider_data = self._get_provider_via_api(provider_id) + + self.assertEqual(2, len(provider_data['licenses'])) + oh_license = next((lic for lic in provider_data['licenses'] if lic['jurisdiction'] == 'oh'), None) + ky_license = next((lic for lic in provider_data['licenses'] if lic['jurisdiction'] == 'ky'), None) + + # Verify both licenses exist + self.assertIsNotNone(oh_license, 'Ohio license not found') + self.assertIsNotNone(ky_license, 'Kentucky license not found') + + # Verify license details + self.assertEqual('cosmetologist', oh_license['licenseType']) + self.assertEqual('A0608337260', oh_license['licenseNumber']) + self.assertEqual('2010-06-06', oh_license['dateOfIssuance']) + self.assertEqual('Björk', oh_license['givenName']) + + self.assertEqual('cosmetologist', ky_license['licenseType']) + self.assertEqual('B0608337260', ky_license['licenseNumber']) + self.assertEqual('2020-06-06', ky_license['dateOfIssuance']) + self.assertEqual('Audrey', ky_license['givenName']) + + self.assertEqual('ky', provider_data['licenseJurisdiction']) + self.assertEqual('Audrey', provider_data['givenName']) + + def test_multiple_license_types_different_jurisdictions_does_not_trigger_home_jurisdiction_change( + self, + ): + """ + In this case, we have a practitioner with two existing license types in a jurisdiction. A new license is added + from jurisdiction that is more recent than the corresponding license type in the original jurisdiction, but not + the most recent license. The home state should be determined solely by the most recently issued/renewed license, + regardless of the license type. + """ + import handlers.ingest as ingest_handler + from handlers.ingest import ingest_license_message + + provider_id = self._with_ingested_license() + # add a new license type, + self.test_data_generator.put_default_license_record_in_provider_table( + value_overrides={ + 'providerId': provider_id, + 'licenseType': 'esthetician', + 'dateOfIssuance': date.fromisoformat('2024-05-06'), + 'jurisdiction': 'oh', + } + ) + # update the original to later date + self.test_data_generator.put_default_license_record_in_provider_table( + value_overrides={ + 'providerId': provider_id, + 'licenseType': 'cosmetologist', + 'jurisdiction': 'oh', + 'dateOfRenewal': date.fromisoformat('2026-06-06'), + } + ) + + with open('../common/tests/resources/ingest/event-bridge-message.json') as f: + message = json.load(f) + + # Same license type in KY, with a newer issuance date then the same license in OH, + # but not the most recent renewal date. No new "home" license jurisdiction event should be issued. + message['detail'].update( + { + 'licenseType': 'esthetician', + 'jurisdiction': 'ky', + 'dateOfIssuance': '2025-06-06', + 'licenseNumber': 'B0608337260', + 'givenName': 'Audrey', + } + ) + + mock_put_events = MagicMock(return_value={'FailedEntryCount': 0, 'Entries': [{'EventId': 'evt-1'}]}) + # Patch the EventBridge client bound on this lambda's config (setUp replaces the global singleton each test). + with patch.object(ingest_handler.config.events_client, 'put_events', mock_put_events): + event = {'Records': [{'messageId': '456', 'body': json.dumps(message)}]} + resp = ingest_license_message(event, self.mock_context) + self.assertEqual({'batchItemFailures': []}, resp) + + mock_put_events.assert_not_called() + + # Verify provider record remains the same + provider_data = self._get_provider_via_api(provider_id) + self.assertEqual('oh', provider_data['licenseJurisdiction']) + self.assertEqual('Björk', provider_data['givenName']) diff --git a/backend/cosmetology-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.py b/backend/cosmetology-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.py index d7c72db8f..09b4f8d58 100644 --- a/backend/cosmetology-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.py +++ b/backend/cosmetology-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.py @@ -1,11 +1,50 @@ import json -from datetime import datetime +from datetime import date, datetime from unittest.mock import patch from moto import mock_aws from .. import TstFunction +# ProviderPublicResponseSchema + LicensePublicResponseSchema + PrivilegePublicResponseSchema +EXPECTED_PROVIDER_RESPONSE = { + 'type': 'provider', + 'providerId': '89a6377e-c3a5-40e5-bca5-317ec854c570', + 'dateOfUpdate': '2024-07-08T23:59:59+00:00', + 'compact': 'cosm', + 'licenseJurisdiction': 'oh', + 'licenseStatus': 'active', + 'compactEligibility': 'eligible', + 'givenName': 'Björk', + 'middleName': 'Gunnar', + 'familyName': 'Guðmundsdóttir', + 'licenses': [ + { + 'type': 'license', + 'compact': 'cosm', + 'jurisdiction': 'oh', + 'licenseType': 'cosmetologist', + 'licenseStatus': 'active', + 'compactEligibility': 'eligible', + 'dateOfExpiration': '2025-04-04', + 'licenseNumber': 'A0608337260', + } + ], + 'privileges': [ + { + 'type': 'privilege', + 'providerId': '89a6377e-c3a5-40e5-bca5-317ec854c570', + 'compact': 'cosm', + 'jurisdiction': 'ne', + 'licenseJurisdiction': 'oh', + 'licenseType': 'cosmetologist', + 'dateOfExpiration': '2025-04-04', + 'administratorSetStatus': 'active', + 'status': 'active', + } + ], +} + @mock_aws @patch('cc_common.config._Config.current_standard_datetime', datetime.fromisoformat('2024-11-08T23:59:59+00:00')) @@ -32,46 +71,110 @@ def test_public_get_provider_response_with_expected_fields_filtered(self): self.assertEqual(200, resp['statusCode']) provider_data = json.loads(resp['body']) - # ProviderPublicResponseSchema + LicensePublicResponseSchema + PrivilegePublicResponseSchema - expected_provider = { - 'type': 'provider', - 'providerId': '89a6377e-c3a5-40e5-bca5-317ec854c570', - 'dateOfUpdate': '2024-07-08T23:59:59+00:00', - 'compact': 'cosm', - 'licenseJurisdiction': 'oh', - 'licenseStatus': 'active', - 'compactEligibility': 'eligible', - 'givenName': 'Björk', - 'middleName': 'Gunnar', - 'familyName': 'Guðmundsdóttir', - 'licenses': [ - { - 'type': 'license', - 'compact': 'cosm', - 'jurisdiction': 'oh', - 'licenseType': 'cosmetologist', - 'licenseStatus': 'active', - 'compactEligibility': 'eligible', - 'dateOfExpiration': '2025-04-04', - 'licenseNumber': 'A0608337260', - } - ], - 'privileges': [ - { - 'type': 'privilege', - 'providerId': '89a6377e-c3a5-40e5-bca5-317ec854c570', - 'compact': 'cosm', - 'jurisdiction': 'ne', - 'licenseJurisdiction': 'oh', - 'licenseType': 'cosmetologist', - 'dateOfExpiration': '2025-04-04', - 'administratorSetStatus': 'active', - 'status': 'active', - } - ], - } + self.assertEqual(EXPECTED_PROVIDER_RESPONSE, provider_data) + + def test_public_get_provider_response_only_returns_most_recent_licenses(self): + self._load_provider_data() + # adding another license for same license type from another state, with an older issuance and renewal date + self.test_data_generator.put_default_license_record_in_provider_table( + value_overrides={ + 'dateOfIssuance': date(2019, 1, 1), + 'dateOfRenewal': date(2020, 1, 1), + 'licenseNumber': 'olderCosmLicense', + 'jurisdiction': 'az', + } + ) + + from handlers.public_lookup import public_get_provider + + with open('../common/tests/resources/api-event.json') as f: + event = json.load(f) + + # public endpoint does not have authorizer + del event['requestContext']['authorizer'] + event['pathParameters'] = {'compact': 'cosm', 'providerId': '89a6377e-c3a5-40e5-bca5-317ec854c570'} + event['queryStringParameters'] = None + + resp = public_get_provider(event, self.mock_context) + + self.assertEqual(200, resp['statusCode']) + provider_data = json.loads(resp['body']) + + # the older license should not be included in the response + self.assertEqual(EXPECTED_PROVIDER_RESPONSE, provider_data) + + def test_public_get_provider_response_returns_multiple_license_types(self): + self._load_provider_data() + # adding another license for same license type from another state, with an older issuance and renewal date + self.test_data_generator.put_default_license_record_in_provider_table( + value_overrides={ + 'dateOfIssuance': date(2019, 1, 1), + 'dateOfRenewal': date(2020, 1, 1), + 'licenseNumber': 'olderCosmLicense', + 'jurisdiction': 'az', + } + ) + + # add two more licenses for another license type + self.test_data_generator.put_default_license_record_in_provider_table( + value_overrides={ + 'licenseType': 'esthetician', + 'dateOfIssuance': date(2019, 1, 1), + 'dateOfRenewal': date(2020, 1, 1), + 'licenseNumber': 'olderEstLicense', + 'jurisdiction': 'az', + } + ) + self.test_data_generator.put_default_license_record_in_provider_table( + value_overrides={ + 'licenseType': 'esthetician', + 'dateOfIssuance': date(2024, 1, 1), + 'dateOfRenewal': date(2025, 1, 1), + 'jurisdiction': 'oh', + 'licenseNumber': 'mostRecentEstLicense', + 'dateOfExpiration': date(2026, 1, 1), + } + ) + + from handlers.public_lookup import public_get_provider + + with open('../common/tests/resources/api-event.json') as f: + event = json.load(f) + + # public endpoint does not have authorizer + del event['requestContext']['authorizer'] + event['pathParameters'] = {'compact': 'cosm', 'providerId': '89a6377e-c3a5-40e5-bca5-317ec854c570'} + event['queryStringParameters'] = None + + resp = public_get_provider(event, self.mock_context) + + self.assertEqual(200, resp['statusCode']) + provider_data = json.loads(resp['body']) - self.assertEqual(expected_provider, provider_data) + # the older license should not be included in the response + expected_licenses = [ + { + 'type': 'license', + 'compact': 'cosm', + 'jurisdiction': 'oh', + 'licenseType': 'cosmetologist', + 'licenseStatus': 'active', + 'compactEligibility': 'eligible', + 'dateOfExpiration': '2025-04-04', + 'licenseNumber': 'A0608337260', + }, + { + 'type': 'license', + 'compact': 'cosm', + 'jurisdiction': 'oh', + 'licenseType': 'esthetician', + 'licenseStatus': 'active', + 'compactEligibility': 'eligible', + 'dateOfExpiration': '2026-01-01', + 'licenseNumber': 'mostRecentEstLicense', + }, + ] + self.assertEqual(expected_licenses, provider_data['licenses']) def test_public_get_provider_missing_provider_id(self): from handlers.public_lookup import public_get_provider diff --git a/backend/cosmetology-app/lambdas/python/search/handlers/public_search.py b/backend/cosmetology-app/lambdas/python/search/handlers/public_search.py index 80e173c13..e2f076178 100644 --- a/backend/cosmetology-app/lambdas/python/search/handlers/public_search.py +++ b/backend/cosmetology-app/lambdas/python/search/handlers/public_search.py @@ -3,7 +3,9 @@ from aws_lambda_powertools.utilities.typing import LambdaContext from cc_common.config import config, logger +from cc_common.data_model.schema.common import CompactEligibilityStatus from cc_common.data_model.schema.provider.api import ( + ProviderOpenSearchDocumentSchema, PublicLicenseSearchResponseSchema, PublicQueryProvidersRequestSchema, ) @@ -34,6 +36,64 @@ def public_search_api_handler(event: dict, context: LambdaContext): # noqa: ARG return _public_query_licenses(event, context) +def _unlifted_adverse_action_found(adverse_actions: list[dict]) -> bool: + for aa in adverse_actions: + if not aa.get('effectiveLiftDate'): + return True + return False + + +def _provider_has_unlifted_adverse_actions_associated_with_license( + license_row: dict, license_privileges: list[dict] +) -> bool: + # A home state license is determined to be restricted + # if there is an unlifted encumbrance on the license or + # any of the privileges associated with the license + if _unlifted_adverse_action_found(license_row.get('adverseActions')): + return True + for privilege in license_privileges: + if _unlifted_adverse_action_found(privilege.get('adverseActions')): + return True + return False + + +def _determine_license_eligibility(*, provider_source: dict) -> str: + """ + Derive public licenseEligibility from the full provider OpenSearch document. + + Each indexed document contains exactly one license. Ineligible if that license's compactEligibility is + ineligible, or if any adverse action on that license or on a privilege in the same document lacks + effectiveLiftDate. + """ + schema = ProviderOpenSearchDocumentSchema() + try: + loaded_provider = schema.load(provider_source) + except ValidationError as e: + logger.error( + 'Failed to load provider document for eligibility', + provider_id=provider_source.get('providerId'), + errors=e.messages, + ) + return CompactEligibilityStatus.INELIGIBLE.value + + licenses_list = loaded_provider.get('licenses') or [] + if not licenses_list: + logger.warning( + 'Loaded provider has no licenses for eligibility', + provider_id=loaded_provider.get('providerId'), + ) + return CompactEligibilityStatus.INELIGIBLE.value + + license_row = licenses_list[0] + if license_row.get('compactEligibility') == CompactEligibilityStatus.INELIGIBLE.value: + return CompactEligibilityStatus.INELIGIBLE.value + + if _provider_has_unlifted_adverse_actions_associated_with_license(license_row, loaded_provider['privileges']): + return CompactEligibilityStatus.INELIGIBLE.value + + return CompactEligibilityStatus.ELIGIBLE.value + + def _public_query_licenses(event: dict, context: LambdaContext): # noqa: ARG001 unused-argument path_params = event.get('pathParameters') or {} compact_raw = path_params.get('compact') @@ -65,16 +125,20 @@ def _public_query_licenses(event: dict, context: LambdaContext): # noqa: ARG001 path_compact=compact, ) continue - licenses = source.get('licenses') or [] - if not licenses: - logger.warning('OpenSearch hit has no licenses array', provider_id=provider_id) - continue - license_fields = licenses[0].copy() - license_fields['providerId'] = source['providerId'] - license_fields['compact'] = source['compact'] - license_fields['givenName'] = source['givenName'] - license_fields['familyName'] = source['familyName'] + try: + licenses = source.get('licenses') or [] + if not licenses: + logger.warning('OpenSearch hit has no licenses array', provider_id=provider_id) + continue + + license_fields = licenses[0].copy() + license_fields['providerId'] = source['providerId'] + license_fields['compact'] = source['compact'] + license_fields['givenName'] = source['givenName'] + license_fields['familyName'] = source['familyName'] + license_fields['licenseEligibility'] = _determine_license_eligibility(provider_source=source) + # home state is stored under the 'jurisdiction' field on the license record, but # the frontend expects this to be labeled 'licenseJurisdiction' for parity with other # public search response schemas. @@ -197,7 +261,9 @@ def _build_public_license_search_body(*, compact: str, body: dict, cursor: dict search_after = cursor.get('search_after') if cursor else None - nested_must = [] + # For public search, we only match against licenses that are most recent + # for its license type. This value is set when the document is indexed into OpenSearch. + nested_must: list[dict] = [{'term': {'licenses.mostRecentLicenseForType': True}}] if query_obj.get('licenseNumber'): nested_must.append({'term': {'licenses.licenseNumber': query_obj['licenseNumber']}}) if query_obj.get('jurisdiction'): diff --git a/backend/cosmetology-app/lambdas/python/search/opensearch_client.py b/backend/cosmetology-app/lambdas/python/search/opensearch_client.py index 945f15912..9958d2f40 100644 --- a/backend/cosmetology-app/lambdas/python/search/opensearch_client.py +++ b/backend/cosmetology-app/lambdas/python/search/opensearch_client.py @@ -290,6 +290,11 @@ def _get_provider_index_mapping(self, number_of_shards: int, number_of_replicas: 'adverseActions': {'type': 'nested', 'properties': adverse_action_properties}, 'investigations': {'type': 'nested', 'properties': investigation_properties}, 'investigationStatus': {'type': 'keyword'}, + # This field is not in the original license record, but is added + # by the provider_record_util.generate_opensearch_documents method + # and is used to indicate the most recent license for filtering + # public search results + 'mostRecentLicenseForType': {'type': 'boolean'}, } privilege_properties = { @@ -362,6 +367,7 @@ def _get_provider_index_mapping(self, number_of_shards: int, number_of_replicas: 'providerFamGivMid': {'type': 'keyword'}, 'providerDateOfUpdate': {'type': 'date'}, 'birthMonthDay': {'type': 'keyword'}, + 'adverseActions': {'type': 'nested', 'properties': adverse_action_properties}, 'licenses': {'type': 'nested', 'properties': license_properties}, 'privileges': {'type': 'nested', 'properties': privilege_properties}, } diff --git a/backend/cosmetology-app/lambdas/python/search/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/search/requirements-dev.txt index 8f467d21b..df9a382d1 100644 --- a/backend/cosmetology-app/lambdas/python/search/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/search/requirements-dev.txt @@ -4,59 +4,53 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/search/requirements-dev.in # -boto3==1.42.89 +boto3==1.43.7 # via moto -botocore==1.42.90 +botocore==1.43.7 # via # boto3 # moto # s3transfer -certifi==2026.2.25 +certifi==2026.4.22 # via requests cffi==2.0.0 # via cryptography charset-normalizer==3.4.7 # via requests -cryptography==46.0.7 +cryptography==48.0.0 # via moto docker==7.1.0 # via moto -idna==3.11 +idna==3.15 # via requests -jinja2==3.1.6 - # via moto jmespath==1.1.0 # via # boto3 # botocore markupsafe==3.0.3 - # via - # jinja2 - # werkzeug -moto[dynamodb]==5.1.22 - # via -r search/requirements-dev.in + # via werkzeug +moto[dynamodb]==5.2.1 + # via -r lambdas/python/search/requirements-dev.in py-partiql-parser==0.6.3 # via moto pycparser==3.0 # via cffi python-dateutil==2.9.0.post0 - # via - # botocore - # moto + # via botocore pyyaml==6.0.3 # via responses -requests==2.33.1 +requests==2.34.1 # via # docker # moto # responses responses==0.26.0 # via moto -s3transfer==0.16.0 +s3transfer==0.17.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/cosmetology-app/lambdas/python/search/requirements.txt b/backend/cosmetology-app/lambdas/python/search/requirements.txt index b31b83558..18af4eceb 100644 --- a/backend/cosmetology-app/lambdas/python/search/requirements.txt +++ b/backend/cosmetology-app/lambdas/python/search/requirements.txt @@ -4,7 +4,7 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/search/requirements.in # -certifi==2026.2.25 +certifi==2026.4.22 # via # opensearch-py # requests @@ -14,23 +14,23 @@ events==0.5 # via opensearch-py grpcio==1.80.0 # via opensearch-protobufs -idna==3.11 +idna==3.15 # via requests -opensearch-protobufs==0.19.0 +opensearch-protobufs==1.2.0 # via opensearch-py -opensearch-py==3.1.0 - # via -r search/requirements.in +opensearch-py==3.2.0 + # via -r lambdas/python/search/requirements.in protobuf==7.34.1 # via opensearch-protobufs python-dateutil==2.9.0.post0 # via opensearch-py -requests==2.33.1 +requests==2.34.1 # via opensearch-py six==1.17.0 # via python-dateutil typing-extensions==4.15.0 # via grpcio -urllib3==2.6.3 +urllib3==2.7.0 # via # opensearch-py # requests diff --git a/backend/cosmetology-app/lambdas/python/search/tests/function/test_manage_opensearch_indices.py b/backend/cosmetology-app/lambdas/python/search/tests/function/test_manage_opensearch_indices.py index 0b9593263..694afb900 100644 --- a/backend/cosmetology-app/lambdas/python/search/tests/function/test_manage_opensearch_indices.py +++ b/backend/cosmetology-app/lambdas/python/search/tests/function/test_manage_opensearch_indices.py @@ -143,6 +143,28 @@ def test_on_create_creates_versioned_indices_and_aliases_for_all_compacts_when_n { 'mappings': { 'properties': { + 'adverseActions': { + 'properties': { + 'actionAgainst': {'type': 'keyword'}, + 'adverseActionId': {'type': 'keyword'}, + 'clinicalPrivilegeActionCategories': {'type': 'keyword'}, + 'clinicalPrivilegeActionCategory': {'type': 'keyword'}, + 'compact': {'type': 'keyword'}, + 'creationDate': {'type': 'date'}, + 'dateOfUpdate': {'type': 'date'}, + 'effectiveLiftDate': {'type': 'date'}, + 'effectiveStartDate': {'type': 'date'}, + 'encumbranceType': {'type': 'keyword'}, + 'jurisdiction': {'type': 'keyword'}, + 'licenseType': {'type': 'keyword'}, + 'licenseTypeAbbreviation': {'type': 'keyword'}, + 'liftingUser': {'type': 'keyword'}, + 'providerId': {'type': 'keyword'}, + 'submittingUser': {'type': 'keyword'}, + 'type': {'type': 'keyword'}, + }, + 'type': 'nested', + }, 'birthMonthDay': {'type': 'keyword'}, 'compact': {'type': 'keyword'}, 'compactEligibility': {'type': 'keyword'}, @@ -238,6 +260,7 @@ def test_on_create_creates_versioned_indices_and_aliases_for_all_compacts_when_n 'fields': {'keyword': {'ignore_above': 256, 'type': 'keyword'}}, 'type': 'text', }, + 'mostRecentLicenseForType': {'type': 'boolean'}, 'phoneNumber': {'type': 'keyword'}, 'providerId': {'type': 'keyword'}, 'suffix': {'type': 'keyword'}, diff --git a/backend/cosmetology-app/lambdas/python/search/tests/function/test_populate_provider_documents.py b/backend/cosmetology-app/lambdas/python/search/tests/function/test_populate_provider_documents.py index 3f1a89233..68045a4ad 100644 --- a/backend/cosmetology-app/lambdas/python/search/tests/function/test_populate_provider_documents.py +++ b/backend/cosmetology-app/lambdas/python/search/tests/function/test_populate_provider_documents.py @@ -99,6 +99,7 @@ def _generate_expected_document(self, compact): 'jurisdictionUploadedLicenseStatus': 'active', 'jurisdictionUploadedCompactEligibility': 'eligible', 'birthMonthDay': '06-06', + 'adverseActions': [], 'documentId': f'{provider_id}#oh#{license_type}', 'licenses': [ { @@ -116,6 +117,7 @@ def _generate_expected_document(self, compact): 'licenseNumber': 'A0608337260', 'givenName': f'test{compact}GivenName', 'middleName': 'Gunnar', + 'mostRecentLicenseForType': True, 'familyName': f'test{compact}FamilyName', 'dateOfIssuance': DEFAULT_LICENSE_ISSUANCE_DATE, 'dateOfRenewal': DEFAULT_LICENSE_RENEWAL_DATE, diff --git a/backend/cosmetology-app/lambdas/python/search/tests/function/test_provider_update_ingest.py b/backend/cosmetology-app/lambdas/python/search/tests/function/test_provider_update_ingest.py index 7cb73bc47..4976fbad9 100644 --- a/backend/cosmetology-app/lambdas/python/search/tests/function/test_provider_update_ingest.py +++ b/backend/cosmetology-app/lambdas/python/search/tests/function/test_provider_update_ingest.py @@ -1,4 +1,5 @@ import json +from datetime import date from unittest.mock import MagicMock, patch from common_test.test_constants import ( @@ -141,6 +142,7 @@ def _generate_expected_document(self, compact: str, provider_id: str = None) -> 'jurisdictionUploadedLicenseStatus': 'active', 'jurisdictionUploadedCompactEligibility': 'eligible', 'birthMonthDay': '06-06', + 'adverseActions': [], 'documentId': f'{provider_id}#oh#{license_type}', 'licenses': [ { @@ -158,6 +160,7 @@ def _generate_expected_document(self, compact: str, provider_id: str = None) -> 'licenseNumber': 'A0608337260', 'givenName': f'test{compact}GivenName', 'middleName': 'Gunnar', + 'mostRecentLicenseForType': True, 'familyName': f'test{compact}FamilyName', 'dateOfIssuance': DEFAULT_LICENSE_ISSUANCE_DATE, 'dateOfRenewal': DEFAULT_LICENSE_RENEWAL_DATE, @@ -248,6 +251,81 @@ def test_opensearch_client_called_with_expected_parameters(self, mock_opensearch self.assertEqual({'batchItemFailures': []}, result) + def _put_provider_with_two_cosm_licenses_oh_newer_than_ky(self): + """Provider + OH cosmetologist (default dates) + KY cosmetologist (older issuance/renewal).""" + self.test_data_generator.put_default_provider_record_in_provider_table( + value_overrides={ + 'compact': 'cosm', + 'providerId': MOCK_COSM_PROVIDER_ID, + 'givenName': 'testcosmGivenName', + 'familyName': 'testcosmFamilyName', + }, + date_of_update_override=DEFAULT_PROVIDER_UPDATE_DATETIME, + ) + self.test_data_generator.put_default_license_record_in_provider_table( + value_overrides={ + 'compact': 'cosm', + 'providerId': MOCK_COSM_PROVIDER_ID, + 'givenName': 'testcosmGivenName', + 'familyName': 'testcosmFamilyName', + 'licenseType': TEST_LICENSE_TYPE_MAPPING['cosm'], + 'jurisdiction': 'oh', + }, + date_of_update_override=DEFAULT_LICENSE_UPDATE_DATE_OF_UPDATE, + ) + self.test_data_generator.put_default_license_record_in_provider_table( + value_overrides={ + 'compact': 'cosm', + 'providerId': MOCK_COSM_PROVIDER_ID, + 'givenName': 'testcosmGivenName', + 'familyName': 'testcosmFamilyName', + 'licenseType': TEST_LICENSE_TYPE_MAPPING['cosm'], + 'jurisdiction': 'ky', + 'licenseNumber': 'KY-COSM-001', + 'dateOfIssuance': date(2005, 1, 1), + 'dateOfRenewal': date(2010, 6, 1), + 'dateOfExpiration': date.fromisoformat(DEFAULT_LICENSE_EXPIRATION_DATE), + }, + date_of_update_override=DEFAULT_LICENSE_UPDATE_DATE_OF_UPDATE, + ) + + @patch('handlers.provider_update_ingest.opensearch_client') + def test_home_state_license_is_set_as_most_recent(self, mock_opensearch_client): + """Documents for providers with multiple licenses have the home state license indexed with + mostRecentLicenseForType set to true. All other licenses have mostRecentLicenseForType set to false.""" + from handlers.provider_update_ingest import provider_update_ingest_handler + + self._when_testing_mock_opensearch_client(mock_opensearch_client) + self._put_provider_with_two_cosm_licenses_oh_newer_than_ky() + + event = { + 'Records': [ + { + 'messageId': '12345', + 'body': json.dumps( + self._create_dynamodb_stream_record( + compact='cosm', + provider_id=MOCK_COSM_PROVIDER_ID, + sequence_number='some-sequence-number', + ) + ), + } + ] + } + + mock_context = MagicMock() + result = provider_update_ingest_handler(event, mock_context) + + self.assertEqual({'batchItemFailures': []}, result) + self.assertEqual(1, mock_opensearch_client.bulk_index.call_count) + documents = mock_opensearch_client.bulk_index.call_args.kwargs['documents'] + self.assertEqual(2, len(documents)) + documents_by_id = {doc['documentId']: doc for doc in documents} + oh_id = f'{MOCK_COSM_PROVIDER_ID}#oh#cosmetologist' + ky_id = f'{MOCK_COSM_PROVIDER_ID}#ky#cosmetologist' + self.assertTrue(documents_by_id[oh_id]['licenses'][0]['mostRecentLicenseForType']) + self.assertFalse(documents_by_id[ky_id]['licenses'][0]['mostRecentLicenseForType']) + @patch('handlers.provider_update_ingest.opensearch_client') def test_provider_ids_are_deduped_only_one_document_indexed(self, mock_opensearch_client): """Test that duplicate provider IDs in the batch are deduplicated.""" diff --git a/backend/cosmetology-app/lambdas/python/search/tests/function/test_public_search_providers.py b/backend/cosmetology-app/lambdas/python/search/tests/function/test_public_search_providers.py index 512bb8d5b..88628133e 100644 --- a/backend/cosmetology-app/lambdas/python/search/tests/function/test_public_search_providers.py +++ b/backend/cosmetology-app/lambdas/python/search/tests/function/test_public_search_providers.py @@ -1,10 +1,36 @@ import json +from datetime import date from unittest.mock import patch +from common_test.test_constants import ( + DEFAULT_LICENSE_ISSUANCE_DATE, + DEFAULT_LICENSE_UPDATE_DATETIME, + DEFAULT_PROVIDER_UPDATE_DATETIME, +) from moto import mock_aws from . import TstFunction +# Public search always scopes nested license clauses to the per-type "home" indexed row. +_MOST_RECENT_LICENSE_FOR_TYPE_TERM = {'term': {'licenses.mostRecentLicenseForType': True}} + +_DEFAULT_PUBLIC_SEARCH_SORT_FAMILY_NAME_ASC = [ + {'licenses.familyName.keyword': {'order': 'asc', 'nested': {'path': 'licenses'}}}, + {'licenses.givenName.keyword': {'order': 'asc', 'nested': {'path': 'licenses'}}}, + {'providerId': 'asc'}, + {'_id': 'asc'}, +] + +_DEFAULT_PUBLIC_SEARCH_SORT_FAMILY_NAME_DESC = [ + {'licenses.familyName.keyword': {'order': 'desc', 'nested': {'path': 'licenses'}}}, + {'licenses.givenName.keyword': {'order': 'desc', 'nested': {'path': 'licenses'}}}, + {'providerId': 'desc'}, + {'_id': 'asc'}, +] + +_PUBLIC_SEARCH_SORT_DATE_OF_UPDATE_ASC = [{'dateOfUpdate': 'asc'}, {'_id': 'asc'}] +_PUBLIC_SEARCH_SORT_DATE_OF_UPDATE_DESC = [{'dateOfUpdate': 'desc'}, {'_id': 'asc'}] + @mock_aws class TestPublicSearchProviders(TstFunction): @@ -13,6 +39,58 @@ class TestPublicSearchProviders(TstFunction): def setUp(self): super().setUp() + @staticmethod + def _expected_public_search_request_body( + *, + licenses_nested_must: list, + page_size: int = 10, + sort: list | None = None, + compact: str = 'cosm', + search_after: list | None = None, + ) -> dict: + """Full OpenSearch search body for public license query (must stay aligned with public_search handler).""" + body: dict = { + 'query': { + 'bool': { + 'must': [ + {'term': {'compact': compact}}, + { + 'nested': { + 'path': 'licenses', + 'query': {'bool': {'must': licenses_nested_must}}, + } + }, + ] + } + }, + 'size': page_size, + 'sort': sort or _DEFAULT_PUBLIC_SEARCH_SORT_FAMILY_NAME_ASC, + } + if search_after is not None: + body['search_after'] = search_after + return body + + def _ingest_style_sanitize_opensearch_source(self, source: dict) -> dict: + """ + Mirror production ingest behavior used by provider_update_ingest/populate_provider_documents. + + In prod we build raw docs then do: + ProviderOpenSearchDocumentSchema().load(raw_doc) -> json roundtrip via ResponseEncoder + (see lambdas/python/search/utils.py generate_provider_opensearch_documents). + """ + from cc_common.data_model.schema.provider.api import ProviderOpenSearchDocumentSchema + from cc_common.utils import ResponseEncoder + + # Only sanitize for supported compacts. Some tests intentionally construct + # mismatched compacts to verify handler filtering; those documents would + # never be produced by ingest and will fail schema validation. + if source.get('compact') != 'cosm': + return source + + schema = ProviderOpenSearchDocumentSchema() + sanitized = schema.load(source) + return json.loads(json.dumps(sanitized, cls=ResponseEncoder)) + def _create_public_api_event(self, compact: str, body: dict = None) -> dict: """Create API Gateway event for public query providers (no auth).""" return { @@ -31,6 +109,129 @@ def _create_public_api_event(self, compact: str, body: dict = None) -> dict: 'isBase64Encoded': False, } + def _minimal_opensearch_license( + self, + *, + provider_id: str, + compact: str, + jurisdiction: str, + license_number: str, + license_type: str, + given_name: str, + family_name: str, + date_of_expiration: str, + license_status: str = 'active', + jurisdiction_uploaded_compact_eligibility: str = 'eligible', + adverse_actions: list | None = None, + ) -> dict: + """Nested license object sufficient for ProviderOpenSearchDocumentSchema / LicenseGeneralResponseSchema.""" + return { + 'providerId': provider_id, + 'type': 'license', + 'dateOfUpdate': DEFAULT_LICENSE_UPDATE_DATETIME, + 'compact': compact, + 'jurisdiction': jurisdiction, + 'licenseType': license_type, + 'licenseStatusName': 'OK', + 'licenseStatus': license_status, + 'jurisdictionUploadedLicenseStatus': 'active', + # for simplicity in the test setup, we set this field to whatever was passed + # in for the 'jurisdictionUploadedCompactEligibility' field. It will be recalculated + # to its actual value when run through the '_ingest_style_sanitize_opensearch_source' method + 'compactEligibility': jurisdiction_uploaded_compact_eligibility, + 'jurisdictionUploadedCompactEligibility': jurisdiction_uploaded_compact_eligibility, + 'licenseNumber': license_number, + 'givenName': given_name, + 'familyName': family_name, + 'dateOfIssuance': DEFAULT_LICENSE_ISSUANCE_DATE, + 'dateOfExpiration': date_of_expiration, + 'dateOfBirth': '1985-06-06', + 'homeAddressStreet1': '123 A St.', + 'homeAddressCity': 'Columbus', + 'homeAddressState': 'oh', + 'homeAddressPostalCode': '43004', + 'mostRecentLicenseForType': True, + 'adverseActions': adverse_actions if adverse_actions is not None else [], + 'investigations': [], + } + + def _minimal_opensearch_privilege( + self, + *, + provider_id: str, + compact: str, + license_jurisdiction: str, + license_type: str, + privilege_jurisdiction: str, + date_of_expiration: str, + adverse_actions: list | None = None, + ) -> dict: + """Privilege row sufficient for PrivilegeGeneralResponseSchema / ingest sanitize.""" + return { + 'type': 'privilege', + 'providerId': provider_id, + 'compact': compact, + 'jurisdiction': privilege_jurisdiction, + 'licenseJurisdiction': license_jurisdiction, + 'licenseType': license_type, + 'dateOfExpiration': date_of_expiration, + 'adverseActions': adverse_actions if adverse_actions is not None else [], + 'investigations': [], + 'administratorSetStatus': 'active', + 'status': 'active', + } + + def _generate_unlifted_license_adverse_action(self, *, provider_id: str) -> dict: + return { + 'type': 'adverseAction', + 'compact': 'cosm', + 'providerId': provider_id, + 'jurisdiction': 'oh', + 'licenseTypeAbbreviation': 'cos', + 'licenseType': 'cosmetologist', + 'actionAgainst': 'license', + 'effectiveStartDate': '2024-01-01', + 'creationDate': '2024-01-01T00:00:00+00:00', + 'adverseActionId': 'aa-license-unlifted', + 'dateOfUpdate': '2024-01-02T00:00:00+00:00', + 'encumbranceType': 'suspension', + 'clinicalPrivilegeActionCategories': ['fraud'], + 'submittingUser': {'userId': 'staff-1'}, + } + + def _minimal_opensearch_provider_source( + self, + *, + provider_id: str, + compact: str, + given_name: str, + family_name: str, + license_nested: dict, + provider_adverse_actions: list | None = None, + privileges: list | None = None, + ) -> dict: + """Top-level OpenSearch provider document sufficient for ProviderOpenSearchDocumentSchema.""" + lic_exp = license_nested['dateOfExpiration'] + source = { + 'providerId': provider_id, + 'type': 'provider', + 'dateOfUpdate': DEFAULT_PROVIDER_UPDATE_DATETIME, + 'compact': compact, + 'licenseJurisdiction': license_nested['jurisdiction'], + 'licenseStatus': license_nested['licenseStatus'], + 'compactEligibility': 'eligible', + 'givenName': given_name, + 'familyName': family_name, + 'dateOfExpiration': lic_exp, + 'jurisdictionUploadedLicenseStatus': 'active', + 'jurisdictionUploadedCompactEligibility': 'eligible', + 'birthMonthDay': '06-06', + 'licenses': [license_nested], + 'privileges': privileges if privileges is not None else [], + 'adverseActions': provider_adverse_actions or [], + } + return self._ingest_style_sanitize_opensearch_source(source) + def _create_mock_hit( self, provider_id: str = '00000000-0000-0000-0000-000000000001', @@ -41,25 +242,35 @@ def _create_mock_hit( given_name: str = 'John', sort_values: list = None, license_type: str = 'cosmetologist', + license_nested: dict | None = None, + provider_adverse_actions: list | None = None, + privileges: list | None = None, ) -> dict: """Create a mock OpenSearch hit for one document per license.""" doc_id = f'{provider_id}#{jurisdiction}#{license_type}' + nested = license_nested or self._minimal_opensearch_license( + provider_id=provider_id, + compact=compact, + jurisdiction=jurisdiction, + license_number=license_number, + license_type=license_type, + given_name=given_name, + family_name=family_name, + date_of_expiration='2035-01-01', + ) + source = self._minimal_opensearch_provider_source( + provider_id=provider_id, + compact=compact, + given_name=given_name, + family_name=family_name, + license_nested=nested, + provider_adverse_actions=provider_adverse_actions, + privileges=privileges, + ) hit = { '_index': f'compact_{compact}_providers', '_id': doc_id, - '_source': { - 'providerId': provider_id, - 'compact': compact, - 'givenName': given_name, - 'familyName': family_name, - 'licenses': [ - { - 'jurisdiction': jurisdiction, - 'licenseNumber': license_number, - 'licenseType': license_type, - } - ], - }, + '_source': source, } if sort_values is not None: hit['sort'] = sort_values @@ -79,13 +290,15 @@ def test_license_number_search_builds_nested_query(self, mock_opensearch_client) ) public_search_api_handler(event, self.mock_context) call_body = mock_opensearch_client.search.call_args.kwargs['body'] - self.assertIn('query', call_body) - must = call_body['query']['bool']['must'] - nested = next(m for m in must if 'nested' in m) - self.assertEqual('licenses', nested['nested']['path']) - self.assertNotIn('inner_hits', nested['nested']) - inner_must = nested['nested']['query']['bool']['must'] - self.assertIn({'term': {'licenses.licenseNumber': 'LN999'}}, inner_must) + self.assertEqual( + self._expected_public_search_request_body( + licenses_nested_must=[ + _MOST_RECENT_LICENSE_FOR_TYPE_TERM, + {'term': {'licenses.licenseNumber': 'LN999'}}, + ], + ), + call_body, + ) @patch('handlers.public_search.opensearch_client') def test_jurisdiction_and_name_search_builds_nested_query(self, mock_opensearch_client): @@ -104,12 +317,16 @@ def test_jurisdiction_and_name_search_builds_nested_query(self, mock_opensearch_ ) public_search_api_handler(event, self.mock_context) call_body = mock_opensearch_client.search.call_args.kwargs['body'] - must = call_body['query']['bool']['must'] - nested = next(m for m in must if 'nested' in m) - self.assertNotIn('inner_hits', nested['nested']) - inner_must = nested['nested']['query']['bool']['must'] - self.assertIn({'term': {'licenses.jurisdiction': 'oh'}}, inner_must) - self.assertTrue(any('licenses.familyName' in str(m) for m in inner_must)) + self.assertEqual( + self._expected_public_search_request_body( + licenses_nested_must=[ + _MOST_RECENT_LICENSE_FOR_TYPE_TERM, + {'term': {'licenses.jurisdiction': 'oh'}}, + {'match': {'licenses.familyName': 'Smith'}}, + ], + ), + call_body, + ) @patch('handlers.public_search.opensearch_client') def test_name_only_search_builds_nested_query(self, mock_opensearch_client): @@ -125,11 +342,15 @@ def test_name_only_search_builds_nested_query(self, mock_opensearch_client): ) public_search_api_handler(event, self.mock_context) call_body = mock_opensearch_client.search.call_args.kwargs['body'] - must = call_body['query']['bool']['must'] - nested = next(m for m in must if 'nested' in m) - self.assertNotIn('inner_hits', nested['nested']) - inner_must = nested['nested']['query']['bool']['must'] - self.assertTrue(any('familyName' in str(m) for m in inner_must)) + self.assertEqual( + self._expected_public_search_request_body( + licenses_nested_must=[ + _MOST_RECENT_LICENSE_FOR_TYPE_TERM, + {'match': {'licenses.familyName': 'Jones'}}, + ], + ), + call_body, + ) @patch('handlers.public_search.opensearch_client') def test_sort_includes_id_tiebreaker(self, mock_opensearch_client): @@ -145,6 +366,15 @@ def test_sort_includes_id_tiebreaker(self, mock_opensearch_client): ) public_search_api_handler(event, self.mock_context) call_body = mock_opensearch_client.search.call_args.kwargs['body'] + self.assertEqual( + self._expected_public_search_request_body( + licenses_nested_must=[ + _MOST_RECENT_LICENSE_FOR_TYPE_TERM, + {'match': {'licenses.familyName': 'Doe'}}, + ], + ), + call_body, + ) sort = call_body['sort'] self.assertEqual(4, len(sort)) self.assertEqual({'_id': 'asc'}, sort[3]) @@ -163,12 +393,15 @@ def test_default_sort_is_family_name_ascending(self, mock_opensearch_client): ) response = public_search_api_handler(event, self.mock_context) call_body = mock_opensearch_client.search.call_args.kwargs['body'] - sort = call_body['sort'] - self.assertEqual(4, len(sort)) - self.assertEqual({'licenses.familyName.keyword': {'order': 'asc', 'nested': {'path': 'licenses'}}}, sort[0]) - self.assertEqual({'licenses.givenName.keyword': {'order': 'asc', 'nested': {'path': 'licenses'}}}, sort[1]) - self.assertEqual({'providerId': 'asc'}, sort[2]) - self.assertEqual({'_id': 'asc'}, sort[3]) + self.assertEqual( + self._expected_public_search_request_body( + licenses_nested_must=[ + _MOST_RECENT_LICENSE_FOR_TYPE_TERM, + {'match': {'licenses.familyName': 'Doe'}}, + ], + ), + call_body, + ) body = json.loads(response['body']) self.assertEqual( {'key': 'familyName', 'direction': 'ascending'}, @@ -193,11 +426,16 @@ def test_family_name_sort_descending(self, mock_opensearch_client): ) response = public_search_api_handler(event, self.mock_context) call_body = mock_opensearch_client.search.call_args.kwargs['body'] - sort = call_body['sort'] - self.assertEqual({'licenses.familyName.keyword': {'order': 'desc', 'nested': {'path': 'licenses'}}}, sort[0]) - self.assertEqual({'licenses.givenName.keyword': {'order': 'desc', 'nested': {'path': 'licenses'}}}, sort[1]) - self.assertEqual({'providerId': 'desc'}, sort[2]) - self.assertEqual({'_id': 'asc'}, sort[3]) + self.assertEqual( + self._expected_public_search_request_body( + licenses_nested_must=[ + _MOST_RECENT_LICENSE_FOR_TYPE_TERM, + {'match': {'licenses.familyName': 'Doe'}}, + ], + sort=_DEFAULT_PUBLIC_SEARCH_SORT_FAMILY_NAME_DESC, + ), + call_body, + ) body = json.loads(response['body']) self.assertEqual( {'key': 'familyName', 'direction': 'descending'}, @@ -223,8 +461,14 @@ def test_date_of_update_sort_ascending(self, mock_opensearch_client): response = public_search_api_handler(event, self.mock_context) call_body = mock_opensearch_client.search.call_args.kwargs['body'] self.assertEqual( - [{'dateOfUpdate': 'asc'}, {'_id': 'asc'}], - call_body['sort'], + self._expected_public_search_request_body( + licenses_nested_must=[ + _MOST_RECENT_LICENSE_FOR_TYPE_TERM, + {'term': {'licenses.licenseNumber': 'LN999'}}, + ], + sort=_PUBLIC_SEARCH_SORT_DATE_OF_UPDATE_ASC, + ), + call_body, ) body = json.loads(response['body']) self.assertEqual( @@ -251,8 +495,14 @@ def test_date_of_update_sort_descending(self, mock_opensearch_client): public_search_api_handler(event, self.mock_context) call_body = mock_opensearch_client.search.call_args.kwargs['body'] self.assertEqual( - [{'dateOfUpdate': 'desc'}, {'_id': 'asc'}], - call_body['sort'], + self._expected_public_search_request_body( + licenses_nested_must=[ + _MOST_RECENT_LICENSE_FOR_TYPE_TERM, + {'term': {'licenses.licenseNumber': 'LN999'}}, + ], + sort=_PUBLIC_SEARCH_SORT_DATE_OF_UPDATE_DESC, + ), + call_body, ) @patch('handlers.public_search.opensearch_client') @@ -269,6 +519,16 @@ def test_response_always_contains_sorting_field(self, mock_opensearch_client): ) response = public_search_api_handler(event, self.mock_context) self.assertEqual(200, response['statusCode']) + call_body = mock_opensearch_client.search.call_args.kwargs['body'] + self.assertEqual( + self._expected_public_search_request_body( + licenses_nested_must=[ + _MOST_RECENT_LICENSE_FOR_TYPE_TERM, + {'term': {'licenses.jurisdiction': 'oh'}}, + ], + ), + call_body, + ) body = json.loads(response['body']) self.assertIn('sorting', body) self.assertEqual({'key', 'direction'}, set(body['sorting'].keys())) @@ -322,6 +582,11 @@ def test_no_search_criteria_returns_200(self, mock_opensearch_client): ) response = public_search_api_handler(event, self.mock_context) self.assertEqual(200, response['statusCode']) + call_body = mock_opensearch_client.search.call_args.kwargs['body'] + self.assertEqual( + self._expected_public_search_request_body(licenses_nested_must=[_MOST_RECENT_LICENSE_FOR_TYPE_TERM]), + call_body, + ) body = json.loads(response['body']) self.assertEqual( { @@ -373,10 +638,16 @@ def test_pagination_page_size_maps_to_size_and_search_after_from_last_key(self, ) public_search_api_handler(event, self.mock_context) call_body = mock_opensearch_client.search.call_args.kwargs['body'] - self.assertEqual(25, call_body['size']) self.assertEqual( - ['doe', 'jane', 'uuid-123', 'uuid-123#oh#cosmetologist'], - call_body['search_after'], + self._expected_public_search_request_body( + licenses_nested_must=[ + _MOST_RECENT_LICENSE_FOR_TYPE_TERM, + {'match': {'licenses.familyName': 'Doe'}}, + ], + page_size=25, + search_after=['doe', 'jane', 'uuid-123', 'uuid-123#oh#cosmetologist'], + ), + call_body, ) @patch('handlers.public_search.opensearch_client') @@ -456,11 +727,263 @@ def test_response_contains_only_allowed_license_fields(self, mock_opensearch_cli 'compact', 'licenseType', 'licenseNumber', + 'licenseEligibility', } self.assertEqual(set(provider.keys()), allowed) self.assertEqual(provider['licenseJurisdiction'], 'oh') self.assertEqual(provider['licenseType'], 'cosmetologist') self.assertEqual(provider['licenseNumber'], 'LN123') + self.assertEqual(provider['licenseEligibility'], 'eligible') + + @patch('handlers.public_search.opensearch_client') + @patch('cc_common.config._Config.expiration_resolution_date', date(2030, 1, 1)) + def test_license_eligibility_ineligible_when_license_expired(self, mock_opensearch_client): + """Expired license (inactive after schema correction) yields licenseEligibility ineligible.""" + from handlers.public_search import public_search_api_handler + + pid = '00000000-0000-0000-0000-0000000000aa' + nested = self._minimal_opensearch_license( + provider_id=pid, + compact='cosm', + jurisdiction='oh', + license_number='LN-EXP', + license_type='cosmetologist', + given_name='John', + family_name='Doe', + date_of_expiration='2020-01-01', + license_status='active', + ) + mock_hit = self._create_mock_hit( + provider_id=pid, + license_number='LN-EXP', + license_nested=nested, + ) + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 1, 'relation': 'eq'}, 'hits': [mock_hit]}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'licenseNumber': 'LN-EXP'}, 'pagination': {'pageSize': 10}}, + ) + response = public_search_api_handler(event, self.mock_context) + body = json.loads(response['body']) + self.assertEqual('ineligible', body['providers'][0]['licenseEligibility']) + + @patch('handlers.public_search.opensearch_client') + @patch('cc_common.config._Config.expiration_resolution_date', date(2030, 1, 1)) + def test_license_eligibility_eligible_when_no_unlifted_adverse_action_on_license_or_privileges( + self, mock_opensearch_client + ): + """LicenseEligibility is eligible when there are no unlifted adverse actions on the license or privileges.""" + from handlers.public_search import public_search_api_handler + + pid = '00000000-0000-0000-0000-0000000000bb' + # create a unlifted adverse action for another license + # which should not be considered + unlifted = { + 'type': 'adverseAction', + 'compact': 'cosm', + 'providerId': pid, + 'jurisdiction': 'oh', + 'licenseTypeAbbreviation': 'cos', + 'licenseType': 'esthetician', + 'actionAgainst': 'license', + 'effectiveStartDate': '2024-01-01', + 'creationDate': '2024-01-01T00:00:00+00:00', + 'adverseActionId': 'aa-unlifted', + 'dateOfUpdate': '2024-01-02T00:00:00+00:00', + 'encumbranceType': 'suspension', + 'clinicalPrivilegeActionCategories': ['fraud'], + 'submittingUser': {'userId': 'staff-1'}, + } + mock_hit = self._create_mock_hit( + provider_id=pid, + license_number='LN-AA', + provider_adverse_actions=[unlifted], + ) + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 1, 'relation': 'eq'}, 'hits': [mock_hit]}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'licenseNumber': 'LN-AA'}, 'pagination': {'pageSize': 10}}, + ) + response = public_search_api_handler(event, self.mock_context) + body = json.loads(response['body']) + self.assertEqual(body['providers'][0]['licenseEligibility'], 'eligible') + + @patch('handlers.public_search.opensearch_client') + @patch('cc_common.config._Config.expiration_resolution_date', date(2030, 1, 1)) + def test_license_eligibility_set_to_ineligible_if_adverse_action_on_license(self, mock_opensearch_client): + """Unlifted adverse action on the indexed license row marks licenseEligibility ineligible.""" + from handlers.public_search import public_search_api_handler + + pid = '00000000-0000-0000-0000-0000000000ee' + unlifted = self._generate_unlifted_license_adverse_action(provider_id=pid) + nested = self._minimal_opensearch_license( + provider_id=pid, + compact='cosm', + jurisdiction='oh', + license_number='LN-LIC-AA', + license_type='cosmetologist', + given_name='John', + family_name='Doe', + date_of_expiration='2035-01-01', + adverse_actions=[unlifted], + ) + mock_hit = self._create_mock_hit( + provider_id=pid, + license_number='LN-LIC-AA', + license_nested=nested, + provider_adverse_actions=[], + ) + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 1, 'relation': 'eq'}, 'hits': [mock_hit]}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'licenseNumber': 'LN-LIC-AA'}, 'pagination': {'pageSize': 10}}, + ) + response = public_search_api_handler(event, self.mock_context) + body = json.loads(response['body']) + self.assertEqual('ineligible', body['providers'][0]['licenseEligibility']) + + @patch('handlers.public_search.opensearch_client') + @patch('cc_common.config._Config.expiration_resolution_date', date(2030, 1, 1)) + def test_license_eligibility_set_to_ineligible_if_unlifted_adverse_action_on_privilege_for_license( + self, mock_opensearch_client + ): + """Unlifted adverse action on a privilege bundled with the license doc marks licenseEligibility ineligible.""" + from handlers.public_search import public_search_api_handler + + pid = '00000000-0000-0000-0000-0000000000ff' + unlifted = { + 'type': 'adverseAction', + 'compact': 'cosm', + 'providerId': pid, + 'jurisdiction': 'mi', + 'licenseTypeAbbreviation': 'cos', + 'licenseType': 'cosmetologist', + 'actionAgainst': 'privilege', + 'effectiveStartDate': '2024-01-01', + 'creationDate': '2024-01-01T00:00:00+00:00', + 'adverseActionId': 'aa-priv-unlifted', + 'dateOfUpdate': '2024-01-02T00:00:00+00:00', + 'encumbranceType': 'suspension', + 'clinicalPrivilegeActionCategories': ['fraud'], + 'submittingUser': {'userId': 'staff-1'}, + } + nested = self._minimal_opensearch_license( + provider_id=pid, + compact='cosm', + jurisdiction='oh', + license_number='LN-PRIV-AA', + license_type='cosmetologist', + given_name='John', + family_name='Doe', + date_of_expiration='2035-01-01', + adverse_actions=[], + ) + privilege = self._minimal_opensearch_privilege( + provider_id=pid, + compact='cosm', + license_jurisdiction='oh', + license_type='cosmetologist', + privilege_jurisdiction='mi', + date_of_expiration='2035-01-01', + adverse_actions=[unlifted], + ) + mock_hit = self._create_mock_hit( + provider_id=pid, + license_number='LN-PRIV-AA', + license_nested=nested, + provider_adverse_actions=[], + privileges=[privilege], + ) + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 1, 'relation': 'eq'}, 'hits': [mock_hit]}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'licenseNumber': 'LN-PRIV-AA'}, 'pagination': {'pageSize': 10}}, + ) + response = public_search_api_handler(event, self.mock_context) + body = json.loads(response['body']) + self.assertEqual('ineligible', body['providers'][0]['licenseEligibility']) + + @patch('handlers.public_search.opensearch_client') + @patch('cc_common.config._Config.expiration_resolution_date', date(2030, 1, 1)) + def test_license_eligibility_ineligible_when_jurisdiction_uploaded_ineligible(self, mock_opensearch_client): + """jurisdictionUploadedCompactEligibility ineligible on the matched license yields ineligible.""" + from handlers.public_search import public_search_api_handler + + pid = '00000000-0000-0000-0000-0000000000cc' + nested = self._minimal_opensearch_license( + provider_id=pid, + compact='cosm', + jurisdiction='oh', + license_number='LN-JUR', + license_type='cosmetologist', + given_name='John', + family_name='Doe', + date_of_expiration='2035-01-01', + jurisdiction_uploaded_compact_eligibility='ineligible', + ) + mock_hit = self._create_mock_hit( + provider_id=pid, + license_number='LN-JUR', + license_nested=nested, + ) + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 1, 'relation': 'eq'}, 'hits': [mock_hit]}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'licenseNumber': 'LN-JUR'}, 'pagination': {'pageSize': 10}}, + ) + response = public_search_api_handler(event, self.mock_context) + body = json.loads(response['body']) + self.assertEqual('ineligible', body['providers'][0]['licenseEligibility']) + + @patch('handlers.public_search.opensearch_client') + @patch('cc_common.config._Config.expiration_resolution_date', date(2030, 1, 1)) + def test_license_eligibility_eligible_when_no_blocking_factors(self, mock_opensearch_client): + """Active license, eligible jurisdiction upload, lifted adverse only -> eligible.""" + from handlers.public_search import public_search_api_handler + + pid = '00000000-0000-0000-0000-0000000000dd' + lifted = { + 'type': 'adverseAction', + 'compact': 'cosm', + 'providerId': pid, + 'jurisdiction': 'oh', + 'licenseTypeAbbreviation': 'cos', + 'licenseType': 'cosmetologist', + 'actionAgainst': 'license', + 'effectiveStartDate': '2024-01-01', + 'creationDate': '2024-01-01T00:00:00+00:00', + 'adverseActionId': 'aa-lifted', + 'dateOfUpdate': '2024-06-01T00:00:00+00:00', + 'effectiveLiftDate': '2024-06-01', + 'encumbranceType': 'suspension', + 'clinicalPrivilegeActionCategories': ['fraud'], + 'submittingUser': {'userId': 'staff-1'}, + } + mock_hit = self._create_mock_hit( + provider_id=pid, + license_number='LN-OK', + provider_adverse_actions=[lifted], + ) + mock_opensearch_client.search.return_value = { + 'hits': {'total': {'value': 1, 'relation': 'eq'}, 'hits': [mock_hit]}, + } + event = self._create_public_api_event( + 'cosm', + body={'query': {'licenseNumber': 'LN-OK'}, 'pagination': {'pageSize': 10}}, + ) + response = public_search_api_handler(event, self.mock_context) + body = json.loads(response['body']) + self.assertEqual(body['providers'][0]['licenseEligibility'], 'eligible') @patch('handlers.public_search.opensearch_client') def test_compact_mismatch_filtered_out(self, mock_opensearch_client): diff --git a/backend/cosmetology-app/lambdas/python/staff-user-pre-token/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/staff-user-pre-token/requirements-dev.txt index 9c4dfaf88..8a90cd2f4 100644 --- a/backend/cosmetology-app/lambdas/python/staff-user-pre-token/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/staff-user-pre-token/requirements-dev.txt @@ -4,61 +4,55 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/staff-user-pre-token/requirements-dev.in # -boto3==1.42.89 +boto3==1.43.7 # via moto -botocore==1.42.90 +botocore==1.43.7 # via # boto3 # moto # s3transfer -certifi==2026.2.25 +certifi==2026.4.22 # via requests cffi==2.0.0 # via cryptography charset-normalizer==3.4.7 # via requests -cryptography==46.0.7 +cryptography==48.0.0 # via moto docker==7.1.0 # via moto -idna==3.11 +idna==3.15 # via requests -jinja2==3.1.6 - # via moto jmespath==1.1.0 # via # boto3 # botocore markupsafe==3.0.3 - # via - # jinja2 - # werkzeug -moto[dynamodb,s3]==5.1.22 - # via -r staff-user-pre-token/requirements-dev.in + # via werkzeug +moto[dynamodb,s3]==5.2.1 + # via -r lambdas/python/staff-user-pre-token/requirements-dev.in py-partiql-parser==0.6.3 # via moto pycparser==3.0 # via cffi python-dateutil==2.9.0.post0 - # via - # botocore - # moto + # via botocore pyyaml==6.0.3 # via # moto # responses -requests==2.33.1 +requests==2.34.1 # via # docker # moto # responses responses==0.26.0 # via moto -s3transfer==0.16.0 +s3transfer==0.17.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/cosmetology-app/lambdas/python/staff-user-pre-token/tests/test_user_scopes.py b/backend/cosmetology-app/lambdas/python/staff-user-pre-token/tests/test_user_scopes.py index 655104374..bf2da9a82 100644 --- a/backend/cosmetology-app/lambdas/python/staff-user-pre-token/tests/test_user_scopes.py +++ b/backend/cosmetology-app/lambdas/python/staff-user-pre-token/tests/test_user_scopes.py @@ -52,13 +52,7 @@ def test_board_ed_user(self): user_data = UserData(self._user_sub) self.assertEqual( - { - 'profile', - 'cosm/readGeneral', - 'al/cosm.admin', - 'al/cosm.write', - 'al/cosm.readPrivate' - }, + {'profile', 'cosm/readGeneral', 'al/cosm.admin', 'al/cosm.write', 'al/cosm.readPrivate'}, user_data.scopes, ) diff --git a/backend/cosmetology-app/lambdas/python/staff-user-pre-token/user_data.py b/backend/cosmetology-app/lambdas/python/staff-user-pre-token/user_data.py index 46a3b4b72..fd3a1eff4 100644 --- a/backend/cosmetology-app/lambdas/python/staff-user-pre-token/user_data.py +++ b/backend/cosmetology-app/lambdas/python/staff-user-pre-token/user_data.py @@ -53,7 +53,7 @@ def _process_compact_permissions(self, compact_abbr, compact_permissions): disallowed_actions = compact_actions - { CCPermissionsAction.READ, CCPermissionsAction.ADMIN, - CCPermissionsAction.READ_PRIVATE + CCPermissionsAction.READ_PRIVATE, } if disallowed_actions: raise ValueError(f'User {compact_abbr} permissions include disallowed actions: {disallowed_actions}') @@ -83,7 +83,7 @@ def _process_jurisdiction_permissions(self, compact_abbr, jurisdiction_name, jur disallowed_actions = jurisdiction_actions - { CCPermissionsAction.WRITE, CCPermissionsAction.ADMIN, - CCPermissionsAction.READ_PRIVATE + CCPermissionsAction.READ_PRIVATE, } if disallowed_actions: raise ValueError( diff --git a/backend/cosmetology-app/lambdas/python/staff-users/requirements-dev.txt b/backend/cosmetology-app/lambdas/python/staff-users/requirements-dev.txt index af470f1ea..abc674ddf 100644 --- a/backend/cosmetology-app/lambdas/python/staff-users/requirements-dev.txt +++ b/backend/cosmetology-app/lambdas/python/staff-users/requirements-dev.txt @@ -4,67 +4,61 @@ # # pip-compile --no-emit-index-url --no-strip-extras lambdas/python/staff-users/requirements-dev.in # -boto3==1.42.89 +boto3==1.43.7 # via moto -botocore==1.42.90 +botocore==1.43.7 # via # boto3 # moto # s3transfer -certifi==2026.2.25 +certifi==2026.4.22 # via requests cffi==2.0.0 # via cryptography charset-normalizer==3.4.7 # via requests -cryptography==46.0.7 +cryptography==48.0.0 # via # joserfc # moto docker==7.1.0 # via moto -faker==40.13.0 - # via -r staff-users/requirements-dev.in -idna==3.11 +faker==40.15.0 + # via -r lambdas/python/staff-users/requirements-dev.in +idna==3.15 # via requests -jinja2==3.1.6 - # via moto jmespath==1.1.0 # via # boto3 # botocore -joserfc==1.6.4 +joserfc==1.6.5 # via moto markupsafe==3.0.3 - # via - # jinja2 - # werkzeug -moto[cognitoidp,dynamodb,s3]==5.1.22 - # via -r staff-users/requirements-dev.in + # via werkzeug +moto[cognitoidp,dynamodb,s3]==5.2.1 + # via -r lambdas/python/staff-users/requirements-dev.in py-partiql-parser==0.6.3 # via moto pycparser==3.0 # via cffi python-dateutil==2.9.0.post0 - # via - # botocore - # moto + # via botocore pyyaml==6.0.3 # via # moto # responses -requests==2.33.1 +requests==2.34.1 # via # docker # moto # responses responses==0.26.0 # via moto -s3transfer==0.16.0 +s3transfer==0.17.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # docker diff --git a/backend/cosmetology-app/requirements-dev.txt b/backend/cosmetology-app/requirements-dev.txt index d6e82d687..601d86237 100644 --- a/backend/cosmetology-app/requirements-dev.txt +++ b/backend/cosmetology-app/requirements-dev.txt @@ -6,19 +6,19 @@ # boolean-py==5.0 # via license-expression -build==1.4.3 +build==1.5.0 # via pip-tools cachecontrol[filecache]==0.14.4 # via # cachecontrol # pip-audit -certifi==2026.2.25 +certifi==2026.4.22 # via requests charset-normalizer==3.4.7 # via requests -click==8.3.2 +click==8.3.3 # via pip-tools -coverage[toml]==7.13.5 +coverage[toml]==7.14.0 # via # -r requirements-dev.in # pytest-cov @@ -26,17 +26,17 @@ cyclonedx-python-lib==11.7.0 # via pip-audit defusedxml==0.7.1 # via py-serializable -faker==40.13.0 +faker==40.15.0 # via -r requirements-dev.in -filelock==3.28.0 +filelock==3.29.0 # via cachecontrol -idna==3.11 +idna==3.15 # via requests iniconfig==2.3.0 # via pytest license-expression==30.4.4 # via cyclonedx-python-lib -markdown-it-py==4.0.0 +markdown-it-py==4.2.0 # via rich mdurl==0.1.2 # via markdown-it-py @@ -44,7 +44,7 @@ msgpack==1.1.2 # via cachecontrol packageurl-python==0.17.6 # via cyclonedx-python-lib -packaging==26.1 +packaging==26.2 # via # build # pip-audit @@ -83,13 +83,13 @@ pytest==9.0.3 # pytest-cov pytest-cov==7.1.0 # via -r requirements-dev.in -requests==2.33.1 +requests==2.34.1 # via # cachecontrol # pip-audit rich==15.0.0 # via pip-audit -ruff==0.15.11 +ruff==0.15.13 # via -r requirements-dev.in sortedcontainers==2.4.0 # via cyclonedx-python-lib @@ -97,9 +97,9 @@ tomli==2.4.1 # via pip-audit tomli-w==1.2.0 # via pip-audit -urllib3==2.6.3 +urllib3==2.7.0 # via requests -wheel==0.46.3 +wheel==0.47.0 # via pip-tools # The following packages are considered to be unsafe in a requirements file: diff --git a/backend/cosmetology-app/requirements.txt b/backend/cosmetology-app/requirements.txt index 29b05a129..2b5f638c2 100644 --- a/backend/cosmetology-app/requirements.txt +++ b/backend/cosmetology-app/requirements.txt @@ -12,18 +12,18 @@ aws-cdk-asset-awscli-v1==2.2.273 # via aws-cdk-lib aws-cdk-asset-node-proxy-agent-v6==2.1.1 # via aws-cdk-lib -aws-cdk-aws-lambda-python-alpha==2.250.0a0 +aws-cdk-aws-lambda-python-alpha==2.254.0a0 # via -r requirements.in -aws-cdk-cloud-assembly-schema==53.16.0 +aws-cdk-cloud-assembly-schema==53.23.0 # via aws-cdk-lib -aws-cdk-lib==2.250.0 +aws-cdk-lib==2.254.0 # via # -r requirements.in # aws-cdk-aws-lambda-python-alpha # cdk-nag cattrs==25.3.0 # via jsii -cdk-nag==2.37.55 +cdk-nag==2.38.2 # via -r requirements.in constructs==10.6.0 # via @@ -33,7 +33,7 @@ constructs==10.6.0 # cdk-nag importlib-resources==7.1.0 # via jsii -jsii==1.128.0 +jsii==1.129.0 # via # aws-cdk-asset-awscli-v1 # aws-cdk-asset-node-proxy-agent-v6 diff --git a/backend/cosmetology-app/stacks/api_stack/v1_api/api_model.py b/backend/cosmetology-app/stacks/api_stack/v1_api/api_model.py index c43fe6e32..1f2f3f56c 100644 --- a/backend/cosmetology-app/stacks/api_stack/v1_api/api_model.py +++ b/backend/cosmetology-app/stacks/api_stack/v1_api/api_model.py @@ -328,7 +328,7 @@ def _staff_user_permissions_schema(self): properties={ 'write': JsonSchema(type=JsonSchemaType.BOOLEAN), 'admin': JsonSchema(type=JsonSchemaType.BOOLEAN), - 'readPrivate': JsonSchema(type=JsonSchemaType.BOOLEAN) + 'readPrivate': JsonSchema(type=JsonSchemaType.BOOLEAN), }, ), }, @@ -1497,6 +1497,7 @@ def _public_license_search_response_schema(self): 'compact', 'licenseType', 'licenseNumber', + 'licenseEligibility', ], properties={ 'providerId': JsonSchema(type=JsonSchemaType.STRING, pattern=cc_api.UUID4_FORMAT), @@ -1511,6 +1512,11 @@ def _public_license_search_response_schema(self): description='License type or profession designation for this license row', ), 'licenseNumber': JsonSchema(type=JsonSchemaType.STRING, min_length=1, max_length=100), + 'licenseEligibility': JsonSchema( + type=JsonSchemaType.STRING, + description='Whether the license is eligible for compact participation in public search results', + enum=['eligible', 'ineligible'], + ), }, ) diff --git a/backend/cosmetology-app/stacks/notification_stack.py b/backend/cosmetology-app/stacks/notification_stack.py index 4fd2f6fb7..7a8b7fdab 100644 --- a/backend/cosmetology-app/stacks/notification_stack.py +++ b/backend/cosmetology-app/stacks/notification_stack.py @@ -62,6 +62,9 @@ def __init__( self._add_privilege_investigation_closed_notification_listener( persistent_stack=persistent_stack, data_event_bus=data_event_bus, event_state_stack=event_state_stack ) + self._add_provider_home_state_change_notification_listener( + persistent_stack=persistent_stack, data_event_bus=data_event_bus, event_state_stack=event_state_stack + ) def _add_emailer_event_listener( self, @@ -239,3 +242,17 @@ def _add_privilege_investigation_closed_notification_listener( data_event_bus=data_event_bus, event_state_stack=event_state_stack, ) + + def _add_provider_home_state_change_notification_listener( + self, persistent_stack: ps.PersistentStack, data_event_bus: EventBus, event_state_stack: ess.EventStateStack + ): + """Add the provider home state change listener lambda, queues, and event rules.""" + self._add_emailer_event_listener( + construct_id_prefix='ProviderHomeJurisdictionChangeNotificationListener', + index='home_state_change_events.py', + handler='home_state_change_notification_listener', + listener_detail_type='provider.homeStateChange', + persistent_stack=persistent_stack, + data_event_bus=data_event_bus, + event_state_stack=event_state_stack, + ) diff --git a/backend/cosmetology-app/stacks/persistent_stack/bulk_uploads_bucket.py b/backend/cosmetology-app/stacks/persistent_stack/bulk_uploads_bucket.py index 5f39f145e..eb5e3ba12 100644 --- a/backend/cosmetology-app/stacks/persistent_stack/bulk_uploads_bucket.py +++ b/backend/cosmetology-app/stacks/persistent_stack/bulk_uploads_bucket.py @@ -141,21 +141,9 @@ def _add_v1_ingest_object_events( }, ], ) - NagSuppressions.add_resource_suppressions_by_path( - stack, - path=f'{stack.node.path}/BucketNotificationsHandler050a0587b7544547bf325f094a3db834/' - 'Role/DefaultPolicy/Resource', - suppressions=[ - { - 'id': 'AwsSolutions-IAM5', - 'appliesTo': ['Resource::*'], - 'reason': """ - The lambda policy is scoped specifically to the PutBucketNotification action, which - suits its purpose. - """, - }, - ], - ) + # Per-bucket notification permissions are attached as inline HandlerPolicy on the bucket's + # `Notifications` construct as of CDK v2.252.0 (not Role/DefaultPolicy on the stack singleton) so we only + # need to suppress the handler role. See https://github.com/aws/aws-cdk/issues/37667. NagSuppressions.add_resource_suppressions_by_path( stack, path=f'{stack.node.path}/BucketNotificationsHandler050a0587b7544547bf325f094a3db834/Role/Resource', diff --git a/backend/cosmetology-app/stacks/state_auth/state_auth_users.py b/backend/cosmetology-app/stacks/state_auth/state_auth_users.py index 95acc98c6..116d04f25 100644 --- a/backend/cosmetology-app/stacks/state_auth/state_auth_users.py +++ b/backend/cosmetology-app/stacks/state_auth/state_auth_users.py @@ -66,6 +66,11 @@ def __init__( { 'id': 'AwsSolutions-COG3', 'reason': 'Threat protection mode enforcement offers no benefit when there are no users.', - } + }, + { + 'id': 'AwsSolutions-COG8', + 'reason': 'This pool is for state API machine-to-machine auth only; ' + 'Cognito Plus features are not relevant for a user pool with no users.', + }, ], ) diff --git a/backend/cosmetology-app/tests/app/test_notification_stack.py b/backend/cosmetology-app/tests/app/test_notification_stack.py index 9e2a48bd0..305262baa 100644 --- a/backend/cosmetology-app/tests/app/test_notification_stack.py +++ b/backend/cosmetology-app/tests/app/test_notification_stack.py @@ -795,3 +795,112 @@ def test_privilege_investigation_closed_notification_resources_created(self): }, privilege_investigation_closed_rule, ) + + def test_provider_home_jurisdiction_change_notification_listener_resources_created(self): + """ + Test that the provider home jurisdiction change notification listener lambda is added with a SQS queue + and an event bridge event rule that listens for 'provider.homeStateChange' detail types. + """ + notification_stack = self.app.sandbox_backend_stage.notification_stack + notification_template = Template.from_stack(notification_stack) + + # Verify the lambda function is created + provider_home_jurisdiction_change_handler_logical_id = notification_stack.get_logical_id( + notification_stack.event_processors[ + 'ProviderHomeJurisdictionChangeNotificationListener' + ].queue_processor.process_function.node.default_child + ) + provider_home_jurisdiction_change_handler = TestNotificationStack.get_resource_properties_by_logical_id( + provider_home_jurisdiction_change_handler_logical_id, + resources=notification_template.find_resources(CfnFunction.CFN_RESOURCE_TYPE_NAME), + ) + + self.assertEqual( + 'handlers.home_state_change_events.home_state_change_notification_listener', + provider_home_jurisdiction_change_handler['Handler'], + ) + + # Verify SQS queue is created + listener_queue_logical_id = notification_stack.get_logical_id( + notification_stack.event_processors[ + 'ProviderHomeJurisdictionChangeNotificationListener' + ].queue_processor.queue.node.default_child + ) + listener_queue = TestNotificationStack.get_resource_properties_by_logical_id( + listener_queue_logical_id, + resources=notification_template.find_resources(CfnQueue.CFN_RESOURCE_TYPE_NAME), + ) + + dlq_logical_id = notification_stack.get_logical_id( + notification_stack.event_processors[ + 'ProviderHomeJurisdictionChangeNotificationListener' + ].queue_processor.dlq.node.default_child + ) + + # remove dynamic field + del listener_queue['KmsMasterKeyId'] + + self.assertEqual( + { + 'MessageRetentionPeriod': 43200, + 'RedrivePolicy': {'deadLetterTargetArn': {'Fn::GetAtt': [dlq_logical_id, 'Arn']}, 'maxReceiveCount': 3}, + 'VisibilityTimeout': 300, + }, + listener_queue, + ) + + # Verify EventBridge rule is created with correct detail type + event_bridge_rule = TestNotificationStack.get_resource_properties_by_logical_id( + notification_stack.get_logical_id( + notification_stack.event_processors[ + 'ProviderHomeJurisdictionChangeNotificationListener' + ].event_rule.node.default_child + ), + resources=notification_template.find_resources(CfnRule.CFN_RESOURCE_TYPE_NAME), + ) + + self.assertEqual( + { + 'EventBusName': { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '/', + {'Fn::Select': [5, {'Fn::Split': [':', {'Ref': 'DataEventBusArnParameterParameter'}]}]}, + ] + }, + ] + }, + 'EventPattern': {'detail-type': ['provider.homeStateChange']}, + 'State': 'ENABLED', + 'Targets': [ + { + 'Arn': {'Fn::GetAtt': [listener_queue_logical_id, 'Arn']}, + 'DeadLetterConfig': {'Arn': {'Fn::GetAtt': [dlq_logical_id, 'Arn']}}, + 'Id': 'Target0', + } + ], + }, + event_bridge_rule, + ) + + # Verify event source mapping is created + event_source_mapping = TestNotificationStack.get_resource_properties_by_logical_id( + notification_stack.get_logical_id( + notification_stack.event_processors[ + 'ProviderHomeJurisdictionChangeNotificationListener' + ].queue_processor.event_source_mapping.node.default_child + ), + resources=notification_template.find_resources(CfnEventSourceMapping.CFN_RESOURCE_TYPE_NAME), + ) + self.assertEqual( + { + 'BatchSize': 10, + 'EventSourceArn': {'Fn::GetAtt': [listener_queue_logical_id, 'Arn']}, + 'FunctionName': {'Ref': provider_home_jurisdiction_change_handler_logical_id}, + 'FunctionResponseTypes': ['ReportBatchItemFailures'], + 'MaximumBatchingWindowInSeconds': 15, + }, + event_source_mapping, + ) diff --git a/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_RESPONSE_SCHEMA.json b/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_RESPONSE_SCHEMA.json index 4be0803c4..b1d0d96d2 100644 --- a/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_RESPONSE_SCHEMA.json +++ b/backend/cosmetology-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_RESPONSE_SCHEMA.json @@ -46,6 +46,14 @@ "maxLength": 100, "minLength": 1, "type": "string" + }, + "licenseEligibility": { + "description": "Whether the license is eligible for compact participation in public search results", + "enum": [ + "eligible", + "ineligible" + ], + "type": "string" } }, "required": [ @@ -55,7 +63,8 @@ "licenseJurisdiction", "compact", "licenseType", - "licenseNumber" + "licenseNumber", + "licenseEligibility" ], "type": "object" }, diff --git a/backend/cosmetology-app/tests/smoke/license_upload_smoke_tests.py b/backend/cosmetology-app/tests/smoke/license_upload_smoke_tests.py index 41f6fe1e8..a71d82288 100644 --- a/backend/cosmetology-app/tests/smoke/license_upload_smoke_tests.py +++ b/backend/cosmetology-app/tests/smoke/license_upload_smoke_tests.py @@ -4,37 +4,47 @@ from datetime import UTC, datetime, timedelta import requests +from boto3.dynamodb.conditions import Key +from compact_configuration_smoke_tests import test_jurisdiction_configuration from config import config, logger from smoke_common import ( SmokeTestFailureException, + call_provider_details_endpoint, create_test_app_client, create_test_staff_user, delete_test_app_client, delete_test_staff_user, - get_api_base_url, get_client_auth_headers, get_data_events_dynamodb_table, get_provider_user_dynamodb_table, get_staff_user_auth_headers, load_smoke_test_env, + wait_for_provider_creation, ) -MOCK_SSN = '999-99-9999' COMPACT = 'cosm' -JURISDICTION = 'az' -TEST_PROVIDER_GIVEN_NAME = 'Joe' -TEST_PROVIDER_FAMILY_NAME = 'Dokes' # This script can be run locally to test the license upload/ingest flow against a sandbox environment. # License POST uses the state API (CC_TEST_STATE_API_BASE_URL) with a short-lived Cognito app client # (CC_TEST_STATE_AUTH_URL, CC_TEST_COGNITO_STATE_AUTH_USER_POOL_ID); provider query/GET use the internal API # (CC_TEST_API_BASE_URL) with a staff user. Configure smoke_tests_env.json from smoke_tests_env_example.json. +# Developer note: this smoke test intentionally polls up to 12 minutes (60s interval) because the +# preprocess and ingest SQS event source mappings currently use 5-minute max batching windows. +# If faster runtime is needed, manually lower those event source mapping batching windows in the +# target environment before running this test. + # Note that by design, developers do not have the ability to delete records from the SSN DynamoDB table, # so this script does not delete the created SSN records as part of cleanup. TEST_STAFF_USER_EMAIL = 'testStaffUserLicenseUploader@smokeTestFakeEmail.com' TEST_APP_CLIENT_NAME = 'test-license-upload-smoke-client' +HOME_STATE_CHANGE_MOCK_SSN = '999-88-8888' +HOME_STATE_CHANGE_PROVIDER_GIVEN_NAME = 'Jane' +HOME_STATE_CHANGE_PROVIDER_FAMILY_NAME = 'TestSmith' +HOME_STATE_CHANGE_LICENSE_TYPE = 'cosmetologist' +HOME_STATE_CHANGE_FORMER_JURISDICTION = 'az' +HOME_STATE_CHANGE_NEW_JURISDICTION = 'oh' def _cleanup_test_generated_records(provider_id: str, license_ingest_record_response: dict): @@ -60,150 +70,255 @@ def _cleanup_test_generated_records(provider_id: str, license_ingest_record_resp logger.info('Successfully deleted license ingest record from data events table') -def upload_licenses_record(license_upload_auth_headers: dict): - """ - Verifies that a license record can be uploaded to the Compact Connect API and the appropriate - records are created in the provider table as well as the data events table. - - Step 1: Upload a license via the state API (POST .../licenses) using state app client credentials. - Step 2: Verify the provider records are added by querying the internal staff API. - Step 3: Verify the license record is recorded in the data events table. - """ - staff_headers = get_staff_user_auth_headers(TEST_STAFF_USER_EMAIL) - - # Step 1: State-authenticated license upload (see stacks/state_api_stack). - post_body = [ +def _build_home_state_change_license_post_body(jurisdiction: str, date_of_issuance: str): + return [ { - 'licenseNumber': 'A0608337260', + 'licenseNumber': f'{jurisdiction.upper()}-HOME-STATE-TEST', 'homeAddressPostalCode': '68001', - 'givenName': TEST_PROVIDER_GIVEN_NAME, - 'familyName': TEST_PROVIDER_FAMILY_NAME, - 'homeAddressStreet1': '123 Fake Street', + 'givenName': HOME_STATE_CHANGE_PROVIDER_GIVEN_NAME, + 'familyName': HOME_STATE_CHANGE_PROVIDER_FAMILY_NAME, + 'homeAddressStreet1': '123 Home State Test Street', 'dateOfBirth': '1991-12-10', - 'dateOfIssuance': '2024-12-10', - 'ssn': MOCK_SSN, - 'licenseType': 'cosmetologist', + 'dateOfIssuance': date_of_issuance, + 'ssn': HOME_STATE_CHANGE_MOCK_SSN, + 'licenseType': HOME_STATE_CHANGE_LICENSE_TYPE, 'dateOfExpiration': '2050-12-10', - 'homeAddressState': 'AZ', + 'homeAddressState': jurisdiction.upper(), 'homeAddressCity': 'Omaha', 'compactEligibility': 'eligible', 'licenseStatus': 'active', } ] + +def _post_license_to_state_api(client_id: str, client_secret: str, jurisdiction: str, post_body: list[dict]): + # Access tokens are short lived, so regenerate before each upload call. + license_upload_auth_headers = get_client_auth_headers(client_id, client_secret, COMPACT, jurisdiction) post_response = requests.post( - url=f'{config.state_api_base_url}/v1/compacts/{COMPACT}/jurisdictions/{JURISDICTION}/licenses', + url=f'{config.state_api_base_url}/v1/compacts/{COMPACT}/jurisdictions/{jurisdiction}/licenses', headers=license_upload_auth_headers, json=post_body, timeout=60, ) if post_response.status_code != 200: - raise SmokeTestFailureException(f'Failed to POST license record. Response: {post_response.json()}') - - logger.info(f'License record successfully uploaded {post_response.json()}') - - # Step 2: Verify the provider records are added by querying the API - provider_id = None - - # The preprocessing and ingest SQS queues have a visibility timeout of 5 minutes each - # so we will need to poll until the record is available - for _ in range(30): - # Query the provider API to find the provider by name - query_body = {'query': {'familyName': TEST_PROVIDER_FAMILY_NAME, 'givenName': TEST_PROVIDER_GIVEN_NAME}} - - query_response = requests.post( - url=get_api_base_url() + f'/v1/compacts/{COMPACT}/providers/query', - headers=staff_headers, - json=query_body, - timeout=10, + raise SmokeTestFailureException( + f'Failed to POST home state change license record for {jurisdiction}. Response: {post_response.json()}' ) - if query_response.status_code != 200: - logger.info(f'Query failed with status {query_response.status_code}. Retrying...') - time.sleep(30) - continue - - providers = query_response.json().get('providers', []) - if providers: - # Find our test provider in the results - for provider in providers: - if ( - provider.get('givenName') == TEST_PROVIDER_GIVEN_NAME - and provider.get('familyName') == TEST_PROVIDER_FAMILY_NAME - ): - provider_id = provider.get('providerId') - break - - if provider_id: - break + logger.info(f'Home state change license record successfully uploaded for {jurisdiction}: {post_response.json()}') - logger.info('Provider record not found via API query. Retrying...') - time.sleep(30) - if not provider_id: - raise SmokeTestFailureException('Failed to find provider record via API query.') - - logger.info(f'Provider record successfully found via API query. Provider ID: {provider_id}') - - # Now get the provider details to verify the license record - provider_details_response = requests.get( - url=get_api_base_url() + f'/v1/compacts/{COMPACT}/providers/{provider_id}', - headers=staff_headers, - timeout=10, - ) - - if provider_details_response.status_code != 200: - raise SmokeTestFailureException(f'Failed to get provider details. Response: {provider_details_response.json()}') - - provider_details = provider_details_response.json() - licenses = provider_details.get('licenses', []) - - if not licenses: - raise SmokeTestFailureException('Failed to find license record in provider details.') +def _wait_for_home_state_change_event(provider_id: str, max_wait_seconds: int = 720, poll_interval_seconds: int = 60): + data_events_table = get_data_events_dynamodb_table() + max_attempts = max_wait_seconds // poll_interval_seconds + event_pk = f'COMPACT#{COMPACT}#JURISDICTION#{HOME_STATE_CHANGE_NEW_JURISDICTION}' + + for attempt in range(1, max_attempts + 1): + response = data_events_table.query( + KeyConditionExpression=Key('pk').eq(event_pk) + & Key('sk').begins_with('TYPE#provider.homeStateChange#TIME#'), + FilterExpression='providerId = :provider_id', + ExpressionAttributeValues={':provider_id': provider_id}, + ConsistentRead=True, + ) + matching_event = next(iter(response.get('Items', [])), None) + if matching_event: + logger.info(f'Found provider.homeStateChange data event for provider {provider_id}') + return matching_event - license_record = next( - (license_record for license_record in licenses if license_record.get('licenseType') == 'cosmetologist'), None - ) + if attempt < max_attempts: + logger.info( + f'provider.homeStateChange event not found yet for provider {provider_id}. ' + f'Attempt {attempt}/{max_attempts}. Retrying in {poll_interval_seconds} seconds.' + ) + time.sleep(poll_interval_seconds) - if not license_record: - raise SmokeTestFailureException('Failed to find cosmetologist license record in provider details.') + return None - logger.info(f'License record successfully found in provider details: {license_record}') - # Step 3: Verify the license record is recorded in the data events table. - # we don't loop here because the record should be available in the data events table by the time the - # provider table record is available. We use a consistent read to ensure that we get the latest record. +def _query_license_ingest_events_for_jurisdiction( + jurisdiction: str, provider_id: str, start_time: datetime, end_time: datetime +): data_events_table = get_data_events_dynamodb_table() - event_time = datetime.now(tz=UTC) - start_time = event_time - timedelta(minutes=15) - logger.info('searching for license in data event') - license_ingest_record_response = data_events_table.query( + return data_events_table.query( KeyConditionExpression='pk = :pk AND sk BETWEEN :start_time AND :end_time', + FilterExpression='providerId = :provider_id', ExpressionAttributeValues={ - ':pk': f'COMPACT#{COMPACT}#JURISDICTION#{JURISDICTION}', + ':pk': f'COMPACT#{COMPACT}#JURISDICTION#{jurisdiction}', ':start_time': f'TYPE#license.ingest#TIME#{int(start_time.timestamp())}', - ':end_time': f'TYPE#license.ingest#TIME#{int(event_time.timestamp())}', + ':end_time': f'TYPE#license.ingest#TIME#{int(end_time.timestamp())}', + ':provider_id': provider_id, }, ConsistentRead=True, ) - if not license_ingest_record_response.get('Items'): - logger.error( - f'Failed to find license ingest record in data events table. Response: {license_ingest_record_response}' + +def test_home_state_change_notification(staff_headers: dict, client_id: str, client_secret: str): + start_time = datetime.now(tz=UTC) - timedelta(minutes=2) + provider_id = None + try: + _post_license_to_state_api( + client_id=client_id, + client_secret=client_secret, + jurisdiction=HOME_STATE_CHANGE_FORMER_JURISDICTION, + post_body=_build_home_state_change_license_post_body( + jurisdiction=HOME_STATE_CHANGE_FORMER_JURISDICTION, date_of_issuance='2024-01-15' + ), + ) + + provider_id = wait_for_provider_creation( + staff_headers=staff_headers, + compact=COMPACT, + given_name=HOME_STATE_CHANGE_PROVIDER_GIVEN_NAME, + family_name=HOME_STATE_CHANGE_PROVIDER_FAMILY_NAME, + max_wait_time=750, + staff_user_email=TEST_STAFF_USER_EMAIL, + poll_interval_seconds=60, + ) + logger.info(f'Found home state change test provider id {provider_id}') + + refreshed_staff_headers = get_staff_user_auth_headers(TEST_STAFF_USER_EMAIL) + az_provider_details = call_provider_details_endpoint( + headers=refreshed_staff_headers, compact=COMPACT, provider_id=provider_id + ) + az_cosmetology_licenses = [ + license_record + for license_record in az_provider_details.get('licenses', []) + if license_record.get('licenseType') == HOME_STATE_CHANGE_LICENSE_TYPE + ] + + if len(az_cosmetology_licenses) != 1: + raise SmokeTestFailureException( + f'Expected one {HOME_STATE_CHANGE_LICENSE_TYPE} license after AZ upload, ' + f'found {len(az_cosmetology_licenses)}' + ) + + if az_cosmetology_licenses[0].get('jurisdiction') != HOME_STATE_CHANGE_FORMER_JURISDICTION: + raise SmokeTestFailureException( + 'Expected first home state license jurisdiction to be ' + f'{HOME_STATE_CHANGE_FORMER_JURISDICTION}, found {az_cosmetology_licenses[0].get("jurisdiction")}' + ) + + if az_provider_details.get('licenseJurisdiction') != HOME_STATE_CHANGE_FORMER_JURISDICTION: + raise SmokeTestFailureException( + 'Expected licenseJurisdiction to be ' + f'{HOME_STATE_CHANGE_FORMER_JURISDICTION} after first upload, ' + f'found {az_provider_details.get("licenseJurisdiction")}' + ) + + _post_license_to_state_api( + client_id=client_id, + client_secret=client_secret, + jurisdiction=HOME_STATE_CHANGE_NEW_JURISDICTION, + post_body=_build_home_state_change_license_post_body( + # upload license that was issued at a later date to trigger home state change + jurisdiction=HOME_STATE_CHANGE_NEW_JURISDICTION, + date_of_issuance='2025-06-15', + ), + ) + + home_state_change_event = _wait_for_home_state_change_event( + provider_id=provider_id, max_wait_seconds=750, poll_interval_seconds=60 + ) + if not home_state_change_event: + raise SmokeTestFailureException( + 'Failed to find provider.homeStateChange data event for the home state change smoke test.' + ) + + refreshed_staff_headers = get_staff_user_auth_headers(TEST_STAFF_USER_EMAIL) + updated_provider_details = call_provider_details_endpoint( + headers=refreshed_staff_headers, compact=COMPACT, provider_id=provider_id + ) + updated_cosmetology_licenses = [ + license_record + for license_record in updated_provider_details.get('licenses', []) + if license_record.get('licenseType') == HOME_STATE_CHANGE_LICENSE_TYPE + ] + updated_jurisdictions = {license_record.get('jurisdiction') for license_record in updated_cosmetology_licenses} + if updated_jurisdictions != {HOME_STATE_CHANGE_FORMER_JURISDICTION, HOME_STATE_CHANGE_NEW_JURISDICTION}: + raise SmokeTestFailureException( + f'Expected cosmetology licenses for both {HOME_STATE_CHANGE_FORMER_JURISDICTION} and ' + f'{HOME_STATE_CHANGE_NEW_JURISDICTION}, found {sorted(updated_jurisdictions)}' + ) + + if updated_provider_details.get('licenseJurisdiction') != HOME_STATE_CHANGE_NEW_JURISDICTION: + raise SmokeTestFailureException( + 'Expected licenseJurisdiction to change to ' + f'{HOME_STATE_CHANGE_NEW_JURISDICTION}, found {updated_provider_details.get("licenseJurisdiction")}' + ) + + logger.info( + 'MANUAL VERIFICATION REQUIRED: check inbox for ' + f'{config.smoke_test_notification_email}. Verify a provider home state change email was sent to ' + f'the former home jurisdiction {HOME_STATE_CHANGE_FORMER_JURISDICTION.upper()} after upload from ' + f'{HOME_STATE_CHANGE_NEW_JURISDICTION.upper()} for provider ' + f'{HOME_STATE_CHANGE_PROVIDER_GIVEN_NAME} {HOME_STATE_CHANGE_PROVIDER_FAMILY_NAME} ({provider_id}).' ) - _cleanup_test_generated_records(provider_id, license_ingest_record_response) - raise SmokeTestFailureException('Failed to find license ingest records in data event table.') + finally: + if provider_id: + logger.info('cleaning up test provider records', provider_id=provider_id) + end_time = datetime.now(tz=UTC) + az_license_ingest_events = _query_license_ingest_events_for_jurisdiction( + jurisdiction=HOME_STATE_CHANGE_FORMER_JURISDICTION, + provider_id=provider_id, + start_time=start_time, + end_time=end_time, + ) + oh_license_ingest_events = _query_license_ingest_events_for_jurisdiction( + jurisdiction=HOME_STATE_CHANGE_NEW_JURISDICTION, + provider_id=provider_id, + start_time=start_time, + end_time=end_time, + ) + home_state_change_events = _query_home_state_change_events_for_provider(provider_id) + _cleanup_home_state_change_generated_records( + provider_id=provider_id, + az_license_ingest_events=az_license_ingest_events, + oh_license_ingest_events=oh_license_ingest_events, + home_state_change_events=home_state_change_events, + ) + else: + logger.info('Skipping provider cleanup because provider id was never discovered.') + + +def _cleanup_home_state_change_generated_records( + provider_id: str, + az_license_ingest_events: dict, + oh_license_ingest_events: dict, + home_state_change_events: list[dict] | None = None, +): + merged_items = [ + *az_license_ingest_events.get('Items', []), + *oh_license_ingest_events.get('Items', []), + ] + _cleanup_test_generated_records(provider_id, {'Items': merged_items}) - logger.info( - f'License ingest data event successfully added to data events table {license_ingest_record_response["Items"]}' + if home_state_change_events: + data_events_table = get_data_events_dynamodb_table() + for home_state_change_event in home_state_change_events: + data_events_table.delete_item( + Key={'pk': home_state_change_event['pk'], 'sk': home_state_change_event['sk']} + ) + logger.info('Successfully deleted provider.homeStateChange event(s) from data events table') + + +def _query_home_state_change_events_for_provider(provider_id: str): + data_events_table = get_data_events_dynamodb_table() + event_pk = f'COMPACT#{COMPACT}#JURISDICTION#{HOME_STATE_CHANGE_NEW_JURISDICTION}' + response = data_events_table.query( + KeyConditionExpression=Key('pk').eq(event_pk) & Key('sk').begins_with('TYPE#provider.homeStateChange#TIME#'), + ConsistentRead=True, ) - _cleanup_test_generated_records(provider_id, license_ingest_record_response) + return [item for item in response.get('Items', []) if item.get('providerId') == provider_id] if __name__ == '__main__': load_smoke_test_env() + test_jurisdiction_configuration(HOME_STATE_CHANGE_FORMER_JURISDICTION, recreate_compact_config=True) + test_jurisdiction_configuration(HOME_STATE_CHANGE_NEW_JURISDICTION) + test_user_sub = None client_id = None try: @@ -211,15 +326,30 @@ def upload_licenses_record(license_upload_auth_headers: dict): test_user_sub = create_test_staff_user( email=TEST_STAFF_USER_EMAIL, compact=COMPACT, - jurisdiction=JURISDICTION, - permissions={'actions': {'admin'}, 'jurisdictions': {JURISDICTION: {'write', 'admin'}}}, + jurisdiction=HOME_STATE_CHANGE_FORMER_JURISDICTION, + permissions={ + 'actions': {'admin'}, + 'jurisdictions': { + HOME_STATE_CHANGE_FORMER_JURISDICTION: {'write', 'admin'}, + HOME_STATE_CHANGE_NEW_JURISDICTION: {'write', 'admin'}, + }, + }, + ) + + client_credentials = create_test_app_client( + TEST_APP_CLIENT_NAME, + COMPACT, + jurisdictions=[HOME_STATE_CHANGE_FORMER_JURISDICTION, HOME_STATE_CHANGE_NEW_JURISDICTION], ) - client_credentials = create_test_app_client(TEST_APP_CLIENT_NAME, COMPACT, JURISDICTION) client_id = client_credentials['client_id'] client_secret = client_credentials['client_secret'] - license_upload_headers = get_client_auth_headers(client_id, client_secret, COMPACT, JURISDICTION) - upload_licenses_record(license_upload_headers) - logger.info('License record upload smoke test passed') + home_state_change_staff_headers = get_staff_user_auth_headers(TEST_STAFF_USER_EMAIL) + test_home_state_change_notification( + staff_headers=home_state_change_staff_headers, + client_id=client_id, + client_secret=client_secret, + ) + logger.info('Home state change notification smoke test passed') except SmokeTestFailureException as e: logger.error(f'License record upload smoke test failed: {str(e)}') finally: diff --git a/backend/cosmetology-app/tests/smoke/public_search_smoke_tests.py b/backend/cosmetology-app/tests/smoke/public_search_smoke_tests.py new file mode 100644 index 000000000..a98b0dd9a --- /dev/null +++ b/backend/cosmetology-app/tests/smoke/public_search_smoke_tests.py @@ -0,0 +1,276 @@ +# ruff: noqa: T201 we use print statements for smoke testing +#!/usr/bin/env python3 +""" +Smoke tests for public license search (unauthenticated). + +POST /v1/public/compacts/{compact}/providers/query and GET /v1/public/compacts/{compact}/providers/{providerId}. +Uses CC_TEST_PROVIDER_ID and mutates the smoke license in DynamoDB; restores state in finally blocks. + +This test assumes the test provider has no existing license in TEST_JURISDICTION. If this is not the case, +you can change the TEST_JURISDICTION variable to a jurisdiction where the test provider does not have a license. + +Run from repo root with cosmetology-app cwd, or set paths like other smoke scripts: + + cd backend/cosmetology-app && python tests/smoke/public_search_smoke_tests.py +""" + +from __future__ import annotations + +import copy + +from config import config, logger +from smoke_common import ( + SmokeTestFailureException, + call_public_get_provider, + call_public_query_providers, + get_all_provider_database_records, + get_license_type_abbreviation, + get_most_recently_issued_or_renewed_license, + get_provider_user_dynamodb_table, + load_smoke_test_env, + wait_for_opensearch_sync, +) + +COMPACT = 'cosm' +EXPIRED_DATE_FOR_TEST = '2020-05-05' +# set older date of issuance and renewal for the test license that should be excluded from the public search results +TEST_DATE_OF_ISSUANCE = '2013-05-05' +TEST_DATE_OF_RENEWAL = '2014-05-05' +TEST_JURISDICTION = 'az' +TEST_LICENSE_NUMBER = 'SMOKE-TEST-LICENSE' + + +def _ensure_no_existing_license_in_test_jurisdiction(license_records: list[dict]) -> None: + for record in license_records: + if str(record.get('jurisdiction', '')).lower() == TEST_JURISDICTION: + raise SmokeTestFailureException( + 'Smoke test prerequisite failed: the configured test provider already has at least one ' + f'license in jurisdiction {TEST_JURISDICTION}. Set TEST_JURISDICTION to a jurisdiction where ' + 'the test provider has no license, then re-run.' + ) + + +def _assert_license_eligibility_for_smoke_license( + *, + provider_id: str, + license_number: str, + expected_license_eligibility: str, +) -> None: + """Public query by license number; assert ``licenseEligibility`` for the smoke provider's row.""" + matching_license_rows = call_public_query_providers( + COMPACT, + license_number_filter=license_number, + provider_id_filter=provider_id, + page_size=25, + ) + if not matching_license_rows: + raise SmokeTestFailureException( + f'Public query returned no rows for provider {provider_id} (licenseNumber={license_number!r})' + ) + license_row = matching_license_rows[0] + actual_eligibility = license_row.get('licenseEligibility') + if actual_eligibility != expected_license_eligibility: + raise SmokeTestFailureException( + f'Expected licenseEligibility {expected_license_eligibility!r} for provider {provider_id}, ' + f'got {actual_eligibility!r}' + ) + + +def test_public_search_endpoints_returns_details_of_provider() -> dict: + """ + Public query by smoke license number for the configured test provider; verify eligible search row + and public GET license compactEligibility. + """ + provider_id = config.test_provider_id + database_records = get_all_provider_database_records(COMPACT, provider_id) + license_records = [record for record in database_records if record.get('type') == 'license'] + logger.info(f'License record count: {len(license_records)}') + _ensure_no_existing_license_in_test_jurisdiction(license_records) + smoke_license_record = get_most_recently_issued_or_renewed_license(license_records) + license_number = smoke_license_record.get('licenseNumber') + if not license_number: + raise SmokeTestFailureException('Smoke license record has no licenseNumber for public query') + + logger.info('Running public query endpoint test') + matching_license_rows = call_public_query_providers( + COMPACT, + license_number_filter=license_number, + provider_id_filter=provider_id, + ) + if not matching_license_rows: + raise SmokeTestFailureException( + f'Public query returned no rows for provider {provider_id} (licenseNumber={license_number})' + ) + license_row = matching_license_rows[0] + if license_row.get('licenseEligibility') != 'eligible': + raise SmokeTestFailureException( + f'Expected licenseEligibility eligible for provider {provider_id}, ' + f'got {license_row.get("licenseEligibility")!r}' + ) + + public_provider_detail = call_public_get_provider(COMPACT, provider_id) + licenses_from_get = public_provider_detail.get('licenses') or [] + # get the license from the public GET response that matches the smoke license record + matching_license_from_detail_response = next( + ( + license_payload + for license_payload in licenses_from_get + if str(license_payload.get('jurisdiction', '')).lower() == smoke_license_record.get('jurisdiction') + and license_payload.get('licenseType') == smoke_license_record.get('licenseType') + ), + None, + ) + if matching_license_from_detail_response is None: + raise SmokeTestFailureException( + f'Matching license not found for provider {provider_id} from public GET response' + ) + if matching_license_from_detail_response.get('compactEligibility') != 'eligible': + raise SmokeTestFailureException( + f'Expected compactEligibility eligible on public GET license, got ' + f'{matching_license_from_detail_response.get("compactEligibility")!r}' + ) + + logger.info('Public search smoke: baseline query + GET checks passed') + + return { + 'provider_id': provider_id, + 'license_number': license_number, + 'license_pk': smoke_license_record['pk'], + 'license_sk': smoke_license_record['sk'], + 'original_date_of_expiration': smoke_license_record['dateOfExpiration'], + 'original_jurisdiction_uploaded_compact_eligibility': smoke_license_record[ + 'jurisdictionUploadedCompactEligibility' + ], + } + + +def test_public_query_endpoint_returns_ineligible_license_if_license_is_expired(provider_context: dict) -> None: + provider_user_table = get_provider_user_dynamodb_table() + license_partition_and_sort_key = {'pk': provider_context['license_pk'], 'sk': provider_context['license_sk']} + original_date_of_expiration = provider_context['original_date_of_expiration'] + + try: + logger.info('Updating license expiration date to expired date') + provider_user_table.update_item( + Key=license_partition_and_sort_key, + UpdateExpression='SET dateOfExpiration = :exp', + ExpressionAttributeValues={':exp': EXPIRED_DATE_FOR_TEST}, + ) + wait_for_opensearch_sync() + _assert_license_eligibility_for_smoke_license( + provider_id=provider_context['provider_id'], + license_number=provider_context['license_number'], + expected_license_eligibility='ineligible', + ) + logger.info('expiration ineligibility test passed') + finally: + logger.info('Restoring license expiration date to original value') + provider_user_table.update_item( + Key=license_partition_and_sort_key, + UpdateExpression='SET dateOfExpiration = :exp', + ExpressionAttributeValues={':exp': original_date_of_expiration}, + ) + wait_for_opensearch_sync() + _assert_license_eligibility_for_smoke_license( + provider_id=provider_context['provider_id'], + license_number=provider_context['license_number'], + expected_license_eligibility='eligible', + ) + logger.info('license expiration date restored to original value') + + +def test_public_query_endpoint_returns_ineligible_license_if_license_is_marked_by_jurisdiction_as_ineligible( + provider_context: dict, +) -> None: + provider_user_table = get_provider_user_dynamodb_table() + license_partition_and_sort_key = {'pk': provider_context['license_pk'], 'sk': provider_context['license_sk']} + original_jurisdiction_uploaded_compact_eligibility = provider_context[ + 'original_jurisdiction_uploaded_compact_eligibility' + ] + + try: + logger.info('Updating license jurisdiction uploaded compact eligibility to ineligible') + provider_user_table.update_item( + Key=license_partition_and_sort_key, + UpdateExpression='SET jurisdictionUploadedCompactEligibility = :ineligible', + ExpressionAttributeValues={':ineligible': 'ineligible'}, + ) + wait_for_opensearch_sync() + _assert_license_eligibility_for_smoke_license( + provider_id=provider_context['provider_id'], + license_number=provider_context['license_number'], + expected_license_eligibility='ineligible', + ) + logger.info('jurisdiction ineligibility test passed') + finally: + logger.info('Restoring license jurisdiction uploaded compact eligibility to original value') + provider_user_table.update_item( + Key=license_partition_and_sort_key, + UpdateExpression='SET jurisdictionUploadedCompactEligibility = :j', + ExpressionAttributeValues={':j': original_jurisdiction_uploaded_compact_eligibility}, + ) + wait_for_opensearch_sync() + _assert_license_eligibility_for_smoke_license( + provider_id=provider_context['provider_id'], + license_number=provider_context['license_number'], + expected_license_eligibility='eligible', + ) + logger.info('license jurisdiction uploaded compact eligibility restored to original value') + + +def test_public_lookup_does_not_match_against_old_license_records(provider_context: dict) -> None: + """ + Inserts a license with older issuance/renewal and verifies that it is not included in the public search results. + """ + table = get_provider_user_dynamodb_table() + source_key = {'pk': provider_context['license_pk'], 'sk': provider_context['license_sk']} + response = table.get_item(Key=source_key) + + clone = copy.deepcopy(response['Item']) + license_type = clone['licenseType'] + license_type_abbr = get_license_type_abbreviation(license_type) + + clone['dateOfIssuance'] = TEST_DATE_OF_ISSUANCE + clone['dateOfRenewal'] = TEST_DATE_OF_RENEWAL + clone['licenseNumber'] = TEST_LICENSE_NUMBER + clone['jurisdiction'] = TEST_JURISDICTION + + clone['sk'] = f'{COMPACT}#PROVIDER#license/{TEST_JURISDICTION}/{license_type_abbr}#' + + new_key: dict[str, str] | None = None + try: + table.put_item(Item=clone) + new_key = {'pk': clone['pk'], 'sk': clone['sk']} + wait_for_opensearch_sync() + + matching_rows = call_public_query_providers( + COMPACT, + license_number_filter=TEST_LICENSE_NUMBER, + provider_id_filter=provider_context['provider_id'], + ) + if matching_rows: + raise SmokeTestFailureException( + f'Expected no public query rows for test license {TEST_LICENSE_NUMBER!r}, got {matching_rows}' + ) + + public_provider_detail = call_public_get_provider(COMPACT, provider_context['provider_id']) + for lic in public_provider_detail.get('licenses'): + if lic.get('licenseNumber') == TEST_LICENSE_NUMBER: + raise SmokeTestFailureException(f'Public GET unexpectedly included test license: {lic}') + + logger.info('Public search old license exclusion test passed') + finally: + if new_key is not None: + logger.info(f'Deleting test license {new_key}') + table.delete_item(Key=new_key) + + +if __name__ == '__main__': + load_smoke_test_env() + provider_context = test_public_search_endpoints_returns_details_of_provider() + test_public_query_endpoint_returns_ineligible_license_if_license_is_expired(provider_context=provider_context) + test_public_query_endpoint_returns_ineligible_license_if_license_is_marked_by_jurisdiction_as_ineligible( + provider_context=provider_context + ) + test_public_lookup_does_not_match_against_old_license_records(provider_context=provider_context) + logger.info('All public search smoke tests completed successfully.') diff --git a/backend/cosmetology-app/tests/smoke/smoke_common.py b/backend/cosmetology-app/tests/smoke/smoke_common.py index 7d54fc0a8..cf5d45499 100644 --- a/backend/cosmetology-app/tests/smoke/smoke_common.py +++ b/backend/cosmetology-app/tests/smoke/smoke_common.py @@ -1,6 +1,7 @@ import json import os import sys +import time import boto3 import requests @@ -32,7 +33,7 @@ def __init__(self, message): os.environ['LICENSE_TYPES'] = json.dumps(LICENSE_TYPES) # We have to import this after we've added the common lib to our path and environment -from cc_common.data_model.provider_record_util import ProviderUserRecords # noqa: E402 F401 +from cc_common.data_model.provider_record_util import ProviderRecordUtility, ProviderUserRecords # noqa: E402 F401 # importing this here so it can be easily referenced in the rollback upload tests from cc_common.data_model.schema.license import LicenseData, LicenseUpdateData # noqa: E402 F401 @@ -225,11 +226,83 @@ def call_provider_details_endpoint(headers: dict, compact: str, provider_id: str return response.json() +def wait_for_opensearch_sync() -> None: + """Wait for provider table changes to propagate into OpenSearch (best-effort fixed delay).""" + seconds = 30 + logger.info(f'Waiting {seconds}s for changes to propagate in OpenSearch...') + time.sleep(seconds) + + +def get_most_recently_issued_or_renewed_license(licenses: list[dict]) -> dict: + return ProviderRecordUtility.find_most_recently_issued_or_renewed_license(licenses) + + +_PUBLIC_QUERY_INTERNAL_MAX_PAGES = 500 + + +def call_public_query_providers( + compact: str, + *, + provider_id_filter: str, + first_name_filter: str | None = None, + last_name_filter: str | None = None, + license_number_filter: str | None = None, + page_size: int = 100, + timeout: int = 30, +) -> list[dict]: + """ + POST /v1/public/compacts/{compact}/providers/query (no auth). + + Builds query body from provided filters + """ + url = f'{config.api_base_url}/v1/public/compacts/{compact}/providers/query' + headers = {'Content-Type': 'application/json'} + query_parameters: dict = {} + if first_name_filter: + query_parameters['givenName'] = first_name_filter + if last_name_filter: + query_parameters['familyName'] = last_name_filter + if license_number_filter: + query_parameters['licenseNumber'] = license_number_filter + + pagination_state: dict = {'pageSize': page_size} + matching_license_rows: list[dict] = [] + + for _page_index in range(_PUBLIC_QUERY_INTERNAL_MAX_PAGES): + request_body = {'query': query_parameters, 'pagination': pagination_state} + response = requests.post(url=url, headers=headers, json=request_body, timeout=timeout) + if response.status_code != 200: + raise SmokeTestFailureException(f'Failed POST public query providers. Response: {response.json()}') + page_response_body = response.json() + + for provider_license_row in page_response_body.get('providers') or []: + if provider_id_filter and provider_license_row.get('providerId') == provider_id_filter: + matching_license_rows.append(provider_license_row) + + last_pagination_key = (page_response_body.get('pagination') or {}).get('lastKey') + if not last_pagination_key: + break + pagination_state = {**pagination_state, 'lastKey': last_pagination_key} + + return matching_license_rows + + +def call_public_get_provider(compact: str, provider_id: str, *, timeout: int = 30) -> dict: + """GET /v1/public/compacts/{compact}/providers/{provider_id} (no auth).""" + url = f'{config.api_base_url}/v1/public/compacts/{compact}/providers/{provider_id}' + response = requests.get(url=url, timeout=timeout) + + if response.status_code != 200: + raise SmokeTestFailureException(f'Failed GET public provider. Response: {response.json()}') + return response.json() + + def get_all_provider_database_records(compact: str = 'cosm', provider_id: str = None): if provider_id is None: provider_id = config.test_provider_id + logger.info('Querying records for provider', provider_id=provider_id) items: list = [] last_evaluated_key = None while True: @@ -360,7 +433,13 @@ def query_provider_by_name(staff_headers: dict, compact: str, given_name: str, f def wait_for_provider_creation( - staff_headers: dict, compact: str, given_name: str, family_name: str, max_wait_time: int = 300 + staff_headers: dict, + compact: str, + given_name: str, + family_name: str, + max_wait_time: int = 300, + staff_user_email: str | None = None, + poll_interval_seconds: int = 30, ): """Poll for provider creation after license upload. @@ -369,6 +448,8 @@ def wait_for_provider_creation( :param given_name: Provider's given name :param family_name: Provider's family name :param max_wait_time: Maximum time to wait in seconds (default: 300 = 5 minutes) + :param staff_user_email: Optional staff email; if provided, refresh auth headers on every poll attempt + :param poll_interval_seconds: Poll interval in seconds (default: 30) :return: The provider ID when found :raises SmokeTestFailureException: If provider not found within max_wait_time """ @@ -377,14 +458,14 @@ def wait_for_provider_creation( logger.info(f'Waiting for provider creation for {given_name} {family_name}...') start_time = time.time() - check_interval = 30 # Check every 30 seconds attempts = 0 - max_attempts = max_wait_time // check_interval + max_attempts = max_wait_time // poll_interval_seconds while attempts < max_attempts: attempts += 1 - provider_id = query_provider_by_name(staff_headers, compact, given_name, family_name) + headers = get_staff_user_auth_headers(staff_user_email) if staff_user_email else staff_headers + provider_id = query_provider_by_name(headers, compact, given_name, family_name) if provider_id: elapsed_time = time.time() - start_time logger.info(f'✅ Provider found after {elapsed_time:.1f} seconds. Provider ID: {provider_id}') @@ -392,9 +473,9 @@ def wait_for_provider_creation( if attempts < max_attempts: logger.info( - f'Attempt {attempts}/{max_attempts}: Provider not found yet. Waiting {check_interval} seconds...' + f'Attempt {attempts}/{max_attempts}: Provider not found yet. Waiting {poll_interval_seconds} seconds...' ) - time.sleep(check_interval) + time.sleep(poll_interval_seconds) elapsed_time = time.time() - start_time raise SmokeTestFailureException( @@ -427,19 +508,33 @@ def cleanup_test_provider_records(provider_id: str, compact: str): logger.warning(f'Error during cleanup: {str(e)}') -def create_test_app_client(client_name: str, compact: str, jurisdiction: str): +def create_test_app_client( + client_name: str, + compact: str, + jurisdiction: str | None = None, + jurisdictions: list[str] | None = None, +): """ Create a test app client in Cognito for authentication testing. :param client_name: Name for the test app client :param compact: Compact abbreviation - :param jurisdiction: Jurisdiction abbreviation + :param jurisdiction: Jurisdiction abbreviation (backward-compatible single value) + :param jurisdictions: Optional list of jurisdiction abbreviations for write scopes :return: Dictionary containing client_id and client_secret """ logger.info(f'Creating test app client: {client_name}') try: cognito_client = boto3.client('cognito-idp') + jurisdiction_list = jurisdictions if jurisdictions else ([jurisdiction] if jurisdiction else []) + if not jurisdiction_list: + raise SmokeTestFailureException('At least one jurisdiction is required to create a test app client') + + allowed_scopes = [ + f'{compact}/readGeneral', + *[f'{jurisdiction}/{compact}.write' for jurisdiction in jurisdiction_list], + ] # Create the user pool client response = cognito_client.create_user_pool_client( @@ -451,7 +546,7 @@ def create_test_app_client(client_name: str, compact: str, jurisdiction: str): AccessTokenValidity=15, AllowedOAuthFlowsUserPoolClient=True, AllowedOAuthFlows=['client_credentials'], - AllowedOAuthScopes=[f'{compact}/readGeneral', f'{jurisdiction}/{compact}.write'], + AllowedOAuthScopes=allowed_scopes, ) user_pool_client = response.get('UserPoolClient', {}) diff --git a/backend/multi-account/README.md b/backend/multi-account/README.md index d84b012ff..7c9aae255 100644 --- a/backend/multi-account/README.md +++ b/backend/multi-account/README.md @@ -124,6 +124,7 @@ We do not want users updating runtime code or deleting critical resources outsid "Sid": "DenyComputeAndBackupUpdates", "Effect": "Deny", "Action": [ + "ec2:RunInstances", "lambda:Delete*", "lambda:Create*", "lambda:Update*", @@ -155,6 +156,7 @@ We do not want users updating runtime code or deleting critical resources outsid "Sid": "DenyResourceModification", "Effect": "Deny", "Action": [ + "dynamodb:BatchWriteItem", "dynamodb:Delete*", "s3:Delete*", "s3:Create*", diff --git a/backend/multi-account/backups/requirements-dev.txt b/backend/multi-account/backups/requirements-dev.txt index 08fc787c5..4c11f1644 100644 --- a/backend/multi-account/backups/requirements-dev.txt +++ b/backend/multi-account/backups/requirements-dev.txt @@ -61,7 +61,7 @@ s3transfer==0.16.0 # via boto3 six==1.17.0 # via python-dateutil -urllib3==2.6.3 +urllib3==2.7.0 # via # botocore # requests diff --git a/backend/multi-account/control-tower/requirements-dev.txt b/backend/multi-account/control-tower/requirements-dev.txt index 32843ff99..6ac9d2147 100644 --- a/backend/multi-account/control-tower/requirements-dev.txt +++ b/backend/multi-account/control-tower/requirements-dev.txt @@ -95,7 +95,7 @@ tomli==2.4.1 # via pip-audit tomli-w==1.2.0 # via pip-audit -urllib3==2.6.3 +urllib3==2.7.0 # via requests wheel==0.46.3 # via pip-tools