@awsless/awsless 0.0.42 → 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 +590 -228
- package/dist/index.d.ts +599 -138
- package/dist/index.js +40 -4
- package/package.json +5 -6
- package/dist/bin.cjs +0 -6171
- 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
|
|
@@ -747,8 +650,9 @@ var LocalFileSchema = z3.string().refine(async (path) => {
|
|
|
747
650
|
}, `File doesn't exist`);
|
|
748
651
|
|
|
749
652
|
// src/schema/resource-id.ts
|
|
653
|
+
import { paramCase as paramCase3 } from "change-case";
|
|
750
654
|
import { z as z4 } from "zod";
|
|
751
|
-
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));
|
|
752
656
|
|
|
753
657
|
// src/schema/size.ts
|
|
754
658
|
import { z as z5 } from "zod";
|
|
@@ -1062,7 +966,7 @@ import { relative as relative2 } from "path";
|
|
|
1062
966
|
// src/util/type-gen.ts
|
|
1063
967
|
import { mkdir, writeFile } from "fs/promises";
|
|
1064
968
|
import { join as join2, relative } from "path";
|
|
1065
|
-
import { camelCase } from "change-case";
|
|
969
|
+
import { camelCase, constantCase } from "change-case";
|
|
1066
970
|
var generateResourceTypes = async (config) => {
|
|
1067
971
|
const plugins = [
|
|
1068
972
|
...defaultPlugins,
|
|
@@ -1084,9 +988,10 @@ var generateResourceTypes = async (config) => {
|
|
|
1084
988
|
}
|
|
1085
989
|
};
|
|
1086
990
|
var TypeGen = class {
|
|
1087
|
-
constructor(module, interfaceName) {
|
|
991
|
+
constructor(module, interfaceName, readonly = true) {
|
|
1088
992
|
this.module = module;
|
|
1089
993
|
this.interfaceName = interfaceName;
|
|
994
|
+
this.readonly = readonly;
|
|
1090
995
|
}
|
|
1091
996
|
codes = /* @__PURE__ */ new Set();
|
|
1092
997
|
types = /* @__PURE__ */ new Map();
|
|
@@ -1101,7 +1006,13 @@ var TypeGen = class {
|
|
|
1101
1006
|
}
|
|
1102
1007
|
addType(name, type) {
|
|
1103
1008
|
if (type) {
|
|
1104
|
-
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);
|
|
1105
1016
|
}
|
|
1106
1017
|
return this;
|
|
1107
1018
|
}
|
|
@@ -1132,7 +1043,7 @@ var TypeGen = class {
|
|
|
1132
1043
|
`declare module '${this.module}' {`,
|
|
1133
1044
|
` interface ${this.interfaceName} {`,
|
|
1134
1045
|
...Array.from(this.types.entries()).map(([propName, type]) => {
|
|
1135
|
-
return ` readonly ${
|
|
1046
|
+
return ` ${this.readonly ? "readonly " : ""}${propName}: ${type}`;
|
|
1136
1047
|
}),
|
|
1137
1048
|
` }`,
|
|
1138
1049
|
`}`,
|
|
@@ -1145,7 +1056,15 @@ var TypeGen = class {
|
|
|
1145
1056
|
var TypeObject = class {
|
|
1146
1057
|
types = /* @__PURE__ */ new Map();
|
|
1147
1058
|
addType(name, type) {
|
|
1148
|
-
|
|
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
|
+
}
|
|
1149
1068
|
return this;
|
|
1150
1069
|
}
|
|
1151
1070
|
toString() {
|
|
@@ -1155,7 +1074,7 @@ var TypeObject = class {
|
|
|
1155
1074
|
return [
|
|
1156
1075
|
"{",
|
|
1157
1076
|
...Array.from(this.types.entries()).map(([propName, type]) => {
|
|
1158
|
-
return ` readonly ${
|
|
1077
|
+
return ` readonly ${propName}: ${type}`;
|
|
1159
1078
|
}),
|
|
1160
1079
|
" }"
|
|
1161
1080
|
].join("\n");
|
|
@@ -1229,6 +1148,9 @@ var FunctionSchema = z6.union([
|
|
|
1229
1148
|
// onFailure: ResourceIdSchema.optional(),
|
|
1230
1149
|
})
|
|
1231
1150
|
]);
|
|
1151
|
+
var isFunctionProps = (input) => {
|
|
1152
|
+
return typeof input === "string" || typeof input.file === "string";
|
|
1153
|
+
};
|
|
1232
1154
|
var schema = z6.object({
|
|
1233
1155
|
defaults: z6.object({
|
|
1234
1156
|
function: z6.object({
|
|
@@ -1428,7 +1350,7 @@ var Permission2 = class extends Resource {
|
|
|
1428
1350
|
FunctionName: this.props.functionArn,
|
|
1429
1351
|
Action: this.props.action || "lambda:InvokeFunction",
|
|
1430
1352
|
Principal: this.props.principal,
|
|
1431
|
-
SourceArn
|
|
1353
|
+
...this.attr("SourceArn", this.props.sourceArn)
|
|
1432
1354
|
};
|
|
1433
1355
|
}
|
|
1434
1356
|
};
|
|
@@ -1554,7 +1476,7 @@ var Queue = class extends Resource {
|
|
|
1554
1476
|
};
|
|
1555
1477
|
|
|
1556
1478
|
// src/formation/resource/lambda/event-source-mapping.ts
|
|
1557
|
-
import { constantCase } from "change-case";
|
|
1479
|
+
import { constantCase as constantCase2 } from "change-case";
|
|
1558
1480
|
var EventSourceMapping = class extends Resource {
|
|
1559
1481
|
constructor(logicalId, props) {
|
|
1560
1482
|
super("AWS::Lambda::EventSourceMapping", logicalId);
|
|
@@ -1576,7 +1498,7 @@ var EventSourceMapping = class extends Resource {
|
|
|
1576
1498
|
...this.attr("ParallelizationFactor", this.props.parallelizationFactor),
|
|
1577
1499
|
...this.attr("TumblingWindowInSeconds", this.props.tumblingWindow?.toSeconds()),
|
|
1578
1500
|
...this.attr("BisectBatchOnFunctionError", this.props.bisectBatchOnError),
|
|
1579
|
-
...this.attr("StartingPosition", this.props.startingPosition &&
|
|
1501
|
+
...this.attr("StartingPosition", this.props.startingPosition && constantCase2(this.props.startingPosition)),
|
|
1580
1502
|
...this.attr("StartingPositionTimestamp", this.props.startingPositionTimestamp),
|
|
1581
1503
|
...this.props.maxConcurrency ? {
|
|
1582
1504
|
ScalingConfig: {
|
|
@@ -1617,7 +1539,7 @@ var SqsEventSource = class extends Group {
|
|
|
1617
1539
|
};
|
|
1618
1540
|
|
|
1619
1541
|
// src/plugins/queue.ts
|
|
1620
|
-
import { camelCase as camelCase3, constantCase as
|
|
1542
|
+
import { camelCase as camelCase3, constantCase as constantCase3 } from "change-case";
|
|
1621
1543
|
import { relative as relative3 } from "path";
|
|
1622
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");
|
|
1623
1545
|
var VisibilityTimeoutSchema = DurationSchema.refine(durationMax(Duration.hours(12)), "Maximum visibility timeout is 12 hours");
|
|
@@ -1772,7 +1694,7 @@ var queuePlugin = definePlugin({
|
|
|
1772
1694
|
stack.add(queue2, lambda, source);
|
|
1773
1695
|
bind((lambda2) => {
|
|
1774
1696
|
lambda2.addPermissions(queue2.permissions);
|
|
1775
|
-
lambda2.addEnvironment(`QUEUE_${
|
|
1697
|
+
lambda2.addEnvironment(`QUEUE_${constantCase3(stack.name)}_${constantCase3(id)}_URL`, queue2.url);
|
|
1776
1698
|
});
|
|
1777
1699
|
}
|
|
1778
1700
|
}
|
|
@@ -1782,7 +1704,7 @@ var queuePlugin = definePlugin({
|
|
|
1782
1704
|
import { z as z9 } from "zod";
|
|
1783
1705
|
|
|
1784
1706
|
// src/formation/resource/dynamodb/table.ts
|
|
1785
|
-
import { constantCase as
|
|
1707
|
+
import { constantCase as constantCase4 } from "change-case";
|
|
1786
1708
|
var Table = class extends Resource {
|
|
1787
1709
|
constructor(logicalId, props) {
|
|
1788
1710
|
super("AWS::DynamoDB::Table", logicalId);
|
|
@@ -1855,7 +1777,7 @@ var Table = class extends Resource {
|
|
|
1855
1777
|
return {
|
|
1856
1778
|
TableName: this.name,
|
|
1857
1779
|
BillingMode: "PAY_PER_REQUEST",
|
|
1858
|
-
TableClass:
|
|
1780
|
+
TableClass: constantCase4(this.props.class || "standard"),
|
|
1859
1781
|
PointInTimeRecoverySpecification: {
|
|
1860
1782
|
PointInTimeRecoveryEnabled: this.props.pointInTimeRecovery || false
|
|
1861
1783
|
},
|
|
@@ -1866,7 +1788,7 @@ var Table = class extends Resource {
|
|
|
1866
1788
|
AttributeDefinitions: this.attributeDefinitions(),
|
|
1867
1789
|
...this.props.stream ? {
|
|
1868
1790
|
StreamSpecification: {
|
|
1869
|
-
StreamViewType:
|
|
1791
|
+
StreamViewType: constantCase4(this.props.stream)
|
|
1870
1792
|
}
|
|
1871
1793
|
} : {},
|
|
1872
1794
|
...this.props.timeToLiveAttribute ? {
|
|
@@ -1883,7 +1805,7 @@ var Table = class extends Resource {
|
|
|
1883
1805
|
...props.sort ? [{ KeyType: "RANGE", AttributeName: props.sort }] : []
|
|
1884
1806
|
],
|
|
1885
1807
|
Projection: {
|
|
1886
|
-
ProjectionType:
|
|
1808
|
+
ProjectionType: constantCase4(props.projection || "all")
|
|
1887
1809
|
}
|
|
1888
1810
|
}))
|
|
1889
1811
|
} : {}
|
|
@@ -2233,54 +2155,81 @@ var topicPlugin = definePlugin({
|
|
|
2233
2155
|
name: "topic",
|
|
2234
2156
|
schema: z11.object({
|
|
2235
2157
|
stacks: z11.object({
|
|
2236
|
-
/** Define the
|
|
2158
|
+
/** Define the events to publish too in your stack.
|
|
2237
2159
|
* @example
|
|
2238
2160
|
* {
|
|
2239
|
-
* 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: {
|
|
2240
2171
|
* TOPIC_NAME: 'function.ts'
|
|
2241
2172
|
* }
|
|
2242
2173
|
* }
|
|
2243
2174
|
*/
|
|
2244
|
-
|
|
2245
|
-
}).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
|
+
})
|
|
2246
2194
|
}),
|
|
2247
2195
|
onTypeGen({ config }) {
|
|
2248
2196
|
const gen = new TypeGen("@awsless/awsless", "TopicResources");
|
|
2249
2197
|
gen.addCode(typeGenCode3);
|
|
2250
2198
|
for (const stack of config.stacks) {
|
|
2251
|
-
for (const topic of
|
|
2199
|
+
for (const topic of stack.topics || []) {
|
|
2252
2200
|
const name = formatName(`${config.name}-${topic}`);
|
|
2253
2201
|
gen.addType(topic, `Publish<'${name}'>`);
|
|
2254
2202
|
}
|
|
2255
2203
|
}
|
|
2256
2204
|
return gen.toString();
|
|
2257
2205
|
},
|
|
2258
|
-
onApp({ config, bootstrap: bootstrap2
|
|
2259
|
-
const
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
}
|
|
2267
|
-
bootstrap2.add(topic);
|
|
2268
|
-
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
|
+
}
|
|
2269
2215
|
}
|
|
2270
|
-
bind((lambda) => {
|
|
2271
|
-
lambda.addPermissions({
|
|
2272
|
-
actions: ["sns:Publish"],
|
|
2273
|
-
resources: [
|
|
2274
|
-
sub("arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:${app}-*", {
|
|
2275
|
-
app: config.name
|
|
2276
|
-
})
|
|
2277
|
-
]
|
|
2278
|
-
});
|
|
2279
|
-
});
|
|
2280
2216
|
},
|
|
2281
2217
|
onStack(ctx) {
|
|
2282
|
-
const { stack, stackConfig, bootstrap: bootstrap2 } = ctx;
|
|
2283
|
-
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 || {})) {
|
|
2284
2233
|
const lambda = toLambdaFunction(ctx, `topic-${id}`, props);
|
|
2285
2234
|
const source = new SnsEventSource(id, lambda, {
|
|
2286
2235
|
topicArn: bootstrap2.import(`topic-${id}-arn`)
|
|
@@ -2419,10 +2368,10 @@ var toArray = (value) => {
|
|
|
2419
2368
|
};
|
|
2420
2369
|
|
|
2421
2370
|
// src/plugins/graphql.ts
|
|
2422
|
-
import { paramCase as
|
|
2371
|
+
import { paramCase as paramCase4 } from "change-case";
|
|
2423
2372
|
|
|
2424
2373
|
// src/formation/resource/appsync/graphql-api.ts
|
|
2425
|
-
import { constantCase as
|
|
2374
|
+
import { constantCase as constantCase5 } from "change-case";
|
|
2426
2375
|
var GraphQLApi = class extends Resource {
|
|
2427
2376
|
constructor(logicalId, props) {
|
|
2428
2377
|
super("AWS::AppSync::GraphQLApi", logicalId);
|
|
@@ -2454,7 +2403,7 @@ var GraphQLApi = class extends Resource {
|
|
|
2454
2403
|
properties() {
|
|
2455
2404
|
return {
|
|
2456
2405
|
Name: this.name,
|
|
2457
|
-
AuthenticationType:
|
|
2406
|
+
AuthenticationType: constantCase5(this.props.authenticationType || "api-key"),
|
|
2458
2407
|
AdditionalAuthenticationProviders: this.lambdaAuthProviders.map((provider) => ({
|
|
2459
2408
|
AuthenticationType: "AWS_LAMBDA",
|
|
2460
2409
|
LambdaAuthorizerConfig: {
|
|
@@ -2783,10 +2732,18 @@ var graphqlPlugin = definePlugin({
|
|
|
2783
2732
|
z14.array(LocalFileSchema).min(1)
|
|
2784
2733
|
]).optional(),
|
|
2785
2734
|
resolvers: z14.record(
|
|
2735
|
+
// TypeName
|
|
2786
2736
|
z14.string(),
|
|
2787
2737
|
z14.record(
|
|
2738
|
+
// FieldName
|
|
2788
2739
|
z14.string(),
|
|
2789
|
-
|
|
2740
|
+
z14.union([
|
|
2741
|
+
FunctionSchema,
|
|
2742
|
+
z14.object({
|
|
2743
|
+
consumer: FunctionSchema,
|
|
2744
|
+
resolver: LocalFileSchema
|
|
2745
|
+
})
|
|
2746
|
+
])
|
|
2790
2747
|
)
|
|
2791
2748
|
).optional()
|
|
2792
2749
|
})).optional()
|
|
@@ -2854,14 +2811,15 @@ var graphqlPlugin = definePlugin({
|
|
|
2854
2811
|
for (const [id, props] of Object.entries(stackConfig.graphql || {})) {
|
|
2855
2812
|
const apiId = bootstrap2.import(`graphql-${id}`);
|
|
2856
2813
|
for (const [typeName, fields] of Object.entries(props.resolvers || {})) {
|
|
2857
|
-
for (const [fieldName,
|
|
2858
|
-
const
|
|
2859
|
-
const
|
|
2814
|
+
for (const [fieldName, resolverProps] of Object.entries(fields || {})) {
|
|
2815
|
+
const props2 = isFunctionProps(resolverProps) ? { consumer: resolverProps } : resolverProps;
|
|
2816
|
+
const entryId = paramCase4(`${id}-${typeName}-${fieldName}`);
|
|
2817
|
+
const lambda = toLambdaFunction(ctx, `graphql-${entryId}`, props2.consumer);
|
|
2860
2818
|
const source = new AppsyncEventSource(entryId, lambda, {
|
|
2861
2819
|
apiId,
|
|
2862
2820
|
typeName,
|
|
2863
2821
|
fieldName,
|
|
2864
|
-
code: Code2.fromInline(entryId, defaultResolver)
|
|
2822
|
+
code: Code2.fromInline(entryId, props2.resolver || defaultResolver)
|
|
2865
2823
|
});
|
|
2866
2824
|
stack.add(lambda, source);
|
|
2867
2825
|
}
|
|
@@ -2942,6 +2900,37 @@ var RecordSetGroup = class extends Resource {
|
|
|
2942
2900
|
}
|
|
2943
2901
|
};
|
|
2944
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
|
+
|
|
2945
2934
|
// src/custom/delete-hosted-zone/handler.ts
|
|
2946
2935
|
var deleteHostedZoneRecordsHandlerCode = (
|
|
2947
2936
|
/* JS */
|
|
@@ -2951,6 +2940,8 @@ const { Route53Client, ListResourceRecordSetsCommand, ChangeResourceRecordSetsCo
|
|
|
2951
2940
|
|
|
2952
2941
|
const client = new Route53Client({})
|
|
2953
2942
|
|
|
2943
|
+
${sendCode}
|
|
2944
|
+
|
|
2954
2945
|
exports.handler = async (event) => {
|
|
2955
2946
|
const type = event.RequestType
|
|
2956
2947
|
const hostedZoneId = event.ResourceProperties.hostedZoneId
|
|
@@ -2974,29 +2965,6 @@ exports.handler = async (event) => {
|
|
|
2974
2965
|
}
|
|
2975
2966
|
}
|
|
2976
2967
|
|
|
2977
|
-
const send = async (event, id, status, data = {}, reason = '') => {
|
|
2978
|
-
const body = JSON.stringify({
|
|
2979
|
-
Status: status,
|
|
2980
|
-
Reason: reason,
|
|
2981
|
-
PhysicalResourceId: id,
|
|
2982
|
-
StackId: event.StackId,
|
|
2983
|
-
RequestId: event.RequestId,
|
|
2984
|
-
LogicalResourceId: event.LogicalResourceId,
|
|
2985
|
-
NoEcho: false,
|
|
2986
|
-
Data: data
|
|
2987
|
-
})
|
|
2988
|
-
|
|
2989
|
-
await fetch(event.ResponseURL, {
|
|
2990
|
-
method: 'PUT',
|
|
2991
|
-
port: 443,
|
|
2992
|
-
body,
|
|
2993
|
-
headers: {
|
|
2994
|
-
'content-type': '',
|
|
2995
|
-
'content-length': Buffer.from(body).byteLength,
|
|
2996
|
-
},
|
|
2997
|
-
})
|
|
2998
|
-
}
|
|
2999
|
-
|
|
3000
2968
|
const deleteHostedZoneRecords = async (hostedZoneId, records) => {
|
|
3001
2969
|
records = records.filter(record => ![ 'SOA', 'NS' ].includes(record.Type))
|
|
3002
2970
|
if(records.length === 0) {
|
|
@@ -3540,7 +3508,7 @@ var LoadBalancer = class extends Resource {
|
|
|
3540
3508
|
};
|
|
3541
3509
|
|
|
3542
3510
|
// src/formation/resource/elb/listener.ts
|
|
3543
|
-
import { constantCase as
|
|
3511
|
+
import { constantCase as constantCase6 } from "change-case";
|
|
3544
3512
|
var Listener = class extends Resource {
|
|
3545
3513
|
constructor(logicalId, props) {
|
|
3546
3514
|
super("AWS::ElasticLoadBalancingV2::Listener", logicalId);
|
|
@@ -3556,7 +3524,7 @@ var Listener = class extends Resource {
|
|
|
3556
3524
|
return {
|
|
3557
3525
|
LoadBalancerArn: this.props.loadBalancerArn,
|
|
3558
3526
|
Port: this.props.port,
|
|
3559
|
-
Protocol:
|
|
3527
|
+
Protocol: constantCase6(this.props.protocol),
|
|
3560
3528
|
Certificates: this.props.certificates.map((arn) => ({
|
|
3561
3529
|
CertificateArn: arn
|
|
3562
3530
|
})),
|
|
@@ -3995,7 +3963,7 @@ var SubnetGroup = class extends Resource {
|
|
|
3995
3963
|
};
|
|
3996
3964
|
|
|
3997
3965
|
// src/plugins/cache.ts
|
|
3998
|
-
import { constantCase as
|
|
3966
|
+
import { constantCase as constantCase7 } from "change-case";
|
|
3999
3967
|
var TypeSchema = z19.enum([
|
|
4000
3968
|
"t4g.small",
|
|
4001
3969
|
"t4g.medium",
|
|
@@ -4081,17 +4049,429 @@ var cachePlugin = definePlugin({
|
|
|
4081
4049
|
}).dependsOn(subnetGroup, securityGroup);
|
|
4082
4050
|
stack.add(subnetGroup, securityGroup, cluster);
|
|
4083
4051
|
bind((lambda) => {
|
|
4084
|
-
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"
|
|
4085
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
|
+
}
|
|
4086
4318
|
}
|
|
4087
4319
|
}
|
|
4088
4320
|
});
|
|
4089
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
|
+
}
|
|
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
|
+
});
|
|
4466
|
+
}
|
|
4467
|
+
});
|
|
4468
|
+
|
|
4090
4469
|
// src/plugins/index.ts
|
|
4091
4470
|
var defaultPlugins = [
|
|
4092
4471
|
extendPlugin,
|
|
4093
4472
|
vpcPlugin,
|
|
4094
4473
|
functionPlugin,
|
|
4474
|
+
configPlugin,
|
|
4095
4475
|
cachePlugin,
|
|
4096
4476
|
cronPlugin,
|
|
4097
4477
|
queuePlugin,
|
|
@@ -4103,6 +4483,7 @@ var defaultPlugins = [
|
|
|
4103
4483
|
domainPlugin,
|
|
4104
4484
|
graphqlPlugin,
|
|
4105
4485
|
httpPlugin,
|
|
4486
|
+
restPlugin,
|
|
4106
4487
|
onFailurePlugin
|
|
4107
4488
|
];
|
|
4108
4489
|
|
|
@@ -4140,6 +4521,8 @@ var globalExportsHandlerCode = (
|
|
|
4140
4521
|
|
|
4141
4522
|
const { CloudFormationClient, ListExportsCommand } = require('@aws-sdk/client-cloudformation')
|
|
4142
4523
|
|
|
4524
|
+
${sendCode}
|
|
4525
|
+
|
|
4143
4526
|
exports.handler = async (event) => {
|
|
4144
4527
|
const region = event.ResourceProperties.region
|
|
4145
4528
|
|
|
@@ -4156,29 +4539,6 @@ exports.handler = async (event) => {
|
|
|
4156
4539
|
}
|
|
4157
4540
|
}
|
|
4158
4541
|
|
|
4159
|
-
const send = async (event, id, status, data, reason = '') => {
|
|
4160
|
-
const body = JSON.stringify({
|
|
4161
|
-
Status: status,
|
|
4162
|
-
Reason: reason,
|
|
4163
|
-
PhysicalResourceId: id,
|
|
4164
|
-
StackId: event.StackId,
|
|
4165
|
-
RequestId: event.RequestId,
|
|
4166
|
-
LogicalResourceId: event.LogicalResourceId,
|
|
4167
|
-
NoEcho: false,
|
|
4168
|
-
Data: data
|
|
4169
|
-
})
|
|
4170
|
-
|
|
4171
|
-
await fetch(event.ResponseURL, {
|
|
4172
|
-
method: 'PUT',
|
|
4173
|
-
port: 443,
|
|
4174
|
-
body,
|
|
4175
|
-
headers: {
|
|
4176
|
-
'content-type': '',
|
|
4177
|
-
'content-length': Buffer.from(body).byteLength,
|
|
4178
|
-
},
|
|
4179
|
-
})
|
|
4180
|
-
}
|
|
4181
|
-
|
|
4182
4542
|
const listExports = async (region) => {
|
|
4183
4543
|
const client = new CloudFormationClient({ region })
|
|
4184
4544
|
const data = {}
|
|
@@ -4356,17 +4716,17 @@ var getCredentials = (profile) => {
|
|
|
4356
4716
|
};
|
|
4357
4717
|
|
|
4358
4718
|
// src/schema/app.ts
|
|
4359
|
-
import { z as
|
|
4719
|
+
import { z as z26 } from "zod";
|
|
4360
4720
|
|
|
4361
4721
|
// src/schema/stack.ts
|
|
4362
|
-
import { z as
|
|
4363
|
-
var StackSchema =
|
|
4722
|
+
import { z as z23 } from "zod";
|
|
4723
|
+
var StackSchema = z23.object({
|
|
4364
4724
|
name: ResourceIdSchema,
|
|
4365
|
-
depends:
|
|
4725
|
+
depends: z23.array(z23.lazy(() => StackSchema)).optional()
|
|
4366
4726
|
});
|
|
4367
4727
|
|
|
4368
4728
|
// src/schema/region.ts
|
|
4369
|
-
import { z as
|
|
4729
|
+
import { z as z24 } from "zod";
|
|
4370
4730
|
var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
|
|
4371
4731
|
var AF = ["af-south-1"];
|
|
4372
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"];
|
|
@@ -4383,41 +4743,41 @@ var regions = [
|
|
|
4383
4743
|
...ME,
|
|
4384
4744
|
...SA
|
|
4385
4745
|
];
|
|
4386
|
-
var RegionSchema =
|
|
4746
|
+
var RegionSchema = z24.enum(regions);
|
|
4387
4747
|
|
|
4388
4748
|
// src/schema/plugin.ts
|
|
4389
|
-
import { z as
|
|
4390
|
-
var PluginSchema =
|
|
4391
|
-
name:
|
|
4392
|
-
schema:
|
|
4749
|
+
import { z as z25 } from "zod";
|
|
4750
|
+
var PluginSchema = z25.object({
|
|
4751
|
+
name: z25.string(),
|
|
4752
|
+
schema: z25.custom().optional(),
|
|
4393
4753
|
// depends: z.array(z.lazy(() => PluginSchema)).optional(),
|
|
4394
|
-
onApp:
|
|
4395
|
-
onStack:
|
|
4396
|
-
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()
|
|
4397
4757
|
// bind: z.function().optional(),
|
|
4398
4758
|
});
|
|
4399
4759
|
|
|
4400
4760
|
// src/schema/app.ts
|
|
4401
|
-
var AppSchema =
|
|
4761
|
+
var AppSchema = z26.object({
|
|
4402
4762
|
/** App name */
|
|
4403
4763
|
name: ResourceIdSchema,
|
|
4404
4764
|
/** The AWS region to deploy to. */
|
|
4405
4765
|
region: RegionSchema,
|
|
4406
4766
|
/** The AWS profile to deploy to. */
|
|
4407
|
-
profile:
|
|
4767
|
+
profile: z26.string(),
|
|
4408
4768
|
/** The deployment stage.
|
|
4409
4769
|
* @default 'prod'
|
|
4410
4770
|
*/
|
|
4411
|
-
stage:
|
|
4771
|
+
stage: z26.string().regex(/^[a-z]+$/).default("prod"),
|
|
4412
4772
|
/** Default properties. */
|
|
4413
|
-
defaults:
|
|
4773
|
+
defaults: z26.object({}).default({}),
|
|
4414
4774
|
/** The application stacks. */
|
|
4415
|
-
stacks:
|
|
4775
|
+
stacks: z26.array(StackSchema).min(1).refine((stacks) => {
|
|
4416
4776
|
const unique = new Set(stacks.map((stack) => stack.name));
|
|
4417
4777
|
return unique.size === stacks.length;
|
|
4418
4778
|
}, "Must be an array of unique stacks"),
|
|
4419
4779
|
/** Custom plugins. */
|
|
4420
|
-
plugins:
|
|
4780
|
+
plugins: z26.array(PluginSchema).optional()
|
|
4421
4781
|
});
|
|
4422
4782
|
|
|
4423
4783
|
// src/util/import.ts
|
|
@@ -4514,7 +4874,7 @@ var watchFile = (path) => {
|
|
|
4514
4874
|
};
|
|
4515
4875
|
|
|
4516
4876
|
// src/config.ts
|
|
4517
|
-
import { z as
|
|
4877
|
+
import { z as z27 } from "zod";
|
|
4518
4878
|
var ConfigError = class extends Error {
|
|
4519
4879
|
constructor(error, data) {
|
|
4520
4880
|
super(error.message);
|
|
@@ -4547,7 +4907,7 @@ var importConfig = async (options) => {
|
|
|
4547
4907
|
try {
|
|
4548
4908
|
config = await schema2.parseAsync(appConfig);
|
|
4549
4909
|
} catch (error) {
|
|
4550
|
-
if (error instanceof
|
|
4910
|
+
if (error instanceof z27.ZodError) {
|
|
4551
4911
|
throw new ConfigError(error, appConfig);
|
|
4552
4912
|
}
|
|
4553
4913
|
throw error;
|
|
@@ -4588,7 +4948,7 @@ var watchConfig = async function* (options) {
|
|
|
4588
4948
|
try {
|
|
4589
4949
|
config = await schema2.parseAsync(appConfig);
|
|
4590
4950
|
} catch (error) {
|
|
4591
|
-
if (error instanceof
|
|
4951
|
+
if (error instanceof z27.ZodError) {
|
|
4592
4952
|
throw new ConfigError(error, appConfig);
|
|
4593
4953
|
}
|
|
4594
4954
|
throw error;
|
|
@@ -5363,7 +5723,7 @@ var shouldDeployBootstrap = async (client, stack) => {
|
|
|
5363
5723
|
// src/formation/client.ts
|
|
5364
5724
|
import { CloudFormationClient, CreateStackCommand, DeleteStackCommand, DescribeStackEventsCommand, DescribeStacksCommand, GetTemplateCommand, OnFailure, TemplateStage, UpdateStackCommand, ValidateTemplateCommand, waitUntilStackCreateComplete, waitUntilStackDeleteComplete, waitUntilStackUpdateComplete } from "@aws-sdk/client-cloudformation";
|
|
5365
5725
|
import { S3Client, PutObjectCommand, ObjectCannedACL, StorageClass } from "@aws-sdk/client-s3";
|
|
5366
|
-
import { paramCase as
|
|
5726
|
+
import { paramCase as paramCase6 } from "change-case";
|
|
5367
5727
|
var StackClient = class {
|
|
5368
5728
|
constructor(app, account, region, credentials) {
|
|
5369
5729
|
this.app = app;
|
|
@@ -5396,7 +5756,7 @@ var StackClient = class {
|
|
|
5396
5756
|
};
|
|
5397
5757
|
}
|
|
5398
5758
|
stackName(stackName) {
|
|
5399
|
-
return
|
|
5759
|
+
return paramCase6(`${this.app.name}-${stackName}`);
|
|
5400
5760
|
}
|
|
5401
5761
|
tags(stack) {
|
|
5402
5762
|
const tags = [];
|
|
@@ -5409,7 +5769,8 @@ var StackClient = class {
|
|
|
5409
5769
|
debug("Upload the", style.info(stack.name), "stack to awsless assets bucket");
|
|
5410
5770
|
const client = new S3Client({
|
|
5411
5771
|
credentials: this.credentials,
|
|
5412
|
-
region: stack.region
|
|
5772
|
+
region: stack.region,
|
|
5773
|
+
maxAttempts: 5
|
|
5413
5774
|
});
|
|
5414
5775
|
await client.send(new PutObjectCommand({
|
|
5415
5776
|
Bucket: this.assetBucketName,
|
|
@@ -5829,7 +6190,8 @@ import { GetObjectCommand, ObjectCannedACL as ObjectCannedACL2, PutObjectCommand
|
|
|
5829
6190
|
var assetPublisher = (config, app) => {
|
|
5830
6191
|
const client = new S3Client2({
|
|
5831
6192
|
credentials: config.credentials,
|
|
5832
|
-
region: config.region
|
|
6193
|
+
region: config.region,
|
|
6194
|
+
maxAttempts: 5
|
|
5833
6195
|
});
|
|
5834
6196
|
return async (term) => {
|
|
5835
6197
|
const done = term.out.write(loadingDialog("Publishing stack assets to AWS..."));
|