sst 2.30.4 → 2.32.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/App.js +7 -7
- package/constructs/BaseSite.d.ts +2 -13
- package/constructs/Distribution.d.ts +5 -10
- package/constructs/Distribution.js +6 -4
- package/constructs/Function.d.ts +6 -6
- package/constructs/Function.js +3 -3
- package/constructs/NextjsSite.d.ts +14 -2
- package/constructs/NextjsSite.js +204 -39
- package/constructs/RDS.js +2 -2
- package/constructs/Service.d.ts +0 -1
- package/constructs/Service.js +0 -1
- package/constructs/SsrSite.d.ts +58 -88
- package/constructs/SsrSite.js +136 -238
- package/constructs/StaticSite.d.ts +46 -33
- package/constructs/StaticSite.js +60 -76
- package/constructs/deprecated/NextjsSite.js +57 -71
- package/package.json +5 -4
- package/support/base-site-archiver.mjs +18 -18
- package/support/custom-resources/index.mjs +14875 -6761
- package/support/base-site-custom-resource/s3-handler.py +0 -195
- package/support/base-site-custom-resource/s3-upload.py +0 -89
package/constructs/App.js
CHANGED
|
@@ -264,28 +264,28 @@ export class App extends CDKApp {
|
|
|
264
264
|
const functions = useFunctions();
|
|
265
265
|
const sourcemaps = functions.sourcemaps.forStack(child.stackName);
|
|
266
266
|
if (sourcemaps.length) {
|
|
267
|
-
const policy = new Policy(child, "
|
|
267
|
+
const policy = new Policy(child, "SourcemapUploaderPolicy", {
|
|
268
268
|
statements: [
|
|
269
269
|
new PolicyStatement({
|
|
270
270
|
effect: Effect.ALLOW,
|
|
271
271
|
actions: ["s3:GetObject", "s3:PutObject"],
|
|
272
272
|
resources: [
|
|
273
|
-
sourcemaps[0].
|
|
273
|
+
sourcemaps[0].srcBucket.bucketArn + "/*",
|
|
274
274
|
`arn:${child.partition}:s3:::${bootstrap.bucket}/*`,
|
|
275
275
|
],
|
|
276
276
|
}),
|
|
277
277
|
],
|
|
278
278
|
});
|
|
279
279
|
child.customResourceHandler.role?.attachInlinePolicy(policy);
|
|
280
|
-
const resource = new CustomResource(child, "
|
|
280
|
+
const resource = new CustomResource(child, "SourcemapUploader", {
|
|
281
281
|
serviceToken: child.customResourceHandler.functionArn,
|
|
282
|
-
resourceType: "Custom::
|
|
282
|
+
resourceType: "Custom::SourcemapUploader",
|
|
283
283
|
properties: {
|
|
284
284
|
app: this.name,
|
|
285
285
|
stage: this.stage,
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
286
|
+
tarBucket: bootstrap.bucket,
|
|
287
|
+
srcBucket: sourcemaps[0].srcBucket.bucketName,
|
|
288
|
+
sourcemaps: sourcemaps.map((s) => [s.tarKey, s.srcKey]),
|
|
289
289
|
},
|
|
290
290
|
});
|
|
291
291
|
resource.node.addDependency(policy);
|
package/constructs/BaseSite.d.ts
CHANGED
|
@@ -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
|
-
|
|
8
|
-
|
|
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;
|
|
@@ -94,15 +94,6 @@ export interface DistributionProps {
|
|
|
94
94
|
* ```
|
|
95
95
|
*/
|
|
96
96
|
customDomain?: string | DistributionDomainProps;
|
|
97
|
-
/**
|
|
98
|
-
* The SSR function is deployed to Lambda in a single region. Alternatively, you can enable this option to deploy to Lambda@Edge.
|
|
99
|
-
* @default false
|
|
100
|
-
*/
|
|
101
|
-
/**
|
|
102
|
-
* 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.
|
|
103
|
-
* @default false
|
|
104
|
-
*/
|
|
105
|
-
waitForInvalidation?: boolean;
|
|
106
97
|
scopeOverride?: IConstruct;
|
|
107
98
|
cdk: {
|
|
108
99
|
distribution: CdkDistributionProps | IDistribution;
|
|
@@ -132,7 +123,11 @@ export declare class Distribution extends Construct {
|
|
|
132
123
|
hostedZone: IHostedZone | undefined;
|
|
133
124
|
certificate: ICertificate | undefined;
|
|
134
125
|
};
|
|
135
|
-
createInvalidation(
|
|
126
|
+
createInvalidation(props?: {
|
|
127
|
+
version?: string;
|
|
128
|
+
paths?: string[];
|
|
129
|
+
wait?: boolean;
|
|
130
|
+
}): CustomResource;
|
|
136
131
|
private validateCloudFrontDistributionSettings;
|
|
137
132
|
private validateCustomDomainSettings;
|
|
138
133
|
private lookupHostedZone;
|
|
@@ -70,7 +70,8 @@ export class Distribution extends Construct {
|
|
|
70
70
|
certificate: this.certificate,
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
|
-
createInvalidation(
|
|
73
|
+
createInvalidation(props) {
|
|
74
|
+
const { version, paths, wait } = props ?? {};
|
|
74
75
|
const stack = Stack.of(this);
|
|
75
76
|
const policy = new Policy(this.scope, "CloudFrontInvalidatorPolicy", {
|
|
76
77
|
statements: [
|
|
@@ -91,10 +92,11 @@ export class Distribution extends Construct {
|
|
|
91
92
|
serviceToken: stack.customResourceHandler.functionArn,
|
|
92
93
|
resourceType: "Custom::CloudFrontInvalidator",
|
|
93
94
|
properties: {
|
|
94
|
-
|
|
95
|
+
version: version ||
|
|
96
|
+
Date.now().toString(16) + Math.random().toString(16).slice(2),
|
|
95
97
|
distributionId: this.distribution.distributionId,
|
|
96
|
-
paths: paths ?? ["/*"],
|
|
97
|
-
|
|
98
|
+
paths: [...new Set(paths ?? ["/*"])],
|
|
99
|
+
wait: wait ?? false,
|
|
98
100
|
},
|
|
99
101
|
});
|
|
100
102
|
resource.node.addDependency(policy);
|
package/constructs/Function.d.ts
CHANGED
|
@@ -693,14 +693,14 @@ export declare class Function extends CDKFunction implements SSTConstruct {
|
|
|
693
693
|
export declare const useFunctions: () => {
|
|
694
694
|
sourcemaps: {
|
|
695
695
|
add(stack: string, source: {
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
696
|
+
srcBucket: IBucket;
|
|
697
|
+
srcKey: string;
|
|
698
|
+
tarKey: string;
|
|
699
699
|
}): void;
|
|
700
700
|
forStack(stack: string): {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
701
|
+
srcBucket: IBucket;
|
|
702
|
+
srcKey: string;
|
|
703
|
+
tarKey: string;
|
|
704
704
|
}[];
|
|
705
705
|
};
|
|
706
706
|
fromID(id: string): FunctionProps | undefined;
|
package/constructs/Function.js
CHANGED
|
@@ -257,9 +257,9 @@ export class Function extends CDKFunction {
|
|
|
257
257
|
});
|
|
258
258
|
await fs.rm(result.sourcemap);
|
|
259
259
|
useFunctions().sourcemaps.add(stack.stackName, {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
260
|
+
srcBucket: asset.bucket,
|
|
261
|
+
srcKey: asset.s3ObjectKey,
|
|
262
|
+
tarKey: this.functionArn,
|
|
263
263
|
});
|
|
264
264
|
}
|
|
265
265
|
// Update code
|
|
@@ -27,7 +27,7 @@ export interface NextjsSiteProps extends Omit<SsrSiteProps, "nodejs"> {
|
|
|
27
27
|
* logging: "per-route",
|
|
28
28
|
* ```
|
|
29
29
|
*/
|
|
30
|
-
|
|
30
|
+
logging?: "combined" | "per-route";
|
|
31
31
|
imageOptimization?: {
|
|
32
32
|
/**
|
|
33
33
|
* The amount of memory in MB allocated for image optimization function.
|
|
@@ -123,7 +123,11 @@ type NextjsSiteNormalizedProps = NextjsSiteProps & SsrSiteNormalizedProps;
|
|
|
123
123
|
*/
|
|
124
124
|
export declare class NextjsSite extends SsrSite {
|
|
125
125
|
props: NextjsSiteNormalizedProps;
|
|
126
|
-
private
|
|
126
|
+
private _routes?;
|
|
127
|
+
private routesManifest?;
|
|
128
|
+
private appPathRoutesManifest?;
|
|
129
|
+
private appPathsManifest?;
|
|
130
|
+
private pagesManifest?;
|
|
127
131
|
constructor(scope: Construct, id: string, props?: NextjsSiteProps);
|
|
128
132
|
static buildDefaultServerCachePolicyProps(): CachePolicyProps;
|
|
129
133
|
protected plan(bucket: Bucket): {
|
|
@@ -335,10 +339,18 @@ export declare class NextjsSite extends SsrSite {
|
|
|
335
339
|
};
|
|
336
340
|
};
|
|
337
341
|
private wrapServerFunction;
|
|
342
|
+
private removeSourcemaps;
|
|
338
343
|
private useRoutes;
|
|
344
|
+
private useRoutesManifest;
|
|
345
|
+
private useAppPathRoutesManifest;
|
|
346
|
+
private useAppPathsManifest;
|
|
347
|
+
private usePagesManifest;
|
|
339
348
|
private getBuildId;
|
|
349
|
+
private getSourcemapForAppRoute;
|
|
350
|
+
private getSourcemapForPagesRoute;
|
|
340
351
|
private isPerRouteLoggingEnabled;
|
|
341
352
|
private disableDefaultLogging;
|
|
353
|
+
private uploadSourcemaps;
|
|
342
354
|
private static buildCloudWatchRouteName;
|
|
343
355
|
private static buildCloudWatchRouteHash;
|
|
344
356
|
static _test: {
|
package/constructs/NextjsSite.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
+
import zlib from "zlib";
|
|
3
4
|
import crypto from "crypto";
|
|
5
|
+
import { globSync } from "glob";
|
|
4
6
|
import { Duration as CdkDuration, RemovalPolicy, CustomResource, } from "aws-cdk-lib/core";
|
|
5
7
|
import { Code, Runtime, Function as CdkFunction, Architecture, LayerVersion, } from "aws-cdk-lib/aws-lambda";
|
|
6
8
|
import { AttributeType, Billing, TableV2 as Table, } from "aws-cdk-lib/aws-dynamodb";
|
|
@@ -13,7 +15,10 @@ import { toCdkSize } from "./util/size.js";
|
|
|
13
15
|
import { Effect, Policy, PolicyStatement } from "aws-cdk-lib/aws-iam";
|
|
14
16
|
import { RetentionDays } from "aws-cdk-lib/aws-logs";
|
|
15
17
|
import { VisibleError } from "../error.js";
|
|
16
|
-
|
|
18
|
+
import { Asset } from "aws-cdk-lib/aws-s3-assets";
|
|
19
|
+
import { useFunctions } from "./Function.js";
|
|
20
|
+
import { useDeferredTasks } from "./deferred_task.js";
|
|
21
|
+
const LAYER_VERSION = "2";
|
|
17
22
|
const DEFAULT_OPEN_NEXT_VERSION = "2.2.4";
|
|
18
23
|
const DEFAULT_CACHE_POLICY_ALLOWED_HEADERS = [
|
|
19
24
|
"accept",
|
|
@@ -34,7 +39,11 @@ const DEFAULT_CACHE_POLICY_ALLOWED_HEADERS = [
|
|
|
34
39
|
* ```
|
|
35
40
|
*/
|
|
36
41
|
export class NextjsSite extends SsrSite {
|
|
37
|
-
|
|
42
|
+
_routes;
|
|
43
|
+
routesManifest;
|
|
44
|
+
appPathRoutesManifest;
|
|
45
|
+
appPathsManifest;
|
|
46
|
+
pagesManifest;
|
|
38
47
|
constructor(scope, id, props) {
|
|
39
48
|
const streaming = props?.experimental?.streaming ?? false;
|
|
40
49
|
const disableDynamoDBCache = props?.experimental?.disableDynamoDBCache ?? false;
|
|
@@ -57,6 +66,7 @@ export class NextjsSite extends SsrSite {
|
|
|
57
66
|
});
|
|
58
67
|
if (this.isPerRouteLoggingEnabled()) {
|
|
59
68
|
this.disableDefaultLogging();
|
|
69
|
+
this.uploadSourcemaps();
|
|
60
70
|
}
|
|
61
71
|
if (!disableIncrementalCache) {
|
|
62
72
|
this.createRevalidationQueue();
|
|
@@ -80,6 +90,7 @@ export class NextjsSite extends SsrSite {
|
|
|
80
90
|
CACHE_BUCKET_REGION: Stack.of(this).region,
|
|
81
91
|
},
|
|
82
92
|
});
|
|
93
|
+
this.removeSourcemaps();
|
|
83
94
|
return this.validatePlan({
|
|
84
95
|
cloudFrontFunctions: {
|
|
85
96
|
serverCfFunction: {
|
|
@@ -305,14 +316,17 @@ export class NextjsSite extends SsrSite {
|
|
|
305
316
|
};
|
|
306
317
|
}
|
|
307
318
|
wrapServerFunction(config) {
|
|
308
|
-
const { path: sitePath, experimental } = this.props;
|
|
319
|
+
const { path: sitePath, experimental, cdk } = this.props;
|
|
309
320
|
const stack = Stack.of(this);
|
|
310
321
|
const wrapperName = "nextjssite-index";
|
|
311
322
|
const serverPath = path.join(sitePath, ".open-next", "server-function");
|
|
312
323
|
const injections = [];
|
|
313
324
|
if (this.isPerRouteLoggingEnabled()) {
|
|
314
325
|
injections.push(`
|
|
315
|
-
const routeData = ${JSON.stringify(this.useRoutes()
|
|
326
|
+
const routeData = ${JSON.stringify(this.useRoutes().map(({ regex, logGroupPath }) => ({
|
|
327
|
+
regex,
|
|
328
|
+
logGroupPath,
|
|
329
|
+
})))}.find(({ regex }) => event.rawPath.match(new RegExp(regex)));
|
|
316
330
|
if (routeData) {
|
|
317
331
|
console.log("::sst::" + JSON.stringify({
|
|
318
332
|
action:"log.split",
|
|
@@ -341,65 +355,194 @@ export class NextjsSite extends SsrSite {
|
|
|
341
355
|
...config,
|
|
342
356
|
layers: this.isPerRouteLoggingEnabled()
|
|
343
357
|
? [
|
|
344
|
-
LayerVersion.fromLayerVersionArn(this, "SSTExtension",
|
|
358
|
+
LayerVersion.fromLayerVersionArn(this, "SSTExtension", cdk?.server?.architecture?.name === Architecture.X86_64.name
|
|
359
|
+
? `arn:aws:lambda:${stack.region}:226609089145:layer:sst-extension-amd64:${LAYER_VERSION}`
|
|
360
|
+
: `arn:aws:lambda:${stack.region}:226609089145:layer:sst-extension-arm64:${LAYER_VERSION}`),
|
|
345
361
|
]
|
|
346
362
|
: undefined,
|
|
347
363
|
handler: `${wrapperName}.handler`,
|
|
348
364
|
};
|
|
349
365
|
}
|
|
366
|
+
removeSourcemaps() {
|
|
367
|
+
const { path: sitePath } = this.props;
|
|
368
|
+
const files = globSync("**/*.js.map", {
|
|
369
|
+
cwd: path.join(sitePath, ".open-next", "server-function"),
|
|
370
|
+
nodir: true,
|
|
371
|
+
dot: true,
|
|
372
|
+
});
|
|
373
|
+
for (const file of files) {
|
|
374
|
+
fs.rmSync(path.join(sitePath, ".open-next", "server-function", file));
|
|
375
|
+
}
|
|
376
|
+
}
|
|
350
377
|
useRoutes() {
|
|
351
|
-
if (this.
|
|
352
|
-
return this.
|
|
353
|
-
const
|
|
378
|
+
if (this._routes)
|
|
379
|
+
return this._routes;
|
|
380
|
+
const routesManifest = this.useRoutesManifest();
|
|
381
|
+
this._routes = [
|
|
382
|
+
...[...routesManifest.dynamicRoutes, ...routesManifest.staticRoutes]
|
|
383
|
+
.map(({ page, regex }) => {
|
|
384
|
+
const cwRoute = NextjsSite.buildCloudWatchRouteName(page);
|
|
385
|
+
const cwHash = NextjsSite.buildCloudWatchRouteHash(page);
|
|
386
|
+
const sourcemapPath = this.getSourcemapForAppRoute(page) ||
|
|
387
|
+
this.getSourcemapForPagesRoute(page);
|
|
388
|
+
return {
|
|
389
|
+
route: page,
|
|
390
|
+
regex,
|
|
391
|
+
logGroupPath: `/${cwHash}${cwRoute}`,
|
|
392
|
+
sourcemapPath: sourcemapPath,
|
|
393
|
+
sourcemapKey: cwHash,
|
|
394
|
+
};
|
|
395
|
+
})
|
|
396
|
+
.sort((a, b) => a.route.localeCompare(b.route)),
|
|
397
|
+
...(routesManifest.dataRoutes || [])
|
|
398
|
+
.map(({ page, dataRouteRegex }) => {
|
|
399
|
+
const routeDisplayName = page.endsWith("/")
|
|
400
|
+
? `/_next/data/BUILD_ID${page}index.json`
|
|
401
|
+
: `/_next/data/BUILD_ID${page}.json`;
|
|
402
|
+
const cwRoute = NextjsSite.buildCloudWatchRouteName(routeDisplayName);
|
|
403
|
+
const cwHash = NextjsSite.buildCloudWatchRouteHash(page);
|
|
404
|
+
return {
|
|
405
|
+
route: routeDisplayName,
|
|
406
|
+
regex: dataRouteRegex,
|
|
407
|
+
logGroupPath: `/${cwHash}${cwRoute}`,
|
|
408
|
+
};
|
|
409
|
+
})
|
|
410
|
+
.sort((a, b) => a.route.localeCompare(b.route)),
|
|
411
|
+
];
|
|
412
|
+
return this._routes;
|
|
413
|
+
}
|
|
414
|
+
useRoutesManifest() {
|
|
415
|
+
if (this.routesManifest)
|
|
416
|
+
return this.routesManifest;
|
|
354
417
|
const { path: sitePath } = this.props;
|
|
418
|
+
const id = this.node.id;
|
|
355
419
|
try {
|
|
356
|
-
const content =
|
|
420
|
+
const content = fs
|
|
357
421
|
.readFileSync(path.join(sitePath, ".next/routes-manifest.json"))
|
|
358
|
-
.toString()
|
|
359
|
-
this.
|
|
360
|
-
|
|
361
|
-
.map(({ page, regex }) => {
|
|
362
|
-
const cwRoute = NextjsSite.buildCloudWatchRouteName(page);
|
|
363
|
-
const cwHash = NextjsSite.buildCloudWatchRouteHash(page);
|
|
364
|
-
return {
|
|
365
|
-
route: page,
|
|
366
|
-
regex,
|
|
367
|
-
logGroupPath: `/${cwHash}${cwRoute}`,
|
|
368
|
-
};
|
|
369
|
-
})
|
|
370
|
-
.sort((a, b) => a.route.localeCompare(b.route)),
|
|
371
|
-
...(content.dataRoutes || [])
|
|
372
|
-
.map(({ page, dataRouteRegex }) => {
|
|
373
|
-
const routeDisplayName = page.endsWith("/")
|
|
374
|
-
? `/_next/data/BUILD_ID${page}index.json`
|
|
375
|
-
: `/_next/data/BUILD_ID${page}.json`;
|
|
376
|
-
const cwRoute = NextjsSite.buildCloudWatchRouteName(routeDisplayName);
|
|
377
|
-
const cwHash = NextjsSite.buildCloudWatchRouteHash(`data:${page}`);
|
|
378
|
-
return {
|
|
379
|
-
route: routeDisplayName,
|
|
380
|
-
regex: dataRouteRegex,
|
|
381
|
-
logGroupPath: `/${cwHash}${cwRoute}`,
|
|
382
|
-
};
|
|
383
|
-
})
|
|
384
|
-
.sort((a, b) => a.route.localeCompare(b.route)),
|
|
385
|
-
];
|
|
386
|
-
return this.routes;
|
|
422
|
+
.toString();
|
|
423
|
+
this.routesManifest = JSON.parse(content);
|
|
424
|
+
return this.routesManifest;
|
|
387
425
|
}
|
|
388
426
|
catch (e) {
|
|
389
427
|
console.error(e);
|
|
390
428
|
throw new VisibleError(`Failed to read routes data from ".next/routes-manifest.json" for the "${id}" site.`);
|
|
391
429
|
}
|
|
392
430
|
}
|
|
431
|
+
useAppPathRoutesManifest() {
|
|
432
|
+
if (this.appPathRoutesManifest)
|
|
433
|
+
return this.appPathRoutesManifest;
|
|
434
|
+
const { path: sitePath } = this.props;
|
|
435
|
+
try {
|
|
436
|
+
const content = fs
|
|
437
|
+
.readFileSync(path.join(sitePath, ".next/app-path-routes-manifest.json"))
|
|
438
|
+
.toString();
|
|
439
|
+
this.appPathRoutesManifest = JSON.parse(content);
|
|
440
|
+
return this.appPathRoutesManifest;
|
|
441
|
+
}
|
|
442
|
+
catch (e) {
|
|
443
|
+
return {};
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
useAppPathsManifest() {
|
|
447
|
+
if (this.appPathsManifest)
|
|
448
|
+
return this.appPathsManifest;
|
|
449
|
+
const { path: sitePath } = this.props;
|
|
450
|
+
try {
|
|
451
|
+
const content = fs
|
|
452
|
+
.readFileSync(path.join(sitePath, ".next/server/app-paths-manifest.json"))
|
|
453
|
+
.toString();
|
|
454
|
+
this.appPathsManifest = JSON.parse(content);
|
|
455
|
+
return this.appPathsManifest;
|
|
456
|
+
}
|
|
457
|
+
catch (e) {
|
|
458
|
+
return {};
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
usePagesManifest() {
|
|
462
|
+
if (this.pagesManifest)
|
|
463
|
+
return this.pagesManifest;
|
|
464
|
+
const { path: sitePath } = this.props;
|
|
465
|
+
try {
|
|
466
|
+
const content = fs
|
|
467
|
+
.readFileSync(path.join(sitePath, ".next/server/pages-manifest.json"))
|
|
468
|
+
.toString();
|
|
469
|
+
this.pagesManifest = JSON.parse(content);
|
|
470
|
+
return this.pagesManifest;
|
|
471
|
+
}
|
|
472
|
+
catch (e) {
|
|
473
|
+
return {};
|
|
474
|
+
}
|
|
475
|
+
}
|
|
393
476
|
getBuildId() {
|
|
394
477
|
const { path: sitePath } = this.props;
|
|
395
478
|
return fs.readFileSync(path.join(sitePath, ".next/BUILD_ID")).toString();
|
|
396
479
|
}
|
|
480
|
+
getSourcemapForAppRoute(page) {
|
|
481
|
+
const { path: sitePath } = this.props;
|
|
482
|
+
// Step 1: look up in "appPathRoutesManifest" to find the key with
|
|
483
|
+
// value equal to the page
|
|
484
|
+
// {
|
|
485
|
+
// "/_not-found": "/_not-found",
|
|
486
|
+
// "/about/page": "/about",
|
|
487
|
+
// "/about/profile/page": "/about/profile",
|
|
488
|
+
// "/page": "/",
|
|
489
|
+
// "/favicon.ico/route": "/favicon.ico"
|
|
490
|
+
// }
|
|
491
|
+
const appPathRoutesManifest = this.useAppPathRoutesManifest();
|
|
492
|
+
const appPathRoute = Object.keys(appPathRoutesManifest).find((key) => appPathRoutesManifest[key] === page);
|
|
493
|
+
if (!appPathRoute)
|
|
494
|
+
return;
|
|
495
|
+
// Step 2: look up in "appPathsManifest" to find the file with key equal
|
|
496
|
+
// to the page
|
|
497
|
+
// {
|
|
498
|
+
// "/_not-found": "app/_not-found.js",
|
|
499
|
+
// "/about/page": "app/about/page.js",
|
|
500
|
+
// "/about/profile/page": "app/about/profile/page.js",
|
|
501
|
+
// "/page": "app/page.js",
|
|
502
|
+
// "/favicon.ico/route": "app/favicon.ico/route.js"
|
|
503
|
+
// }
|
|
504
|
+
const appPathsManifest = this.useAppPathsManifest();
|
|
505
|
+
const filePath = appPathsManifest[appPathRoute];
|
|
506
|
+
if (!filePath)
|
|
507
|
+
return;
|
|
508
|
+
// Step 3: check the .map file exists
|
|
509
|
+
const sourcemapPath = path.join(sitePath, ".next", "server", `${filePath}.map`);
|
|
510
|
+
if (!fs.existsSync(sourcemapPath))
|
|
511
|
+
return;
|
|
512
|
+
return sourcemapPath;
|
|
513
|
+
}
|
|
514
|
+
getSourcemapForPagesRoute(page) {
|
|
515
|
+
const { path: sitePath } = this.props;
|
|
516
|
+
// Step 1: look up in "pathsManifest" to find the file with key equal
|
|
517
|
+
// to the page
|
|
518
|
+
// {
|
|
519
|
+
// "/_app": "pages/_app.js",
|
|
520
|
+
// "/_error": "pages/_error.js",
|
|
521
|
+
// "/404": "pages/404.html",
|
|
522
|
+
// "/api/hello": "pages/api/hello.js",
|
|
523
|
+
// "/api/auth/[...nextauth]": "pages/api/auth/[...nextauth].js",
|
|
524
|
+
// "/api/next-auth-restricted": "pages/api/next-auth-restricted.js",
|
|
525
|
+
// "/": "pages/index.js",
|
|
526
|
+
// "/ssr": "pages/ssr.js"
|
|
527
|
+
// }
|
|
528
|
+
const pagesManifest = this.usePagesManifest();
|
|
529
|
+
const filePath = pagesManifest[page];
|
|
530
|
+
if (!filePath)
|
|
531
|
+
return;
|
|
532
|
+
// Step 2: check the .map file exists
|
|
533
|
+
const sourcemapPath = path.join(sitePath, ".next", "server", `${filePath}.map`);
|
|
534
|
+
if (!fs.existsSync(sourcemapPath))
|
|
535
|
+
return;
|
|
536
|
+
return sourcemapPath;
|
|
537
|
+
}
|
|
397
538
|
isPerRouteLoggingEnabled() {
|
|
398
539
|
return (!this.doNotDeploy &&
|
|
399
540
|
!this.props.edge &&
|
|
400
|
-
this.props.
|
|
541
|
+
this.props.logging === "per-route");
|
|
401
542
|
}
|
|
402
543
|
disableDefaultLogging() {
|
|
544
|
+
// Note: keep default logs enabled
|
|
545
|
+
return;
|
|
403
546
|
const stack = Stack.of(this);
|
|
404
547
|
const server = this.serverFunction;
|
|
405
548
|
const policy = new Policy(this, "DisableLoggingPolicy", {
|
|
@@ -420,6 +563,28 @@ export class NextjsSite extends SsrSite {
|
|
|
420
563
|
});
|
|
421
564
|
server.role?.attachInlinePolicy(policy);
|
|
422
565
|
}
|
|
566
|
+
uploadSourcemaps() {
|
|
567
|
+
const stack = Stack.of(this);
|
|
568
|
+
const server = this.serverFunction;
|
|
569
|
+
this.useRoutes().forEach(({ sourcemapPath, sourcemapKey }) => {
|
|
570
|
+
if (!sourcemapPath || !sourcemapKey)
|
|
571
|
+
return;
|
|
572
|
+
useDeferredTasks().add(async () => {
|
|
573
|
+
// zip sourcemap
|
|
574
|
+
const zipPath = `${sourcemapPath}.gz.zip`;
|
|
575
|
+
const data = await fs.promises.readFile(sourcemapPath);
|
|
576
|
+
await fs.promises.writeFile(zipPath, zlib.gzipSync(data));
|
|
577
|
+
const asset = new Asset(this, `Sourcemap-${sourcemapKey}`, {
|
|
578
|
+
path: zipPath,
|
|
579
|
+
});
|
|
580
|
+
useFunctions().sourcemaps.add(stack.stackName, {
|
|
581
|
+
srcBucket: asset.bucket,
|
|
582
|
+
srcKey: asset.s3ObjectKey,
|
|
583
|
+
tarKey: path.join(server.functionArn, sourcemapKey),
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
}
|
|
423
588
|
static buildCloudWatchRouteName(route) {
|
|
424
589
|
return route.replace(/[^a-zA-Z0-9_\-/.#]/g, "");
|
|
425
590
|
}
|
package/constructs/RDS.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
-
import
|
|
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 =
|
|
350
|
+
const files = globSync("**", {
|
|
351
351
|
dot: true,
|
|
352
352
|
nodir: true,
|
|
353
353
|
follow: true,
|
package/constructs/Service.d.ts
CHANGED
|
@@ -375,7 +375,6 @@ type ServiceNormalizedProps = ServiceProps & {
|
|
|
375
375
|
memory: Exclude<ServiceProps["memory"], undefined>;
|
|
376
376
|
port: Exclude<ServiceProps["port"], undefined>;
|
|
377
377
|
logRetention: Exclude<ServiceProps["logRetention"], undefined>;
|
|
378
|
-
waitForInvalidation: Exclude<ServiceProps["waitForInvalidation"], undefined>;
|
|
379
378
|
};
|
|
380
379
|
/**
|
|
381
380
|
* The `Service` construct is a higher level CDK construct that makes it easy to create modern web apps with Server Side Rendering capabilities.
|
package/constructs/Service.js
CHANGED