carlin 1.31.6 → 1.31.8
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.
- package/dist/config.js +1 -1
- package/dist/deploy/baseStack/config.js +1 -1
- package/dist/deploy/baseStack/deployBaseStack.js +11 -10
- package/dist/deploy/baseStack/getBaseStackResource.js +3 -2
- package/dist/deploy/baseStack/{getLambdaLayerBuilder.template.js → getLambdaLayerBuilderTemplate.js} +4 -2
- package/dist/deploy/cicd/deployCicd.js +4 -3
- package/dist/deploy/{cloudFormation.core.js → cloudformation.core.js} +53 -27
- package/dist/deploy/{cloudFormation.js → cloudformation.js} +9 -11
- package/dist/deploy/command.js +5 -5
- package/dist/deploy/lambda/buildLambdaSingleFile.js +14 -2
- package/dist/deploy/lambdaLayer/deployLambdaLayer.js +5 -3
- package/dist/deploy/s3.js +2 -0
- package/dist/deploy/staticApp/command.js +17 -12
- package/dist/deploy/staticApp/deployStaticApp.js +4 -3
- package/dist/deploy/staticApp/getStaticAppBucket.js +2 -2
- package/package.json +13 -13
- package/dist/deploy/{addDefaults.cloudFormation.js → addDefaults.cloudformation.js} +0 -0
- package/dist/deploy/baseStack/{getBucket.template.js → getBucketTemplate.js} +0 -0
- package/dist/deploy/baseStack/{getLambdaImageBuilder.template.js → getLambdaImageBuilderTemplate.js} +2 -2
- /package/dist/deploy/baseStack/{getVpc.template.js → getVpcTemplate.js} +0 -0
package/dist/config.js
CHANGED
|
@@ -8,4 +8,4 @@ exports.AWS_DEFAULT_REGION = 'us-east-1';
|
|
|
8
8
|
* https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-requirements-limits.html#lambda-requirements-cloudfront-triggers
|
|
9
9
|
*/
|
|
10
10
|
exports.CLOUDFRONT_REGION = 'us-east-1';
|
|
11
|
-
exports.NODE_RUNTIME = '
|
|
11
|
+
exports.NODE_RUNTIME = 'nodejs20.x';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BASE_STACK_VPC_PUBLIC_SUBNET_2_EXPORTED_NAME = exports.BASE_STACK_VPC_PUBLIC_SUBNET_1_EXPORTED_NAME = exports.BASE_STACK_VPC_PUBLIC_SUBNET_0_EXPORTED_NAME = exports.BASE_STACK_VPC_DEFAULT_SECURITY_GROUP_EXPORTED_NAME = exports.BASE_STACK_VPC_ID_EXPORTED_NAME = exports.BASE_STACK_LAMBDA_LAYER_BUILDER_LOGICAL_NAME = exports.BASE_STACK_LAMBDA_IMAGE_BUILDER_EXPORTED_NAME = exports.BASE_STACK_LAMBDA_IMAGE_BUILDER_LOGICAL_NAME = exports.BASE_STACK_BUCKET_NAME_EXPORTED_NAME = exports.BASE_STACK_BUCKET_LOGICAL_NAME = exports.BASE_STACK_BUCKET_TEMPLATES_FOLDER = exports.BASE_STACK_NAME = void 0;
|
|
4
|
-
const change_case_1 = require("change-case");
|
|
5
4
|
const config_1 = require("../../config");
|
|
5
|
+
const change_case_1 = require("change-case");
|
|
6
6
|
const pascalCaseName = (0, change_case_1.pascalCase)(config_1.NAME);
|
|
7
7
|
exports.BASE_STACK_NAME = `${pascalCaseName}BaseStack`;
|
|
8
8
|
exports.BASE_STACK_BUCKET_TEMPLATES_FOLDER = 'cloudformation-templates';
|
|
@@ -5,19 +5,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.deployBaseStack = exports.baseStackTemplate = void 0;
|
|
7
7
|
const config_1 = require("./config");
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
8
|
+
const cloudformation_core_1 = require("../cloudformation.core");
|
|
9
|
+
const getBucketTemplate_1 = require("./getBucketTemplate");
|
|
10
|
+
const getLambdaImageBuilderTemplate_1 = require("./getLambdaImageBuilderTemplate");
|
|
11
|
+
const getLambdaLayerBuilderTemplate_1 = require("./getLambdaLayerBuilderTemplate");
|
|
12
|
+
const getVpcTemplate_1 = require("./getVpcTemplate");
|
|
13
13
|
const utils_1 = require("../utils");
|
|
14
14
|
const deepmerge_1 = __importDefault(require("deepmerge"));
|
|
15
15
|
const logPrefix = 'base-stack';
|
|
16
16
|
exports.baseStackTemplate = deepmerge_1.default.all([
|
|
17
|
-
(0,
|
|
18
|
-
(0,
|
|
19
|
-
(0,
|
|
20
|
-
(0,
|
|
17
|
+
(0, getBucketTemplate_1.getBucketTemplate)(),
|
|
18
|
+
(0, getLambdaImageBuilderTemplate_1.getLambdaImageBuilderTemplate)(),
|
|
19
|
+
(0, getLambdaLayerBuilderTemplate_1.getLambdaLayerBuilderTemplate)(),
|
|
20
|
+
(0, getVpcTemplate_1.getVpcTemplate)(),
|
|
21
21
|
]);
|
|
22
22
|
/**
|
|
23
23
|
* Base Stack is a set of auxiliary resources that will be used to help at the
|
|
@@ -48,11 +48,12 @@ const deployBaseStack = async () => {
|
|
|
48
48
|
logPrefix,
|
|
49
49
|
stackName: config_1.BASE_STACK_NAME,
|
|
50
50
|
});
|
|
51
|
-
await (0,
|
|
51
|
+
await (0, cloudformation_core_1.deploy)({
|
|
52
52
|
template: exports.baseStackTemplate,
|
|
53
53
|
params: { StackName: stackName },
|
|
54
54
|
terminationProtection: true,
|
|
55
55
|
});
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
56
57
|
}
|
|
57
58
|
catch (error) {
|
|
58
59
|
(0, utils_1.handleDeployError)({ error, logPrefix });
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getBaseStackResource = exports.getBaseStackOutput = void 0;
|
|
4
|
-
const cloudFormation_core_1 = require("../cloudFormation.core");
|
|
5
4
|
const config_1 = require("./config");
|
|
5
|
+
const cloudformation_core_1 = require("../cloudformation.core");
|
|
6
6
|
const getBaseStackOutput = async (outputKey) => {
|
|
7
|
-
const output = await (0,
|
|
7
|
+
const output = await (0, cloudformation_core_1.getStackOutput)({
|
|
8
8
|
stackName: config_1.BASE_STACK_NAME,
|
|
9
9
|
outputKey,
|
|
10
10
|
});
|
|
@@ -16,6 +16,7 @@ const resourcesKeys = {
|
|
|
16
16
|
BASE_STACK_LAMBDA_IMAGE_BUILDER_LOGICAL_NAME: config_1.BASE_STACK_LAMBDA_IMAGE_BUILDER_LOGICAL_NAME,
|
|
17
17
|
BASE_STACK_LAMBDA_LAYER_BUILDER_LOGICAL_NAME: config_1.BASE_STACK_LAMBDA_LAYER_BUILDER_LOGICAL_NAME,
|
|
18
18
|
};
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
20
|
const resources = {};
|
|
20
21
|
const getBaseStackResource = async (resource) => {
|
|
21
22
|
if (!resources[resource]) {
|
package/dist/deploy/baseStack/{getLambdaLayerBuilder.template.js → getLambdaLayerBuilderTemplate.js}
RENAMED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getLambdaLayerBuilderTemplate = exports.getBuildSpec = void 0;
|
|
4
|
-
const utils_1 = require("../../utils");
|
|
5
4
|
const config_1 = require("./config");
|
|
5
|
+
const utils_1 = require("../../utils");
|
|
6
6
|
const CODE_BUILD_PROJECT_LOGS_GROUP_LOGICAL_ID = `${config_1.BASE_STACK_LAMBDA_LAYER_BUILDER_LOGICAL_NAME}LogsLogGroup`;
|
|
7
7
|
const CODE_BUILD_PROJECT_IAM_ROLE_LOGICAL_ID = `${config_1.BASE_STACK_LAMBDA_LAYER_BUILDER_LOGICAL_NAME}Role`;
|
|
8
8
|
/**
|
|
9
9
|
* https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html
|
|
10
10
|
*/
|
|
11
|
-
const getBuildSpec = () =>
|
|
11
|
+
const getBuildSpec = () => {
|
|
12
|
+
return `
|
|
12
13
|
version: 0.2
|
|
13
14
|
phases:
|
|
14
15
|
install:
|
|
@@ -23,6 +24,7 @@ artifacts:
|
|
|
23
24
|
- nodejs/**/*
|
|
24
25
|
name: $PACKAGE_NAME.zip
|
|
25
26
|
`.trim();
|
|
27
|
+
};
|
|
26
28
|
exports.getBuildSpec = getBuildSpec;
|
|
27
29
|
/**
|
|
28
30
|
* https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codebuild-project.html
|
|
@@ -30,7 +30,7 @@ exports.deployCicd = exports.getLambdaInput = void 0;
|
|
|
30
30
|
const fs = __importStar(require("fs"));
|
|
31
31
|
const path = __importStar(require("path"));
|
|
32
32
|
const cicd_template_1 = require("./cicd.template");
|
|
33
|
-
const
|
|
33
|
+
const cloudformation_core_1 = require("../cloudformation.core");
|
|
34
34
|
const deployLambdaCode_1 = require("../lambda/deployLambdaCode");
|
|
35
35
|
const getCicdStackName_1 = require("./getCicdStackName");
|
|
36
36
|
const utils_1 = require("../utils");
|
|
@@ -73,7 +73,7 @@ const deployCicdLambdas = async ({ stackName }) => {
|
|
|
73
73
|
};
|
|
74
74
|
const waitRepositoryImageUpdate = async ({ stackName, }) => {
|
|
75
75
|
npmlog_1.default.info(logPrefix, 'Starting repository image update...');
|
|
76
|
-
const { OutputValue: projectName } = await (0,
|
|
76
|
+
const { OutputValue: projectName } = await (0, cloudformation_core_1.getStackOutput)({
|
|
77
77
|
stackName,
|
|
78
78
|
outputKey: cicd_template_1.REPOSITORY_IMAGE_CODE_BUILD_PROJECT_LOGICAL_ID,
|
|
79
79
|
});
|
|
@@ -91,7 +91,7 @@ const deployCicd = async ({ cpu, memory, pipelines, updateRepository, slackWebho
|
|
|
91
91
|
logPrefix,
|
|
92
92
|
stackName: (0, getCicdStackName_1.getCicdStackName)(),
|
|
93
93
|
});
|
|
94
|
-
await (0,
|
|
94
|
+
await (0, cloudformation_core_1.deploy)({
|
|
95
95
|
template: (0, cicd_template_1.getCicdTemplate)({
|
|
96
96
|
cpu,
|
|
97
97
|
memory,
|
|
@@ -112,6 +112,7 @@ const deployCicd = async ({ cpu, memory, pipelines, updateRepository, slackWebho
|
|
|
112
112
|
if (updateRepository) {
|
|
113
113
|
await waitRepositoryImageUpdate({ stackName });
|
|
114
114
|
}
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
115
116
|
}
|
|
116
117
|
catch (error) {
|
|
117
118
|
(0, utils_1.handleDeployError)({ error, logPrefix });
|
|
@@ -26,13 +26,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.destroy = exports.canDestroyStack = exports.deploy = exports.defaultTemplatePaths = exports.enableTerminationProtection = exports.updateStack = exports.createStack = exports.deleteStack = exports.printStackOutputsAfterDeploy = exports.getStackOutput = exports.describeStack = exports.describeStackEvents = exports.doesStackExist = exports.describeStackResource = exports.describeStacks = exports.cloudFormationV2 = exports.
|
|
29
|
+
exports.validateTemplate = exports.destroy = exports.canDestroyStack = exports.deploy = exports.defaultTemplatePaths = exports.enableTerminationProtection = exports.updateStack = exports.createStack = exports.deleteStack = exports.printStackOutputsAfterDeploy = exports.getStackOutput = exports.describeStack = exports.describeStackEvents = exports.doesStackExist = exports.describeStackResource = exports.describeStacks = exports.cloudFormationV2 = exports.cloudformation = void 0;
|
|
30
30
|
const fs = __importStar(require("fs"));
|
|
31
31
|
const path = __importStar(require("path"));
|
|
32
|
+
const config_1 = require("./baseStack/config");
|
|
32
33
|
const client_cloudformation_1 = require("@aws-sdk/client-cloudformation");
|
|
33
34
|
const utils_1 = require("../utils");
|
|
34
|
-
const
|
|
35
|
+
const addDefaults_cloudformation_1 = require("./addDefaults.cloudformation");
|
|
35
36
|
const s3_1 = require("./s3");
|
|
37
|
+
const getBaseStackResource_1 = require("./baseStack/getBaseStackResource");
|
|
36
38
|
const aws_sdk_1 = __importDefault(require("aws-sdk"));
|
|
37
39
|
const npmlog_1 = __importDefault(require("npmlog"));
|
|
38
40
|
const logPrefix = 'cloudformation';
|
|
@@ -52,37 +54,46 @@ const isTemplateBodyGreaterThanMaxSize = (template) => {
|
|
|
52
54
|
* @param input.template: CloudFormation template.
|
|
53
55
|
*/
|
|
54
56
|
const uploadTemplateToBaseStackBucket = async ({ stackName, template, }) => {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// contentType: 'application/json',
|
|
64
|
-
// file: Buffer.from(JSON.stringify(template, null, 2)),
|
|
65
|
-
// key,
|
|
66
|
-
// });
|
|
57
|
+
const bucketName = await (0, getBaseStackResource_1.getBaseStackResource)('BASE_STACK_BUCKET_LOGICAL_NAME');
|
|
58
|
+
const { url } = await (0, s3_1.uploadFileToS3)({
|
|
59
|
+
bucket: bucketName,
|
|
60
|
+
contentType: 'application/json',
|
|
61
|
+
key: `${config_1.BASE_STACK_BUCKET_TEMPLATES_FOLDER}/${stackName}.json`,
|
|
62
|
+
file: Buffer.from(JSON.stringify(template, null, 2)),
|
|
63
|
+
});
|
|
64
|
+
return { url };
|
|
67
65
|
};
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
/**
|
|
67
|
+
* CloudFormation client cache to avoid creating multiple clients.
|
|
68
|
+
* Each client is created with different parameters.
|
|
69
|
+
*/
|
|
70
|
+
const cloudFormationClients = {};
|
|
71
|
+
const cloudformation = () => {
|
|
72
|
+
const cloudFormationClientConfig = {
|
|
70
73
|
apiVersion: '2010-05-15',
|
|
71
74
|
region: (0, utils_1.getEnvVar)('REGION'),
|
|
72
|
-
}
|
|
75
|
+
};
|
|
76
|
+
const key = JSON.stringify(cloudFormationClientConfig);
|
|
77
|
+
if (!cloudFormationClients[key]) {
|
|
78
|
+
cloudFormationClients[key] = new client_cloudformation_1.CloudFormationClient({
|
|
79
|
+
apiVersion: '2010-05-15',
|
|
80
|
+
region: (0, utils_1.getEnvVar)('REGION'),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return cloudFormationClients[key];
|
|
73
84
|
};
|
|
74
|
-
exports.
|
|
85
|
+
exports.cloudformation = cloudformation;
|
|
75
86
|
const cloudFormationV2 = () => {
|
|
76
87
|
return new aws_sdk_1.default.CloudFormation({ apiVersion: '2010-05-15' });
|
|
77
88
|
};
|
|
78
89
|
exports.cloudFormationV2 = cloudFormationV2;
|
|
79
90
|
const describeStacks = async ({ stackName, } = {}) => {
|
|
80
|
-
const { Stacks } = await (0, exports.
|
|
91
|
+
const { Stacks } = await (0, exports.cloudformation)().send(new client_cloudformation_1.DescribeStacksCommand({ StackName: stackName }));
|
|
81
92
|
return Stacks;
|
|
82
93
|
};
|
|
83
94
|
exports.describeStacks = describeStacks;
|
|
84
95
|
const describeStackResource = async (input) => {
|
|
85
|
-
return (0, exports.
|
|
96
|
+
return (0, exports.cloudformation)().send(new client_cloudformation_1.DescribeStackResourceCommand(input));
|
|
86
97
|
};
|
|
87
98
|
exports.describeStackResource = describeStackResource;
|
|
88
99
|
const doesStackExist = async ({ stackName }) => {
|
|
@@ -104,7 +115,7 @@ const doesStackExist = async ({ stackName }) => {
|
|
|
104
115
|
exports.doesStackExist = doesStackExist;
|
|
105
116
|
const describeStackEvents = async ({ stackName, }) => {
|
|
106
117
|
npmlog_1.default.error(logPrefix, 'Stack events:');
|
|
107
|
-
const { StackEvents } = await (0, exports.
|
|
118
|
+
const { StackEvents } = await (0, exports.cloudformation)().send(new client_cloudformation_1.DescribeStackEventsCommand({ StackName: stackName }));
|
|
108
119
|
const events = (StackEvents || [])
|
|
109
120
|
.filter(({ Timestamp }) => {
|
|
110
121
|
return Date.now() - Number(Timestamp) < 10 * 60 * 1000;
|
|
@@ -180,7 +191,7 @@ const printStackOutputsAfterDeploy = async ({ stackName, }) => {
|
|
|
180
191
|
exports.printStackOutputsAfterDeploy = printStackOutputsAfterDeploy;
|
|
181
192
|
const deleteStack = async ({ stackName }) => {
|
|
182
193
|
npmlog_1.default.info(logPrefix, `Deleting stack ${stackName}...`);
|
|
183
|
-
await (0, exports.
|
|
194
|
+
await (0, exports.cloudformation)().send(new client_cloudformation_1.DeleteStackCommand({ StackName: stackName }));
|
|
184
195
|
try {
|
|
185
196
|
await (0, exports.cloudFormationV2)()
|
|
186
197
|
.waitFor('stackDeleteComplete', { StackName: stackName })
|
|
@@ -197,7 +208,7 @@ exports.deleteStack = deleteStack;
|
|
|
197
208
|
const createStack = async ({ params, }) => {
|
|
198
209
|
const { StackName: stackName = '' } = params;
|
|
199
210
|
npmlog_1.default.info(logPrefix, `Creating stack ${stackName}...`);
|
|
200
|
-
await (0, exports.
|
|
211
|
+
await (0, exports.cloudformation)().send(new client_cloudformation_1.CreateStackCommand(params));
|
|
201
212
|
try {
|
|
202
213
|
await (0, exports.cloudFormationV2)()
|
|
203
214
|
.waitFor('stackCreateComplete', { StackName: stackName })
|
|
@@ -216,7 +227,7 @@ const updateStack = async ({ params, }) => {
|
|
|
216
227
|
const { StackName: stackName = '' } = params;
|
|
217
228
|
npmlog_1.default.info(logPrefix, `Updating stack ${stackName}...`);
|
|
218
229
|
try {
|
|
219
|
-
await (0, exports.
|
|
230
|
+
await (0, exports.cloudformation)().send(new client_cloudformation_1.UpdateStackCommand(params));
|
|
220
231
|
await (0, exports.cloudFormationV2)()
|
|
221
232
|
.waitFor('stackUpdateComplete', { StackName: stackName })
|
|
222
233
|
.promise();
|
|
@@ -237,7 +248,7 @@ exports.updateStack = updateStack;
|
|
|
237
248
|
const enableTerminationProtection = async ({ stackName, }) => {
|
|
238
249
|
npmlog_1.default.info(logPrefix, `Enabling termination protection...`);
|
|
239
250
|
try {
|
|
240
|
-
await (0, exports.
|
|
251
|
+
await (0, exports.cloudformation)().send(new client_cloudformation_1.UpdateTerminationProtectionCommand({
|
|
241
252
|
EnableTerminationProtection: true,
|
|
242
253
|
StackName: stackName,
|
|
243
254
|
}));
|
|
@@ -260,7 +271,7 @@ exports.defaultTemplatePaths = ['ts', 'js', 'yaml', 'yml', 'json'].map((extensio
|
|
|
260
271
|
* then stack termination protection will be enabled.
|
|
261
272
|
*/
|
|
262
273
|
const deploy = async ({ terminationProtection = false, ...paramsAndTemplate }) => {
|
|
263
|
-
const { params, template } = await (0,
|
|
274
|
+
const { params, template } = await (0, addDefaults_cloudformation_1.addDefaults)(paramsAndTemplate);
|
|
264
275
|
const stackName = params.StackName;
|
|
265
276
|
if (!stackName) {
|
|
266
277
|
throw new Error('StackName is required');
|
|
@@ -309,7 +320,7 @@ exports.canDestroyStack = canDestroyStack;
|
|
|
309
320
|
const emptyStackBuckets = async ({ stackName }) => {
|
|
310
321
|
const buckets = [];
|
|
311
322
|
await (async ({ nextToken }) => {
|
|
312
|
-
const { NextToken, StackResourceSummaries } = await (0, exports.
|
|
323
|
+
const { NextToken, StackResourceSummaries } = await (0, exports.cloudformation)().send(new client_cloudformation_1.ListStackResourcesCommand({
|
|
313
324
|
StackName: stackName,
|
|
314
325
|
NextToken: nextToken,
|
|
315
326
|
}));
|
|
@@ -351,3 +362,18 @@ const destroy = async ({ stackName }) => {
|
|
|
351
362
|
await (0, exports.deleteStack)({ stackName });
|
|
352
363
|
};
|
|
353
364
|
exports.destroy = destroy;
|
|
365
|
+
const validateTemplate = async ({ stackName, template, }) => {
|
|
366
|
+
const validateTemplateCommandInput = {};
|
|
367
|
+
if (isTemplateBodyGreaterThanMaxSize(template)) {
|
|
368
|
+
const { url } = await uploadTemplateToBaseStackBucket({
|
|
369
|
+
stackName,
|
|
370
|
+
template,
|
|
371
|
+
});
|
|
372
|
+
validateTemplateCommandInput.TemplateURL = url;
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
validateTemplateCommandInput.TemplateBody = JSON.stringify(template);
|
|
376
|
+
}
|
|
377
|
+
await (0, exports.cloudformation)().send(new client_cloudformation_1.ValidateTemplateCommand(validateTemplateCommandInput));
|
|
378
|
+
};
|
|
379
|
+
exports.validateTemplate = validateTemplate;
|
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.destroyCloudFormation = exports.deployCloudFormation = exports.defaultTemplatePaths = void 0;
|
|
7
7
|
const utils_1 = require("../utils");
|
|
8
|
-
const
|
|
8
|
+
const cloudformation_core_1 = require("./cloudformation.core");
|
|
9
9
|
const deployLambdaCode_1 = require("./lambda/deployLambdaCode");
|
|
10
10
|
const s3_1 = require("./s3");
|
|
11
11
|
const cloudformation_1 = require("@ttoss/cloudformation");
|
|
@@ -51,11 +51,7 @@ const deployCloudFormation = async ({ lambdaDockerfile, lambdaInput, lambdaImage
|
|
|
51
51
|
Type: type,
|
|
52
52
|
};
|
|
53
53
|
});
|
|
54
|
-
await (0,
|
|
55
|
-
.validateTemplate({
|
|
56
|
-
TemplateBody: JSON.stringify(cloudFormationTemplate, null, 2),
|
|
57
|
-
})
|
|
58
|
-
.promise();
|
|
54
|
+
await (0, cloudformation_core_1.validateTemplate)({ stackName, template: cloudFormationTemplate });
|
|
59
55
|
const params = {
|
|
60
56
|
StackName: stackName,
|
|
61
57
|
Parameters: parameters?.map((parameter) => {
|
|
@@ -121,11 +117,12 @@ const deployCloudFormation = async ({ lambdaDockerfile, lambdaInput, lambdaImage
|
|
|
121
117
|
}
|
|
122
118
|
};
|
|
123
119
|
await deployCloudFormationDeployLambdaCode();
|
|
124
|
-
const output = await (0,
|
|
120
|
+
const output = await (0, cloudformation_core_1.deploy)({
|
|
125
121
|
params,
|
|
126
122
|
template: cloudFormationTemplate,
|
|
127
123
|
});
|
|
128
124
|
return output;
|
|
125
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
129
126
|
}
|
|
130
127
|
catch (error) {
|
|
131
128
|
return (0, utils_2.handleDeployError)({ error, logPrefix });
|
|
@@ -137,7 +134,7 @@ const emptyStackBuckets = async ({ stackName }) => {
|
|
|
137
134
|
await (async ({ nextToken }) => {
|
|
138
135
|
const {
|
|
139
136
|
// NextToken,
|
|
140
|
-
StackResourceSummaries, } = await (0,
|
|
137
|
+
StackResourceSummaries, } = await (0, cloudformation_core_1.cloudFormationV2)()
|
|
141
138
|
.listStackResources({ StackName: stackName, NextToken: nextToken })
|
|
142
139
|
.promise();
|
|
143
140
|
// if (NextToken) {
|
|
@@ -166,16 +163,16 @@ const destroy = async ({ stackName }) => {
|
|
|
166
163
|
npmlog_1.default.info(logPrefix, `Cannot destroy stack when environment (${environment}) is defined.`);
|
|
167
164
|
return;
|
|
168
165
|
}
|
|
169
|
-
if (!(await (0,
|
|
166
|
+
if (!(await (0, cloudformation_core_1.doesStackExist)({ stackName }))) {
|
|
170
167
|
npmlog_1.default.info(logPrefix, `Stack ${stackName} doesn't exist.`);
|
|
171
168
|
return;
|
|
172
169
|
}
|
|
173
|
-
if (!(await (0,
|
|
170
|
+
if (!(await (0, cloudformation_core_1.canDestroyStack)({ stackName }))) {
|
|
174
171
|
const message = `Stack ${stackName} cannot be destroyed while TerminationProtection is enabled.`;
|
|
175
172
|
throw new Error(message);
|
|
176
173
|
}
|
|
177
174
|
await emptyStackBuckets({ stackName });
|
|
178
|
-
await (0,
|
|
175
|
+
await (0, cloudformation_core_1.deleteStack)({ stackName });
|
|
179
176
|
};
|
|
180
177
|
const destroyCloudFormation = async ({ stackName: defaultStackName, } = {}) => {
|
|
181
178
|
try {
|
|
@@ -183,6 +180,7 @@ const destroyCloudFormation = async ({ stackName: defaultStackName, } = {}) => {
|
|
|
183
180
|
const stackName = defaultStackName || (await (0, stackName_1.getStackName)());
|
|
184
181
|
npmlog_1.default.info(logPrefix, `stackName: ${stackName}`);
|
|
185
182
|
await destroy({ stackName });
|
|
183
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
186
184
|
}
|
|
187
185
|
catch (error) {
|
|
188
186
|
(0, utils_2.handleDeployError)({ error, logPrefix });
|
package/dist/deploy/command.js
CHANGED
|
@@ -7,12 +7,12 @@ exports.deployCommand = exports.examples = exports.options = void 0;
|
|
|
7
7
|
const utils_1 = require("../utils");
|
|
8
8
|
const command_1 = require("./baseStack/command");
|
|
9
9
|
const command_2 = require("./cicd/command");
|
|
10
|
-
const
|
|
10
|
+
const cloudformation_1 = require("./cloudformation");
|
|
11
11
|
const command_3 = require("./lambdaLayer/command");
|
|
12
12
|
const command_4 = require("./staticApp/command");
|
|
13
13
|
const command_5 = require("./vercel/command");
|
|
14
14
|
const stackName_1 = require("./stackName");
|
|
15
|
-
const
|
|
15
|
+
const cloudformation_core_1 = require("./cloudformation.core");
|
|
16
16
|
const readDockerfile_1 = require("./readDockerfile");
|
|
17
17
|
const npmlog_1 = __importDefault(require("npmlog"));
|
|
18
18
|
const logPrefix = 'deploy';
|
|
@@ -40,7 +40,7 @@ const describeDeployCommand = {
|
|
|
40
40
|
handler: async ({ stackName }) => {
|
|
41
41
|
try {
|
|
42
42
|
const newStackName = stackName || (await (0, stackName_1.getStackName)());
|
|
43
|
-
await (0,
|
|
43
|
+
await (0, cloudformation_core_1.printStackOutputsAfterDeploy)({ stackName: newStackName });
|
|
44
44
|
}
|
|
45
45
|
catch (error) {
|
|
46
46
|
npmlog_1.default.info(logPrefix, 'Cannot describe stack. Message: %s', error.message);
|
|
@@ -196,10 +196,10 @@ exports.deployCommand = {
|
|
|
196
196
|
},
|
|
197
197
|
handler: ({ destroy, ...rest }) => {
|
|
198
198
|
if (destroy) {
|
|
199
|
-
(0,
|
|
199
|
+
(0, cloudformation_1.destroyCloudFormation)();
|
|
200
200
|
}
|
|
201
201
|
else {
|
|
202
|
-
(0,
|
|
202
|
+
(0, cloudformation_1.deployCloudFormation)(rest);
|
|
203
203
|
}
|
|
204
204
|
},
|
|
205
205
|
};
|
|
@@ -42,10 +42,22 @@ const buildLambdaSingleFile = async ({ lambdaExternals, lambdaInput, }) => {
|
|
|
42
42
|
},
|
|
43
43
|
bundle: true,
|
|
44
44
|
entryPoints: [path_1.default.resolve(process.cwd(), lambdaInput)],
|
|
45
|
-
external: [
|
|
45
|
+
external: [
|
|
46
|
+
/**
|
|
47
|
+
* Only AWS SDK v3 on Node.js 18.x or higher.
|
|
48
|
+
* https://aws.amazon.com/blogs/compute/node-js-18-x-runtime-now-available-in-aws-lambda/
|
|
49
|
+
*/
|
|
50
|
+
'@aws-sdk/*',
|
|
51
|
+
...builtin_modules_1.default,
|
|
52
|
+
...lambdaExternals,
|
|
53
|
+
],
|
|
54
|
+
/**
|
|
55
|
+
* https://esbuild.github.io/api/#minify
|
|
56
|
+
*/
|
|
57
|
+
minifySyntax: true,
|
|
46
58
|
platform: 'node',
|
|
47
59
|
outfile: path_1.default.join(process.cwd(), outFolder, outFile),
|
|
48
|
-
target: '
|
|
60
|
+
target: 'node20',
|
|
49
61
|
treeShaking: true,
|
|
50
62
|
});
|
|
51
63
|
if (errors.length > 0) {
|
|
@@ -7,7 +7,7 @@ exports.deployLambdaLayer = exports.getLambdaLayerTemplate = void 0;
|
|
|
7
7
|
const utils_1 = require("../../utils");
|
|
8
8
|
const aws_sdk_1 = require("aws-sdk");
|
|
9
9
|
const config_1 = require("../../config");
|
|
10
|
-
const
|
|
10
|
+
const cloudformation_core_1 = require("../cloudformation.core");
|
|
11
11
|
const getBaseStackResource_1 = require("../baseStack/getBaseStackResource");
|
|
12
12
|
const getPackageLambdaLayerStackName_1 = require("./getPackageLambdaLayerStackName");
|
|
13
13
|
const utils_2 = require("../utils");
|
|
@@ -88,7 +88,7 @@ exports.getLambdaLayerTemplate = getLambdaLayerTemplate;
|
|
|
88
88
|
const getPackagesThatAreNotDeployed = async ({ packages, }) => {
|
|
89
89
|
return (await Promise.all(packages.map(async (packageName) => {
|
|
90
90
|
const stackName = (0, getPackageLambdaLayerStackName_1.getPackageLambdaLayerStackName)(packageName);
|
|
91
|
-
return (await (0,
|
|
91
|
+
return (await (0, cloudformation_core_1.doesStackExist)({ stackName })) ? '' : packageName;
|
|
92
92
|
}))).filter((packageName) => {
|
|
93
93
|
return !!packageName;
|
|
94
94
|
});
|
|
@@ -116,11 +116,12 @@ const deployLambdaLayer = async ({ packages, deployIfExists = true, }) => {
|
|
|
116
116
|
bucket,
|
|
117
117
|
key,
|
|
118
118
|
});
|
|
119
|
-
await (0,
|
|
119
|
+
await (0, cloudformation_core_1.deploy)({
|
|
120
120
|
template: lambdaLayerTemplate,
|
|
121
121
|
terminationProtection: true,
|
|
122
122
|
params: { StackName: (0, getPackageLambdaLayerStackName_1.getPackageLambdaLayerStackName)(packageName) },
|
|
123
123
|
});
|
|
124
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
124
125
|
}
|
|
125
126
|
catch (error) {
|
|
126
127
|
(0, utils_2.handleDeployError)({ error, logPrefix });
|
|
@@ -129,6 +130,7 @@ const deployLambdaLayer = async ({ packages, deployIfExists = true, }) => {
|
|
|
129
130
|
await Promise.all(packagesToBeDeployed.map((packageName) => {
|
|
130
131
|
return deployLambdaLayerSinglePackage(packageName);
|
|
131
132
|
}));
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
132
134
|
}
|
|
133
135
|
catch (error) {
|
|
134
136
|
(0, utils_2.handleDeployError)({ error, logPrefix });
|
package/dist/deploy/s3.js
CHANGED
|
@@ -38,6 +38,7 @@ const uploadFileToS3 = async ({ bucket, contentType, file, filePath, key, }) =>
|
|
|
38
38
|
};
|
|
39
39
|
params.Body = Buffer.from(readFile);
|
|
40
40
|
}
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
42
|
const { Bucket, Key, VersionId } = (await exports.s3.upload(params).promise());
|
|
42
43
|
return {
|
|
43
44
|
bucket: Bucket,
|
|
@@ -113,6 +114,7 @@ const uploadDirectoryToS3 = async ({ bucket, bucketKey = '', directory, }) => {
|
|
|
113
114
|
* Divide all files and create "numberOfGroups" groups of files whose max
|
|
114
115
|
* length is GROUP_MAX_LENGTH.
|
|
115
116
|
*/
|
|
117
|
+
// eslint-disable-next-line max-params
|
|
116
118
|
const aoaOfFiles = allFiles.reduce((acc, file, index) => {
|
|
117
119
|
const groupIndex = index % numberOfGroups;
|
|
118
120
|
if (!acc[groupIndex]) {
|
|
@@ -9,7 +9,7 @@ const config_1 = require("../../config");
|
|
|
9
9
|
const utils_1 = require("../../utils");
|
|
10
10
|
const findDefaultBuildFolder_1 = require("./findDefaultBuildFolder");
|
|
11
11
|
const deployStaticApp_1 = require("./deployStaticApp");
|
|
12
|
-
const
|
|
12
|
+
const cloudformation_1 = require("../cloudformation");
|
|
13
13
|
const aws_sdk_1 = __importDefault(require("aws-sdk"));
|
|
14
14
|
exports.options = {
|
|
15
15
|
acm: {
|
|
@@ -41,7 +41,9 @@ exports.options = {
|
|
|
41
41
|
* https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-requirements-limits.html#lambda-requirements-cloudfront-triggers
|
|
42
42
|
*/
|
|
43
43
|
region: {
|
|
44
|
-
coerce: () =>
|
|
44
|
+
coerce: () => {
|
|
45
|
+
return config_1.CLOUDFRONT_REGION;
|
|
46
|
+
},
|
|
45
47
|
default: config_1.CLOUDFRONT_REGION,
|
|
46
48
|
hidden: true,
|
|
47
49
|
type: 'string',
|
|
@@ -61,20 +63,23 @@ exports.options = {
|
|
|
61
63
|
exports.deployStaticAppCommand = {
|
|
62
64
|
command: 'static-app',
|
|
63
65
|
describe: 'Deploy static app.',
|
|
64
|
-
builder: (yargs) =>
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
builder: (yargs) => {
|
|
67
|
+
return (yargs
|
|
68
|
+
.options((0, utils_1.addGroupToOptions)(exports.options, 'Deploy Static App Options'))
|
|
69
|
+
/**
|
|
70
|
+
* CloudFront triggers can be only in US East (N. Virginia) Region.
|
|
71
|
+
* https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-requirements-limits.html#lambda-requirements-cloudfront-triggers
|
|
72
|
+
*/
|
|
73
|
+
.middleware(() => {
|
|
74
|
+
aws_sdk_1.default.config.region = config_1.CLOUDFRONT_REGION;
|
|
75
|
+
}));
|
|
76
|
+
},
|
|
73
77
|
handler: ({ destroy, ...rest }) => {
|
|
74
78
|
if (destroy) {
|
|
75
|
-
(0,
|
|
79
|
+
(0, cloudformation_1.destroyCloudFormation)();
|
|
76
80
|
}
|
|
77
81
|
else {
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
83
|
(0, deployStaticApp_1.deployStaticApp)(rest);
|
|
79
84
|
}
|
|
80
85
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.deployStaticApp = void 0;
|
|
4
|
-
const
|
|
4
|
+
const cloudformation_core_1 = require("../cloudformation.core");
|
|
5
5
|
const getStaticAppBucket_1 = require("./getStaticAppBucket");
|
|
6
6
|
const staticApp_template_1 = require("./staticApp.template");
|
|
7
7
|
const utils_1 = require("../utils");
|
|
@@ -38,7 +38,7 @@ const deployStaticApp = async ({ acm, aliases, buildFolder, cloudfront, spa, hos
|
|
|
38
38
|
if (!skipUpload) {
|
|
39
39
|
await (0, uploadBuiltAppToS3_1.uploadBuiltAppToS3)({ buildFolder, bucket, cloudfront });
|
|
40
40
|
}
|
|
41
|
-
const { Outputs } = await (0,
|
|
41
|
+
const { Outputs } = await (0, cloudformation_core_1.deploy)({ params, template });
|
|
42
42
|
await (0, invalidateCloudFront_1.invalidateCloudFront)({ outputs: Outputs });
|
|
43
43
|
if (!skipUpload) {
|
|
44
44
|
await (0, removeOldVersions_1.removeOldVersions)({ bucket });
|
|
@@ -49,13 +49,14 @@ const deployStaticApp = async ({ acm, aliases, buildFolder, cloudfront, spa, hos
|
|
|
49
49
|
* Stack doesn't exist. Deploy CloudFormation first, get the bucket name,
|
|
50
50
|
* and upload files to S3.
|
|
51
51
|
*/
|
|
52
|
-
await (0,
|
|
52
|
+
await (0, cloudformation_core_1.deploy)({ params, template });
|
|
53
53
|
const newBucket = await (0, getStaticAppBucket_1.getStaticAppBucket)({ stackName });
|
|
54
54
|
if (!newBucket) {
|
|
55
55
|
throw new Error(`Cannot find bucket at ${stackName}.`);
|
|
56
56
|
}
|
|
57
57
|
await (0, uploadBuiltAppToS3_1.uploadBuiltAppToS3)({ buildFolder, bucket: newBucket, cloudfront });
|
|
58
58
|
}
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
60
|
}
|
|
60
61
|
catch (error) {
|
|
61
62
|
(0, utils_1.handleDeployError)({ error, logPrefix });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getStaticAppBucket = void 0;
|
|
4
|
-
const
|
|
4
|
+
const cloudformation_core_1 = require("../cloudformation.core");
|
|
5
5
|
const STATIC_APP_BUCKET_LOGICAL_ID = 'StaticBucket';
|
|
6
6
|
const getStaticAppBucket = async ({ stackName, }) => {
|
|
7
7
|
const params = {
|
|
@@ -9,7 +9,7 @@ const getStaticAppBucket = async ({ stackName, }) => {
|
|
|
9
9
|
StackName: stackName,
|
|
10
10
|
};
|
|
11
11
|
try {
|
|
12
|
-
const { StackResourceDetail } = await (0,
|
|
12
|
+
const { StackResourceDetail } = await (0, cloudformation_core_1.describeStackResource)(params);
|
|
13
13
|
return StackResourceDetail?.PhysicalResourceId;
|
|
14
14
|
}
|
|
15
15
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "carlin",
|
|
3
|
-
"version": "1.31.
|
|
3
|
+
"version": "1.31.8",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"author": "Pedro Arantes <arantespp@gmail.com> (https://twitter.com/arantespp)",
|
|
@@ -22,48 +22,48 @@
|
|
|
22
22
|
"dist/"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@aws-sdk/client-cloudformation": "^3.
|
|
26
|
-
"@octokit/webhooks": "^12.0.
|
|
25
|
+
"@aws-sdk/client-cloudformation": "^3.470.0",
|
|
26
|
+
"@octokit/webhooks": "^12.0.10",
|
|
27
27
|
"@slack/webhook": "^7.0.1",
|
|
28
28
|
"adm-zip": "^0.5.10",
|
|
29
|
-
"aws-sdk": "^2.
|
|
29
|
+
"aws-sdk": "^2.1516.0",
|
|
30
30
|
"builtin-modules": "^3.3.0",
|
|
31
31
|
"change-case": "^4.1.2",
|
|
32
32
|
"deep-equal": "^2.2.3",
|
|
33
33
|
"deepmerge": "^4.3.1",
|
|
34
34
|
"dotenv": "^16.3.1",
|
|
35
|
-
"esbuild": "^0.19.
|
|
35
|
+
"esbuild": "^0.19.9",
|
|
36
36
|
"findup-sync": "^5.0.0",
|
|
37
37
|
"glob": "^10.3.10",
|
|
38
38
|
"js-yaml": "^4.1.0",
|
|
39
39
|
"mime-types": "^2.1.35",
|
|
40
40
|
"npmlog": "^7.0.1",
|
|
41
|
-
"prettier": "^3.1.
|
|
41
|
+
"prettier": "^3.1.1",
|
|
42
42
|
"semver": "^7.5.4",
|
|
43
43
|
"simple-git": "^3.21.0",
|
|
44
|
-
"ts-node": "^10.9.
|
|
44
|
+
"ts-node": "^10.9.2",
|
|
45
45
|
"uglify-js": "^3.17.4",
|
|
46
|
-
"vercel": "^32.
|
|
46
|
+
"vercel": "^32.7.0",
|
|
47
47
|
"yargs": "^17.7.2",
|
|
48
|
-
"@ttoss/cloudformation": "^0.8.
|
|
48
|
+
"@ttoss/cloudformation": "^0.8.7"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/adm-zip": "^0.5.5",
|
|
52
|
-
"@types/aws-lambda": "^8.10.
|
|
52
|
+
"@types/aws-lambda": "^8.10.130",
|
|
53
53
|
"@types/deep-equal": "^1.0.4",
|
|
54
54
|
"@types/findup-sync": "^4.0.4",
|
|
55
55
|
"@types/glob": "^8.1.0",
|
|
56
|
-
"@types/jest": "^29.5.
|
|
56
|
+
"@types/jest": "^29.5.11",
|
|
57
57
|
"@types/js-yaml": "^4.0.9",
|
|
58
58
|
"@types/mime-types": "^2.1.4",
|
|
59
|
-
"@types/node": "^20.10.
|
|
59
|
+
"@types/node": "^20.10.4",
|
|
60
60
|
"@types/npmlog": "^7.0.0",
|
|
61
61
|
"@types/semver": "^7.5.6",
|
|
62
62
|
"@types/uglify-js": "^3.17.4",
|
|
63
63
|
"@types/yargs": "^17.0.32",
|
|
64
64
|
"jest": "^29.7.0",
|
|
65
65
|
"typescript": "~5.2.2",
|
|
66
|
-
"@ttoss/test-utils": "^2.0.
|
|
66
|
+
"@ttoss/test-utils": "^2.0.4"
|
|
67
67
|
},
|
|
68
68
|
"keywords": [],
|
|
69
69
|
"publishConfig": {
|
|
File without changes
|
|
File without changes
|
package/dist/deploy/baseStack/{getLambdaImageBuilder.template.js → getLambdaImageBuilderTemplate.js}
RENAMED
|
@@ -4,9 +4,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getLambdaImageBuilderTemplate = void 0;
|
|
7
|
-
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
8
|
-
const utils_1 = require("../../utils");
|
|
9
7
|
const config_1 = require("./config");
|
|
8
|
+
const utils_1 = require("../../utils");
|
|
9
|
+
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
10
10
|
const getLambdaImageBuilderTemplate = () => {
|
|
11
11
|
const CODE_BUILD_PROJECT_LOGS_LOGICAL_ID = 'CodeBuildProjectLogsLogGroup';
|
|
12
12
|
const CODE_BUILD_PROJECT_SERVICE_ROLE_LOGICAL_ID = 'ImageCodeBuildProjectIAMRole';
|
|
File without changes
|