sst 2.25.0 → 2.25.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/constructs/App.js CHANGED
@@ -17,6 +17,7 @@ import { Bucket } from "aws-cdk-lib/aws-s3";
17
17
  import { Effect, Policy, PolicyStatement } from "aws-cdk-lib/aws-iam";
18
18
  import { CfnLogGroup } from "aws-cdk-lib/aws-logs";
19
19
  import { useBootstrap } from "../bootstrap.js";
20
+ import { useWarning } from "./util/warning.js";
20
21
  /**
21
22
  * The App construct extends cdk.App and is used internally by SST.
22
23
  */
@@ -188,6 +189,7 @@ export class App extends CDKApp {
188
189
  await useDeferredTasks().run();
189
190
  this.createBindingSsmParameters();
190
191
  this.removeGovCloudUnsupportedResourceProperties();
192
+ useWarning().print();
191
193
  const bootstrap = await useBootstrap();
192
194
  for (const child of this.node.children) {
193
195
  if (isStackConstruct(child)) {
@@ -1,6 +1,5 @@
1
1
  import { Construct } from "constructs";
2
2
  import { FunctionProps } from "aws-cdk-lib/aws-lambda";
3
- import { CachePolicy } from "aws-cdk-lib/aws-cloudfront";
4
3
  import { Distribution } from "./Distribution.js";
5
4
  import { SsrFunction } from "./SsrFunction.js";
6
5
  import { EdgeFunction } from "./EdgeFunction.js";
@@ -18,11 +17,6 @@ export interface NextjsSiteProps extends Omit<SsrSiteProps, "nodejs"> {
18
17
  */
19
18
  memorySize?: number | Size;
20
19
  };
21
- /**
22
- * The number of server functions to keep warm. This option is only supported for the regional mode.
23
- * @default Server function is not kept warm
24
- */
25
- warm?: number;
26
20
  cdk?: SsrSiteProps["cdk"] & {
27
21
  revalidation?: Pick<FunctionProps, "vpc" | "vpcSubnets">;
28
22
  /**
@@ -84,14 +78,14 @@ export declare class NextjsSite extends SsrSite {
84
78
  clientBuildS3KeyPrefix: string;
85
79
  prerenderedBuildOutputDir: string;
86
80
  prerenderedBuildS3KeyPrefix: string;
81
+ warmerFunctionAssetPath: string;
87
82
  };
88
83
  protected createFunctionForRegional(): SsrFunction;
89
84
  protected createFunctionForEdge(): EdgeFunction;
90
85
  private createImageOptimizationFunction;
91
- private createWarmer;
92
86
  protected createCloudFrontDistributionForRegional(): Distribution;
93
87
  protected createCloudFrontDistributionForEdge(): Distribution;
94
- protected useServerBehaviorCachePolicy(): CachePolicy;
88
+ protected useServerBehaviorCachePolicy(): import("aws-cdk-lib/aws-cloudfront").CachePolicy;
95
89
  private buildImageBehavior;
96
90
  protected generateBuildId(): string;
97
91
  getConstructMetadata(): {
@@ -1,13 +1,11 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { Fn, Duration as CdkDuration, RemovalPolicy, CustomResource, } from "aws-cdk-lib/core";
4
- import { Effect, Policy, PolicyStatement } from "aws-cdk-lib/aws-iam";
3
+ import { Fn, Duration as CdkDuration, RemovalPolicy } from "aws-cdk-lib/core";
4
+ import { PolicyStatement } from "aws-cdk-lib/aws-iam";
5
5
  import { RetentionDays } from "aws-cdk-lib/aws-logs";
6
6
  import { Code, Runtime, Architecture, Function as CdkFunction, FunctionUrlAuthType, } from "aws-cdk-lib/aws-lambda";
7
7
  import { ViewerProtocolPolicy, AllowedMethods, CachedMethods, LambdaEdgeEventType, } from "aws-cdk-lib/aws-cloudfront";
8
8
  import { HttpOrigin } from "aws-cdk-lib/aws-cloudfront-origins";
9
- import { Rule, Schedule } from "aws-cdk-lib/aws-events";
10
- import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
11
9
  import { Queue } from "aws-cdk-lib/aws-sqs";
12
10
  import { SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
13
11
  import { Stack } from "./Stack.js";
@@ -34,7 +32,6 @@ export class NextjsSite extends SsrSite {
34
32
  ...props,
35
33
  });
36
34
  this.deferredTaskCallbacks.push(() => {
37
- this.createWarmer();
38
35
  this.createRevalidation();
39
36
  });
40
37
  }
@@ -70,6 +67,7 @@ export class NextjsSite extends SsrSite {
70
67
  clientBuildS3KeyPrefix: "_assets",
71
68
  prerenderedBuildOutputDir: ".open-next/cache",
72
69
  prerenderedBuildS3KeyPrefix: "_cache",
70
+ warmerFunctionAssetPath: path.join(this.props.path, ".open-next/warmer-function"),
73
71
  };
74
72
  }
75
73
  createFunctionForRegional() {
@@ -153,56 +151,6 @@ export class NextjsSite extends SsrSite {
153
151
  });
154
152
  return fn;
155
153
  }
156
- createWarmer() {
157
- const { warm, edge } = this.props;
158
- if (!warm)
159
- return;
160
- if (warm && edge) {
161
- throw new Error(`Warming is currently supported only for the regional mode.`);
162
- }
163
- if (!this.serverLambdaForRegional)
164
- return;
165
- // Create warmer function
166
- const warmer = new CdkFunction(this, "WarmerFunction", {
167
- description: "Next.js warmer",
168
- code: Code.fromAsset(path.join(this.props.path, ".open-next/warmer-function")),
169
- runtime: Runtime.NODEJS_18_X,
170
- handler: "index.handler",
171
- timeout: CdkDuration.minutes(15),
172
- memorySize: 1024,
173
- environment: {
174
- FUNCTION_NAME: this.serverLambdaForRegional.functionName,
175
- CONCURRENCY: warm.toString(),
176
- },
177
- });
178
- this.serverLambdaForRegional.grantInvoke(warmer);
179
- // Create cron job
180
- new Rule(this, "WarmerRule", {
181
- schedule: Schedule.rate(CdkDuration.minutes(5)),
182
- targets: [new LambdaFunction(warmer, { retryAttempts: 0 })],
183
- });
184
- // Create custom resource to prewarm on deploy
185
- const stack = Stack.of(this);
186
- const policy = new Policy(this, "PrewarmerPolicy", {
187
- statements: [
188
- new PolicyStatement({
189
- effect: Effect.ALLOW,
190
- actions: ["lambda:InvokeFunction"],
191
- resources: [warmer.functionArn],
192
- }),
193
- ],
194
- });
195
- stack.customResourceHandler.role?.attachInlinePolicy(policy);
196
- const resource = new CustomResource(this, "Prewarmer", {
197
- serviceToken: stack.customResourceHandler.functionArn,
198
- resourceType: "Custom::FunctionInvoker",
199
- properties: {
200
- version: Date.now().toString(),
201
- functionName: warmer.functionName,
202
- },
203
- });
204
- resource.node.addDependency(policy);
205
- }
206
154
  createCloudFrontDistributionForRegional() {
207
155
  /**
208
156
  * Next.js requests
@@ -15,6 +15,7 @@ import { EdgeFunction } from "./EdgeFunction.js";
15
15
  * ```
16
16
  */
17
17
  export declare class RemixSite extends SsrSite {
18
+ private serverModuleFormat;
18
19
  protected initBuildConfig(): {
19
20
  typesPath: string;
20
21
  serverBuildOutputFile: string;
@@ -6,6 +6,8 @@ const require = createRequire(import.meta.url);
6
6
  import { SsrSite } from "./SsrSite.js";
7
7
  import { SsrFunction } from "./SsrFunction.js";
8
8
  import { EdgeFunction } from "./EdgeFunction.js";
9
+ import { VisibleError } from "../error.js";
10
+ import { useWarning } from "./util/warning.js";
9
11
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
10
12
  /**
11
13
  * The `RemixSite` construct is a higher level CDK construct that makes it easy to create a Remix app.
@@ -21,31 +23,36 @@ const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
21
23
  * ```
22
24
  */
23
25
  export class RemixSite extends SsrSite {
26
+ serverModuleFormat = "cjs";
24
27
  initBuildConfig() {
25
28
  const { path: sitePath } = this.props;
26
29
  const configDefaults = {
27
30
  assetsBuildDirectory: "public/build",
28
31
  publicPath: "/build/",
29
32
  serverBuildPath: "build/index.js",
30
- serverModuleFormat: "cjs",
33
+ serverModuleFormat: "esm",
31
34
  serverPlatform: "node",
32
35
  };
33
36
  // Validate config path
34
37
  const configPath = path.resolve(sitePath, "remix.config.js");
35
38
  if (!fs.existsSync(configPath)) {
36
- throw new Error(`Could not find "remix.config.js" at expected path "${configPath}".`);
39
+ throw new VisibleError(`In the "${this.node.id}" Site, could not find "remix.config.js" at expected path "${configPath}".`);
37
40
  }
38
41
  // Load config
39
42
  const userConfig = require(configPath);
43
+ this.serverModuleFormat = userConfig.serverModuleFormat ?? "cjs";
44
+ if (userConfig.serverModuleFormat !== "esm") {
45
+ useWarning().add("remix.cjs");
46
+ }
47
+ // Validate config
40
48
  const config = {
41
49
  ...configDefaults,
42
50
  ...userConfig,
43
51
  };
44
- // Validate config
45
52
  Object.keys(configDefaults).forEach((key) => {
46
53
  const k = key;
47
54
  if (config[k] !== configDefaults[k]) {
48
- throw new Error(`RemixSite: remix.config.js "${key}" must be "${configDefaults[k]}".`);
55
+ throw new VisibleError(`In the "${this.node.id}" Site, remix.config.js "${key}" must be "${configDefaults[k]}".`);
49
56
  }
50
57
  });
51
58
  return {
@@ -106,7 +113,7 @@ export class RemixSite extends SsrSite {
106
113
  memorySize,
107
114
  timeout,
108
115
  nodejs: {
109
- format: "cjs",
116
+ format: this.serverModuleFormat,
110
117
  ...nodejs,
111
118
  esbuild: {
112
119
  ...esbuild,
@@ -133,7 +140,7 @@ export class RemixSite extends SsrSite {
133
140
  environment,
134
141
  permissions,
135
142
  nodejs: {
136
- format: "cjs",
143
+ format: this.serverModuleFormat,
137
144
  ...nodejs,
138
145
  esbuild: {
139
146
  ...esbuild,
@@ -22,6 +22,7 @@ export type SsrBuildConfig = {
22
22
  clientCFFunctionInjection?: string;
23
23
  prerenderedBuildOutputDir?: string;
24
24
  prerenderedBuildS3KeyPrefix?: string;
25
+ warmerFunctionAssetPath?: string;
25
26
  };
26
27
  export interface SsrSiteNodeJSProps extends NodeJSProps {
27
28
  }
@@ -137,6 +138,11 @@ export interface SsrSiteProps {
137
138
  * ```
138
139
  */
139
140
  environment?: Record<string, string>;
141
+ /**
142
+ * The number of server functions to keep warm. This option is only supported for the regional mode.
143
+ * @default Server function is not kept warm
144
+ */
145
+ warm?: number;
140
146
  regional?: {
141
147
  /**
142
148
  * Secure the server function URL using AWS IAM authentication. By default, the server function URL is publicly accessible. When this flag is enabled, the server function URL will require IAM authorization, and a Lambda@Edge function will sign the requests. Be aware that this introduces added latency to the requests.
@@ -364,6 +370,7 @@ export declare abstract class SsrSite extends Construct implements SSTConstruct
364
370
  protected createFunctionForDev(): SsrFunction;
365
371
  private grantServerS3Permissions;
366
372
  private grantServerCloudFrontPermissions;
373
+ private createWarmer;
367
374
  private createCloudFrontS3Origin;
368
375
  protected createCloudFrontDistributionForRegional(): Distribution;
369
376
  protected createCloudFrontDistributionForEdge(): Distribution;
@@ -8,12 +8,14 @@ import { execSync } from "child_process";
8
8
  import { Construct } from "constructs";
9
9
  import { Fn, Token, Duration as CdkDuration, RemovalPolicy, CustomResource, } from "aws-cdk-lib/core";
10
10
  import { BlockPublicAccess, Bucket, } from "aws-cdk-lib/aws-s3";
11
- import { Role, Policy, PolicyStatement, AccountPrincipal, ServicePrincipal, CompositePrincipal, } from "aws-cdk-lib/aws-iam";
11
+ import { Effect, Role, Policy, PolicyStatement, AccountPrincipal, ServicePrincipal, CompositePrincipal, } from "aws-cdk-lib/aws-iam";
12
12
  import { Function as CdkFunction, Code, Runtime, FunctionUrlAuthType, InvokeMode, } from "aws-cdk-lib/aws-lambda";
13
13
  import { Asset } from "aws-cdk-lib/aws-s3-assets";
14
14
  import { ViewerProtocolPolicy, AllowedMethods, CachedMethods, LambdaEdgeEventType, CachePolicy, CacheQueryStringBehavior, CacheHeaderBehavior, CacheCookieBehavior, OriginRequestPolicy, Function as CfFunction, FunctionCode as CfFunctionCode, FunctionEventType as CfFunctionEventType, } from "aws-cdk-lib/aws-cloudfront";
15
15
  import { AwsCliLayer } from "aws-cdk-lib/lambda-layer-awscli";
16
16
  import { S3Origin, HttpOrigin } from "aws-cdk-lib/aws-cloudfront-origins";
17
+ import { Rule, Schedule } from "aws-cdk-lib/aws-events";
18
+ import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
17
19
  import { Stack } from "./Stack.js";
18
20
  import { Distribution } from "./Distribution.js";
19
21
  import { Logger } from "../logger.js";
@@ -28,6 +30,7 @@ import { toCdkDuration } from "./util/duration.js";
28
30
  import { attachPermissionsToRole } from "./util/permission.js";
29
31
  import { getParameterPath, } from "./util/functionBinding.js";
30
32
  import { useProject } from "../project.js";
33
+ import { VisibleError } from "../error.js";
31
34
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
32
35
  /**
33
36
  * The `SsrSite` construct is a higher level CDK construct that makes it easy to create modern web apps with Server Side Rendering capabilities.
@@ -106,6 +109,10 @@ export class SsrSite extends Construct {
106
109
  await this.serverLambdaForEdge?.build();
107
110
  await this.serverLambdaForRegional?.build();
108
111
  await this.serverUrlSigningFunction?.build();
112
+ // Create warmer
113
+ // Note: create warmer after build app b/c the warmer code
114
+ // for NextjsSite depends on OpenNext build output
115
+ this.createWarmer();
109
116
  // Create S3 Deployment
110
117
  const cliLayer = new AwsCliLayer(this, "AwsCliLayer");
111
118
  const assets = this.createS3Assets();
@@ -480,6 +487,57 @@ export class SsrSite extends Construct {
480
487
  });
481
488
  server?.role?.attachInlinePolicy(policy);
482
489
  }
490
+ createWarmer() {
491
+ const { warm, edge } = this.props;
492
+ if (!warm)
493
+ return;
494
+ if (warm && edge) {
495
+ throw new VisibleError(`In the "${this.node.id}" Site, warming is currently supported only for the regional mode.`);
496
+ }
497
+ if (!this.serverLambdaForRegional)
498
+ return;
499
+ // Create warmer function
500
+ const warmer = new CdkFunction(this, "WarmerFunction", {
501
+ description: "Next.js warmer",
502
+ code: Code.fromAsset(this.buildConfig.warmerFunctionAssetPath ??
503
+ path.join(__dirname, "../support/ssr-warmer")),
504
+ runtime: Runtime.NODEJS_18_X,
505
+ handler: "index.handler",
506
+ timeout: CdkDuration.minutes(15),
507
+ memorySize: 1024,
508
+ environment: {
509
+ FUNCTION_NAME: this.serverLambdaForRegional.functionName,
510
+ CONCURRENCY: warm.toString(),
511
+ },
512
+ });
513
+ this.serverLambdaForRegional.grantInvoke(warmer);
514
+ // Create cron job
515
+ new Rule(this, "WarmerRule", {
516
+ schedule: Schedule.rate(CdkDuration.minutes(5)),
517
+ targets: [new LambdaFunction(warmer, { retryAttempts: 0 })],
518
+ });
519
+ // Create custom resource to prewarm on deploy
520
+ const stack = Stack.of(this);
521
+ const policy = new Policy(this, "PrewarmerPolicy", {
522
+ statements: [
523
+ new PolicyStatement({
524
+ effect: Effect.ALLOW,
525
+ actions: ["lambda:InvokeFunction"],
526
+ resources: [warmer.functionArn],
527
+ }),
528
+ ],
529
+ });
530
+ stack.customResourceHandler.role?.attachInlinePolicy(policy);
531
+ const resource = new CustomResource(this, "Prewarmer", {
532
+ serviceToken: stack.customResourceHandler.functionArn,
533
+ resourceType: "Custom::FunctionInvoker",
534
+ properties: {
535
+ version: Date.now().toString(),
536
+ functionName: warmer.functionName,
537
+ },
538
+ });
539
+ resource.node.addDependency(policy);
540
+ }
483
541
  /////////////////////
484
542
  // CloudFront Distribution
485
543
  /////////////////////
@@ -2,6 +2,7 @@ declare const WARNINGS: {
2
2
  "config.deprecated": string;
3
3
  "permissions.noConstructs": string;
4
4
  "go.deprecated": string;
5
+ "remix.cjs": string;
5
6
  };
6
7
  export declare const useWarning: () => {
7
8
  add(message: keyof typeof WARNINGS): void;
@@ -1,8 +1,10 @@
1
1
  import { createAppContext } from "../context.js";
2
+ import { Colors } from "../../cli/colors.js";
2
3
  const WARNINGS = {
3
- "config.deprecated": `WARNING: The "config" prop is deprecated, and will be removed in SST v2. Pass Parameters and Secrets in through the "bind" prop. Read more about how to upgrade here — https://docs.serverless-stack.com/upgrade-guide#upgrade-to-v116`,
4
- "permissions.noConstructs": `WARNING: Passing SST constructs into "permissions" is deprecated, and will be removed in SST v2. Pass them into the "bind" prop. Read more about how to upgrade here — https://docs.serverless-stack.com/upgrade-guide#upgrade-to-v116`,
5
- "go.deprecated": `WARNING: The "go1.x" runtime is deprecated and replaced by the "go" runtime`,
4
+ "config.deprecated": `The "config" prop is deprecated, and will be removed in SST v2. Pass Parameters and Secrets in through the "bind" prop. Read more about how to upgrade here — https://docs.serverless-stack.com/upgrade-guide#upgrade-to-v116`,
5
+ "permissions.noConstructs": `Passing SST constructs into "permissions" is deprecated, and will be removed in SST v2. Pass them into the "bind" prop. Read more about how to upgrade here — https://docs.serverless-stack.com/upgrade-guide#upgrade-to-v116`,
6
+ "go.deprecated": `The "go1.x" runtime is deprecated and replaced by the "go" runtime`,
7
+ "remix.cjs": `"RemixSite" will soon deprecate support for the "cjs" output format. Please update your "remix.config.js" to set "serverModuleFormat" to "esm".`,
6
8
  };
7
9
  export const useWarning = createAppContext(() => {
8
10
  const set = new Set();
@@ -12,7 +14,7 @@ export const useWarning = createAppContext(() => {
12
14
  },
13
15
  print() {
14
16
  for (const key of set) {
15
- console.warn(WARNINGS[key]);
17
+ Colors.line(Colors.warning(`Warning: ${WARNINGS[key]}`));
16
18
  }
17
19
  },
18
20
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "sideEffects": false,
3
3
  "name": "sst",
4
- "version": "2.25.0",
4
+ "version": "2.25.1",
5
5
  "bin": {
6
6
  "sst": "cli/sst.js"
7
7
  },