sst 2.0.0-rc.50 → 2.0.0-rc.52

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.
@@ -1,5 +1,7 @@
1
1
  import { useSTSIdentity } from "../../credentials.js";
2
2
  import { Colors } from "../colors.js";
3
+ import fs from "fs/promises";
4
+ import path from "path";
3
5
  export const deploy = (program) => program.command("deploy [filter]", "Deploy your app to AWS", (yargs) => yargs
4
6
  .option("from", {
5
7
  type: "string",
@@ -17,6 +19,7 @@ export const deploy = (program) => program.command("deploy [filter]", "Deploy yo
17
19
  const { loadAssembly, Stacks } = await import("../../stacks/index.js");
18
20
  const { render } = await import("ink");
19
21
  const { DeploymentUI } = await import("../ui/deploy.js");
22
+ const { mapValues } = await import("remeda");
20
23
  const project = useProject();
21
24
  const identity = await useSTSIdentity();
22
25
  Colors.line(`${Colors.primary.bold(`SST v${project.version}`)}`);
@@ -35,7 +38,7 @@ export const deploy = (program) => program.command("deploy [filter]", "Deploy yo
35
38
  return result;
36
39
  }
37
40
  const spinner = createSpinner({
38
- text: " Building stacks",
41
+ text: " Building...",
39
42
  });
40
43
  const result = await Stacks.synth({
41
44
  fn: project.stacks,
@@ -57,5 +60,6 @@ export const deploy = (program) => program.command("deploy [filter]", "Deploy yo
57
60
  printDeploymentResults(assembly, results);
58
61
  if (Object.values(results).some((stack) => Stacks.isFailed(stack.status)))
59
62
  process.exit(1);
63
+ fs.writeFile(path.join(project.paths.out, "outputs.json"), JSON.stringify(mapValues(results, (val) => val.outputs), null, 2));
60
64
  process.exit(0);
61
65
  });
@@ -1,6 +1,6 @@
1
- import chalk from "chalk";
2
1
  import { Colors } from "../colors.js";
3
2
  import { printHeader } from "../ui/header.js";
3
+ import { mapValues, omitBy, pipe } from "remeda";
4
4
  export const dev = (program) => program.command(["dev", "start"], "Work on your app locally", (yargs) => yargs.option("increase-timeout", {
5
5
  type: "boolean",
6
6
  description: "Increase function timeout",
@@ -69,11 +69,17 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
69
69
  }
70
70
  });
71
71
  bus.subscribe("function.build.success", async (evt) => {
72
- Colors.line(Colors.dim(Colors.prefix, "Built", useFunctions().fromID(evt.properties.functionID).handler));
72
+ const info = useFunctions().fromID(evt.properties.functionID);
73
+ if (!info.enableLiveDev)
74
+ return;
75
+ Colors.line(Colors.dim(Colors.prefix, "Built", info.handler));
73
76
  });
74
77
  bus.subscribe("function.build.failed", async (evt) => {
78
+ const info = useFunctions().fromID(evt.properties.functionID);
79
+ if (!info.enableLiveDev)
80
+ return;
75
81
  Colors.gap();
76
- Colors.line(Colors.danger("✖ "), "Build failed", useFunctions().fromID(evt.properties.functionID).handler);
82
+ Colors.line(Colors.danger("✖ "), "Build failed", info.handler);
77
83
  for (const line of evt.properties.errors) {
78
84
  Colors.line(" ", line);
79
85
  }
@@ -81,9 +87,10 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
81
87
  });
82
88
  bus.subscribe("function.success", async (evt) => {
83
89
  // stdout logs sometimes come in after
90
+ const p = prefix(evt.properties.requestID);
84
91
  const req = pending.get(evt.properties.requestID);
85
92
  setTimeout(() => {
86
- Colors.line(prefix(evt.properties.requestID), Colors.dim(`Done in ${Date.now() - req.started - 100}ms`));
93
+ Colors.line(p, Colors.dim(`Done in ${Date.now() - req.started - 100}ms`));
87
94
  end(evt.properties.requestID);
88
95
  }, 100);
89
96
  });
@@ -102,9 +109,15 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
102
109
  const project = useProject();
103
110
  const bus = useBus();
104
111
  let lastDeployed;
105
- let pending;
106
- let isDeploying = false;
112
+ let isWorking = false;
113
+ let isDirty = false;
107
114
  async function build() {
115
+ if (isWorking) {
116
+ isDirty = true;
117
+ return;
118
+ }
119
+ isDirty = false;
120
+ isWorking = true;
108
121
  Colors.gap();
109
122
  const spinner = createSpinner({
110
123
  color: "gray",
@@ -125,6 +138,9 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
125
138
  Logger.debug("Checksum", "next", next, "old", lastDeployed);
126
139
  if (next === lastDeployed) {
127
140
  spinner.succeed(Colors.dim(" Built with no changes"));
141
+ isWorking = false;
142
+ if (isDirty)
143
+ build();
128
144
  return;
129
145
  }
130
146
  if (!lastDeployed) {
@@ -134,11 +150,9 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
134
150
  }
135
151
  else {
136
152
  spinner.succeed(Colors.dim(` Built`));
137
- Colors.mode("gap");
153
+ Colors.gap();
138
154
  }
139
- pending = assembly;
140
- if (lastDeployed)
141
- setTimeout(() => deploy(), 100);
155
+ deploy(assembly);
142
156
  }
143
157
  catch (ex) {
144
158
  spinner.fail();
@@ -149,17 +163,8 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
149
163
  Colors.gap();
150
164
  }
151
165
  }
152
- async function deploy() {
153
- if (!pending)
154
- return;
155
- if (isDeploying)
156
- return;
157
- isDeploying = true;
158
- const assembly = pending;
166
+ async function deploy(assembly) {
159
167
  const nextChecksum = await checksum(assembly.directory);
160
- pending = undefined;
161
- if (lastDeployed)
162
- console.log();
163
168
  const component = render(React.createElement(DeploymentUI, { assembly: assembly }));
164
169
  const results = await Stacks.deployMany(assembly.stacks);
165
170
  component.clear();
@@ -181,8 +186,10 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
181
186
  }
182
187
  await SiteEnv.writeValues(result);
183
188
  }
184
- isDeploying = false;
185
- deploy();
189
+ fs.writeFile(path.join(project.paths.out, "outputs.json"), JSON.stringify(pipe(results, omitBy((_, key) => key.includes("SstSiteEnv")), mapValues((val) => val.outputs)), null, 2));
190
+ isWorking = false;
191
+ if (isDirty)
192
+ build();
186
193
  }
187
194
  async function checksum(cdkOutPath) {
188
195
  const manifestPath = path.join(cdkOutPath, "manifest.json");
@@ -209,11 +216,7 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
209
216
  build();
210
217
  });
211
218
  await build();
212
- await deploy();
213
219
  });
214
- const project = useProject();
215
- const primary = chalk.hex("#E27152");
216
- const link = chalk.cyan;
217
220
  await useLocalServer({
218
221
  key: "",
219
222
  cert: "",
@@ -221,17 +224,6 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
221
224
  });
222
225
  clear();
223
226
  await printHeader({ console: true, hint: "ready!" });
224
- /*
225
- console.log(` ${primary(`➜`)} ${bold(dim(`Outputs:`))}`);
226
- for (let i = 0; i < 3; i++) {
227
- console.log(` ${dim(`thdxr-scratch-MyStack`)}`);
228
- console.log(
229
- ` ${bold(
230
- dim(`ApiEndpoint`)
231
- )}: https://hdq3z0es2d.execute-api.us-east-1.amazonaws.com`
232
- );
233
- }
234
- */
235
227
  await Promise.all([
236
228
  useRuntimeWorkers(),
237
229
  useIOTBridge(),
@@ -0,0 +1,15 @@
1
+ /// <reference types="yargs" />
2
+ import type { Program } from "../program.js";
3
+ export declare const telemetry: (program: Program) => import("yargs").Argv<{
4
+ stage: string | undefined;
5
+ } & {
6
+ profile: string | undefined;
7
+ } & {
8
+ region: string | undefined;
9
+ } & {
10
+ verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
13
+ } & {
14
+ action: string;
15
+ }>;
@@ -0,0 +1,17 @@
1
+ import { Colors } from "../colors.js";
2
+ export const telemetry = (program) => program.command("telemetry <action>", "Load environment variables and start your frontend", (yargs) => yargs.positional("action", {
3
+ type: "string",
4
+ describe: "Whether to enable or disable",
5
+ choices: ["enable", "disable"],
6
+ demandOption: true,
7
+ }), async (args) => {
8
+ const { enable, disable } = await import("../telemetry/telemetry.js");
9
+ if (args.action === "enable") {
10
+ enable();
11
+ Colors.line(Colors.success(`✔ `), `Telemetry enabled`);
12
+ }
13
+ if (args.action === "disable") {
14
+ disable();
15
+ Colors.line(Colors.success(`✔ `), `Telemetry disabled`);
16
+ }
17
+ });
package/cli/program.js CHANGED
@@ -22,7 +22,7 @@ export const program = yargs(hideBin(process.argv))
22
22
  type: "string",
23
23
  describe: "ARN of the IAM role to use when invoking AWS",
24
24
  })
25
- .group(["stage", "profile", "region", "help", "verbose", "role"], "Global:")
25
+ .group(["stage", "profile", "region", "role", "verbose", "help"], "Global:")
26
26
  .middleware(async (argv) => {
27
27
  if (argv.verbose) {
28
28
  process.env.SST_VERBOSE = "1";
package/cli/sst.js CHANGED
@@ -20,6 +20,7 @@ import { update } from "./commands/update.js";
20
20
  import { transform } from "./commands/transform.js";
21
21
  import { diff } from "./commands/diff.js";
22
22
  import { version } from "./commands/version.js";
23
+ import { telemetry } from "./commands/telemetry.js";
23
24
  dev(program);
24
25
  deploy(program);
25
26
  build(program);
@@ -32,6 +33,7 @@ transform(program);
32
33
  consoleCommand(program);
33
34
  diff(program);
34
35
  version(program);
36
+ telemetry(program);
35
37
  // @ts-expect-error
36
38
  process.setSourceMapsEnabled(true);
37
39
  process.removeAllListeners("uncaughtException");
package/cli/ui/deploy.js CHANGED
@@ -70,15 +70,7 @@ export function printDeploymentResults(assembly, results, remove) {
70
70
  Colors.gap();
71
71
  Colors.line(Colors.success(`✔`), Colors.bold(remove ? ` Removed:` : ` Deployed:`));
72
72
  for (const [stack, result] of success) {
73
- const outputs = Object.entries(result.outputs).filter(([key, _]) => {
74
- if (key.startsWith("Export"))
75
- return false;
76
- if (key.includes("SstSiteEnv"))
77
- return false;
78
- if (key === "SSTMetadata")
79
- return false;
80
- return true;
81
- });
73
+ const outputs = Object.entries(result.outputs).filter(([key, _]) => !key.includes("SstSiteEnv"));
82
74
  Colors.line(` ${Colors.dim(stackNameToId(stack))}`);
83
75
  if (outputs.length > 0) {
84
76
  for (const key of Object.keys(Object.fromEntries(outputs)).sort()) {
@@ -87,6 +79,7 @@ export function printDeploymentResults(assembly, results, remove) {
87
79
  }
88
80
  }
89
81
  }
82
+ Colors.gap();
90
83
  }
91
84
  // Print failed stacks
92
85
  const failed = Object.entries(results).filter(([_stack, result]) => Object.keys(result.errors).length > 0);
@@ -121,9 +114,9 @@ function logicalIdToCdkPath(assembly, stack, logicalId) {
121
114
  }
122
115
  function getHelper(error) {
123
116
  return `This is a common deploy error. Check out this GitHub issue for more details - https://github.com/serverless-stack/sst/issues/125`;
124
- return getApiAccessLogPermissionsHelper(error)
125
- || getAppSyncMultiResolverHelper(error)
126
- || getApiLogRoleHelper(error);
117
+ return (getApiAccessLogPermissionsHelper(error) ||
118
+ getAppSyncMultiResolverHelper(error) ||
119
+ getApiLogRoleHelper(error));
127
120
  }
128
121
  function getApiAccessLogPermissionsHelper(error) {
129
122
  // Can run into this issue when enabling access logs for API Gateway
@@ -17,7 +17,6 @@ export declare class AstroSite extends SsrSite {
17
17
  serverBuildOutputFile: string;
18
18
  clientBuildOutputDir: string;
19
19
  clientBuildVersionedSubDir: string;
20
- siteStub: string;
21
20
  };
22
21
  protected validateBuildOutput(): void;
23
22
  protected createFunctionForRegional(): lambda.Function;
@@ -4,6 +4,7 @@ import path from "path";
4
4
  import * as esbuild from "esbuild";
5
5
  import { SsrSite } from "./SsrSite.js";
6
6
  import { Function } from "./Function.js";
7
+ import { useProject } from "../project.js";
7
8
  import { EdgeFunction } from "./EdgeFunction.js";
8
9
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
9
10
  /**
@@ -23,7 +24,6 @@ export class AstroSite extends SsrSite {
23
24
  serverBuildOutputFile: "dist/server/entry.mjs",
24
25
  clientBuildOutputDir: "dist/client",
25
26
  clientBuildVersionedSubDir: "assets",
26
- siteStub: path.resolve(__dirname, "../support/astro-site-html-stub"),
27
27
  };
28
28
  }
29
29
  validateBuildOutput() {
@@ -36,14 +36,10 @@ export class AstroSite extends SsrSite {
36
36
  }
37
37
  createFunctionForRegional() {
38
38
  const { defaults, environment, bind } = this.props;
39
- // Bundle code
40
- const handler = this.isPlaceholder
41
- ? path.resolve(__dirname, "../support/ssr-site-function-stub/index.handler")
42
- : path.join(this.props.path, "dist", "server", "entry.handler");
43
39
  // Create function
44
40
  const fn = new Function(this, `ServerFunction`, {
45
41
  description: "Server handler",
46
- handler,
42
+ handler: path.join(this.props.path, "dist", "server", "entry.handler"),
47
43
  bind,
48
44
  logRetention: "three_days",
49
45
  runtime: "nodejs16.x",
@@ -60,50 +56,39 @@ export class AstroSite extends SsrSite {
60
56
  }
61
57
  createFunctionForEdge() {
62
58
  const { defaults, environment } = this.props;
63
- // Bundle code
64
- let bundlePath;
65
- let handler;
66
- if (this.isPlaceholder) {
67
- bundlePath = path.resolve(__dirname, "../support/ssr-site-function-stub");
68
- handler = "index.handler";
69
- }
70
- else {
71
- // Create a directory that we will use to create the bundled version
72
- // of the "core server build" along with our custom Lamba server handler.
73
- const outputPath = path.resolve(path.join(this.sstBuildDir, `AstroSiteFunction-${this.node.id}-${this.node.addr}`));
74
- const result = esbuild.buildSync({
75
- entryPoints: [
76
- path.join(this.props.path, this.buildConfig.serverBuildOutputFile),
77
- ],
78
- target: "esnext",
79
- format: "esm",
80
- platform: "node",
81
- metafile: true,
82
- bundle: true,
83
- write: true,
84
- allowOverwrite: true,
85
- outfile: path.join(outputPath, "entry.mjs"),
86
- banner: {
87
- js: [
88
- `import { createRequire as topLevelCreateRequire } from 'module';`,
89
- `const require = topLevelCreateRequire(import.meta.url);`,
90
- ].join(""),
91
- },
92
- });
93
- if (result.errors.length > 0) {
94
- result.errors.forEach((error) => console.error(error));
95
- throw new Error(`There was a problem bundling the function code for the ${this.id} AstroSite.`);
96
- }
97
- // Create package.json
98
- fs.writeFileSync(path.join(outputPath, "package.json"), `{"type":"module"}`);
99
- bundlePath = outputPath;
100
- handler = "entry.handler";
59
+ // Create a directory that we will use to create the bundled version
60
+ // of the "core server build" along with our custom Lamba server handler.
61
+ const outputPath = path.resolve(path.join(useProject().paths.artifacts, `AstroSiteFunction-${this.node.id}-${this.node.addr}`));
62
+ const result = esbuild.buildSync({
63
+ entryPoints: [
64
+ path.join(this.props.path, this.buildConfig.serverBuildOutputFile),
65
+ ],
66
+ target: "esnext",
67
+ format: "esm",
68
+ platform: "node",
69
+ metafile: true,
70
+ bundle: true,
71
+ write: true,
72
+ allowOverwrite: true,
73
+ outfile: path.join(outputPath, "entry.mjs"),
74
+ banner: {
75
+ js: [
76
+ `import { createRequire as topLevelCreateRequire } from 'module';`,
77
+ `const require = topLevelCreateRequire(import.meta.url);`,
78
+ ].join(""),
79
+ },
80
+ });
81
+ if (result.errors.length > 0) {
82
+ result.errors.forEach((error) => console.error(error));
83
+ throw new Error(`There was a problem bundling the function code for the ${this.id} AstroSite.`);
101
84
  }
85
+ // Create package.json
86
+ fs.writeFileSync(path.join(outputPath, "package.json"), `{"type":"module"}`);
102
87
  // Create function
103
88
  return new EdgeFunction(this, `Server`, {
104
89
  scopeOverride: this,
105
- bundlePath,
106
- handler,
90
+ bundlePath: outputPath,
91
+ handler: "entry.handler",
107
92
  timeout: defaults?.function?.timeout,
108
93
  memory: defaults?.function?.memorySize,
109
94
  permissions: defaults?.function?.permissions,
package/constructs/Job.js CHANGED
@@ -7,7 +7,7 @@ import * as iam from "aws-cdk-lib/aws-iam";
7
7
  import * as lambda from "aws-cdk-lib/aws-lambda";
8
8
  import * as codebuild from "aws-cdk-lib/aws-codebuild";
9
9
  import { Stack } from "./Stack.js";
10
- import { Function } from "./Function.js";
10
+ import { Function, useFunctions } from "./Function.js";
11
11
  import { toCdkDuration } from "./util/duration.js";
12
12
  import { attachPermissionsToRole } from "./util/permission.js";
13
13
  import { bindEnvironment, bindPermissions } from "./util/functionBinding.js";
@@ -44,6 +44,10 @@ export class Job extends Construct {
44
44
  const app = this.node.root;
45
45
  this.id = id;
46
46
  this.props = props;
47
+ useFunctions().add(this.node.addr, {
48
+ ...props,
49
+ runtime: "nodejs16.x",
50
+ });
47
51
  this.localId = path.posix
48
52
  .join(scope.node.path, id)
49
53
  .replace(/\$/g, "-")
@@ -254,7 +258,7 @@ export class Job extends Construct {
254
258
  }
255
259
  createCodeBuildInvoker() {
256
260
  return new Function(this, this.node.id, {
257
- handler: path.join(__dirname, "../dist/support/job-invoke/index.main"),
261
+ handler: path.join(__dirname, "../support/job-invoker/index.main"),
258
262
  runtime: "nodejs16.x",
259
263
  timeout: 10,
260
264
  memorySize: 1024,
@@ -21,13 +21,11 @@ export declare class NextjsSite extends SsrSite {
21
21
  serverBuildOutputFile: string;
22
22
  clientBuildOutputDir: string;
23
23
  clientBuildVersionedSubDir: string;
24
- siteStub: string;
25
24
  };
26
25
  protected createFunctionForRegional(): lambda.Function;
26
+ private createImageOptimizationFunctionForRegional;
27
+ private createMiddlewareEdgeFunctionForRegional;
27
28
  protected createCloudFrontDistributionForRegional(): cloudfront.Distribution;
28
- protected createCloudFrontDistributionForStub(): cloudfront.Distribution;
29
29
  protected createCloudFrontServerCachePolicy(): cloudfront.CachePolicy;
30
30
  protected generateBuildId(): string;
31
- private createImageOptimizationFunctionForRegional;
32
- private createMiddlewareEdgeFunctionForRegional;
33
31
  }
@@ -2,14 +2,14 @@ import fs from "fs";
2
2
  import url from "url";
3
3
  import path from "path";
4
4
  import spawn from "cross-spawn";
5
- import { buildErrorResponsesForRedirectToIndex } from "./BaseSite.js";
6
5
  import { Fn, Duration, RemovalPolicy, } from "aws-cdk-lib";
7
6
  import * as logs from "aws-cdk-lib/aws-logs";
8
7
  import * as lambda from "aws-cdk-lib/aws-lambda";
9
8
  import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
10
9
  import * as origins from "aws-cdk-lib/aws-cloudfront-origins";
11
- import { SsrSite } from "./SsrSite.js";
10
+ import { useProject } from "../project.js";
12
11
  import { EdgeFunction } from "./EdgeFunction.js";
12
+ import { SsrSite } from "./SsrSite.js";
13
13
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
14
14
  /**
15
15
  * The `NextjsSite` construct is a higher level CDK construct that makes it easy to create a Next.js app.
@@ -34,50 +34,82 @@ export class NextjsSite extends SsrSite {
34
34
  serverBuildOutputFile: ".open-next/server-function/index.mjs",
35
35
  clientBuildOutputDir: ".open-next/assets",
36
36
  clientBuildVersionedSubDir: "_next",
37
- siteStub: path.resolve(__dirname, "../support/nextjs-site-html-stub"),
38
37
  };
39
38
  }
40
39
  createFunctionForRegional() {
41
40
  const { defaults, environment } = this.props;
42
- let bundlePath, handler;
43
- if (this.isPlaceholder) {
44
- bundlePath = path.resolve(__dirname, "../support/ssr-site-function-stub");
45
- handler = "server.handler";
46
- }
47
- else {
48
- // Note: cannot point the bundlePath to the `.open-next/server-function`
49
- // b/c the folder contains node_modules. And pnpm node_modules
50
- // contains symlinks. CDK cannot zip symlinks correctly.
51
- // https://github.com/aws/aws-cdk/issues/9251
52
- // We will zip the folder ourselves.
53
- const zipOutDir = path.resolve(path.join(this.sstBuildDir, `Site-${this.node.id}-${this.node.addr}`));
54
- const script = path.resolve(__dirname, "../support/ssr-site-function-archiver.mjs");
55
- const result = spawn.sync("node", [
56
- script,
57
- path.join(this.props.path, ".open-next", "server-function"),
58
- path.join(zipOutDir, "server-function.zip"),
59
- ], {
60
- stdio: "inherit",
61
- });
62
- if (result.status !== 0) {
63
- throw new Error(`There was a problem generating the assets package.`);
64
- }
65
- bundlePath = path.join(zipOutDir, "server-function.zip");
66
- handler = "index.handler";
41
+ // Note: cannot point the bundlePath to the `.open-next/server-function`
42
+ // b/c the folder contains node_modules. And pnpm node_modules
43
+ // contains symlinks. CDK cannot zip symlinks correctly.
44
+ // https://github.com/aws/aws-cdk/issues/9251
45
+ // We will zip the folder ourselves.
46
+ const zipOutDir = path.resolve(path.join(useProject().paths.artifacts, `Site-${this.node.id}-${this.node.addr}`));
47
+ const script = path.resolve(__dirname, "../support/ssr-site-function-archiver.mjs");
48
+ const result = spawn.sync("node", [
49
+ script,
50
+ path.join(this.props.path, ".open-next", "server-function"),
51
+ path.join(zipOutDir, "server-function.zip"),
52
+ ], {
53
+ stdio: "inherit",
54
+ });
55
+ if (result.status !== 0) {
56
+ throw new Error(`There was a problem generating the assets package.`);
67
57
  }
68
58
  return new lambda.Function(this, `ServerFunction`, {
69
59
  description: "Server handler for Next.js",
70
- handler,
60
+ handler: "index.handler",
61
+ currentVersionOptions: {
62
+ removalPolicy: RemovalPolicy.DESTROY,
63
+ },
64
+ logRetention: logs.RetentionDays.THREE_DAYS,
65
+ code: lambda.Code.fromAsset(path.join(zipOutDir, "server-function.zip")),
66
+ runtime: lambda.Runtime.NODEJS_18_X,
67
+ memorySize: defaults?.function?.memorySize || 512,
68
+ timeout: Duration.seconds(defaults?.function?.timeout || 10),
69
+ environment,
70
+ });
71
+ }
72
+ createImageOptimizationFunctionForRegional() {
73
+ const { defaults, path: sitePath } = this.props;
74
+ return new lambda.Function(this, `ImageFunction`, {
75
+ description: "Image optimization handler for Next.js",
76
+ handler: "index.handler",
71
77
  currentVersionOptions: {
72
78
  removalPolicy: RemovalPolicy.DESTROY,
73
79
  },
74
80
  logRetention: logs.RetentionDays.THREE_DAYS,
75
- code: lambda.Code.fromAsset(bundlePath),
81
+ code: lambda.Code.fromAsset(path.join(sitePath, ".open-next/image-optimization-function")),
76
82
  runtime: lambda.Runtime.NODEJS_18_X,
77
83
  memorySize: defaults?.function?.memorySize || 512,
78
84
  timeout: Duration.seconds(defaults?.function?.timeout || 10),
85
+ environment: {
86
+ BUCKET_NAME: this.cdk.bucket.bucketName,
87
+ }
88
+ });
89
+ }
90
+ createMiddlewareEdgeFunctionForRegional() {
91
+ const { defaults, environment, path: sitePath } = this.props;
92
+ const middlewarePath = path.resolve(sitePath, ".open-next/middleware-function");
93
+ const isMiddlewareEnabled = fs.existsSync(middlewarePath);
94
+ let bundlePath, handler;
95
+ if (isMiddlewareEnabled) {
96
+ bundlePath = middlewarePath;
97
+ handler = "index.handler";
98
+ }
99
+ else {
100
+ bundlePath = path.resolve(__dirname, "../support/ssr-site-function-stub");
101
+ handler = "server.handler";
102
+ }
103
+ const fn = new EdgeFunction(this, "Middleware", {
104
+ bundlePath,
105
+ handler,
106
+ timeout: 5,
107
+ memory: 128,
108
+ permissions: defaults?.function?.permissions,
79
109
  environment,
110
+ format: "esm",
80
111
  });
112
+ return { fn, isMiddlewareEnabled };
81
113
  }
82
114
  createCloudFrontDistributionForRegional() {
83
115
  const { cdk } = this.props;
@@ -96,7 +128,7 @@ export class NextjsSite extends SsrSite {
96
128
  compress: true,
97
129
  cachePolicy: cdk?.cachePolicies?.serverRequests ??
98
130
  this.createCloudFrontServerCachePolicy(),
99
- edgeLambdas: isMiddlewareEnabled && !this.isPlaceholder
131
+ edgeLambdas: isMiddlewareEnabled
100
132
  ? [{
101
133
  eventType: cloudfront.LambdaEdgeEventType.VIEWER_REQUEST,
102
134
  functionVersion: middlewareFn.currentVersion,
@@ -208,22 +240,6 @@ export class NextjsSite extends SsrSite {
208
240
  },
209
241
  });
210
242
  }
211
- createCloudFrontDistributionForStub() {
212
- // Keep creating middleware edge function b/c edge function cannot be removed
213
- // immediately.
214
- this.createMiddlewareEdgeFunctionForRegional();
215
- // Create placeholder distribution
216
- return new cloudfront.Distribution(this, "Distribution", {
217
- defaultRootObject: "index.html",
218
- errorResponses: buildErrorResponsesForRedirectToIndex("index.html"),
219
- domainNames: this.buildDistributionDomainNames(),
220
- certificate: this.cdk.certificate,
221
- defaultBehavior: {
222
- origin: new origins.S3Origin(this.cdk.bucket),
223
- viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
224
- },
225
- });
226
- }
227
243
  createCloudFrontServerCachePolicy() {
228
244
  return new cloudfront.CachePolicy(this, "ServerCache", {
229
245
  queryStringBehavior: cloudfront.CacheQueryStringBehavior.all(),
@@ -242,61 +258,7 @@ export class NextjsSite extends SsrSite {
242
258
  });
243
259
  }
244
260
  generateBuildId() {
245
- if (this.isPlaceholder) {
246
- return "live";
247
- }
248
261
  const filePath = path.join(this.props.path, ".next/BUILD_ID");
249
262
  return fs.readFileSync(filePath).toString();
250
263
  }
251
- createImageOptimizationFunctionForRegional() {
252
- const { defaults, path: sitePath } = this.props;
253
- let bundlePath, handler;
254
- if (this.isPlaceholder) {
255
- bundlePath = path.resolve(__dirname, "../support/ssr-site-function-stub");
256
- handler = "server.handler";
257
- }
258
- else {
259
- bundlePath = path.join(sitePath, ".open-next/image-optimization-function");
260
- handler = "index.handler";
261
- }
262
- return new lambda.Function(this, `ImageFunction`, {
263
- description: "Image optimization handler for Next.js",
264
- handler,
265
- currentVersionOptions: {
266
- removalPolicy: RemovalPolicy.DESTROY,
267
- },
268
- logRetention: logs.RetentionDays.THREE_DAYS,
269
- code: lambda.Code.fromAsset(bundlePath),
270
- runtime: lambda.Runtime.NODEJS_18_X,
271
- memorySize: defaults?.function?.memorySize || 512,
272
- timeout: Duration.seconds(defaults?.function?.timeout || 10),
273
- environment: {
274
- BUCKET_NAME: this.cdk.bucket.bucketName,
275
- }
276
- });
277
- }
278
- createMiddlewareEdgeFunctionForRegional() {
279
- const { defaults, environment, path: sitePath } = this.props;
280
- const middlewarePath = path.resolve(sitePath, ".open-next/middleware-function");
281
- const isMiddlewareEnabled = fs.existsSync(middlewarePath);
282
- let bundlePath, handler;
283
- if (this.isPlaceholder || !isMiddlewareEnabled) {
284
- bundlePath = path.resolve(__dirname, "../support/ssr-site-function-stub");
285
- handler = "server.handler";
286
- }
287
- else {
288
- bundlePath = middlewarePath;
289
- handler = "index.handler";
290
- }
291
- const fn = new EdgeFunction(this, "Middleware", {
292
- bundlePath,
293
- handler,
294
- timeout: 5,
295
- memory: 128,
296
- permissions: defaults?.function?.permissions,
297
- environment,
298
- format: "esm",
299
- });
300
- return { fn, isMiddlewareEnabled };
301
- }
302
264
  }