sst 2.29.0 → 2.30.1
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/cdk/deploy-stack.d.ts +4 -4
- package/cdk/deploy-stack.js +6 -5
- package/cdk/deployments-wrapper.js +7 -9
- package/cdk/deployments.d.ts +15 -8
- package/cdk/deployments.js +30 -42
- package/cli/commands/bind.js +0 -3
- package/cli/commands/types.js +12 -2
- package/cli/sst.js +0 -2
- package/constructs/BaseSite.d.ts +12 -3
- package/constructs/Distribution.d.ts +1 -1
- package/constructs/Distribution.js +2 -2
- package/constructs/NextjsSite.d.ts +2 -0
- package/constructs/NextjsSite.js +25 -14
- package/constructs/Script.d.ts +7 -5
- package/constructs/SsrSite.d.ts +97 -8
- package/constructs/SsrSite.js +208 -61
- package/constructs/StaticSite.d.ts +7 -9
- package/constructs/StaticSite.js +20 -15
- package/package.json +3 -3
- package/runtime/handlers.js +21 -10
- package/stacks/build.js +7 -1
- package/stacks/synth.js +62 -54
- package/util/semaphore.d.ts +7 -0
- package/util/semaphore.js +27 -0
package/cdk/deploy-stack.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import * as cxapi from "@aws-cdk/cx-api";
|
|
|
2
2
|
import { Tag } from "sst-aws-cdk/lib/cdk-toolkit.js";
|
|
3
3
|
import { AssetManifestBuilder } from "sst-aws-cdk/lib/util/asset-manifest-builder.js";
|
|
4
4
|
import { ISDK, SdkProvider } from "sst-aws-cdk/lib/api/aws-auth/index.js";
|
|
5
|
+
import { EnvironmentResources } from "sst-aws-cdk/lib/api/environment-resources.js";
|
|
5
6
|
import { HotswapMode } from "sst-aws-cdk/lib/api/hotswap/common.js";
|
|
6
|
-
import { ToolkitInfo } from "sst-aws-cdk/lib/api/toolkit-info.js";
|
|
7
7
|
import { ResourcesToImport } from "sst-aws-cdk/lib/api/util/cloudformation.js";
|
|
8
8
|
import { StackActivityProgress } from "sst-aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.js";
|
|
9
9
|
type TemplateBodyParameter = {
|
|
@@ -56,7 +56,7 @@ export interface DeployStackOptions {
|
|
|
56
56
|
/**
|
|
57
57
|
* Information about the bootstrap stack found in the target environment
|
|
58
58
|
*/
|
|
59
|
-
readonly
|
|
59
|
+
readonly envResources: EnvironmentResources;
|
|
60
60
|
/**
|
|
61
61
|
* Role to pass to CloudFormation to execute the change set
|
|
62
62
|
*
|
|
@@ -200,14 +200,14 @@ export declare function deployStack(options: DeployStackOptions): Promise<Deploy
|
|
|
200
200
|
* @param stack the synthesized stack that provides the CloudFormation template
|
|
201
201
|
* @param toolkitInfo information about the toolkit stack
|
|
202
202
|
*/
|
|
203
|
-
export declare function makeBodyParameter(stack: cxapi.CloudFormationStackArtifact, resolvedEnvironment: cxapi.Environment, assetManifest: AssetManifestBuilder,
|
|
203
|
+
export declare function makeBodyParameter(stack: cxapi.CloudFormationStackArtifact, resolvedEnvironment: cxapi.Environment, assetManifest: AssetManifestBuilder, resources: EnvironmentResources, sdk: ISDK, overrideTemplate?: any): Promise<TemplateBodyParameter>;
|
|
204
204
|
/**
|
|
205
205
|
* Prepare a body parameter for CFN, performing the upload
|
|
206
206
|
*
|
|
207
207
|
* Return it as-is if it is small enough to pass in the API call,
|
|
208
208
|
* upload to S3 and return the coordinates if it is not.
|
|
209
209
|
*/
|
|
210
|
-
export declare function makeBodyParameterAndUpload(stack: cxapi.CloudFormationStackArtifact, resolvedEnvironment: cxapi.Environment,
|
|
210
|
+
export declare function makeBodyParameterAndUpload(stack: cxapi.CloudFormationStackArtifact, resolvedEnvironment: cxapi.Environment, resources: EnvironmentResources, sdkProvider: SdkProvider, sdk: ISDK, overrideTemplate?: any): Promise<TemplateBodyParameter>;
|
|
211
211
|
export interface DestroyStackOptions {
|
|
212
212
|
/**
|
|
213
213
|
* The stack to be destroyed
|
package/cdk/deploy-stack.js
CHANGED
|
@@ -37,7 +37,7 @@ export async function deployStack(options) {
|
|
|
37
37
|
// an ad-hoc asset manifest, while passing their locations via template
|
|
38
38
|
// parameters.
|
|
39
39
|
const legacyAssets = new AssetManifestBuilder();
|
|
40
|
-
const assetParams = await addMetadataAssetsToManifest(stackArtifact, legacyAssets, options.
|
|
40
|
+
const assetParams = await addMetadataAssetsToManifest(stackArtifact, legacyAssets, options.envResources, options.reuseAssets);
|
|
41
41
|
const finalParameterValues = { ...options.parameters, ...assetParams };
|
|
42
42
|
const templateParams = TemplateParameters.fromTemplate(stackArtifact.template);
|
|
43
43
|
const stackParams = options.usePreviousParameters
|
|
@@ -58,7 +58,7 @@ export async function deployStack(options) {
|
|
|
58
58
|
else {
|
|
59
59
|
debug(`${deployName}: deploying...`);
|
|
60
60
|
}
|
|
61
|
-
const bodyParameter = await makeBodyParameter(stackArtifact, options.resolvedEnvironment, legacyAssets, options.
|
|
61
|
+
const bodyParameter = await makeBodyParameter(stackArtifact, options.resolvedEnvironment, legacyAssets, options.envResources, options.sdk, options.overrideTemplate);
|
|
62
62
|
await publishAssets(legacyAssets.toManifest(stackArtifact.assembly.directory), options.sdkProvider, stackEnv, {
|
|
63
63
|
parallel: options.assetParallelism,
|
|
64
64
|
});
|
|
@@ -352,7 +352,7 @@ class FullCloudFormationDeployment {
|
|
|
352
352
|
* @param stack the synthesized stack that provides the CloudFormation template
|
|
353
353
|
* @param toolkitInfo information about the toolkit stack
|
|
354
354
|
*/
|
|
355
|
-
export async function makeBodyParameter(stack, resolvedEnvironment, assetManifest,
|
|
355
|
+
export async function makeBodyParameter(stack, resolvedEnvironment, assetManifest, resources, sdk, overrideTemplate) {
|
|
356
356
|
// If the template has already been uploaded to S3, just use it from there.
|
|
357
357
|
if (stack.stackTemplateAssetObjectUrl && !overrideTemplate) {
|
|
358
358
|
return {
|
|
@@ -364,6 +364,7 @@ export async function makeBodyParameter(stack, resolvedEnvironment, assetManifes
|
|
|
364
364
|
if (templateJson.length <= LARGE_TEMPLATE_SIZE_KB * 1024) {
|
|
365
365
|
return { TemplateBody: templateJson };
|
|
366
366
|
}
|
|
367
|
+
const toolkitInfo = await resources.lookupToolkit();
|
|
367
368
|
if (!toolkitInfo.found) {
|
|
368
369
|
error(`The template for stack "${stack.displayName}" is ${Math.round(templateJson.length / 1024)}KiB. ` +
|
|
369
370
|
`Templates larger than ${LARGE_TEMPLATE_SIZE_KB}KiB must be uploaded to S3.\n` +
|
|
@@ -394,14 +395,14 @@ export async function makeBodyParameter(stack, resolvedEnvironment, assetManifes
|
|
|
394
395
|
* Return it as-is if it is small enough to pass in the API call,
|
|
395
396
|
* upload to S3 and return the coordinates if it is not.
|
|
396
397
|
*/
|
|
397
|
-
export async function makeBodyParameterAndUpload(stack, resolvedEnvironment,
|
|
398
|
+
export async function makeBodyParameterAndUpload(stack, resolvedEnvironment, resources, sdkProvider, sdk, overrideTemplate) {
|
|
398
399
|
// We don't have access to the actual asset manifest here, so pretend that the
|
|
399
400
|
// stack doesn't have a pre-published URL.
|
|
400
401
|
const forceUploadStack = Object.create(stack, {
|
|
401
402
|
stackTemplateAssetObjectUrl: { value: undefined },
|
|
402
403
|
});
|
|
403
404
|
const builder = new AssetManifestBuilder();
|
|
404
|
-
const bodyparam = await makeBodyParameter(forceUploadStack, resolvedEnvironment, builder,
|
|
405
|
+
const bodyparam = await makeBodyParameter(forceUploadStack, resolvedEnvironment, builder, resources, sdk, overrideTemplate);
|
|
405
406
|
const manifest = builder.toManifest(stack.assembly.directory);
|
|
406
407
|
await publishAssets(manifest, sdkProvider, resolvedEnvironment, {
|
|
407
408
|
quiet: true,
|
|
@@ -3,7 +3,6 @@ import { AssetManifest } from "cdk-assets";
|
|
|
3
3
|
import { debug } from "sst-aws-cdk/lib/logging.js";
|
|
4
4
|
import { CloudFormationStack, TemplateParameters, waitForStackDelete, } from "sst-aws-cdk/lib/api/util/cloudformation.js";
|
|
5
5
|
import { Mode } from "sst-aws-cdk/lib/api/aws-auth/credentials.js";
|
|
6
|
-
import { ToolkitInfo } from "sst-aws-cdk/lib/api/toolkit-info.js";
|
|
7
6
|
import { addMetadataAssetsToManifest } from "sst-aws-cdk/lib/assets.js";
|
|
8
7
|
import { publishAssets } from "sst-aws-cdk/lib/util/asset-publishing.js";
|
|
9
8
|
import { AssetManifestBuilder } from "sst-aws-cdk/lib/util/asset-manifest-builder.js";
|
|
@@ -11,7 +10,7 @@ import { Deployments, } from "./deployments.js";
|
|
|
11
10
|
import { makeBodyParameter } from "./deploy-stack.js";
|
|
12
11
|
import { lazy } from "../util/lazy.js";
|
|
13
12
|
export async function publishDeployAssets(sdkProvider, options) {
|
|
14
|
-
const { deployment,
|
|
13
|
+
const { deployment, envResources, stackSdk, resolvedEnvironment, cloudFormationRoleArn, } = await useDeployment().get(sdkProvider, options);
|
|
15
14
|
// TODO
|
|
16
15
|
// old
|
|
17
16
|
//await deployment.publishStackAssets(options.stack, toolkitInfo, {
|
|
@@ -44,7 +43,7 @@ export async function publishDeployAssets(sdkProvider, options) {
|
|
|
44
43
|
sdkProvider,
|
|
45
44
|
roleArn: cloudFormationRoleArn,
|
|
46
45
|
reuseAssets: options.reuseAssets,
|
|
47
|
-
|
|
46
|
+
envResources,
|
|
48
47
|
tags: options.tags,
|
|
49
48
|
deploymentMethod: options.deploymentMethod,
|
|
50
49
|
force: options.force,
|
|
@@ -67,13 +66,12 @@ const useDeployment = lazy(() => {
|
|
|
67
66
|
const region = options.stack.environment.region;
|
|
68
67
|
if (!state.has(region)) {
|
|
69
68
|
const deployment = new Deployments({ sdkProvider });
|
|
70
|
-
const { stackSdk, resolvedEnvironment, cloudFormationRoleArn } = await deployment.prepareSdkFor(options.stack, options.roleArn, Mode.ForWriting);
|
|
71
|
-
const toolkitInfo = await ToolkitInfo.lookup(resolvedEnvironment, stackSdk, options.toolkitStackName);
|
|
69
|
+
const { stackSdk, resolvedEnvironment, cloudFormationRoleArn, envResources, } = await deployment.prepareSdkFor(options.stack, options.roleArn, Mode.ForWriting);
|
|
72
70
|
// Do a verification of the bootstrap stack version
|
|
73
|
-
await deployment.validateBootstrapStackVersion(options.stack.stackName, options.stack.requiresBootstrapStackVersion, options.stack.bootstrapStackVersionSsmParameter,
|
|
71
|
+
await deployment.validateBootstrapStackVersion(options.stack.stackName, options.stack.requiresBootstrapStackVersion, options.stack.bootstrapStackVersionSsmParameter, envResources);
|
|
74
72
|
state.set(region, {
|
|
75
73
|
deployment,
|
|
76
|
-
|
|
74
|
+
envResources,
|
|
77
75
|
stackSdk,
|
|
78
76
|
resolvedEnvironment,
|
|
79
77
|
cloudFormationRoleArn,
|
|
@@ -106,13 +104,13 @@ async function deployStack(options) {
|
|
|
106
104
|
// an ad-hoc asset manifest, while passing their locations via template
|
|
107
105
|
// parameters.
|
|
108
106
|
const legacyAssets = new AssetManifestBuilder();
|
|
109
|
-
const assetParams = await addMetadataAssetsToManifest(stackArtifact, legacyAssets, options.
|
|
107
|
+
const assetParams = await addMetadataAssetsToManifest(stackArtifact, legacyAssets, options.envResources, options.reuseAssets);
|
|
110
108
|
const finalParameterValues = { ...options.parameters, ...assetParams };
|
|
111
109
|
const templateParams = TemplateParameters.fromTemplate(stackArtifact.template);
|
|
112
110
|
const stackParams = options.usePreviousParameters
|
|
113
111
|
? templateParams.updateExisting(finalParameterValues, cloudFormationStack.parameters)
|
|
114
112
|
: templateParams.supplyAll(finalParameterValues);
|
|
115
|
-
const bodyParameter = await makeBodyParameter(stackArtifact, options.resolvedEnvironment, legacyAssets, options.
|
|
113
|
+
const bodyParameter = await makeBodyParameter(stackArtifact, options.resolvedEnvironment, legacyAssets, options.envResources, options.sdk, options.overrideTemplate);
|
|
116
114
|
await publishAssets(legacyAssets.toManifest(stackArtifact.assembly.directory), options.sdkProvider, stackEnv, {
|
|
117
115
|
parallel: options.assetParallelism,
|
|
118
116
|
});
|
package/cdk/deployments.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Mode } from "sst-aws-cdk/lib/api/aws-auth/credentials.js";
|
|
|
6
6
|
import { ISDK } from "sst-aws-cdk/lib/api/aws-auth/sdk.js";
|
|
7
7
|
import { SdkProvider } from "sst-aws-cdk/lib/api/aws-auth/sdk-provider.js";
|
|
8
8
|
import { DeployStackResult, DeploymentMethod } from "./deploy-stack.js";
|
|
9
|
-
import {
|
|
9
|
+
import { EnvironmentResources } from "sst-aws-cdk/lib/api/environment-resources.js";
|
|
10
10
|
import { Template, ResourcesToImport, ResourceIdentifierSummaries } from "sst-aws-cdk/lib/api/util/cloudformation.js";
|
|
11
11
|
import { StackActivityProgress } from "sst-aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.js";
|
|
12
12
|
import { HotswapMode } from "sst-aws-cdk/lib/api/hotswap/common.js";
|
|
@@ -31,6 +31,10 @@ export interface PreparedSdkWithLookupRoleForEnvironment {
|
|
|
31
31
|
* the default credentials (not the assume role credentials)
|
|
32
32
|
*/
|
|
33
33
|
readonly didAssumeRole: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* An object for accessing the bootstrap resources in this environment
|
|
36
|
+
*/
|
|
37
|
+
readonly envResources: EnvironmentResources;
|
|
34
38
|
}
|
|
35
39
|
export interface DeployStackOptions {
|
|
36
40
|
/**
|
|
@@ -212,6 +216,7 @@ export interface StackExistsOptions {
|
|
|
212
216
|
}
|
|
213
217
|
export interface DeploymentsProps {
|
|
214
218
|
sdkProvider: SdkProvider;
|
|
219
|
+
readonly toolkitStackName?: string;
|
|
215
220
|
readonly quiet?: boolean;
|
|
216
221
|
}
|
|
217
222
|
/**
|
|
@@ -234,6 +239,10 @@ export interface PreparedSdkForEnvironment {
|
|
|
234
239
|
* @default - no execution role is used
|
|
235
240
|
*/
|
|
236
241
|
readonly cloudFormationRoleArn?: string;
|
|
242
|
+
/**
|
|
243
|
+
* Access class for environmental resources to help the deployment
|
|
244
|
+
*/
|
|
245
|
+
readonly envResources: EnvironmentResources;
|
|
237
246
|
}
|
|
238
247
|
/**
|
|
239
248
|
* Scope for a single set of deployments from a set of Cloud Assembly Artifacts
|
|
@@ -243,13 +252,13 @@ export interface PreparedSdkForEnvironment {
|
|
|
243
252
|
export declare class Deployments {
|
|
244
253
|
private readonly props;
|
|
245
254
|
private readonly sdkProvider;
|
|
246
|
-
private readonly toolkitInfoCache;
|
|
247
255
|
private readonly sdkCache;
|
|
248
256
|
private readonly publisherCache;
|
|
257
|
+
private readonly environmentResources;
|
|
249
258
|
constructor(props: DeploymentsProps);
|
|
250
259
|
readCurrentTemplateWithNestedStacks(rootStackArtifact: cxapi.CloudFormationStackArtifact, retrieveProcessedTemplate?: boolean): Promise<Template>;
|
|
251
260
|
readCurrentTemplate(stackArtifact: cxapi.CloudFormationStackArtifact): Promise<Template>;
|
|
252
|
-
resourceIdentifierSummaries(stackArtifact: cxapi.CloudFormationStackArtifact
|
|
261
|
+
resourceIdentifierSummaries(stackArtifact: cxapi.CloudFormationStackArtifact): Promise<ResourceIdentifierSummaries>;
|
|
253
262
|
deployStack(options: DeployStackOptions): Promise<DeployStackResult | undefined>;
|
|
254
263
|
destroyStack(options: DestroyStackOptions): Promise<void>;
|
|
255
264
|
stackExists(options: StackExistsOptions): Promise<boolean>;
|
|
@@ -283,10 +292,6 @@ export declare class Deployments {
|
|
|
283
292
|
* function can then decide to use them or fallback to another role.
|
|
284
293
|
*/
|
|
285
294
|
prepareSdkWithLookupRoleFor(stack: cxapi.CloudFormationStackArtifact): Promise<PreparedSdkWithLookupRoleForEnvironment>;
|
|
286
|
-
/**
|
|
287
|
-
* Look up the toolkit for a given environment, using a given SDK
|
|
288
|
-
*/
|
|
289
|
-
lookupToolkit(resolvedEnvironment: cxapi.Environment, sdk: ISDK, toolkitStackName?: string): Promise<ToolkitInfo>;
|
|
290
295
|
private prepareAndValidateAssets;
|
|
291
296
|
/**
|
|
292
297
|
* Build all assets in a manifest
|
|
@@ -314,8 +319,10 @@ export declare class Deployments {
|
|
|
314
319
|
isSingleAssetPublished(assetManifest: AssetManifest, asset: IManifestEntry, options: PublishStackAssetsOptions): Promise<boolean>;
|
|
315
320
|
/**
|
|
316
321
|
* Validate that the bootstrap stack has the right version for this stack
|
|
322
|
+
*
|
|
323
|
+
* Call into envResources.validateVersion, but prepend the stack name in case of failure.
|
|
317
324
|
*/
|
|
318
|
-
validateBootstrapStackVersion(stackName: string, requiresBootstrapStackVersion: number | undefined, bootstrapStackVersionSsmParameter: string | undefined,
|
|
325
|
+
validateBootstrapStackVersion(stackName: string, requiresBootstrapStackVersion: number | undefined, bootstrapStackVersionSsmParameter: string | undefined, envResources: EnvironmentResources): Promise<void>;
|
|
319
326
|
private cachedSdkForEnvironment;
|
|
320
327
|
private cachedPublisher;
|
|
321
328
|
}
|
package/cdk/deployments.js
CHANGED
|
@@ -6,11 +6,10 @@ import { debug, warning } from "sst-aws-cdk/lib/logging.js";
|
|
|
6
6
|
import { buildAssets, publishAssets, PublishingAws, EVENT_TO_LOGGER, } from "sst-aws-cdk/lib/util/asset-publishing.js";
|
|
7
7
|
import { Mode } from "sst-aws-cdk/lib/api/aws-auth/credentials.js";
|
|
8
8
|
import { deployStack, destroyStack, makeBodyParameterAndUpload, } from "./deploy-stack.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { EnvironmentResourcesRegistry, } from "sst-aws-cdk/lib/api/environment-resources.js";
|
|
10
|
+
import { loadCurrentTemplateWithNestedStacks, loadCurrentTemplate, flattenNestedStackNames, } from "sst-aws-cdk/lib/api/nested-stack-helpers.js";
|
|
11
11
|
import { CloudFormationStack, } from "sst-aws-cdk/lib/api/util/cloudformation.js";
|
|
12
12
|
import { replaceEnvPlaceholders } from "sst-aws-cdk/lib/api/util/placeholders.js";
|
|
13
|
-
import { callWithRetry } from "./util.js";
|
|
14
13
|
/**
|
|
15
14
|
* Scope for a single set of deployments from a set of Cloud Assembly Artifacts
|
|
16
15
|
*
|
|
@@ -19,17 +18,22 @@ import { callWithRetry } from "./util.js";
|
|
|
19
18
|
export class Deployments {
|
|
20
19
|
props;
|
|
21
20
|
sdkProvider;
|
|
22
|
-
toolkitInfoCache = new Map();
|
|
23
21
|
sdkCache = new Map();
|
|
24
22
|
publisherCache = new Map();
|
|
23
|
+
environmentResources;
|
|
25
24
|
constructor(props) {
|
|
26
25
|
this.props = props;
|
|
27
26
|
this.sdkProvider = props.sdkProvider;
|
|
27
|
+
this.environmentResources = new EnvironmentResourcesRegistry(props.toolkitStackName);
|
|
28
28
|
}
|
|
29
29
|
async readCurrentTemplateWithNestedStacks(rootStackArtifact, retrieveProcessedTemplate = false) {
|
|
30
30
|
const sdk = (await this.prepareSdkWithLookupOrDeployRole(rootStackArtifact))
|
|
31
31
|
.stackSdk;
|
|
32
|
-
|
|
32
|
+
const templateWithNestedStacks = await loadCurrentTemplateWithNestedStacks(rootStackArtifact, sdk, retrieveProcessedTemplate);
|
|
33
|
+
return {
|
|
34
|
+
deployedTemplate: templateWithNestedStacks.deployedTemplate,
|
|
35
|
+
nestedStackCount: flattenNestedStackNames(templateWithNestedStacks.nestedStackNames).length,
|
|
36
|
+
};
|
|
33
37
|
}
|
|
34
38
|
async readCurrentTemplate(stackArtifact) {
|
|
35
39
|
debug(`Reading existing template for stack ${stackArtifact.displayName}.`);
|
|
@@ -37,15 +41,14 @@ export class Deployments {
|
|
|
37
41
|
.stackSdk;
|
|
38
42
|
return loadCurrentTemplate(stackArtifact, sdk);
|
|
39
43
|
}
|
|
40
|
-
async resourceIdentifierSummaries(stackArtifact
|
|
44
|
+
async resourceIdentifierSummaries(stackArtifact) {
|
|
41
45
|
debug(`Retrieving template summary for stack ${stackArtifact.displayName}.`);
|
|
42
46
|
// Currently, needs to use `deploy-role` since it may need to read templates in the staging
|
|
43
47
|
// bucket which have been encrypted with a KMS key (and lookup-role may not read encrypted things)
|
|
44
|
-
const { stackSdk, resolvedEnvironment } = await this.prepareSdkFor(stackArtifact, undefined, Mode.ForReading);
|
|
48
|
+
const { stackSdk, resolvedEnvironment, envResources } = await this.prepareSdkFor(stackArtifact, undefined, Mode.ForReading);
|
|
45
49
|
const cfn = stackSdk.cloudFormation();
|
|
46
|
-
const toolkitInfo = await this.lookupToolkit(resolvedEnvironment, stackSdk, toolkitStackName);
|
|
47
50
|
// Upload the template, if necessary, before passing it to CFN
|
|
48
|
-
const cfnParam = await makeBodyParameterAndUpload(stackArtifact, resolvedEnvironment,
|
|
51
|
+
const cfnParam = await makeBodyParameterAndUpload(stackArtifact, resolvedEnvironment, envResources, this.sdkProvider, stackSdk);
|
|
49
52
|
const response = await cfn.getTemplateSummary(cfnParam).promise();
|
|
50
53
|
if (!response.ResourceIdentifierSummaries) {
|
|
51
54
|
debug('GetTemplateSummary API call did not return "ResourceIdentifierSummaries"');
|
|
@@ -64,10 +67,9 @@ export class Deployments {
|
|
|
64
67
|
execute: options.execute,
|
|
65
68
|
};
|
|
66
69
|
}
|
|
67
|
-
const { stackSdk, resolvedEnvironment, cloudFormationRoleArn } = await this.prepareSdkFor(options.stack, options.roleArn, Mode.ForWriting);
|
|
68
|
-
const toolkitInfo = await callWithRetry(() => this.lookupToolkit(resolvedEnvironment, stackSdk, options.toolkitStackName));
|
|
70
|
+
const { stackSdk, resolvedEnvironment, cloudFormationRoleArn, envResources, } = await this.prepareSdkFor(options.stack, options.roleArn, Mode.ForWriting);
|
|
69
71
|
// Do a verification of the bootstrap stack version
|
|
70
|
-
await this.validateBootstrapStackVersion(options.stack.stackName, options.stack.requiresBootstrapStackVersion, options.stack.bootstrapStackVersionSsmParameter,
|
|
72
|
+
await this.validateBootstrapStackVersion(options.stack.stackName, options.stack.requiresBootstrapStackVersion, options.stack.bootstrapStackVersionSsmParameter, envResources);
|
|
71
73
|
// Deploy assets
|
|
72
74
|
const assetArtifacts = options.stack.dependencies.filter(cxapi.AssetManifestArtifact.isAssetManifestArtifact);
|
|
73
75
|
for (const asset of assetArtifacts) {
|
|
@@ -89,7 +91,7 @@ export class Deployments {
|
|
|
89
91
|
sdkProvider: this.sdkProvider,
|
|
90
92
|
roleArn: cloudFormationRoleArn,
|
|
91
93
|
reuseAssets: options.reuseAssets,
|
|
92
|
-
|
|
94
|
+
envResources,
|
|
93
95
|
tags: options.tags,
|
|
94
96
|
deploymentMethod,
|
|
95
97
|
force: options.force,
|
|
@@ -129,6 +131,7 @@ export class Deployments {
|
|
|
129
131
|
return {
|
|
130
132
|
resolvedEnvironment: result.resolvedEnvironment,
|
|
131
133
|
stackSdk: result.sdk,
|
|
134
|
+
envResources: result.envResources,
|
|
132
135
|
};
|
|
133
136
|
}
|
|
134
137
|
}
|
|
@@ -164,6 +167,7 @@ export class Deployments {
|
|
|
164
167
|
stackSdk: stackSdk.sdk,
|
|
165
168
|
resolvedEnvironment,
|
|
166
169
|
cloudFormationRoleArn: arns.cloudFormationRoleArn,
|
|
170
|
+
envResources: this.environmentResources.for(resolvedEnvironment, stackSdk.sdk),
|
|
167
171
|
};
|
|
168
172
|
}
|
|
169
173
|
/**
|
|
@@ -198,11 +202,12 @@ export class Deployments {
|
|
|
198
202
|
assumeRoleArn: arns.lookupRoleArn,
|
|
199
203
|
assumeRoleExternalId: stack.lookupRole?.assumeRoleExternalId,
|
|
200
204
|
});
|
|
205
|
+
const envResources = this.environmentResources.for(resolvedEnvironment, stackSdk.sdk);
|
|
201
206
|
// if we succeed in assuming the lookup role, make sure we have the correct bootstrap stack version
|
|
202
207
|
if (stackSdk.didAssumeRole &&
|
|
203
208
|
stack.lookupRole?.bootstrapStackVersionSsmParameter &&
|
|
204
209
|
stack.lookupRole.requiresBootstrapStackVersion) {
|
|
205
|
-
const version = await
|
|
210
|
+
const version = await envResources.versionFromSsmParameter(stack.lookupRole.bootstrapStackVersionSsmParameter);
|
|
206
211
|
if (version < stack.lookupRole.requiresBootstrapStackVersion) {
|
|
207
212
|
throw new Error(`Bootstrap stack version '${stack.lookupRole.requiresBootstrapStackVersion}' is required, found version '${version}'.`);
|
|
208
213
|
}
|
|
@@ -213,7 +218,7 @@ export class Deployments {
|
|
|
213
218
|
stack.lookupRole?.requiresBootstrapStackVersion) {
|
|
214
219
|
warning(upgradeMessage);
|
|
215
220
|
}
|
|
216
|
-
return { ...stackSdk, resolvedEnvironment };
|
|
221
|
+
return { ...stackSdk, resolvedEnvironment, envResources };
|
|
217
222
|
}
|
|
218
223
|
catch (e) {
|
|
219
224
|
debug(e);
|
|
@@ -226,26 +231,11 @@ export class Deployments {
|
|
|
226
231
|
throw e;
|
|
227
232
|
}
|
|
228
233
|
}
|
|
229
|
-
/**
|
|
230
|
-
* Look up the toolkit for a given environment, using a given SDK
|
|
231
|
-
*/
|
|
232
|
-
async lookupToolkit(resolvedEnvironment, sdk, toolkitStackName) {
|
|
233
|
-
const key = `${resolvedEnvironment.account}:${resolvedEnvironment.region}:${toolkitStackName}`;
|
|
234
|
-
const existing = this.toolkitInfoCache.get(key);
|
|
235
|
-
if (existing) {
|
|
236
|
-
return existing;
|
|
237
|
-
}
|
|
238
|
-
const ret = await ToolkitInfo.lookup(resolvedEnvironment, sdk, toolkitStackName);
|
|
239
|
-
this.toolkitInfoCache.set(key, ret);
|
|
240
|
-
return ret;
|
|
241
|
-
}
|
|
242
234
|
async prepareAndValidateAssets(asset, options) {
|
|
243
|
-
const {
|
|
244
|
-
|
|
245
|
-
const stackEnv = await this.sdkProvider.resolveEnvironment(options.stack.environment);
|
|
246
|
-
await this.validateBootstrapStackVersion(options.stack.stackName, asset.requiresBootstrapStackVersion, asset.bootstrapStackVersionSsmParameter, toolkitInfo);
|
|
235
|
+
const { envResources } = await this.prepareSdkFor(options.stack, options.roleArn, Mode.ForWriting);
|
|
236
|
+
await this.validateBootstrapStackVersion(options.stack.stackName, asset.requiresBootstrapStackVersion, asset.bootstrapStackVersionSsmParameter, envResources);
|
|
247
237
|
const manifest = AssetManifest.fromFile(asset.file);
|
|
248
|
-
return { manifest, stackEnv };
|
|
238
|
+
return { manifest, stackEnv: envResources.environment };
|
|
249
239
|
}
|
|
250
240
|
/**
|
|
251
241
|
* Build all assets in a manifest
|
|
@@ -270,10 +260,9 @@ export class Deployments {
|
|
|
270
260
|
*/
|
|
271
261
|
// eslint-disable-next-line max-len
|
|
272
262
|
async buildSingleAsset(assetArtifact, assetManifest, asset, options) {
|
|
273
|
-
const {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
const publisher = this.cachedPublisher(assetManifest, stackEnv, options.stackName);
|
|
263
|
+
const { resolvedEnvironment, envResources } = await this.prepareSdkFor(options.stack, options.roleArn, Mode.ForWriting);
|
|
264
|
+
await this.validateBootstrapStackVersion(options.stack.stackName, assetArtifact.requiresBootstrapStackVersion, assetArtifact.bootstrapStackVersionSsmParameter, envResources);
|
|
265
|
+
const publisher = this.cachedPublisher(assetManifest, resolvedEnvironment, options.stackName);
|
|
277
266
|
await publisher.buildEntry(asset);
|
|
278
267
|
}
|
|
279
268
|
/**
|
|
@@ -296,13 +285,12 @@ export class Deployments {
|
|
|
296
285
|
}
|
|
297
286
|
/**
|
|
298
287
|
* Validate that the bootstrap stack has the right version for this stack
|
|
288
|
+
*
|
|
289
|
+
* Call into envResources.validateVersion, but prepend the stack name in case of failure.
|
|
299
290
|
*/
|
|
300
|
-
async validateBootstrapStackVersion(stackName, requiresBootstrapStackVersion, bootstrapStackVersionSsmParameter,
|
|
301
|
-
if (requiresBootstrapStackVersion === undefined) {
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
291
|
+
async validateBootstrapStackVersion(stackName, requiresBootstrapStackVersion, bootstrapStackVersionSsmParameter, envResources) {
|
|
304
292
|
try {
|
|
305
|
-
await
|
|
293
|
+
await envResources.validateVersion(requiresBootstrapStackVersion, bootstrapStackVersionSsmParameter);
|
|
306
294
|
}
|
|
307
295
|
catch (e) {
|
|
308
296
|
throw new Error(`${stackName}: ${e.message}`);
|
package/cli/commands/bind.js
CHANGED
|
@@ -81,13 +81,10 @@ export const bind = (program) => program
|
|
|
81
81
|
});
|
|
82
82
|
async function buildApp() {
|
|
83
83
|
const [_metafile, sstConfig] = await Stacks.load(project.paths.config);
|
|
84
|
-
const cwd = process.cwd();
|
|
85
|
-
process.chdir(project.paths.root);
|
|
86
84
|
await Stacks.synth({
|
|
87
85
|
fn: sstConfig.stacks,
|
|
88
86
|
mode: "remove",
|
|
89
87
|
});
|
|
90
|
-
process.chdir(cwd);
|
|
91
88
|
}
|
|
92
89
|
function isInSsrSite() {
|
|
93
90
|
const cwd = process.cwd();
|
package/cli/commands/types.js
CHANGED
|
@@ -8,10 +8,20 @@ export const types = (program) => program.command("types", "Generate resource ty
|
|
|
8
8
|
try {
|
|
9
9
|
const project = useProject();
|
|
10
10
|
const [_metafile, sstConfig] = await Stacks.load(project.paths.config);
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
// Note: do not run synth which requires AWS credentials. B/c generating
|
|
12
|
+
// types is usually done inside CI pipelines. And credentials
|
|
13
|
+
// might not be available. ie.
|
|
14
|
+
// await Stacks.synth({
|
|
15
|
+
// fn: sstConfig.stacks,
|
|
16
|
+
// mode: "remove",
|
|
17
|
+
// });
|
|
18
|
+
const app = new App({
|
|
13
19
|
mode: "remove",
|
|
20
|
+
stage: project.config.stage,
|
|
21
|
+
name: project.config.name,
|
|
22
|
+
region: project.config.region,
|
|
14
23
|
});
|
|
24
|
+
sstConfig.stacks(app);
|
|
15
25
|
Colors.line(Colors.success(`✔ `), `Types generated in ${path.resolve(project.paths.out, "types")}`);
|
|
16
26
|
await exit();
|
|
17
27
|
}
|
package/cli/sst.js
CHANGED
|
@@ -3,7 +3,6 @@ import { blue, red } from "colorette";
|
|
|
3
3
|
import { program } from "./program.js";
|
|
4
4
|
import { SilentError, VisibleError } from "../error.js";
|
|
5
5
|
import { useSpinners } from "./spinner.js";
|
|
6
|
-
import { Logger } from "../logger.js";
|
|
7
6
|
import dotenv from "dotenv";
|
|
8
7
|
dotenv.config({
|
|
9
8
|
override: true,
|
|
@@ -48,7 +47,6 @@ if ("setSourceMapsEnabled" in process) {
|
|
|
48
47
|
}
|
|
49
48
|
process.removeAllListeners("uncaughtException");
|
|
50
49
|
process.on("uncaughtException", (err) => {
|
|
51
|
-
Logger.debug(err);
|
|
52
50
|
const spinners = useSpinners();
|
|
53
51
|
for (const spinner of spinners) {
|
|
54
52
|
if (spinner.isSpinning)
|
package/constructs/BaseSite.d.ts
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { ErrorResponse, DistributionProps, BehaviorOptions, IOrigin } from "aws-cdk-lib/aws-cloudfront";
|
|
2
2
|
export interface BaseSiteFileOptions {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
filters: {
|
|
4
|
+
[key in "include" | "exclude"]?: string;
|
|
5
|
+
}[];
|
|
6
|
+
cacheControl?: string;
|
|
6
7
|
contentType?: string;
|
|
8
|
+
contentEncoding?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface BaseSiteFileOptionsDeprecated {
|
|
11
|
+
include?: string | string[];
|
|
12
|
+
exclude?: string | string[];
|
|
13
|
+
cacheControl?: string;
|
|
14
|
+
contentType?: string;
|
|
15
|
+
contentEncoding?: string;
|
|
7
16
|
}
|
|
8
17
|
export interface BaseSiteEnvironmentOutputsInfo {
|
|
9
18
|
path: string;
|
|
@@ -132,7 +132,7 @@ export declare class Distribution extends Construct {
|
|
|
132
132
|
hostedZone: IHostedZone | undefined;
|
|
133
133
|
certificate: ICertificate | undefined;
|
|
134
134
|
};
|
|
135
|
-
createInvalidation(buildId?: string): CustomResource;
|
|
135
|
+
createInvalidation(buildId?: string, paths?: string[]): CustomResource;
|
|
136
136
|
private validateCloudFrontDistributionSettings;
|
|
137
137
|
private validateCustomDomainSettings;
|
|
138
138
|
private lookupHostedZone;
|
|
@@ -70,7 +70,7 @@ export class Distribution extends Construct {
|
|
|
70
70
|
certificate: this.certificate,
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
|
-
createInvalidation(buildId) {
|
|
73
|
+
createInvalidation(buildId, paths) {
|
|
74
74
|
const stack = Stack.of(this);
|
|
75
75
|
const policy = new Policy(this.scope, "CloudFrontInvalidatorPolicy", {
|
|
76
76
|
statements: [
|
|
@@ -93,7 +93,7 @@ export class Distribution extends Construct {
|
|
|
93
93
|
properties: {
|
|
94
94
|
buildId: buildId || Date.now().toString(),
|
|
95
95
|
distributionId: this.distribution.distributionId,
|
|
96
|
-
paths: ["/*"],
|
|
96
|
+
paths: paths ?? ["/*"],
|
|
97
97
|
waitForInvalidation: this.props.waitForInvalidation,
|
|
98
98
|
},
|
|
99
99
|
});
|
|
@@ -3,6 +3,7 @@ import { Runtime, FunctionProps, Architecture } from "aws-cdk-lib/aws-lambda";
|
|
|
3
3
|
import { SsrSite, SsrSiteNormalizedProps, SsrSiteProps } from "./SsrSite.js";
|
|
4
4
|
import { Size } from "./util/size.js";
|
|
5
5
|
import { Bucket } from "aws-cdk-lib/aws-s3";
|
|
6
|
+
import { CachePolicyProps } from "aws-cdk-lib/aws-cloudfront";
|
|
6
7
|
export interface NextjsSiteProps extends Omit<SsrSiteProps, "nodejs"> {
|
|
7
8
|
imageOptimization?: {
|
|
8
9
|
/**
|
|
@@ -101,6 +102,7 @@ export declare class NextjsSite extends SsrSite {
|
|
|
101
102
|
props: NextjsSiteNormalizedProps;
|
|
102
103
|
private buildId?;
|
|
103
104
|
constructor(scope: Construct, id: string, props?: NextjsSiteProps);
|
|
105
|
+
static buildDefaultServerCachePolicyProps(): CachePolicyProps;
|
|
104
106
|
protected plan(bucket: Bucket): {
|
|
105
107
|
cloudFrontFunctions?: {
|
|
106
108
|
serverCfFunction: {
|
package/constructs/NextjsSite.js
CHANGED
|
@@ -12,6 +12,13 @@ import { toCdkSize } from "./util/size.js";
|
|
|
12
12
|
import { PolicyStatement } from "aws-cdk-lib/aws-iam";
|
|
13
13
|
import { RetentionDays } from "aws-cdk-lib/aws-logs";
|
|
14
14
|
import { VisibleError } from "../error.js";
|
|
15
|
+
const DEFAULT_CACHE_POLICY_ALLOWED_HEADERS = [
|
|
16
|
+
"accept",
|
|
17
|
+
"rsc",
|
|
18
|
+
"next-router-prefetch",
|
|
19
|
+
"next-router-state-tree",
|
|
20
|
+
"next-url",
|
|
21
|
+
];
|
|
15
22
|
/**
|
|
16
23
|
* The `NextjsSite` construct is a higher level CDK construct that makes it easy to create a Next.js app.
|
|
17
24
|
* @example
|
|
@@ -52,6 +59,9 @@ export class NextjsSite extends SsrSite {
|
|
|
52
59
|
}
|
|
53
60
|
}
|
|
54
61
|
}
|
|
62
|
+
static buildDefaultServerCachePolicyProps() {
|
|
63
|
+
return super.buildDefaultServerCachePolicyProps(DEFAULT_CACHE_POLICY_ALLOWED_HEADERS);
|
|
64
|
+
}
|
|
55
65
|
plan(bucket) {
|
|
56
66
|
const { path: sitePath, edge, experimental, imageOptimization, } = this.props;
|
|
57
67
|
const serverConfig = {
|
|
@@ -184,13 +194,7 @@ export class NextjsSite extends SsrSite {
|
|
|
184
194
|
origin: "s3",
|
|
185
195
|
})),
|
|
186
196
|
],
|
|
187
|
-
cachePolicyAllowedHeaders:
|
|
188
|
-
"accept",
|
|
189
|
-
"rsc",
|
|
190
|
-
"next-router-prefetch",
|
|
191
|
-
"next-router-state-tree",
|
|
192
|
-
"next-url",
|
|
193
|
-
],
|
|
197
|
+
cachePolicyAllowedHeaders: DEFAULT_CACHE_POLICY_ALLOWED_HEADERS,
|
|
194
198
|
buildId: this.getBuildId(),
|
|
195
199
|
warmerConfig: {
|
|
196
200
|
function: path.join(sitePath, ".open-next", "warmer-function"),
|
|
@@ -287,15 +291,22 @@ export class NextjsSite extends SsrSite {
|
|
|
287
291
|
};
|
|
288
292
|
}
|
|
289
293
|
wrapHandler() {
|
|
290
|
-
const { path: sitePath } = this.props;
|
|
294
|
+
const { path: sitePath, experimental } = this.props;
|
|
291
295
|
const wrapperName = "nextjssite-index";
|
|
292
296
|
const serverPath = path.join(sitePath, ".open-next", "server-function");
|
|
293
|
-
fs.writeFileSync(path.join(serverPath, `${wrapperName}.mjs`),
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
297
|
+
fs.writeFileSync(path.join(serverPath, `${wrapperName}.mjs`), experimental?.streaming
|
|
298
|
+
? [
|
|
299
|
+
`export const handler = awslambda.streamifyResponse(async (...args) => {`,
|
|
300
|
+
` const { handler: rawHandler} = await import("./index.mjs");`,
|
|
301
|
+
` return rawHandler(...args);`,
|
|
302
|
+
`});`,
|
|
303
|
+
].join("\n")
|
|
304
|
+
: [
|
|
305
|
+
`export const handler = async (...args) => {`,
|
|
306
|
+
` const { handler: rawHandler} = await import("./index.mjs");`,
|
|
307
|
+
` return rawHandler(...args);`,
|
|
308
|
+
`};`,
|
|
309
|
+
].join("\n"));
|
|
299
310
|
return `${wrapperName}.handler`;
|
|
300
311
|
}
|
|
301
312
|
getRoutes() {
|
package/constructs/Script.d.ts
CHANGED
|
@@ -51,8 +51,7 @@ export interface ScriptProps {
|
|
|
51
51
|
function?: FunctionProps;
|
|
52
52
|
};
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
54
|
+
* Specifies the function to be run once when the Script construct is created.
|
|
56
55
|
* @example
|
|
57
56
|
* ```js
|
|
58
57
|
* new Script(stack, "Api", {
|
|
@@ -62,8 +61,11 @@ export interface ScriptProps {
|
|
|
62
61
|
*/
|
|
63
62
|
onCreate?: FunctionDefinition;
|
|
64
63
|
/**
|
|
65
|
-
*
|
|
64
|
+
* Specifies the function to be run each time the Script construct is redeployed. If a version is provided,
|
|
65
|
+
* the function is only executed when the version changes.
|
|
66
66
|
*
|
|
67
|
+
* Note that the `onUpdate` function is not run during the initial creation of the Script construct.
|
|
68
|
+
* For initial creation, use `onCreate`.
|
|
67
69
|
* @example
|
|
68
70
|
* ```js
|
|
69
71
|
* new Script(stack, "Api", {
|
|
@@ -73,8 +75,8 @@ export interface ScriptProps {
|
|
|
73
75
|
*/
|
|
74
76
|
onUpdate?: FunctionDefinition;
|
|
75
77
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
+
* Specifies the function to be run once when the Script construct is deleted from the stack or
|
|
79
|
+
* when the entire stack is removed from the app.
|
|
78
80
|
* @example
|
|
79
81
|
* ```js
|
|
80
82
|
* new Script(stack, "Api", {
|