sst 2.7.1 → 2.7.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/cli/ci-info.d.ts +4 -0
- package/cli/ci-info.js +8 -0
- package/cli/commands/deploy.js +2 -1
- package/cli/commands/dev.js +6 -2
- package/cli/commands/diff.js +20 -5
- package/cli/telemetry/environment.js +4 -4
- package/cli/ui/functions.js +3 -3
- package/constructs/AppSyncApi.d.ts +1 -2
- package/constructs/AppSyncApi.js +5 -15
- package/constructs/Function.d.ts +1 -1
- package/constructs/Function.js +7 -2
- package/constructs/deprecated/cross-region-helper.js +3 -3
- package/constructs/util/appSyncApiDomain.d.ts +14 -2
- package/constructs/util/appSyncApiDomain.js +56 -11
- package/package.json +1 -1
- package/runtime/handlers.js +7 -0
- package/runtime/workers.js +4 -0
- package/sst.mjs +66 -14
- package/support/base-site-archiver.mjs +12 -12
- package/support/bootstrap-metadata-function/index.mjs +1345 -1409
- package/support/bridge/bridge.mjs +46 -35
- package/support/custom-resources/index.mjs +6468 -6532
- package/support/job-invoker/index.mjs +90 -907
- package/support/rds-migrator/index.mjs +16 -16
- package/support/script-function/index.mjs +90 -907
- package/support/ssr-site-function-archiver.mjs +9 -9
package/cli/ci-info.d.ts
ADDED
package/cli/ci-info.js
ADDED
package/cli/commands/deploy.js
CHANGED
|
@@ -17,6 +17,7 @@ export const deploy = (program) => program.command("deploy [filter]", "Deploy yo
|
|
|
17
17
|
const { dim, blue, bold } = await import("colorette");
|
|
18
18
|
const { useProject } = await import("../../project.js");
|
|
19
19
|
const { loadAssembly, useAppMetadata, saveAppMetadata, Stacks } = await import("../../stacks/index.js");
|
|
20
|
+
const { getCiInfo } = await import("../ci-info.js");
|
|
20
21
|
const { render } = await import("ink");
|
|
21
22
|
const { DeploymentUI } = await import("../ui/deploy.js");
|
|
22
23
|
const { mapValues } = await import("remeda");
|
|
@@ -40,7 +41,7 @@ export const deploy = (program) => program.command("deploy [filter]", "Deploy yo
|
|
|
40
41
|
});
|
|
41
42
|
}
|
|
42
43
|
// Check app mode changed
|
|
43
|
-
if (appMetadata && appMetadata.mode !== "deploy") {
|
|
44
|
+
if (!getCiInfo().isCI && appMetadata && appMetadata.mode !== "deploy") {
|
|
44
45
|
if (!(await promptChangeMode())) {
|
|
45
46
|
process.exit(0);
|
|
46
47
|
}
|
package/cli/commands/dev.js
CHANGED
|
@@ -31,6 +31,7 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
|
|
|
31
31
|
const { useMetadata } = await import("../../stacks/metadata.js");
|
|
32
32
|
const { useIOT } = await import("../../iot.js");
|
|
33
33
|
const { clear } = await import("../terminal.js");
|
|
34
|
+
const { getCiInfo } = await import("../ci-info.js");
|
|
34
35
|
if (args._[0] === "start") {
|
|
35
36
|
console.log(yellow(`Warning: ${bold(`sst start`)} has been renamed to ${bold(`sst dev`)}`));
|
|
36
37
|
}
|
|
@@ -69,12 +70,16 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
|
|
|
69
70
|
});
|
|
70
71
|
bus.subscribe("function.build.success", async (evt) => {
|
|
71
72
|
const info = useFunctions().fromID(evt.properties.functionID);
|
|
73
|
+
if (!info)
|
|
74
|
+
return;
|
|
72
75
|
if (info.enableLiveDev === false)
|
|
73
76
|
return;
|
|
74
77
|
Colors.line(Colors.dim(Colors.prefix, "Built", info.handler));
|
|
75
78
|
});
|
|
76
79
|
bus.subscribe("function.build.failed", async (evt) => {
|
|
77
80
|
const info = useFunctions().fromID(evt.properties.functionID);
|
|
81
|
+
if (!info)
|
|
82
|
+
return;
|
|
78
83
|
if (info.enableLiveDev === false)
|
|
79
84
|
return;
|
|
80
85
|
Colors.gap();
|
|
@@ -109,7 +114,6 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
|
|
|
109
114
|
const useStackBuilder = Context.memo(async () => {
|
|
110
115
|
const watcher = useWatcher();
|
|
111
116
|
const project = useProject();
|
|
112
|
-
const bus = useBus();
|
|
113
117
|
let lastDeployed;
|
|
114
118
|
let isWorking = false;
|
|
115
119
|
let isDirty = false;
|
|
@@ -276,7 +280,7 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
|
|
|
276
280
|
});
|
|
277
281
|
}
|
|
278
282
|
// Check app mode changed
|
|
279
|
-
if (appMetadata && appMetadata.mode !== "dev") {
|
|
283
|
+
if (!getCiInfo().isCI && appMetadata && appMetadata.mode !== "dev") {
|
|
280
284
|
if (!(await promptChangeMode())) {
|
|
281
285
|
process.exit(0);
|
|
282
286
|
}
|
package/cli/commands/diff.js
CHANGED
|
@@ -8,7 +8,6 @@ export const diff = (program) => program.command("diff", "Compare your app with
|
|
|
8
8
|
const { useAWSClient } = await import("../../credentials.js");
|
|
9
9
|
const { CloudFormationClient, GetTemplateCommand } = await import("@aws-sdk/client-cloudformation");
|
|
10
10
|
const { createSpinner } = await import("../spinner.js");
|
|
11
|
-
const { green } = await import("colorette");
|
|
12
11
|
const { Colors } = await import("../colors.js");
|
|
13
12
|
// Build app
|
|
14
13
|
const project = useProject();
|
|
@@ -23,10 +22,13 @@ export const diff = (program) => program.command("diff", "Compare your app with
|
|
|
23
22
|
for (const stack of assembly.stacks) {
|
|
24
23
|
const spinner = createSpinner(`${stack.stackName}: Checking for changes...`);
|
|
25
24
|
// get old template
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
const oldTemplate = await getTemplate(stack.stackName);
|
|
26
|
+
if (!oldTemplate) {
|
|
27
|
+
spinner.clear();
|
|
28
|
+
Colors.line(`➜ ${Colors.dim.bold(stackNameToId(stack.stackName) + ":")} New stack`);
|
|
29
|
+
Colors.gap();
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
30
32
|
// generate diff
|
|
31
33
|
const { count, diff } = await Stacks.diff(stack, oldTemplate);
|
|
32
34
|
spinner.clear();
|
|
@@ -58,4 +60,17 @@ export const diff = (program) => program.command("diff", "Compare your app with
|
|
|
58
60
|
Colors.line(Colors.success(`✔`), Colors.bold(" Diff:"), changesAcc === 1 ? "1 change found in" : `${changesAcc} changes in`, changedStacks === 1 ? "1 stack" : `${changedStacks} stacks`);
|
|
59
61
|
}
|
|
60
62
|
process.exit(0);
|
|
63
|
+
async function getTemplate(stackName) {
|
|
64
|
+
try {
|
|
65
|
+
const response = await cfn.send(new GetTemplateCommand({ StackName: stackName }));
|
|
66
|
+
return JSON.parse(response.TemplateBody);
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
if (e.name === "ValidationError" &&
|
|
70
|
+
e.message.includes("does not exist")) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
throw e;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
61
76
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import os from "os";
|
|
2
|
-
import
|
|
2
|
+
import { getCiInfo } from "../ci-info.js";
|
|
3
3
|
import { useProject } from "../../project.js";
|
|
4
4
|
let data;
|
|
5
5
|
export function getEnvironmentData() {
|
|
@@ -7,7 +7,7 @@ export function getEnvironmentData() {
|
|
|
7
7
|
return data;
|
|
8
8
|
}
|
|
9
9
|
const cpus = os.cpus() || [];
|
|
10
|
-
const
|
|
10
|
+
const ciInfo = getCiInfo();
|
|
11
11
|
data = {
|
|
12
12
|
// Software information
|
|
13
13
|
systemPlatform: os.platform(),
|
|
@@ -19,8 +19,8 @@ export function getEnvironmentData() {
|
|
|
19
19
|
cpuSpeed: cpus.length ? cpus[0].speed : null,
|
|
20
20
|
memoryInMb: Math.trunc(os.totalmem() / Math.pow(1024, 2)),
|
|
21
21
|
// Environment information
|
|
22
|
-
isCI: ciInfo.isCI
|
|
23
|
-
ciName:
|
|
22
|
+
isCI: ciInfo.isCI,
|
|
23
|
+
ciName: ciInfo.name,
|
|
24
24
|
sstVersion: useProject().version,
|
|
25
25
|
};
|
|
26
26
|
return data;
|
package/cli/ui/functions.js
CHANGED
|
@@ -48,7 +48,7 @@ export function Functions() {
|
|
|
48
48
|
const success = bus.subscribe("function.success", (evt) => {
|
|
49
49
|
function print(input, diff) {
|
|
50
50
|
setTimeout(() => {
|
|
51
|
-
console.log(Colors.primary(` ➜ `), useFunctions().fromID(input.functionID)
|
|
51
|
+
console.log(Colors.primary(` ➜ `), useFunctions().fromID(input.functionID)?.handler);
|
|
52
52
|
for (const log of input.logs) {
|
|
53
53
|
console.log(` ${dim(log)}`);
|
|
54
54
|
}
|
|
@@ -78,7 +78,7 @@ export function Functions() {
|
|
|
78
78
|
const error = bus.subscribe("function.error", (evt) => {
|
|
79
79
|
function print(input, diff) {
|
|
80
80
|
setTimeout(() => {
|
|
81
|
-
console.log(Colors.primary(` ➜ `), useFunctions().fromID(input.functionID)
|
|
81
|
+
console.log(Colors.primary(` ➜ `), useFunctions().fromID(input.functionID)?.handler);
|
|
82
82
|
for (const log of input.logs) {
|
|
83
83
|
console.log(` ${dim(log)}`);
|
|
84
84
|
}
|
|
@@ -122,7 +122,7 @@ export function Functions() {
|
|
|
122
122
|
" ",
|
|
123
123
|
React.createElement(Spinner, null),
|
|
124
124
|
" ",
|
|
125
|
-
useFunctions().fromID(evt.functionID)
|
|
125
|
+
useFunctions().fromID(evt.functionID)?.handler),
|
|
126
126
|
evt.logs.map((log, index) => (React.createElement(Text, { dimColor: true, key: index },
|
|
127
127
|
" ",
|
|
128
128
|
log))),
|
|
@@ -10,7 +10,7 @@ import { Permissions } from "./util/permission.js";
|
|
|
10
10
|
import { Table as CDKTable } from "aws-cdk-lib/aws-dynamodb";
|
|
11
11
|
import { IServerlessCluster } from "aws-cdk-lib/aws-rds";
|
|
12
12
|
import { ISecret } from "aws-cdk-lib/aws-secretsmanager";
|
|
13
|
-
import { AwsIamConfig, BaseDataSource,
|
|
13
|
+
import { AwsIamConfig, BaseDataSource, GraphqlApi, GraphqlApiProps, IGraphqlApi, Resolver, ResolverProps } from "aws-cdk-lib/aws-appsync";
|
|
14
14
|
import { ICertificate } from "aws-cdk-lib/aws-certificatemanager";
|
|
15
15
|
import { IDomain } from "aws-cdk-lib/aws-opensearchservice";
|
|
16
16
|
export interface AppSyncApiDomainProps extends appSyncApiDomain.CustomDomainProps {
|
|
@@ -403,7 +403,6 @@ export declare class AppSyncApi extends Construct implements SSTConstruct {
|
|
|
403
403
|
};
|
|
404
404
|
private readonly props;
|
|
405
405
|
private _customDomainUrl?;
|
|
406
|
-
_cfnDomainName?: CfnDomainName;
|
|
407
406
|
private readonly functionsByDsKey;
|
|
408
407
|
private readonly dataSourcesByDsKey;
|
|
409
408
|
private readonly dsKeysByResKey;
|
package/constructs/AppSyncApi.js
CHANGED
|
@@ -48,7 +48,6 @@ export class AppSyncApi extends Construct {
|
|
|
48
48
|
cdk;
|
|
49
49
|
props;
|
|
50
50
|
_customDomainUrl;
|
|
51
|
-
_cfnDomainName;
|
|
52
51
|
functionsByDsKey = {};
|
|
53
52
|
dataSourcesByDsKey = {};
|
|
54
53
|
dsKeysByResKey = {};
|
|
@@ -308,24 +307,15 @@ export class AppSyncApi extends Construct {
|
|
|
308
307
|
name: app.logicalPrefixedName(id),
|
|
309
308
|
xrayEnabled: true,
|
|
310
309
|
schema: mainSchema,
|
|
311
|
-
domainName: domainData
|
|
310
|
+
domainName: domainData && {
|
|
311
|
+
certificate: domainData.certificate,
|
|
312
|
+
domainName: domainData.domainName,
|
|
313
|
+
},
|
|
312
314
|
...graphqlApiProps,
|
|
313
315
|
});
|
|
314
316
|
this.cdk.certificate = domainData?.certificate;
|
|
315
|
-
// note: As of CDK 2.20.0, the "AWS::AppSync::DomainNameApiAssociation" resource
|
|
316
|
-
// is not dependent on the "AWS::AppSync::DomainName" resource. This leads
|
|
317
|
-
// CloudFormation deploy error if DomainNameApiAssociation is created before
|
|
318
|
-
// DomainName is created.
|
|
319
|
-
// https://github.com/aws/aws-cdk/issues/18395#issuecomment-1099455502
|
|
320
|
-
// To workaround this issue, we need to add a dependency manually.
|
|
321
317
|
if (domainData) {
|
|
322
|
-
this
|
|
323
|
-
"AWS::AppSync::DomainName");
|
|
324
|
-
const cfnDomainNameApiAssociation = this.cdk.graphqlApi.node.children.find((child) => child.cfnResourceType ===
|
|
325
|
-
"AWS::AppSync::DomainNameApiAssociation");
|
|
326
|
-
if (this._cfnDomainName && cfnDomainNameApiAssociation) {
|
|
327
|
-
cfnDomainNameApiAssociation.node.addDependency(this._cfnDomainName);
|
|
328
|
-
}
|
|
318
|
+
appSyncApiDomain.cleanup(this, domainData);
|
|
329
319
|
}
|
|
330
320
|
}
|
|
331
321
|
}
|
package/constructs/Function.d.ts
CHANGED
|
@@ -590,7 +590,7 @@ export declare class Function extends CDKFunction implements SSTConstruct {
|
|
|
590
590
|
static mergeProps(baseProps?: FunctionProps, props?: FunctionProps): FunctionProps;
|
|
591
591
|
}
|
|
592
592
|
export declare const useFunctions: () => {
|
|
593
|
-
fromID(id: string): FunctionProps;
|
|
593
|
+
fromID(id: string): FunctionProps | undefined;
|
|
594
594
|
add(name: string, props: FunctionProps): void;
|
|
595
595
|
readonly all: Record<string, FunctionProps>;
|
|
596
596
|
};
|
package/constructs/Function.js
CHANGED
|
@@ -171,7 +171,9 @@ export class Function extends CDKFunction {
|
|
|
171
171
|
new PolicyStatement({
|
|
172
172
|
actions: ["s3:*"],
|
|
173
173
|
effect: Effect.ALLOW,
|
|
174
|
-
resources: [
|
|
174
|
+
resources: [
|
|
175
|
+
`arn:${Stack.of(this).partition}:s3:::${bootstrap.bucket}`,
|
|
176
|
+
],
|
|
175
177
|
}),
|
|
176
178
|
]);
|
|
177
179
|
});
|
|
@@ -499,7 +501,10 @@ export const useFunctions = createAppContext(() => {
|
|
|
499
501
|
const functions = {};
|
|
500
502
|
return {
|
|
501
503
|
fromID(id) {
|
|
502
|
-
|
|
504
|
+
const result = functions[id];
|
|
505
|
+
if (!result)
|
|
506
|
+
return;
|
|
507
|
+
return result;
|
|
503
508
|
},
|
|
504
509
|
add(name, props) {
|
|
505
510
|
functions[name] = props;
|
|
@@ -16,7 +16,7 @@ export function getOrCreateBucket(scope) {
|
|
|
16
16
|
}
|
|
17
17
|
// Create provider
|
|
18
18
|
const provider = new lambda.Function(stack, providerId, {
|
|
19
|
-
code: lambda.Code.fromAsset(path.join(__dirname, "
|
|
19
|
+
code: lambda.Code.fromAsset(path.join(__dirname, "../../support/edge-function")),
|
|
20
20
|
handler: "s3-bucket.handler",
|
|
21
21
|
runtime: lambda.Runtime.NODEJS_16_X,
|
|
22
22
|
timeout: cdk.Duration.minutes(15),
|
|
@@ -48,7 +48,7 @@ export function createFunction(scope, name, role, bucketName, functionParams) {
|
|
|
48
48
|
// Create provider if not already created
|
|
49
49
|
if (!provider) {
|
|
50
50
|
provider = new lambda.Function(stack, providerId, {
|
|
51
|
-
code: lambda.Code.fromAsset(path.join(__dirname, "
|
|
51
|
+
code: lambda.Code.fromAsset(path.join(__dirname, "../../support/edge-function")),
|
|
52
52
|
handler: "edge-lambda.handler",
|
|
53
53
|
runtime: lambda.Runtime.NODEJS_16_X,
|
|
54
54
|
timeout: cdk.Duration.minutes(15),
|
|
@@ -86,7 +86,7 @@ export function createVersion(scope, name, functionArn) {
|
|
|
86
86
|
// Create provider if not already created
|
|
87
87
|
if (!provider) {
|
|
88
88
|
provider = new lambda.Function(stack, providerId, {
|
|
89
|
-
code: lambda.Code.fromAsset(path.join(__dirname, "
|
|
89
|
+
code: lambda.Code.fromAsset(path.join(__dirname, "../../support/edge-function")),
|
|
90
90
|
handler: "edge-lambda-version.handler",
|
|
91
91
|
runtime: lambda.Runtime.NODEJS_16_X,
|
|
92
92
|
timeout: cdk.Duration.minutes(15),
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as route53 from "aws-cdk-lib/aws-route53";
|
|
2
|
-
import * as appsync from "aws-cdk-lib/aws-appsync";
|
|
3
2
|
import * as acm from "aws-cdk-lib/aws-certificatemanager";
|
|
4
3
|
import { AppSyncApi } from "../AppSyncApi.js";
|
|
5
4
|
export interface CustomDomainProps {
|
|
@@ -11,6 +10,11 @@ export interface CustomDomainProps {
|
|
|
11
10
|
* The hosted zone in Route 53 that contains the domain. By default, SST will look for a hosted zone by stripping out the first part of the domainName that's passed in. So, if your domainName is api.domain.com. SST will default the hostedZone to domain.com.
|
|
12
11
|
*/
|
|
13
12
|
hostedZone?: string;
|
|
13
|
+
/**
|
|
14
|
+
* DNS record type for the Route 53 record associated with the custom domain. Default is CNAME.
|
|
15
|
+
* @default CNAME
|
|
16
|
+
*/
|
|
17
|
+
recordType?: "CNAME" | "A_AAAA";
|
|
14
18
|
/**
|
|
15
19
|
* Set this option if the domain is not hosted on Amazon Route 53.
|
|
16
20
|
*/
|
|
@@ -26,4 +30,12 @@ export interface CustomDomainProps {
|
|
|
26
30
|
certificate?: acm.ICertificate;
|
|
27
31
|
};
|
|
28
32
|
}
|
|
29
|
-
|
|
33
|
+
interface CustomDomainData {
|
|
34
|
+
certificate: acm.ICertificate;
|
|
35
|
+
domainName: string;
|
|
36
|
+
hostedZone?: route53.IHostedZone;
|
|
37
|
+
recordType?: CustomDomainProps["recordType"];
|
|
38
|
+
}
|
|
39
|
+
export declare function buildCustomDomainData(scope: AppSyncApi, customDomain: string | CustomDomainProps | undefined): CustomDomainData | undefined;
|
|
40
|
+
export declare function cleanup(scope: AppSyncApi, domainData: CustomDomainData): void;
|
|
41
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Token
|
|
1
|
+
import { Token } from "aws-cdk-lib";
|
|
2
2
|
import * as route53 from "aws-cdk-lib/aws-route53";
|
|
3
|
+
import * as route53Targets from "aws-cdk-lib/aws-route53-targets";
|
|
3
4
|
import * as acm from "aws-cdk-lib/aws-certificatemanager";
|
|
4
5
|
export function buildCustomDomainData(scope, customDomain) {
|
|
5
6
|
if (customDomain === undefined) {
|
|
@@ -18,6 +19,14 @@ export function buildCustomDomainData(scope, customDomain) {
|
|
|
18
19
|
// customDomain.domainName not exists
|
|
19
20
|
throw new Error(`Missing "domainName" in sst.AppSyncApi's customDomain setting`);
|
|
20
21
|
}
|
|
22
|
+
export function cleanup(scope, domainData) {
|
|
23
|
+
const cfnDomainName = getCfnDomainName(scope);
|
|
24
|
+
const cfnDomainNameApiAssociation = getCfnDomainNameApiAssociation(scope);
|
|
25
|
+
if (domainData.hostedZone) {
|
|
26
|
+
createRecords(scope, domainData.domainName, domainData.hostedZone, domainData.recordType, cfnDomainName);
|
|
27
|
+
}
|
|
28
|
+
fixDomainResourceDependencies(cfnDomainName, cfnDomainNameApiAssociation);
|
|
29
|
+
}
|
|
21
30
|
function buildDataForStringInput(scope, customDomain) {
|
|
22
31
|
// validate: customDomain is a TOKEN string
|
|
23
32
|
// ie. imported SSM value: ssm.StringParameter.valueForStringParameter()
|
|
@@ -29,10 +38,10 @@ function buildDataForStringInput(scope, customDomain) {
|
|
|
29
38
|
const hostedZoneDomain = domainName.split(".").slice(1).join(".");
|
|
30
39
|
const hostedZone = lookupHostedZone(scope, hostedZoneDomain);
|
|
31
40
|
const certificate = createCertificate(scope, domainName, hostedZone);
|
|
32
|
-
createRecord(scope, hostedZone, domainName);
|
|
33
41
|
return {
|
|
34
42
|
certificate,
|
|
35
43
|
domainName,
|
|
44
|
+
hostedZone,
|
|
36
45
|
};
|
|
37
46
|
}
|
|
38
47
|
function buildDataForInternalDomainInput(scope, customDomain) {
|
|
@@ -69,10 +78,11 @@ function buildDataForInternalDomainInput(scope, customDomain) {
|
|
|
69
78
|
const certificate = customDomain.cdk?.certificate
|
|
70
79
|
? customDomain.cdk.certificate
|
|
71
80
|
: createCertificate(scope, domainName, hostedZone);
|
|
72
|
-
createRecord(scope, hostedZone, domainName);
|
|
73
81
|
return {
|
|
74
82
|
certificate,
|
|
75
83
|
domainName,
|
|
84
|
+
hostedZone,
|
|
85
|
+
recordType: customDomain.recordType,
|
|
76
86
|
};
|
|
77
87
|
}
|
|
78
88
|
function buildDataForExternalDomainInput(scope, customDomain) {
|
|
@@ -103,25 +113,60 @@ function createCertificate(scope, domainName, hostedZone) {
|
|
|
103
113
|
validation: acm.CertificateValidation.fromDns(hostedZone),
|
|
104
114
|
});
|
|
105
115
|
}
|
|
106
|
-
function
|
|
116
|
+
function createRecords(scope, domainName, hostedZone, recordType, cfnDomainName) {
|
|
107
117
|
// create DNS record
|
|
108
|
-
const
|
|
118
|
+
const aRecordProps = {
|
|
109
119
|
recordName: domainName,
|
|
110
120
|
zone: hostedZone,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return
|
|
121
|
+
target: route53.RecordTarget.fromAlias({
|
|
122
|
+
bind() {
|
|
123
|
+
return {
|
|
124
|
+
hostedZoneId: route53Targets.CloudFrontTarget.CLOUDFRONT_ZONE_ID,
|
|
125
|
+
dnsName: cfnDomainName.attrAppSyncDomainName,
|
|
126
|
+
};
|
|
114
127
|
},
|
|
115
128
|
}),
|
|
116
|
-
}
|
|
129
|
+
};
|
|
130
|
+
const records = (recordType || "CNAME") === "CNAME"
|
|
131
|
+
? [
|
|
132
|
+
new route53.CnameRecord(scope, "CnameRecord", {
|
|
133
|
+
recordName: domainName,
|
|
134
|
+
zone: hostedZone,
|
|
135
|
+
domainName: cfnDomainName.attrAppSyncDomainName,
|
|
136
|
+
}),
|
|
137
|
+
]
|
|
138
|
+
: [
|
|
139
|
+
new route53.ARecord(scope, "AliasRecord", aRecordProps),
|
|
140
|
+
new route53.AaaaRecord(scope, "AliasRecordAAAA", aRecordProps),
|
|
141
|
+
];
|
|
117
142
|
// note: If domainName is a TOKEN string ie. ${TOKEN..}, the route53.ARecord
|
|
118
143
|
// construct will append ".${hostedZoneName}" to the end of the domain.
|
|
119
144
|
// This is because the construct tries to check if the record name
|
|
120
145
|
// ends with the domain name. If not, it will append the domain name.
|
|
121
146
|
// So, we need remove this behavior.
|
|
122
147
|
if (Token.isUnresolved(domainName)) {
|
|
123
|
-
|
|
124
|
-
|
|
148
|
+
records.forEach((record) => {
|
|
149
|
+
const cfnRecord = record.node.defaultChild;
|
|
150
|
+
cfnRecord.name = domainName;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function getCfnDomainName(scope) {
|
|
155
|
+
return scope.cdk.graphqlApi.node.children.find((child) => child.cfnResourceType === "AWS::AppSync::DomainName");
|
|
156
|
+
}
|
|
157
|
+
function getCfnDomainNameApiAssociation(scope) {
|
|
158
|
+
return scope.cdk.graphqlApi.node.children.find((child) => child.cfnResourceType ===
|
|
159
|
+
"AWS::AppSync::DomainNameApiAssociation");
|
|
160
|
+
}
|
|
161
|
+
function fixDomainResourceDependencies(cfnDomainName, cfnDomainNameApiAssociation) {
|
|
162
|
+
// note: As of CDK 2.20.0, the "AWS::AppSync::DomainNameApiAssociation" resource
|
|
163
|
+
// is not dependent on the "AWS::AppSync::DomainName" resource. This leads
|
|
164
|
+
// CloudFormation deploy error if DomainNameApiAssociation is created before
|
|
165
|
+
// DomainName is created.
|
|
166
|
+
// https://github.com/aws/aws-cdk/issues/18395#issuecomment-1099455502
|
|
167
|
+
// To workaround this issue, we need to add a dependency manually.
|
|
168
|
+
if (cfnDomainName && cfnDomainNameApiAssociation) {
|
|
169
|
+
cfnDomainNameApiAssociation.node.addDependency(cfnDomainName);
|
|
125
170
|
}
|
|
126
171
|
}
|
|
127
172
|
function assertDomainNameIsLowerCase(domainName) {
|
package/package.json
CHANGED
package/runtime/handlers.js
CHANGED
|
@@ -25,6 +25,11 @@ export const useRuntimeHandlers = Context.memo(() => {
|
|
|
25
25
|
async build(functionID, mode) {
|
|
26
26
|
async function task() {
|
|
27
27
|
const func = useFunctions().fromID(functionID);
|
|
28
|
+
if (!func)
|
|
29
|
+
return {
|
|
30
|
+
type: "error",
|
|
31
|
+
errors: [`Function with ID "${functionID}" not found`],
|
|
32
|
+
};
|
|
28
33
|
const handler = result.for(func.runtime);
|
|
29
34
|
const out = path.join(project.paths.artifacts, functionID);
|
|
30
35
|
await fs.rm(out, { recursive: true, force: true });
|
|
@@ -100,6 +105,8 @@ export const useFunctionBuilder = Context.memo(() => {
|
|
|
100
105
|
},
|
|
101
106
|
build: async (functionID) => {
|
|
102
107
|
const result = await handlers.build(functionID, "start");
|
|
108
|
+
if (!result)
|
|
109
|
+
return;
|
|
103
110
|
if (result.type === "error")
|
|
104
111
|
return;
|
|
105
112
|
artifacts.set(functionID, result);
|
package/runtime/workers.js
CHANGED
|
@@ -13,6 +13,8 @@ export const useRuntimeWorkers = Context.memo(async () => {
|
|
|
13
13
|
for (const [_, worker] of workers) {
|
|
14
14
|
if (worker.functionID === evt.properties.functionID) {
|
|
15
15
|
const props = useFunctions().fromID(worker.functionID);
|
|
16
|
+
if (!props)
|
|
17
|
+
return;
|
|
16
18
|
const handler = handlers.for(props.runtime);
|
|
17
19
|
await handler?.stopWorker(worker.workerID);
|
|
18
20
|
bus.publish("worker.stopped", worker);
|
|
@@ -30,6 +32,8 @@ export const useRuntimeWorkers = Context.memo(async () => {
|
|
|
30
32
|
if (worker)
|
|
31
33
|
return;
|
|
32
34
|
const props = useFunctions().fromID(evt.properties.functionID);
|
|
35
|
+
if (!props)
|
|
36
|
+
return;
|
|
33
37
|
const handler = handlers.for(props.runtime);
|
|
34
38
|
if (!handler)
|
|
35
39
|
return;
|