@awsless/awsless 0.0.15 → 0.0.16
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/README.MD +6 -0
- package/dist/bin.cjs +1488 -295
- package/dist/bin.js +1474 -281
- package/dist/index.d.ts +493 -13
- package/package.json +1 -1
package/dist/bin.cjs
CHANGED
|
@@ -77,7 +77,7 @@ var flushDebug = () => {
|
|
|
77
77
|
// src/util/param.ts
|
|
78
78
|
var import_client_ssm = require("@aws-sdk/client-ssm");
|
|
79
79
|
var configParameterPrefix = (config) => {
|
|
80
|
-
return
|
|
80
|
+
return `/.awsless/${config.name}`;
|
|
81
81
|
};
|
|
82
82
|
var Params = class {
|
|
83
83
|
constructor(config) {
|
|
@@ -158,8 +158,18 @@ var Params = class {
|
|
|
158
158
|
}
|
|
159
159
|
};
|
|
160
160
|
|
|
161
|
-
// src/formation/
|
|
161
|
+
// src/formation/asset.ts
|
|
162
162
|
var import_change_case = require("change-case");
|
|
163
|
+
var Asset = class {
|
|
164
|
+
constructor(type, id) {
|
|
165
|
+
this.type = type;
|
|
166
|
+
this.id = (0, import_change_case.paramCase)(id);
|
|
167
|
+
}
|
|
168
|
+
id;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// src/formation/util.ts
|
|
172
|
+
var import_change_case2 = require("change-case");
|
|
163
173
|
var ref = (logicalId) => {
|
|
164
174
|
return { Ref: logicalId };
|
|
165
175
|
};
|
|
@@ -176,10 +186,10 @@ var importValue = (name) => {
|
|
|
176
186
|
return { "Fn::ImportValue": name };
|
|
177
187
|
};
|
|
178
188
|
var formatLogicalId = (id) => {
|
|
179
|
-
return (0,
|
|
189
|
+
return (0, import_change_case2.pascalCase)(id).replaceAll("_", "");
|
|
180
190
|
};
|
|
181
191
|
var formatName = (name) => {
|
|
182
|
-
return (0,
|
|
192
|
+
return (0, import_change_case2.paramCase)(name);
|
|
183
193
|
};
|
|
184
194
|
|
|
185
195
|
// src/formation/resource.ts
|
|
@@ -315,11 +325,11 @@ var Function = class extends Resource {
|
|
|
315
325
|
});
|
|
316
326
|
role.addInlinePolicy(policy);
|
|
317
327
|
role.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName("AWSLambdaBasicExecutionRole"));
|
|
318
|
-
super("AWS::Lambda::Function", logicalId, [
|
|
319
|
-
role,
|
|
320
|
-
props.code
|
|
321
|
-
]);
|
|
328
|
+
super("AWS::Lambda::Function", logicalId, [role]);
|
|
322
329
|
this.props = props;
|
|
330
|
+
if (props.code instanceof Asset) {
|
|
331
|
+
this.children.push(props.code);
|
|
332
|
+
}
|
|
323
333
|
this.dependsOn(role);
|
|
324
334
|
this.role = role;
|
|
325
335
|
this.policy = policy;
|
|
@@ -372,16 +382,6 @@ var Function = class extends Resource {
|
|
|
372
382
|
}
|
|
373
383
|
};
|
|
374
384
|
|
|
375
|
-
// src/formation/asset.ts
|
|
376
|
-
var import_change_case2 = require("change-case");
|
|
377
|
-
var Asset = class {
|
|
378
|
-
constructor(type, id) {
|
|
379
|
-
this.type = type;
|
|
380
|
-
this.id = (0, import_change_case2.paramCase)(id);
|
|
381
|
-
}
|
|
382
|
-
id;
|
|
383
|
-
};
|
|
384
|
-
|
|
385
385
|
// src/formation/stack.ts
|
|
386
386
|
var Stack = class {
|
|
387
387
|
constructor(name, region) {
|
|
@@ -406,10 +406,16 @@ var Stack = class {
|
|
|
406
406
|
return this;
|
|
407
407
|
}
|
|
408
408
|
export(name, value) {
|
|
409
|
-
|
|
410
|
-
this.exports.set(name, value);
|
|
409
|
+
this.exports.set(formatName(name), value);
|
|
411
410
|
return this;
|
|
412
411
|
}
|
|
412
|
+
get(name) {
|
|
413
|
+
name = formatName(name);
|
|
414
|
+
if (!this.exports.has(name)) {
|
|
415
|
+
throw new Error(`Undefined export value: ${name}`);
|
|
416
|
+
}
|
|
417
|
+
return this.exports.get(name);
|
|
418
|
+
}
|
|
413
419
|
import(name) {
|
|
414
420
|
name = formatName(name);
|
|
415
421
|
if (!this.exports.has(name)) {
|
|
@@ -820,55 +826,24 @@ var zipFiles = (files) => {
|
|
|
820
826
|
};
|
|
821
827
|
|
|
822
828
|
// src/formation/resource/lambda/code.ts
|
|
823
|
-
var import_crypto2 = require("crypto");
|
|
824
829
|
var Code = class {
|
|
825
830
|
static fromFile(id, file, bundler) {
|
|
826
831
|
return new FileCode(id, file, bundler);
|
|
827
832
|
}
|
|
828
|
-
static fromInline(
|
|
829
|
-
return new InlineCode(
|
|
833
|
+
static fromInline(code, handler) {
|
|
834
|
+
return new InlineCode(code, handler);
|
|
830
835
|
}
|
|
831
836
|
};
|
|
832
|
-
var InlineCode = class
|
|
833
|
-
constructor(
|
|
834
|
-
super("function", id);
|
|
837
|
+
var InlineCode = class {
|
|
838
|
+
constructor(code, handler = "index.default") {
|
|
835
839
|
this.code = code;
|
|
836
840
|
this.handler = handler;
|
|
837
841
|
}
|
|
838
|
-
hash;
|
|
839
|
-
bundle;
|
|
840
|
-
s3;
|
|
841
|
-
async build({ write }) {
|
|
842
|
-
const hash = (0, import_crypto2.createHash)("sha1").update(this.code).digest("hex");
|
|
843
|
-
const bundle = await zipFiles([{
|
|
844
|
-
name: "index.js",
|
|
845
|
-
code: this.code
|
|
846
|
-
}]);
|
|
847
|
-
await Promise.all([
|
|
848
|
-
write("HASH", hash),
|
|
849
|
-
write("bundle.zip", bundle),
|
|
850
|
-
write("files/inline.js", this.code)
|
|
851
|
-
]);
|
|
852
|
-
this.bundle = bundle;
|
|
853
|
-
this.hash = hash;
|
|
854
|
-
return {
|
|
855
|
-
size: formatByteSize(bundle.byteLength)
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
|
-
async publish({ publish }) {
|
|
859
|
-
this.s3 = await publish(
|
|
860
|
-
`${this.id}.zip`,
|
|
861
|
-
this.bundle,
|
|
862
|
-
this.hash
|
|
863
|
-
);
|
|
864
|
-
}
|
|
865
842
|
toCodeJson() {
|
|
866
843
|
return {
|
|
867
844
|
Handler: this.handler,
|
|
868
845
|
Code: {
|
|
869
|
-
|
|
870
|
-
S3Key: this.s3.key,
|
|
871
|
-
S3ObjectVersion: this.s3.version
|
|
846
|
+
ZipFile: this.code
|
|
872
847
|
}
|
|
873
848
|
};
|
|
874
849
|
}
|
|
@@ -919,6 +894,44 @@ var FileCode = class extends Asset {
|
|
|
919
894
|
}
|
|
920
895
|
};
|
|
921
896
|
|
|
897
|
+
// src/formation/resource/lambda/event-invoke-config.ts
|
|
898
|
+
var EventInvokeConfig = class extends Resource {
|
|
899
|
+
constructor(logicalId, props) {
|
|
900
|
+
super("AWS::Lambda::EventInvokeConfig", logicalId);
|
|
901
|
+
this.props = props;
|
|
902
|
+
}
|
|
903
|
+
setOnFailure(arn) {
|
|
904
|
+
this.props.onFailure = arn;
|
|
905
|
+
return this;
|
|
906
|
+
}
|
|
907
|
+
setOnSuccess(arn) {
|
|
908
|
+
this.props.onSuccess = arn;
|
|
909
|
+
return this;
|
|
910
|
+
}
|
|
911
|
+
properties() {
|
|
912
|
+
return {
|
|
913
|
+
FunctionName: this.props.functionName,
|
|
914
|
+
Qualifier: this.props.qualifier || "$LATEST",
|
|
915
|
+
...this.attr("MaximumEventAgeInSeconds", this.props.maxEventAge?.toSeconds()),
|
|
916
|
+
...this.attr("MaximumRetryAttempts", this.props.retryAttempts),
|
|
917
|
+
...this.props.onFailure || this.props.onSuccess ? {
|
|
918
|
+
DestinationConfig: {
|
|
919
|
+
...this.props.onFailure ? {
|
|
920
|
+
OnFailure: {
|
|
921
|
+
Destination: this.props.onFailure
|
|
922
|
+
}
|
|
923
|
+
} : {},
|
|
924
|
+
...this.props.onSuccess ? {
|
|
925
|
+
OnSuccess: {
|
|
926
|
+
Destination: this.props.onSuccess
|
|
927
|
+
}
|
|
928
|
+
} : {}
|
|
929
|
+
}
|
|
930
|
+
} : {}
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
|
|
922
935
|
// src/plugins/function.ts
|
|
923
936
|
var MemorySizeSchema = SizeSchema.refine(sizeMin(Size.megaBytes(128)), "Minimum memory size is 128 MB").refine(sizeMax(Size.gigaBytes(10)), "Minimum memory size is 10 GB");
|
|
924
937
|
var TimeoutSchema = DurationSchema.refine(durationMin(Duration.seconds(10)), "Minimum timeout duration is 10 seconds").refine(durationMax(Duration.minutes(15)), "Maximum timeout duration is 15 minutes");
|
|
@@ -933,29 +946,104 @@ var RuntimeSchema = import_zod6.z.enum([
|
|
|
933
946
|
var FunctionSchema = import_zod6.z.union([
|
|
934
947
|
LocalFileSchema,
|
|
935
948
|
import_zod6.z.object({
|
|
949
|
+
/** The file path ofthe function code. */
|
|
936
950
|
file: LocalFileSchema,
|
|
951
|
+
/** The amount of time that Lambda allows a function to run before stopping it.
|
|
952
|
+
* You can specify a size value from 1 second to 15 minutes.
|
|
953
|
+
* @default '10 seconds'
|
|
954
|
+
*/
|
|
937
955
|
timeout: TimeoutSchema.optional(),
|
|
956
|
+
/** The identifier of the function's runtime.
|
|
957
|
+
* @default 'nodejs18.x'
|
|
958
|
+
*/
|
|
938
959
|
runtime: RuntimeSchema.optional(),
|
|
960
|
+
/** The amount of memory available to the function at runtime.
|
|
961
|
+
* Increasing the function memory also increases its CPU allocation.
|
|
962
|
+
* The value can be any multiple of 1 MB.
|
|
963
|
+
* You can specify a size value from 128 MB to 10 GB.
|
|
964
|
+
* @default '128 MB'
|
|
965
|
+
*/
|
|
939
966
|
memorySize: MemorySizeSchema.optional(),
|
|
967
|
+
/** The instruction set architecture that the function supports.
|
|
968
|
+
* @default 'arm64'
|
|
969
|
+
*/
|
|
940
970
|
architecture: ArchitectureSchema.optional(),
|
|
971
|
+
/** The size of the function's /tmp directory.
|
|
972
|
+
* You can specify a size value from 512 MB to 10 GB.
|
|
973
|
+
* @default 512 MB
|
|
974
|
+
*/
|
|
941
975
|
ephemeralStorageSize: EphemeralStorageSizeSchema.optional(),
|
|
976
|
+
/** The maximum number of times to retry when the function returns an error.
|
|
977
|
+
* You can specify a number from 0 to 2.
|
|
978
|
+
* @default 2
|
|
979
|
+
*/
|
|
942
980
|
retryAttempts: RetryAttemptsSchema.optional(),
|
|
981
|
+
/** Environment variable key-value pairs.
|
|
982
|
+
* @example
|
|
983
|
+
* {
|
|
984
|
+
* environment: {
|
|
985
|
+
* name: 'value'
|
|
986
|
+
* }
|
|
987
|
+
* }
|
|
988
|
+
*/
|
|
943
989
|
environment: EnvironmentSchema.optional()
|
|
990
|
+
// onFailure: ResourceIdSchema.optional(),
|
|
944
991
|
})
|
|
945
992
|
]);
|
|
946
993
|
var schema = import_zod6.z.object({
|
|
947
994
|
defaults: import_zod6.z.object({
|
|
948
995
|
function: import_zod6.z.object({
|
|
996
|
+
/** The amount of time that Lambda allows a function to run before stopping it.
|
|
997
|
+
* You can specify a size value from 1 second to 15 minutes.
|
|
998
|
+
* @default '10 seconds'
|
|
999
|
+
*/
|
|
949
1000
|
timeout: TimeoutSchema.default("10 seconds"),
|
|
1001
|
+
/** The identifier of the function's runtime.
|
|
1002
|
+
* @default 'nodejs18.x'
|
|
1003
|
+
*/
|
|
950
1004
|
runtime: RuntimeSchema.default("nodejs18.x"),
|
|
1005
|
+
/** The amount of memory available to the function at runtime.
|
|
1006
|
+
* Increasing the function memory also increases its CPU allocation.
|
|
1007
|
+
* The value can be any multiple of 1 MB.
|
|
1008
|
+
* You can specify a size value from 128 MB to 10 GB.
|
|
1009
|
+
* @default '128 MB'
|
|
1010
|
+
*/
|
|
951
1011
|
memorySize: MemorySizeSchema.default("128 MB"),
|
|
1012
|
+
/** The instruction set architecture that the function supports.
|
|
1013
|
+
* @default 'arm64'
|
|
1014
|
+
*/
|
|
952
1015
|
architecture: ArchitectureSchema.default("arm64"),
|
|
1016
|
+
/** The size of the function's /tmp directory.
|
|
1017
|
+
* You can specify a size value from 512 MB to 10 GB.
|
|
1018
|
+
* @default 512 MB
|
|
1019
|
+
*/
|
|
953
1020
|
ephemeralStorageSize: EphemeralStorageSizeSchema.default("512 MB"),
|
|
1021
|
+
/** The maximum number of times to retry when the function returns an error.
|
|
1022
|
+
* You can specify a number from 0 to 2.
|
|
1023
|
+
* @default 2
|
|
1024
|
+
*/
|
|
954
1025
|
retryAttempts: RetryAttemptsSchema.default(2),
|
|
1026
|
+
/** Environment variable key-value pairs.
|
|
1027
|
+
* @example
|
|
1028
|
+
* {
|
|
1029
|
+
* environment: {
|
|
1030
|
+
* name: 'value'
|
|
1031
|
+
* }
|
|
1032
|
+
* }
|
|
1033
|
+
*/
|
|
955
1034
|
environment: EnvironmentSchema.optional()
|
|
1035
|
+
// onFailure: ResourceIdSchema.optional(),
|
|
956
1036
|
}).default({})
|
|
957
1037
|
}).default({}),
|
|
958
1038
|
stacks: import_zod6.z.object({
|
|
1039
|
+
/** Define the functions in your stack.
|
|
1040
|
+
* @example
|
|
1041
|
+
* {
|
|
1042
|
+
* functions: {
|
|
1043
|
+
* FUNCTION_NAME: 'function.ts'
|
|
1044
|
+
* }
|
|
1045
|
+
* }
|
|
1046
|
+
*/
|
|
959
1047
|
functions: import_zod6.z.record(
|
|
960
1048
|
ResourceIdSchema,
|
|
961
1049
|
FunctionSchema
|
|
@@ -981,12 +1069,15 @@ var toLambdaFunction = (ctx, id, fileOrProps) => {
|
|
|
981
1069
|
code: Code.fromFile(id, props.file),
|
|
982
1070
|
...props
|
|
983
1071
|
});
|
|
984
|
-
lambda.addEnvironment("APP", config.name);
|
|
985
|
-
lambda.addEnvironment("STAGE", config.stage);
|
|
986
|
-
lambda.addEnvironment("STACK", stack.name);
|
|
1072
|
+
lambda.addEnvironment("APP", config.name).addEnvironment("STAGE", config.stage).addEnvironment("STACK", stack.name);
|
|
987
1073
|
if (props.runtime.startsWith("nodejs")) {
|
|
988
1074
|
lambda.addEnvironment("AWS_NODEJS_CONNECTION_REUSE_ENABLED", "1");
|
|
989
1075
|
}
|
|
1076
|
+
const invoke = new EventInvokeConfig(id, {
|
|
1077
|
+
functionName: lambda.name,
|
|
1078
|
+
retryAttempts: props.retryAttempts
|
|
1079
|
+
}).dependsOn(lambda);
|
|
1080
|
+
ctx.stack.add(invoke);
|
|
990
1081
|
return lambda;
|
|
991
1082
|
};
|
|
992
1083
|
|
|
@@ -1064,9 +1155,26 @@ var cronPlugin = definePlugin({
|
|
|
1064
1155
|
name: "cron",
|
|
1065
1156
|
schema: import_zod7.z.object({
|
|
1066
1157
|
stacks: import_zod7.z.object({
|
|
1158
|
+
/** Define the crons in your stack
|
|
1159
|
+
* @example
|
|
1160
|
+
* {
|
|
1161
|
+
* crons: {
|
|
1162
|
+
* CRON_NAME: {
|
|
1163
|
+
* consumer: 'function.ts',
|
|
1164
|
+
* schedule: 'rate(5 minutes)',
|
|
1165
|
+
* }
|
|
1166
|
+
* }
|
|
1167
|
+
* }
|
|
1168
|
+
* */
|
|
1067
1169
|
crons: import_zod7.z.record(ResourceIdSchema, import_zod7.z.object({
|
|
1170
|
+
/** The consuming lambda function properties */
|
|
1068
1171
|
consumer: FunctionSchema,
|
|
1172
|
+
/** The scheduling expression.
|
|
1173
|
+
* @example 'cron(0 20 * * ? *)'
|
|
1174
|
+
* @example 'rate(5 minutes)'
|
|
1175
|
+
*/
|
|
1069
1176
|
schedule: ScheduleExpressionSchema,
|
|
1177
|
+
// Valid JSON passed to the consumer.
|
|
1070
1178
|
payload: import_zod7.z.unknown().optional()
|
|
1071
1179
|
})).optional()
|
|
1072
1180
|
}).array()
|
|
@@ -1095,6 +1203,10 @@ var Queue = class extends Resource {
|
|
|
1095
1203
|
this.name = formatName(this.props.name || logicalId);
|
|
1096
1204
|
}
|
|
1097
1205
|
name;
|
|
1206
|
+
setDeadLetter(arn) {
|
|
1207
|
+
this.props.deadLetterArn = arn;
|
|
1208
|
+
return this;
|
|
1209
|
+
}
|
|
1098
1210
|
get arn() {
|
|
1099
1211
|
return getAtt(this.logicalId, "Arn");
|
|
1100
1212
|
}
|
|
@@ -1119,7 +1231,12 @@ var Queue = class extends Resource {
|
|
|
1119
1231
|
MaximumMessageSize: this.props.maxMessageSize?.toBytes() ?? Size.kiloBytes(256).toBytes(),
|
|
1120
1232
|
MessageRetentionPeriod: this.props.retentionPeriod?.toSeconds() ?? Duration.days(4).toSeconds(),
|
|
1121
1233
|
ReceiveMessageWaitTimeSeconds: this.props.receiveMessageWaitTime?.toSeconds() ?? 0,
|
|
1122
|
-
VisibilityTimeout: this.props.visibilityTimeout?.toSeconds() ?? 30
|
|
1234
|
+
VisibilityTimeout: this.props.visibilityTimeout?.toSeconds() ?? 30,
|
|
1235
|
+
...this.props.deadLetterArn ? {
|
|
1236
|
+
RedrivePolicy: {
|
|
1237
|
+
deadLetterTargetArn: this.props.deadLetterArn
|
|
1238
|
+
}
|
|
1239
|
+
} : {}
|
|
1123
1240
|
};
|
|
1124
1241
|
}
|
|
1125
1242
|
};
|
|
@@ -1131,6 +1248,10 @@ var EventSourceMapping = class extends Resource {
|
|
|
1131
1248
|
super("AWS::Lambda::EventSourceMapping", logicalId);
|
|
1132
1249
|
this.props = props;
|
|
1133
1250
|
}
|
|
1251
|
+
setOnFailure(arn) {
|
|
1252
|
+
this.props.onFailure = arn;
|
|
1253
|
+
return this;
|
|
1254
|
+
}
|
|
1134
1255
|
properties() {
|
|
1135
1256
|
return {
|
|
1136
1257
|
Enabled: true,
|
|
@@ -1189,7 +1310,7 @@ var queuePlugin = definePlugin({
|
|
|
1189
1310
|
name: "queue",
|
|
1190
1311
|
schema: import_zod8.z.object({
|
|
1191
1312
|
defaults: import_zod8.z.object({
|
|
1192
|
-
/** Define the defaults properties for all queue's in your app */
|
|
1313
|
+
/** Define the defaults properties for all queue's in your app. */
|
|
1193
1314
|
queue: import_zod8.z.object({
|
|
1194
1315
|
/** The number of seconds that Amazon SQS retains a message.
|
|
1195
1316
|
* You can specify a duration value from 1 minute to 14 days.
|
|
@@ -1218,20 +1339,20 @@ var queuePlugin = definePlugin({
|
|
|
1218
1339
|
}).default({})
|
|
1219
1340
|
}).default({}),
|
|
1220
1341
|
stacks: import_zod8.z.object({
|
|
1221
|
-
/** Define the queues in your stack
|
|
1342
|
+
/** Define the queues in your stack.
|
|
1222
1343
|
* @example
|
|
1223
1344
|
* {
|
|
1224
1345
|
* queues: {
|
|
1225
1346
|
* QUEUE_NAME: 'function.ts'
|
|
1226
1347
|
* }
|
|
1227
1348
|
* }
|
|
1228
|
-
|
|
1349
|
+
*/
|
|
1229
1350
|
queues: import_zod8.z.record(
|
|
1230
1351
|
ResourceIdSchema,
|
|
1231
1352
|
import_zod8.z.union([
|
|
1232
1353
|
LocalFileSchema,
|
|
1233
1354
|
import_zod8.z.object({
|
|
1234
|
-
/** The consuming lambda function properties */
|
|
1355
|
+
/** The consuming lambda function properties. */
|
|
1235
1356
|
consumer: FunctionSchema,
|
|
1236
1357
|
/** The number of seconds that Amazon SQS retains a message.
|
|
1237
1358
|
* You can specify a duration value from 1 minute to 14 days.
|
|
@@ -1249,7 +1370,6 @@ var queuePlugin = definePlugin({
|
|
|
1249
1370
|
/** Specifies the duration, in seconds,
|
|
1250
1371
|
* that the ReceiveMessage action call waits until a message is in the queue in order to include it in the response,
|
|
1251
1372
|
* rather than returning an empty response if a message isn't yet available.
|
|
1252
|
-
* You can specify an integer from 1 to 20.
|
|
1253
1373
|
* You can specify a duration value from 1 to 20 seconds.
|
|
1254
1374
|
* @default '0 seconds' */
|
|
1255
1375
|
receiveMessageWaitTime: DurationSchema.optional(),
|
|
@@ -1270,7 +1390,7 @@ var queuePlugin = definePlugin({
|
|
|
1270
1390
|
name: `${config.name}-${stack.name}-${id}`,
|
|
1271
1391
|
...props
|
|
1272
1392
|
});
|
|
1273
|
-
const lambda = toLambdaFunction(ctx, id
|
|
1393
|
+
const lambda = toLambdaFunction(ctx, `queue-${id}`, props.consumer);
|
|
1274
1394
|
const source = new SqsEventSource(id, lambda, {
|
|
1275
1395
|
queueArn: queue2.arn
|
|
1276
1396
|
});
|
|
@@ -1296,12 +1416,21 @@ var Table = class extends Resource {
|
|
|
1296
1416
|
}
|
|
1297
1417
|
name;
|
|
1298
1418
|
indexes;
|
|
1419
|
+
enableStream(viewType) {
|
|
1420
|
+
this.props.stream = viewType;
|
|
1421
|
+
}
|
|
1299
1422
|
addIndex(name, props) {
|
|
1300
1423
|
this.indexes[name] = props;
|
|
1301
1424
|
}
|
|
1302
|
-
get
|
|
1425
|
+
get id() {
|
|
1303
1426
|
return ref(this.logicalId);
|
|
1304
1427
|
}
|
|
1428
|
+
get arn() {
|
|
1429
|
+
return getAtt(this.logicalId, "Arn");
|
|
1430
|
+
}
|
|
1431
|
+
get streamArn() {
|
|
1432
|
+
return getAtt(this.logicalId, "StreamArn");
|
|
1433
|
+
}
|
|
1305
1434
|
get permissions() {
|
|
1306
1435
|
return {
|
|
1307
1436
|
actions: [
|
|
@@ -1335,6 +1464,11 @@ var Table = class extends Resource {
|
|
|
1335
1464
|
AttributeName: name,
|
|
1336
1465
|
AttributeType: type[0].toUpperCase()
|
|
1337
1466
|
})),
|
|
1467
|
+
...this.props.stream ? {
|
|
1468
|
+
StreamSpecification: {
|
|
1469
|
+
StreamViewType: (0, import_change_case4.constantCase)(this.props.stream)
|
|
1470
|
+
}
|
|
1471
|
+
} : {},
|
|
1338
1472
|
...this.props.timeToLiveAttribute ? {
|
|
1339
1473
|
TimeToLiveSpecification: {
|
|
1340
1474
|
AttributeName: this.props.timeToLiveAttribute,
|
|
@@ -1357,13 +1491,42 @@ var Table = class extends Resource {
|
|
|
1357
1491
|
}
|
|
1358
1492
|
};
|
|
1359
1493
|
|
|
1494
|
+
// src/formation/resource/lambda/event-source/dynamodb.ts
|
|
1495
|
+
var DynamoDBEventSource = class extends Group {
|
|
1496
|
+
constructor(id, lambda, props) {
|
|
1497
|
+
const source = new EventSourceMapping(id, {
|
|
1498
|
+
functionArn: lambda.arn,
|
|
1499
|
+
sourceArn: props.tableArn,
|
|
1500
|
+
batchSize: props.batchSize ?? 100,
|
|
1501
|
+
bisectBatchOnError: props.bisectBatchOnError ?? true,
|
|
1502
|
+
maxBatchingWindow: props.maxBatchingWindow,
|
|
1503
|
+
maxRecordAge: props.maxRecordAge,
|
|
1504
|
+
retryAttempts: props.retryAttempts ?? -1,
|
|
1505
|
+
parallelizationFactor: props.parallelizationFactor ?? 1,
|
|
1506
|
+
startingPosition: props.startingPosition,
|
|
1507
|
+
startingPositionTimestamp: props.startingPositionTimestamp,
|
|
1508
|
+
tumblingWindow: props.tumblingWindow
|
|
1509
|
+
});
|
|
1510
|
+
lambda.addPermissions({
|
|
1511
|
+
actions: [
|
|
1512
|
+
"dynamodb:ListStreams",
|
|
1513
|
+
"dynamodb:DescribeStream",
|
|
1514
|
+
"dynamodb:GetRecords",
|
|
1515
|
+
"dynamodb:GetShardIterator"
|
|
1516
|
+
],
|
|
1517
|
+
resources: [props.tableArn]
|
|
1518
|
+
});
|
|
1519
|
+
super([source]);
|
|
1520
|
+
}
|
|
1521
|
+
};
|
|
1522
|
+
|
|
1360
1523
|
// src/plugins/table.ts
|
|
1361
1524
|
var KeySchema = import_zod9.z.string().min(1).max(255);
|
|
1362
1525
|
var tablePlugin = definePlugin({
|
|
1363
1526
|
name: "table",
|
|
1364
1527
|
schema: import_zod9.z.object({
|
|
1365
1528
|
stacks: import_zod9.z.object({
|
|
1366
|
-
/** Define the tables in your stack
|
|
1529
|
+
/** Define the tables in your stack.
|
|
1367
1530
|
* @example
|
|
1368
1531
|
* {
|
|
1369
1532
|
* tables: {
|
|
@@ -1390,20 +1553,34 @@ var tablePlugin = definePlugin({
|
|
|
1390
1553
|
* id: 'string'
|
|
1391
1554
|
* }
|
|
1392
1555
|
* }
|
|
1393
|
-
|
|
1556
|
+
*/
|
|
1394
1557
|
fields: import_zod9.z.record(import_zod9.z.string(), import_zod9.z.enum(["string", "number", "binary"])),
|
|
1395
1558
|
/** The table class of the table.
|
|
1396
1559
|
* @default 'standard'
|
|
1397
|
-
|
|
1560
|
+
*/
|
|
1398
1561
|
class: import_zod9.z.enum(["standard", "standard-infrequent-access"]).default("standard"),
|
|
1399
1562
|
/** Indicates whether point in time recovery is enabled on the table.
|
|
1400
1563
|
* @default false
|
|
1401
|
-
|
|
1564
|
+
*/
|
|
1402
1565
|
pointInTimeRecovery: import_zod9.z.boolean().default(false),
|
|
1403
1566
|
/** The name of the TTL attribute used to store the expiration time for items in the table.
|
|
1404
1567
|
* - To update this property, you must first disable TTL and then enable TTL with the new attribute name.
|
|
1405
|
-
|
|
1568
|
+
*/
|
|
1406
1569
|
timeToLiveAttribute: KeySchema.optional(),
|
|
1570
|
+
/** The settings for the DynamoDB table stream, which capture changes to items stored in the table. */
|
|
1571
|
+
stream: import_zod9.z.object({
|
|
1572
|
+
/** When an item in the table is modified,
|
|
1573
|
+
* stream.type determines what information is written to the stream for this table.
|
|
1574
|
+
* Valid values are:
|
|
1575
|
+
* - keys-only - Only the key attributes of the modified item are written to the stream.
|
|
1576
|
+
* - new-image - The entire item, as it appears after it was modified, is written to the stream.
|
|
1577
|
+
* - old-image - The entire item, as it appeared before it was modified, is written to the stream.
|
|
1578
|
+
* - new-and-old-images - Both the new and the old item images of the item are written to the stream.
|
|
1579
|
+
*/
|
|
1580
|
+
type: import_zod9.z.enum(["keys-only", "new-image", "old-image", "new-and-old-images"]),
|
|
1581
|
+
/** The consuming lambda function for the stream */
|
|
1582
|
+
consumer: FunctionSchema
|
|
1583
|
+
}).optional(),
|
|
1407
1584
|
/** Specifies the global secondary indexes to be created on the table.
|
|
1408
1585
|
* @example
|
|
1409
1586
|
* {
|
|
@@ -1413,7 +1590,7 @@ var tablePlugin = definePlugin({
|
|
|
1413
1590
|
* }
|
|
1414
1591
|
* }
|
|
1415
1592
|
* }
|
|
1416
|
-
|
|
1593
|
+
*/
|
|
1417
1594
|
indexes: import_zod9.z.record(import_zod9.z.string(), import_zod9.z.object({
|
|
1418
1595
|
/** Specifies the name of the partition / hash key that makes up the primary key for the global secondary index. */
|
|
1419
1596
|
hash: KeySchema,
|
|
@@ -1441,13 +1618,23 @@ var tablePlugin = definePlugin({
|
|
|
1441
1618
|
).optional()
|
|
1442
1619
|
}).array()
|
|
1443
1620
|
}),
|
|
1444
|
-
onStack(
|
|
1621
|
+
onStack(ctx) {
|
|
1622
|
+
const { config, stack, stackConfig, bind } = ctx;
|
|
1445
1623
|
for (const [id, props] of Object.entries(stackConfig.tables || {})) {
|
|
1446
1624
|
const table = new Table(id, {
|
|
1625
|
+
...props,
|
|
1447
1626
|
name: `${config.name}-${stack.name}-${id}`,
|
|
1448
|
-
|
|
1627
|
+
stream: props.stream?.type
|
|
1449
1628
|
});
|
|
1450
1629
|
stack.add(table);
|
|
1630
|
+
if (props.stream) {
|
|
1631
|
+
const lambda = toLambdaFunction(ctx, `stream-${id}`, props.stream.consumer);
|
|
1632
|
+
const source = new DynamoDBEventSource(id, lambda, {
|
|
1633
|
+
tableArn: table.arn,
|
|
1634
|
+
...props.stream
|
|
1635
|
+
});
|
|
1636
|
+
stack.add(lambda, source);
|
|
1637
|
+
}
|
|
1451
1638
|
bind((lambda) => {
|
|
1452
1639
|
lambda.addPermissions(table.permissions);
|
|
1453
1640
|
});
|
|
@@ -1502,12 +1689,12 @@ var storePlugin = definePlugin({
|
|
|
1502
1689
|
name: "store",
|
|
1503
1690
|
schema: import_zod10.z.object({
|
|
1504
1691
|
stacks: import_zod10.z.object({
|
|
1505
|
-
/** Define the stores in your stack
|
|
1692
|
+
/** Define the stores in your stack.
|
|
1506
1693
|
* @example
|
|
1507
1694
|
* {
|
|
1508
1695
|
* stores: [ 'STORE_NAME' ]
|
|
1509
1696
|
* }
|
|
1510
|
-
|
|
1697
|
+
*/
|
|
1511
1698
|
stores: import_zod10.z.array(ResourceIdSchema).optional()
|
|
1512
1699
|
}).array()
|
|
1513
1700
|
}),
|
|
@@ -1591,14 +1778,14 @@ var topicPlugin = definePlugin({
|
|
|
1591
1778
|
name: "topic",
|
|
1592
1779
|
schema: import_zod11.z.object({
|
|
1593
1780
|
stacks: import_zod11.z.object({
|
|
1594
|
-
/** Define the topics to listen too in your stack
|
|
1781
|
+
/** Define the topics to listen too in your stack.
|
|
1595
1782
|
* @example
|
|
1596
1783
|
* {
|
|
1597
1784
|
* topics: {
|
|
1598
1785
|
* TOPIC_NAME: 'function.ts'
|
|
1599
1786
|
* }
|
|
1600
1787
|
* }
|
|
1601
|
-
|
|
1788
|
+
*/
|
|
1602
1789
|
topics: import_zod11.z.record(ResourceIdSchema, FunctionSchema).optional()
|
|
1603
1790
|
}).array()
|
|
1604
1791
|
}),
|
|
@@ -1628,7 +1815,7 @@ var topicPlugin = definePlugin({
|
|
|
1628
1815
|
onStack(ctx) {
|
|
1629
1816
|
const { stack, stackConfig, bootstrap: bootstrap2 } = ctx;
|
|
1630
1817
|
for (const [id, props] of Object.entries(stackConfig.topics || {})) {
|
|
1631
|
-
const lambda = toLambdaFunction(ctx, id
|
|
1818
|
+
const lambda = toLambdaFunction(ctx, `topic-${id}`, props);
|
|
1632
1819
|
const source = new SnsEventSource(id, lambda, {
|
|
1633
1820
|
topicArn: bootstrap2.import(`topic-${id}-arn`)
|
|
1634
1821
|
});
|
|
@@ -1642,10 +1829,10 @@ var import_zod12 = require("zod");
|
|
|
1642
1829
|
var extendPlugin = definePlugin({
|
|
1643
1830
|
name: "extend",
|
|
1644
1831
|
schema: import_zod12.z.object({
|
|
1645
|
-
/** Extend your app with custom resources */
|
|
1832
|
+
/** Extend your app with custom resources. */
|
|
1646
1833
|
extend: import_zod12.z.custom().optional(),
|
|
1647
1834
|
stacks: import_zod12.z.object({
|
|
1648
|
-
/** Extend your stack with custom resources */
|
|
1835
|
+
/** Extend your stack with custom resources. */
|
|
1649
1836
|
extend: import_zod12.z.custom().optional()
|
|
1650
1837
|
}).array()
|
|
1651
1838
|
}),
|
|
@@ -1711,7 +1898,7 @@ var pubsubPlugin = definePlugin({
|
|
|
1711
1898
|
name: "pubsub",
|
|
1712
1899
|
schema: import_zod13.z.object({
|
|
1713
1900
|
stacks: import_zod13.z.object({
|
|
1714
|
-
/** Define the pubsub subscriber in your stack
|
|
1901
|
+
/** Define the pubsub subscriber in your stack.
|
|
1715
1902
|
* @example
|
|
1716
1903
|
* {
|
|
1717
1904
|
* pubsub: {
|
|
@@ -1723,11 +1910,11 @@ var pubsubPlugin = definePlugin({
|
|
|
1723
1910
|
* }
|
|
1724
1911
|
*/
|
|
1725
1912
|
pubsub: import_zod13.z.record(ResourceIdSchema, import_zod13.z.object({
|
|
1726
|
-
/** The SQL statement used to query the iot topic */
|
|
1913
|
+
/** The SQL statement used to query the iot topic. */
|
|
1727
1914
|
sql: import_zod13.z.string(),
|
|
1728
|
-
/** The version of the SQL rules engine to use when evaluating the rule */
|
|
1915
|
+
/** The version of the SQL rules engine to use when evaluating the rule. */
|
|
1729
1916
|
sqlVersion: import_zod13.z.enum(["2015-10-08", "2016-03-23", "beta"]).default("2016-03-23"),
|
|
1730
|
-
/** The consuming lambda function properties */
|
|
1917
|
+
/** The consuming lambda function properties. */
|
|
1731
1918
|
consumer: FunctionSchema
|
|
1732
1919
|
})).optional()
|
|
1733
1920
|
}).array()
|
|
@@ -1743,7 +1930,7 @@ var pubsubPlugin = definePlugin({
|
|
|
1743
1930
|
onStack(ctx) {
|
|
1744
1931
|
const { config, stack, stackConfig } = ctx;
|
|
1745
1932
|
for (const [id, props] of Object.entries(stackConfig.pubsub || {})) {
|
|
1746
|
-
const lambda = toLambdaFunction(ctx, id
|
|
1933
|
+
const lambda = toLambdaFunction(ctx, `pubsub-${id}`, props.consumer);
|
|
1747
1934
|
const source = new IotEventSource(id, lambda, {
|
|
1748
1935
|
name: `${config.name}-${stack.name}-${id}`,
|
|
1749
1936
|
sql: props.sql,
|
|
@@ -1770,34 +1957,6 @@ var import_change_case10 = require("change-case");
|
|
|
1770
1957
|
|
|
1771
1958
|
// src/formation/resource/appsync/graphql-api.ts
|
|
1772
1959
|
var import_change_case7 = require("change-case");
|
|
1773
|
-
var GraphQL = class extends Group {
|
|
1774
|
-
constructor(logicalId, props) {
|
|
1775
|
-
const api = new GraphQLApi(logicalId, props);
|
|
1776
|
-
const schema2 = new GraphQLSchema(logicalId, {
|
|
1777
|
-
apiId: api.id,
|
|
1778
|
-
definition: props.schema
|
|
1779
|
-
}).dependsOn(api);
|
|
1780
|
-
super([api, schema2]);
|
|
1781
|
-
this.logicalId = logicalId;
|
|
1782
|
-
this.api = api;
|
|
1783
|
-
this.schema = schema2;
|
|
1784
|
-
}
|
|
1785
|
-
api;
|
|
1786
|
-
schema;
|
|
1787
|
-
attachDomainName(domainName, certificateArn) {
|
|
1788
|
-
const id = this.logicalId + domainName;
|
|
1789
|
-
const domain = new DomainName(id, {
|
|
1790
|
-
domainName,
|
|
1791
|
-
certificateArn
|
|
1792
|
-
});
|
|
1793
|
-
const association = new DomainNameApiAssociation(id, {
|
|
1794
|
-
apiId: this.api.id,
|
|
1795
|
-
domainName
|
|
1796
|
-
}).dependsOn(this.api, domain);
|
|
1797
|
-
this.children.push(domain, association);
|
|
1798
|
-
return this;
|
|
1799
|
-
}
|
|
1800
|
-
};
|
|
1801
1960
|
var GraphQLApi = class extends Resource {
|
|
1802
1961
|
constructor(logicalId, props) {
|
|
1803
1962
|
super("AWS::AppSync::GraphQLApi", logicalId);
|
|
@@ -1839,44 +1998,6 @@ var GraphQLApi = class extends Resource {
|
|
|
1839
1998
|
};
|
|
1840
1999
|
}
|
|
1841
2000
|
};
|
|
1842
|
-
var GraphQLSchema = class extends Resource {
|
|
1843
|
-
constructor(logicalId, props) {
|
|
1844
|
-
super("AWS::AppSync::GraphQLSchema", logicalId, [
|
|
1845
|
-
props.definition
|
|
1846
|
-
]);
|
|
1847
|
-
this.props = props;
|
|
1848
|
-
}
|
|
1849
|
-
properties() {
|
|
1850
|
-
return {
|
|
1851
|
-
ApiId: this.props.apiId,
|
|
1852
|
-
Definition: this.props.definition.toDefinition()
|
|
1853
|
-
};
|
|
1854
|
-
}
|
|
1855
|
-
};
|
|
1856
|
-
var DomainName = class extends Resource {
|
|
1857
|
-
constructor(logicalId, props) {
|
|
1858
|
-
super("AWS::AppSync::DomainName", logicalId);
|
|
1859
|
-
this.props = props;
|
|
1860
|
-
}
|
|
1861
|
-
properties() {
|
|
1862
|
-
return {
|
|
1863
|
-
DomainName: this.props.domainName,
|
|
1864
|
-
CertificateArn: this.props.certificateArn
|
|
1865
|
-
};
|
|
1866
|
-
}
|
|
1867
|
-
};
|
|
1868
|
-
var DomainNameApiAssociation = class extends Resource {
|
|
1869
|
-
constructor(logicalId, props) {
|
|
1870
|
-
super("AWS::AppSync::DomainNameApiAssociation", logicalId);
|
|
1871
|
-
this.props = props;
|
|
1872
|
-
}
|
|
1873
|
-
properties() {
|
|
1874
|
-
return {
|
|
1875
|
-
ApiId: this.props.apiId,
|
|
1876
|
-
DomainName: this.props.domainName
|
|
1877
|
-
};
|
|
1878
|
-
}
|
|
1879
|
-
};
|
|
1880
2001
|
|
|
1881
2002
|
// src/formation/resource/route53/record-set.ts
|
|
1882
2003
|
var RecordSet = class extends Resource {
|
|
@@ -1897,19 +2018,33 @@ var RecordSet = class extends Resource {
|
|
|
1897
2018
|
} : {},
|
|
1898
2019
|
...this.props.alias ? {
|
|
1899
2020
|
AliasTarget: {
|
|
1900
|
-
DNSName: this.props.alias,
|
|
1901
|
-
HostedZoneId: this.props.hostedZoneId
|
|
2021
|
+
DNSName: this.props.alias.dnsName,
|
|
2022
|
+
HostedZoneId: this.props.alias.hostedZoneId
|
|
1902
2023
|
}
|
|
1903
2024
|
} : {}
|
|
1904
2025
|
};
|
|
1905
2026
|
}
|
|
1906
2027
|
};
|
|
1907
2028
|
|
|
1908
|
-
// src/formation/resource/appsync/schema.ts
|
|
2029
|
+
// src/formation/resource/appsync/graphql-schema.ts
|
|
1909
2030
|
var import_graphql = require("graphql");
|
|
1910
2031
|
var import_promises2 = require("fs/promises");
|
|
1911
2032
|
var import_merge = require("@graphql-tools/merge");
|
|
1912
|
-
var
|
|
2033
|
+
var GraphQLSchema = class extends Resource {
|
|
2034
|
+
constructor(logicalId, props) {
|
|
2035
|
+
super("AWS::AppSync::GraphQLSchema", logicalId, [
|
|
2036
|
+
props.definition
|
|
2037
|
+
]);
|
|
2038
|
+
this.props = props;
|
|
2039
|
+
}
|
|
2040
|
+
properties() {
|
|
2041
|
+
return {
|
|
2042
|
+
ApiId: this.props.apiId,
|
|
2043
|
+
Definition: this.props.definition.toString()
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
};
|
|
2047
|
+
var Definition = class extends Asset {
|
|
1913
2048
|
constructor(id, files) {
|
|
1914
2049
|
super("graphql", id);
|
|
1915
2050
|
this.files = files;
|
|
@@ -1922,10 +2057,14 @@ var Schema = class extends Asset {
|
|
|
1922
2057
|
}));
|
|
1923
2058
|
const defs = (0, import_merge.mergeTypeDefs)(schemas);
|
|
1924
2059
|
const schema2 = (0, import_graphql.print)(defs);
|
|
2060
|
+
const size = Buffer.from(schema2, "utf8").byteLength;
|
|
1925
2061
|
await write("schema.gql", schema2);
|
|
1926
2062
|
this.schema = schema2;
|
|
2063
|
+
return {
|
|
2064
|
+
size: formatByteSize(size)
|
|
2065
|
+
};
|
|
1927
2066
|
}
|
|
1928
|
-
|
|
2067
|
+
toString() {
|
|
1929
2068
|
return this.schema;
|
|
1930
2069
|
}
|
|
1931
2070
|
};
|
|
@@ -2105,6 +2244,41 @@ var AppsyncEventSource = class extends Group {
|
|
|
2105
2244
|
}
|
|
2106
2245
|
};
|
|
2107
2246
|
|
|
2247
|
+
// src/formation/resource/appsync/domain-name.ts
|
|
2248
|
+
var DomainName = class extends Resource {
|
|
2249
|
+
constructor(logicalId, props) {
|
|
2250
|
+
super("AWS::AppSync::DomainName", logicalId);
|
|
2251
|
+
this.props = props;
|
|
2252
|
+
}
|
|
2253
|
+
get appSyncDomainName() {
|
|
2254
|
+
return getAtt(this.logicalId, "AppSyncDomainName");
|
|
2255
|
+
}
|
|
2256
|
+
get domainName() {
|
|
2257
|
+
return getAtt(this.logicalId, "DomainName");
|
|
2258
|
+
}
|
|
2259
|
+
get hostedZoneId() {
|
|
2260
|
+
return getAtt(this.logicalId, "HostedZoneId");
|
|
2261
|
+
}
|
|
2262
|
+
properties() {
|
|
2263
|
+
return {
|
|
2264
|
+
DomainName: this.props.domainName,
|
|
2265
|
+
CertificateArn: this.props.certificateArn
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
};
|
|
2269
|
+
var DomainNameApiAssociation = class extends Resource {
|
|
2270
|
+
constructor(logicalId, props) {
|
|
2271
|
+
super("AWS::AppSync::DomainNameApiAssociation", logicalId);
|
|
2272
|
+
this.props = props;
|
|
2273
|
+
}
|
|
2274
|
+
properties() {
|
|
2275
|
+
return {
|
|
2276
|
+
ApiId: this.props.apiId,
|
|
2277
|
+
DomainName: this.props.domainName
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
2280
|
+
};
|
|
2281
|
+
|
|
2108
2282
|
// src/plugins/graphql.ts
|
|
2109
2283
|
var defaultResolver = `
|
|
2110
2284
|
export function request(ctx) {
|
|
@@ -2154,38 +2328,51 @@ var graphqlPlugin = definePlugin({
|
|
|
2154
2328
|
}
|
|
2155
2329
|
}
|
|
2156
2330
|
for (const id of apis) {
|
|
2157
|
-
const
|
|
2331
|
+
const schemaFiles = [];
|
|
2158
2332
|
for (const stack of config.stacks) {
|
|
2159
2333
|
const files = toArray(stack.graphql?.[id]?.schema || []);
|
|
2160
|
-
|
|
2334
|
+
schemaFiles.push(...files);
|
|
2161
2335
|
}
|
|
2162
|
-
const
|
|
2336
|
+
const api = new GraphQLApi(id, {
|
|
2163
2337
|
name: `${config.name}-${id}`,
|
|
2164
|
-
authenticationType: "api-key"
|
|
2165
|
-
schema: new Schema(id, schema2)
|
|
2338
|
+
authenticationType: "api-key"
|
|
2166
2339
|
});
|
|
2167
|
-
|
|
2340
|
+
const schema2 = new GraphQLSchema(id, {
|
|
2341
|
+
apiId: api.id,
|
|
2342
|
+
definition: new Definition(id, schemaFiles)
|
|
2343
|
+
}).dependsOn(api);
|
|
2344
|
+
bootstrap2.add(api).add(schema2).export(`graphql-${id}`, api.id);
|
|
2168
2345
|
const props = config.defaults.graphql?.[id];
|
|
2169
2346
|
if (!props) {
|
|
2170
2347
|
continue;
|
|
2171
2348
|
}
|
|
2172
2349
|
if (props.authorization) {
|
|
2173
2350
|
const lambda = toLambdaFunction(ctx, `${id}-authorizer`, props.authorization.authorizer);
|
|
2174
|
-
|
|
2351
|
+
api.addLambdaAuthProvider(lambda.arn, props.authorization.ttl);
|
|
2175
2352
|
bootstrap2.add(lambda);
|
|
2176
2353
|
}
|
|
2177
2354
|
if (props.domain) {
|
|
2178
2355
|
const domainName = props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain;
|
|
2179
|
-
const hostedZoneId =
|
|
2356
|
+
const hostedZoneId = usEastBootstrap.import(`hosted-zone-${props.domain}-id`);
|
|
2180
2357
|
const certificateArn = usEastBootstrap.import(`certificate-${props.domain}-arn`);
|
|
2181
|
-
|
|
2182
|
-
|
|
2358
|
+
const domain = new DomainName(id, {
|
|
2359
|
+
domainName,
|
|
2360
|
+
certificateArn
|
|
2361
|
+
});
|
|
2362
|
+
const association = new DomainNameApiAssociation(id, {
|
|
2363
|
+
apiId: api.id,
|
|
2364
|
+
domainName: domain.domainName
|
|
2365
|
+
}).dependsOn(api, domain);
|
|
2366
|
+
const record = new RecordSet(`${id}-graphql`, {
|
|
2183
2367
|
hostedZoneId,
|
|
2184
2368
|
type: "A",
|
|
2185
2369
|
name: domainName,
|
|
2186
|
-
alias:
|
|
2187
|
-
|
|
2188
|
-
|
|
2370
|
+
alias: {
|
|
2371
|
+
dnsName: domain.appSyncDomainName,
|
|
2372
|
+
hostedZoneId: domain.hostedZoneId
|
|
2373
|
+
}
|
|
2374
|
+
}).dependsOn(domain, association);
|
|
2375
|
+
bootstrap2.add(domain, association, record);
|
|
2189
2376
|
}
|
|
2190
2377
|
}
|
|
2191
2378
|
},
|
|
@@ -2196,7 +2383,7 @@ var graphqlPlugin = definePlugin({
|
|
|
2196
2383
|
for (const [typeAndField, functionProps] of Object.entries(props.resolvers || {})) {
|
|
2197
2384
|
const [typeName, fieldName] = typeAndField.split(/[\s]+/g);
|
|
2198
2385
|
const entryId = (0, import_change_case10.paramCase)(`${id}-${typeName}-${fieldName}`);
|
|
2199
|
-
const lambda = toLambdaFunction(ctx, entryId
|
|
2386
|
+
const lambda = toLambdaFunction(ctx, `graphql-${entryId}`, functionProps);
|
|
2200
2387
|
const source = new AppsyncEventSource(entryId, lambda, {
|
|
2201
2388
|
apiId,
|
|
2202
2389
|
typeName,
|
|
@@ -2232,7 +2419,7 @@ var HostedZone = class extends Resource {
|
|
|
2232
2419
|
|
|
2233
2420
|
// src/formation/resource/certificate-manager/certificate.ts
|
|
2234
2421
|
var Certificate = class extends Resource {
|
|
2235
|
-
constructor(logicalId, props
|
|
2422
|
+
constructor(logicalId, props) {
|
|
2236
2423
|
super("AWS::CertificateManager::Certificate", logicalId);
|
|
2237
2424
|
this.props = props;
|
|
2238
2425
|
this.name = this.props.domainName || logicalId;
|
|
@@ -2244,8 +2431,12 @@ var Certificate = class extends Resource {
|
|
|
2244
2431
|
properties() {
|
|
2245
2432
|
return {
|
|
2246
2433
|
DomainName: this.name,
|
|
2434
|
+
SubjectAlternativeNames: this.props.alternativeNames || [],
|
|
2247
2435
|
ValidationMethod: "DNS",
|
|
2248
|
-
|
|
2436
|
+
DomainValidationOptions: [{
|
|
2437
|
+
DomainName: this.name,
|
|
2438
|
+
HostedZoneId: this.props.hostedZoneId
|
|
2439
|
+
}]
|
|
2249
2440
|
};
|
|
2250
2441
|
}
|
|
2251
2442
|
};
|
|
@@ -2277,40 +2468,986 @@ var RecordSetGroup = class extends Resource {
|
|
|
2277
2468
|
}
|
|
2278
2469
|
};
|
|
2279
2470
|
|
|
2280
|
-
// src/
|
|
2281
|
-
var
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
}
|
|
2471
|
+
// src/custom/delete-hosted-zone/handler.ts
|
|
2472
|
+
var deleteHostedZoneRecordsHandlerCode = (
|
|
2473
|
+
/* JS */
|
|
2474
|
+
`
|
|
2475
|
+
|
|
2476
|
+
const { Route53Client, ListResourceRecordSetsCommand, ChangeResourceRecordSetsCommand } = require('@aws-sdk/client-route-53')
|
|
2477
|
+
|
|
2478
|
+
const client = new Route53Client({})
|
|
2479
|
+
|
|
2480
|
+
exports.handler = async (event) => {
|
|
2481
|
+
const type = event.RequestType
|
|
2482
|
+
const hostedZoneId = event.ResourceProperties.hostedZoneId
|
|
2483
|
+
|
|
2484
|
+
try {
|
|
2485
|
+
if(type === 'Delete') {
|
|
2486
|
+
const records = await listHostedZoneRecords(hostedZoneId)
|
|
2487
|
+
console.log(records)
|
|
2488
|
+
|
|
2489
|
+
await deleteHostedZoneRecords(hostedZoneId, records)
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
await send(event, hostedZoneId, 'SUCCESS')
|
|
2493
|
+
}
|
|
2494
|
+
catch(error) {
|
|
2495
|
+
if (error instanceof Error) {
|
|
2496
|
+
await send(event, hostedZoneId, 'FAILED', {}, error.message)
|
|
2497
|
+
} else {
|
|
2498
|
+
await send(event, hostedZoneId, 'FAILED', {}, 'Unknown error')
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
const send = async (event, id, status, data = {}, reason = '') => {
|
|
2504
|
+
const body = JSON.stringify({
|
|
2505
|
+
Status: status,
|
|
2506
|
+
Reason: reason,
|
|
2507
|
+
PhysicalResourceId: id,
|
|
2508
|
+
StackId: event.StackId,
|
|
2509
|
+
RequestId: event.RequestId,
|
|
2510
|
+
LogicalResourceId: event.LogicalResourceId,
|
|
2511
|
+
NoEcho: false,
|
|
2512
|
+
Data: data
|
|
2513
|
+
})
|
|
2514
|
+
|
|
2515
|
+
await fetch(event.ResponseURL, {
|
|
2516
|
+
method: 'PUT',
|
|
2517
|
+
port: 443,
|
|
2518
|
+
body,
|
|
2519
|
+
headers: {
|
|
2520
|
+
'content-type': '',
|
|
2521
|
+
'content-length': Buffer.from(body).byteLength,
|
|
2522
|
+
},
|
|
2523
|
+
})
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2526
|
+
const deleteHostedZoneRecords = async (hostedZoneId, records) => {
|
|
2527
|
+
records = records.filter(record => ![ 'SOA', 'NS' ].includes(record.Type))
|
|
2528
|
+
if(records.length === 0) {
|
|
2529
|
+
return
|
|
2530
|
+
}
|
|
2531
|
+
|
|
2532
|
+
const chunkSize = 100;
|
|
2533
|
+
for (let i = 0; i < records.length; i += chunkSize) {
|
|
2534
|
+
const chunk = records.slice(i, i + chunkSize);
|
|
2535
|
+
|
|
2536
|
+
await client.send(new ChangeResourceRecordSetsCommand({
|
|
2537
|
+
HostedZoneId: hostedZoneId,
|
|
2538
|
+
ChangeBatch: {
|
|
2539
|
+
Changes: chunk.map(record => ({
|
|
2540
|
+
Action: 'DELETE',
|
|
2541
|
+
ResourceRecordSet: record
|
|
2542
|
+
}))
|
|
2543
|
+
}
|
|
2544
|
+
}))
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
const listHostedZoneRecords = async (hostedZoneId) => {
|
|
2549
|
+
|
|
2550
|
+
const records = []
|
|
2551
|
+
let token
|
|
2552
|
+
|
|
2553
|
+
while(true) {
|
|
2554
|
+
const result = await client.send(new ListResourceRecordSetsCommand({
|
|
2555
|
+
HostedZoneId: hostedZoneId,
|
|
2556
|
+
NextRecordName: token
|
|
2557
|
+
}))
|
|
2558
|
+
|
|
2559
|
+
if(result.ResourceRecordSets && result.ResourceRecordSets.length) {
|
|
2560
|
+
records.push(...result.ResourceRecordSets)
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
if(result.NextRecordName) {
|
|
2564
|
+
token = result.NextRecordName
|
|
2565
|
+
} else {
|
|
2566
|
+
return records
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
`
|
|
2571
|
+
);
|
|
2572
|
+
|
|
2573
|
+
// src/formation/resource/cloud-formation/custom-resource.ts
|
|
2574
|
+
var CustomResource = class extends Resource {
|
|
2575
|
+
constructor(logicalId, props) {
|
|
2576
|
+
super("AWS::CloudFormation::CustomResource", logicalId);
|
|
2577
|
+
this.props = props;
|
|
2578
|
+
}
|
|
2579
|
+
getAtt(name) {
|
|
2580
|
+
return getAtt(this.logicalId, name);
|
|
2581
|
+
}
|
|
2582
|
+
properties() {
|
|
2583
|
+
return {
|
|
2584
|
+
ServiceToken: this.props.serviceToken,
|
|
2585
|
+
...this.props.properties
|
|
2586
|
+
};
|
|
2587
|
+
}
|
|
2588
|
+
};
|
|
2589
|
+
|
|
2590
|
+
// src/plugins/domain.ts
|
|
2591
|
+
var DomainNameSchema = import_zod15.z.string().regex(/[a-z\-\_\.]/g, "Invalid domain name");
|
|
2592
|
+
var domainPlugin = definePlugin({
|
|
2593
|
+
name: "domain",
|
|
2594
|
+
schema: import_zod15.z.object({
|
|
2595
|
+
/** Define the domains for your application.
|
|
2596
|
+
* @example
|
|
2597
|
+
* {
|
|
2598
|
+
* domains: {
|
|
2599
|
+
* 'example.com': [{
|
|
2600
|
+
* name: 'www',
|
|
2601
|
+
* type: 'TXT',
|
|
2602
|
+
* ttl: '60 seconds',
|
|
2603
|
+
* records: [ 'value' ]
|
|
2604
|
+
* }]
|
|
2605
|
+
* }
|
|
2606
|
+
* }
|
|
2607
|
+
*/
|
|
2608
|
+
domains: import_zod15.z.record(DomainNameSchema, import_zod15.z.object({
|
|
2609
|
+
/** Enter a fully qualified domain name, for example, www.example.com.
|
|
2610
|
+
* You can optionally include a trailing dot.
|
|
2611
|
+
* If you omit the trailing dot, Amazon Route 53 assumes that the domain name that you specify is fully qualified.
|
|
2612
|
+
* This means that Route 53 treats www.example.com (without a trailing dot) and www.example.com. (with a trailing dot) as identical.
|
|
2613
|
+
*/
|
|
2614
|
+
name: DomainNameSchema.optional(),
|
|
2615
|
+
/** The DNS record type. */
|
|
2616
|
+
type: import_zod15.z.enum(["A", "AAAA", "CAA", "CNAME", "DS", "MX", "NAPTR", "NS", "PTR", "SOA", "SPF", "SRV", "TXT"]),
|
|
2617
|
+
/** The resource record cache time to live (TTL) */
|
|
2618
|
+
ttl: DurationSchema,
|
|
2619
|
+
/** One or more values that correspond with the value that you specified for the Type property. */
|
|
2620
|
+
records: import_zod15.z.string().array()
|
|
2621
|
+
}).array()).optional()
|
|
2622
|
+
}),
|
|
2623
|
+
onApp({ config, bootstrap: bootstrap2, usEastBootstrap }) {
|
|
2624
|
+
const domains = Object.entries(config.domains || {});
|
|
2625
|
+
if (domains.length === 0) {
|
|
2626
|
+
return;
|
|
2627
|
+
}
|
|
2628
|
+
const lambda = new Function("delete-hosted-zone", {
|
|
2629
|
+
name: `${config.name}-delete-hosted-zone`,
|
|
2630
|
+
code: Code.fromInline(deleteHostedZoneRecordsHandlerCode, "index.handler")
|
|
2631
|
+
});
|
|
2632
|
+
lambda.addPermissions({
|
|
2633
|
+
actions: [
|
|
2634
|
+
"route53:ListResourceRecordSets",
|
|
2635
|
+
"route53:ChangeResourceRecordSets"
|
|
2636
|
+
],
|
|
2637
|
+
resources: ["*"]
|
|
2638
|
+
});
|
|
2639
|
+
usEastBootstrap.add(lambda);
|
|
2640
|
+
for (const [domain, records] of domains) {
|
|
2641
|
+
const hostedZone = new HostedZone(domain);
|
|
2642
|
+
const usEastCertificate = new Certificate(domain, {
|
|
2643
|
+
hostedZoneId: hostedZone.id,
|
|
2644
|
+
alternativeNames: [`*.${domain}`]
|
|
2645
|
+
});
|
|
2646
|
+
const custom = new CustomResource(domain, {
|
|
2647
|
+
serviceToken: lambda.arn,
|
|
2648
|
+
properties: {
|
|
2649
|
+
hostedZoneId: hostedZone.id
|
|
2650
|
+
}
|
|
2651
|
+
}).dependsOn(hostedZone);
|
|
2652
|
+
usEastBootstrap.add(custom).add(hostedZone).add(usEastCertificate).export(`certificate-${domain}-arn`, usEastCertificate.arn).export(`hosted-zone-${domain}-id`, hostedZone.id);
|
|
2653
|
+
const certificate = new Certificate(domain, {
|
|
2654
|
+
hostedZoneId: usEastBootstrap.import(`hosted-zone-${domain}-id`),
|
|
2655
|
+
alternativeNames: [`*.${domain}`]
|
|
2656
|
+
});
|
|
2657
|
+
bootstrap2.add(certificate).export(`certificate-${domain}-arn`, certificate.arn);
|
|
2658
|
+
if (records.length > 0) {
|
|
2659
|
+
const group = new RecordSetGroup(domain, {
|
|
2660
|
+
hostedZoneId: hostedZone.id,
|
|
2661
|
+
records
|
|
2662
|
+
}).dependsOn(hostedZone);
|
|
2663
|
+
usEastBootstrap.add(group);
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
});
|
|
2668
|
+
|
|
2669
|
+
// src/plugins/on-failure.ts
|
|
2670
|
+
var import_zod16 = require("zod");
|
|
2671
|
+
var hasOnFailure = (config) => {
|
|
2672
|
+
const onFailure = config.stacks.find((stack) => {
|
|
2673
|
+
return typeof stack.onFailure !== "undefined";
|
|
2674
|
+
});
|
|
2675
|
+
return !!onFailure;
|
|
2676
|
+
};
|
|
2677
|
+
var onFailurePlugin = definePlugin({
|
|
2678
|
+
name: "on-failure",
|
|
2679
|
+
schema: import_zod16.z.object({
|
|
2680
|
+
stacks: import_zod16.z.object({
|
|
2681
|
+
/** Defining a onFailure handler will add a global onFailure handler for the following resources:
|
|
2682
|
+
* - Async lambda functions
|
|
2683
|
+
* - SQS queues
|
|
2684
|
+
* - DynamoDB streams
|
|
2685
|
+
* @example
|
|
2686
|
+
* {
|
|
2687
|
+
* onFailure: 'on-failure.ts'
|
|
2688
|
+
* }
|
|
2689
|
+
*/
|
|
2690
|
+
onFailure: FunctionSchema.optional()
|
|
2691
|
+
}).array()
|
|
2692
|
+
}),
|
|
2693
|
+
onApp({ config, bootstrap: bootstrap2 }) {
|
|
2694
|
+
if (!hasOnFailure(config)) {
|
|
2695
|
+
return;
|
|
2696
|
+
}
|
|
2697
|
+
const queue2 = new Queue("on-failure", {
|
|
2698
|
+
name: `${config.name}-failure`
|
|
2699
|
+
});
|
|
2700
|
+
bootstrap2.add(queue2).export("on-failure-queue-arn", queue2.arn);
|
|
2701
|
+
},
|
|
2702
|
+
onStack(ctx) {
|
|
2703
|
+
const { stack, stackConfig, bootstrap: bootstrap2 } = ctx;
|
|
2704
|
+
const onFailure = stackConfig.onFailure;
|
|
2705
|
+
if (!onFailure) {
|
|
2706
|
+
return;
|
|
2707
|
+
}
|
|
2708
|
+
const queueArn = bootstrap2.import("on-failure-queue-arn");
|
|
2709
|
+
const lambda = toLambdaFunction(ctx, "on-failure", onFailure);
|
|
2710
|
+
const source = new SqsEventSource("on-failure", lambda, {
|
|
2711
|
+
queueArn
|
|
2712
|
+
});
|
|
2713
|
+
lambda.addPermissions({
|
|
2714
|
+
actions: [
|
|
2715
|
+
"sqs:SendMessage",
|
|
2716
|
+
"sqs:ReceiveMessage",
|
|
2717
|
+
"sqs:GetQueueUrl",
|
|
2718
|
+
"sqs:GetQueueAttributes"
|
|
2719
|
+
],
|
|
2720
|
+
resources: [queueArn]
|
|
2721
|
+
});
|
|
2722
|
+
stack.add(lambda, source);
|
|
2723
|
+
},
|
|
2724
|
+
onResource({ config, resource, bootstrap: bootstrap2 }) {
|
|
2725
|
+
if (!hasOnFailure(config)) {
|
|
2726
|
+
return;
|
|
2727
|
+
}
|
|
2728
|
+
const queueArn = bootstrap2.import("on-failure-queue-arn");
|
|
2729
|
+
if (resource instanceof Queue) {
|
|
2730
|
+
resource.setDeadLetter(queueArn);
|
|
2731
|
+
}
|
|
2732
|
+
if (resource instanceof EventInvokeConfig) {
|
|
2733
|
+
resource.setOnFailure(queueArn);
|
|
2734
|
+
}
|
|
2735
|
+
if (resource instanceof EventSourceMapping) {
|
|
2736
|
+
resource.setOnFailure(queueArn);
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
});
|
|
2740
|
+
|
|
2741
|
+
// src/formation/resource/ec2/vpc.ts
|
|
2742
|
+
var Vpc = class extends Resource {
|
|
2743
|
+
constructor(logicalId, props) {
|
|
2744
|
+
super("AWS::EC2::VPC", logicalId);
|
|
2745
|
+
this.props = props;
|
|
2746
|
+
}
|
|
2747
|
+
get id() {
|
|
2748
|
+
return ref(this.logicalId);
|
|
2749
|
+
}
|
|
2750
|
+
properties() {
|
|
2751
|
+
return {
|
|
2752
|
+
CidrBlock: this.props.cidrBlock.ip
|
|
2753
|
+
};
|
|
2754
|
+
}
|
|
2755
|
+
};
|
|
2756
|
+
var RouteTable = class extends Resource {
|
|
2757
|
+
constructor(logicalId, props) {
|
|
2758
|
+
super("AWS::EC2::RouteTable", logicalId);
|
|
2759
|
+
this.props = props;
|
|
2760
|
+
this.name = formatName(props.name || logicalId);
|
|
2761
|
+
}
|
|
2762
|
+
name;
|
|
2763
|
+
get id() {
|
|
2764
|
+
return ref(this.logicalId);
|
|
2765
|
+
}
|
|
2766
|
+
properties() {
|
|
2767
|
+
return {
|
|
2768
|
+
VpcId: this.props.vpcId,
|
|
2769
|
+
Tags: [{
|
|
2770
|
+
Key: "name",
|
|
2771
|
+
Value: this.name
|
|
2772
|
+
}]
|
|
2773
|
+
};
|
|
2774
|
+
}
|
|
2775
|
+
};
|
|
2776
|
+
var InternetGateway = class extends Resource {
|
|
2777
|
+
constructor(logicalId) {
|
|
2778
|
+
super("AWS::EC2::InternetGateway", logicalId);
|
|
2779
|
+
}
|
|
2780
|
+
get id() {
|
|
2781
|
+
return ref(this.logicalId);
|
|
2782
|
+
}
|
|
2783
|
+
properties() {
|
|
2784
|
+
return {};
|
|
2785
|
+
}
|
|
2786
|
+
};
|
|
2787
|
+
var VPCGatewayAttachment = class extends Resource {
|
|
2788
|
+
constructor(logicalId, props) {
|
|
2789
|
+
super("AWS::EC2::VPCGatewayAttachment", logicalId);
|
|
2790
|
+
this.props = props;
|
|
2791
|
+
}
|
|
2792
|
+
get id() {
|
|
2793
|
+
return ref(this.logicalId);
|
|
2794
|
+
}
|
|
2795
|
+
properties() {
|
|
2796
|
+
return {
|
|
2797
|
+
VpcId: this.props.vpcId,
|
|
2798
|
+
InternetGatewayId: this.props.internetGatewayId
|
|
2799
|
+
};
|
|
2800
|
+
}
|
|
2801
|
+
};
|
|
2802
|
+
var Route = class extends Resource {
|
|
2803
|
+
constructor(logicalId, props) {
|
|
2804
|
+
super("AWS::EC2::Route", logicalId);
|
|
2805
|
+
this.props = props;
|
|
2806
|
+
}
|
|
2807
|
+
get id() {
|
|
2808
|
+
return ref(this.logicalId);
|
|
2809
|
+
}
|
|
2810
|
+
properties() {
|
|
2811
|
+
return {
|
|
2812
|
+
GatewayId: this.props.gatewayId,
|
|
2813
|
+
RouteTableId: this.props.routeTableId,
|
|
2814
|
+
DestinationCidrBlock: this.props.destination.ip
|
|
2815
|
+
};
|
|
2816
|
+
}
|
|
2817
|
+
};
|
|
2818
|
+
var Subnet = class extends Resource {
|
|
2819
|
+
constructor(logicalId, props) {
|
|
2820
|
+
super("AWS::EC2::Subnet", logicalId);
|
|
2821
|
+
this.props = props;
|
|
2822
|
+
}
|
|
2823
|
+
get id() {
|
|
2824
|
+
return ref(this.logicalId);
|
|
2825
|
+
}
|
|
2826
|
+
properties() {
|
|
2827
|
+
return {
|
|
2828
|
+
VpcId: this.props.vpcId,
|
|
2829
|
+
CidrBlock: this.props.cidrBlock.ip,
|
|
2830
|
+
AvailabilityZone: this.props.availabilityZone
|
|
2831
|
+
};
|
|
2832
|
+
}
|
|
2833
|
+
};
|
|
2834
|
+
var SubnetRouteTableAssociation = class extends Resource {
|
|
2835
|
+
constructor(logicalId, props) {
|
|
2836
|
+
super("AWS::EC2::SubnetRouteTableAssociation", logicalId);
|
|
2837
|
+
this.props = props;
|
|
2838
|
+
}
|
|
2839
|
+
get id() {
|
|
2840
|
+
return ref(this.logicalId);
|
|
2841
|
+
}
|
|
2842
|
+
properties() {
|
|
2843
|
+
return {
|
|
2844
|
+
SubnetId: this.props.subnetId,
|
|
2845
|
+
RouteTableId: this.props.routeTableId
|
|
2846
|
+
};
|
|
2847
|
+
}
|
|
2848
|
+
};
|
|
2849
|
+
|
|
2850
|
+
// src/formation/resource/ec2/peer.ts
|
|
2851
|
+
var Peer = class {
|
|
2852
|
+
constructor(ip, type) {
|
|
2853
|
+
this.ip = ip;
|
|
2854
|
+
this.type = type;
|
|
2855
|
+
}
|
|
2856
|
+
static ipv4(cidrIp) {
|
|
2857
|
+
const cidrMatch = cidrIp.match(/^(\d{1,3}\.){3}\d{1,3}(\/\d+)?$/);
|
|
2858
|
+
if (!cidrMatch) {
|
|
2859
|
+
throw new Error(`Invalid IPv4 CIDR: "${cidrIp}"`);
|
|
2860
|
+
}
|
|
2861
|
+
if (!cidrMatch[2]) {
|
|
2862
|
+
throw new Error(`CIDR mask is missing in IPv4: "${cidrIp}". Did you mean "${cidrIp}/32"?`);
|
|
2863
|
+
}
|
|
2864
|
+
return new Peer(cidrIp, "v4");
|
|
2865
|
+
}
|
|
2866
|
+
static anyIpv4() {
|
|
2867
|
+
return new Peer("0.0.0.0/0", "v4");
|
|
2868
|
+
}
|
|
2869
|
+
static ipv6(cidrIpv6) {
|
|
2870
|
+
const cidrMatch = cidrIpv6.match(/^([\da-f]{0,4}:){2,7}([\da-f]{0,4})?(\/\d+)?$/);
|
|
2871
|
+
if (!cidrMatch) {
|
|
2872
|
+
throw new Error(`Invalid IPv6 CIDR: "${cidrIpv6}"`);
|
|
2873
|
+
}
|
|
2874
|
+
if (!cidrMatch[3]) {
|
|
2875
|
+
throw new Error(`CIDR mask is missing in IPv6: "${cidrIpv6}". Did you mean "${cidrIpv6}/128"?`);
|
|
2876
|
+
}
|
|
2877
|
+
return new Peer(cidrIpv6, "v6");
|
|
2878
|
+
}
|
|
2879
|
+
static anyIpv6() {
|
|
2880
|
+
return new Peer("::/0", "v6");
|
|
2881
|
+
}
|
|
2882
|
+
toRuleJson() {
|
|
2883
|
+
switch (this.type) {
|
|
2884
|
+
case "v4":
|
|
2885
|
+
return { CidrIp: this.ip };
|
|
2886
|
+
case "v6":
|
|
2887
|
+
return { CidrIpv6: this.ip };
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
toString() {
|
|
2891
|
+
return this.ip;
|
|
2892
|
+
}
|
|
2893
|
+
};
|
|
2894
|
+
|
|
2895
|
+
// src/plugins/vpc.ts
|
|
2896
|
+
var vpcPlugin = definePlugin({
|
|
2897
|
+
name: "vpc",
|
|
2898
|
+
// schema: z.object({
|
|
2899
|
+
// defaults: z.object({
|
|
2900
|
+
// vpc: z.boolean().default(false),
|
|
2901
|
+
// }).default({}),
|
|
2902
|
+
// }),
|
|
2903
|
+
onApp({ config, bootstrap: bootstrap2 }) {
|
|
2904
|
+
const vpc = new Vpc("main", {
|
|
2905
|
+
cidrBlock: Peer.ipv4("10.0.0.0/16")
|
|
2906
|
+
});
|
|
2907
|
+
const privateRouteTable = new RouteTable("private", {
|
|
2908
|
+
vpcId: vpc.id,
|
|
2909
|
+
name: "private"
|
|
2910
|
+
}).dependsOn(vpc);
|
|
2911
|
+
const publicRouteTable = new RouteTable("public", {
|
|
2912
|
+
vpcId: vpc.id,
|
|
2913
|
+
name: "public"
|
|
2914
|
+
}).dependsOn(vpc);
|
|
2915
|
+
const gateway = new InternetGateway("");
|
|
2916
|
+
const attachment = new VPCGatewayAttachment("", {
|
|
2917
|
+
vpcId: vpc.id,
|
|
2918
|
+
internetGatewayId: gateway.id
|
|
2919
|
+
}).dependsOn(vpc, gateway);
|
|
2920
|
+
const route = new Route("", {
|
|
2921
|
+
gatewayId: gateway.id,
|
|
2922
|
+
routeTableId: publicRouteTable.id,
|
|
2923
|
+
destination: Peer.anyIpv4()
|
|
2924
|
+
}).dependsOn(gateway, publicRouteTable);
|
|
2925
|
+
bootstrap2.export(`vpc-id`, vpc.id);
|
|
2926
|
+
bootstrap2.add(
|
|
2927
|
+
vpc,
|
|
2928
|
+
privateRouteTable,
|
|
2929
|
+
publicRouteTable,
|
|
2930
|
+
gateway,
|
|
2931
|
+
attachment,
|
|
2932
|
+
route
|
|
2933
|
+
);
|
|
2934
|
+
const zones = ["a", "b"];
|
|
2935
|
+
const tables = [privateRouteTable, publicRouteTable];
|
|
2936
|
+
let block = 0;
|
|
2937
|
+
for (const table of tables) {
|
|
2938
|
+
for (const i in zones) {
|
|
2939
|
+
const id = `${table.name}-${i}`;
|
|
2940
|
+
const subnet = new Subnet(id, {
|
|
2941
|
+
vpcId: vpc.id,
|
|
2942
|
+
cidrBlock: Peer.ipv4(`10.0.${block++}.0/24`),
|
|
2943
|
+
availabilityZone: config.region + zones[i]
|
|
2944
|
+
}).dependsOn(vpc);
|
|
2945
|
+
const association = new SubnetRouteTableAssociation(id, {
|
|
2946
|
+
routeTableId: table.id,
|
|
2947
|
+
subnetId: subnet.id
|
|
2948
|
+
}).dependsOn(subnet, table);
|
|
2949
|
+
bootstrap2.export(`${table.name}-subnet-${Number(i) + 1}`, subnet.id);
|
|
2950
|
+
bootstrap2.add(
|
|
2951
|
+
subnet,
|
|
2952
|
+
association
|
|
2953
|
+
);
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
});
|
|
2958
|
+
|
|
2959
|
+
// src/plugins/http.ts
|
|
2960
|
+
var import_zod17 = require("zod");
|
|
2961
|
+
|
|
2962
|
+
// src/formation/resource/ec2/security-group.ts
|
|
2963
|
+
var SecurityGroup = class extends Resource {
|
|
2964
|
+
constructor(logicalId, props) {
|
|
2965
|
+
super("AWS::EC2::SecurityGroup", logicalId);
|
|
2966
|
+
this.props = props;
|
|
2967
|
+
}
|
|
2968
|
+
ingress = [];
|
|
2969
|
+
egress = [];
|
|
2970
|
+
get id() {
|
|
2971
|
+
return ref(this.logicalId);
|
|
2972
|
+
}
|
|
2973
|
+
addIngressRule(peer, port, description) {
|
|
2974
|
+
this.ingress.push({
|
|
2975
|
+
peer,
|
|
2976
|
+
port,
|
|
2977
|
+
description
|
|
2978
|
+
});
|
|
2979
|
+
return this;
|
|
2980
|
+
}
|
|
2981
|
+
addEgressRule(peer, port, description) {
|
|
2982
|
+
this.egress.push({
|
|
2983
|
+
peer,
|
|
2984
|
+
port,
|
|
2985
|
+
description
|
|
2986
|
+
});
|
|
2987
|
+
return this;
|
|
2988
|
+
}
|
|
2989
|
+
properties() {
|
|
2990
|
+
return {
|
|
2991
|
+
VpcId: this.props.vpcId,
|
|
2992
|
+
GroupName: this.logicalId,
|
|
2993
|
+
GroupDescription: this.props.description,
|
|
2994
|
+
SecurityGroupIngress: this.ingress.map((rule) => ({
|
|
2995
|
+
Description: rule.description || "",
|
|
2996
|
+
...rule.port.toRuleJson(),
|
|
2997
|
+
...rule.peer.toRuleJson()
|
|
2998
|
+
})),
|
|
2999
|
+
SecurityGroupEgress: this.egress.map((rule) => ({
|
|
3000
|
+
Description: rule.description || "",
|
|
3001
|
+
...rule.port.toRuleJson(),
|
|
3002
|
+
...rule.peer.toRuleJson()
|
|
3003
|
+
}))
|
|
3004
|
+
};
|
|
3005
|
+
}
|
|
3006
|
+
};
|
|
3007
|
+
|
|
3008
|
+
// src/formation/resource/ec2/port.ts
|
|
3009
|
+
var Port = class {
|
|
3010
|
+
static tcp(port) {
|
|
3011
|
+
return new Port({
|
|
3012
|
+
protocol: "tcp" /* TCP */,
|
|
3013
|
+
from: port,
|
|
3014
|
+
to: port
|
|
3015
|
+
});
|
|
3016
|
+
}
|
|
3017
|
+
static tcpRange(startPort, endPort) {
|
|
3018
|
+
return new Port({
|
|
3019
|
+
protocol: "tcp" /* TCP */,
|
|
3020
|
+
from: startPort,
|
|
3021
|
+
to: endPort
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3024
|
+
static allTcp() {
|
|
3025
|
+
return new Port({
|
|
3026
|
+
protocol: "tcp" /* TCP */,
|
|
3027
|
+
from: 0,
|
|
3028
|
+
to: 65535
|
|
3029
|
+
});
|
|
3030
|
+
}
|
|
3031
|
+
static allTraffic() {
|
|
3032
|
+
return new Port({
|
|
3033
|
+
protocol: "-1" /* ALL */
|
|
3034
|
+
});
|
|
3035
|
+
}
|
|
3036
|
+
protocol;
|
|
3037
|
+
from;
|
|
3038
|
+
to;
|
|
3039
|
+
constructor(props) {
|
|
3040
|
+
this.protocol = props.protocol;
|
|
3041
|
+
this.from = props.from;
|
|
3042
|
+
this.to = props.to;
|
|
3043
|
+
}
|
|
3044
|
+
toRuleJson() {
|
|
3045
|
+
return {
|
|
3046
|
+
IpProtocol: this.protocol,
|
|
3047
|
+
FromPort: this.from,
|
|
3048
|
+
ToPort: this.to
|
|
3049
|
+
};
|
|
3050
|
+
}
|
|
3051
|
+
};
|
|
3052
|
+
|
|
3053
|
+
// src/formation/resource/elb/load-balancer.ts
|
|
3054
|
+
var LoadBalancer = class extends Resource {
|
|
3055
|
+
constructor(logicalId, props) {
|
|
3056
|
+
super("AWS::ElasticLoadBalancingV2::LoadBalancer", logicalId);
|
|
3057
|
+
this.props = props;
|
|
3058
|
+
this.name = this.props.name || logicalId;
|
|
3059
|
+
}
|
|
3060
|
+
name;
|
|
3061
|
+
get arn() {
|
|
3062
|
+
return ref(this.logicalId);
|
|
3063
|
+
}
|
|
3064
|
+
get dnsName() {
|
|
3065
|
+
return getAtt(this.logicalId, "DNSName");
|
|
3066
|
+
}
|
|
3067
|
+
get hostedZoneId() {
|
|
3068
|
+
return getAtt(this.logicalId, "CanonicalHostedZoneID");
|
|
3069
|
+
}
|
|
3070
|
+
properties() {
|
|
3071
|
+
return {
|
|
3072
|
+
Name: this.name,
|
|
3073
|
+
Type: this.props.type,
|
|
3074
|
+
Scheme: this.props.schema || "internet-facing",
|
|
3075
|
+
SecurityGroups: this.props.securityGroups,
|
|
3076
|
+
Subnets: this.props.subnets
|
|
3077
|
+
};
|
|
3078
|
+
}
|
|
3079
|
+
};
|
|
3080
|
+
|
|
3081
|
+
// src/formation/resource/elb/listener.ts
|
|
3082
|
+
var import_change_case11 = require("change-case");
|
|
3083
|
+
var Listener = class extends Resource {
|
|
3084
|
+
constructor(logicalId, props) {
|
|
3085
|
+
super("AWS::ElasticLoadBalancingV2::Listener", logicalId);
|
|
3086
|
+
this.props = props;
|
|
3087
|
+
}
|
|
3088
|
+
get id() {
|
|
3089
|
+
return ref(this.logicalId);
|
|
3090
|
+
}
|
|
3091
|
+
get arn() {
|
|
3092
|
+
return getAtt(this.logicalId, "ListenerArn");
|
|
3093
|
+
}
|
|
3094
|
+
properties() {
|
|
3095
|
+
return {
|
|
3096
|
+
LoadBalancerArn: this.props.loadBalancerArn,
|
|
3097
|
+
Port: this.props.port,
|
|
3098
|
+
Protocol: (0, import_change_case11.constantCase)(this.props.protocol),
|
|
3099
|
+
Certificates: this.props.certificates.map((arn) => ({
|
|
3100
|
+
CertificateArn: arn
|
|
3101
|
+
})),
|
|
3102
|
+
...this.attr("DefaultActions", this.props.defaultActions?.map((action) => action.toJSON()))
|
|
3103
|
+
};
|
|
3104
|
+
}
|
|
3105
|
+
};
|
|
3106
|
+
var ListenerAction = class {
|
|
3107
|
+
constructor(props) {
|
|
3108
|
+
this.props = props;
|
|
3109
|
+
}
|
|
3110
|
+
static fixedResponse(statusCode, props = {}) {
|
|
3111
|
+
return new ListenerAction({
|
|
3112
|
+
type: "fixed-response",
|
|
3113
|
+
fixedResponse: {
|
|
3114
|
+
statusCode,
|
|
3115
|
+
...props
|
|
3116
|
+
}
|
|
3117
|
+
});
|
|
3118
|
+
}
|
|
3119
|
+
static forward(targets) {
|
|
3120
|
+
return new ListenerAction({
|
|
3121
|
+
type: "forward",
|
|
3122
|
+
forward: {
|
|
3123
|
+
targetGroups: targets
|
|
3124
|
+
}
|
|
3125
|
+
});
|
|
3126
|
+
}
|
|
3127
|
+
toJSON() {
|
|
3128
|
+
return {
|
|
3129
|
+
// AuthenticateCognitoConfig: AuthenticateCognitoConfig,
|
|
3130
|
+
// AuthenticateOidcConfig: AuthenticateOidcConfig,
|
|
3131
|
+
// RedirectConfig: RedirectConfig,
|
|
3132
|
+
Type: this.props.type,
|
|
3133
|
+
// Order: Integer,
|
|
3134
|
+
...this.props.type === "fixed-response" ? {
|
|
3135
|
+
FixedResponseConfig: {
|
|
3136
|
+
StatusCode: this.props.fixedResponse.statusCode,
|
|
3137
|
+
...this.props.fixedResponse.contentType ? {
|
|
3138
|
+
ContentType: this.props.fixedResponse.contentType
|
|
3139
|
+
} : {},
|
|
3140
|
+
...this.props.fixedResponse.messageBody ? {
|
|
3141
|
+
MessageBody: this.props.fixedResponse.messageBody
|
|
3142
|
+
} : {}
|
|
3143
|
+
}
|
|
3144
|
+
} : {},
|
|
3145
|
+
...this.props.type === "forward" ? {
|
|
3146
|
+
ForwardConfig: {
|
|
3147
|
+
TargetGroups: this.props.forward.targetGroups.map((target) => ({
|
|
3148
|
+
TargetGroupArn: target
|
|
3149
|
+
}))
|
|
3150
|
+
}
|
|
3151
|
+
} : {}
|
|
3152
|
+
};
|
|
3153
|
+
}
|
|
3154
|
+
};
|
|
3155
|
+
|
|
3156
|
+
// src/formation/resource/elb/listener-rule.ts
|
|
3157
|
+
var ListenerRule = class extends Resource {
|
|
3158
|
+
constructor(logicalId, props) {
|
|
3159
|
+
super("AWS::ElasticLoadBalancingV2::ListenerRule", logicalId);
|
|
3160
|
+
this.props = props;
|
|
3161
|
+
}
|
|
3162
|
+
get id() {
|
|
3163
|
+
return ref(this.logicalId);
|
|
3164
|
+
}
|
|
3165
|
+
get arn() {
|
|
3166
|
+
return getAtt(this.logicalId, "ListenerArn");
|
|
3167
|
+
}
|
|
3168
|
+
properties() {
|
|
3169
|
+
return {
|
|
3170
|
+
ListenerArn: this.props.listenerArn,
|
|
3171
|
+
Priority: this.props.priority,
|
|
3172
|
+
Conditions: this.props.conditions.map((condition) => condition.toJSON()),
|
|
3173
|
+
Actions: this.props.actions.map((action) => action.toJSON())
|
|
3174
|
+
};
|
|
3175
|
+
}
|
|
3176
|
+
};
|
|
3177
|
+
var ListenerCondition = class {
|
|
3178
|
+
constructor(props) {
|
|
3179
|
+
this.props = props;
|
|
3180
|
+
}
|
|
3181
|
+
static httpRequestMethods(methods) {
|
|
3182
|
+
return new ListenerCondition({
|
|
3183
|
+
field: "http-request-method",
|
|
3184
|
+
methods
|
|
3185
|
+
});
|
|
3186
|
+
}
|
|
3187
|
+
static pathPatterns(paths) {
|
|
3188
|
+
return new ListenerCondition({
|
|
3189
|
+
field: "path-pattern",
|
|
3190
|
+
paths
|
|
3191
|
+
});
|
|
3192
|
+
}
|
|
3193
|
+
toJSON() {
|
|
3194
|
+
return {
|
|
3195
|
+
Field: this.props.field,
|
|
3196
|
+
...this.props.field === "http-request-method" ? {
|
|
3197
|
+
HttpRequestMethodConfig: {
|
|
3198
|
+
Values: this.props.methods
|
|
3199
|
+
}
|
|
3200
|
+
} : {},
|
|
3201
|
+
...this.props.field === "path-pattern" ? {
|
|
3202
|
+
PathPatternConfig: {
|
|
3203
|
+
Values: this.props.paths
|
|
3204
|
+
}
|
|
3205
|
+
} : {}
|
|
3206
|
+
};
|
|
3207
|
+
}
|
|
3208
|
+
};
|
|
3209
|
+
|
|
3210
|
+
// src/formation/resource/elb/target-group.ts
|
|
3211
|
+
var TargetGroup = class extends Resource {
|
|
3212
|
+
constructor(logicalId, props) {
|
|
3213
|
+
super("AWS::ElasticLoadBalancingV2::TargetGroup", logicalId);
|
|
3214
|
+
this.props = props;
|
|
3215
|
+
this.name = formatName(this.props.name || logicalId);
|
|
3216
|
+
}
|
|
3217
|
+
name;
|
|
3218
|
+
get arn() {
|
|
3219
|
+
return ref(this.logicalId);
|
|
3220
|
+
}
|
|
3221
|
+
get fullName() {
|
|
3222
|
+
return getAtt(this.logicalId, "TargetGroupFullName");
|
|
3223
|
+
}
|
|
3224
|
+
properties() {
|
|
3225
|
+
return {
|
|
3226
|
+
Name: this.name,
|
|
3227
|
+
TargetType: this.props.type,
|
|
3228
|
+
Targets: this.props.targets.map((target) => ({
|
|
3229
|
+
Id: target
|
|
3230
|
+
}))
|
|
3231
|
+
};
|
|
3232
|
+
}
|
|
3233
|
+
};
|
|
3234
|
+
|
|
3235
|
+
// src/formation/resource/lambda/event-source/elb.ts
|
|
3236
|
+
var ElbEventSource = class extends Group {
|
|
3237
|
+
constructor(id, lambda, props) {
|
|
3238
|
+
const name = formatName(id);
|
|
3239
|
+
const permission = new Permission2(id, {
|
|
3240
|
+
action: "lambda:InvokeFunction",
|
|
3241
|
+
principal: "elasticloadbalancing.amazonaws.com",
|
|
3242
|
+
functionArn: lambda.arn,
|
|
3243
|
+
sourceArn: sub("arn:${AWS::Partition}:elasticloadbalancing:${AWS::Region}:${AWS::AccountId}:targetgroup/${name}/*", {
|
|
3244
|
+
name
|
|
3245
|
+
})
|
|
3246
|
+
}).dependsOn(lambda);
|
|
3247
|
+
const target = new TargetGroup(id, {
|
|
3248
|
+
name,
|
|
3249
|
+
type: "lambda",
|
|
3250
|
+
targets: [lambda.arn]
|
|
3251
|
+
}).dependsOn(lambda, permission);
|
|
3252
|
+
const rule = new ListenerRule(id, {
|
|
3253
|
+
listenerArn: props.listenerArn,
|
|
3254
|
+
priority: props.priority,
|
|
3255
|
+
conditions: props.conditions,
|
|
3256
|
+
actions: [
|
|
3257
|
+
ListenerAction.forward([target.arn])
|
|
3258
|
+
]
|
|
3259
|
+
}).dependsOn(target);
|
|
3260
|
+
super([target, rule, permission]);
|
|
3261
|
+
}
|
|
3262
|
+
};
|
|
3263
|
+
|
|
3264
|
+
// src/plugins/http.ts
|
|
3265
|
+
var RouteSchema = import_zod17.z.custom((route) => {
|
|
3266
|
+
return import_zod17.z.string().regex(/^(POST|GET|PUT|DELETE|HEAD|OPTIONS)(\s\/[a-z0-9\+\_\-\/]*)$/ig).safeParse(route).success;
|
|
3267
|
+
}, "Invalid route");
|
|
3268
|
+
var parseRoute = (route) => {
|
|
3269
|
+
const [method, ...paths] = route.split(" ");
|
|
3270
|
+
const path = paths.join(" ");
|
|
3271
|
+
return { method, path };
|
|
3272
|
+
};
|
|
3273
|
+
var strToInt = (str) => {
|
|
3274
|
+
return parseInt(Buffer.from(str, "utf8").toString("hex"), 16);
|
|
3275
|
+
};
|
|
3276
|
+
var generatePriority = (stackName, route) => {
|
|
3277
|
+
const start = strToInt(stackName) % 500 + 1;
|
|
3278
|
+
const end = strToInt(route) % 100;
|
|
3279
|
+
const priority = start + "" + end;
|
|
3280
|
+
return parseInt(priority, 10);
|
|
3281
|
+
};
|
|
3282
|
+
var httpPlugin = definePlugin({
|
|
3283
|
+
name: "http",
|
|
3284
|
+
schema: import_zod17.z.object({
|
|
3285
|
+
defaults: import_zod17.z.object({
|
|
3286
|
+
/** Define your global http api's.
|
|
3287
|
+
* @example
|
|
3288
|
+
* {
|
|
3289
|
+
* http: {
|
|
3290
|
+
* HTTP_API_NAME: {
|
|
3291
|
+
* domain: 'example.com',
|
|
3292
|
+
* subDomain: 'api',
|
|
3293
|
+
* }
|
|
3294
|
+
* }
|
|
3295
|
+
* }
|
|
3296
|
+
*/
|
|
3297
|
+
http: import_zod17.z.record(
|
|
3298
|
+
ResourceIdSchema,
|
|
3299
|
+
import_zod17.z.object({
|
|
3300
|
+
/** The domain to link your api with. */
|
|
3301
|
+
domain: import_zod17.z.string(),
|
|
3302
|
+
subDomain: import_zod17.z.string().optional()
|
|
3303
|
+
})
|
|
3304
|
+
).optional()
|
|
3305
|
+
}).default({}),
|
|
3306
|
+
stacks: import_zod17.z.object({
|
|
3307
|
+
/** Define routes in your stack for your global http api.
|
|
3308
|
+
* @example
|
|
3309
|
+
* {
|
|
3310
|
+
* http: {
|
|
3311
|
+
* HTTP_API_NAME: {
|
|
3312
|
+
* 'GET /': 'index.ts',
|
|
3313
|
+
* 'POST /posts': 'create-post.ts',
|
|
3314
|
+
* }
|
|
3315
|
+
* }
|
|
3316
|
+
* }
|
|
3317
|
+
*/
|
|
3318
|
+
http: import_zod17.z.record(
|
|
3319
|
+
ResourceIdSchema,
|
|
3320
|
+
import_zod17.z.record(RouteSchema, FunctionSchema)
|
|
3321
|
+
).optional()
|
|
3322
|
+
}).array()
|
|
3323
|
+
}),
|
|
3324
|
+
onApp({ config, bootstrap: bootstrap2, usEastBootstrap }) {
|
|
3325
|
+
if (Object.keys(config.defaults?.http || {}).length === 0) {
|
|
3326
|
+
return;
|
|
3327
|
+
}
|
|
3328
|
+
const vpcId = bootstrap2.get("vpc-id");
|
|
3329
|
+
const securityGroup = new SecurityGroup("http", {
|
|
3330
|
+
description: "http security group",
|
|
3331
|
+
vpcId
|
|
3332
|
+
});
|
|
3333
|
+
securityGroup.addIngressRule(Peer.anyIpv4(), Port.tcp(443));
|
|
3334
|
+
securityGroup.addIngressRule(Peer.anyIpv6(), Port.tcp(443));
|
|
3335
|
+
bootstrap2.add(securityGroup);
|
|
3336
|
+
for (const [id, props] of Object.entries(config.defaults?.http || {})) {
|
|
3337
|
+
const loadBalancer = new LoadBalancer(id, {
|
|
3338
|
+
name: `${config.name}-${id}`,
|
|
3339
|
+
type: "application",
|
|
3340
|
+
securityGroups: [securityGroup.id],
|
|
3341
|
+
subnets: [
|
|
3342
|
+
bootstrap2.get("public-subnet-1"),
|
|
3343
|
+
bootstrap2.get("public-subnet-2")
|
|
3344
|
+
]
|
|
3345
|
+
}).dependsOn(securityGroup);
|
|
3346
|
+
const listener = new Listener(id, {
|
|
3347
|
+
loadBalancerArn: loadBalancer.arn,
|
|
3348
|
+
port: 443,
|
|
3349
|
+
protocol: "https",
|
|
3350
|
+
certificates: [
|
|
3351
|
+
bootstrap2.get(`certificate-${props.domain}-arn`)
|
|
3352
|
+
],
|
|
3353
|
+
defaultActions: [
|
|
3354
|
+
ListenerAction.fixedResponse(404, {
|
|
3355
|
+
contentType: "application/json",
|
|
3356
|
+
messageBody: JSON.stringify({
|
|
3357
|
+
message: "Route not found"
|
|
3358
|
+
})
|
|
3359
|
+
})
|
|
3360
|
+
]
|
|
3361
|
+
}).dependsOn(loadBalancer);
|
|
3362
|
+
const record = new RecordSet(`${id}-http`, {
|
|
3363
|
+
hostedZoneId: usEastBootstrap.import(`hosted-zone-${props.domain}-id`),
|
|
3364
|
+
name: props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain,
|
|
3365
|
+
type: "A",
|
|
3366
|
+
alias: {
|
|
3367
|
+
hostedZoneId: loadBalancer.hostedZoneId,
|
|
3368
|
+
dnsName: loadBalancer.dnsName
|
|
3369
|
+
}
|
|
3370
|
+
}).dependsOn(loadBalancer);
|
|
3371
|
+
bootstrap2.add(loadBalancer, listener, record).export(`http-${id}-listener-arn`, listener.arn);
|
|
3372
|
+
}
|
|
3373
|
+
},
|
|
3374
|
+
onStack(ctx) {
|
|
3375
|
+
const { stack, stackConfig, bootstrap: bootstrap2 } = ctx;
|
|
3376
|
+
for (const [id, routes] of Object.entries(stackConfig.http || {})) {
|
|
3377
|
+
for (const [route, props] of Object.entries(routes)) {
|
|
3378
|
+
const { method, path } = parseRoute(route);
|
|
3379
|
+
const lambda = toLambdaFunction(ctx, `http-${id}`, props);
|
|
3380
|
+
const source = new ElbEventSource(`http-${id}-${route}`, lambda, {
|
|
3381
|
+
listenerArn: bootstrap2.import(`http-${id}-listener-arn`),
|
|
3382
|
+
priority: generatePriority(stackConfig.name, route),
|
|
3383
|
+
conditions: [
|
|
3384
|
+
ListenerCondition.httpRequestMethods([method]),
|
|
3385
|
+
ListenerCondition.pathPatterns([path])
|
|
3386
|
+
]
|
|
3387
|
+
});
|
|
3388
|
+
stack.add(lambda, source);
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
});
|
|
3393
|
+
|
|
3394
|
+
// src/plugins/search.ts
|
|
3395
|
+
var import_zod18 = require("zod");
|
|
3396
|
+
|
|
3397
|
+
// src/formation/resource/open-search-serverless/collection.ts
|
|
3398
|
+
var Collection = class extends Resource {
|
|
3399
|
+
constructor(logicalId, props) {
|
|
3400
|
+
super("AWS::OpenSearchServerless::Collection", logicalId);
|
|
3401
|
+
this.props = props;
|
|
3402
|
+
this.name = this.props.name || logicalId;
|
|
3403
|
+
}
|
|
3404
|
+
name;
|
|
3405
|
+
get id() {
|
|
3406
|
+
return ref(this.logicalId);
|
|
3407
|
+
}
|
|
3408
|
+
get arn() {
|
|
3409
|
+
return getAtt(this.logicalId, "Arn");
|
|
3410
|
+
}
|
|
3411
|
+
get endpoint() {
|
|
3412
|
+
return getAtt(this.logicalId, "CollectionEndpoint");
|
|
3413
|
+
}
|
|
3414
|
+
properties() {
|
|
3415
|
+
return {
|
|
3416
|
+
Name: this.name,
|
|
3417
|
+
Type: this.props.type.toUpperCase(),
|
|
3418
|
+
...this.attr("Description", this.props.description)
|
|
3419
|
+
};
|
|
3420
|
+
}
|
|
3421
|
+
};
|
|
3422
|
+
|
|
3423
|
+
// src/plugins/search.ts
|
|
3424
|
+
var searchPlugin = definePlugin({
|
|
3425
|
+
name: "search",
|
|
3426
|
+
schema: import_zod18.z.object({
|
|
3427
|
+
stacks: import_zod18.z.object({
|
|
3428
|
+
searchs: import_zod18.z.array(ResourceIdSchema).optional()
|
|
3429
|
+
}).array()
|
|
3430
|
+
}),
|
|
3431
|
+
onStack({ config, stack, stackConfig, bind }) {
|
|
3432
|
+
for (const id of stackConfig.searchs || []) {
|
|
3433
|
+
const collection = new Collection(id, {
|
|
3434
|
+
name: `${config.name}-${stack.name}-${id}`,
|
|
3435
|
+
type: "search"
|
|
3436
|
+
});
|
|
3437
|
+
bind((lambda) => {
|
|
3438
|
+
lambda.addPermissions({
|
|
3439
|
+
actions: ["aoss:APIAccessAll"],
|
|
3440
|
+
resources: [collection.arn]
|
|
3441
|
+
});
|
|
3442
|
+
});
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
});
|
|
2310
3446
|
|
|
2311
3447
|
// src/plugins/index.ts
|
|
2312
3448
|
var defaultPlugins = [
|
|
2313
3449
|
extendPlugin,
|
|
3450
|
+
vpcPlugin,
|
|
2314
3451
|
functionPlugin,
|
|
2315
3452
|
cronPlugin,
|
|
2316
3453
|
queuePlugin,
|
|
@@ -2318,10 +3455,11 @@ var defaultPlugins = [
|
|
|
2318
3455
|
storePlugin,
|
|
2319
3456
|
topicPlugin,
|
|
2320
3457
|
pubsubPlugin,
|
|
2321
|
-
|
|
3458
|
+
searchPlugin,
|
|
2322
3459
|
domainPlugin,
|
|
2323
|
-
graphqlPlugin
|
|
2324
|
-
|
|
3460
|
+
graphqlPlugin,
|
|
3461
|
+
httpPlugin,
|
|
3462
|
+
onFailurePlugin
|
|
2325
3463
|
];
|
|
2326
3464
|
|
|
2327
3465
|
// src/formation/app.ts
|
|
@@ -2348,23 +3486,6 @@ var App = class {
|
|
|
2348
3486
|
// }
|
|
2349
3487
|
};
|
|
2350
3488
|
|
|
2351
|
-
// src/formation/resource/cloud-formation/custom-resource.ts
|
|
2352
|
-
var CustomResource = class extends Resource {
|
|
2353
|
-
constructor(logicalId, props) {
|
|
2354
|
-
super("AWS::CloudFormation::CustomResource", logicalId);
|
|
2355
|
-
this.props = props;
|
|
2356
|
-
}
|
|
2357
|
-
getAtt(name) {
|
|
2358
|
-
return getAtt(this.logicalId, name);
|
|
2359
|
-
}
|
|
2360
|
-
properties() {
|
|
2361
|
-
return {
|
|
2362
|
-
ServiceToken: this.props.serviceToken,
|
|
2363
|
-
...this.props.properties
|
|
2364
|
-
};
|
|
2365
|
-
}
|
|
2366
|
-
};
|
|
2367
|
-
|
|
2368
3489
|
// src/custom/global-export/handler.ts
|
|
2369
3490
|
var globalExportsHandlerCode = (
|
|
2370
3491
|
/* JS */
|
|
@@ -2459,7 +3580,7 @@ var extendWithGlobalExports = (appName, importable, exportable) => {
|
|
|
2459
3580
|
region: importable.region
|
|
2460
3581
|
}
|
|
2461
3582
|
});
|
|
2462
|
-
exportable.add(crossRegionExports);
|
|
3583
|
+
exportable.add(lambda, crossRegionExports);
|
|
2463
3584
|
}
|
|
2464
3585
|
return crossRegionExports.getAtt(name);
|
|
2465
3586
|
};
|
|
@@ -2520,6 +3641,20 @@ var toApp = async (config, filters) => {
|
|
|
2520
3641
|
app.add(stack);
|
|
2521
3642
|
stacks.push({ stack, config: stackConfig });
|
|
2522
3643
|
}
|
|
3644
|
+
for (const plugin of plugins) {
|
|
3645
|
+
for (const stack of app.stacks) {
|
|
3646
|
+
for (const resource of stack) {
|
|
3647
|
+
plugin.onResource?.({
|
|
3648
|
+
config,
|
|
3649
|
+
app,
|
|
3650
|
+
stack,
|
|
3651
|
+
bootstrap: bootstrap2,
|
|
3652
|
+
usEastBootstrap,
|
|
3653
|
+
resource
|
|
3654
|
+
});
|
|
3655
|
+
}
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
2523
3658
|
const functions = app.find(Function);
|
|
2524
3659
|
for (const bind2 of bindings) {
|
|
2525
3660
|
for (const fn of functions) {
|
|
@@ -2566,17 +3701,17 @@ var getCredentials = (profile) => {
|
|
|
2566
3701
|
};
|
|
2567
3702
|
|
|
2568
3703
|
// src/schema/app.ts
|
|
2569
|
-
var
|
|
3704
|
+
var import_zod22 = require("zod");
|
|
2570
3705
|
|
|
2571
3706
|
// src/schema/stack.ts
|
|
2572
|
-
var
|
|
2573
|
-
var StackSchema =
|
|
3707
|
+
var import_zod19 = require("zod");
|
|
3708
|
+
var StackSchema = import_zod19.z.object({
|
|
2574
3709
|
name: ResourceIdSchema,
|
|
2575
|
-
depends:
|
|
3710
|
+
depends: import_zod19.z.array(import_zod19.z.lazy(() => StackSchema)).optional()
|
|
2576
3711
|
});
|
|
2577
3712
|
|
|
2578
3713
|
// src/schema/region.ts
|
|
2579
|
-
var
|
|
3714
|
+
var import_zod20 = require("zod");
|
|
2580
3715
|
var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
|
|
2581
3716
|
var AF = ["af-south-1"];
|
|
2582
3717
|
var AP = ["ap-east-1", "ap-south-2", "ap-southeast-3", "ap-southeast-4", "ap-south-1", "ap-northeast-3", "ap-northeast-2", "ap-southeast-1", "ap-southeast-2", "ap-northeast-1"];
|
|
@@ -2593,46 +3728,91 @@ var regions = [
|
|
|
2593
3728
|
...ME,
|
|
2594
3729
|
...SA
|
|
2595
3730
|
];
|
|
2596
|
-
var RegionSchema =
|
|
3731
|
+
var RegionSchema = import_zod20.z.enum(regions);
|
|
2597
3732
|
|
|
2598
3733
|
// src/schema/plugin.ts
|
|
2599
|
-
var
|
|
2600
|
-
var PluginSchema =
|
|
2601
|
-
name:
|
|
2602
|
-
schema:
|
|
3734
|
+
var import_zod21 = require("zod");
|
|
3735
|
+
var PluginSchema = import_zod21.z.object({
|
|
3736
|
+
name: import_zod21.z.string(),
|
|
3737
|
+
schema: import_zod21.z.custom().optional(),
|
|
2603
3738
|
// depends: z.array(z.lazy(() => PluginSchema)).optional(),
|
|
2604
|
-
|
|
2605
|
-
onStack:
|
|
2606
|
-
|
|
3739
|
+
onApp: import_zod21.z.function().returns(import_zod21.z.void()).optional(),
|
|
3740
|
+
onStack: import_zod21.z.function().returns(import_zod21.z.any()).optional(),
|
|
3741
|
+
onResource: import_zod21.z.function().returns(import_zod21.z.any()).optional()
|
|
2607
3742
|
// bind: z.function().optional(),
|
|
2608
3743
|
});
|
|
2609
3744
|
|
|
2610
3745
|
// src/schema/app.ts
|
|
2611
|
-
var AppSchema =
|
|
3746
|
+
var AppSchema = import_zod22.z.object({
|
|
3747
|
+
/** App name */
|
|
2612
3748
|
name: ResourceIdSchema,
|
|
3749
|
+
/** The AWS region to deploy to. */
|
|
2613
3750
|
region: RegionSchema,
|
|
2614
|
-
profile
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
3751
|
+
/** The AWS profile to deploy to. */
|
|
3752
|
+
profile: import_zod22.z.string(),
|
|
3753
|
+
/** The deployment stage.
|
|
3754
|
+
* @default 'prod'
|
|
3755
|
+
*/
|
|
3756
|
+
stage: import_zod22.z.string().regex(/[a-z]+/).default("prod"),
|
|
3757
|
+
/** Default properties. */
|
|
3758
|
+
defaults: import_zod22.z.object({}).default({}),
|
|
3759
|
+
/** The application stacks. */
|
|
3760
|
+
stacks: import_zod22.z.array(StackSchema).min(1).refine((stacks) => {
|
|
2618
3761
|
const unique = new Set(stacks.map((stack) => stack.name));
|
|
2619
3762
|
return unique.size === stacks.length;
|
|
2620
3763
|
}, "Must be an array of unique stacks"),
|
|
2621
|
-
plugins
|
|
3764
|
+
/** Custom plugins. */
|
|
3765
|
+
plugins: import_zod22.z.array(PluginSchema).optional()
|
|
2622
3766
|
});
|
|
2623
3767
|
|
|
2624
3768
|
// src/util/import.ts
|
|
2625
3769
|
var import_core = require("@swc/core");
|
|
2626
3770
|
var import_path2 = require("path");
|
|
2627
|
-
var
|
|
3771
|
+
var import_promises5 = require("fs/promises");
|
|
2628
3772
|
|
|
2629
3773
|
// src/util/path.ts
|
|
3774
|
+
var import_promises4 = require("fs/promises");
|
|
2630
3775
|
var import_path = require("path");
|
|
2631
|
-
var
|
|
2632
|
-
var
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
3776
|
+
var root = process.cwd();
|
|
3777
|
+
var directories = {
|
|
3778
|
+
root,
|
|
3779
|
+
get output() {
|
|
3780
|
+
return (0, import_path.join)(this.root, ".awsless");
|
|
3781
|
+
},
|
|
3782
|
+
get cache() {
|
|
3783
|
+
return (0, import_path.join)(this.output, "cache");
|
|
3784
|
+
},
|
|
3785
|
+
get asset() {
|
|
3786
|
+
return (0, import_path.join)(this.output, "asset");
|
|
3787
|
+
},
|
|
3788
|
+
get template() {
|
|
3789
|
+
return (0, import_path.join)(this.output, "template");
|
|
3790
|
+
}
|
|
3791
|
+
};
|
|
3792
|
+
var setRoot = (path = root) => {
|
|
3793
|
+
directories.root = path;
|
|
3794
|
+
};
|
|
3795
|
+
var findRootDir = async (path, configFile, level = 5) => {
|
|
3796
|
+
if (!level) {
|
|
3797
|
+
throw new TypeError("No awsless project found");
|
|
3798
|
+
}
|
|
3799
|
+
const file = (0, import_path.join)(path, configFile);
|
|
3800
|
+
const exists = await fileExist(file);
|
|
3801
|
+
if (exists) {
|
|
3802
|
+
return path;
|
|
3803
|
+
}
|
|
3804
|
+
return findRootDir((0, import_path.normalize)((0, import_path.join)(path, "..")), configFile, level - 1);
|
|
3805
|
+
};
|
|
3806
|
+
var fileExist = async (file) => {
|
|
3807
|
+
try {
|
|
3808
|
+
const stat = await (0, import_promises4.lstat)(file);
|
|
3809
|
+
if (stat.isFile()) {
|
|
3810
|
+
return true;
|
|
3811
|
+
}
|
|
3812
|
+
} catch (error) {
|
|
3813
|
+
}
|
|
3814
|
+
return false;
|
|
3815
|
+
};
|
|
2636
3816
|
|
|
2637
3817
|
// src/util/import.ts
|
|
2638
3818
|
var resolveFileNameExtension = async (path) => {
|
|
@@ -2647,7 +3827,7 @@ var resolveFileNameExtension = async (path) => {
|
|
|
2647
3827
|
const file = path.replace(/\.js$/, "") + option;
|
|
2648
3828
|
let stat;
|
|
2649
3829
|
try {
|
|
2650
|
-
stat = await (0,
|
|
3830
|
+
stat = await (0, import_promises5.lstat)(file);
|
|
2651
3831
|
} catch (error) {
|
|
2652
3832
|
continue;
|
|
2653
3833
|
}
|
|
@@ -2658,11 +3838,11 @@ var resolveFileNameExtension = async (path) => {
|
|
|
2658
3838
|
throw new Error(`Failed to load file: ${path}`);
|
|
2659
3839
|
};
|
|
2660
3840
|
var resolveDir = (path) => {
|
|
2661
|
-
return (0, import_path2.dirname)(path).replace(
|
|
3841
|
+
return (0, import_path2.dirname)(path).replace(directories.root + "/", "");
|
|
2662
3842
|
};
|
|
2663
3843
|
var importFile = async (path) => {
|
|
2664
3844
|
const load = async (file) => {
|
|
2665
|
-
debug("Load file", file);
|
|
3845
|
+
debug("Load file:", style.info(file));
|
|
2666
3846
|
let { code: code2 } = await (0, import_core.transformFile)(file, {
|
|
2667
3847
|
isModule: true
|
|
2668
3848
|
});
|
|
@@ -2682,16 +3862,22 @@ var importFile = async (path) => {
|
|
|
2682
3862
|
return code2;
|
|
2683
3863
|
};
|
|
2684
3864
|
const code = await load(path);
|
|
2685
|
-
const outputFile = (0, import_path2.join)(
|
|
2686
|
-
await (0,
|
|
2687
|
-
await (0,
|
|
3865
|
+
const outputFile = (0, import_path2.join)(directories.cache, "config.js");
|
|
3866
|
+
await (0, import_promises5.mkdir)(directories.cache, { recursive: true });
|
|
3867
|
+
await (0, import_promises5.writeFile)(outputFile, code);
|
|
3868
|
+
debug("Save config file:", style.info(outputFile));
|
|
2688
3869
|
return import(outputFile);
|
|
2689
3870
|
};
|
|
2690
3871
|
|
|
2691
3872
|
// src/config.ts
|
|
2692
3873
|
var importConfig = async (options) => {
|
|
3874
|
+
debug("Find the root directory");
|
|
3875
|
+
const configFile = options.configFile || "awsless.config.ts";
|
|
3876
|
+
const root2 = await findRootDir(process.cwd(), configFile);
|
|
3877
|
+
setRoot(root2);
|
|
3878
|
+
debug("CWD:", style.info(root2));
|
|
2693
3879
|
debug("Import config file");
|
|
2694
|
-
const fileName = (0, import_path4.join)(
|
|
3880
|
+
const fileName = (0, import_path4.join)(root2, configFile);
|
|
2695
3881
|
const module2 = await importFile(fileName);
|
|
2696
3882
|
const appConfig = typeof module2.default === "function" ? await module2.default(options) : module2.default;
|
|
2697
3883
|
debug("Validate config file");
|
|
@@ -3191,7 +4377,7 @@ var layout = async (cb) => {
|
|
|
3191
4377
|
};
|
|
3192
4378
|
|
|
3193
4379
|
// src/cli/ui/complex/builder.ts
|
|
3194
|
-
var
|
|
4380
|
+
var import_promises6 = require("fs/promises");
|
|
3195
4381
|
|
|
3196
4382
|
// src/cli/ui/layout/flex-line.ts
|
|
3197
4383
|
var stripEscapeCode = (str) => {
|
|
@@ -3214,7 +4400,7 @@ var flexLine = (term, left, right, reserveSpace = 0) => {
|
|
|
3214
4400
|
};
|
|
3215
4401
|
|
|
3216
4402
|
// src/cli/ui/complex/builder.ts
|
|
3217
|
-
var
|
|
4403
|
+
var import_path7 = require("path");
|
|
3218
4404
|
var assetBuilder = (app) => {
|
|
3219
4405
|
return async (term) => {
|
|
3220
4406
|
const assets = [];
|
|
@@ -3265,7 +4451,7 @@ var assetBuilder = (app) => {
|
|
|
3265
4451
|
derive([details], (details2) => {
|
|
3266
4452
|
return Object.entries(details2).map(([key, value]) => {
|
|
3267
4453
|
return `${style.label(key)} ${value}`;
|
|
3268
|
-
}).join("
|
|
4454
|
+
}).join(style.placeholder(" \u2500 "));
|
|
3269
4455
|
}),
|
|
3270
4456
|
br()
|
|
3271
4457
|
]);
|
|
@@ -3273,10 +4459,10 @@ var assetBuilder = (app) => {
|
|
|
3273
4459
|
const timer = createTimer();
|
|
3274
4460
|
const data = await asset.build({
|
|
3275
4461
|
async write(file, data2) {
|
|
3276
|
-
const fullpath = (0,
|
|
3277
|
-
const basepath = (0,
|
|
3278
|
-
await (0,
|
|
3279
|
-
await (0,
|
|
4462
|
+
const fullpath = (0, import_path7.join)(directories.asset, asset.type, app.name, stack.name, asset.id, file);
|
|
4463
|
+
const basepath = (0, import_path7.dirname)(fullpath);
|
|
4464
|
+
await (0, import_promises6.mkdir)(basepath, { recursive: true });
|
|
4465
|
+
await (0, import_promises6.writeFile)(fullpath, data2);
|
|
3280
4466
|
}
|
|
3281
4467
|
});
|
|
3282
4468
|
details.set({
|
|
@@ -3293,36 +4479,36 @@ var assetBuilder = (app) => {
|
|
|
3293
4479
|
};
|
|
3294
4480
|
|
|
3295
4481
|
// src/util/cleanup.ts
|
|
3296
|
-
var
|
|
4482
|
+
var import_promises7 = require("fs/promises");
|
|
3297
4483
|
var cleanUp = async () => {
|
|
3298
4484
|
debug("Clean up template, cache, and asset files");
|
|
3299
4485
|
const paths = [
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
4486
|
+
directories.asset,
|
|
4487
|
+
directories.cache,
|
|
4488
|
+
directories.template
|
|
3303
4489
|
];
|
|
3304
|
-
await Promise.all(paths.map((path) => (0,
|
|
4490
|
+
await Promise.all(paths.map((path) => (0, import_promises7.rm)(path, {
|
|
3305
4491
|
recursive: true,
|
|
3306
4492
|
force: true,
|
|
3307
4493
|
maxRetries: 2
|
|
3308
4494
|
})));
|
|
3309
|
-
await Promise.all(paths.map((path) => (0,
|
|
4495
|
+
await Promise.all(paths.map((path) => (0, import_promises7.mkdir)(path, {
|
|
3310
4496
|
recursive: true
|
|
3311
4497
|
})));
|
|
3312
4498
|
};
|
|
3313
4499
|
|
|
3314
4500
|
// src/cli/ui/complex/template.ts
|
|
3315
|
-
var
|
|
3316
|
-
var
|
|
4501
|
+
var import_promises8 = require("fs/promises");
|
|
4502
|
+
var import_path10 = require("path");
|
|
3317
4503
|
var templateBuilder = (app) => {
|
|
3318
4504
|
return async (term) => {
|
|
3319
4505
|
const done = term.out.write(loadingDialog("Building stack templates..."));
|
|
3320
4506
|
await Promise.all(app.stacks.map(async (stack) => {
|
|
3321
4507
|
const template = stack.toString(true);
|
|
3322
|
-
const path = (0,
|
|
3323
|
-
const file = (0,
|
|
3324
|
-
await (0,
|
|
3325
|
-
await (0,
|
|
4508
|
+
const path = (0, import_path10.join)(directories.template, app.name);
|
|
4509
|
+
const file = (0, import_path10.join)(path, `${stack.name}.json`);
|
|
4510
|
+
await (0, import_promises8.mkdir)(path, { recursive: true });
|
|
4511
|
+
await (0, import_promises8.writeFile)(file, template);
|
|
3326
4512
|
}));
|
|
3327
4513
|
done("Done building stack templates");
|
|
3328
4514
|
};
|
|
@@ -3370,7 +4556,7 @@ var shouldDeployBootstrap = async (client, stack) => {
|
|
|
3370
4556
|
// src/formation/client.ts
|
|
3371
4557
|
var import_client_cloudformation = require("@aws-sdk/client-cloudformation");
|
|
3372
4558
|
var import_client_s3 = require("@aws-sdk/client-s3");
|
|
3373
|
-
var
|
|
4559
|
+
var import_change_case12 = require("change-case");
|
|
3374
4560
|
var StackClient = class {
|
|
3375
4561
|
constructor(app, account, region, credentials) {
|
|
3376
4562
|
this.app = app;
|
|
@@ -3403,7 +4589,7 @@ var StackClient = class {
|
|
|
3403
4589
|
};
|
|
3404
4590
|
}
|
|
3405
4591
|
stackName(stackName) {
|
|
3406
|
-
return (0,
|
|
4592
|
+
return (0, import_change_case12.paramCase)(`${this.app.name}-${stackName}`);
|
|
3407
4593
|
}
|
|
3408
4594
|
tags(stack) {
|
|
3409
4595
|
const tags = [];
|
|
@@ -3448,19 +4634,26 @@ var StackClient = class {
|
|
|
3448
4634
|
async update(stack, capabilities) {
|
|
3449
4635
|
debug("Update the", style.info(stack.name), "stack");
|
|
3450
4636
|
const client = this.getClient(stack.region);
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
4637
|
+
try {
|
|
4638
|
+
await client.send(new import_client_cloudformation.UpdateStackCommand({
|
|
4639
|
+
StackName: this.stackName(stack.name),
|
|
4640
|
+
Capabilities: capabilities,
|
|
4641
|
+
Tags: this.tags(stack),
|
|
4642
|
+
...this.templateProp(stack)
|
|
4643
|
+
}));
|
|
4644
|
+
await (0, import_client_cloudformation.waitUntilStackUpdateComplete)({
|
|
4645
|
+
client,
|
|
4646
|
+
maxWaitTime: this.maxWaitTime,
|
|
4647
|
+
maxDelay: this.maxDelay
|
|
4648
|
+
}, {
|
|
4649
|
+
StackName: this.stackName(stack.name)
|
|
4650
|
+
});
|
|
4651
|
+
} catch (error) {
|
|
4652
|
+
if (error instanceof Error && error.name === "ValidationError" && error.message.toLowerCase().includes("no updates")) {
|
|
4653
|
+
return;
|
|
4654
|
+
}
|
|
4655
|
+
throw error;
|
|
4656
|
+
}
|
|
3464
4657
|
}
|
|
3465
4658
|
async validate(stack) {
|
|
3466
4659
|
debug("Validate the", style.info(stack.name), "stack");
|
|
@@ -3746,8 +4939,8 @@ var status = (program2) => {
|
|
|
3746
4939
|
};
|
|
3747
4940
|
|
|
3748
4941
|
// src/cli/ui/complex/publisher.ts
|
|
3749
|
-
var
|
|
3750
|
-
var
|
|
4942
|
+
var import_promises9 = require("fs/promises");
|
|
4943
|
+
var import_path12 = require("path");
|
|
3751
4944
|
var import_client_s32 = require("@aws-sdk/client-s3");
|
|
3752
4945
|
var assetPublisher = (config, app) => {
|
|
3753
4946
|
const client = new import_client_s32.S3Client({
|
|
@@ -3760,8 +4953,8 @@ var assetPublisher = (config, app) => {
|
|
|
3760
4953
|
await Promise.all([...stack.assets].map(async (asset) => {
|
|
3761
4954
|
await asset.publish?.({
|
|
3762
4955
|
async read(file) {
|
|
3763
|
-
const path = (0,
|
|
3764
|
-
const data = await (0,
|
|
4956
|
+
const path = (0, import_path12.join)(directories.asset, asset.type, app.name, stack.name, asset.id, file);
|
|
4957
|
+
const data = await (0, import_promises9.readFile)(path);
|
|
3765
4958
|
return data;
|
|
3766
4959
|
},
|
|
3767
4960
|
async publish(name, data, hash) {
|