Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions .projen/deps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .projen/tasks.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions src/patterns/apigateway-static-hosting/handler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

import SE from '@codegenie/serverless-express';
import { InlineHost } from './hosts/inline';
import { S3Host } from './hosts/s3';
import { Configuration } from './types/configuration';
import { InlineHost } from '../worker/hosts/inline';
import { S3Host } from '../worker/hosts/s3';
import { Configuration } from '../worker/types/configuration';

/**
* Lambda entry point
Expand Down
2 changes: 1 addition & 1 deletion src/patterns/apigateway-static-hosting/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
import { Construct } from 'constructs';
import { SecureFunction } from '../../constructs/secure-function';
import { LambdaConfiguration } from '../../types';
import { S3HostingConfiguration } from './handler/hosts/s3';
import { S3HostingConfiguration } from './worker/hosts/s3';
import { DefaultConfig } from '../../common/default-config';

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { Express, Handler, Request, Response, NextFunction } from 'express';
import {
Express,
Handler,
Request,
Response,
Router,
NextFunction
} from 'express';
import express = require('express');
import helmet from 'helmet';
import morgan = require('morgan');
import { CommonHostingConfiguration } from '../../types/configuration';

Expand Down Expand Up @@ -80,6 +88,17 @@ export abstract class CommonHost<
*/
protected abstract get spaHandler(): Handler;

/**
* Add the middleware to an existing Express router
* Either use this with an existing router or use the `create` method but not both
* @param router Express router on an existing app
*/
addMiddleware(router: Router): void {
// First, try to load the URI as a static asset
// Second (only for SPA) load the base page which allows client to perform routing
router.use(this.fileHandler, this.spaHandler);
}

/**
* Create an Express app to host static assets
* @returns Express app for static asset hosting
Expand All @@ -92,17 +111,19 @@ export abstract class CommonHost<
app.use(morgan('combined'));
}

// First, try to load the URI as a static asset
app.use(this.fileHandler);
// Security
app.disable('x-powered-by');
app.use(helmet());

if (this.props.spaIndexPage) {
// Second (only for SPA) load the base page which allows client to perform routing
app.get('*spa', this.spaHandler);
}
const router = Router();
this.addMiddleware(router);

app.use(router);

// Last, override error handler to only show 404 and nondescript 500 for everything else
// TODO: Allow verbose logging in dev
app.use(CommonHost.nonspecificErrorHandler);
if (!this.props.enableVerboseErrors) {
app.use(CommonHost.nonspecificErrorHandler);
}

return app;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import { join } from 'node:path';
import { Handler, Request, Response } from 'express';
import { Handler, NextFunction, Request, Response } from 'express';
import express = require('express');
import { CommonHostingConfiguration } from '../../types/configuration';
import { CommonHost } from '../common';
Expand All @@ -28,7 +28,7 @@ export class InlineHost extends CommonHost<InlineHostingConfiguration> {
* Express handler for the fallthrough SPA route
*/
protected get spaHandler(): Handler {
return (_req: Request, res: Response) => {
return (_req: Request, res: Response, next: NextFunction) => {
if (this.props.spaIndexPage) {
res.sendFile(
join(
Expand All @@ -38,7 +38,7 @@ export class InlineHost extends CommonHost<InlineHostingConfiguration> {
)
);
} else {
res.sendStatus(500);
next();
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { type SdkStream } from '@smithy/types';
import { sdkStreamMixin } from '@smithy/util-stream-node';
import { Handler, Request, Response, NextFunction } from 'express';
import expressAsyncHandler = require('express-async-handler');
import { getType } from 'mime';
import mime from 'mime';
import { CommonHostingConfiguration } from '../../types/configuration';
import { CommonHost } from '../common';

Expand Down Expand Up @@ -95,7 +95,8 @@ export class S3Host extends CommonHost<S3HostingConfiguration> {
try {
if (this.props.spaIndexPage) {
const defaultContentType =
getType(this.props.spaIndexPage) ?? 'text/plain';
mime.getType(this.props.spaIndexPage) ??
'text/plain';

const file = await this.loadObject(
this.props.spaIndexPage
Expand All @@ -112,7 +113,7 @@ export class S3Host extends CommonHost<S3HostingConfiguration> {
res.sendStatus(500);
}
} else {
res.sendStatus(404);
next();
}
} catch (e) {
// Failed to load the default object
Expand All @@ -133,7 +134,7 @@ export class S3Host extends CommonHost<S3HostingConfiguration> {
return expressAsyncHandler(
async (req: Request, res: Response, next: NextFunction) => {
try {
const contentType = getType(req.path) ?? 'text/plain';
const contentType = mime.getType(req.path) ?? 'text/plain';

const file = await this.loadObject(req.path);

Expand Down
6 changes: 6 additions & 0 deletions src/patterns/apigateway-static-hosting/worker/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

export { InlineHost, InlineHostingConfiguration } from './hosts/inline';
export { S3Host, S3HostingConfiguration } from './hosts/s3';
export { Configuration } from './types/configuration';
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ export interface CommonHostingConfiguration {
* @default false
*/
readonly disableHttpLogging?: boolean;

/**
* If specified, the host will allow full error stacks to be returned to the client
* It is recommended to not enable this in production
*
* @default false
*/
readonly enableVerboseErrors?: boolean;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { describe, it, expect } from 'vitest';
import {
InlineHost,
InlineHostingConfiguration
} from '../../../../../../src/patterns/apigateway-static-hosting/handler/hosts/inline';
} from '../../../../../../src/patterns/apigateway-static-hosting/worker';

const commonConfig: Partial<InlineHostingConfiguration> = {
disableHttpLogging: true
Expand All @@ -24,7 +24,7 @@ const relativeFixturesDir = join(
'test',
'patterns',
'apigateway-static-hosting',
'handler',
'worker',
'fixtures'
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { describe, beforeEach, it, expect } from 'vitest';
import {
S3Host,
S3HostingConfiguration
} from '../../../../../../src/patterns/apigateway-static-hosting/handler/hosts/s3';
} from '../../../../../../src/patterns/apigateway-static-hosting/worker';
import { streamFile } from '../../utilities/stream-fixture';

const commonConfig: Partial<S3HostingConfiguration> = {
Expand Down
4 changes: 2 additions & 2 deletions utilities/projen/lib/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ export const configureDependencies = (project: CdklabsTypeScriptProject) => {
'@smithy/[email protected]',
'@types/[email protected]',
'@types/[email protected]',
'@types/[email protected]',
'@types/[email protected]',
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]',
'[email protected]'
];
Expand Down
1 change: 1 addition & 0 deletions utilities/projen/lib/lint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const configureLinting = (project: CdklabsTypeScriptProject) => {
});

project.eslint?.allowDevDeps('**/handler/**/*.ts');
project.eslint?.allowDevDeps('**/worker/**/*.ts');
project.eslint?.allowDevDeps('**/utilities/**/*.ts');

project.eslint?.addRules({
Expand Down
2 changes: 2 additions & 0 deletions utilities/projen/lib/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export const configurePackaging = (project: CdklabsTypeScriptProject) => {
'./aspects': './aspects/index.js',
'./constructs': './constructs/index.js',
'./patterns': './patterns/index.js',
'./patterns/apigateway-static-hosting/worker':
'./patterns/apigateway-static-hosting/worker/index.js',
'./types': './types/index.js'
},
// Represents the structure in the package staging directory
Expand Down
Loading
Loading