@fjall/components-infrastructure 0.79.1 → 0.80.4

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.
Files changed (97) hide show
  1. package/dist/lib/app.d.ts +39 -2
  2. package/dist/lib/app.js +85 -4
  3. package/dist/lib/aspects/resourceInventory.d.ts +41 -0
  4. package/dist/lib/aspects/resourceInventory.js +56 -0
  5. package/dist/lib/config/audit.d.ts +18 -0
  6. package/dist/lib/config/audit.js +22 -0
  7. package/dist/lib/config/aws/accountId.js +3 -3
  8. package/dist/lib/config/aws/ecrDefaultImage.js +7 -7
  9. package/dist/lib/config/aws/identityCenter.js +7 -8
  10. package/dist/lib/config/aws/identityCenterGroupMembership.js +6 -6
  11. package/dist/lib/config/aws/ipam.js +3 -3
  12. package/dist/lib/config/aws/ipamPoolId.js +4 -4
  13. package/dist/lib/config/aws/organisation.js +2 -3
  14. package/dist/lib/config/aws/organisationId.js +4 -4
  15. package/dist/lib/patterns/aws/auditRole.d.ts +44 -0
  16. package/dist/lib/patterns/aws/auditRole.js +58 -0
  17. package/dist/lib/patterns/aws/buildkite.js +12 -12
  18. package/dist/lib/patterns/aws/cdn.d.ts +133 -0
  19. package/dist/lib/patterns/aws/cdn.js +216 -0
  20. package/dist/lib/patterns/aws/compute.d.ts +32 -13
  21. package/dist/lib/patterns/aws/compute.js +24 -14
  22. package/dist/lib/patterns/aws/database.d.ts +8 -1
  23. package/dist/lib/patterns/aws/database.js +13 -5
  24. package/dist/lib/patterns/aws/dynamodb.d.ts +66 -0
  25. package/dist/lib/patterns/aws/dynamodb.js +106 -0
  26. package/dist/lib/patterns/aws/hostedZone.js +7 -2
  27. package/dist/lib/patterns/aws/index.d.ts +1 -0
  28. package/dist/lib/patterns/aws/index.js +2 -1
  29. package/dist/lib/patterns/aws/loadBalancer.d.ts +163 -0
  30. package/dist/lib/patterns/aws/loadBalancer.js +278 -0
  31. package/dist/lib/patterns/aws/managedAccount.js +3 -4
  32. package/dist/lib/patterns/aws/queue.d.ts +61 -0
  33. package/dist/lib/patterns/aws/queue.js +103 -0
  34. package/dist/lib/patterns/aws/storage.js +3 -2
  35. package/dist/lib/patterns/aws/subdomainHostedZone.js +2 -2
  36. package/dist/lib/resources/aws/audit/auditRole.d.ts +32 -0
  37. package/dist/lib/resources/aws/audit/auditRole.js +44 -0
  38. package/dist/lib/resources/aws/backup/backupPlan.js +3 -4
  39. package/dist/lib/resources/aws/backup/backupVault.js +3 -4
  40. package/dist/lib/resources/aws/base/awsStack.js +1 -2
  41. package/dist/lib/resources/aws/cdn/cloudFront.d.ts +65 -0
  42. package/dist/lib/resources/aws/cdn/cloudFront.js +135 -0
  43. package/dist/lib/resources/aws/cdn/index.d.ts +1 -0
  44. package/dist/lib/resources/aws/cdn/index.js +18 -0
  45. package/dist/lib/resources/aws/compute/capacityProviderDrainWaiter.d.ts +20 -0
  46. package/dist/lib/resources/aws/compute/capacityProviderDrainWaiter.js +180 -0
  47. package/dist/lib/resources/aws/compute/ecs.d.ts +65 -11
  48. package/dist/lib/resources/aws/compute/ecs.js +293 -124
  49. package/dist/lib/resources/aws/compute/ecsFreeTier.d.ts +1 -2
  50. package/dist/lib/resources/aws/compute/ecsFreeTier.js +1 -4
  51. package/dist/lib/resources/aws/compute/ecsSpot.d.ts +1 -2
  52. package/dist/lib/resources/aws/compute/ecsSpot.js +1 -4
  53. package/dist/lib/resources/aws/compute/lambda.d.ts +10 -1
  54. package/dist/lib/resources/aws/compute/lambda.js +71 -4
  55. package/dist/lib/resources/aws/database/database.js +1 -1
  56. package/dist/lib/resources/aws/database/dynamodb.d.ts +70 -0
  57. package/dist/lib/resources/aws/database/dynamodb.js +170 -0
  58. package/dist/lib/resources/aws/database/rdsAurora.d.ts +2 -0
  59. package/dist/lib/resources/aws/database/rdsAurora.js +9 -6
  60. package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +2 -0
  61. package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +9 -8
  62. package/dist/lib/resources/aws/database/rdsDeletionWaiter.d.ts +33 -0
  63. package/dist/lib/resources/aws/database/rdsDeletionWaiter.js +74 -0
  64. package/dist/lib/resources/aws/database/rdsInstance.d.ts +2 -0
  65. package/dist/lib/resources/aws/database/rdsInstance.js +7 -4
  66. package/dist/lib/resources/aws/iam/identityCenter/assignment.js +2 -2
  67. package/dist/lib/resources/aws/iam/identityCenter/attachManagedPolicy.js +1 -1
  68. package/dist/lib/resources/aws/iam/identityCenter/group.js +1 -1
  69. package/dist/lib/resources/aws/iam/identityCenter/permissionSet.js +1 -1
  70. package/dist/lib/resources/aws/logging/cloudTrail.js +1 -1
  71. package/dist/lib/resources/aws/messaging/index.d.ts +1 -0
  72. package/dist/lib/resources/aws/messaging/index.js +18 -0
  73. package/dist/lib/resources/aws/messaging/sqs.d.ts +65 -0
  74. package/dist/lib/resources/aws/messaging/sqs.js +195 -0
  75. package/dist/lib/resources/aws/monitoring/monitoringRole.js +2 -3
  76. package/dist/lib/resources/aws/networking/ipamPool.js +1 -1
  77. package/dist/lib/resources/aws/networking/vpc.d.ts +1 -0
  78. package/dist/lib/resources/aws/networking/vpc.js +7 -3
  79. package/dist/lib/resources/aws/networking/vpcEndpoint.d.ts +20 -0
  80. package/dist/lib/resources/aws/networking/vpcEndpoint.js +59 -0
  81. package/dist/lib/resources/aws/networking/vpcEndpoints.d.ts +71 -0
  82. package/dist/lib/resources/aws/networking/vpcEndpoints.js +125 -0
  83. package/dist/lib/resources/aws/secrets/secret.js +1 -1
  84. package/dist/lib/resources/aws/storage/ecr.d.ts +1 -2
  85. package/dist/lib/resources/aws/storage/ecr.js +2 -2
  86. package/dist/lib/resources/aws/utilities/cfnOutput.test.d.ts +1 -0
  87. package/dist/lib/resources/aws/utilities/cfnOutput.test.js +102 -0
  88. package/dist/lib/resources/aws/utilities/codeBuild.d.ts +1 -2
  89. package/dist/lib/resources/aws/utilities/codeBuild.js +1 -1
  90. package/dist/lib/resources/aws/utilities/customResource.d.ts +2 -1
  91. package/dist/lib/resources/aws/utilities/customResource.js +1 -1
  92. package/dist/lib/utils/getStackOutput.js +2 -2
  93. package/dist/lib/utils/sanitizeCfnKey.d.ts +5 -0
  94. package/dist/lib/utils/sanitizeCfnKey.js +11 -0
  95. package/dist/lib/utils/tagResource.d.ts +24 -0
  96. package/dist/lib/utils/tagResource.js +30 -0
  97. package/package.json +6 -5
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CdnFactory = exports.Cdn = void 0;
4
+ const cdn_1 = require("../../resources/aws/cdn");
5
+ const storage_1 = require("./storage");
6
+ const compute_1 = require("./compute");
7
+ /**
8
+ * Validates CDN props and logs warnings for misconfigured options.
9
+ */
10
+ function validateCdnProps(props) {
11
+ // Validate certificate region warning
12
+ if (props.certificate && props.domainNames && props.domainNames.length > 0) {
13
+ console.info("[Fjall] Note: CloudFront certificates must be in us-east-1 region. " +
14
+ "Ensure your certificate was created in us-east-1.");
15
+ }
16
+ // Validate domain names require certificate
17
+ if (props.domainNames && props.domainNames.length > 0 && !props.certificate) {
18
+ console.warn("[Fjall] Warning: 'domainNames' provided but no 'certificate' specified. " +
19
+ "Custom domain names require an ACM certificate in us-east-1.");
20
+ }
21
+ // Validate ALB origin
22
+ if (props.originType === "alb") {
23
+ const albProps = props;
24
+ if (albProps.loadBalancer instanceof compute_1.Compute) {
25
+ const lb = albProps.loadBalancer.getLoadBalancer();
26
+ if (!lb) {
27
+ throw new Error("Compute resource does not have a load balancer. " +
28
+ "Ensure ECS compute has loadBalancer enabled for CDN origin.");
29
+ }
30
+ }
31
+ }
32
+ // Validate smart origin
33
+ if (props.originType === "auto") {
34
+ const smartProps = props;
35
+ if (smartProps.origin instanceof compute_1.Compute) {
36
+ const computeType = smartProps.origin.getComputeType();
37
+ if (computeType === "ec2") {
38
+ throw new Error("EC2 compute type is not supported for CDN origin. " +
39
+ "Use ECS with load balancer or Lambda with function URL.");
40
+ }
41
+ if (computeType === "ecs" && !smartProps.origin.getLoadBalancer()) {
42
+ throw new Error("ECS compute must have a load balancer for CDN origin. " +
43
+ "Enable loadBalancer in your ECS compute configuration.");
44
+ }
45
+ if (computeType === "lambda" && !smartProps.origin.getFunctionUrl()) {
46
+ throw new Error("Lambda compute must have a function URL for CDN origin. " +
47
+ "Enable functionUrl in your Lambda compute configuration.");
48
+ }
49
+ }
50
+ }
51
+ }
52
+ /**
53
+ * CDN wrapper class that extends CloudFrontDistribution with Fjall patterns.
54
+ */
55
+ class Cdn extends cdn_1.CloudFrontDistribution {
56
+ constructor(scope, id, props) {
57
+ const resolvedProps = Cdn.resolveProps(props);
58
+ super(scope, id, resolvedProps);
59
+ }
60
+ /**
61
+ * Resolve ICdnProps to CloudFrontDistributionProps.
62
+ */
63
+ static resolveProps(props) {
64
+ const defaultOrigin = Cdn.resolveDefaultOrigin(props);
65
+ return {
66
+ defaultOrigin,
67
+ defaultCachePolicy: props.cachePolicy,
68
+ behaviours: props.behaviours,
69
+ domainNames: props.domainNames,
70
+ certificate: props.certificate,
71
+ comment: props.comment,
72
+ enableLogging: props.enableLogging,
73
+ logBucket: props.logBucket
74
+ };
75
+ }
76
+ /**
77
+ * Resolve the default origin from ICdnProps.
78
+ */
79
+ static resolveDefaultOrigin(props) {
80
+ switch (props.originType) {
81
+ case "s3": {
82
+ const s3Props = props;
83
+ const bucket = s3Props.bucket instanceof storage_1.S3Storage
84
+ ? s3Props.bucket.getBucket()
85
+ : s3Props.bucket;
86
+ return {
87
+ type: "s3",
88
+ bucket,
89
+ originPath: s3Props.originPath
90
+ };
91
+ }
92
+ case "alb": {
93
+ const albProps = props;
94
+ const loadBalancer = albProps.loadBalancer instanceof compute_1.Compute
95
+ ? albProps.loadBalancer.getLoadBalancer()
96
+ : albProps.loadBalancer;
97
+ return {
98
+ type: "alb",
99
+ loadBalancer,
100
+ protocolPolicy: albProps.protocolPolicy
101
+ };
102
+ }
103
+ case "http": {
104
+ const httpProps = props;
105
+ return {
106
+ type: "http",
107
+ domainName: httpProps.domainName,
108
+ originPath: httpProps.originPath,
109
+ protocolPolicy: httpProps.protocolPolicy
110
+ };
111
+ }
112
+ case "auto": {
113
+ const smartProps = props;
114
+ return Cdn.detectOriginFromResource(smartProps.origin);
115
+ }
116
+ }
117
+ }
118
+ /**
119
+ * Auto-detect origin configuration from a Fjall resource.
120
+ */
121
+ static detectOriginFromResource(resource) {
122
+ // String → HTTP origin
123
+ if (typeof resource === "string") {
124
+ return {
125
+ type: "http",
126
+ domainName: resource
127
+ };
128
+ }
129
+ // S3Storage → S3 origin
130
+ if (resource instanceof storage_1.S3Storage) {
131
+ return {
132
+ type: "s3",
133
+ bucket: resource.getBucket()
134
+ };
135
+ }
136
+ // Compute → ALB or Lambda origin
137
+ if (resource instanceof compute_1.Compute) {
138
+ const computeType = resource.getComputeType();
139
+ if (computeType === "ecs") {
140
+ const loadBalancer = resource.getLoadBalancer();
141
+ if (loadBalancer) {
142
+ return {
143
+ type: "alb",
144
+ loadBalancer
145
+ };
146
+ }
147
+ }
148
+ if (computeType === "lambda") {
149
+ const functionUrl = resource.getFunctionUrl();
150
+ if (functionUrl) {
151
+ // Lambda function URL is an HTTP origin
152
+ const url = new URL(functionUrl);
153
+ return {
154
+ type: "http",
155
+ domainName: url.hostname
156
+ };
157
+ }
158
+ }
159
+ }
160
+ throw new Error(`Unable to detect CDN origin from resource: ${typeof resource}. ` +
161
+ "Provide explicit origin configuration using originType.");
162
+ }
163
+ }
164
+ exports.Cdn = Cdn;
165
+ /**
166
+ * Factory for creating CDN (CloudFront) distributions.
167
+ *
168
+ * @example
169
+ * // S3 origin
170
+ * const assets = app.addStorage(StorageFactory.build("Assets", { bucketType: "private" }));
171
+ * app.addCdn(CdnFactory.build("AssetsCdn", {
172
+ * originType: "s3",
173
+ * bucket: assets
174
+ * }));
175
+ *
176
+ * @example
177
+ * // ALB origin (ECS)
178
+ * const api = app.addCompute(ComputeFactory.build("Api", { type: "ecs", ... }));
179
+ * app.addCdn(CdnFactory.build("ApiCdn", {
180
+ * originType: "alb",
181
+ * loadBalancer: api
182
+ * }));
183
+ *
184
+ * @example
185
+ * // Smart detection
186
+ * app.addCdn(CdnFactory.build("AppCdn", {
187
+ * originType: "auto",
188
+ * origin: assets
189
+ * }));
190
+ *
191
+ * @example
192
+ * // Custom domain
193
+ * app.addCdn(CdnFactory.build("AppCdn", {
194
+ * originType: "s3",
195
+ * bucket: assets,
196
+ * domainNames: ["app.example.com"],
197
+ * certificate: myCert
198
+ * }));
199
+ */
200
+ class CdnFactory {
201
+ /**
202
+ * Build a CDN factory function.
203
+ *
204
+ * @param id - Unique identifier for the CDN
205
+ * @param props - CDN configuration properties
206
+ * @returns Factory function that creates the CDN when invoked
207
+ */
208
+ static build(id, props) {
209
+ return (_app, scope) => {
210
+ validateCdnProps(props);
211
+ return new Cdn(scope, id, props);
212
+ };
213
+ }
214
+ }
215
+ exports.CdnFactory = CdnFactory;
216
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2RuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vbGliL3BhdHRlcm5zL2F3cy9jZG4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBT0EsaURBTWlDO0FBQ2pDLHVDQUFzQztBQUN0Qyx1Q0FBb0M7QUFvRXBDOztHQUVHO0FBQ0gsU0FBUyxnQkFBZ0IsQ0FBQyxLQUFnQjtJQUN4QyxzQ0FBc0M7SUFDdEMsSUFBSSxLQUFLLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxXQUFXLElBQUksS0FBSyxDQUFDLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDM0UsT0FBTyxDQUFDLElBQUksQ0FDVixxRUFBcUU7WUFDbkUsbURBQW1ELENBQ3RELENBQUM7SUFDSixDQUFDO0lBRUQsNENBQTRDO0lBQzVDLElBQUksS0FBSyxDQUFDLFdBQVcsSUFBSSxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDNUUsT0FBTyxDQUFDLElBQUksQ0FDViwwRUFBMEU7WUFDeEUsOERBQThELENBQ2pFLENBQUM7SUFDSixDQUFDO0lBRUQsc0JBQXNCO0lBQ3RCLElBQUksS0FBSyxDQUFDLFVBQVUsS0FBSyxLQUFLLEVBQUUsQ0FBQztRQUMvQixNQUFNLFFBQVEsR0FBRyxLQUFvQixDQUFDO1FBQ3RDLElBQUksUUFBUSxDQUFDLFlBQVksWUFBWSxpQkFBTyxFQUFFLENBQUM7WUFDN0MsTUFBTSxFQUFFLEdBQUcsUUFBUSxDQUFDLFlBQVksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUNuRCxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQ1IsTUFBTSxJQUFJLEtBQUssQ0FDYixrREFBa0Q7b0JBQ2hELDZEQUE2RCxDQUNoRSxDQUFDO1lBQ0osQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQsd0JBQXdCO0lBQ3hCLElBQUksS0FBSyxDQUFD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SUFBSSxFQUFFLEtBQUs7d0JBQ1gsWUFBWTtxQkFDYixDQUFDO2dCQUNKLENBQUM7WUFDSCxDQUFDO1lBRUQsSUFBSSxXQUFXLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQzdCLE1BQU0sV0FBVyxHQUFHLFFBQVEsQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDOUMsSUFBSSxXQUFXLEVBQUUsQ0FBQztvQkFDaEIsd0NBQXdDO29CQUN4QyxNQUFNLEdBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQztvQkFDakMsT0FBTzt3QkFDTCxJQUFJLEVBQUUsTUFBTTt3QkFDWixVQUFVLEVBQUUsR0FBRyxDQUFDLFFBQVE7cUJBQ3pCLENBQUM7Z0JBQ0osQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBRUQsTUFBTSxJQUFJLEtBQUssQ0FDYiw4Q0FBOEMsT0FBTyxRQUFRLElBQUk7WUFDL0QseURBQXlELENBQzVELENBQUM7SUFDSixDQUFDO0NBQ0Y7QUE5SEQsa0JBOEhDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQ0c7QUFDSCxNQUFhLFVBQVU7SUFDckI7Ozs7OztPQU1HO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFVLEVBQUUsS0FBZ0I7UUFDdkMsT0FBTyxDQUFDLElBQVMsRUFBRSxLQUFnQixFQUFPLEVBQUU7WUFDMUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDeEIsT0FBTyxJQUFJLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ25DLENBQUMsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQWRELGdDQWNDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IHR5cGUgSUJ1Y2tldCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtczNcIjtcbmltcG9ydCB7IHR5cGUgSUFwcGxpY2F0aW9uTG9hZEJhbGFuY2VyIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1lbGFzdGljbG9hZGJhbGFuY2luZ3YyXCI7XG5pbXBvcnQgeyB0eXBlIElDZXJ0aWZpY2F0ZSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyXCI7XG5pbXBvcnQgeyB0eXBlIElDYWNoZVBvbGljeSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2xvdWRmcm9udFwiO1xuXG5pbXBvcnQgdHlwZSBBcHAgZnJvbSBcIi4uLy4uL2FwcFwiO1xuaW1wb3J0IHtcbiAgQ2xvdWRGcm9udERpc3RyaWJ1dGlvbixcbiAgdHlwZSBDbG91ZEZyb250RGlzdHJpYnV0aW9uUHJvcHMsXG4gIHR5cGUgQ2RuT3JpZ2luQ29uZmlnLFxuICB0eXBlIENkbkJlaGF2aW91cixcbiAgdHlwZSBDYWNoZVBvbGljeVByZXNldFxufSBmcm9tIFwiLi4vLi4vcmVzb3VyY2VzL2F3cy9jZG5cIjtcbmltcG9ydCB7IFMzU3RvcmFnZSB9IGZyb20gXCIuL3N0b3JhZ2VcIjtcbmltcG9ydCB7IENvbXB1dGUgfSBmcm9tIFwiLi9jb21wdXRlXCI7XG5cbi8qKlxuICogUzMgb3JpZ2luIENETiBwcm9wcyAtIHVzZSB3aXRoIFMzIGJ1Y2tldFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFMzQ2RuUHJvcHMge1xuICBvcmlnaW5UeXBlOiBcInMzXCI7XG4gIGJ1Y2tldDogSUJ1Y2tldCB8IFMzU3RvcmFnZTtcbiAgb3JpZ2luUGF0aD86IHN0cmluZztcbiAgY2FjaGVQb2xpY3k/OiBDYWNoZVBvbGljeVByZXNldCB8IElDYWNoZVBvbGljeTtcbiAgYmVoYXZpb3Vycz86IENkbkJlaGF2aW91cltdO1xuICBkb21haW5OYW1lcz86IHN0cmluZ1tdO1xuICBjZXJ0aWZpY2F0ZT86IElDZXJ0aWZpY2F0ZTtcbiAgY29tbWVudD86IHN0cmluZztcbiAgZW5hYmxlTG9nZ2luZz86IGJvb2xlYW47XG4gIGxvZ0J1Y2tldD86IElCdWNrZXQ7XG59XG5cbi8qKlxuICogQUxCIG9yaWdpbiBDRE4gcHJvcHMgLSB1c2Ugd2l0aCBBcHBsaWNhdGlvbiBMb2FkIEJhbGFuY2VyXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQWxiQ2RuUHJvcHMge1xuICBvcmlnaW5UeXBlOiBcImFsYlwiO1xuICBsb2FkQmFsYW5jZXI6IElBcHBsaWNhdGlvbkxvYWRCYWxhbmNlciB8IENvbXB1dGU7XG4gIHByb3RvY29sUG9saWN5PzogXCJIVFRQX09OTFlcIiB8IFwiSFRUUFNfT05MWVwiIHwgXCJNQVRDSF9WSUVXRVJcIjtcbiAgY2FjaGVQb2xpY3k/OiBDYWNoZVBvbGljeVByZXNldCB8IElDYWNoZVBvbGljeTtcbiAgYmVoYXZpb3Vycz86IENkbkJlaGF2aW91cltdO1xuICBkb21haW5OYW1lcz86IHN0cmluZ1tdO1xuICBjZXJ0aWZpY2F0ZT86IElDZXJ0aWZpY2F0ZTtcbiAgY29tbWVudD86IHN0cmluZztcbiAgZW5hYmxlTG9nZ2luZz86IGJvb2xlYW47XG4gIGxvZ0J1Y2tldD86IElCdWNrZXQ7XG59XG5cbi8qKlxuICogSFRUUCBvcmlnaW4gQ0ROIHByb3BzIC0gdXNlIHdpdGggY3VzdG9tIEhUVFAgZW5kcG9pbnRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBIdHRwQ2RuUHJvcHMge1xuICBvcmlnaW5UeXBlOiBcImh0dHBcIjtcbiAgZG9tYWluTmFtZTogc3RyaW5nO1xuICBvcmlnaW5QYXRoPzogc3RyaW5nO1xuICBwcm90b2NvbFBvbGljeT86IFwiSFRUUF9PTkxZXCIgfCBcIkhUVFBTX09OTFlcIiB8IFwiTUFUQ0hfVklFV0VSXCI7XG4gIGNhY2hlUG9saWN5PzogQ2FjaGVQb2xpY3lQcmVzZXQgfCBJQ2FjaGVQb2xpY3k7XG4gIGJlaGF2aW91cnM/OiBDZG5CZWhhdmlvdXJbXTtcbiAgZG9tYWluTmFtZXM/OiBzdHJpbmdbXTtcbiAgY2VydGlmaWNhdGU/OiBJQ2VydGlmaWNhdGU7XG4gIGNvbW1lbnQ/OiBzdHJpbmc7XG4gIGVuYWJsZUxvZ2dpbmc/OiBib29sZWFuO1xuICBsb2dCdWNrZXQ/OiBJQnVja2V0O1xufVxuXG4vKipcbiAqIFNtYXJ0IG9yaWdpbiBDRE4gcHJvcHMgLSBhdXRvLWRldGVjdCBvcmlnaW4gdHlwZSBmcm9tIEZqYWxsIHJlc291cmNlXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU21hcnRDZG5Qcm9wcyB7XG4gIG9yaWdpblR5cGU6IFwiYXV0b1wiO1xuICBvcmlnaW46IFMzU3RvcmFnZSB8IENvbXB1dGUgfCBzdHJpbmc7XG4gIGNhY2hlUG9saWN5PzogQ2FjaGVQb2xpY3lQcmVzZXQgfCBJQ2FjaGVQb2xpY3k7XG4gIGJlaGF2aW91cnM/OiBDZG5CZWhhdmlvdXJbXTtcbiAgZG9tYWluTmFtZXM/OiBzdHJpbmdbXTtcbiAgY2VydGlmaWNhdGU/OiBJQ2VydGlmaWNhdGU7XG4gIGNvbW1lbnQ/OiBzdHJpbmc7XG4gIGVuYWJsZUxvZ2dpbmc/OiBib29sZWFuO1xuICBsb2dCdWNrZXQ/OiBJQnVja2V0O1xufVxuXG5leHBvcnQgdHlwZSBJQ2RuUHJvcHMgPSBTM0NkblByb3BzIHwgQWxiQ2RuUHJvcHMgfCBIdHRwQ2RuUHJvcHMgfCBTbWFydENkblByb3BzO1xuXG4vKipcbiAqIFZhbGlkYXRlcyBDRE4gcHJvcHMgYW5kIGxvZ3Mgd2FybmluZ3MgZm9yIG1pc2NvbmZpZ3VyZWQgb3B0aW9ucy5cbiAqL1xuZnVuY3Rpb24gdmFsaWRhdGVDZG5Qcm9wcyhwcm9wczogSUNkblByb3BzKTogdm9pZCB7XG4gIC8vIFZhbGlkYXRlIGNlcnRpZmljYXRlIHJlZ2lvbiB3YXJuaW5nXG4gIGlmIChwcm9wcy5jZXJ0aWZpY2F0ZSAmJiBwcm9wcy5kb21haW5OYW1lcyAmJiBwcm9wcy5kb21haW5OYW1lcy5sZW5ndGggPiAwKSB7XG4gICAgY29uc29sZS5pbmZvKFxuICAgICAgXCJbRmphbGxdIE5vdGU6IENsb3VkRnJvbnQgY2VydGlmaWNhdGVzIG11c3QgYmUgaW4gdXMtZWFzdC0xIHJlZ2lvbi4gXCIgK1xuICAgICAgICBcIkVuc3VyZSB5b3VyIGNlcnRpZmljYXRlIHdhcyBjcmVhdGVkIGluIHVzLWVhc3QtMS5cIlxuICAgICk7XG4gIH1cblxuICAvLyBWYWxpZGF0ZSBkb21haW4gbmFtZXMgcmVxdWlyZSBjZXJ0aWZpY2F0ZVxuICBpZiAocHJvcHMuZG9tYWluTmFtZXMgJiYgcHJvcHMuZG9tYWluTmFtZXMubGVuZ3RoID4gMCAmJiAhcHJvcHMuY2VydGlmaWNhdGUpIHtcbiAgICBjb25zb2xlLndhcm4oXG4gICAgICBcIltGamFsbF0gV2FybmluZzogJ2RvbWFpbk5hbWVzJyBwcm92aWRlZCBidXQgbm8gJ2NlcnRpZmljYXRlJyBzcGVjaWZpZWQuIFwiICtcbiAgICAgICAgXCJDdXN0b20gZG9tYWluIG5hbWVzIHJlcXVpcmUgYW4gQUNNIGNlcnRpZmljYXRlIGluIHVzLWVhc3QtMS5cIlxuICAgICk7XG4gIH1cblxuICAvLyBWYWxpZGF0ZSBBTEIgb3JpZ2luXG4gIGlmIChwcm9wcy5vcmlnaW5UeXBlID09PSBcImFsYlwiKSB7XG4gICAgY29uc3QgYWxiUHJvcHMgPSBwcm9wcyBhcyBBbGJDZG5Qcm9wcztcbiAgICBpZiAoYWxiUHJvcHMubG9hZEJhbGFuY2VyIGluc3RhbmNlb2YgQ29tcHV0ZSkge1xuICAgICAgY29uc3QgbGIgPSBhbGJQcm9wcy5sb2FkQmFsYW5jZXIuZ2V0TG9hZEJhbGFuY2VyKCk7XG4gICAgICBpZiAoIWxiKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBcIkNvbXB1dGUgcmVzb3VyY2UgZG9lcyBub3QgaGF2ZSBhIGxvYWQgYmFsYW5jZXIuIFwiICtcbiAgICAgICAgICAgIFwiRW5zdXJlIEVDUyBjb21wdXRlIGhhcyBsb2FkQmFsYW5jZXIgZW5hYmxlZCBmb3IgQ0ROIG9yaWdpbi5cIlxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFZhbGlkYXRlIHNtYXJ0IG9yaWdpblxuICBpZiAocHJvcHMub3JpZ2luVHlwZSA9PT0gXCJhdXRvXCIpIHtcbiAgICBjb25zdCBzbWFydFByb3BzID0gcHJvcHMgYXMgU21hcnRDZG5Qcm9wcztcbiAgICBpZiAoc21hcnRQcm9wcy5vcmlnaW4gaW5zdGFuY2VvZiBDb21wdXRlKSB7XG4gICAgICBjb25zdCBjb21wdXRlVHlwZSA9IHNtYXJ0UHJvcHMub3JpZ2luLmdldENvbXB1dGVUeXBlKCk7XG4gICAgICBpZiAoY29tcHV0ZVR5cGUgPT09IFwiZWMyXCIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIFwiRUMyIGNvbXB1dGUgdHlwZSBpcyBub3Qgc3VwcG9ydGVkIGZvciBDRE4gb3JpZ2luLiBcIiArXG4gICAgICAgICAgICBcIlVzZSBFQ1Mgd2l0aCBsb2FkIGJhbGFuY2VyIG9yIExhbWJkYSB3aXRoIGZ1bmN0aW9uIFVSTC5cIlxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgaWYgKGNvbXB1dGVUeXBlID09PSBcImVjc1wiICYmICFzbWFydFByb3BzLm9yaWdpbi5nZXRMb2FkQmFsYW5jZXIoKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgXCJFQ1MgY29tcHV0ZSBtdXN0IGhhdmUgYSBsb2FkIGJhbGFuY2VyIGZvciBDRE4gb3JpZ2luLiBcIiArXG4gICAgICAgICAgICBcIkVuYWJsZSBsb2FkQmFsYW5jZXIgaW4geW91ciBFQ1MgY29tcHV0ZSBjb25maWd1cmF0aW9uLlwiXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAoY29tcHV0ZVR5cGUgPT09IFwibGFtYmRhXCIgJiYgIXNtYXJ0UHJvcHMub3JpZ2luLmdldEZ1bmN0aW9uVXJsKCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIFwiTGFtYmRhIGNvbXB1dGUgbXVzdCBoYXZlIGEgZnVuY3Rpb24gVVJMIGZvciBDRE4gb3JpZ2luLiBcIiArXG4gICAgICAgICAgICBcIkVuYWJsZSBmdW5jdGlvblVybCBpbiB5b3VyIExhbWJkYSBjb21wdXRlIGNvbmZpZ3VyYXRpb24uXCJcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBDRE4gd3JhcHBlciBjbGFzcyB0aGF0IGV4dGVuZHMgQ2xvdWRGcm9udERpc3RyaWJ1dGlvbiB3aXRoIEZqYWxsIHBhdHRlcm5zLlxuICovXG5leHBvcnQgY2xhc3MgQ2RuIGV4dGVuZHMgQ2xvdWRGcm9udERpc3RyaWJ1dGlvbiB7XG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBJQ2RuUHJvcHMpIHtcbiAgICBjb25zdCByZXNvbHZlZFByb3BzID0gQ2RuLnJlc29sdmVQcm9wcyhwcm9wcyk7XG4gICAgc3VwZXIoc2NvcGUsIGlkLCByZXNvbHZlZFByb3BzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlIElDZG5Qcm9wcyB0byBDbG91ZEZyb250RGlzdHJpYnV0aW9uUHJvcHMuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyByZXNvbHZlUHJvcHMocHJvcHM6IElDZG5Qcm9wcyk6IENsb3VkRnJvbnREaXN0cmlidXRpb25Qcm9wcyB7XG4gICAgY29uc3QgZGVmYXVsdE9yaWdpbiA9IENkbi5yZXNvbHZlRGVmYXVsdE9yaWdpbihwcm9wcyk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgZGVmYXVsdE9yaWdpbixcbiAgICAgIGRlZmF1bHRDYWNoZVBvbGljeTogcHJvcHMuY2FjaGVQb2xpY3ksXG4gICAgICBiZWhhdmlvdXJzOiBwcm9wcy5iZWhhdmlvdXJzLFxuICAgICAgZG9tYWluTmFtZXM6IHByb3BzLmRvbWFpbk5hbWVzLFxuICAgICAgY2VydGlmaWNhdGU6IHByb3BzLmNlcnRpZmljYXRlLFxuICAgICAgY29tbWVudDogcHJvcHMuY29tbWVudCxcbiAgICAgIGVuYWJsZUxvZ2dpbmc6IHByb3BzLmVuYWJsZUxvZ2dpbmcsXG4gICAgICBsb2dCdWNrZXQ6IHByb3BzLmxvZ0J1Y2tldFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZSB0aGUgZGVmYXVsdCBvcmlnaW4gZnJvbSBJQ2RuUHJvcHMuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyByZXNvbHZlRGVmYXVsdE9yaWdpbihwcm9wczogSUNkblByb3BzKTogQ2RuT3JpZ2luQ29uZmlnIHtcbiAgICBzd2l0Y2ggKHByb3BzLm9yaWdpblR5cGUpIHtcbiAgICAgIGNhc2UgXCJzM1wiOiB7XG4gICAgICAgIGNvbnN0IHMzUHJvcHMgPSBwcm9wcyBhcyBTM0NkblByb3BzO1xuICAgICAgICBjb25zdCBidWNrZXQgPVxuICAgICAgICAgIHMzUHJvcHMuYnVja2V0IGluc3RhbmNlb2YgUzNTdG9yYWdlXG4gICAgICAgICAgICA/IHMzUHJvcHMuYnVja2V0LmdldEJ1Y2tldCgpXG4gICAgICAgICAgICA6IHMzUHJvcHMuYnVja2V0O1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHR5cGU6IFwiczNcIixcbiAgICAgICAgICBidWNrZXQsXG4gICAgICAgICAgb3JpZ2luUGF0aDogczNQcm9wcy5vcmlnaW5QYXRoXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGNhc2UgXCJhbGJcIjoge1xuICAgICAgICBjb25zdCBhbGJQcm9wcyA9IHByb3BzIGFzIEFsYkNkblByb3BzO1xuICAgICAgICBjb25zdCBsb2FkQmFsYW5jZXIgPVxuICAgICAgICAgIGFsYlByb3BzLmxvYWRCYWxhbmNlciBpbnN0YW5jZW9mIENvbXB1dGVcbiAgICAgICAgICAgID8gYWxiUHJvcHMubG9hZEJhbGFuY2VyLmdldExvYWRCYWxhbmNlcigpIVxuICAgICAgICAgICAgOiBhbGJQcm9wcy5sb2FkQmFsYW5jZXI7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdHlwZTogXCJhbGJcIixcbiAgICAgICAgICBsb2FkQmFsYW5jZXIsXG4gICAgICAgICAgcHJvdG9jb2xQb2xpY3k6IGFsYlByb3BzLnByb3RvY29sUG9saWN5XG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGNhc2UgXCJodHRwXCI6IHtcbiAgICAgICAgY29uc3QgaHR0cFByb3BzID0gcHJvcHMgYXMgSHR0cENkblByb3BzO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHR5cGU6IFwiaHR0cFwiLFxuICAgICAgICAgIGRvbWFpbk5hbWU6IGh0dHBQcm9wcy5kb21haW5OYW1lLFxuICAgICAgICAgIG9yaWdpblBhdGg6IGh0dHBQcm9wcy5vcmlnaW5QYXRoLFxuICAgICAgICAgIHByb3RvY29sUG9saWN5OiBodHRwUHJvcHMucHJvdG9jb2xQb2xpY3lcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY2FzZSBcImF1dG9cIjoge1xuICAgICAgICBjb25zdCBzbWFydFByb3BzID0gcHJvcHMgYXMgU21hcnRDZG5Qcm9wcztcbiAgICAgICAgcmV0dXJuIENkbi5kZXRlY3RPcmlnaW5Gcm9tUmVzb3VyY2Uoc21hcnRQcm9wcy5vcmlnaW4pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBdXRvLWRldGVjdCBvcmlnaW4gY29uZmlndXJhdGlvbiBmcm9tIGEgRmphbGwgcmVzb3VyY2UuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBkZXRlY3RPcmlnaW5Gcm9tUmVzb3VyY2UoXG4gICAgcmVzb3VyY2U6IFMzU3RvcmFnZSB8IENvbXB1dGUgfCBzdHJpbmdcbiAgKTogQ2RuT3JpZ2luQ29uZmlnIHtcbiAgICAvLyBTdHJpbmcg4oaSIEhUVFAgb3JpZ2luXG4gICAgaWYgKHR5cGVvZiByZXNvdXJjZSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdHlwZTogXCJodHRwXCIsXG4gICAgICAgIGRvbWFpbk5hbWU6IHJlc291cmNlXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIFMzU3RvcmFnZSDihpIgUzMgb3JpZ2luXG4gICAgaWYgKHJlc291cmNlIGluc3RhbmNlb2YgUzNTdG9yYWdlKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB0eXBlOiBcInMzXCIsXG4gICAgICAgIGJ1Y2tldDogcmVzb3VyY2UuZ2V0QnVja2V0KClcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gQ29tcHV0ZSDihpIgQUxCIG9yIExhbWJkYSBvcmlnaW5cbiAgICBpZiAocmVzb3VyY2UgaW5zdGFuY2VvZiBDb21wdXRlKSB7XG4gICAgICBjb25zdCBjb21wdXRlVHlwZSA9IHJlc291cmNlLmdldENvbXB1dGVUeXBlKCk7XG5cbiAgICAgIGlmIChjb21wdXRlVHlwZSA9PT0gXCJlY3NcIikge1xuICAgICAgICBjb25zdCBsb2FkQmFsYW5jZXIgPSByZXNvdXJjZS5nZXRMb2FkQmFsYW5jZXIoKTtcbiAgICAgICAgaWYgKGxvYWRCYWxhbmNlcikge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0eXBlOiBcImFsYlwiLFxuICAgICAgICAgICAgbG9hZEJhbGFuY2VyXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoY29tcHV0ZVR5cGUgPT09IFwibGFtYmRhXCIpIHtcbiAgICAgICAgY29uc3QgZnVuY3Rpb25VcmwgPSByZXNvdXJjZS5nZXRGdW5jdGlvblVybCgpO1xuICAgICAgICBpZiAoZnVuY3Rpb25VcmwpIHtcbiAgICAgICAgICAvLyBMYW1iZGEgZnVuY3Rpb24gVVJMIGlzIGFuIEhUVFAgb3JpZ2luXG4gICAgICAgICAgY29uc3QgdXJsID0gbmV3IFVSTChmdW5jdGlvblVybCk7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHR5cGU6IFwiaHR0cFwiLFxuICAgICAgICAgICAgZG9tYWluTmFtZTogdXJsLmhvc3RuYW1lXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBVbmFibGUgdG8gZGV0ZWN0IENETiBvcmlnaW4gZnJvbSByZXNvdXJjZTogJHt0eXBlb2YgcmVzb3VyY2V9LiBgICtcbiAgICAgICAgXCJQcm92aWRlIGV4cGxpY2l0IG9yaWdpbiBjb25maWd1cmF0aW9uIHVzaW5nIG9yaWdpblR5cGUuXCJcbiAgICApO1xuICB9XG59XG5cbi8qKlxuICogRmFjdG9yeSBmb3IgY3JlYXRpbmcgQ0ROIChDbG91ZEZyb250KSBkaXN0cmlidXRpb25zLlxuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBTMyBvcmlnaW5cbiAqIGNvbnN0IGFzc2V0cyA9IGFwcC5hZGRTdG9yYWdlKFN0b3JhZ2VGYWN0b3J5LmJ1aWxkKFwiQXNzZXRzXCIsIHsgYnVja2V0VHlwZTogXCJwcml2YXRlXCIgfSkpO1xuICogYXBwLmFkZENkbihDZG5GYWN0b3J5LmJ1aWxkKFwiQXNzZXRzQ2RuXCIsIHtcbiAqICAgb3JpZ2luVHlwZTogXCJzM1wiLFxuICogICBidWNrZXQ6IGFzc2V0c1xuICogfSkpO1xuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBBTEIgb3JpZ2luIChFQ1MpXG4gKiBjb25zdCBhcGkgPSBhcHAuYWRkQ29tcHV0ZShDb21wdXRlRmFjdG9yeS5idWlsZChcIkFwaVwiLCB7IHR5cGU6IFwiZWNzXCIsIC4uLiB9KSk7XG4gKiBhcHAuYWRkQ2RuKENkbkZhY3RvcnkuYnVpbGQoXCJBcGlDZG5cIiwge1xuICogICBvcmlnaW5UeXBlOiBcImFsYlwiLFxuICogICBsb2FkQmFsYW5jZXI6IGFwaVxuICogfSkpO1xuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBTbWFydCBkZXRlY3Rpb25cbiAqIGFwcC5hZGRDZG4oQ2RuRmFjdG9yeS5idWlsZChcIkFwcENkblwiLCB7XG4gKiAgIG9yaWdpblR5cGU6IFwiYXV0b1wiLFxuICogICBvcmlnaW46IGFzc2V0c1xuICogfSkpO1xuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBDdXN0b20gZG9tYWluXG4gKiBhcHAuYWRkQ2RuKENkbkZhY3RvcnkuYnVpbGQoXCJBcHBDZG5cIiwge1xuICogICBvcmlnaW5UeXBlOiBcInMzXCIsXG4gKiAgIGJ1Y2tldDogYXNzZXRzLFxuICogICBkb21haW5OYW1lczogW1wiYXBwLmV4YW1wbGUuY29tXCJdLFxuICogICBjZXJ0aWZpY2F0ZTogbXlDZXJ0XG4gKiB9KSk7XG4gKi9cbmV4cG9ydCBjbGFzcyBDZG5GYWN0b3J5IHtcbiAgLyoqXG4gICAqIEJ1aWxkIGEgQ0ROIGZhY3RvcnkgZnVuY3Rpb24uXG4gICAqXG4gICAqIEBwYXJhbSBpZCAtIFVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgQ0ROXG4gICAqIEBwYXJhbSBwcm9wcyAtIENETiBjb25maWd1cmF0aW9uIHByb3BlcnRpZXNcbiAgICogQHJldHVybnMgRmFjdG9yeSBmdW5jdGlvbiB0aGF0IGNyZWF0ZXMgdGhlIENETiB3aGVuIGludm9rZWRcbiAgICovXG4gIHN0YXRpYyBidWlsZChpZDogc3RyaW5nLCBwcm9wczogSUNkblByb3BzKSB7XG4gICAgcmV0dXJuIChfYXBwOiBBcHAsIHNjb3BlOiBDb25zdHJ1Y3QpOiBDZG4gPT4ge1xuICAgICAgdmFsaWRhdGVDZG5Qcm9wcyhwcm9wcyk7XG4gICAgICByZXR1cm4gbmV3IENkbihzY29wZSwgaWQsIHByb3BzKTtcbiAgICB9O1xuICB9XG59XG4iXX0=
@@ -1,6 +1,6 @@
1
1
  import { type RepositoryImage } from "aws-cdk-lib/aws-ecs";
2
2
  import { Repository } from "aws-cdk-lib/aws-ecr";
3
- import { Connections, type IConnectable, type IVpc, type UserData, type IMachineImage } from "aws-cdk-lib/aws-ec2";
3
+ import { type Connections, type IConnectable, type IVpc, type UserData, type IMachineImage } from "aws-cdk-lib/aws-ec2";
4
4
  import { Code, Runtime, type FunctionUrlAuthType, type FunctionUrlCorsOptions } from "aws-cdk-lib/aws-lambda";
5
5
  import { type PolicyStatement, type PolicyDocument, type IManagedPolicy } from "aws-cdk-lib/aws-iam";
6
6
  import { Construct } from "constructs";
@@ -273,6 +273,26 @@ export interface EcsServiceConfig {
273
273
  * ]
274
274
  */
275
275
  connections?: IConnectable[];
276
+ /**
277
+ * Capacity provider for this service. REQUIRED.
278
+ * Each service specifies its own capacity provider.
279
+ *
280
+ * @example
281
+ * // Mixed FARGATE and EC2 services in same cluster
282
+ * {
283
+ * services: [
284
+ * { name: "api", capacityProvider: "FARGATE" },
285
+ * { name: "worker", capacityProvider: "EC2", ec2Config: { instanceType: "t3.micro" } }
286
+ * ]
287
+ * }
288
+ */
289
+ capacityProvider: EcsCapacityProvider;
290
+ /**
291
+ * EC2 capacity configuration for this service.
292
+ * Only used when service capacityProvider is "EC2".
293
+ * Services with matching ec2Config share an ASG for efficiency.
294
+ */
295
+ ec2Config?: Ec2CapacityConfig;
276
296
  }
277
297
  /**
278
298
  * SSH access configuration for EC2 instances.
@@ -347,21 +367,10 @@ export interface EcsComputeProps extends BaseComputeProps {
347
367
  /**
348
368
  * Services in this cluster.
349
369
  * Each service gets its own task definition, scaling, and target group.
370
+ * Each service MUST specify its own capacityProvider.
350
371
  * All services share the cluster's ALB (unless disabled).
351
372
  */
352
373
  services: EcsServiceConfig[];
353
- /**
354
- * Capacity provider determines infrastructure type.
355
- * - "FARGATE": Serverless containers (default)
356
- * - "FARGATE_SPOT": Serverless with Spot pricing
357
- * - "EC2": EC2-backed containers
358
- */
359
- capacityProvider?: EcsCapacityProvider;
360
- /**
361
- * EC2 capacity configuration.
362
- * Only used when capacityProvider is "EC2".
363
- */
364
- ec2Config?: Ec2CapacityConfig;
365
374
  /**
366
375
  * ECR repository for all services (default image).
367
376
  * Individual services can override with their own `image` property.
@@ -403,6 +412,7 @@ interface BaseLambdaProps extends BaseComputeProps {
403
412
  timeout?: number;
404
413
  /** Memory size in MB. Default: 128 */
405
414
  memorySize?: number;
415
+ ephemeralStorageSize?: number;
406
416
  /** Lambda function description */
407
417
  description?: string;
408
418
  /** IAM role description */
@@ -419,6 +429,15 @@ interface BaseLambdaProps extends BaseComputeProps {
419
429
  functionUrl?: FunctionUrlConfig | false;
420
430
  /** Environment variables */
421
431
  environment?: Record<string, string>;
432
+ /** Container secrets import (key: env var, value: SecretImport) */
433
+ containerSecretsImport?: {
434
+ [key: string]: SecretImport;
435
+ };
436
+ /**
437
+ * Resources this Lambda needs to connect to (e.g., databases).
438
+ * Creates security group rules to allow traffic from this Lambda.
439
+ */
440
+ connections?: IConnectable[];
422
441
  }
423
442
  /**
424
443
  * Container-based Lambda using ECR image.