├── .eslintrc.json ├── .gitattributes ├── .github ├── pull_request_template.md └── workflows │ ├── auto-approve.yml │ ├── build.yml │ ├── pull-request-lint.yml │ ├── release.yml │ ├── upgrade-cdklabs-projen-project-types-main.yml │ ├── upgrade-dev-deps-main.yml │ └── upgrade-main.yml ├── .gitignore ├── .mergify.yml ├── .npmignore ├── .prettierignore ├── .prettierrc.json ├── .projen ├── deps.json ├── files.json └── tasks.json ├── .projenrc.ts ├── API.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── UPGRADING.md ├── package.json ├── rosetta └── default.ts-fixture ├── src ├── amazonrdsforpostgresql │ ├── destination.ts │ ├── index.ts │ ├── profile.ts │ └── type.ts ├── asana │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ └── type.ts ├── core │ ├── appflow-permissions-manager.ts │ ├── connectors │ │ ├── connection-mode.ts │ │ ├── connector-authentication-type.ts │ │ ├── connector-profile.ts │ │ ├── connector-type.ts │ │ ├── index.ts │ │ └── oauth2-granttype.ts │ ├── error-handling.ts │ ├── flows │ │ ├── flow-base.ts │ │ ├── flow-time-updater │ │ │ ├── api.ts │ │ │ ├── flow-time-updater-function.ts │ │ │ ├── flow-time-updater.lambda.ts │ │ │ ├── flow-time-updater.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── on-demand-flow.ts │ │ ├── on-event-flow.ts │ │ ├── on-schedule-flow.ts │ │ └── triggered-flow-base.ts │ ├── index.ts │ ├── s3-location.ts │ ├── tasks │ │ ├── field.ts │ │ ├── filters.ts │ │ ├── index.ts │ │ ├── mappings.ts │ │ ├── operation.ts │ │ ├── tasks.ts │ │ ├── transforms.ts │ │ └── validations.ts │ ├── vertices │ │ ├── destination.ts │ │ ├── index.ts │ │ ├── source.ts │ │ └── vertex.ts │ └── write-operation.ts ├── eventbridge │ ├── destination.ts │ ├── events.ts │ ├── index.ts │ └── type.ts ├── googleads │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ ├── type.ts │ └── util.ts ├── googleanalytics4 │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ ├── type.ts │ └── util.ts ├── googlebigquery │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ ├── type.ts │ └── util.ts ├── hubspot │ ├── destination.ts │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ ├── type.ts │ └── util.ts ├── index.ts ├── jdbcsmalldatascale │ ├── destination.ts │ ├── driver.ts │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ └── type.ts ├── mailchimp │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ ├── type.ts │ └── util.ts ├── marketo │ ├── README.md │ ├── destination.ts │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ ├── type.ts │ └── util.ts ├── microsoftdynamics365 │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ ├── type.ts │ └── util.ts ├── microsoftsharepointonline │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ ├── type.ts │ └── util.ts ├── redshift │ ├── destination.ts │ ├── index.ts │ ├── profile.ts │ └── type.ts ├── s3 │ ├── destination.ts │ ├── index.ts │ ├── source.ts │ └── type.ts ├── salesforce-marketing-cloud │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ ├── type.ts │ └── util.ts ├── salesforce │ ├── destination.ts │ ├── index.ts │ ├── profile.ts │ ├── salesforce-data-transfer-api.ts │ ├── source.ts │ └── type.ts ├── sapodata │ ├── destination.ts │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ └── type.ts ├── servicenow │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ ├── type.ts │ └── util.ts ├── slack │ ├── README.md │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ ├── type.ts │ └── util.ts ├── snowflake │ ├── README.md │ ├── destination.ts │ ├── index.ts │ ├── profile.ts │ └── type.ts └── zendesk │ ├── destination.ts │ ├── index.ts │ ├── profile.ts │ ├── source.ts │ ├── type.ts │ └── util.ts ├── test ├── asana │ ├── profile.test.ts │ └── source.test.ts ├── core │ └── flows │ │ ├── flow-time-updater │ │ └── flow-time-updater-function.test.ts │ │ ├── on-demand-flow-metrics.test.ts │ │ ├── on-demand-flow.test.ts │ │ ├── on-event-flow.test.ts │ │ └── on-schedule-flow.test.ts ├── googleads │ ├── profile.test.ts │ └── source.test.ts ├── googlebigquery │ ├── profile.test.ts │ └── source.test.ts ├── hubspot │ ├── destination.test.ts │ ├── profile.test.ts │ └── source.test.ts ├── integ │ ├── ondemand-asana-to-s3.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── ondemand-asana-to-s3.integ.ts │ ├── ondemand-googleanalytics4-to-s3.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── ondemand-googleanalytics4-to-s3.integ.ts │ ├── ondemand-hubspot-to-s3.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── ondemand-hubspot-to-s3.integ.ts │ ├── ondemand-jdbcsmalldatascale-to-amazonrdsforpostgresql.integ.snapshot │ │ ├── TestStack.assets.json │ │ ├── TestStack.template.json │ │ ├── cdk.out │ │ └── manifest.json │ ├── ondemand-jdbcsmalldatascale-to-amazonrdsforpostgresql.integ.ts │ ├── ondemand-jdbcsmalldatascale-to-s3.integ.snapshot │ │ ├── TestStack.assets.json │ │ ├── TestStack.template.json │ │ ├── cdk.out │ │ └── manifest.json │ ├── ondemand-jdbcsmalldatascale-to-s3.integ.ts │ ├── ondemand-mailchimp-to-s3.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── ondemand-mailchimp-to-s3.integ.ts │ ├── ondemand-microsoftdynamics365-to-s3.integ.snapshot │ │ ├── TestStack.assets.json │ │ ├── TestStack.template.json │ │ ├── asset.b7f33614a69548d6bafe224d751a7ef238cde19097415e553fe8b63a4c8fd8a6 │ │ │ └── index.js │ │ ├── cdk.out │ │ └── manifest.json │ ├── ondemand-microsoftdynamics365-to-s3.integ.ts │ ├── ondemand-microsoftsharepointonline-to-s3.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── ondemand-microsoftsharepointonline-to-s3.integ.ts │ ├── ondemand-s3-to-hubspot.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── ondemand-s3-to-hubspot.integ.ts │ ├── ondemand-s3-to-s3.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── ondemand-s3-to-s3.integ.ts │ ├── ondemand-s3-to-snowflake.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── ondemand-s3-to-snowflake.integ.ts │ ├── ondemand-salesforce-to-redshift.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── ondemand-salesforce-to-redshift.integ.ts │ ├── ondemand-salesforce-to-s3.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── ondemand-salesforce-to-s3.integ.ts │ ├── ondemand-sapodata-to-s3.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── ondemand-sapodata-to-s3.integ.ts │ ├── ondemand-slack-to-s3.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── ondemand-slack-to-s3.integ.ts │ ├── onevent-salesforce-to-eventbridge.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── onevent-salesforce-to-eventbridge.integ.ts │ ├── onschedule-s3-to-salesforce.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ ├── onschedule-s3-to-salesforce.integ.ts │ ├── onschedule-salesforce-marketing-cloud-to-s3.integ.snapshot │ │ ├── TestStack.assets.json │ │ └── TestStack.template.json │ └── onschedule-salesforce-marketing-cloud-to-s3.integ.ts ├── mailchimp │ ├── profile.test.ts │ └── source.test.ts ├── marketo │ ├── profile.test.ts │ └── source.test.ts ├── microsoftsharepointonline │ ├── profile.test.ts │ └── source.test.ts ├── s3 │ ├── destination.test.ts │ ├── s3.test.ts │ └── source.test.ts ├── salesforce │ ├── destination.test.ts │ ├── profile.test.ts │ └── source.test.ts ├── slack │ ├── profile.test.ts │ └── source.test.ts └── zendesk │ ├── profile.test.ts │ └── source.test.ts ├── tsconfig.dev.json └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | // ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | { 3 | "env": { 4 | "jest": true, 5 | "node": true 6 | }, 7 | "root": true, 8 | "plugins": [ 9 | "@typescript-eslint", 10 | "import" 11 | ], 12 | "parser": "@typescript-eslint/parser", 13 | "parserOptions": { 14 | "ecmaVersion": 2018, 15 | "sourceType": "module", 16 | "project": "./tsconfig.dev.json" 17 | }, 18 | "extends": [ 19 | "plugin:import/typescript", 20 | "plugin:prettier/recommended" 21 | ], 22 | "settings": { 23 | "import/parsers": { 24 | "@typescript-eslint/parser": [ 25 | ".ts", 26 | ".tsx" 27 | ] 28 | }, 29 | "import/resolver": { 30 | "node": {}, 31 | "typescript": { 32 | "project": "./tsconfig.dev.json", 33 | "alwaysTryTypes": true 34 | } 35 | } 36 | }, 37 | "ignorePatterns": [ 38 | "*.js", 39 | "*.d.ts", 40 | "node_modules/", 41 | "*.generated.ts", 42 | "coverage", 43 | "!.projenrc.ts", 44 | "!projenrc/**/*.ts" 45 | ], 46 | "rules": { 47 | "curly": [ 48 | "error", 49 | "multi-line", 50 | "consistent" 51 | ], 52 | "@typescript-eslint/no-require-imports": "error", 53 | "import/no-extraneous-dependencies": [ 54 | "error", 55 | { 56 | "devDependencies": [ 57 | "**/test/**", 58 | "**/build-tools/**", 59 | "src/core/flows/flow-time-updater/flow-time-updater.lambda.ts", 60 | ".projenrc.ts", 61 | "projenrc/**/*.ts" 62 | ], 63 | "optionalDependencies": false, 64 | "peerDependencies": true 65 | } 66 | ], 67 | "import/no-unresolved": [ 68 | "error" 69 | ], 70 | "import/order": [ 71 | "warn", 72 | { 73 | "groups": [ 74 | "builtin", 75 | "external" 76 | ], 77 | "alphabetize": { 78 | "order": "asc", 79 | "caseInsensitive": true 80 | } 81 | } 82 | ], 83 | "import/no-duplicates": [ 84 | "error" 85 | ], 86 | "no-shadow": [ 87 | "off" 88 | ], 89 | "@typescript-eslint/no-shadow": "error", 90 | "@typescript-eslint/no-floating-promises": "error", 91 | "no-return-await": [ 92 | "off" 93 | ], 94 | "@typescript-eslint/return-await": "error", 95 | "dot-notation": [ 96 | "error" 97 | ], 98 | "no-bitwise": [ 99 | "error" 100 | ], 101 | "@typescript-eslint/member-ordering": [ 102 | "error", 103 | { 104 | "default": [ 105 | "public-static-field", 106 | "public-static-method", 107 | "protected-static-field", 108 | "protected-static-method", 109 | "private-static-field", 110 | "private-static-method", 111 | "field", 112 | "constructor", 113 | "method" 114 | ] 115 | } 116 | ] 117 | }, 118 | "overrides": [ 119 | { 120 | "files": [ 121 | ".projenrc.ts" 122 | ], 123 | "rules": { 124 | "@typescript-eslint/no-require-imports": "off", 125 | "import/no-extraneous-dependencies": "off" 126 | } 127 | } 128 | ] 129 | } 130 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | * text=auto eol=lf 4 | *.snap linguist-generated 5 | /.eslintrc.json linguist-generated 6 | /.gitattributes linguist-generated 7 | /.github/pull_request_template.md linguist-generated 8 | /.github/workflows/auto-approve.yml linguist-generated 9 | /.github/workflows/build.yml linguist-generated 10 | /.github/workflows/pull-request-lint.yml linguist-generated 11 | /.github/workflows/release.yml linguist-generated 12 | /.github/workflows/upgrade-cdklabs-projen-project-types-main.yml linguist-generated 13 | /.github/workflows/upgrade-dev-deps-main.yml linguist-generated 14 | /.github/workflows/upgrade-main.yml linguist-generated 15 | /.gitignore linguist-generated 16 | /.mergify.yml linguist-generated 17 | /.npmignore linguist-generated 18 | /.prettierignore linguist-generated 19 | /.prettierrc.json linguist-generated 20 | /.projen/** linguist-generated 21 | /.projen/deps.json linguist-generated 22 | /.projen/files.json linguist-generated 23 | /.projen/tasks.json linguist-generated 24 | /API.md linguist-generated 25 | /LICENSE linguist-generated 26 | /package.json linguist-generated 27 | /src/core/flows/flow-time-updater/flow-time-updater-function.ts linguist-generated 28 | /tsconfig.dev.json linguist-generated 29 | /yarn.lock linguist-generated -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Fixes # -------------------------------------------------------------------------------- /.github/workflows/auto-approve.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: auto-approve 4 | on: 5 | pull_request_target: 6 | types: 7 | - labeled 8 | - opened 9 | - synchronize 10 | - reopened 11 | - ready_for_review 12 | jobs: 13 | approve: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | pull-requests: write 17 | if: contains(github.event.pull_request.labels.*.name, 'auto-approve') && (github.event.pull_request.user.login == 'cdklabs-automation' || github.event.pull_request.user.login == 'dependabot[bot]') 18 | steps: 19 | - uses: hmarr/auto-approve-action@v2.2.1 20 | with: 21 | github-token: ${{ secrets.GITHUB_TOKEN }} 22 | -------------------------------------------------------------------------------- /.github/workflows/pull-request-lint.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | name: pull-request-lint 4 | on: 5 | pull_request_target: 6 | types: 7 | - labeled 8 | - opened 9 | - synchronize 10 | - reopened 11 | - ready_for_review 12 | - edited 13 | merge_group: {} 14 | jobs: 15 | validate: 16 | name: Validate PR title 17 | runs-on: ubuntu-latest 18 | permissions: 19 | pull-requests: write 20 | if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') 21 | steps: 22 | - uses: amannn/action-semantic-pull-request@v5.4.0 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | with: 26 | types: |- 27 | feat 28 | fix 29 | chore 30 | requireScope: false 31 | -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | 3 | queue_rules: 4 | - name: default 5 | update_method: merge 6 | conditions: 7 | - "#approved-reviews-by>=1" 8 | - -label~=(do-not-merge) 9 | - status-success=build 10 | - status-success=package-js 11 | - status-success=package-java 12 | - status-success=package-python 13 | - status-success=package-dotnet 14 | - status-success=package-go 15 | merge_method: squash 16 | commit_message_template: |- 17 | {{ title }} (#{{ number }}) 18 | 19 | {{ body }} 20 | pull_request_rules: 21 | - name: Automatic merge on approval and successful build 22 | actions: 23 | delete_head_branch: {} 24 | queue: 25 | name: default 26 | conditions: 27 | - "#approved-reviews-by>=1" 28 | - -label~=(do-not-merge) 29 | - status-success=build 30 | - status-success=package-js 31 | - status-success=package-java 32 | - status-success=package-python 33 | - status-success=package-dotnet 34 | - status-success=package-go 35 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | /.projen/ 3 | /test-reports/ 4 | junit.xml 5 | /coverage/ 6 | permissions-backup.acl 7 | /dist/changelog.md 8 | /dist/version.txt 9 | /.mergify.yml 10 | /.prettierignore 11 | /.prettierrc.json 12 | /test/ 13 | /tsconfig.dev.json 14 | /src/ 15 | !/lib/ 16 | !/lib/**/*.js 17 | !/lib/**/*.d.ts 18 | dist 19 | /tsconfig.json 20 | /.github/ 21 | /.vscode/ 22 | /.idea/ 23 | /.projenrc.js 24 | tsconfig.tsbuildinfo 25 | /.eslintrc.json 26 | !.jsii 27 | !/assets/ 28 | test/integ/ondemand-asana-to-s3.integ.snapshot 29 | test/integ/ondemand-googleanalytics4-to-s3.integ.snapshot 30 | test/integ/ondemand-hubspot-to-s3.integ.snapshot 31 | test/integ/ondemand-jdbcsmalldatascale-to-amazonrdsforpostgresql.integ.snapshot 32 | test/integ/ondemand-jdbcsmalldatascale-to-s3.integ.snapshot 33 | test/integ/ondemand-mailchimp-to-s3.integ.snapshot 34 | test/integ/ondemand-microsoftdynamics365-to-s3.integ.snapshot 35 | test/integ/ondemand-microsoftsharepointonline-to-s3.integ.snapshot 36 | test/integ/ondemand-s3-to-hubspot.integ.snapshot 37 | test/integ/ondemand-s3-to-s3.integ.snapshot 38 | test/integ/ondemand-s3-to-snowflake.integ.snapshot 39 | test/integ/ondemand-salesforce-to-redshift.integ.snapshot 40 | test/integ/ondemand-salesforce-to-s3.integ.snapshot 41 | test/integ/ondemand-sapodata-to-s3.integ.snapshot 42 | test/integ/ondemand-slack-to-s3.integ.snapshot 43 | test/integ/onevent-salesforce-to-eventbridge.integ.snapshot 44 | test/integ/onschedule-s3-to-salesforce.integ.snapshot 45 | test/integ/.tmp 46 | test/integ/onschedule-salesforce-marketing-cloud-to-s3.integ.snapshot 47 | /.gitattributes 48 | /.projenrc.ts 49 | /projenrc 50 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | src/core/flows/flow-time-updater/flow-time-updater-function.ts 3 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [] 3 | } 4 | -------------------------------------------------------------------------------- /.projen/files.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | ".eslintrc.json", 4 | ".gitattributes", 5 | ".github/pull_request_template.md", 6 | ".github/workflows/auto-approve.yml", 7 | ".github/workflows/build.yml", 8 | ".github/workflows/pull-request-lint.yml", 9 | ".github/workflows/release.yml", 10 | ".github/workflows/upgrade-cdklabs-projen-project-types-main.yml", 11 | ".github/workflows/upgrade-dev-deps-main.yml", 12 | ".github/workflows/upgrade-main.yml", 13 | ".gitignore", 14 | ".mergify.yml", 15 | ".prettierignore", 16 | ".prettierrc.json", 17 | ".projen/deps.json", 18 | ".projen/files.json", 19 | ".projen/tasks.json", 20 | "LICENSE", 21 | "src/core/flows/flow-time-updater/flow-time-updater-function.ts", 22 | "tsconfig.dev.json" 23 | ], 24 | "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"." 25 | } 26 | -------------------------------------------------------------------------------- /.projenrc.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CdklabsConstructLibrary } from "cdklabs-projen-project-types"; 6 | import { Stability } from "projen/lib/cdk"; 7 | 8 | const cdkVersion = "2.185.0"; 9 | 10 | const project = new CdklabsConstructLibrary({ 11 | name: "@cdklabs/cdk-appflow", 12 | author: "Amazon Web Services", 13 | authorAddress: "cdk-appflow-maintainers@amazon.com", 14 | cdkVersion, 15 | defaultReleaseBranch: "main", 16 | projenrcTs: true, 17 | private: false, 18 | repositoryUrl: "https://github.com/cdklabs/cdk-appflow.git", 19 | stability: Stability.EXPERIMENTAL, 20 | docgen: true, 21 | eslint: true, 22 | prettier: true, 23 | bundledDeps: [], 24 | devDeps: ["@types/aws-lambda", "esbuild"], 25 | peerDeps: [ 26 | `@aws-cdk/aws-redshift-alpha@^${cdkVersion}-alpha.0`, 27 | `@aws-cdk/aws-glue-alpha@^${cdkVersion}-alpha.0`, 28 | ], 29 | keywords: ["aws", "appflow", "cdk"], 30 | gitignore: ["*.rest", ".vscode", "**/.DS_Store"], 31 | jestOptions: { 32 | jestVersion: "^29", 33 | }, 34 | }); 35 | project.synth(); 36 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | ## Code of Conduct 7 | 8 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 9 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 10 | opensource-codeofconduct@amazon.com with any additional questions or comments. 11 | -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Upgrading 2 | 3 | ## 0.0.x to 0.1.x 4 | Release [0.1.0](https://github.com/cdklabs/cdk-appflow/releases/tag/v0.1.0) has changed how CDK generates `FlowName` property of `AWS::AppFlow::Flow` constructs. 5 | 6 | AppFlow requires `FlowName` property to be stable so after upgrade to 0.1.0, `cdk diff` will produce change like this: 7 | 8 | ``` 9 | Resources 10 | [~] AWS::AppFlow::Flow OnDemandFlow OnDemandFlow4ECA54C5 replace 11 | └─ [~] FlowName (requires replacement) 12 | ├─ [-] OnDemandFlow 13 | └─ [+] TestStackOnDemandFlow2E777DF5 14 | ``` 15 | 16 | If applied, this diff will destroy the old OnDemandFlow and create new one. 17 | To prevent recreate, user can restore original `FlowName` property with following code: 18 | ```typescript 19 | import { IFlow } from '@cdklabs/cdk-appflow'; 20 | import { CfnFlow } from 'aws-cdk-lib/aws-appflow'; 21 | 22 | declare const flow: IFlow; 23 | 24 | const flowNode = flow.node.defaultChild as CfnFlow; 25 | flowNode.flowName = "OnDemandFlow" 26 | ``` 27 | 28 | Once applied, another run of `cdk diff` should produce `There were no differences` 29 | 30 | ## 0.1.x to 0.2.x 31 | Release [0.2.0](https://github.com/cdklabs/cdk-appflow/releases/tag/v0.2.0) has changed logical ID of `AWS::AppFlow::Flow` constructs. 32 | As a result, `cdk diff` produces change like this: 33 | ``` 34 | Resources 35 | [-] AWS::AppFlow::Flow OnDemandFlow/OnDemandFlow OnDemandFlow4ECA54C5 destroy 36 | [+] AWS::AppFlow::Flow OnDemandFlow OnDemandFlow00CE33FE 37 | ``` 38 | 39 | If applied, this diff will destroy the old OnDemandFlow and create new one. 40 | To prevent recreate, user can override logical ID with following code: 41 | ```typescript 42 | import { IFlow } from '@cdklabs/cdk-appflow'; 43 | import { CfnFlow } from 'aws-cdk-lib/aws-appflow'; 44 | 45 | declare const flow: IFlow; 46 | 47 | const flowNode = flow.node.defaultChild as CfnFlow; 48 | flowNode.overrideLogicalId("OnDemandFlow4ECA54C5"); 49 | ``` 50 | 51 | Once applied, another run of `cdk diff` should produce `There were no differences` 52 | -------------------------------------------------------------------------------- /rosetta/default.ts-fixture: -------------------------------------------------------------------------------- 1 | // Fixture with packages imported, but nothing else 2 | import { Construct } from 'constructs'; 3 | import { 4 | Stack, 5 | } from 'aws-cdk-lib'; 6 | 7 | class Fixture extends Stack { 8 | constructor(scope: Construct, id: string) { 9 | super(scope, id); 10 | 11 | /// here 12 | } 13 | } -------------------------------------------------------------------------------- /src/amazonrdsforpostgresql/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./destination"; 8 | -------------------------------------------------------------------------------- /src/amazonrdsforpostgresql/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class AmazonRdsForPostgreSqlConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!AmazonRdsForPostgreSqlConnectorType.actualInstance) { 13 | AmazonRdsForPostgreSqlConnectorType.actualInstance = 14 | new AmazonRdsForPostgreSqlConnectorType(); 15 | } 16 | return AmazonRdsForPostgreSqlConnectorType.actualInstance; 17 | } 18 | 19 | private static actualInstance: ConnectorType; 20 | 21 | constructor() { 22 | super("AmazonRDSPostgreSQL", true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/asana/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | -------------------------------------------------------------------------------- /src/asana/profile.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { SecretValue } from "aws-cdk-lib"; 6 | import { CfnConnectorProfile } from "aws-cdk-lib/aws-appflow"; 7 | import { Construct } from "constructs"; 8 | import { AsanaConnectorType } from "./type"; 9 | import { ConnectorAuthenticationType } from "../core/connectors/connector-authentication-type"; 10 | import { 11 | ConnectorProfileBase, 12 | ConnectorProfileProps, 13 | } from "../core/connectors/connector-profile"; 14 | 15 | export interface AsanaConnectorProfileProps extends ConnectorProfileProps { 16 | readonly patToken: SecretValue; 17 | } 18 | 19 | /** 20 | * A class that represents a Asana Connector Profile. 21 | * 22 | */ 23 | export class AsanaConnectorProfile extends ConnectorProfileBase { 24 | public static fromConnectionProfileArn( 25 | scope: Construct, 26 | id: string, 27 | arn: string, 28 | ) { 29 | return this._fromConnectorProfileAttributes(scope, id, { 30 | arn, 31 | }) as AsanaConnectorProfile; 32 | } 33 | 34 | public static fromConnectionProfileName( 35 | scope: Construct, 36 | id: string, 37 | name: string, 38 | ) { 39 | return this._fromConnectorProfileAttributes(scope, id, { 40 | name, 41 | }) as AsanaConnectorProfile; 42 | } 43 | 44 | constructor(scope: Construct, id: string, props: AsanaConnectorProfileProps) { 45 | super(scope, id, props, AsanaConnectorType.instance); 46 | } 47 | 48 | protected buildConnectorProfileProperties( 49 | _props: ConnectorProfileProps, 50 | ): CfnConnectorProfile.ConnectorProfilePropertiesProperty { 51 | return { 52 | customConnector: { 53 | profileProperties: {}, 54 | }, 55 | }; 56 | } 57 | 58 | protected buildConnectorProfileCredentials( 59 | props: ConnectorProfileProps, 60 | ): CfnConnectorProfile.ConnectorProfileCredentialsProperty { 61 | const properties = props as AsanaConnectorProfileProps; 62 | 63 | return { 64 | customConnector: { 65 | authenticationType: ConnectorAuthenticationType.CUSTOM, 66 | custom: { 67 | credentialsMap: { 68 | patToken: properties.patToken.unsafeUnwrap(), 69 | }, 70 | customAuthenticationType: "PAT", 71 | }, 72 | }, 73 | }; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/asana/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { AsanaConnectorProfile } from "./profile"; 8 | import { AsanaConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices"; 12 | 13 | export interface AsanaSourceProps { 14 | readonly profile: AsanaConnectorProfile; 15 | readonly object: string; 16 | readonly apiVersion?: string; 17 | } 18 | 19 | /** 20 | * A class that represents a Asana v3 Source 21 | */ 22 | export class AsanaSource implements ISource { 23 | private static readonly apiVersion: string = "1.0"; 24 | 25 | /** 26 | * The AppFlow type of the connector that this source is implemented for 27 | */ 28 | public readonly connectorType: ConnectorType = AsanaConnectorType.instance; 29 | 30 | constructor(private readonly props: AsanaSourceProps) {} 31 | 32 | bind(flow: IFlow): CfnFlow.SourceFlowConfigProperty { 33 | this.tryAddNodeDependency(flow, this.props.profile); 34 | 35 | return { 36 | apiVersion: this.props.apiVersion ?? AsanaSource.apiVersion, 37 | connectorType: this.connectorType.asProfileConnectorType, 38 | connectorProfileName: this.props.profile.name, 39 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 40 | }; 41 | } 42 | 43 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 44 | return { 45 | customConnector: { 46 | entityName: this.props.object, 47 | }, 48 | }; 49 | } 50 | 51 | private tryAddNodeDependency( 52 | scope: IConstruct, 53 | resource?: IConstruct | string, 54 | ) { 55 | if (resource && typeof resource !== "string") { 56 | scope.node.addDependency(resource); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/asana/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class AsanaConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!AsanaConnectorType.actualInstance) { 13 | AsanaConnectorType.actualInstance = new AsanaConnectorType(); 14 | } 15 | return AsanaConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("Asana", true); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/core/connectors/connection-mode.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export enum ConnectionMode { 6 | PUBLIC = "Public", 7 | /** 8 | * @internal 9 | */ 10 | PRIVATE = "Private", 11 | } 12 | -------------------------------------------------------------------------------- /src/core/connectors/connector-authentication-type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export enum ConnectorAuthenticationType { 6 | APIKEY = "APIKEY", 7 | BASIC = "BASIC", 8 | CUSTOM = "CUSTOM", 9 | OAUTH2 = "OAUTH2", 10 | } 11 | -------------------------------------------------------------------------------- /src/core/connectors/connector-type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export class ConnectorType { 6 | protected constructor( 7 | protected readonly name: string, 8 | public readonly isCustom: boolean, 9 | ) {} 10 | 11 | public get asProfileConnectorType(): string { 12 | return this.isCustom 13 | ? "CustomConnector" 14 | : `${this.name[0].toUpperCase()}${this.name.substring(1).toLowerCase()}`; 15 | } 16 | 17 | public get asTaskConnectorOperatorOrigin(): string { 18 | return this.isCustom 19 | ? "customConnector" 20 | : `${this.name[0].toLowerCase()}${this.name.substring(1)}`; 21 | } 22 | 23 | public get asProfileConnectorLabel(): string | undefined { 24 | return this.isCustom ? this.name : undefined; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/core/connectors/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./connection-mode"; 6 | export * from "./connector-profile"; 7 | export * from "./connector-type"; 8 | export * from "./oauth2-granttype"; 9 | export * from "./connector-authentication-type"; 10 | -------------------------------------------------------------------------------- /src/core/connectors/oauth2-granttype.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export enum OAuth2GrantType { 6 | CLIENT_CREDENTIALS = "CLIENT_CREDENTIALS", 7 | AUTHORIZATION_CODE = "AUTHORIZATION_CODE", 8 | } 9 | -------------------------------------------------------------------------------- /src/core/error-handling.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { S3Location } from "./s3-location"; 6 | 7 | export interface ErrorHandlingConfiguration { 8 | readonly errorLocation?: S3Location; 9 | readonly failOnFirstError?: boolean; 10 | } 11 | -------------------------------------------------------------------------------- /src/core/flows/flow-time-updater/api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export const PROP_SCHEDULE = "Schedule"; 6 | export const PROP_STARTTIME = "StartTime"; 7 | export const PROP_ENDTIME = "EndTime"; 8 | 9 | export const ATTR_SCHEDULE = "Schedule"; 10 | export const ATTR_STARTTIME = "StartTime"; 11 | export const ATTR_ENDTIME = "EndTime"; 12 | -------------------------------------------------------------------------------- /src/core/flows/flow-time-updater/flow-time-updater-function.ts: -------------------------------------------------------------------------------- 1 | // ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | import * as path from 'path'; 3 | import * as lambda from 'aws-cdk-lib/aws-lambda'; 4 | import { Construct } from 'constructs'; 5 | 6 | /** 7 | * Props for FlowTimeUpdaterFunction 8 | */ 9 | export interface FlowTimeUpdaterFunctionProps extends lambda.FunctionOptions { 10 | } 11 | 12 | /** 13 | * An AWS Lambda function which executes src/core/flows/flow-time-updater/flow-time-updater. 14 | */ 15 | export class FlowTimeUpdaterFunction extends lambda.Function { 16 | constructor(scope: Construct, id: string, props?: FlowTimeUpdaterFunctionProps) { 17 | super(scope, id, { 18 | description: 'src/core/flows/flow-time-updater/flow-time-updater.lambda.ts', 19 | ...props, 20 | runtime: new lambda.Runtime('nodejs18.x', lambda.RuntimeFamily.NODEJS), 21 | handler: 'index.handler', 22 | code: lambda.Code.fromAsset(path.join(__dirname, '../../../../assets/core/flows/flow-time-updater/flow-time-updater.lambda')), 23 | }); 24 | this.addEnvironment('AWS_NODEJS_CONNECTION_REUSE_ENABLED', '1', { removeInEdge: true }); 25 | } 26 | } -------------------------------------------------------------------------------- /src/core/flows/flow-time-updater/flow-time-updater.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | // import * as path from 'path'; 6 | import { CustomResource, Stack, Token } from "aws-cdk-lib"; 7 | import { Schedule } from "aws-cdk-lib/aws-events"; 8 | // import { Runtime } from 'aws-cdk-lib/aws-lambda'; 9 | // import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'; 10 | import { Provider } from "aws-cdk-lib/custom-resources"; 11 | import { Construct } from "constructs"; 12 | import * as api from "./api"; 13 | import { FlowTimeUpdaterFunction } from "./flow-time-updater-function"; 14 | 15 | interface FlowTimeUpdaterProps { 16 | readonly schedule: Schedule; 17 | readonly startTime?: Date; 18 | readonly endTime?: Date; 19 | } 20 | 21 | export class FlowTimeUpdater extends Construct { 22 | public readonly scheduleExpression: string; 23 | public readonly startTime?: number; 24 | public readonly endTime?: number; 25 | 26 | constructor(scope: Construct, id: string, props: FlowTimeUpdaterProps) { 27 | super(scope, id); 28 | 29 | const resource = new CustomResource(this, "Resource", { 30 | serviceToken: FlowTimeUpdaterProvider.getOrCreate(this), 31 | resourceType: "Custom::FlowTimeUpdater", 32 | properties: { 33 | [api.PROP_SCHEDULE]: props.schedule.expressionString, 34 | [api.PROP_STARTTIME]: props.startTime && props.startTime.toISOString(), 35 | [api.PROP_ENDTIME]: props.endTime && props.endTime.toISOString(), 36 | }, 37 | }); 38 | 39 | this.scheduleExpression = resource.getAttString(api.ATTR_SCHEDULE); 40 | this.startTime = Token.asNumber(resource.getAtt(api.ATTR_STARTTIME)); 41 | this.endTime = Token.asNumber(resource.getAtt(api.ATTR_ENDTIME)); 42 | } 43 | } 44 | 45 | class FlowTimeUpdaterProvider extends Construct { 46 | /** 47 | * Returns the singleton provider. 48 | */ 49 | public static getOrCreate(scope: Construct) { 50 | const stack = Stack.of(scope); 51 | const id = "com.amazonaws.cdk.custom-resources.flow-time-provider"; 52 | const x = 53 | (stack.node.tryFindChild(id) as FlowTimeUpdaterProvider) || 54 | new FlowTimeUpdaterProvider(stack, id); 55 | return x.provider.serviceToken; 56 | } 57 | 58 | private readonly provider: Provider; 59 | 60 | constructor(scope: Construct, id: string) { 61 | super(scope, id); 62 | 63 | this.provider = new Provider(this, "flow-time-provider", { 64 | onEventHandler: new FlowTimeUpdaterFunction(this, "flow-time-on-event"), 65 | }); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/core/flows/flow-time-updater/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./flow-time-updater"; 6 | -------------------------------------------------------------------------------- /src/core/flows/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./flow-base"; 6 | export * from "./triggered-flow-base"; 7 | export * from "./on-demand-flow"; 8 | export * from "./on-event-flow"; 9 | export * from "./on-schedule-flow"; 10 | -------------------------------------------------------------------------------- /src/core/flows/on-demand-flow.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { Construct } from "constructs"; 6 | import { FlowBase, FlowProps, FlowType, IFlow } from "./flow-base"; 7 | 8 | export interface OnDemandFlowProps extends FlowProps {} 9 | 10 | export class OnDemandFlow extends FlowBase implements IFlow { 11 | constructor(scope: Construct, id: string, props: OnDemandFlowProps) { 12 | super(scope, id, { 13 | ...props, 14 | type: FlowType.ON_DEMAND, 15 | }); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/core/flows/on-event-flow.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { OnEventOptions } from "aws-cdk-lib/aws-events"; 6 | import { Construct } from "constructs"; 7 | import { FlowType, IFlow } from "./flow-base"; 8 | import { 9 | TriggeredFlowBase, 10 | TriggeredFlowBaseProps, 11 | } from "./triggered-flow-base"; 12 | 13 | export interface OnEventFlowProps extends TriggeredFlowBaseProps {} 14 | 15 | export class OnEventFlow extends TriggeredFlowBase implements IFlow { 16 | constructor(scope: Construct, id: string, props: OnEventFlowProps) { 17 | super(scope, id, { 18 | ...props, 19 | type: FlowType.EVENT, 20 | status: TriggeredFlowBase.setStatus(props.autoActivate, props.status), 21 | }); 22 | } 23 | 24 | public onDeactivated(id: string, options: OnEventOptions = {}) { 25 | const rule = this.onEvent(id, options); 26 | rule.addEventPattern({ 27 | detailType: ["AppFlow Event Flow Deactivated"], 28 | }); 29 | return rule; 30 | } 31 | 32 | public onStatus(id: string, options: OnEventOptions = {}) { 33 | const rule = this.onEvent(id, options); 34 | rule.addEventPattern({ 35 | detailType: ["AppFlow Event Flow Report"], 36 | }); 37 | return rule; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/core/flows/on-schedule-flow.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { OnEventOptions, Schedule } from "aws-cdk-lib/aws-events"; 6 | import { Construct } from "constructs"; 7 | import { 8 | DataPullConfig, 9 | FlowType, 10 | IFlow, 11 | ScheduleProperties, 12 | } from "./flow-base"; 13 | import { 14 | TriggeredFlowBase, 15 | TriggeredFlowBaseProps, 16 | } from "./triggered-flow-base"; 17 | 18 | export interface OnScheduleFlowProps extends TriggeredFlowBaseProps { 19 | readonly schedule: Schedule; 20 | readonly pullConfig: DataPullConfig; 21 | readonly scheduleProperties?: ScheduleProperties; 22 | } 23 | 24 | export class OnScheduleFlow extends TriggeredFlowBase implements IFlow { 25 | constructor(scope: Construct, id: string, props: OnScheduleFlowProps) { 26 | super(scope, id, { 27 | ...props, 28 | type: FlowType.SCHEDULED, 29 | status: TriggeredFlowBase.setStatus(props.autoActivate, props.status), 30 | triggerConfig: { 31 | properties: { 32 | schedule: props.schedule, 33 | dataPullConfig: props.pullConfig, 34 | properties: props.scheduleProperties, 35 | }, 36 | }, 37 | }); 38 | } 39 | 40 | public onDeactivated(id: string, options: OnEventOptions = {}) { 41 | const rule = this.onEvent(id, options); 42 | rule.addEventPattern({ 43 | detailType: ["AppFlow Scheduled Flow Deactivated"], 44 | }); 45 | return rule; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/core/flows/triggered-flow-base.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { OnEventOptions, Rule } from "aws-cdk-lib/aws-events"; 6 | import { Construct } from "constructs"; 7 | import { 8 | FlowBase, 9 | FlowBaseProps, 10 | FlowProps, 11 | FlowStatus, 12 | IFlow, 13 | } from "./flow-base"; 14 | 15 | export interface TriggeredFlowBaseProps extends FlowProps { 16 | /** 17 | * The status to set on the flow. Use this over {@link autoActivate}. 18 | */ 19 | readonly status?: FlowStatus; 20 | /** 21 | * @deprecated. This property is deprecated and will be removed in a future release. Use {@link status} instead 22 | */ 23 | readonly autoActivate?: boolean; 24 | } 25 | 26 | /** 27 | * A base class for triggered flows. 28 | */ 29 | export abstract class TriggeredFlowBase extends FlowBase implements IFlow { 30 | /** 31 | * 32 | * @param autoActivate - a boolean value indicating whether to automatically activate the flow. 33 | * @param status - a {@link FlowStatus} value indicating the status to set on the flow. 34 | * @returns 35 | */ 36 | protected static setStatus( 37 | autoActivate?: boolean, 38 | status?: FlowStatus, 39 | ): FlowStatus | undefined { 40 | if (autoActivate !== undefined && status !== undefined) { 41 | throw new Error("Cannot specify both autoActivate and status"); 42 | } 43 | 44 | return autoActivate !== undefined 45 | ? autoActivate 46 | ? FlowStatus.ACTIVE 47 | : FlowStatus.SUSPENDED 48 | : status !== undefined 49 | ? status 50 | : undefined; 51 | } 52 | /** 53 | * 54 | * @param scope 55 | * @param id 56 | * @param props 57 | */ 58 | constructor(scope: Construct, id: string, props: FlowBaseProps) { 59 | super(scope, id, props); 60 | } 61 | 62 | public abstract onDeactivated(id: string, options?: OnEventOptions): Rule; 63 | } 64 | -------------------------------------------------------------------------------- /src/core/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./vertices"; 6 | export * from "./tasks"; 7 | export * from "./flows"; 8 | export * from "./error-handling"; 9 | export * from "./s3-location"; 10 | export * from "./write-operation"; 11 | 12 | export * from "./connectors"; 13 | 14 | // utils 15 | export * from "./appflow-permissions-manager"; 16 | -------------------------------------------------------------------------------- /src/core/s3-location.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { IBucket } from "aws-cdk-lib/aws-s3"; 6 | 7 | export interface S3Location { 8 | readonly bucket: IBucket; 9 | readonly prefix?: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/core/tasks/field.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export interface Field { 6 | readonly name: string; 7 | readonly dataType?: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/tasks/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./field"; 6 | export * from "./tasks"; 7 | export * from "./operation"; 8 | export * from "./validations"; 9 | export * from "./mappings"; 10 | export * from "./filters"; 11 | export * from "./transforms"; 12 | -------------------------------------------------------------------------------- /src/core/tasks/operation.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { ITask } from "./tasks"; 7 | import { IFlow } from "../flows/flow-base"; 8 | import { ISource } from "../vertices/source"; 9 | 10 | /** 11 | * A representation of a set of tasks that deliver complete operation 12 | */ 13 | export interface IOperation { 14 | bind(flow: IFlow, source: ISource): CfnFlow.TaskProperty[]; 15 | } 16 | 17 | /** 18 | * A base class for all operations 19 | */ 20 | export abstract class OperationBase implements IOperation { 21 | constructor(private readonly tasks: ITask[]) {} 22 | 23 | public bind(flow: IFlow, source: ISource): CfnFlow.TaskProperty[] { 24 | return this.tasks.map((t) => t.bind(flow, source)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/core/tasks/tasks.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { ConnectorType } from "../connectors/connector-type"; 7 | import { IFlow } from "../flows"; 8 | import { ISource } from "../vertices/source"; 9 | 10 | /** 11 | * A representation of a unitary action on the record fields 12 | */ 13 | export interface ITask { 14 | bind(flow: IFlow, source: ISource): CfnFlow.TaskProperty; 15 | } 16 | 17 | export interface TaskProperty { 18 | readonly key: string; 19 | readonly value: string; 20 | } 21 | 22 | /** 23 | * A pair that represents the (typically source) connector, and a task operation to be performed in the context of the connector 24 | */ 25 | export interface TaskConnectorOperator { 26 | readonly type?: ConnectorType; 27 | readonly operation: string; 28 | } 29 | 30 | /** 31 | * A representation of a unitary action on the record fields 32 | */ 33 | export class Task implements ITask { 34 | constructor( 35 | protected type: string, 36 | protected sourceFields: string[], 37 | protected connectorOperator: TaskConnectorOperator, 38 | protected properties: TaskProperty[], 39 | protected destinationField?: string, 40 | ) {} 41 | 42 | public bind(_flow: IFlow, source: ISource): CfnFlow.TaskProperty { 43 | return { 44 | taskType: this.type, 45 | sourceFields: this.sourceFields, 46 | taskProperties: this.properties.map(({ key, value }) => ({ 47 | key: key, 48 | value: value, 49 | })), 50 | connectorOperator: this.buildOperatorFor(source), 51 | destinationField: this.destinationField, 52 | }; 53 | } 54 | 55 | private buildOperatorFor(source: ISource): CfnFlow.ConnectorOperatorProperty { 56 | const operator: { [key: string]: string } = {}; 57 | const origin = 58 | this.connectorOperator.type?.asTaskConnectorOperatorOrigin ?? 59 | source.connectorType.asTaskConnectorOperatorOrigin; 60 | operator[origin] = this.connectorOperator.operation; 61 | return operator; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/core/vertices/destination.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IVertex } from "./vertex"; 7 | import { IFlow } from "../flows"; 8 | 9 | /** 10 | * A destination of an AppFlow flow 11 | */ 12 | export interface IDestination extends IVertex { 13 | bind(scope: IFlow): CfnFlow.DestinationFlowConfigProperty; 14 | } 15 | -------------------------------------------------------------------------------- /src/core/vertices/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./source"; 6 | export * from "./vertex"; 7 | export * from "./destination"; 8 | -------------------------------------------------------------------------------- /src/core/vertices/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IVertex } from "./vertex"; 7 | import { IFlow } from "../flows"; 8 | 9 | /** 10 | * A source of an AppFlow flow 11 | */ 12 | export interface ISource extends IVertex { 13 | bind(scope: IFlow): CfnFlow.SourceFlowConfigProperty; 14 | } 15 | -------------------------------------------------------------------------------- /src/core/vertices/vertex.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../connectors/connector-type"; 6 | 7 | /** 8 | * An interface representing a vertex, i.e. a source or a destination of an AppFlow flow 9 | */ 10 | export interface IVertex { 11 | /** 12 | * The AppFlow type of the connector that this source is implemented for 13 | */ 14 | readonly connectorType: ConnectorType; 15 | } 16 | -------------------------------------------------------------------------------- /src/core/write-operation.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export enum WriteOperationType { 6 | DELETE = "DELETE", 7 | INSERT = "INSERT", 8 | UPDATE = "UPDATE", 9 | UPSERT = "UPSERT", 10 | } 11 | 12 | export class WriteOperation { 13 | public static insert(ids?: string[]): WriteOperation { 14 | return new WriteOperation(WriteOperationType.INSERT, ids); 15 | } 16 | public static delete(ids?: string[]): WriteOperation { 17 | return new WriteOperation(WriteOperationType.DELETE, ids); 18 | } 19 | public static update(ids?: string[]): WriteOperation { 20 | return new WriteOperation(WriteOperationType.UPDATE, ids); 21 | } 22 | public static upsert(ids?: string[]): WriteOperation { 23 | return new WriteOperation(WriteOperationType.UPSERT, ids); 24 | } 25 | 26 | constructor( 27 | public readonly type: WriteOperationType, 28 | public readonly ids?: string[], 29 | ) {} 30 | } 31 | -------------------------------------------------------------------------------- /src/eventbridge/destination.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { EventBridgeConnectorType } from "./type"; 8 | import { AppFlowPermissionsManager } from "../core/appflow-permissions-manager"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { ErrorHandlingConfiguration } from "../core/error-handling"; 11 | import { FlowType, IFlow } from "../core/flows"; 12 | import { IDestination } from "../core/vertices/destination"; 13 | 14 | /** 15 | * The properties for the EventBridge destination 16 | */ 17 | export interface EventBridgeDestinationProps { 18 | readonly partnerBus: string; 19 | readonly errorHandling?: ErrorHandlingConfiguration; 20 | } 21 | 22 | /** 23 | * This class represents AppFlow's EventBridge destination 24 | */ 25 | export class EventBridgeDestination implements IDestination { 26 | private readonly compatibleFlows: FlowType[] = [FlowType.EVENT]; 27 | public readonly connectorType: ConnectorType = 28 | EventBridgeConnectorType.instance; 29 | 30 | constructor(private readonly props: EventBridgeDestinationProps) {} 31 | 32 | bind(flow: IFlow): CfnFlow.DestinationFlowConfigProperty { 33 | if (!this.compatibleFlows.includes(flow.type)) { 34 | throw new Error( 35 | `Flow of type ${flow.type} does not support EventBridge as a destination`, 36 | ); 37 | } 38 | 39 | this.tryAddNodeDependency( 40 | flow, 41 | this.props.errorHandling?.errorLocation?.bucket, 42 | ); 43 | AppFlowPermissionsManager.instance().grantBucketWrite( 44 | this.props.errorHandling?.errorLocation?.bucket, 45 | ); 46 | 47 | return { 48 | connectorType: this.connectorType.asProfileConnectorType, 49 | destinationConnectorProperties: 50 | this.buildDestinationConnectorProperties(), 51 | }; 52 | } 53 | 54 | private buildDestinationConnectorProperties(): CfnFlow.DestinationConnectorPropertiesProperty { 55 | return { 56 | eventBridge: { 57 | object: this.props.partnerBus, 58 | errorHandlingConfig: this.props.errorHandling && { 59 | bucketName: 60 | this.props.errorHandling?.errorLocation?.bucket?.bucketName, 61 | bucketPrefix: this.props.errorHandling?.errorLocation?.prefix, 62 | failOnFirstError: this.props.errorHandling?.failOnFirstError, 63 | }, 64 | }, 65 | }; 66 | } 67 | 68 | private tryAddNodeDependency( 69 | scope: IConstruct, 70 | resource?: IConstruct | string, 71 | ): void { 72 | if (resource && typeof resource !== "string") { 73 | scope.node.addDependency(resource); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/eventbridge/events.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { Aws } from "aws-cdk-lib"; 6 | 7 | export class EventSources { 8 | public static salesforceEventSource(suffix?: string): string { 9 | return suffix 10 | ? `aws.partner/appflow/salesforce.com/${Aws.ACCOUNT_ID}/${suffix}` 11 | : `aws.partner/appflow/salesforce.com/${Aws.ACCOUNT_ID}`; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/eventbridge/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./destination"; 7 | export * from "./events"; 8 | -------------------------------------------------------------------------------- /src/eventbridge/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class EventBridgeConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!EventBridgeConnectorType.actualInstance) { 13 | EventBridgeConnectorType.actualInstance = new EventBridgeConnectorType(); 14 | } 15 | return EventBridgeConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("EventBridge", false); 22 | } 23 | 24 | public get asProfileConnectorType(): string { 25 | return this.name; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/googleads/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./util"; 9 | -------------------------------------------------------------------------------- /src/googleads/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { GoogleAdsConnectorProfile } from "./profile"; 8 | import { GoogleAdsConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices"; 12 | /** 13 | * Properties of a Google Ads Source 14 | */ 15 | export interface GoogleAdsSourceProps { 16 | readonly profile: GoogleAdsConnectorProfile; 17 | readonly apiVersion: string; 18 | readonly object: string; 19 | } 20 | /** 21 | * A class that represents a Google Ads v4 Source 22 | */ 23 | export class GoogleAdsSource implements ISource { 24 | /** 25 | * The AppFlow type of the connector that this source is implemented for 26 | */ 27 | public readonly connectorType: ConnectorType = 28 | GoogleAdsConnectorType.instance; 29 | 30 | constructor(private readonly props: GoogleAdsSourceProps) {} 31 | 32 | bind(scope: IFlow): CfnFlow.SourceFlowConfigProperty { 33 | this.tryAddNodeDependency(scope, this.props.profile); 34 | 35 | return { 36 | connectorType: this.connectorType.asProfileConnectorType, 37 | connectorProfileName: this.props.profile.name, 38 | apiVersion: this.props.apiVersion, 39 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 40 | }; 41 | } 42 | 43 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 44 | return { 45 | customConnector: { 46 | entityName: this.props.object, 47 | }, 48 | }; 49 | } 50 | private tryAddNodeDependency( 51 | scope: IConstruct, 52 | resource?: IConstruct | string, 53 | ): void { 54 | if (resource && typeof resource !== "string") { 55 | scope.node.addDependency(resource); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/googleads/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class GoogleAdsConnectorType extends ConnectorType { 11 | /** 12 | * Singleton 13 | */ 14 | public static get instance(): ConnectorType { 15 | if (!GoogleAdsConnectorType.actualInstance) { 16 | GoogleAdsConnectorType.actualInstance = new GoogleAdsConnectorType(); 17 | } 18 | return GoogleAdsConnectorType.actualInstance; 19 | } 20 | 21 | private static actualInstance: ConnectorType; 22 | 23 | constructor() { 24 | super("GoogleAds", true); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/googleads/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | /** 7 | * An enum representing the GoogleAds API versions. 8 | */ 9 | export enum GoogleAdsApiVersion { 10 | V16 = "v16", 11 | } 12 | -------------------------------------------------------------------------------- /src/googleanalytics4/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./util"; 9 | -------------------------------------------------------------------------------- /src/googleanalytics4/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { GoogleAnalytics4ConnectorProfile } from "./profile"; 8 | import { GoogleAnalytics4ConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices"; 12 | 13 | /** 14 | * Properties of a Google Analytics v4 Source 15 | */ 16 | export interface GoogleAnalytics4SourceProps { 17 | readonly profile: GoogleAnalytics4ConnectorProfile; 18 | readonly apiVersion: string; 19 | readonly object: string; 20 | } 21 | 22 | /** 23 | * A class that represents a Google Analytics v4 Source 24 | */ 25 | export class GoogleAnalytics4Source implements ISource { 26 | /** 27 | * The AppFlow type of the connector that this source is implemented for 28 | */ 29 | public readonly connectorType: ConnectorType = 30 | GoogleAnalytics4ConnectorType.instance; 31 | 32 | constructor(private readonly props: GoogleAnalytics4SourceProps) {} 33 | 34 | bind(scope: IFlow): CfnFlow.SourceFlowConfigProperty { 35 | this.tryAddNodeDependency(scope, this.props.profile); 36 | 37 | return { 38 | connectorType: this.connectorType.asProfileConnectorType, 39 | connectorProfileName: this.props.profile.name, 40 | apiVersion: this.props.apiVersion, 41 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 42 | }; 43 | } 44 | 45 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 46 | return { 47 | customConnector: { 48 | entityName: this.props.object, 49 | }, 50 | }; 51 | } 52 | 53 | private tryAddNodeDependency( 54 | scope: IConstruct, 55 | resource?: IConstruct | string, 56 | ): void { 57 | if (resource && typeof resource !== "string") { 58 | scope.node.addDependency(resource); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/googleanalytics4/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class GoogleAnalytics4ConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!GoogleAnalytics4ConnectorType.actualInstance) { 13 | GoogleAnalytics4ConnectorType.actualInstance = 14 | new GoogleAnalytics4ConnectorType(); 15 | } 16 | return GoogleAnalytics4ConnectorType.actualInstance; 17 | } 18 | 19 | private static actualInstance: ConnectorType; 20 | 21 | constructor() { 22 | super("GoogleAnalytics4", true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/googleanalytics4/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export enum GoogleAnalytics4ApiVersion { 6 | V1BETA = "v1beta", 7 | } 8 | -------------------------------------------------------------------------------- /src/googlebigquery/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./util"; 9 | -------------------------------------------------------------------------------- /src/googlebigquery/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { GoogleBigQueryConnectorProfile } from "./profile"; 8 | import { GoogleBigQueryConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices"; 12 | 13 | export interface GoogleBigQueryObject { 14 | readonly project: string; 15 | readonly dataset: string; 16 | readonly table: string; 17 | } 18 | 19 | /** 20 | * Properties of a Google BigQuery Source 21 | */ 22 | export interface GoogleBigQuerySourceProps { 23 | readonly profile: GoogleBigQueryConnectorProfile; 24 | readonly apiVersion: string; 25 | readonly object: GoogleBigQueryObject; 26 | } 27 | 28 | /** 29 | * A class that represents a Google BigQuery Source 30 | */ 31 | export class GoogleBigQuerySource implements ISource { 32 | /** 33 | * The AppFlow type of the connector that this source is implemented for 34 | */ 35 | public readonly connectorType: ConnectorType = 36 | GoogleBigQueryConnectorType.instance; 37 | 38 | constructor(private readonly props: GoogleBigQuerySourceProps) {} 39 | 40 | bind(scope: IFlow): CfnFlow.SourceFlowConfigProperty { 41 | this.tryAddNodeDependency(scope, this.props.profile); 42 | 43 | return { 44 | connectorType: this.connectorType.asProfileConnectorType, 45 | connectorProfileName: this.props.profile.name, 46 | apiVersion: this.props.apiVersion, 47 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 48 | }; 49 | } 50 | 51 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 52 | return { 53 | customConnector: { 54 | entityName: `table/${this.props.object.project}/${this.props.object.dataset}/${this.props.object.table}`, 55 | }, 56 | }; 57 | } 58 | 59 | private tryAddNodeDependency( 60 | scope: IConstruct, 61 | resource?: IConstruct | string, 62 | ): void { 63 | if (resource && typeof resource !== "string") { 64 | scope.node.addDependency(resource); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/googlebigquery/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class GoogleBigQueryConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!GoogleBigQueryConnectorType.actualInstance) { 13 | GoogleBigQueryConnectorType.actualInstance = 14 | new GoogleBigQueryConnectorType(); 15 | } 16 | return GoogleBigQueryConnectorType.actualInstance; 17 | } 18 | 19 | private static actualInstance: ConnectorType; 20 | 21 | constructor() { 22 | super("GoogleBigQuery", true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/googlebigquery/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export enum GoogleBigQueryApiVersion { 6 | V2 = "v2", 7 | } 8 | -------------------------------------------------------------------------------- /src/hubspot/destination.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { HubSpotConnectorProfile } from "./profile"; 8 | import { HubSpotConnectorType } from "./type"; 9 | import { HubSpotApiVersion } from "./util"; 10 | import { AppFlowPermissionsManager } from "../core/appflow-permissions-manager"; 11 | import { ConnectorType } from "../core/connectors/connector-type"; 12 | import { ErrorHandlingConfiguration } from "../core/error-handling"; 13 | import { IFlow } from "../core/flows"; 14 | import { IDestination } from "../core/vertices/destination"; 15 | import { WriteOperation } from "../core/write-operation"; 16 | 17 | export interface HubSpotDestinationProps { 18 | readonly profile: HubSpotConnectorProfile; 19 | readonly apiVersion: HubSpotApiVersion; 20 | readonly entity: string[]; 21 | readonly operation: WriteOperation; 22 | 23 | /** 24 | * The settings that determine how Amazon AppFlow handles an error when placing data in the HubSpot destination. For example, this setting would determine if the flow should fail after one insertion error, or continue and attempt to insert every record regardless of the initial failure. 25 | */ 26 | readonly errorHandling?: ErrorHandlingConfiguration; 27 | } 28 | 29 | export class HubSpotDestination implements IDestination { 30 | public readonly connectorType: ConnectorType = HubSpotConnectorType.instance; 31 | 32 | constructor(private readonly props: HubSpotDestinationProps) {} 33 | 34 | bind(flow: IFlow): CfnFlow.DestinationFlowConfigProperty { 35 | this.tryAddNodeDependency( 36 | flow, 37 | this.props.errorHandling?.errorLocation?.bucket, 38 | ); 39 | AppFlowPermissionsManager.instance().grantBucketWrite( 40 | this.props.errorHandling?.errorLocation?.bucket, 41 | ); 42 | this.tryAddNodeDependency(flow, this.props.profile); 43 | 44 | return { 45 | connectorType: this.connectorType.asProfileConnectorType, 46 | connectorProfileName: this.props.profile.name, 47 | apiVersion: this.props.apiVersion, 48 | destinationConnectorProperties: 49 | this.buildDestinationConnectorProperties(), 50 | }; 51 | } 52 | 53 | private buildDestinationConnectorProperties(): CfnFlow.DestinationConnectorPropertiesProperty { 54 | return { 55 | customConnector: { 56 | entityName: this.props.entity.join("/"), 57 | errorHandlingConfig: this.props.errorHandling && { 58 | bucketName: 59 | this.props.errorHandling?.errorLocation?.bucket.bucketName, 60 | bucketPrefix: this.props.errorHandling?.errorLocation?.prefix, 61 | failOnFirstError: this.props.errorHandling.failOnFirstError, 62 | }, 63 | writeOperationType: this.props.operation.type, 64 | idFieldNames: this.props.operation.ids, 65 | }, 66 | }; 67 | } 68 | 69 | private tryAddNodeDependency( 70 | scope: IConstruct, 71 | resource?: IConstruct | string, 72 | ) { 73 | if (resource && typeof resource !== "string") { 74 | scope.node.addDependency(resource); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/hubspot/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./destination"; 9 | export * from "./util"; 10 | -------------------------------------------------------------------------------- /src/hubspot/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { HubSpotConnectorProfile } from "./profile"; 8 | import { HubSpotConnectorType } from "./type"; 9 | import { HubSpotApiVersion } from "./util"; 10 | import { ConnectorType } from "../core/connectors/connector-type"; 11 | import { IFlow } from "../core/flows"; 12 | import { ISource } from "../core/vertices"; 13 | 14 | /** 15 | * Properties of a Hubspot Source 16 | */ 17 | export interface HubSpotSourceProps { 18 | readonly profile: HubSpotConnectorProfile; 19 | readonly apiVersion: HubSpotApiVersion; 20 | readonly entity: string[]; 21 | } 22 | 23 | /** 24 | * A class that represents a Hubspot Source 25 | */ 26 | export class HubSpotSource implements ISource { 27 | /** 28 | * The AppFlow type of the connector that this source is implemented for 29 | */ 30 | public readonly connectorType: ConnectorType = HubSpotConnectorType.instance; 31 | 32 | constructor(private readonly props: HubSpotSourceProps) {} 33 | 34 | bind(scope: IFlow): CfnFlow.SourceFlowConfigProperty { 35 | this.tryAddNodeDependency(scope, this.props.profile); 36 | 37 | return { 38 | connectorType: this.connectorType.asProfileConnectorType, 39 | connectorProfileName: this.props.profile.name, 40 | apiVersion: this.props.apiVersion, 41 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 42 | }; 43 | } 44 | 45 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 46 | return { 47 | customConnector: { 48 | entityName: this.props.entity.join("/"), 49 | }, 50 | }; 51 | } 52 | 53 | private tryAddNodeDependency( 54 | scope: IConstruct, 55 | resource?: IConstruct | string, 56 | ): void { 57 | if (resource && typeof resource !== "string") { 58 | scope.node.addDependency(resource); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/hubspot/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class HubSpotConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!HubSpotConnectorType.actualInstance) { 13 | HubSpotConnectorType.actualInstance = new HubSpotConnectorType(); 14 | } 15 | return HubSpotConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("HubSpot", true); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/hubspot/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export enum HubSpotApiVersion { 6 | V1 = "v1", 7 | V2 = "v2", 8 | V3 = "v3", 9 | V4 = "v4", 10 | } 11 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./core"; 6 | 7 | export * from "./amazonrdsforpostgresql"; 8 | export * from "./asana"; 9 | export * from "./eventbridge"; 10 | export * from "./googleanalytics4"; 11 | export * from "./googlebigquery"; 12 | export * from "./hubspot"; 13 | export * from "./jdbcsmalldatascale"; 14 | export * from "./marketo"; 15 | export * from "./microsoftdynamics365"; 16 | export * from "./microsoftsharepointonline"; 17 | export * from "./s3"; 18 | export * from "./salesforce"; 19 | export * from "./salesforce-marketing-cloud"; 20 | export * from "./sapodata"; 21 | export * from "./servicenow"; 22 | export * from "./slack"; 23 | export * from "./snowflake"; 24 | export * from "./redshift"; 25 | export * from "./zendesk"; 26 | export * from "./mailchimp"; 27 | export * from "./googleads"; 28 | -------------------------------------------------------------------------------- /src/jdbcsmalldatascale/driver.ts: -------------------------------------------------------------------------------- 1 | export enum JdbcDriver { 2 | POSTGRES = "postgresql", 3 | MYSQL = "mysql", 4 | } 5 | -------------------------------------------------------------------------------- /src/jdbcsmalldatascale/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./driver"; 7 | export * from "./profile"; 8 | export * from "./source"; 9 | -------------------------------------------------------------------------------- /src/jdbcsmalldatascale/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { JdbcSmallDataScaleConnectorProfile } from "./profile"; 8 | import { JdbcSmallDataScaleConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices/source"; 12 | 13 | export interface JdbcSmallDataScaleObject { 14 | readonly schema: string; 15 | readonly table: string; 16 | } 17 | 18 | export interface JdbcSmallDataScaleSourceProps { 19 | readonly profile: JdbcSmallDataScaleConnectorProfile; 20 | readonly object: JdbcSmallDataScaleObject; 21 | readonly apiVersion?: string; 22 | } 23 | 24 | export class JdbcSmallDataScaleSource implements ISource { 25 | private static readonly defaultApiVersion = "V1"; 26 | 27 | public readonly connectorType: ConnectorType = 28 | JdbcSmallDataScaleConnectorType.instance; 29 | 30 | constructor(private readonly props: JdbcSmallDataScaleSourceProps) {} 31 | 32 | bind(flow: IFlow): CfnFlow.SourceFlowConfigProperty { 33 | this.tryAddNodeDependency(flow, this.props.profile); 34 | 35 | return { 36 | connectorType: this.connectorType.asProfileConnectorType, 37 | apiVersion: 38 | this.props.apiVersion ?? JdbcSmallDataScaleSource.defaultApiVersion, 39 | connectorProfileName: this.props.profile.name, 40 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 41 | }; 42 | } 43 | 44 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 45 | return { 46 | customConnector: { 47 | entityName: `${this.props.object.schema}.${this.props.object.table}`, 48 | }, 49 | }; 50 | } 51 | 52 | private tryAddNodeDependency( 53 | scope: IConstruct, 54 | resource?: IConstruct | string, 55 | ): void { 56 | if (resource && typeof resource !== "string") { 57 | scope.node.addDependency(resource); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/jdbcsmalldatascale/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class JdbcSmallDataScaleConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!JdbcSmallDataScaleConnectorType.actualInstance) { 13 | JdbcSmallDataScaleConnectorType.actualInstance = 14 | new JdbcSmallDataScaleConnectorType(); 15 | } 16 | return JdbcSmallDataScaleConnectorType.actualInstance; 17 | } 18 | 19 | private static actualInstance: ConnectorType; 20 | 21 | constructor() { 22 | super("JDBCsmall", true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/mailchimp/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./util"; 9 | -------------------------------------------------------------------------------- /src/mailchimp/profile.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { SecretValue } from "aws-cdk-lib"; 6 | import { CfnConnectorProfile } from "aws-cdk-lib/aws-appflow"; 7 | import { Construct } from "constructs"; 8 | import { MailchimpConnectorType } from "./type"; 9 | import { ConnectorAuthenticationType } from "../core/connectors/connector-authentication-type"; 10 | import { 11 | ConnectorProfileBase, 12 | ConnectorProfileProps, 13 | } from "../core/connectors/connector-profile"; 14 | 15 | export interface MailchimpConnectorProfileProps extends ConnectorProfileProps { 16 | readonly apiKey: SecretValue; 17 | readonly instanceUrl: string; 18 | } 19 | 20 | /** 21 | * A class that represents a Mailchimp Connector Profile. 22 | * 23 | */ 24 | export class MailchimpConnectorProfile extends ConnectorProfileBase { 25 | public static fromConnectionProfileArn( 26 | scope: Construct, 27 | id: string, 28 | arn: string, 29 | ) { 30 | return this._fromConnectorProfileAttributes(scope, id, { 31 | arn, 32 | }) as MailchimpConnectorProfile; 33 | } 34 | 35 | public static fromConnectionProfileName( 36 | scope: Construct, 37 | id: string, 38 | name: string, 39 | ) { 40 | return this._fromConnectorProfileAttributes(scope, id, { 41 | name, 42 | }) as MailchimpConnectorProfile; 43 | } 44 | 45 | constructor( 46 | scope: Construct, 47 | id: string, 48 | props: MailchimpConnectorProfileProps, 49 | ) { 50 | super(scope, id, props, MailchimpConnectorType.instance); 51 | } 52 | 53 | protected buildConnectorProfileProperties( 54 | props: ConnectorProfileProps, 55 | ): CfnConnectorProfile.ConnectorProfilePropertiesProperty { 56 | const properties = props as MailchimpConnectorProfileProps; 57 | return { 58 | customConnector: { 59 | profileProperties: { 60 | instanceUrl: properties.instanceUrl, 61 | }, 62 | }, 63 | }; 64 | } 65 | 66 | protected buildConnectorProfileCredentials( 67 | props: ConnectorProfileProps, 68 | ): CfnConnectorProfile.ConnectorProfileCredentialsProperty { 69 | const properties = props as MailchimpConnectorProfileProps; 70 | 71 | return { 72 | customConnector: { 73 | authenticationType: ConnectorAuthenticationType.CUSTOM, 74 | custom: { 75 | credentialsMap: { 76 | api_key: properties.apiKey.unsafeUnwrap(), 77 | }, 78 | customAuthenticationType: "api_key", 79 | }, 80 | }, 81 | }; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/mailchimp/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { MailchimpConnectorProfile } from "./profile"; 8 | import { MailchimpConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices"; 12 | 13 | export interface MailchimpSourceProps { 14 | readonly profile: MailchimpConnectorProfile; 15 | readonly apiVersion: string; 16 | readonly object: string; 17 | } 18 | 19 | /** 20 | * A class that represents a Mailchimp v3 Source 21 | */ 22 | export class MailchimpSource implements ISource { 23 | /** 24 | * The AppFlow type of the connector that this source is implemented for 25 | */ 26 | public readonly connectorType: ConnectorType = 27 | MailchimpConnectorType.instance; 28 | 29 | constructor(private readonly props: MailchimpSourceProps) {} 30 | 31 | bind(flow: IFlow): CfnFlow.SourceFlowConfigProperty { 32 | this.tryAddNodeDependency(flow, this.props.profile); 33 | 34 | return { 35 | connectorType: this.connectorType.asProfileConnectorType, 36 | apiVersion: this.props.apiVersion, 37 | connectorProfileName: this.props.profile.name, 38 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 39 | }; 40 | } 41 | 42 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 43 | return { 44 | customConnector: { 45 | entityName: this.props.object, 46 | }, 47 | }; 48 | } 49 | 50 | private tryAddNodeDependency( 51 | scope: IConstruct, 52 | resource?: IConstruct | string, 53 | ) { 54 | if (resource && typeof resource !== "string") { 55 | scope.node.addDependency(resource); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/mailchimp/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class MailchimpConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!MailchimpConnectorType.actualInstance) { 13 | MailchimpConnectorType.actualInstance = new MailchimpConnectorType(); 14 | } 15 | return MailchimpConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("Mailchimp", true); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/mailchimp/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | /** 7 | * An enum representing the Mailchimp API versions. 8 | */ 9 | export enum MailchimpApiVersion { 10 | V3 = "3.0", 11 | } 12 | -------------------------------------------------------------------------------- /src/marketo/README.md: -------------------------------------------------------------------------------- 1 | see: https://developers.marketo.com/rest-api/authentication/ 2 | 3 | Maketo uses Client Credentials Flow -------------------------------------------------------------------------------- /src/marketo/destination.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { MarketoConnectorType } from "./type"; 8 | import { AppFlowPermissionsManager } from "../core"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { ErrorHandlingConfiguration } from "../core/error-handling"; 11 | import { IFlow } from "../core/flows"; 12 | import { IDestination } from "../core/vertices/destination"; 13 | import { MarketoConnectorProfile } from "../marketo/profile"; 14 | 15 | export interface MarketoDestinationProps { 16 | readonly profile: MarketoConnectorProfile; 17 | 18 | /** 19 | * The settings that determine how Amazon AppFlow handles an error when placing data in the Marketo destination. For example, this setting would determine if the flow should fail after one insertion error, or continue and attempt to insert every record regardless of the initial failure. 20 | */ 21 | readonly errorHandling?: ErrorHandlingConfiguration; 22 | 23 | /** 24 | * The Marketo object for which the operation is to be set. 25 | */ 26 | readonly object: string; 27 | } 28 | 29 | export class MarketoDestination implements IDestination { 30 | public readonly connectorType: ConnectorType = MarketoConnectorType.instance; 31 | 32 | constructor(private readonly props: MarketoDestinationProps) {} 33 | 34 | bind(flow: IFlow): CfnFlow.DestinationFlowConfigProperty { 35 | this.tryAddNodeDependency( 36 | flow, 37 | this.props.errorHandling?.errorLocation?.bucket, 38 | ); 39 | this.tryAddNodeDependency(flow, this.props.profile); 40 | AppFlowPermissionsManager.instance().grantBucketWrite( 41 | this.props.errorHandling?.errorLocation?.bucket, 42 | ); 43 | 44 | return { 45 | connectorType: this.connectorType.asProfileConnectorType, 46 | connectorProfileName: this.props.profile.name, 47 | destinationConnectorProperties: 48 | this.buildDestinationConnectorProperties(), 49 | }; 50 | } 51 | 52 | private buildDestinationConnectorProperties(): CfnFlow.DestinationConnectorPropertiesProperty { 53 | return { 54 | marketo: { 55 | errorHandlingConfig: this.props.errorHandling && { 56 | bucketName: 57 | this.props.errorHandling?.errorLocation?.bucket?.bucketName, 58 | bucketPrefix: this.props.errorHandling?.errorLocation?.prefix, 59 | failOnFirstError: this.props.errorHandling.failOnFirstError, 60 | }, 61 | object: this.props.object, 62 | }, 63 | }; 64 | } 65 | 66 | private tryAddNodeDependency(scope: IConstruct, resource?: IConstruct): void { 67 | if (resource) { 68 | scope.node.addDependency(resource); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/marketo/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./util"; 9 | -------------------------------------------------------------------------------- /src/marketo/profile.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { SecretValue } from "aws-cdk-lib"; 6 | import { CfnConnectorProfile } from "aws-cdk-lib/aws-appflow"; 7 | import { Construct } from "constructs"; 8 | import { MarketoConnectorType } from "./type"; 9 | import { 10 | ConnectorProfileBase, 11 | ConnectorProfileProps, 12 | } from "../core/connectors/connector-profile"; 13 | 14 | export interface MarketoConnectorProfileProps extends ConnectorProfileProps { 15 | readonly oAuth: MarketoOAuthSettings; 16 | readonly instanceUrl: string; 17 | } 18 | 19 | export interface MarketoOAuthClientCredentialsFlow { 20 | readonly clientId: SecretValue; 21 | readonly clientSecret: SecretValue; 22 | } 23 | 24 | export interface MarketoOAuthFlow { 25 | readonly clientCredentials: MarketoOAuthClientCredentialsFlow; 26 | } 27 | 28 | export interface MarketoOAuthSettings { 29 | readonly accessToken?: SecretValue; 30 | readonly flow: MarketoOAuthFlow; 31 | } 32 | 33 | export class MarketoConnectorProfile extends ConnectorProfileBase { 34 | public static fromConnectionProfileArn( 35 | scope: Construct, 36 | id: string, 37 | arn: string, 38 | ) { 39 | return this._fromConnectorProfileAttributes(scope, id, { 40 | arn, 41 | }) as MarketoConnectorProfile; 42 | } 43 | 44 | public static fromConnectionProfileName( 45 | scope: Construct, 46 | id: string, 47 | name: string, 48 | ) { 49 | return this._fromConnectorProfileAttributes(scope, id, { 50 | name, 51 | }) as MarketoConnectorProfile; 52 | } 53 | 54 | constructor( 55 | scope: Construct, 56 | id: string, 57 | props: MarketoConnectorProfileProps, 58 | ) { 59 | super(scope, id, props, MarketoConnectorType.instance); 60 | } 61 | 62 | protected buildConnectorProfileProperties( 63 | props: ConnectorProfileProps, 64 | ): CfnConnectorProfile.ConnectorProfilePropertiesProperty { 65 | const properties = props as MarketoConnectorProfileProps; 66 | return { 67 | marketo: { 68 | instanceUrl: properties.instanceUrl, 69 | }, 70 | }; 71 | } 72 | 73 | protected buildConnectorProfileCredentials( 74 | props: ConnectorProfileProps, 75 | ): CfnConnectorProfile.ConnectorProfileCredentialsProperty { 76 | const properties = props as MarketoConnectorProfileProps; 77 | return { 78 | marketo: { 79 | accessToken: properties.oAuth.accessToken?.unsafeUnwrap(), 80 | clientId: 81 | properties.oAuth.flow.clientCredentials.clientId.unsafeUnwrap(), 82 | clientSecret: 83 | properties.oAuth.flow.clientCredentials.clientSecret.unsafeUnwrap(), 84 | }, 85 | }; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/marketo/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { MarketoConnectorProfile } from "./profile"; 8 | import { MarketoConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices/source"; 12 | 13 | export interface MarketoSourceProps { 14 | readonly profile: MarketoConnectorProfile; 15 | readonly object: string; 16 | readonly apiVersion?: string; 17 | } 18 | 19 | export class MarketoSource implements ISource { 20 | public readonly connectorType: ConnectorType = MarketoConnectorType.instance; 21 | 22 | constructor(private readonly props: MarketoSourceProps) {} 23 | 24 | bind(flow: IFlow): CfnFlow.SourceFlowConfigProperty { 25 | this.tryAddNodeDependency(flow, this.props.profile); 26 | 27 | return { 28 | connectorType: this.connectorType.asProfileConnectorType, 29 | apiVersion: this.props.apiVersion, 30 | connectorProfileName: this.props.profile.name, 31 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 32 | }; 33 | } 34 | 35 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 36 | return { 37 | marketo: { 38 | object: this.props.object, 39 | }, 40 | }; 41 | } 42 | 43 | private tryAddNodeDependency( 44 | scope: IConstruct, 45 | resource?: IConstruct | string, 46 | ) { 47 | if (resource && typeof resource !== "string") { 48 | scope.node.addDependency(resource); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/marketo/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class MarketoConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!MarketoConnectorType.actualInstance) { 13 | MarketoConnectorType.actualInstance = new MarketoConnectorType(); 14 | } 15 | return MarketoConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("Marketo", false); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/marketo/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export class MarketoInstanceUrlBuilder { 6 | public static buildFromAccount(account: string): string { 7 | return `https://${account}.mktorest.com`; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/microsoftdynamics365/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./util"; 9 | -------------------------------------------------------------------------------- /src/microsoftdynamics365/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { MicrosoftDynamics365ConnectorProfile } from "./profile"; 8 | import { MicrosoftDynamics365ConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices"; 12 | 13 | /** 14 | * Properties of a Microsoft Dynamics 365 Source 15 | */ 16 | export interface MicrosoftDynamics365SourceProps { 17 | readonly profile: MicrosoftDynamics365ConnectorProfile; 18 | readonly apiVersion: string; 19 | readonly object: string; 20 | } 21 | 22 | /** 23 | * A class that represents a Microsoft Dynamics 365 Source 24 | */ 25 | export class MicrosoftDynamics365Source implements ISource { 26 | /** 27 | * The AppFlow type of the connector that this source is implemented for 28 | */ 29 | public readonly connectorType: ConnectorType = 30 | MicrosoftDynamics365ConnectorType.instance; 31 | 32 | constructor(private readonly props: MicrosoftDynamics365SourceProps) {} 33 | 34 | bind(scope: IFlow): CfnFlow.SourceFlowConfigProperty { 35 | this.tryAddNodeDependency(scope, this.props.profile); 36 | 37 | return { 38 | connectorType: this.connectorType.asProfileConnectorType, 39 | connectorProfileName: this.props.profile.name, 40 | apiVersion: this.props.apiVersion, 41 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 42 | }; 43 | } 44 | 45 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 46 | return { 47 | customConnector: { 48 | entityName: this.props.object, 49 | customProperties: {}, 50 | }, 51 | }; 52 | } 53 | 54 | private tryAddNodeDependency( 55 | scope: IConstruct, 56 | resource?: IConstruct | string, 57 | ): void { 58 | if (resource && typeof resource !== "string") { 59 | scope.node.addDependency(resource); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/microsoftdynamics365/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class MicrosoftDynamics365ConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!MicrosoftDynamics365ConnectorType.actualInstance) { 13 | MicrosoftDynamics365ConnectorType.actualInstance = 14 | new MicrosoftDynamics365ConnectorType(); 15 | } 16 | return MicrosoftDynamics365ConnectorType.actualInstance; 17 | } 18 | 19 | private static actualInstance: ConnectorType; 20 | 21 | constructor() { 22 | super("MicrosoftDynamics365", true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/microsoftdynamics365/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | /** 7 | * A utility class for building Microsoft Dynamics 365 token URLs. 8 | */ 9 | export class MicrosoftDynamics365TokenUrlBuilder { 10 | public static buildTokenUrl(tenantId?: string) { 11 | return `https://login.microsoftonline.com/${tenantId ?? "common"}/oauth2/v2.0/token`; 12 | } 13 | } 14 | 15 | export class MicrosoftDynamics365ApiUrlBuilder { 16 | public static buildApiUrl(org: string) { 17 | return `https://${org}.api.crm.dynamics.com`; 18 | } 19 | } 20 | 21 | /** 22 | * An enum representing the Microsoft Dynamics 365 API versions. 23 | */ 24 | export enum MicrosoftDynamics365ApiVersion { 25 | /** 26 | * Version 9.2 27 | */ 28 | V9_2 = "v9.2", 29 | } 30 | -------------------------------------------------------------------------------- /src/microsoftsharepointonline/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./util"; 9 | -------------------------------------------------------------------------------- /src/microsoftsharepointonline/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class MicrosoftSharepointOnlineConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!MicrosoftSharepointOnlineConnectorType.actualInstance) { 13 | MicrosoftSharepointOnlineConnectorType.actualInstance = 14 | new MicrosoftSharepointOnlineConnectorType(); 15 | } 16 | return MicrosoftSharepointOnlineConnectorType.actualInstance; 17 | } 18 | 19 | private static actualInstance: ConnectorType; 20 | 21 | constructor() { 22 | super("MicrosoftSharePointOnline", true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/microsoftsharepointonline/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | /** 7 | * A utility class for building Microsoft Online token URLs. 8 | */ 9 | export class MicrosoftSharepointOnlineTokenUrlBuilder { 10 | public static buildTokenUrl(tenantId?: string) { 11 | return `https://login.microsoftonline.com/${tenantId ?? "common"}/oauth2/v2.0/token`; 12 | } 13 | } 14 | 15 | /** 16 | * An enum representing the Microsoft Sharepoint Online API versions. 17 | */ 18 | export enum MicrosoftSharepointOnlineApiVersion { 19 | /** 20 | * Version 1.0 21 | */ 22 | V1 = "v1.0", 23 | } 24 | -------------------------------------------------------------------------------- /src/redshift/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./destination"; 8 | -------------------------------------------------------------------------------- /src/redshift/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class RedshiftConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!RedshiftConnectorType.actualInstance) { 13 | RedshiftConnectorType.actualInstance = new RedshiftConnectorType(); 14 | } 15 | return RedshiftConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("Redshift", false); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/s3/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./destination"; 7 | export * from "./source"; 8 | -------------------------------------------------------------------------------- /src/s3/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IBucket } from "aws-cdk-lib/aws-s3"; 7 | import { IConstruct } from "constructs"; 8 | import { S3ConnectorType } from "./type"; 9 | import { AppFlowPermissionsManager } from "../core/appflow-permissions-manager"; 10 | import { ConnectorType } from "../core/connectors/connector-type"; 11 | import { IFlow } from "../core/flows"; 12 | import { ISource } from "../core/vertices/source"; 13 | 14 | /** 15 | * The file type that Amazon AppFlow gets from your Amazon S3 bucket. 16 | */ 17 | export enum S3InputFileType { 18 | CSV = "CSV", 19 | JSON = "JSON", 20 | } 21 | 22 | export interface S3InputFormat { 23 | readonly type: S3InputFileType; 24 | } 25 | 26 | export interface S3SourceProps { 27 | readonly bucket: IBucket; 28 | readonly prefix: string; 29 | readonly format?: S3InputFormat; 30 | } 31 | 32 | export class S3Source implements ISource { 33 | public readonly connectorType: ConnectorType = S3ConnectorType.instance; 34 | 35 | constructor(private readonly props: S3SourceProps) {} 36 | 37 | bind(scope: IFlow): CfnFlow.SourceFlowConfigProperty { 38 | this.tryAddNodeDependency(scope, this.props.bucket); 39 | AppFlowPermissionsManager.instance().grantBucketRead(this.props.bucket); 40 | 41 | return { 42 | connectorType: this.connectorType.asProfileConnectorType, 43 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 44 | }; 45 | } 46 | 47 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 48 | return { 49 | s3: { 50 | bucketName: this.props.bucket.bucketName, 51 | bucketPrefix: this.props.prefix, 52 | s3InputFormatConfig: this.props.format && { 53 | s3InputFileType: this.props.format.type, 54 | }, 55 | }, 56 | }; 57 | } 58 | 59 | private tryAddNodeDependency( 60 | scope: IConstruct, 61 | resource?: IConstruct | string, 62 | ): void { 63 | if (resource && typeof resource !== "string") { 64 | scope.node.addDependency(resource); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/s3/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class S3ConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!S3ConnectorType.actualInstance) { 13 | S3ConnectorType.actualInstance = new S3ConnectorType(); 14 | } 15 | return S3ConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("S3", false); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/salesforce-marketing-cloud/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./util"; 9 | -------------------------------------------------------------------------------- /src/salesforce-marketing-cloud/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { SalesforceMarketingCloudConnectorProfile } from "./profile"; 8 | import { SalesforceMarketingCloudConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices"; 12 | 13 | /** 14 | * Properties of a Salesforce Marketing Cloud Source 15 | */ 16 | export interface SalesforceMarketingCloudSourceProps { 17 | readonly profile: SalesforceMarketingCloudConnectorProfile; 18 | readonly apiVersion: string; 19 | readonly object: string; 20 | } 21 | 22 | /** 23 | * A class that represents a Salesforce Marketing Cloud Source 24 | */ 25 | export class SalesforceMarketingCloudSource implements ISource { 26 | /** 27 | * The AppFlow type of the connector that this source is implemented for 28 | */ 29 | public readonly connectorType: ConnectorType = 30 | SalesforceMarketingCloudConnectorType.instance; 31 | 32 | constructor(private readonly props: SalesforceMarketingCloudSourceProps) {} 33 | 34 | bind(scope: IFlow): CfnFlow.SourceFlowConfigProperty { 35 | this.tryAddNodeDependency(scope, this.props.profile); 36 | 37 | return { 38 | connectorType: this.connectorType.asProfileConnectorType, 39 | connectorProfileName: this.props.profile.name, 40 | apiVersion: this.props.apiVersion, 41 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 42 | }; 43 | } 44 | 45 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 46 | return { 47 | customConnector: { 48 | entityName: this.props.object, 49 | }, 50 | }; 51 | } 52 | 53 | private tryAddNodeDependency( 54 | scope: IConstruct, 55 | resource?: IConstruct | string, 56 | ): void { 57 | if (resource && typeof resource !== "string") { 58 | scope.node.addDependency(resource); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/salesforce-marketing-cloud/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class SalesforceMarketingCloudConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!SalesforceMarketingCloudConnectorType.actualInstance) { 13 | SalesforceMarketingCloudConnectorType.actualInstance = 14 | new SalesforceMarketingCloudConnectorType(); 15 | } 16 | return SalesforceMarketingCloudConnectorType.actualInstance; 17 | } 18 | 19 | private static actualInstance: ConnectorType; 20 | 21 | constructor() { 22 | super("SalesforceMarketingCloud", true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/salesforce-marketing-cloud/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | /** 6 | * A helper enum for SFMC api version 7 | */ 8 | export enum SalesforceMarketingCloudApiVersions { 9 | V1 = "v1", 10 | } 11 | -------------------------------------------------------------------------------- /src/salesforce/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./destination"; 9 | export * from "./salesforce-data-transfer-api"; 10 | -------------------------------------------------------------------------------- /src/salesforce/salesforce-data-transfer-api.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The default. Amazon AppFlow selects which API to use based on the number of records that your flow transfers to Salesforce. If your flow transfers fewer than 1,000 records, Amazon AppFlow uses Salesforce REST API. If your flow transfers 1,000 records or more, Amazon AppFlow uses Salesforce Bulk API 2.0. 3 | * 4 | * Each of these Salesforce APIs structures data differently. If Amazon AppFlow selects the API automatically, be aware that, for recurring flows, the data output might vary from one flow run to the next. For example, if a flow runs daily, it might use REST API on one day to transfer 900 records, and it might use Bulk API 2.0 on the next day to transfer 1,100 records. For each of these flow runs, the respective Salesforce API formats the data differently. Some of the differences include how dates are formatted and null values are represented. Also, Bulk API 2.0 doesn't transfer Salesforce compound fields. 5 | * 6 | * By choosing this option, you optimize flow performance for both small and large data transfers, but the tradeoff is inconsistent formatting in the output. 7 | */ 8 | export enum SalesforceDataTransferApi { 9 | AUTOMATIC = "AUTOMATIC", 10 | BULKV2 = "BULKV2", 11 | REST_SYNC = "REST_SYNC", 12 | } 13 | -------------------------------------------------------------------------------- /src/salesforce/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { SalesforceConnectorProfile } from "./profile"; 8 | import { SalesforceDataTransferApi } from "./salesforce-data-transfer-api"; 9 | import { SalesforceConnectorType } from "./type"; 10 | import { ConnectorType } from "../core/connectors/connector-type"; 11 | import { IFlow } from "../core/flows"; 12 | import { ISource } from "../core/vertices/source"; 13 | 14 | export interface SalesforceSourceProps { 15 | readonly profile: SalesforceConnectorProfile; 16 | 17 | /** 18 | * Specifies which Salesforce API is used by Amazon AppFlow when your flow transfers data from Salesforce. 19 | */ 20 | readonly dataTransferApi?: SalesforceDataTransferApi; 21 | 22 | readonly object: string; 23 | readonly apiVersion?: string; 24 | readonly enableDynamicFieldUpdate?: boolean; 25 | readonly includeDeletedRecords?: boolean; 26 | } 27 | 28 | export class SalesforceSource implements ISource { 29 | public readonly connectorType: ConnectorType = 30 | SalesforceConnectorType.instance; 31 | 32 | constructor(private readonly props: SalesforceSourceProps) {} 33 | 34 | bind(flow: IFlow): CfnFlow.SourceFlowConfigProperty { 35 | this.tryAddNodeDependency(flow, this.props.profile); 36 | 37 | return { 38 | connectorType: this.connectorType.asProfileConnectorType, 39 | connectorProfileName: this.props.profile.name, 40 | apiVersion: this.props.apiVersion, 41 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 42 | }; 43 | } 44 | 45 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 46 | return { 47 | salesforce: { 48 | dataTransferApi: this.props.dataTransferApi, 49 | enableDynamicFieldUpdate: this.props.enableDynamicFieldUpdate, 50 | includeDeletedRecords: this.props.includeDeletedRecords, 51 | object: this.props.object, 52 | }, 53 | }; 54 | } 55 | 56 | private tryAddNodeDependency( 57 | scope: IConstruct, 58 | resource?: IConstruct | string, 59 | ): void { 60 | if (resource && typeof resource !== "string") { 61 | scope.node.addDependency(resource); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/salesforce/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class SalesforceConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!SalesforceConnectorType.actualInstance) { 13 | SalesforceConnectorType.actualInstance = new SalesforceConnectorType(); 14 | } 15 | return SalesforceConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("Salesforce", false); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/sapodata/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./destination"; 9 | -------------------------------------------------------------------------------- /src/sapodata/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { SAPOdataConnectorProfile } from "./profile"; 8 | import { SAPOdataConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices/source"; 12 | 13 | export interface SAPOdataSourceProps { 14 | readonly profile: SAPOdataConnectorProfile; 15 | readonly object: string; 16 | } 17 | 18 | export class SAPOdataSource implements ISource { 19 | public readonly connectorType: ConnectorType = SAPOdataConnectorType.instance; 20 | 21 | constructor(private readonly props: SAPOdataSourceProps) {} 22 | 23 | bind(flow: IFlow): CfnFlow.SourceFlowConfigProperty { 24 | this.tryAddNodeDependency(flow, this.props.profile); 25 | 26 | return { 27 | connectorType: this.connectorType.asProfileConnectorType, 28 | connectorProfileName: this.props.profile.name, 29 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 30 | }; 31 | } 32 | 33 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 34 | return { 35 | sapoData: { 36 | objectPath: this.props.object, 37 | }, 38 | }; 39 | } 40 | 41 | private tryAddNodeDependency( 42 | scope: IConstruct, 43 | resource?: IConstruct | string, 44 | ): void { 45 | if (resource && typeof resource !== "string") { 46 | scope.node.addDependency(resource); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/sapodata/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class SAPOdataConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!SAPOdataConnectorType.actualInstance) { 13 | SAPOdataConnectorType.actualInstance = new SAPOdataConnectorType(); 14 | } 15 | return SAPOdataConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("SAPOData", false); 22 | } 23 | 24 | public get asTaskConnectorOperatorOrigin(): string { 25 | return "sapoData"; 26 | } 27 | 28 | public get asProfileConnectorType(): string { 29 | return this.name; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/servicenow/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./util"; 9 | -------------------------------------------------------------------------------- /src/servicenow/profile.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { SecretValue } from "aws-cdk-lib"; 6 | import { CfnConnectorProfile } from "aws-cdk-lib/aws-appflow"; 7 | import { Construct } from "constructs"; 8 | import { ServiceNowConnectorType } from "./type"; 9 | import { 10 | ConnectorProfileBase, 11 | ConnectorProfileProps, 12 | } from "../core/connectors/connector-profile"; 13 | 14 | export interface ServiceNowConnectorProfileProps extends ConnectorProfileProps { 15 | readonly basicAuth: ServiceNowBasicSettings; 16 | readonly instanceUrl: string; 17 | } 18 | 19 | export interface ServiceNowBasicSettings { 20 | readonly username: string; 21 | readonly password: SecretValue; 22 | } 23 | 24 | export class ServiceNowConnectorProfile extends ConnectorProfileBase { 25 | public static fromConnectionProfileArn( 26 | scope: Construct, 27 | id: string, 28 | arn: string, 29 | ) { 30 | return this._fromConnectorProfileAttributes(scope, id, { 31 | arn, 32 | }) as ServiceNowConnectorProfile; 33 | } 34 | 35 | public static fromConnectionProfileName( 36 | scope: Construct, 37 | id: string, 38 | name: string, 39 | ) { 40 | return this._fromConnectorProfileAttributes(scope, id, { 41 | name, 42 | }) as ServiceNowConnectorProfile; 43 | } 44 | 45 | constructor( 46 | scope: Construct, 47 | id: string, 48 | props: ServiceNowConnectorProfileProps, 49 | ) { 50 | super(scope, id, props, ServiceNowConnectorType.instance); 51 | } 52 | 53 | protected buildConnectorProfileCredentials( 54 | props: ConnectorProfileProps, 55 | ): CfnConnectorProfile.ConnectorProfileCredentialsProperty { 56 | const properties = props as ServiceNowConnectorProfileProps; 57 | return { 58 | serviceNow: { 59 | username: properties.basicAuth?.username, 60 | password: properties.basicAuth?.password.unsafeUnwrap(), 61 | }, 62 | }; 63 | } 64 | 65 | protected buildConnectorProfileProperties( 66 | props: ConnectorProfileProps, 67 | ): CfnConnectorProfile.ConnectorProfilePropertiesProperty { 68 | const properties = props as ServiceNowConnectorProfileProps; 69 | return { 70 | serviceNow: { 71 | instanceUrl: properties.instanceUrl, 72 | }, 73 | }; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/servicenow/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { ServiceNowConnectorProfile } from "./profile"; 8 | import { ServiceNowConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices/source"; 12 | 13 | export interface ServiceNowSourceProps { 14 | readonly profile: ServiceNowConnectorProfile; 15 | readonly object: string; 16 | } 17 | 18 | export class ServiceNowSource implements ISource { 19 | public readonly connectorType: ConnectorType = 20 | ServiceNowConnectorType.instance; 21 | 22 | constructor(private readonly props: ServiceNowSourceProps) {} 23 | 24 | bind(flow: IFlow): CfnFlow.SourceFlowConfigProperty { 25 | this.tryAddNodeDependency(flow, this.props.profile); 26 | 27 | return { 28 | connectorType: this.connectorType.asProfileConnectorType, 29 | connectorProfileName: this.props.profile.name, 30 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 31 | }; 32 | } 33 | 34 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 35 | return { 36 | serviceNow: { 37 | object: this.props.object, 38 | }, 39 | }; 40 | } 41 | 42 | private tryAddNodeDependency( 43 | scope: IConstruct, 44 | resource?: IConstruct | string, 45 | ): void { 46 | if (resource && typeof resource !== "string") { 47 | scope.node.addDependency(resource); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/servicenow/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class ServiceNowConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!ServiceNowConnectorType.actualInstance) { 13 | ServiceNowConnectorType.actualInstance = new ServiceNowConnectorType(); 14 | } 15 | return ServiceNowConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("ServiceNow", false); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/servicenow/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export class ServiceNowInstanceUrlBuilder { 6 | public static buildFromDomain(domain: string): string { 7 | return `https://${domain}.service-now.com`; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/slack/README.md: -------------------------------------------------------------------------------- 1 | 1. Slack uses authorization code grant for a user token 2 | 2. We can use a bot token as well, but this will have access only to a particular conversation that the bot got invited to 3 | 3. AppFlow currently cannot work with expiring access tokens 4 | 4. Actually, Slack only needs an access token. 5 | 6 | see: https://api.slack.com/authentication/token-types and https://api.slack.com/authentication/rotation -------------------------------------------------------------------------------- /src/slack/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./util"; 9 | -------------------------------------------------------------------------------- /src/slack/profile.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { SecretValue } from "aws-cdk-lib"; 6 | import { CfnConnectorProfile } from "aws-cdk-lib/aws-appflow"; 7 | import { Construct } from "constructs"; 8 | import { SlackConnectorType } from "./type"; 9 | import { 10 | ConnectorProfileBase, 11 | ConnectorProfileProps, 12 | } from "../core/connectors/connector-profile"; 13 | 14 | export interface SlackConnectorProfileProps extends ConnectorProfileProps { 15 | readonly oAuth: SlackOAuthSettings; 16 | readonly instanceUrl: string; 17 | } 18 | 19 | export interface SlackOAuthSettings { 20 | readonly accessToken: SecretValue; 21 | readonly clientId?: SecretValue; 22 | readonly clientSecret?: SecretValue; 23 | } 24 | 25 | export class SlackConnectorProfile extends ConnectorProfileBase { 26 | public static fromConnectionProfileArn( 27 | scope: Construct, 28 | id: string, 29 | arn: string, 30 | ) { 31 | return this._fromConnectorProfileAttributes(scope, id, { 32 | arn, 33 | }) as SlackConnectorProfile; 34 | } 35 | 36 | public static fromConnectionProfileName( 37 | scope: Construct, 38 | id: string, 39 | name: string, 40 | ) { 41 | return this._fromConnectorProfileAttributes(scope, id, { 42 | name, 43 | }) as SlackConnectorProfile; 44 | } 45 | 46 | constructor(scope: Construct, id: string, props: SlackConnectorProfileProps) { 47 | super(scope, id, props, SlackConnectorType.instance); 48 | } 49 | 50 | protected buildConnectorProfileProperties( 51 | props: ConnectorProfileProps, 52 | ): CfnConnectorProfile.ConnectorProfilePropertiesProperty { 53 | const properties = props as SlackConnectorProfileProps; 54 | return { 55 | slack: { 56 | instanceUrl: properties.instanceUrl, 57 | }, 58 | }; 59 | } 60 | 61 | protected buildConnectorProfileCredentials( 62 | props: ConnectorProfileProps, 63 | ): CfnConnectorProfile.ConnectorProfileCredentialsProperty { 64 | const properties = props as SlackConnectorProfileProps; 65 | return { 66 | slack: { 67 | accessToken: properties.oAuth.accessToken.unsafeUnwrap(), 68 | clientId: properties.oAuth.clientId?.unsafeUnwrap() ?? "dummyClientId", 69 | clientSecret: 70 | properties.oAuth.clientSecret?.unsafeUnwrap() ?? "dummyClientSecret", 71 | }, 72 | }; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/slack/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { SlackConnectorProfile } from "./profile"; 8 | import { SlackConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices/source"; 12 | 13 | export interface SlackSourceProps { 14 | readonly profile: SlackConnectorProfile; 15 | readonly object: string; 16 | readonly apiVersion?: string; 17 | } 18 | 19 | export class SlackSource implements ISource { 20 | public readonly connectorType: ConnectorType = SlackConnectorType.instance; 21 | 22 | constructor(private readonly props: SlackSourceProps) {} 23 | 24 | bind(flow: IFlow): CfnFlow.SourceFlowConfigProperty { 25 | this.tryAddNodeDependency(flow, this.props.profile); 26 | 27 | return { 28 | connectorType: this.connectorType.asProfileConnectorType, 29 | apiVersion: this.props.apiVersion, 30 | connectorProfileName: this.props.profile.name, 31 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 32 | }; 33 | } 34 | 35 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 36 | return { 37 | slack: { 38 | object: this.props.object, 39 | }, 40 | }; 41 | } 42 | 43 | private tryAddNodeDependency( 44 | scope: IConstruct, 45 | resource?: IConstruct | string, 46 | ): void { 47 | if (resource && typeof resource !== "string") { 48 | scope.node.addDependency(resource); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/slack/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class SlackConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!SlackConnectorType.actualInstance) { 13 | SlackConnectorType.actualInstance = new SlackConnectorType(); 14 | } 15 | return SlackConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("Slack", false); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/slack/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export class SlackInstanceUrlBuilder { 6 | public static buildFromWorkspace(workspace: string): string { 7 | return `https://${workspace}.slack.com`; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/snowflake/README.md: -------------------------------------------------------------------------------- 1 | Read: https://docs.snowflake.com/en/user-guide/data-load-s3-config-storage-integration 2 | 3 | Snowflake first: 4 | 1. Create the Snowflake components 5 | 2. With this create storage integration with some dummy IAM Role and S3 bucket values 6 | IMPORTANT: each time the storage integration is created/replaced a new STORAGE_AWS_EXTERNAL_ID is generated, so this operation should be done once 7 | 3. run `DESC INTEGRATION ` 8 | 4. save STORAGE_AWS_IAM_USER_ARN - this is static per an account 9 | 5. save STORAGE_AWS_EXTENRAL_ID - this can change so protect that 10 | 11 | AWS second: 12 | 1. create the S3 Bucket, IAM policy and IAM role for the integration using the STORAGE_AWS_IAM_USER_ARN, STORAGE_AWS_EXTERNAL_ID values 13 | 2. create the profile for the connector profile 14 | 15 | Snowflake again: 16 | 1. Run 17 | 18 | ```sql 19 | ALTER STORAGE INTEGRATION 20 | SET 21 | STORAGE_AWS_ROLE_ARN = 22 | STORAGE_ALLOWED_LOCATIONS = (''); 23 | ``` 24 | If you run `CREATE OR REPLACE` Snowflake will change the external id and you'll need to get back to correctign the AWS part. -------------------------------------------------------------------------------- /src/snowflake/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./destination"; 8 | -------------------------------------------------------------------------------- /src/snowflake/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class SnowflakeConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!SnowflakeConnectorType.actualInstance) { 13 | SnowflakeConnectorType.actualInstance = new SnowflakeConnectorType(); 14 | } 15 | return SnowflakeConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("Snowflake", false); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/zendesk/destination.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { ZendeskConnectorType } from "./type"; 8 | import { ConnectorType } from "../core/connectors/connector-type"; 9 | import { ErrorHandlingConfiguration } from "../core/error-handling"; 10 | import { IFlow } from "../core/flows"; 11 | import { IDestination } from "../core/vertices/destination"; 12 | import { WriteOperation } from "../core/write-operation"; 13 | import { ZendeskConnectorProfile } from "../zendesk/profile"; 14 | 15 | export interface ZendeskDestinationProps { 16 | readonly profile: ZendeskConnectorProfile; 17 | 18 | /** 19 | * The settings that determine how Amazon AppFlow handles an error when placing data in the Zendesk destination. For example, this setting would determine if the flow should fail after one insertion error, or continue and attempt to insert every record regardless of the initial failure. 20 | */ 21 | readonly errorHandling?: ErrorHandlingConfiguration; 22 | 23 | /** 24 | * The Zendesk object for which the operation is to be set. 25 | */ 26 | readonly object: string; 27 | 28 | readonly operation: WriteOperation; 29 | } 30 | 31 | export class ZendeskDestination implements IDestination { 32 | public readonly connectorType: ConnectorType = ZendeskConnectorType.instance; 33 | 34 | constructor(private readonly props: ZendeskDestinationProps) {} 35 | 36 | bind(flow: IFlow): CfnFlow.DestinationFlowConfigProperty { 37 | this.tryAddNodeDependency( 38 | flow, 39 | this.props.errorHandling?.errorLocation?.bucket, 40 | ); 41 | this.tryAddNodeDependency(flow, this.props.profile); 42 | 43 | return { 44 | connectorType: this.connectorType.asProfileConnectorType, 45 | connectorProfileName: this.props.profile.name, 46 | destinationConnectorProperties: 47 | this.buildDestinationConnectorProperties(), 48 | }; 49 | } 50 | 51 | private buildDestinationConnectorProperties(): CfnFlow.DestinationConnectorPropertiesProperty { 52 | return { 53 | zendesk: { 54 | errorHandlingConfig: this.props.errorHandling && { 55 | bucketName: 56 | this.props.errorHandling?.errorLocation?.bucket.bucketName, 57 | bucketPrefix: this.props.errorHandling?.errorLocation?.prefix, 58 | failOnFirstError: this.props.errorHandling.failOnFirstError, 59 | }, 60 | idFieldNames: this.props.operation.ids, 61 | object: this.props.object, 62 | writeOperationType: this.props.operation.type, 63 | }, 64 | }; 65 | } 66 | 67 | private tryAddNodeDependency(scope: IConstruct, resource?: IConstruct): void { 68 | if (resource) { 69 | scope.node.addDependency(resource); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/zendesk/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export * from "./type"; 6 | export * from "./profile"; 7 | export * from "./source"; 8 | export * from "./util"; 9 | -------------------------------------------------------------------------------- /src/zendesk/profile.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { SecretValue } from "aws-cdk-lib"; 6 | import { CfnConnectorProfile } from "aws-cdk-lib/aws-appflow"; 7 | import { Construct } from "constructs"; 8 | import { ZendeskConnectorType } from "./type"; 9 | import { 10 | ConnectorProfileBase, 11 | ConnectorProfileProps, 12 | } from "../core/connectors/connector-profile"; 13 | 14 | export interface ZendeskConnectorProfileProps extends ConnectorProfileProps { 15 | readonly oAuth: ZendeskOAuthSettings; 16 | readonly instanceUrl: string; 17 | } 18 | 19 | export interface ZendeskOAuthSettings { 20 | readonly accessToken?: SecretValue; 21 | readonly clientId: SecretValue; 22 | readonly clientSecret: SecretValue; 23 | } 24 | 25 | export class ZendeskConnectorProfile extends ConnectorProfileBase { 26 | public static fromConnectionProfileArn( 27 | scope: Construct, 28 | id: string, 29 | arn: string, 30 | ) { 31 | return this._fromConnectorProfileAttributes(scope, id, { 32 | arn, 33 | }) as ZendeskConnectorProfile; 34 | } 35 | 36 | public static fromConnectionProfileName( 37 | scope: Construct, 38 | id: string, 39 | name: string, 40 | ) { 41 | return this._fromConnectorProfileAttributes(scope, id, { 42 | name, 43 | }) as ZendeskConnectorProfile; 44 | } 45 | 46 | constructor( 47 | scope: Construct, 48 | id: string, 49 | props: ZendeskConnectorProfileProps, 50 | ) { 51 | super(scope, id, props, ZendeskConnectorType.instance); 52 | } 53 | 54 | protected buildConnectorProfileProperties( 55 | props: ConnectorProfileProps, 56 | ): CfnConnectorProfile.ConnectorProfilePropertiesProperty { 57 | const properties = props as ZendeskConnectorProfileProps; 58 | return { 59 | zendesk: { 60 | instanceUrl: properties.instanceUrl, 61 | }, 62 | }; 63 | } 64 | 65 | protected buildConnectorProfileCredentials( 66 | props: ConnectorProfileProps, 67 | ): CfnConnectorProfile.ConnectorProfileCredentialsProperty { 68 | const properties = props as ZendeskConnectorProfileProps; 69 | return { 70 | zendesk: { 71 | accessToken: properties.oAuth.accessToken?.unsafeUnwrap(), 72 | clientId: properties.oAuth.clientId.unsafeUnwrap(), 73 | clientSecret: properties.oAuth.clientSecret.unsafeUnwrap(), 74 | }, 75 | }; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/zendesk/source.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { CfnFlow } from "aws-cdk-lib/aws-appflow"; 6 | import { IConstruct } from "constructs"; 7 | import { ZendeskConnectorProfile } from "./profile"; 8 | import { ZendeskConnectorType } from "./type"; 9 | import { ConnectorType } from "../core/connectors/connector-type"; 10 | import { IFlow } from "../core/flows"; 11 | import { ISource } from "../core/vertices/source"; 12 | 13 | export interface ZendeskSourceProps { 14 | readonly profile: ZendeskConnectorProfile; 15 | readonly object: string; 16 | readonly apiVersion?: string; 17 | } 18 | 19 | export class ZendeskSource implements ISource { 20 | public readonly connectorType: ConnectorType = ZendeskConnectorType.instance; 21 | 22 | constructor(private readonly props: ZendeskSourceProps) {} 23 | 24 | bind(flow: IFlow): CfnFlow.SourceFlowConfigProperty { 25 | this.tryAddNodeDependency(flow, this.props.profile); 26 | 27 | return { 28 | connectorType: this.connectorType.asProfileConnectorType, 29 | apiVersion: this.props.apiVersion, 30 | connectorProfileName: this.props.profile.name, 31 | sourceConnectorProperties: this.buildSourceConnectorProperties(), 32 | }; 33 | } 34 | 35 | private buildSourceConnectorProperties(): CfnFlow.SourceConnectorPropertiesProperty { 36 | return { 37 | zendesk: { 38 | object: this.props.object, 39 | }, 40 | }; 41 | } 42 | 43 | private tryAddNodeDependency( 44 | scope: IConstruct, 45 | resource?: IConstruct | string, 46 | ) { 47 | if (resource && typeof resource !== "string") { 48 | scope.node.addDependency(resource); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/zendesk/type.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { ConnectorType } from "../core/connectors/connector-type"; 6 | 7 | /** 8 | * @internal 9 | */ 10 | export class ZendeskConnectorType extends ConnectorType { 11 | public static get instance(): ConnectorType { 12 | if (!ZendeskConnectorType.actualInstance) { 13 | ZendeskConnectorType.actualInstance = new ZendeskConnectorType(); 14 | } 15 | return ZendeskConnectorType.actualInstance; 16 | } 17 | 18 | private static actualInstance: ConnectorType; 19 | 20 | constructor() { 21 | super("Zendesk", false); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/zendesk/util.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | export class ZendeskInstanceUrlBuilder { 6 | public static buildFromAccount(account: string): string { 7 | return `https://${account}.zendesk.com`; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/asana/profile.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { SecretValue, Stack } from "aws-cdk-lib"; 6 | import { Template } from "aws-cdk-lib/assertions"; 7 | import { AsanaConnectorProfile } from "../../src"; 8 | 9 | describe("AsanaConnectorProfileProps", () => { 10 | test("API Key profile with credentials exists in the stack", () => { 11 | const stack = new Stack(undefined, "TestStack", { 12 | env: { account: "12345678", region: "dummy" }, 13 | }); 14 | 15 | new AsanaConnectorProfile(stack, "TestProfile", { 16 | patToken: SecretValue.unsafePlainText("patToken"), 17 | }); 18 | 19 | Template.fromStack(stack).hasResourceProperties( 20 | "AWS::AppFlow::ConnectorProfile", 21 | { 22 | ConnectionMode: "Public", 23 | ConnectorLabel: "Asana", 24 | ConnectorProfileName: "TestStackTestProfile18724107", 25 | ConnectorType: "CustomConnector", 26 | ConnectorProfileConfig: { 27 | ConnectorProfileCredentials: { 28 | CustomConnector: { 29 | AuthenticationType: "CUSTOM", 30 | Custom: { 31 | CredentialsMap: { 32 | patToken: "patToken", 33 | }, 34 | CustomAuthenticationType: "PAT", 35 | }, 36 | }, 37 | }, 38 | ConnectorProfileProperties: { 39 | CustomConnector: { 40 | ProfileProperties: {}, 41 | }, 42 | }, 43 | }, 44 | }, 45 | ); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /test/asana/source.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { 8 | AsanaConnectorProfile, 9 | AsanaSource, 10 | AsanaConnectorType, 11 | OnDemandFlow, 12 | S3Destination, 13 | Mapping, 14 | } from "../../src"; 15 | 16 | describe("AsanaSource", () => { 17 | test("Source with connector name", () => { 18 | const stack = new Stack(undefined, "TestStack"); 19 | const source = new AsanaSource({ 20 | profile: AsanaConnectorProfile.fromConnectionProfileName( 21 | stack, 22 | "TestProfile", 23 | "dummy-profile", 24 | ), 25 | object: "workspace", 26 | }); 27 | 28 | const destination = new S3Destination({ 29 | location: { bucket: new Bucket(stack, "TestBucket") }, 30 | }); 31 | 32 | new OnDemandFlow(stack, "TestFlow", { 33 | source: source, 34 | destination: destination, 35 | mappings: [Mapping.mapAll()], 36 | }); 37 | 38 | const expectedConnectorType = AsanaConnectorType.instance; 39 | expect(source.connectorType.asProfileConnectorLabel).toEqual( 40 | expectedConnectorType.asProfileConnectorLabel, 41 | ); 42 | expect(source.connectorType.asProfileConnectorType).toEqual( 43 | expectedConnectorType.asProfileConnectorType, 44 | ); 45 | expect(source.connectorType.asTaskConnectorOperatorOrigin).toEqual( 46 | expectedConnectorType.asTaskConnectorOperatorOrigin, 47 | ); 48 | expect(source.connectorType.isCustom).toEqual( 49 | expectedConnectorType.isCustom, 50 | ); 51 | }); 52 | 53 | test("Source with connector Arn", () => { 54 | const stack = new Stack(undefined, "TestStack"); 55 | const source = new AsanaSource({ 56 | profile: AsanaConnectorProfile.fromConnectionProfileArn( 57 | stack, 58 | "TestProfile", 59 | "arn:aws:appflow:region:account-id:connectorprofile/TestProfile", 60 | ), 61 | object: "workspace", 62 | }); 63 | 64 | const destination = new S3Destination({ 65 | location: { bucket: new Bucket(stack, "TestBucket") }, 66 | }); 67 | 68 | new OnDemandFlow(stack, "TestFlow", { 69 | source: source, 70 | destination: destination, 71 | mappings: [Mapping.mapAll()], 72 | }); 73 | 74 | const expectedConnectorType = AsanaConnectorType.instance; 75 | expect(source.connectorType.asProfileConnectorLabel).toEqual( 76 | expectedConnectorType.asProfileConnectorLabel, 77 | ); 78 | expect(source.connectorType.asProfileConnectorType).toEqual( 79 | expectedConnectorType.asProfileConnectorType, 80 | ); 81 | expect(source.connectorType.asTaskConnectorOperatorOrigin).toEqual( 82 | expectedConnectorType.asTaskConnectorOperatorOrigin, 83 | ); 84 | expect(source.connectorType.isCustom).toEqual( 85 | expectedConnectorType.isCustom, 86 | ); 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /test/core/flows/flow-time-updater/flow-time-updater-function.test.ts: -------------------------------------------------------------------------------- 1 | import { Duration } from "aws-cdk-lib"; 2 | import { Schedule } from "aws-cdk-lib/aws-events"; 3 | import type { CloudFormationCustomResourceEvent } from "aws-lambda"; 4 | import * as API from "../../../../src/core/flows/flow-time-updater/api"; 5 | import { handler } from "../../../../src/core/flows/flow-time-updater/flow-time-updater.lambda"; 6 | 7 | describe("flow time updater function", () => { 8 | it("converts CDK rate expressions to AppFlow rate expressions", async () => { 9 | const cdkExpression = Schedule.rate(Duration.days(1)).expressionString; 10 | expect(cdkExpression).toEqual("rate(1 day)"); // validate assumption 11 | 12 | const result = await handler(createEvent({ schedule: cdkExpression })); 13 | 14 | expect(result).toEqual({ 15 | Data: { 16 | [API.ATTR_SCHEDULE]: "rate(1days)", // no space + pluralized 17 | [API.ATTR_STARTTIME]: undefined, 18 | [API.ATTR_ENDTIME]: undefined, 19 | }, 20 | }); 21 | }); 22 | }); 23 | 24 | function createEvent(props: { 25 | schedule: string; 26 | startTime?: string; 27 | endTime?: string; 28 | }): CloudFormationCustomResourceEvent { 29 | const { schedule, startTime, endTime } = props; 30 | 31 | const event: CloudFormationCustomResourceEvent = { 32 | RequestType: "Create", 33 | ResourceProperties: { 34 | [API.PROP_SCHEDULE]: schedule, 35 | [API.PROP_STARTTIME]: startTime, 36 | [API.PROP_ENDTIME]: endTime, 37 | ServiceToken: "", 38 | }, 39 | 40 | // These are boilerplate values that are not used in the function 41 | ServiceToken: "", 42 | ResponseURL: "", 43 | StackId: "", 44 | RequestId: "", 45 | LogicalResourceId: "", 46 | ResourceType: "", 47 | }; 48 | return event; 49 | } 50 | -------------------------------------------------------------------------------- /test/core/flows/on-demand-flow-metrics.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { Stack } from "aws-cdk-lib"; 6 | import { Template } from "aws-cdk-lib/assertions"; 7 | import { Alarm, Metric } from "aws-cdk-lib/aws-cloudwatch"; 8 | import { Key } from "aws-cdk-lib/aws-kms"; 9 | import { Bucket } from "aws-cdk-lib/aws-s3"; 10 | import { OnDemandFlow, S3Source, S3Destination, Mapping } from "../../../src"; 11 | 12 | describe("OnDemandFlow metrics", () => { 13 | test("default", () => { 14 | const stack = new Stack(undefined, "TestStack"); 15 | 16 | const bucket = new Bucket(stack, "TestBucket"); 17 | 18 | const source = new S3Source({ 19 | bucket: bucket, 20 | prefix: "account", 21 | }); 22 | 23 | const destination = new S3Destination({ 24 | location: { bucket, prefix: "new-account" }, 25 | }); 26 | 27 | const flow = new OnDemandFlow(stack, "OnDemandFlow", { 28 | source, 29 | destination, 30 | key: new Key(stack, "TestKey"), 31 | mappings: [Mapping.mapAll()], 32 | }); 33 | 34 | addAlarmForMetric( 35 | stack, 36 | flow.metricFlowExecutionsStarted(), 37 | "FlowExecutionsStartedAlarm", 38 | ); 39 | addAlarmForMetric( 40 | stack, 41 | flow.metricFlowExecutionsFailed(), 42 | "FlowExecutionsFailedAlarm", 43 | ); 44 | addAlarmForMetric( 45 | stack, 46 | flow.metricFlowExecutionsSucceeded(), 47 | "FlowxecutionsSucceededAlarm", 48 | ); 49 | addAlarmForMetric( 50 | stack, 51 | flow.metricFlowExecutionTime(), 52 | "FlowExecutionTimeAlarm", 53 | ); 54 | addAlarmForMetric( 55 | stack, 56 | flow.metricFlowExecutionRecordsProcessed(), 57 | "FlowExecutionRecordsProcessedAlarm", 58 | ); 59 | 60 | const template = Template.fromStack(stack); 61 | 62 | template.resourceCountIs("AWS::CloudWatch::Alarm", 5); 63 | template.hasResourceProperties("AWS::CloudWatch::Alarm", { 64 | MetricName: "FlowExecutionsStarted", 65 | Namespace: "AWS/AppFlow", 66 | }); 67 | template.hasResourceProperties("AWS::CloudWatch::Alarm", { 68 | MetricName: "FlowExecutionsFailed", 69 | Namespace: "AWS/AppFlow", 70 | }); 71 | template.hasResourceProperties("AWS::CloudWatch::Alarm", { 72 | MetricName: "FlowExecutionsSucceeded", 73 | Namespace: "AWS/AppFlow", 74 | }); 75 | template.hasResourceProperties("AWS::CloudWatch::Alarm", { 76 | MetricName: "FlowExecutionTime", 77 | Namespace: "AWS/AppFlow", 78 | }); 79 | template.hasResourceProperties("AWS::CloudWatch::Alarm", { 80 | MetricName: "FlowExecutionRecordsProcessed", 81 | Namespace: "AWS/AppFlow", 82 | }); 83 | }); 84 | }); 85 | 86 | function addAlarmForMetric(stack: Stack, metric: Metric, name: string) { 87 | new Alarm(stack, name, { 88 | metric, 89 | threshold: 1000, 90 | evaluationPeriods: 2, 91 | }); 92 | } 93 | -------------------------------------------------------------------------------- /test/core/flows/on-demand-flow.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { Stack } from "aws-cdk-lib"; 6 | import { Template } from "aws-cdk-lib/assertions"; 7 | import { Key } from "aws-cdk-lib/aws-kms"; 8 | import { Bucket } from "aws-cdk-lib/aws-s3"; 9 | import { OnDemandFlow, S3Source, S3Destination, Mapping } from "../../../src"; 10 | 11 | describe("OnDemandFlow", () => { 12 | test("default", () => { 13 | const stack = new Stack(undefined, "TestStack"); 14 | 15 | const bucket = new Bucket(stack, "TestBucket"); 16 | 17 | const source = new S3Source({ 18 | bucket: bucket, 19 | prefix: "account", 20 | }); 21 | 22 | const destination = new S3Destination({ 23 | location: { bucket, prefix: "new-account" }, 24 | }); 25 | 26 | new OnDemandFlow(stack, "OnDemandFlow", { 27 | source, 28 | destination, 29 | key: new Key(stack, "TestKey"), 30 | mappings: [Mapping.mapAll()], 31 | }); 32 | 33 | const template = Template.fromStack(stack); 34 | 35 | template.hasResourceProperties("AWS::AppFlow::Flow", { 36 | DestinationFlowConfigList: [ 37 | { 38 | ConnectorType: "S3", 39 | DestinationConnectorProperties: { 40 | S3: { 41 | BucketName: { 42 | Ref: "TestBucket560B80BC", 43 | }, 44 | BucketPrefix: "new-account", 45 | }, 46 | }, 47 | }, 48 | ], 49 | FlowName: "TestStackOnDemandFlow53F97EB9", 50 | SourceFlowConfig: { 51 | ConnectorType: "S3", 52 | SourceConnectorProperties: { 53 | S3: { 54 | BucketName: { 55 | Ref: "TestBucket560B80BC", 56 | }, 57 | BucketPrefix: "account", 58 | }, 59 | }, 60 | }, 61 | Tasks: [ 62 | { 63 | ConnectorOperator: { 64 | S3: "NO_OP", 65 | }, 66 | SourceFields: [], 67 | TaskProperties: [ 68 | { 69 | Key: "EXCLUDE_SOURCE_FIELDS_LIST", 70 | Value: "[]", 71 | }, 72 | ], 73 | TaskType: "Map_all", 74 | }, 75 | ], 76 | TriggerConfig: { 77 | TriggerType: "OnDemand", 78 | }, 79 | KMSArn: { 80 | "Fn::GetAtt": ["TestKey4CACAF33", "Arn"], 81 | }, 82 | }); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /test/googleads/profile.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { SecretValue, Stack } from "aws-cdk-lib"; 6 | import { Template } from "aws-cdk-lib/assertions"; 7 | 8 | import { GoogleAdsConnectorProfile, GoogleAdsApiVersion } from "../../src"; 9 | 10 | describe("GoogleAdsConnectorProfile", () => { 11 | test("OAuth2 profile with direct client credentials exists in the stack", () => { 12 | const stack = new Stack(undefined, "TestStack", { 13 | env: { account: "12345678", region: "dummy" }, 14 | }); 15 | 16 | // readonly oAuth: GoogleAdsOAuthSettings; 17 | // readonly apiVersion: string; 18 | // readonly managerID: string; 19 | // readonly developerToken: string; 20 | new GoogleAdsConnectorProfile(stack, "TestProfile", { 21 | oAuth: { 22 | accessToken: SecretValue.unsafePlainText("accessToken"), 23 | flow: { 24 | refreshTokenGrant: { 25 | refreshToken: SecretValue.unsafePlainText("refreshToken"), 26 | clientId: SecretValue.unsafePlainText("clientId"), 27 | clientSecret: SecretValue.unsafePlainText("clientSecret"), 28 | }, 29 | }, 30 | }, 31 | apiVersion: GoogleAdsApiVersion.V16, 32 | managerID: SecretValue.unsafePlainText("managerId"), 33 | developerToken: SecretValue.unsafePlainText("developerToken"), 34 | }); 35 | 36 | Template.fromStack(stack).hasResourceProperties( 37 | "AWS::AppFlow::ConnectorProfile", 38 | { 39 | ConnectionMode: "Public", 40 | ConnectorLabel: "GoogleAds", 41 | ConnectorProfileName: "TestStackTestProfile18724107", 42 | ConnectorType: "CustomConnector", 43 | ConnectorProfileConfig: { 44 | ConnectorProfileCredentials: { 45 | CustomConnector: { 46 | AuthenticationType: "OAUTH2", 47 | Oauth2: { 48 | AccessToken: "accessToken", 49 | ClientId: "clientId", 50 | ClientSecret: "clientSecret", 51 | RefreshToken: "refreshToken", 52 | }, 53 | }, 54 | }, 55 | ConnectorProfileProperties: { 56 | CustomConnector: { 57 | OAuth2Properties: { 58 | OAuth2GrantType: "AUTHORIZATION_CODE", 59 | TokenUrl: "https://oauth2.googleapis.com/token", 60 | }, 61 | }, 62 | }, 63 | }, 64 | }, 65 | ); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /test/integ/ondemand-asana-to-s3.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6": { 5 | "source": { 6 | "path": "asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6", 7 | "packaging": "zip" 8 | }, 9 | "destinations": { 10 | "current_account-current_region": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 12 | "objectKey": "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6.zip", 13 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 14 | } 15 | } 16 | }, 17 | "47a2b281fe9fc8be079da82791f28e2055aa9b90b02963e506a48904025425e4": { 18 | "source": { 19 | "path": "TestStack.template.json", 20 | "packaging": "file" 21 | }, 22 | "destinations": { 23 | "current_account-current_region": { 24 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 25 | "objectKey": "47a2b281fe9fc8be079da82791f28e2055aa9b90b02963e506a48904025425e4.json", 26 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 27 | } 28 | } 29 | } 30 | }, 31 | "dockerImages": {} 32 | } -------------------------------------------------------------------------------- /test/integ/ondemand-asana-to-s3.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 8 | import { 9 | Mapping, 10 | OnDemandFlow, 11 | S3Destination, 12 | AsanaConnectorProfile, 13 | AsanaSource, 14 | } from "../../src"; 15 | 16 | const app = new App({ 17 | treeMetadata: false, 18 | }); 19 | 20 | const stack = new Stack(app, "TestStack"); 21 | 22 | const secret = Secret.fromSecretNameV2(stack, "TestSecret", "appflow/asana"); 23 | 24 | const profile = new AsanaConnectorProfile(stack, "TestConnectorProfile", { 25 | patToken: secret.secretValueFromJson("patToken"), 26 | }); 27 | 28 | const source = new AsanaSource({ 29 | profile: profile, 30 | object: secret.secretValueFromJson("object").toString(), 31 | }); 32 | 33 | const bucket = new Bucket(stack, "TestBucket", { 34 | autoDeleteObjects: true, 35 | removalPolicy: RemovalPolicy.DESTROY, 36 | }); 37 | 38 | const destination = new S3Destination({ 39 | location: { bucket }, 40 | }); 41 | 42 | new OnDemandFlow(stack, "OnDemandFlow", { 43 | source: source, 44 | destination: destination, 45 | mappings: [Mapping.mapAll()], 46 | }); 47 | 48 | app.synth(); 49 | -------------------------------------------------------------------------------- /test/integ/ondemand-googleanalytics4-to-s3.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6": { 5 | "source": { 6 | "path": "asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6", 7 | "packaging": "zip" 8 | }, 9 | "destinations": { 10 | "current_account-current_region": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 12 | "objectKey": "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6.zip", 13 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 14 | } 15 | } 16 | }, 17 | "fac84bc66539a4f3a1b39c29bfd2b3f6a621cddaced08c38dd779c3023cd7456": { 18 | "source": { 19 | "path": "TestStack.template.json", 20 | "packaging": "file" 21 | }, 22 | "destinations": { 23 | "current_account-current_region": { 24 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 25 | "objectKey": "fac84bc66539a4f3a1b39c29bfd2b3f6a621cddaced08c38dd779c3023cd7456.json", 26 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 27 | } 28 | } 29 | } 30 | }, 31 | "dockerImages": {} 32 | } -------------------------------------------------------------------------------- /test/integ/ondemand-googleanalytics4-to-s3.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 8 | import { 9 | GoogleAnalytics4ApiVersion, 10 | GoogleAnalytics4ConnectorProfile, 11 | GoogleAnalytics4Source, 12 | Mapping, 13 | OnDemandFlow, 14 | S3Destination, 15 | } from "../../src"; 16 | 17 | const app = new App({ 18 | treeMetadata: false, 19 | }); 20 | 21 | const stack = new Stack(app, "TestStack"); 22 | 23 | const secret = Secret.fromSecretNameV2(stack, "TestSecret", "appflow/ga4"); 24 | 25 | const profile = new GoogleAnalytics4ConnectorProfile(stack, "TestConnector", { 26 | oAuth: { 27 | flow: { 28 | refreshTokenGrant: { 29 | refreshToken: secret.secretValueFromJson("refreshToken"), 30 | clientId: secret.secretValueFromJson("clientId"), 31 | clientSecret: secret.secretValueFromJson("clientSecret"), 32 | }, 33 | }, 34 | }, 35 | }); 36 | 37 | const source = new GoogleAnalytics4Source({ 38 | profile: profile, 39 | apiVersion: GoogleAnalytics4ApiVersion.V1BETA, 40 | object: secret.secretValueFromJson("coreReport").toString(), 41 | }); 42 | 43 | const bucket = new Bucket(stack, "TestBucket", { 44 | autoDeleteObjects: true, 45 | removalPolicy: RemovalPolicy.DESTROY, 46 | }); 47 | 48 | const destination = new S3Destination({ 49 | location: { bucket }, 50 | }); 51 | 52 | new OnDemandFlow(stack, "OnDemandFlow", { 53 | source: source, 54 | destination: destination, 55 | mappings: [ 56 | Mapping.map( 57 | { name: "achievementId", dataType: "String" }, 58 | { name: "achievementId", dataType: "String" }, 59 | ), 60 | Mapping.map( 61 | { name: "adFormat", dataType: "String" }, 62 | { name: "adFormat", dataType: "String" }, 63 | ), 64 | Mapping.map( 65 | { name: "adSourceName", dataType: "String" }, 66 | { name: "adSourceName", dataType: "String" }, 67 | ), 68 | ], 69 | }); 70 | 71 | app.synth(); 72 | -------------------------------------------------------------------------------- /test/integ/ondemand-hubspot-to-s3.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6": { 5 | "source": { 6 | "path": "asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6", 7 | "packaging": "zip" 8 | }, 9 | "destinations": { 10 | "current_account-current_region": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 12 | "objectKey": "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6.zip", 13 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 14 | } 15 | } 16 | }, 17 | "9e3f1c511fbc36d0243ab4e9f4cccc65504dc0260d1381ddf2646dcd2d57be51": { 18 | "source": { 19 | "path": "TestStack.template.json", 20 | "packaging": "file" 21 | }, 22 | "destinations": { 23 | "current_account-current_region": { 24 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 25 | "objectKey": "9e3f1c511fbc36d0243ab4e9f4cccc65504dc0260d1381ddf2646dcd2d57be51.json", 26 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 27 | } 28 | } 29 | } 30 | }, 31 | "dockerImages": {} 32 | } -------------------------------------------------------------------------------- /test/integ/ondemand-hubspot-to-s3.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 8 | import { 9 | HubSpotApiVersion, 10 | HubSpotConnectorProfile, 11 | HubSpotSource, 12 | Mapping, 13 | OnDemandFlow, 14 | S3Destination, 15 | } from "../../src"; 16 | 17 | const app = new App({ 18 | treeMetadata: false, 19 | }); 20 | 21 | const stack = new Stack(app, "TestStack"); 22 | 23 | const secret = Secret.fromSecretNameV2(stack, "TestSecret", "appflow/hubspot"); 24 | 25 | const profile = new HubSpotConnectorProfile(stack, "TestConnector", { 26 | oAuth: { 27 | flow: { 28 | refreshTokenGrant: { 29 | refreshToken: secret.secretValueFromJson("refreshToken"), 30 | clientId: secret.secretValueFromJson("clientId"), 31 | clientSecret: secret.secretValueFromJson("clientSecret"), 32 | }, 33 | }, 34 | }, 35 | }); 36 | 37 | const source = new HubSpotSource({ 38 | profile: profile, 39 | apiVersion: HubSpotApiVersion.V4, 40 | entity: ["association_label", "ticket", "contact"], 41 | }); 42 | 43 | const bucket = new Bucket(stack, "TestBucket", { 44 | autoDeleteObjects: true, 45 | removalPolicy: RemovalPolicy.DESTROY, 46 | }); 47 | 48 | const destination = new S3Destination({ 49 | location: { bucket }, 50 | }); 51 | 52 | new OnDemandFlow(stack, "OnDemandFlow", { 53 | source: source, 54 | destination: destination, 55 | mappings: [Mapping.mapAll()], 56 | }); 57 | 58 | app.synth(); 59 | -------------------------------------------------------------------------------- /test/integ/ondemand-jdbcsmalldatascale-to-amazonrdsforpostgresql.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "9dd52abf0489ce71ca2300e218bd47d2fc5454dfecdf034daf6229b6823feec4": { 5 | "source": { 6 | "path": "TestStack.template.json", 7 | "packaging": "file" 8 | }, 9 | "destinations": { 10 | "current_account-current_region": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 12 | "objectKey": "9dd52abf0489ce71ca2300e218bd47d2fc5454dfecdf034daf6229b6823feec4.json", 13 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 14 | } 15 | } 16 | } 17 | }, 18 | "dockerImages": {} 19 | } -------------------------------------------------------------------------------- /test/integ/ondemand-jdbcsmalldatascale-to-amazonrdsforpostgresql.integ.snapshot/cdk.out: -------------------------------------------------------------------------------- 1 | {"version":"40.0.0"} -------------------------------------------------------------------------------- /test/integ/ondemand-jdbcsmalldatascale-to-amazonrdsforpostgresql.integ.snapshot/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "artifacts": { 4 | "TestStack.assets": { 5 | "type": "cdk:asset-manifest", 6 | "properties": { 7 | "file": "TestStack.assets.json", 8 | "requiresBootstrapStackVersion": 6, 9 | "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" 10 | } 11 | }, 12 | "TestStack": { 13 | "type": "aws:cloudformation:stack", 14 | "environment": "aws://unknown-account/unknown-region", 15 | "properties": { 16 | "templateFile": "TestStack.template.json", 17 | "terminationProtection": false, 18 | "validateOnSynth": false, 19 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", 20 | "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", 21 | "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/9dd52abf0489ce71ca2300e218bd47d2fc5454dfecdf034daf6229b6823feec4.json", 22 | "requiresBootstrapStackVersion": 6, 23 | "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", 24 | "additionalDependencies": [ 25 | "TestStack.assets" 26 | ], 27 | "lookupRole": { 28 | "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", 29 | "requiresBootstrapStackVersion": 8, 30 | "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" 31 | } 32 | }, 33 | "dependencies": [ 34 | "TestStack.assets" 35 | ], 36 | "metadata": { 37 | "/TestStack/JdbcSmallTestConnectorProfile/Resource": [ 38 | { 39 | "type": "aws:cdk:logicalId", 40 | "data": "JdbcSmallTestConnectorProfile4B32988D" 41 | } 42 | ], 43 | "/TestStack/AmazonRdsTestConnectorProfile/Resource": [ 44 | { 45 | "type": "aws:cdk:logicalId", 46 | "data": "AmazonRdsTestConnectorProfile5A37DC65" 47 | } 48 | ], 49 | "/TestStack/OnDemandFlow/Resource": [ 50 | { 51 | "type": "aws:cdk:logicalId", 52 | "data": "OnDemandFlow00CE33FE" 53 | } 54 | ], 55 | "/TestStack/BootstrapVersion": [ 56 | { 57 | "type": "aws:cdk:logicalId", 58 | "data": "BootstrapVersion" 59 | } 60 | ], 61 | "/TestStack/CheckBootstrapVersion": [ 62 | { 63 | "type": "aws:cdk:logicalId", 64 | "data": "CheckBootstrapVersion" 65 | } 66 | ] 67 | }, 68 | "displayName": "TestStack" 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /test/integ/ondemand-jdbcsmalldatascale-to-amazonrdsforpostgresql.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, Stack, Token } from "aws-cdk-lib"; 6 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 7 | import { 8 | AmazonRdsForPostgreSqlConnectorProfile, 9 | AmazonRdsForPostgreSqlDestination, 10 | JdbcDriver, 11 | JdbcSmallDataScaleConnectorProfile, 12 | JdbcSmallDataScaleSource, 13 | Mapping, 14 | OnDemandFlow, 15 | } from "../../src"; 16 | 17 | const app = new App({ 18 | treeMetadata: false, 19 | }); 20 | 21 | const stack = new Stack(app, "TestStack"); 22 | 23 | const secret = Secret.fromSecretNameV2( 24 | stack, 25 | "TestSecret", 26 | "appflow/rdspostgres", 27 | ); 28 | 29 | const profile = new JdbcSmallDataScaleConnectorProfile( 30 | stack, 31 | "JdbcSmallTestConnectorProfile", 32 | { 33 | basicAuth: { 34 | username: secret.secretValueFromJson("username").toString(), 35 | password: secret.secretValueFromJson("password"), 36 | }, 37 | hostname: secret.secretValueFromJson("hostname").toString(), 38 | port: Token.asNumber(secret.secretValueFromJson("port").toString()), 39 | database: secret.secretValueFromJson("database").toString(), 40 | driver: secret.secretValueFromJson("driver").toString() as JdbcDriver, 41 | }, 42 | ); 43 | 44 | const source = new JdbcSmallDataScaleSource({ 45 | profile, 46 | object: { 47 | schema: secret.secretValueFromJson("schema").toString(), 48 | table: secret.secretValueFromJson("table").toString(), 49 | }, 50 | }); 51 | 52 | const destProfile = new AmazonRdsForPostgreSqlConnectorProfile( 53 | stack, 54 | "AmazonRdsTestConnectorProfile", 55 | { 56 | basicAuth: { 57 | username: secret.secretValueFromJson("username").toString(), 58 | password: secret.secretValueFromJson("password"), 59 | }, 60 | hostname: secret.secretValueFromJson("hostname").toString(), 61 | port: Token.asNumber(secret.secretValueFromJson("port").toString()), 62 | database: secret.secretValueFromJson("database").toString(), 63 | }, 64 | ); 65 | 66 | const destination = new AmazonRdsForPostgreSqlDestination({ 67 | profile: destProfile, 68 | object: { 69 | schema: secret.secretValueFromJson("schema").toString(), 70 | table: secret.secretValueFromJson("table").toString(), 71 | }, 72 | }); 73 | 74 | new OnDemandFlow(stack, "OnDemandFlow", { 75 | source: source, 76 | destination: destination, 77 | mappings: [ 78 | Mapping.map({ name: "username" }, { name: "username" }), 79 | Mapping.map({ name: "password" }, { name: "password" }), 80 | Mapping.map({ name: "created_on" }, { name: "created_on" }), 81 | Mapping.map({ name: "email" }, { name: "email" }), 82 | ], 83 | }); 84 | 85 | app.synth(); 86 | -------------------------------------------------------------------------------- /test/integ/ondemand-jdbcsmalldatascale-to-s3.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6": { 5 | "source": { 6 | "path": "asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6", 7 | "packaging": "zip" 8 | }, 9 | "destinations": { 10 | "current_account-current_region": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 12 | "objectKey": "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6.zip", 13 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 14 | } 15 | } 16 | }, 17 | "12ab6b1ff63583316b085ee5c37f4d268d88fe8dca18295502b417f83e177652": { 18 | "source": { 19 | "path": "TestStack.template.json", 20 | "packaging": "file" 21 | }, 22 | "destinations": { 23 | "current_account-current_region": { 24 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 25 | "objectKey": "12ab6b1ff63583316b085ee5c37f4d268d88fe8dca18295502b417f83e177652.json", 26 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 27 | } 28 | } 29 | } 30 | }, 31 | "dockerImages": {} 32 | } -------------------------------------------------------------------------------- /test/integ/ondemand-jdbcsmalldatascale-to-s3.integ.snapshot/cdk.out: -------------------------------------------------------------------------------- 1 | {"version":"40.0.0"} -------------------------------------------------------------------------------- /test/integ/ondemand-jdbcsmalldatascale-to-s3.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack, Token } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 8 | import { 9 | JdbcSmallDataScaleConnectorProfile, 10 | JdbcDriver, 11 | JdbcSmallDataScaleSource, 12 | S3Destination, 13 | OnDemandFlow, 14 | Mapping, 15 | } from "../../src"; 16 | 17 | const app = new App({ 18 | treeMetadata: false, 19 | }); 20 | 21 | const stack = new Stack(app, "TestStack"); 22 | 23 | const secret = Secret.fromSecretNameV2( 24 | stack, 25 | "TestSecret", 26 | "appflow/rdspostgres", 27 | ); 28 | 29 | const profile = new JdbcSmallDataScaleConnectorProfile( 30 | stack, 31 | "TestConnectorProfile", 32 | { 33 | basicAuth: { 34 | username: secret.secretValueFromJson("username").toString(), 35 | password: secret.secretValueFromJson("password"), 36 | }, 37 | hostname: secret.secretValueFromJson("hostname").toString(), 38 | port: Token.asNumber(secret.secretValueFromJson("port").toString()), 39 | database: secret.secretValueFromJson("database").toString(), 40 | driver: secret.secretValueFromJson("driver").toString() as JdbcDriver, 41 | }, 42 | ); 43 | 44 | const source = new JdbcSmallDataScaleSource({ 45 | profile, 46 | object: { 47 | schema: secret.secretValueFromJson("schema").toString(), 48 | table: secret.secretValueFromJson("table").toString(), 49 | }, 50 | }); 51 | 52 | const bucket = new Bucket(stack, "TestBucket", { 53 | autoDeleteObjects: true, 54 | removalPolicy: RemovalPolicy.DESTROY, 55 | }); 56 | 57 | const destination = new S3Destination({ 58 | location: { bucket }, 59 | }); 60 | 61 | new OnDemandFlow(stack, "OnDemandFlow", { 62 | source: source, 63 | destination: destination, 64 | mappings: [Mapping.mapAll()], 65 | }); 66 | 67 | app.synth(); 68 | -------------------------------------------------------------------------------- /test/integ/ondemand-mailchimp-to-s3.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6": { 5 | "source": { 6 | "path": "asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6", 7 | "packaging": "zip" 8 | }, 9 | "destinations": { 10 | "current_account-current_region": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 12 | "objectKey": "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6.zip", 13 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 14 | } 15 | } 16 | }, 17 | "db8bc53529478b0eee419ac97850a554f1f77cfe47cf414d286160d9fc36aa6e": { 18 | "source": { 19 | "path": "TestStack.template.json", 20 | "packaging": "file" 21 | }, 22 | "destinations": { 23 | "current_account-current_region": { 24 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 25 | "objectKey": "db8bc53529478b0eee419ac97850a554f1f77cfe47cf414d286160d9fc36aa6e.json", 26 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 27 | } 28 | } 29 | } 30 | }, 31 | "dockerImages": {} 32 | } -------------------------------------------------------------------------------- /test/integ/ondemand-mailchimp-to-s3.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 8 | import { 9 | MailchimpApiVersion, 10 | MailchimpConnectorProfile, 11 | MailchimpSource, 12 | Mapping, 13 | OnDemandFlow, 14 | S3Destination, 15 | } from "../../src"; 16 | 17 | const app = new App({ 18 | treeMetadata: false, 19 | }); 20 | 21 | const stack = new Stack(app, "TestStack"); 22 | 23 | const secret = Secret.fromSecretNameV2( 24 | stack, 25 | "TestSecret", 26 | "appflow/mailchimp", 27 | ); 28 | // const secret = new Secret(stack, 'TestSecret', { 29 | // secretName: 'appflow/mailchimp', 30 | // removalPolicy: RemovalPolicy.DESTROY, 31 | // secretObjectValue: { 32 | // "apiKey":SecretValue.unsafePlainText(""), 33 | // "instanceUrl":SecretValue.unsafePlainText("https://<>.api.mailchimp.com") 34 | // }, 35 | // }) 36 | 37 | const profile = new MailchimpConnectorProfile(stack, "TestConnectorProfile", { 38 | apiKey: secret.secretValueFromJson("apiKey"), 39 | instanceUrl: secret.secretValueFromJson("instanceUrl").toString(), 40 | }); 41 | 42 | const source = new MailchimpSource({ 43 | profile: profile, 44 | apiVersion: MailchimpApiVersion.V3, 45 | object: "campaigns", 46 | }); 47 | 48 | const bucket = new Bucket(stack, "TestBucket", { 49 | autoDeleteObjects: true, 50 | removalPolicy: RemovalPolicy.DESTROY, 51 | }); 52 | 53 | const destination = new S3Destination({ 54 | location: { bucket }, 55 | }); 56 | 57 | new OnDemandFlow(stack, "OnDemandFlow", { 58 | source: source, 59 | destination: destination, 60 | mappings: [Mapping.mapAll()], 61 | }); 62 | 63 | app.synth(); 64 | -------------------------------------------------------------------------------- /test/integ/ondemand-microsoftdynamics365-to-s3.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6": { 5 | "source": { 6 | "path": "asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6", 7 | "packaging": "zip" 8 | }, 9 | "destinations": { 10 | "current_account-us-east-1": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1", 12 | "objectKey": "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6.zip", 13 | "region": "us-east-1", 14 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-east-1" 15 | } 16 | } 17 | }, 18 | "a7e9e94497cbe41b814c241bcafefaabe68ece70b82575fac7a7e91ce1d79f8f": { 19 | "source": { 20 | "path": "TestStack.template.json", 21 | "packaging": "file" 22 | }, 23 | "destinations": { 24 | "current_account-us-east-1": { 25 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1", 26 | "objectKey": "a7e9e94497cbe41b814c241bcafefaabe68ece70b82575fac7a7e91ce1d79f8f.json", 27 | "region": "us-east-1", 28 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-east-1" 29 | } 30 | } 31 | } 32 | }, 33 | "dockerImages": {} 34 | } -------------------------------------------------------------------------------- /test/integ/ondemand-microsoftdynamics365-to-s3.integ.snapshot/cdk.out: -------------------------------------------------------------------------------- 1 | {"version":"40.0.0"} -------------------------------------------------------------------------------- /test/integ/ondemand-microsoftdynamics365-to-s3.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 8 | import { 9 | Mapping, 10 | MicrosoftDynamics365ApiVersion, 11 | MicrosoftDynamics365ConnectorProfile, 12 | MicrosoftDynamics365Source, 13 | OnDemandFlow, 14 | S3Destination, 15 | S3OutputAggregationType, 16 | } from "../../src"; 17 | 18 | const app = new App({ 19 | treeMetadata: false, 20 | }); 21 | 22 | const stack = new Stack(app, "TestStack", { 23 | env: { 24 | region: "us-east-1", 25 | }, 26 | }); 27 | 28 | const secret = Secret.fromSecretNameV2( 29 | stack, 30 | "TestSecret", 31 | "appflow/msdynamics365", 32 | ); 33 | 34 | const profile = new MicrosoftDynamics365ConnectorProfile( 35 | stack, 36 | "TestConnector", 37 | { 38 | oAuth: { 39 | accessToken: secret.secretValueFromJson("accessToken"), 40 | flow: { 41 | refreshTokenGrant: { 42 | refreshToken: secret.secretValueFromJson("refreshToken"), 43 | clientId: secret.secretValueFromJson("clientId"), 44 | clientSecret: secret.secretValueFromJson("clientSecret"), 45 | }, 46 | }, 47 | }, 48 | instanceUrl: secret.secretValueFromJson("instanceUrl").toString(), 49 | }, 50 | ); 51 | 52 | const source = new MicrosoftDynamics365Source({ 53 | profile: profile, 54 | apiVersion: MicrosoftDynamics365ApiVersion.V9_2, 55 | object: secret.secretValueFromJson("object").toString(), 56 | }); 57 | 58 | const bucket = new Bucket(stack, "TestBucket", { 59 | autoDeleteObjects: true, 60 | removalPolicy: RemovalPolicy.DESTROY, 61 | }); 62 | 63 | const destination = new S3Destination({ 64 | location: { bucket }, 65 | formatting: { 66 | aggregation: { 67 | type: S3OutputAggregationType.SINGLE_FILE, 68 | }, 69 | }, 70 | }); 71 | 72 | new OnDemandFlow(stack, "OnDemandFlow", { 73 | source: source, 74 | destination: destination, 75 | mappings: [Mapping.mapAll()], 76 | }); 77 | 78 | app.synth(); 79 | -------------------------------------------------------------------------------- /test/integ/ondemand-microsoftsharepointonline-to-s3.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6": { 5 | "source": { 6 | "path": "asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6", 7 | "packaging": "zip" 8 | }, 9 | "destinations": { 10 | "current_account-current_region": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 12 | "objectKey": "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6.zip", 13 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 14 | } 15 | } 16 | }, 17 | "1a172133dad336c24c46173d2bef420636340e7c255c8699ae5796f47fe01c2f": { 18 | "source": { 19 | "path": "TestStack.template.json", 20 | "packaging": "file" 21 | }, 22 | "destinations": { 23 | "current_account-current_region": { 24 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 25 | "objectKey": "1a172133dad336c24c46173d2bef420636340e7c255c8699ae5796f47fe01c2f.json", 26 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 27 | } 28 | } 29 | } 30 | }, 31 | "dockerImages": {} 32 | } -------------------------------------------------------------------------------- /test/integ/ondemand-microsoftsharepointonline-to-s3.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 8 | import { 9 | MicrosoftSharepointOnlineApiVersion, 10 | MicrosoftSharepointOnlineConnectorProfile, 11 | MicrosoftSharepointOnlineSource, 12 | Mapping, 13 | OnDemandFlow, 14 | S3Destination, 15 | MicrosoftSharepointOnlineTokenUrlBuilder, 16 | S3OutputAggregationType, 17 | } from "../../src"; 18 | 19 | const app = new App({ 20 | treeMetadata: false, 21 | }); 22 | 23 | const stack = new Stack(app, "TestStack"); 24 | 25 | const secret = Secret.fromSecretNameV2( 26 | stack, 27 | "TestSecret", 28 | "appflow/mssharepointonline", 29 | ); 30 | 31 | const profile = new MicrosoftSharepointOnlineConnectorProfile( 32 | stack, 33 | "TestConnector", 34 | { 35 | oAuth: { 36 | accessToken: secret.secretValueFromJson("accessToken"), 37 | flow: { 38 | refreshTokenGrant: { 39 | refreshToken: secret.secretValueFromJson("refreshToken"), 40 | }, 41 | }, 42 | endpoints: { 43 | token: MicrosoftSharepointOnlineTokenUrlBuilder.buildTokenUrl( 44 | secret.secretValueFromJson("tenantId").toString(), 45 | ), 46 | }, 47 | }, 48 | }, 49 | ); 50 | 51 | const source = new MicrosoftSharepointOnlineSource({ 52 | profile: profile, 53 | apiVersion: MicrosoftSharepointOnlineApiVersion.V1, 54 | object: { 55 | site: secret.secretValueFromJson("site").toString(), 56 | entities: [secret.secretValueFromJson("drive").toString()], 57 | }, 58 | }); 59 | 60 | const bucket = new Bucket(stack, "TestBucket", { 61 | autoDeleteObjects: true, 62 | removalPolicy: RemovalPolicy.DESTROY, 63 | }); 64 | 65 | const destination = new S3Destination({ 66 | location: { bucket }, 67 | formatting: { 68 | aggregation: { 69 | type: S3OutputAggregationType.SINGLE_FILE, 70 | }, 71 | }, 72 | }); 73 | 74 | new OnDemandFlow(stack, "OnDemandFlow", { 75 | source: source, 76 | destination: destination, 77 | mappings: [Mapping.mapAll()], 78 | }); 79 | 80 | app.synth(); 81 | -------------------------------------------------------------------------------- /test/integ/ondemand-s3-to-hubspot.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { BucketDeployment, Source } from "aws-cdk-lib/aws-s3-deployment"; 8 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 9 | import { 10 | Mapping, 11 | OnDemandFlow, 12 | S3InputFileType, 13 | S3Source, 14 | HubSpotDestination, 15 | HubSpotConnectorProfile, 16 | WriteOperationType, 17 | HubSpotApiVersion, 18 | } from "../../src"; 19 | 20 | const app = new App({ 21 | treeMetadata: false, 22 | }); 23 | 24 | const stack = new Stack(app, "TestStack"); 25 | const secret = Secret.fromSecretNameV2(stack, "TestSecret", "appflow/hubspot"); 26 | 27 | const sourceBucket = new Bucket(stack, "TestSourceBucket", { 28 | autoDeleteObjects: true, 29 | removalPolicy: RemovalPolicy.DESTROY, 30 | }); 31 | 32 | const deployment = new BucketDeployment(stack, "TestDeployment", { 33 | sources: [ 34 | Source.jsonData("init.json", { 35 | annualrevenue: "1000000", 36 | description: "Sample Corp", 37 | domain: "sample.corp", 38 | industry: "INTERNET", 39 | name: "sample", 40 | website: "sample.corp", 41 | }), 42 | ], 43 | destinationBucket: sourceBucket, 44 | destinationKeyPrefix: "hubspot", 45 | }); 46 | 47 | const profile = new HubSpotConnectorProfile(stack, "TestConnector", { 48 | oAuth: { 49 | flow: { 50 | refreshTokenGrant: { 51 | refreshToken: secret.secretValueFromJson("refreshToken"), 52 | clientId: secret.secretValueFromJson("clientId"), 53 | clientSecret: secret.secretValueFromJson("clientSecret"), 54 | }, 55 | }, 56 | }, 57 | }); 58 | 59 | const source = new S3Source({ 60 | bucket: sourceBucket, 61 | prefix: "hubspot", 62 | format: { 63 | type: S3InputFileType.JSON, 64 | }, 65 | }); 66 | 67 | const destination = new HubSpotDestination({ 68 | profile: profile, 69 | apiVersion: HubSpotApiVersion.V3, 70 | entity: ["company"], 71 | operation: { type: WriteOperationType.INSERT }, 72 | errorHandling: { 73 | errorLocation: { 74 | bucket: sourceBucket, 75 | prefix: "error", 76 | }, 77 | }, 78 | }); 79 | 80 | const flow = new OnDemandFlow(stack, "OnDemandFlow", { 81 | source: source, 82 | destination: destination, 83 | mappings: [Mapping.mapAll()], 84 | }); 85 | 86 | flow.node.addDependency(deployment); 87 | 88 | app.synth(); 89 | -------------------------------------------------------------------------------- /test/integ/ondemand-s3-to-s3.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { BucketDeployment, Source } from "aws-cdk-lib/aws-s3-deployment"; 8 | import { 9 | Mapping, 10 | OnDemandFlow, 11 | S3Destination, 12 | S3InputFileType, 13 | S3OutputAggregationType, 14 | S3OutputFilePrefixHierarchy, 15 | S3OutputFilePrefixType, 16 | S3OutputFileType, 17 | S3Source, 18 | } from "../../src"; 19 | 20 | const app = new App({ 21 | treeMetadata: false, 22 | }); 23 | 24 | const stack = new Stack(app, "TestStack"); 25 | 26 | const sourceBucket = new Bucket(stack, "TestSourceBucket", { 27 | autoDeleteObjects: true, 28 | removalPolicy: RemovalPolicy.DESTROY, 29 | }); 30 | 31 | const destinationBucket = new Bucket(stack, "TestDestinationBucket", { 32 | autoDeleteObjects: true, 33 | removalPolicy: RemovalPolicy.DESTROY, 34 | }); 35 | 36 | const deployment = new BucketDeployment(stack, "TestDeployment", { 37 | sources: [Source.jsonData("init.json", { Name: "name" })], 38 | destinationBucket: sourceBucket, 39 | destinationKeyPrefix: "account", 40 | }); 41 | 42 | const source = new S3Source({ 43 | bucket: sourceBucket, 44 | prefix: "account", 45 | format: { 46 | type: S3InputFileType.JSON, 47 | }, 48 | }); 49 | 50 | const destination = new S3Destination({ 51 | location: { bucket: destinationBucket }, 52 | formatting: { 53 | fileType: S3OutputFileType.PARQUET, 54 | filePrefix: { 55 | type: S3OutputFilePrefixType.FILENAME, 56 | hierarchy: [ 57 | S3OutputFilePrefixHierarchy.SCHEMA_VERSION, 58 | S3OutputFilePrefixHierarchy.EXECUTION_ID, 59 | ], 60 | }, 61 | aggregation: { type: S3OutputAggregationType.NONE }, 62 | preserveSourceDataTypes: true, 63 | }, 64 | }); 65 | 66 | const flow = new OnDemandFlow(stack, "OnDemandFlow", { 67 | source: source, 68 | destination: destination, 69 | mappings: [Mapping.mapAll()], 70 | }); 71 | 72 | flow.node.addDependency(deployment); 73 | 74 | app.synth(); 75 | -------------------------------------------------------------------------------- /test/integ/ondemand-s3-to-snowflake.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { BucketDeployment, Source } from "aws-cdk-lib/aws-s3-deployment"; 8 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 9 | import { 10 | Mapping, 11 | OnDemandFlow, 12 | S3InputFileType, 13 | S3Source, 14 | SnowflakeConnectorProfile, 15 | SnowflakeDestination, 16 | } from "../../src"; 17 | 18 | const app = new App({ 19 | treeMetadata: false, 20 | }); 21 | 22 | const stack = new Stack(app, "TestStack"); 23 | 24 | const bucket = new Bucket(stack, "TestBucket", { 25 | autoDeleteObjects: true, 26 | removalPolicy: RemovalPolicy.DESTROY, 27 | }); 28 | 29 | const deployment = new BucketDeployment(stack, "TestDeployment", { 30 | sources: [Source.jsonData("init.json", { Name: "name" })], 31 | destinationBucket: bucket, 32 | destinationKeyPrefix: "account", 33 | }); 34 | 35 | const source = new S3Source({ 36 | bucket: bucket, 37 | prefix: "account", 38 | format: { 39 | type: S3InputFileType.JSON, 40 | }, 41 | }); 42 | const secret = Secret.fromSecretNameV2( 43 | stack, 44 | "SnowTestSecret", 45 | "appflow/snowflake", 46 | ); 47 | 48 | const dataBucket = Bucket.fromBucketAttributes(stack, "ImportedBucket", { 49 | bucketName: secret.secretValueFromJson("bucketName").toString(), 50 | }); 51 | 52 | const snowProfile = new SnowflakeConnectorProfile(stack, "SnowTestConnector", { 53 | account: secret.secretValueFromJson("account").toString(), 54 | region: secret.secretValueFromJson("region").toString(), 55 | basicAuth: { 56 | username: secret.secretValueFromJson("username").toString(), 57 | password: secret.secretValueFromJson("password"), 58 | }, 59 | warehouse: secret.secretValueFromJson("warehouse").toString(), 60 | database: secret.secretValueFromJson("database").toString(), 61 | schema: secret.secretValueFromJson("schema").toString(), 62 | stage: secret.secretValueFromJson("stage").toString(), 63 | location: { 64 | bucket: dataBucket, 65 | }, 66 | }); 67 | 68 | const destination = new SnowflakeDestination({ 69 | profile: snowProfile, 70 | object: { 71 | table: secret.secretValueFromJson("table").toString(), 72 | }, 73 | errorHandling: { 74 | errorLocation: { 75 | bucket: dataBucket, 76 | prefix: "error", 77 | }, 78 | }, 79 | }); 80 | 81 | const flow = new OnDemandFlow(stack, "OnDemandFlow", { 82 | source: source, 83 | destination: destination, 84 | mappings: [Mapping.mapAll()], 85 | }); 86 | 87 | flow.node.addDependency(deployment); 88 | 89 | app.synth(); 90 | -------------------------------------------------------------------------------- /test/integ/ondemand-salesforce-to-redshift.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { Cluster, Table } from "@aws-cdk/aws-redshift-alpha"; 6 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 7 | import { Vpc } from "aws-cdk-lib/aws-ec2"; 8 | import { Bucket } from "aws-cdk-lib/aws-s3"; 9 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 10 | import { 11 | Mapping, 12 | OnDemandFlow, 13 | RedshiftConnectorProfile, 14 | RedshiftDestination, 15 | SalesforceConnectorProfile, 16 | SalesforceSource, 17 | } from "../../src"; 18 | 19 | const app = new App({ 20 | treeMetadata: false, 21 | }); 22 | 23 | const stack = new Stack(app, "TestStack"); 24 | 25 | const creds = Secret.fromSecretNameV2( 26 | stack, 27 | "TestSecret", 28 | "appflow/salesforce", 29 | ); 30 | 31 | const profile = new SalesforceConnectorProfile(stack, "TestProfile", { 32 | oAuth: { 33 | accessToken: creds.secretValueFromJson("accessToken"), 34 | }, 35 | instanceUrl: creds.secretValueFromJson("instanceUrl").toString(), 36 | isSandbox: false, 37 | }); 38 | 39 | const source = new SalesforceSource({ 40 | profile: profile, 41 | object: "Contact", 42 | }); 43 | 44 | const bucket = new Bucket(stack, "TestBucket", { 45 | autoDeleteObjects: true, 46 | removalPolicy: RemovalPolicy.DESTROY, 47 | }); 48 | 49 | const materUserName = "admin"; 50 | const databaseName = "workshop"; 51 | 52 | const cluster = new Cluster(stack, "TestCluster", { 53 | encrypted: false, 54 | masterUser: { 55 | masterUsername: materUserName, 56 | }, 57 | defaultDatabaseName: databaseName, 58 | vpc: new Vpc(stack, "TestVpc"), 59 | removalPolicy: RemovalPolicy.DESTROY, 60 | }); 61 | 62 | const table = new Table(stack, "TestTable", { 63 | tableName: "contact", 64 | tableColumns: [{ name: "name", dataType: "character varying" }], 65 | cluster: cluster, 66 | databaseName: databaseName, 67 | removalPolicy: RemovalPolicy.DESTROY, 68 | }); 69 | 70 | const redshiftProfile = new RedshiftConnectorProfile( 71 | stack, 72 | "TestRedshiftProfile", 73 | { 74 | basicAuth: { 75 | username: materUserName, 76 | }, 77 | intermediateLocation: { bucket, prefix: "intermediate" }, 78 | cluster: cluster, 79 | databaseName: databaseName, 80 | }, 81 | ); 82 | 83 | const destination = new RedshiftDestination({ 84 | profile: redshiftProfile, 85 | object: { 86 | table: table, 87 | }, 88 | }); 89 | 90 | new OnDemandFlow(stack, "SfdcToRedshiftELT", { 91 | source, 92 | destination, 93 | mappings: [ 94 | Mapping.map( 95 | { name: "Name", dataType: "string" }, 96 | { name: "name", dataType: "character varying" }, 97 | ), 98 | ], 99 | }); 100 | 101 | app.synth(); 102 | -------------------------------------------------------------------------------- /test/integ/ondemand-salesforce-to-s3.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6": { 5 | "source": { 6 | "path": "asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6", 7 | "packaging": "zip" 8 | }, 9 | "destinations": { 10 | "current_account-current_region": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 12 | "objectKey": "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6.zip", 13 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 14 | } 15 | } 16 | }, 17 | "b9e4b599a3ca16d56b0c823cbd42b4792fb368a1ae7a4473382997d79abbf445": { 18 | "source": { 19 | "path": "TestStack.template.json", 20 | "packaging": "file" 21 | }, 22 | "destinations": { 23 | "current_account-current_region": { 24 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 25 | "objectKey": "b9e4b599a3ca16d56b0c823cbd42b4792fb368a1ae7a4473382997d79abbf445.json", 26 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 27 | } 28 | } 29 | } 30 | }, 31 | "dockerImages": {} 32 | } -------------------------------------------------------------------------------- /test/integ/ondemand-salesforce-to-s3.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { Database } from "@aws-cdk/aws-glue-alpha"; 6 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 7 | import { Bucket } from "aws-cdk-lib/aws-s3"; 8 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 9 | import { 10 | Filter, 11 | FilterCondition, 12 | Mapping, 13 | OnDemandFlow, 14 | S3Destination, 15 | S3OutputFilePrefixHierarchy, 16 | S3OutputFileType, 17 | SalesforceConnectorProfile, 18 | SalesforceSource, 19 | } from "../../src"; 20 | 21 | const app = new App({ 22 | treeMetadata: false, 23 | }); 24 | 25 | const stack = new Stack(app, "TestStack"); 26 | 27 | const secret = Secret.fromSecretNameV2( 28 | stack, 29 | "TestSecret", 30 | "appflow/salesforce/client", 31 | ); 32 | 33 | const profile = new SalesforceConnectorProfile(stack, "TestConnectorProfile", { 34 | oAuth: { 35 | flow: { 36 | refreshTokenGrant: { 37 | refreshToken: secret.secretValueFromJson("refreshToken"), 38 | client: secret, 39 | }, 40 | }, 41 | }, 42 | instanceUrl: secret.secretValueFromJson("instanceUrl").toString(), 43 | isSandbox: false, 44 | }); 45 | 46 | const source = new SalesforceSource({ 47 | profile: profile, 48 | object: "Contact", 49 | }); 50 | 51 | const bucket = new Bucket(stack, "TestBucket", { 52 | autoDeleteObjects: true, 53 | removalPolicy: RemovalPolicy.DESTROY, 54 | }); 55 | 56 | const destination = new S3Destination({ 57 | location: { bucket }, 58 | formatting: { 59 | filePrefix: { 60 | hierarchy: [ 61 | S3OutputFilePrefixHierarchy.SCHEMA_VERSION, 62 | S3OutputFilePrefixHierarchy.EXECUTION_ID, 63 | ], 64 | }, 65 | fileType: S3OutputFileType.JSON, 66 | }, 67 | catalog: { 68 | database: new Database(stack, "TestDatabase", { databaseName: "testdb" }), 69 | tablePrefix: "test_prefix", 70 | }, 71 | }); 72 | 73 | new OnDemandFlow(stack, "OnDemandFlow", { 74 | source: source, 75 | destination: destination, 76 | mappings: [Mapping.mapAll()], 77 | filters: [ 78 | Filter.when( 79 | FilterCondition.timestampGreaterThanEquals( 80 | { name: "LastModifiedDate", dataType: "datetime" }, 81 | new Date(Date.parse("2022-02-02")), 82 | ), 83 | ), 84 | ], 85 | }); 86 | 87 | app.synth(); 88 | -------------------------------------------------------------------------------- /test/integ/ondemand-sapodata-to-s3.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6": { 5 | "source": { 6 | "path": "asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6", 7 | "packaging": "zip" 8 | }, 9 | "destinations": { 10 | "current_account-current_region": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 12 | "objectKey": "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6.zip", 13 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 14 | } 15 | } 16 | }, 17 | "091e8aa04bab890be1c643bfa51a1c1eacd3b7bb8cdd79ab1533c1add562b531": { 18 | "source": { 19 | "path": "TestStack.template.json", 20 | "packaging": "file" 21 | }, 22 | "destinations": { 23 | "current_account-current_region": { 24 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 25 | "objectKey": "091e8aa04bab890be1c643bfa51a1c1eacd3b7bb8cdd79ab1533c1add562b531.json", 26 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 27 | } 28 | } 29 | } 30 | }, 31 | "dockerImages": {} 32 | } -------------------------------------------------------------------------------- /test/integ/ondemand-sapodata-to-s3.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack, Token } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 8 | import { 9 | Mapping, 10 | OnDemandFlow, 11 | S3Destination, 12 | SAPOdataConnectorProfile, 13 | SAPOdataSource, 14 | } from "../../src"; 15 | 16 | const app = new App({ 17 | treeMetadata: false, 18 | }); 19 | 20 | const stack = new Stack(app, "TestStack"); 21 | 22 | const secret = Secret.fromSecretNameV2( 23 | stack, 24 | "TestSecret", 25 | "appflow/sap/basic", 26 | ); 27 | 28 | const profile = new SAPOdataConnectorProfile(stack, "TestConnectorProfile", { 29 | basicAuth: { 30 | username: secret.secretValueFromJson("username").toString(), 31 | password: secret.secretValueFromJson("password"), 32 | }, 33 | applicationHostUrl: secret.secretValueFromJson("appHostUrl").toString(), 34 | applicationServicePath: secret.secretValueFromJson("servicePath").toString(), 35 | portNumber: Token.asNumber(secret.secretValueFromJson("portNumber")), 36 | clientNumber: secret.secretValueFromJson("clientNumber").toString(), 37 | logonLanguage: secret.secretValueFromJson("logonLanguage").toString(), 38 | }); 39 | 40 | const source = new SAPOdataSource({ 41 | profile: profile, 42 | object: secret.secretValueFromJson("objectName").toString(), 43 | }); 44 | 45 | const bucket = new Bucket(stack, "TestBucket", { 46 | autoDeleteObjects: true, 47 | removalPolicy: RemovalPolicy.DESTROY, 48 | }); 49 | 50 | const destination = new S3Destination({ 51 | location: { bucket }, 52 | }); 53 | 54 | new OnDemandFlow(stack, "OnDemandFlow", { 55 | source: source, 56 | destination: destination, 57 | mappings: [Mapping.mapAll()], 58 | }); 59 | 60 | app.synth(); 61 | -------------------------------------------------------------------------------- /test/integ/ondemand-slack-to-s3.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6": { 5 | "source": { 6 | "path": "asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6", 7 | "packaging": "zip" 8 | }, 9 | "destinations": { 10 | "current_account-current_region": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 12 | "objectKey": "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6.zip", 13 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 14 | } 15 | } 16 | }, 17 | "24d693be1b66f44f44681870f4fc7ddd30109b301416c67122ba2c82f7941767": { 18 | "source": { 19 | "path": "TestStack.template.json", 20 | "packaging": "file" 21 | }, 22 | "destinations": { 23 | "current_account-current_region": { 24 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 25 | "objectKey": "24d693be1b66f44f44681870f4fc7ddd30109b301416c67122ba2c82f7941767.json", 26 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 27 | } 28 | } 29 | } 30 | }, 31 | "dockerImages": {} 32 | } -------------------------------------------------------------------------------- /test/integ/ondemand-slack-to-s3.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 8 | import { 9 | Mapping, 10 | OnDemandFlow, 11 | S3Destination, 12 | SlackConnectorProfile, 13 | SlackSource, 14 | } from "../../src"; 15 | 16 | const app = new App({ 17 | treeMetadata: false, 18 | }); 19 | 20 | const stack = new Stack(app, "TestStack"); 21 | 22 | const secret = Secret.fromSecretNameV2(stack, "TestSecret", "appflow/slack"); 23 | 24 | const profile = new SlackConnectorProfile(stack, "TestConnectorProfile", { 25 | oAuth: { 26 | accessToken: secret.secretValueFromJson("accessToken"), 27 | }, 28 | instanceUrl: secret.secretValueFromJson("instanceUrl").toString(), 29 | }); 30 | 31 | const source = new SlackSource({ 32 | profile: profile, 33 | object: secret.secretValueFromJson("conversation").toString(), 34 | }); 35 | 36 | const bucket = new Bucket(stack, "TestBucket", { 37 | autoDeleteObjects: true, 38 | removalPolicy: RemovalPolicy.DESTROY, 39 | }); 40 | 41 | const destination = new S3Destination({ 42 | location: { bucket }, 43 | }); 44 | 45 | new OnDemandFlow(stack, "OnDemandFlow", { 46 | source: source, 47 | destination: destination, 48 | mappings: [Mapping.mapAll()], 49 | }); 50 | 51 | app.synth(); 52 | -------------------------------------------------------------------------------- /test/integ/onevent-salesforce-to-eventbridge.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6": { 5 | "source": { 6 | "path": "asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6", 7 | "packaging": "zip" 8 | }, 9 | "destinations": { 10 | "current_account-current_region": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 12 | "objectKey": "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6.zip", 13 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 14 | } 15 | } 16 | }, 17 | "fc66ca7ab26607a2493f22ebad08391a3bd3aacdc4dde0692e020bee29aa247e": { 18 | "source": { 19 | "path": "TestStack.template.json", 20 | "packaging": "file" 21 | }, 22 | "destinations": { 23 | "current_account-current_region": { 24 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", 25 | "objectKey": "fc66ca7ab26607a2493f22ebad08391a3bd3aacdc4dde0692e020bee29aa247e.json", 26 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" 27 | } 28 | } 29 | } 30 | }, 31 | "dockerImages": {} 32 | } -------------------------------------------------------------------------------- /test/integ/onevent-salesforce-to-eventbridge.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 8 | import { 9 | EventBridgeDestination, 10 | SalesforceSource, 11 | EventSources, 12 | Mapping, 13 | OnEventFlow, 14 | SalesforceConnectorProfile, 15 | } from "../../src"; 16 | 17 | const app = new App({ 18 | treeMetadata: false, 19 | }); 20 | 21 | const stack = new Stack(app, "TestStack"); 22 | 23 | const secret = Secret.fromSecretNameV2( 24 | stack, 25 | "TestSecret", 26 | "appflow/salesforce/client", 27 | ); 28 | 29 | const profile = new SalesforceConnectorProfile(stack, "TestConnectorProfile", { 30 | oAuth: { 31 | flow: { 32 | refreshTokenGrant: { 33 | refreshToken: secret.secretValueFromJson("refreshToken"), 34 | client: secret, 35 | }, 36 | }, 37 | }, 38 | instanceUrl: secret.secretValueFromJson("instanceUrl").toString(), 39 | isSandbox: false, 40 | }); 41 | 42 | const source = new SalesforceSource({ 43 | profile: profile, 44 | object: "AccountChangeEvent", 45 | }); 46 | 47 | const bucket = new Bucket(stack, "TestBucket", { 48 | autoDeleteObjects: true, 49 | removalPolicy: RemovalPolicy.DESTROY, 50 | }); 51 | 52 | const destination = new EventBridgeDestination({ 53 | partnerBus: EventSources.salesforceEventSource("test"), 54 | errorHandling: { errorLocation: { bucket } }, 55 | }); 56 | 57 | const flow = new OnEventFlow(stack, "EventFlow", { 58 | source: source, 59 | destination: destination, 60 | mappings: [Mapping.mapAll()], 61 | }); 62 | 63 | flow.onRunStarted("captureOnRunStarted"); 64 | 65 | app.synth(); 66 | -------------------------------------------------------------------------------- /test/integ/onschedule-s3-to-salesforce.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, Duration, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Schedule } from "aws-cdk-lib/aws-events"; 7 | import { Bucket } from "aws-cdk-lib/aws-s3"; 8 | import { BucketDeployment, Source } from "aws-cdk-lib/aws-s3-deployment"; 9 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 10 | import { 11 | SalesforceDestination, 12 | S3Source, 13 | S3InputFileType, 14 | Mapping, 15 | OnScheduleFlow, 16 | DataPullMode, 17 | Validation, 18 | ValidationCondition, 19 | ValidationAction, 20 | Transform, 21 | WriteOperation, 22 | SalesforceConnectorProfile, 23 | FlowStatus, 24 | } from "../../src"; 25 | 26 | const app = new App({ 27 | treeMetadata: false, 28 | }); 29 | 30 | const stack = new Stack(app, "TestStack"); 31 | 32 | const bucket = new Bucket(stack, "TestBucket", { 33 | autoDeleteObjects: true, 34 | removalPolicy: RemovalPolicy.DESTROY, 35 | }); 36 | 37 | const deployment = new BucketDeployment(stack, "TestDeployment", { 38 | sources: [Source.jsonData("init.json", { Name: "name" })], 39 | destinationBucket: bucket, 40 | destinationKeyPrefix: "account", 41 | }); 42 | 43 | const source = new S3Source({ 44 | bucket: bucket, 45 | prefix: "account", 46 | format: { 47 | type: S3InputFileType.JSON, 48 | }, 49 | }); 50 | 51 | const secret = Secret.fromSecretNameV2( 52 | stack, 53 | "TestSecret", 54 | "appflow/salesforce/client", 55 | ); 56 | 57 | const profile = new SalesforceConnectorProfile(stack, "TestConnectorProfile", { 58 | oAuth: { 59 | flow: { 60 | refreshTokenGrant: { 61 | refreshToken: secret.secretValueFromJson("refreshToken"), 62 | client: secret, 63 | }, 64 | }, 65 | }, 66 | instanceUrl: secret.secretValueFromJson("instanceUrl").toString(), 67 | isSandbox: false, 68 | }); 69 | 70 | const destination = new SalesforceDestination({ 71 | profile: profile, 72 | object: "Account", 73 | operation: WriteOperation.insert(), 74 | }); 75 | 76 | const flow = new OnScheduleFlow(stack, "OnScheduleFlow", { 77 | source: source, 78 | destination: destination, 79 | mappings: [ 80 | Mapping.map( 81 | { name: "Name", dataType: "string" }, 82 | { name: "Name", dataType: "string" }, 83 | ), 84 | ], 85 | transforms: [Transform.mask({ name: "Name" }, "*")], 86 | validations: [ 87 | Validation.when( 88 | ValidationCondition.isNull("Name"), 89 | ValidationAction.ignoreRecord(), 90 | ), 91 | ], 92 | schedule: Schedule.rate(Duration.minutes(10)), 93 | pullConfig: { mode: DataPullMode.INCREMENTAL }, 94 | scheduleProperties: { 95 | startTime: new Date(Date.parse("2024-01-01")), 96 | }, 97 | status: FlowStatus.ACTIVE, 98 | }); 99 | 100 | flow.node.addDependency(deployment); 101 | flow.onRunCompleted("captureOnRunCompleted"); 102 | flow.onDeactivated("captureOnDeactivated"); 103 | 104 | app.synth(); 105 | -------------------------------------------------------------------------------- /test/integ/onschedule-salesforce-marketing-cloud-to-s3.integ.snapshot/TestStack.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "40.0.0", 3 | "files": { 4 | "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6": { 5 | "source": { 6 | "path": "asset.faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6", 7 | "packaging": "zip" 8 | }, 9 | "destinations": { 10 | "current_account-eu-west-2": { 11 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-eu-west-2", 12 | "objectKey": "faa95a81ae7d7373f3e1f242268f904eb748d8d0fdd306e8a6fe515a1905a7d6.zip", 13 | "region": "eu-west-2", 14 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-eu-west-2" 15 | } 16 | } 17 | }, 18 | "3d8e27d488be48c03663849f78d10bccd12d62c87af6b9bbf55731095cc2a07f": { 19 | "source": { 20 | "path": "asset.3d8e27d488be48c03663849f78d10bccd12d62c87af6b9bbf55731095cc2a07f.lambda", 21 | "packaging": "zip" 22 | }, 23 | "destinations": { 24 | "current_account-eu-west-2": { 25 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-eu-west-2", 26 | "objectKey": "3d8e27d488be48c03663849f78d10bccd12d62c87af6b9bbf55731095cc2a07f.zip", 27 | "region": "eu-west-2", 28 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-eu-west-2" 29 | } 30 | } 31 | }, 32 | "bdc104ed9cab1b5b6421713c8155f0b753380595356f710400609664d3635eca": { 33 | "source": { 34 | "path": "asset.bdc104ed9cab1b5b6421713c8155f0b753380595356f710400609664d3635eca", 35 | "packaging": "zip" 36 | }, 37 | "destinations": { 38 | "current_account-eu-west-2": { 39 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-eu-west-2", 40 | "objectKey": "bdc104ed9cab1b5b6421713c8155f0b753380595356f710400609664d3635eca.zip", 41 | "region": "eu-west-2", 42 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-eu-west-2" 43 | } 44 | } 45 | }, 46 | "7ae026390f11eec3bd30549247ace397b19eb7271c1f3313b2990ff4b71c4b22": { 47 | "source": { 48 | "path": "TestStack.template.json", 49 | "packaging": "file" 50 | }, 51 | "destinations": { 52 | "current_account-eu-west-2": { 53 | "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-eu-west-2", 54 | "objectKey": "7ae026390f11eec3bd30549247ace397b19eb7271c1f3313b2990ff4b71c4b22.json", 55 | "region": "eu-west-2", 56 | "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-eu-west-2" 57 | } 58 | } 59 | } 60 | }, 61 | "dockerImages": {} 62 | } -------------------------------------------------------------------------------- /test/integ/onschedule-salesforce-marketing-cloud-to-s3.integ.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { App, RemovalPolicy, Stack } from "aws-cdk-lib"; 6 | import { Schedule } from "aws-cdk-lib/aws-events"; 7 | import { Bucket } from "aws-cdk-lib/aws-s3"; 8 | import { Secret } from "aws-cdk-lib/aws-secretsmanager"; 9 | import { 10 | DataPullMode, 11 | Mapping, 12 | OnScheduleFlow, 13 | S3Destination, 14 | SalesforceMarketingCloudApiVersions, 15 | SalesforceMarketingCloudConnectorProfile, 16 | SalesforceMarketingCloudSource, 17 | Transform, 18 | Validation, 19 | ValidationAction, 20 | ValidationCondition, 21 | } from "../../src"; 22 | 23 | const app = new App({ 24 | treeMetadata: false, 25 | }); 26 | 27 | const stack = new Stack(app, "TestStack", { 28 | env: { 29 | region: "eu-west-2", 30 | }, 31 | }); 32 | 33 | const secret = Secret.fromSecretNameV2(stack, "TestSecret", "sfmc/secret"); 34 | 35 | const profile = new SalesforceMarketingCloudConnectorProfile( 36 | stack, 37 | "TestConnector", 38 | { 39 | instanceUrl: secret.secretValueFromJson("instanceUrl").toString(), 40 | oAuth: { 41 | flow: { 42 | clientCredentials: { 43 | clientId: secret.secretValueFromJson("clientId"), 44 | clientSecret: secret.secretValueFromJson("clientSecret"), 45 | }, 46 | }, 47 | endpoints: { 48 | token: secret.secretValueFromJson("tokenUrl").toString(), 49 | }, 50 | }, 51 | }, 52 | ); 53 | 54 | const source = new SalesforceMarketingCloudSource({ 55 | profile: profile, 56 | apiVersion: SalesforceMarketingCloudApiVersions.V1, 57 | object: "Email", 58 | }); 59 | 60 | const bucket = new Bucket(stack, "TestBucket", { 61 | autoDeleteObjects: true, 62 | removalPolicy: RemovalPolicy.DESTROY, 63 | }); 64 | 65 | const destination = new S3Destination({ 66 | location: { bucket }, 67 | }); 68 | 69 | const flow = new OnScheduleFlow(stack, "OnScheduleFlow", { 70 | source: source, 71 | destination: destination, 72 | mappings: [ 73 | Mapping.map( 74 | { name: "Name", dataType: "String" }, 75 | { name: "Name", dataType: "string" }, 76 | ), 77 | ], 78 | transforms: [Transform.mask({ name: "Name" }, "*")], 79 | validations: [ 80 | Validation.when( 81 | ValidationCondition.isNull("Name"), 82 | ValidationAction.ignoreRecord(), 83 | ), 84 | ], 85 | schedule: Schedule.cron({ hour: "1", minute: "1" }), 86 | pullConfig: { mode: DataPullMode.INCREMENTAL }, 87 | scheduleProperties: { 88 | startTime: new Date(Date.parse("2024-01-01")), 89 | }, 90 | }); 91 | 92 | flow.onRunStarted("OnRunStarted"); 93 | 94 | app.synth(); 95 | -------------------------------------------------------------------------------- /test/mailchimp/profile.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { SecretValue, Stack } from "aws-cdk-lib"; 6 | import { Template } from "aws-cdk-lib/assertions"; 7 | import { MailchimpConnectorProfile } from "../../src"; 8 | 9 | describe("MailchimpConnectorProfileProps", () => { 10 | test("API Key profile with credentials exists in the stack", () => { 11 | const stack = new Stack(undefined, "TestStack", { 12 | env: { account: "12345678", region: "dummy" }, 13 | }); 14 | 15 | new MailchimpConnectorProfile(stack, "TestProfile", { 16 | apiKey: SecretValue.unsafePlainText("apiKey"), 17 | instanceUrl: SecretValue.unsafePlainText("instanceUrl").toString(), 18 | }); 19 | 20 | Template.fromStack(stack).hasResourceProperties( 21 | "AWS::AppFlow::ConnectorProfile", 22 | { 23 | ConnectionMode: "Public", 24 | ConnectorLabel: "Mailchimp", 25 | ConnectorProfileName: "TestStackTestProfile18724107", 26 | ConnectorType: "CustomConnector", 27 | ConnectorProfileConfig: { 28 | ConnectorProfileCredentials: { 29 | CustomConnector: { 30 | AuthenticationType: "CUSTOM", 31 | Custom: { 32 | CredentialsMap: { 33 | api_key: "apiKey", 34 | }, 35 | CustomAuthenticationType: "api_key", 36 | }, 37 | }, 38 | }, 39 | ConnectorProfileProperties: { 40 | CustomConnector: { 41 | ProfileProperties: { 42 | instanceUrl: "instanceUrl", 43 | }, 44 | }, 45 | }, 46 | }, 47 | }, 48 | ); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /test/mailchimp/source.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { Stack } from "aws-cdk-lib"; 6 | import { Bucket } from "aws-cdk-lib/aws-s3"; 7 | import { 8 | MailchimpConnectorProfile, 9 | MailchimpSource, 10 | MailchimpConnectorType, 11 | MailchimpApiVersion, 12 | OnDemandFlow, 13 | S3Destination, 14 | Mapping, 15 | } from "../../src"; 16 | 17 | describe("MailchimpSource", () => { 18 | test("Source with connector name", () => { 19 | const stack = new Stack(undefined, "TestStack"); 20 | const source = new MailchimpSource({ 21 | profile: MailchimpConnectorProfile.fromConnectionProfileName( 22 | stack, 23 | "TestProfile", 24 | "dummy-profile", 25 | ), 26 | apiVersion: MailchimpApiVersion.V3, 27 | object: "campaigns", 28 | }); 29 | 30 | const destination = new S3Destination({ 31 | location: { bucket: new Bucket(stack, "TestBucket") }, 32 | }); 33 | 34 | new OnDemandFlow(stack, "TestFlow", { 35 | source: source, 36 | destination: destination, 37 | mappings: [Mapping.mapAll()], 38 | }); 39 | 40 | const expectedConnectorType = MailchimpConnectorType.instance; 41 | expect(source.connectorType.asProfileConnectorLabel).toEqual( 42 | expectedConnectorType.asProfileConnectorLabel, 43 | ); 44 | expect(source.connectorType.asProfileConnectorType).toEqual( 45 | expectedConnectorType.asProfileConnectorType, 46 | ); 47 | expect(source.connectorType.asTaskConnectorOperatorOrigin).toEqual( 48 | expectedConnectorType.asTaskConnectorOperatorOrigin, 49 | ); 50 | expect(source.connectorType.isCustom).toEqual( 51 | expectedConnectorType.isCustom, 52 | ); 53 | }); 54 | 55 | test("Source with connector Arn", () => { 56 | const stack = new Stack(undefined, "TestStack"); 57 | const source = new MailchimpSource({ 58 | profile: MailchimpConnectorProfile.fromConnectionProfileArn( 59 | stack, 60 | "TestProfile", 61 | "arn:aws:appflow:region:account-id:connectorprofile/TestProfile", 62 | ), 63 | apiVersion: MailchimpApiVersion.V3, 64 | object: "campaigns", 65 | }); 66 | 67 | const destination = new S3Destination({ 68 | location: { bucket: new Bucket(stack, "TestBucket") }, 69 | }); 70 | 71 | new OnDemandFlow(stack, "TestFlow", { 72 | source: source, 73 | destination: destination, 74 | mappings: [Mapping.mapAll()], 75 | }); 76 | 77 | const expectedConnectorType = MailchimpConnectorType.instance; 78 | expect(source.connectorType.asProfileConnectorLabel).toEqual( 79 | expectedConnectorType.asProfileConnectorLabel, 80 | ); 81 | expect(source.connectorType.asProfileConnectorType).toEqual( 82 | expectedConnectorType.asProfileConnectorType, 83 | ); 84 | expect(source.connectorType.asTaskConnectorOperatorOrigin).toEqual( 85 | expectedConnectorType.asTaskConnectorOperatorOrigin, 86 | ); 87 | expect(source.connectorType.isCustom).toEqual( 88 | expectedConnectorType.isCustom, 89 | ); 90 | }); 91 | }); 92 | -------------------------------------------------------------------------------- /test/s3/source.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | SPDX-License-Identifier: Apache-2.0 4 | */ 5 | import { Stack } from "aws-cdk-lib"; 6 | import { Template } from "aws-cdk-lib/assertions"; 7 | import { Bucket } from "aws-cdk-lib/aws-s3"; 8 | import { 9 | OnDemandFlow, 10 | S3Destination, 11 | Mapping, 12 | S3Source, 13 | S3InputFileType, 14 | S3ConnectorType, 15 | } from "../../src"; 16 | 17 | describe("S3Source", () => { 18 | test("Source", () => { 19 | const stack = new Stack(undefined, "TestStack"); 20 | 21 | const bucket = new Bucket(stack, "TestBucket", { 22 | bucketName: "test-bucket", 23 | }); 24 | 25 | const source = new S3Source({ 26 | bucket: bucket, 27 | prefix: "prefix", 28 | format: { 29 | type: S3InputFileType.CSV, 30 | }, 31 | }); 32 | 33 | const destination = new S3Destination({ 34 | location: { 35 | bucket, 36 | }, 37 | }); 38 | 39 | new OnDemandFlow(stack, "TestFlow", { 40 | source: source, 41 | destination: destination, 42 | mappings: [Mapping.mapAll()], 43 | }); 44 | 45 | const expectedConnectorType = S3ConnectorType.instance; 46 | expect(source.connectorType.asProfileConnectorLabel).toEqual( 47 | expectedConnectorType.asProfileConnectorLabel, 48 | ); 49 | expect(source.connectorType.asProfileConnectorType).toEqual( 50 | expectedConnectorType.asProfileConnectorType, 51 | ); 52 | expect(source.connectorType.asTaskConnectorOperatorOrigin).toEqual( 53 | expectedConnectorType.asTaskConnectorOperatorOrigin, 54 | ); 55 | expect(source.connectorType.isCustom).toEqual( 56 | expectedConnectorType.isCustom, 57 | ); 58 | }); 59 | 60 | test("Flow source template is valid", () => { 61 | const stack = new Stack(undefined, "TestStack"); 62 | 63 | const bucket = new Bucket(stack, "TestBucket", { 64 | bucketName: "test-bucket", 65 | }); 66 | 67 | const source = new S3Source({ 68 | bucket: bucket, 69 | prefix: "prefix", 70 | format: { 71 | type: S3InputFileType.CSV, 72 | }, 73 | }); 74 | 75 | const destination = new S3Destination({ 76 | location: { 77 | bucket, 78 | }, 79 | }); 80 | 81 | new OnDemandFlow(stack, "TestFlow", { 82 | source: source, 83 | destination: destination, 84 | mappings: [Mapping.mapAll()], 85 | }); 86 | 87 | const template = Template.fromStack(stack); 88 | template.hasResourceProperties("AWS::AppFlow::Flow", { 89 | SourceFlowConfig: { 90 | ConnectorType: "S3", 91 | SourceConnectorProperties: { 92 | S3: { 93 | BucketName: { 94 | Ref: "TestBucket560B80BC", 95 | }, 96 | BucketPrefix: "prefix", 97 | S3InputFormatConfig: { 98 | S3InputFileType: "CSV", 99 | }, 100 | }, 101 | }, 102 | }, 103 | }); 104 | }); 105 | 106 | test("Only known S3InputFileType specified", () => { 107 | const expectedTypes = ["CSV", "JSON"]; 108 | const actualTypes = Object.values(S3InputFileType); 109 | 110 | expect(actualTypes).toEqual(expectedTypes); 111 | }); 112 | }); 113 | -------------------------------------------------------------------------------- /tsconfig.dev.json: -------------------------------------------------------------------------------- 1 | // ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". 2 | { 3 | "compilerOptions": { 4 | "alwaysStrict": true, 5 | "declaration": true, 6 | "esModuleInterop": true, 7 | "experimentalDecorators": true, 8 | "inlineSourceMap": true, 9 | "inlineSources": true, 10 | "lib": [ 11 | "es2020" 12 | ], 13 | "module": "CommonJS", 14 | "noEmitOnError": false, 15 | "noFallthroughCasesInSwitch": true, 16 | "noImplicitAny": true, 17 | "noImplicitReturns": true, 18 | "noImplicitThis": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "resolveJsonModule": true, 22 | "strict": true, 23 | "strictNullChecks": true, 24 | "strictPropertyInitialization": true, 25 | "stripInternal": true, 26 | "target": "ES2020" 27 | }, 28 | "include": [ 29 | "src/**/*.ts", 30 | "test/**/*.ts", 31 | ".projenrc.ts", 32 | "projenrc/**/*.ts" 33 | ], 34 | "exclude": [ 35 | "node_modules" 36 | ] 37 | } 38 | --------------------------------------------------------------------------------