sst 2.30.3 → 2.31.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.
@@ -1,20 +1,9 @@
1
1
  import { ErrorResponse, DistributionProps, BehaviorOptions, IOrigin } from "aws-cdk-lib/aws-cloudfront";
2
- export interface BaseSiteFileOptionsFilter {
3
- include?: string;
4
- exclude?: string;
5
- }
6
2
  export interface BaseSiteFileOptions {
7
- filters: BaseSiteFileOptionsFilter[];
8
- cacheControl?: string;
9
- contentType?: string;
10
- contentEncoding?: string;
11
- }
12
- export interface BaseSiteFileOptionsDeprecated {
13
- include?: string | string[];
14
- exclude?: string | string[];
3
+ files: string | string[];
4
+ ignore?: string | string[];
15
5
  cacheControl?: string;
16
6
  contentType?: string;
17
- contentEncoding?: string;
18
7
  }
19
8
  export interface BaseSiteEnvironmentOutputsInfo {
20
9
  path: string;
@@ -1,8 +1,11 @@
1
1
  import { Construct } from "constructs";
2
+ import { Duration as CdkDuration } from "aws-cdk-lib/core";
2
3
  import { Runtime, FunctionProps, Architecture } from "aws-cdk-lib/aws-lambda";
3
4
  import { SsrSite, SsrSiteNormalizedProps, SsrSiteProps } from "./SsrSite.js";
4
5
  import { Size } from "./util/size.js";
5
6
  import { Bucket } from "aws-cdk-lib/aws-s3";
7
+ import { PolicyStatement } from "aws-cdk-lib/aws-iam";
8
+ import { RetentionDays } from "aws-cdk-lib/aws-logs";
6
9
  import { CachePolicyProps } from "aws-cdk-lib/aws-cloudfront";
7
10
  export interface NextjsSiteProps extends Omit<SsrSiteProps, "nodejs"> {
8
11
  /**
@@ -14,6 +17,17 @@ export interface NextjsSiteProps extends Omit<SsrSiteProps, "nodejs"> {
14
17
  * ```
15
18
  */
16
19
  openNextVersion?: string;
20
+ /**
21
+ * How the logs are stored in CloudWatch
22
+ * - "combined" - Logs from all routes are stored in the same log group.
23
+ * - "per-route" - Logs from each route are stored in a separate log group.
24
+ * @default "combined"
25
+ * @example
26
+ * ```js
27
+ * logging: "per-route",
28
+ * ```
29
+ */
30
+ logging?: "combined" | "per-route";
17
31
  imageOptimization?: {
18
32
  /**
19
33
  * The amount of memory in MB allocated for image optimization function.
@@ -109,6 +123,7 @@ type NextjsSiteNormalizedProps = NextjsSiteProps & SsrSiteNormalizedProps;
109
123
  */
110
124
  export declare class NextjsSite extends SsrSite {
111
125
  props: NextjsSiteNormalizedProps;
126
+ private routes?;
112
127
  constructor(scope: Construct, id: string, props?: NextjsSiteProps);
113
128
  static buildDefaultServerCachePolicyProps(): CachePolicyProps;
114
129
  protected plan(bucket: Bucket): {
@@ -122,14 +137,64 @@ export declare class NextjsSite extends SsrSite {
122
137
  edgeServer: {
123
138
  constructId: string;
124
139
  function: {
125
- description: string;
126
- bundle: string;
140
+ layers: import("aws-cdk-lib/aws-lambda").ILayerVersion[] | undefined;
127
141
  handler: string;
128
- environment: {
129
- CACHE_BUCKET_NAME: string;
130
- CACHE_BUCKET_KEY_PREFIX: string;
131
- CACHE_BUCKET_REGION: string;
132
- };
142
+ bundle?: string | undefined;
143
+ runtime?: "nodejs14.x" | "nodejs16.x" | "nodejs18.x" | undefined;
144
+ timeout?: number | `${number} second` | `${number} seconds` | `${number} minute` | `${number} minutes` | `${number} hour` | `${number} hours` | `${number} day` | `${number} days` | undefined;
145
+ memorySize?: number | `${number} MB` | `${number} GB` | undefined;
146
+ permissions?: import("./index.js").Permissions | undefined;
147
+ environment?: Record<string, string> | undefined;
148
+ bind?: import("./Construct.js").SSTConstruct[] | undefined;
149
+ nodejs?: import("./Function.js").NodeJSProps | undefined;
150
+ copyFiles?: import("./Function.js").FunctionCopyFilesProps[] | undefined;
151
+ logRetention?: RetentionDays | undefined;
152
+ functionName?: string | undefined;
153
+ tracing?: import("aws-cdk-lib/aws-lambda").Tracing | undefined;
154
+ architecture?: Architecture | undefined;
155
+ description?: string | undefined;
156
+ ephemeralStorageSize?: import("aws-cdk-lib/core").Size | undefined;
157
+ initialPolicy?: PolicyStatement[] | undefined;
158
+ role?: import("aws-cdk-lib/aws-iam").IRole | undefined;
159
+ vpc?: import("aws-cdk-lib/aws-ec2").IVpc | undefined;
160
+ vpcSubnets?: import("aws-cdk-lib/aws-ec2").SubnetSelection | undefined;
161
+ securityGroups?: import("aws-cdk-lib/aws-ec2").ISecurityGroup[] | undefined;
162
+ allowAllOutbound?: boolean | undefined;
163
+ deadLetterQueueEnabled?: boolean | undefined;
164
+ deadLetterQueue?: import("aws-cdk-lib/aws-sqs").IQueue | undefined;
165
+ deadLetterTopic?: import("aws-cdk-lib/aws-sns").ITopic | undefined;
166
+ snapStart?: import("aws-cdk-lib/aws-lambda").SnapStartConf | undefined;
167
+ profiling?: boolean | undefined;
168
+ profilingGroup?: import("aws-cdk-lib/aws-codeguruprofiler").IProfilingGroup | undefined;
169
+ insightsVersion?: import("aws-cdk-lib/aws-lambda").LambdaInsightsVersion | undefined;
170
+ adotInstrumentation?: import("aws-cdk-lib/aws-lambda").AdotInstrumentationConfig | undefined;
171
+ paramsAndSecrets?: import("aws-cdk-lib/aws-lambda").ParamsAndSecretsLayerVersion | undefined;
172
+ reservedConcurrentExecutions?: number | undefined;
173
+ events?: import("aws-cdk-lib/aws-lambda").IEventSource[] | undefined;
174
+ logRetentionRole?: import("aws-cdk-lib/aws-iam").IRole | undefined;
175
+ logRetentionRetryOptions?: import("aws-cdk-lib/aws-lambda").LogRetentionRetryOptions | undefined;
176
+ currentVersionOptions?: import("aws-cdk-lib/aws-lambda").VersionOptions | undefined;
177
+ filesystem?: import("aws-cdk-lib/aws-lambda").FileSystem | undefined;
178
+ allowPublicSubnet?: boolean | undefined;
179
+ environmentEncryption?: import("aws-cdk-lib/aws-kms").IKey | undefined;
180
+ codeSigningConfig?: import("aws-cdk-lib/aws-lambda").ICodeSigningConfig | undefined;
181
+ runtimeManagementMode?: import("aws-cdk-lib/aws-lambda").RuntimeManagementMode | undefined;
182
+ onFailure?: import("aws-cdk-lib/aws-lambda").IDestination | undefined;
183
+ onSuccess?: import("aws-cdk-lib/aws-lambda").IDestination | undefined;
184
+ maxEventAge?: CdkDuration | undefined;
185
+ retryAttempts?: number | undefined;
186
+ } | {
187
+ layers: import("aws-cdk-lib/aws-lambda").ILayerVersion[] | undefined;
188
+ handler: string;
189
+ bundle?: string | undefined;
190
+ runtime?: "nodejs14.x" | "nodejs16.x" | "nodejs18.x" | undefined;
191
+ timeout?: number | `${number} second` | `${number} seconds` | `${number} minute` | `${number} minutes` | `${number} hour` | `${number} hours` | `${number} day` | `${number} days` | undefined;
192
+ memorySize?: number | `${number} MB` | `${number} GB` | undefined;
193
+ permissions?: import("./index.js").Permissions | undefined;
194
+ environment?: Record<string, string> | undefined;
195
+ bind?: import("./Construct.js").SSTConstruct[] | undefined;
196
+ nodejs?: import("./Function.js").NodeJSProps | undefined;
197
+ scopeOverride?: import("constructs").IConstruct | undefined;
133
198
  };
134
199
  };
135
200
  } | undefined;
@@ -169,14 +234,64 @@ export declare class NextjsSite extends SsrSite {
169
234
  type: "function";
170
235
  constructId: string;
171
236
  function: {
172
- description: string;
173
- bundle: string;
237
+ layers: import("aws-cdk-lib/aws-lambda").ILayerVersion[] | undefined;
174
238
  handler: string;
175
- environment: {
176
- CACHE_BUCKET_NAME: string;
177
- CACHE_BUCKET_KEY_PREFIX: string;
178
- CACHE_BUCKET_REGION: string;
179
- };
239
+ bundle?: string | undefined;
240
+ runtime?: "nodejs14.x" | "nodejs16.x" | "nodejs18.x" | undefined;
241
+ timeout?: number | `${number} second` | `${number} seconds` | `${number} minute` | `${number} minutes` | `${number} hour` | `${number} hours` | `${number} day` | `${number} days` | undefined;
242
+ memorySize?: number | `${number} MB` | `${number} GB` | undefined;
243
+ permissions?: import("./index.js").Permissions | undefined;
244
+ environment?: Record<string, string> | undefined;
245
+ bind?: import("./Construct.js").SSTConstruct[] | undefined;
246
+ nodejs?: import("./Function.js").NodeJSProps | undefined;
247
+ copyFiles?: import("./Function.js").FunctionCopyFilesProps[] | undefined;
248
+ logRetention?: RetentionDays | undefined;
249
+ functionName?: string | undefined;
250
+ tracing?: import("aws-cdk-lib/aws-lambda").Tracing | undefined;
251
+ architecture?: Architecture | undefined;
252
+ description?: string | undefined;
253
+ ephemeralStorageSize?: import("aws-cdk-lib/core").Size | undefined;
254
+ initialPolicy?: PolicyStatement[] | undefined;
255
+ role?: import("aws-cdk-lib/aws-iam").IRole | undefined;
256
+ vpc?: import("aws-cdk-lib/aws-ec2").IVpc | undefined;
257
+ vpcSubnets?: import("aws-cdk-lib/aws-ec2").SubnetSelection | undefined;
258
+ securityGroups?: import("aws-cdk-lib/aws-ec2").ISecurityGroup[] | undefined;
259
+ allowAllOutbound?: boolean | undefined;
260
+ deadLetterQueueEnabled?: boolean | undefined;
261
+ deadLetterQueue?: import("aws-cdk-lib/aws-sqs").IQueue | undefined;
262
+ deadLetterTopic?: import("aws-cdk-lib/aws-sns").ITopic | undefined;
263
+ snapStart?: import("aws-cdk-lib/aws-lambda").SnapStartConf | undefined;
264
+ profiling?: boolean | undefined;
265
+ profilingGroup?: import("aws-cdk-lib/aws-codeguruprofiler").IProfilingGroup | undefined;
266
+ insightsVersion?: import("aws-cdk-lib/aws-lambda").LambdaInsightsVersion | undefined;
267
+ adotInstrumentation?: import("aws-cdk-lib/aws-lambda").AdotInstrumentationConfig | undefined;
268
+ paramsAndSecrets?: import("aws-cdk-lib/aws-lambda").ParamsAndSecretsLayerVersion | undefined;
269
+ reservedConcurrentExecutions?: number | undefined;
270
+ events?: import("aws-cdk-lib/aws-lambda").IEventSource[] | undefined;
271
+ logRetentionRole?: import("aws-cdk-lib/aws-iam").IRole | undefined;
272
+ logRetentionRetryOptions?: import("aws-cdk-lib/aws-lambda").LogRetentionRetryOptions | undefined;
273
+ currentVersionOptions?: import("aws-cdk-lib/aws-lambda").VersionOptions | undefined;
274
+ filesystem?: import("aws-cdk-lib/aws-lambda").FileSystem | undefined;
275
+ allowPublicSubnet?: boolean | undefined;
276
+ environmentEncryption?: import("aws-cdk-lib/aws-kms").IKey | undefined;
277
+ codeSigningConfig?: import("aws-cdk-lib/aws-lambda").ICodeSigningConfig | undefined;
278
+ runtimeManagementMode?: import("aws-cdk-lib/aws-lambda").RuntimeManagementMode | undefined;
279
+ onFailure?: import("aws-cdk-lib/aws-lambda").IDestination | undefined;
280
+ onSuccess?: import("aws-cdk-lib/aws-lambda").IDestination | undefined;
281
+ maxEventAge?: CdkDuration | undefined;
282
+ retryAttempts?: number | undefined;
283
+ } | {
284
+ layers: import("aws-cdk-lib/aws-lambda").ILayerVersion[] | undefined;
285
+ handler: string;
286
+ bundle?: string | undefined;
287
+ runtime?: "nodejs14.x" | "nodejs16.x" | "nodejs18.x" | undefined;
288
+ timeout?: number | `${number} second` | `${number} seconds` | `${number} minute` | `${number} minutes` | `${number} hour` | `${number} hours` | `${number} day` | `${number} days` | undefined;
289
+ memorySize?: number | `${number} MB` | `${number} GB` | undefined;
290
+ permissions?: import("./index.js").Permissions | undefined;
291
+ environment?: Record<string, string> | undefined;
292
+ bind?: import("./Construct.js").SSTConstruct[] | undefined;
293
+ nodejs?: import("./Function.js").NodeJSProps | undefined;
294
+ scopeOverride?: import("constructs").IConstruct | undefined;
180
295
  };
181
296
  streaming: boolean | undefined;
182
297
  } | undefined;
@@ -203,8 +318,12 @@ export declare class NextjsSite extends SsrSite {
203
318
  type: "NextjsSite";
204
319
  data: {
205
320
  routes: {
206
- route: string;
207
- }[] | undefined;
321
+ logGroupPrefix: string;
322
+ data: {
323
+ route: string;
324
+ logGroupPath: string;
325
+ }[];
326
+ } | undefined;
208
327
  mode: "placeholder" | "deployed";
209
328
  path: string;
210
329
  runtime: "nodejs14.x" | "nodejs16.x" | "nodejs18.x";
@@ -215,8 +334,15 @@ export declare class NextjsSite extends SsrSite {
215
334
  secrets: string[];
216
335
  };
217
336
  };
218
- private wrapHandler;
219
- private getRoutes;
337
+ private wrapServerFunction;
338
+ private useRoutes;
220
339
  private getBuildId;
340
+ private isPerRouteLoggingEnabled;
341
+ private disableDefaultLogging;
342
+ private static buildCloudWatchRouteName;
343
+ private static buildCloudWatchRouteHash;
344
+ static _test: {
345
+ buildCloudWatchRouteName: typeof NextjsSite.buildCloudWatchRouteName;
346
+ };
221
347
  }
222
348
  export {};
@@ -1,7 +1,8 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
+ import crypto from "crypto";
3
4
  import { Duration as CdkDuration, RemovalPolicy, CustomResource, } from "aws-cdk-lib/core";
4
- import { Code, Runtime, Function as CdkFunction, Architecture, } from "aws-cdk-lib/aws-lambda";
5
+ import { Code, Runtime, Function as CdkFunction, Architecture, LayerVersion, } from "aws-cdk-lib/aws-lambda";
5
6
  import { AttributeType, Billing, TableV2 as Table, } from "aws-cdk-lib/aws-dynamodb";
6
7
  import { Provider } from "aws-cdk-lib/custom-resources";
7
8
  import { Queue } from "aws-cdk-lib/aws-sqs";
@@ -9,9 +10,10 @@ import { SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
9
10
  import { Stack } from "./Stack.js";
10
11
  import { SsrSite } from "./SsrSite.js";
11
12
  import { toCdkSize } from "./util/size.js";
12
- import { PolicyStatement } from "aws-cdk-lib/aws-iam";
13
+ import { Effect, Policy, PolicyStatement } from "aws-cdk-lib/aws-iam";
13
14
  import { RetentionDays } from "aws-cdk-lib/aws-logs";
14
15
  import { VisibleError } from "../error.js";
16
+ const LAYER_VERSION = "2";
15
17
  const DEFAULT_OPEN_NEXT_VERSION = "2.2.4";
16
18
  const DEFAULT_CACHE_POLICY_ALLOWED_HEADERS = [
17
19
  "accept",
@@ -32,13 +34,11 @@ const DEFAULT_CACHE_POLICY_ALLOWED_HEADERS = [
32
34
  * ```
33
35
  */
34
36
  export class NextjsSite extends SsrSite {
37
+ routes;
35
38
  constructor(scope, id, props) {
36
- const { streaming, disableDynamoDBCache, disableIncrementalCache } = {
37
- streaming: false,
38
- disableDynamoDBCache: false,
39
- disableIncrementalCache: false,
40
- ...props?.experimental,
41
- };
39
+ const streaming = props?.experimental?.streaming ?? false;
40
+ const disableDynamoDBCache = props?.experimental?.disableDynamoDBCache ?? false;
41
+ const disableIncrementalCache = props?.experimental?.disableIncrementalCache ?? false;
42
42
  super(scope, id, {
43
43
  buildCommand: [
44
44
  "npx",
@@ -55,6 +55,9 @@ export class NextjsSite extends SsrSite {
55
55
  ].join(" "),
56
56
  ...props,
57
57
  });
58
+ if (this.isPerRouteLoggingEnabled()) {
59
+ this.disableDefaultLogging();
60
+ }
58
61
  if (!disableIncrementalCache) {
59
62
  this.createRevalidationQueue();
60
63
  if (!disableDynamoDBCache) {
@@ -67,16 +70,16 @@ export class NextjsSite extends SsrSite {
67
70
  }
68
71
  plan(bucket) {
69
72
  const { path: sitePath, edge, experimental, imageOptimization, } = this.props;
70
- const serverConfig = {
73
+ const serverConfig = this.wrapServerFunction({
71
74
  description: "Next.js server",
72
75
  bundle: path.join(sitePath, ".open-next", "server-function"),
73
- handler: this.wrapHandler(),
76
+ handler: "index.handler",
74
77
  environment: {
75
78
  CACHE_BUCKET_NAME: bucket.bucketName,
76
79
  CACHE_BUCKET_KEY_PREFIX: "_cache",
77
80
  CACHE_BUCKET_REGION: Stack.of(this).region,
78
81
  },
79
- };
82
+ });
80
83
  return this.validatePlan({
81
84
  cloudFrontFunctions: {
82
85
  serverCfFunction: {
@@ -289,50 +292,100 @@ export class NextjsSite extends SsrSite {
289
292
  type: "NextjsSite",
290
293
  data: {
291
294
  ...metadata.data,
292
- routes: this.props.edge || this.doNotDeploy ? undefined : this.getRoutes(),
295
+ routes: this.isPerRouteLoggingEnabled()
296
+ ? {
297
+ logGroupPrefix: `/sst/lambda/${this.serverFunction.functionName}`,
298
+ data: this.useRoutes().map(({ route, logGroupPath }) => ({
299
+ route,
300
+ logGroupPath,
301
+ })),
302
+ }
303
+ : undefined,
293
304
  },
294
305
  };
295
306
  }
296
- wrapHandler() {
297
- const { path: sitePath, experimental } = this.props;
307
+ wrapServerFunction(config) {
308
+ const { path: sitePath, experimental, cdk } = this.props;
309
+ const stack = Stack.of(this);
298
310
  const wrapperName = "nextjssite-index";
299
311
  const serverPath = path.join(sitePath, ".open-next", "server-function");
312
+ const injections = [];
313
+ if (this.isPerRouteLoggingEnabled()) {
314
+ injections.push(`
315
+ const routeData = ${JSON.stringify(this.useRoutes())}.find(({ regex }) => event.rawPath.match(new RegExp(regex)));
316
+ if (routeData) {
317
+ console.log("::sst::" + JSON.stringify({
318
+ action:"log.split",
319
+ properties: {
320
+ logGroupName:"/sst/lambda/" + context.functionName + routeData.logGroupPath,
321
+ },
322
+ }));
323
+ }`);
324
+ }
300
325
  fs.writeFileSync(path.join(serverPath, `${wrapperName}.mjs`), experimental?.streaming
301
326
  ? [
302
- `export const handler = awslambda.streamifyResponse(async (...args) => {`,
327
+ `export const handler = awslambda.streamifyResponse(async (event, context) => {`,
328
+ ...injections,
303
329
  ` const { handler: rawHandler} = await import("./index.mjs");`,
304
- ` return rawHandler(...args);`,
330
+ ` return rawHandler(event, context);`,
305
331
  `});`,
306
332
  ].join("\n")
307
333
  : [
308
- `export const handler = async (...args) => {`,
334
+ `export const handler = async (event, context) => {`,
335
+ ...injections,
309
336
  ` const { handler: rawHandler} = await import("./index.mjs");`,
310
- ` return rawHandler(...args);`,
337
+ ` return rawHandler(event, context);`,
311
338
  `};`,
312
339
  ].join("\n"));
313
- return `${wrapperName}.handler`;
340
+ return {
341
+ ...config,
342
+ layers: this.isPerRouteLoggingEnabled()
343
+ ? [
344
+ LayerVersion.fromLayerVersionArn(this, "SSTExtension", cdk?.server?.architecture?.name === Architecture.X86_64.name
345
+ ? `arn:aws:lambda:${stack.region}:226609089145:layer:sst-extension-amd64:${LAYER_VERSION}`
346
+ : `arn:aws:lambda:${stack.region}:226609089145:layer:sst-extension-arm64:${LAYER_VERSION}`),
347
+ ]
348
+ : undefined,
349
+ handler: `${wrapperName}.handler`,
350
+ };
314
351
  }
315
- getRoutes() {
352
+ useRoutes() {
353
+ if (this.routes)
354
+ return this.routes;
316
355
  const id = this.node.id;
317
356
  const { path: sitePath } = this.props;
318
357
  try {
319
358
  const content = JSON.parse(fs
320
359
  .readFileSync(path.join(sitePath, ".next/routes-manifest.json"))
321
360
  .toString());
322
- return [
361
+ this.routes = [
323
362
  ...[...content.dynamicRoutes, ...content.staticRoutes]
324
- .map(({ page }) => ({
325
- route: page,
326
- }))
363
+ .map(({ page, regex }) => {
364
+ const cwRoute = NextjsSite.buildCloudWatchRouteName(page);
365
+ const cwHash = NextjsSite.buildCloudWatchRouteHash(page);
366
+ return {
367
+ route: page,
368
+ regex,
369
+ logGroupPath: `/${cwHash}${cwRoute}`,
370
+ };
371
+ })
327
372
  .sort((a, b) => a.route.localeCompare(b.route)),
328
373
  ...(content.dataRoutes || [])
329
- .map(({ page }) => ({
330
- route: page.endsWith("/")
374
+ .map(({ page, dataRouteRegex }) => {
375
+ const routeDisplayName = page.endsWith("/")
331
376
  ? `/_next/data/BUILD_ID${page}index.json`
332
- : `/_next/data/BUILD_ID${page}.json`,
333
- }))
377
+ : `/_next/data/BUILD_ID${page}.json`;
378
+ const cwRoute = NextjsSite.buildCloudWatchRouteName(routeDisplayName);
379
+ const cwHash = NextjsSite.buildCloudWatchRouteHash(`data:${page}`);
380
+ return {
381
+ route: routeDisplayName,
382
+ regex: dataRouteRegex,
383
+ logGroupPath: `/${cwHash}${cwRoute}`,
384
+ };
385
+ })
334
386
  .sort((a, b) => a.route.localeCompare(b.route)),
335
387
  ];
388
+ return this.routes;
336
389
  }
337
390
  catch (e) {
338
391
  console.error(e);
@@ -343,4 +396,43 @@ export class NextjsSite extends SsrSite {
343
396
  const { path: sitePath } = this.props;
344
397
  return fs.readFileSync(path.join(sitePath, ".next/BUILD_ID")).toString();
345
398
  }
399
+ isPerRouteLoggingEnabled() {
400
+ return (!this.doNotDeploy &&
401
+ !this.props.edge &&
402
+ this.props.logging === "per-route");
403
+ }
404
+ disableDefaultLogging() {
405
+ // Note: keep default logs enabled
406
+ return;
407
+ const stack = Stack.of(this);
408
+ const server = this.serverFunction;
409
+ const policy = new Policy(this, "DisableLoggingPolicy", {
410
+ statements: [
411
+ new PolicyStatement({
412
+ effect: Effect.DENY,
413
+ actions: [
414
+ "logs:CreateLogGroup",
415
+ "logs:CreateLogStream",
416
+ "logs:PutLogEvents",
417
+ ],
418
+ resources: [
419
+ `arn:aws:logs:${stack.region}:${stack.account}:log-group:/aws/lambda/${server.functionName}`,
420
+ `arn:aws:logs:${stack.region}:${stack.account}:log-group:/aws/lambda/${server.functionName}:*`,
421
+ ],
422
+ }),
423
+ ],
424
+ });
425
+ server.role?.attachInlinePolicy(policy);
426
+ }
427
+ static buildCloudWatchRouteName(route) {
428
+ return route.replace(/[^a-zA-Z0-9_\-/.#]/g, "");
429
+ }
430
+ static buildCloudWatchRouteHash(route) {
431
+ const hash = crypto.createHash("sha256");
432
+ hash.update(route);
433
+ return hash.digest("hex").substring(0, 8);
434
+ }
435
+ static _test = {
436
+ buildCloudWatchRouteName: NextjsSite.buildCloudWatchRouteName,
437
+ };
346
438
  }
package/constructs/RDS.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import path from "path";
2
- import glob from "glob";
2
+ import { globSync } from "glob";
3
3
  import fs from "fs";
4
4
  import url from "url";
5
5
  import * as crypto from "crypto";
@@ -347,7 +347,7 @@ export class RDS extends Construct {
347
347
  }
348
348
  generateMigrationsHash(migrations) {
349
349
  // Get all files inside the migrations folder
350
- const files = glob.sync("**", {
350
+ const files = globSync("**", {
351
351
  dot: true,
352
352
  nodir: true,
353
353
  follow: true,
@@ -8,7 +8,7 @@ import { SSTConstruct } from "./Construct.js";
8
8
  import { NodeJSProps, FunctionProps } from "./Function.js";
9
9
  import { SsrFunction, SsrFunctionProps } from "./SsrFunction.js";
10
10
  import { EdgeFunction, EdgeFunctionProps } from "./EdgeFunction.js";
11
- import { BaseSiteFileOptions, BaseSiteFileOptionsFilter, BaseSiteFileOptionsDeprecated, BaseSiteReplaceProps, BaseSiteCdkDistributionProps } from "./BaseSite.js";
11
+ import { BaseSiteFileOptions, BaseSiteReplaceProps, BaseSiteCdkDistributionProps } from "./BaseSite.js";
12
12
  import { Size } from "./util/size.js";
13
13
  import { Duration } from "./util/duration.js";
14
14
  import { Permissions } from "./util/permission.js";
@@ -52,12 +52,7 @@ export interface SsrSiteNodeJSProps extends NodeJSProps {
52
52
  }
53
53
  export interface SsrDomainProps extends DistributionDomainProps {
54
54
  }
55
- export interface SsrSiteFileOptionsFilter extends BaseSiteFileOptionsFilter {
56
- }
57
55
  export interface SsrSiteFileOptions extends BaseSiteFileOptions {
58
- filters: SsrSiteFileOptionsFilter[];
59
- }
60
- export interface SsrSiteFileOptionsDeprecated extends BaseSiteFileOptionsDeprecated {
61
56
  }
62
57
  export interface SsrSiteReplaceProps extends BaseSiteReplaceProps {
63
58
  }
@@ -207,18 +202,18 @@ export interface SsrSiteProps {
207
202
  */
208
203
  url?: string;
209
204
  };
210
- cache?: {
205
+ assets?: {
211
206
  /**
212
- * Character encoding for text based assets stored in the S3 cache (ex: html, css, js, etc.). If "none" is specified, no charset will be returned in header.
207
+ * Character encoding for text based assets uploaded to S3 (ex: html, css, js, etc.). If "none" is specified, no charset will be returned in header.
213
208
  * @default utf-8
214
209
  * @example
215
210
  * ```js
216
- * cache: {
217
- * textEncoding: "iso-8859-1"
211
+ * assets: {
212
+ * textEncoding: "iso-8859-1"
218
213
  * }
219
214
  * ```
220
215
  */
221
- textEncoding?: "UTF-8" | "ISO-8859-1" | "Windows-1252" | "ASCII" | "none";
216
+ textEncoding?: "utf-8" | "iso-8859-1" | "windows-1252" | "ascii" | "none";
222
217
  /**
223
218
  * The strategy to use for invalidating the CDN cache. By default, the CDN cache will invalidate on changes any cached file, but this could become slow on very large projects.
224
219
  * - "never" - No invalidation will be performed.
@@ -228,7 +223,7 @@ export interface SsrSiteProps {
228
223
  * @default all
229
224
  * @example
230
225
  * ```js
231
- * cache: {
226
+ * assets: {
232
227
  * cdnInvalidationStrategy: "versioned"
233
228
  * }
234
229
  * ```
@@ -239,8 +234,8 @@ export interface SsrSiteProps {
239
234
  * @default 1 year
240
235
  * @example
241
236
  * ```js
242
- * cache: {
243
- * versionedFilesTTL: "30 days"
237
+ * assets: {
238
+ * versionedFilesTTL: "30 days"
244
239
  * }
245
240
  * ```
246
241
  */
@@ -250,7 +245,7 @@ export interface SsrSiteProps {
250
245
  * @default public,max-age=31536000,immutable
251
246
  * @example
252
247
  * ```js
253
- * cache: {
248
+ * assets: {
254
249
  * versionedFilesCacheHeader: "public,max-age=31536000,immutable"
255
250
  * }
256
251
  * ```
@@ -261,8 +256,8 @@ export interface SsrSiteProps {
261
256
  * @default 1 day
262
257
  * @example
263
258
  * ```js
264
- * cache: {
265
- * nonVersionedFilesTTL: "4 hours"
259
+ * assets: {
260
+ * nonVersionedFilesTTL: "4 hours"
266
261
  * }
267
262
  * ```
268
263
  */
@@ -272,7 +267,7 @@ export interface SsrSiteProps {
272
267
  * @default public,max-age=0,s-maxage=86400,stale-while-revalidate=8640
273
268
  * @example
274
269
  * ```js
275
- * cache: {
270
+ * assets: {
276
271
  * nonVersionedFilesCacheHeader: "public,max-age=0,no-cache"
277
272
  * }
278
273
  * ```
@@ -282,10 +277,10 @@ export interface SsrSiteProps {
282
277
  * List of file options to specify cache control and content type for cached files. These file options are appended to the default file options so it's possible to override the default file options by specifying an overlapping file pattern.
283
278
  * @example
284
279
  * ```js
285
- * cache: {
280
+ * assets: {
286
281
  * fileOptions: [
287
282
  * {
288
- * filters: [ { exclude: "*" }, { include: "*.zip" } ],
283
+ * files: "**\/*.zip",
289
284
  * cacheControl: "private,no-cache,no-store,must-revalidate",
290
285
  * contentType: "application/zip",
291
286
  * },
@@ -294,6 +289,10 @@ export interface SsrSiteProps {
294
289
  * ```
295
290
  */
296
291
  fileOptions?: SsrSiteFileOptions[];
292
+ /**
293
+ * @internal
294
+ */
295
+ _uploadConcurrency?: number;
297
296
  };
298
297
  /**
299
298
  * While deploying, SST waits for the CloudFront cache invalidation process to finish. This ensures that the new content will be served once the deploy command finishes. However, this process can sometimes take more than 5 mins. For non-prod environments it might make sense to pass in `false`. That'll skip waiting for the cache to invalidate and speed up the deploy process.
@@ -343,59 +342,6 @@ export interface SsrSiteProps {
343
342
  responseHeadersPolicy?: IResponseHeadersPolicy;
344
343
  server?: Pick<CdkFunctionProps, "layers" | "vpc" | "vpcSubnets" | "securityGroups" | "allowAllOutbound" | "allowPublicSubnet" | "architecture" | "logRetention"> & Pick<FunctionProps, "copyFiles">;
345
344
  };
346
- /**
347
- * Pass in a list of file options to customize cache control and content type specific files. Specifying file options will bypass all default file options and only use the ones specified. Most configurations within the `cache` prop will be ignored.
348
- * @deprecated Use `cache.fileOptions` instead. Note that the `cache.fileOptions` are appended to default file options, not a replacement as this prop was.
349
- * @default
350
- * Versioned files cached for 1 year at the CDN and browser level.
351
- * Nonversioned files cached for 1 day at the CDN level, but not at the browser level.
352
- * ```js
353
- * fileOptions: [
354
- * {
355
- * exclude: "*",
356
- * include: "{versioned_directory}/*",
357
- * cacheControl: "public,max-age=31536000,immutable",
358
- * },
359
- * {
360
- * exclude: "*",
361
- * include: "[{non_versioned_file1}, {non_versioned_file2}, ...]",
362
- * cacheControl: "public,max-age=0,s-maxage=31536000,must-revalidate",
363
- * },
364
- * {
365
- * exclude: "*",
366
- * include: "[{non_versioned_dir_1}/*, {non_versioned_dir_2}/*, ...]",
367
- * cacheControl: "public,max-age=0,s-maxage=31536000,must-revalidate",
368
- * },
369
- * ]
370
- * ```
371
- *
372
- * @example
373
- * ```js
374
- * fileOptions: [
375
- * {
376
- * exclude: "*",
377
- * include: "{versioned_directory}/*.css",
378
- * cacheControl: "public,max-age=31536000,immutable",
379
- * contentType: "text/css; charset=UTF-8",
380
- * },
381
- * {
382
- * exclude: "*",
383
- * include: "{versioned_directory}/*.js",
384
- * cacheControl: "public,max-age=31536000,immutable",
385
- * },
386
- * {
387
- * exclude: "*",
388
- * include: "[{non_versioned_file1}, {non_versioned_file2}, ...]",
389
- * cacheControl: "public,max-age=0,s-maxage=31536000,must-revalidate",
390
- * },
391
- * {
392
- * exclude: "*",
393
- * include: "[{non_versioned_dir_1}/*, {non_versioned_dir_2}/*, ...]",
394
- * cacheControl: "public,max-age=0,s-maxage=31536000,must-revalidate",
395
- * },
396
- * ]
397
- */
398
- fileOptions?: SsrSiteFileOptionsDeprecated[];
399
345
  }
400
346
  export type SsrSiteNormalizedProps = SsrSiteProps & {
401
347
  path: Exclude<SsrSiteProps["path"], undefined>;