quidproquo-deploy-awscdk 0.0.43 → 0.0.44
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/lib/QPQPrototypeSingleServiceStack.d.ts +0 -1
- package/lib/QPQPrototypeSingleServiceStack.js +92 -40
- package/lib/lambdas/actionProcessorListResolver.d.ts +3 -0
- package/lib/lambdas/actionProcessorListResolver.js +2 -0
- package/lib/lambdas/awsLambdaMissingTypes.d.ts +51 -0
- package/lib/lambdas/awsLambdaMissingTypes.js +2 -0
- package/lib/lambdas/lambdaAPIGatewayEvent.d.ts +1 -1
- package/lib/lambdas/lambdaAPIGatewayEvent.js +0 -1
- package/lib/lambdas/lambdaConfig copy.d.ts +4 -0
- package/lib/lambdas/lambdaConfig copy.js +4 -0
- package/lib/lambdas/lambdaConfig.d.ts +0 -2
- package/lib/lambdas/lambdaEventBridgeEvent.d.ts +1 -1
- package/lib/lambdas/lambdaEventOriginRequest copy.d.ts +5 -0
- package/lib/lambdas/lambdaEventOriginRequest copy.js +74 -0
- package/lib/lambdas/lambdaEventOriginRequest.d.ts +15 -0
- package/lib/lambdas/lambdaEventOriginRequest.js +75 -0
- package/lib/lambdas/lambdaEventViewerRequest.d.ts +39 -0
- package/lib/lambdas/lambdaEventViewerRequest.js +31 -0
- package/lib/lambdas/types.d.ts +51 -0
- package/lib/lambdas/types.js +2 -0
- package/package.json +2 -2
- package/src/QPQPrototypeSingleServiceStack.ts +187 -48
- package/src/lambdas/actionProcessorListResolver.ts +6 -0
- package/src/lambdas/lambdaAPIGatewayEvent.ts +2 -2
- package/src/lambdas/lambdaConfig.ts +0 -5
- package/src/lambdas/lambdaEventBridgeEvent.ts +2 -1
- package/src/lambdas/lambdaEventOriginRequest.ts +120 -0
- package/src/lambdas/lambdaEventViewerRequest.ts +28 -0
|
@@ -3,7 +3,6 @@ import { Stack } from 'aws-cdk-lib';
|
|
|
3
3
|
import { Construct } from 'constructs';
|
|
4
4
|
export interface QPQPrototypeStackProps extends DeploymentSettings {
|
|
5
5
|
account: string;
|
|
6
|
-
region: string;
|
|
7
6
|
apiBuildPath: string;
|
|
8
7
|
webBuildPath: string;
|
|
9
8
|
lambdaAPIGatewayEventPath?: string;
|
|
@@ -24,10 +24,31 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.QPQPrototypeSingleServiceStack = void 0;
|
|
27
|
+
const path = __importStar(require("path"));
|
|
27
28
|
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
28
29
|
const cdk = __importStar(require("aws-cdk-lib"));
|
|
29
30
|
const quidproquo_core_1 = require("quidproquo-core");
|
|
30
31
|
const quidproquo_webserver_1 = require("quidproquo-webserver");
|
|
32
|
+
const grantReadToOwnedResources = (ownedResourceSettings, identity) => {
|
|
33
|
+
ownedResourceSettings.ownedBuckets.forEach((b) => b.bucket.grantReadWrite(identity));
|
|
34
|
+
ownedResourceSettings.ownedSecrets.forEach((os) => os.secret.grantRead(identity));
|
|
35
|
+
ownedResourceSettings.ownedParameters.forEach((os) => os.parameter.grantRead(identity));
|
|
36
|
+
};
|
|
37
|
+
const getParameterName = (parameterKey, service, environment) => `${parameterKey}-${service}-${environment}`;
|
|
38
|
+
const createServiceParameter = (stack, id, service, environment, parameterKey, value) => {
|
|
39
|
+
const realParameterName = getParameterName(parameterKey, service, environment);
|
|
40
|
+
return {
|
|
41
|
+
parameterName: parameterKey,
|
|
42
|
+
realName: realParameterName,
|
|
43
|
+
parameter: new aws_cdk_lib_1.aws_ssm.StringParameter(stack, `${id}-parameter-${parameterKey}`, {
|
|
44
|
+
parameterName: realParameterName,
|
|
45
|
+
description: `${environment}-${service}`,
|
|
46
|
+
stringValue: value,
|
|
47
|
+
// No additional costs ~ 4k max size
|
|
48
|
+
tier: aws_cdk_lib_1.aws_ssm.ParameterTier.STANDARD,
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
};
|
|
31
52
|
const createApiDomainName = (stack, id, stackProps) => {
|
|
32
53
|
const apexDomain = quidproquo_webserver_1.qpqWebServerUtils.getFeatureDomainName(stackProps.qpqConfig);
|
|
33
54
|
const apiDomainName = `api.${apexDomain}`;
|
|
@@ -52,7 +73,7 @@ const createApiDomainName = (stack, id, stackProps) => {
|
|
|
52
73
|
});
|
|
53
74
|
return domainName;
|
|
54
75
|
};
|
|
55
|
-
const createWebDistribution = (stack, id, stackProps) => {
|
|
76
|
+
const createWebDistribution = (stack, id, stackProps, ownedResourceSettings) => {
|
|
56
77
|
const environment = quidproquo_core_1.qpqCoreUtils.getAppFeature(stackProps.qpqConfig);
|
|
57
78
|
const apexDomain = quidproquo_webserver_1.qpqWebServerUtils.getFeatureDomainName(stackProps.qpqConfig);
|
|
58
79
|
const serviceName = quidproquo_core_1.qpqCoreUtils.getAppName(stackProps.qpqConfig);
|
|
@@ -92,8 +113,52 @@ const createWebDistribution = (stack, id, stackProps) => {
|
|
|
92
113
|
sources: [aws_cdk_lib_1.aws_s3_deployment.Source.asset(stackProps.webBuildPath)],
|
|
93
114
|
destinationBucket: staticWebFilesBucket,
|
|
94
115
|
});
|
|
116
|
+
const cloudFrontBehaviors = quidproquo_webserver_1.qpqWebServerUtils
|
|
117
|
+
.getAllSeo(stackProps.qpqConfig)
|
|
118
|
+
.map((seo, index) => {
|
|
119
|
+
const edgeFunctionVR = new aws_cdk_lib_1.aws_cloudfront.experimental.EdgeFunction(stack, `${id}-SEO-${index}-${seo.runtime}-VR`, {
|
|
120
|
+
functionName: `SEO-VR-${index}-${seo.runtime}-${environment}-${serviceName}`,
|
|
121
|
+
timeout: cdk.Duration.seconds(5),
|
|
122
|
+
runtime: aws_cdk_lib_1.aws_lambda.Runtime.NODEJS_16_X,
|
|
123
|
+
code: aws_cdk_lib_1.aws_lambda.Code.fromAsset(path.join(stackProps.apiBuildPath, 'lambdaEventViewerRequest')),
|
|
124
|
+
handler: 'index.executeEventViewerRequest',
|
|
125
|
+
});
|
|
126
|
+
const edgeFunctionOR = new aws_cdk_lib_1.aws_cloudfront.experimental.EdgeFunction(stack, `${id}-SEO-${index}-${seo.runtime}-OR`, {
|
|
127
|
+
functionName: `SEO-OR-${index}-${seo.runtime}-${environment}-${serviceName}`,
|
|
128
|
+
timeout: cdk.Duration.seconds(30),
|
|
129
|
+
runtime: aws_cdk_lib_1.aws_lambda.Runtime.NODEJS_16_X,
|
|
130
|
+
memorySize: 1024,
|
|
131
|
+
code: aws_cdk_lib_1.aws_lambda.Code.fromAsset(path.join(stackProps.apiBuildPath, 'lambdaEventOriginRequest')),
|
|
132
|
+
handler: 'index.executeEventOriginRequest',
|
|
133
|
+
});
|
|
134
|
+
// We don't need access to anything in the VR
|
|
135
|
+
grantReadToOwnedResources(ownedResourceSettings, edgeFunctionOR);
|
|
136
|
+
const wildcardPath = seo.path.replaceAll(/{(.+?)}/g, '*');
|
|
137
|
+
return {
|
|
138
|
+
pathPattern: wildcardPath,
|
|
139
|
+
// Update this to 24 hours
|
|
140
|
+
maxTtl: cdk.Duration.seconds(0),
|
|
141
|
+
minTtl: cdk.Duration.seconds(0),
|
|
142
|
+
defaultTtl: cdk.Duration.seconds(0),
|
|
143
|
+
lambdaFunctionAssociations: [
|
|
144
|
+
{
|
|
145
|
+
includeBody: true,
|
|
146
|
+
eventType: aws_cdk_lib_1.aws_cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST,
|
|
147
|
+
lambdaFunction: edgeFunctionOR.currentVersion,
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
includeBody: false,
|
|
151
|
+
eventType: aws_cdk_lib_1.aws_cloudfront.LambdaEdgeEventType.VIEWER_REQUEST,
|
|
152
|
+
lambdaFunction: edgeFunctionVR.currentVersion,
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
};
|
|
156
|
+
});
|
|
95
157
|
// Create a cloud front distribution
|
|
96
158
|
// TODO: use aws_cloudfront.Distribution
|
|
159
|
+
// TODO: Somehow expose query strings: Note ~
|
|
160
|
+
// (Lambda@Edge only) To access the query string in an origin request or origin response function,
|
|
161
|
+
// your cache policy or origin request policy must be set to All for Query strings.
|
|
97
162
|
const distribution = new aws_cdk_lib_1.aws_cloudfront.CloudFrontWebDistribution(stack, 'cf-distribution', {
|
|
98
163
|
originConfigs: [
|
|
99
164
|
{
|
|
@@ -102,16 +167,7 @@ const createWebDistribution = (stack, id, stackProps) => {
|
|
|
102
167
|
originAccessIdentity: websiteOAI,
|
|
103
168
|
},
|
|
104
169
|
behaviors: [
|
|
105
|
-
...
|
|
106
|
-
'/remoteEntry.js',
|
|
107
|
-
'/index.js',
|
|
108
|
-
'/index.html', // Add this if we need it
|
|
109
|
-
].map((pp) => ({
|
|
110
|
-
pathPattern: pp,
|
|
111
|
-
maxTtl: cdk.Duration.seconds(0),
|
|
112
|
-
minTtl: cdk.Duration.seconds(0),
|
|
113
|
-
defaultTtl: cdk.Duration.seconds(0),
|
|
114
|
-
})),
|
|
170
|
+
...cloudFrontBehaviors,
|
|
115
171
|
{
|
|
116
172
|
isDefaultBehavior: true,
|
|
117
173
|
},
|
|
@@ -140,7 +196,7 @@ class QPQPrototypeSingleServiceStack extends aws_cdk_lib_1.Stack {
|
|
|
140
196
|
super(scope, id, {
|
|
141
197
|
env: {
|
|
142
198
|
account: props.account,
|
|
143
|
-
region: props.
|
|
199
|
+
region: quidproquo_webserver_1.qpqWebServerUtils.getDeployRegion(props.qpqConfig),
|
|
144
200
|
},
|
|
145
201
|
});
|
|
146
202
|
const settings = {
|
|
@@ -148,7 +204,6 @@ class QPQPrototypeSingleServiceStack extends aws_cdk_lib_1.Stack {
|
|
|
148
204
|
service: quidproquo_core_1.qpqCoreUtils.getAppName(props.qpqConfig),
|
|
149
205
|
};
|
|
150
206
|
const domainName = createApiDomainName(this, id, props);
|
|
151
|
-
createWebDistribution(this, `${id}-web-dist`, props);
|
|
152
207
|
const resourceName = (name) => {
|
|
153
208
|
return `${settings.service}-${settings.environment}-${name}`;
|
|
154
209
|
};
|
|
@@ -164,21 +219,10 @@ class QPQPrototypeSingleServiceStack extends aws_cdk_lib_1.Stack {
|
|
|
164
219
|
}),
|
|
165
220
|
};
|
|
166
221
|
});
|
|
167
|
-
const ownedParameters = quidproquo_core_1.qpqCoreUtils
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
realName: realParameterName,
|
|
172
|
-
parameter: new aws_cdk_lib_1.aws_ssm.StringParameter(this, `${id}-parameter-${parameter.key}`, {
|
|
173
|
-
parameterName: realParameterName,
|
|
174
|
-
description: `${settings.environment}-${settings.service}`,
|
|
175
|
-
stringValue: parameter.value,
|
|
176
|
-
// No additional costs ~ 4k max size
|
|
177
|
-
tier: aws_cdk_lib_1.aws_ssm.ParameterTier.STANDARD,
|
|
178
|
-
}),
|
|
179
|
-
};
|
|
180
|
-
});
|
|
181
|
-
const buckets = quidproquo_core_1.qpqCoreUtils.getStorageDriveNames(props.qpqConfig).map((driveName) => {
|
|
222
|
+
const ownedParameters = quidproquo_core_1.qpqCoreUtils
|
|
223
|
+
.getOwnedParameters(props.qpqConfig)
|
|
224
|
+
.map((parameter) => createServiceParameter(this, id, settings.service, settings.environment, parameter.key, parameter.value));
|
|
225
|
+
const ownedBuckets = quidproquo_core_1.qpqCoreUtils.getStorageDriveNames(props.qpqConfig).map((driveName) => {
|
|
182
226
|
const bucketName = resourceName(driveName);
|
|
183
227
|
const bucket = new aws_cdk_lib_1.aws_s3.Bucket(this, bucketName, {
|
|
184
228
|
bucketName: resourceName(driveName),
|
|
@@ -199,25 +243,35 @@ class QPQPrototypeSingleServiceStack extends aws_cdk_lib_1.Stack {
|
|
|
199
243
|
const runtimeConfigLambdaConfig = {
|
|
200
244
|
qpqConfig: props.qpqConfig,
|
|
201
245
|
secretNameMap: ownedSecrets.reduce((acc, os) => (Object.assign(Object.assign({}, acc), { [os.secretName]: os.realName })), {}),
|
|
202
|
-
parameterNameMap: ownedParameters.reduce((acc, os) => (Object.assign(Object.assign({}, acc), { [os.parameterName]: os.realName })), {}),
|
|
203
|
-
resourceNameMap:
|
|
246
|
+
parameterNameMap: Object.assign(Object.assign({}, ownedParameters.reduce((acc, os) => (Object.assign(Object.assign({}, acc), { [os.parameterName]: os.realName })), {})), { ['qpqRuntimeConfig']: getParameterName('qpqRuntimeConfig', settings.service, settings.environment) }),
|
|
247
|
+
resourceNameMap: ownedBuckets.reduce((acc, b) => (Object.assign(Object.assign({}, acc), { [b.driveName]: b.bucketName })), {}),
|
|
248
|
+
};
|
|
249
|
+
// Build the param that stores the config
|
|
250
|
+
// Note: The mapping was done manually previously inside the value
|
|
251
|
+
ownedParameters.push(createServiceParameter(this, id, settings.service, settings.environment, 'qpqRuntimeConfig', JSON.stringify(runtimeConfigLambdaConfig)));
|
|
252
|
+
const ownedResourceSettings = {
|
|
253
|
+
ownedBuckets,
|
|
254
|
+
ownedParameters,
|
|
255
|
+
ownedSecrets,
|
|
204
256
|
};
|
|
257
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
258
|
+
// Finished building resources, now we can build the lambdas
|
|
259
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
260
|
+
createWebDistribution(this, `${id}-web-dist`, props, ownedResourceSettings);
|
|
205
261
|
const lambdaHandler = new aws_cdk_lib_1.aws_lambda.Function(this, `${settings.environment}-${settings.service}-lambda-rest`, {
|
|
206
262
|
functionName: `lambda-rest-${settings.service}-${settings.environment}`,
|
|
207
263
|
timeout: cdk.Duration.seconds(25),
|
|
208
264
|
runtime: aws_cdk_lib_1.aws_lambda.Runtime.NODEJS_16_X,
|
|
209
265
|
memorySize: 1024,
|
|
210
|
-
code: aws_cdk_lib_1.aws_lambda.Code.fromAsset(props.apiBuildPath),
|
|
211
|
-
handler: '
|
|
266
|
+
code: aws_cdk_lib_1.aws_lambda.Code.fromAsset(path.join(props.apiBuildPath, 'lambdaAPIGatewayEvent')),
|
|
267
|
+
handler: 'index.executeAPIGatewayEvent',
|
|
212
268
|
environment: {
|
|
213
269
|
TABLES: JSON.stringify([]),
|
|
214
270
|
lambdaRuntimeConfig: JSON.stringify(runtimeConfigLambdaConfig),
|
|
215
271
|
},
|
|
216
272
|
});
|
|
217
273
|
// Grant access to the lambda
|
|
218
|
-
|
|
219
|
-
ownedSecrets.forEach((os) => os.secret.grantRead(lambdaHandler));
|
|
220
|
-
ownedParameters.forEach((os) => os.parameter.grantRead(lambdaHandler));
|
|
274
|
+
grantReadToOwnedResources(ownedResourceSettings, lambdaHandler);
|
|
221
275
|
// Create a rest api
|
|
222
276
|
const api = new aws_cdk_lib_1.aws_apigateway.LambdaRestApi(this, `${settings.environment}-${settings.service}-http-api`, {
|
|
223
277
|
restApiName: `${settings.environment}-${settings.service}-http-api`,
|
|
@@ -241,8 +295,8 @@ class QPQPrototypeSingleServiceStack extends aws_cdk_lib_1.Stack {
|
|
|
241
295
|
timeout: cdk.Duration.minutes(15),
|
|
242
296
|
runtime: aws_cdk_lib_1.aws_lambda.Runtime.NODEJS_16_X,
|
|
243
297
|
memorySize: 1024,
|
|
244
|
-
code: aws_cdk_lib_1.aws_lambda.Code.fromAsset(props.apiBuildPath),
|
|
245
|
-
handler: '
|
|
298
|
+
code: aws_cdk_lib_1.aws_lambda.Code.fromAsset(path.join(props.apiBuildPath, 'lambdaEventBridgeEvent')),
|
|
299
|
+
handler: 'index.executeEventBridgeEvent',
|
|
246
300
|
environment: {
|
|
247
301
|
TABLES: JSON.stringify([]),
|
|
248
302
|
lambdaRuntimeConfig: JSON.stringify(Object.assign(Object.assign({}, runtimeConfigLambdaConfig), { lambdaRuntimeConfig: {
|
|
@@ -251,9 +305,7 @@ class QPQPrototypeSingleServiceStack extends aws_cdk_lib_1.Stack {
|
|
|
251
305
|
} })),
|
|
252
306
|
},
|
|
253
307
|
});
|
|
254
|
-
|
|
255
|
-
ownedSecrets.forEach((os) => os.secret.grantRead(schedulerFunction));
|
|
256
|
-
ownedParameters.forEach((os) => os.parameter.grantRead(schedulerFunction));
|
|
308
|
+
grantReadToOwnedResources(ownedResourceSettings, schedulerFunction);
|
|
257
309
|
// EventBridge rule which runs every five minutes
|
|
258
310
|
const cronRule = new aws_cdk_lib_1.aws_events.Rule(this, `${id}-se-cronrule-${index}`, {
|
|
259
311
|
schedule: aws_cdk_lib_1.aws_events.Schedule.expression(`cron(${se.cronExpression})`),
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
interface CloudFrontConfig {
|
|
2
|
+
distributionDomainName: string;
|
|
3
|
+
distributionId: string;
|
|
4
|
+
eventType: string;
|
|
5
|
+
requestId: string;
|
|
6
|
+
}
|
|
7
|
+
interface Body {
|
|
8
|
+
action: string;
|
|
9
|
+
data: string;
|
|
10
|
+
encoding: string;
|
|
11
|
+
inputTruncated: boolean;
|
|
12
|
+
}
|
|
13
|
+
interface KeyValueHeader {
|
|
14
|
+
key: string;
|
|
15
|
+
value: string;
|
|
16
|
+
}
|
|
17
|
+
interface Headers {
|
|
18
|
+
[key: string]: KeyValueHeader[];
|
|
19
|
+
}
|
|
20
|
+
interface CustomHeaders {
|
|
21
|
+
}
|
|
22
|
+
interface S3 {
|
|
23
|
+
authMethod: string;
|
|
24
|
+
customHeaders: CustomHeaders;
|
|
25
|
+
domainName: string;
|
|
26
|
+
path: string;
|
|
27
|
+
region: string;
|
|
28
|
+
}
|
|
29
|
+
interface Origin {
|
|
30
|
+
s3: S3;
|
|
31
|
+
}
|
|
32
|
+
interface CloudFrontOriginRequest {
|
|
33
|
+
body?: Body;
|
|
34
|
+
clientIp: string;
|
|
35
|
+
headers: Headers;
|
|
36
|
+
method: string;
|
|
37
|
+
origin: Origin;
|
|
38
|
+
querystring: string;
|
|
39
|
+
uri: string;
|
|
40
|
+
}
|
|
41
|
+
interface CloudFrontOriginConfigRequest {
|
|
42
|
+
config: CloudFrontConfig;
|
|
43
|
+
request: CloudFrontOriginRequest;
|
|
44
|
+
}
|
|
45
|
+
interface CloudFrontRecord {
|
|
46
|
+
cf: CloudFrontOriginConfigRequest;
|
|
47
|
+
}
|
|
48
|
+
export interface CloudFrontOriginRequestEvent {
|
|
49
|
+
Records: CloudFrontRecord[];
|
|
50
|
+
}
|
|
51
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DynamicModuleLoader } from 'quidproquo-actionprocessor-awslambda';
|
|
2
2
|
import { Context } from 'aws-lambda';
|
|
3
|
-
import { ActionProcessorListResolver } from './
|
|
3
|
+
import { ActionProcessorListResolver } from './actionProcessorListResolver';
|
|
4
4
|
export declare const getAPIGatewayEventExecutor: (dynamicModuleLoader: DynamicModuleLoader, getCustomActionProcessors?: ActionProcessorListResolver) => (event: import("aws-lambda").APIGatewayProxyEvent, context: Context) => Promise<{
|
|
5
5
|
statusCode: any;
|
|
6
6
|
body: string;
|
|
@@ -63,7 +63,6 @@ const getAPIGatewayEventExecutor = (dynamicModuleLoader, getCustomActionProcesso
|
|
|
63
63
|
headers: result.result.headers,
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
|
-
console.log(JSON.stringify(result));
|
|
67
66
|
const code = ErrorTypeHttpResponseMap[result.error.errorType];
|
|
68
67
|
return {
|
|
69
68
|
statusCode: code || 500,
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ActionProcessorList } from 'quidproquo-core';
|
|
2
|
+
import { QPQAWSLambdaConfig } from 'quidproquo-actionprocessor-awslambda';
|
|
3
|
+
export declare const lambdaRuntimeConfig: QPQAWSLambdaConfig;
|
|
4
|
+
export type ActionProcessorListResolver = (lambdaRuntimeConfig: QPQAWSLambdaConfig) => ActionProcessorList;
|
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
import { ActionProcessorList } from 'quidproquo-core';
|
|
2
1
|
import { QPQAWSLambdaConfig } from 'quidproquo-actionprocessor-awslambda';
|
|
3
2
|
export declare const lambdaRuntimeConfig: QPQAWSLambdaConfig;
|
|
4
|
-
export type ActionProcessorListResolver = (lambdaRuntimeConfig: QPQAWSLambdaConfig) => ActionProcessorList;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DynamicModuleLoader } from 'quidproquo-actionprocessor-awslambda';
|
|
2
2
|
import { EventBridgeEvent, Context } from 'aws-lambda';
|
|
3
|
-
import { ActionProcessorListResolver } from './
|
|
3
|
+
import { ActionProcessorListResolver } from './actionProcessorListResolver';
|
|
4
4
|
export declare const getEventBridgeEventExecutor: (dynamicModuleLoader: DynamicModuleLoader, getCustomActionProcessors?: ActionProcessorListResolver) => (event: EventBridgeEvent<string, void>, context: Context) => Promise<void>;
|
|
5
5
|
export declare const executeEventBridgeEvent: (event: EventBridgeEvent<string, void>, context: Context) => Promise<void>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { DynamicModuleLoader } from 'quidproquo-actionprocessor-awslambda';
|
|
2
|
+
import { CloudFrontRequestEvent, Context } from 'aws-lambda';
|
|
3
|
+
import { ActionProcessorListResolver } from './actionProcessorListResolver';
|
|
4
|
+
export declare const getOriginRequestEventExecutor: (dynamicModuleLoader: DynamicModuleLoader, getCustomActionProcessors?: ActionProcessorListResolver) => (event: CloudFrontRequestEvent, context: Context) => Promise<any>;
|
|
5
|
+
export declare const executeEventOriginRequest: (event: CloudFrontRequestEvent, context: Context) => Promise<any>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.executeEventOriginRequest = exports.getOriginRequestEventExecutor = void 0;
|
|
16
|
+
const quidproquo_actionprocessor_node_1 = require("quidproquo-actionprocessor-node");
|
|
17
|
+
const quidproquo_actionprocessor_awslambda_1 = require("quidproquo-actionprocessor-awslambda");
|
|
18
|
+
const quidproquo_core_1 = require("quidproquo-core");
|
|
19
|
+
// @ts-ignore - Special webpack loader
|
|
20
|
+
const qpq_dynamic_loader_1 = __importDefault(require("qpq-dynamic-loader!"));
|
|
21
|
+
// @ts-ignore - Special webpack loader
|
|
22
|
+
// import qpqConfig from 'qpq-config-loader!';
|
|
23
|
+
// TODO: Make this a util or something based on server time or something..
|
|
24
|
+
const getDateNow = () => new Date().toISOString();
|
|
25
|
+
const ErrorTypeHttpResponseMap = {
|
|
26
|
+
[quidproquo_core_1.ErrorTypeEnum.NoContent]: 204,
|
|
27
|
+
[quidproquo_core_1.ErrorTypeEnum.BadRequest]: 400,
|
|
28
|
+
[quidproquo_core_1.ErrorTypeEnum.Unauthorized]: 401,
|
|
29
|
+
[quidproquo_core_1.ErrorTypeEnum.PaymentRequired]: 402,
|
|
30
|
+
[quidproquo_core_1.ErrorTypeEnum.Forbidden]: 403,
|
|
31
|
+
[quidproquo_core_1.ErrorTypeEnum.NotFound]: 404,
|
|
32
|
+
[quidproquo_core_1.ErrorTypeEnum.TimeOut]: 408,
|
|
33
|
+
[quidproquo_core_1.ErrorTypeEnum.UnsupportedMediaType]: 415,
|
|
34
|
+
[quidproquo_core_1.ErrorTypeEnum.Invalid]: 422,
|
|
35
|
+
[quidproquo_core_1.ErrorTypeEnum.OutOfResources]: 500,
|
|
36
|
+
[quidproquo_core_1.ErrorTypeEnum.GenericError]: 500,
|
|
37
|
+
[quidproquo_core_1.ErrorTypeEnum.NotImplemented]: 501,
|
|
38
|
+
};
|
|
39
|
+
const getOriginRequestEventExecutor = (dynamicModuleLoader, getCustomActionProcessors = () => ({})) => {
|
|
40
|
+
return (event, context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
41
|
+
console.log('AAAAAAAAAAAAAAAAA');
|
|
42
|
+
// TODO: Make this error safe
|
|
43
|
+
const param = yield (0, quidproquo_actionprocessor_awslambda_1.getParameter)('qpqRuntimeConfig-theconspiracytest-development');
|
|
44
|
+
const lambdaRuntimeConfig = JSON.parse(param);
|
|
45
|
+
// //////////////////////////
|
|
46
|
+
console.log('BBBBBBBBBB');
|
|
47
|
+
// Build a processor for the session and stuff
|
|
48
|
+
// Remove the non route ones ~ let the story execute action add them
|
|
49
|
+
const storyActionProcessor = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, quidproquo_actionprocessor_node_1.coreActionProcessor), quidproquo_actionprocessor_node_1.webserverActionProcessor), (0, quidproquo_actionprocessor_awslambda_1.getCloudFrontOriginRequestEventActionProcessor)(lambdaRuntimeConfig.qpqConfig)), (0, quidproquo_actionprocessor_awslambda_1.getConfigGetSecretActionProcessor)(lambdaRuntimeConfig)), (0, quidproquo_actionprocessor_awslambda_1.getConfigGetParameterActionProcessor)(lambdaRuntimeConfig)), (0, quidproquo_actionprocessor_awslambda_1.getConfigGetParametersActionProcessor)(lambdaRuntimeConfig)), (0, quidproquo_actionprocessor_awslambda_1.getSystemActionProcessor)(dynamicModuleLoader)), (0, quidproquo_actionprocessor_awslambda_1.getFileActionProcessor)(lambdaRuntimeConfig)), getCustomActionProcessors(lambdaRuntimeConfig));
|
|
50
|
+
console.log('CCCCCCCCCCCCCCC');
|
|
51
|
+
const logger = (result) => __awaiter(void 0, void 0, void 0, function* () { });
|
|
52
|
+
// Run the callback
|
|
53
|
+
const resolveStory = (0, quidproquo_core_1.createRuntime)({}, storyActionProcessor, getDateNow, logger, quidproquo_actionprocessor_awslambda_1.awsLambdaUtils.randomGuid);
|
|
54
|
+
console.log('DDDDDDDDDDDD');
|
|
55
|
+
const result = yield resolveStory(quidproquo_core_1.askProcessEvent, [event, context]);
|
|
56
|
+
console.log('EEEEEEEEEEEEEE');
|
|
57
|
+
console.log(JSON.stringify(result));
|
|
58
|
+
// Run the callback
|
|
59
|
+
if (!result.error) {
|
|
60
|
+
return result.result;
|
|
61
|
+
}
|
|
62
|
+
console.log('FFFFFFFFFFFFFFFFFFF');
|
|
63
|
+
const code = ErrorTypeHttpResponseMap[result.error.errorType];
|
|
64
|
+
return {
|
|
65
|
+
statusCode: code || 500,
|
|
66
|
+
statusDescription: result.error.errorType,
|
|
67
|
+
body: JSON.stringify(result.error),
|
|
68
|
+
headers: {},
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
exports.getOriginRequestEventExecutor = getOriginRequestEventExecutor;
|
|
73
|
+
// Default executor
|
|
74
|
+
exports.executeEventOriginRequest = (0, exports.getOriginRequestEventExecutor)(qpq_dynamic_loader_1.default);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DynamicModuleLoader } from 'quidproquo-actionprocessor-awslambda';
|
|
2
|
+
import { CloudFrontRequestEvent, Context } from 'aws-lambda';
|
|
3
|
+
import { ActionProcessorListResolver } from './actionProcessorListResolver';
|
|
4
|
+
export declare const getOriginRequestEventExecutor: (dynamicModuleLoader: DynamicModuleLoader, getCustomActionProcessors?: ActionProcessorListResolver) => (event: CloudFrontRequestEvent, context: Context) => Promise<import("aws-lambda").CloudFrontRequest | {
|
|
5
|
+
status: string;
|
|
6
|
+
statusDescription: string;
|
|
7
|
+
body: any;
|
|
8
|
+
headers: {};
|
|
9
|
+
}>;
|
|
10
|
+
export declare const executeEventOriginRequest: (event: CloudFrontRequestEvent, context: Context) => Promise<import("aws-lambda").CloudFrontRequest | {
|
|
11
|
+
status: string;
|
|
12
|
+
statusDescription: string;
|
|
13
|
+
body: any;
|
|
14
|
+
headers: {};
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.executeEventOriginRequest = exports.getOriginRequestEventExecutor = void 0;
|
|
16
|
+
const quidproquo_actionprocessor_node_1 = require("quidproquo-actionprocessor-node");
|
|
17
|
+
const quidproquo_actionprocessor_awslambda_1 = require("quidproquo-actionprocessor-awslambda");
|
|
18
|
+
const quidproquo_webserver_1 = require("quidproquo-webserver");
|
|
19
|
+
const quidproquo_core_1 = require("quidproquo-core");
|
|
20
|
+
// @ts-ignore - Special webpack loader
|
|
21
|
+
const qpq_dynamic_loader_1 = __importDefault(require("qpq-dynamic-loader!"));
|
|
22
|
+
// @ts-ignore - Special webpack loader
|
|
23
|
+
const qpq_config_loader_1 = __importDefault(require("qpq-config-loader!"));
|
|
24
|
+
// TODO: Make this a util or something based on server time or something..
|
|
25
|
+
const getDateNow = () => new Date().toISOString();
|
|
26
|
+
const getOriginRequestEventExecutor = (dynamicModuleLoader, getCustomActionProcessors = () => ({})) => {
|
|
27
|
+
return (event, context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
28
|
+
// Don't run the lambda if we are not a bot
|
|
29
|
+
if (event.Records[0].cf.request.headers['x-qpq-is-bot'][0].value !== 'true') {
|
|
30
|
+
return event.Records[0].cf.request;
|
|
31
|
+
}
|
|
32
|
+
// TODO: Make this error safe
|
|
33
|
+
const service = quidproquo_core_1.qpqCoreUtils.getAppName(qpq_config_loader_1.default);
|
|
34
|
+
const environment = quidproquo_core_1.qpqCoreUtils.getAppFeature(qpq_config_loader_1.default);
|
|
35
|
+
const param = yield (0, quidproquo_actionprocessor_awslambda_1.getParameter)(`qpqRuntimeConfig-${service}-${environment}`, quidproquo_webserver_1.qpqWebServerUtils.getDeployRegion(qpq_config_loader_1.default));
|
|
36
|
+
const lambdaRuntimeConfig = JSON.parse(param);
|
|
37
|
+
// //////////////////////////
|
|
38
|
+
// Build a processor for the session and stuff
|
|
39
|
+
// Remove the non route ones ~ let the story execute action add them
|
|
40
|
+
const storyActionProcessor = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, quidproquo_actionprocessor_node_1.coreActionProcessor), quidproquo_actionprocessor_node_1.webserverActionProcessor), (0, quidproquo_actionprocessor_awslambda_1.getCloudFrontOriginRequestEventActionProcessor)(lambdaRuntimeConfig.qpqConfig)), (0, quidproquo_actionprocessor_awslambda_1.getConfigGetSecretActionProcessor)(lambdaRuntimeConfig)), (0, quidproquo_actionprocessor_awslambda_1.getConfigGetParameterActionProcessor)(lambdaRuntimeConfig)), (0, quidproquo_actionprocessor_awslambda_1.getConfigGetParametersActionProcessor)(lambdaRuntimeConfig)), (0, quidproquo_actionprocessor_awslambda_1.getSystemActionProcessor)(dynamicModuleLoader)), (0, quidproquo_actionprocessor_awslambda_1.getFileActionProcessor)(lambdaRuntimeConfig)), getCustomActionProcessors(lambdaRuntimeConfig));
|
|
41
|
+
const logger = (result) => __awaiter(void 0, void 0, void 0, function* () { });
|
|
42
|
+
// Run the callback
|
|
43
|
+
const resolveStory = (0, quidproquo_core_1.createRuntime)({}, storyActionProcessor, getDateNow, logger, quidproquo_actionprocessor_awslambda_1.awsLambdaUtils.randomGuid);
|
|
44
|
+
const result = yield resolveStory(quidproquo_core_1.askProcessEvent, [event, context]);
|
|
45
|
+
// Run the callback
|
|
46
|
+
if (!result.error) {
|
|
47
|
+
// TODO: Get typing to work here.
|
|
48
|
+
if (result.result.fallbackToCDN) {
|
|
49
|
+
// to forward the result to the origin, just return the request
|
|
50
|
+
// it has the origin details.
|
|
51
|
+
return event.Records[0].cf.request;
|
|
52
|
+
}
|
|
53
|
+
const headers = result.result.headers || {};
|
|
54
|
+
const responseHeaders = Object.keys(headers).reduce((acc, header) => (Object.assign(Object.assign({}, acc), { [header]: [{ value: headers[header] }] })), {});
|
|
55
|
+
return {
|
|
56
|
+
status: `${result.result.status}`,
|
|
57
|
+
statusDescription: 'OK',
|
|
58
|
+
body: result.result.body,
|
|
59
|
+
headers: responseHeaders,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// CloudFront seems to throw an error when you send back a 404 or something, so we will just hit the normal origin
|
|
63
|
+
return event.Records[0].cf.request;
|
|
64
|
+
// const code = ErrorTypeHttpResponseMap[result.error.errorType];
|
|
65
|
+
// return {
|
|
66
|
+
// statusCode: code || 500,
|
|
67
|
+
// statusDescription: result.error.errorType,
|
|
68
|
+
// body: JSON.stringify(result.error),
|
|
69
|
+
// headers: {},
|
|
70
|
+
// };
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
exports.getOriginRequestEventExecutor = getOriginRequestEventExecutor;
|
|
74
|
+
// Default executor
|
|
75
|
+
exports.executeEventOriginRequest = (0, exports.getOriginRequestEventExecutor)(qpq_dynamic_loader_1.default);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { CloudFrontRequestEvent, Context } from 'aws-lambda';
|
|
2
|
+
export declare const getViewerRequestEventExecutor: () => (event: CloudFrontRequestEvent, context: Context) => Promise<{
|
|
3
|
+
headers: {
|
|
4
|
+
"x-qpq-is-bot": {
|
|
5
|
+
key: string;
|
|
6
|
+
value: string;
|
|
7
|
+
}[];
|
|
8
|
+
};
|
|
9
|
+
body?: {
|
|
10
|
+
action: "read-only" | "replace";
|
|
11
|
+
data: string;
|
|
12
|
+
encoding: "base64" | "text";
|
|
13
|
+
readonly inputTruncated: boolean;
|
|
14
|
+
} | undefined;
|
|
15
|
+
clientIp: string;
|
|
16
|
+
method: string;
|
|
17
|
+
uri: string;
|
|
18
|
+
querystring: string;
|
|
19
|
+
origin?: import("aws-lambda").CloudFrontOrigin | undefined;
|
|
20
|
+
}>;
|
|
21
|
+
export declare const executeEventViewerRequest: (event: CloudFrontRequestEvent, context: Context) => Promise<{
|
|
22
|
+
headers: {
|
|
23
|
+
"x-qpq-is-bot": {
|
|
24
|
+
key: string;
|
|
25
|
+
value: string;
|
|
26
|
+
}[];
|
|
27
|
+
};
|
|
28
|
+
body?: {
|
|
29
|
+
action: "read-only" | "replace";
|
|
30
|
+
data: string;
|
|
31
|
+
encoding: "base64" | "text";
|
|
32
|
+
readonly inputTruncated: boolean;
|
|
33
|
+
} | undefined;
|
|
34
|
+
clientIp: string;
|
|
35
|
+
method: string;
|
|
36
|
+
uri: string;
|
|
37
|
+
querystring: string;
|
|
38
|
+
origin?: import("aws-lambda").CloudFrontOrigin | undefined;
|
|
39
|
+
}>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.executeEventViewerRequest = exports.getViewerRequestEventExecutor = void 0;
|
|
13
|
+
const getViewerRequestEventExecutor = () => {
|
|
14
|
+
return (event, context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
|
+
var _a;
|
|
16
|
+
const request = event.Records[0].cf.request;
|
|
17
|
+
const headers = request.headers;
|
|
18
|
+
const customUserAgentHeaderName = 'x-qpq-is-bot';
|
|
19
|
+
const userAgent = ((_a = headers['user-agent'][0]) === null || _a === void 0 ? void 0 : _a.value) || 'unknown';
|
|
20
|
+
let isBot = userAgent.match(/bot|crawl|spider|slurp|facebot|facebookexternalhit/i);
|
|
21
|
+
return Object.assign(Object.assign({}, request), { headers: Object.assign(Object.assign({}, request.headers), { [customUserAgentHeaderName]: [
|
|
22
|
+
{
|
|
23
|
+
key: customUserAgentHeaderName,
|
|
24
|
+
value: isBot ? 'true' : 'false',
|
|
25
|
+
},
|
|
26
|
+
] }) });
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
exports.getViewerRequestEventExecutor = getViewerRequestEventExecutor;
|
|
30
|
+
// Default executor
|
|
31
|
+
exports.executeEventViewerRequest = (0, exports.getViewerRequestEventExecutor)();
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
interface CloudFrontConfig {
|
|
2
|
+
distributionDomainName: string;
|
|
3
|
+
distributionId: string;
|
|
4
|
+
eventType: string;
|
|
5
|
+
requestId: string;
|
|
6
|
+
}
|
|
7
|
+
interface Body {
|
|
8
|
+
action: string;
|
|
9
|
+
data: string;
|
|
10
|
+
encoding: string;
|
|
11
|
+
inputTruncated: boolean;
|
|
12
|
+
}
|
|
13
|
+
interface KeyValueHeader {
|
|
14
|
+
key: string;
|
|
15
|
+
value: string;
|
|
16
|
+
}
|
|
17
|
+
interface Headers {
|
|
18
|
+
[key: string]: KeyValueHeader[];
|
|
19
|
+
}
|
|
20
|
+
interface CustomHeaders {
|
|
21
|
+
}
|
|
22
|
+
interface S3 {
|
|
23
|
+
authMethod: string;
|
|
24
|
+
customHeaders: CustomHeaders;
|
|
25
|
+
domainName: string;
|
|
26
|
+
path: string;
|
|
27
|
+
region: string;
|
|
28
|
+
}
|
|
29
|
+
interface Origin {
|
|
30
|
+
s3: S3;
|
|
31
|
+
}
|
|
32
|
+
interface CloudFrontOriginRequest {
|
|
33
|
+
body?: Body;
|
|
34
|
+
clientIp: string;
|
|
35
|
+
headers: Headers;
|
|
36
|
+
method: string;
|
|
37
|
+
origin: Origin;
|
|
38
|
+
querystring: string;
|
|
39
|
+
uri: string;
|
|
40
|
+
}
|
|
41
|
+
interface CloudFrontOriginConfigRequest {
|
|
42
|
+
config: CloudFrontConfig;
|
|
43
|
+
request: CloudFrontOriginRequest;
|
|
44
|
+
}
|
|
45
|
+
interface CloudFrontRecord {
|
|
46
|
+
cf: CloudFrontOriginConfigRequest;
|
|
47
|
+
}
|
|
48
|
+
export interface CloudFrontOriginRequestEvent {
|
|
49
|
+
Records: CloudFrontRecord[];
|
|
50
|
+
}
|
|
51
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "quidproquo-deploy-awscdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.44",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
13
13
|
"clean": "npx rimraf lib",
|
|
14
14
|
"build": "",
|
|
15
|
-
"watch": "
|
|
15
|
+
"watch": "tsc -w"
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
@@ -28,7 +28,6 @@ import { qpqWebServerUtils } from 'quidproquo-webserver';
|
|
|
28
28
|
|
|
29
29
|
export interface QPQPrototypeStackProps extends DeploymentSettings {
|
|
30
30
|
account: string;
|
|
31
|
-
region: string;
|
|
32
31
|
|
|
33
32
|
apiBuildPath: string;
|
|
34
33
|
webBuildPath: string;
|
|
@@ -37,6 +36,65 @@ export interface QPQPrototypeStackProps extends DeploymentSettings {
|
|
|
37
36
|
lambdaEventBridgeEventPath?: string;
|
|
38
37
|
}
|
|
39
38
|
|
|
39
|
+
interface OwnedBucket {
|
|
40
|
+
driveName: string;
|
|
41
|
+
bucketName: string;
|
|
42
|
+
bucket: aws_s3.Bucket;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface OwnedSecret {
|
|
46
|
+
secretName: string;
|
|
47
|
+
realName: string;
|
|
48
|
+
secret: aws_secretsmanager.Secret;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface OwnedParameter {
|
|
52
|
+
parameterName: string;
|
|
53
|
+
realName: string;
|
|
54
|
+
parameter: aws_ssm.StringParameter;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface OwnedResourceSettings {
|
|
58
|
+
ownedBuckets: OwnedBucket[];
|
|
59
|
+
ownedSecrets: OwnedSecret[];
|
|
60
|
+
ownedParameters: OwnedParameter[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const grantReadToOwnedResources = (
|
|
64
|
+
ownedResourceSettings: OwnedResourceSettings,
|
|
65
|
+
identity: cdk.aws_iam.IGrantable,
|
|
66
|
+
) => {
|
|
67
|
+
ownedResourceSettings.ownedBuckets.forEach((b) => b.bucket.grantReadWrite(identity));
|
|
68
|
+
ownedResourceSettings.ownedSecrets.forEach((os) => os.secret.grantRead(identity));
|
|
69
|
+
ownedResourceSettings.ownedParameters.forEach((os) => os.parameter.grantRead(identity));
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const getParameterName = (parameterKey: string, service: string, environment: string) =>
|
|
73
|
+
`${parameterKey}-${service}-${environment}`;
|
|
74
|
+
|
|
75
|
+
const createServiceParameter = (
|
|
76
|
+
stack: cdk.Stack,
|
|
77
|
+
id: string,
|
|
78
|
+
service: string,
|
|
79
|
+
environment: string,
|
|
80
|
+
parameterKey: string,
|
|
81
|
+
value: string,
|
|
82
|
+
) => {
|
|
83
|
+
const realParameterName = getParameterName(parameterKey, service, environment);
|
|
84
|
+
return {
|
|
85
|
+
parameterName: parameterKey,
|
|
86
|
+
realName: realParameterName,
|
|
87
|
+
parameter: new aws_ssm.StringParameter(stack, `${id}-parameter-${parameterKey}`, {
|
|
88
|
+
parameterName: realParameterName,
|
|
89
|
+
description: `${environment}-${service}`,
|
|
90
|
+
stringValue: value,
|
|
91
|
+
|
|
92
|
+
// No additional costs ~ 4k max size
|
|
93
|
+
tier: aws_ssm.ParameterTier.STANDARD,
|
|
94
|
+
}),
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
|
|
40
98
|
const createApiDomainName = (stack: cdk.Stack, id: string, stackProps: QPQPrototypeStackProps) => {
|
|
41
99
|
const apexDomain = qpqWebServerUtils.getFeatureDomainName(stackProps.qpqConfig);
|
|
42
100
|
|
|
@@ -74,6 +132,7 @@ const createWebDistribution = (
|
|
|
74
132
|
stack: cdk.Stack,
|
|
75
133
|
id: string,
|
|
76
134
|
stackProps: QPQPrototypeStackProps,
|
|
135
|
+
ownedResourceSettings: OwnedResourceSettings,
|
|
77
136
|
) => {
|
|
78
137
|
const environment = qpqCoreUtils.getAppFeature(stackProps.qpqConfig);
|
|
79
138
|
const apexDomain = qpqWebServerUtils.getFeatureDomainName(stackProps.qpqConfig);
|
|
@@ -127,8 +186,74 @@ const createWebDistribution = (
|
|
|
127
186
|
destinationBucket: staticWebFilesBucket,
|
|
128
187
|
});
|
|
129
188
|
|
|
189
|
+
const cloudFrontBehaviors = qpqWebServerUtils
|
|
190
|
+
.getAllSeo(stackProps.qpqConfig)
|
|
191
|
+
.map((seo, index) => {
|
|
192
|
+
const edgeFunctionVR = new aws_cloudfront.experimental.EdgeFunction(
|
|
193
|
+
stack,
|
|
194
|
+
`${id}-SEO-${index}-${seo.runtime}-VR`,
|
|
195
|
+
{
|
|
196
|
+
functionName: `SEO-VR-${index}-${seo.runtime}-${environment}-${serviceName}`,
|
|
197
|
+
timeout: cdk.Duration.seconds(5),
|
|
198
|
+
runtime: aws_lambda.Runtime.NODEJS_16_X,
|
|
199
|
+
|
|
200
|
+
code: aws_lambda.Code.fromAsset(
|
|
201
|
+
path.join(stackProps.apiBuildPath, 'lambdaEventViewerRequest'),
|
|
202
|
+
),
|
|
203
|
+
handler: 'index.executeEventViewerRequest',
|
|
204
|
+
},
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
const edgeFunctionOR = new aws_cloudfront.experimental.EdgeFunction(
|
|
208
|
+
stack,
|
|
209
|
+
`${id}-SEO-${index}-${seo.runtime}-OR`,
|
|
210
|
+
{
|
|
211
|
+
functionName: `SEO-OR-${index}-${seo.runtime}-${environment}-${serviceName}`,
|
|
212
|
+
timeout: cdk.Duration.seconds(30),
|
|
213
|
+
runtime: aws_lambda.Runtime.NODEJS_16_X,
|
|
214
|
+
|
|
215
|
+
memorySize: 1024,
|
|
216
|
+
|
|
217
|
+
code: aws_lambda.Code.fromAsset(
|
|
218
|
+
path.join(stackProps.apiBuildPath, 'lambdaEventOriginRequest'),
|
|
219
|
+
),
|
|
220
|
+
handler: 'index.executeEventOriginRequest',
|
|
221
|
+
},
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
// We don't need access to anything in the VR
|
|
225
|
+
grantReadToOwnedResources(ownedResourceSettings, edgeFunctionOR);
|
|
226
|
+
|
|
227
|
+
const wildcardPath = seo.path.replaceAll(/{(.+?)}/g, '*');
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
pathPattern: wildcardPath,
|
|
231
|
+
|
|
232
|
+
// Update this to 24 hours
|
|
233
|
+
maxTtl: cdk.Duration.seconds(0),
|
|
234
|
+
minTtl: cdk.Duration.seconds(0),
|
|
235
|
+
defaultTtl: cdk.Duration.seconds(0),
|
|
236
|
+
|
|
237
|
+
lambdaFunctionAssociations: [
|
|
238
|
+
{
|
|
239
|
+
includeBody: true,
|
|
240
|
+
eventType: aws_cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST,
|
|
241
|
+
lambdaFunction: edgeFunctionOR.currentVersion,
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
includeBody: false,
|
|
245
|
+
eventType: aws_cloudfront.LambdaEdgeEventType.VIEWER_REQUEST,
|
|
246
|
+
lambdaFunction: edgeFunctionVR.currentVersion,
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
};
|
|
250
|
+
});
|
|
251
|
+
|
|
130
252
|
// Create a cloud front distribution
|
|
131
253
|
// TODO: use aws_cloudfront.Distribution
|
|
254
|
+
// TODO: Somehow expose query strings: Note ~
|
|
255
|
+
// (Lambda@Edge only) To access the query string in an origin request or origin response function,
|
|
256
|
+
// your cache policy or origin request policy must be set to All for Query strings.
|
|
132
257
|
const distribution = new aws_cloudfront.CloudFrontWebDistribution(stack, 'cf-distribution', {
|
|
133
258
|
originConfigs: [
|
|
134
259
|
{
|
|
@@ -137,16 +262,7 @@ const createWebDistribution = (
|
|
|
137
262
|
originAccessIdentity: websiteOAI,
|
|
138
263
|
},
|
|
139
264
|
behaviors: [
|
|
140
|
-
...
|
|
141
|
-
'/remoteEntry.js',
|
|
142
|
-
'/index.js', // Add this if we need it
|
|
143
|
-
'/index.html', // Add this if we need it
|
|
144
|
-
].map((pp) => ({
|
|
145
|
-
pathPattern: pp,
|
|
146
|
-
maxTtl: cdk.Duration.seconds(0),
|
|
147
|
-
minTtl: cdk.Duration.seconds(0),
|
|
148
|
-
defaultTtl: cdk.Duration.seconds(0),
|
|
149
|
-
})),
|
|
265
|
+
...cloudFrontBehaviors,
|
|
150
266
|
{
|
|
151
267
|
isDefaultBehavior: true,
|
|
152
268
|
},
|
|
@@ -180,7 +296,7 @@ export class QPQPrototypeSingleServiceStack extends Stack {
|
|
|
180
296
|
super(scope, id, {
|
|
181
297
|
env: {
|
|
182
298
|
account: props.account,
|
|
183
|
-
region: props.
|
|
299
|
+
region: qpqWebServerUtils.getDeployRegion(props.qpqConfig),
|
|
184
300
|
},
|
|
185
301
|
});
|
|
186
302
|
|
|
@@ -191,8 +307,6 @@ export class QPQPrototypeSingleServiceStack extends Stack {
|
|
|
191
307
|
|
|
192
308
|
const domainName = createApiDomainName(this, id, props);
|
|
193
309
|
|
|
194
|
-
createWebDistribution(this, `${id}-web-dist`, props);
|
|
195
|
-
|
|
196
310
|
const resourceName = (name: string) => {
|
|
197
311
|
return `${settings.service}-${settings.environment}-${name}`;
|
|
198
312
|
};
|
|
@@ -210,23 +324,20 @@ export class QPQPrototypeSingleServiceStack extends Stack {
|
|
|
210
324
|
};
|
|
211
325
|
});
|
|
212
326
|
|
|
213
|
-
const ownedParameters = qpqCoreUtils
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}),
|
|
226
|
-
};
|
|
227
|
-
});
|
|
327
|
+
const ownedParameters = qpqCoreUtils
|
|
328
|
+
.getOwnedParameters(props.qpqConfig)
|
|
329
|
+
.map((parameter) =>
|
|
330
|
+
createServiceParameter(
|
|
331
|
+
this,
|
|
332
|
+
id,
|
|
333
|
+
settings.service,
|
|
334
|
+
settings.environment,
|
|
335
|
+
parameter.key,
|
|
336
|
+
parameter.value,
|
|
337
|
+
),
|
|
338
|
+
);
|
|
228
339
|
|
|
229
|
-
const
|
|
340
|
+
const ownedBuckets = qpqCoreUtils.getStorageDriveNames(props.qpqConfig).map((driveName) => {
|
|
230
341
|
const bucketName = resourceName(driveName);
|
|
231
342
|
|
|
232
343
|
const bucket = new aws_s3.Bucket(this, bucketName, {
|
|
@@ -258,14 +369,21 @@ export class QPQPrototypeSingleServiceStack extends Stack {
|
|
|
258
369
|
}),
|
|
259
370
|
{},
|
|
260
371
|
),
|
|
261
|
-
parameterNameMap:
|
|
262
|
-
(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
372
|
+
parameterNameMap: {
|
|
373
|
+
...ownedParameters.reduce(
|
|
374
|
+
(acc, os) => ({
|
|
375
|
+
...acc,
|
|
376
|
+
[os.parameterName]: os.realName,
|
|
377
|
+
}),
|
|
378
|
+
{},
|
|
379
|
+
),
|
|
380
|
+
['qpqRuntimeConfig']: getParameterName(
|
|
381
|
+
'qpqRuntimeConfig',
|
|
382
|
+
settings.service,
|
|
383
|
+
settings.environment,
|
|
384
|
+
),
|
|
385
|
+
},
|
|
386
|
+
resourceNameMap: ownedBuckets.reduce(
|
|
269
387
|
(acc, b) => ({
|
|
270
388
|
...acc,
|
|
271
389
|
[b.driveName]: b.bucketName,
|
|
@@ -274,6 +392,31 @@ export class QPQPrototypeSingleServiceStack extends Stack {
|
|
|
274
392
|
),
|
|
275
393
|
};
|
|
276
394
|
|
|
395
|
+
// Build the param that stores the config
|
|
396
|
+
// Note: The mapping was done manually previously inside the value
|
|
397
|
+
ownedParameters.push(
|
|
398
|
+
createServiceParameter(
|
|
399
|
+
this,
|
|
400
|
+
id,
|
|
401
|
+
settings.service,
|
|
402
|
+
settings.environment,
|
|
403
|
+
'qpqRuntimeConfig',
|
|
404
|
+
JSON.stringify(runtimeConfigLambdaConfig),
|
|
405
|
+
),
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
const ownedResourceSettings: OwnedResourceSettings = {
|
|
409
|
+
ownedBuckets,
|
|
410
|
+
ownedParameters,
|
|
411
|
+
ownedSecrets,
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
415
|
+
// Finished building resources, now we can build the lambdas
|
|
416
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
417
|
+
|
|
418
|
+
createWebDistribution(this, `${id}-web-dist`, props, ownedResourceSettings);
|
|
419
|
+
|
|
277
420
|
const lambdaHandler = new aws_lambda.Function(
|
|
278
421
|
this,
|
|
279
422
|
`${settings.environment}-${settings.service}-lambda-rest`,
|
|
@@ -284,8 +427,8 @@ export class QPQPrototypeSingleServiceStack extends Stack {
|
|
|
284
427
|
runtime: aws_lambda.Runtime.NODEJS_16_X,
|
|
285
428
|
memorySize: 1024,
|
|
286
429
|
|
|
287
|
-
code: aws_lambda.Code.fromAsset(props.apiBuildPath),
|
|
288
|
-
handler: '
|
|
430
|
+
code: aws_lambda.Code.fromAsset(path.join(props.apiBuildPath, 'lambdaAPIGatewayEvent')),
|
|
431
|
+
handler: 'index.executeAPIGatewayEvent',
|
|
289
432
|
|
|
290
433
|
environment: {
|
|
291
434
|
TABLES: JSON.stringify([]),
|
|
@@ -295,9 +438,7 @@ export class QPQPrototypeSingleServiceStack extends Stack {
|
|
|
295
438
|
);
|
|
296
439
|
|
|
297
440
|
// Grant access to the lambda
|
|
298
|
-
|
|
299
|
-
ownedSecrets.forEach((os) => os.secret.grantRead(lambdaHandler));
|
|
300
|
-
ownedParameters.forEach((os) => os.parameter.grantRead(lambdaHandler));
|
|
441
|
+
grantReadToOwnedResources(ownedResourceSettings, lambdaHandler);
|
|
301
442
|
|
|
302
443
|
// Create a rest api
|
|
303
444
|
const api = new aws_apigateway.LambdaRestApi(
|
|
@@ -334,8 +475,8 @@ export class QPQPrototypeSingleServiceStack extends Stack {
|
|
|
334
475
|
runtime: aws_lambda.Runtime.NODEJS_16_X,
|
|
335
476
|
memorySize: 1024,
|
|
336
477
|
|
|
337
|
-
code: aws_lambda.Code.fromAsset(props.apiBuildPath),
|
|
338
|
-
handler: '
|
|
478
|
+
code: aws_lambda.Code.fromAsset(path.join(props.apiBuildPath, 'lambdaEventBridgeEvent')),
|
|
479
|
+
handler: 'index.executeEventBridgeEvent',
|
|
339
480
|
|
|
340
481
|
environment: {
|
|
341
482
|
TABLES: JSON.stringify([]),
|
|
@@ -350,9 +491,7 @@ export class QPQPrototypeSingleServiceStack extends Stack {
|
|
|
350
491
|
},
|
|
351
492
|
);
|
|
352
493
|
|
|
353
|
-
|
|
354
|
-
ownedSecrets.forEach((os) => os.secret.grantRead(schedulerFunction));
|
|
355
|
-
ownedParameters.forEach((os) => os.parameter.grantRead(schedulerFunction));
|
|
494
|
+
grantReadToOwnedResources(ownedResourceSettings, schedulerFunction);
|
|
356
495
|
|
|
357
496
|
// EventBridge rule which runs every five minutes
|
|
358
497
|
const cronRule = new aws_events.Rule(this, `${id}-se-cronrule-${index}`, {
|
|
@@ -17,7 +17,8 @@ import { createRuntime, askProcessEvent, ErrorTypeEnum } from 'quidproquo-core';
|
|
|
17
17
|
|
|
18
18
|
import { APIGatewayEvent, Context } from 'aws-lambda';
|
|
19
19
|
|
|
20
|
-
import { lambdaRuntimeConfig
|
|
20
|
+
import { lambdaRuntimeConfig } from './lambdaConfig';
|
|
21
|
+
import { ActionProcessorListResolver } from './actionProcessorListResolver';
|
|
21
22
|
|
|
22
23
|
// @ts-ignore - Special webpack loader
|
|
23
24
|
import qpqDynamicModuleLoader from 'qpq-dynamic-loader!';
|
|
@@ -94,7 +95,6 @@ export const getAPIGatewayEventExecutor = (
|
|
|
94
95
|
};
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
console.log(JSON.stringify(result));
|
|
98
98
|
const code = ErrorTypeHttpResponseMap[result.error.errorType];
|
|
99
99
|
return {
|
|
100
100
|
statusCode: code || 500,
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import { ActionProcessorList } from 'quidproquo-core';
|
|
2
1
|
import { QPQAWSLambdaConfig } from 'quidproquo-actionprocessor-awslambda';
|
|
3
2
|
|
|
4
3
|
export const lambdaRuntimeConfig = JSON.parse(
|
|
5
4
|
process.env.lambdaRuntimeConfig || '{}',
|
|
6
5
|
) as QPQAWSLambdaConfig;
|
|
7
|
-
|
|
8
|
-
export type ActionProcessorListResolver = (
|
|
9
|
-
lambdaRuntimeConfig: QPQAWSLambdaConfig,
|
|
10
|
-
) => ActionProcessorList;
|
|
@@ -14,7 +14,8 @@ import { createRuntime, askProcessEvent } from 'quidproquo-core';
|
|
|
14
14
|
|
|
15
15
|
import { EventBridgeEvent, Context } from 'aws-lambda';
|
|
16
16
|
|
|
17
|
-
import { lambdaRuntimeConfig
|
|
17
|
+
import { lambdaRuntimeConfig } from './lambdaConfig';
|
|
18
|
+
import { ActionProcessorListResolver } from './actionProcessorListResolver';
|
|
18
19
|
|
|
19
20
|
// @ts-ignore - Special webpack loader
|
|
20
21
|
import qpqDynamicModuleLoader from 'qpq-dynamic-loader!';
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { coreActionProcessor, webserverActionProcessor } from 'quidproquo-actionprocessor-node';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
getCloudFrontOriginRequestEventActionProcessor,
|
|
5
|
+
getSystemActionProcessor,
|
|
6
|
+
getFileActionProcessor,
|
|
7
|
+
getConfigGetSecretActionProcessor,
|
|
8
|
+
getConfigGetParameterActionProcessor,
|
|
9
|
+
getConfigGetParametersActionProcessor,
|
|
10
|
+
awsLambdaUtils,
|
|
11
|
+
QPQAWSLambdaConfig,
|
|
12
|
+
DynamicModuleLoader,
|
|
13
|
+
getParameter,
|
|
14
|
+
} from 'quidproquo-actionprocessor-awslambda';
|
|
15
|
+
|
|
16
|
+
import { qpqWebServerUtils } from 'quidproquo-webserver';
|
|
17
|
+
|
|
18
|
+
import { createRuntime, askProcessEvent, ErrorTypeEnum, qpqCoreUtils } from 'quidproquo-core';
|
|
19
|
+
|
|
20
|
+
import { CloudFrontRequestEvent, Context } from 'aws-lambda';
|
|
21
|
+
|
|
22
|
+
import { ActionProcessorListResolver } from './actionProcessorListResolver';
|
|
23
|
+
|
|
24
|
+
// @ts-ignore - Special webpack loader
|
|
25
|
+
import qpqDynamicModuleLoader from 'qpq-dynamic-loader!';
|
|
26
|
+
|
|
27
|
+
// @ts-ignore - Special webpack loader
|
|
28
|
+
import qpqConfig from 'qpq-config-loader!';
|
|
29
|
+
|
|
30
|
+
// TODO: Make this a util or something based on server time or something..
|
|
31
|
+
const getDateNow = () => new Date().toISOString();
|
|
32
|
+
|
|
33
|
+
export const getOriginRequestEventExecutor = (
|
|
34
|
+
dynamicModuleLoader: DynamicModuleLoader,
|
|
35
|
+
getCustomActionProcessors: ActionProcessorListResolver = () => ({}),
|
|
36
|
+
) => {
|
|
37
|
+
return async (event: CloudFrontRequestEvent, context: Context) => {
|
|
38
|
+
// Don't run the lambda if we are not a bot
|
|
39
|
+
if (event.Records[0].cf.request.headers['x-qpq-is-bot'][0].value !== 'true') {
|
|
40
|
+
return event.Records[0].cf.request;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// TODO: Make this error safe
|
|
44
|
+
const service = qpqCoreUtils.getAppName(qpqConfig);
|
|
45
|
+
const environment = qpqCoreUtils.getAppFeature(qpqConfig);
|
|
46
|
+
const param = await getParameter(
|
|
47
|
+
`qpqRuntimeConfig-${service}-${environment}`,
|
|
48
|
+
qpqWebServerUtils.getDeployRegion(qpqConfig),
|
|
49
|
+
);
|
|
50
|
+
const lambdaRuntimeConfig: QPQAWSLambdaConfig = JSON.parse(param);
|
|
51
|
+
// //////////////////////////
|
|
52
|
+
|
|
53
|
+
// Build a processor for the session and stuff
|
|
54
|
+
// Remove the non route ones ~ let the story execute action add them
|
|
55
|
+
const storyActionProcessor = {
|
|
56
|
+
...coreActionProcessor,
|
|
57
|
+
...webserverActionProcessor,
|
|
58
|
+
|
|
59
|
+
...getCloudFrontOriginRequestEventActionProcessor(lambdaRuntimeConfig.qpqConfig),
|
|
60
|
+
...getConfigGetSecretActionProcessor(lambdaRuntimeConfig),
|
|
61
|
+
...getConfigGetParameterActionProcessor(lambdaRuntimeConfig),
|
|
62
|
+
...getConfigGetParametersActionProcessor(lambdaRuntimeConfig),
|
|
63
|
+
...getSystemActionProcessor(dynamicModuleLoader),
|
|
64
|
+
...getFileActionProcessor(lambdaRuntimeConfig),
|
|
65
|
+
|
|
66
|
+
...getCustomActionProcessors(lambdaRuntimeConfig),
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const logger = async (result: any) => {};
|
|
70
|
+
|
|
71
|
+
// Run the callback
|
|
72
|
+
|
|
73
|
+
const resolveStory = createRuntime(
|
|
74
|
+
{},
|
|
75
|
+
storyActionProcessor,
|
|
76
|
+
getDateNow,
|
|
77
|
+
logger,
|
|
78
|
+
awsLambdaUtils.randomGuid,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const result = await resolveStory(askProcessEvent, [event, context]);
|
|
82
|
+
|
|
83
|
+
// Run the callback
|
|
84
|
+
if (!result.error) {
|
|
85
|
+
// TODO: Get typing to work here.
|
|
86
|
+
if (result.result.fallbackToCDN) {
|
|
87
|
+
// to forward the result to the origin, just return the request
|
|
88
|
+
// it has the origin details.
|
|
89
|
+
return event.Records[0].cf.request;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const headers = result.result.headers || {};
|
|
93
|
+
const responseHeaders = Object.keys(headers).reduce(
|
|
94
|
+
(acc, header) => ({ ...acc, [header]: [{ value: headers[header] }] }),
|
|
95
|
+
{},
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
status: `${result.result.status}`,
|
|
100
|
+
statusDescription: 'OK',
|
|
101
|
+
body: result.result.body,
|
|
102
|
+
headers: responseHeaders,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// CloudFront seems to throw an error when you send back a 404 or something, so we will just hit the normal origin
|
|
107
|
+
return event.Records[0].cf.request;
|
|
108
|
+
|
|
109
|
+
// const code = ErrorTypeHttpResponseMap[result.error.errorType];
|
|
110
|
+
// return {
|
|
111
|
+
// statusCode: code || 500,
|
|
112
|
+
// statusDescription: result.error.errorType,
|
|
113
|
+
// body: JSON.stringify(result.error),
|
|
114
|
+
// headers: {},
|
|
115
|
+
// };
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// Default executor
|
|
120
|
+
export const executeEventOriginRequest = getOriginRequestEventExecutor(qpqDynamicModuleLoader);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { CloudFrontRequestEvent, Context } from 'aws-lambda';
|
|
2
|
+
|
|
3
|
+
export const getViewerRequestEventExecutor = () => {
|
|
4
|
+
return async (event: CloudFrontRequestEvent, context: Context) => {
|
|
5
|
+
const request = event.Records[0].cf.request;
|
|
6
|
+
const headers = request.headers;
|
|
7
|
+
const customUserAgentHeaderName = 'x-qpq-is-bot';
|
|
8
|
+
const userAgent = headers['user-agent'][0]?.value || 'unknown';
|
|
9
|
+
|
|
10
|
+
let isBot = userAgent.match(/bot|crawl|spider|slurp|facebot|facebookexternalhit/i);
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
...request,
|
|
14
|
+
headers: {
|
|
15
|
+
...request.headers,
|
|
16
|
+
[customUserAgentHeaderName]: [
|
|
17
|
+
{
|
|
18
|
+
key: customUserAgentHeaderName,
|
|
19
|
+
value: isBot ? 'true' : 'false',
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Default executor
|
|
28
|
+
export const executeEventViewerRequest = getViewerRequestEventExecutor();
|