@awsless/awsless 0.0.43 → 0.0.44
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 +20 -2
- package/dist/bin.js +587 -227
- package/dist/index.d.ts +586 -125
- package/dist/index.js +40 -4
- package/package.json +4 -5
- 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 {
|
|
@@ -261,11 +177,12 @@ var Lazy = class {
|
|
|
261
177
|
|
|
262
178
|
// src/formation/resource/iam/inline-policy.ts
|
|
263
179
|
var InlinePolicy = class {
|
|
180
|
+
name;
|
|
181
|
+
statements;
|
|
264
182
|
constructor(name, props = {}) {
|
|
265
|
-
this.name = name;
|
|
266
183
|
this.statements = props.statements || [];
|
|
184
|
+
this.name = formatName(name);
|
|
267
185
|
}
|
|
268
|
-
statements;
|
|
269
186
|
addStatement(...statements) {
|
|
270
187
|
this.statements.push(...statements.flat());
|
|
271
188
|
return this;
|
|
@@ -304,9 +221,7 @@ var Role = class extends Resource {
|
|
|
304
221
|
constructor(logicalId, props = {}) {
|
|
305
222
|
super("AWS::IAM::Role", logicalId);
|
|
306
223
|
this.props = props;
|
|
307
|
-
this.name = formatName(logicalId);
|
|
308
224
|
}
|
|
309
|
-
name;
|
|
310
225
|
inlinePolicies = /* @__PURE__ */ new Set();
|
|
311
226
|
managedPolicies = /* @__PURE__ */ new Set();
|
|
312
227
|
get arn() {
|
|
@@ -571,18 +486,6 @@ var toStack = ({ config, app, stackConfig, bootstrap: bootstrap2, usEastBootstra
|
|
|
571
486
|
bind2(fn);
|
|
572
487
|
}
|
|
573
488
|
}
|
|
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
489
|
return {
|
|
587
490
|
stack,
|
|
588
491
|
bindings
|
|
@@ -749,7 +652,7 @@ var LocalFileSchema = z3.string().refine(async (path) => {
|
|
|
749
652
|
// src/schema/resource-id.ts
|
|
750
653
|
import { paramCase as paramCase3 } from "change-case";
|
|
751
654
|
import { z as z4 } from "zod";
|
|
752
|
-
var ResourceIdSchema = z4.string().min(3).max(24).regex(/^[a-
|
|
655
|
+
var ResourceIdSchema = z4.string().min(3).max(24).regex(/^[a-z0-9\-]+$/i, "Invalid resource ID").transform((value) => paramCase3(value));
|
|
753
656
|
|
|
754
657
|
// src/schema/size.ts
|
|
755
658
|
import { z as z5 } from "zod";
|
|
@@ -1063,7 +966,7 @@ import { relative as relative2 } from "path";
|
|
|
1063
966
|
// src/util/type-gen.ts
|
|
1064
967
|
import { mkdir, writeFile } from "fs/promises";
|
|
1065
968
|
import { join as join2, relative } from "path";
|
|
1066
|
-
import { camelCase } from "change-case";
|
|
969
|
+
import { camelCase, constantCase } from "change-case";
|
|
1067
970
|
var generateResourceTypes = async (config) => {
|
|
1068
971
|
const plugins = [
|
|
1069
972
|
...defaultPlugins,
|
|
@@ -1085,9 +988,10 @@ var generateResourceTypes = async (config) => {
|
|
|
1085
988
|
}
|
|
1086
989
|
};
|
|
1087
990
|
var TypeGen = class {
|
|
1088
|
-
constructor(module, interfaceName) {
|
|
991
|
+
constructor(module, interfaceName, readonly = true) {
|
|
1089
992
|
this.module = module;
|
|
1090
993
|
this.interfaceName = interfaceName;
|
|
994
|
+
this.readonly = readonly;
|
|
1091
995
|
}
|
|
1092
996
|
codes = /* @__PURE__ */ new Set();
|
|
1093
997
|
types = /* @__PURE__ */ new Map();
|
|
@@ -1102,7 +1006,13 @@ var TypeGen = class {
|
|
|
1102
1006
|
}
|
|
1103
1007
|
addType(name, type) {
|
|
1104
1008
|
if (type) {
|
|
1105
|
-
this.types.set(name, type);
|
|
1009
|
+
this.types.set(camelCase(name), type);
|
|
1010
|
+
}
|
|
1011
|
+
return this;
|
|
1012
|
+
}
|
|
1013
|
+
addConst(name, type) {
|
|
1014
|
+
if (type) {
|
|
1015
|
+
this.types.set(constantCase(name), type);
|
|
1106
1016
|
}
|
|
1107
1017
|
return this;
|
|
1108
1018
|
}
|
|
@@ -1133,7 +1043,7 @@ var TypeGen = class {
|
|
|
1133
1043
|
`declare module '${this.module}' {`,
|
|
1134
1044
|
` interface ${this.interfaceName} {`,
|
|
1135
1045
|
...Array.from(this.types.entries()).map(([propName, type]) => {
|
|
1136
|
-
return ` readonly ${
|
|
1046
|
+
return ` ${this.readonly ? "readonly " : ""}${propName}: ${type}`;
|
|
1137
1047
|
}),
|
|
1138
1048
|
` }`,
|
|
1139
1049
|
`}`,
|
|
@@ -1146,7 +1056,15 @@ var TypeGen = class {
|
|
|
1146
1056
|
var TypeObject = class {
|
|
1147
1057
|
types = /* @__PURE__ */ new Map();
|
|
1148
1058
|
addType(name, type) {
|
|
1149
|
-
|
|
1059
|
+
if (type) {
|
|
1060
|
+
this.types.set(camelCase(name), type);
|
|
1061
|
+
}
|
|
1062
|
+
return this;
|
|
1063
|
+
}
|
|
1064
|
+
addConst(name, type) {
|
|
1065
|
+
if (type) {
|
|
1066
|
+
this.types.set(constantCase(name), type);
|
|
1067
|
+
}
|
|
1150
1068
|
return this;
|
|
1151
1069
|
}
|
|
1152
1070
|
toString() {
|
|
@@ -1156,7 +1074,7 @@ var TypeObject = class {
|
|
|
1156
1074
|
return [
|
|
1157
1075
|
"{",
|
|
1158
1076
|
...Array.from(this.types.entries()).map(([propName, type]) => {
|
|
1159
|
-
return ` readonly ${
|
|
1077
|
+
return ` readonly ${propName}: ${type}`;
|
|
1160
1078
|
}),
|
|
1161
1079
|
" }"
|
|
1162
1080
|
].join("\n");
|
|
@@ -1230,6 +1148,9 @@ var FunctionSchema = z6.union([
|
|
|
1230
1148
|
// onFailure: ResourceIdSchema.optional(),
|
|
1231
1149
|
})
|
|
1232
1150
|
]);
|
|
1151
|
+
var isFunctionProps = (input) => {
|
|
1152
|
+
return typeof input === "string" || typeof input.file === "string";
|
|
1153
|
+
};
|
|
1233
1154
|
var schema = z6.object({
|
|
1234
1155
|
defaults: z6.object({
|
|
1235
1156
|
function: z6.object({
|
|
@@ -1429,7 +1350,7 @@ var Permission2 = class extends Resource {
|
|
|
1429
1350
|
FunctionName: this.props.functionArn,
|
|
1430
1351
|
Action: this.props.action || "lambda:InvokeFunction",
|
|
1431
1352
|
Principal: this.props.principal,
|
|
1432
|
-
SourceArn
|
|
1353
|
+
...this.attr("SourceArn", this.props.sourceArn)
|
|
1433
1354
|
};
|
|
1434
1355
|
}
|
|
1435
1356
|
};
|
|
@@ -1555,7 +1476,7 @@ var Queue = class extends Resource {
|
|
|
1555
1476
|
};
|
|
1556
1477
|
|
|
1557
1478
|
// src/formation/resource/lambda/event-source-mapping.ts
|
|
1558
|
-
import { constantCase } from "change-case";
|
|
1479
|
+
import { constantCase as constantCase2 } from "change-case";
|
|
1559
1480
|
var EventSourceMapping = class extends Resource {
|
|
1560
1481
|
constructor(logicalId, props) {
|
|
1561
1482
|
super("AWS::Lambda::EventSourceMapping", logicalId);
|
|
@@ -1577,7 +1498,7 @@ var EventSourceMapping = class extends Resource {
|
|
|
1577
1498
|
...this.attr("ParallelizationFactor", this.props.parallelizationFactor),
|
|
1578
1499
|
...this.attr("TumblingWindowInSeconds", this.props.tumblingWindow?.toSeconds()),
|
|
1579
1500
|
...this.attr("BisectBatchOnFunctionError", this.props.bisectBatchOnError),
|
|
1580
|
-
...this.attr("StartingPosition", this.props.startingPosition &&
|
|
1501
|
+
...this.attr("StartingPosition", this.props.startingPosition && constantCase2(this.props.startingPosition)),
|
|
1581
1502
|
...this.attr("StartingPositionTimestamp", this.props.startingPositionTimestamp),
|
|
1582
1503
|
...this.props.maxConcurrency ? {
|
|
1583
1504
|
ScalingConfig: {
|
|
@@ -1618,7 +1539,7 @@ var SqsEventSource = class extends Group {
|
|
|
1618
1539
|
};
|
|
1619
1540
|
|
|
1620
1541
|
// src/plugins/queue.ts
|
|
1621
|
-
import { camelCase as camelCase3, constantCase as
|
|
1542
|
+
import { camelCase as camelCase3, constantCase as constantCase3 } from "change-case";
|
|
1622
1543
|
import { relative as relative3 } from "path";
|
|
1623
1544
|
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
1545
|
var VisibilityTimeoutSchema = DurationSchema.refine(durationMax(Duration.hours(12)), "Maximum visibility timeout is 12 hours");
|
|
@@ -1773,7 +1694,7 @@ var queuePlugin = definePlugin({
|
|
|
1773
1694
|
stack.add(queue2, lambda, source);
|
|
1774
1695
|
bind((lambda2) => {
|
|
1775
1696
|
lambda2.addPermissions(queue2.permissions);
|
|
1776
|
-
lambda2.addEnvironment(`QUEUE_${
|
|
1697
|
+
lambda2.addEnvironment(`QUEUE_${constantCase3(stack.name)}_${constantCase3(id)}_URL`, queue2.url);
|
|
1777
1698
|
});
|
|
1778
1699
|
}
|
|
1779
1700
|
}
|
|
@@ -1783,7 +1704,7 @@ var queuePlugin = definePlugin({
|
|
|
1783
1704
|
import { z as z9 } from "zod";
|
|
1784
1705
|
|
|
1785
1706
|
// src/formation/resource/dynamodb/table.ts
|
|
1786
|
-
import { constantCase as
|
|
1707
|
+
import { constantCase as constantCase4 } from "change-case";
|
|
1787
1708
|
var Table = class extends Resource {
|
|
1788
1709
|
constructor(logicalId, props) {
|
|
1789
1710
|
super("AWS::DynamoDB::Table", logicalId);
|
|
@@ -1856,7 +1777,7 @@ var Table = class extends Resource {
|
|
|
1856
1777
|
return {
|
|
1857
1778
|
TableName: this.name,
|
|
1858
1779
|
BillingMode: "PAY_PER_REQUEST",
|
|
1859
|
-
TableClass:
|
|
1780
|
+
TableClass: constantCase4(this.props.class || "standard"),
|
|
1860
1781
|
PointInTimeRecoverySpecification: {
|
|
1861
1782
|
PointInTimeRecoveryEnabled: this.props.pointInTimeRecovery || false
|
|
1862
1783
|
},
|
|
@@ -1867,7 +1788,7 @@ var Table = class extends Resource {
|
|
|
1867
1788
|
AttributeDefinitions: this.attributeDefinitions(),
|
|
1868
1789
|
...this.props.stream ? {
|
|
1869
1790
|
StreamSpecification: {
|
|
1870
|
-
StreamViewType:
|
|
1791
|
+
StreamViewType: constantCase4(this.props.stream)
|
|
1871
1792
|
}
|
|
1872
1793
|
} : {},
|
|
1873
1794
|
...this.props.timeToLiveAttribute ? {
|
|
@@ -1884,7 +1805,7 @@ var Table = class extends Resource {
|
|
|
1884
1805
|
...props.sort ? [{ KeyType: "RANGE", AttributeName: props.sort }] : []
|
|
1885
1806
|
],
|
|
1886
1807
|
Projection: {
|
|
1887
|
-
ProjectionType:
|
|
1808
|
+
ProjectionType: constantCase4(props.projection || "all")
|
|
1888
1809
|
}
|
|
1889
1810
|
}))
|
|
1890
1811
|
} : {}
|
|
@@ -2234,54 +2155,81 @@ var topicPlugin = definePlugin({
|
|
|
2234
2155
|
name: "topic",
|
|
2235
2156
|
schema: z11.object({
|
|
2236
2157
|
stacks: z11.object({
|
|
2237
|
-
/** Define the
|
|
2158
|
+
/** Define the events to publish too in your stack.
|
|
2238
2159
|
* @example
|
|
2239
2160
|
* {
|
|
2240
|
-
* topics:
|
|
2161
|
+
* topics: [ 'TOPIC_NAME' ]
|
|
2162
|
+
* }
|
|
2163
|
+
*/
|
|
2164
|
+
topics: z11.array(ResourceIdSchema).refine((topics) => {
|
|
2165
|
+
return topics.length === new Set(topics).size;
|
|
2166
|
+
}, "Must be a list of unique topic names").optional(),
|
|
2167
|
+
/** Define the events to subscribe too in your stack.
|
|
2168
|
+
* @example
|
|
2169
|
+
* {
|
|
2170
|
+
* subscribers: {
|
|
2241
2171
|
* TOPIC_NAME: 'function.ts'
|
|
2242
2172
|
* }
|
|
2243
2173
|
* }
|
|
2244
2174
|
*/
|
|
2245
|
-
|
|
2246
|
-
}).array()
|
|
2175
|
+
subscribers: z11.record(ResourceIdSchema, FunctionSchema).optional()
|
|
2176
|
+
}).array().superRefine((stacks, ctx) => {
|
|
2177
|
+
const topics = [];
|
|
2178
|
+
for (const stack of stacks) {
|
|
2179
|
+
topics.push(...stack.topics || []);
|
|
2180
|
+
}
|
|
2181
|
+
for (const index in stacks) {
|
|
2182
|
+
const stack = stacks[index];
|
|
2183
|
+
for (const sub2 of Object.keys(stack.subscribers || {})) {
|
|
2184
|
+
if (!topics.includes(sub2)) {
|
|
2185
|
+
ctx.addIssue({
|
|
2186
|
+
code: z11.ZodIssueCode.custom,
|
|
2187
|
+
message: `Topic subscription to "${sub2}" is undefined`,
|
|
2188
|
+
path: [Number(index), "subscribers"]
|
|
2189
|
+
});
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
})
|
|
2247
2194
|
}),
|
|
2248
2195
|
onTypeGen({ config }) {
|
|
2249
2196
|
const gen = new TypeGen("@awsless/awsless", "TopicResources");
|
|
2250
2197
|
gen.addCode(typeGenCode3);
|
|
2251
2198
|
for (const stack of config.stacks) {
|
|
2252
|
-
for (const topic of
|
|
2199
|
+
for (const topic of stack.topics || []) {
|
|
2253
2200
|
const name = formatName(`${config.name}-${topic}`);
|
|
2254
2201
|
gen.addType(topic, `Publish<'${name}'>`);
|
|
2255
2202
|
}
|
|
2256
2203
|
}
|
|
2257
2204
|
return gen.toString();
|
|
2258
2205
|
},
|
|
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);
|
|
2206
|
+
onApp({ config, bootstrap: bootstrap2 }) {
|
|
2207
|
+
for (const stack of config.stacks) {
|
|
2208
|
+
for (const id of stack.topics || []) {
|
|
2209
|
+
const topic = new Topic(id, {
|
|
2210
|
+
name: `${config.name}-${id}`
|
|
2211
|
+
});
|
|
2212
|
+
bootstrap2.add(topic);
|
|
2213
|
+
bootstrap2.export(`topic-${id}-arn`, topic.arn);
|
|
2214
|
+
}
|
|
2270
2215
|
}
|
|
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
2216
|
},
|
|
2282
2217
|
onStack(ctx) {
|
|
2283
|
-
const { stack, stackConfig, bootstrap: bootstrap2 } = ctx;
|
|
2284
|
-
for (const
|
|
2218
|
+
const { config, stack, stackConfig, bootstrap: bootstrap2, bind } = ctx;
|
|
2219
|
+
for (const id of stackConfig.topics || []) {
|
|
2220
|
+
bind((lambda) => {
|
|
2221
|
+
lambda.addPermissions({
|
|
2222
|
+
actions: ["sns:Publish"],
|
|
2223
|
+
resources: [
|
|
2224
|
+
sub("arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:${app}-${topic}", {
|
|
2225
|
+
app: config.name,
|
|
2226
|
+
topic: id
|
|
2227
|
+
})
|
|
2228
|
+
]
|
|
2229
|
+
});
|
|
2230
|
+
});
|
|
2231
|
+
}
|
|
2232
|
+
for (const [id, props] of Object.entries(stackConfig.subscribers || {})) {
|
|
2285
2233
|
const lambda = toLambdaFunction(ctx, `topic-${id}`, props);
|
|
2286
2234
|
const source = new SnsEventSource(id, lambda, {
|
|
2287
2235
|
topicArn: bootstrap2.import(`topic-${id}-arn`)
|
|
@@ -2423,7 +2371,7 @@ var toArray = (value) => {
|
|
|
2423
2371
|
import { paramCase as paramCase4 } from "change-case";
|
|
2424
2372
|
|
|
2425
2373
|
// src/formation/resource/appsync/graphql-api.ts
|
|
2426
|
-
import { constantCase as
|
|
2374
|
+
import { constantCase as constantCase5 } from "change-case";
|
|
2427
2375
|
var GraphQLApi = class extends Resource {
|
|
2428
2376
|
constructor(logicalId, props) {
|
|
2429
2377
|
super("AWS::AppSync::GraphQLApi", logicalId);
|
|
@@ -2455,7 +2403,7 @@ var GraphQLApi = class extends Resource {
|
|
|
2455
2403
|
properties() {
|
|
2456
2404
|
return {
|
|
2457
2405
|
Name: this.name,
|
|
2458
|
-
AuthenticationType:
|
|
2406
|
+
AuthenticationType: constantCase5(this.props.authenticationType || "api-key"),
|
|
2459
2407
|
AdditionalAuthenticationProviders: this.lambdaAuthProviders.map((provider) => ({
|
|
2460
2408
|
AuthenticationType: "AWS_LAMBDA",
|
|
2461
2409
|
LambdaAuthorizerConfig: {
|
|
@@ -2784,10 +2732,18 @@ var graphqlPlugin = definePlugin({
|
|
|
2784
2732
|
z14.array(LocalFileSchema).min(1)
|
|
2785
2733
|
]).optional(),
|
|
2786
2734
|
resolvers: z14.record(
|
|
2735
|
+
// TypeName
|
|
2787
2736
|
z14.string(),
|
|
2788
2737
|
z14.record(
|
|
2738
|
+
// FieldName
|
|
2789
2739
|
z14.string(),
|
|
2790
|
-
|
|
2740
|
+
z14.union([
|
|
2741
|
+
FunctionSchema,
|
|
2742
|
+
z14.object({
|
|
2743
|
+
consumer: FunctionSchema,
|
|
2744
|
+
resolver: LocalFileSchema
|
|
2745
|
+
})
|
|
2746
|
+
])
|
|
2791
2747
|
)
|
|
2792
2748
|
).optional()
|
|
2793
2749
|
})).optional()
|
|
@@ -2855,14 +2811,15 @@ var graphqlPlugin = definePlugin({
|
|
|
2855
2811
|
for (const [id, props] of Object.entries(stackConfig.graphql || {})) {
|
|
2856
2812
|
const apiId = bootstrap2.import(`graphql-${id}`);
|
|
2857
2813
|
for (const [typeName, fields] of Object.entries(props.resolvers || {})) {
|
|
2858
|
-
for (const [fieldName,
|
|
2814
|
+
for (const [fieldName, resolverProps] of Object.entries(fields || {})) {
|
|
2815
|
+
const props2 = isFunctionProps(resolverProps) ? { consumer: resolverProps } : resolverProps;
|
|
2859
2816
|
const entryId = paramCase4(`${id}-${typeName}-${fieldName}`);
|
|
2860
|
-
const lambda = toLambdaFunction(ctx, `graphql-${entryId}`,
|
|
2817
|
+
const lambda = toLambdaFunction(ctx, `graphql-${entryId}`, props2.consumer);
|
|
2861
2818
|
const source = new AppsyncEventSource(entryId, lambda, {
|
|
2862
2819
|
apiId,
|
|
2863
2820
|
typeName,
|
|
2864
2821
|
fieldName,
|
|
2865
|
-
code: Code2.fromInline(entryId, defaultResolver)
|
|
2822
|
+
code: Code2.fromInline(entryId, props2.resolver || defaultResolver)
|
|
2866
2823
|
});
|
|
2867
2824
|
stack.add(lambda, source);
|
|
2868
2825
|
}
|
|
@@ -2943,6 +2900,37 @@ var RecordSetGroup = class extends Resource {
|
|
|
2943
2900
|
}
|
|
2944
2901
|
};
|
|
2945
2902
|
|
|
2903
|
+
// src/custom/util.ts
|
|
2904
|
+
var sendCode = (
|
|
2905
|
+
/* JS */
|
|
2906
|
+
`
|
|
2907
|
+
|
|
2908
|
+
const send = async (event, id, status, data, reason = '') => {
|
|
2909
|
+
const body = JSON.stringify({
|
|
2910
|
+
Status: status,
|
|
2911
|
+
Reason: reason,
|
|
2912
|
+
PhysicalResourceId: id,
|
|
2913
|
+
StackId: event.StackId,
|
|
2914
|
+
RequestId: event.RequestId,
|
|
2915
|
+
LogicalResourceId: event.LogicalResourceId,
|
|
2916
|
+
NoEcho: false,
|
|
2917
|
+
Data: data
|
|
2918
|
+
})
|
|
2919
|
+
|
|
2920
|
+
await fetch(event.ResponseURL, {
|
|
2921
|
+
method: 'PUT',
|
|
2922
|
+
port: 443,
|
|
2923
|
+
body,
|
|
2924
|
+
headers: {
|
|
2925
|
+
'content-type': '',
|
|
2926
|
+
'content-length': Buffer.from(body).byteLength,
|
|
2927
|
+
},
|
|
2928
|
+
})
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
`
|
|
2932
|
+
);
|
|
2933
|
+
|
|
2946
2934
|
// src/custom/delete-hosted-zone/handler.ts
|
|
2947
2935
|
var deleteHostedZoneRecordsHandlerCode = (
|
|
2948
2936
|
/* JS */
|
|
@@ -2952,6 +2940,8 @@ const { Route53Client, ListResourceRecordSetsCommand, ChangeResourceRecordSetsCo
|
|
|
2952
2940
|
|
|
2953
2941
|
const client = new Route53Client({})
|
|
2954
2942
|
|
|
2943
|
+
${sendCode}
|
|
2944
|
+
|
|
2955
2945
|
exports.handler = async (event) => {
|
|
2956
2946
|
const type = event.RequestType
|
|
2957
2947
|
const hostedZoneId = event.ResourceProperties.hostedZoneId
|
|
@@ -2975,29 +2965,6 @@ exports.handler = async (event) => {
|
|
|
2975
2965
|
}
|
|
2976
2966
|
}
|
|
2977
2967
|
|
|
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
2968
|
const deleteHostedZoneRecords = async (hostedZoneId, records) => {
|
|
3002
2969
|
records = records.filter(record => ![ 'SOA', 'NS' ].includes(record.Type))
|
|
3003
2970
|
if(records.length === 0) {
|
|
@@ -3541,7 +3508,7 @@ var LoadBalancer = class extends Resource {
|
|
|
3541
3508
|
};
|
|
3542
3509
|
|
|
3543
3510
|
// src/formation/resource/elb/listener.ts
|
|
3544
|
-
import { constantCase as
|
|
3511
|
+
import { constantCase as constantCase6 } from "change-case";
|
|
3545
3512
|
var Listener = class extends Resource {
|
|
3546
3513
|
constructor(logicalId, props) {
|
|
3547
3514
|
super("AWS::ElasticLoadBalancingV2::Listener", logicalId);
|
|
@@ -3557,7 +3524,7 @@ var Listener = class extends Resource {
|
|
|
3557
3524
|
return {
|
|
3558
3525
|
LoadBalancerArn: this.props.loadBalancerArn,
|
|
3559
3526
|
Port: this.props.port,
|
|
3560
|
-
Protocol:
|
|
3527
|
+
Protocol: constantCase6(this.props.protocol),
|
|
3561
3528
|
Certificates: this.props.certificates.map((arn) => ({
|
|
3562
3529
|
CertificateArn: arn
|
|
3563
3530
|
})),
|
|
@@ -3996,7 +3963,7 @@ var SubnetGroup = class extends Resource {
|
|
|
3996
3963
|
};
|
|
3997
3964
|
|
|
3998
3965
|
// src/plugins/cache.ts
|
|
3999
|
-
import { constantCase as
|
|
3966
|
+
import { constantCase as constantCase7 } from "change-case";
|
|
4000
3967
|
var TypeSchema = z19.enum([
|
|
4001
3968
|
"t4g.small",
|
|
4002
3969
|
"t4g.medium",
|
|
@@ -4082,9 +4049,420 @@ var cachePlugin = definePlugin({
|
|
|
4082
4049
|
}).dependsOn(subnetGroup, securityGroup);
|
|
4083
4050
|
stack.add(subnetGroup, securityGroup, cluster);
|
|
4084
4051
|
bind((lambda) => {
|
|
4085
|
-
lambda.addEnvironment(`CACHE_${
|
|
4052
|
+
lambda.addEnvironment(`CACHE_${constantCase7(stack.name)}_${constantCase7(id)}_HOST`, cluster.address).addEnvironment(`CACHE_${constantCase7(stack.name)}_${constantCase7(id)}_PORT`, props.port.toString());
|
|
4053
|
+
});
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
});
|
|
4057
|
+
|
|
4058
|
+
// src/plugins/rest.ts
|
|
4059
|
+
import { z as z21 } from "zod";
|
|
4060
|
+
|
|
4061
|
+
// src/schema/route.ts
|
|
4062
|
+
import { z as z20 } from "zod";
|
|
4063
|
+
var RouteSchema2 = z20.custom((route) => {
|
|
4064
|
+
return z20.string().regex(/^(POST|GET|PUT|DELETE|HEAD|OPTIONS)(\s\/[a-z0-9\+\_\-\/\{\}]*)$/ig).safeParse(route).success;
|
|
4065
|
+
}, "Invalid route");
|
|
4066
|
+
|
|
4067
|
+
// src/formation/resource/api-gateway-v2/api.ts
|
|
4068
|
+
var Api = class extends Resource {
|
|
4069
|
+
constructor(logicalId, props) {
|
|
4070
|
+
super("AWS::ApiGatewayV2::Api", logicalId);
|
|
4071
|
+
this.props = props;
|
|
4072
|
+
this.name = formatName(this.props.name || logicalId);
|
|
4073
|
+
}
|
|
4074
|
+
name;
|
|
4075
|
+
get endpoint() {
|
|
4076
|
+
return getAtt(this.logicalId, "ApiEndpoint");
|
|
4077
|
+
}
|
|
4078
|
+
get id() {
|
|
4079
|
+
return getAtt(this.logicalId, "ApiId");
|
|
4080
|
+
}
|
|
4081
|
+
properties() {
|
|
4082
|
+
return {
|
|
4083
|
+
Name: this.name,
|
|
4084
|
+
ProtocolType: this.props.protocolType,
|
|
4085
|
+
...this.attr("Description", this.props.description),
|
|
4086
|
+
CorsConfiguration: {
|
|
4087
|
+
...this.attr("AllowCredentials", this.props.cors?.allow?.credentials),
|
|
4088
|
+
...this.attr("AllowHeaders", this.props.cors?.allow?.headers),
|
|
4089
|
+
...this.attr("AllowMethods", this.props.cors?.allow?.methods),
|
|
4090
|
+
...this.attr("AllowOrigins", this.props.cors?.allow?.origins),
|
|
4091
|
+
...this.attr("ExposeHeaders", this.props.cors?.expose?.headers),
|
|
4092
|
+
...this.attr("MaxAge", this.props.cors?.maxAge?.toSeconds())
|
|
4093
|
+
}
|
|
4094
|
+
};
|
|
4095
|
+
}
|
|
4096
|
+
};
|
|
4097
|
+
|
|
4098
|
+
// src/formation/resource/api-gateway-v2/integration.ts
|
|
4099
|
+
var Integration = class extends Resource {
|
|
4100
|
+
constructor(logicalId, props) {
|
|
4101
|
+
super("AWS::ApiGatewayV2::Integration", logicalId);
|
|
4102
|
+
this.props = props;
|
|
4103
|
+
}
|
|
4104
|
+
get id() {
|
|
4105
|
+
return ref(this.logicalId);
|
|
4106
|
+
}
|
|
4107
|
+
properties() {
|
|
4108
|
+
return {
|
|
4109
|
+
ApiId: this.props.apiId,
|
|
4110
|
+
IntegrationType: this.props.type,
|
|
4111
|
+
IntegrationUri: this.props.uri,
|
|
4112
|
+
IntegrationMethod: this.props.method,
|
|
4113
|
+
PayloadFormatVersion: this.props.payloadFormatVersion ?? "2.0",
|
|
4114
|
+
...this.attr("Description", this.props.description)
|
|
4115
|
+
};
|
|
4116
|
+
}
|
|
4117
|
+
};
|
|
4118
|
+
|
|
4119
|
+
// src/formation/resource/api-gateway-v2/route.ts
|
|
4120
|
+
var Route2 = class extends Resource {
|
|
4121
|
+
constructor(logicalId, props) {
|
|
4122
|
+
super("AWS::ApiGatewayV2::Route", logicalId);
|
|
4123
|
+
this.props = props;
|
|
4124
|
+
}
|
|
4125
|
+
get id() {
|
|
4126
|
+
return getAtt(this.logicalId, "RouteId");
|
|
4127
|
+
}
|
|
4128
|
+
properties() {
|
|
4129
|
+
return {
|
|
4130
|
+
ApiId: this.props.apiId,
|
|
4131
|
+
RouteKey: this.props.routeKey,
|
|
4132
|
+
Target: this.props.target
|
|
4133
|
+
};
|
|
4134
|
+
}
|
|
4135
|
+
};
|
|
4136
|
+
|
|
4137
|
+
// src/formation/resource/lambda/event-source/api-gateway-v2.ts
|
|
4138
|
+
var ApiGatewayV2EventSource = class extends Group {
|
|
4139
|
+
constructor(id, lambda, props) {
|
|
4140
|
+
const name = formatName(id);
|
|
4141
|
+
const permission = new Permission2(id, {
|
|
4142
|
+
action: "lambda:InvokeFunction",
|
|
4143
|
+
principal: "apigateway.amazonaws.com",
|
|
4144
|
+
functionArn: lambda.arn
|
|
4145
|
+
}).dependsOn(lambda);
|
|
4146
|
+
const integration = new Integration(id, {
|
|
4147
|
+
apiId: props.apiId,
|
|
4148
|
+
description: name,
|
|
4149
|
+
method: "POST",
|
|
4150
|
+
payloadFormatVersion: "2.0",
|
|
4151
|
+
type: "AWS_PROXY",
|
|
4152
|
+
uri: sub("arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambda}/invocations", {
|
|
4153
|
+
lambda: lambda.arn
|
|
4154
|
+
})
|
|
4155
|
+
});
|
|
4156
|
+
const route = new Route2(id, {
|
|
4157
|
+
apiId: props.apiId,
|
|
4158
|
+
routeKey: props.routeKey,
|
|
4159
|
+
target: sub("integrations/${id}", { id: integration.id })
|
|
4160
|
+
}).dependsOn(lambda, permission, integration);
|
|
4161
|
+
super([integration, route, permission]);
|
|
4162
|
+
}
|
|
4163
|
+
};
|
|
4164
|
+
|
|
4165
|
+
// src/formation/resource/api-gateway-v2/domain-name.ts
|
|
4166
|
+
var DomainName2 = class extends Resource {
|
|
4167
|
+
constructor(logicalId, props) {
|
|
4168
|
+
super("AWS::ApiGatewayV2::DomainName", logicalId);
|
|
4169
|
+
this.props = props;
|
|
4170
|
+
}
|
|
4171
|
+
get name() {
|
|
4172
|
+
return ref(this.logicalId);
|
|
4173
|
+
}
|
|
4174
|
+
get regionalDomainName() {
|
|
4175
|
+
return getAtt(this.logicalId, "RegionalDomainName");
|
|
4176
|
+
}
|
|
4177
|
+
get regionalHostedZoneId() {
|
|
4178
|
+
return getAtt(this.logicalId, "RegionalHostedZoneId");
|
|
4179
|
+
}
|
|
4180
|
+
properties() {
|
|
4181
|
+
return {
|
|
4182
|
+
DomainName: this.props.name,
|
|
4183
|
+
DomainNameConfigurations: [{
|
|
4184
|
+
CertificateArn: this.props.certificateArn
|
|
4185
|
+
}]
|
|
4186
|
+
};
|
|
4187
|
+
}
|
|
4188
|
+
};
|
|
4189
|
+
|
|
4190
|
+
// src/formation/resource/api-gateway-v2/stage.ts
|
|
4191
|
+
var Stage = class extends Resource {
|
|
4192
|
+
constructor(logicalId, props) {
|
|
4193
|
+
super("AWS::ApiGatewayV2::Stage", logicalId);
|
|
4194
|
+
this.props = props;
|
|
4195
|
+
this.name = formatName(this.props.name || logicalId);
|
|
4196
|
+
}
|
|
4197
|
+
name;
|
|
4198
|
+
properties() {
|
|
4199
|
+
return {
|
|
4200
|
+
ApiId: this.props.apiId,
|
|
4201
|
+
StageName: this.name,
|
|
4202
|
+
AutoDeploy: this.props.autoDeploy ?? true,
|
|
4203
|
+
...this.attr("DeploymentId", this.props.deploymentId),
|
|
4204
|
+
...this.attr("Description", this.props.description)
|
|
4205
|
+
};
|
|
4206
|
+
}
|
|
4207
|
+
};
|
|
4208
|
+
|
|
4209
|
+
// src/formation/resource/api-gateway-v2/api-mapping.ts
|
|
4210
|
+
var ApiMapping = class extends Resource {
|
|
4211
|
+
constructor(logicalId, props) {
|
|
4212
|
+
super("AWS::ApiGatewayV2::ApiMapping", logicalId);
|
|
4213
|
+
this.props = props;
|
|
4214
|
+
}
|
|
4215
|
+
get id() {
|
|
4216
|
+
return getAtt(this.logicalId, "ApiMappingId");
|
|
4217
|
+
}
|
|
4218
|
+
properties() {
|
|
4219
|
+
return {
|
|
4220
|
+
DomainName: this.props.domainName,
|
|
4221
|
+
ApiId: this.props.apiId,
|
|
4222
|
+
Stage: this.props.stage
|
|
4223
|
+
};
|
|
4224
|
+
}
|
|
4225
|
+
};
|
|
4226
|
+
|
|
4227
|
+
// src/plugins/rest.ts
|
|
4228
|
+
var restPlugin = definePlugin({
|
|
4229
|
+
name: "rest",
|
|
4230
|
+
schema: z21.object({
|
|
4231
|
+
defaults: z21.object({
|
|
4232
|
+
/** Define your global REST API's.
|
|
4233
|
+
* @example
|
|
4234
|
+
* {
|
|
4235
|
+
* rest: {
|
|
4236
|
+
* REST_API_NAME: {
|
|
4237
|
+
* domain: 'example.com',
|
|
4238
|
+
* subDomain: 'api',
|
|
4239
|
+
* }
|
|
4240
|
+
* }
|
|
4241
|
+
* }
|
|
4242
|
+
*/
|
|
4243
|
+
rest: z21.record(
|
|
4244
|
+
ResourceIdSchema,
|
|
4245
|
+
z21.object({
|
|
4246
|
+
/** The domain to link your API with. */
|
|
4247
|
+
domain: z21.string(),
|
|
4248
|
+
subDomain: z21.string().optional()
|
|
4249
|
+
})
|
|
4250
|
+
).optional()
|
|
4251
|
+
}).default({}),
|
|
4252
|
+
stacks: z21.object({
|
|
4253
|
+
/** Define routes in your stack for your global REST API.
|
|
4254
|
+
* @example
|
|
4255
|
+
* {
|
|
4256
|
+
* rest: {
|
|
4257
|
+
* REST_API_NAME: {
|
|
4258
|
+
* 'GET /': 'index.ts',
|
|
4259
|
+
* 'POST /posts': 'create-post.ts',
|
|
4260
|
+
* }
|
|
4261
|
+
* }
|
|
4262
|
+
* }
|
|
4263
|
+
*/
|
|
4264
|
+
rest: z21.record(
|
|
4265
|
+
ResourceIdSchema,
|
|
4266
|
+
z21.record(RouteSchema2, FunctionSchema)
|
|
4267
|
+
).optional()
|
|
4268
|
+
}).array()
|
|
4269
|
+
}),
|
|
4270
|
+
onApp({ config, bootstrap: bootstrap2, usEastBootstrap }) {
|
|
4271
|
+
for (const [id, props] of Object.entries(config.defaults?.rest || {})) {
|
|
4272
|
+
const api = new Api(id, {
|
|
4273
|
+
name: `${config.name}-${id}`,
|
|
4274
|
+
protocolType: "HTTP"
|
|
4086
4275
|
});
|
|
4276
|
+
const stage = new Stage(id, {
|
|
4277
|
+
name: "v1",
|
|
4278
|
+
apiId: api.id
|
|
4279
|
+
}).dependsOn(api);
|
|
4280
|
+
bootstrap2.add(api, stage).export(`rest-${id}-id`, api.id);
|
|
4281
|
+
if (props.domain) {
|
|
4282
|
+
const domainName = props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain;
|
|
4283
|
+
const hostedZoneId = usEastBootstrap.import(`hosted-zone-${props.domain}-id`);
|
|
4284
|
+
const certificateArn = bootstrap2.import(`certificate-${props.domain}-arn`);
|
|
4285
|
+
const domain = new DomainName2(id, {
|
|
4286
|
+
name: domainName,
|
|
4287
|
+
certificateArn
|
|
4288
|
+
});
|
|
4289
|
+
const mapping = new ApiMapping(id, {
|
|
4290
|
+
apiId: api.id,
|
|
4291
|
+
domainName: domain.name,
|
|
4292
|
+
stage: stage.name
|
|
4293
|
+
}).dependsOn(api, domain, stage);
|
|
4294
|
+
const record = new RecordSet(`${id}-rest`, {
|
|
4295
|
+
hostedZoneId,
|
|
4296
|
+
type: "A",
|
|
4297
|
+
name: domainName,
|
|
4298
|
+
alias: {
|
|
4299
|
+
dnsName: domain.regionalDomainName,
|
|
4300
|
+
hostedZoneId: domain.regionalHostedZoneId
|
|
4301
|
+
}
|
|
4302
|
+
}).dependsOn(domain, mapping);
|
|
4303
|
+
bootstrap2.add(domain, mapping, record);
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
},
|
|
4307
|
+
onStack(ctx) {
|
|
4308
|
+
const { stack, stackConfig, bootstrap: bootstrap2 } = ctx;
|
|
4309
|
+
for (const [id, routes] of Object.entries(stackConfig.rest || {})) {
|
|
4310
|
+
for (const [routeKey, props] of Object.entries(routes)) {
|
|
4311
|
+
const lambda = toLambdaFunction(ctx, `rest-${id}-${routeKey}`, props);
|
|
4312
|
+
const source = new ApiGatewayV2EventSource(`rest-${id}-${routeKey}`, lambda, {
|
|
4313
|
+
apiId: bootstrap2.import(`rest-${id}-id`),
|
|
4314
|
+
routeKey
|
|
4315
|
+
});
|
|
4316
|
+
stack.add(lambda, source);
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
});
|
|
4321
|
+
|
|
4322
|
+
// src/plugins/config.ts
|
|
4323
|
+
import { z as z22 } from "zod";
|
|
4324
|
+
|
|
4325
|
+
// src/util/param.ts
|
|
4326
|
+
import { DeleteParameterCommand, GetParameterCommand, GetParametersByPathCommand, ParameterType, PutParameterCommand, SSMClient } from "@aws-sdk/client-ssm";
|
|
4327
|
+
var configParameterPrefix = (config) => {
|
|
4328
|
+
return `/.awsless/${config.name}`;
|
|
4329
|
+
};
|
|
4330
|
+
var Params = class {
|
|
4331
|
+
constructor(config) {
|
|
4332
|
+
this.config = config;
|
|
4333
|
+
this.client = new SSMClient({
|
|
4334
|
+
credentials: config.credentials,
|
|
4335
|
+
region: config.region
|
|
4336
|
+
});
|
|
4337
|
+
}
|
|
4338
|
+
client;
|
|
4339
|
+
getName(name) {
|
|
4340
|
+
return `${configParameterPrefix(this.config)}/${name}`;
|
|
4341
|
+
}
|
|
4342
|
+
async get(name) {
|
|
4343
|
+
debug("Get remote config value");
|
|
4344
|
+
debug("Name:", style.info(name));
|
|
4345
|
+
let result;
|
|
4346
|
+
try {
|
|
4347
|
+
result = await this.client.send(new GetParameterCommand({
|
|
4348
|
+
Name: this.getName(name),
|
|
4349
|
+
WithDecryption: true
|
|
4350
|
+
}));
|
|
4351
|
+
} catch (error) {
|
|
4352
|
+
if (error instanceof Error && error.name === "ParameterNotFound") {
|
|
4353
|
+
debug("Parameter not found");
|
|
4354
|
+
return;
|
|
4355
|
+
}
|
|
4356
|
+
throw error;
|
|
4357
|
+
}
|
|
4358
|
+
const value = result.Parameter?.Value;
|
|
4359
|
+
debug("Value:", style.info(value));
|
|
4360
|
+
debug("Done getting remote config value");
|
|
4361
|
+
return value;
|
|
4362
|
+
}
|
|
4363
|
+
async set(name, value) {
|
|
4364
|
+
debug("Save remote config value");
|
|
4365
|
+
debug("Name:", style.info(name));
|
|
4366
|
+
debug("Value:", style.info(value));
|
|
4367
|
+
await this.client.send(new PutParameterCommand({
|
|
4368
|
+
Type: ParameterType.STRING,
|
|
4369
|
+
Name: this.getName(name),
|
|
4370
|
+
Value: value,
|
|
4371
|
+
Overwrite: true
|
|
4372
|
+
}));
|
|
4373
|
+
debug("Done saving remote config value");
|
|
4374
|
+
}
|
|
4375
|
+
async delete(name) {
|
|
4376
|
+
debug("Delete remote config value");
|
|
4377
|
+
debug("Name:", style.info(name));
|
|
4378
|
+
try {
|
|
4379
|
+
await this.client.send(new DeleteParameterCommand({
|
|
4380
|
+
Name: this.getName(name)
|
|
4381
|
+
}));
|
|
4382
|
+
} catch (error) {
|
|
4383
|
+
if (error instanceof Error && error.name === "ParameterNotFound") {
|
|
4384
|
+
debug("Remote config value was already deleted");
|
|
4385
|
+
return;
|
|
4386
|
+
}
|
|
4387
|
+
throw error;
|
|
4388
|
+
}
|
|
4389
|
+
debug("Done deleting remote config value");
|
|
4390
|
+
}
|
|
4391
|
+
async list() {
|
|
4392
|
+
debug("Load remote config values");
|
|
4393
|
+
const result = await this.client.send(new GetParametersByPathCommand({
|
|
4394
|
+
Path: configParameterPrefix(this.config),
|
|
4395
|
+
WithDecryption: true,
|
|
4396
|
+
MaxResults: 10,
|
|
4397
|
+
Recursive: true
|
|
4398
|
+
}));
|
|
4399
|
+
debug("Done loading remote config values");
|
|
4400
|
+
const values = {};
|
|
4401
|
+
result.Parameters?.forEach((param) => {
|
|
4402
|
+
const name = param.Name.substring(configParameterPrefix(this.config).length).substring(1);
|
|
4403
|
+
values[name] = param.Value || "";
|
|
4404
|
+
});
|
|
4405
|
+
return values;
|
|
4406
|
+
}
|
|
4407
|
+
};
|
|
4408
|
+
|
|
4409
|
+
// src/plugins/config.ts
|
|
4410
|
+
import { paramCase as paramCase5 } from "change-case";
|
|
4411
|
+
var ConfigNameSchema = z22.string().regex(/[a-z0-9\-]/g, "Invalid config name");
|
|
4412
|
+
var configPlugin = definePlugin({
|
|
4413
|
+
name: "config",
|
|
4414
|
+
schema: z22.object({
|
|
4415
|
+
stacks: z22.object({
|
|
4416
|
+
/** Define the config values for your stack.
|
|
4417
|
+
* @example
|
|
4418
|
+
* ```
|
|
4419
|
+
* {
|
|
4420
|
+
* configs: [ 'your-secret' ]
|
|
4421
|
+
* }
|
|
4422
|
+
* ```
|
|
4423
|
+
*
|
|
4424
|
+
* You can access the config values via:
|
|
4425
|
+
* @example
|
|
4426
|
+
* ```
|
|
4427
|
+
* import { Config } from '@awsless/awsless'
|
|
4428
|
+
*
|
|
4429
|
+
* Config.YOUR_SECRET
|
|
4430
|
+
* ```
|
|
4431
|
+
*/
|
|
4432
|
+
configs: z22.array(ConfigNameSchema).optional()
|
|
4433
|
+
}).array()
|
|
4434
|
+
}),
|
|
4435
|
+
onTypeGen({ config }) {
|
|
4436
|
+
const types2 = new TypeGen("@awsless/awsless", "ConfigResources", false);
|
|
4437
|
+
for (const stack of config.stacks) {
|
|
4438
|
+
for (const name of stack.configs || []) {
|
|
4439
|
+
types2.addConst(name, "string");
|
|
4440
|
+
}
|
|
4087
4441
|
}
|
|
4442
|
+
return types2.toString();
|
|
4443
|
+
},
|
|
4444
|
+
onStack({ bind, config, stackConfig }) {
|
|
4445
|
+
const configs = stackConfig.configs;
|
|
4446
|
+
bind((lambda) => {
|
|
4447
|
+
if (configs && configs.length) {
|
|
4448
|
+
lambda.addEnvironment("AWSLESS_CONFIG", configs.join(","));
|
|
4449
|
+
lambda.addPermissions({
|
|
4450
|
+
actions: [
|
|
4451
|
+
"ssm:GetParameter",
|
|
4452
|
+
"ssm:GetParameters",
|
|
4453
|
+
"ssm:GetParametersByPath"
|
|
4454
|
+
],
|
|
4455
|
+
resources: configs.map((name) => {
|
|
4456
|
+
return formatArn({
|
|
4457
|
+
service: "ssm",
|
|
4458
|
+
resource: "parameter",
|
|
4459
|
+
resourceName: configParameterPrefix(config) + "/" + paramCase5(name),
|
|
4460
|
+
seperator: ""
|
|
4461
|
+
});
|
|
4462
|
+
})
|
|
4463
|
+
});
|
|
4464
|
+
}
|
|
4465
|
+
});
|
|
4088
4466
|
}
|
|
4089
4467
|
});
|
|
4090
4468
|
|
|
@@ -4093,6 +4471,7 @@ var defaultPlugins = [
|
|
|
4093
4471
|
extendPlugin,
|
|
4094
4472
|
vpcPlugin,
|
|
4095
4473
|
functionPlugin,
|
|
4474
|
+
configPlugin,
|
|
4096
4475
|
cachePlugin,
|
|
4097
4476
|
cronPlugin,
|
|
4098
4477
|
queuePlugin,
|
|
@@ -4104,6 +4483,7 @@ var defaultPlugins = [
|
|
|
4104
4483
|
domainPlugin,
|
|
4105
4484
|
graphqlPlugin,
|
|
4106
4485
|
httpPlugin,
|
|
4486
|
+
restPlugin,
|
|
4107
4487
|
onFailurePlugin
|
|
4108
4488
|
];
|
|
4109
4489
|
|
|
@@ -4141,6 +4521,8 @@ var globalExportsHandlerCode = (
|
|
|
4141
4521
|
|
|
4142
4522
|
const { CloudFormationClient, ListExportsCommand } = require('@aws-sdk/client-cloudformation')
|
|
4143
4523
|
|
|
4524
|
+
${sendCode}
|
|
4525
|
+
|
|
4144
4526
|
exports.handler = async (event) => {
|
|
4145
4527
|
const region = event.ResourceProperties.region
|
|
4146
4528
|
|
|
@@ -4157,29 +4539,6 @@ exports.handler = async (event) => {
|
|
|
4157
4539
|
}
|
|
4158
4540
|
}
|
|
4159
4541
|
|
|
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
4542
|
const listExports = async (region) => {
|
|
4184
4543
|
const client = new CloudFormationClient({ region })
|
|
4185
4544
|
const data = {}
|
|
@@ -4357,17 +4716,17 @@ var getCredentials = (profile) => {
|
|
|
4357
4716
|
};
|
|
4358
4717
|
|
|
4359
4718
|
// src/schema/app.ts
|
|
4360
|
-
import { z as
|
|
4719
|
+
import { z as z26 } from "zod";
|
|
4361
4720
|
|
|
4362
4721
|
// src/schema/stack.ts
|
|
4363
|
-
import { z as
|
|
4364
|
-
var StackSchema =
|
|
4722
|
+
import { z as z23 } from "zod";
|
|
4723
|
+
var StackSchema = z23.object({
|
|
4365
4724
|
name: ResourceIdSchema,
|
|
4366
|
-
depends:
|
|
4725
|
+
depends: z23.array(z23.lazy(() => StackSchema)).optional()
|
|
4367
4726
|
});
|
|
4368
4727
|
|
|
4369
4728
|
// src/schema/region.ts
|
|
4370
|
-
import { z as
|
|
4729
|
+
import { z as z24 } from "zod";
|
|
4371
4730
|
var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
|
|
4372
4731
|
var AF = ["af-south-1"];
|
|
4373
4732
|
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 +4743,41 @@ var regions = [
|
|
|
4384
4743
|
...ME,
|
|
4385
4744
|
...SA
|
|
4386
4745
|
];
|
|
4387
|
-
var RegionSchema =
|
|
4746
|
+
var RegionSchema = z24.enum(regions);
|
|
4388
4747
|
|
|
4389
4748
|
// src/schema/plugin.ts
|
|
4390
|
-
import { z as
|
|
4391
|
-
var PluginSchema =
|
|
4392
|
-
name:
|
|
4393
|
-
schema:
|
|
4749
|
+
import { z as z25 } from "zod";
|
|
4750
|
+
var PluginSchema = z25.object({
|
|
4751
|
+
name: z25.string(),
|
|
4752
|
+
schema: z25.custom().optional(),
|
|
4394
4753
|
// depends: z.array(z.lazy(() => PluginSchema)).optional(),
|
|
4395
|
-
onApp:
|
|
4396
|
-
onStack:
|
|
4397
|
-
onResource:
|
|
4754
|
+
onApp: z25.function().returns(z25.void()).optional(),
|
|
4755
|
+
onStack: z25.function().returns(z25.any()).optional(),
|
|
4756
|
+
onResource: z25.function().returns(z25.any()).optional()
|
|
4398
4757
|
// bind: z.function().optional(),
|
|
4399
4758
|
});
|
|
4400
4759
|
|
|
4401
4760
|
// src/schema/app.ts
|
|
4402
|
-
var AppSchema =
|
|
4761
|
+
var AppSchema = z26.object({
|
|
4403
4762
|
/** App name */
|
|
4404
4763
|
name: ResourceIdSchema,
|
|
4405
4764
|
/** The AWS region to deploy to. */
|
|
4406
4765
|
region: RegionSchema,
|
|
4407
4766
|
/** The AWS profile to deploy to. */
|
|
4408
|
-
profile:
|
|
4767
|
+
profile: z26.string(),
|
|
4409
4768
|
/** The deployment stage.
|
|
4410
4769
|
* @default 'prod'
|
|
4411
4770
|
*/
|
|
4412
|
-
stage:
|
|
4771
|
+
stage: z26.string().regex(/^[a-z]+$/).default("prod"),
|
|
4413
4772
|
/** Default properties. */
|
|
4414
|
-
defaults:
|
|
4773
|
+
defaults: z26.object({}).default({}),
|
|
4415
4774
|
/** The application stacks. */
|
|
4416
|
-
stacks:
|
|
4775
|
+
stacks: z26.array(StackSchema).min(1).refine((stacks) => {
|
|
4417
4776
|
const unique = new Set(stacks.map((stack) => stack.name));
|
|
4418
4777
|
return unique.size === stacks.length;
|
|
4419
4778
|
}, "Must be an array of unique stacks"),
|
|
4420
4779
|
/** Custom plugins. */
|
|
4421
|
-
plugins:
|
|
4780
|
+
plugins: z26.array(PluginSchema).optional()
|
|
4422
4781
|
});
|
|
4423
4782
|
|
|
4424
4783
|
// src/util/import.ts
|
|
@@ -4515,7 +4874,7 @@ var watchFile = (path) => {
|
|
|
4515
4874
|
};
|
|
4516
4875
|
|
|
4517
4876
|
// src/config.ts
|
|
4518
|
-
import { z as
|
|
4877
|
+
import { z as z27 } from "zod";
|
|
4519
4878
|
var ConfigError = class extends Error {
|
|
4520
4879
|
constructor(error, data) {
|
|
4521
4880
|
super(error.message);
|
|
@@ -4548,7 +4907,7 @@ var importConfig = async (options) => {
|
|
|
4548
4907
|
try {
|
|
4549
4908
|
config = await schema2.parseAsync(appConfig);
|
|
4550
4909
|
} catch (error) {
|
|
4551
|
-
if (error instanceof
|
|
4910
|
+
if (error instanceof z27.ZodError) {
|
|
4552
4911
|
throw new ConfigError(error, appConfig);
|
|
4553
4912
|
}
|
|
4554
4913
|
throw error;
|
|
@@ -4589,7 +4948,7 @@ var watchConfig = async function* (options) {
|
|
|
4589
4948
|
try {
|
|
4590
4949
|
config = await schema2.parseAsync(appConfig);
|
|
4591
4950
|
} catch (error) {
|
|
4592
|
-
if (error instanceof
|
|
4951
|
+
if (error instanceof z27.ZodError) {
|
|
4593
4952
|
throw new ConfigError(error, appConfig);
|
|
4594
4953
|
}
|
|
4595
4954
|
throw error;
|
|
@@ -5080,7 +5439,6 @@ var format = (value) => {
|
|
|
5080
5439
|
};
|
|
5081
5440
|
var zodError = (error, data) => {
|
|
5082
5441
|
return (term) => {
|
|
5083
|
-
term.out.write(JSON.stringify(error.errors));
|
|
5084
5442
|
for (const issue of error.issues) {
|
|
5085
5443
|
term.out.gap();
|
|
5086
5444
|
term.out.write(dialog("error", [
|
|
@@ -5365,7 +5723,7 @@ var shouldDeployBootstrap = async (client, stack) => {
|
|
|
5365
5723
|
// src/formation/client.ts
|
|
5366
5724
|
import { CloudFormationClient, CreateStackCommand, DeleteStackCommand, DescribeStackEventsCommand, DescribeStacksCommand, GetTemplateCommand, OnFailure, TemplateStage, UpdateStackCommand, ValidateTemplateCommand, waitUntilStackCreateComplete, waitUntilStackDeleteComplete, waitUntilStackUpdateComplete } from "@aws-sdk/client-cloudformation";
|
|
5367
5725
|
import { S3Client, PutObjectCommand, ObjectCannedACL, StorageClass } from "@aws-sdk/client-s3";
|
|
5368
|
-
import { paramCase as
|
|
5726
|
+
import { paramCase as paramCase6 } from "change-case";
|
|
5369
5727
|
var StackClient = class {
|
|
5370
5728
|
constructor(app, account, region, credentials) {
|
|
5371
5729
|
this.app = app;
|
|
@@ -5398,7 +5756,7 @@ var StackClient = class {
|
|
|
5398
5756
|
};
|
|
5399
5757
|
}
|
|
5400
5758
|
stackName(stackName) {
|
|
5401
|
-
return
|
|
5759
|
+
return paramCase6(`${this.app.name}-${stackName}`);
|
|
5402
5760
|
}
|
|
5403
5761
|
tags(stack) {
|
|
5404
5762
|
const tags = [];
|
|
@@ -5411,7 +5769,8 @@ var StackClient = class {
|
|
|
5411
5769
|
debug("Upload the", style.info(stack.name), "stack to awsless assets bucket");
|
|
5412
5770
|
const client = new S3Client({
|
|
5413
5771
|
credentials: this.credentials,
|
|
5414
|
-
region: stack.region
|
|
5772
|
+
region: stack.region,
|
|
5773
|
+
maxAttempts: 5
|
|
5415
5774
|
});
|
|
5416
5775
|
await client.send(new PutObjectCommand({
|
|
5417
5776
|
Bucket: this.assetBucketName,
|
|
@@ -5831,7 +6190,8 @@ import { GetObjectCommand, ObjectCannedACL as ObjectCannedACL2, PutObjectCommand
|
|
|
5831
6190
|
var assetPublisher = (config, app) => {
|
|
5832
6191
|
const client = new S3Client2({
|
|
5833
6192
|
credentials: config.credentials,
|
|
5834
|
-
region: config.region
|
|
6193
|
+
region: config.region,
|
|
6194
|
+
maxAttempts: 5
|
|
5835
6195
|
});
|
|
5836
6196
|
return async (term) => {
|
|
5837
6197
|
const done = term.out.write(loadingDialog("Publishing stack assets to AWS..."));
|