@taimos/projen 0.1.78 → 0.1.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,187 @@
1
+ import { Component, github } from 'projen';
2
+ import { GitHubProject } from 'projen/lib/github';
3
+ /**
4
+ * One deploy stage: a git branch, the logical stage it serves, and the AWS
5
+ * account its Amplify apps live in.
6
+ *
7
+ * Both shapes seen in practice are expressible: separate accounts per stage
8
+ * (each entry has its own `account`), or a single account serving several
9
+ * branches (every entry repeats the same `account`, and the branch alone
10
+ * selects which Amplify branch is built).
11
+ */
12
+ export interface AmplifyDeployStage {
13
+ /** The git branch the Amplify apps build from, e.g. `main` or `production`. */
14
+ readonly branch: string;
15
+ /**
16
+ * The logical stage this branch serves, e.g. `dev` or `prod`. Used as the
17
+ * GitHub environment so protection rules apply per stage.
18
+ */
19
+ readonly stageName: string;
20
+ /** The AWS account hosting this stage's Amplify apps. */
21
+ readonly account: string;
22
+ }
23
+ /**
24
+ * One Amplify Hosting application whose builds CI drives.
25
+ *
26
+ * Mirrors a `MonorepoAmplifyApp` entry in the generated `amplify.yml`; the
27
+ * `appRoot` should match so a build is triggered by exactly the directory it is
28
+ * built from.
29
+ */
30
+ export interface AmplifyDeployApp {
31
+ /**
32
+ * Short key identifying the app. Used in the app-id SSM parameter path and,
33
+ * by default, in the workflow name.
34
+ *
35
+ * Must match the key the CDK side registers the app under.
36
+ */
37
+ readonly key: string;
38
+ /**
39
+ * The package path that is the Amplify app root, e.g. `packages/frontend`.
40
+ * `<appRoot>/**` becomes a push trigger path.
41
+ */
42
+ readonly appRoot: string;
43
+ /**
44
+ * Extra path globs that affect this app's build output.
45
+ *
46
+ * Set this for workspace packages the app consumes via `workspace:*` and that
47
+ * the build spec pre-builds — a shared API package, say. Without them a change
48
+ * to shared types would not rebuild the app and it would ship stale.
49
+ *
50
+ * @default []
51
+ */
52
+ readonly dependencyPaths?: string[];
53
+ /**
54
+ * Human-readable name used in step names and log lines.
55
+ *
56
+ * @default - the `key`
57
+ */
58
+ readonly label?: string;
59
+ /**
60
+ * The generated workflow name, which is also its `.yml` file name.
61
+ *
62
+ * @default - `<key>-deploy`
63
+ */
64
+ readonly workflowName?: string;
65
+ }
66
+ export interface GitHubAmplifyDeployOptions {
67
+ /** The Amplify apps to generate deploy workflows for. At least one. */
68
+ readonly apps: AmplifyDeployApp[];
69
+ /** The branches that deploy, and the account each one deploys into. At least one. */
70
+ readonly stages: AmplifyDeployStage[];
71
+ /**
72
+ * The GitHub OIDC deployment role every workflow assumes first, typically in
73
+ * a management account. The per-stage build-trigger role is reached from it
74
+ * by role chaining, so it must be allowed to `sts:AssumeRole` on that role —
75
+ * an IAM grant that lives outside the generated code.
76
+ */
77
+ readonly deploymentRoleArn: string;
78
+ /**
79
+ * Name of the per-account IAM role CI chains into to start builds.
80
+ *
81
+ * The same name is expected in every stage account, so the workflow can build
82
+ * the ARN from the account id alone. The CDK side must create a role with
83
+ * exactly this name.
84
+ *
85
+ * @default - `<project name>-amplify-build-trigger`
86
+ */
87
+ readonly buildTriggerRoleName?: string;
88
+ /**
89
+ * Prefix of the SSM parameter path holding each app's Amplify app id. The
90
+ * full path is `<prefix>/<app key>/app-id`.
91
+ *
92
+ * Reading the app id at run time means CI never hardcodes an id that changes
93
+ * whenever an app is replaced.
94
+ *
95
+ * @default - `/<project name>/amplify`
96
+ */
97
+ readonly parameterPrefix?: string;
98
+ /**
99
+ * The AWS region the Amplify apps live in.
100
+ *
101
+ * @default 'eu-central-1'
102
+ */
103
+ readonly region?: string;
104
+ /**
105
+ * Paths that change what *every* Amplify build produces, added to each app's
106
+ * own paths.
107
+ *
108
+ * @default - the Amplify build spec, the lockfile and the workspace file
109
+ */
110
+ readonly sharedBuildPaths?: string[];
111
+ /**
112
+ * The runner tags used to select the runner.
113
+ *
114
+ * @default ['ubuntu-latest']
115
+ */
116
+ readonly runnerTags?: string[];
117
+ /**
118
+ * Timeout for a deploy job, bounding a hung Amplify build.
119
+ *
120
+ * @default 45
121
+ */
122
+ readonly timeoutMinutes?: number;
123
+ }
124
+ /**
125
+ * Adds one path-scoped deploy workflow per Amplify Hosting app.
126
+ *
127
+ * Amplify's own auto-build fires on every push to a tracked branch. In a
128
+ * monorepo that means every frontend rebuilds whenever anything changes — the
129
+ * marketing site rebuilding for a backend-only commit and vice versa, once per
130
+ * tracked branch. Amplify bills build minutes, so most of those are waste.
131
+ *
132
+ * Amplify's native answer, `AMPLIFY_DIFF_DEPLOY`, diffs exactly one directory
133
+ * (`AMPLIFY_MONOREPO_APP_ROOT`, overridable via `AMPLIFY_DIFF_DEPLOY_ROOT` —
134
+ * still a single path). That is enough for a self-contained app but not for one
135
+ * that also depends on a shared workspace package: a one-directory diff would
136
+ * ship a stale frontend whenever the shared types changed. GitHub's `paths:`
137
+ * filters accept multiple globs, so builds move to CI.
138
+ *
139
+ * Each generated workflow resolves the pushed branch to its stage and account,
140
+ * chains OIDC -> deployment role -> build-trigger role, reads the app id from
141
+ * SSM, starts a `RELEASE` job and polls until it reaches a terminal state — so
142
+ * a failed Amplify build fails the workflow instead of passing silently.
143
+ *
144
+ * This component generates the CI half only. The infrastructure half belongs in
145
+ * the project's own CDK app, which must:
146
+ *
147
+ * 1. set `autoBuild: false` on every branch these workflows build,
148
+ * 2. publish each app's id to `<parameterPrefix>/<key>/app-id`, and
149
+ * 3. create a role named `buildTriggerRoleName` in each stage account,
150
+ * trusted by `deploymentRoleArn` and granting `amplify:StartJob` +
151
+ * `amplify:GetJob` on the tracked branch ARNs only.
152
+ *
153
+ * Use `buildTriggerRoleName` and `appIdParameterName()` from the projenrc to
154
+ * keep those names in step; a mismatch fails the workflow loudly at the
155
+ * assume-role or parameter-read step rather than skipping a deploy.
156
+ */
157
+ export declare class GitHubAmplifyDeploy extends Component {
158
+ /** The generated deploy workflows, one per app. */
159
+ readonly workflows: github.GithubWorkflow[];
160
+ /** Name of the IAM role CI chains into, in every stage account. */
161
+ readonly buildTriggerRoleName: string;
162
+ /** Prefix of the SSM parameter path holding each app's Amplify app id. */
163
+ readonly parameterPrefix: string;
164
+ private readonly region;
165
+ constructor(scope: GitHubProject, options: GitHubAmplifyDeployOptions);
166
+ /**
167
+ * The SSM parameter path holding an app's Amplify app id. The CDK side must
168
+ * publish the id under exactly this name.
169
+ */
170
+ appIdParameterName(key: string): string;
171
+ /**
172
+ * The job-level `environment:` expression mapping branch to stage, so each
173
+ * stage keeps whatever GitHub environment protection rules it has. The first
174
+ * stage is the fallback; every later stage gets an explicit branch test.
175
+ */
176
+ private environmentExpression;
177
+ /**
178
+ * Bash mapping the pushed branch to its stage and build-trigger role ARN, so
179
+ * account ids live only in the projenrc. A branch that is not a deploy branch
180
+ * is an error rather than a silent no-op.
181
+ */
182
+ private resolveStageScript;
183
+ /** Reads the app id from SSM and starts a RELEASE build. */
184
+ private startBuildScript;
185
+ /** Polls the job until it reaches a terminal state, failing on a bad one. */
186
+ private waitForBuildScript;
187
+ }
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitHubAmplifyDeploy = void 0;
4
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
5
+ const projen_1 = require("projen");
6
+ /** Paths that invalidate every app's build output. */
7
+ const DEFAULT_SHARED_BUILD_PATHS = [
8
+ 'amplify.yml',
9
+ 'pnpm-lock.yaml',
10
+ 'pnpm-workspace.yaml',
11
+ ];
12
+ /**
13
+ * Adds one path-scoped deploy workflow per Amplify Hosting app.
14
+ *
15
+ * Amplify's own auto-build fires on every push to a tracked branch. In a
16
+ * monorepo that means every frontend rebuilds whenever anything changes — the
17
+ * marketing site rebuilding for a backend-only commit and vice versa, once per
18
+ * tracked branch. Amplify bills build minutes, so most of those are waste.
19
+ *
20
+ * Amplify's native answer, `AMPLIFY_DIFF_DEPLOY`, diffs exactly one directory
21
+ * (`AMPLIFY_MONOREPO_APP_ROOT`, overridable via `AMPLIFY_DIFF_DEPLOY_ROOT` —
22
+ * still a single path). That is enough for a self-contained app but not for one
23
+ * that also depends on a shared workspace package: a one-directory diff would
24
+ * ship a stale frontend whenever the shared types changed. GitHub's `paths:`
25
+ * filters accept multiple globs, so builds move to CI.
26
+ *
27
+ * Each generated workflow resolves the pushed branch to its stage and account,
28
+ * chains OIDC -> deployment role -> build-trigger role, reads the app id from
29
+ * SSM, starts a `RELEASE` job and polls until it reaches a terminal state — so
30
+ * a failed Amplify build fails the workflow instead of passing silently.
31
+ *
32
+ * This component generates the CI half only. The infrastructure half belongs in
33
+ * the project's own CDK app, which must:
34
+ *
35
+ * 1. set `autoBuild: false` on every branch these workflows build,
36
+ * 2. publish each app's id to `<parameterPrefix>/<key>/app-id`, and
37
+ * 3. create a role named `buildTriggerRoleName` in each stage account,
38
+ * trusted by `deploymentRoleArn` and granting `amplify:StartJob` +
39
+ * `amplify:GetJob` on the tracked branch ARNs only.
40
+ *
41
+ * Use `buildTriggerRoleName` and `appIdParameterName()` from the projenrc to
42
+ * keep those names in step; a mismatch fails the workflow loudly at the
43
+ * assume-role or parameter-read step rather than skipping a deploy.
44
+ */
45
+ class GitHubAmplifyDeploy extends projen_1.Component {
46
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "@taimos/projen.GitHubAmplifyDeploy", version: "0.1.80" };
47
+ /** The generated deploy workflows, one per app. */
48
+ workflows = [];
49
+ /** Name of the IAM role CI chains into, in every stage account. */
50
+ buildTriggerRoleName;
51
+ /** Prefix of the SSM parameter path holding each app's Amplify app id. */
52
+ parameterPrefix;
53
+ region;
54
+ constructor(scope, options) {
55
+ super(scope);
56
+ if (!scope.github) {
57
+ throw new Error('GitHubAmplifyDeploy requires a project with GitHub enabled');
58
+ }
59
+ if (options.apps.length === 0) {
60
+ throw new Error('GitHubAmplifyDeploy requires at least one app');
61
+ }
62
+ if (options.stages.length === 0) {
63
+ throw new Error('GitHubAmplifyDeploy requires at least one stage');
64
+ }
65
+ const keys = options.apps.map((app) => app.key);
66
+ const duplicateKey = keys.find((key, index) => keys.indexOf(key) !== index);
67
+ if (duplicateKey) {
68
+ throw new Error(`GitHubAmplifyDeploy app keys must be unique, got '${duplicateKey}' twice`);
69
+ }
70
+ const branches = options.stages.map((stage) => stage.branch);
71
+ const duplicateBranch = branches.find((branch, index) => branches.indexOf(branch) !== index);
72
+ if (duplicateBranch) {
73
+ throw new Error(`GitHubAmplifyDeploy stage branches must be unique, got '${duplicateBranch}' twice`);
74
+ }
75
+ this.buildTriggerRoleName = options.buildTriggerRoleName ?? `${scope.name}-amplify-build-trigger`;
76
+ this.parameterPrefix = options.parameterPrefix ?? `/${scope.name}/amplify`;
77
+ this.region = options.region ?? 'eu-central-1';
78
+ const sharedBuildPaths = options.sharedBuildPaths ?? DEFAULT_SHARED_BUILD_PATHS;
79
+ const runnerTags = options.runnerTags ?? ['ubuntu-latest'];
80
+ const timeoutMinutes = options.timeoutMinutes ?? 45;
81
+ for (const app of options.apps) {
82
+ const label = app.label ?? app.key;
83
+ const workflowName = app.workflowName ?? `${app.key}-deploy`;
84
+ const workflow = new projen_1.github.GithubWorkflow(scope.github, workflowName);
85
+ workflow.on({
86
+ push: {
87
+ branches: options.stages.map((stage) => stage.branch),
88
+ paths: [
89
+ `${app.appRoot}/**`,
90
+ ...(app.dependencyPaths ?? []),
91
+ ...sharedBuildPaths,
92
+ // Changing the workflow itself should prove it still works.
93
+ `.github/workflows/${workflowName}.yml`,
94
+ ],
95
+ },
96
+ // Manual redeploy, e.g. after a build-only failure.
97
+ workflowDispatch: {},
98
+ });
99
+ workflow.addJob('deploy', {
100
+ name: `Build and deploy the ${label} on Amplify`,
101
+ runsOn: runnerTags,
102
+ permissions: {
103
+ contents: projen_1.github.workflows.JobPermission.READ,
104
+ idToken: projen_1.github.workflows.JobPermission.WRITE,
105
+ },
106
+ environment: this.environmentExpression(options.stages),
107
+ concurrency: {
108
+ 'group': `${workflowName}-\${{ github.ref_name }}`,
109
+ // Cancelling the workflow would not cancel the Amplify job it started,
110
+ // so let runs queue instead of orphaning builds.
111
+ 'cancel-in-progress': false,
112
+ },
113
+ timeoutMinutes,
114
+ steps: [
115
+ {
116
+ name: 'Resolve stage',
117
+ id: 'stage',
118
+ run: this.resolveStageScript(options.stages),
119
+ },
120
+ {
121
+ name: 'AWS credentials — deployment role',
122
+ id: 'aws_credentials_deployment_role',
123
+ uses: 'aws-actions/configure-aws-credentials@v5',
124
+ with: {
125
+ 'role-to-assume': options.deploymentRoleArn,
126
+ 'role-session-name': 'GitHubAction',
127
+ 'aws-region': this.region,
128
+ },
129
+ },
130
+ {
131
+ name: 'AWS credentials — Amplify build trigger',
132
+ id: 'aws_credentials_amplify_build_trigger',
133
+ uses: 'aws-actions/configure-aws-credentials@v5',
134
+ with: {
135
+ 'role-to-assume': '${{ steps.stage.outputs.role_arn }}',
136
+ 'role-session-name': 'AmplifyBuildTrigger',
137
+ 'aws-region': this.region,
138
+ // Chain from the deployment role rather than re-using the OIDC
139
+ // token, so no identity provider is needed in the stage account.
140
+ 'role-chaining': true,
141
+ // The action tags sessions by default, which turns the chained
142
+ // call into AssumeRole + TagSession. The trust policy grants
143
+ // AssumeRole only, so tagging fails the step; the session is
144
+ // already tagged by the first assume anyway.
145
+ 'role-skip-session-tagging': true,
146
+ },
147
+ },
148
+ {
149
+ name: `Start ${label} build`,
150
+ id: 'start',
151
+ run: this.startBuildScript(app, label),
152
+ },
153
+ {
154
+ name: 'Wait for build to finish',
155
+ id: 'wait_for_build_to_finish',
156
+ run: this.waitForBuildScript(label),
157
+ },
158
+ ],
159
+ });
160
+ this.workflows.push(workflow);
161
+ }
162
+ }
163
+ /**
164
+ * The SSM parameter path holding an app's Amplify app id. The CDK side must
165
+ * publish the id under exactly this name.
166
+ */
167
+ appIdParameterName(key) {
168
+ return `${this.parameterPrefix}/${key}/app-id`;
169
+ }
170
+ /**
171
+ * The job-level `environment:` expression mapping branch to stage, so each
172
+ * stage keeps whatever GitHub environment protection rules it has. The first
173
+ * stage is the fallback; every later stage gets an explicit branch test.
174
+ */
175
+ environmentExpression(stages) {
176
+ const [fallback, ...rest] = stages;
177
+ const tests = rest.map((s) => `github.ref_name == '${s.branch}' && '${s.stageName}' || `).join('');
178
+ return `\${{ ${tests}'${fallback.stageName}' }}`;
179
+ }
180
+ /**
181
+ * Bash mapping the pushed branch to its stage and build-trigger role ARN, so
182
+ * account ids live only in the projenrc. A branch that is not a deploy branch
183
+ * is an error rather than a silent no-op.
184
+ */
185
+ resolveStageScript(stages) {
186
+ const cases = stages.map((s) => ` ${s.branch}) stage='${s.stageName}'; account='${s.account}' ;;`);
187
+ return [
188
+ 'set -euo pipefail',
189
+ 'case "$GITHUB_REF_NAME" in',
190
+ ...cases,
191
+ ' *)',
192
+ ' echo "::error::$GITHUB_REF_NAME is not a deploy branch"',
193
+ ' exit 1',
194
+ ' ;;',
195
+ 'esac',
196
+ `role="arn:aws:iam::$account:role/${this.buildTriggerRoleName}"`,
197
+ 'echo "stage=$stage" >> "$GITHUB_OUTPUT"',
198
+ 'echo "role_arn=$role" >> "$GITHUB_OUTPUT"',
199
+ 'echo "Deploying $GITHUB_REF_NAME to stage $stage ($account)" >> "$GITHUB_STEP_SUMMARY"',
200
+ ].join('\n');
201
+ }
202
+ /** Reads the app id from SSM and starts a RELEASE build. */
203
+ startBuildScript(app, label) {
204
+ return [
205
+ 'set -euo pipefail',
206
+ `app_id="$(aws ssm get-parameter --name '${this.appIdParameterName(app.key)}' --query Parameter.Value --output text)"`,
207
+ '# RELEASE builds the current tip of the branch. That is normally $GITHUB_SHA;',
208
+ '# if two pushes race, the tip wins and the earlier run is redundant rather',
209
+ '# than wrong. The job concurrency group keeps that rare.',
210
+ 'job_id="$(aws amplify start-job \\',
211
+ ' --app-id "$app_id" \\',
212
+ ' --branch-name "$GITHUB_REF_NAME" \\',
213
+ ' --job-type RELEASE \\',
214
+ ' --job-reason "GitHub Actions $GITHUB_WORKFLOW run $GITHUB_RUN_ID for $GITHUB_SHA" \\',
215
+ ' --query jobSummary.jobId --output text)"',
216
+ 'echo "app_id=$app_id" >> "$GITHUB_OUTPUT"',
217
+ 'echo "job_id=$job_id" >> "$GITHUB_OUTPUT"',
218
+ `echo "Started ${label} Amplify job \$job_id on app \$app_id" >> "\$GITHUB_STEP_SUMMARY"`,
219
+ ].join('\n');
220
+ }
221
+ /** Polls the job until it reaches a terminal state, failing on a bad one. */
222
+ waitForBuildScript(label) {
223
+ return [
224
+ 'set -euo pipefail',
225
+ 'while true; do',
226
+ ' status="$(aws amplify get-job \\',
227
+ ' --app-id "${{ steps.start.outputs.app_id }}" \\',
228
+ ' --branch-name "$GITHUB_REF_NAME" \\',
229
+ ' --job-id "${{ steps.start.outputs.job_id }}" \\',
230
+ ' --query job.summary.status --output text)"',
231
+ ' case "$status" in',
232
+ ' SUCCEED)',
233
+ ` echo "${label} build succeeded" >> "\$GITHUB_STEP_SUMMARY"`,
234
+ ' exit 0',
235
+ ' ;;',
236
+ ' FAILED|CANCELLED)',
237
+ ` echo "::error::${label} Amplify job \${{ steps.start.outputs.job_id }} ended as \$status"`,
238
+ ' exit 1',
239
+ ' ;;',
240
+ ' esac',
241
+ ' echo "status: $status"',
242
+ ' sleep 15',
243
+ 'done',
244
+ ].join('\n');
245
+ }
246
+ }
247
+ exports.GitHubAmplifyDeploy = GitHubAmplifyDeploy;
248
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW1wbGlmeS1kZXBsb3kuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tcG9uZW50cy9hbXBsaWZ5LWRlcGxveS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsbUNBQTJDO0FBNkkzQyxzREFBc0Q7QUFDdEQsTUFBTSwwQkFBMEIsR0FBRztJQUNqQyxhQUFhO0lBQ2IsZ0JBQWdCO0lBQ2hCLHFCQUFxQjtDQUN0QixDQUFDO0FBRUY7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBZ0NHO0FBQ0gsTUFBYSxtQkFBb0IsU0FBUSxrQkFBUzs7SUFDaEQsbURBQW1EO0lBQ25DLFNBQVMsR0FBNEIsRUFBRSxDQUFDO0lBRXhELG1FQUFtRTtJQUNuRCxvQkFBb0IsQ0FBUztJQUU3QywwRUFBMEU7SUFDMUQsZUFBZSxDQUFTO0lBRXZCLE1BQU0sQ0FBUztJQUVoQyxZQUFZLEtBQW9CLEVBQUUsT0FBbUM7UUFDbkUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRWIsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNsQixNQUFNLElBQUksS0FBSyxDQUFDLDREQUE0RCxDQUFDLENBQUM7UUFDaEYsQ0FBQztRQUNELElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDOUIsTUFBTSxJQUFJLEtBQUssQ0FBQywrQ0FBK0MsQ0FBQyxDQUFDO1FBQ25FLENBQUM7UUFDRCxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ2hDLE1BQU0sSUFBSSxLQUFLLENBQUMsaURBQWlELENBQUMsQ0FBQztRQUNyRSxDQUFDO1FBRUQsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNoRCxNQUFN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RztZQUNoRSx5Q0FBeUM7WUFDekMsMkNBQTJDO1lBQzNDLHdGQUF3RjtTQUN6RixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNmLENBQUM7SUFFRCw0REFBNEQ7SUFDcEQsZ0JBQWdCLENBQUMsR0FBcUIsRUFBRSxLQUFhO1FBQzNELE9BQU87WUFDTCxtQkFBbUI7WUFDbkIsMkNBQTJDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLDJDQUEyQztZQUN0SCwrRUFBK0U7WUFDL0UsNEVBQTRFO1lBQzVFLDBEQUEwRDtZQUMxRCxvQ0FBb0M7WUFDcEMseUJBQXlCO1lBQ3pCLHVDQUF1QztZQUN2Qyx5QkFBeUI7WUFDekIsd0ZBQXdGO1lBQ3hGLDRDQUE0QztZQUM1QywyQ0FBMkM7WUFDM0MsMkNBQTJDO1lBQzNDLGlCQUFpQixLQUFLLG1FQUFtRTtTQUMxRixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNmLENBQUM7SUFFRCw2RUFBNkU7SUFDckUsa0JBQWtCLENBQUMsS0FBYTtRQUN0QyxPQUFPO1lBQ0wsbUJBQW1CO1lBQ25CLGdCQUFnQjtZQUNoQixvQ0FBb0M7WUFDcEMscURBQXFEO1lBQ3JELHlDQUF5QztZQUN6QyxxREFBcUQ7WUFDckQsZ0RBQWdEO1lBQ2hELHFCQUFxQjtZQUNyQixjQUFjO1lBQ2QsZUFBZSxLQUFLLDhDQUE4QztZQUNsRSxjQUFjO1lBQ2QsVUFBVTtZQUNWLHVCQUF1QjtZQUN2Qix3QkFBd0IsS0FBSyxvRUFBb0U7WUFDakcsY0FBYztZQUNkLFVBQVU7WUFDVixRQUFRO1lBQ1IsMEJBQTBCO1lBQzFCLFlBQVk7WUFDWixNQUFNO1NBQ1AsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDZixDQUFDOztBQXpOSCxrREEwTkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIGdpdGh1YiB9IGZyb20gJ3Byb2plbic7XG5pbXBvcnQgeyBHaXRIdWJQcm9qZWN0IH0gZnJvbSAncHJvamVuL2xpYi9naXRodWInO1xuXG4vKipcbiAqIE9uZSBkZXBsb3kgc3RhZ2U6IGEgZ2l0IGJyYW5jaCwgdGhlIGxvZ2ljYWwgc3RhZ2UgaXQgc2VydmVzLCBhbmQgdGhlIEFXU1xuICogYWNjb3VudCBpdHMgQW1wbGlmeSBhcHBzIGxpdmUgaW4uXG4gKlxuICogQm90aCBzaGFwZXMgc2VlbiBpbiBwcmFjdGljZSBhcmUgZXhwcmVzc2libGU6IHNlcGFyYXRlIGFjY291bnRzIHBlciBzdGFnZVxuICogKGVhY2ggZW50cnkgaGFzIGl0cyBvd24gYGFjY291bnRgKSwgb3IgYSBzaW5nbGUgYWNjb3VudCBzZXJ2aW5nIHNldmVyYWxcbiAqIGJyYW5jaGVzIChldmVyeSBlbnRyeSByZXBlYXRzIHRoZSBzYW1lIGBhY2NvdW50YCwgYW5kIHRoZSBicmFuY2ggYWxvbmVcbiAqIHNlbGVjdHMgd2hpY2ggQW1wbGlmeSBicmFuY2ggaXMgYnVpbHQpLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEFtcGxpZnlEZXBsb3lTdGFnZSB7XG4gIC8qKiBUaGUgZ2l0IGJyYW5jaCB0aGUgQW1wbGlmeSBhcHBzIGJ1aWxkIGZyb20sIGUuZy4gYG1haW5gIG9yIGBwcm9kdWN0aW9uYC4gKi9cbiAgcmVhZG9ubHkgYnJhbmNoOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBsb2dpY2FsIHN0YWdlIHRoaXMgYnJhbmNoIHNlcnZlcywgZS5nLiBgZGV2YCBvciBgcHJvZGAuIFVzZWQgYXMgdGhlXG4gICAqIEdpdEh1YiBlbnZpcm9ubWVudCBzbyBwcm90ZWN0aW9uIHJ1bGVzIGFwcGx5IHBlciBzdGFnZS5cbiAgICovXG4gIHJlYWRvbmx5IHN0YWdlTmFtZTogc3RyaW5nO1xuXG4gIC8qKiBUaGUgQVdTIGFjY291bnQgaG9zdGluZyB0aGlzIHN0YWdlJ3MgQW1wbGlmeSBhcHBzLiAqL1xuICByZWFkb25seSBhY2NvdW50OiBzdHJpbmc7XG59XG5cbi8qKlxuICogT25lIEFtcGxpZnkgSG9zdGluZyBhcHBsaWNhdGlvbiB3aG9zZSBidWlsZHMgQ0kgZHJpdmVzLlxuICpcbiAqIE1pcnJvcnMgYSBgTW9ub3JlcG9BbXBsaWZ5QXBwYCBlbnRyeSBpbiB0aGUgZ2VuZXJhdGVkIGBhbXBsaWZ5LnltbGA7IHRoZVxuICogYGFwcFJvb3RgIHNob3VsZCBtYXRjaCBzbyBhIGJ1aWxkIGlzIHRyaWdnZXJlZCBieSBleGFjdGx5IHRoZSBkaXJlY3RvcnkgaXQgaXNcbiAqIGJ1aWx0IGZyb20uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQW1wbGlmeURlcGxveUFwcCB7XG4gIC8qKlxuICAgKiBTaG9ydCBrZXkgaWRlbnRpZnlpbmcgdGhlIGFwcC4gVXNlZCBpbiB0aGUgYXBwLWlkIFNTTSBwYXJhbWV0ZXIgcGF0aCBhbmQsXG4gICAqIGJ5IGRlZmF1bHQsIGluIHRoZSB3b3JrZmxvdyBuYW1lLlxuICAgKlxuICAgKiBNdXN0IG1hdGNoIHRoZSBrZXkgdGhlIENESyBzaWRlIHJlZ2lzdGVycyB0aGUgYXBwIHVuZGVyLlxuICAgKi9cbiAgcmVhZG9ubHkga2V5OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBwYWNrYWdlIHBhdGggdGhhdCBpcyB0aGUgQW1wbGlmeSBhcHAgcm9vdCwgZS5nLiBgcGFja2FnZXMvZnJvbnRlbmRgLlxuICAgKiBgPGFwcFJvb3Q+LyoqYCBiZWNvbWVzIGEgcHVzaCB0cmlnZ2VyIHBhdGguXG4gICAqL1xuICByZWFkb25seSBhcHBSb290OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEV4dHJhIHBhdGggZ2xvYnMgdGhhdCBhZmZlY3QgdGhpcyBhcHAncyBidWlsZCBvdXRwdXQuXG4gICAqXG4gICAqIFNldCB0aGlzIGZvciB3b3Jrc3BhY2UgcGFja2FnZXMgdGhlIGFwcCBjb25zdW1lcyB2aWEgYHdvcmtzcGFjZToqYCBhbmQgdGhhdFxuICAgKiB0aGUgYnVpbGQgc3BlYyBwcmUtYnVpbGRzIOKAlCBhIHNoYXJlZCBBUEkgcGFja2FnZSwgc2F5LiBXaXRob3V0IHRoZW0gYSBjaGFuZ2VcbiAgICogdG8gc2hhcmVkIHR5cGVzIHdvdWxkIG5vdCByZWJ1aWxkIHRoZSBhcHAgYW5kIGl0IHdvdWxkIHNoaXAgc3RhbGUuXG4gICAqXG4gICAqIEBkZWZhdWx0IFtdXG4gICAqL1xuICByZWFkb25seSBkZXBlbmRlbmN5UGF0aHM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogSHVtYW4tcmVhZGFibGUgbmFtZSB1c2VkIGluIHN0ZXAgbmFtZXMgYW5kIGxvZyBsaW5lcy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSB0aGUgYGtleWBcbiAgICovXG4gIHJlYWRvbmx5IGxhYmVsPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgZ2VuZXJhdGVkIHdvcmtmbG93IG5hbWUsIHdoaWNoIGlzIGFsc28gaXRzIGAueW1sYCBmaWxlIG5hbWUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gYDxrZXk+LWRlcGxveWBcbiAgICovXG4gIHJlYWRvbmx5IHdvcmtmbG93TmFtZT86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHaXRIdWJBbXBsaWZ5RGVwbG95T3B0aW9ucyB7XG4gIC8qKiBUaGUgQW1wbGlmeSBhcHBzIHRvIGdlbmVyYXRlIGRlcGxveSB3b3JrZmxvd3MgZm9yLiBBdCBsZWFzdCBvbmUuICovXG4gIHJlYWRvbmx5IGFwcHM6IEFtcGxpZnlEZXBsb3lBcHBbXTtcblxuICAvKiogVGhlIGJyYW5jaGVzIHRoYXQgZGVwbG95LCBhbmQgdGhlIGFjY291bnQgZWFjaCBvbmUgZGVwbG95cyBpbnRvLiBBdCBsZWFzdCBvbmUuICovXG4gIHJlYWRvbmx5IHN0YWdlczogQW1wbGlmeURlcGxveVN0YWdlW107XG5cbiAgLyoqXG4gICAqIFRoZSBHaXRIdWIgT0lEQyBkZXBsb3ltZW50IHJvbGUgZXZlcnkgd29ya2Zsb3cgYXNzdW1lcyBmaXJzdCwgdHlwaWNhbGx5IGluXG4gICAqIGEgbWFuYWdlbWVudCBhY2NvdW50LiBUaGUgcGVyLXN0YWdlIGJ1aWxkLXRyaWdnZXIgcm9sZSBpcyByZWFjaGVkIGZyb20gaXRcbiAgICogYnkgcm9sZSBjaGFpbmluZywgc28gaXQgbXVzdCBiZSBhbGxvd2VkIHRvIGBzdHM6QXNzdW1lUm9sZWAgb24gdGhhdCByb2xlIOKAlFxuICAgKiBhbiBJQU0gZ3JhbnQgdGhhdCBsaXZlcyBvdXRzaWRlIHRoZSBnZW5lcmF0ZWQgY29kZS5cbiAgICovXG4gIHJlYWRvbmx5IGRlcGxveW1lbnRSb2xlQXJuOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE5hbWUgb2YgdGhlIHBlci1hY2NvdW50IElBTSByb2xlIENJIGNoYWlucyBpbnRvIHRvIHN0YXJ0IGJ1aWxkcy5cbiAgICpcbiAgICogVGhlIHNhbWUgbmFtZSBpcyBleHBlY3RlZCBpbiBldmVyeSBzdGFnZSBhY2NvdW50LCBzbyB0aGUgd29ya2Zsb3cgY2FuIGJ1aWxkXG4gICAqIHRoZSBBUk4gZnJvbSB0aGUgYWNjb3VudCBpZCBhbG9uZS4gVGhlIENESyBzaWRlIG11c3QgY3JlYXRlIGEgcm9sZSB3aXRoXG4gICAqIGV4YWN0bHkgdGhpcyBuYW1lLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGA8cHJvamVjdCBuYW1lPi1hbXBsaWZ5LWJ1aWxkLXRyaWdnZXJgXG4gICAqL1xuICByZWFkb25seSBidWlsZFRyaWdnZXJSb2xlTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogUHJlZml4IG9mIHRoZSBTU00gcGFyYW1ldGVyIHBhdGggaG9sZGluZyBlYWNoIGFwcCdzIEFtcGxpZnkgYXBwIGlkLiBUaGVcbiAgICogZnVsbCBwYXRoIGlzIGA8cHJlZml4Pi88YXBwIGtleT4vYXBwLWlkYC5cbiAgICpcbiAgICogUmVhZGluZyB0aGUgYXBwIGlkIGF0IHJ1biB0aW1lIG1lYW5zIENJIG5ldmVyIGhhcmRjb2RlcyBhbiBpZCB0aGF0IGNoYW5nZXNcbiAgICogd2hlbmV2ZXIgYW4gYXBwIGlzIHJlcGxhY2VkLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGAvPHByb2plY3QgbmFtZT4vYW1wbGlmeWBcbiAgICovXG4gIHJlYWRvbmx5IHBhcmFtZXRlclByZWZpeD86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIEFXUyByZWdpb24gdGhlIEFtcGxpZnkgYXBwcyBsaXZlIGluLlxuICAgKlxuICAgKiBAZGVmYXVsdCAnZXUtY2VudHJhbC0xJ1xuICAgKi9cbiAgcmVhZG9ubHkgcmVnaW9uPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBQYXRocyB0aGF0IGNoYW5nZSB3aGF0ICpldmVyeSogQW1wbGlmeSBidWlsZCBwcm9kdWNlcywgYWRkZWQgdG8gZWFjaCBhcHAnc1xuICAgKiBvd24gcGF0aHMuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gdGhlIEFtcGxpZnkgYnVpbGQgc3BlYywgdGhlIGxvY2tmaWxlIGFuZCB0aGUgd29ya3NwYWNlIGZpbGVcbiAgICovXG4gIHJlYWRvbmx5IHNoYXJlZEJ1aWxkUGF0aHM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogVGhlIHJ1bm5lciB0YWdzIHVzZWQgdG8gc2VsZWN0IHRoZSBydW5uZXIuXG4gICAqXG4gICAqIEBkZWZhdWx0IFsndWJ1bnR1LWxhdGVzdCddXG4gICAqL1xuICByZWFkb25seSBydW5uZXJUYWdzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIFRpbWVvdXQgZm9yIGEgZGVwbG95IGpvYiwgYm91bmRpbmcgYSBodW5nIEFtcGxpZnkgYnVpbGQuXG4gICAqXG4gICAqIEBkZWZhdWx0IDQ1XG4gICAqL1xuICByZWFkb25seSB0aW1lb3V0TWludXRlcz86IG51bWJlcjtcbn1cblxuLyoqIFBhdGhzIHRoYXQgaW52YWxpZGF0ZSBldmVyeSBhcHAncyBidWlsZCBvdXRwdXQuICovXG5jb25zdCBERUZBVUxUX1NIQVJFRF9CVUlMRF9QQVRIUyA9IFtcbiAgJ2FtcGxpZnkueW1sJyxcbiAgJ3BucG0tbG9jay55YW1sJyxcbiAgJ3BucG0td29ya3NwYWNlLnlhbWwnLFxuXTtcblxuLyoqXG4gKiBBZGRzIG9uZSBwYXRoLXNjb3BlZCBkZXBsb3kgd29ya2Zsb3cgcGVyIEFtcGxpZnkgSG9zdGluZyBhcHAuXG4gKlxuICogQW1wbGlmeSdzIG93biBhdXRvLWJ1aWxkIGZpcmVzIG9uIGV2ZXJ5IHB1c2ggdG8gYSB0cmFja2VkIGJyYW5jaC4gSW4gYVxuICogbW9ub3JlcG8gdGhhdCBtZWFucyBldmVyeSBmcm9udGVuZCByZWJ1aWxkcyB3aGVuZXZlciBhbnl0aGluZyBjaGFuZ2VzIOKAlCB0aGVcbiAqIG1hcmtldGluZyBzaXRlIHJlYnVpbGRpbmcgZm9yIGEgYmFja2VuZC1vbmx5IGNvbW1pdCBhbmQgdmljZSB2ZXJzYSwgb25jZSBwZXJcbiAqIHRyYWNrZWQgYnJhbmNoLiBBbXBsaWZ5IGJpbGxzIGJ1aWxkIG1pbnV0ZXMsIHNvIG1vc3Qgb2YgdGhvc2UgYXJlIHdhc3RlLlxuICpcbiAqIEFtcGxpZnkncyBuYXRpdmUgYW5zd2VyLCBgQU1QTElGWV9ESUZGX0RFUExPWWAsIGRpZmZzIGV4YWN0bHkgb25lIGRpcmVjdG9yeVxuICogKGBBTVBMSUZZX01PTk9SRVBPX0FQUF9ST09UYCwgb3ZlcnJpZGFibGUgdmlhIGBBTVBMSUZZX0RJRkZfREVQTE9ZX1JPT1RgIOKAlFxuICogc3RpbGwgYSBzaW5nbGUgcGF0aCkuIFRoYXQgaXMgZW5vdWdoIGZvciBhIHNlbGYtY29udGFpbmVkIGFwcCBidXQgbm90IGZvciBvbmVcbiAqIHRoYXQgYWxzbyBkZXBlbmRzIG9uIGEgc2hhcmVkIHdvcmtzcGFjZSBwYWNrYWdlOiBhIG9uZS1kaXJlY3RvcnkgZGlmZiB3b3VsZFxuICogc2hpcCBhIHN0YWxlIGZyb250ZW5kIHdoZW5ldmVyIHRoZSBzaGFyZWQgdHlwZXMgY2hhbmdlZC4gR2l0SHViJ3MgYHBhdGhzOmBcbiAqIGZpbHRlcnMgYWNjZXB0IG11bHRpcGxlIGdsb2JzLCBzbyBidWlsZHMgbW92ZSB0byBDSS5cbiAqXG4gKiBFYWNoIGdlbmVyYXRlZCB3b3JrZmxvdyByZXNvbHZlcyB0aGUgcHVzaGVkIGJyYW5jaCB0byBpdHMgc3RhZ2UgYW5kIGFjY291bnQsXG4gKiBjaGFpbnMgT0lEQyAtPiBkZXBsb3ltZW50IHJvbGUgLT4gYnVpbGQtdHJpZ2dlciByb2xlLCByZWFkcyB0aGUgYXBwIGlkIGZyb21cbiAqIFNTTSwgc3RhcnRzIGEgYFJFTEVBU0VgIGpvYiBhbmQgcG9sbHMgdW50aWwgaXQgcmVhY2hlcyBhIHRlcm1pbmFsIHN0YXRlIOKAlCBzb1xuICogYSBmYWlsZWQgQW1wbGlmeSBidWlsZCBmYWlscyB0aGUgd29ya2Zsb3cgaW5zdGVhZCBvZiBwYXNzaW5nIHNpbGVudGx5LlxuICpcbiAqIFRoaXMgY29tcG9uZW50IGdlbmVyYXRlcyB0aGUgQ0kgaGFsZiBvbmx5LiBUaGUgaW5mcmFzdHJ1Y3R1cmUgaGFsZiBiZWxvbmdzIGluXG4gKiB0aGUgcHJvamVjdCdzIG93biBDREsgYXBwLCB3aGljaCBtdXN0OlxuICpcbiAqICAgMS4gc2V0IGBhdXRvQnVpbGQ6IGZhbHNlYCBvbiBldmVyeSBicmFuY2ggdGhlc2Ugd29ya2Zsb3dzIGJ1aWxkLFxuICogICAyLiBwdWJsaXNoIGVhY2ggYXBwJ3MgaWQgdG8gYDxwYXJhbWV0ZXJQcmVmaXg+LzxrZXk+L2FwcC1pZGAsIGFuZFxuICogICAzLiBjcmVhdGUgYSByb2xlIG5hbWVkIGBidWlsZFRyaWdnZXJSb2xlTmFtZWAgaW4gZWFjaCBzdGFnZSBhY2NvdW50LFxuICogICAgICB0cnVzdGVkIGJ5IGBkZXBsb3ltZW50Um9sZUFybmAgYW5kIGdyYW50aW5nIGBhbXBsaWZ5OlN0YXJ0Sm9iYCArXG4gKiAgICAgIGBhbXBsaWZ5OkdldEpvYmAgb24gdGhlIHRyYWNrZWQgYnJhbmNoIEFSTnMgb25seS5cbiAqXG4gKiBVc2UgYGJ1aWxkVHJpZ2dlclJvbGVOYW1lYCBhbmQgYGFwcElkUGFyYW1ldGVyTmFtZSgpYCBmcm9tIHRoZSBwcm9qZW5yYyB0b1xuICoga2VlcCB0aG9zZSBuYW1lcyBpbiBzdGVwOyBhIG1pc21hdGNoIGZhaWxzIHRoZSB3b3JrZmxvdyBsb3VkbHkgYXQgdGhlXG4gKiBhc3N1bWUtcm9sZSBvciBwYXJhbWV0ZXItcmVhZCBzdGVwIHJhdGhlciB0aGFuIHNraXBwaW5nIGEgZGVwbG95LlxuICovXG5leHBvcnQgY2xhc3MgR2l0SHViQW1wbGlmeURlcGxveSBleHRlbmRzIENvbXBvbmVudCB7XG4gIC8qKiBUaGUgZ2VuZXJhdGVkIGRlcGxveSB3b3JrZmxvd3MsIG9uZSBwZXIgYXBwLiAqL1xuICBwdWJsaWMgcmVhZG9ubHkgd29ya2Zsb3dzOiBnaXRodWIuR2l0aHViV29ya2Zsb3dbXSA9IFtdO1xuXG4gIC8qKiBOYW1lIG9mIHRoZSBJQU0gcm9sZSBDSSBjaGFpbnMgaW50bywgaW4gZXZlcnkgc3RhZ2UgYWNjb3VudC4gKi9cbiAgcHVibGljIHJlYWRvbmx5IGJ1aWxkVHJpZ2dlclJvbGVOYW1lOiBzdHJpbmc7XG5cbiAgLyoqIFByZWZpeCBvZiB0aGUgU1NNIHBhcmFtZXRlciBwYXRoIGhvbGRpbmcgZWFjaCBhcHAncyBBbXBsaWZ5IGFwcCBpZC4gKi9cbiAgcHVibGljIHJlYWRvbmx5IHBhcmFtZXRlclByZWZpeDogc3RyaW5nO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgcmVnaW9uOiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IEdpdEh1YlByb2plY3QsIG9wdGlvbnM6IEdpdEh1YkFtcGxpZnlEZXBsb3lPcHRpb25zKSB7XG4gICAgc3VwZXIoc2NvcGUpO1xuXG4gICAgaWYgKCFzY29wZS5naXRodWIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignR2l0SHViQW1wbGlmeURlcGxveSByZXF1aXJlcyBhIHByb2plY3Qgd2l0aCBHaXRIdWIgZW5hYmxlZCcpO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucy5hcHBzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdHaXRIdWJBbXBsaWZ5RGVwbG95IHJlcXVpcmVzIGF0IGxlYXN0IG9uZSBhcHAnKTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMuc3RhZ2VzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdHaXRIdWJBbXBsaWZ5RGVwbG95IHJlcXVpcmVzIGF0IGxlYXN0IG9uZSBzdGFnZScpO1xuICAgIH1cblxuICAgIGNvbnN0IGtleXMgPSBvcHRpb25zLmFwcHMubWFwKChhcHApID0+IGFwcC5rZXkpO1xuICAgIGNvbnN0IGR1cGxpY2F0ZUtleSA9IGtleXMuZmluZCgoa2V5LCBpbmRleCkgPT4ga2V5cy5pbmRleE9mKGtleSkgIT09IGluZGV4KTtcbiAgICBpZiAoZHVwbGljYXRlS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEdpdEh1YkFtcGxpZnlEZXBsb3kgYXBwIGtleXMgbXVzdCBiZSB1bmlxdWUsIGdvdCAnJHtkdXBsaWNhdGVLZXl9JyB0d2ljZWApO1xuICAgIH1cblxuICAgIGNvbnN0IGJyYW5jaGVzID0gb3B0aW9ucy5zdGFnZXMubWFwKChzdGFnZSkgPT4gc3RhZ2UuYnJhbmNoKTtcbiAgICBjb25zdCBkdXBsaWNhdGVCcmFuY2ggPSBicmFuY2hlcy5maW5kKChicmFuY2gsIGluZGV4KSA9PiBicmFuY2hlcy5pbmRleE9mKGJyYW5jaCkgIT09IGluZGV4KTtcbiAgICBpZiAoZHVwbGljYXRlQnJhbmNoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEdpdEh1YkFtcGxpZnlEZXBsb3kgc3RhZ2UgYnJhbmNoZXMgbXVzdCBiZSB1bmlxdWUsIGdvdCAnJHtkdXBsaWNhdGVCcmFuY2h9JyB0d2ljZWApO1xuICAgIH1cblxuICAgIHRoaXMuYnVpbGRUcmlnZ2VyUm9sZU5hbWUgPSBvcHRpb25zLmJ1aWxkVHJpZ2dlclJvbGVOYW1lID8/IGAke3Njb3BlLm5hbWV9LWFtcGxpZnktYnVpbGQtdHJpZ2dlcmA7XG4gICAgdGhpcy5wYXJhbWV0ZXJQcmVmaXggPSBvcHRpb25zLnBhcmFtZXRlclByZWZpeCA/PyBgLyR7c2NvcGUubmFtZX0vYW1wbGlmeWA7XG4gICAgdGhpcy5yZWdpb24gPSBvcHRpb25zLnJlZ2lvbiA/PyAnZXUtY2VudHJhbC0xJztcblxuICAgIGNvbnN0IHNoYXJlZEJ1aWxkUGF0aHMgPSBvcHRpb25zLnNoYXJlZEJ1aWxkUGF0aHMgPz8gREVGQVVMVF9TSEFSRURfQlVJTERfUEFUSFM7XG4gICAgY29uc3QgcnVubmVyVGFncyA9IG9wdGlvbnMucnVubmVyVGFncyA/PyBbJ3VidW50dS1sYXRlc3QnXTtcbiAgICBjb25zdCB0aW1lb3V0TWludXRlcyA9IG9wdGlvbnMudGltZW91dE1pbnV0ZXMgPz8gNDU7XG5cbiAgICBmb3IgKGNvbnN0IGFwcCBvZiBvcHRpb25zLmFwcHMpIHtcbiAgICAgIGNvbnN0IGxhYmVsID0gYXBwLmxhYmVsID8/IGFwcC5rZXk7XG4gICAgICBjb25zdCB3b3JrZmxvd05hbWUgPSBhcHAud29ya2Zsb3dOYW1lID8/IGAke2FwcC5rZXl9LWRlcGxveWA7XG5cbiAgICAgIGNvbnN0IHdvcmtmbG93ID0gbmV3IGdpdGh1Yi5HaXRodWJXb3JrZmxvdyhzY29wZS5naXRodWIsIHdvcmtmbG93TmFtZSk7XG4gICAgICB3b3JrZmxvdy5vbih7XG4gICAgICAgIHB1c2g6IHtcbiAgICAgICAgICBicmFuY2hlczogb3B0aW9ucy5zdGFnZXMubWFwKChzdGFnZSkgPT4gc3RhZ2UuYnJhbmNoKSxcbiAgICAgICAgICBwYXRoczogW1xuICAgICAgICAgICAgYCR7YXBwLmFwcFJvb3R9LyoqYCxcbiAgICAgICAgICAgIC4uLihhcHAuZGVwZW5kZW5jeVBhdGhzID8/IFtdKSxcbiAgICAgICAgICAgIC4uLnNoYXJlZEJ1aWxkUGF0aHMsXG4gICAgICAgICAgICAvLyBDaGFuZ2luZyB0aGUgd29ya2Zsb3cgaXRzZWxmIHNob3VsZCBwcm92ZSBpdCBzdGlsbCB3b3Jrcy5cbiAgICAgICAgICAgIGAuZ2l0aHViL3dvcmtmbG93cy8ke3dvcmtmbG93TmFtZX0ueW1sYCxcbiAgICAgICAgICBdLFxuICAgICAgICB9LFxuICAgICAgICAvLyBNYW51YWwgcmVkZXBsb3ksIGUuZy4gYWZ0ZXIgYSBidWlsZC1vbmx5IGZhaWx1cmUuXG4gICAgICAgIHdvcmtmbG93RGlzcGF0Y2g6IHt9LFxuICAgICAgfSk7XG5cbiAgICAgIHdvcmtmbG93LmFkZEpvYignZGVwbG95Jywge1xuICAgICAgICBuYW1lOiBgQnVpbGQgYW5kIGRlcGxveSB0aGUgJHtsYWJlbH0gb24gQW1wbGlmeWAsXG4gICAgICAgIHJ1bnNPbjogcnVubmVyVGFncyxcbiAgICAgICAgcGVybWlzc2lvbnM6IHtcbiAgICAgICAgICBjb250ZW50czogZ2l0aHViLndvcmtmbG93cy5Kb2JQZXJtaXNzaW9uLlJFQUQsXG4gICAgICAgICAgaWRUb2tlbjogZ2l0aHViLndvcmtmbG93cy5Kb2JQZXJtaXNzaW9uLldSSVRFLFxuICAgICAgICB9LFxuICAgICAgICBlbnZpcm9ubWVudDogdGhpcy5lbnZpcm9ubWVudEV4cHJlc3Npb24ob3B0aW9ucy5zdGFnZXMpLFxuICAgICAgICBjb25jdXJyZW5jeToge1xuICAgICAgICAgICdncm91cCc6IGAke3dvcmtmbG93TmFtZX0tXFwke3sgZ2l0aHViLnJlZl9uYW1lIH19YCxcbiAgICAgICAgICAvLyBDYW5jZWxsaW5nIHRoZSB3b3JrZmxvdyB3b3VsZCBub3QgY2FuY2VsIHRoZSBBbXBsaWZ5IGpvYiBpdCBzdGFydGVkLFxuICAgICAgICAgIC8vIHNvIGxldCBydW5zIHF1ZXVlIGluc3RlYWQgb2Ygb3JwaGFuaW5nIGJ1aWxkcy5cbiAgICAgICAgICAnY2FuY2VsLWluLXByb2dyZXNzJzogZmFsc2UsXG4gICAgICAgIH0sXG4gICAgICAgIHRpbWVvdXRNaW51dGVzLFxuICAgICAgICBzdGVwczogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIG5hbWU6ICdSZXNvbHZlIHN0YWdlJyxcbiAgICAgICAgICAgIGlkOiAnc3RhZ2UnLFxuICAgICAgICAgICAgcnVuOiB0aGlzLnJlc29sdmVTdGFnZVNjcmlwdChvcHRpb25zLnN0YWdlcyksXG4gICAgICAgICAgfSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBuYW1lOiAnQVdTIGNyZWRlbnRpYWxzIOKAlCBkZXBsb3ltZW50IHJvbGUnLFxuICAgICAgICAgICAgaWQ6ICdhd3NfY3JlZGVudGlhbHNfZGVwbG95bWVudF9yb2xlJyxcbiAgICAgICAgICAgIHVzZXM6ICdhd3MtYWN0aW9ucy9jb25maWd1cmUtYXdzLWNyZWRlbnRpYWxzQHY1JyxcbiAgICAgICAgICAgIHdpdGg6IHtcbiAgICAgICAgICAgICAgJ3JvbGUtdG8tYXNzdW1lJzogb3B0aW9ucy5kZXBsb3ltZW50Um9sZUFybixcbiAgICAgICAgICAgICAgJ3JvbGUtc2Vzc2lvbi1uYW1lJzogJ0dpdEh1YkFjdGlvbicsXG4gICAgICAgICAgICAgICdhd3MtcmVnaW9uJzogdGhpcy5yZWdpb24sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgbmFtZTogJ0FXUyBjcmVkZW50aWFscyDigJQgQW1wbGlmeSBidWlsZCB0cmlnZ2VyJyxcbiAgICAgICAgICAgIGlkOiAnYXdzX2NyZWRlbnRpYWxzX2FtcGxpZnlfYnVpbGRfdHJpZ2dlcicsXG4gICAgICAgICAgICB1c2VzOiAnYXdzLWFjdGlvbnMvY29uZmlndXJlLWF3cy1jcmVkZW50aWFsc0B2NScsXG4gICAgICAgICAgICB3aXRoOiB7XG4gICAgICAgICAgICAgICdyb2xlLXRvLWFzc3VtZSc6ICcke3sgc3RlcHMuc3RhZ2Uub3V0cHV0cy5yb2xlX2FybiB9fScsXG4gICAgICAgICAgICAgICdyb2xlLXNlc3Npb24tbmFtZSc6ICdBbXBsaWZ5QnVpbGRUcmlnZ2VyJyxcbiAgICAgICAgICAgICAgJ2F3cy1yZWdpb24nOiB0aGlzLnJlZ2lvbixcbiAgICAgICAgICAgICAgLy8gQ2hhaW4gZnJvbSB0aGUgZGVwbG95bWVudCByb2xlIHJhdGhlciB0aGFuIHJlLXVzaW5nIHRoZSBPSURDXG4gICAgICAgICAgICAgIC8vIHRva2VuLCBzbyBubyBpZGVudGl0eSBwcm92aWRlciBpcyBuZWVkZWQgaW4gdGhlIHN0YWdlIGFjY291bnQuXG4gICAgICAgICAgICAgICdyb2xlLWNoYWluaW5nJzogdHJ1ZSxcbiAgICAgICAgICAgICAgLy8gVGhlIGFjdGlvbiB0YWdzIHNlc3Npb25zIGJ5IGRlZmF1bHQsIHdoaWNoIHR1cm5zIHRoZSBjaGFpbmVkXG4gICAgICAgICAgICAgIC8vIGNhbGwgaW50byBBc3N1bWVSb2xlICsgVGFnU2Vzc2lvbi4gVGhlIHRydXN0IHBvbGljeSBncmFudHNcbiAgICAgICAgICAgICAgLy8gQXNzdW1lUm9sZSBvbmx5LCBzbyB0YWdnaW5nIGZhaWxzIHRoZSBzdGVwOyB0aGUgc2Vzc2lvbiBpc1xuICAgICAgICAgICAgICAvLyBhbHJlYWR5IHRhZ2dlZCBieSB0aGUgZmlyc3QgYXNzdW1lIGFueXdheS5cbiAgICAgICAgICAgICAgJ3JvbGUtc2tpcC1zZXNzaW9uLXRhZ2dpbmcnOiB0cnVlLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIG5hbWU6IGBTdGFydCAke2xhYmVsfSBidWlsZGAsXG4gICAgICAgICAgICBpZDogJ3N0YXJ0JyxcbiAgICAgICAgICAgIHJ1bjogdGhpcy5zdGFydEJ1aWxkU2NyaXB0KGFwcCwgbGFiZWwpLFxuICAgICAgICAgIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgbmFtZTogJ1dhaXQgZm9yIGJ1aWxkIHRvIGZpbmlzaCcsXG4gICAgICAgICAgICBpZDogJ3dhaXRfZm9yX2J1aWxkX3RvX2ZpbmlzaCcsXG4gICAgICAgICAgICBydW46IHRoaXMud2FpdEZvckJ1aWxkU2NyaXB0KGxhYmVsKSxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfSk7XG5cbiAgICAgIHRoaXMud29ya2Zsb3dzLnB1c2god29ya2Zsb3cpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgU1NNIHBhcmFtZXRlciBwYXRoIGhvbGRpbmcgYW4gYXBwJ3MgQW1wbGlmeSBhcHAgaWQuIFRoZSBDREsgc2lkZSBtdXN0XG4gICAqIHB1Ymxpc2ggdGhlIGlkIHVuZGVyIGV4YWN0bHkgdGhpcyBuYW1lLlxuICAgKi9cbiAgcHVibGljIGFwcElkUGFyYW1ldGVyTmFtZShrZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGAke3RoaXMucGFyYW1ldGVyUHJlZml4fS8ke2tleX0vYXBwLWlkYDtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgam9iLWxldmVsIGBlbnZpcm9ubWVudDpgIGV4cHJlc3Npb24gbWFwcGluZyBicmFuY2ggdG8gc3RhZ2UsIHNvIGVhY2hcbiAgICogc3RhZ2Uga2VlcHMgd2hhdGV2ZXIgR2l0SHViIGVudmlyb25tZW50IHByb3RlY3Rpb24gcnVsZXMgaXQgaGFzLiBUaGUgZmlyc3RcbiAgICogc3RhZ2UgaXMgdGhlIGZhbGxiYWNrOyBldmVyeSBsYXRlciBzdGFnZSBnZXRzIGFuIGV4cGxpY2l0IGJyYW5jaCB0ZXN0LlxuICAgKi9cbiAgcHJpdmF0ZSBlbnZpcm9ubWVudEV4cHJlc3Npb24oc3RhZ2VzOiBBbXBsaWZ5RGVwbG95U3RhZ2VbXSk6IHN0cmluZyB7XG4gICAgY29uc3QgW2ZhbGxiYWNrLCAuLi5yZXN0XSA9IHN0YWdlcztcbiAgICBjb25zdCB0ZXN0cyA9IHJlc3QubWFwKChzKSA9PiBgZ2l0aHViLnJlZl9uYW1lID09ICcke3MuYnJhbmNofScgJiYgJyR7cy5zdGFnZU5hbWV9JyB8fCBgKS5qb2luKCcnKTtcbiAgICByZXR1cm4gYFxcJHt7ICR7dGVzdHN9JyR7ZmFsbGJhY2suc3RhZ2VOYW1lfScgfX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIEJhc2ggbWFwcGluZyB0aGUgcHVzaGVkIGJyYW5jaCB0byBpdHMgc3RhZ2UgYW5kIGJ1aWxkLXRyaWdnZXIgcm9sZSBBUk4sIHNvXG4gICAqIGFjY291bnQgaWRzIGxpdmUgb25seSBpbiB0aGUgcHJvamVucmMuIEEgYnJhbmNoIHRoYXQgaXMgbm90IGEgZGVwbG95IGJyYW5jaFxuICAgKiBpcyBhbiBlcnJvciByYXRoZXIgdGhhbiBhIHNpbGVudCBuby1vcC5cbiAgICovXG4gIHByaXZhdGUgcmVzb2x2ZVN0YWdlU2NyaXB0KHN0YWdlczogQW1wbGlmeURlcGxveVN0YWdlW10pOiBzdHJpbmcge1xuICAgIGNvbnN0IGNhc2VzID0gc3RhZ2VzLm1hcCgocykgPT4gYCAgJHtzLmJyYW5jaH0pIHN0YWdlPScke3Muc3RhZ2VOYW1lfSc7IGFjY291bnQ9JyR7cy5hY2NvdW50fScgOztgKTtcbiAgICByZXR1cm4gW1xuICAgICAgJ3NldCAtZXVvIHBpcGVmYWlsJyxcbiAgICAgICdjYXNlIFwiJEdJVEhVQl9SRUZfTkFNRVwiIGluJyxcbiAgICAgIC4uLmNhc2VzLFxuICAgICAgJyAgKiknLFxuICAgICAgJyAgICBlY2hvIFwiOjplcnJvcjo6JEdJVEhVQl9SRUZfTkFNRSBpcyBub3QgYSBkZXBsb3kgYnJhbmNoXCInLFxuICAgICAgJyAgICBleGl0IDEnLFxuICAgICAgJyAgICA7OycsXG4gICAgICAnZXNhYycsXG4gICAgICBgcm9sZT1cImFybjphd3M6aWFtOjokYWNjb3VudDpyb2xlLyR7dGhpcy5idWlsZFRyaWdnZXJSb2xlTmFtZX1cImAsXG4gICAgICAnZWNobyBcInN0YWdlPSRzdGFnZVwiID4+IFwiJEdJVEhVQl9PVVRQVVRcIicsXG4gICAgICAnZWNobyBcInJvbGVfYXJuPSRyb2xlXCIgPj4gXCIkR0lUSFVCX09VVFBVVFwiJyxcbiAgICAgICdlY2hvIFwiRGVwbG95aW5nICRHSVRIVUJfUkVGX05BTUUgdG8gc3RhZ2UgJHN0YWdlICgkYWNjb3VudClcIiA+PiBcIiRHSVRIVUJfU1RFUF9TVU1NQVJZXCInLFxuICAgIF0uam9pbignXFxuJyk7XG4gIH1cblxuICAvKiogUmVhZHMgdGhlIGFwcCBpZCBmcm9tIFNTTSBhbmQgc3RhcnRzIGEgUkVMRUFTRSBidWlsZC4gKi9cbiAgcHJpdmF0ZSBzdGFydEJ1aWxkU2NyaXB0KGFwcDogQW1wbGlmeURlcGxveUFwcCwgbGFiZWw6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIFtcbiAgICAgICdzZXQgLWV1byBwaXBlZmFpbCcsXG4gICAgICBgYXBwX2lkPVwiJChhd3Mgc3NtIGdldC1wYXJhbWV0ZXIgLS1uYW1lICcke3RoaXMuYXBwSWRQYXJhbWV0ZXJOYW1lKGFwcC5rZXkpfScgLS1xdWVyeSBQYXJhbWV0ZXIuVmFsdWUgLS1vdXRwdXQgdGV4dClcImAsXG4gICAgICAnIyBSRUxFQVNFIGJ1aWxkcyB0aGUgY3VycmVudCB0aXAgb2YgdGhlIGJyYW5jaC4gVGhhdCBpcyBub3JtYWxseSAkR0lUSFVCX1NIQTsnLFxuICAgICAgJyMgaWYgdHdvIHB1c2hlcyByYWNlLCB0aGUgdGlwIHdpbnMgYW5kIHRoZSBlYXJsaWVyIHJ1biBpcyByZWR1bmRhbnQgcmF0aGVyJyxcbiAgICAgICcjIHRoYW4gd3JvbmcuIFRoZSBqb2IgY29uY3VycmVuY3kgZ3JvdXAga2VlcHMgdGhhdCByYXJlLicsXG4gICAgICAnam9iX2lkPVwiJChhd3MgYW1wbGlmeSBzdGFydC1qb2IgXFxcXCcsXG4gICAgICAnICAtLWFwcC1pZCBcIiRhcHBfaWRcIiBcXFxcJyxcbiAgICAgICcgIC0tYnJhbmNoLW5hbWUgXCIkR0lUSFVCX1JFRl9OQU1FXCIgXFxcXCcsXG4gICAgICAnICAtLWpvYi10eXBlIFJFTEVBU0UgXFxcXCcsXG4gICAgICAnICAtLWpvYi1yZWFzb24gXCJHaXRIdWIgQWN0aW9ucyAkR0lUSFVCX1dPUktGTE9XIHJ1biAkR0lUSFVCX1JVTl9JRCBmb3IgJEdJVEhVQl9TSEFcIiBcXFxcJyxcbiAgICAgICcgIC0tcXVlcnkgam9iU3VtbWFyeS5qb2JJZCAtLW91dHB1dCB0ZXh0KVwiJyxcbiAgICAgICdlY2hvIFwiYXBwX2lkPSRhcHBfaWRcIiA+PiBcIiRHSVRIVUJfT1VUUFVUXCInLFxuICAgICAgJ2VjaG8gXCJqb2JfaWQ9JGpvYl9pZFwiID4+IFwiJEdJVEhVQl9PVVRQVVRcIicsXG4gICAgICBgZWNobyBcIlN0YXJ0ZWQgJHtsYWJlbH0gQW1wbGlmeSBqb2IgXFwkam9iX2lkIG9uIGFwcCBcXCRhcHBfaWRcIiA+PiBcIlxcJEdJVEhVQl9TVEVQX1NVTU1BUllcImAsXG4gICAgXS5qb2luKCdcXG4nKTtcbiAgfVxuXG4gIC8qKiBQb2xscyB0aGUgam9iIHVudGlsIGl0IHJlYWNoZXMgYSB0ZXJtaW5hbCBzdGF0ZSwgZmFpbGluZyBvbiBhIGJhZCBvbmUuICovXG4gIHByaXZhdGUgd2FpdEZvckJ1aWxkU2NyaXB0KGxhYmVsOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBbXG4gICAgICAnc2V0IC1ldW8gcGlwZWZhaWwnLFxuICAgICAgJ3doaWxlIHRydWU7IGRvJyxcbiAgICAgICcgIHN0YXR1cz1cIiQoYXdzIGFtcGxpZnkgZ2V0LWpvYiBcXFxcJyxcbiAgICAgICcgICAgLS1hcHAtaWQgXCIke3sgc3RlcHMuc3RhcnQub3V0cHV0cy5hcHBfaWQgfX1cIiBcXFxcJyxcbiAgICAgICcgICAgLS1icmFuY2gtbmFtZSBcIiRHSVRIVUJfUkVGX05BTUVcIiBcXFxcJyxcbiAgICAgICcgICAgLS1qb2ItaWQgXCIke3sgc3RlcHMuc3RhcnQub3V0cHV0cy5qb2JfaWQgfX1cIiBcXFxcJyxcbiAgICAgICcgICAgLS1xdWVyeSBqb2Iuc3VtbWFyeS5zdGF0dXMgLS1vdXRwdXQgdGV4dClcIicsXG4gICAgICAnICBjYXNlIFwiJHN0YXR1c1wiIGluJyxcbiAgICAgICcgICAgU1VDQ0VFRCknLFxuICAgICAgYCAgICAgIGVjaG8gXCIke2xhYmVsfSBidWlsZCBzdWNjZWVkZWRcIiA+PiBcIlxcJEdJVEhVQl9TVEVQX1NVTU1BUllcImAsXG4gICAgICAnICAgICAgZXhpdCAwJyxcbiAgICAgICcgICAgICA7OycsXG4gICAgICAnICAgIEZBSUxFRHxDQU5DRUxMRUQpJyxcbiAgICAgIGAgICAgICBlY2hvIFwiOjplcnJvcjo6JHtsYWJlbH0gQW1wbGlmeSBqb2IgXFwke3sgc3RlcHMuc3RhcnQub3V0cHV0cy5qb2JfaWQgfX0gZW5kZWQgYXMgXFwkc3RhdHVzXCJgLFxuICAgICAgJyAgICAgIGV4aXQgMScsXG4gICAgICAnICAgICAgOzsnLFxuICAgICAgJyAgZXNhYycsXG4gICAgICAnICBlY2hvIFwic3RhdHVzOiAkc3RhdHVzXCInLFxuICAgICAgJyAgc2xlZXAgMTUnLFxuICAgICAgJ2RvbmUnLFxuICAgIF0uam9pbignXFxuJyk7XG4gIH1cbn1cbiJdfQ==
@@ -1 +1,2 @@
1
+ export * from './amplify-deploy';
1
2
  export * from './production-release';
@@ -14,5 +14,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./amplify-deploy"), exports);
17
18
  __exportStar(require("./production-release"), exports);
18
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tcG9uZW50cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsdURBQXFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSAnLi9wcm9kdWN0aW9uLXJlbGVhc2UnO1xuIl19
19
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tcG9uZW50cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsbURBQWlDO0FBQ2pDLHVEQUFxQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vYW1wbGlmeS1kZXBsb3knO1xuZXhwb3J0ICogZnJvbSAnLi9wcm9kdWN0aW9uLXJlbGVhc2UnO1xuIl19
@@ -15,7 +15,7 @@ const projen_1 = require("projen");
15
15
  * dispatch time.
16
16
  */
17
17
  class GitHubProductionRelease extends projen_1.Component {
18
- static [JSII_RTTI_SYMBOL_1] = { fqn: "@taimos/projen.GitHubProductionRelease", version: "0.1.78" };
18
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "@taimos/projen.GitHubProductionRelease", version: "0.1.80" };
19
19
  /**
20
20
  * Resolves the branch that is promoted — the project's default release branch.
21
21
  *
@@ -9,7 +9,7 @@ const projen_1 = require("projen");
9
9
  * @pjid taimos-cdk-app
10
10
  */
11
11
  class TaimosCdkApp extends projen_1.awscdk.AwsCdkTypeScriptApp {
12
- static [JSII_RTTI_SYMBOL_1] = { fqn: "@taimos/projen.TaimosCdkApp", version: "0.1.78" };
12
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "@taimos/projen.TaimosCdkApp", version: "0.1.80" };
13
13
  constructor(options) {
14
14
  super({
15
15
  authorEmail: 'info@taimos.de',
@@ -9,7 +9,7 @@ const projen_1 = require("projen");
9
9
  * @pjid taimos-awscdk-construct
10
10
  */
11
11
  class TaimosCdkConstructLibrary extends projen_1.awscdk.AwsCdkConstructLibrary {
12
- static [JSII_RTTI_SYMBOL_1] = { fqn: "@taimos/projen.TaimosCdkConstructLibrary", version: "0.1.78" };
12
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "@taimos/projen.TaimosCdkConstructLibrary", version: "0.1.80" };
13
13
  constructor(options) {
14
14
  super({
15
15
  authorOrganization: true,
@@ -1,6 +1,6 @@
1
1
  import { github, typescript, YamlFile } from 'projen';
2
2
  import { GitHubAssignApprover } from 'projen-pipelines';
3
- import { GitHubProductionRelease, GitHubProductionReleaseOptions } from '../components';
3
+ import { GitHubAmplifyDeploy, GitHubAmplifyDeployOptions, GitHubProductionRelease, GitHubProductionReleaseOptions } from '../components';
4
4
  /**
5
5
  * The frontend framework an Amplify Hosting application is built with.
6
6
  *
@@ -211,6 +211,18 @@ export interface MonorepoProjectOptions extends typescript.TypeScriptProjectOpti
211
211
  * @default - promote `main` to a `production` branch
212
212
  */
213
213
  readonly productionReleaseOptions?: GitHubProductionReleaseOptions;
214
+ /**
215
+ * Drive Amplify Hosting builds from GitHub Actions instead of Amplify's own
216
+ * auto-build, so an app only rebuilds when the packages it is built from
217
+ * actually changed (see `GitHubAmplifyDeploy`).
218
+ *
219
+ * Setting this generates one deploy workflow per listed app. The project's
220
+ * CDK app must disable `autoBuild` on the tracked branches and provide the
221
+ * app-id parameters and build-trigger role the workflows expect.
222
+ *
223
+ * @default - Amplify's own auto-build is left in place
224
+ */
225
+ readonly amplifyDeployOptions?: GitHubAmplifyDeployOptions;
214
226
  }
215
227
  /**
216
228
  * Private PNPM-workspace monorepo root, following Taimos ADR-0002.
@@ -236,6 +248,8 @@ export declare class MonorepoProject extends typescript.TypeScriptProject {
236
248
  readonly assignApprover?: GitHubAssignApprover;
237
249
  /** The production release workflow, if enabled. */
238
250
  readonly productionRelease?: GitHubProductionRelease;
251
+ /** The Amplify deploy workflows, when `amplifyDeployOptions` is set. */
252
+ readonly amplifyDeploy?: GitHubAmplifyDeploy;
239
253
  /** The default release branch (promoted by the production release workflow). */
240
254
  readonly defaultReleaseBranch: string;
241
255
  constructor(options: MonorepoProjectOptions);