diff --git a/.github/workflows/pullRequests.yml b/.github/workflows/pullRequests.yml index 70c224a4152..b193d937797 100644 --- a/.github/workflows/pullRequests.yml +++ b/.github/workflows/pullRequests.yml @@ -281,6 +281,64 @@ jobs: permissions: id-token: write if: needs.init.outputs.is-fork-pr != 'true' + jestTestsDdbOs: + needs: init + name: ${{ matrix.package.cmd }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + node: + - 18 + package: >- + ${{ fromJson('[{"cmd":"packages/api-aco + --storage=ddb-os,ddb","storage":"ddb-os","id":"api-aco_ddb-os_ddb"},{"cmd":"packages/api-audit-logs + --storage=ddb-os,ddb","storage":"ddb-os","id":"api-audit-logs_ddb-os_ddb"},{"cmd":"packages/api-elasticsearch","storage":["ddb-es","ddb-os"],"id":"api-elasticsearch"},{"cmd":"packages/api-file-manager + --storage=ddb-os,ddb","storage":"ddb-os","id":"api-file-manager_ddb-os_ddb"},{"cmd":"packages/api-form-builder + --storage=ddb-os,ddb","storage":"ddb-os","id":"api-form-builder_ddb-os_ddb"},{"cmd":"packages/api-form-builder-so-ddb-es + --storage=ddb-os,ddb","storage":"ddb-os","id":"api-form-builder-so-ddb-es_ddb-os_ddb"},{"cmd":"packages/api-headless-cms + --storage=ddb-os,ddb","storage":"ddb-os","id":"api-headless-cms_ddb-os_ddb"},{"cmd":"packages/api-headless-cms-ddb-es + --storage=ddb-os,ddb","storage":"ddb-os","id":"api-headless-cms-ddb-es_ddb-os_ddb"},{"cmd":"packages/api-mailer + --storage=ddb-os,ddb","storage":"ddb-os","id":"api-mailer_ddb-os_ddb"},{"cmd":"packages/api-page-builder + --storage=ddb-os,ddb","storage":"ddb-os","id":"api-page-builder_ddb-os_ddb"},{"cmd":"packages/api-page-builder-aco + --storage=ddb-os,ddb","storage":"ddb-os","id":"api-page-builder-aco_ddb-os_ddb"},{"cmd":"packages/api-page-builder-so-ddb-es + --storage=ddb-os,ddb","storage":"ddb-os","id":"api-page-builder-so-ddb-es_ddb-os_ddb"},{"cmd":"packages/migrations","storage":["ddb-es","ddb-os"],"id":"migrations"}]') + }} + runs-on: ${{ matrix.os }} + env: + NODE_OPTIONS: '--max_old_space_size=4096' + YARN_ENABLE_IMMUTABLE_INSTALLS: false + AWS_ELASTIC_SEARCH_DOMAIN_NAME: ${{ secrets.AWS_OPEN_SEARCH_DOMAIN_NAME }} + ELASTIC_SEARCH_ENDPOINT: ${{ secrets.OPEN_SEARCH_ENDPOINT }} + ELASTIC_SEARCH_INDEX_PREFIX: ${{ matrix.package.id }} + steps: + - uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::726952677045:role/GitHubActionsWebinyJs + aws-region: eu-central-1 + - uses: actions/checkout@v3 + - uses: actions/cache@v3 + with: + path: .yarn/cache + key: yarn-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + - uses: actions/cache@v3 + with: + path: .webiny/cached-packages + key: packages-cache-${{ needs.init.outputs.ts }} + - name: Install dependencies + run: yarn --immutable + - name: Build packages + run: yarn build:quick + - name: Run tests + run: yarn test ${{ matrix.package.cmd }} + permissions: + id-token: write + if: needs.init.outputs.is-fork-pr != 'true' verdaccioPublish: name: Publish to Verdaccio needs: init diff --git a/.github/workflows/pullRequestsCommandCypress.yml b/.github/workflows/pullRequestsCommandCypress.yml index c511a799d40..952b8f9821b 100644 --- a/.github/workflows/pullRequestsCommandCypress.yml +++ b/.github/workflows/pullRequestsCommandCypress.yml @@ -534,3 +534,251 @@ jobs: yarn cypress run --browser chrome --spec "${{ matrix.cypress-folder }}" runs-on: ubuntu-latest + e2e-wby-cms-ddb-os-init: + needs: checkComment + name: E2E (DDB-OS) - Init + outputs: + day: ${{ steps.get-day.outputs.day }} + ts: ${{ steps.get-timestamp.outputs.ts }} + cypress-folders: ${{ steps.list-cypress-folders.outputs.cypress-folders }} + steps: + - uses: actions/setup-node@v3 + with: + node-version: 18 + - uses: actions/checkout@v3 + - name: Install Hub Utility + run: sudo apt-get install -y hub + - name: Checkout Pull Request + working-directory: '' + run: hub pr checkout ${{ github.event.issue.number }} + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + - name: Get day of the month + id: get-day + run: >- + echo "day=$(node --eval "console.log(new Date().getDate())")" >> + $GITHUB_OUTPUT + - name: Get timestamp + id: get-timestamp + run: >- + echo "ts=$(node --eval "console.log(new Date().getTime())")" >> + $GITHUB_OUTPUT + - name: List Cypress tests folders + id: list-cypress-folders + run: >- + echo "cypress-folders=$(node scripts/listCypressTestsFolders.js)" >> + $GITHUB_OUTPUT + runs-on: ubuntu-latest + env: + NODE_OPTIONS: '--max_old_space_size=4096' + YARN_ENABLE_IMMUTABLE_INSTALLS: false + e2e-wby-cms-ddb-os-project-setup: + needs: e2e-wby-cms-ddb-os-init + name: E2E (DDB-OS) - Project setup + outputs: + cypress-config: ${{ steps.save-cypress-config.outputs.cypress-config }} + environment: next + env: + NODE_OPTIONS: '--max_old_space_size=4096' + YARN_ENABLE_IMMUTABLE_INSTALLS: 'false' + CYPRESS_MAILOSAUR_API_KEY: ${{ secrets.CYPRESS_MAILOSAUR_API_KEY }} + PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} + PULUMI_SECRETS_PROVIDER: ${{ secrets.PULUMI_SECRETS_PROVIDER }} + WEBINY_PULUMI_BACKEND: >- + ${{ secrets.WEBINY_PULUMI_BACKEND }}${{ + needs.e2e-wby-cms-ddb-os-init.outputs.ts }}_ddb + AWS_ELASTIC_SEARCH_DOMAIN_NAME: ${{ secrets.AWS_OPEN_SEARCH_DOMAIN_NAME }} + ELASTIC_SEARCH_ENDPOINT: ${{ secrets.OPEN_SEARCH_ENDPOINT }} + ELASTIC_SEARCH_INDEX_PREFIX: ${{ needs.e2e-wby-cms-ddb-os-init.outputs.ts }}_ + steps: + - uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::726952677045:role/GitHubActionsWebinyJs + aws-region: eu-central-1 + - uses: actions/checkout@v3 + with: + path: dev + - name: Install Hub Utility + run: sudo apt-get install -y hub + - name: Checkout Pull Request + working-directory: dev + run: hub pr checkout ${{ github.event.issue.number }} + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + - uses: actions/cache@v3 + id: yarn-cache + with: + path: dev/.yarn/cache + key: yarn-${{ runner.os }}-${{ hashFiles('dev/**/yarn.lock') }} + - uses: actions/cache@v3 + id: cached-packages + with: + path: dev/.webiny/cached-packages + key: >- + ${{ runner.os }}-${{ needs.e2e-wby-cms-ddb-os-init.outputs.day + }}-${{ secrets.RANDOM_CACHE_KEY_SUFFIX }} + - name: Install dependencies + working-directory: dev + run: yarn --immutable + - name: Build packages + working-directory: dev + run: yarn build:quick + - uses: actions/cache@v3 + id: packages-cache + with: + path: dev/.webiny/cached-packages + key: packages-cache-${{ needs.e2e-wby-cms-ddb-os-init.outputs.ts }} + - name: Start Verdaccio local server + working-directory: dev + run: >- + yarn add pm2 verdaccio && npx pm2 start verdaccio -- -c + .verdaccio.yaml + - name: Configure NPM to use local registry + run: npm config set registry http://localhost:4873 + - name: Set git email + run: git config --global user.email "webiny-bot@webiny.com" + - name: Set git username + run: git config --global user.name "webiny-bot" + - name: Create ".npmrc" file in the project root, with a dummy auth token + working-directory: dev + run: echo '//localhost:4873/:_authToken="dummy-auth-token"' > .npmrc + - name: Version and publish to Verdaccio + working-directory: dev + run: yarn release --type=verdaccio + - name: Create verdaccio-files artifact + uses: actions/upload-artifact@v3 + with: + name: verdaccio-files-ddb-os + retention-days: 1 + path: | + dev/.verdaccio/ + dev/.verdaccio.yaml + - name: Create directory + run: mkdir xyz + - name: Disable Webiny telemetry + run: > + mkdir ~/.webiny && echo '{ "id": "ci", "telemetry": false }' > + ~/.webiny/config + - name: Create a new Webiny project + working-directory: xyz + run: > + npx create-webiny-project@local-npm test-project --tag local-npm + --no-interactive --assign-to-yarnrc + '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' + --template-options '{"region":"${{ env.AWS_REGION + }}","storageOperations":"ddb-os"}' + - name: Print CLI version + working-directory: xyz/test-project + run: yarn webiny --version + - name: Create project-files artifact + uses: actions/upload-artifact@v3 + with: + name: project-files-ddb-os + retention-days: 1 + path: | + xyz/test-project/ + !xyz/test-project/node_modules/**/* + !xyz/test-project/**/node_modules/**/* + !xyz/test-project/.yarn/cache/**/* + - name: Deploy Core + working-directory: xyz/test-project + run: yarn webiny deploy apps/core --env dev + - name: Deploy API + working-directory: xyz/test-project + run: yarn webiny deploy apps/api --env dev + - name: Deploy Admin Area + working-directory: xyz/test-project + run: yarn webiny deploy apps/admin --env dev + - name: Deploy Website + working-directory: xyz/test-project + run: yarn webiny deploy apps/website --env dev + - name: Create Cypress config + working-directory: dev + run: yarn setup-cypress --projectFolder ../xyz/test-project + - name: Save Cypress config + id: save-cypress-config + working-directory: dev + run: >- + echo "cypress-config=$(cat cypress-tests/cypress.config.ts | tr -d + '\t\n\r')" >> $GITHUB_OUTPUT + - name: Cypress - run installation wizard test + working-directory: dev/cypress-tests + run: >- + yarn cypress run --browser chrome --spec + "cypress/e2e/adminInstallation/**/*.cy.js" + runs-on: ubuntu-latest + permissions: + id-token: write + e2e-wby-cms-ddb-os-cypress-tests: + name: >- + ${{ matrix.cypress-folder }} (ddb-os, ${{ matrix.os }}, Node v${{ + matrix.node }}) + needs: + - e2e-wby-cms-ddb-os-init + - e2e-wby-cms-ddb-os-project-setup + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + node: + - 18 + cypress-folder: ${{ fromJson(needs.e2e-wby-cms-ddb-os-init.outputs.cypress-folders) }} + environment: next + env: + NODE_OPTIONS: '--max_old_space_size=4096' + YARN_ENABLE_IMMUTABLE_INSTALLS: 'false' + CYPRESS_MAILOSAUR_API_KEY: ${{ secrets.CYPRESS_MAILOSAUR_API_KEY }} + PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} + PULUMI_SECRETS_PROVIDER: ${{ secrets.PULUMI_SECRETS_PROVIDER }} + WEBINY_PULUMI_BACKEND: >- + ${{ secrets.WEBINY_PULUMI_BACKEND }}${{ + needs.e2e-wby-cms-ddb-os-init.outputs.ts }}_ddb + AWS_ELASTIC_SEARCH_DOMAIN_NAME: ${{ secrets.AWS_OPEN_SEARCH_DOMAIN_NAME }} + ELASTIC_SEARCH_ENDPOINT: ${{ secrets.OPEN_SEARCH_ENDPOINT }} + ELASTIC_SEARCH_INDEX_PREFIX: ${{ needs.e2e-wby-cms-ddb-os-init.outputs.ts }}_ + steps: + - uses: actions/setup-node@v3 + with: + node-version: 18 + - uses: actions/checkout@v3 + with: + path: dev + - name: Install Hub Utility + run: sudo apt-get install -y hub + - name: Checkout Pull Request + working-directory: dev + run: hub pr checkout ${{ github.event.issue.number }} + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + - uses: actions/cache@v3 + with: + path: dev/.webiny/cached-packages + key: packages-cache-${{ needs.e2e-wby-cms-ddb-os-init.outputs.ts }} + - uses: actions/cache@v3 + with: + path: dev/.yarn/cache + key: yarn-${{ runner.os }}-${{ hashFiles('dev/**/yarn.lock') }} + - name: Install dependencies + working-directory: dev + run: yarn --immutable + - name: Build packages + working-directory: dev + run: yarn build:quick + - name: Set up Cypress config + working-directory: dev + run: >- + echo '${{ + needs.e2e-wby-cms-ddb-os-project-setup.outputs.cypress-config }}' > + cypress-tests/cypress.config.ts + - name: Cypress - run "${{ matrix.cypress-folder }}" tests + working-directory: dev/cypress-tests + timeout-minutes: 40 + run: >- + yarn cypress run --browser chrome --spec "${{ matrix.cypress-folder + }}" + runs-on: ubuntu-latest diff --git a/.github/workflows/pullRequestsCommandCypressTest.yml b/.github/workflows/pullRequestsCommandCypressTest.yml deleted file mode 100644 index 0d2242bb575..00000000000 --- a/.github/workflows/pullRequestsCommandCypressTest.yml +++ /dev/null @@ -1,784 +0,0 @@ -# This file was automatically generated by github-actions-wac. -# DO NOT MODIFY IT BY HAND. Instead, modify the source *.wac.ts file(s) -# and run "github-actions-wac build" (or "ghawac build") to regenerate this file. -# For more information, run "github-actions-wac --help". -name: Pull Requests Command - Cypress (TEST) -'on': issue_comment -env: - NODE_OPTIONS: '--max_old_space_size=4096' - AWS_REGION: eu-central-1 -jobs: - validateWorkflows: - name: Validate workflows - runs-on: ubuntu-latest - steps: - - name: Install dependencies - run: yarn --immutable - - name: Validate - run: npx github-actions-wac validate - checkComment: - name: Check comment for /cypress_test - if: ${{ github.event.issue.pull_request }} - steps: - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Check for Command - id: command - uses: xt0rted/slash-command-action@v2 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - command: cypress_test - reaction: 'true' - reaction-type: eyes - allow-edits: 'false' - permission-level: write - - name: Create comment - uses: peter-evans/create-or-update-comment@v2 - with: - issue-number: ${{ github.event.issue.number }} - body: >- - Cypress E2E tests have been initiated (for more information, click - [here](https://github.com/webiny/webiny-js/actions/runs/${{ - github.run_id }})). :sparkles: - runs-on: ubuntu-latest - env: - NODE_OPTIONS: '--max_old_space_size=4096' - YARN_ENABLE_IMMUTABLE_INSTALLS: false - e2e-wby-cms-ddb-init: - needs: checkComment - name: E2E (DDB) - Init - outputs: - day: ${{ steps.get-day.outputs.day }} - ts: ${{ steps.get-timestamp.outputs.ts }} - cypress-folders: ${{ steps.list-cypress-folders.outputs.cypress-folders }} - steps: - - uses: actions/setup-node@v3 - with: - node-version: 18 - - uses: actions/checkout@v3 - - name: Install Hub Utility - run: sudo apt-get install -y hub - - name: Checkout Pull Request - working-directory: '' - run: hub pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - - name: Get day of the month - id: get-day - run: >- - echo "day=$(node --eval "console.log(new Date().getDate())")" >> - $GITHUB_OUTPUT - - name: Get timestamp - id: get-timestamp - run: >- - echo "ts=$(node --eval "console.log(new Date().getTime())")" >> - $GITHUB_OUTPUT - - name: List Cypress tests folders - id: list-cypress-folders - run: >- - echo "cypress-folders=$(node scripts/listCypressTestsFolders.js)" >> - $GITHUB_OUTPUT - runs-on: ubuntu-latest - env: - NODE_OPTIONS: '--max_old_space_size=4096' - YARN_ENABLE_IMMUTABLE_INSTALLS: false - e2e-wby-cms-ddb-project-setup: - needs: e2e-wby-cms-ddb-init - name: E2E (DDB) - Project setup - outputs: - cypress-config: ${{ steps.save-cypress-config.outputs.cypress-config }} - environment: next - env: - NODE_OPTIONS: '--max_old_space_size=4096' - YARN_ENABLE_IMMUTABLE_INSTALLS: 'false' - CYPRESS_MAILOSAUR_API_KEY: ${{ secrets.CYPRESS_MAILOSAUR_API_KEY }} - PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} - PULUMI_SECRETS_PROVIDER: ${{ secrets.PULUMI_SECRETS_PROVIDER }} - WEBINY_PULUMI_BACKEND: >- - ${{ secrets.WEBINY_PULUMI_BACKEND }}${{ - needs.e2e-wby-cms-ddb-init.outputs.ts }}_ddb - steps: - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: arn:aws:iam::726952677045:role/GitHubActionsWebinyJs - aws-region: eu-central-1 - - uses: actions/checkout@v3 - with: - path: dev - - name: Install Hub Utility - run: sudo apt-get install -y hub - - name: Checkout Pull Request - working-directory: dev - run: hub pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - - uses: actions/cache@v3 - id: yarn-cache - with: - path: dev/.yarn/cache - key: yarn-${{ runner.os }}-${{ hashFiles('dev/**/yarn.lock') }} - - uses: actions/cache@v3 - id: cached-packages - with: - path: dev/.webiny/cached-packages - key: >- - ${{ runner.os }}-${{ needs.e2e-wby-cms-ddb-init.outputs.day }}-${{ - secrets.RANDOM_CACHE_KEY_SUFFIX }} - - name: Install dependencies - working-directory: dev - run: yarn --immutable - - name: Build packages - working-directory: dev - run: yarn build:quick - - uses: actions/cache@v3 - id: packages-cache - with: - path: dev/.webiny/cached-packages - key: packages-cache-${{ needs.e2e-wby-cms-ddb-init.outputs.ts }} - - name: Start Verdaccio local server - working-directory: dev - run: >- - yarn add pm2 verdaccio && npx pm2 start verdaccio -- -c - .verdaccio.yaml - - name: Configure NPM to use local registry - run: npm config set registry http://localhost:4873 - - name: Set git email - run: git config --global user.email "webiny-bot@webiny.com" - - name: Set git username - run: git config --global user.name "webiny-bot" - - name: Create ".npmrc" file in the project root, with a dummy auth token - working-directory: dev - run: echo '//localhost:4873/:_authToken="dummy-auth-token"' > .npmrc - - name: Version and publish to Verdaccio - working-directory: dev - run: yarn release --type=verdaccio - - name: Create verdaccio-files artifact - uses: actions/upload-artifact@v3 - with: - name: verdaccio-files-ddb - retention-days: 1 - path: | - dev/.verdaccio/ - dev/.verdaccio.yaml - - name: Create directory - run: mkdir xyz - - name: Disable Webiny telemetry - run: > - mkdir ~/.webiny && echo '{ "id": "ci", "telemetry": false }' > - ~/.webiny/config - - name: Create a new Webiny project - working-directory: xyz - run: > - npx create-webiny-project@local-npm test-project --tag local-npm - --no-interactive --assign-to-yarnrc - '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' - --template-options '{"region":"${{ env.AWS_REGION - }}","storageOperations":"ddb"}' - - name: Print CLI version - working-directory: xyz/test-project - run: yarn webiny --version - - name: Create project-files artifact - uses: actions/upload-artifact@v3 - with: - name: project-files-ddb - retention-days: 1 - path: | - xyz/test-project/ - !xyz/test-project/node_modules/**/* - !xyz/test-project/**/node_modules/**/* - !xyz/test-project/.yarn/cache/**/* - - name: Deploy Core - working-directory: xyz/test-project - run: yarn webiny deploy apps/core --env dev - - name: Deploy API - working-directory: xyz/test-project - run: yarn webiny deploy apps/api --env dev - - name: Deploy Admin Area - working-directory: xyz/test-project - run: yarn webiny deploy apps/admin --env dev - - name: Deploy Website - working-directory: xyz/test-project - run: yarn webiny deploy apps/website --env dev - - name: Create Cypress config - working-directory: dev - run: yarn setup-cypress --projectFolder ../xyz/test-project - - name: Save Cypress config - id: save-cypress-config - working-directory: dev - run: >- - echo "cypress-config=$(cat cypress-tests/cypress.config.ts | tr -d - '\t\n\r')" >> $GITHUB_OUTPUT - - name: Cypress - run installation wizard test - working-directory: dev/cypress-tests - run: >- - yarn cypress run --browser chrome --spec - "cypress/e2e/adminInstallation/**/*.cy.js" - runs-on: ubuntu-latest - permissions: - id-token: write - e2e-wby-cms-ddb-cypress-tests: - name: >- - ${{ matrix.cypress-folder }} (ddb, ${{ matrix.os }}, Node v${{ matrix.node - }}) - needs: - - e2e-wby-cms-ddb-init - - e2e-wby-cms-ddb-project-setup - strategy: - fail-fast: false - matrix: - os: - - ubuntu-latest - node: - - 18 - cypress-folder: ${{ fromJson(needs.e2e-wby-cms-ddb-init.outputs.cypress-folders) }} - environment: next - env: - NODE_OPTIONS: '--max_old_space_size=4096' - YARN_ENABLE_IMMUTABLE_INSTALLS: 'false' - CYPRESS_MAILOSAUR_API_KEY: ${{ secrets.CYPRESS_MAILOSAUR_API_KEY }} - PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} - PULUMI_SECRETS_PROVIDER: ${{ secrets.PULUMI_SECRETS_PROVIDER }} - WEBINY_PULUMI_BACKEND: >- - ${{ secrets.WEBINY_PULUMI_BACKEND }}${{ - needs.e2e-wby-cms-ddb-init.outputs.ts }}_ddb - steps: - - uses: actions/setup-node@v3 - with: - node-version: 18 - - uses: actions/checkout@v3 - with: - path: dev - - name: Install Hub Utility - run: sudo apt-get install -y hub - - name: Checkout Pull Request - working-directory: dev - run: hub pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - - uses: actions/cache@v3 - with: - path: dev/.webiny/cached-packages - key: packages-cache-${{ needs.e2e-wby-cms-ddb-init.outputs.ts }} - - uses: actions/cache@v3 - with: - path: dev/.yarn/cache - key: yarn-${{ runner.os }}-${{ hashFiles('dev/**/yarn.lock') }} - - name: Install dependencies - working-directory: dev - run: yarn --immutable - - name: Build packages - working-directory: dev - run: yarn build:quick - - name: Set up Cypress config - working-directory: dev - run: >- - echo '${{ needs.e2e-wby-cms-ddb-project-setup.outputs.cypress-config - }}' > cypress-tests/cypress.config.ts - - name: Cypress - run "${{ matrix.cypress-folder }}" tests - working-directory: dev/cypress-tests - timeout-minutes: 40 - run: >- - yarn cypress run --browser chrome --spec "${{ matrix.cypress-folder - }}" - runs-on: ubuntu-latest - e2e-wby-cms-ddb-es-init: - needs: checkComment - name: E2E (DDB-ES) - Init - outputs: - day: ${{ steps.get-day.outputs.day }} - ts: ${{ steps.get-timestamp.outputs.ts }} - cypress-folders: ${{ steps.list-cypress-folders.outputs.cypress-folders }} - steps: - - uses: actions/setup-node@v3 - with: - node-version: 18 - - uses: actions/checkout@v3 - - name: Install Hub Utility - run: sudo apt-get install -y hub - - name: Checkout Pull Request - working-directory: '' - run: hub pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - - name: Get day of the month - id: get-day - run: >- - echo "day=$(node --eval "console.log(new Date().getDate())")" >> - $GITHUB_OUTPUT - - name: Get timestamp - id: get-timestamp - run: >- - echo "ts=$(node --eval "console.log(new Date().getTime())")" >> - $GITHUB_OUTPUT - - name: List Cypress tests folders - id: list-cypress-folders - run: >- - echo "cypress-folders=$(node scripts/listCypressTestsFolders.js)" >> - $GITHUB_OUTPUT - runs-on: ubuntu-latest - env: - NODE_OPTIONS: '--max_old_space_size=4096' - YARN_ENABLE_IMMUTABLE_INSTALLS: false - e2e-wby-cms-ddb-es-project-setup: - needs: e2e-wby-cms-ddb-es-init - name: E2E (DDB-ES) - Project setup - outputs: - cypress-config: ${{ steps.save-cypress-config.outputs.cypress-config }} - environment: next - env: - NODE_OPTIONS: '--max_old_space_size=4096' - YARN_ENABLE_IMMUTABLE_INSTALLS: 'false' - CYPRESS_MAILOSAUR_API_KEY: ${{ secrets.CYPRESS_MAILOSAUR_API_KEY }} - PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} - PULUMI_SECRETS_PROVIDER: ${{ secrets.PULUMI_SECRETS_PROVIDER }} - WEBINY_PULUMI_BACKEND: >- - ${{ secrets.WEBINY_PULUMI_BACKEND }}${{ - needs.e2e-wby-cms-ddb-es-init.outputs.ts }}_ddb - AWS_ELASTIC_SEARCH_DOMAIN_NAME: ${{ secrets.AWS_ELASTIC_SEARCH_DOMAIN_NAME }} - ELASTIC_SEARCH_ENDPOINT: ${{ secrets.ELASTIC_SEARCH_ENDPOINT }} - ELASTIC_SEARCH_INDEX_PREFIX: ${{ needs.e2e-wby-cms-ddb-es-init.outputs.ts }}_ - steps: - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: arn:aws:iam::726952677045:role/GitHubActionsWebinyJs - aws-region: eu-central-1 - - uses: actions/checkout@v3 - with: - path: dev - - name: Install Hub Utility - run: sudo apt-get install -y hub - - name: Checkout Pull Request - working-directory: dev - run: hub pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - - uses: actions/cache@v3 - id: yarn-cache - with: - path: dev/.yarn/cache - key: yarn-${{ runner.os }}-${{ hashFiles('dev/**/yarn.lock') }} - - uses: actions/cache@v3 - id: cached-packages - with: - path: dev/.webiny/cached-packages - key: >- - ${{ runner.os }}-${{ needs.e2e-wby-cms-ddb-es-init.outputs.day - }}-${{ secrets.RANDOM_CACHE_KEY_SUFFIX }} - - name: Install dependencies - working-directory: dev - run: yarn --immutable - - name: Build packages - working-directory: dev - run: yarn build:quick - - uses: actions/cache@v3 - id: packages-cache - with: - path: dev/.webiny/cached-packages - key: packages-cache-${{ needs.e2e-wby-cms-ddb-es-init.outputs.ts }} - - name: Start Verdaccio local server - working-directory: dev - run: >- - yarn add pm2 verdaccio && npx pm2 start verdaccio -- -c - .verdaccio.yaml - - name: Configure NPM to use local registry - run: npm config set registry http://localhost:4873 - - name: Set git email - run: git config --global user.email "webiny-bot@webiny.com" - - name: Set git username - run: git config --global user.name "webiny-bot" - - name: Create ".npmrc" file in the project root, with a dummy auth token - working-directory: dev - run: echo '//localhost:4873/:_authToken="dummy-auth-token"' > .npmrc - - name: Version and publish to Verdaccio - working-directory: dev - run: yarn release --type=verdaccio - - name: Create verdaccio-files artifact - uses: actions/upload-artifact@v3 - with: - name: verdaccio-files-ddb-es - retention-days: 1 - path: | - dev/.verdaccio/ - dev/.verdaccio.yaml - - name: Create directory - run: mkdir xyz - - name: Disable Webiny telemetry - run: > - mkdir ~/.webiny && echo '{ "id": "ci", "telemetry": false }' > - ~/.webiny/config - - name: Create a new Webiny project - working-directory: xyz - run: > - npx create-webiny-project@local-npm test-project --tag local-npm - --no-interactive --assign-to-yarnrc - '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' - --template-options '{"region":"${{ env.AWS_REGION - }}","storageOperations":"ddb-es"}' - - name: Print CLI version - working-directory: xyz/test-project - run: yarn webiny --version - - name: Create project-files artifact - uses: actions/upload-artifact@v3 - with: - name: project-files-ddb-es - retention-days: 1 - path: | - xyz/test-project/ - !xyz/test-project/node_modules/**/* - !xyz/test-project/**/node_modules/**/* - !xyz/test-project/.yarn/cache/**/* - - name: Deploy Core - working-directory: xyz/test-project - run: yarn webiny deploy apps/core --env dev - - name: Deploy API - working-directory: xyz/test-project - run: yarn webiny deploy apps/api --env dev - - name: Deploy Admin Area - working-directory: xyz/test-project - run: yarn webiny deploy apps/admin --env dev - - name: Deploy Website - working-directory: xyz/test-project - run: yarn webiny deploy apps/website --env dev - - name: Create Cypress config - working-directory: dev - run: yarn setup-cypress --projectFolder ../xyz/test-project - - name: Save Cypress config - id: save-cypress-config - working-directory: dev - run: >- - echo "cypress-config=$(cat cypress-tests/cypress.config.ts | tr -d - '\t\n\r')" >> $GITHUB_OUTPUT - - name: Cypress - run installation wizard test - working-directory: dev/cypress-tests - run: >- - yarn cypress run --browser chrome --spec - "cypress/e2e/adminInstallation/**/*.cy.js" - runs-on: ubuntu-latest - permissions: - id-token: write - e2e-wby-cms-ddb-es-cypress-tests: - name: >- - ${{ matrix.cypress-folder }} (ddb-es, ${{ matrix.os }}, Node v${{ - matrix.node }}) - needs: - - e2e-wby-cms-ddb-es-init - - e2e-wby-cms-ddb-es-project-setup - strategy: - fail-fast: false - matrix: - os: - - ubuntu-latest - node: - - 18 - cypress-folder: ${{ fromJson(needs.e2e-wby-cms-ddb-es-init.outputs.cypress-folders) }} - environment: next - env: - NODE_OPTIONS: '--max_old_space_size=4096' - YARN_ENABLE_IMMUTABLE_INSTALLS: 'false' - CYPRESS_MAILOSAUR_API_KEY: ${{ secrets.CYPRESS_MAILOSAUR_API_KEY }} - PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} - PULUMI_SECRETS_PROVIDER: ${{ secrets.PULUMI_SECRETS_PROVIDER }} - WEBINY_PULUMI_BACKEND: >- - ${{ secrets.WEBINY_PULUMI_BACKEND }}${{ - needs.e2e-wby-cms-ddb-es-init.outputs.ts }}_ddb - AWS_ELASTIC_SEARCH_DOMAIN_NAME: ${{ secrets.AWS_ELASTIC_SEARCH_DOMAIN_NAME }} - ELASTIC_SEARCH_ENDPOINT: ${{ secrets.ELASTIC_SEARCH_ENDPOINT }} - ELASTIC_SEARCH_INDEX_PREFIX: ${{ needs.e2e-wby-cms-ddb-es-init.outputs.ts }}_ - steps: - - uses: actions/setup-node@v3 - with: - node-version: 18 - - uses: actions/checkout@v3 - with: - path: dev - - name: Install Hub Utility - run: sudo apt-get install -y hub - - name: Checkout Pull Request - working-directory: dev - run: hub pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - - uses: actions/cache@v3 - with: - path: dev/.webiny/cached-packages - key: packages-cache-${{ needs.e2e-wby-cms-ddb-es-init.outputs.ts }} - - uses: actions/cache@v3 - with: - path: dev/.yarn/cache - key: yarn-${{ runner.os }}-${{ hashFiles('dev/**/yarn.lock') }} - - name: Install dependencies - working-directory: dev - run: yarn --immutable - - name: Build packages - working-directory: dev - run: yarn build:quick - - name: Set up Cypress config - working-directory: dev - run: >- - echo '${{ - needs.e2e-wby-cms-ddb-es-project-setup.outputs.cypress-config }}' > - cypress-tests/cypress.config.ts - - name: Cypress - run "${{ matrix.cypress-folder }}" tests - working-directory: dev/cypress-tests - timeout-minutes: 40 - run: >- - yarn cypress run --browser chrome --spec "${{ matrix.cypress-folder - }}" - runs-on: ubuntu-latest - e2e-wby-cms-ddb-os-init: - needs: checkComment - name: E2E (DDB-OS) - Init - outputs: - day: ${{ steps.get-day.outputs.day }} - ts: ${{ steps.get-timestamp.outputs.ts }} - cypress-folders: ${{ steps.list-cypress-folders.outputs.cypress-folders }} - steps: - - uses: actions/setup-node@v3 - with: - node-version: 18 - - uses: actions/checkout@v3 - - name: Install Hub Utility - run: sudo apt-get install -y hub - - name: Checkout Pull Request - working-directory: '' - run: hub pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - - name: Get day of the month - id: get-day - run: >- - echo "day=$(node --eval "console.log(new Date().getDate())")" >> - $GITHUB_OUTPUT - - name: Get timestamp - id: get-timestamp - run: >- - echo "ts=$(node --eval "console.log(new Date().getTime())")" >> - $GITHUB_OUTPUT - - name: List Cypress tests folders - id: list-cypress-folders - run: >- - echo "cypress-folders=$(node scripts/listCypressTestsFolders.js)" >> - $GITHUB_OUTPUT - runs-on: ubuntu-latest - env: - NODE_OPTIONS: '--max_old_space_size=4096' - YARN_ENABLE_IMMUTABLE_INSTALLS: false - e2e-wby-cms-ddb-os-project-setup: - needs: e2e-wby-cms-ddb-os-init - name: E2E (DDB-OS) - Project setup - outputs: - cypress-config: ${{ steps.save-cypress-config.outputs.cypress-config }} - environment: next - env: - NODE_OPTIONS: '--max_old_space_size=4096' - YARN_ENABLE_IMMUTABLE_INSTALLS: 'false' - CYPRESS_MAILOSAUR_API_KEY: ${{ secrets.CYPRESS_MAILOSAUR_API_KEY }} - PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} - PULUMI_SECRETS_PROVIDER: ${{ secrets.PULUMI_SECRETS_PROVIDER }} - WEBINY_PULUMI_BACKEND: >- - ${{ secrets.WEBINY_PULUMI_BACKEND }}${{ - needs.e2e-wby-cms-ddb-os-init.outputs.ts }}_ddb - AWS_ELASTIC_SEARCH_DOMAIN_NAME: ${{ secrets.AWS_OPEN_SEARCH_DOMAIN_NAME }} - ELASTIC_SEARCH_ENDPOINT: ${{ secrets.OPEN_SEARCH_ENDPOINT }} - ELASTIC_SEARCH_INDEX_PREFIX: ${{ needs.e2e-wby-cms-ddb-os-init.outputs.ts }}_ - steps: - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: arn:aws:iam::726952677045:role/GitHubActionsWebinyJs - aws-region: eu-central-1 - - uses: actions/checkout@v3 - with: - path: dev - - name: Install Hub Utility - run: sudo apt-get install -y hub - - name: Checkout Pull Request - working-directory: dev - run: hub pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - - uses: actions/cache@v3 - id: yarn-cache - with: - path: dev/.yarn/cache - key: yarn-${{ runner.os }}-${{ hashFiles('dev/**/yarn.lock') }} - - uses: actions/cache@v3 - id: cached-packages - with: - path: dev/.webiny/cached-packages - key: >- - ${{ runner.os }}-${{ needs.e2e-wby-cms-ddb-os-init.outputs.day - }}-${{ secrets.RANDOM_CACHE_KEY_SUFFIX }} - - name: Install dependencies - working-directory: dev - run: yarn --immutable - - name: Build packages - working-directory: dev - run: yarn build:quick - - uses: actions/cache@v3 - id: packages-cache - with: - path: dev/.webiny/cached-packages - key: packages-cache-${{ needs.e2e-wby-cms-ddb-os-init.outputs.ts }} - - name: Start Verdaccio local server - working-directory: dev - run: >- - yarn add pm2 verdaccio && npx pm2 start verdaccio -- -c - .verdaccio.yaml - - name: Configure NPM to use local registry - run: npm config set registry http://localhost:4873 - - name: Set git email - run: git config --global user.email "webiny-bot@webiny.com" - - name: Set git username - run: git config --global user.name "webiny-bot" - - name: Create ".npmrc" file in the project root, with a dummy auth token - working-directory: dev - run: echo '//localhost:4873/:_authToken="dummy-auth-token"' > .npmrc - - name: Version and publish to Verdaccio - working-directory: dev - run: yarn release --type=verdaccio - - name: Create verdaccio-files artifact - uses: actions/upload-artifact@v3 - with: - name: verdaccio-files-ddb-os - retention-days: 1 - path: | - dev/.verdaccio/ - dev/.verdaccio.yaml - - name: Create directory - run: mkdir xyz - - name: Disable Webiny telemetry - run: > - mkdir ~/.webiny && echo '{ "id": "ci", "telemetry": false }' > - ~/.webiny/config - - name: Create a new Webiny project - working-directory: xyz - run: > - npx create-webiny-project@local-npm test-project --tag local-npm - --no-interactive --assign-to-yarnrc - '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' - --template-options '{"region":"${{ env.AWS_REGION - }}","storageOperations":"ddb-os"}' - - name: Print CLI version - working-directory: xyz/test-project - run: yarn webiny --version - - name: Create project-files artifact - uses: actions/upload-artifact@v3 - with: - name: project-files-ddb-os - retention-days: 1 - path: | - xyz/test-project/ - !xyz/test-project/node_modules/**/* - !xyz/test-project/**/node_modules/**/* - !xyz/test-project/.yarn/cache/**/* - - name: Deploy Core - working-directory: xyz/test-project - run: yarn webiny deploy apps/core --env dev - - name: Deploy API - working-directory: xyz/test-project - run: yarn webiny deploy apps/api --env dev - - name: Deploy Admin Area - working-directory: xyz/test-project - run: yarn webiny deploy apps/admin --env dev - - name: Deploy Website - working-directory: xyz/test-project - run: yarn webiny deploy apps/website --env dev - - name: Create Cypress config - working-directory: dev - run: yarn setup-cypress --projectFolder ../xyz/test-project - - name: Save Cypress config - id: save-cypress-config - working-directory: dev - run: >- - echo "cypress-config=$(cat cypress-tests/cypress.config.ts | tr -d - '\t\n\r')" >> $GITHUB_OUTPUT - - name: Cypress - run installation wizard test - working-directory: dev/cypress-tests - run: >- - yarn cypress run --browser chrome --spec - "cypress/e2e/adminInstallation/**/*.cy.js" - runs-on: ubuntu-latest - permissions: - id-token: write - e2e-wby-cms-ddb-os-cypress-tests: - name: >- - ${{ matrix.cypress-folder }} (ddb-os, ${{ matrix.os }}, Node v${{ - matrix.node }}) - needs: - - e2e-wby-cms-ddb-os-init - - e2e-wby-cms-ddb-os-project-setup - strategy: - fail-fast: false - matrix: - os: - - ubuntu-latest - node: - - 18 - cypress-folder: ${{ fromJson(needs.e2e-wby-cms-ddb-os-init.outputs.cypress-folders) }} - environment: next - env: - NODE_OPTIONS: '--max_old_space_size=4096' - YARN_ENABLE_IMMUTABLE_INSTALLS: 'false' - CYPRESS_MAILOSAUR_API_KEY: ${{ secrets.CYPRESS_MAILOSAUR_API_KEY }} - PULUMI_CONFIG_PASSPHRASE: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} - PULUMI_SECRETS_PROVIDER: ${{ secrets.PULUMI_SECRETS_PROVIDER }} - WEBINY_PULUMI_BACKEND: >- - ${{ secrets.WEBINY_PULUMI_BACKEND }}${{ - needs.e2e-wby-cms-ddb-os-init.outputs.ts }}_ddb - AWS_ELASTIC_SEARCH_DOMAIN_NAME: ${{ secrets.AWS_OPEN_SEARCH_DOMAIN_NAME }} - ELASTIC_SEARCH_ENDPOINT: ${{ secrets.OPEN_SEARCH_ENDPOINT }} - ELASTIC_SEARCH_INDEX_PREFIX: ${{ needs.e2e-wby-cms-ddb-os-init.outputs.ts }}_ - steps: - - uses: actions/setup-node@v3 - with: - node-version: 18 - - uses: actions/checkout@v3 - with: - path: dev - - name: Install Hub Utility - run: sudo apt-get install -y hub - - name: Checkout Pull Request - working-directory: dev - run: hub pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - - uses: actions/cache@v3 - with: - path: dev/.webiny/cached-packages - key: packages-cache-${{ needs.e2e-wby-cms-ddb-os-init.outputs.ts }} - - uses: actions/cache@v3 - with: - path: dev/.yarn/cache - key: yarn-${{ runner.os }}-${{ hashFiles('dev/**/yarn.lock') }} - - name: Install dependencies - working-directory: dev - run: yarn --immutable - - name: Build packages - working-directory: dev - run: yarn build:quick - - name: Set up Cypress config - working-directory: dev - run: >- - echo '${{ - needs.e2e-wby-cms-ddb-os-project-setup.outputs.cypress-config }}' > - cypress-tests/cypress.config.ts - - name: Cypress - run "${{ matrix.cypress-folder }}" tests - working-directory: dev/cypress-tests - timeout-minutes: 40 - run: >- - yarn cypress run --browser chrome --spec "${{ matrix.cypress-folder - }}" - runs-on: ubuntu-latest diff --git a/.github/workflows/wac/pullRequests.wac.ts b/.github/workflows/wac/pullRequests.wac.ts index cd18bc3083c..d7edfd3cb45 100644 --- a/.github/workflows/wac/pullRequests.wac.ts +++ b/.github/workflows/wac/pullRequests.wac.ts @@ -217,6 +217,7 @@ export const pullRequests = createWorkflow({ jestTestsNoStorage: createJestTestsJob(null), jestTestsDdb: createJestTestsJob("ddb"), jestTestsDdbEs: createJestTestsJob("ddb-es"), + jestTestsDdbOs: createJestTestsJob("ddb-os"), verdaccioPublish: createJob({ name: "Publish to Verdaccio", diff --git a/.github/workflows/wac/pullRequestsCommandCypress.wac.ts b/.github/workflows/wac/pullRequestsCommandCypress.wac.ts index fc76e6510a1..847f539bd7b 100644 --- a/.github/workflows/wac/pullRequestsCommandCypress.wac.ts +++ b/.github/workflows/wac/pullRequestsCommandCypress.wac.ts @@ -246,7 +246,6 @@ const createJobs = (dbSetup: string) => { }; }; -// Create "Pull requests" workflow. export const pullRequestsCommandCypress = createWorkflow({ name: "Pull Requests Command - Cypress", on: "issue_comment", @@ -285,6 +284,7 @@ export const pullRequestsCommandCypress = createWorkflow({ ] }), ...createJobs("ddb"), - ...createJobs("ddb-es") + ...createJobs("ddb-es"), + ...createJobs("ddb-os") } }); diff --git a/apps/api/graphql/src/security.ts b/apps/api/graphql/src/security.ts index fe13b802963..aa51f0581aa 100644 --- a/apps/api/graphql/src/security.ts +++ b/apps/api/graphql/src/security.ts @@ -83,7 +83,7 @@ export default ({ documentClient }: { documentClient: DynamoDBClient }) => [ apiKeyAuthorization({ identityType: "api-key" }), /** - * Authorization plugin to fetch permissions from a security group associated with the identity. + * Authorization plugin to fetch permissions from a security role or team associated with the identity. */ tenantLinkAuthorization({ identityType: "admin" }), diff --git a/docs/DEPLOY_WEBINY_PROJECT_CF_TEMPLATE.yaml b/docs/DEPLOY_WEBINY_PROJECT_CF_TEMPLATE.yaml index 4d73160bc5b..49786c3f8dd 100644 --- a/docs/DEPLOY_WEBINY_PROJECT_CF_TEMPLATE.yaml +++ b/docs/DEPLOY_WEBINY_PROJECT_CF_TEMPLATE.yaml @@ -245,6 +245,7 @@ Resources: - iam:GetRole - iam:CreateServiceLinkedRole Resource: + - arn:aws:iam::*:role/aws-service-role/es.amazonaws.com/AWSServiceRoleForAmazonOpenSearchService - arn:aws:iam::*:role/aws-service-role/es.amazonaws.com/AWSServiceRoleForAmazonElasticsearchService # AWS Lambda diff --git a/packages/api-aco-so-ddb-es/package.json b/packages/api-aco-so-ddb-es/package.json index 197f1de0969..30a770835ce 100644 --- a/packages/api-aco-so-ddb-es/package.json +++ b/packages/api-aco-so-ddb-es/package.json @@ -9,7 +9,10 @@ "dynamodb", "elasticsearch", "ddb-es", - "aco:ddb-es" + "aco:ddb-es", + "opensearch", + "ddb-os", + "aco:ddb-os" ], "repository": { "type": "git", diff --git a/packages/api-form-builder-so-ddb-es/package.json b/packages/api-form-builder-so-ddb-es/package.json index e5b2c0e153c..7513e7b7227 100644 --- a/packages/api-form-builder-so-ddb-es/package.json +++ b/packages/api-form-builder-so-ddb-es/package.json @@ -8,7 +8,10 @@ "dynamodb", "elasticsearch", "ddb-es", - "fb:ddb-es" + "fb:ddb-es", + "opensearch", + "ddb-os", + "fb:ddb-os" ], "repository": { "type": "git", diff --git a/packages/api-headless-cms-ddb-es/package.json b/packages/api-headless-cms-ddb-es/package.json index d3e25d287b7..07550a0de53 100644 --- a/packages/api-headless-cms-ddb-es/package.json +++ b/packages/api-headless-cms-ddb-es/package.json @@ -8,7 +8,10 @@ "dynamodb", "elasticsearch", "ddb-es", - "cms:ddb-es" + "cms:ddb-es", + "opensearch", + "ddb-os", + "cms:ddb-os" ], "repository": { "type": "git", diff --git a/packages/api-page-builder-so-ddb-es/package.json b/packages/api-page-builder-so-ddb-es/package.json index 334e7430642..43a9842a36e 100644 --- a/packages/api-page-builder-so-ddb-es/package.json +++ b/packages/api-page-builder-so-ddb-es/package.json @@ -8,7 +8,10 @@ "dynamodb", "elasticsearch", "ddb-es", - "pb:ddb-es" + "pb:ddb-es", + "opensearch", + "ddb-os", + "pb:ddb-os" ], "repository": { "type": "git", diff --git a/packages/cwp-template-aws/index.js b/packages/cwp-template-aws/index.js index 003372fb024..0606637d999 100644 --- a/packages/cwp-template-aws/index.js +++ b/packages/cwp-template-aws/index.js @@ -6,9 +6,9 @@ const choices = { value: "ddb", name: "DynamoDB (for small and medium sized projects)" }, - ddbEs: { - value: "ddb-es", - name: "DynamoDB + Elasticsearch (for larger projects)" + ddbOs: { + value: "ddb-os", + name: "Amazon DynamoDB + Amazon OpenSearch (for larger projects)" } }; diff --git a/packages/cwp-template-aws/template/common/apps/theme/layouts/forms/DefaultFormLayout/SubmitButton.tsx b/packages/cwp-template-aws/template/common/apps/theme/layouts/forms/DefaultFormLayout/SubmitButton.tsx deleted file mode 100644 index dd20ca5e744..00000000000 --- a/packages/cwp-template-aws/template/common/apps/theme/layouts/forms/DefaultFormLayout/SubmitButton.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from "react"; -import { FormRenderPropParamsSubmit } from "@webiny/form"; -import styled from "@emotion/styled"; - -export const Wrapper = styled.div<{ fullWidth: boolean }>` - ${props => props.theme.styles.elements["button"]["primary"]} - .button-body { - width: ${props => (props.fullWidth ? "100%" : "auto")}; - margin-left: auto; - - &:disabled { - opacity: 0.5; - } - } -`; - -interface Props { - fullWidth: boolean; - onClick: FormRenderPropParamsSubmit; - loading: boolean; - children: React.ReactNode; -} - -export const SubmitButton: React.FC = ({ fullWidth, onClick, loading, children }) => { - return ( - - - - ); -}; diff --git a/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/.babelrc.js b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/.babelrc.js new file mode 100644 index 00000000000..9da7674cb52 --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/.babelrc.js @@ -0,0 +1 @@ +module.exports = require("@webiny/project-utils").createBabelConfigForNode({ path: __dirname }); diff --git a/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/jest.config.js b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/jest.config.js new file mode 100644 index 00000000000..d45bed2636f --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/jest.config.js @@ -0,0 +1,41 @@ +const base = require("../../../jest.config.base"); +const { log } = require("@webiny/cli/utils"); +const { getStackOutput } = require("@webiny/cli-plugin-deploy-pulumi/utils"); + +/** + * `getStackOutput` retrieves all values that were exported from `apps/api/pulumi/dev/index.ts`. + * Note that this means the project needs to be already deployed into the "dev" environment. + * If you want to use a different environment for testing purposes, change the `env` argument. + * Finally, note that usually we don't need to perform this step if we're running unit tests. + */ + +const TEST_TYPE = process.env.TEST_TYPE; +const DEPLOY_ENVIRONMENT = "dev"; + +if (TEST_TYPE !== "unit") { + log.info(`${log.info.hl("apps/api/graphql")}: Assigning environment variables...`); + const stackOutput = getStackOutput({ folder: "apps/api", env: DEPLOY_ENVIRONMENT }); + + if (stackOutput) { + // Assign received values as environment variables. + Object.assign(process.env, { + // We assign `region`, `dynamoDbTable`, and `apiUrl` as AWS_REGION, DB_TABLE, and API_URL + // environment variables. If needed, you can export additional values from the mentioned + // `apps/api/pulumi/dev/index.ts` file and assign them here. + AWS_REGION: stackOutput.region, + DB_TABLE: stackOutput.dynamoDbTable, + DB_TABLE_ELASTICSEARCH: stackOutput.dynamoDbElasticsearchTable, + API_URL: stackOutput.apiUrl, + + // Can be of use while writing tests, for example to distinguish test data from non-test data. + TEST_RUN_ID: new Date().getTime() + }); + log.success("Environment variables successfully assigned."); + } else { + log.warning(`Could not assign environment variables.`); + } + console.log(); +} + +// Finally, export Jest config to be used while tests are being run. +module.exports = { ...base({ path: __dirname }) }; diff --git a/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/package.json b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/package.json new file mode 100644 index 00000000000..286bed1545d --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/package.json @@ -0,0 +1,48 @@ +{ + "name": "api-graphql", + "version": "0.1.0", + "scripts": { + "build": "yarn webiny run build", + "watch": "yarn webiny run watch" + }, + "dependencies": { + "@webiny/api-aco": "latest", + "@webiny/api-apw": "latest", + "@webiny/api-apw-scheduler-so-ddb": "latest", + "@webiny/api-audit-logs": "latest", + "@webiny/api-file-manager": "latest", + "@webiny/api-file-manager-ddb": "latest", + "@webiny/api-file-manager-s3": "latest", + "@webiny/api-form-builder": "latest", + "@webiny/api-form-builder-so-ddb-es": "latest", + "@webiny/api-i18n": "latest", + "@webiny/api-i18n-ddb": "latest", + "@webiny/api-i18n-content": "latest", + "@webiny/api-headless-cms": "latest", + "@webiny/api-headless-cms-ddb-es": "latest", + "@webiny/api-page-builder": "latest", + "@webiny/api-page-builder-aco": "latest", + "@webiny/api-page-builder-so-ddb-es": "latest", + "@webiny/api-page-builder-import-export": "latest", + "@webiny/api-page-builder-import-export-so-ddb": "latest", + "@webiny/api-elasticsearch": "latest", + "@webiny/api-prerendering-service": "latest", + "@webiny/api-security": "latest", + "@webiny/api-security-so-ddb": "latest", + "@webiny/api-security-cognito": "latest", + "@webiny/api-admin-users": "latest", + "@webiny/api-admin-users-so-ddb": "latest", + "@webiny/api-tenancy": "latest", + "@webiny/api-tenancy-so-ddb": "latest", + "@webiny/api-tenant-manager": "latest", + "@webiny/api-wcp": "latest", + "@webiny/cli": "latest", + "@webiny/db-dynamodb": "latest", + "@webiny/handler-aws": "latest", + "@webiny/handler-client": "latest", + "@webiny/handler-db": "latest", + "@webiny/handler-graphql": "latest", + "@webiny/handler-logs": "latest", + "@webiny/project-utils": "latest" + } +} diff --git a/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/src/index.ts b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/src/index.ts new file mode 100644 index 00000000000..781ae150326 --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/src/index.ts @@ -0,0 +1,116 @@ +import { getDocumentClient } from "@webiny/aws-sdk/client-dynamodb"; +import { createHandler } from "@webiny/handler-aws"; +import graphqlPlugins from "@webiny/handler-graphql"; +import { createWcpContext, createWcpGraphQL } from "@webiny/api-wcp"; +import i18nPlugins from "@webiny/api-i18n/graphql"; +import i18nDynamoDbStorageOperations from "@webiny/api-i18n-ddb"; +import { + createPageBuilderContext, + createPageBuilderGraphQL +} from "@webiny/api-page-builder/graphql"; +import { createStorageOperations as createPageBuilderStorageOperations } from "@webiny/api-page-builder-so-ddb-es"; +import pageBuilderPrerenderingPlugins from "@webiny/api-page-builder/prerendering"; +import pageBuilderImportExportPlugins from "@webiny/api-page-builder-import-export/graphql"; +import { createStorageOperations as createPageBuilderImportExportStorageOperations } from "@webiny/api-page-builder-import-export-so-ddb"; +import prerenderingServicePlugins from "@webiny/api-prerendering-service-aws/client"; +import dbPlugins from "@webiny/handler-db"; +import { DynamoDbDriver } from "@webiny/db-dynamodb"; +import dynamoDbPlugins from "@webiny/db-dynamodb/plugins"; +import elasticsearchClientContext, { + createElasticsearchClient, + createGzipCompression +} from "@webiny/api-elasticsearch"; +import { createFileManagerContext, createFileManagerGraphQL } from "@webiny/api-file-manager"; +import { createFileManagerStorageOperations } from "@webiny/api-file-manager-ddb"; +import logsPlugins from "@webiny/handler-logs"; +import fileManagerS3 from "@webiny/api-file-manager-s3"; +import { createFormBuilder } from "@webiny/api-form-builder"; +import { createFormBuilderStorageOperations } from "@webiny/api-form-builder-so-ddb-es"; +import { createHeadlessCmsContext, createHeadlessCmsGraphQL } from "@webiny/api-headless-cms"; +import { createStorageOperations as createHeadlessCmsStorageOperations } from "@webiny/api-headless-cms-ddb-es"; +import { createAco } from "@webiny/api-aco"; +import { createAcoPageBuilderContext } from "@webiny/api-page-builder-aco"; +import securityPlugins from "./security"; +import tenantManager from "@webiny/api-tenant-manager"; +import { createAuditLogs } from "@webiny/api-audit-logs"; +/** + * APW + */ +import { createApwGraphQL, createApwPageBuilderContext } from "@webiny/api-apw"; +import { createStorageOperations as createApwSaStorageOperations } from "@webiny/api-apw-scheduler-so-ddb"; + +// Imports plugins created via scaffolding utilities. +import scaffoldsPlugins from "./plugins/scaffolds"; + +const debug = process.env.DEBUG === "true"; + +const documentClient = getDocumentClient(); + +const elasticsearchClient = createElasticsearchClient({ + endpoint: `https://${process.env.ELASTIC_SEARCH_ENDPOINT}` +}); + +export const handler = createHandler({ + plugins: [ + createWcpContext(), + createWcpGraphQL(), + dynamoDbPlugins(), + logsPlugins(), + graphqlPlugins({ debug }), + elasticsearchClientContext(elasticsearchClient), + dbPlugins({ + table: process.env.DB_TABLE, + driver: new DynamoDbDriver({ documentClient }) + }), + securityPlugins({ documentClient }), + tenantManager(), + i18nPlugins(), + i18nDynamoDbStorageOperations(), + createHeadlessCmsContext({ + storageOperations: createHeadlessCmsStorageOperations({ + documentClient, + elasticsearch: elasticsearchClient, + plugins: [] + }) + }), + createHeadlessCmsGraphQL(), + createFileManagerContext({ + storageOperations: createFileManagerStorageOperations({ + documentClient + }) + }), + createFileManagerGraphQL(), + fileManagerS3(), + prerenderingServicePlugins({ + eventBus: String(process.env.EVENT_BUS) + }), + createPageBuilderContext({ + storageOperations: createPageBuilderStorageOperations({ + documentClient, + elasticsearch: elasticsearchClient, + plugins: [] + }) + }), + createPageBuilderGraphQL(), + pageBuilderPrerenderingPlugins(), + pageBuilderImportExportPlugins({ + storageOperations: createPageBuilderImportExportStorageOperations({ documentClient }) + }), + createFormBuilder({ + storageOperations: createFormBuilderStorageOperations({ + documentClient, + elasticsearch: elasticsearchClient + }) + }), + createGzipCompression(), + createApwGraphQL(), + createApwPageBuilderContext({ + storageOperations: createApwSaStorageOperations({ documentClient }) + }), + createAco(), + createAcoPageBuilderContext(), + createAuditLogs(), + scaffoldsPlugins() + ], + debug +}); diff --git a/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/src/plugins/scaffolds/index.ts b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/src/plugins/scaffolds/index.ts new file mode 100644 index 00000000000..be7d9a84514 --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/src/plugins/scaffolds/index.ts @@ -0,0 +1,3 @@ +// This file is automatically updated via various scaffolding utilities. + +export default () => []; diff --git a/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/src/security.ts b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/src/security.ts new file mode 100644 index 00000000000..0a8a480cdb0 --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/src/security.ts @@ -0,0 +1,101 @@ +import { DynamoDBClient } from "@webiny/aws-sdk/client-dynamodb"; +import { createTenancyContext, createTenancyGraphQL } from "@webiny/api-tenancy"; +import { createStorageOperations as tenancyStorageOperations } from "@webiny/api-tenancy-so-ddb"; +import { createSecurityContext, createSecurityGraphQL } from "@webiny/api-security"; +import { createStorageOperations as securityStorageOperations } from "@webiny/api-security-so-ddb"; +import { authenticateUsingHttpHeader } from "@webiny/api-security/plugins/authenticateUsingHttpHeader"; +import apiKeyAuthentication from "@webiny/api-security/plugins/apiKeyAuthentication"; +import apiKeyAuthorization from "@webiny/api-security/plugins/apiKeyAuthorization"; +import tenantLinkAuthorization from "@webiny/api-security/plugins/tenantLinkAuthorization"; +import cognitoAuthentication, { syncWithCognito } from "@webiny/api-security-cognito"; +import anonymousAuthorization from "@webiny/api-security/plugins/anonymousAuthorization"; +import createAdminUsersApp from "@webiny/api-admin-users"; +import { createStorageOperations as createAdminUsersStorageOperations } from "@webiny/api-admin-users-so-ddb"; + +export default ({ documentClient }: { documentClient: DynamoDBClient }) => [ + /** + * Create Tenancy app in the `context`. + */ + createTenancyContext({ + storageOperations: tenancyStorageOperations({ documentClient }) + }), + + /** + * Expose tenancy GraphQL schema. + */ + createTenancyGraphQL(), + + /** + * Create Security app in the `context`. + */ + createSecurityContext({ + storageOperations: securityStorageOperations({ documentClient }) + }), + + /** + * Expose security GraphQL schema. + */ + createSecurityGraphQL(), + + /** + * Create Admin Users app. + */ + createAdminUsersApp({ + storageOperations: createAdminUsersStorageOperations({ documentClient }) + }), + + /** + * Sync Admin Users with Cognito User Pool. + */ + syncWithCognito({ + region: String(process.env.COGNITO_REGION), + userPoolId: String(process.env.COGNITO_USER_POOL_ID) + }), + + /** + * Perform authentication using the common "Authorization" HTTP header. + * This will fetch the value of the header, and execute the authentication process. + */ + authenticateUsingHttpHeader(), + + /** + * API Key authenticator. + * API Keys are a standalone entity, and are not connected to users in any way. + * They identify a project, a 3rd party client, not a particular user. + * They are used for programmatic API access, CMS data import/export, etc. + */ + apiKeyAuthentication({ identityType: "api-key" }), + + /** + * Cognito authentication plugin. + * This plugin will verify the JWT token against the provided User Pool. + */ + cognitoAuthentication({ + region: String(process.env.COGNITO_REGION), + userPoolId: String(process.env.COGNITO_USER_POOL_ID), + identityType: "admin" + }), + + /** + * Authorization plugin to fetch permissions for a verified API key. + * The "identityType" must match the authentication plugin used to load the identity. + */ + apiKeyAuthorization({ identityType: "api-key" }), + + /** + * Authorization plugin to fetch permissions from a security role or team associated with the identity. + */ + tenantLinkAuthorization({ identityType: "admin" }), + + /** + * Authorization plugin to fetch permissions from the parent tenant. + */ + tenantLinkAuthorization({ identityType: "admin", parent: true }), + + /** + * Authorization plugin to load permissions for anonymous requests. + * This allows you to control which API resources can be accessed publicly. + * The authorization is performed by loading permissions from the "anonymous" user group. + */ + anonymousAuthorization() +]; diff --git a/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/src/types.ts b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/src/types.ts new file mode 100644 index 00000000000..b10411e4512 --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/src/types.ts @@ -0,0 +1,34 @@ +import { ClientContext } from "@webiny/handler-client/types"; +import { ElasticsearchContext } from "@webiny/api-elasticsearch/types"; +import { TenancyContext } from "@webiny/api-tenancy/types"; +import { SecurityContext } from "@webiny/api-security/types"; +import { I18NContext } from "@webiny/api-i18n/types"; +import { I18NContentContext } from "@webiny/api-i18n-content/types"; +import { PbContext } from "@webiny/api-page-builder/graphql/types"; +import { PrerenderingServiceClientContext } from "@webiny/api-prerendering-service/client/types"; +import { FileManagerContext } from "@webiny/api-file-manager/types"; +import { FormBuilderContext } from "@webiny/api-form-builder/types"; +import { CmsContext } from "@webiny/api-headless-cms/types"; +import { AcoContext } from "@webiny/api-aco/types"; +import { PbAcoContext } from "@webiny/api-page-builder-aco/types"; + +// When working with the `context` object (for example while defining a new GraphQL resolver function), +// you can import this interface and assign it to it. This will give you full autocomplete functionality +// and type safety. The easiest way to import it would be via the following import statement: +// import { Context } from "~/types"; +// Feel free to extend it with additional context interfaces, if needed. Also, please do not change the +// name of the interface, as existing scaffolding utilities may rely on it during the scaffolding process. +export interface Context + extends ClientContext, + ElasticsearchContext, + TenancyContext, + SecurityContext, + I18NContext, + I18NContentContext, + PbContext, + PrerenderingServiceClientContext, + FileManagerContext, + FormBuilderContext, + AcoContext, + PbAcoContext, + CmsContext {} diff --git a/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/tsconfig.json b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/tsconfig.json new file mode 100644 index 00000000000..357dca51a00 --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig", + "include": ["src"], + "compilerOptions": { + "paths": { + "~/*": ["./src/*"] + }, + "baseUrl": "." + } +} diff --git a/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/webiny.config.ts b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/webiny.config.ts new file mode 100644 index 00000000000..af49be8a390 --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/apps/api/graphql/webiny.config.ts @@ -0,0 +1,8 @@ +import { createBuildFunction, createWatchFunction } from "@webiny/project-utils"; + +export default { + commands: { + build: createBuildFunction({ cwd: __dirname }), + watch: createWatchFunction({ cwd: __dirname }) + } +}; diff --git a/packages/cwp-template-aws/template/ddb-os/apps/api/webiny.application.ts b/packages/cwp-template-aws/template/ddb-os/apps/api/webiny.application.ts new file mode 100644 index 00000000000..c283159af33 --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/apps/api/webiny.application.ts @@ -0,0 +1,6 @@ +import { createApiApp } from "@webiny/serverless-cms-aws"; + +export default createApiApp({ + openSearch: true, + pulumiResourceNamePrefix: "wby-" +}); diff --git a/packages/cwp-template-aws/template/ddb-os/apps/core/webiny.application.ts b/packages/cwp-template-aws/template/ddb-os/apps/core/webiny.application.ts new file mode 100644 index 00000000000..f8f0cb5ec8d --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/apps/core/webiny.application.ts @@ -0,0 +1,6 @@ +import { createCoreApp } from "@webiny/serverless-cms-aws"; + +export default createCoreApp({ + openSearch: true, + pulumiResourceNamePrefix: "wby-" +}); diff --git a/packages/cwp-template-aws/template/ddb-os/dependencies.json b/packages/cwp-template-aws/template/ddb-os/dependencies.json new file mode 100644 index 00000000000..4dc141bec1a --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/dependencies.json @@ -0,0 +1,85 @@ +{ + "private": true, + "keywords": ["aws+dynamodb+elasticsearch"], + "dependencies": { + "@webiny/aws-layers": "latest", + "@webiny/cli": "latest", + "@webiny/cli-plugin-scaffold": "latest", + "@webiny/cli-plugin-scaffold-admin-app-module": "latest", + "@webiny/cli-plugin-scaffold-graphql-service": "latest", + "@webiny/cli-plugin-scaffold-ci": "latest", + "@webiny/cli-plugin-workspaces": "latest", + "@webiny/cli-plugin-deploy-pulumi": "latest", + "@webiny/project-utils": "latest", + "@webiny/serverless-cms-aws": "latest" + }, + "devDependencies": { + "@babel/cli": "^7.22.6", + "@babel/core": "^7.22.8", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.20.7", + "@babel/plugin-proposal-throw-expressions": "^7.22.5", + "@babel/plugin-transform-runtime": "^7.22.7", + "@babel/preset-env": "^7.22.7", + "@babel/preset-typescript": "^7.22.5", + "@types/jest": "^26.0.20", + "@types/node": "^16.0.0", + "@types/react": "17.0.39", + "@types/react-dom": "17.0.11", + "@typescript-eslint/eslint-plugin": "^5.5.0", + "@typescript-eslint/parser": "^5.5.0", + "babel-plugin-dynamic-import-node": "^2.3.3", + + "babel-plugin-module-resolver": "^4.1.0", + "chalk": "^4.1.0", + "cross-env": "^5.0.2", + "eslint": "^8.4.1", + "eslint-config-standard": "^16.0.3", + "eslint-import-resolver-babel-module": "^5.3.1", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jest": "^25.3.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^5.2.0", + "eslint-plugin-react": "^7.27.1", + "eslint-plugin-standard": "^5.0.0", + "execa": "^5.0.0", + "jest": "^29.5.0", + "merge": "^2.0.0", + "prettier": "^2.8.3", + "ts-jest": "^28.0.5", + "typescript": "4.7.4" + }, + "workspaces": { + "packages": [ + "apps/admin", + "apps/website", + "apps/theme", + "apps/api/graphql", + "apps/api/headlessCMS", + "packages/*" + ] + }, + "scripts": { + "test": "jest --config jest.config.js --passWithNoTests", + "test:unit": "cross-env TEST_TYPE=unit yarn test", + "test:integration": "cross-env TEST_TYPE=integration yarn test", + "test:e2e": "cross-env TEST_TYPE=e2e yarn test", + "eslint": "eslint \"**/*.{js,jsx,ts,tsx}\" --max-warnings=0", + "eslint:fix": "yarn eslint --fix", + "prettier": "prettier \"**/**/*.{js,jsx,ts,tsx,json}\" --config .prettierrc.js", + "prettier:check": "yarn prettier --check", + "prettier:fix": "yarn prettier --write", + "setup-project": "node ./scripts/setupProject.js", + "setup-env-files": "node ./scripts/setupEnvFiles.js", + "link-workspaces": "node ./scripts/linkWorkspaces.js", + "postinstall": "yarn link-workspaces" + }, + "resolutions": { + "@emotion/react": "11.10.8", + "@types/react": "17.0.39", + "react": "17.0.2", + "typescript": "4.7.4", + "react-dom": "17.0.2", + "codex-tooltip": "1.0.2" + } +} diff --git a/packages/cwp-template-aws/template/ddb-os/example.env b/packages/cwp-template-aws/template/ddb-os/example.env new file mode 100644 index 00000000000..b994228d434 --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/example.env @@ -0,0 +1,13 @@ +# The region into which your project will be deployed. +AWS_REGION={REGION} + +# Set secrets provider. +# See https://www.pulumi.com/docs/intro/concepts/secrets/#changing-the-secrets-provider-for-a-stack. +PULUMI_SECRETS_PROVIDER={PULUMI_SECRETS_PROVIDER} + +# Used with "passphrase" secrets provider. +# See https://www.pulumi.com/docs/reference/cli/environment-variables/. +PULUMI_CONFIG_PASSPHRASE={PULUMI_CONFIG_PASSPHRASE} + +# Enable debugging mode. +DEBUG=true \ No newline at end of file diff --git a/packages/cwp-template-aws/template/ddb-os/example.keep.env b/packages/cwp-template-aws/template/ddb-os/example.keep.env new file mode 100644 index 00000000000..b994228d434 --- /dev/null +++ b/packages/cwp-template-aws/template/ddb-os/example.keep.env @@ -0,0 +1,13 @@ +# The region into which your project will be deployed. +AWS_REGION={REGION} + +# Set secrets provider. +# See https://www.pulumi.com/docs/intro/concepts/secrets/#changing-the-secrets-provider-for-a-stack. +PULUMI_SECRETS_PROVIDER={PULUMI_SECRETS_PROVIDER} + +# Used with "passphrase" secrets provider. +# See https://www.pulumi.com/docs/reference/cli/environment-variables/. +PULUMI_CONFIG_PASSPHRASE={PULUMI_CONFIG_PASSPHRASE} + +# Enable debugging mode. +DEBUG=true \ No newline at end of file diff --git a/packages/pulumi-aws/package.json b/packages/pulumi-aws/package.json index d856179c411..1d3df0cb194 100644 --- a/packages/pulumi-aws/package.json +++ b/packages/pulumi-aws/package.json @@ -15,6 +15,7 @@ "dependencies": { "@pulumi/aws": "^5.8.0", "@pulumi/pulumi": "^3.34.0", + "@pulumi/random": "^3.0.0", "@webiny/aws-sdk": "0.0.0", "@webiny/cli-plugin-deploy-pulumi": "0.0.0", "@webiny/pulumi": "0.0.0", diff --git a/packages/pulumi-aws/src/apps/api/createApiPulumiApp.ts b/packages/pulumi-aws/src/apps/api/createApiPulumiApp.ts index af553dc351a..c026c448775 100644 --- a/packages/pulumi-aws/src/apps/api/createApiPulumiApp.ts +++ b/packages/pulumi-aws/src/apps/api/createApiPulumiApp.ts @@ -9,7 +9,8 @@ import { ApiMigration, ApiPageBuilder, CoreOutput, - VpcConfig + VpcConfig, + CreateCorePulumiAppParams } from "~/apps"; import { applyCustomDomain, CustomDomainParams } from "../customDomain"; import { tagResources, withCommonLambdaEnvVariables, addDomainsUrlsOutputs } from "~/utils"; @@ -29,6 +30,18 @@ export interface CreateApiPulumiAppParams { }> >; + /** + * Enables OpenSearch infrastructure. + * Note that it requires also changes in application code. + */ + openSearch?: PulumiAppParam< + | boolean + | Partial<{ + domainName: string; + indexPrefix: string; + }> + >; + /** * Enables or disables VPC for the API. * For VPC to work you also have to enable it in the Core application. @@ -63,15 +76,26 @@ export const createApiPulumiApp = (projectAppParams: CreateApiPulumiAppParams = path: "apps/api", config: projectAppParams, program: async app => { - if (projectAppParams.elasticSearch) { - const elasticSearch = app.getParam(projectAppParams.elasticSearch); - if (typeof elasticSearch === "object") { - if (elasticSearch.domainName) { - process.env.AWS_ELASTIC_SEARCH_DOMAIN_NAME = elasticSearch.domainName; + let searchEngineParams: + | CreateCorePulumiAppParams["openSearch"] + | CreateCorePulumiAppParams["elasticSearch"] + | null = null; + + if (projectAppParams.openSearch) { + searchEngineParams = app.getParam(projectAppParams.openSearch); + } else if (projectAppParams.elasticSearch) { + searchEngineParams = app.getParam(projectAppParams.elasticSearch); + } + + if (searchEngineParams) { + const params = app.getParam(searchEngineParams); + if (typeof params === "object") { + if (params.domainName) { + process.env.AWS_ELASTIC_SEARCH_DOMAIN_NAME = params.domainName; } - if (elasticSearch.indexPrefix) { - process.env.ELASTIC_SEARCH_INDEX_PREFIX = elasticSearch.indexPrefix; + if (params.indexPrefix) { + process.env.ELASTIC_SEARCH_INDEX_PREFIX = params.indexPrefix; } } } diff --git a/packages/pulumi-aws/src/apps/core/CoreOpenSearch.ts b/packages/pulumi-aws/src/apps/core/CoreOpenSearch.ts new file mode 100644 index 00000000000..8c76e95cb3a --- /dev/null +++ b/packages/pulumi-aws/src/apps/core/CoreOpenSearch.ts @@ -0,0 +1,311 @@ +import path from "path"; +import * as pulumi from "@pulumi/pulumi"; +import * as aws from "@pulumi/aws"; +import * as random from "@pulumi/random"; +import { + createAppModule, + PulumiApp, + PulumiAppResource, + PulumiAppResourceConstructor, + PulumiAppRemoteResource +} from "@webiny/pulumi"; + +import { getAwsAccountId } from "../awsUtils"; +import { CoreVpc } from "./CoreVpc"; + +export interface OpenSearchParams { + protect: boolean; +} + +function getDevClusterConfig(): aws.types.input.opensearch.DomainClusterConfig { + return { + instanceType: "t3.small.search" + }; +} + +function getProdClusterConfig(): aws.types.input.opensearch.DomainClusterConfig { + return { + // For production deployments, we create 2 instances and configure multi-AZ. + instanceType: "t3.medium.search", + instanceCount: 2, + zoneAwarenessEnabled: true, + zoneAwarenessConfig: { + availabilityZoneCount: 2 + } + }; +} + +const OS_ENGINE_VERSION = "OpenSearch_2.11"; + +export const OpenSearch = createAppModule({ + name: "OpenSearch", + config(app, params: OpenSearchParams) { + const productionEnvironments = app.params.create.productionEnvironments || ["prod"]; + const isProduction = productionEnvironments.includes(app.params.run.env); + + const vpc = app.getModule(CoreVpc, { optional: true }); + + // This needs to be implemented in order to be able to use a shared OpenSearch cluster. + let domain: + | PulumiAppResource> + | PulumiAppRemoteResource; + + let domainPolicy; + + if (process.env.AWS_ELASTIC_SEARCH_DOMAIN_NAME) { + const domainName = String(process.env.AWS_ELASTIC_SEARCH_DOMAIN_NAME); + // This can be useful for testing purposes in ephemeral environments. More information here: + // https://www.webiny.com/docs/key-topics/ci-cd/testing/slow-ephemeral-environments + domain = app.addRemoteResource(domainName, () => { + return aws.opensearch.getDomain({ domainName }, { async: true }); + }); + } else { + const randomId = new random.RandomId("osDomainRandomId", { byteLength: 8 }); + const namePrefix = app.getParam(app.params.create.pulumiResourceNamePrefix) || ""; + + const domainLogicalName = "webiny-js"; + const domainPhysicalName = randomId.hex.apply((hex: string) => { + return `${namePrefix}${domainLogicalName}-${hex.slice(-7)}`; + }); + + domain = app.addResource(aws.opensearch.Domain, { + name: domainLogicalName, + config: { + domainName: domainPhysicalName, + engineVersion: OS_ENGINE_VERSION, + clusterConfig: isProduction ? getProdClusterConfig() : getDevClusterConfig(), + vpcOptions: vpc + ? { + subnetIds: vpc.subnets.private.map(s => s.output.id), + securityGroupIds: [vpc.vpc.output.defaultSecurityGroupId] + } + : undefined, + ebsOptions: { + ebsEnabled: true, + volumeSize: 10, + volumeType: "gp2" + }, + advancedOptions: { + "rest.action.multi.allow_explicit_index": "true" + }, + snapshotOptions: { + automatedSnapshotStartHour: 23 + } + }, + opts: { protect: params.protect } + }); + + /** + * Domain policy defines who can access your OpenSearch Domain. + * For details on OpenSearch security, read the official documentation: + * https://docs.aws.amazon.com/openSearch-service/latest/developerguide/security.html + */ + const accountId = getAwsAccountId(app); + + domainPolicy = app.addResource(aws.opensearch.DomainPolicy, { + name: `${domainLogicalName}-policy`, + config: { + domainName: domain.output.domainName, + accessPolicies: pulumi + .all([accountId, domain.output.arn]) + .apply(([accountId, domainArn]) => { + return JSON.stringify({ + Version: "2012-10-17", + Statement: [ + /** + * Allow requests signed with current account + */ + { + Effect: "Allow", + Principal: { + AWS: accountId + }, + Action: "es:*", + Resource: `${domainArn}/*` + } + ] + }); + }) + }, + opts: { protect: params.protect } + }); + } + + /** + * Create a table for OpenSearch records. All ES records are stored in this table to dramatically improve + * performance and stability on write operations (especially massive data imports). This table also serves as a backup and + * a single source of truth for your OpenSearch domain. Streaming is enabled on this table, and it will + * allow asynchronous synchronization of data with OpenSearch domain. + */ + const table = app.addResource(aws.dynamodb.Table, { + name: "webiny-es", + config: { + attributes: [ + { name: "PK", type: "S" }, + { name: "SK", type: "S" } + ], + streamEnabled: true, + streamViewType: "NEW_AND_OLD_IMAGES", + billingMode: "PAY_PER_REQUEST", + hashKey: "PK", + rangeKey: "SK" + }, + opts: { protect: params.protect } + }); + + const roleName = "dynamo-to-elastic-lambda-role"; + + const role = app.addResource(aws.iam.Role, { + name: roleName, + config: { + assumeRolePolicy: { + Version: "2012-10-17", + Statement: [ + { + Action: "sts:AssumeRole", + Principal: { + Service: "lambda.amazonaws.com" + }, + Effect: "Allow" + } + ] + } + }, + meta: { isLambdaFunctionRole: true } + }); + + const policy = getDynamoDbToElasticLambdaPolicy(app, domain.output); + + app.addResource(aws.iam.RolePolicyAttachment, { + name: `${roleName}-DynamoDbToElasticLambdaPolicy`, + config: { + role: role.output, + policyArn: policy.output.arn + } + }); + + // Only use `AWSLambdaVPCAccessExecutionRole` policy if VPC feature is enabled. + if (vpc) { + app.addResource(aws.iam.RolePolicyAttachment, { + name: `${roleName}-AWSLambdaVPCAccessExecutionRole`, + config: { + role: role.output, + policyArn: aws.iam.ManagedPolicy.AWSLambdaVPCAccessExecutionRole + } + }); + } else { + app.addResource(aws.iam.RolePolicyAttachment, { + name: `${roleName}-AWSLambdaBasicExecutionRole`, + config: { + role: role.output, + policyArn: aws.iam.ManagedPolicy.AWSLambdaBasicExecutionRole + } + }); + } + + app.addResource(aws.iam.RolePolicyAttachment, { + name: `${roleName}-AWSLambdaDynamoDBExecutionRole`, + config: { + role: role.output, + policyArn: aws.iam.ManagedPolicy.AWSLambdaDynamoDBExecutionRole + } + }); + + /** + * This Lambda will process the stream events from DynamoDB table that contains OpenSearch items. + * OpenSearch can't take large amount of individual writes in a short period of time, so this way + * we store data for OpenSearch in a DynamoDB table, and asynchronously insert it into OpenSearch + * using batching. + */ + const lambda = app.addResource(aws.lambda.Function, { + name: "dynamo-to-elastic", + config: { + role: role.output.arn, + runtime: "nodejs14.x", + handler: "handler.handler", + timeout: 600, + memorySize: 512, + environment: { + variables: { + DEBUG: String(process.env.DEBUG), + ELASTIC_SEARCH_ENDPOINT: domain.output.endpoint + } + }, + description: "Process DynamoDB Stream.", + code: new pulumi.asset.AssetArchive({ + ".": new pulumi.asset.FileArchive( + path.join(app.paths.workspace, "dynamoToElastic/build") + ) + }), + vpcConfig: vpc + ? { + subnetIds: vpc.subnets.private.map(s => s.output.id), + securityGroupIds: [vpc.vpc.output.defaultSecurityGroupId] + } + : undefined + } + }); + + const eventSourceMapping = app.addResource(aws.lambda.EventSourceMapping, { + name: "dynamo-to-elastic", + config: { + eventSourceArn: table.output.streamArn, + functionName: lambda.output.arn, + startingPosition: "LATEST", + maximumRetryAttempts: 3, + batchSize: 1000, + maximumBatchingWindowInSeconds: 1 + } + }); + + app.addOutputs({ + elasticsearchDomainArn: domain.output.arn, + elasticsearchDomainEndpoint: domain.output.endpoint, + elasticsearchDynamodbTableArn: table.output.arn, + elasticsearchDynamodbTableName: table.output.name + }); + + return { + domain, + domainPolicy, + table, + dynamoToElastic: { + role, + policy, + lambda, + eventSourceMapping + } + }; + } +}); + +function getDynamoDbToElasticLambdaPolicy( + app: PulumiApp, + domain: pulumi.Output +) { + return app.addResource(aws.iam.Policy, { + name: "DynamoDbToElasticLambdaPolicy-updated", + config: { + description: "This policy enables access to ES and Dynamodb streams", + policy: { + Version: "2012-10-17", + Statement: [ + { + Sid: "PermissionForES", + Effect: "Allow", + Action: [ + "es:ESHttpDelete", + "es:ESHttpPatch", + "es:ESHttpPost", + "es:ESHttpPut" + ], + Resource: [ + pulumi.interpolate`${domain.arn}`, + pulumi.interpolate`${domain.arn}/*` + ] + } + ] + } + } + }); +} diff --git a/packages/pulumi-aws/src/apps/core/createCorePulumiApp.ts b/packages/pulumi-aws/src/apps/core/createCorePulumiApp.ts index e5cab82f316..0245f2f7020 100644 --- a/packages/pulumi-aws/src/apps/core/createCorePulumiApp.ts +++ b/packages/pulumi-aws/src/apps/core/createCorePulumiApp.ts @@ -3,6 +3,7 @@ import { createPulumiApp, PulumiAppParam } from "@webiny/pulumi"; import { CoreCognito } from "./CoreCognito"; import { CoreDynamo } from "./CoreDynamo"; import { ElasticSearch } from "./CoreElasticSearch"; +import { OpenSearch } from "./CoreOpenSearch"; import { CoreEventBus } from "./CoreEventBus"; import { CoreFileManger } from "./CoreFileManager"; import { CoreVpc } from "./CoreVpc"; @@ -29,6 +30,18 @@ export interface CreateCorePulumiAppParams { }> >; + /** + * Enables OpenSearch infrastructure. + * Note that it requires also changes in application code. + */ + openSearch?: PulumiAppParam< + | boolean + | Partial<{ + domainName: string; + indexPrefix: string; + }> + >; + /** * Enables VPC for the application. * By default enabled in production environments. @@ -69,15 +82,29 @@ export function createCorePulumiApp(projectAppParams: CreateCorePulumiAppParams path: "apps/core", config: projectAppParams, program: async app => { - if (projectAppParams.elasticSearch) { - const elasticSearch = app.getParam(projectAppParams.elasticSearch); - if (typeof elasticSearch === "object") { - if (elasticSearch.domainName) { - process.env.AWS_ELASTIC_SEARCH_DOMAIN_NAME = elasticSearch.domainName; + let searchEngineType: "openSearch" | "elasticSearch" | null = null; + let searchEngineParams: + | CreateCorePulumiAppParams["openSearch"] + | CreateCorePulumiAppParams["elasticSearch"] + | null = null; + + if (projectAppParams.openSearch) { + searchEngineParams = app.getParam(projectAppParams.openSearch); + searchEngineType = "openSearch"; + } else if (projectAppParams.elasticSearch) { + searchEngineParams = app.getParam(projectAppParams.elasticSearch); + searchEngineType = "elasticSearch"; + } + + if (searchEngineParams) { + const params = app.getParam(searchEngineParams); + if (typeof params === "object") { + if (params.domainName) { + process.env.AWS_ELASTIC_SEARCH_DOMAIN_NAME = params.domainName; } - if (elasticSearch.indexPrefix) { - process.env.ELASTIC_SEARCH_INDEX_PREFIX = elasticSearch.indexPrefix; + if (params.indexPrefix) { + process.env.ELASTIC_SEARCH_INDEX_PREFIX = params.indexPrefix; } } } @@ -85,6 +112,7 @@ export function createCorePulumiApp(projectAppParams: CreateCorePulumiAppParams const pulumiResourceNamePrefix = app.getParam( projectAppParams.pulumiResourceNamePrefix ); + if (pulumiResourceNamePrefix) { app.onResource(resource => { if (!resource.name.startsWith(pulumiResourceNamePrefix)) { @@ -126,9 +154,12 @@ export function createCorePulumiApp(projectAppParams: CreateCorePulumiAppParams // Setup file core bucket const { bucket: fileManagerBucket } = app.addModule(CoreFileManger, { protect }); - const elasticSearch = app.getParam(projectAppParams?.elasticSearch) - ? app.addModule(ElasticSearch, { protect }) - : null; + let elasticSearch; + if (searchEngineType === "openSearch") { + elasticSearch = app.addModule(OpenSearch, { protect }); + } else if (searchEngineType === "elasticSearch") { + elasticSearch = app.addModule(ElasticSearch, { protect }); + } app.addOutputs({ region: aws.config.region, diff --git a/packages/serverless-cms-aws/src/createApiApp.ts b/packages/serverless-cms-aws/src/createApiApp.ts index 5b8cf72e8ba..90c45d4587d 100644 --- a/packages/serverless-cms-aws/src/createApiApp.ts +++ b/packages/serverless-cms-aws/src/createApiApp.ts @@ -21,7 +21,7 @@ export function createApiApp(projectAppParams: CreateApiAppParams = {}) { executeDataMigrations ]; - if (projectAppParams.elasticSearch) { + if (projectAppParams.elasticSearch || projectAppParams.openSearch) { builtInPlugins.push(generateDdbEsHandlers); } else { builtInPlugins.push(generateDdbHandlers); diff --git a/packages/serverless-cms-aws/src/createCoreApp.ts b/packages/serverless-cms-aws/src/createCoreApp.ts index fce9b4be866..d3fbe04ccb9 100644 --- a/packages/serverless-cms-aws/src/createCoreApp.ts +++ b/packages/serverless-cms-aws/src/createCoreApp.ts @@ -10,7 +10,7 @@ export interface CreateCoreAppParams extends CreateCorePulumiAppParams { export function createCoreApp(projectAppParams: CreateCoreAppParams = {}) { const builtInPlugins = []; - if (projectAppParams.elasticSearch) { + if (projectAppParams.elasticSearch || projectAppParams.openSearch) { builtInPlugins.push(generateDdbToEsHandler, checkEsServiceRole); } diff --git a/packages/serverless-cms-aws/src/enterprise/createApiApp.ts b/packages/serverless-cms-aws/src/enterprise/createApiApp.ts index 27cb8900a8b..bccdc1b75c8 100644 --- a/packages/serverless-cms-aws/src/enterprise/createApiApp.ts +++ b/packages/serverless-cms-aws/src/enterprise/createApiApp.ts @@ -20,7 +20,8 @@ export function createApiApp(projectAppParams: CreateApiAppParams = {}) { generateCommonHandlers, executeDataMigrations ]; - if (projectAppParams.elasticSearch) { + + if (projectAppParams.elasticSearch || projectAppParams.openSearch) { builtInPlugins.push(generateDdbEsHandlers); } else { builtInPlugins.push(generateDdbHandlers); diff --git a/packages/serverless-cms-aws/src/enterprise/createCoreApp.ts b/packages/serverless-cms-aws/src/enterprise/createCoreApp.ts index 79a7ceda935..49605d62c23 100644 --- a/packages/serverless-cms-aws/src/enterprise/createCoreApp.ts +++ b/packages/serverless-cms-aws/src/enterprise/createCoreApp.ts @@ -10,7 +10,7 @@ export interface CreateCoreAppParams extends CreateCorePulumiAppParams { export function createCoreApp(projectAppParams: CreateCoreAppParams = {}) { const builtInPlugins = []; - if (projectAppParams.elasticSearch) { + if (projectAppParams.elasticSearch || projectAppParams.openSearch) { builtInPlugins.push(generateDdbToEsHandler, checkEsServiceRole); } diff --git a/scripts/prepublishOnly/src/prepublishOnly.ts b/scripts/prepublishOnly/src/prepublishOnly.ts index 41dce5be03e..50c46ae9de6 100644 --- a/scripts/prepublishOnly/src/prepublishOnly.ts +++ b/scripts/prepublishOnly/src/prepublishOnly.ts @@ -126,8 +126,10 @@ class PackageLoader { const extraFiles: string[] = [ "packages/cwp-template-aws/template/ddb/dependencies.json", "packages/cwp-template-aws/template/ddb-es/dependencies.json", + "packages/cwp-template-aws/template/ddb-os/dependencies.json", "packages/cwp-template-aws/template/ddb/apps/api/graphql/package.json", "packages/cwp-template-aws/template/ddb-es/apps/api/graphql/package.json", + "packages/cwp-template-aws/template/ddb-os/apps/api/graphql/package.json", "packages/cwp-template-aws/template/common/apps/admin/package.json", "packages/cwp-template-aws/template/common/apps/theme/package.json", "packages/cwp-template-aws/template/common/apps/website/package.json" diff --git a/yarn.lock b/yarn.lock index f632a2818f9..f6b09b94e93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6388,6 +6388,16 @@ __metadata: languageName: node linkType: hard +"@grpc/grpc-js@npm:^1.2.7": + version: 1.9.12 + resolution: "@grpc/grpc-js@npm:1.9.12" + dependencies: + "@grpc/proto-loader": ^0.7.8 + "@types/node": ">=12.12.47" + checksum: 1788bdc7256b003261d5cfd6858fe21c06043742a5f512b9855df66998239d645e6eda1612d17dbffa19a7fcce950cd2ff661e9818ce67ca36198501020da06d + languageName: node + linkType: hard + "@grpc/grpc-js@npm:~1.3.8": version: 1.3.8 resolution: "@grpc/grpc-js@npm:1.3.8" @@ -6397,6 +6407,20 @@ __metadata: languageName: node linkType: hard +"@grpc/proto-loader@npm:^0.7.8": + version: 0.7.10 + resolution: "@grpc/proto-loader@npm:0.7.10" + dependencies: + lodash.camelcase: ^4.3.0 + long: ^5.0.0 + protobufjs: ^7.2.4 + yargs: ^17.7.2 + bin: + proto-loader-gen-types: build/bin/proto-loader-gen-types.js + checksum: 4987e23b57942c2363b6a6a106e63efae636666cefa348778dfafef2ff72da7343c8587667521cb1d52482827bcd001dd535bdc27065110af56d9c7c176334c9 + languageName: node + linkType: hard + "@humanwhocodes/config-array@npm:^0.11.8": version: 0.11.8 resolution: "@humanwhocodes/config-array@npm:0.11.8" @@ -9593,6 +9617,79 @@ __metadata: languageName: node linkType: hard +"@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2": + version: 1.1.2 + resolution: "@protobufjs/aspromise@npm:1.1.2" + checksum: 011fe7ef0826b0fd1a95935a033a3c0fd08483903e1aa8f8b4e0704e3233406abb9ee25350ec0c20bbecb2aad8da0dcea58b392bbd77d6690736f02c143865d2 + languageName: node + linkType: hard + +"@protobufjs/base64@npm:^1.1.2": + version: 1.1.2 + resolution: "@protobufjs/base64@npm:1.1.2" + checksum: 67173ac34de1e242c55da52c2f5bdc65505d82453893f9b51dc74af9fe4c065cf4a657a4538e91b0d4a1a1e0a0642215e31894c31650ff6e3831471061e1ee9e + languageName: node + linkType: hard + +"@protobufjs/codegen@npm:^2.0.4": + version: 2.0.4 + resolution: "@protobufjs/codegen@npm:2.0.4" + checksum: 59240c850b1d3d0b56d8f8098dd04787dcaec5c5bd8de186fa548de86b86076e1c50e80144b90335e705a044edf5bc8b0998548474c2a10a98c7e004a1547e4b + languageName: node + linkType: hard + +"@protobufjs/eventemitter@npm:^1.1.0": + version: 1.1.0 + resolution: "@protobufjs/eventemitter@npm:1.1.0" + checksum: 0369163a3d226851682f855f81413cbf166cd98f131edb94a0f67f79e75342d86e89df9d7a1df08ac28be2bc77e0a7f0200526bb6c2a407abbfee1f0262d5fd7 + languageName: node + linkType: hard + +"@protobufjs/fetch@npm:^1.1.0": + version: 1.1.0 + resolution: "@protobufjs/fetch@npm:1.1.0" + dependencies: + "@protobufjs/aspromise": ^1.1.1 + "@protobufjs/inquire": ^1.1.0 + checksum: 3fce7e09eb3f1171dd55a192066450f65324fd5f7cc01a431df01bb00d0a895e6bfb5b0c5561ce157ee1d886349c90703d10a4e11a1a256418ff591b969b3477 + languageName: node + linkType: hard + +"@protobufjs/float@npm:^1.0.2": + version: 1.0.2 + resolution: "@protobufjs/float@npm:1.0.2" + checksum: 5781e1241270b8bd1591d324ca9e3a3128d2f768077a446187a049e36505e91bc4156ed5ac3159c3ce3d2ba3743dbc757b051b2d723eea9cd367bfd54ab29b2f + languageName: node + linkType: hard + +"@protobufjs/inquire@npm:^1.1.0": + version: 1.1.0 + resolution: "@protobufjs/inquire@npm:1.1.0" + checksum: ca06f02eaf65ca36fb7498fc3492b7fc087bfcc85c702bac5b86fad34b692bdce4990e0ef444c1e2aea8c034227bd1f0484be02810d5d7e931c55445555646f4 + languageName: node + linkType: hard + +"@protobufjs/path@npm:^1.1.2": + version: 1.1.2 + resolution: "@protobufjs/path@npm:1.1.2" + checksum: 856eeb532b16a7aac071cacde5c5620df800db4c80cee6dbc56380524736205aae21e5ae47739114bf669ab5e8ba0e767a282ad894f3b5e124197cb9224445ee + languageName: node + linkType: hard + +"@protobufjs/pool@npm:^1.1.0": + version: 1.1.0 + resolution: "@protobufjs/pool@npm:1.1.0" + checksum: d6a34fbbd24f729e2a10ee915b74e1d77d52214de626b921b2d77288bd8f2386808da2315080f2905761527cceffe7ec34c7647bd21a5ae41a25e8212ff79451 + languageName: node + linkType: hard + +"@protobufjs/utf8@npm:^1.1.0": + version: 1.1.0 + resolution: "@protobufjs/utf8@npm:1.1.0" + checksum: f9bf3163d13aaa3b6f5e6fbf37a116e094ea021c0e1f2a7ccd0e12a29e2ce08dafba4e8b36e13f8ed7397e1591610ce880ed1289af4d66cf4ace8a36a9557278 + languageName: node + linkType: hard + "@pulumi/aws@npm:^5.8.0": version: 5.29.1 resolution: "@pulumi/aws@npm:5.29.1" @@ -9607,6 +9704,30 @@ __metadata: languageName: node linkType: hard +"@pulumi/pulumi@npm:^2.15.0": + version: 2.25.2 + resolution: "@pulumi/pulumi@npm:2.25.2" + dependencies: + "@grpc/grpc-js": ^1.2.7 + "@logdna/tail-file": ^2.0.6 + "@pulumi/query": ^0.3.0 + google-protobuf: ^3.5.0 + js-yaml: ^3.14.0 + minimist: ^1.2.0 + normalize-package-data: ^2.4.0 + protobufjs: ^6.8.6 + read-package-tree: ^5.3.1 + require-from-string: ^2.0.1 + semver: ^6.1.0 + source-map-support: ^0.4.16 + split2: ^3.2.2 + ts-node: ^7.0.1 + typescript: ~3.7.3 + upath: ^1.1.0 + checksum: 3780e44740815a68f8ecc6221dd931f065107f15036d5405130ab8e86151089b2a24e2dbfbb9ec3eb41704a95258f4f273c0f3d089cedb2d32160467ed1b5cfb + languageName: node + linkType: hard + "@pulumi/pulumi@npm:^3.0.0, @pulumi/pulumi@npm:^3.34.0": version: 3.54.0 resolution: "@pulumi/pulumi@npm:3.54.0" @@ -9645,6 +9766,15 @@ __metadata: languageName: node linkType: hard +"@pulumi/random@npm:^3.0.0": + version: 3.2.0 + resolution: "@pulumi/random@npm:3.2.0" + dependencies: + "@pulumi/pulumi": ^2.15.0 + checksum: 489485cb757fde37e5591658c61371722f4f5892cafcb15159cf4a483c5c654376d28963204178b6a6dbe945d6cc81daeb7fe47356f3af9bc19b6f000ed760d8 + languageName: node + linkType: hard + "@reach/router@npm:^1.2.1": version: 1.3.4 resolution: "@reach/router@npm:1.3.4" @@ -12480,6 +12610,13 @@ __metadata: languageName: node linkType: hard +"@types/long@npm:^4.0.1": + version: 4.0.2 + resolution: "@types/long@npm:4.0.2" + checksum: d16cde7240d834cf44ba1eaec49e78ae3180e724cd667052b194a372f350d024cba8dd3f37b0864931683dab09ca935d52f0c4c1687178af5ada9fc85b0635f4 + languageName: node + linkType: hard + "@types/lru-cache@npm:^5.1.0": version: 5.1.1 resolution: "@types/lru-cache@npm:5.1.1" @@ -12555,6 +12692,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:>=13.7.0": + version: 20.10.1 + resolution: "@types/node@npm:20.10.1" + dependencies: + undici-types: ~5.26.4 + checksum: 9dfdcd2496ce535dba0ae496985d6e991a8a5d70a180db3a94c947a2123d99318a95dce4aa2a192f7e57c3afa3fdb44d6fd63e18efd49568950d6c239dadcc39 + languageName: node + linkType: hard + "@types/node@npm:^18.0.0": version: 18.18.3 resolution: "@types/node@npm:18.18.3" @@ -17464,6 +17610,7 @@ __metadata: "@babel/runtime": ^7.22.6 "@pulumi/aws": ^5.8.0 "@pulumi/pulumi": ^3.34.0 + "@pulumi/random": ^3.0.0 "@webiny/api-page-builder": 0.0.0 "@webiny/aws-layers": 0.0.0 "@webiny/aws-sdk": 0.0.0 @@ -32836,6 +32983,13 @@ __metadata: languageName: node linkType: hard +"lodash.camelcase@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.camelcase@npm:4.3.0" + checksum: cb9227612f71b83e42de93eccf1232feeb25e705bdb19ba26c04f91e885bfd3dd5c517c4a97137658190581d3493ea3973072ca010aab7e301046d90740393d1 + languageName: node + linkType: hard + "lodash.clonedeep@npm:^4.5.0": version: 4.5.0 resolution: "lodash.clonedeep@npm:4.5.0" @@ -33128,6 +33282,20 @@ __metadata: languageName: node linkType: hard +"long@npm:^4.0.0": + version: 4.0.0 + resolution: "long@npm:4.0.0" + checksum: 16afbe8f749c7c849db1f4de4e2e6a31ac6e617cead3bdc4f9605cb703cd20e1e9fc1a7baba674ffcca57d660a6e5b53a9e236d7b25a295d3855cca79cc06744 + languageName: node + linkType: hard + +"long@npm:^5.0.0": + version: 5.2.3 + resolution: "long@npm:5.2.3" + checksum: 885ede7c3de4facccbd2cacc6168bae3a02c3e836159ea4252c87b6e34d40af819824b2d4edce330bfb5c4d6e8ce3ec5864bdcf9473fa1f53a4f8225860e5897 + languageName: node + linkType: hard + "longest@npm:^1.0.1": version: 1.0.1 resolution: "longest@npm:1.0.1" @@ -38011,6 +38179,50 @@ __metadata: languageName: node linkType: hard +"protobufjs@npm:^6.8.6": + version: 6.11.4 + resolution: "protobufjs@npm:6.11.4" + dependencies: + "@protobufjs/aspromise": ^1.1.2 + "@protobufjs/base64": ^1.1.2 + "@protobufjs/codegen": ^2.0.4 + "@protobufjs/eventemitter": ^1.1.0 + "@protobufjs/fetch": ^1.1.0 + "@protobufjs/float": ^1.0.2 + "@protobufjs/inquire": ^1.1.0 + "@protobufjs/path": ^1.1.2 + "@protobufjs/pool": ^1.1.0 + "@protobufjs/utf8": ^1.1.0 + "@types/long": ^4.0.1 + "@types/node": ">=13.7.0" + long: ^4.0.0 + bin: + pbjs: bin/pbjs + pbts: bin/pbts + checksum: b2fc6a01897b016c2a7e43a854ab4a3c57080f61be41e552235436e7a730711b8e89e47cb4ae52f0f065b5ab5d5989fc932f390337ce3a8ccf07203415700850 + languageName: node + linkType: hard + +"protobufjs@npm:^7.2.4": + version: 7.2.5 + resolution: "protobufjs@npm:7.2.5" + dependencies: + "@protobufjs/aspromise": ^1.1.2 + "@protobufjs/base64": ^1.1.2 + "@protobufjs/codegen": ^2.0.4 + "@protobufjs/eventemitter": ^1.1.0 + "@protobufjs/fetch": ^1.1.0 + "@protobufjs/float": ^1.0.2 + "@protobufjs/inquire": ^1.1.0 + "@protobufjs/path": ^1.1.2 + "@protobufjs/pool": ^1.1.0 + "@protobufjs/utf8": ^1.1.0 + "@types/node": ">=13.7.0" + long: ^5.0.0 + checksum: 3770a072114061faebbb17cfd135bc4e187b66bc6f40cd8bac624368b0270871ec0cfb43a02b9fb4f029c8335808a840f1afba3c2e7ede7063b98ae6b98a703f + languageName: node + linkType: hard + "protocols@npm:^1.4.0": version: 1.4.8 resolution: "protocols@npm:1.4.8" @@ -41780,6 +41992,15 @@ __metadata: languageName: node linkType: hard +"source-map-support@npm:^0.4.16": + version: 0.4.18 + resolution: "source-map-support@npm:0.4.18" + dependencies: + source-map: ^0.5.6 + checksum: 669aa7e992fec586fac0ba9a8dea8ce81b7328f92806335f018ffac5709afb2920e3870b4e56c68164282607229f04b8bbcf5d0e5c845eb1b5119b092e7585c0 + languageName: node + linkType: hard + "source-map-support@npm:^0.5.16, source-map-support@npm:^0.5.21, source-map-support@npm:^0.5.6, source-map-support@npm:~0.5.12, source-map-support@npm:~0.5.20": version: 0.5.21 resolution: "source-map-support@npm:0.5.21" @@ -41942,7 +42163,7 @@ __metadata: languageName: node linkType: hard -"split2@npm:^3.0.0": +"split2@npm:^3.0.0, split2@npm:^3.2.2": version: 3.2.2 resolution: "split2@npm:3.2.2" dependencies: