sst 2.13.9 → 2.14.0
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/constructs/EdgeFunction.d.ts +1 -0
- package/constructs/EdgeFunction.js +11 -0
- package/constructs/NextjsSite.d.ts +4 -0
- package/constructs/NextjsSite.js +50 -6
- package/constructs/SsrSite.d.ts +10 -8
- package/constructs/SsrSite.js +38 -19
- package/constructs/StaticSite.js +7 -1
- package/constructs/deprecated/NextjsSite.js +6 -1
- package/package.json +1 -1
- package/support/base-site-archiver.mjs +13 -13
|
@@ -31,6 +31,7 @@ export declare class EdgeFunction extends Construct {
|
|
|
31
31
|
constructor(scope: Construct, id: string, props: EdgeFunctionProps);
|
|
32
32
|
get currentVersion(): IVersion;
|
|
33
33
|
attachPermissions(permissions: Permissions): void;
|
|
34
|
+
addEnvironment(key: string, value: string): void;
|
|
34
35
|
private buildAssetFromHandler;
|
|
35
36
|
private buildAssetFromBundle;
|
|
36
37
|
private bind;
|
|
@@ -89,6 +89,17 @@ export class EdgeFunction extends Construct {
|
|
|
89
89
|
attachPermissions(permissions) {
|
|
90
90
|
attachPermissionsToRole(this.role, permissions);
|
|
91
91
|
}
|
|
92
|
+
addEnvironment(key, value) {
|
|
93
|
+
// Note: addEnvironment currently only updates AssetReplacer's
|
|
94
|
+
// "_SST_FUNCTION_ENVIRONMENT_" replacements
|
|
95
|
+
this.props.environment[key] = value;
|
|
96
|
+
const cfnReplacer = this.assetReplacer.node
|
|
97
|
+
.defaultChild;
|
|
98
|
+
cfnReplacer.addPropertyOverride("replacements.0.replace", JSON.stringify({
|
|
99
|
+
...this.props.environment,
|
|
100
|
+
...this.bindingEnvs,
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
92
103
|
buildAssetFromHandler(onBundled) {
|
|
93
104
|
const { nodejs } = this.props;
|
|
94
105
|
useFunctions().add(this.node.addr, {
|
|
@@ -42,11 +42,15 @@ export declare class NextjsSite extends SsrSite {
|
|
|
42
42
|
waitForInvalidation: Exclude<NextjsSiteProps["waitForInvalidation"], undefined>;
|
|
43
43
|
};
|
|
44
44
|
constructor(scope: Construct, id: string, props?: NextjsSiteProps);
|
|
45
|
+
protected createRevalidation(): void;
|
|
45
46
|
protected initBuildConfig(): {
|
|
46
47
|
typesPath: string;
|
|
47
48
|
serverBuildOutputFile: string;
|
|
48
49
|
clientBuildOutputDir: string;
|
|
49
50
|
clientBuildVersionedSubDir: string;
|
|
51
|
+
clientBuildS3KeyPrefix: string;
|
|
52
|
+
prerenderedBuildOutputDir: string;
|
|
53
|
+
prerenderedBuildS3KeyPrefix: string;
|
|
50
54
|
};
|
|
51
55
|
protected createFunctionForRegional(): CdkFunction;
|
|
52
56
|
protected createFunctionForEdge(): EdgeFunction;
|
package/constructs/NextjsSite.js
CHANGED
|
@@ -8,6 +8,8 @@ import { Distribution, ViewerProtocolPolicy, AllowedMethods, LambdaEdgeEventType
|
|
|
8
8
|
import { S3Origin, HttpOrigin, OriginGroup, } from "aws-cdk-lib/aws-cloudfront-origins";
|
|
9
9
|
import { Rule, Schedule } from "aws-cdk-lib/aws-events";
|
|
10
10
|
import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
|
|
11
|
+
import { Queue } from "aws-cdk-lib/aws-sqs";
|
|
12
|
+
import { SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
|
|
11
13
|
import { Stack } from "./Stack.js";
|
|
12
14
|
import { SsrFunction } from "./SsrFunction.js";
|
|
13
15
|
import { EdgeFunction } from "./EdgeFunction.js";
|
|
@@ -28,10 +30,34 @@ import { toCdkDuration } from "./util/duration.js";
|
|
|
28
30
|
export class NextjsSite extends SsrSite {
|
|
29
31
|
constructor(scope, id, props) {
|
|
30
32
|
super(scope, id, {
|
|
31
|
-
buildCommand: "npx --yes open-next@
|
|
33
|
+
buildCommand: "npx --yes open-next@2.0.0 build",
|
|
32
34
|
...props,
|
|
33
35
|
});
|
|
36
|
+
if (this.doNotDeploy)
|
|
37
|
+
return;
|
|
34
38
|
this.createWarmer();
|
|
39
|
+
this.createRevalidation();
|
|
40
|
+
}
|
|
41
|
+
createRevalidation() {
|
|
42
|
+
if (!this.serverLambdaForRegional && !this.serverLambdaForEdge)
|
|
43
|
+
return;
|
|
44
|
+
const queue = new Queue(this, "RevalidationQueue", {
|
|
45
|
+
fifo: true,
|
|
46
|
+
receiveMessageWaitTime: CdkDuration.seconds(20),
|
|
47
|
+
});
|
|
48
|
+
const consumer = new CdkFunction(this, "RevalidationFunction", {
|
|
49
|
+
description: "Next.js revalidator",
|
|
50
|
+
handler: "index.handler",
|
|
51
|
+
code: Code.fromAsset(path.join(this.props.path, ".open-next", "revalidation-function")),
|
|
52
|
+
runtime: Runtime.NODEJS_18_X,
|
|
53
|
+
timeout: CdkDuration.seconds(30),
|
|
54
|
+
});
|
|
55
|
+
consumer.addEventSource(new SqsEventSource(queue, { batchSize: 5 }));
|
|
56
|
+
// Allow server to send messages to the queue
|
|
57
|
+
const server = this.serverLambdaForRegional || this.serverLambdaForEdge;
|
|
58
|
+
server?.addEnvironment("REVALIDATION_QUEUE_URL", queue.queueUrl);
|
|
59
|
+
server?.addEnvironment("REVALIDATION_QUEUE_REGION", Stack.of(this).region);
|
|
60
|
+
queue.grantSendMessages(server?.role);
|
|
35
61
|
}
|
|
36
62
|
initBuildConfig() {
|
|
37
63
|
return {
|
|
@@ -39,6 +65,9 @@ export class NextjsSite extends SsrSite {
|
|
|
39
65
|
serverBuildOutputFile: ".open-next/server-function/index.mjs",
|
|
40
66
|
clientBuildOutputDir: ".open-next/assets",
|
|
41
67
|
clientBuildVersionedSubDir: "_next",
|
|
68
|
+
clientBuildS3KeyPrefix: "_assets",
|
|
69
|
+
prerenderedBuildOutputDir: ".open-next/cache",
|
|
70
|
+
prerenderedBuildS3KeyPrefix: "_cache",
|
|
42
71
|
};
|
|
43
72
|
}
|
|
44
73
|
createFunctionForRegional() {
|
|
@@ -52,7 +81,12 @@ export class NextjsSite extends SsrSite {
|
|
|
52
81
|
memorySize,
|
|
53
82
|
bind,
|
|
54
83
|
permissions,
|
|
55
|
-
environment
|
|
84
|
+
environment: {
|
|
85
|
+
...environment,
|
|
86
|
+
CACHE_BUCKET_NAME: this.bucket.bucketName,
|
|
87
|
+
CACHE_BUCKET_KEY_PREFIX: "_cache",
|
|
88
|
+
CACHE_BUCKET_REGION: Stack.of(this).region,
|
|
89
|
+
},
|
|
56
90
|
...cdk?.server,
|
|
57
91
|
});
|
|
58
92
|
return ssrFn.function;
|
|
@@ -67,7 +101,12 @@ export class NextjsSite extends SsrSite {
|
|
|
67
101
|
memorySize,
|
|
68
102
|
bind,
|
|
69
103
|
permissions,
|
|
70
|
-
environment
|
|
104
|
+
environment: {
|
|
105
|
+
...environment,
|
|
106
|
+
CACHE_BUCKET_NAME: this.bucket.bucketName,
|
|
107
|
+
CACHE_BUCKET_KEY_PREFIX: "_cache",
|
|
108
|
+
CACHE_BUCKET_REGION: Stack.of(this).region,
|
|
109
|
+
},
|
|
71
110
|
});
|
|
72
111
|
}
|
|
73
112
|
createImageOptimizationFunction() {
|
|
@@ -90,6 +129,7 @@ export class NextjsSite extends SsrSite {
|
|
|
90
129
|
architecture: Architecture.ARM_64,
|
|
91
130
|
environment: {
|
|
92
131
|
BUCKET_NAME: this.cdk.bucket.bucketName,
|
|
132
|
+
BUCKET_KEY_PREFIX: "_assets",
|
|
93
133
|
},
|
|
94
134
|
initialPolicy: [
|
|
95
135
|
new PolicyStatement({
|
|
@@ -201,7 +241,9 @@ export class NextjsSite extends SsrSite {
|
|
|
201
241
|
*/
|
|
202
242
|
const { timeout, cdk } = this.props;
|
|
203
243
|
const cfDistributionProps = cdk?.distribution || {};
|
|
204
|
-
const s3Origin = new S3Origin(this.cdk.bucket
|
|
244
|
+
const s3Origin = new S3Origin(this.cdk.bucket, {
|
|
245
|
+
originPath: "/" + this.buildConfig.clientBuildS3KeyPrefix,
|
|
246
|
+
});
|
|
205
247
|
const serverFnUrl = this.serverLambdaForRegional.addFunctionUrl({
|
|
206
248
|
authType: FunctionUrlAuthType.NONE,
|
|
207
249
|
});
|
|
@@ -240,7 +282,9 @@ export class NextjsSite extends SsrSite {
|
|
|
240
282
|
createCloudFrontDistributionForEdge() {
|
|
241
283
|
const { cdk } = this.props;
|
|
242
284
|
const cfDistributionProps = cdk?.distribution || {};
|
|
243
|
-
const s3Origin = new S3Origin(this.cdk.bucket
|
|
285
|
+
const s3Origin = new S3Origin(this.cdk.bucket, {
|
|
286
|
+
originPath: "/" + this.buildConfig.clientBuildS3KeyPrefix,
|
|
287
|
+
});
|
|
244
288
|
const cachePolicy = cdk?.serverCachePolicy ??
|
|
245
289
|
this.buildServerCachePolicy([
|
|
246
290
|
"accept",
|
|
@@ -249,7 +293,7 @@ export class NextjsSite extends SsrSite {
|
|
|
249
293
|
"next-router-state-tree",
|
|
250
294
|
]);
|
|
251
295
|
const originRequestPolicy = this.buildServerOriginRequestPolicy();
|
|
252
|
-
const functionVersion = this.
|
|
296
|
+
const functionVersion = this.serverLambdaForEdge.currentVersion;
|
|
253
297
|
const serverBehavior = this.buildServerBehaviorForEdge(functionVersion, s3Origin, cachePolicy, originRequestPolicy);
|
|
254
298
|
return new Distribution(this, "Distribution", {
|
|
255
299
|
// these values can be overwritten by cfDistributionProps
|
package/constructs/SsrSite.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Construct } from "constructs";
|
|
2
2
|
import { Bucket, BucketProps, IBucket } from "aws-cdk-lib/aws-s3";
|
|
3
|
-
import { Function as CdkFunction, FunctionProps } from "aws-cdk-lib/aws-lambda";
|
|
3
|
+
import { Function as CdkFunction, IFunction as ICdkFunction, FunctionProps } from "aws-cdk-lib/aws-lambda";
|
|
4
4
|
import { IHostedZone } from "aws-cdk-lib/aws-route53";
|
|
5
5
|
import { Distribution, ICachePolicy, IResponseHeadersPolicy, BehaviorOptions, CachePolicy, Function as CfFunction, FunctionEventType as CfFunctionEventType } from "aws-cdk-lib/aws-cloudfront";
|
|
6
6
|
import { ICertificate } from "aws-cdk-lib/aws-certificatemanager";
|
|
@@ -18,7 +18,9 @@ export type SsrBuildConfig = {
|
|
|
18
18
|
serverCFFunctionInjection?: string;
|
|
19
19
|
clientBuildOutputDir: string;
|
|
20
20
|
clientBuildVersionedSubDir: string;
|
|
21
|
+
clientBuildS3KeyPrefix?: string;
|
|
21
22
|
prerenderedBuildOutputDir?: string;
|
|
23
|
+
prerenderedBuildS3KeyPrefix?: string;
|
|
22
24
|
};
|
|
23
25
|
export interface SsrSiteNodeJSProps extends NodeJSProps {
|
|
24
26
|
}
|
|
@@ -211,13 +213,13 @@ type SsrSiteNormalizedProps = SsrSiteProps & {
|
|
|
211
213
|
export declare abstract class SsrSite extends Construct implements SSTConstruct {
|
|
212
214
|
readonly id: string;
|
|
213
215
|
protected props: SsrSiteNormalizedProps;
|
|
214
|
-
|
|
216
|
+
protected doNotDeploy: boolean;
|
|
215
217
|
protected buildConfig: SsrBuildConfig;
|
|
216
|
-
|
|
217
|
-
|
|
218
|
+
private serverLambdaCdkFunctionForEdge?;
|
|
219
|
+
protected serverLambdaForEdge?: EdgeFunction;
|
|
218
220
|
protected serverLambdaForRegional?: CdkFunction;
|
|
219
221
|
private serverLambdaForDev?;
|
|
220
|
-
|
|
222
|
+
protected bucket: Bucket;
|
|
221
223
|
private cfFunction;
|
|
222
224
|
private distribution;
|
|
223
225
|
private hostedZone?;
|
|
@@ -236,7 +238,7 @@ export declare abstract class SsrSite extends Construct implements SSTConstruct
|
|
|
236
238
|
* The internally created CDK resources.
|
|
237
239
|
*/
|
|
238
240
|
get cdk(): {
|
|
239
|
-
function:
|
|
241
|
+
function: ICdkFunction | undefined;
|
|
240
242
|
bucket: Bucket;
|
|
241
243
|
distribution: Distribution;
|
|
242
244
|
hostedZone: IHostedZone | undefined;
|
|
@@ -278,8 +280,8 @@ export declare abstract class SsrSite extends Construct implements SSTConstruct
|
|
|
278
280
|
protected createFunctionForRegional(): CdkFunction;
|
|
279
281
|
protected createFunctionForEdge(): EdgeFunction;
|
|
280
282
|
protected createFunctionForDev(): CdkFunction;
|
|
281
|
-
private
|
|
282
|
-
private
|
|
283
|
+
private grantServerS3Permissions;
|
|
284
|
+
private grantServerCloudFrontPermissions;
|
|
283
285
|
private validateCloudFrontDistributionSettings;
|
|
284
286
|
private createCloudFrontFunction;
|
|
285
287
|
protected createCloudFrontDistributionForRegional(): Distribution;
|
package/constructs/SsrSite.js
CHANGED
|
@@ -46,7 +46,7 @@ export class SsrSite extends Construct {
|
|
|
46
46
|
props;
|
|
47
47
|
doNotDeploy;
|
|
48
48
|
buildConfig;
|
|
49
|
-
|
|
49
|
+
serverLambdaCdkFunctionForEdge;
|
|
50
50
|
serverLambdaForEdge;
|
|
51
51
|
serverLambdaForRegional;
|
|
52
52
|
serverLambdaForDev;
|
|
@@ -88,17 +88,16 @@ export class SsrSite extends Construct {
|
|
|
88
88
|
this.bucket = this.createS3Bucket();
|
|
89
89
|
// Create Server functions
|
|
90
90
|
if (this.props.edge) {
|
|
91
|
-
this.
|
|
92
|
-
this.
|
|
93
|
-
functionArn: this.
|
|
94
|
-
role: this.
|
|
91
|
+
this.serverLambdaForEdge = this.createFunctionForEdge();
|
|
92
|
+
this.serverLambdaCdkFunctionForEdge = CdkFunction.fromFunctionAttributes(this, "IEdgeFunction", {
|
|
93
|
+
functionArn: this.serverLambdaForEdge.functionArn,
|
|
94
|
+
role: this.serverLambdaForEdge.role,
|
|
95
95
|
});
|
|
96
|
-
this.createFunctionPermissionsForEdge();
|
|
97
96
|
}
|
|
98
97
|
else {
|
|
99
98
|
this.serverLambdaForRegional = this.createFunctionForRegional();
|
|
100
|
-
this.createFunctionPermissionsForRegional();
|
|
101
99
|
}
|
|
100
|
+
this.grantServerS3Permissions();
|
|
102
101
|
// Create Custom Domain
|
|
103
102
|
this.validateCustomDomainSettings();
|
|
104
103
|
this.hostedZone = this.lookupHostedZone();
|
|
@@ -114,6 +113,7 @@ export class SsrSite extends Construct {
|
|
|
114
113
|
? this.createCloudFrontDistributionForEdge()
|
|
115
114
|
: this.createCloudFrontDistributionForRegional();
|
|
116
115
|
this.distribution.node.addDependency(s3deployCR);
|
|
116
|
+
this.grantServerCloudFrontPermissions();
|
|
117
117
|
// Invalidate CloudFront
|
|
118
118
|
this.createCloudFrontInvalidation();
|
|
119
119
|
// Connect Custom Domain to CloudFront Distribution
|
|
@@ -154,7 +154,7 @@ export class SsrSite extends Construct {
|
|
|
154
154
|
if (this.doNotDeploy)
|
|
155
155
|
return;
|
|
156
156
|
return {
|
|
157
|
-
function: this.
|
|
157
|
+
function: this.serverLambdaCdkFunctionForEdge || this.serverLambdaForRegional,
|
|
158
158
|
bucket: this.bucket,
|
|
159
159
|
distribution: this.distribution,
|
|
160
160
|
hostedZone: this.hostedZone,
|
|
@@ -174,7 +174,7 @@ export class SsrSite extends Construct {
|
|
|
174
174
|
* ```
|
|
175
175
|
*/
|
|
176
176
|
attachPermissions(permissions) {
|
|
177
|
-
const server = this.
|
|
177
|
+
const server = this.serverLambdaCdkFunctionForEdge ||
|
|
178
178
|
this.serverLambdaForRegional ||
|
|
179
179
|
this.serverLambdaForDev;
|
|
180
180
|
attachPermissionsToRole(server?.role, permissions);
|
|
@@ -192,7 +192,7 @@ export class SsrSite extends Construct {
|
|
|
192
192
|
edge: this.props.edge,
|
|
193
193
|
server: (this.serverLambdaForDev ||
|
|
194
194
|
this.serverLambdaForRegional ||
|
|
195
|
-
this.
|
|
195
|
+
this.serverLambdaCdkFunctionForEdge)?.functionArn,
|
|
196
196
|
secrets: (this.props.bind || [])
|
|
197
197
|
.filter((c) => c instanceof Secret)
|
|
198
198
|
.map((c) => c.name),
|
|
@@ -298,14 +298,20 @@ export class SsrSite extends Construct {
|
|
|
298
298
|
: 200;
|
|
299
299
|
const result = spawn.sync("node", [
|
|
300
300
|
script,
|
|
301
|
-
[
|
|
302
|
-
|
|
301
|
+
Buffer.from(JSON.stringify([
|
|
302
|
+
{
|
|
303
|
+
src: path.join(this.props.path, this.buildConfig.clientBuildOutputDir),
|
|
304
|
+
tar: this.buildConfig.clientBuildS3KeyPrefix || "",
|
|
305
|
+
},
|
|
303
306
|
...(this.buildConfig.prerenderedBuildOutputDir
|
|
304
307
|
? [
|
|
305
|
-
|
|
308
|
+
{
|
|
309
|
+
src: path.join(this.props.path, this.buildConfig.prerenderedBuildOutputDir),
|
|
310
|
+
tar: this.buildConfig.prerenderedBuildS3KeyPrefix || "",
|
|
311
|
+
},
|
|
306
312
|
]
|
|
307
313
|
: []),
|
|
308
|
-
].
|
|
314
|
+
])).toString("base64"),
|
|
309
315
|
zipOutDir,
|
|
310
316
|
`${fileSizeLimit}`,
|
|
311
317
|
], {
|
|
@@ -452,11 +458,24 @@ export class SsrSite extends Construct {
|
|
|
452
458
|
});
|
|
453
459
|
return ssrFn.function;
|
|
454
460
|
}
|
|
455
|
-
|
|
456
|
-
this.
|
|
461
|
+
grantServerS3Permissions() {
|
|
462
|
+
const server = this.serverLambdaCdkFunctionForEdge || this.serverLambdaForRegional;
|
|
463
|
+
this.bucket.grantReadWrite(server.role);
|
|
457
464
|
}
|
|
458
|
-
|
|
459
|
-
|
|
465
|
+
grantServerCloudFrontPermissions() {
|
|
466
|
+
const stack = Stack.of(this);
|
|
467
|
+
const server = this.serverLambdaCdkFunctionForEdge || this.serverLambdaForRegional;
|
|
468
|
+
const policy = new Policy(this, "ServerFunctionInvalidatorPolicy", {
|
|
469
|
+
statements: [
|
|
470
|
+
new PolicyStatement({
|
|
471
|
+
actions: ["cloudfront:CreateInvalidation"],
|
|
472
|
+
resources: [
|
|
473
|
+
`arn:${stack.partition}:cloudfront::${stack.account}:distribution/${this.distribution.distributionId}`,
|
|
474
|
+
],
|
|
475
|
+
}),
|
|
476
|
+
],
|
|
477
|
+
});
|
|
478
|
+
server?.role?.attachInlinePolicy(policy);
|
|
460
479
|
}
|
|
461
480
|
/////////////////////
|
|
462
481
|
// CloudFront Distribution
|
|
@@ -585,7 +604,7 @@ function handler(event) {
|
|
|
585
604
|
{
|
|
586
605
|
includeBody: true,
|
|
587
606
|
eventType: LambdaEdgeEventType.ORIGIN_REQUEST,
|
|
588
|
-
functionVersion: this.
|
|
607
|
+
functionVersion: this.serverLambdaForEdge.currentVersion,
|
|
589
608
|
},
|
|
590
609
|
...(cfDistributionProps.defaultBehavior?.edgeLambdas || []),
|
|
591
610
|
],
|
package/constructs/StaticSite.js
CHANGED
|
@@ -237,7 +237,13 @@ interface ImportMeta {
|
|
|
237
237
|
force: true,
|
|
238
238
|
recursive: true,
|
|
239
239
|
});
|
|
240
|
-
const cmd = [
|
|
240
|
+
const cmd = [
|
|
241
|
+
"node",
|
|
242
|
+
script,
|
|
243
|
+
Buffer.from(JSON.stringify([{ src: siteOutputPath, tar: "" }])).toString("base64"),
|
|
244
|
+
zipPath,
|
|
245
|
+
fileSizeLimit,
|
|
246
|
+
].join(" ");
|
|
241
247
|
try {
|
|
242
248
|
execSync(cmd, {
|
|
243
249
|
cwd: sitePath,
|
|
@@ -273,7 +273,12 @@ export class NextjsSite extends Construct {
|
|
|
273
273
|
force: true,
|
|
274
274
|
recursive: true,
|
|
275
275
|
});
|
|
276
|
-
const result = spawn.sync("node", [
|
|
276
|
+
const result = spawn.sync("node", [
|
|
277
|
+
script,
|
|
278
|
+
Buffer.from(JSON.stringify([{ src: siteOutputPath, tar: "" }])).toString("base64"),
|
|
279
|
+
zipPath,
|
|
280
|
+
`${fileSizeLimit}`,
|
|
281
|
+
], {
|
|
277
282
|
stdio: "inherit",
|
|
278
283
|
});
|
|
279
284
|
if (result.status !== 0) {
|