sst 3.0.0 → 3.0.1-2
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/package.json +8 -139
- package/src/index.ts +1 -0
- package/src/resource.ts +15 -0
- package/tsconfig.json +11 -0
- package/LICENSE +0 -21
- package/README.md +0 -43
- package/bootstrap.d.ts +0 -5
- package/bootstrap.js +0 -318
- package/bus.d.ts +0 -20
- package/bus.js +0 -52
- package/cache.d.ts +0 -4
- package/cache.js +0 -31
- package/cdk/deploy-stack.d.ts +0 -223
- package/cdk/deploy-stack.js +0 -562
- package/cdk/deployments-wrapper.d.ts +0 -3
- package/cdk/deployments-wrapper.js +0 -135
- package/cdk/deployments.d.ts +0 -327
- package/cdk/deployments.js +0 -360
- package/cdk/util.d.ts +0 -1
- package/cdk/util.js +0 -17
- package/cli/ci-info.d.ts +0 -4
- package/cli/ci-info.js +0 -8
- package/cli/colors.d.ts +0 -17
- package/cli/colors.js +0 -27
- package/cli/commands/bind.d.ts +0 -19
- package/cli/commands/bind.js +0 -360
- package/cli/commands/bootstrap.d.ts +0 -15
- package/cli/commands/bootstrap.js +0 -11
- package/cli/commands/build.d.ts +0 -17
- package/cli/commands/build.js +0 -25
- package/cli/commands/connect.d.ts +0 -17
- package/cli/commands/connect.js +0 -55
- package/cli/commands/console.d.ts +0 -15
- package/cli/commands/console.js +0 -22
- package/cli/commands/deploy.d.ts +0 -19
- package/cli/commands/deploy.js +0 -112
- package/cli/commands/dev.d.ts +0 -25
- package/cli/commands/dev.js +0 -351
- package/cli/commands/diff.d.ts +0 -19
- package/cli/commands/diff.js +0 -89
- package/cli/commands/plugins/kysely.d.ts +0 -1
- package/cli/commands/plugins/kysely.js +0 -87
- package/cli/commands/plugins/pothos.d.ts +0 -1
- package/cli/commands/plugins/pothos.js +0 -58
- package/cli/commands/plugins/warmer.d.ts +0 -1
- package/cli/commands/plugins/warmer.js +0 -33
- package/cli/commands/remove.d.ts +0 -19
- package/cli/commands/remove.js +0 -62
- package/cli/commands/secrets/get.d.ts +0 -19
- package/cli/commands/secrets/get.js +0 -27
- package/cli/commands/secrets/list.d.ts +0 -19
- package/cli/commands/secrets/list.js +0 -69
- package/cli/commands/secrets/load.d.ts +0 -17
- package/cli/commands/secrets/load.js +0 -47
- package/cli/commands/secrets/remove.d.ts +0 -19
- package/cli/commands/secrets/remove.js +0 -27
- package/cli/commands/secrets/secrets.d.ts +0 -2
- package/cli/commands/secrets/secrets.js +0 -16
- package/cli/commands/secrets/set.d.ts +0 -21
- package/cli/commands/secrets/set.js +0 -54
- package/cli/commands/telemetry.d.ts +0 -17
- package/cli/commands/telemetry.js +0 -24
- package/cli/commands/transform.d.ts +0 -17
- package/cli/commands/transform.js +0 -62
- package/cli/commands/types.d.ts +0 -15
- package/cli/commands/types.js +0 -25
- package/cli/commands/update.d.ts +0 -17
- package/cli/commands/update.js +0 -116
- package/cli/commands/version.d.ts +0 -15
- package/cli/commands/version.js +0 -15
- package/cli/local/router.d.ts +0 -44
- package/cli/local/router.js +0 -43
- package/cli/local/server.d.ts +0 -22
- package/cli/local/server.js +0 -319
- package/cli/program.d.ts +0 -19
- package/cli/program.js +0 -87
- package/cli/spinner.d.ts +0 -3
- package/cli/spinner.js +0 -14
- package/cli/sst.d.ts +0 -2
- package/cli/sst.js +0 -74
- package/cli/telemetry/environment.d.ts +0 -15
- package/cli/telemetry/environment.js +0 -27
- package/cli/telemetry/post-payload.d.ts +0 -1
- package/cli/telemetry/post-payload.js +0 -27
- package/cli/telemetry/project-id.d.ts +0 -2
- package/cli/telemetry/project-id.js +0 -47
- package/cli/telemetry/telemetry.d.ts +0 -19
- package/cli/telemetry/telemetry.js +0 -103
- package/cli/terminal.d.ts +0 -1
- package/cli/terminal.js +0 -8
- package/cli/ui/deploy.d.ts +0 -10
- package/cli/ui/deploy.js +0 -172
- package/cli/ui/functions.d.ts +0 -2
- package/cli/ui/functions.js +0 -130
- package/cli/ui/header.d.ts +0 -5
- package/cli/ui/header.js +0 -16
- package/cli/ui/stack.d.ts +0 -1
- package/cli/ui/stack.js +0 -6
- package/config.d.ts +0 -56
- package/config.js +0 -244
- package/constructs/Api.d.ts +0 -814
- package/constructs/Api.js +0 -743
- package/constructs/ApiGatewayV1Api.d.ts +0 -642
- package/constructs/ApiGatewayV1Api.js +0 -767
- package/constructs/App.d.ts +0 -168
- package/constructs/App.js +0 -493
- package/constructs/AppSyncApi.d.ts +0 -550
- package/constructs/AppSyncApi.js +0 -493
- package/constructs/AstroSite.d.ts +0 -39
- package/constructs/AstroSite.js +0 -78
- package/constructs/AstroSite.tsdoc.d.ts +0 -2
- package/constructs/AstroSite.tsdoc.js +0 -2
- package/constructs/Auth.d.ts +0 -100
- package/constructs/Auth.js +0 -177
- package/constructs/BaseSite.d.ts +0 -29
- package/constructs/BaseSite.js +0 -43
- package/constructs/Bucket.d.ts +0 -364
- package/constructs/Bucket.js +0 -327
- package/constructs/Cognito.d.ts +0 -232
- package/constructs/Cognito.js +0 -370
- package/constructs/Config.d.ts +0 -3
- package/constructs/Config.js +0 -3
- package/constructs/Construct.d.ts +0 -23
- package/constructs/Construct.js +0 -46
- package/constructs/Cron.d.ts +0 -164
- package/constructs/Cron.js +0 -114
- package/constructs/Distribution.d.ts +0 -143
- package/constructs/Distribution.js +0 -260
- package/constructs/EdgeFunction.d.ts +0 -49
- package/constructs/EdgeFunction.js +0 -442
- package/constructs/EventBus.d.ts +0 -444
- package/constructs/EventBus.js +0 -440
- package/constructs/Function.d.ts +0 -690
- package/constructs/Function.js +0 -583
- package/constructs/FunctionalStack.d.ts +0 -13
- package/constructs/FunctionalStack.js +0 -62
- package/constructs/Job.d.ts +0 -337
- package/constructs/Job.js +0 -404
- package/constructs/KinesisStream.d.ts +0 -224
- package/constructs/KinesisStream.js +0 -207
- package/constructs/Metadata.d.ts +0 -60
- package/constructs/Metadata.js +0 -1
- package/constructs/NextjsSite.d.ts +0 -104
- package/constructs/NextjsSite.js +0 -308
- package/constructs/Parameter.d.ts +0 -37
- package/constructs/Parameter.js +0 -53
- package/constructs/Queue.d.ts +0 -194
- package/constructs/Queue.js +0 -204
- package/constructs/RDS.d.ts +0 -221
- package/constructs/RDS.js +0 -363
- package/constructs/RemixSite.d.ts +0 -42
- package/constructs/RemixSite.js +0 -158
- package/constructs/RemixSite.tsdoc.d.ts +0 -2
- package/constructs/RemixSite.tsdoc.js +0 -2
- package/constructs/Script.d.ts +0 -160
- package/constructs/Script.js +0 -179
- package/constructs/Secret.d.ts +0 -30
- package/constructs/Secret.js +0 -59
- package/constructs/Service.d.ts +0 -487
- package/constructs/Service.js +0 -655
- package/constructs/SolidStartSite.d.ts +0 -37
- package/constructs/SolidStartSite.js +0 -66
- package/constructs/SolidStartSite.tsdoc.d.ts +0 -2
- package/constructs/SolidStartSite.tsdoc.js +0 -2
- package/constructs/SsrFunction.d.ts +0 -60
- package/constructs/SsrFunction.js +0 -226
- package/constructs/SsrSite.d.ts +0 -407
- package/constructs/SsrSite.js +0 -850
- package/constructs/Stack.d.ts +0 -127
- package/constructs/Stack.js +0 -243
- package/constructs/StaticSite.d.ts +0 -348
- package/constructs/StaticSite.js +0 -468
- package/constructs/SvelteKitSite.d.ts +0 -40
- package/constructs/SvelteKitSite.js +0 -106
- package/constructs/SvelteKitSite.tsdoc.d.ts +0 -2
- package/constructs/SvelteKitSite.tsdoc.js +0 -2
- package/constructs/Table.d.ts +0 -410
- package/constructs/Table.js +0 -425
- package/constructs/Topic.d.ts +0 -257
- package/constructs/Topic.js +0 -273
- package/constructs/WebSocketApi.d.ts +0 -355
- package/constructs/WebSocketApi.js +0 -404
- package/constructs/cdk/HttpAwsIntegration.d.ts +0 -32
- package/constructs/cdk/HttpAwsIntegration.js +0 -24
- package/constructs/cdk/certificate-base.d.ts +0 -18
- package/constructs/cdk/certificate-base.js +0 -26
- package/constructs/cdk/dns-validated-certificate.d.ts +0 -77
- package/constructs/cdk/dns-validated-certificate.js +0 -125
- package/constructs/cdk/website-redirect.d.ts +0 -53
- package/constructs/cdk/website-redirect.js +0 -77
- package/constructs/context.d.ts +0 -3
- package/constructs/context.js +0 -27
- package/constructs/deferred_task.d.ts +0 -6
- package/constructs/deferred_task.js +0 -45
- package/constructs/deprecated/NextjsSite.d.ts +0 -309
- package/constructs/deprecated/NextjsSite.js +0 -1074
- package/constructs/deprecated/cross-region-helper.d.ts +0 -7
- package/constructs/deprecated/cross-region-helper.js +0 -152
- package/constructs/deprecated/index.d.ts +0 -1
- package/constructs/deprecated/index.js +0 -1
- package/constructs/future/Auth.d.ts +0 -80
- package/constructs/future/Auth.js +0 -122
- package/constructs/future/index.d.ts +0 -1
- package/constructs/future/index.js +0 -1
- package/constructs/index.d.ts +0 -32
- package/constructs/index.js +0 -32
- package/constructs/static-file-list.d.ts +0 -1
- package/constructs/static-file-list.js +0 -51
- package/constructs/util/apiGatewayV1AccessLog.d.ts +0 -15
- package/constructs/util/apiGatewayV1AccessLog.js +0 -76
- package/constructs/util/apiGatewayV2AccessLog.d.ts +0 -10
- package/constructs/util/apiGatewayV2AccessLog.js +0 -107
- package/constructs/util/apiGatewayV2Cors.d.ts +0 -67
- package/constructs/util/apiGatewayV2Cors.js +0 -21
- package/constructs/util/apiGatewayV2Domain.d.ts +0 -47
- package/constructs/util/apiGatewayV2Domain.js +0 -208
- package/constructs/util/appSyncApiDomain.d.ts +0 -41
- package/constructs/util/appSyncApiDomain.js +0 -176
- package/constructs/util/builder.d.ts +0 -3
- package/constructs/util/builder.js +0 -9
- package/constructs/util/duration.d.ts +0 -3
- package/constructs/util/duration.js +0 -19
- package/constructs/util/functionBinding.d.ts +0 -31
- package/constructs/util/functionBinding.js +0 -104
- package/constructs/util/functionUrlCors.d.ts +0 -67
- package/constructs/util/functionUrlCors.js +0 -23
- package/constructs/util/permission.d.ts +0 -8
- package/constructs/util/permission.js +0 -228
- package/constructs/util/size.d.ts +0 -3
- package/constructs/util/size.js +0 -12
- package/constructs/util/warning.d.ts +0 -11
- package/constructs/util/warning.js +0 -21
- package/context/context.d.ts +0 -13
- package/context/context.js +0 -69
- package/context/context2.d.ts +0 -16
- package/context/context2.js +0 -108
- package/context/handler.d.ts +0 -25
- package/context/handler.js +0 -21
- package/context/index.d.ts +0 -2
- package/context/index.js +0 -2
- package/credentials.d.ts +0 -9
- package/credentials.js +0 -145
- package/error.d.ts +0 -6
- package/error.js +0 -10
- package/index.d.ts +0 -1
- package/index.js +0 -1
- package/iot.d.ts +0 -6
- package/iot.js +0 -163
- package/logger.d.ts +0 -3
- package/logger.js +0 -32
- package/node/actor/index.d.ts +0 -29
- package/node/actor/index.js +0 -17
- package/node/api/index.d.ts +0 -64
- package/node/api/index.js +0 -179
- package/node/auth/adapter/adapter.d.ts +0 -3
- package/node/auth/adapter/adapter.js +0 -3
- package/node/auth/adapter/facebook.d.ts +0 -2
- package/node/auth/adapter/facebook.js +0 -26
- package/node/auth/adapter/github.d.ts +0 -2
- package/node/auth/adapter/github.js +0 -21
- package/node/auth/adapter/google.d.ts +0 -9
- package/node/auth/adapter/google.js +0 -18
- package/node/auth/adapter/link.d.ts +0 -8
- package/node/auth/adapter/link.js +0 -39
- package/node/auth/adapter/oauth.d.ts +0 -25
- package/node/auth/adapter/oauth.js +0 -52
- package/node/auth/adapter/oidc.d.ts +0 -17
- package/node/auth/adapter/oidc.js +0 -50
- package/node/auth/adapter/twitch.d.ts +0 -2
- package/node/auth/adapter/twitch.js +0 -11
- package/node/auth/auth.d.ts +0 -24
- package/node/auth/auth.js +0 -74
- package/node/auth/index.d.ts +0 -13
- package/node/auth/index.js +0 -12
- package/node/auth/session.d.ts +0 -76
- package/node/auth/session.js +0 -121
- package/node/bucket/index.d.ts +0 -3
- package/node/bucket/index.js +0 -2
- package/node/config/index.d.ts +0 -13
- package/node/config/index.js +0 -22
- package/node/event-bus/index.d.ts +0 -51
- package/node/event-bus/index.js +0 -76
- package/node/function/index.d.ts +0 -3
- package/node/function/index.js +0 -3
- package/node/future/auth/adapter/adapter.d.ts +0 -10
- package/node/future/auth/adapter/adapter.js +0 -1
- package/node/future/auth/adapter/code.d.ts +0 -17
- package/node/future/auth/adapter/code.js +0 -68
- package/node/future/auth/adapter/facebook.d.ts +0 -16
- package/node/future/auth/adapter/facebook.js +0 -27
- package/node/future/auth/adapter/github.d.ts +0 -23
- package/node/future/auth/adapter/github.js +0 -23
- package/node/future/auth/adapter/google.d.ts +0 -28
- package/node/future/auth/adapter/google.js +0 -22
- package/node/future/auth/adapter/link.d.ts +0 -13
- package/node/future/auth/adapter/link.js +0 -47
- package/node/future/auth/adapter/microsoft.d.ts +0 -22
- package/node/future/auth/adapter/microsoft.js +0 -16
- package/node/future/auth/adapter/oauth.d.ts +0 -41
- package/node/future/auth/adapter/oauth.js +0 -67
- package/node/future/auth/adapter/oidc.d.ts +0 -30
- package/node/future/auth/adapter/oidc.js +0 -63
- package/node/future/auth/adapter/spotify.d.ts +0 -23
- package/node/future/auth/adapter/spotify.js +0 -22
- package/node/future/auth/encryption.d.ts +0 -2
- package/node/future/auth/encryption.js +0 -30
- package/node/future/auth/handler.d.ts +0 -46
- package/node/future/auth/handler.js +0 -280
- package/node/future/auth/index.d.ts +0 -17
- package/node/future/auth/index.js +0 -15
- package/node/future/auth/session.d.ts +0 -71
- package/node/future/auth/session.js +0 -146
- package/node/graphql/index.d.ts +0 -15
- package/node/graphql/index.js +0 -32
- package/node/job/index.d.ts +0 -37
- package/node/job/index.js +0 -64
- package/node/kinesis-stream/index.d.ts +0 -3
- package/node/kinesis-stream/index.js +0 -3
- package/node/queue/index.d.ts +0 -3
- package/node/queue/index.js +0 -2
- package/node/rds/index.d.ts +0 -3
- package/node/rds/index.js +0 -2
- package/node/service/index.d.ts +0 -3
- package/node/service/index.js +0 -4
- package/node/site/index.d.ts +0 -18
- package/node/site/index.js +0 -18
- package/node/table/index.d.ts +0 -3
- package/node/table/index.js +0 -4
- package/node/topic/index.d.ts +0 -3
- package/node/topic/index.js +0 -4
- package/node/util/index.d.ts +0 -2
- package/node/util/index.js +0 -196
- package/node/util/loader.d.ts +0 -2
- package/node/util/loader.js +0 -51
- package/node/websocket-api/index.d.ts +0 -23
- package/node/websocket-api/index.js +0 -48
- package/pothos.d.ts +0 -7
- package/pothos.js +0 -160
- package/project.d.ts +0 -75
- package/project.js +0 -188
- package/runtime/handlers/container.d.ts +0 -2
- package/runtime/handlers/container.js +0 -263
- package/runtime/handlers/dotnet.d.ts +0 -2
- package/runtime/handlers/dotnet.js +0 -115
- package/runtime/handlers/go.d.ts +0 -2
- package/runtime/handlers/go.js +0 -126
- package/runtime/handlers/java.d.ts +0 -2
- package/runtime/handlers/java.js +0 -103
- package/runtime/handlers/node.d.ts +0 -2
- package/runtime/handlers/node.js +0 -269
- package/runtime/handlers/python.d.ts +0 -2
- package/runtime/handlers/python.js +0 -141
- package/runtime/handlers/pythonBundling.d.ts +0 -82
- package/runtime/handlers/pythonBundling.js +0 -80
- package/runtime/handlers/rust.d.ts +0 -2
- package/runtime/handlers/rust.js +0 -110
- package/runtime/handlers.d.ts +0 -74
- package/runtime/handlers.js +0 -151
- package/runtime/iot.d.ts +0 -1
- package/runtime/iot.js +0 -17
- package/runtime/runtime.d.ts +0 -32
- package/runtime/runtime.js +0 -1
- package/runtime/server.d.ts +0 -6
- package/runtime/server.js +0 -150
- package/runtime/workers.d.ts +0 -37
- package/runtime/workers.js +0 -85
- package/stacks/app-metadata.d.ts +0 -7
- package/stacks/app-metadata.js +0 -75
- package/stacks/assembly.d.ts +0 -1
- package/stacks/assembly.js +0 -4
- package/stacks/build.d.ts +0 -9
- package/stacks/build.js +0 -110
- package/stacks/deploy.d.ts +0 -9
- package/stacks/deploy.js +0 -240
- package/stacks/diff.d.ts +0 -8
- package/stacks/diff.js +0 -62
- package/stacks/index.d.ts +0 -10
- package/stacks/index.js +0 -10
- package/stacks/metadata.d.ts +0 -11
- package/stacks/metadata.js +0 -83
- package/stacks/monitor.d.ts +0 -32
- package/stacks/monitor.js +0 -151
- package/stacks/remove.d.ts +0 -8
- package/stacks/remove.js +0 -76
- package/stacks/synth.d.ts +0 -12
- package/stacks/synth.js +0 -94
- package/support/base-site-archiver.mjs +0 -99
- package/support/base-site-custom-resource/s3-handler.py +0 -195
- package/support/base-site-custom-resource/s3-upload.py +0 -89
- package/support/bootstrap-metadata-function/index.mjs +0 -58011
- package/support/bridge/Dockerfile +0 -3
- package/support/bridge/bridge.mjs +0 -146
- package/support/certificate-requestor/index.js +0 -549
- package/support/custom-resources/index.mjs +0 -180627
- package/support/dotnet31-bootstrap/Program.cs +0 -17
- package/support/dotnet31-bootstrap/dotnet-bootstrap.csproj +0 -12
- package/support/dotnet31-bootstrap/release/Amazon.Lambda.Core.dll +0 -0
- package/support/dotnet31-bootstrap/release/Amazon.Lambda.RuntimeSupport.dll +0 -0
- package/support/dotnet31-bootstrap/release/System.Runtime.CompilerServices.Unsafe.dll +0 -0
- package/support/dotnet31-bootstrap/release/System.Text.Encodings.Web.dll +0 -0
- package/support/dotnet31-bootstrap/release/System.Text.Json.dll +0 -0
- package/support/dotnet31-bootstrap/release/dotnet-bootstrap +0 -0
- package/support/dotnet31-bootstrap/release/dotnet-bootstrap.deps.json +0 -230
- package/support/dotnet31-bootstrap/release/dotnet-bootstrap.dll +0 -0
- package/support/dotnet31-bootstrap/release/dotnet-bootstrap.pdb +0 -0
- package/support/dotnet31-bootstrap/release/dotnet-bootstrap.runtimeconfig.json +0 -9
- package/support/dotnet6-bootstrap/Program.cs +0 -17
- package/support/dotnet6-bootstrap/dotnet-bootstrap.csproj +0 -12
- package/support/dotnet6-bootstrap/release/Amazon.Lambda.Core.dll +0 -0
- package/support/dotnet6-bootstrap/release/Amazon.Lambda.RuntimeSupport.dll +0 -0
- package/support/dotnet6-bootstrap/release/dotnet-bootstrap +0 -0
- package/support/dotnet6-bootstrap/release/dotnet-bootstrap.deps.json +0 -59
- package/support/dotnet6-bootstrap/release/dotnet-bootstrap.dll +0 -0
- package/support/dotnet6-bootstrap/release/dotnet-bootstrap.pdb +0 -0
- package/support/dotnet6-bootstrap/release/dotnet-bootstrap.runtimeconfig.json +0 -12
- package/support/edge-function/edge-lambda-version.mjs +0 -3
- package/support/edge-function/edge-lambda.mjs +0 -3
- package/support/edge-function/s3-bucket.mjs +0 -3
- package/support/event-bus-retrier/index.mjs +0 -75
- package/support/java-runtime/install.sh +0 -25
- package/support/java-runtime/pom.xml +0 -39
- package/support/java-runtime/release/aws-lambda-java-core-1.2.0.jar +0 -0
- package/support/java-runtime/release/aws-lambda-java-runtime-interface-client-1.1.0.jar +0 -0
- package/support/java-runtime/release/aws-lambda-java-serialization-1.0.0.jar +0 -0
- package/support/job-manager/index.mjs +0 -57679
- package/support/nixpacks/Dockerfile +0 -6
- package/support/nodejs-runtime/index.mjs +0 -169
- package/support/python-runtime/Dockerfile +0 -9
- package/support/python-runtime/Dockerfile.custom +0 -21
- package/support/python-runtime/Dockerfile.dependencies +0 -26
- package/support/python-runtime/runtime.py +0 -127
- package/support/rds-migrator/index.mjs +0 -49
- package/support/remix-site-function/edge-server.js +0 -161
- package/support/remix-site-function/polyfill.js +0 -24
- package/support/remix-site-function/regional-server.js +0 -164
- package/support/script-function/index.mjs +0 -48760
- package/support/service-dev-function/index.js +0 -1
- package/support/signing-function/index.mjs +0 -3769
- package/support/sls-nextjs-site-build-helper/build.cjs +0 -91
- package/support/sls-nextjs-site-build-helper/index-wrapper.js +0 -19
- package/support/sls-nextjs-site-function-code-replacer/lambda-code-updater.py +0 -156
- package/support/sls-nextjs-site-stub/index.html +0 -99
- package/support/ssr-site-function-archiver.mjs +0 -96
- package/support/ssr-site-function-stub/index.js +0 -5
- package/support/ssr-warmer/index.mjs +0 -34235
- package/util/error.d.ts +0 -3
- package/util/error.js +0 -6
- package/util/fs.d.ts +0 -4
- package/util/fs.js +0 -46
- package/util/lazy.d.ts +0 -1
- package/util/lazy.js +0 -11
- package/util/module.d.ts +0 -1
- package/util/module.js +0 -5
- package/util/process.d.ts +0 -2
- package/util/process.js +0 -3
- package/watcher.d.ts +0 -14
- package/watcher.js +0 -35
|
@@ -1,1074 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import url from "url";
|
|
3
|
-
import fs from "fs";
|
|
4
|
-
import spawn from "cross-spawn";
|
|
5
|
-
import { execSync } from "child_process";
|
|
6
|
-
import { Construct } from "constructs";
|
|
7
|
-
import { Token, Duration, RemovalPolicy, CustomResource, } from "aws-cdk-lib/core";
|
|
8
|
-
import * as s3 from "aws-cdk-lib/aws-s3";
|
|
9
|
-
import { Role, Effect, PolicyStatement, CompositePrincipal, ServicePrincipal, ManagedPolicy, } from "aws-cdk-lib/aws-iam";
|
|
10
|
-
import * as sqs from "aws-cdk-lib/aws-sqs";
|
|
11
|
-
import * as logs from "aws-cdk-lib/aws-logs";
|
|
12
|
-
import * as lambda from "aws-cdk-lib/aws-lambda";
|
|
13
|
-
import * as route53 from "aws-cdk-lib/aws-route53";
|
|
14
|
-
import * as s3Assets from "aws-cdk-lib/aws-s3-assets";
|
|
15
|
-
import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
|
|
16
|
-
import * as acm from "aws-cdk-lib/aws-certificatemanager";
|
|
17
|
-
import { AwsCliLayer } from "aws-cdk-lib/lambda-layer-awscli";
|
|
18
|
-
import * as origins from "aws-cdk-lib/aws-cloudfront-origins";
|
|
19
|
-
import * as route53Targets from "aws-cdk-lib/aws-route53-targets";
|
|
20
|
-
import * as route53Patterns from "aws-cdk-lib/aws-route53-patterns";
|
|
21
|
-
import * as lambdaEventSources from "aws-cdk-lib/aws-lambda-event-sources";
|
|
22
|
-
import { Stack } from "../Stack.js";
|
|
23
|
-
import { isCDKConstruct } from "../Construct.js";
|
|
24
|
-
import { getBuildCmdEnvironment, buildErrorResponsesForRedirectToIndex, } from "../BaseSite.js";
|
|
25
|
-
import { attachPermissionsToRole } from "../util/permission.js";
|
|
26
|
-
import { getHandlerHash } from "../util/builder.js";
|
|
27
|
-
import { getParameterPath, } from "../util/functionBinding.js";
|
|
28
|
-
import * as crossRegionHelper from "./cross-region-helper.js";
|
|
29
|
-
import { gray, red } from "colorette";
|
|
30
|
-
import { useProject } from "../../project.js";
|
|
31
|
-
import { VisibleError } from "../../error.js";
|
|
32
|
-
import { createAppContext } from "../context.js";
|
|
33
|
-
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
|
34
|
-
/////////////////////
|
|
35
|
-
// Construct
|
|
36
|
-
/////////////////////
|
|
37
|
-
/**
|
|
38
|
-
* The `NextjsSite` construct is a higher level CDK construct that makes it easy to create a Next.js app.
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
*
|
|
42
|
-
* Deploys a Next.js app in the `path/to/site` directory.
|
|
43
|
-
*
|
|
44
|
-
* ```js
|
|
45
|
-
* new NextjsSite(stack, "NextSite", {
|
|
46
|
-
* path: "path/to/site",
|
|
47
|
-
* });
|
|
48
|
-
* ```
|
|
49
|
-
*/
|
|
50
|
-
export class NextjsSite extends Construct {
|
|
51
|
-
id;
|
|
52
|
-
/**
|
|
53
|
-
* The default CloudFront cache policy properties for static pages.
|
|
54
|
-
*/
|
|
55
|
-
static staticCachePolicyProps = {
|
|
56
|
-
queryStringBehavior: cloudfront.CacheQueryStringBehavior.none(),
|
|
57
|
-
headerBehavior: cloudfront.CacheHeaderBehavior.none(),
|
|
58
|
-
cookieBehavior: cloudfront.CacheCookieBehavior.none(),
|
|
59
|
-
defaultTtl: Duration.days(30),
|
|
60
|
-
maxTtl: Duration.days(30),
|
|
61
|
-
minTtl: Duration.days(30),
|
|
62
|
-
enableAcceptEncodingBrotli: true,
|
|
63
|
-
enableAcceptEncodingGzip: true,
|
|
64
|
-
comment: "SST NextjsSite Static Default Cache Policy",
|
|
65
|
-
};
|
|
66
|
-
/**
|
|
67
|
-
* The default CloudFront cache policy properties for images.
|
|
68
|
-
*/
|
|
69
|
-
static imageCachePolicyProps = {
|
|
70
|
-
queryStringBehavior: cloudfront.CacheQueryStringBehavior.all(),
|
|
71
|
-
headerBehavior: cloudfront.CacheHeaderBehavior.allowList("Accept"),
|
|
72
|
-
cookieBehavior: cloudfront.CacheCookieBehavior.none(),
|
|
73
|
-
defaultTtl: Duration.days(1),
|
|
74
|
-
maxTtl: Duration.days(365),
|
|
75
|
-
minTtl: Duration.days(0),
|
|
76
|
-
enableAcceptEncodingBrotli: true,
|
|
77
|
-
enableAcceptEncodingGzip: true,
|
|
78
|
-
comment: "SST NextjsSite Image Default Cache Policy",
|
|
79
|
-
};
|
|
80
|
-
/**
|
|
81
|
-
* The default CloudFront cache policy properties for Lambda@Edge.
|
|
82
|
-
*/
|
|
83
|
-
static lambdaCachePolicyProps = {
|
|
84
|
-
queryStringBehavior: cloudfront.CacheQueryStringBehavior.all(),
|
|
85
|
-
headerBehavior: cloudfront.CacheHeaderBehavior.none(),
|
|
86
|
-
cookieBehavior: cloudfront.CacheCookieBehavior.all(),
|
|
87
|
-
defaultTtl: Duration.seconds(0),
|
|
88
|
-
maxTtl: Duration.days(365),
|
|
89
|
-
minTtl: Duration.seconds(0),
|
|
90
|
-
enableAcceptEncodingBrotli: true,
|
|
91
|
-
enableAcceptEncodingGzip: true,
|
|
92
|
-
comment: "SST NextjsSite Lambda Default Cache Policy",
|
|
93
|
-
};
|
|
94
|
-
/**
|
|
95
|
-
* The default CloudFront image origin request policy properties for Lambda@Edge.
|
|
96
|
-
*/
|
|
97
|
-
static imageOriginRequestPolicyProps = {
|
|
98
|
-
queryStringBehavior: cloudfront.OriginRequestQueryStringBehavior.all(),
|
|
99
|
-
comment: "SST NextjsSite Lambda Default Origin Request Policy",
|
|
100
|
-
};
|
|
101
|
-
cdk;
|
|
102
|
-
/**
|
|
103
|
-
* The root SST directory used for builds.
|
|
104
|
-
*/
|
|
105
|
-
sstBuildDir;
|
|
106
|
-
props;
|
|
107
|
-
isPlaceholder;
|
|
108
|
-
buildOutDir;
|
|
109
|
-
assets;
|
|
110
|
-
awsCliLayer;
|
|
111
|
-
routesManifest;
|
|
112
|
-
edgeLambdaRole;
|
|
113
|
-
mainFunctionVersion;
|
|
114
|
-
apiFunctionVersion;
|
|
115
|
-
imageFunctionVersion;
|
|
116
|
-
regenerationFunction;
|
|
117
|
-
constructor(scope, id, props) {
|
|
118
|
-
super(scope, props.cdk?.id || id);
|
|
119
|
-
this.id = id;
|
|
120
|
-
const app = scope.node.root;
|
|
121
|
-
const stack = Stack.of(this);
|
|
122
|
-
// Local development or skip build => stub asset
|
|
123
|
-
this.isPlaceholder =
|
|
124
|
-
!stack.isActive && app.mode === "dev" && !props.disablePlaceholder;
|
|
125
|
-
this.sstBuildDir = useProject().paths.artifacts;
|
|
126
|
-
const fileSizeLimit = app.isRunningSSTTest()
|
|
127
|
-
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
128
|
-
// @ts-ignore: "sstTestFileSizeLimitOverride" not exposed in props
|
|
129
|
-
props.sstTestFileSizeLimitOverride || 200
|
|
130
|
-
: 200;
|
|
131
|
-
this.props = props;
|
|
132
|
-
this.cdk = {};
|
|
133
|
-
this.awsCliLayer = new AwsCliLayer(this, "AwsCliLayer");
|
|
134
|
-
useSites().add(stack.stackName, id, this.props);
|
|
135
|
-
// Build app
|
|
136
|
-
if (this.isPlaceholder) {
|
|
137
|
-
this.buildOutDir = null;
|
|
138
|
-
this.assets = this.zipAppStubAssets();
|
|
139
|
-
this.routesManifest = null;
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
this.buildOutDir = this.buildApp();
|
|
143
|
-
this.assets = this.zipAppAssets(fileSizeLimit);
|
|
144
|
-
this.routesManifest = this.readRoutesManifest();
|
|
145
|
-
}
|
|
146
|
-
// Create Bucket
|
|
147
|
-
this.cdk.bucket = this.createS3Bucket();
|
|
148
|
-
// Handle Incremental Static Regeneration
|
|
149
|
-
this.cdk.regenerationQueue = this.createRegenerationQueue();
|
|
150
|
-
this.regenerationFunction = this.createRegenerationFunction();
|
|
151
|
-
// Create Lambda@Edge functions (always created in us-east-1)
|
|
152
|
-
this.edgeLambdaRole = this.createEdgeFunctionRole();
|
|
153
|
-
this.mainFunctionVersion = this.createEdgeFunction("Main", "default-lambda");
|
|
154
|
-
this.apiFunctionVersion = this.createEdgeFunction("Api", "api-lambda");
|
|
155
|
-
this.imageFunctionVersion = this.createEdgeFunction("Image", "image-lambda");
|
|
156
|
-
// Create Custom Domain
|
|
157
|
-
this.validateCustomDomainSettings();
|
|
158
|
-
this.cdk.hostedZone = this.lookupHostedZone();
|
|
159
|
-
this.cdk.certificate = this.createCertificate();
|
|
160
|
-
// Create S3 Deployment
|
|
161
|
-
const s3deployCR = this.createS3Deployment();
|
|
162
|
-
// Create CloudFront
|
|
163
|
-
this.cdk.distribution = this.createCloudFrontDistribution();
|
|
164
|
-
this.cdk.distribution.node.addDependency(s3deployCR);
|
|
165
|
-
// Invalidate CloudFront
|
|
166
|
-
const invalidationCR = this.createCloudFrontInvalidation();
|
|
167
|
-
invalidationCR.node.addDependency(this.cdk.distribution);
|
|
168
|
-
// Connect Custom Domain to CloudFront Distribution
|
|
169
|
-
this.createRoute53Records();
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* The CloudFront URL of the website.
|
|
173
|
-
*/
|
|
174
|
-
get url() {
|
|
175
|
-
return `https://${this.cdk.distribution.distributionDomainName}`;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* If the custom domain is enabled, this is the URL of the website with the custom domain.
|
|
179
|
-
*/
|
|
180
|
-
get customDomainUrl() {
|
|
181
|
-
const { customDomain } = this.props;
|
|
182
|
-
if (!customDomain) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
if (typeof customDomain === "string") {
|
|
186
|
-
return `https://${customDomain}`;
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
return `https://${customDomain.domainName}`;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* The ARN of the internally created S3 Bucket.
|
|
194
|
-
*/
|
|
195
|
-
get bucketArn() {
|
|
196
|
-
return this.cdk.bucket.bucketArn;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* The name of the internally created S3 Bucket.
|
|
200
|
-
*/
|
|
201
|
-
get bucketName() {
|
|
202
|
-
return this.cdk.bucket.bucketName;
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* The ID of the internally created CloudFront Distribution.
|
|
206
|
-
*/
|
|
207
|
-
get distributionId() {
|
|
208
|
-
return this.cdk.distribution.distributionId;
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* The domain name of the internally created CloudFront Distribution.
|
|
212
|
-
*/
|
|
213
|
-
get distributionDomain() {
|
|
214
|
-
return this.cdk.distribution.distributionDomainName;
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Attaches the given list of permissions to allow the Next.js API routes and Server Side rendering `getServerSideProps` to access other AWS resources.
|
|
218
|
-
* @example
|
|
219
|
-
* ### Attaching permissions
|
|
220
|
-
*
|
|
221
|
-
* ```js {5}
|
|
222
|
-
* const site = new NextjsSite(stack, "Site", {
|
|
223
|
-
* path: "path/to/site",
|
|
224
|
-
* });
|
|
225
|
-
*
|
|
226
|
-
* site.attachPermissions(["sns"]);
|
|
227
|
-
* ```
|
|
228
|
-
*/
|
|
229
|
-
attachPermissions(permissions) {
|
|
230
|
-
attachPermissionsToRole(this.edgeLambdaRole, permissions);
|
|
231
|
-
}
|
|
232
|
-
getConstructMetadata() {
|
|
233
|
-
return {
|
|
234
|
-
type: "SlsNextjsSite",
|
|
235
|
-
data: {
|
|
236
|
-
path: this.props.path,
|
|
237
|
-
environment: this.props.environment || {},
|
|
238
|
-
distributionId: this.cdk.distribution.distributionId,
|
|
239
|
-
customDomainUrl: this.customDomainUrl,
|
|
240
|
-
},
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
/** @internal */
|
|
244
|
-
getFunctionBinding() {
|
|
245
|
-
const app = this.node.root;
|
|
246
|
-
return {
|
|
247
|
-
clientPackage: "site",
|
|
248
|
-
variables: {
|
|
249
|
-
url: {
|
|
250
|
-
// Do not set real value b/c we don't want to make the Lambda function
|
|
251
|
-
// depend on the Site. B/c often the site depends on the Api, causing
|
|
252
|
-
// a CloudFormation circular dependency if the Api and the Site belong
|
|
253
|
-
// to different stacks.
|
|
254
|
-
type: "site_url",
|
|
255
|
-
value: this.customDomainUrl || this.url,
|
|
256
|
-
},
|
|
257
|
-
},
|
|
258
|
-
permissions: {
|
|
259
|
-
"ssm:GetParameters": [
|
|
260
|
-
`arn:${Stack.of(this).partition}:ssm:${app.region}:${app.account}:parameter${getParameterPath(this, "url")}`,
|
|
261
|
-
],
|
|
262
|
-
},
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
zipAppAssets(fileSizeLimit) {
|
|
266
|
-
// validate buildOutput exists
|
|
267
|
-
const siteOutputPath = path.resolve(path.join(this.buildOutDir, "assets"));
|
|
268
|
-
if (!fs.existsSync(siteOutputPath)) {
|
|
269
|
-
throw new Error(`No build output found at "${siteOutputPath}" for the "${this.node.id}" NextjsSite.`);
|
|
270
|
-
}
|
|
271
|
-
// create zip files
|
|
272
|
-
const script = path.join(__dirname, "../../support/base-site-archiver.mjs");
|
|
273
|
-
const zipPath = path.resolve(path.join(this.sstBuildDir, `NextjsSite-${this.node.id}-${this.node.addr}`));
|
|
274
|
-
// clear zip path to ensure no partX.zip remain from previous build
|
|
275
|
-
fs.rmSync(zipPath, {
|
|
276
|
-
force: true,
|
|
277
|
-
recursive: true,
|
|
278
|
-
});
|
|
279
|
-
const result = spawn.sync("node", [
|
|
280
|
-
script,
|
|
281
|
-
Buffer.from(JSON.stringify([{ src: siteOutputPath, tar: "" }])).toString("base64"),
|
|
282
|
-
zipPath,
|
|
283
|
-
`${fileSizeLimit}`,
|
|
284
|
-
], {
|
|
285
|
-
stdio: "inherit",
|
|
286
|
-
});
|
|
287
|
-
if (result.status !== 0) {
|
|
288
|
-
throw new VisibleError(`There was a problem generating the "${this.node.id}" NextjsSite package.`);
|
|
289
|
-
}
|
|
290
|
-
// create assets
|
|
291
|
-
const assets = [];
|
|
292
|
-
for (let partId = 0;; partId++) {
|
|
293
|
-
const zipFilePath = path.join(zipPath, `part${partId}.zip`);
|
|
294
|
-
if (!fs.existsSync(zipFilePath)) {
|
|
295
|
-
break;
|
|
296
|
-
}
|
|
297
|
-
assets.push(new s3Assets.Asset(this, `Asset${partId}`, {
|
|
298
|
-
path: zipFilePath,
|
|
299
|
-
}));
|
|
300
|
-
}
|
|
301
|
-
return assets;
|
|
302
|
-
}
|
|
303
|
-
zipAppStubAssets() {
|
|
304
|
-
return [
|
|
305
|
-
new s3Assets.Asset(this, "Asset", {
|
|
306
|
-
path: path.resolve(__dirname, "../../support/sls-nextjs-site-stub"),
|
|
307
|
-
}),
|
|
308
|
-
];
|
|
309
|
-
}
|
|
310
|
-
createEdgeFunction(name, handlerPath) {
|
|
311
|
-
// Use real code if:
|
|
312
|
-
// - Next.js app was build; AND
|
|
313
|
-
// - the Lambda code directory is not empty
|
|
314
|
-
const hasRealCode = typeof this.buildOutDir === "string" &&
|
|
315
|
-
fs.existsSync(path.join(this.buildOutDir, handlerPath, "index.js"));
|
|
316
|
-
// Create function asset
|
|
317
|
-
const assetPath = hasRealCode && this.buildOutDir
|
|
318
|
-
? path.join(this.buildOutDir, handlerPath)
|
|
319
|
-
: path.join(__dirname, "../../support/ssr-site-function-stub");
|
|
320
|
-
const asset = new s3Assets.Asset(this, `${name}FunctionAsset`, {
|
|
321
|
-
path: assetPath,
|
|
322
|
-
});
|
|
323
|
-
// Create function based on region
|
|
324
|
-
const app = this.node.root;
|
|
325
|
-
return app.region === "us-east-1"
|
|
326
|
-
? this.createEdgeFunctionInUE1(name, assetPath, asset, hasRealCode)
|
|
327
|
-
: this.createEdgeFunctionInNonUE1(name, assetPath, asset, hasRealCode);
|
|
328
|
-
}
|
|
329
|
-
createEdgeFunctionInUE1(name, assetPath, asset, hasRealCode) {
|
|
330
|
-
const { defaults } = this.props;
|
|
331
|
-
// Create function
|
|
332
|
-
const fn = new lambda.Function(this, `${name}Function`, {
|
|
333
|
-
description: `${name} handler for Next.js`,
|
|
334
|
-
handler: "index-wrapper.handler",
|
|
335
|
-
currentVersionOptions: {
|
|
336
|
-
removalPolicy: RemovalPolicy.DESTROY,
|
|
337
|
-
},
|
|
338
|
-
logRetention: logs.RetentionDays.THREE_DAYS,
|
|
339
|
-
code: lambda.Code.fromAsset(assetPath),
|
|
340
|
-
runtime: this.normalizeRuntime(defaults?.function?.runtime),
|
|
341
|
-
memorySize: defaults?.function?.memorySize || 512,
|
|
342
|
-
timeout: Duration.seconds(defaults?.function?.timeout || 10),
|
|
343
|
-
role: this.edgeLambdaRole,
|
|
344
|
-
});
|
|
345
|
-
// Create alias
|
|
346
|
-
// note: Alias used to be created using on the Version using
|
|
347
|
-
// "fn.currentVersion.addAlias()". It was deprecated.
|
|
348
|
-
// To preserve the logical id, we are going to manually create
|
|
349
|
-
// the Alias on the version, and use "Aliaslive" as id to preserve
|
|
350
|
-
// the logical id.
|
|
351
|
-
const version = fn.currentVersion;
|
|
352
|
-
new lambda.Alias(version, "Aliaslive", {
|
|
353
|
-
aliasName: "live",
|
|
354
|
-
version,
|
|
355
|
-
});
|
|
356
|
-
// Deploy after the code is updated
|
|
357
|
-
if (hasRealCode) {
|
|
358
|
-
const updaterCR = this.createLambdaCodeReplacer(name, asset);
|
|
359
|
-
fn.node.addDependency(updaterCR);
|
|
360
|
-
}
|
|
361
|
-
return fn.currentVersion;
|
|
362
|
-
}
|
|
363
|
-
createEdgeFunctionInNonUE1(name, _assetPath, asset, hasRealCode) {
|
|
364
|
-
const { defaults } = this.props;
|
|
365
|
-
// If app region is NOT us-east-1, create a Function in us-east-1
|
|
366
|
-
// using a Custom Resource
|
|
367
|
-
// Create a S3 bucket in us-east-1 to store Lambda code. Create
|
|
368
|
-
// 1 bucket for all Edge functions.
|
|
369
|
-
const bucketCR = crossRegionHelper.getOrCreateBucket(this);
|
|
370
|
-
const bucketName = bucketCR.getAttString("BucketName");
|
|
371
|
-
// Create a Lambda function in us-east-1
|
|
372
|
-
const functionCR = crossRegionHelper.createFunction(this, name, this.edgeLambdaRole, bucketName, {
|
|
373
|
-
Description: `handler for Next.js`,
|
|
374
|
-
Handler: "index-wrapper.handler",
|
|
375
|
-
Code: {
|
|
376
|
-
S3Bucket: asset.s3BucketName,
|
|
377
|
-
S3Key: asset.s3ObjectKey,
|
|
378
|
-
},
|
|
379
|
-
Runtime: this.normalizeRuntime(defaults?.function?.runtime).name,
|
|
380
|
-
MemorySize: defaults?.function?.memorySize || 512,
|
|
381
|
-
Timeout: Duration.seconds(defaults?.function?.timeout || 10).toSeconds(),
|
|
382
|
-
Role: this.edgeLambdaRole.roleArn,
|
|
383
|
-
});
|
|
384
|
-
const functionArn = functionCR.getAttString("FunctionArn");
|
|
385
|
-
// Create a Lambda function version in us-east-1
|
|
386
|
-
const versionCR = crossRegionHelper.createVersion(this, name, functionArn);
|
|
387
|
-
const versionId = versionCR.getAttString("Version");
|
|
388
|
-
crossRegionHelper.updateVersionLogicalId(functionCR, versionCR);
|
|
389
|
-
// Deploy after the code is updated
|
|
390
|
-
if (hasRealCode) {
|
|
391
|
-
const updaterCR = this.createLambdaCodeReplacer(name, asset);
|
|
392
|
-
functionCR.node.addDependency(updaterCR);
|
|
393
|
-
}
|
|
394
|
-
return lambda.Version.fromVersionArn(this, `${name}FunctionVersion`, `${functionArn}:${versionId}`);
|
|
395
|
-
}
|
|
396
|
-
createEdgeFunctionRole() {
|
|
397
|
-
const { defaults } = this.props;
|
|
398
|
-
// Create function role
|
|
399
|
-
const role = new Role(this, `EdgeLambdaRole`, {
|
|
400
|
-
assumedBy: new CompositePrincipal(new ServicePrincipal("lambda.amazonaws.com"), new ServicePrincipal("edgelambda.amazonaws.com")),
|
|
401
|
-
managedPolicies: [
|
|
402
|
-
ManagedPolicy.fromManagedPolicyArn(this, "EdgeLambdaPolicy", `arn:${Stack.of(this).partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole`),
|
|
403
|
-
],
|
|
404
|
-
});
|
|
405
|
-
// Attach permission
|
|
406
|
-
this.cdk.bucket.grantReadWrite(role);
|
|
407
|
-
this.cdk.regenerationQueue.grantSendMessages(role);
|
|
408
|
-
this.regenerationFunction.grantInvoke(role);
|
|
409
|
-
if (defaults?.function?.permissions) {
|
|
410
|
-
attachPermissionsToRole(role, defaults.function.permissions);
|
|
411
|
-
}
|
|
412
|
-
return role;
|
|
413
|
-
}
|
|
414
|
-
createRegenerationQueue() {
|
|
415
|
-
const { cdk } = this.props;
|
|
416
|
-
return new sqs.Queue(this, "RegenerationQueue", {
|
|
417
|
-
...cdk?.regenerationQueue,
|
|
418
|
-
// We call the queue the same name as the bucket so that we can easily
|
|
419
|
-
// reference it from within the lambda@edge, given we can't use env vars
|
|
420
|
-
// in a lambda@edge
|
|
421
|
-
queueName: `${this.cdk.bucket.bucketName}.fifo`,
|
|
422
|
-
fifo: true,
|
|
423
|
-
removalPolicy: RemovalPolicy.DESTROY,
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
createRegenerationFunction() {
|
|
427
|
-
// Use real code if:
|
|
428
|
-
// - Next.js app was build; AND
|
|
429
|
-
// - the Lambda code directory is not empty
|
|
430
|
-
let code;
|
|
431
|
-
let updaterCR;
|
|
432
|
-
if (this.buildOutDir &&
|
|
433
|
-
fs.existsSync(path.join(this.buildOutDir, "regeneration-lambda", "index.js"))) {
|
|
434
|
-
const asset = new s3Assets.Asset(this, `RegenerationFunctionAsset`, {
|
|
435
|
-
path: path.join(this.buildOutDir, "regeneration-lambda"),
|
|
436
|
-
});
|
|
437
|
-
code = lambda.Code.fromAsset(path.join(this.buildOutDir, "regeneration-lambda"));
|
|
438
|
-
updaterCR = this.createLambdaCodeReplacer("Regeneration", asset);
|
|
439
|
-
}
|
|
440
|
-
else {
|
|
441
|
-
code = lambda.Code.fromInline(" ");
|
|
442
|
-
}
|
|
443
|
-
// Create function
|
|
444
|
-
const { defaults } = this.props;
|
|
445
|
-
const fn = new lambda.Function(this, "RegenerationFunction", {
|
|
446
|
-
handler: "index-wrapper.handler",
|
|
447
|
-
runtime: this.normalizeRuntime(defaults?.function?.runtime),
|
|
448
|
-
memorySize: defaults?.function?.memorySize || 1024,
|
|
449
|
-
timeout: Duration.seconds(defaults?.function?.timeout || 30),
|
|
450
|
-
code,
|
|
451
|
-
});
|
|
452
|
-
fn.addEventSource(new lambdaEventSources.SqsEventSource(this.cdk.regenerationQueue));
|
|
453
|
-
// Grant permissions
|
|
454
|
-
this.cdk.bucket.grantReadWrite(fn);
|
|
455
|
-
// Deploy after the code is updated
|
|
456
|
-
if (updaterCR) {
|
|
457
|
-
fn.node.addDependency(updaterCR);
|
|
458
|
-
}
|
|
459
|
-
return fn;
|
|
460
|
-
}
|
|
461
|
-
createLambdaCodeReplacer(name, asset) {
|
|
462
|
-
// Note: Source code for the Lambda functions have "{{ ENV_KEY }}" in them.
|
|
463
|
-
// They need to be replaced with real values before the Lambda
|
|
464
|
-
// functions get deployed.
|
|
465
|
-
const providerId = "LambdaCodeReplacerProvider";
|
|
466
|
-
const resId = `${name}LambdaCodeReplacer`;
|
|
467
|
-
const stack = Stack.of(this);
|
|
468
|
-
let provider = stack.node.tryFindChild(providerId);
|
|
469
|
-
// Create provider if not already created
|
|
470
|
-
if (!provider) {
|
|
471
|
-
provider = new lambda.Function(stack, providerId, {
|
|
472
|
-
code: lambda.Code.fromAsset(path.join(__dirname, "../../support/sls-nextjs-site-function-code-replacer")),
|
|
473
|
-
layers: [this.awsCliLayer],
|
|
474
|
-
runtime: lambda.Runtime.PYTHON_3_7,
|
|
475
|
-
handler: "lambda-code-updater.handler",
|
|
476
|
-
timeout: Duration.minutes(15),
|
|
477
|
-
memorySize: 1024,
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
// Allow provider to perform search/replace on the asset
|
|
481
|
-
provider.role?.addToPrincipalPolicy(new PolicyStatement({
|
|
482
|
-
effect: Effect.ALLOW,
|
|
483
|
-
actions: ["s3:*"],
|
|
484
|
-
resources: [
|
|
485
|
-
`arn:${Stack.of(this).partition}:s3:::${asset.s3BucketName}/${asset.s3ObjectKey}`,
|
|
486
|
-
],
|
|
487
|
-
}));
|
|
488
|
-
// Create custom resource
|
|
489
|
-
const resource = new CustomResource(this, resId, {
|
|
490
|
-
serviceToken: provider.functionArn,
|
|
491
|
-
resourceType: "Custom::SSTLambdaCodeUpdater",
|
|
492
|
-
properties: {
|
|
493
|
-
Source: {
|
|
494
|
-
BucketName: asset.s3BucketName,
|
|
495
|
-
ObjectKey: asset.s3ObjectKey,
|
|
496
|
-
},
|
|
497
|
-
ReplaceValues: this.getLambdaContentReplaceValues(),
|
|
498
|
-
},
|
|
499
|
-
});
|
|
500
|
-
return resource;
|
|
501
|
-
}
|
|
502
|
-
createS3Bucket() {
|
|
503
|
-
const { cdk } = this.props;
|
|
504
|
-
// cdk.bucket is an imported construct
|
|
505
|
-
if (cdk?.bucket && isCDKConstruct(cdk?.bucket)) {
|
|
506
|
-
return cdk.bucket;
|
|
507
|
-
}
|
|
508
|
-
// cdk.bucket is a prop
|
|
509
|
-
else {
|
|
510
|
-
const bucketProps = cdk?.bucket;
|
|
511
|
-
return new s3.Bucket(this, "S3Bucket", {
|
|
512
|
-
publicReadAccess: true,
|
|
513
|
-
autoDeleteObjects: true,
|
|
514
|
-
removalPolicy: RemovalPolicy.DESTROY,
|
|
515
|
-
...bucketProps,
|
|
516
|
-
});
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
createS3Deployment() {
|
|
520
|
-
// Create a Lambda function that will be doing the uploading
|
|
521
|
-
const uploader = new lambda.Function(this, "S3Uploader", {
|
|
522
|
-
code: lambda.Code.fromAsset(path.join(__dirname, "../../support/base-site-custom-resource")),
|
|
523
|
-
layers: [this.awsCliLayer],
|
|
524
|
-
runtime: lambda.Runtime.PYTHON_3_7,
|
|
525
|
-
handler: "s3-upload.handler",
|
|
526
|
-
timeout: Duration.minutes(15),
|
|
527
|
-
memorySize: 1024,
|
|
528
|
-
});
|
|
529
|
-
this.cdk.bucket.grantReadWrite(uploader);
|
|
530
|
-
this.assets.forEach((asset) => asset.grantRead(uploader));
|
|
531
|
-
// Create the custom resource function
|
|
532
|
-
const handler = new lambda.Function(this, "S3Handler", {
|
|
533
|
-
code: lambda.Code.fromAsset(path.join(__dirname, "../../support/base-site-custom-resource")),
|
|
534
|
-
layers: [this.awsCliLayer],
|
|
535
|
-
runtime: lambda.Runtime.PYTHON_3_7,
|
|
536
|
-
handler: "s3-handler.handler",
|
|
537
|
-
timeout: Duration.minutes(15),
|
|
538
|
-
memorySize: 1024,
|
|
539
|
-
environment: {
|
|
540
|
-
UPLOADER_FUNCTION_NAME: uploader.functionName,
|
|
541
|
-
},
|
|
542
|
-
});
|
|
543
|
-
this.cdk.bucket.grantReadWrite(handler);
|
|
544
|
-
uploader.grantInvoke(handler);
|
|
545
|
-
// Create custom resource
|
|
546
|
-
const fileOptions = [
|
|
547
|
-
{
|
|
548
|
-
exclude: "*",
|
|
549
|
-
include: "public/*",
|
|
550
|
-
cacheControl: "public,max-age=31536000,must-revalidate",
|
|
551
|
-
},
|
|
552
|
-
{
|
|
553
|
-
exclude: "*",
|
|
554
|
-
include: "static/*",
|
|
555
|
-
cacheControl: "public,max-age=31536000,must-revalidate",
|
|
556
|
-
},
|
|
557
|
-
{
|
|
558
|
-
exclude: "*",
|
|
559
|
-
include: "static-pages/*",
|
|
560
|
-
cacheControl: "public,max-age=0,s-maxage=2678400,must-revalidate",
|
|
561
|
-
},
|
|
562
|
-
{
|
|
563
|
-
exclude: "*",
|
|
564
|
-
include: "_next/data/*",
|
|
565
|
-
cacheControl: "public,max-age=0,s-maxage=2678400,must-revalidate",
|
|
566
|
-
},
|
|
567
|
-
{
|
|
568
|
-
exclude: "*",
|
|
569
|
-
include: "_next/static/*",
|
|
570
|
-
cacheControl: "public,max-age=31536000,immutable",
|
|
571
|
-
},
|
|
572
|
-
];
|
|
573
|
-
return new CustomResource(this, "S3Deployment", {
|
|
574
|
-
serviceToken: handler.functionArn,
|
|
575
|
-
resourceType: "Custom::SSTBucketDeployment",
|
|
576
|
-
properties: {
|
|
577
|
-
Sources: this.assets.map((asset) => ({
|
|
578
|
-
BucketName: asset.s3BucketName,
|
|
579
|
-
ObjectKey: asset.s3ObjectKey,
|
|
580
|
-
})),
|
|
581
|
-
DestinationBucketName: this.cdk.bucket.bucketName,
|
|
582
|
-
FileOptions: (fileOptions || []).map(({ exclude, include, cacheControl }) => {
|
|
583
|
-
return [
|
|
584
|
-
"--exclude",
|
|
585
|
-
exclude,
|
|
586
|
-
"--include",
|
|
587
|
-
include,
|
|
588
|
-
"--cache-control",
|
|
589
|
-
cacheControl,
|
|
590
|
-
];
|
|
591
|
-
}),
|
|
592
|
-
ReplaceValues: this.getS3ContentReplaceValues(),
|
|
593
|
-
},
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
/////////////////////
|
|
597
|
-
// Build App
|
|
598
|
-
/////////////////////
|
|
599
|
-
buildApp() {
|
|
600
|
-
const app = this.node.root;
|
|
601
|
-
const buildOutput = app.isRunningSSTTest()
|
|
602
|
-
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
603
|
-
// @ts-ignore: "sstTestBuildOutputPath" not exposed in props
|
|
604
|
-
props.sstTestBuildOutputPath || this.runBuild()
|
|
605
|
-
: this.runBuild();
|
|
606
|
-
this.runAfterBuild();
|
|
607
|
-
return buildOutput;
|
|
608
|
-
}
|
|
609
|
-
runBuild() {
|
|
610
|
-
const { path: sitePath } = this.props;
|
|
611
|
-
// validate site path exists
|
|
612
|
-
if (!fs.existsSync(sitePath)) {
|
|
613
|
-
throw new Error(`No path found at "${path.resolve(sitePath)}" for the "${this.node.id}" NextjsSite.`);
|
|
614
|
-
}
|
|
615
|
-
// Build command
|
|
616
|
-
// Note: probably could pass JSON string also, but this felt safer.
|
|
617
|
-
const app = this.node.root;
|
|
618
|
-
const pathHash = getHandlerHash(sitePath);
|
|
619
|
-
const buildOutput = path.join(this.sstBuildDir, pathHash);
|
|
620
|
-
const configBuffer = Buffer.from(JSON.stringify({
|
|
621
|
-
cwd: path.resolve(sitePath),
|
|
622
|
-
args: ["build"],
|
|
623
|
-
cmd: this.props.nextBinPath ?? "./node_modules/.bin/next",
|
|
624
|
-
}));
|
|
625
|
-
// Run build
|
|
626
|
-
console.log(gray(`Building Next.js site ${sitePath}`));
|
|
627
|
-
const result = spawn.sync("node", [
|
|
628
|
-
path.join(__dirname, "../../support/sls-nextjs-site-build-helper/build.cjs"),
|
|
629
|
-
"--path",
|
|
630
|
-
path.resolve(sitePath),
|
|
631
|
-
"--output",
|
|
632
|
-
path.resolve(buildOutput),
|
|
633
|
-
"--config",
|
|
634
|
-
configBuffer.toString("base64"),
|
|
635
|
-
], {
|
|
636
|
-
cwd: sitePath,
|
|
637
|
-
stdio: "inherit",
|
|
638
|
-
env: {
|
|
639
|
-
...process.env,
|
|
640
|
-
...getBuildCmdEnvironment(this.props.environment),
|
|
641
|
-
},
|
|
642
|
-
});
|
|
643
|
-
if (result.status !== 0) {
|
|
644
|
-
throw new VisibleError(`There was a problem building the "${this.node.id}" NextjsSite.`);
|
|
645
|
-
}
|
|
646
|
-
return buildOutput;
|
|
647
|
-
}
|
|
648
|
-
runAfterBuild() {
|
|
649
|
-
const { path, commandHooks } = this.props;
|
|
650
|
-
// Build command
|
|
651
|
-
const cmds = commandHooks?.afterBuild ?? [];
|
|
652
|
-
if (cmds.length === 0) {
|
|
653
|
-
return;
|
|
654
|
-
}
|
|
655
|
-
try {
|
|
656
|
-
execSync(cmds.join(" && "), {
|
|
657
|
-
cwd: path,
|
|
658
|
-
stdio: "inherit",
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
catch (e) {
|
|
662
|
-
console.log(red(`There was a problem running "afterBuild" command.`));
|
|
663
|
-
throw e;
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
/////////////////////
|
|
667
|
-
// CloudFront Distribution
|
|
668
|
-
/////////////////////
|
|
669
|
-
createCloudFrontDistribution() {
|
|
670
|
-
const { cdk, customDomain } = this.props;
|
|
671
|
-
const cfDistributionProps = cdk?.distribution || {};
|
|
672
|
-
// Validate input
|
|
673
|
-
if (cfDistributionProps.certificate) {
|
|
674
|
-
throw new Error(`Do not configure the "cfDistribution.certificate". Use the "customDomain" to configure the NextjsSite domain certificate.`);
|
|
675
|
-
}
|
|
676
|
-
if (cfDistributionProps.domainNames) {
|
|
677
|
-
throw new Error(`Do not configure the "cfDistribution.domainNames". Use the "customDomain" to configure the NextjsSite domain.`);
|
|
678
|
-
}
|
|
679
|
-
// Build domainNames
|
|
680
|
-
const domainNames = [];
|
|
681
|
-
if (!customDomain) {
|
|
682
|
-
// no domain
|
|
683
|
-
}
|
|
684
|
-
else if (typeof customDomain === "string") {
|
|
685
|
-
domainNames.push(customDomain);
|
|
686
|
-
}
|
|
687
|
-
else {
|
|
688
|
-
domainNames.push(customDomain.domainName);
|
|
689
|
-
}
|
|
690
|
-
// Build behavior
|
|
691
|
-
const origin = new origins.S3Origin(this.cdk.bucket);
|
|
692
|
-
const viewerProtocolPolicy = cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS;
|
|
693
|
-
if (this.isPlaceholder) {
|
|
694
|
-
return new cloudfront.Distribution(this, "Distribution", {
|
|
695
|
-
defaultRootObject: "index.html",
|
|
696
|
-
errorResponses: buildErrorResponsesForRedirectToIndex("index.html"),
|
|
697
|
-
domainNames,
|
|
698
|
-
certificate: this.cdk.certificate,
|
|
699
|
-
defaultBehavior: {
|
|
700
|
-
origin,
|
|
701
|
-
viewerProtocolPolicy,
|
|
702
|
-
},
|
|
703
|
-
});
|
|
704
|
-
}
|
|
705
|
-
// Build Edge functions
|
|
706
|
-
const edgeLambdas = [
|
|
707
|
-
{
|
|
708
|
-
includeBody: true,
|
|
709
|
-
eventType: cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST,
|
|
710
|
-
functionVersion: this.mainFunctionVersion,
|
|
711
|
-
},
|
|
712
|
-
{
|
|
713
|
-
eventType: cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE,
|
|
714
|
-
functionVersion: this.mainFunctionVersion,
|
|
715
|
-
},
|
|
716
|
-
];
|
|
717
|
-
// Build cache policies
|
|
718
|
-
const staticCachePolicy = cdk?.cachePolicies?.staticCachePolicy ??
|
|
719
|
-
this.createCloudFrontStaticCachePolicy();
|
|
720
|
-
const imageCachePolicy = cdk?.cachePolicies?.imageCachePolicy ??
|
|
721
|
-
this.createCloudFrontImageCachePolicy();
|
|
722
|
-
const lambdaCachePolicy = cdk?.cachePolicies?.lambdaCachePolicy ??
|
|
723
|
-
this.createCloudFrontLambdaCachePolicy();
|
|
724
|
-
// Build origin request policy
|
|
725
|
-
const imageOriginRequestPolicy = cdk?.imageOriginRequestPolicy ??
|
|
726
|
-
this.createCloudFrontImageOriginRequestPolicy();
|
|
727
|
-
// Create Distribution
|
|
728
|
-
return new cloudfront.Distribution(this, "Distribution", {
|
|
729
|
-
// these values can be overwritten by cfDistributionProps
|
|
730
|
-
defaultRootObject: "",
|
|
731
|
-
// Override props.
|
|
732
|
-
...cfDistributionProps,
|
|
733
|
-
// these values can NOT be overwritten by cfDistributionProps
|
|
734
|
-
domainNames,
|
|
735
|
-
certificate: this.cdk.certificate,
|
|
736
|
-
defaultBehavior: {
|
|
737
|
-
viewerProtocolPolicy,
|
|
738
|
-
origin,
|
|
739
|
-
allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
|
|
740
|
-
cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
|
|
741
|
-
compress: true,
|
|
742
|
-
cachePolicy: lambdaCachePolicy,
|
|
743
|
-
...(cfDistributionProps.defaultBehavior || {}),
|
|
744
|
-
// concatenate edgeLambdas
|
|
745
|
-
edgeLambdas: [
|
|
746
|
-
...edgeLambdas,
|
|
747
|
-
...(cfDistributionProps.defaultBehavior?.edgeLambdas || []),
|
|
748
|
-
],
|
|
749
|
-
},
|
|
750
|
-
additionalBehaviors: {
|
|
751
|
-
[this.pathPattern("_next/image*")]: {
|
|
752
|
-
viewerProtocolPolicy,
|
|
753
|
-
origin,
|
|
754
|
-
allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
|
|
755
|
-
cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
|
|
756
|
-
compress: true,
|
|
757
|
-
cachePolicy: imageCachePolicy,
|
|
758
|
-
originRequestPolicy: imageOriginRequestPolicy,
|
|
759
|
-
edgeLambdas: [
|
|
760
|
-
{
|
|
761
|
-
eventType: cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST,
|
|
762
|
-
functionVersion: this.imageFunctionVersion,
|
|
763
|
-
},
|
|
764
|
-
],
|
|
765
|
-
},
|
|
766
|
-
[this.pathPattern("_next/data/*")]: {
|
|
767
|
-
viewerProtocolPolicy,
|
|
768
|
-
origin,
|
|
769
|
-
allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
|
|
770
|
-
cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
|
|
771
|
-
compress: true,
|
|
772
|
-
cachePolicy: lambdaCachePolicy,
|
|
773
|
-
edgeLambdas,
|
|
774
|
-
},
|
|
775
|
-
[this.pathPattern("_next/*")]: {
|
|
776
|
-
viewerProtocolPolicy,
|
|
777
|
-
origin,
|
|
778
|
-
allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
|
|
779
|
-
cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
|
|
780
|
-
compress: true,
|
|
781
|
-
cachePolicy: staticCachePolicy,
|
|
782
|
-
},
|
|
783
|
-
[this.pathPattern("static/*")]: {
|
|
784
|
-
viewerProtocolPolicy,
|
|
785
|
-
origin,
|
|
786
|
-
allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
|
|
787
|
-
cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
|
|
788
|
-
compress: true,
|
|
789
|
-
cachePolicy: staticCachePolicy,
|
|
790
|
-
},
|
|
791
|
-
[this.pathPattern("api/*")]: {
|
|
792
|
-
viewerProtocolPolicy,
|
|
793
|
-
origin,
|
|
794
|
-
allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
|
|
795
|
-
cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
|
|
796
|
-
compress: true,
|
|
797
|
-
cachePolicy: lambdaCachePolicy,
|
|
798
|
-
edgeLambdas: [
|
|
799
|
-
{
|
|
800
|
-
includeBody: true,
|
|
801
|
-
eventType: cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST,
|
|
802
|
-
functionVersion: this.apiFunctionVersion,
|
|
803
|
-
},
|
|
804
|
-
],
|
|
805
|
-
},
|
|
806
|
-
...(cfDistributionProps.additionalBehaviors || {}),
|
|
807
|
-
},
|
|
808
|
-
});
|
|
809
|
-
}
|
|
810
|
-
createCloudFrontStaticCachePolicy() {
|
|
811
|
-
return new cloudfront.CachePolicy(this, "StaticsCache", NextjsSite.staticCachePolicyProps);
|
|
812
|
-
}
|
|
813
|
-
createCloudFrontImageCachePolicy() {
|
|
814
|
-
return new cloudfront.CachePolicy(this, "ImageCache", NextjsSite.imageCachePolicyProps);
|
|
815
|
-
}
|
|
816
|
-
createCloudFrontLambdaCachePolicy() {
|
|
817
|
-
return new cloudfront.CachePolicy(this, "LambdaCache", NextjsSite.lambdaCachePolicyProps);
|
|
818
|
-
}
|
|
819
|
-
createCloudFrontImageOriginRequestPolicy() {
|
|
820
|
-
return new cloudfront.OriginRequestPolicy(this, "ImageOriginRequest", NextjsSite.imageOriginRequestPolicyProps);
|
|
821
|
-
}
|
|
822
|
-
createCloudFrontInvalidation() {
|
|
823
|
-
const stack = Stack.of(this);
|
|
824
|
-
// need the BuildId field so this CR gets updated on each deploy
|
|
825
|
-
let buildId;
|
|
826
|
-
if (this.isPlaceholder) {
|
|
827
|
-
buildId = "live";
|
|
828
|
-
}
|
|
829
|
-
else {
|
|
830
|
-
const buildIdFile = path.resolve(this.buildOutDir, "assets", "BUILD_ID");
|
|
831
|
-
buildId = fs.readFileSync(buildIdFile).toString();
|
|
832
|
-
}
|
|
833
|
-
// Create custom resource
|
|
834
|
-
const waitForInvalidation = this.isPlaceholder
|
|
835
|
-
? false
|
|
836
|
-
: this.props.waitForInvalidation === false
|
|
837
|
-
? false
|
|
838
|
-
: true;
|
|
839
|
-
const resource = new CustomResource(this, "CloudFrontInvalidator", {
|
|
840
|
-
serviceToken: stack.customResourceHandler.functionArn,
|
|
841
|
-
resourceType: "Custom::CloudFrontInvalidator",
|
|
842
|
-
properties: {
|
|
843
|
-
buildId,
|
|
844
|
-
distributionId: this.cdk.distribution.distributionId,
|
|
845
|
-
paths: ["/*"],
|
|
846
|
-
waitForInvalidation,
|
|
847
|
-
},
|
|
848
|
-
});
|
|
849
|
-
stack.customResourceHandler.role?.addToPrincipalPolicy(new PolicyStatement({
|
|
850
|
-
effect: Effect.ALLOW,
|
|
851
|
-
actions: [
|
|
852
|
-
"cloudfront:GetInvalidation",
|
|
853
|
-
"cloudfront:CreateInvalidation",
|
|
854
|
-
],
|
|
855
|
-
resources: [
|
|
856
|
-
`arn:${stack.partition}:cloudfront::${stack.account}:distribution/${this.cdk.distribution.distributionId}`,
|
|
857
|
-
],
|
|
858
|
-
}));
|
|
859
|
-
return resource;
|
|
860
|
-
}
|
|
861
|
-
/////////////////////
|
|
862
|
-
// Custom Domain
|
|
863
|
-
/////////////////////
|
|
864
|
-
validateCustomDomainSettings() {
|
|
865
|
-
const { customDomain } = this.props;
|
|
866
|
-
if (!customDomain) {
|
|
867
|
-
return;
|
|
868
|
-
}
|
|
869
|
-
if (typeof customDomain === "string") {
|
|
870
|
-
return;
|
|
871
|
-
}
|
|
872
|
-
if (customDomain.isExternalDomain === true) {
|
|
873
|
-
if (!customDomain.cdk?.certificate) {
|
|
874
|
-
throw new Error(`A valid certificate is required when "isExternalDomain" is set to "true".`);
|
|
875
|
-
}
|
|
876
|
-
if (customDomain.domainAlias) {
|
|
877
|
-
throw new Error(`Domain alias is only supported for domains hosted on Amazon Route 53. Do not set the "customDomain.domainAlias" when "isExternalDomain" is enabled.`);
|
|
878
|
-
}
|
|
879
|
-
if (customDomain.hostedZone) {
|
|
880
|
-
throw new Error(`Hosted zones can only be configured for domains hosted on Amazon Route 53. Do not set the "customDomain.hostedZone" when "isExternalDomain" is enabled.`);
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
lookupHostedZone() {
|
|
885
|
-
const { customDomain } = this.props;
|
|
886
|
-
// Skip if customDomain is not configured
|
|
887
|
-
if (!customDomain) {
|
|
888
|
-
return;
|
|
889
|
-
}
|
|
890
|
-
let hostedZone;
|
|
891
|
-
if (typeof customDomain === "string") {
|
|
892
|
-
hostedZone = route53.HostedZone.fromLookup(this, "HostedZone", {
|
|
893
|
-
domainName: customDomain,
|
|
894
|
-
});
|
|
895
|
-
}
|
|
896
|
-
else if (customDomain.cdk?.hostedZone) {
|
|
897
|
-
hostedZone = customDomain.cdk.hostedZone;
|
|
898
|
-
}
|
|
899
|
-
else if (typeof customDomain.hostedZone === "string") {
|
|
900
|
-
hostedZone = route53.HostedZone.fromLookup(this, "HostedZone", {
|
|
901
|
-
domainName: customDomain.hostedZone,
|
|
902
|
-
});
|
|
903
|
-
}
|
|
904
|
-
else if (typeof customDomain.domainName === "string") {
|
|
905
|
-
// Skip if domain is not a Route53 domain
|
|
906
|
-
if (customDomain.isExternalDomain === true) {
|
|
907
|
-
return;
|
|
908
|
-
}
|
|
909
|
-
hostedZone = route53.HostedZone.fromLookup(this, "HostedZone", {
|
|
910
|
-
domainName: customDomain.domainName,
|
|
911
|
-
});
|
|
912
|
-
}
|
|
913
|
-
else {
|
|
914
|
-
hostedZone = customDomain.hostedZone;
|
|
915
|
-
}
|
|
916
|
-
return hostedZone;
|
|
917
|
-
}
|
|
918
|
-
createCertificate() {
|
|
919
|
-
const { customDomain } = this.props;
|
|
920
|
-
if (!customDomain) {
|
|
921
|
-
return;
|
|
922
|
-
}
|
|
923
|
-
let acmCertificate;
|
|
924
|
-
// HostedZone is set for Route 53 domains
|
|
925
|
-
if (this.cdk.hostedZone) {
|
|
926
|
-
if (typeof customDomain === "string") {
|
|
927
|
-
acmCertificate = new acm.DnsValidatedCertificate(this, "Certificate", {
|
|
928
|
-
domainName: customDomain,
|
|
929
|
-
hostedZone: this.cdk.hostedZone,
|
|
930
|
-
region: "us-east-1",
|
|
931
|
-
});
|
|
932
|
-
}
|
|
933
|
-
else if (customDomain.cdk?.certificate) {
|
|
934
|
-
acmCertificate = customDomain.cdk.certificate;
|
|
935
|
-
}
|
|
936
|
-
else {
|
|
937
|
-
acmCertificate = new acm.DnsValidatedCertificate(this, "Certificate", {
|
|
938
|
-
domainName: customDomain.domainName,
|
|
939
|
-
hostedZone: this.cdk.hostedZone,
|
|
940
|
-
region: "us-east-1",
|
|
941
|
-
});
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
// HostedZone is NOT set for non-Route 53 domains
|
|
945
|
-
else {
|
|
946
|
-
if (typeof customDomain !== "string") {
|
|
947
|
-
acmCertificate = customDomain.cdk?.certificate;
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
return acmCertificate;
|
|
951
|
-
}
|
|
952
|
-
createRoute53Records() {
|
|
953
|
-
const { customDomain } = this.props;
|
|
954
|
-
if (!customDomain || !this.cdk.hostedZone) {
|
|
955
|
-
return;
|
|
956
|
-
}
|
|
957
|
-
let recordName;
|
|
958
|
-
let domainAlias;
|
|
959
|
-
if (typeof customDomain === "string") {
|
|
960
|
-
recordName = customDomain;
|
|
961
|
-
}
|
|
962
|
-
else {
|
|
963
|
-
recordName = customDomain.domainName;
|
|
964
|
-
domainAlias = customDomain.domainAlias;
|
|
965
|
-
}
|
|
966
|
-
// Create DNS record
|
|
967
|
-
const recordProps = {
|
|
968
|
-
recordName,
|
|
969
|
-
zone: this.cdk.hostedZone,
|
|
970
|
-
target: route53.RecordTarget.fromAlias(new route53Targets.CloudFrontTarget(this.cdk.distribution)),
|
|
971
|
-
};
|
|
972
|
-
new route53.ARecord(this, "AliasRecord", recordProps);
|
|
973
|
-
new route53.AaaaRecord(this, "AliasRecordAAAA", recordProps);
|
|
974
|
-
// Create Alias redirect record
|
|
975
|
-
if (domainAlias) {
|
|
976
|
-
new route53Patterns.HttpsRedirect(this, "Redirect", {
|
|
977
|
-
zone: this.cdk.hostedZone,
|
|
978
|
-
recordNames: [domainAlias],
|
|
979
|
-
targetDomain: recordName,
|
|
980
|
-
});
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
/////////////////////
|
|
984
|
-
// Helper Functions
|
|
985
|
-
/////////////////////
|
|
986
|
-
pathPattern(pattern) {
|
|
987
|
-
const { basePath } = this.routesManifest || {};
|
|
988
|
-
return basePath && basePath.length > 0
|
|
989
|
-
? `${basePath.slice(1)}/${pattern}`
|
|
990
|
-
: pattern;
|
|
991
|
-
}
|
|
992
|
-
readRoutesManifest() {
|
|
993
|
-
return JSON.parse(fs
|
|
994
|
-
.readFileSync(path.join(this.buildOutDir, "default-lambda/routes-manifest.json"))
|
|
995
|
-
.toString());
|
|
996
|
-
}
|
|
997
|
-
getS3ContentReplaceValues() {
|
|
998
|
-
const replaceValues = [];
|
|
999
|
-
Object.entries(this.props.environment || {})
|
|
1000
|
-
.filter(([, value]) => Token.isUnresolved(value))
|
|
1001
|
-
.forEach(([key, value]) => {
|
|
1002
|
-
const token = `{{ ${key} }}`;
|
|
1003
|
-
replaceValues.push({
|
|
1004
|
-
files: "**/*.html",
|
|
1005
|
-
search: token,
|
|
1006
|
-
replace: value,
|
|
1007
|
-
}, {
|
|
1008
|
-
files: "**/*.js",
|
|
1009
|
-
search: token,
|
|
1010
|
-
replace: value,
|
|
1011
|
-
}, {
|
|
1012
|
-
files: "**/*.json",
|
|
1013
|
-
search: token,
|
|
1014
|
-
replace: value,
|
|
1015
|
-
});
|
|
1016
|
-
});
|
|
1017
|
-
return replaceValues;
|
|
1018
|
-
}
|
|
1019
|
-
getLambdaContentReplaceValues() {
|
|
1020
|
-
const replaceValues = [];
|
|
1021
|
-
// The Next.js app can have environment variables like
|
|
1022
|
-
// `process.env.API_URL` in the JS code. `process.env.API_URL` might or
|
|
1023
|
-
// might not get resolved on `next build` if it is used in
|
|
1024
|
-
// server-side functions, ie. getServerSideProps().
|
|
1025
|
-
// Because Lambda@Edge does not support environment variables, we will
|
|
1026
|
-
// use the trick of replacing "{{ _SST_NEXTJS_SITE_ENVIRONMENT_ }}" with
|
|
1027
|
-
// a JSON encoded string of all environment key-value pairs. This string
|
|
1028
|
-
// will then get decoded at run time.
|
|
1029
|
-
const lambdaEnvs = {};
|
|
1030
|
-
Object.entries(this.props.environment || {}).forEach(([key, value]) => {
|
|
1031
|
-
const token = `{{ ${key} }}`;
|
|
1032
|
-
replaceValues.push({
|
|
1033
|
-
files: "**/*.html",
|
|
1034
|
-
search: token,
|
|
1035
|
-
replace: value,
|
|
1036
|
-
}, {
|
|
1037
|
-
files: "**/*.js",
|
|
1038
|
-
search: token,
|
|
1039
|
-
replace: value,
|
|
1040
|
-
}, {
|
|
1041
|
-
files: "**/*.json",
|
|
1042
|
-
search: token,
|
|
1043
|
-
replace: value,
|
|
1044
|
-
});
|
|
1045
|
-
lambdaEnvs[key] = value;
|
|
1046
|
-
});
|
|
1047
|
-
replaceValues.push({
|
|
1048
|
-
files: "**/*.js",
|
|
1049
|
-
search: '"{{ _SST_NEXTJS_SITE_ENVIRONMENT_ }}"',
|
|
1050
|
-
replace: JSON.stringify(lambdaEnvs),
|
|
1051
|
-
});
|
|
1052
|
-
return replaceValues;
|
|
1053
|
-
}
|
|
1054
|
-
normalizeRuntime(runtime) {
|
|
1055
|
-
if (runtime === "nodejs12.x") {
|
|
1056
|
-
return lambda.Runtime.NODEJS_12_X;
|
|
1057
|
-
}
|
|
1058
|
-
else if (runtime === "nodejs14.x") {
|
|
1059
|
-
return lambda.Runtime.NODEJS_14_X;
|
|
1060
|
-
}
|
|
1061
|
-
return lambda.Runtime.NODEJS_16_X;
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
export const useSites = createAppContext(() => {
|
|
1065
|
-
const sites = [];
|
|
1066
|
-
return {
|
|
1067
|
-
add(stack, name, props) {
|
|
1068
|
-
sites.push({ stack, name, props });
|
|
1069
|
-
},
|
|
1070
|
-
get all() {
|
|
1071
|
-
return sites;
|
|
1072
|
-
},
|
|
1073
|
-
};
|
|
1074
|
-
});
|