@awsless/cli 0.0.46-next.0 → 0.0.46-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.json +1 -1
- package/dist/app.stage.json +1 -1
- package/dist/bin.js +254 -50
- package/dist/build-json-schema.js +16 -0
- package/dist/handlers/bundle.mjs +2 -138
- package/dist/handlers/on-failure.mjs +86 -8
- package/package.json +8 -8
package/dist/bin.js
CHANGED
|
@@ -528,6 +528,8 @@ import {
|
|
|
528
528
|
CreateAliasCommand as CreateAliasCommand2,
|
|
529
529
|
CreateFunctionUrlConfigCommand,
|
|
530
530
|
GetFunctionUrlConfigCommand,
|
|
531
|
+
RemovePermissionCommand,
|
|
532
|
+
UpdateFunctionUrlConfigCommand,
|
|
531
533
|
LambdaClient as LambdaClient2,
|
|
532
534
|
PutFunctionEventInvokeConfigCommand
|
|
533
535
|
} from "@aws-sdk/client-lambda";
|
|
@@ -559,7 +561,8 @@ var createLambdaProvider = ({ credentials, region }) => {
|
|
|
559
561
|
deploymentId: z2.string(),
|
|
560
562
|
functionName: z2.string(),
|
|
561
563
|
functionVersion: z2.string(),
|
|
562
|
-
onFailureArn: z2.string()
|
|
564
|
+
onFailureArn: z2.string(),
|
|
565
|
+
sourceAccount: z2.string().optional()
|
|
563
566
|
});
|
|
564
567
|
const bundleDeploymentStateSchema = bundleDeploymentInputSchema.extend({
|
|
565
568
|
deploymentAlias: z2.string(),
|
|
@@ -596,14 +599,15 @@ var createLambdaProvider = ({ credentials, region }) => {
|
|
|
596
599
|
})
|
|
597
600
|
);
|
|
598
601
|
};
|
|
599
|
-
const
|
|
602
|
+
const createDeploymentUrl = async (functionName, alias, sourceAccount) => {
|
|
603
|
+
const authType = sourceAccount ? "AWS_IAM" : "NONE";
|
|
600
604
|
let url;
|
|
601
605
|
try {
|
|
602
606
|
const result = await lambda.send(
|
|
603
607
|
new CreateFunctionUrlConfigCommand({
|
|
604
608
|
FunctionName: functionName,
|
|
605
609
|
Qualifier: alias,
|
|
606
|
-
AuthType:
|
|
610
|
+
AuthType: authType
|
|
607
611
|
})
|
|
608
612
|
);
|
|
609
613
|
url = result.FunctionUrl;
|
|
@@ -612,21 +616,39 @@ var createLambdaProvider = ({ credentials, region }) => {
|
|
|
612
616
|
throw error;
|
|
613
617
|
}
|
|
614
618
|
const result = await lambda.send(
|
|
615
|
-
new
|
|
619
|
+
new UpdateFunctionUrlConfigCommand({
|
|
616
620
|
FunctionName: functionName,
|
|
617
|
-
Qualifier: alias
|
|
621
|
+
Qualifier: alias,
|
|
622
|
+
AuthType: authType
|
|
618
623
|
})
|
|
619
624
|
);
|
|
620
625
|
url = result.FunctionUrl;
|
|
621
626
|
}
|
|
622
|
-
const permissions = [
|
|
627
|
+
const permissions = sourceAccount ? [
|
|
628
|
+
{
|
|
629
|
+
StatementId: "cloudfront-url",
|
|
630
|
+
Principal: "cloudfront.amazonaws.com",
|
|
631
|
+
SourceAccount: sourceAccount,
|
|
632
|
+
Action: "lambda:InvokeFunctionUrl",
|
|
633
|
+
FunctionUrlAuthType: "AWS_IAM"
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
StatementId: "cloudfront-invoke",
|
|
637
|
+
Principal: "cloudfront.amazonaws.com",
|
|
638
|
+
SourceAccount: sourceAccount,
|
|
639
|
+
Action: "lambda:InvokeFunction",
|
|
640
|
+
InvokedViaFunctionUrl: true
|
|
641
|
+
}
|
|
642
|
+
] : [
|
|
623
643
|
{
|
|
624
644
|
StatementId: "public-url",
|
|
645
|
+
Principal: "*",
|
|
625
646
|
Action: "lambda:InvokeFunctionUrl",
|
|
626
647
|
FunctionUrlAuthType: "NONE"
|
|
627
648
|
},
|
|
628
649
|
{
|
|
629
650
|
StatementId: "public-invoke",
|
|
651
|
+
Principal: "*",
|
|
630
652
|
Action: "lambda:InvokeFunction",
|
|
631
653
|
InvokedViaFunctionUrl: true
|
|
632
654
|
}
|
|
@@ -637,7 +659,6 @@ var createLambdaProvider = ({ credentials, region }) => {
|
|
|
637
659
|
new AddPermissionCommand({
|
|
638
660
|
FunctionName: functionName,
|
|
639
661
|
Qualifier: alias,
|
|
640
|
-
Principal: "*",
|
|
641
662
|
...permission
|
|
642
663
|
})
|
|
643
664
|
);
|
|
@@ -647,6 +668,23 @@ var createLambdaProvider = ({ credentials, region }) => {
|
|
|
647
668
|
}
|
|
648
669
|
}
|
|
649
670
|
}
|
|
671
|
+
if (sourceAccount) {
|
|
672
|
+
for (const statementId of ["public-url", "public-invoke"]) {
|
|
673
|
+
try {
|
|
674
|
+
await lambda.send(
|
|
675
|
+
new RemovePermissionCommand({
|
|
676
|
+
FunctionName: functionName,
|
|
677
|
+
Qualifier: alias,
|
|
678
|
+
StatementId: statementId
|
|
679
|
+
})
|
|
680
|
+
);
|
|
681
|
+
} catch (error) {
|
|
682
|
+
if (!isError(error, "ResourceNotFoundException")) {
|
|
683
|
+
throw error;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
650
688
|
return url;
|
|
651
689
|
};
|
|
652
690
|
const createBundleDeployment = async (state2) => {
|
|
@@ -658,7 +696,7 @@ var createLambdaProvider = ({ credentials, region }) => {
|
|
|
658
696
|
name: deploymentAlias
|
|
659
697
|
});
|
|
660
698
|
await configureVersion(state2);
|
|
661
|
-
const url = await
|
|
699
|
+
const url = await createDeploymentUrl(state2.functionName, deploymentAlias, state2.sourceAccount);
|
|
662
700
|
return {
|
|
663
701
|
...state2,
|
|
664
702
|
deploymentAlias,
|
|
@@ -769,7 +807,20 @@ var createLambdaProvider = ({ credentials, region }) => {
|
|
|
769
807
|
deploymentAliases.push(deploymentAlias);
|
|
770
808
|
}
|
|
771
809
|
await configureVersion(proposed);
|
|
772
|
-
const url = await
|
|
810
|
+
const url = await createDeploymentUrl(proposed.functionName, deploymentAlias, proposed.sourceAccount);
|
|
811
|
+
if (proposed.sourceAccount && prior.sourceAccount !== proposed.sourceAccount) {
|
|
812
|
+
await Promise.all(
|
|
813
|
+
deploymentAliases.filter((name) => name !== deploymentAlias).map(
|
|
814
|
+
(name) => createDeploymentUrl(proposed.functionName, name, proposed.sourceAccount).catch(
|
|
815
|
+
(error) => {
|
|
816
|
+
if (!isError(error, "ResourceNotFoundException")) {
|
|
817
|
+
throw error;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
)
|
|
821
|
+
)
|
|
822
|
+
);
|
|
823
|
+
}
|
|
773
824
|
return {
|
|
774
825
|
...proposed,
|
|
775
826
|
deploymentAlias,
|
|
@@ -1276,20 +1327,16 @@ var readDeployedFunctionVersion = (state2) => {
|
|
|
1276
1327
|
};
|
|
1277
1328
|
var formatDeploymentSummary = (props) => {
|
|
1278
1329
|
let previewUrl;
|
|
1279
|
-
let lambdaUrl;
|
|
1280
1330
|
for (const [urn, node] of readStateNodes(props.state)) {
|
|
1281
1331
|
if (node.type === "aws_cloudfront_distribution" && urn.endsWith(":{preview}")) {
|
|
1282
1332
|
previewUrl = `https://${node.output.domainName}`;
|
|
1283
1333
|
}
|
|
1284
|
-
if (node.type === "bundle-deployment") {
|
|
1285
|
-
lambdaUrl = node.output.url;
|
|
1286
|
-
}
|
|
1287
1334
|
}
|
|
1288
1335
|
return Object.keys(props.appConfig.defaults.router ?? {}).map((routerId, index) => {
|
|
1289
1336
|
return [
|
|
1290
1337
|
`${routerId}: deployment #${props.id}`,
|
|
1291
1338
|
index === 0 ? previewUrl : void 0,
|
|
1292
|
-
index === 0 ?
|
|
1339
|
+
index === 0 && previewUrl ? `${previewUrl}/?awsless-deployment=${props.id}` : void 0
|
|
1293
1340
|
].filter(Boolean).join("\n");
|
|
1294
1341
|
});
|
|
1295
1342
|
};
|
|
@@ -1418,6 +1465,9 @@ var activateDeployment = async (props) => {
|
|
|
1418
1465
|
});
|
|
1419
1466
|
return id;
|
|
1420
1467
|
};
|
|
1468
|
+
var promoteAppDeployment = (props) => {
|
|
1469
|
+
return activateDeployment({ ...props, rejectStale: true });
|
|
1470
|
+
};
|
|
1421
1471
|
var rollbackAppDeployment = (props) => {
|
|
1422
1472
|
return withAppReleaseLock(props.appConfig, () => activateDeployment(props));
|
|
1423
1473
|
};
|
|
@@ -2153,6 +2203,7 @@ var RouterDefaultSchema = z20.record(
|
|
|
2153
2203
|
z20.object({
|
|
2154
2204
|
domain: ResourceIdSchema.describe("The domain id to link your Router.").optional(),
|
|
2155
2205
|
subDomain: z20.string().optional(),
|
|
2206
|
+
redirectWww: z20.boolean().default(false).describe("Redirect all www subdomain requests to your root domain."),
|
|
2156
2207
|
waf: WafSettingsSchema.optional(),
|
|
2157
2208
|
geoRestrictions: z20.array(z20.string().length(2).toUpperCase()).default([]).describe("Specifies a blacklist of countries that should be blocked."),
|
|
2158
2209
|
errors: z20.object({
|
|
@@ -2241,6 +2292,21 @@ var RouterDefaultSchema = z20.record(
|
|
|
2241
2292
|
}).optional().describe(
|
|
2242
2293
|
"Specifies the cookies, headers, and query values that CloudFront includes in the cache key."
|
|
2243
2294
|
)
|
|
2295
|
+
}).superRefine((props, ctx) => {
|
|
2296
|
+
if (props.redirectWww && !props.domain) {
|
|
2297
|
+
ctx.addIssue({
|
|
2298
|
+
code: z20.ZodIssueCode.custom,
|
|
2299
|
+
path: ["redirectWww"],
|
|
2300
|
+
message: "The redirectWww option requires a domain to be set."
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
if (props.redirectWww && props.subDomain) {
|
|
2304
|
+
ctx.addIssue({
|
|
2305
|
+
code: z20.ZodIssueCode.custom,
|
|
2306
|
+
path: ["redirectWww"],
|
|
2307
|
+
message: `The redirectWww option can't be combined with a subDomain, because the domain certificate only covers single level subdomains.`
|
|
2308
|
+
});
|
|
2309
|
+
}
|
|
2244
2310
|
})
|
|
2245
2311
|
).optional().describe(`Define the global Router. Backed by AWS CloudFront.`);
|
|
2246
2312
|
|
|
@@ -3824,7 +3890,6 @@ var bundleTypeScriptWithRolldown = async ({
|
|
|
3824
3890
|
format: format3 = "esm",
|
|
3825
3891
|
minify = true,
|
|
3826
3892
|
file,
|
|
3827
|
-
nativeDir,
|
|
3828
3893
|
external,
|
|
3829
3894
|
importAsString: importAsStringList
|
|
3830
3895
|
}) => {
|
|
@@ -3835,7 +3900,25 @@ var bundleTypeScriptWithRolldown = async ({
|
|
|
3835
3900
|
return importee.startsWith("@aws-sdk") || importee.startsWith("aws-sdk") || external?.includes(importee);
|
|
3836
3901
|
},
|
|
3837
3902
|
treeshake: {
|
|
3838
|
-
|
|
3903
|
+
// The @awsless packages are pure clients, but their entry points
|
|
3904
|
+
// also export test helpers that pull in local server
|
|
3905
|
+
// implementations like dynamo-db-local, which crash the ESM
|
|
3906
|
+
// runtime with CJS globals like __dirname. Treating the scope as
|
|
3907
|
+
// side-effect free prunes those unused chains from production
|
|
3908
|
+
// bundles, while every other dependency keeps its import side
|
|
3909
|
+
// effects, like the fs patching of graceful-fs.
|
|
3910
|
+
moduleSideEffects: (id, isExternal) => {
|
|
3911
|
+
if (isExternal) {
|
|
3912
|
+
return external?.includes(id) === true;
|
|
3913
|
+
}
|
|
3914
|
+
if (id.includes("/node_modules/@awsless/")) {
|
|
3915
|
+
return false;
|
|
3916
|
+
}
|
|
3917
|
+
if (id.includes("/node_modules/")) {
|
|
3918
|
+
return true;
|
|
3919
|
+
}
|
|
3920
|
+
return id.startsWith(`${directories.root}/`);
|
|
3921
|
+
}
|
|
3839
3922
|
},
|
|
3840
3923
|
onwarn: (error) => {
|
|
3841
3924
|
debugError(error.message);
|
|
@@ -3882,6 +3965,7 @@ var bundleTypeScriptWithRolldown = async ({
|
|
|
3882
3965
|
chunkFileNames: `[name].${ext}`,
|
|
3883
3966
|
minify
|
|
3884
3967
|
});
|
|
3968
|
+
assertNoTestOnlyModules(result.output);
|
|
3885
3969
|
const hash = createHash4("sha1");
|
|
3886
3970
|
const files = [];
|
|
3887
3971
|
for (const item of result.output) {
|
|
@@ -3903,6 +3987,22 @@ var bundleTypeScriptWithRolldown = async ({
|
|
|
3903
3987
|
files
|
|
3904
3988
|
};
|
|
3905
3989
|
};
|
|
3990
|
+
var TEST_ONLY_MODULES = ["dynamo-db-local", "@awsless/dynamodb-server", "redis-memory-server"];
|
|
3991
|
+
var assertNoTestOnlyModules = (output) => {
|
|
3992
|
+
for (const item of output) {
|
|
3993
|
+
if (item.type !== "chunk") {
|
|
3994
|
+
continue;
|
|
3995
|
+
}
|
|
3996
|
+
for (const id of item.moduleIds ?? []) {
|
|
3997
|
+
const found = TEST_ONLY_MODULES.find((name) => id.includes(`/node_modules/${name}/`));
|
|
3998
|
+
if (found) {
|
|
3999
|
+
throw new Error(
|
|
4000
|
+
`The test-only package "${found}" was bundled into a production build through "${id}". Remove the import from the handler, or keep the package tree-shakeable.`
|
|
4001
|
+
);
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
}
|
|
4005
|
+
};
|
|
3906
4006
|
|
|
3907
4007
|
// src/feature/bundle/util.ts
|
|
3908
4008
|
var ROUTE_HEADER = "x-awsless-route";
|
|
@@ -4188,7 +4288,8 @@ var bundleFeature = defineFeature({
|
|
|
4188
4288
|
deploymentId: ctx.deploymentId ?? "local-0",
|
|
4189
4289
|
functionName: lambda.functionName,
|
|
4190
4290
|
functionVersion: lambda.version,
|
|
4191
|
-
onFailureArn: onFailure
|
|
4291
|
+
onFailureArn: onFailure,
|
|
4292
|
+
sourceAccount: ctx.accountId
|
|
4192
4293
|
},
|
|
4193
4294
|
{
|
|
4194
4295
|
// Make sure the permissions are in place before any event source is wired up.
|
|
@@ -4329,6 +4430,7 @@ var cacheFeature = defineFeature({
|
|
|
4329
4430
|
{
|
|
4330
4431
|
name,
|
|
4331
4432
|
engine: "valkey",
|
|
4433
|
+
networkType: "dual_stack",
|
|
4332
4434
|
dailySnapshotTime: "02:00",
|
|
4333
4435
|
majorEngineVersion: "8",
|
|
4334
4436
|
snapshotRetentionLimit: props.snapshotRetentionLimit,
|
|
@@ -4354,7 +4456,9 @@ var cacheFeature = defineFeature({
|
|
|
4354
4456
|
},
|
|
4355
4457
|
{
|
|
4356
4458
|
retainOnDelete: ctx.appConfig.removal === "retain",
|
|
4357
|
-
import: ctx.import ? name : void 0
|
|
4459
|
+
import: ctx.import ? name : void 0,
|
|
4460
|
+
// The network type can only be set at creation time.
|
|
4461
|
+
replaceOnChanges: ["networkType"]
|
|
4358
4462
|
}
|
|
4359
4463
|
);
|
|
4360
4464
|
const masterHost = cache.endpoint.pipe((v) => v.at(0).address);
|
|
@@ -5893,12 +5997,15 @@ var pubsubFeature = defineFeature({
|
|
|
5893
5997
|
{
|
|
5894
5998
|
name: cacheName,
|
|
5895
5999
|
engine: "valkey",
|
|
6000
|
+
networkType: "dual_stack",
|
|
5896
6001
|
majorEngineVersion: "8",
|
|
5897
6002
|
securityGroupIds: [cacheSecurityGroup.id],
|
|
5898
6003
|
subnetIds: ctx.shared.get("vpc", "private-subnets")
|
|
5899
6004
|
},
|
|
5900
6005
|
{
|
|
5901
|
-
import: ctx.import ? cacheName : void 0
|
|
6006
|
+
import: ctx.import ? cacheName : void 0,
|
|
6007
|
+
// The network type can only be set at creation time.
|
|
6008
|
+
replaceOnChanges: ["networkType"]
|
|
5902
6009
|
}
|
|
5903
6010
|
);
|
|
5904
6011
|
const redisHost = cache.endpoint.pipe((v) => v.at(0).address);
|
|
@@ -6484,7 +6591,7 @@ var searchFeature = defineFeature({
|
|
|
6484
6591
|
{
|
|
6485
6592
|
domainName: name,
|
|
6486
6593
|
engineVersion: `OpenSearch_${props.version}`,
|
|
6487
|
-
ipAddressType: "
|
|
6594
|
+
ipAddressType: "dualstack",
|
|
6488
6595
|
clusterConfig: {
|
|
6489
6596
|
instanceType: `${props.type}.search`,
|
|
6490
6597
|
instanceCount: props.count
|
|
@@ -6539,7 +6646,7 @@ var searchFeature = defineFeature({
|
|
|
6539
6646
|
import: ctx.import ? name : void 0
|
|
6540
6647
|
}
|
|
6541
6648
|
);
|
|
6542
|
-
ctx.addEnv(`SEARCH_${constantCase8(ctx.stack.name)}_${constantCase8(id)}_DOMAIN`, openSearch.
|
|
6649
|
+
ctx.addEnv(`SEARCH_${constantCase8(ctx.stack.name)}_${constantCase8(id)}_DOMAIN`, openSearch.endpointV2);
|
|
6543
6650
|
ctx.addStackPermission({
|
|
6544
6651
|
actions: ["es:ESHttp*"],
|
|
6545
6652
|
resources: [
|
|
@@ -9083,6 +9190,7 @@ var getViewerRequestFunctionCode = (props) => {
|
|
|
9083
9190
|
return CODE(
|
|
9084
9191
|
[
|
|
9085
9192
|
props.blockDirectAccess ? BLOCK_DIRECT_ACCESS_TO_CLOUDFRONT : "",
|
|
9193
|
+
props.redirectWww ? REDIRECT_WWW : "",
|
|
9086
9194
|
props.passwordAuth ?? props.basicAuth ? AUTH_WRAPPER(
|
|
9087
9195
|
[
|
|
9088
9196
|
//
|
|
@@ -9091,7 +9199,7 @@ var getViewerRequestFunctionCode = (props) => {
|
|
|
9091
9199
|
].join("\n")
|
|
9092
9200
|
) : ""
|
|
9093
9201
|
],
|
|
9094
|
-
ACTIVE_PREFIX(props.router)
|
|
9202
|
+
props.preview ? PREVIEW_PREFIX(props.router) : ACTIVE_PREFIX(props.router)
|
|
9095
9203
|
);
|
|
9096
9204
|
};
|
|
9097
9205
|
var BLOCK_DIRECT_ACCESS_TO_CLOUDFRONT = `
|
|
@@ -9101,6 +9209,38 @@ if (headers.host && headers.host.value.includes('cloudfront.net')) {
|
|
|
9101
9209
|
statusDescription: 'Forbidden'
|
|
9102
9210
|
};
|
|
9103
9211
|
}`;
|
|
9212
|
+
var REDIRECT_WWW = `
|
|
9213
|
+
if (headers.host && headers.host.value.startsWith('www.')) {
|
|
9214
|
+
let location = 'https://' + headers.host.value.slice(4) + request.uri;
|
|
9215
|
+
const query = [];
|
|
9216
|
+
|
|
9217
|
+
for(const key in request.querystring) {
|
|
9218
|
+
const item = request.querystring[key];
|
|
9219
|
+
|
|
9220
|
+
if(item.multiValue) {
|
|
9221
|
+
for(const i in item.multiValue) {
|
|
9222
|
+
query.push(key + '=' + item.multiValue[i].value);
|
|
9223
|
+
}
|
|
9224
|
+
} else if(item.value === '') {
|
|
9225
|
+
query.push(key);
|
|
9226
|
+
} else {
|
|
9227
|
+
query.push(key + '=' + item.value);
|
|
9228
|
+
}
|
|
9229
|
+
}
|
|
9230
|
+
|
|
9231
|
+
if(query.length > 0) {
|
|
9232
|
+
location += '?' + query.join('&');
|
|
9233
|
+
}
|
|
9234
|
+
|
|
9235
|
+
return {
|
|
9236
|
+
statusCode: 301,
|
|
9237
|
+
statusDescription: 'Moved Permanently',
|
|
9238
|
+
headers: {
|
|
9239
|
+
'location': { value: location },
|
|
9240
|
+
'strict-transport-security': { value: 'max-age=31536000; includeSubdomains; preload' }
|
|
9241
|
+
}
|
|
9242
|
+
};
|
|
9243
|
+
}`;
|
|
9104
9244
|
var BASIC_AUTH_CHECK = (username, password) => `
|
|
9105
9245
|
authMethods.push('Basic realm="Protected"');
|
|
9106
9246
|
|
|
@@ -9119,6 +9259,58 @@ if(!isAuthorized) {
|
|
|
9119
9259
|
}
|
|
9120
9260
|
}
|
|
9121
9261
|
`;
|
|
9262
|
+
var PREVIEW_PREFIX = (router) => `
|
|
9263
|
+
const router = ${JSON.stringify(router)};
|
|
9264
|
+
let deployment;
|
|
9265
|
+
|
|
9266
|
+
if (request.querystring['awsless-deployment'] && request.querystring['awsless-deployment'].value) {
|
|
9267
|
+
deployment = request.querystring['awsless-deployment'].value;
|
|
9268
|
+
} else if (request.cookies && request.cookies['awsless-deployment'] && request.cookies['awsless-deployment'].value) {
|
|
9269
|
+
deployment = request.cookies['awsless-deployment'].value;
|
|
9270
|
+
}
|
|
9271
|
+
|
|
9272
|
+
let prefix;
|
|
9273
|
+
|
|
9274
|
+
try {
|
|
9275
|
+
const pointer = deployment ? '$deploy:' + deployment : '$active';
|
|
9276
|
+
prefix = (await cf.kvs().get(pointer)).split(':')[0] + ':' + router + ':';
|
|
9277
|
+
} catch (e) {
|
|
9278
|
+
return deployment
|
|
9279
|
+
? { statusCode: 404, statusDescription: 'Unknown Deployment' }
|
|
9280
|
+
: { statusCode: 503, statusDescription: 'Service Unavailable' };
|
|
9281
|
+
}
|
|
9282
|
+
|
|
9283
|
+
if (request.querystring['awsless-deployment']) {
|
|
9284
|
+
delete request.querystring['awsless-deployment'];
|
|
9285
|
+
|
|
9286
|
+
const query = [];
|
|
9287
|
+
|
|
9288
|
+
for (const key in request.querystring) {
|
|
9289
|
+
const entry = request.querystring[key];
|
|
9290
|
+
|
|
9291
|
+
if (entry.multiValue) {
|
|
9292
|
+
for (const item of entry.multiValue) {
|
|
9293
|
+
query.push(key + '=' + item.value);
|
|
9294
|
+
}
|
|
9295
|
+
} else {
|
|
9296
|
+
query.push(key + '=' + entry.value);
|
|
9297
|
+
}
|
|
9298
|
+
}
|
|
9299
|
+
|
|
9300
|
+
return {
|
|
9301
|
+
statusCode: 302,
|
|
9302
|
+
statusDescription: 'Found',
|
|
9303
|
+
headers: {
|
|
9304
|
+
location: { value: request.uri + (query.length ? '?' + query.join('&') : '') }
|
|
9305
|
+
},
|
|
9306
|
+
cookies: {
|
|
9307
|
+
'awsless-deployment': {
|
|
9308
|
+
value: deployment,
|
|
9309
|
+
attributes: 'Path=/; Secure; SameSite=Lax'
|
|
9310
|
+
}
|
|
9311
|
+
}
|
|
9312
|
+
};
|
|
9313
|
+
}`;
|
|
9122
9314
|
var ACTIVE_PREFIX = (router) => `
|
|
9123
9315
|
const router = ${JSON.stringify(router)};
|
|
9124
9316
|
let prefix;
|
|
@@ -9416,6 +9608,7 @@ var routerFeature = defineFeature({
|
|
|
9416
9608
|
code: getViewerRequestFunctionCode({
|
|
9417
9609
|
router: id,
|
|
9418
9610
|
blockDirectAccess: !!props.domain,
|
|
9611
|
+
redirectWww: !!props.domain && props.redirectWww,
|
|
9419
9612
|
basicAuth: props.basicAuth,
|
|
9420
9613
|
passwordAuth: props.passwordAuth
|
|
9421
9614
|
}),
|
|
@@ -9734,6 +9927,7 @@ var routerFeature = defineFeature({
|
|
|
9734
9927
|
runtime: "cloudfront-js-2.0",
|
|
9735
9928
|
code: getViewerRequestFunctionCode({
|
|
9736
9929
|
router: id,
|
|
9930
|
+
preview: true,
|
|
9737
9931
|
basicAuth: props.basicAuth,
|
|
9738
9932
|
passwordAuth: props.passwordAuth
|
|
9739
9933
|
}),
|
|
@@ -9746,6 +9940,7 @@ var routerFeature = defineFeature({
|
|
|
9746
9940
|
},
|
|
9747
9941
|
comment: `${name} preview`,
|
|
9748
9942
|
enabled: true,
|
|
9943
|
+
isIpv6Enabled: true,
|
|
9749
9944
|
waitForDeployment: true,
|
|
9750
9945
|
origin: [
|
|
9751
9946
|
{
|
|
@@ -9841,22 +10036,6 @@ var routerFeature = defineFeature({
|
|
|
9841
10036
|
dependsOn: Array.from(routeDependencies)
|
|
9842
10037
|
}
|
|
9843
10038
|
);
|
|
9844
|
-
if (!(props.basicAuth ?? props.passwordAuth)) {
|
|
9845
|
-
bundle.addEnv(
|
|
9846
|
-
"AWSLESS_PREVIEW",
|
|
9847
|
-
$resolve(
|
|
9848
|
-
[routes],
|
|
9849
|
-
(routes2) => JSON.stringify({
|
|
9850
|
-
router: id,
|
|
9851
|
-
routes: Object.fromEntries(
|
|
9852
|
-
Object.entries(routes2).filter(
|
|
9853
|
-
([key, route]) => key.startsWith(`${id}:`) && route.type !== "url"
|
|
9854
|
-
)
|
|
9855
|
-
)
|
|
9856
|
-
})
|
|
9857
|
-
)
|
|
9858
|
-
);
|
|
9859
|
-
}
|
|
9860
10039
|
});
|
|
9861
10040
|
}
|
|
9862
10041
|
ctx.shared.add("router", "id", id, distribution.id);
|
|
@@ -9864,29 +10043,50 @@ var routerFeature = defineFeature({
|
|
|
9864
10043
|
distributionIds.push(distribution.id);
|
|
9865
10044
|
if (props.domain) {
|
|
9866
10045
|
const domainName = formatFullDomainName(ctx.appConfig, props.domain, props.subDomain);
|
|
10046
|
+
const wwwDomainName = props.redirectWww ? `www.${domainName}` : void 0;
|
|
9867
10047
|
const certificateArn = ctx.shared.entry("domain", `global-certificate-arn`, props.domain);
|
|
9868
10048
|
const zoneId = ctx.shared.entry("domain", "zone-id", props.domain);
|
|
9869
10049
|
const connectionGroup = new aws30.cloudfront.ConnectionGroup(group, "connection-group", {
|
|
9870
|
-
name
|
|
10050
|
+
name,
|
|
10051
|
+
ipv6Enabled: true
|
|
9871
10052
|
});
|
|
9872
10053
|
new aws30.cloudfront.DistributionTenant(group, `tenant`, {
|
|
9873
10054
|
name,
|
|
9874
10055
|
enabled: true,
|
|
9875
10056
|
distributionId: distribution.id,
|
|
9876
10057
|
connectionGroupId: connectionGroup.id,
|
|
9877
|
-
domain: [
|
|
10058
|
+
domain: [
|
|
10059
|
+
//
|
|
10060
|
+
{ domain: domainName },
|
|
10061
|
+
...wwwDomainName ? [{ domain: wwwDomainName }] : []
|
|
10062
|
+
],
|
|
9878
10063
|
customizations: [{ certificate: [{ arn: certificateArn }] }]
|
|
9879
10064
|
});
|
|
9880
|
-
|
|
9881
|
-
|
|
9882
|
-
|
|
9883
|
-
|
|
9884
|
-
|
|
9885
|
-
|
|
9886
|
-
|
|
9887
|
-
|
|
9888
|
-
|
|
9889
|
-
|
|
10065
|
+
for (const [recordId, recordName] of [
|
|
10066
|
+
["record", domainName],
|
|
10067
|
+
...wwwDomainName ? [["www-record", wwwDomainName]] : []
|
|
10068
|
+
]) {
|
|
10069
|
+
new aws30.route53.Record(group, recordId, {
|
|
10070
|
+
zoneId,
|
|
10071
|
+
type: "A",
|
|
10072
|
+
name: recordName,
|
|
10073
|
+
alias: {
|
|
10074
|
+
name: connectionGroup.routingEndpoint,
|
|
10075
|
+
zoneId: "Z2FDTNDATAQYW2",
|
|
10076
|
+
evaluateTargetHealth: false
|
|
10077
|
+
}
|
|
10078
|
+
});
|
|
10079
|
+
new aws30.route53.Record(group, `${recordId}-ipv6`, {
|
|
10080
|
+
zoneId,
|
|
10081
|
+
type: "AAAA",
|
|
10082
|
+
name: recordName,
|
|
10083
|
+
alias: {
|
|
10084
|
+
name: connectionGroup.routingEndpoint,
|
|
10085
|
+
zoneId: "Z2FDTNDATAQYW2",
|
|
10086
|
+
evaluateTargetHealth: false
|
|
10087
|
+
}
|
|
10088
|
+
});
|
|
10089
|
+
}
|
|
9890
10090
|
ctx.bind(`ROUTER_${constantCase15(id)}_ENDPOINT`, domainName);
|
|
9891
10091
|
}
|
|
9892
10092
|
}
|
|
@@ -11391,6 +11591,10 @@ var deploy = (program2) => {
|
|
|
11391
11591
|
appConfig,
|
|
11392
11592
|
id: deployment.id
|
|
11393
11593
|
});
|
|
11594
|
+
await promoteAppDeployment({
|
|
11595
|
+
appConfig,
|
|
11596
|
+
id: deployment.id
|
|
11597
|
+
});
|
|
11394
11598
|
return deployments3;
|
|
11395
11599
|
} finally {
|
|
11396
11600
|
await release();
|
|
@@ -560,6 +560,7 @@ var RouterDefaultSchema = z16.record(
|
|
|
560
560
|
z16.object({
|
|
561
561
|
domain: ResourceIdSchema.describe("The domain id to link your Router.").optional(),
|
|
562
562
|
subDomain: z16.string().optional(),
|
|
563
|
+
redirectWww: z16.boolean().default(false).describe("Redirect all www subdomain requests to your root domain."),
|
|
563
564
|
waf: WafSettingsSchema.optional(),
|
|
564
565
|
geoRestrictions: z16.array(z16.string().length(2).toUpperCase()).default([]).describe("Specifies a blacklist of countries that should be blocked."),
|
|
565
566
|
errors: z16.object({
|
|
@@ -648,6 +649,21 @@ var RouterDefaultSchema = z16.record(
|
|
|
648
649
|
}).optional().describe(
|
|
649
650
|
"Specifies the cookies, headers, and query values that CloudFront includes in the cache key."
|
|
650
651
|
)
|
|
652
|
+
}).superRefine((props, ctx) => {
|
|
653
|
+
if (props.redirectWww && !props.domain) {
|
|
654
|
+
ctx.addIssue({
|
|
655
|
+
code: z16.ZodIssueCode.custom,
|
|
656
|
+
path: ["redirectWww"],
|
|
657
|
+
message: "The redirectWww option requires a domain to be set."
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
if (props.redirectWww && props.subDomain) {
|
|
661
|
+
ctx.addIssue({
|
|
662
|
+
code: z16.ZodIssueCode.custom,
|
|
663
|
+
path: ["redirectWww"],
|
|
664
|
+
message: `The redirectWww option can't be combined with a subDomain, because the domain certificate only covers single level subdomains.`
|
|
665
|
+
});
|
|
666
|
+
}
|
|
651
667
|
})
|
|
652
668
|
).optional().describe(`Define the global Router. Backed by AWS CloudFront.`);
|
|
653
669
|
|