@awsless/awsless 0.0.43 → 0.0.45
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 +21 -2
- package/dist/bin.js +1741 -688
- package/dist/features/delete-bucket.js +86 -0
- package/dist/features/delete-hosted-zone.js +127 -0
- package/dist/features/global-exports.js +61 -0
- package/dist/features/upload-bucket-asset.js +28384 -0
- package/dist/index.d.ts +1375 -385
- package/dist/index.js +40 -4
- package/package.json +17 -8
- package/dist/bin.cjs +0 -6173
- package/dist/index.cjs +0 -235
package/dist/bin.js
CHANGED
|
@@ -54,90 +54,6 @@ var flushDebug = () => {
|
|
|
54
54
|
return queue.splice(0, queue.length);
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
// src/util/param.ts
|
|
58
|
-
import { DeleteParameterCommand, GetParameterCommand, GetParametersByPathCommand, ParameterType, PutParameterCommand, SSMClient } from "@aws-sdk/client-ssm";
|
|
59
|
-
var configParameterPrefix = (config) => {
|
|
60
|
-
return `/.awsless/${config.name}`;
|
|
61
|
-
};
|
|
62
|
-
var Params = class {
|
|
63
|
-
constructor(config) {
|
|
64
|
-
this.config = config;
|
|
65
|
-
this.client = new SSMClient({
|
|
66
|
-
credentials: config.credentials,
|
|
67
|
-
region: config.region
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
client;
|
|
71
|
-
getName(name) {
|
|
72
|
-
return `${configParameterPrefix(this.config)}/${name}`;
|
|
73
|
-
}
|
|
74
|
-
async get(name) {
|
|
75
|
-
debug("Get remote config value");
|
|
76
|
-
debug("Name:", style.info(name));
|
|
77
|
-
let result;
|
|
78
|
-
try {
|
|
79
|
-
result = await this.client.send(new GetParameterCommand({
|
|
80
|
-
Name: this.getName(name),
|
|
81
|
-
WithDecryption: true
|
|
82
|
-
}));
|
|
83
|
-
} catch (error) {
|
|
84
|
-
if (error instanceof Error && error.name === "ParameterNotFound") {
|
|
85
|
-
debug("Parameter not found");
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
throw error;
|
|
89
|
-
}
|
|
90
|
-
const value = result.Parameter?.Value;
|
|
91
|
-
debug("Value:", style.info(value));
|
|
92
|
-
debug("Done getting remote config value");
|
|
93
|
-
return value;
|
|
94
|
-
}
|
|
95
|
-
async set(name, value) {
|
|
96
|
-
debug("Save remote config value");
|
|
97
|
-
debug("Name:", style.info(name));
|
|
98
|
-
debug("Value:", style.info(value));
|
|
99
|
-
await this.client.send(new PutParameterCommand({
|
|
100
|
-
Type: ParameterType.STRING,
|
|
101
|
-
Name: this.getName(name),
|
|
102
|
-
Value: value,
|
|
103
|
-
Overwrite: true
|
|
104
|
-
}));
|
|
105
|
-
debug("Done saving remote config value");
|
|
106
|
-
}
|
|
107
|
-
async delete(name) {
|
|
108
|
-
debug("Delete remote config value");
|
|
109
|
-
debug("Name:", style.info(name));
|
|
110
|
-
try {
|
|
111
|
-
await this.client.send(new DeleteParameterCommand({
|
|
112
|
-
Name: this.getName(name)
|
|
113
|
-
}));
|
|
114
|
-
} catch (error) {
|
|
115
|
-
if (error instanceof Error && error.name === "ParameterNotFound") {
|
|
116
|
-
debug("Remote config value was already deleted");
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
throw error;
|
|
120
|
-
}
|
|
121
|
-
debug("Done deleting remote config value");
|
|
122
|
-
}
|
|
123
|
-
async list() {
|
|
124
|
-
debug("Load remote config values");
|
|
125
|
-
const result = await this.client.send(new GetParametersByPathCommand({
|
|
126
|
-
Path: configParameterPrefix(this.config),
|
|
127
|
-
WithDecryption: true,
|
|
128
|
-
MaxResults: 10,
|
|
129
|
-
Recursive: true
|
|
130
|
-
}));
|
|
131
|
-
debug("Done loading remote config values");
|
|
132
|
-
const values = {};
|
|
133
|
-
result.Parameters?.forEach((param) => {
|
|
134
|
-
const name = param.Name.substring(configParameterPrefix(this.config).length).substring(1);
|
|
135
|
-
values[name] = param.Value || "";
|
|
136
|
-
});
|
|
137
|
-
return values;
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
|
|
141
57
|
// src/formation/asset.ts
|
|
142
58
|
import { paramCase } from "change-case";
|
|
143
59
|
var Asset = class {
|
|
@@ -159,13 +75,20 @@ var sub = (value, params) => {
|
|
|
159
75
|
}
|
|
160
76
|
return { "Fn::Sub": value };
|
|
161
77
|
};
|
|
78
|
+
var split = (seperator, value) => {
|
|
79
|
+
return { "Fn::Split": [seperator, value] };
|
|
80
|
+
};
|
|
81
|
+
var select = (index, value) => {
|
|
82
|
+
return { "Fn::Select": [index, value] };
|
|
83
|
+
};
|
|
162
84
|
var getAtt = (logicalId, attr) => {
|
|
163
85
|
return { "Fn::GetAtt": [logicalId, attr] };
|
|
164
86
|
};
|
|
87
|
+
var lazy = (cb) => {
|
|
88
|
+
return new Lazy(cb);
|
|
89
|
+
};
|
|
165
90
|
var importValue = (name) => {
|
|
166
|
-
return
|
|
167
|
-
"Fn::ImportValue": `${stack.app.name}-${name}`
|
|
168
|
-
}));
|
|
91
|
+
return { "Fn::ImportValue": name };
|
|
169
92
|
};
|
|
170
93
|
var formatLogicalId = (id) => {
|
|
171
94
|
return pascalCase(id).replaceAll("_", "");
|
|
@@ -191,6 +114,10 @@ var Resource = class {
|
|
|
191
114
|
tags = /* @__PURE__ */ new Map();
|
|
192
115
|
deps = /* @__PURE__ */ new Set();
|
|
193
116
|
stack;
|
|
117
|
+
addChild(...children) {
|
|
118
|
+
this.children.push(...children);
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
194
121
|
dependsOn(...dependencies) {
|
|
195
122
|
for (const dependency of dependencies) {
|
|
196
123
|
this.deps.add(dependency);
|
|
@@ -259,13 +186,33 @@ var Lazy = class {
|
|
|
259
186
|
}
|
|
260
187
|
};
|
|
261
188
|
|
|
189
|
+
// src/formation/resource/cloud-watch/log-group.ts
|
|
190
|
+
var LogGroup = class extends Resource {
|
|
191
|
+
constructor(logicalId, props) {
|
|
192
|
+
super("AWS::Logs::LogGroup", logicalId);
|
|
193
|
+
this.props = props;
|
|
194
|
+
}
|
|
195
|
+
get arn() {
|
|
196
|
+
return getAtt(this.logicalId, "Arn");
|
|
197
|
+
}
|
|
198
|
+
properties() {
|
|
199
|
+
return {
|
|
200
|
+
LogGroupName: this.props.name,
|
|
201
|
+
...this.attr("RetentionInDays", this.props.retention?.toDays())
|
|
202
|
+
// KmsKeyId: String
|
|
203
|
+
// DataProtectionPolicy : Json,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
262
208
|
// src/formation/resource/iam/inline-policy.ts
|
|
263
209
|
var InlinePolicy = class {
|
|
210
|
+
name;
|
|
211
|
+
statements;
|
|
264
212
|
constructor(name, props = {}) {
|
|
265
|
-
this.name = name;
|
|
266
213
|
this.statements = props.statements || [];
|
|
214
|
+
this.name = formatName(name);
|
|
267
215
|
}
|
|
268
|
-
statements;
|
|
269
216
|
addStatement(...statements) {
|
|
270
217
|
this.statements.push(...statements.flat());
|
|
271
218
|
return this;
|
|
@@ -285,28 +232,12 @@ var InlinePolicy = class {
|
|
|
285
232
|
}
|
|
286
233
|
};
|
|
287
234
|
|
|
288
|
-
// src/formation/resource/iam/managed-policy.ts
|
|
289
|
-
var ManagedPolicy = class {
|
|
290
|
-
constructor(arn) {
|
|
291
|
-
this.arn = arn;
|
|
292
|
-
}
|
|
293
|
-
static fromAwsManagedPolicyName(name) {
|
|
294
|
-
const arn = sub("arn:${AWS::Partition}:iam::aws:policy/service-role/" + name);
|
|
295
|
-
return new ManagedPolicy(arn);
|
|
296
|
-
}
|
|
297
|
-
static fromManagedPolicyArn(arn) {
|
|
298
|
-
return new ManagedPolicy(arn);
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
|
|
302
235
|
// src/formation/resource/iam/role.ts
|
|
303
236
|
var Role = class extends Resource {
|
|
304
237
|
constructor(logicalId, props = {}) {
|
|
305
238
|
super("AWS::IAM::Role", logicalId);
|
|
306
239
|
this.props = props;
|
|
307
|
-
this.name = formatName(logicalId);
|
|
308
240
|
}
|
|
309
|
-
name;
|
|
310
241
|
inlinePolicies = /* @__PURE__ */ new Set();
|
|
311
242
|
managedPolicies = /* @__PURE__ */ new Set();
|
|
312
243
|
get arn() {
|
|
@@ -344,16 +275,44 @@ var Role = class extends Resource {
|
|
|
344
275
|
}
|
|
345
276
|
};
|
|
346
277
|
|
|
278
|
+
// src/formation/resource/lambda/url.ts
|
|
279
|
+
import { constantCase } from "change-case";
|
|
280
|
+
var Url = class extends Resource {
|
|
281
|
+
constructor(logicalId, props) {
|
|
282
|
+
super("AWS::Lambda::Url", logicalId);
|
|
283
|
+
this.props = props;
|
|
284
|
+
}
|
|
285
|
+
get url() {
|
|
286
|
+
return getAtt(this.logicalId, "FunctionUrl");
|
|
287
|
+
}
|
|
288
|
+
properties() {
|
|
289
|
+
return {
|
|
290
|
+
AuthType: constantCase(this.props.authType ?? "none"),
|
|
291
|
+
InvokeMode: constantCase(this.props.invokeMode ?? "buffered"),
|
|
292
|
+
TargetFunctionArn: this.props.target,
|
|
293
|
+
...this.attr("Qualifier", this.props.qualifier),
|
|
294
|
+
Cors: {
|
|
295
|
+
...this.attr("AllowCredentials", this.props.cors?.allow?.credentials),
|
|
296
|
+
...this.attr("AllowHeaders", this.props.cors?.allow?.headers),
|
|
297
|
+
...this.attr("AllowMethods", this.props.cors?.allow?.methods),
|
|
298
|
+
...this.attr("AllowOrigins", this.props.cors?.allow?.origins),
|
|
299
|
+
...this.attr("ExposeHeaders", this.props.cors?.expose?.headers),
|
|
300
|
+
...this.attr("MaxAge", this.props.cors?.maxAge?.toSeconds())
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
|
|
347
306
|
// src/formation/resource/lambda/function.ts
|
|
348
307
|
var Function = class extends Resource {
|
|
349
|
-
constructor(
|
|
350
|
-
const policy = new InlinePolicy(
|
|
351
|
-
const role = new Role(
|
|
308
|
+
constructor(_logicalId, props) {
|
|
309
|
+
const policy = new InlinePolicy(_logicalId);
|
|
310
|
+
const role = new Role(_logicalId, {
|
|
352
311
|
assumedBy: "lambda.amazonaws.com"
|
|
353
312
|
});
|
|
354
313
|
role.addInlinePolicy(policy);
|
|
355
|
-
|
|
356
|
-
|
|
314
|
+
super("AWS::Lambda::Function", _logicalId, [role]);
|
|
315
|
+
this._logicalId = _logicalId;
|
|
357
316
|
this.props = props;
|
|
358
317
|
if (props.code instanceof Asset) {
|
|
359
318
|
this.children.push(props.code);
|
|
@@ -361,7 +320,7 @@ var Function = class extends Resource {
|
|
|
361
320
|
this.dependsOn(role);
|
|
362
321
|
this.role = role;
|
|
363
322
|
this.policy = policy;
|
|
364
|
-
this.name = formatName(this.props.name ||
|
|
323
|
+
this.name = formatName(this.props.name || _logicalId);
|
|
365
324
|
this.environmentVariables = props.environment ? { ...props.environment } : {};
|
|
366
325
|
this.tag("name", this.name);
|
|
367
326
|
}
|
|
@@ -369,6 +328,29 @@ var Function = class extends Resource {
|
|
|
369
328
|
role;
|
|
370
329
|
policy;
|
|
371
330
|
environmentVariables;
|
|
331
|
+
enableLogs(retention) {
|
|
332
|
+
const logGroup = new LogGroup(this._logicalId, {
|
|
333
|
+
name: sub("/aws/lambda/${name}", {
|
|
334
|
+
name: this.name
|
|
335
|
+
}),
|
|
336
|
+
retention
|
|
337
|
+
});
|
|
338
|
+
this.addChild(logGroup);
|
|
339
|
+
this.addPermissions({
|
|
340
|
+
actions: ["logs:CreateLogStream"],
|
|
341
|
+
resources: [logGroup.arn]
|
|
342
|
+
}, {
|
|
343
|
+
actions: ["logs:PutLogEvents"],
|
|
344
|
+
resources: [sub("${arn}:*", { arn: logGroup.arn })]
|
|
345
|
+
});
|
|
346
|
+
return this;
|
|
347
|
+
}
|
|
348
|
+
addUrl(props = {}) {
|
|
349
|
+
return new Url(this._logicalId, {
|
|
350
|
+
...props,
|
|
351
|
+
target: this.arn
|
|
352
|
+
}).dependsOn(this);
|
|
353
|
+
}
|
|
372
354
|
addPermissions(...permissions) {
|
|
373
355
|
this.policy.addStatement(...permissions);
|
|
374
356
|
return this;
|
|
@@ -477,7 +459,12 @@ var Stack = class {
|
|
|
477
459
|
if (!this.exports.has(name)) {
|
|
478
460
|
throw new Error(`Undefined export value: ${name}`);
|
|
479
461
|
}
|
|
480
|
-
return
|
|
462
|
+
return lazy((stack) => {
|
|
463
|
+
if (stack === this) {
|
|
464
|
+
return this.exports.get(name);
|
|
465
|
+
}
|
|
466
|
+
return importValue(`${stack.app?.name ?? "default"}-${name}`);
|
|
467
|
+
});
|
|
481
468
|
}
|
|
482
469
|
tag(name, value) {
|
|
483
470
|
this.tags.set(name, value);
|
|
@@ -498,32 +485,33 @@ var Stack = class {
|
|
|
498
485
|
toJSON() {
|
|
499
486
|
const resources = {};
|
|
500
487
|
const outputs = {};
|
|
501
|
-
const walk = (
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
walk(value);
|
|
488
|
+
const walk = (node) => {
|
|
489
|
+
if (node instanceof Lazy) {
|
|
490
|
+
return walk(node.callback(this));
|
|
491
|
+
}
|
|
492
|
+
if (Array.isArray(node)) {
|
|
493
|
+
return node.map(walk);
|
|
494
|
+
}
|
|
495
|
+
if (typeof node === "object" && node !== null) {
|
|
496
|
+
const object = {};
|
|
497
|
+
for (const [key, value] of Object.entries(node)) {
|
|
498
|
+
object[key] = walk(value);
|
|
512
499
|
}
|
|
500
|
+
return object;
|
|
513
501
|
}
|
|
502
|
+
return node;
|
|
514
503
|
};
|
|
515
504
|
for (const resource of this.resources) {
|
|
516
|
-
const json2 = resource.toJSON();
|
|
517
|
-
walk(json2);
|
|
505
|
+
const json2 = walk(resource.toJSON());
|
|
518
506
|
Object.assign(resources, json2);
|
|
519
507
|
}
|
|
520
|
-
for (
|
|
508
|
+
for (let [name, value] of this.exports.entries()) {
|
|
521
509
|
Object.assign(outputs, {
|
|
522
510
|
[formatLogicalId(name)]: {
|
|
523
511
|
Export: {
|
|
524
|
-
Name: `${this.app?.name
|
|
512
|
+
Name: `${this.app?.name ?? "default"}-${name}`
|
|
525
513
|
},
|
|
526
|
-
Value: value
|
|
514
|
+
Value: walk(value)
|
|
527
515
|
}
|
|
528
516
|
});
|
|
529
517
|
}
|
|
@@ -571,18 +559,6 @@ var toStack = ({ config, app, stackConfig, bootstrap: bootstrap2, usEastBootstra
|
|
|
571
559
|
bind2(fn);
|
|
572
560
|
}
|
|
573
561
|
}
|
|
574
|
-
for (const fn of functions) {
|
|
575
|
-
fn.addPermissions({
|
|
576
|
-
actions: [
|
|
577
|
-
"ssm:GetParameter",
|
|
578
|
-
"ssm:GetParameters",
|
|
579
|
-
"ssm:GetParametersByPath"
|
|
580
|
-
],
|
|
581
|
-
resources: [
|
|
582
|
-
sub("arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter" + configParameterPrefix(config))
|
|
583
|
-
]
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
562
|
return {
|
|
587
563
|
stack,
|
|
588
564
|
bindings
|
|
@@ -735,21 +711,21 @@ var durationMax = (max) => {
|
|
|
735
711
|
};
|
|
736
712
|
|
|
737
713
|
// src/schema/local-file.ts
|
|
738
|
-
import {
|
|
714
|
+
import { stat } from "fs/promises";
|
|
739
715
|
import { z as z3 } from "zod";
|
|
740
716
|
var LocalFileSchema = z3.string().refine(async (path) => {
|
|
741
717
|
try {
|
|
742
|
-
await
|
|
718
|
+
const s = await stat(path);
|
|
719
|
+
return s.isFile();
|
|
743
720
|
} catch (error) {
|
|
744
721
|
return false;
|
|
745
722
|
}
|
|
746
|
-
return true;
|
|
747
723
|
}, `File doesn't exist`);
|
|
748
724
|
|
|
749
725
|
// src/schema/resource-id.ts
|
|
750
726
|
import { paramCase as paramCase3 } from "change-case";
|
|
751
727
|
import { z as z4 } from "zod";
|
|
752
|
-
var ResourceIdSchema = z4.string().min(3).max(24).regex(/^[a-
|
|
728
|
+
var ResourceIdSchema = z4.string().min(3).max(24).regex(/^[a-z0-9\-]+$/i, "Invalid resource ID").transform((value) => paramCase3(value));
|
|
753
729
|
|
|
754
730
|
// src/schema/size.ts
|
|
755
731
|
import { z as z5 } from "zod";
|
|
@@ -827,49 +803,54 @@ import json from "@rollup/plugin-json";
|
|
|
827
803
|
import commonjs from "@rollup/plugin-commonjs";
|
|
828
804
|
import nodeResolve from "@rollup/plugin-node-resolve";
|
|
829
805
|
import { dirname } from "path";
|
|
830
|
-
var rollupBundle =
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
minify
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
806
|
+
var rollupBundle = ({ format: format2 = "esm", minify = true, handler = "index.default" } = {}) => {
|
|
807
|
+
return async (input) => {
|
|
808
|
+
const bundle = await rollup({
|
|
809
|
+
input,
|
|
810
|
+
external: (importee) => {
|
|
811
|
+
return importee.startsWith("@aws-sdk") || importee.startsWith("aws-sdk");
|
|
812
|
+
},
|
|
813
|
+
onwarn: (error) => {
|
|
814
|
+
debugError(error.message);
|
|
815
|
+
},
|
|
816
|
+
treeshake: {
|
|
817
|
+
moduleSideEffects: (id) => input === id
|
|
818
|
+
},
|
|
819
|
+
plugins: [
|
|
820
|
+
// @ts-ignore
|
|
821
|
+
commonjs({ sourceMap: true }),
|
|
822
|
+
// @ts-ignore
|
|
823
|
+
nodeResolve({ preferBuiltins: true }),
|
|
824
|
+
swc({
|
|
825
|
+
minify,
|
|
826
|
+
jsc: {
|
|
827
|
+
baseUrl: dirname(input),
|
|
828
|
+
minify: { sourceMap: true }
|
|
829
|
+
},
|
|
830
|
+
sourceMaps: true
|
|
831
|
+
}),
|
|
832
|
+
// @ts-ignore
|
|
833
|
+
json()
|
|
834
|
+
]
|
|
835
|
+
});
|
|
836
|
+
const result = await bundle.generate({
|
|
837
|
+
format: format2,
|
|
838
|
+
sourcemap: "hidden",
|
|
839
|
+
exports: "auto"
|
|
840
|
+
});
|
|
841
|
+
const output = result.output[0];
|
|
842
|
+
const code = Buffer.from(output.code, "utf8");
|
|
843
|
+
const map = output.map ? Buffer.from(output.map.toString(), "utf8") : void 0;
|
|
844
|
+
const hash = createHash("sha1").update(code).digest("hex");
|
|
845
|
+
return {
|
|
846
|
+
handler,
|
|
847
|
+
hash,
|
|
848
|
+
files: [{
|
|
849
|
+
name: format2 === "esm" ? "index.mjs" : "index.js",
|
|
850
|
+
code,
|
|
851
|
+
map
|
|
852
|
+
}]
|
|
853
|
+
};
|
|
873
854
|
};
|
|
874
855
|
};
|
|
875
856
|
|
|
@@ -890,6 +871,8 @@ var zipFiles = (files) => {
|
|
|
890
871
|
};
|
|
891
872
|
|
|
892
873
|
// src/formation/resource/lambda/code.ts
|
|
874
|
+
import { fileURLToPath } from "url";
|
|
875
|
+
import { join } from "path";
|
|
893
876
|
var Code = class {
|
|
894
877
|
static fromFile(id, file, bundler) {
|
|
895
878
|
return new FileCode(id, file, bundler);
|
|
@@ -897,6 +880,29 @@ var Code = class {
|
|
|
897
880
|
static fromInline(code, handler) {
|
|
898
881
|
return new InlineCode(code, handler);
|
|
899
882
|
}
|
|
883
|
+
static fromInlineFile(id, file, bundler) {
|
|
884
|
+
return new InlineFileCode(id, file, bundler);
|
|
885
|
+
}
|
|
886
|
+
// static fromZipFile(id:string, file:string, hash:string, handler?:string) {
|
|
887
|
+
// return new ZipFileCode(id, file, hash, handler)
|
|
888
|
+
// }
|
|
889
|
+
static fromFeature(id) {
|
|
890
|
+
const root2 = fileURLToPath(new URL(".", import.meta.url));
|
|
891
|
+
const file = join(root2, `features/${id}.js`);
|
|
892
|
+
return new FileCode(id, file, rollupBundle({
|
|
893
|
+
minify: false,
|
|
894
|
+
handler: "index.handler"
|
|
895
|
+
}));
|
|
896
|
+
}
|
|
897
|
+
static fromInlineFeature(id) {
|
|
898
|
+
const root2 = fileURLToPath(new URL(".", import.meta.url));
|
|
899
|
+
const file = join(root2, `features/${id}.js`);
|
|
900
|
+
return new InlineFileCode(id, file, rollupBundle({
|
|
901
|
+
format: "cjs",
|
|
902
|
+
minify: false,
|
|
903
|
+
handler: "index.handler"
|
|
904
|
+
}));
|
|
905
|
+
}
|
|
900
906
|
};
|
|
901
907
|
var InlineCode = class {
|
|
902
908
|
constructor(code, handler = "index.default") {
|
|
@@ -912,6 +918,36 @@ var InlineCode = class {
|
|
|
912
918
|
};
|
|
913
919
|
}
|
|
914
920
|
};
|
|
921
|
+
var InlineFileCode = class extends Asset {
|
|
922
|
+
constructor(id, file, bundler) {
|
|
923
|
+
super("function", id);
|
|
924
|
+
this.file = file;
|
|
925
|
+
this.bundler = bundler;
|
|
926
|
+
}
|
|
927
|
+
code;
|
|
928
|
+
handler;
|
|
929
|
+
async build({ write }) {
|
|
930
|
+
const bundler = this.bundler ?? rollupBundle();
|
|
931
|
+
const { hash, files: [file], handler } = await bundler(this.file);
|
|
932
|
+
await Promise.all([
|
|
933
|
+
write("HASH", hash),
|
|
934
|
+
write("file.js", file.code)
|
|
935
|
+
]);
|
|
936
|
+
this.handler = handler;
|
|
937
|
+
this.code = file.code.toString("utf8");
|
|
938
|
+
return {
|
|
939
|
+
size: formatByteSize(file.code.byteLength)
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
toCodeJson() {
|
|
943
|
+
return {
|
|
944
|
+
Handler: this.handler ?? "",
|
|
945
|
+
Code: {
|
|
946
|
+
ZipFile: this.code ?? ""
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
};
|
|
915
951
|
var FileCode = class extends Asset {
|
|
916
952
|
constructor(id, file, bundler) {
|
|
917
953
|
super("function", id);
|
|
@@ -923,7 +959,7 @@ var FileCode = class extends Asset {
|
|
|
923
959
|
bundle;
|
|
924
960
|
s3;
|
|
925
961
|
async build({ write }) {
|
|
926
|
-
const bundler = this.bundler ?? rollupBundle;
|
|
962
|
+
const bundler = this.bundler ?? rollupBundle();
|
|
927
963
|
const { hash, files, handler } = await bundler(this.file);
|
|
928
964
|
const bundle = await zipFiles(files);
|
|
929
965
|
await Promise.all([
|
|
@@ -1012,24 +1048,24 @@ import { camelCase as camelCase2 } from "change-case";
|
|
|
1012
1048
|
|
|
1013
1049
|
// src/util/path.ts
|
|
1014
1050
|
import { lstat } from "fs/promises";
|
|
1015
|
-
import { join, normalize } from "path";
|
|
1051
|
+
import { join as join2, normalize } from "path";
|
|
1016
1052
|
var root = process.cwd();
|
|
1017
1053
|
var directories = {
|
|
1018
1054
|
root,
|
|
1019
1055
|
get output() {
|
|
1020
|
-
return
|
|
1056
|
+
return join2(this.root, ".awsless");
|
|
1021
1057
|
},
|
|
1022
1058
|
get cache() {
|
|
1023
|
-
return
|
|
1059
|
+
return join2(this.output, "cache");
|
|
1024
1060
|
},
|
|
1025
1061
|
get asset() {
|
|
1026
|
-
return
|
|
1062
|
+
return join2(this.output, "asset");
|
|
1027
1063
|
},
|
|
1028
1064
|
get types() {
|
|
1029
|
-
return
|
|
1065
|
+
return join2(this.output, "types");
|
|
1030
1066
|
},
|
|
1031
1067
|
get template() {
|
|
1032
|
-
return
|
|
1068
|
+
return join2(this.output, "template");
|
|
1033
1069
|
}
|
|
1034
1070
|
};
|
|
1035
1071
|
var setRoot = (path = root) => {
|
|
@@ -1039,17 +1075,17 @@ var findRootDir = async (path, configFile, level = 5) => {
|
|
|
1039
1075
|
if (!level) {
|
|
1040
1076
|
throw new TypeError("No awsless project found");
|
|
1041
1077
|
}
|
|
1042
|
-
const file =
|
|
1078
|
+
const file = join2(path, configFile);
|
|
1043
1079
|
const exists = await fileExist(file);
|
|
1044
1080
|
if (exists) {
|
|
1045
1081
|
return path;
|
|
1046
1082
|
}
|
|
1047
|
-
return findRootDir(normalize(
|
|
1083
|
+
return findRootDir(normalize(join2(path, "..")), configFile, level - 1);
|
|
1048
1084
|
};
|
|
1049
1085
|
var fileExist = async (file) => {
|
|
1050
1086
|
try {
|
|
1051
|
-
const
|
|
1052
|
-
if (
|
|
1087
|
+
const stat3 = await lstat(file);
|
|
1088
|
+
if (stat3.isFile()) {
|
|
1053
1089
|
return true;
|
|
1054
1090
|
}
|
|
1055
1091
|
} catch (error) {
|
|
@@ -1062,8 +1098,8 @@ import { relative as relative2 } from "path";
|
|
|
1062
1098
|
|
|
1063
1099
|
// src/util/type-gen.ts
|
|
1064
1100
|
import { mkdir, writeFile } from "fs/promises";
|
|
1065
|
-
import { join as
|
|
1066
|
-
import { camelCase } from "change-case";
|
|
1101
|
+
import { join as join3, relative } from "path";
|
|
1102
|
+
import { camelCase, constantCase as constantCase2 } from "change-case";
|
|
1067
1103
|
var generateResourceTypes = async (config) => {
|
|
1068
1104
|
const plugins = [
|
|
1069
1105
|
...defaultPlugins,
|
|
@@ -1073,7 +1109,7 @@ var generateResourceTypes = async (config) => {
|
|
|
1073
1109
|
for (const plugin of plugins) {
|
|
1074
1110
|
const code = plugin.onTypeGen?.({ config });
|
|
1075
1111
|
if (code) {
|
|
1076
|
-
const file =
|
|
1112
|
+
const file = join3(directories.types, `${plugin.name}.d.ts`);
|
|
1077
1113
|
files.push(relative(directories.root, file));
|
|
1078
1114
|
await mkdir(directories.types, { recursive: true });
|
|
1079
1115
|
await writeFile(file, code);
|
|
@@ -1081,13 +1117,14 @@ var generateResourceTypes = async (config) => {
|
|
|
1081
1117
|
}
|
|
1082
1118
|
if (files.length) {
|
|
1083
1119
|
const code = files.map((file) => `/// <reference path='${file}' />`).join("\n");
|
|
1084
|
-
await writeFile(
|
|
1120
|
+
await writeFile(join3(directories.root, `awsless.d.ts`), code);
|
|
1085
1121
|
}
|
|
1086
1122
|
};
|
|
1087
1123
|
var TypeGen = class {
|
|
1088
|
-
constructor(module, interfaceName) {
|
|
1124
|
+
constructor(module, interfaceName, readonly = true) {
|
|
1089
1125
|
this.module = module;
|
|
1090
1126
|
this.interfaceName = interfaceName;
|
|
1127
|
+
this.readonly = readonly;
|
|
1091
1128
|
}
|
|
1092
1129
|
codes = /* @__PURE__ */ new Set();
|
|
1093
1130
|
types = /* @__PURE__ */ new Map();
|
|
@@ -1102,7 +1139,13 @@ var TypeGen = class {
|
|
|
1102
1139
|
}
|
|
1103
1140
|
addType(name, type) {
|
|
1104
1141
|
if (type) {
|
|
1105
|
-
this.types.set(name, type);
|
|
1142
|
+
this.types.set(camelCase(name), type);
|
|
1143
|
+
}
|
|
1144
|
+
return this;
|
|
1145
|
+
}
|
|
1146
|
+
addConst(name, type) {
|
|
1147
|
+
if (type) {
|
|
1148
|
+
this.types.set(constantCase2(name), type);
|
|
1106
1149
|
}
|
|
1107
1150
|
return this;
|
|
1108
1151
|
}
|
|
@@ -1133,7 +1176,7 @@ var TypeGen = class {
|
|
|
1133
1176
|
`declare module '${this.module}' {`,
|
|
1134
1177
|
` interface ${this.interfaceName} {`,
|
|
1135
1178
|
...Array.from(this.types.entries()).map(([propName, type]) => {
|
|
1136
|
-
return ` readonly ${
|
|
1179
|
+
return ` ${this.readonly ? "readonly " : ""}${propName}: ${type}`;
|
|
1137
1180
|
}),
|
|
1138
1181
|
` }`,
|
|
1139
1182
|
`}`,
|
|
@@ -1146,7 +1189,15 @@ var TypeGen = class {
|
|
|
1146
1189
|
var TypeObject = class {
|
|
1147
1190
|
types = /* @__PURE__ */ new Map();
|
|
1148
1191
|
addType(name, type) {
|
|
1149
|
-
|
|
1192
|
+
if (type) {
|
|
1193
|
+
this.types.set(camelCase(name), type);
|
|
1194
|
+
}
|
|
1195
|
+
return this;
|
|
1196
|
+
}
|
|
1197
|
+
addConst(name, type) {
|
|
1198
|
+
if (type) {
|
|
1199
|
+
this.types.set(constantCase2(name), type);
|
|
1200
|
+
}
|
|
1150
1201
|
return this;
|
|
1151
1202
|
}
|
|
1152
1203
|
toString() {
|
|
@@ -1156,7 +1207,7 @@ var TypeObject = class {
|
|
|
1156
1207
|
return [
|
|
1157
1208
|
"{",
|
|
1158
1209
|
...Array.from(this.types.entries()).map(([propName, type]) => {
|
|
1159
|
-
return ` readonly ${
|
|
1210
|
+
return ` readonly ${propName}: ${type}`;
|
|
1160
1211
|
}),
|
|
1161
1212
|
" }"
|
|
1162
1213
|
].join("\n");
|
|
@@ -1172,9 +1223,12 @@ var EnvironmentSchema = z6.record(z6.string(), z6.string()).optional();
|
|
|
1172
1223
|
var ArchitectureSchema = z6.enum(["x86_64", "arm64"]);
|
|
1173
1224
|
var RetryAttemptsSchema = z6.number().int().min(0).max(2);
|
|
1174
1225
|
var RuntimeSchema = z6.enum([
|
|
1175
|
-
"nodejs16.x",
|
|
1176
1226
|
"nodejs18.x"
|
|
1177
1227
|
]);
|
|
1228
|
+
var LogSchema = z6.union([
|
|
1229
|
+
z6.boolean(),
|
|
1230
|
+
DurationSchema.refine(durationMin(Duration.days(1)), "Minimum log retention is 1 day")
|
|
1231
|
+
]);
|
|
1178
1232
|
var FunctionSchema = z6.union([
|
|
1179
1233
|
LocalFileSchema,
|
|
1180
1234
|
z6.object({
|
|
@@ -1184,6 +1238,11 @@ var FunctionSchema = z6.union([
|
|
|
1184
1238
|
* @default false
|
|
1185
1239
|
*/
|
|
1186
1240
|
vpc: z6.boolean().optional(),
|
|
1241
|
+
/** Enable logging to a CloudWatch log group.
|
|
1242
|
+
* Providing a duration value will set the log retention time.
|
|
1243
|
+
* @default false
|
|
1244
|
+
*/
|
|
1245
|
+
log: LogSchema.optional(),
|
|
1187
1246
|
/** The amount of time that Lambda allows a function to run before stopping it.
|
|
1188
1247
|
* You can specify a size value from 1 second to 15 minutes.
|
|
1189
1248
|
* @default '10 seconds'
|
|
@@ -1230,6 +1289,9 @@ var FunctionSchema = z6.union([
|
|
|
1230
1289
|
// onFailure: ResourceIdSchema.optional(),
|
|
1231
1290
|
})
|
|
1232
1291
|
]);
|
|
1292
|
+
var isFunctionProps = (input) => {
|
|
1293
|
+
return typeof input === "string" || typeof input.file === "string";
|
|
1294
|
+
};
|
|
1233
1295
|
var schema = z6.object({
|
|
1234
1296
|
defaults: z6.object({
|
|
1235
1297
|
function: z6.object({
|
|
@@ -1237,6 +1299,10 @@ var schema = z6.object({
|
|
|
1237
1299
|
* @default false
|
|
1238
1300
|
*/
|
|
1239
1301
|
vpc: z6.boolean().default(false),
|
|
1302
|
+
/** Enable logging to a CloudWatch log group.
|
|
1303
|
+
* @default false
|
|
1304
|
+
*/
|
|
1305
|
+
log: LogSchema.default(false),
|
|
1240
1306
|
/** The amount of time that Lambda allows a function to run before stopping it.
|
|
1241
1307
|
* You can specify a size value from 1 second to 15 minutes.
|
|
1242
1308
|
* @default '10 seconds'
|
|
@@ -1349,22 +1415,26 @@ var functionPlugin = definePlugin({
|
|
|
1349
1415
|
var toLambdaFunction = (ctx, id, fileOrProps) => {
|
|
1350
1416
|
const config = ctx.config;
|
|
1351
1417
|
const stack = ctx.stack;
|
|
1418
|
+
const bootstrap2 = ctx.bootstrap;
|
|
1352
1419
|
const props = typeof fileOrProps === "string" ? { ...config.defaults?.function, file: fileOrProps } : { ...config.defaults?.function, ...fileOrProps };
|
|
1353
1420
|
const lambda = new Function(id, {
|
|
1354
|
-
name: `${config.name}
|
|
1421
|
+
name: `${config.name}-${stack.name}-${id}`,
|
|
1355
1422
|
code: Code.fromFile(id, props.file),
|
|
1356
1423
|
...props,
|
|
1357
1424
|
vpc: void 0
|
|
1358
1425
|
});
|
|
1359
1426
|
lambda.addEnvironment("APP", config.name).addEnvironment("STAGE", config.stage).addEnvironment("STACK", stack.name);
|
|
1427
|
+
if (props.log) {
|
|
1428
|
+
lambda.enableLogs(props.log instanceof Duration ? props.log : void 0);
|
|
1429
|
+
}
|
|
1360
1430
|
if (props.vpc) {
|
|
1361
1431
|
lambda.setVpc({
|
|
1362
1432
|
securityGroupIds: [
|
|
1363
|
-
|
|
1433
|
+
bootstrap2.import(`vpc-security-group-id`)
|
|
1364
1434
|
],
|
|
1365
1435
|
subnetIds: [
|
|
1366
|
-
|
|
1367
|
-
|
|
1436
|
+
bootstrap2.import(`public-subnet-1`),
|
|
1437
|
+
bootstrap2.import(`public-subnet-2`)
|
|
1368
1438
|
]
|
|
1369
1439
|
}).addPermissions({
|
|
1370
1440
|
actions: [
|
|
@@ -1377,9 +1447,6 @@ var toLambdaFunction = (ctx, id, fileOrProps) => {
|
|
|
1377
1447
|
resources: ["*"]
|
|
1378
1448
|
});
|
|
1379
1449
|
}
|
|
1380
|
-
if (props.runtime.startsWith("nodejs")) {
|
|
1381
|
-
lambda.addEnvironment("AWS_NODEJS_CONNECTION_REUSE_ENABLED", "1");
|
|
1382
|
-
}
|
|
1383
1450
|
ctx.bind((other) => {
|
|
1384
1451
|
other.addPermissions(lambda.permissions);
|
|
1385
1452
|
});
|
|
@@ -1419,6 +1486,7 @@ var Rule = class extends Resource {
|
|
|
1419
1486
|
};
|
|
1420
1487
|
|
|
1421
1488
|
// src/formation/resource/lambda/permission.ts
|
|
1489
|
+
import { constantCase as constantCase3 } from "change-case";
|
|
1422
1490
|
var Permission2 = class extends Resource {
|
|
1423
1491
|
constructor(logicalId, props) {
|
|
1424
1492
|
super("AWS::Lambda::Permission", logicalId);
|
|
@@ -1429,7 +1497,8 @@ var Permission2 = class extends Resource {
|
|
|
1429
1497
|
FunctionName: this.props.functionArn,
|
|
1430
1498
|
Action: this.props.action || "lambda:InvokeFunction",
|
|
1431
1499
|
Principal: this.props.principal,
|
|
1432
|
-
|
|
1500
|
+
...this.attr("FunctionUrlAuthType", this.props.urlAuthType && constantCase3(this.props.urlAuthType)),
|
|
1501
|
+
...this.attr("SourceArn", this.props.sourceArn)
|
|
1433
1502
|
};
|
|
1434
1503
|
}
|
|
1435
1504
|
};
|
|
@@ -1555,7 +1624,7 @@ var Queue = class extends Resource {
|
|
|
1555
1624
|
};
|
|
1556
1625
|
|
|
1557
1626
|
// src/formation/resource/lambda/event-source-mapping.ts
|
|
1558
|
-
import { constantCase } from "change-case";
|
|
1627
|
+
import { constantCase as constantCase4 } from "change-case";
|
|
1559
1628
|
var EventSourceMapping = class extends Resource {
|
|
1560
1629
|
constructor(logicalId, props) {
|
|
1561
1630
|
super("AWS::Lambda::EventSourceMapping", logicalId);
|
|
@@ -1577,7 +1646,7 @@ var EventSourceMapping = class extends Resource {
|
|
|
1577
1646
|
...this.attr("ParallelizationFactor", this.props.parallelizationFactor),
|
|
1578
1647
|
...this.attr("TumblingWindowInSeconds", this.props.tumblingWindow?.toSeconds()),
|
|
1579
1648
|
...this.attr("BisectBatchOnFunctionError", this.props.bisectBatchOnError),
|
|
1580
|
-
...this.attr("StartingPosition", this.props.startingPosition &&
|
|
1649
|
+
...this.attr("StartingPosition", this.props.startingPosition && constantCase4(this.props.startingPosition)),
|
|
1581
1650
|
...this.attr("StartingPositionTimestamp", this.props.startingPositionTimestamp),
|
|
1582
1651
|
...this.props.maxConcurrency ? {
|
|
1583
1652
|
ScalingConfig: {
|
|
@@ -1618,7 +1687,7 @@ var SqsEventSource = class extends Group {
|
|
|
1618
1687
|
};
|
|
1619
1688
|
|
|
1620
1689
|
// src/plugins/queue.ts
|
|
1621
|
-
import { camelCase as camelCase3, constantCase as
|
|
1690
|
+
import { camelCase as camelCase3, constantCase as constantCase5 } from "change-case";
|
|
1622
1691
|
import { relative as relative3 } from "path";
|
|
1623
1692
|
var RetentionPeriodSchema = DurationSchema.refine(durationMin(Duration.minutes(1)), "Minimum retention period is 1 minute").refine(durationMax(Duration.days(14)), "Maximum retention period is 14 days");
|
|
1624
1693
|
var VisibilityTimeoutSchema = DurationSchema.refine(durationMax(Duration.hours(12)), "Maximum visibility timeout is 12 hours");
|
|
@@ -1773,7 +1842,7 @@ var queuePlugin = definePlugin({
|
|
|
1773
1842
|
stack.add(queue2, lambda, source);
|
|
1774
1843
|
bind((lambda2) => {
|
|
1775
1844
|
lambda2.addPermissions(queue2.permissions);
|
|
1776
|
-
lambda2.addEnvironment(`QUEUE_${
|
|
1845
|
+
lambda2.addEnvironment(`QUEUE_${constantCase5(stack.name)}_${constantCase5(id)}_URL`, queue2.url);
|
|
1777
1846
|
});
|
|
1778
1847
|
}
|
|
1779
1848
|
}
|
|
@@ -1783,7 +1852,7 @@ var queuePlugin = definePlugin({
|
|
|
1783
1852
|
import { z as z9 } from "zod";
|
|
1784
1853
|
|
|
1785
1854
|
// src/formation/resource/dynamodb/table.ts
|
|
1786
|
-
import { constantCase as
|
|
1855
|
+
import { constantCase as constantCase6 } from "change-case";
|
|
1787
1856
|
var Table = class extends Resource {
|
|
1788
1857
|
constructor(logicalId, props) {
|
|
1789
1858
|
super("AWS::DynamoDB::Table", logicalId);
|
|
@@ -1856,7 +1925,7 @@ var Table = class extends Resource {
|
|
|
1856
1925
|
return {
|
|
1857
1926
|
TableName: this.name,
|
|
1858
1927
|
BillingMode: "PAY_PER_REQUEST",
|
|
1859
|
-
TableClass:
|
|
1928
|
+
TableClass: constantCase6(this.props.class || "standard"),
|
|
1860
1929
|
PointInTimeRecoverySpecification: {
|
|
1861
1930
|
PointInTimeRecoveryEnabled: this.props.pointInTimeRecovery || false
|
|
1862
1931
|
},
|
|
@@ -1867,7 +1936,7 @@ var Table = class extends Resource {
|
|
|
1867
1936
|
AttributeDefinitions: this.attributeDefinitions(),
|
|
1868
1937
|
...this.props.stream ? {
|
|
1869
1938
|
StreamSpecification: {
|
|
1870
|
-
StreamViewType:
|
|
1939
|
+
StreamViewType: constantCase6(this.props.stream)
|
|
1871
1940
|
}
|
|
1872
1941
|
} : {},
|
|
1873
1942
|
...this.props.timeToLiveAttribute ? {
|
|
@@ -1884,7 +1953,7 @@ var Table = class extends Resource {
|
|
|
1884
1953
|
...props.sort ? [{ KeyType: "RANGE", AttributeName: props.sort }] : []
|
|
1885
1954
|
],
|
|
1886
1955
|
Projection: {
|
|
1887
|
-
ProjectionType:
|
|
1956
|
+
ProjectionType: constantCase6(props.projection || "all")
|
|
1888
1957
|
}
|
|
1889
1958
|
}))
|
|
1890
1959
|
} : {}
|
|
@@ -2010,21 +2079,6 @@ var tablePlugin = definePlugin({
|
|
|
2010
2079
|
projection: z9.enum(["all", "keys-only"]).default("all")
|
|
2011
2080
|
})).optional()
|
|
2012
2081
|
})
|
|
2013
|
-
// .refine(props => {
|
|
2014
|
-
// return (
|
|
2015
|
-
// // Check the hash key
|
|
2016
|
-
// props.fields.hasOwnProperty(props.hash) &&
|
|
2017
|
-
// // Check the sort key
|
|
2018
|
-
// (!props.sort || props.fields.hasOwnProperty(props.sort)) &&
|
|
2019
|
-
// // Check all indexes
|
|
2020
|
-
// !Object.values(props.indexes || {}).map(index => (
|
|
2021
|
-
// // Check the index hash key
|
|
2022
|
-
// props.fields.hasOwnProperty(index.hash) &&
|
|
2023
|
-
// // Check the index sort key
|
|
2024
|
-
// (!index.sort || props.fields.hasOwnProperty(index.sort))
|
|
2025
|
-
// )).includes(false)
|
|
2026
|
-
// )
|
|
2027
|
-
// }, 'Hash & Sort keys must be defined inside the table fields')
|
|
2028
2082
|
).optional()
|
|
2029
2083
|
}).array()
|
|
2030
2084
|
}),
|
|
@@ -2079,11 +2133,20 @@ var Bucket = class extends Resource {
|
|
|
2079
2133
|
}
|
|
2080
2134
|
name;
|
|
2081
2135
|
get arn() {
|
|
2082
|
-
return
|
|
2136
|
+
return getAtt(this.logicalId, "Arn");
|
|
2083
2137
|
}
|
|
2084
2138
|
get domainName() {
|
|
2085
2139
|
return getAtt(this.logicalId, "DomainName");
|
|
2086
2140
|
}
|
|
2141
|
+
get dealStackDomainName() {
|
|
2142
|
+
return getAtt(this.logicalId, "DualStackDomainName");
|
|
2143
|
+
}
|
|
2144
|
+
get regionalDomainName() {
|
|
2145
|
+
return getAtt(this.logicalId, "RegionalDomainName");
|
|
2146
|
+
}
|
|
2147
|
+
get url() {
|
|
2148
|
+
return getAtt(this.logicalId, "WebsiteURL");
|
|
2149
|
+
}
|
|
2087
2150
|
get permissions() {
|
|
2088
2151
|
return {
|
|
2089
2152
|
actions: [
|
|
@@ -2105,15 +2168,38 @@ var Bucket = class extends Resource {
|
|
|
2105
2168
|
return {
|
|
2106
2169
|
BucketName: this.name,
|
|
2107
2170
|
AccessControl: pascalCase2(this.props.accessControl ?? "private"),
|
|
2108
|
-
...this.props.
|
|
2171
|
+
...this.props.versioning ? {
|
|
2109
2172
|
VersioningConfiguration: {
|
|
2110
2173
|
Status: "Enabled"
|
|
2111
2174
|
}
|
|
2175
|
+
} : {},
|
|
2176
|
+
...this.props.website ? {
|
|
2177
|
+
WebsiteConfiguration: {
|
|
2178
|
+
...this.attr("IndexDocument", this.props.website.indexDocument),
|
|
2179
|
+
...this.attr("ErrorDocument", this.props.website.errorDocument)
|
|
2180
|
+
}
|
|
2112
2181
|
} : {}
|
|
2113
2182
|
};
|
|
2114
2183
|
}
|
|
2115
2184
|
};
|
|
2116
2185
|
|
|
2186
|
+
// src/formation/resource/cloud-formation/custom-resource.ts
|
|
2187
|
+
var CustomResource = class extends Resource {
|
|
2188
|
+
constructor(logicalId, props) {
|
|
2189
|
+
super("AWS::CloudFormation::CustomResource", logicalId);
|
|
2190
|
+
this.props = props;
|
|
2191
|
+
}
|
|
2192
|
+
getAtt(name) {
|
|
2193
|
+
return getAtt(this.logicalId, name);
|
|
2194
|
+
}
|
|
2195
|
+
properties() {
|
|
2196
|
+
return {
|
|
2197
|
+
ServiceToken: this.props.serviceToken,
|
|
2198
|
+
...this.props.properties
|
|
2199
|
+
};
|
|
2200
|
+
}
|
|
2201
|
+
};
|
|
2202
|
+
|
|
2117
2203
|
// src/plugins/store.ts
|
|
2118
2204
|
var storePlugin = definePlugin({
|
|
2119
2205
|
name: "store",
|
|
@@ -2140,13 +2226,19 @@ var storePlugin = definePlugin({
|
|
|
2140
2226
|
}
|
|
2141
2227
|
return types2.toString();
|
|
2142
2228
|
},
|
|
2143
|
-
onStack({ config, stack, stackConfig, bind }) {
|
|
2229
|
+
onStack({ config, stack, stackConfig, bootstrap: bootstrap2, bind }) {
|
|
2144
2230
|
for (const id of stackConfig.stores || []) {
|
|
2145
2231
|
const bucket = new Bucket(id, {
|
|
2146
|
-
name:
|
|
2232
|
+
name: `store-${config.name}-${stack.name}-${id}`,
|
|
2147
2233
|
accessControl: "private"
|
|
2148
2234
|
});
|
|
2149
|
-
|
|
2235
|
+
const custom = new CustomResource(id, {
|
|
2236
|
+
serviceToken: bootstrap2.import("feature-delete-bucket"),
|
|
2237
|
+
properties: {
|
|
2238
|
+
bucketName: bucket.name
|
|
2239
|
+
}
|
|
2240
|
+
}).dependsOn(bucket);
|
|
2241
|
+
stack.add(bucket, custom);
|
|
2150
2242
|
bind((lambda) => {
|
|
2151
2243
|
lambda.addPermissions(bucket.permissions);
|
|
2152
2244
|
});
|
|
@@ -2234,54 +2326,81 @@ var topicPlugin = definePlugin({
|
|
|
2234
2326
|
name: "topic",
|
|
2235
2327
|
schema: z11.object({
|
|
2236
2328
|
stacks: z11.object({
|
|
2237
|
-
/** Define the
|
|
2329
|
+
/** Define the events to publish too in your stack.
|
|
2330
|
+
* @example
|
|
2331
|
+
* {
|
|
2332
|
+
* topics: [ 'TOPIC_NAME' ]
|
|
2333
|
+
* }
|
|
2334
|
+
*/
|
|
2335
|
+
topics: z11.array(ResourceIdSchema).refine((topics) => {
|
|
2336
|
+
return topics.length === new Set(topics).size;
|
|
2337
|
+
}, "Must be a list of unique topic names").optional(),
|
|
2338
|
+
/** Define the events to subscribe too in your stack.
|
|
2238
2339
|
* @example
|
|
2239
2340
|
* {
|
|
2240
|
-
*
|
|
2341
|
+
* subscribers: {
|
|
2241
2342
|
* TOPIC_NAME: 'function.ts'
|
|
2242
2343
|
* }
|
|
2243
2344
|
* }
|
|
2244
2345
|
*/
|
|
2245
|
-
|
|
2246
|
-
}).array()
|
|
2346
|
+
subscribers: z11.record(ResourceIdSchema, FunctionSchema).optional()
|
|
2347
|
+
}).array().superRefine((stacks, ctx) => {
|
|
2348
|
+
const topics = [];
|
|
2349
|
+
for (const stack of stacks) {
|
|
2350
|
+
topics.push(...stack.topics || []);
|
|
2351
|
+
}
|
|
2352
|
+
for (const index in stacks) {
|
|
2353
|
+
const stack = stacks[index];
|
|
2354
|
+
for (const sub2 of Object.keys(stack.subscribers || {})) {
|
|
2355
|
+
if (!topics.includes(sub2)) {
|
|
2356
|
+
ctx.addIssue({
|
|
2357
|
+
code: z11.ZodIssueCode.custom,
|
|
2358
|
+
message: `Topic subscription to "${sub2}" is undefined`,
|
|
2359
|
+
path: [Number(index), "subscribers"]
|
|
2360
|
+
});
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
})
|
|
2247
2365
|
}),
|
|
2248
2366
|
onTypeGen({ config }) {
|
|
2249
2367
|
const gen = new TypeGen("@awsless/awsless", "TopicResources");
|
|
2250
2368
|
gen.addCode(typeGenCode3);
|
|
2251
2369
|
for (const stack of config.stacks) {
|
|
2252
|
-
for (const topic of
|
|
2370
|
+
for (const topic of stack.topics || []) {
|
|
2253
2371
|
const name = formatName(`${config.name}-${topic}`);
|
|
2254
2372
|
gen.addType(topic, `Publish<'${name}'>`);
|
|
2255
2373
|
}
|
|
2256
2374
|
}
|
|
2257
2375
|
return gen.toString();
|
|
2258
2376
|
},
|
|
2259
|
-
onApp({ config, bootstrap: bootstrap2
|
|
2260
|
-
const
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
}
|
|
2268
|
-
bootstrap2.add(topic);
|
|
2269
|
-
bootstrap2.export(`topic-${id}-arn`, topic.arn);
|
|
2377
|
+
onApp({ config, bootstrap: bootstrap2 }) {
|
|
2378
|
+
for (const stack of config.stacks) {
|
|
2379
|
+
for (const id of stack.topics || []) {
|
|
2380
|
+
const topic = new Topic(id, {
|
|
2381
|
+
name: `${config.name}-${id}`
|
|
2382
|
+
});
|
|
2383
|
+
bootstrap2.add(topic);
|
|
2384
|
+
bootstrap2.export(`topic-${id}-arn`, topic.arn);
|
|
2385
|
+
}
|
|
2270
2386
|
}
|
|
2271
|
-
bind((lambda) => {
|
|
2272
|
-
lambda.addPermissions({
|
|
2273
|
-
actions: ["sns:Publish"],
|
|
2274
|
-
resources: [
|
|
2275
|
-
sub("arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:${app}-*", {
|
|
2276
|
-
app: config.name
|
|
2277
|
-
})
|
|
2278
|
-
]
|
|
2279
|
-
});
|
|
2280
|
-
});
|
|
2281
2387
|
},
|
|
2282
2388
|
onStack(ctx) {
|
|
2283
|
-
const { stack, stackConfig, bootstrap: bootstrap2 } = ctx;
|
|
2284
|
-
for (const
|
|
2389
|
+
const { config, stack, stackConfig, bootstrap: bootstrap2, bind } = ctx;
|
|
2390
|
+
for (const id of stackConfig.topics || []) {
|
|
2391
|
+
bind((lambda) => {
|
|
2392
|
+
lambda.addPermissions({
|
|
2393
|
+
actions: ["sns:Publish"],
|
|
2394
|
+
resources: [
|
|
2395
|
+
sub("arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:${app}-${topic}", {
|
|
2396
|
+
app: config.name,
|
|
2397
|
+
topic: id
|
|
2398
|
+
})
|
|
2399
|
+
]
|
|
2400
|
+
});
|
|
2401
|
+
});
|
|
2402
|
+
}
|
|
2403
|
+
for (const [id, props] of Object.entries(stackConfig.subscribers || {})) {
|
|
2285
2404
|
const lambda = toLambdaFunction(ctx, `topic-${id}`, props);
|
|
2286
2405
|
const source = new SnsEventSource(id, lambda, {
|
|
2287
2406
|
topicArn: bootstrap2.import(`topic-${id}-arn`)
|
|
@@ -2423,7 +2542,7 @@ var toArray = (value) => {
|
|
|
2423
2542
|
import { paramCase as paramCase4 } from "change-case";
|
|
2424
2543
|
|
|
2425
2544
|
// src/formation/resource/appsync/graphql-api.ts
|
|
2426
|
-
import { constantCase as
|
|
2545
|
+
import { constantCase as constantCase7 } from "change-case";
|
|
2427
2546
|
var GraphQLApi = class extends Resource {
|
|
2428
2547
|
constructor(logicalId, props) {
|
|
2429
2548
|
super("AWS::AppSync::GraphQLApi", logicalId);
|
|
@@ -2455,7 +2574,7 @@ var GraphQLApi = class extends Resource {
|
|
|
2455
2574
|
properties() {
|
|
2456
2575
|
return {
|
|
2457
2576
|
Name: this.name,
|
|
2458
|
-
AuthenticationType:
|
|
2577
|
+
AuthenticationType: constantCase7(this.props.authenticationType || "api-key"),
|
|
2459
2578
|
AdditionalAuthenticationProviders: this.lambdaAuthProviders.map((provider) => ({
|
|
2460
2579
|
AuthenticationType: "AWS_LAMBDA",
|
|
2461
2580
|
LambdaAuthorizerConfig: {
|
|
@@ -2784,17 +2903,25 @@ var graphqlPlugin = definePlugin({
|
|
|
2784
2903
|
z14.array(LocalFileSchema).min(1)
|
|
2785
2904
|
]).optional(),
|
|
2786
2905
|
resolvers: z14.record(
|
|
2906
|
+
// TypeName
|
|
2787
2907
|
z14.string(),
|
|
2788
2908
|
z14.record(
|
|
2909
|
+
// FieldName
|
|
2789
2910
|
z14.string(),
|
|
2790
|
-
|
|
2911
|
+
z14.union([
|
|
2912
|
+
FunctionSchema,
|
|
2913
|
+
z14.object({
|
|
2914
|
+
consumer: FunctionSchema,
|
|
2915
|
+
resolver: LocalFileSchema
|
|
2916
|
+
})
|
|
2917
|
+
])
|
|
2791
2918
|
)
|
|
2792
2919
|
).optional()
|
|
2793
2920
|
})).optional()
|
|
2794
2921
|
}).array()
|
|
2795
2922
|
}),
|
|
2796
2923
|
onApp(ctx) {
|
|
2797
|
-
const { config, bootstrap: bootstrap2
|
|
2924
|
+
const { config, bootstrap: bootstrap2 } = ctx;
|
|
2798
2925
|
const apis = /* @__PURE__ */ new Set();
|
|
2799
2926
|
for (const stackConfig of config.stacks) {
|
|
2800
2927
|
for (const id of Object.keys(stackConfig.graphql || {})) {
|
|
@@ -2827,8 +2954,9 @@ var graphqlPlugin = definePlugin({
|
|
|
2827
2954
|
}
|
|
2828
2955
|
if (props.domain) {
|
|
2829
2956
|
const domainName = props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain;
|
|
2830
|
-
const hostedZoneId =
|
|
2831
|
-
const certificateArn =
|
|
2957
|
+
const hostedZoneId = bootstrap2.import(`hosted-zone-${props.domain}-id`);
|
|
2958
|
+
const certificateArn = bootstrap2.import(`us-east-certificate-${props.domain}-arn`);
|
|
2959
|
+
debug("DEBUG CERT", certificateArn);
|
|
2832
2960
|
const domain = new DomainName(id, {
|
|
2833
2961
|
domainName,
|
|
2834
2962
|
certificateArn
|
|
@@ -2855,14 +2983,15 @@ var graphqlPlugin = definePlugin({
|
|
|
2855
2983
|
for (const [id, props] of Object.entries(stackConfig.graphql || {})) {
|
|
2856
2984
|
const apiId = bootstrap2.import(`graphql-${id}`);
|
|
2857
2985
|
for (const [typeName, fields] of Object.entries(props.resolvers || {})) {
|
|
2858
|
-
for (const [fieldName,
|
|
2986
|
+
for (const [fieldName, resolverProps] of Object.entries(fields || {})) {
|
|
2987
|
+
const props2 = isFunctionProps(resolverProps) ? { consumer: resolverProps } : resolverProps;
|
|
2859
2988
|
const entryId = paramCase4(`${id}-${typeName}-${fieldName}`);
|
|
2860
|
-
const lambda = toLambdaFunction(ctx, `graphql-${entryId}`,
|
|
2989
|
+
const lambda = toLambdaFunction(ctx, `graphql-${entryId}`, props2.consumer);
|
|
2861
2990
|
const source = new AppsyncEventSource(entryId, lambda, {
|
|
2862
2991
|
apiId,
|
|
2863
2992
|
typeName,
|
|
2864
2993
|
fieldName,
|
|
2865
|
-
code: Code2.fromInline(entryId, defaultResolver)
|
|
2994
|
+
code: Code2.fromInline(entryId, props2.resolver || defaultResolver)
|
|
2866
2995
|
});
|
|
2867
2996
|
stack.add(lambda, source);
|
|
2868
2997
|
}
|
|
@@ -2943,122 +3072,31 @@ var RecordSetGroup = class extends Resource {
|
|
|
2943
3072
|
}
|
|
2944
3073
|
};
|
|
2945
3074
|
|
|
2946
|
-
// src/custom/
|
|
2947
|
-
var
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
}
|
|
2966
|
-
|
|
2967
|
-
await send(event, hostedZoneId, 'SUCCESS')
|
|
2968
|
-
}
|
|
2969
|
-
catch(error) {
|
|
2970
|
-
if (error instanceof Error) {
|
|
2971
|
-
await send(event, hostedZoneId, 'FAILED', {}, error.message)
|
|
2972
|
-
} else {
|
|
2973
|
-
await send(event, hostedZoneId, 'FAILED', {}, 'Unknown error')
|
|
2974
|
-
}
|
|
2975
|
-
}
|
|
2976
|
-
}
|
|
2977
|
-
|
|
2978
|
-
const send = async (event, id, status, data = {}, reason = '') => {
|
|
2979
|
-
const body = JSON.stringify({
|
|
2980
|
-
Status: status,
|
|
2981
|
-
Reason: reason,
|
|
2982
|
-
PhysicalResourceId: id,
|
|
2983
|
-
StackId: event.StackId,
|
|
2984
|
-
RequestId: event.RequestId,
|
|
2985
|
-
LogicalResourceId: event.LogicalResourceId,
|
|
2986
|
-
NoEcho: false,
|
|
2987
|
-
Data: data
|
|
2988
|
-
})
|
|
2989
|
-
|
|
2990
|
-
await fetch(event.ResponseURL, {
|
|
2991
|
-
method: 'PUT',
|
|
2992
|
-
port: 443,
|
|
2993
|
-
body,
|
|
2994
|
-
headers: {
|
|
2995
|
-
'content-type': '',
|
|
2996
|
-
'content-length': Buffer.from(body).byteLength,
|
|
2997
|
-
},
|
|
2998
|
-
})
|
|
2999
|
-
}
|
|
3000
|
-
|
|
3001
|
-
const deleteHostedZoneRecords = async (hostedZoneId, records) => {
|
|
3002
|
-
records = records.filter(record => ![ 'SOA', 'NS' ].includes(record.Type))
|
|
3003
|
-
if(records.length === 0) {
|
|
3004
|
-
return
|
|
3005
|
-
}
|
|
3006
|
-
|
|
3007
|
-
const chunkSize = 100;
|
|
3008
|
-
for (let i = 0; i < records.length; i += chunkSize) {
|
|
3009
|
-
const chunk = records.slice(i, i + chunkSize);
|
|
3010
|
-
|
|
3011
|
-
await client.send(new ChangeResourceRecordSetsCommand({
|
|
3012
|
-
HostedZoneId: hostedZoneId,
|
|
3013
|
-
ChangeBatch: {
|
|
3014
|
-
Changes: chunk.map(record => ({
|
|
3015
|
-
Action: 'DELETE',
|
|
3016
|
-
ResourceRecordSet: record
|
|
3017
|
-
}))
|
|
3018
|
-
}
|
|
3019
|
-
}))
|
|
3020
|
-
}
|
|
3021
|
-
}
|
|
3022
|
-
|
|
3023
|
-
const listHostedZoneRecords = async (hostedZoneId) => {
|
|
3024
|
-
|
|
3025
|
-
const records = []
|
|
3026
|
-
let token
|
|
3027
|
-
|
|
3028
|
-
while(true) {
|
|
3029
|
-
const result = await client.send(new ListResourceRecordSetsCommand({
|
|
3030
|
-
HostedZoneId: hostedZoneId,
|
|
3031
|
-
NextRecordName: token
|
|
3032
|
-
}))
|
|
3033
|
-
|
|
3034
|
-
if(result.ResourceRecordSets && result.ResourceRecordSets.length) {
|
|
3035
|
-
records.push(...result.ResourceRecordSets)
|
|
3036
|
-
}
|
|
3037
|
-
|
|
3038
|
-
if(result.NextRecordName) {
|
|
3039
|
-
token = result.NextRecordName
|
|
3040
|
-
} else {
|
|
3041
|
-
return records
|
|
3042
|
-
}
|
|
3043
|
-
}
|
|
3044
|
-
}
|
|
3045
|
-
`
|
|
3046
|
-
);
|
|
3047
|
-
|
|
3048
|
-
// src/formation/resource/cloud-formation/custom-resource.ts
|
|
3049
|
-
var CustomResource = class extends Resource {
|
|
3050
|
-
constructor(logicalId, props) {
|
|
3051
|
-
super("AWS::CloudFormation::CustomResource", logicalId);
|
|
3052
|
-
this.props = props;
|
|
3053
|
-
}
|
|
3054
|
-
getAtt(name) {
|
|
3055
|
-
return getAtt(this.logicalId, name);
|
|
3075
|
+
// src/custom/global-exports.ts
|
|
3076
|
+
var GlobalExports = class extends Group {
|
|
3077
|
+
resource;
|
|
3078
|
+
constructor(id, props) {
|
|
3079
|
+
const lambda = new Function(id, {
|
|
3080
|
+
code: Code.fromFeature("global-exports")
|
|
3081
|
+
});
|
|
3082
|
+
lambda.addPermissions({
|
|
3083
|
+
actions: ["cloudformation:ListExports"],
|
|
3084
|
+
resources: ["*"]
|
|
3085
|
+
});
|
|
3086
|
+
const resource = new CustomResource(id, {
|
|
3087
|
+
serviceToken: lambda.arn,
|
|
3088
|
+
properties: {
|
|
3089
|
+
region: props.region
|
|
3090
|
+
}
|
|
3091
|
+
});
|
|
3092
|
+
super([lambda, resource]);
|
|
3093
|
+
this.resource = resource;
|
|
3056
3094
|
}
|
|
3057
|
-
|
|
3058
|
-
return {
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
};
|
|
3095
|
+
import(name) {
|
|
3096
|
+
return lazy((stack) => {
|
|
3097
|
+
const attr = formatName(`${stack.app?.name ?? "default"}-${name}`);
|
|
3098
|
+
return this.resource.getAtt(attr);
|
|
3099
|
+
});
|
|
3062
3100
|
}
|
|
3063
3101
|
};
|
|
3064
3102
|
|
|
@@ -3100,36 +3138,39 @@ var domainPlugin = definePlugin({
|
|
|
3100
3138
|
if (domains.length === 0) {
|
|
3101
3139
|
return;
|
|
3102
3140
|
}
|
|
3103
|
-
const
|
|
3141
|
+
const deleteHostedZoneLambda = new Function("delete-hosted-zone", {
|
|
3104
3142
|
name: `${config.name}-delete-hosted-zone`,
|
|
3105
|
-
code: Code.
|
|
3106
|
-
})
|
|
3107
|
-
lambda.addPermissions({
|
|
3143
|
+
code: Code.fromInlineFeature("delete-hosted-zone")
|
|
3144
|
+
}).enableLogs(Duration.days(3)).addPermissions({
|
|
3108
3145
|
actions: [
|
|
3109
3146
|
"route53:ListResourceRecordSets",
|
|
3110
3147
|
"route53:ChangeResourceRecordSets"
|
|
3111
3148
|
],
|
|
3112
3149
|
resources: ["*"]
|
|
3113
3150
|
});
|
|
3114
|
-
usEastBootstrap.add(
|
|
3151
|
+
usEastBootstrap.add(deleteHostedZoneLambda);
|
|
3152
|
+
const usEastExports = new GlobalExports("us-east-exports", {
|
|
3153
|
+
region: usEastBootstrap.region
|
|
3154
|
+
});
|
|
3155
|
+
bootstrap2.add(usEastExports);
|
|
3115
3156
|
for (const [domain, records] of domains) {
|
|
3116
3157
|
const hostedZone = new HostedZone(domain);
|
|
3117
3158
|
const usEastCertificate = new Certificate(domain, {
|
|
3118
3159
|
hostedZoneId: hostedZone.id,
|
|
3119
3160
|
alternativeNames: [`*.${domain}`]
|
|
3120
3161
|
});
|
|
3121
|
-
const
|
|
3122
|
-
serviceToken:
|
|
3162
|
+
const deleteHostedZone = new CustomResource(domain, {
|
|
3163
|
+
serviceToken: deleteHostedZoneLambda.arn,
|
|
3123
3164
|
properties: {
|
|
3124
3165
|
hostedZoneId: hostedZone.id
|
|
3125
3166
|
}
|
|
3126
|
-
}).dependsOn(hostedZone);
|
|
3127
|
-
usEastBootstrap.add(
|
|
3167
|
+
}).dependsOn(deleteHostedZoneLambda, hostedZone);
|
|
3168
|
+
usEastBootstrap.add(hostedZone).add(deleteHostedZone).add(usEastCertificate).export(`certificate-${domain}-arn`, usEastCertificate.arn).export(`hosted-zone-${domain}-id`, hostedZone.id);
|
|
3128
3169
|
const certificate = new Certificate(domain, {
|
|
3129
|
-
hostedZoneId:
|
|
3170
|
+
hostedZoneId: usEastExports.import(`hosted-zone-${domain}-id`),
|
|
3130
3171
|
alternativeNames: [`*.${domain}`]
|
|
3131
3172
|
});
|
|
3132
|
-
bootstrap2.add(certificate).export(`certificate-${domain}-arn`, certificate.arn);
|
|
3173
|
+
bootstrap2.add(certificate).export(`certificate-${domain}-arn`, certificate.arn).export(`hosted-zone-${domain}-id`, usEastExports.import(`hosted-zone-${domain}-id`)).export(`us-east-certificate-${domain}-arn`, usEastExports.import(`certificate-${domain}-arn`));
|
|
3133
3174
|
if (records.length > 0) {
|
|
3134
3175
|
const group = new RecordSetGroup(domain, {
|
|
3135
3176
|
hostedZoneId: hostedZone.id,
|
|
@@ -3541,7 +3582,7 @@ var LoadBalancer = class extends Resource {
|
|
|
3541
3582
|
};
|
|
3542
3583
|
|
|
3543
3584
|
// src/formation/resource/elb/listener.ts
|
|
3544
|
-
import { constantCase as
|
|
3585
|
+
import { constantCase as constantCase8 } from "change-case";
|
|
3545
3586
|
var Listener = class extends Resource {
|
|
3546
3587
|
constructor(logicalId, props) {
|
|
3547
3588
|
super("AWS::ElasticLoadBalancingV2::Listener", logicalId);
|
|
@@ -3557,7 +3598,7 @@ var Listener = class extends Resource {
|
|
|
3557
3598
|
return {
|
|
3558
3599
|
LoadBalancerArn: this.props.loadBalancerArn,
|
|
3559
3600
|
Port: this.props.port,
|
|
3560
|
-
Protocol:
|
|
3601
|
+
Protocol: constantCase8(this.props.protocol),
|
|
3561
3602
|
Certificates: this.props.certificates.map((arn) => ({
|
|
3562
3603
|
CertificateArn: arn
|
|
3563
3604
|
})),
|
|
@@ -3783,7 +3824,7 @@ var httpPlugin = definePlugin({
|
|
|
3783
3824
|
).optional()
|
|
3784
3825
|
}).array()
|
|
3785
3826
|
}),
|
|
3786
|
-
onApp({ config, bootstrap: bootstrap2
|
|
3827
|
+
onApp({ config, bootstrap: bootstrap2 }) {
|
|
3787
3828
|
if (Object.keys(config.defaults?.http || {}).length === 0) {
|
|
3788
3829
|
return;
|
|
3789
3830
|
}
|
|
@@ -3822,7 +3863,7 @@ var httpPlugin = definePlugin({
|
|
|
3822
3863
|
]
|
|
3823
3864
|
}).dependsOn(loadBalancer);
|
|
3824
3865
|
const record = new RecordSet(`${id}-http`, {
|
|
3825
|
-
hostedZoneId:
|
|
3866
|
+
hostedZoneId: bootstrap2.import(`hosted-zone-${props.domain}-id`),
|
|
3826
3867
|
name: props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain,
|
|
3827
3868
|
type: "A",
|
|
3828
3869
|
alias: {
|
|
@@ -3926,173 +3967,1250 @@ var searchPlugin = definePlugin({
|
|
|
3926
3967
|
});
|
|
3927
3968
|
}
|
|
3928
3969
|
}
|
|
3929
|
-
});
|
|
3930
|
-
|
|
3931
|
-
// src/plugins/cache.ts
|
|
3932
|
-
import { z as z19 } from "zod";
|
|
3970
|
+
});
|
|
3971
|
+
|
|
3972
|
+
// src/plugins/cache.ts
|
|
3973
|
+
import { z as z19 } from "zod";
|
|
3974
|
+
|
|
3975
|
+
// src/formation/resource/memorydb/cluster.ts
|
|
3976
|
+
var Cluster = class extends Resource {
|
|
3977
|
+
constructor(logicalId, props) {
|
|
3978
|
+
super("AWS::MemoryDB::Cluster", logicalId);
|
|
3979
|
+
this.props = props;
|
|
3980
|
+
this.name = formatName(this.props.name || logicalId);
|
|
3981
|
+
this.tag("name", this.name);
|
|
3982
|
+
}
|
|
3983
|
+
name;
|
|
3984
|
+
get status() {
|
|
3985
|
+
return this.getAtt("Status");
|
|
3986
|
+
}
|
|
3987
|
+
get arn() {
|
|
3988
|
+
return this.getAtt("ARN");
|
|
3989
|
+
}
|
|
3990
|
+
get address() {
|
|
3991
|
+
return this.getAtt("ClusterEndpoint.Address");
|
|
3992
|
+
}
|
|
3993
|
+
get port() {
|
|
3994
|
+
return this.getAtt("ClusterEndpoint.Port");
|
|
3995
|
+
}
|
|
3996
|
+
properties() {
|
|
3997
|
+
return {
|
|
3998
|
+
ClusterName: this.name,
|
|
3999
|
+
ClusterEndpoint: {
|
|
4000
|
+
Port: this.props.port
|
|
4001
|
+
},
|
|
4002
|
+
Port: this.props.port,
|
|
4003
|
+
...this.attr("Description", this.props.description),
|
|
4004
|
+
ACLName: this.props.aclName,
|
|
4005
|
+
EngineVersion: this.props.engine ?? "7.0",
|
|
4006
|
+
...this.attr("SubnetGroupName", this.props.subnetGroupName),
|
|
4007
|
+
...this.attr("SecurityGroupIds", this.props.securityGroupIds),
|
|
4008
|
+
NodeType: "db." + this.props.type,
|
|
4009
|
+
NumReplicasPerShard: this.props.replicasPerShard ?? 1,
|
|
4010
|
+
NumShards: this.props.shards ?? 1,
|
|
4011
|
+
TLSEnabled: this.props.tls ?? false,
|
|
4012
|
+
DataTiering: this.props.dataTiering ? "true" : "false",
|
|
4013
|
+
AutoMinorVersionUpgrade: this.props.autoMinorVersionUpgrade ?? true,
|
|
4014
|
+
MaintenanceWindow: this.props.maintenanceWindow ?? "Sat:02:00-Sat:05:00"
|
|
4015
|
+
};
|
|
4016
|
+
}
|
|
4017
|
+
};
|
|
4018
|
+
|
|
4019
|
+
// src/formation/resource/memorydb/subnet-group.ts
|
|
4020
|
+
var SubnetGroup = class extends Resource {
|
|
4021
|
+
constructor(logicalId, props) {
|
|
4022
|
+
super("AWS::MemoryDB::SubnetGroup", logicalId);
|
|
4023
|
+
this.props = props;
|
|
4024
|
+
this.name = formatName(this.props.name || logicalId);
|
|
4025
|
+
}
|
|
4026
|
+
name;
|
|
4027
|
+
get arn() {
|
|
4028
|
+
return getAtt(this.logicalId, "Arn");
|
|
4029
|
+
}
|
|
4030
|
+
properties() {
|
|
4031
|
+
return {
|
|
4032
|
+
SubnetGroupName: this.name,
|
|
4033
|
+
SubnetIds: this.props.subnetIds,
|
|
4034
|
+
...this.attr("Description", this.props.description)
|
|
4035
|
+
};
|
|
4036
|
+
}
|
|
4037
|
+
};
|
|
4038
|
+
|
|
4039
|
+
// src/plugins/cache.ts
|
|
4040
|
+
import { constantCase as constantCase9 } from "change-case";
|
|
4041
|
+
var TypeSchema = z19.enum([
|
|
4042
|
+
"t4g.small",
|
|
4043
|
+
"t4g.medium",
|
|
4044
|
+
"r6g.large",
|
|
4045
|
+
"r6g.xlarge",
|
|
4046
|
+
"r6g.2xlarge",
|
|
4047
|
+
"r6g.4xlarge",
|
|
4048
|
+
"r6g.8xlarge",
|
|
4049
|
+
"r6g.12xlarge",
|
|
4050
|
+
"r6g.16xlarge",
|
|
4051
|
+
"r6gd.xlarge",
|
|
4052
|
+
"r6gd.2xlarge",
|
|
4053
|
+
"r6gd.4xlarge",
|
|
4054
|
+
"r6gd.8xlarge"
|
|
4055
|
+
]);
|
|
4056
|
+
var PortSchema = z19.number().int().min(1).max(5e4);
|
|
4057
|
+
var ShardsSchema = z19.number().int().min(0).max(100);
|
|
4058
|
+
var ReplicasPerShardSchema = z19.number().int().min(0).max(5);
|
|
4059
|
+
var EngineSchema = z19.enum(["7.0", "6.2"]);
|
|
4060
|
+
var cachePlugin = definePlugin({
|
|
4061
|
+
name: "cache",
|
|
4062
|
+
schema: z19.object({
|
|
4063
|
+
stacks: z19.object({
|
|
4064
|
+
/** Define the caches in your stack.
|
|
4065
|
+
* For access to the cache put your functions inside the global VPC.
|
|
4066
|
+
* @example
|
|
4067
|
+
* {
|
|
4068
|
+
* caches: {
|
|
4069
|
+
* CACHE_NAME: {
|
|
4070
|
+
* type: 't4g.small'
|
|
4071
|
+
* }
|
|
4072
|
+
* }
|
|
4073
|
+
* }
|
|
4074
|
+
*/
|
|
4075
|
+
caches: z19.record(
|
|
4076
|
+
ResourceIdSchema,
|
|
4077
|
+
z19.object({
|
|
4078
|
+
type: TypeSchema.default("t4g.small"),
|
|
4079
|
+
port: PortSchema.default(6379),
|
|
4080
|
+
shards: ShardsSchema.default(1),
|
|
4081
|
+
replicasPerShard: ReplicasPerShardSchema.default(1),
|
|
4082
|
+
engine: EngineSchema.default("7.0"),
|
|
4083
|
+
dataTiering: z19.boolean().default(false)
|
|
4084
|
+
})
|
|
4085
|
+
).optional()
|
|
4086
|
+
}).array()
|
|
4087
|
+
}),
|
|
4088
|
+
onTypeGen({ config }) {
|
|
4089
|
+
const gen = new TypeGen("@awsless/awsless", "CacheResources");
|
|
4090
|
+
for (const stack of config.stacks) {
|
|
4091
|
+
const list3 = new TypeObject();
|
|
4092
|
+
for (const name of Object.keys(stack.caches || {})) {
|
|
4093
|
+
list3.addType(name, `{ host: string, port: number }`);
|
|
4094
|
+
}
|
|
4095
|
+
gen.addType(stack.name, list3.toString());
|
|
4096
|
+
}
|
|
4097
|
+
return gen.toString();
|
|
4098
|
+
},
|
|
4099
|
+
onStack({ config, stack, stackConfig, bootstrap: bootstrap2, bind }) {
|
|
4100
|
+
for (const [id, props] of Object.entries(stackConfig.caches || {})) {
|
|
4101
|
+
const name = `${config.name}-${stack.name}-${id}`;
|
|
4102
|
+
const subnetGroup = new SubnetGroup(id, {
|
|
4103
|
+
name,
|
|
4104
|
+
subnetIds: [
|
|
4105
|
+
bootstrap2.import(`private-subnet-1`),
|
|
4106
|
+
bootstrap2.import(`private-subnet-2`)
|
|
4107
|
+
]
|
|
4108
|
+
});
|
|
4109
|
+
const securityGroup = new SecurityGroup(id, {
|
|
4110
|
+
name,
|
|
4111
|
+
vpcId: bootstrap2.import(`vpc-id`),
|
|
4112
|
+
description: name
|
|
4113
|
+
});
|
|
4114
|
+
const port = Port.tcp(props.port);
|
|
4115
|
+
securityGroup.addIngressRule(Peer.anyIpv4(), port);
|
|
4116
|
+
securityGroup.addIngressRule(Peer.anyIpv6(), port);
|
|
4117
|
+
const cluster = new Cluster(id, {
|
|
4118
|
+
name,
|
|
4119
|
+
aclName: "open-access",
|
|
4120
|
+
securityGroupIds: [securityGroup.id],
|
|
4121
|
+
subnetGroupName: subnetGroup.name,
|
|
4122
|
+
...props
|
|
4123
|
+
}).dependsOn(subnetGroup, securityGroup);
|
|
4124
|
+
stack.add(subnetGroup, securityGroup, cluster);
|
|
4125
|
+
bind((lambda) => {
|
|
4126
|
+
lambda.addEnvironment(`CACHE_${constantCase9(stack.name)}_${constantCase9(id)}_HOST`, cluster.address).addEnvironment(`CACHE_${constantCase9(stack.name)}_${constantCase9(id)}_PORT`, props.port.toString());
|
|
4127
|
+
});
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
4130
|
+
});
|
|
4131
|
+
|
|
4132
|
+
// src/plugins/rest.ts
|
|
4133
|
+
import { z as z21 } from "zod";
|
|
4134
|
+
|
|
4135
|
+
// src/schema/route.ts
|
|
4136
|
+
import { z as z20 } from "zod";
|
|
4137
|
+
var RouteSchema2 = z20.custom((route) => {
|
|
4138
|
+
return z20.string().regex(/^(POST|GET|PUT|DELETE|HEAD|OPTIONS)(\s\/[a-z0-9\+\_\-\/\{\}]*)$/ig).safeParse(route).success;
|
|
4139
|
+
}, "Invalid route");
|
|
4140
|
+
|
|
4141
|
+
// src/formation/resource/api-gateway-v2/api.ts
|
|
4142
|
+
var Api = class extends Resource {
|
|
4143
|
+
constructor(logicalId, props) {
|
|
4144
|
+
super("AWS::ApiGatewayV2::Api", logicalId);
|
|
4145
|
+
this.props = props;
|
|
4146
|
+
this.name = formatName(this.props.name || logicalId);
|
|
4147
|
+
}
|
|
4148
|
+
name;
|
|
4149
|
+
get endpoint() {
|
|
4150
|
+
return getAtt(this.logicalId, "ApiEndpoint");
|
|
4151
|
+
}
|
|
4152
|
+
get id() {
|
|
4153
|
+
return getAtt(this.logicalId, "ApiId");
|
|
4154
|
+
}
|
|
4155
|
+
properties() {
|
|
4156
|
+
return {
|
|
4157
|
+
Name: this.name,
|
|
4158
|
+
ProtocolType: this.props.protocolType,
|
|
4159
|
+
...this.attr("Description", this.props.description),
|
|
4160
|
+
CorsConfiguration: {
|
|
4161
|
+
...this.attr("AllowCredentials", this.props.cors?.allow?.credentials),
|
|
4162
|
+
...this.attr("AllowHeaders", this.props.cors?.allow?.headers),
|
|
4163
|
+
...this.attr("AllowMethods", this.props.cors?.allow?.methods),
|
|
4164
|
+
...this.attr("AllowOrigins", this.props.cors?.allow?.origins),
|
|
4165
|
+
...this.attr("ExposeHeaders", this.props.cors?.expose?.headers),
|
|
4166
|
+
...this.attr("MaxAge", this.props.cors?.maxAge?.toSeconds())
|
|
4167
|
+
}
|
|
4168
|
+
};
|
|
4169
|
+
}
|
|
4170
|
+
};
|
|
4171
|
+
|
|
4172
|
+
// src/formation/resource/api-gateway-v2/integration.ts
|
|
4173
|
+
var Integration = class extends Resource {
|
|
4174
|
+
constructor(logicalId, props) {
|
|
4175
|
+
super("AWS::ApiGatewayV2::Integration", logicalId);
|
|
4176
|
+
this.props = props;
|
|
4177
|
+
}
|
|
4178
|
+
get id() {
|
|
4179
|
+
return ref(this.logicalId);
|
|
4180
|
+
}
|
|
4181
|
+
properties() {
|
|
4182
|
+
return {
|
|
4183
|
+
ApiId: this.props.apiId,
|
|
4184
|
+
IntegrationType: this.props.type,
|
|
4185
|
+
IntegrationUri: this.props.uri,
|
|
4186
|
+
IntegrationMethod: this.props.method,
|
|
4187
|
+
PayloadFormatVersion: this.props.payloadFormatVersion ?? "2.0",
|
|
4188
|
+
...this.attr("Description", this.props.description)
|
|
4189
|
+
};
|
|
4190
|
+
}
|
|
4191
|
+
};
|
|
4192
|
+
|
|
4193
|
+
// src/formation/resource/api-gateway-v2/route.ts
|
|
4194
|
+
var Route2 = class extends Resource {
|
|
4195
|
+
constructor(logicalId, props) {
|
|
4196
|
+
super("AWS::ApiGatewayV2::Route", logicalId);
|
|
4197
|
+
this.props = props;
|
|
4198
|
+
}
|
|
4199
|
+
get id() {
|
|
4200
|
+
return getAtt(this.logicalId, "RouteId");
|
|
4201
|
+
}
|
|
4202
|
+
properties() {
|
|
4203
|
+
return {
|
|
4204
|
+
ApiId: this.props.apiId,
|
|
4205
|
+
RouteKey: this.props.routeKey,
|
|
4206
|
+
Target: this.props.target
|
|
4207
|
+
};
|
|
4208
|
+
}
|
|
4209
|
+
};
|
|
4210
|
+
|
|
4211
|
+
// src/formation/resource/lambda/event-source/api-gateway-v2.ts
|
|
4212
|
+
var ApiGatewayV2EventSource = class extends Group {
|
|
4213
|
+
constructor(id, lambda, props) {
|
|
4214
|
+
const name = formatName(id);
|
|
4215
|
+
const permission = new Permission2(id, {
|
|
4216
|
+
action: "lambda:InvokeFunction",
|
|
4217
|
+
principal: "apigateway.amazonaws.com",
|
|
4218
|
+
functionArn: lambda.arn
|
|
4219
|
+
}).dependsOn(lambda);
|
|
4220
|
+
const integration = new Integration(id, {
|
|
4221
|
+
apiId: props.apiId,
|
|
4222
|
+
description: name,
|
|
4223
|
+
method: "POST",
|
|
4224
|
+
payloadFormatVersion: "2.0",
|
|
4225
|
+
type: "AWS_PROXY",
|
|
4226
|
+
uri: sub("arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambda}/invocations", {
|
|
4227
|
+
lambda: lambda.arn
|
|
4228
|
+
})
|
|
4229
|
+
});
|
|
4230
|
+
const route = new Route2(id, {
|
|
4231
|
+
apiId: props.apiId,
|
|
4232
|
+
routeKey: props.routeKey,
|
|
4233
|
+
target: sub("integrations/${id}", { id: integration.id })
|
|
4234
|
+
}).dependsOn(lambda, permission, integration);
|
|
4235
|
+
super([integration, route, permission]);
|
|
4236
|
+
}
|
|
4237
|
+
};
|
|
4238
|
+
|
|
4239
|
+
// src/formation/resource/api-gateway-v2/domain-name.ts
|
|
4240
|
+
var DomainName2 = class extends Resource {
|
|
4241
|
+
constructor(logicalId, props) {
|
|
4242
|
+
super("AWS::ApiGatewayV2::DomainName", logicalId);
|
|
4243
|
+
this.props = props;
|
|
4244
|
+
}
|
|
4245
|
+
get name() {
|
|
4246
|
+
return ref(this.logicalId);
|
|
4247
|
+
}
|
|
4248
|
+
get regionalDomainName() {
|
|
4249
|
+
return getAtt(this.logicalId, "RegionalDomainName");
|
|
4250
|
+
}
|
|
4251
|
+
get regionalHostedZoneId() {
|
|
4252
|
+
return getAtt(this.logicalId, "RegionalHostedZoneId");
|
|
4253
|
+
}
|
|
4254
|
+
properties() {
|
|
4255
|
+
return {
|
|
4256
|
+
DomainName: this.props.name,
|
|
4257
|
+
DomainNameConfigurations: [{
|
|
4258
|
+
CertificateArn: this.props.certificateArn
|
|
4259
|
+
}]
|
|
4260
|
+
};
|
|
4261
|
+
}
|
|
4262
|
+
};
|
|
4263
|
+
|
|
4264
|
+
// src/formation/resource/api-gateway-v2/stage.ts
|
|
4265
|
+
var Stage = class extends Resource {
|
|
4266
|
+
constructor(logicalId, props) {
|
|
4267
|
+
super("AWS::ApiGatewayV2::Stage", logicalId);
|
|
4268
|
+
this.props = props;
|
|
4269
|
+
this.name = formatName(this.props.name || logicalId);
|
|
4270
|
+
}
|
|
4271
|
+
name;
|
|
4272
|
+
properties() {
|
|
4273
|
+
return {
|
|
4274
|
+
ApiId: this.props.apiId,
|
|
4275
|
+
StageName: this.name,
|
|
4276
|
+
AutoDeploy: this.props.autoDeploy ?? true,
|
|
4277
|
+
...this.attr("DeploymentId", this.props.deploymentId),
|
|
4278
|
+
...this.attr("Description", this.props.description)
|
|
4279
|
+
};
|
|
4280
|
+
}
|
|
4281
|
+
};
|
|
4282
|
+
|
|
4283
|
+
// src/formation/resource/api-gateway-v2/api-mapping.ts
|
|
4284
|
+
var ApiMapping = class extends Resource {
|
|
4285
|
+
constructor(logicalId, props) {
|
|
4286
|
+
super("AWS::ApiGatewayV2::ApiMapping", logicalId);
|
|
4287
|
+
this.props = props;
|
|
4288
|
+
}
|
|
4289
|
+
get id() {
|
|
4290
|
+
return getAtt(this.logicalId, "ApiMappingId");
|
|
4291
|
+
}
|
|
4292
|
+
properties() {
|
|
4293
|
+
return {
|
|
4294
|
+
DomainName: this.props.domainName,
|
|
4295
|
+
ApiId: this.props.apiId,
|
|
4296
|
+
Stage: this.props.stage
|
|
4297
|
+
};
|
|
4298
|
+
}
|
|
4299
|
+
};
|
|
4300
|
+
|
|
4301
|
+
// src/plugins/rest.ts
|
|
4302
|
+
var restPlugin = definePlugin({
|
|
4303
|
+
name: "rest",
|
|
4304
|
+
schema: z21.object({
|
|
4305
|
+
defaults: z21.object({
|
|
4306
|
+
/** Define your global REST API's.
|
|
4307
|
+
* @example
|
|
4308
|
+
* {
|
|
4309
|
+
* rest: {
|
|
4310
|
+
* REST_API_NAME: {
|
|
4311
|
+
* domain: 'example.com',
|
|
4312
|
+
* subDomain: 'api',
|
|
4313
|
+
* }
|
|
4314
|
+
* }
|
|
4315
|
+
* }
|
|
4316
|
+
*/
|
|
4317
|
+
rest: z21.record(
|
|
4318
|
+
ResourceIdSchema,
|
|
4319
|
+
z21.object({
|
|
4320
|
+
/** The domain to link your API with. */
|
|
4321
|
+
domain: z21.string(),
|
|
4322
|
+
subDomain: z21.string().optional()
|
|
4323
|
+
})
|
|
4324
|
+
).optional()
|
|
4325
|
+
}).default({}),
|
|
4326
|
+
stacks: z21.object({
|
|
4327
|
+
/** Define routes in your stack for your global REST API.
|
|
4328
|
+
* @example
|
|
4329
|
+
* {
|
|
4330
|
+
* rest: {
|
|
4331
|
+
* REST_API_NAME: {
|
|
4332
|
+
* 'GET /': 'index.ts',
|
|
4333
|
+
* 'POST /posts': 'create-post.ts',
|
|
4334
|
+
* }
|
|
4335
|
+
* }
|
|
4336
|
+
* }
|
|
4337
|
+
*/
|
|
4338
|
+
rest: z21.record(
|
|
4339
|
+
ResourceIdSchema,
|
|
4340
|
+
z21.record(RouteSchema2, FunctionSchema)
|
|
4341
|
+
).optional()
|
|
4342
|
+
}).array()
|
|
4343
|
+
}),
|
|
4344
|
+
onApp({ config, bootstrap: bootstrap2 }) {
|
|
4345
|
+
for (const [id, props] of Object.entries(config.defaults?.rest || {})) {
|
|
4346
|
+
const api = new Api(id, {
|
|
4347
|
+
name: `${config.name}-${id}`,
|
|
4348
|
+
protocolType: "HTTP"
|
|
4349
|
+
});
|
|
4350
|
+
const stage = new Stage(id, {
|
|
4351
|
+
name: "v1",
|
|
4352
|
+
apiId: api.id
|
|
4353
|
+
}).dependsOn(api);
|
|
4354
|
+
bootstrap2.add(api, stage).export(`rest-${id}-id`, api.id);
|
|
4355
|
+
if (props.domain) {
|
|
4356
|
+
const domainName = props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain;
|
|
4357
|
+
const hostedZoneId = bootstrap2.import(`hosted-zone-${props.domain}-id`);
|
|
4358
|
+
const certificateArn = bootstrap2.import(`certificate-${props.domain}-arn`);
|
|
4359
|
+
const domain = new DomainName2(id, {
|
|
4360
|
+
name: domainName,
|
|
4361
|
+
certificateArn
|
|
4362
|
+
});
|
|
4363
|
+
const mapping = new ApiMapping(id, {
|
|
4364
|
+
apiId: api.id,
|
|
4365
|
+
domainName: domain.name,
|
|
4366
|
+
stage: stage.name
|
|
4367
|
+
}).dependsOn(api, domain, stage);
|
|
4368
|
+
const record = new RecordSet(`rest-${id}`, {
|
|
4369
|
+
hostedZoneId,
|
|
4370
|
+
type: "A",
|
|
4371
|
+
name: domainName,
|
|
4372
|
+
alias: {
|
|
4373
|
+
dnsName: domain.regionalDomainName,
|
|
4374
|
+
hostedZoneId: domain.regionalHostedZoneId
|
|
4375
|
+
}
|
|
4376
|
+
}).dependsOn(domain, mapping);
|
|
4377
|
+
bootstrap2.add(domain, mapping, record);
|
|
4378
|
+
}
|
|
4379
|
+
}
|
|
4380
|
+
},
|
|
4381
|
+
onStack(ctx) {
|
|
4382
|
+
const { stack, stackConfig, bootstrap: bootstrap2 } = ctx;
|
|
4383
|
+
for (const [id, routes] of Object.entries(stackConfig.rest || {})) {
|
|
4384
|
+
for (const [routeKey, props] of Object.entries(routes)) {
|
|
4385
|
+
const lambda = toLambdaFunction(ctx, `rest-${id}-${routeKey}`, props);
|
|
4386
|
+
const source = new ApiGatewayV2EventSource(`rest-${id}-${routeKey}`, lambda, {
|
|
4387
|
+
apiId: bootstrap2.import(`rest-${id}-id`),
|
|
4388
|
+
routeKey
|
|
4389
|
+
});
|
|
4390
|
+
stack.add(lambda, source);
|
|
4391
|
+
}
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
4394
|
+
});
|
|
4395
|
+
|
|
4396
|
+
// src/plugins/config.ts
|
|
4397
|
+
import { z as z22 } from "zod";
|
|
4398
|
+
|
|
4399
|
+
// src/util/param.ts
|
|
4400
|
+
import { DeleteParameterCommand, GetParameterCommand, GetParametersByPathCommand, ParameterType, PutParameterCommand, SSMClient } from "@aws-sdk/client-ssm";
|
|
4401
|
+
var configParameterPrefix = (config) => {
|
|
4402
|
+
return `/.awsless/${config.name}`;
|
|
4403
|
+
};
|
|
4404
|
+
var Params = class {
|
|
4405
|
+
constructor(config) {
|
|
4406
|
+
this.config = config;
|
|
4407
|
+
this.client = new SSMClient({
|
|
4408
|
+
credentials: config.credentials,
|
|
4409
|
+
region: config.region
|
|
4410
|
+
});
|
|
4411
|
+
}
|
|
4412
|
+
client;
|
|
4413
|
+
getName(name) {
|
|
4414
|
+
return `${configParameterPrefix(this.config)}/${name}`;
|
|
4415
|
+
}
|
|
4416
|
+
async get(name) {
|
|
4417
|
+
debug("Get remote config value");
|
|
4418
|
+
debug("Name:", style.info(name));
|
|
4419
|
+
let result;
|
|
4420
|
+
try {
|
|
4421
|
+
result = await this.client.send(new GetParameterCommand({
|
|
4422
|
+
Name: this.getName(name),
|
|
4423
|
+
WithDecryption: true
|
|
4424
|
+
}));
|
|
4425
|
+
} catch (error) {
|
|
4426
|
+
if (error instanceof Error && error.name === "ParameterNotFound") {
|
|
4427
|
+
debug("Parameter not found");
|
|
4428
|
+
return;
|
|
4429
|
+
}
|
|
4430
|
+
throw error;
|
|
4431
|
+
}
|
|
4432
|
+
const value = result.Parameter?.Value;
|
|
4433
|
+
debug("Value:", style.info(value));
|
|
4434
|
+
debug("Done getting remote config value");
|
|
4435
|
+
return value;
|
|
4436
|
+
}
|
|
4437
|
+
async set(name, value) {
|
|
4438
|
+
debug("Save remote config value");
|
|
4439
|
+
debug("Name:", style.info(name));
|
|
4440
|
+
debug("Value:", style.info(value));
|
|
4441
|
+
await this.client.send(new PutParameterCommand({
|
|
4442
|
+
Type: ParameterType.STRING,
|
|
4443
|
+
Name: this.getName(name),
|
|
4444
|
+
Value: value,
|
|
4445
|
+
Overwrite: true
|
|
4446
|
+
}));
|
|
4447
|
+
debug("Done saving remote config value");
|
|
4448
|
+
}
|
|
4449
|
+
async delete(name) {
|
|
4450
|
+
debug("Delete remote config value");
|
|
4451
|
+
debug("Name:", style.info(name));
|
|
4452
|
+
try {
|
|
4453
|
+
await this.client.send(new DeleteParameterCommand({
|
|
4454
|
+
Name: this.getName(name)
|
|
4455
|
+
}));
|
|
4456
|
+
} catch (error) {
|
|
4457
|
+
if (error instanceof Error && error.name === "ParameterNotFound") {
|
|
4458
|
+
debug("Remote config value was already deleted");
|
|
4459
|
+
return;
|
|
4460
|
+
}
|
|
4461
|
+
throw error;
|
|
4462
|
+
}
|
|
4463
|
+
debug("Done deleting remote config value");
|
|
4464
|
+
}
|
|
4465
|
+
async list() {
|
|
4466
|
+
debug("Load remote config values");
|
|
4467
|
+
const result = await this.client.send(new GetParametersByPathCommand({
|
|
4468
|
+
Path: configParameterPrefix(this.config),
|
|
4469
|
+
WithDecryption: true,
|
|
4470
|
+
MaxResults: 10,
|
|
4471
|
+
Recursive: true
|
|
4472
|
+
}));
|
|
4473
|
+
debug("Done loading remote config values");
|
|
4474
|
+
const values = {};
|
|
4475
|
+
result.Parameters?.forEach((param) => {
|
|
4476
|
+
const name = param.Name.substring(configParameterPrefix(this.config).length).substring(1);
|
|
4477
|
+
values[name] = param.Value || "";
|
|
4478
|
+
});
|
|
4479
|
+
return values;
|
|
4480
|
+
}
|
|
4481
|
+
};
|
|
4482
|
+
|
|
4483
|
+
// src/plugins/config.ts
|
|
4484
|
+
import { paramCase as paramCase5 } from "change-case";
|
|
4485
|
+
var ConfigNameSchema = z22.string().regex(/[a-z0-9\-]/g, "Invalid config name");
|
|
4486
|
+
var configPlugin = definePlugin({
|
|
4487
|
+
name: "config",
|
|
4488
|
+
schema: z22.object({
|
|
4489
|
+
stacks: z22.object({
|
|
4490
|
+
/** Define the config values for your stack.
|
|
4491
|
+
* @example
|
|
4492
|
+
* ```
|
|
4493
|
+
* {
|
|
4494
|
+
* configs: [ 'your-secret' ]
|
|
4495
|
+
* }
|
|
4496
|
+
* ```
|
|
4497
|
+
*
|
|
4498
|
+
* You can access the config values via:
|
|
4499
|
+
* @example
|
|
4500
|
+
* ```
|
|
4501
|
+
* import { Config } from '@awsless/awsless'
|
|
4502
|
+
*
|
|
4503
|
+
* Config.YOUR_SECRET
|
|
4504
|
+
* ```
|
|
4505
|
+
*/
|
|
4506
|
+
configs: z22.array(ConfigNameSchema).optional()
|
|
4507
|
+
}).array()
|
|
4508
|
+
}),
|
|
4509
|
+
onTypeGen({ config }) {
|
|
4510
|
+
const types2 = new TypeGen("@awsless/awsless", "ConfigResources", false);
|
|
4511
|
+
for (const stack of config.stacks) {
|
|
4512
|
+
for (const name of stack.configs || []) {
|
|
4513
|
+
types2.addConst(name, "string");
|
|
4514
|
+
}
|
|
4515
|
+
}
|
|
4516
|
+
return types2.toString();
|
|
4517
|
+
},
|
|
4518
|
+
onStack({ bind, config, stackConfig }) {
|
|
4519
|
+
const configs = stackConfig.configs;
|
|
4520
|
+
bind((lambda) => {
|
|
4521
|
+
if (configs && configs.length) {
|
|
4522
|
+
lambda.addEnvironment("AWSLESS_CONFIG", configs.join(","));
|
|
4523
|
+
lambda.addPermissions({
|
|
4524
|
+
actions: [
|
|
4525
|
+
"ssm:GetParameter",
|
|
4526
|
+
"ssm:GetParameters",
|
|
4527
|
+
"ssm:GetParametersByPath"
|
|
4528
|
+
],
|
|
4529
|
+
resources: configs.map((name) => {
|
|
4530
|
+
return formatArn({
|
|
4531
|
+
service: "ssm",
|
|
4532
|
+
resource: "parameter",
|
|
4533
|
+
resourceName: configParameterPrefix(config) + "/" + paramCase5(name),
|
|
4534
|
+
seperator: ""
|
|
4535
|
+
});
|
|
4536
|
+
})
|
|
4537
|
+
});
|
|
4538
|
+
}
|
|
4539
|
+
});
|
|
4540
|
+
}
|
|
4541
|
+
});
|
|
4542
|
+
|
|
4543
|
+
// src/plugins/site.ts
|
|
4544
|
+
import { z as z24 } from "zod";
|
|
4545
|
+
|
|
4546
|
+
// src/formation/resource/cloud-front/distribution.ts
|
|
4547
|
+
var Distribution = class extends Resource {
|
|
4548
|
+
constructor(logicalId, props) {
|
|
4549
|
+
super("AWS::CloudFront::Distribution", logicalId);
|
|
4550
|
+
this.props = props;
|
|
4551
|
+
this.name = formatName(this.props.name || logicalId);
|
|
4552
|
+
this.tag("name", this.name);
|
|
4553
|
+
}
|
|
4554
|
+
name;
|
|
4555
|
+
get id() {
|
|
4556
|
+
return getAtt(this.logicalId, "Id");
|
|
4557
|
+
}
|
|
4558
|
+
get arn() {
|
|
4559
|
+
return sub("arn:${AWS::Partition}:cloudfront::${AWS::AccountId}:distribution/${id}", {
|
|
4560
|
+
id: this.id
|
|
4561
|
+
});
|
|
4562
|
+
}
|
|
4563
|
+
get domainName() {
|
|
4564
|
+
return getAtt(this.logicalId, "DomainName");
|
|
4565
|
+
}
|
|
4566
|
+
properties() {
|
|
4567
|
+
return {
|
|
4568
|
+
DistributionConfig: {
|
|
4569
|
+
Enabled: true,
|
|
4570
|
+
Aliases: this.props.aliases ?? [],
|
|
4571
|
+
PriceClass: "PriceClass_" + (this.props.priceClass ?? "All"),
|
|
4572
|
+
HttpVersion: this.props.httpVersion ?? "http2and3",
|
|
4573
|
+
ViewerCertificate: this.props.certificateArn ? {
|
|
4574
|
+
SslSupportMethod: "sni-only",
|
|
4575
|
+
AcmCertificateArn: this.props.certificateArn
|
|
4576
|
+
} : {},
|
|
4577
|
+
Origins: this.props.origins?.map((origin) => origin.toJSON()) ?? [],
|
|
4578
|
+
OriginGroups: {
|
|
4579
|
+
Quantity: this.props.originGroups?.length ?? 0,
|
|
4580
|
+
Items: this.props.originGroups?.map((originGroup) => originGroup.toJSON()) ?? []
|
|
4581
|
+
},
|
|
4582
|
+
DefaultCacheBehavior: {
|
|
4583
|
+
TargetOriginId: this.props.targetOriginId,
|
|
4584
|
+
ViewerProtocolPolicy: this.props.viewerProtocol ?? "redirect-to-https",
|
|
4585
|
+
AllowedMethods: this.props.allowMethod ?? ["GET", "HEAD", "OPTIONS"],
|
|
4586
|
+
Compress: this.props.compress ?? false,
|
|
4587
|
+
FunctionAssociations: this.props.associations?.map((association) => ({
|
|
4588
|
+
EventType: association.type,
|
|
4589
|
+
FunctionARN: association.functionArn
|
|
4590
|
+
})) ?? [],
|
|
4591
|
+
LambdaFunctionAssociations: this.props.lambdaAssociations?.map((association) => ({
|
|
4592
|
+
EventType: association.type,
|
|
4593
|
+
IncludeBody: association.includeBody ?? false,
|
|
4594
|
+
FunctionARN: association.functionArn
|
|
4595
|
+
})) ?? [],
|
|
4596
|
+
...this.attr("CachePolicyId", this.props.cachePolicyId),
|
|
4597
|
+
...this.attr("OriginRequestPolicyId", this.props.originRequestPolicyId),
|
|
4598
|
+
...this.attr("ResponseHeadersPolicyId", this.props.responseHeadersPolicyId)
|
|
4599
|
+
}
|
|
4600
|
+
}
|
|
4601
|
+
};
|
|
4602
|
+
}
|
|
4603
|
+
};
|
|
4604
|
+
var Origin = class {
|
|
4605
|
+
constructor(props) {
|
|
4606
|
+
this.props = props;
|
|
4607
|
+
}
|
|
4608
|
+
toJSON() {
|
|
4609
|
+
return {
|
|
4610
|
+
Id: this.props.id,
|
|
4611
|
+
DomainName: this.props.domainName,
|
|
4612
|
+
OriginCustomHeaders: Object.entries(this.props.headers ?? {}).map(([name, value]) => ({
|
|
4613
|
+
HeaderName: name,
|
|
4614
|
+
HeaderValue: value
|
|
4615
|
+
})),
|
|
4616
|
+
...this.props.path ? {
|
|
4617
|
+
OriginPath: this.props.path
|
|
4618
|
+
} : {},
|
|
4619
|
+
...this.props.protocol ? {
|
|
4620
|
+
CustomOriginConfig: {
|
|
4621
|
+
OriginProtocolPolicy: this.props.protocol
|
|
4622
|
+
}
|
|
4623
|
+
} : {},
|
|
4624
|
+
...this.props.originAccessIdentityId ? {
|
|
4625
|
+
S3OriginConfig: {
|
|
4626
|
+
OriginAccessIdentity: sub("origin-access-identity/cloudfront/${id}", {
|
|
4627
|
+
id: this.props.originAccessIdentityId
|
|
4628
|
+
})
|
|
4629
|
+
}
|
|
4630
|
+
} : {},
|
|
4631
|
+
...this.props.originAccessControlId ? {
|
|
4632
|
+
OriginAccessControlId: this.props.originAccessControlId,
|
|
4633
|
+
S3OriginConfig: {
|
|
4634
|
+
OriginAccessIdentity: ""
|
|
4635
|
+
}
|
|
4636
|
+
} : {}
|
|
4637
|
+
};
|
|
4638
|
+
}
|
|
4639
|
+
};
|
|
4640
|
+
var OriginGroup = class {
|
|
4641
|
+
constructor(props) {
|
|
4642
|
+
this.props = props;
|
|
4643
|
+
}
|
|
4644
|
+
toJSON() {
|
|
4645
|
+
return {
|
|
4646
|
+
Id: this.props.id,
|
|
4647
|
+
Members: {
|
|
4648
|
+
Quantity: this.props.members.length,
|
|
4649
|
+
Items: this.props.members.map((member) => ({
|
|
4650
|
+
OriginId: member
|
|
4651
|
+
}))
|
|
4652
|
+
},
|
|
4653
|
+
FailoverCriteria: {
|
|
4654
|
+
StatusCodes: {
|
|
4655
|
+
Quantity: this.props.statusCodes.length,
|
|
4656
|
+
Items: this.props.statusCodes
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
};
|
|
4660
|
+
}
|
|
4661
|
+
};
|
|
4662
|
+
|
|
4663
|
+
// src/schema/local-directory.ts
|
|
4664
|
+
import { stat as stat2 } from "fs/promises";
|
|
4665
|
+
import { z as z23 } from "zod";
|
|
4666
|
+
var LocalDirectorySchema = z23.string().refine(async (path) => {
|
|
4667
|
+
try {
|
|
4668
|
+
const s = await stat2(path);
|
|
4669
|
+
return s.isDirectory();
|
|
4670
|
+
} catch (error) {
|
|
4671
|
+
return false;
|
|
4672
|
+
}
|
|
4673
|
+
}, `Directory doesn't exist`);
|
|
4674
|
+
|
|
4675
|
+
// src/formation/resource/cloud-front/origin-request-policy.ts
|
|
4676
|
+
import { camelCase as camelCase4 } from "change-case";
|
|
4677
|
+
var OriginRequestPolicy = class extends Resource {
|
|
4678
|
+
constructor(logicalId, props = {}) {
|
|
4679
|
+
super("AWS::CloudFront::OriginRequestPolicy", logicalId);
|
|
4680
|
+
this.props = props;
|
|
4681
|
+
this.name = formatName(this.props.name || logicalId);
|
|
4682
|
+
}
|
|
4683
|
+
name;
|
|
4684
|
+
get id() {
|
|
4685
|
+
return getAtt(this.logicalId, "Id");
|
|
4686
|
+
}
|
|
4687
|
+
properties() {
|
|
4688
|
+
return {
|
|
4689
|
+
OriginRequestPolicyConfig: {
|
|
4690
|
+
Name: this.name,
|
|
4691
|
+
CookiesConfig: {
|
|
4692
|
+
CookieBehavior: camelCase4(this.props.cookie?.behavior ?? "all"),
|
|
4693
|
+
...this.attr("Cookies", this.props.cookie?.values)
|
|
4694
|
+
},
|
|
4695
|
+
HeadersConfig: {
|
|
4696
|
+
HeaderBehavior: camelCase4(this.props.header?.behavior ?? "allViewer"),
|
|
4697
|
+
...this.attr("Headers", this.props.header?.values)
|
|
4698
|
+
},
|
|
4699
|
+
QueryStringsConfig: {
|
|
4700
|
+
QueryStringBehavior: camelCase4(this.props.query?.behavior ?? "all"),
|
|
4701
|
+
...this.attr("QueryStrings", this.props.query?.values)
|
|
4702
|
+
}
|
|
4703
|
+
}
|
|
4704
|
+
};
|
|
4705
|
+
}
|
|
4706
|
+
};
|
|
4707
|
+
|
|
4708
|
+
// src/formation/resource/cloud-front/cache-policy.ts
|
|
4709
|
+
var CachePolicy = class extends Resource {
|
|
4710
|
+
constructor(logicalId, props) {
|
|
4711
|
+
super("AWS::CloudFront::CachePolicy", logicalId);
|
|
4712
|
+
this.props = props;
|
|
4713
|
+
this.name = formatName(this.props.name || logicalId);
|
|
4714
|
+
}
|
|
4715
|
+
name;
|
|
4716
|
+
get id() {
|
|
4717
|
+
return getAtt(this.logicalId, "Id");
|
|
4718
|
+
}
|
|
4719
|
+
properties() {
|
|
4720
|
+
return {
|
|
4721
|
+
CachePolicyConfig: {
|
|
4722
|
+
Name: this.name,
|
|
4723
|
+
MinTTL: this.props.minTtl.toSeconds(),
|
|
4724
|
+
MaxTTL: this.props.maxTtl.toSeconds(),
|
|
4725
|
+
DefaultTTL: this.props.defaultTtl.toSeconds(),
|
|
4726
|
+
ParametersInCacheKeyAndForwardedToOrigin: {
|
|
4727
|
+
EnableAcceptEncodingGzip: this.props.acceptGzip ?? false,
|
|
4728
|
+
EnableAcceptEncodingBrotli: this.props.acceptBrotli ?? false,
|
|
4729
|
+
CookiesConfig: {
|
|
4730
|
+
CookieBehavior: this.props.cookies ? "whitelist" : "none",
|
|
4731
|
+
...this.attr("Cookies", this.props.cookies)
|
|
4732
|
+
},
|
|
4733
|
+
HeadersConfig: {
|
|
4734
|
+
HeaderBehavior: this.props.headers ? "whitelist" : "none",
|
|
4735
|
+
...this.attr("Headers", this.props.headers)
|
|
4736
|
+
},
|
|
4737
|
+
QueryStringsConfig: {
|
|
4738
|
+
QueryStringBehavior: this.props.queries ? "whitelist" : "none",
|
|
4739
|
+
...this.attr("QueryStrings", this.props.queries)
|
|
4740
|
+
}
|
|
4741
|
+
}
|
|
4742
|
+
}
|
|
4743
|
+
};
|
|
4744
|
+
}
|
|
4745
|
+
};
|
|
4746
|
+
|
|
4747
|
+
// src/formation/resource/s3/files.ts
|
|
4748
|
+
import { Glob } from "glob";
|
|
4749
|
+
import JSZip2 from "jszip";
|
|
4750
|
+
import { createHash as createHash2 } from "crypto";
|
|
4751
|
+
import { createReadStream } from "fs";
|
|
4752
|
+
import { join as join4 } from "path";
|
|
4753
|
+
var Files = class extends Asset {
|
|
4754
|
+
constructor(id, props) {
|
|
4755
|
+
super("bucket", id);
|
|
4756
|
+
this.props = props;
|
|
4757
|
+
}
|
|
4758
|
+
hash;
|
|
4759
|
+
bundle;
|
|
4760
|
+
s3;
|
|
4761
|
+
async build({ write }) {
|
|
4762
|
+
const glob = new Glob(this.props.pattern ?? "**/*", {
|
|
4763
|
+
nodir: true,
|
|
4764
|
+
cwd: this.props.directory
|
|
4765
|
+
});
|
|
4766
|
+
const zip = new JSZip2();
|
|
4767
|
+
const hashes = [];
|
|
4768
|
+
let count = 0;
|
|
4769
|
+
for await (const path of glob) {
|
|
4770
|
+
const file = join4(this.props.directory, path);
|
|
4771
|
+
const stream = createReadStream(file);
|
|
4772
|
+
const hash2 = createHash2("sha1");
|
|
4773
|
+
stream.pipe(hash2);
|
|
4774
|
+
hashes.push(hash2);
|
|
4775
|
+
zip.file(path, stream);
|
|
4776
|
+
count++;
|
|
4777
|
+
}
|
|
4778
|
+
this.bundle = await zip.generateAsync({
|
|
4779
|
+
type: "nodebuffer",
|
|
4780
|
+
compression: "DEFLATE",
|
|
4781
|
+
compressionOptions: {
|
|
4782
|
+
level: 9
|
|
4783
|
+
}
|
|
4784
|
+
});
|
|
4785
|
+
const hash = createHash2("sha1");
|
|
4786
|
+
for (const item of hashes) {
|
|
4787
|
+
hash.update(item.digest());
|
|
4788
|
+
}
|
|
4789
|
+
this.hash = hash.digest("hex");
|
|
4790
|
+
await write("HASH", this.hash);
|
|
4791
|
+
await write("bundle.zip", this.bundle);
|
|
4792
|
+
return {
|
|
4793
|
+
files: style.success(String(count)),
|
|
4794
|
+
size: formatByteSize(this.bundle.byteLength)
|
|
4795
|
+
};
|
|
4796
|
+
}
|
|
4797
|
+
async publish({ publish }) {
|
|
4798
|
+
this.s3 = await publish(
|
|
4799
|
+
`${this.id}.zip`,
|
|
4800
|
+
this.bundle,
|
|
4801
|
+
this.hash
|
|
4802
|
+
);
|
|
4803
|
+
}
|
|
4804
|
+
get source() {
|
|
4805
|
+
return this.s3;
|
|
4806
|
+
}
|
|
4807
|
+
};
|
|
4808
|
+
|
|
4809
|
+
// src/formation/resource/s3/bucket-policy.ts
|
|
4810
|
+
import { capitalCase } from "change-case";
|
|
4811
|
+
var BucketPolicy = class extends Resource {
|
|
4812
|
+
constructor(logicalId, props) {
|
|
4813
|
+
super("AWS::S3::BucketPolicy", logicalId);
|
|
4814
|
+
this.props = props;
|
|
4815
|
+
}
|
|
4816
|
+
properties() {
|
|
4817
|
+
return {
|
|
4818
|
+
Bucket: formatName(this.props.bucketName),
|
|
4819
|
+
PolicyDocument: {
|
|
4820
|
+
Version: this.props.version ?? "2012-10-17",
|
|
4821
|
+
Statement: this.props.statements.map((statement) => ({
|
|
4822
|
+
Effect: capitalCase(statement.effect ?? "allow"),
|
|
4823
|
+
...statement.principal ? {
|
|
4824
|
+
Principal: {
|
|
4825
|
+
Service: statement.principal
|
|
4826
|
+
}
|
|
4827
|
+
} : {},
|
|
4828
|
+
Action: statement.actions,
|
|
4829
|
+
Resource: statement.resources,
|
|
4830
|
+
...statement.sourceArn ? {
|
|
4831
|
+
Condition: {
|
|
4832
|
+
StringEquals: {
|
|
4833
|
+
"AWS:SourceArn": statement.sourceArn
|
|
4834
|
+
}
|
|
4835
|
+
}
|
|
4836
|
+
} : {}
|
|
4837
|
+
}))
|
|
4838
|
+
}
|
|
4839
|
+
};
|
|
4840
|
+
}
|
|
4841
|
+
};
|
|
3933
4842
|
|
|
3934
|
-
// src/formation/resource/
|
|
3935
|
-
var
|
|
4843
|
+
// src/formation/resource/cloud-front/origin-access-control.ts
|
|
4844
|
+
var OriginAccessControl = class extends Resource {
|
|
3936
4845
|
constructor(logicalId, props) {
|
|
3937
|
-
super("AWS::
|
|
4846
|
+
super("AWS::CloudFront::OriginAccessControl", logicalId);
|
|
3938
4847
|
this.props = props;
|
|
3939
4848
|
this.name = formatName(this.props.name || logicalId);
|
|
3940
|
-
this.tag("name", this.name);
|
|
3941
4849
|
}
|
|
3942
4850
|
name;
|
|
3943
|
-
get
|
|
3944
|
-
return this.
|
|
3945
|
-
}
|
|
3946
|
-
get arn() {
|
|
3947
|
-
return this.getAtt("ARN");
|
|
3948
|
-
}
|
|
3949
|
-
get address() {
|
|
3950
|
-
return this.getAtt("ClusterEndpoint.Address");
|
|
3951
|
-
}
|
|
3952
|
-
get port() {
|
|
3953
|
-
return this.getAtt("ClusterEndpoint.Port");
|
|
4851
|
+
get id() {
|
|
4852
|
+
return getAtt(this.logicalId, "Id");
|
|
3954
4853
|
}
|
|
3955
4854
|
properties() {
|
|
3956
4855
|
return {
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
ACLName: this.props.aclName,
|
|
3964
|
-
EngineVersion: this.props.engine ?? "7.0",
|
|
3965
|
-
...this.attr("SubnetGroupName", this.props.subnetGroupName),
|
|
3966
|
-
...this.attr("SecurityGroupIds", this.props.securityGroupIds),
|
|
3967
|
-
NodeType: "db." + this.props.type,
|
|
3968
|
-
NumReplicasPerShard: this.props.replicasPerShard ?? 1,
|
|
3969
|
-
NumShards: this.props.shards ?? 1,
|
|
3970
|
-
TLSEnabled: this.props.tls ?? false,
|
|
3971
|
-
DataTiering: this.props.dataTiering ? "true" : "false",
|
|
3972
|
-
AutoMinorVersionUpgrade: this.props.autoMinorVersionUpgrade ?? true,
|
|
3973
|
-
MaintenanceWindow: this.props.maintenanceWindow ?? "Sat:02:00-Sat:05:00"
|
|
4856
|
+
OriginAccessControlConfig: {
|
|
4857
|
+
Name: this.name,
|
|
4858
|
+
OriginAccessControlOriginType: this.props.type,
|
|
4859
|
+
SigningBehavior: this.props.behavior ?? "always",
|
|
4860
|
+
SigningProtocol: this.props.protocol ?? "sigv4"
|
|
4861
|
+
}
|
|
3974
4862
|
};
|
|
3975
4863
|
}
|
|
3976
4864
|
};
|
|
3977
4865
|
|
|
3978
|
-
// src/formation/resource/
|
|
3979
|
-
var
|
|
4866
|
+
// src/formation/resource/cloud-front/response-headers-policy.ts
|
|
4867
|
+
var ResponseHeadersPolicy = class extends Resource {
|
|
3980
4868
|
constructor(logicalId, props) {
|
|
3981
|
-
super("AWS::
|
|
4869
|
+
super("AWS::CloudFront::ResponseHeadersPolicy", logicalId);
|
|
3982
4870
|
this.props = props;
|
|
3983
4871
|
this.name = formatName(this.props.name || logicalId);
|
|
3984
4872
|
}
|
|
3985
4873
|
name;
|
|
3986
|
-
get
|
|
3987
|
-
return getAtt(this.logicalId, "
|
|
4874
|
+
get id() {
|
|
4875
|
+
return getAtt(this.logicalId, "Id");
|
|
3988
4876
|
}
|
|
3989
4877
|
properties() {
|
|
3990
4878
|
return {
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
4879
|
+
ResponseHeadersPolicyConfig: {
|
|
4880
|
+
Name: this.name,
|
|
4881
|
+
...this.props.remove && this.props.remove.length > 0 ? {
|
|
4882
|
+
RemoveHeadersConfig: {
|
|
4883
|
+
Items: this.props.remove?.map((value) => ({
|
|
4884
|
+
Header: value
|
|
4885
|
+
}))
|
|
4886
|
+
}
|
|
4887
|
+
} : {},
|
|
4888
|
+
CorsConfig: {
|
|
4889
|
+
OriginOverride: this.props.cors?.override ?? false,
|
|
4890
|
+
AccessControlAllowCredentials: this.props.cors?.credentials ?? false,
|
|
4891
|
+
AccessControlMaxAgeSec: this.props.cors?.maxAge?.toSeconds() ?? Duration.days(365).toSeconds(),
|
|
4892
|
+
AccessControlAllowHeaders: {
|
|
4893
|
+
Items: this.props.cors?.headers ?? ["*"]
|
|
4894
|
+
},
|
|
4895
|
+
AccessControlAllowMethods: {
|
|
4896
|
+
Items: this.props.cors?.methods ?? ["ALL"]
|
|
4897
|
+
},
|
|
4898
|
+
AccessControlAllowOrigins: {
|
|
4899
|
+
Items: this.props.cors?.origins ?? ["*"]
|
|
4900
|
+
},
|
|
4901
|
+
AccessControlExposeHeaders: {
|
|
4902
|
+
Items: this.props.cors?.exposeHeaders ?? ["*"]
|
|
4903
|
+
}
|
|
4904
|
+
},
|
|
4905
|
+
SecurityHeadersConfig: {
|
|
4906
|
+
...this.props.contentSecurityPolicy ? {
|
|
4907
|
+
ContentSecurityPolicy: {
|
|
4908
|
+
Override: this.props.contentSecurityPolicy?.override ?? false,
|
|
4909
|
+
ContentSecurityPolicy: this.props.contentSecurityPolicy?.contentSecurityPolicy
|
|
4910
|
+
}
|
|
4911
|
+
} : {},
|
|
4912
|
+
ContentTypeOptions: {
|
|
4913
|
+
Override: this.props.contentTypeOptions?.override ?? false
|
|
4914
|
+
},
|
|
4915
|
+
FrameOptions: {
|
|
4916
|
+
Override: this.props.frameOptions?.override ?? false,
|
|
4917
|
+
FrameOption: (this.props.frameOptions?.frameOption ?? "same-origin") === "same-origin" ? "SAMEORIGIN" : "DENY"
|
|
4918
|
+
},
|
|
4919
|
+
ReferrerPolicy: {
|
|
4920
|
+
Override: this.props.referrerPolicy?.override ?? false,
|
|
4921
|
+
ReferrerPolicy: this.props.referrerPolicy?.referrerPolicy ?? "same-origin"
|
|
4922
|
+
},
|
|
4923
|
+
StrictTransportSecurity: {
|
|
4924
|
+
Override: this.props.strictTransportSecurity?.override ?? false,
|
|
4925
|
+
Preload: this.props.strictTransportSecurity?.preload ?? true,
|
|
4926
|
+
AccessControlMaxAgeSec: this.props.strictTransportSecurity?.maxAge?.toSeconds() ?? 31536e3,
|
|
4927
|
+
IncludeSubdomains: this.props.strictTransportSecurity?.includeSubdomains ?? true
|
|
4928
|
+
},
|
|
4929
|
+
XSSProtection: {
|
|
4930
|
+
Override: this.props.xssProtection?.override ?? false,
|
|
4931
|
+
ModeBlock: this.props.xssProtection?.modeBlock ?? true,
|
|
4932
|
+
Protection: this.props.xssProtection?.enable ?? true,
|
|
4933
|
+
...this.attr("ReportUri", this.props.xssProtection?.reportUri)
|
|
4934
|
+
}
|
|
4935
|
+
}
|
|
4936
|
+
}
|
|
3994
4937
|
};
|
|
3995
4938
|
}
|
|
3996
4939
|
};
|
|
3997
4940
|
|
|
3998
|
-
// src/plugins/
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
"r6g.xlarge",
|
|
4005
|
-
"r6g.2xlarge",
|
|
4006
|
-
"r6g.4xlarge",
|
|
4007
|
-
"r6g.8xlarge",
|
|
4008
|
-
"r6g.12xlarge",
|
|
4009
|
-
"r6g.16xlarge",
|
|
4010
|
-
"r6gd.xlarge",
|
|
4011
|
-
"r6gd.2xlarge",
|
|
4012
|
-
"r6gd.4xlarge",
|
|
4013
|
-
"r6gd.8xlarge"
|
|
4014
|
-
]);
|
|
4015
|
-
var PortSchema = z19.number().int().min(1).max(5e4);
|
|
4016
|
-
var ShardsSchema = z19.number().int().min(0).max(100);
|
|
4017
|
-
var ReplicasPerShardSchema = z19.number().int().min(0).max(5);
|
|
4018
|
-
var EngineSchema = z19.enum(["7.0", "6.2"]);
|
|
4019
|
-
var cachePlugin = definePlugin({
|
|
4020
|
-
name: "cache",
|
|
4021
|
-
schema: z19.object({
|
|
4022
|
-
stacks: z19.object({
|
|
4023
|
-
/** Define the caches in your stack.
|
|
4024
|
-
* For access to the cache put your functions inside the global VPC.
|
|
4941
|
+
// src/plugins/site.ts
|
|
4942
|
+
var sitePlugin = definePlugin({
|
|
4943
|
+
name: "site",
|
|
4944
|
+
schema: z24.object({
|
|
4945
|
+
stacks: z24.object({
|
|
4946
|
+
/** Define the sites in your stack.
|
|
4025
4947
|
* @example
|
|
4026
4948
|
* {
|
|
4027
|
-
*
|
|
4028
|
-
*
|
|
4029
|
-
*
|
|
4949
|
+
* sites: {
|
|
4950
|
+
* SITE_NAME: {
|
|
4951
|
+
* static: 'dist/client'
|
|
4952
|
+
* ssr: 'dist/server/index.js'
|
|
4030
4953
|
* }
|
|
4031
4954
|
* }
|
|
4032
4955
|
* }
|
|
4033
|
-
*/
|
|
4034
|
-
|
|
4956
|
+
* */
|
|
4957
|
+
sites: z24.record(
|
|
4035
4958
|
ResourceIdSchema,
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4959
|
+
z24.object({
|
|
4960
|
+
/** The domain to link your site with. */
|
|
4961
|
+
domain: z24.string(),
|
|
4962
|
+
subDomain: z24.string().optional(),
|
|
4963
|
+
/** Specifies the path to the static files directory. */
|
|
4964
|
+
static: LocalDirectorySchema.optional(),
|
|
4965
|
+
/** Specifies the ssr file. */
|
|
4966
|
+
ssr: FunctionSchema.optional(),
|
|
4967
|
+
/** Define the cors headers. */
|
|
4968
|
+
cors: z24.object({
|
|
4969
|
+
override: z24.boolean().default(false),
|
|
4970
|
+
maxAge: DurationSchema.default("365 days"),
|
|
4971
|
+
exposeHeaders: z24.string().array().optional(),
|
|
4972
|
+
credentials: z24.boolean().default(false),
|
|
4973
|
+
headers: z24.string().array().default(["*"]),
|
|
4974
|
+
origins: z24.string().array().default(["*"]),
|
|
4975
|
+
methods: z24.enum(["GET", "DELETE", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "ALL"]).array().default(["ALL"])
|
|
4976
|
+
}).optional(),
|
|
4977
|
+
/** Define the cors headers. */
|
|
4978
|
+
security: z24.object({
|
|
4979
|
+
// contentSecurityPolicy: z.object({
|
|
4980
|
+
// override: z.boolean().default(false),
|
|
4981
|
+
// policy: z.string(),
|
|
4982
|
+
// })
|
|
4983
|
+
// contentSecurityPolicy?: {
|
|
4984
|
+
// override?: boolean
|
|
4985
|
+
// contentSecurityPolicy: string
|
|
4986
|
+
// }
|
|
4987
|
+
// contentTypeOptions?: {
|
|
4988
|
+
// override?: boolean
|
|
4989
|
+
// }
|
|
4990
|
+
// frameOptions?: {
|
|
4991
|
+
// override?: boolean
|
|
4992
|
+
// frameOption?: 'deny' | 'same-origin'
|
|
4993
|
+
// }
|
|
4994
|
+
// referrerPolicy?: {
|
|
4995
|
+
// override?: boolean
|
|
4996
|
+
// referrerPolicy?: (
|
|
4997
|
+
// 'no-referrer' |
|
|
4998
|
+
// 'no-referrer-when-downgrade' |
|
|
4999
|
+
// 'origin' |
|
|
5000
|
+
// 'origin-when-cross-origin' |
|
|
5001
|
+
// 'same-origin' |
|
|
5002
|
+
// 'strict-origin' |
|
|
5003
|
+
// 'strict-origin-when-cross-origin' |
|
|
5004
|
+
// 'unsafe-url'
|
|
5005
|
+
// )
|
|
5006
|
+
// }
|
|
5007
|
+
// strictTransportSecurity?: {
|
|
5008
|
+
// maxAge?: Duration
|
|
5009
|
+
// includeSubdomains?: boolean
|
|
5010
|
+
// override?: boolean
|
|
5011
|
+
// preload?: boolean
|
|
5012
|
+
// }
|
|
5013
|
+
// xssProtection?: {
|
|
5014
|
+
// override?: boolean
|
|
5015
|
+
// enable?: boolean
|
|
5016
|
+
// modeBlock?: boolean
|
|
5017
|
+
// reportUri?: string
|
|
5018
|
+
// }
|
|
5019
|
+
}).optional(),
|
|
5020
|
+
/** Specifies the cookies, headers, and query values that CloudFront includes in the cache key. */
|
|
5021
|
+
cache: z24.object({
|
|
5022
|
+
/** Specifies the cookies that CloudFront includes in the cache key. */
|
|
5023
|
+
cookies: z24.string().array().optional(),
|
|
5024
|
+
/** Specifies the headers that CloudFront includes in the cache key. */
|
|
5025
|
+
headers: z24.string().array().optional(),
|
|
5026
|
+
/** Specifies the query values that CloudFront includes in the cache key. */
|
|
5027
|
+
queries: z24.string().array().optional()
|
|
5028
|
+
}).optional()
|
|
4043
5029
|
})
|
|
4044
5030
|
).optional()
|
|
4045
5031
|
}).array()
|
|
4046
5032
|
}),
|
|
4047
|
-
|
|
4048
|
-
const
|
|
4049
|
-
for (const
|
|
4050
|
-
const
|
|
4051
|
-
|
|
4052
|
-
|
|
5033
|
+
onStack(ctx) {
|
|
5034
|
+
const { config, stack, stackConfig, bootstrap: bootstrap2 } = ctx;
|
|
5035
|
+
for (const [id, props] of Object.entries(stackConfig.sites || {})) {
|
|
5036
|
+
const origins = [];
|
|
5037
|
+
const originGroups = [];
|
|
5038
|
+
const deps = [];
|
|
5039
|
+
let bucket;
|
|
5040
|
+
if (props.ssr) {
|
|
5041
|
+
const lambda = toLambdaFunction(ctx, `site-${id}`, props.ssr);
|
|
5042
|
+
const permissions = new Permission2(`site-${id}`, {
|
|
5043
|
+
principal: "*",
|
|
5044
|
+
// principal: 'cloudfront.amazonaws.com',
|
|
5045
|
+
action: "lambda:InvokeFunctionUrl",
|
|
5046
|
+
functionArn: lambda.arn,
|
|
5047
|
+
urlAuthType: "none"
|
|
5048
|
+
// sourceArn: distribution.arn,
|
|
5049
|
+
}).dependsOn(lambda);
|
|
5050
|
+
const url = lambda.addUrl();
|
|
5051
|
+
stack.add(url, lambda, permissions);
|
|
5052
|
+
origins.push(new Origin({
|
|
5053
|
+
id: "lambda",
|
|
5054
|
+
domainName: select(2, split("/", url.url)),
|
|
5055
|
+
protocol: "https-only"
|
|
5056
|
+
}));
|
|
5057
|
+
deps.push(lambda, url, permissions);
|
|
4053
5058
|
}
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
5059
|
+
if (props.static) {
|
|
5060
|
+
bucket = new Bucket(`site-${id}`, {
|
|
5061
|
+
// name: props.domain,
|
|
5062
|
+
name: `site-${config.name}-${stack.name}-${id}`,
|
|
5063
|
+
accessControl: "private",
|
|
5064
|
+
website: {
|
|
5065
|
+
indexDocument: "index.html",
|
|
5066
|
+
errorDocument: props.ssr ? void 0 : "error.html"
|
|
5067
|
+
}
|
|
5068
|
+
});
|
|
5069
|
+
const accessControl = new OriginAccessControl(`site-${id}`, {
|
|
5070
|
+
type: "s3"
|
|
5071
|
+
});
|
|
5072
|
+
const files = new Files(`site-${id}`, {
|
|
5073
|
+
directory: props.static
|
|
5074
|
+
});
|
|
5075
|
+
const uploadBucketAsset = new CustomResource(`site-${id}-upload-bucket-asset`, {
|
|
5076
|
+
serviceToken: bootstrap2.import("feature-upload-bucket-asset"),
|
|
5077
|
+
properties: {
|
|
5078
|
+
sourceBucketName: lazy(() => files.source?.bucket ?? ""),
|
|
5079
|
+
sourceObjectKey: lazy(() => files.source?.key ?? ""),
|
|
5080
|
+
sourceObjectVersion: lazy(() => files.source?.version ?? ""),
|
|
5081
|
+
destinationBucketName: bucket.name
|
|
5082
|
+
}
|
|
5083
|
+
}).dependsOn(bucket);
|
|
5084
|
+
const deleteBucket = new CustomResource(id, {
|
|
5085
|
+
serviceToken: bootstrap2.import("feature-delete-bucket"),
|
|
5086
|
+
properties: {
|
|
5087
|
+
bucketName: bucket.name
|
|
5088
|
+
}
|
|
5089
|
+
}).dependsOn(bucket);
|
|
5090
|
+
stack.add(bucket, files, uploadBucketAsset, deleteBucket, accessControl);
|
|
5091
|
+
origins.push(new Origin({
|
|
5092
|
+
id: "bucket",
|
|
5093
|
+
// domainName: select(2, split('/', bucket.url)),
|
|
5094
|
+
domainName: bucket.domainName,
|
|
5095
|
+
originAccessControlId: accessControl.id
|
|
5096
|
+
}));
|
|
5097
|
+
deps.push(bucket, accessControl);
|
|
5098
|
+
}
|
|
5099
|
+
if (props.ssr && props.static) {
|
|
5100
|
+
originGroups.push(new OriginGroup({
|
|
5101
|
+
id: "group",
|
|
5102
|
+
members: ["lambda", "bucket"],
|
|
5103
|
+
statusCodes: [403, 404]
|
|
5104
|
+
}));
|
|
5105
|
+
}
|
|
5106
|
+
const cache = new CachePolicy(id, {
|
|
5107
|
+
name: `site-${config.name}-${stack.name}-${id}`,
|
|
5108
|
+
minTtl: Duration.seconds(1),
|
|
5109
|
+
maxTtl: Duration.days(365),
|
|
5110
|
+
defaultTtl: Duration.days(1),
|
|
5111
|
+
...props.cache
|
|
4067
5112
|
});
|
|
4068
|
-
const
|
|
4069
|
-
name
|
|
4070
|
-
|
|
4071
|
-
|
|
5113
|
+
const originRequest = new OriginRequestPolicy(id, {
|
|
5114
|
+
name: `site-${config.name}-${stack.name}-${id}`,
|
|
5115
|
+
header: {
|
|
5116
|
+
behavior: "all-except",
|
|
5117
|
+
values: ["HOST"]
|
|
5118
|
+
}
|
|
4072
5119
|
});
|
|
4073
|
-
const
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
const
|
|
4077
|
-
name
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
subnetGroupName: subnetGroup.name,
|
|
4081
|
-
...props
|
|
4082
|
-
}).dependsOn(subnetGroup, securityGroup);
|
|
4083
|
-
stack.add(subnetGroup, securityGroup, cluster);
|
|
4084
|
-
bind((lambda) => {
|
|
4085
|
-
lambda.addEnvironment(`CACHE_${constantCase6(stack.name)}_${constantCase6(id)}_HOST`, cluster.address).addEnvironment(`CACHE_${constantCase6(stack.name)}_${constantCase6(id)}_PORT`, props.port.toString());
|
|
5120
|
+
const domainName = props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain;
|
|
5121
|
+
const hostedZoneId = bootstrap2.import(`hosted-zone-${props.domain}-id`);
|
|
5122
|
+
const certificateArn = bootstrap2.import(`us-east-certificate-${props.domain}-arn`);
|
|
5123
|
+
const responseHeaders = new ResponseHeadersPolicy(id, {
|
|
5124
|
+
name: `site-${config.name}-${stack.name}-${id}`,
|
|
5125
|
+
cors: props.cors,
|
|
5126
|
+
remove: ["server"]
|
|
4086
5127
|
});
|
|
5128
|
+
const distribution = new Distribution(id, {
|
|
5129
|
+
name: `site-${config.name}-${stack.name}-${id}`,
|
|
5130
|
+
certificateArn,
|
|
5131
|
+
compress: true,
|
|
5132
|
+
aliases: [domainName],
|
|
5133
|
+
origins,
|
|
5134
|
+
originGroups,
|
|
5135
|
+
targetOriginId: props.ssr && props.static ? "group" : props.ssr ? "lambda" : "bucket",
|
|
5136
|
+
originRequestPolicyId: originRequest.id,
|
|
5137
|
+
cachePolicyId: cache.id,
|
|
5138
|
+
responseHeadersPolicyId: responseHeaders.id
|
|
5139
|
+
}).dependsOn(originRequest, responseHeaders, cache, ...deps);
|
|
5140
|
+
if (props.static) {
|
|
5141
|
+
const bucketPolicy = new BucketPolicy(`site-${id}`, {
|
|
5142
|
+
bucketName: bucket.name,
|
|
5143
|
+
statements: [
|
|
5144
|
+
{
|
|
5145
|
+
principal: "cloudfront.amazonaws.com",
|
|
5146
|
+
actions: ["s3:GetObject"],
|
|
5147
|
+
resources: [sub("${arn}/*", { arn: bucket.arn })],
|
|
5148
|
+
sourceArn: distribution.arn
|
|
5149
|
+
}
|
|
5150
|
+
// {
|
|
5151
|
+
// principal: distribution.id,
|
|
5152
|
+
// actions: [ 's3:GetObject' ],
|
|
5153
|
+
// resources: [ oac.attrId ]
|
|
5154
|
+
// }
|
|
5155
|
+
]
|
|
5156
|
+
}).dependsOn(bucket, distribution);
|
|
5157
|
+
stack.add(bucketPolicy);
|
|
5158
|
+
}
|
|
5159
|
+
const record = new RecordSet(`site-${id}`, {
|
|
5160
|
+
hostedZoneId,
|
|
5161
|
+
type: "A",
|
|
5162
|
+
name: domainName,
|
|
5163
|
+
alias: {
|
|
5164
|
+
dnsName: distribution.domainName,
|
|
5165
|
+
hostedZoneId: "Z2FDTNDATAQYW2"
|
|
5166
|
+
}
|
|
5167
|
+
}).dependsOn(distribution);
|
|
5168
|
+
stack.add(
|
|
5169
|
+
distribution,
|
|
5170
|
+
responseHeaders,
|
|
5171
|
+
originRequest,
|
|
5172
|
+
cache,
|
|
5173
|
+
record
|
|
5174
|
+
);
|
|
4087
5175
|
}
|
|
4088
5176
|
}
|
|
4089
5177
|
});
|
|
4090
5178
|
|
|
5179
|
+
// src/plugins/feature.ts
|
|
5180
|
+
var featurePlugin = definePlugin({
|
|
5181
|
+
name: "feature",
|
|
5182
|
+
onApp({ config, bootstrap: bootstrap2 }) {
|
|
5183
|
+
const deleteBucketLambda = new Function("delete-bucket", {
|
|
5184
|
+
name: `${config.name}-delete-bucket`,
|
|
5185
|
+
code: Code.fromFeature("delete-bucket")
|
|
5186
|
+
}).enableLogs(Duration.days(3)).addPermissions({
|
|
5187
|
+
actions: ["s3:*"],
|
|
5188
|
+
resources: ["*"]
|
|
5189
|
+
});
|
|
5190
|
+
const uploadBucketAssetLambda = new Function("upload-bucket-asset", {
|
|
5191
|
+
name: `${config.name}-upload-bucket-asset`,
|
|
5192
|
+
code: Code.fromFeature("upload-bucket-asset"),
|
|
5193
|
+
memorySize: Size.gigaBytes(2)
|
|
5194
|
+
}).enableLogs(Duration.days(3)).addPermissions({
|
|
5195
|
+
actions: ["s3:*"],
|
|
5196
|
+
resources: ["*"]
|
|
5197
|
+
});
|
|
5198
|
+
bootstrap2.add(
|
|
5199
|
+
deleteBucketLambda,
|
|
5200
|
+
uploadBucketAssetLambda
|
|
5201
|
+
);
|
|
5202
|
+
bootstrap2.export("feature-delete-bucket", deleteBucketLambda.arn).export("feature-upload-bucket-asset", uploadBucketAssetLambda.arn);
|
|
5203
|
+
}
|
|
5204
|
+
});
|
|
5205
|
+
|
|
4091
5206
|
// src/plugins/index.ts
|
|
4092
5207
|
var defaultPlugins = [
|
|
4093
5208
|
extendPlugin,
|
|
5209
|
+
featurePlugin,
|
|
4094
5210
|
vpcPlugin,
|
|
5211
|
+
domainPlugin,
|
|
4095
5212
|
functionPlugin,
|
|
5213
|
+
configPlugin,
|
|
4096
5214
|
cachePlugin,
|
|
4097
5215
|
cronPlugin,
|
|
4098
5216
|
queuePlugin,
|
|
@@ -4101,9 +5219,10 @@ var defaultPlugins = [
|
|
|
4101
5219
|
topicPlugin,
|
|
4102
5220
|
pubsubPlugin,
|
|
4103
5221
|
searchPlugin,
|
|
4104
|
-
domainPlugin,
|
|
4105
5222
|
graphqlPlugin,
|
|
4106
5223
|
httpPlugin,
|
|
5224
|
+
restPlugin,
|
|
5225
|
+
sitePlugin,
|
|
4107
5226
|
onFailurePlugin
|
|
4108
5227
|
];
|
|
4109
5228
|
|
|
@@ -4134,106 +5253,6 @@ var App = class {
|
|
|
4134
5253
|
// }
|
|
4135
5254
|
};
|
|
4136
5255
|
|
|
4137
|
-
// src/custom/global-export/handler.ts
|
|
4138
|
-
var globalExportsHandlerCode = (
|
|
4139
|
-
/* JS */
|
|
4140
|
-
`
|
|
4141
|
-
|
|
4142
|
-
const { CloudFormationClient, ListExportsCommand } = require('@aws-sdk/client-cloudformation')
|
|
4143
|
-
|
|
4144
|
-
exports.handler = async (event) => {
|
|
4145
|
-
const region = event.ResourceProperties.region
|
|
4146
|
-
|
|
4147
|
-
try {
|
|
4148
|
-
const data = await listExports(region)
|
|
4149
|
-
|
|
4150
|
-
await send(event, region, 'SUCCESS', data)
|
|
4151
|
-
} catch(error) {
|
|
4152
|
-
if (error instanceof Error) {
|
|
4153
|
-
await send(event, region, 'FAILED', {}, error.message)
|
|
4154
|
-
} else {
|
|
4155
|
-
await send(event, region, 'FAILED', {}, 'Unknown error')
|
|
4156
|
-
}
|
|
4157
|
-
}
|
|
4158
|
-
}
|
|
4159
|
-
|
|
4160
|
-
const send = async (event, id, status, data, reason = '') => {
|
|
4161
|
-
const body = JSON.stringify({
|
|
4162
|
-
Status: status,
|
|
4163
|
-
Reason: reason,
|
|
4164
|
-
PhysicalResourceId: id,
|
|
4165
|
-
StackId: event.StackId,
|
|
4166
|
-
RequestId: event.RequestId,
|
|
4167
|
-
LogicalResourceId: event.LogicalResourceId,
|
|
4168
|
-
NoEcho: false,
|
|
4169
|
-
Data: data
|
|
4170
|
-
})
|
|
4171
|
-
|
|
4172
|
-
await fetch(event.ResponseURL, {
|
|
4173
|
-
method: 'PUT',
|
|
4174
|
-
port: 443,
|
|
4175
|
-
body,
|
|
4176
|
-
headers: {
|
|
4177
|
-
'content-type': '',
|
|
4178
|
-
'content-length': Buffer.from(body).byteLength,
|
|
4179
|
-
},
|
|
4180
|
-
})
|
|
4181
|
-
}
|
|
4182
|
-
|
|
4183
|
-
const listExports = async (region) => {
|
|
4184
|
-
const client = new CloudFormationClient({ region })
|
|
4185
|
-
const data = {}
|
|
4186
|
-
|
|
4187
|
-
let token
|
|
4188
|
-
|
|
4189
|
-
while(true) {
|
|
4190
|
-
const result = await client.send(new ListExportsCommand({
|
|
4191
|
-
NextToken: token
|
|
4192
|
-
}))
|
|
4193
|
-
|
|
4194
|
-
result.Exports?.forEach(item => {
|
|
4195
|
-
data[item.Name] = item.Value
|
|
4196
|
-
})
|
|
4197
|
-
|
|
4198
|
-
if(result.NextToken) {
|
|
4199
|
-
token = result.NextToken
|
|
4200
|
-
} else {
|
|
4201
|
-
return data
|
|
4202
|
-
}
|
|
4203
|
-
}
|
|
4204
|
-
}
|
|
4205
|
-
`
|
|
4206
|
-
);
|
|
4207
|
-
|
|
4208
|
-
// src/custom/global-export/extend.ts
|
|
4209
|
-
var extendWithGlobalExports = (appName, importable, exportable) => {
|
|
4210
|
-
let crossRegionExports;
|
|
4211
|
-
importable.import = (name) => {
|
|
4212
|
-
name = formatName(name);
|
|
4213
|
-
if (!importable.exports.has(name)) {
|
|
4214
|
-
throw new TypeError(`Undefined global export value: ${name}`);
|
|
4215
|
-
}
|
|
4216
|
-
if (!crossRegionExports) {
|
|
4217
|
-
const lambda = new Function("global-exports", {
|
|
4218
|
-
name: `${appName}-global-exports`,
|
|
4219
|
-
code: Code.fromInline(globalExportsHandlerCode, "index.handler")
|
|
4220
|
-
});
|
|
4221
|
-
lambda.addPermissions({
|
|
4222
|
-
actions: ["cloudformation:ListExports"],
|
|
4223
|
-
resources: ["*"]
|
|
4224
|
-
});
|
|
4225
|
-
crossRegionExports = new CustomResource("global-exports", {
|
|
4226
|
-
serviceToken: lambda.arn,
|
|
4227
|
-
properties: {
|
|
4228
|
-
region: importable.region
|
|
4229
|
-
}
|
|
4230
|
-
});
|
|
4231
|
-
exportable.add(lambda, crossRegionExports);
|
|
4232
|
-
}
|
|
4233
|
-
return crossRegionExports.getAtt(name);
|
|
4234
|
-
};
|
|
4235
|
-
};
|
|
4236
|
-
|
|
4237
5256
|
// src/app.ts
|
|
4238
5257
|
var getAllDepends = (filters) => {
|
|
4239
5258
|
const list3 = [];
|
|
@@ -4256,7 +5275,6 @@ var toApp = async (config, filters) => {
|
|
|
4256
5275
|
debug("Plugins detected:", plugins.map((plugin) => style.info(plugin.name)).join(", "));
|
|
4257
5276
|
const bootstrap2 = new Stack("bootstrap", config.region);
|
|
4258
5277
|
const usEastBootstrap = new Stack("us-east-bootstrap", "us-east-1");
|
|
4259
|
-
extendWithGlobalExports(config.name, usEastBootstrap, bootstrap2);
|
|
4260
5278
|
app.add(bootstrap2, usEastBootstrap);
|
|
4261
5279
|
debug("Run plugin onApp listeners");
|
|
4262
5280
|
const bindings = [];
|
|
@@ -4338,7 +5356,7 @@ var toApp = async (config, filters) => {
|
|
|
4338
5356
|
};
|
|
4339
5357
|
|
|
4340
5358
|
// src/config.ts
|
|
4341
|
-
import { join as
|
|
5359
|
+
import { join as join6 } from "path";
|
|
4342
5360
|
|
|
4343
5361
|
// src/util/account.ts
|
|
4344
5362
|
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
|
|
@@ -4357,17 +5375,17 @@ var getCredentials = (profile) => {
|
|
|
4357
5375
|
};
|
|
4358
5376
|
|
|
4359
5377
|
// src/schema/app.ts
|
|
4360
|
-
import { z as
|
|
5378
|
+
import { z as z28 } from "zod";
|
|
4361
5379
|
|
|
4362
5380
|
// src/schema/stack.ts
|
|
4363
|
-
import { z as
|
|
4364
|
-
var StackSchema =
|
|
5381
|
+
import { z as z25 } from "zod";
|
|
5382
|
+
var StackSchema = z25.object({
|
|
4365
5383
|
name: ResourceIdSchema,
|
|
4366
|
-
depends:
|
|
5384
|
+
depends: z25.array(z25.lazy(() => StackSchema)).optional()
|
|
4367
5385
|
});
|
|
4368
5386
|
|
|
4369
5387
|
// src/schema/region.ts
|
|
4370
|
-
import { z as
|
|
5388
|
+
import { z as z26 } from "zod";
|
|
4371
5389
|
var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
|
|
4372
5390
|
var AF = ["af-south-1"];
|
|
4373
5391
|
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"];
|
|
@@ -4384,41 +5402,41 @@ var regions = [
|
|
|
4384
5402
|
...ME,
|
|
4385
5403
|
...SA
|
|
4386
5404
|
];
|
|
4387
|
-
var RegionSchema =
|
|
5405
|
+
var RegionSchema = z26.enum(regions);
|
|
4388
5406
|
|
|
4389
5407
|
// src/schema/plugin.ts
|
|
4390
|
-
import { z as
|
|
4391
|
-
var PluginSchema =
|
|
4392
|
-
name:
|
|
4393
|
-
schema:
|
|
5408
|
+
import { z as z27 } from "zod";
|
|
5409
|
+
var PluginSchema = z27.object({
|
|
5410
|
+
name: z27.string(),
|
|
5411
|
+
schema: z27.custom().optional(),
|
|
4394
5412
|
// depends: z.array(z.lazy(() => PluginSchema)).optional(),
|
|
4395
|
-
onApp:
|
|
4396
|
-
onStack:
|
|
4397
|
-
onResource:
|
|
5413
|
+
onApp: z27.function().returns(z27.void()).optional(),
|
|
5414
|
+
onStack: z27.function().returns(z27.any()).optional(),
|
|
5415
|
+
onResource: z27.function().returns(z27.any()).optional()
|
|
4398
5416
|
// bind: z.function().optional(),
|
|
4399
5417
|
});
|
|
4400
5418
|
|
|
4401
5419
|
// src/schema/app.ts
|
|
4402
|
-
var AppSchema =
|
|
5420
|
+
var AppSchema = z28.object({
|
|
4403
5421
|
/** App name */
|
|
4404
5422
|
name: ResourceIdSchema,
|
|
4405
5423
|
/** The AWS region to deploy to. */
|
|
4406
5424
|
region: RegionSchema,
|
|
4407
5425
|
/** The AWS profile to deploy to. */
|
|
4408
|
-
profile:
|
|
5426
|
+
profile: z28.string(),
|
|
4409
5427
|
/** The deployment stage.
|
|
4410
5428
|
* @default 'prod'
|
|
4411
5429
|
*/
|
|
4412
|
-
stage:
|
|
5430
|
+
stage: z28.string().regex(/^[a-z]+$/).default("prod"),
|
|
4413
5431
|
/** Default properties. */
|
|
4414
|
-
defaults:
|
|
5432
|
+
defaults: z28.object({}).default({}),
|
|
4415
5433
|
/** The application stacks. */
|
|
4416
|
-
stacks:
|
|
5434
|
+
stacks: z28.array(StackSchema).min(1).refine((stacks) => {
|
|
4417
5435
|
const unique = new Set(stacks.map((stack) => stack.name));
|
|
4418
5436
|
return unique.size === stacks.length;
|
|
4419
5437
|
}, "Must be an array of unique stacks"),
|
|
4420
5438
|
/** Custom plugins. */
|
|
4421
|
-
plugins:
|
|
5439
|
+
plugins: z28.array(PluginSchema).optional()
|
|
4422
5440
|
});
|
|
4423
5441
|
|
|
4424
5442
|
// src/util/import.ts
|
|
@@ -4426,7 +5444,7 @@ import { rollup as rollup2, watch } from "rollup";
|
|
|
4426
5444
|
import { swc as swc2 } from "rollup-plugin-swc3";
|
|
4427
5445
|
import replace from "rollup-plugin-replace";
|
|
4428
5446
|
import { EventIterator } from "event-iterator";
|
|
4429
|
-
import { dirname as dirname2, join as
|
|
5447
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
4430
5448
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
4431
5449
|
var importFile = async (path) => {
|
|
4432
5450
|
const bundle = await rollup2({
|
|
@@ -4446,7 +5464,7 @@ var importFile = async (path) => {
|
|
|
4446
5464
|
})
|
|
4447
5465
|
]
|
|
4448
5466
|
});
|
|
4449
|
-
const outputFile =
|
|
5467
|
+
const outputFile = join5(directories.cache, "config.js");
|
|
4450
5468
|
const result = await bundle.generate({
|
|
4451
5469
|
format: "esm",
|
|
4452
5470
|
exports: "default"
|
|
@@ -4497,7 +5515,7 @@ var watchFile = (path) => {
|
|
|
4497
5515
|
event.result.close();
|
|
4498
5516
|
const output = result.output[0];
|
|
4499
5517
|
const code = output.code;
|
|
4500
|
-
const outputFile =
|
|
5518
|
+
const outputFile = join5(directories.cache, "config.js");
|
|
4501
5519
|
await mkdir2(directories.cache, { recursive: true });
|
|
4502
5520
|
await writeFile2(outputFile, code);
|
|
4503
5521
|
debug("Save config file:", style.info(outputFile));
|
|
@@ -4515,7 +5533,7 @@ var watchFile = (path) => {
|
|
|
4515
5533
|
};
|
|
4516
5534
|
|
|
4517
5535
|
// src/config.ts
|
|
4518
|
-
import { z as
|
|
5536
|
+
import { z as z29 } from "zod";
|
|
4519
5537
|
var ConfigError = class extends Error {
|
|
4520
5538
|
constructor(error, data) {
|
|
4521
5539
|
super(error.message);
|
|
@@ -4530,7 +5548,7 @@ var importConfig = async (options) => {
|
|
|
4530
5548
|
setRoot(root2);
|
|
4531
5549
|
debug("CWD:", style.info(root2));
|
|
4532
5550
|
debug("Import config file");
|
|
4533
|
-
const fileName =
|
|
5551
|
+
const fileName = join6(root2, configFile);
|
|
4534
5552
|
const module = await importFile(fileName);
|
|
4535
5553
|
const appConfig = typeof module.default === "function" ? await module.default(options) : module.default;
|
|
4536
5554
|
debug("Validate config file");
|
|
@@ -4548,7 +5566,7 @@ var importConfig = async (options) => {
|
|
|
4548
5566
|
try {
|
|
4549
5567
|
config = await schema2.parseAsync(appConfig);
|
|
4550
5568
|
} catch (error) {
|
|
4551
|
-
if (error instanceof
|
|
5569
|
+
if (error instanceof z29.ZodError) {
|
|
4552
5570
|
throw new ConfigError(error, appConfig);
|
|
4553
5571
|
}
|
|
4554
5572
|
throw error;
|
|
@@ -4571,7 +5589,7 @@ var watchConfig = async function* (options) {
|
|
|
4571
5589
|
setRoot(root2);
|
|
4572
5590
|
debug("CWD:", style.info(root2));
|
|
4573
5591
|
debug("Import config file");
|
|
4574
|
-
const fileName =
|
|
5592
|
+
const fileName = join6(root2, configFile);
|
|
4575
5593
|
for await (const module of watchFile(fileName)) {
|
|
4576
5594
|
const appConfig = typeof module.default === "function" ? await module.default(options) : module.default;
|
|
4577
5595
|
debug("Validate config file");
|
|
@@ -4589,7 +5607,7 @@ var watchConfig = async function* (options) {
|
|
|
4589
5607
|
try {
|
|
4590
5608
|
config = await schema2.parseAsync(appConfig);
|
|
4591
5609
|
} catch (error) {
|
|
4592
|
-
if (error instanceof
|
|
5610
|
+
if (error instanceof z29.ZodError) {
|
|
4593
5611
|
throw new ConfigError(error, appConfig);
|
|
4594
5612
|
}
|
|
4595
5613
|
throw error;
|
|
@@ -5080,7 +6098,6 @@ var format = (value) => {
|
|
|
5080
6098
|
};
|
|
5081
6099
|
var zodError = (error, data) => {
|
|
5082
6100
|
return (term) => {
|
|
5083
|
-
term.out.write(JSON.stringify(error.errors));
|
|
5084
6101
|
for (const issue of error.issues) {
|
|
5085
6102
|
term.out.gap();
|
|
5086
6103
|
term.out.write(dialog("error", [
|
|
@@ -5187,7 +6204,7 @@ var flexLine = (term, left, right, reserveSpace = 0) => {
|
|
|
5187
6204
|
};
|
|
5188
6205
|
|
|
5189
6206
|
// src/cli/ui/complex/builder.ts
|
|
5190
|
-
import { dirname as dirname3, join as
|
|
6207
|
+
import { dirname as dirname3, join as join7 } from "path";
|
|
5191
6208
|
var assetBuilder = (app) => {
|
|
5192
6209
|
return async (term) => {
|
|
5193
6210
|
const assets = [];
|
|
@@ -5250,7 +6267,7 @@ var assetBuilder = (app) => {
|
|
|
5250
6267
|
try {
|
|
5251
6268
|
const data = await asset.build({
|
|
5252
6269
|
async write(file, data2) {
|
|
5253
|
-
const fullpath =
|
|
6270
|
+
const fullpath = join7(directories.asset, asset.type, app.name, stack.name, asset.id, file);
|
|
5254
6271
|
const basepath = dirname3(fullpath);
|
|
5255
6272
|
await mkdir3(basepath, { recursive: true });
|
|
5256
6273
|
await writeFile3(fullpath, data2);
|
|
@@ -5298,14 +6315,14 @@ var cleanUp = async () => {
|
|
|
5298
6315
|
|
|
5299
6316
|
// src/cli/ui/complex/template.ts
|
|
5300
6317
|
import { mkdir as mkdir5, writeFile as writeFile4 } from "fs/promises";
|
|
5301
|
-
import { join as
|
|
6318
|
+
import { join as join8 } from "path";
|
|
5302
6319
|
var templateBuilder = (app) => {
|
|
5303
6320
|
return async (term) => {
|
|
5304
6321
|
const done = term.out.write(loadingDialog("Building stack templates..."));
|
|
5305
6322
|
await Promise.all(app.stacks.map(async (stack) => {
|
|
5306
6323
|
const template = stack.toString(true);
|
|
5307
|
-
const path =
|
|
5308
|
-
const file =
|
|
6324
|
+
const path = join8(directories.template, app.name);
|
|
6325
|
+
const file = join8(path, `${stack.name}.json`);
|
|
5309
6326
|
await mkdir5(path, { recursive: true });
|
|
5310
6327
|
await writeFile4(file, template);
|
|
5311
6328
|
}));
|
|
@@ -5350,7 +6367,7 @@ var bootstrapStack = (account, region) => {
|
|
|
5350
6367
|
stack.add(new Bucket("assets", {
|
|
5351
6368
|
name: assetBucketName(account, region),
|
|
5352
6369
|
accessControl: "private",
|
|
5353
|
-
|
|
6370
|
+
versioning: true
|
|
5354
6371
|
}));
|
|
5355
6372
|
stack.export("version", version);
|
|
5356
6373
|
app.add(stack);
|
|
@@ -5365,7 +6382,7 @@ var shouldDeployBootstrap = async (client, stack) => {
|
|
|
5365
6382
|
// src/formation/client.ts
|
|
5366
6383
|
import { CloudFormationClient, CreateStackCommand, DeleteStackCommand, DescribeStackEventsCommand, DescribeStacksCommand, GetTemplateCommand, OnFailure, TemplateStage, UpdateStackCommand, ValidateTemplateCommand, waitUntilStackCreateComplete, waitUntilStackDeleteComplete, waitUntilStackUpdateComplete } from "@aws-sdk/client-cloudformation";
|
|
5367
6384
|
import { S3Client, PutObjectCommand, ObjectCannedACL, StorageClass } from "@aws-sdk/client-s3";
|
|
5368
|
-
import { paramCase as
|
|
6385
|
+
import { paramCase as paramCase6 } from "change-case";
|
|
5369
6386
|
var StackClient = class {
|
|
5370
6387
|
constructor(app, account, region, credentials) {
|
|
5371
6388
|
this.app = app;
|
|
@@ -5398,7 +6415,7 @@ var StackClient = class {
|
|
|
5398
6415
|
};
|
|
5399
6416
|
}
|
|
5400
6417
|
stackName(stackName) {
|
|
5401
|
-
return
|
|
6418
|
+
return paramCase6(`${this.app.name}-${stackName}`);
|
|
5402
6419
|
}
|
|
5403
6420
|
tags(stack) {
|
|
5404
6421
|
const tags = [];
|
|
@@ -5411,7 +6428,8 @@ var StackClient = class {
|
|
|
5411
6428
|
debug("Upload the", style.info(stack.name), "stack to awsless assets bucket");
|
|
5412
6429
|
const client = new S3Client({
|
|
5413
6430
|
credentials: this.credentials,
|
|
5414
|
-
region: stack.region
|
|
6431
|
+
region: stack.region,
|
|
6432
|
+
maxAttempts: 5
|
|
5415
6433
|
});
|
|
5416
6434
|
await client.send(new PutObjectCommand({
|
|
5417
6435
|
Bucket: this.assetBucketName,
|
|
@@ -5519,6 +6537,7 @@ var StackClient = class {
|
|
|
5519
6537
|
});
|
|
5520
6538
|
debug("Status for:", style.info(name), "is", style.attr(stack.StackStatus));
|
|
5521
6539
|
return {
|
|
6540
|
+
id: stack.StackId,
|
|
5522
6541
|
status: stack.StackStatus,
|
|
5523
6542
|
reason: stack.StackStatusReason,
|
|
5524
6543
|
outputs,
|
|
@@ -5565,10 +6584,10 @@ var StackClient = class {
|
|
|
5565
6584
|
maxWaitTime: this.maxWaitTime,
|
|
5566
6585
|
maxDelay: this.maxDelay
|
|
5567
6586
|
}, {
|
|
5568
|
-
StackName:
|
|
6587
|
+
StackName: data.id
|
|
5569
6588
|
});
|
|
5570
6589
|
} catch (_) {
|
|
5571
|
-
const reason = await this.getFailureReason(
|
|
6590
|
+
const reason = await this.getFailureReason(data.id, region);
|
|
5572
6591
|
throw new Error(reason);
|
|
5573
6592
|
}
|
|
5574
6593
|
}
|
|
@@ -5826,12 +6845,13 @@ var status = (program2) => {
|
|
|
5826
6845
|
|
|
5827
6846
|
// src/cli/ui/complex/publisher.ts
|
|
5828
6847
|
import { readFile as readFile3 } from "fs/promises";
|
|
5829
|
-
import { join as
|
|
6848
|
+
import { join as join9 } from "path";
|
|
5830
6849
|
import { GetObjectCommand, ObjectCannedACL as ObjectCannedACL2, PutObjectCommand as PutObjectCommand2, S3Client as S3Client2, StorageClass as StorageClass2 } from "@aws-sdk/client-s3";
|
|
5831
6850
|
var assetPublisher = (config, app) => {
|
|
5832
6851
|
const client = new S3Client2({
|
|
5833
6852
|
credentials: config.credentials,
|
|
5834
|
-
region: config.region
|
|
6853
|
+
region: config.region,
|
|
6854
|
+
maxAttempts: 5
|
|
5835
6855
|
});
|
|
5836
6856
|
return async (term) => {
|
|
5837
6857
|
const done = term.out.write(loadingDialog("Publishing stack assets to AWS..."));
|
|
@@ -5839,12 +6859,12 @@ var assetPublisher = (config, app) => {
|
|
|
5839
6859
|
await Promise.all([...stack.assets].map(async (asset) => {
|
|
5840
6860
|
await asset.publish?.({
|
|
5841
6861
|
async read(file) {
|
|
5842
|
-
const path =
|
|
6862
|
+
const path = join9(directories.asset, asset.type, app.name, stack.name, asset.id, file);
|
|
5843
6863
|
const data = await readFile3(path);
|
|
5844
6864
|
return data;
|
|
5845
6865
|
},
|
|
5846
6866
|
async publish(name, data, hash) {
|
|
5847
|
-
const key = `${app.name}/${stack.name}
|
|
6867
|
+
const key = `${app.name}/${stack.name}/${asset.type}/${name}`;
|
|
5848
6868
|
const bucket = assetBucketName(config.account, config.region);
|
|
5849
6869
|
let getResult;
|
|
5850
6870
|
try {
|
|
@@ -6084,16 +7104,6 @@ var secrets = (program2) => {
|
|
|
6084
7104
|
commands.forEach((cb) => cb(command));
|
|
6085
7105
|
};
|
|
6086
7106
|
|
|
6087
|
-
// src/cli/command/test.ts
|
|
6088
|
-
var test = (program2) => {
|
|
6089
|
-
program2.command("test").action(async () => {
|
|
6090
|
-
await layout(async (config) => {
|
|
6091
|
-
const app = new App("test");
|
|
6092
|
-
const name = "test5";
|
|
6093
|
-
});
|
|
6094
|
-
});
|
|
6095
|
-
};
|
|
6096
|
-
|
|
6097
7107
|
// src/cli/command/types.ts
|
|
6098
7108
|
var types = (program2) => {
|
|
6099
7109
|
program2.command("types").description("Generate type definition files").action(async () => {
|
|
@@ -6117,6 +7127,48 @@ var dev = (program2) => {
|
|
|
6117
7127
|
});
|
|
6118
7128
|
};
|
|
6119
7129
|
|
|
7130
|
+
// src/cli/command/delete.ts
|
|
7131
|
+
var del2 = (program2) => {
|
|
7132
|
+
program2.command("delete").argument("[stacks...]", "Optionally filter stacks to delete").description("Delete your app from AWS").action(async (filters) => {
|
|
7133
|
+
await layout(async (config, write) => {
|
|
7134
|
+
const { app, deploymentLine } = await toApp(config, filters);
|
|
7135
|
+
const deletingLine = deploymentLine.reverse();
|
|
7136
|
+
const stackNames = app.stacks.map((stack) => stack.name);
|
|
7137
|
+
const formattedFilter = stackNames.map((i) => style.info(i)).join(style.placeholder(", "));
|
|
7138
|
+
debug("Stacks to delete", formattedFilter);
|
|
7139
|
+
const deployAll = filters.length === 0;
|
|
7140
|
+
const deploySingle = filters.length === 1;
|
|
7141
|
+
const confirm = await write(confirmPrompt(deployAll ? `Are you sure you want to ${style.error("delete")} ${style.warning("all")} stacks?` : deploySingle ? `Are you sure you want to ${style.error("delete")} the ${formattedFilter} stack?` : `Are you sure you want to ${style.error("delete")} the [ ${formattedFilter} ] stacks?`));
|
|
7142
|
+
if (!confirm) {
|
|
7143
|
+
throw new Cancelled();
|
|
7144
|
+
}
|
|
7145
|
+
const doneDeploying = write(loadingDialog("Deleting stacks from AWS..."));
|
|
7146
|
+
const client = new StackClient(app, config.account, config.region, config.credentials);
|
|
7147
|
+
const ui = write(stacksDeployer(deletingLine));
|
|
7148
|
+
for (const line2 of deletingLine) {
|
|
7149
|
+
const results = await Promise.allSettled(line2.map(async (stack) => {
|
|
7150
|
+
const item = ui[stack.name];
|
|
7151
|
+
item.start("deleting");
|
|
7152
|
+
try {
|
|
7153
|
+
await client.delete(stack.name, stack.region);
|
|
7154
|
+
} catch (error) {
|
|
7155
|
+
debugError(error);
|
|
7156
|
+
item.fail("failed");
|
|
7157
|
+
throw error;
|
|
7158
|
+
}
|
|
7159
|
+
item.done("deleted");
|
|
7160
|
+
}));
|
|
7161
|
+
for (const result of results) {
|
|
7162
|
+
if (result.status === "rejected") {
|
|
7163
|
+
throw result.reason;
|
|
7164
|
+
}
|
|
7165
|
+
}
|
|
7166
|
+
}
|
|
7167
|
+
doneDeploying("Done deleting stacks from AWS");
|
|
7168
|
+
});
|
|
7169
|
+
});
|
|
7170
|
+
};
|
|
7171
|
+
|
|
6120
7172
|
// src/cli/program.ts
|
|
6121
7173
|
var program = new Command();
|
|
6122
7174
|
program.name(logo().join("").replace(/\s+/, ""));
|
|
@@ -6138,9 +7190,10 @@ var commands2 = [
|
|
|
6138
7190
|
types,
|
|
6139
7191
|
build,
|
|
6140
7192
|
deploy,
|
|
7193
|
+
del2,
|
|
6141
7194
|
dev,
|
|
6142
|
-
secrets
|
|
6143
|
-
test
|
|
7195
|
+
secrets
|
|
7196
|
+
// test,
|
|
6144
7197
|
// diff,
|
|
6145
7198
|
// remove,
|
|
6146
7199
|
];
|