@kensio/yulin 1.21.9 → 1.21.11
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/dist/serve/payload-2/sim-payload-2-endpoint.d.ts +9 -0
- package/dist/serve/payload-2/sim-payload-2-request-context.js +1 -1
- package/dist/service/apigatewayv2/api/sim-http-api-lambda-proxy.factory.d.ts +6 -0
- package/dist/service/apigatewayv2/api/sim-http-api-lambda-proxy.factory.js +2 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-format.d.ts +8 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-format.js +36 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-request.d.ts +53 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-request.js +1 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-settings.d.ts +26 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-settings.js +44 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-settings.type.d.ts +21 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-settings.type.js +1 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-stream-name.d.ts +13 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-stream-name.js +23 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-variables.d.ts +17 -0
- package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-variables.js +86 -0
- package/dist/service/apigatewayv2/api/stage/sim-http-api-stage.d.ts +9 -0
- package/dist/service/apigatewayv2/api/stage/sim-http-api-stage.js +9 -0
- package/dist/service/apigatewayv2/cfn/stage/sim-cfn-http-api-access-log-settings-properties.d.ts +24 -0
- package/dist/service/apigatewayv2/cfn/stage/sim-cfn-http-api-access-log-settings-properties.js +30 -0
- package/dist/service/apigatewayv2/cfn/stage/sim-cfn-http-api-stage-properties.d.ts +1 -0
- package/dist/service/apigatewayv2/cfn/stage/sim-cfn-http-api-stage-properties.js +10 -4
- package/dist/service/apigatewayv2/command/stage/sim-http-api-access-log-settings-input.d.ts +15 -0
- package/dist/service/apigatewayv2/command/stage/sim-http-api-access-log-settings-input.js +33 -0
- package/dist/service/apigatewayv2/command/stage/sim-http-api-stage-commands.js +4 -0
- package/dist/service/apigatewayv2/command/stage/stage.command.d.ts +2 -0
- package/dist/service/apigatewayv2/serve/auth/sim-http-api-route-authorize-input.d.ts +6 -0
- package/dist/service/apigatewayv2/serve/sim-api-gateway-v2-controller.d.ts +13 -15
- package/dist/service/apigatewayv2/serve/sim-api-gateway-v2-controller.js +26 -60
- package/dist/service/apigatewayv2/serve/sim-http-api-access-log-record.d.ts +31 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-access-log-record.js +88 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-access-log.d.ts +43 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-access-log.js +72 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-endpoint.js +1 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-integration-input.d.ts +22 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-integration-input.js +1 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-integration-invocation.d.ts +5 -22
- package/dist/service/apigatewayv2/serve/sim-http-api-integration-invocation.js +17 -20
- package/dist/service/apigatewayv2/serve/sim-http-api-integration-outcome.d.ts +27 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-integration-outcome.js +13 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-may-invoke.d.ts +19 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-may-invoke.js +19 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-serve-pipeline.d.ts +27 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-serve-pipeline.js +75 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-served.d.ts +22 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-served.js +1 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-serving.d.ts +12 -0
- package/dist/service/apigatewayv2/serve/sim-http-api-serving.js +1 -0
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.d.ts +1 -1
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.js +4 -3
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-names.d.ts +30 -0
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-names.js +91 -0
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.d.ts +7 -12
- package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.js +12 -92
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.js +1 -0
- package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-refusals.js +0 -5
- package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.js +1 -1
- package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-polling.js +1 -1
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-bisect.d.ts +53 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-bisect.js +79 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress-state.d.ts +2 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress-state.js +3 -0
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress.d.ts +14 -1
- package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress.js +24 -2
- package/dist/service/lambda/event-source/sim-lambda-event-source-retry-limits.d.ts +8 -7
- package/dist/service/lambda/event-source/sim-lambda-event-source-retry-limits.js +6 -3
- package/dist/service/lambda/event-source/sim-lambda-stream-retry-limits.d.ts +15 -7
- package/dist/service/lambda/event-source/sim-lambda-stream-retry-limits.js +15 -7
- package/dist/service/logs/group/sim-logs-arn.d.ts +15 -0
- package/dist/service/logs/group/sim-logs-arn.js +33 -0
- package/docs/services/apigatewayv2/README.md +162 -6
- package/docs/services/lambda/README.md +54 -7
- package/package.json +1 -1
|
@@ -29,6 +29,15 @@ export interface SimPayload2Endpoint {
|
|
|
29
29
|
readonly pathParameters?: Record<string, string> | undefined;
|
|
30
30
|
/** The stage's variables, if it has any. */
|
|
31
31
|
readonly stageVariables?: Record<string, string> | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* The id the endpoint assigned to this request, where the endpoint assigns
|
|
34
|
+
* one before building the event.
|
|
35
|
+
*
|
|
36
|
+
* An HTTP API settles it up front so that the request's access log line, its
|
|
37
|
+
* authorizer event and its integration event all name the same request.
|
|
38
|
+
* Absent for an endpoint that leaves the event builder to issue one.
|
|
39
|
+
*/
|
|
40
|
+
readonly requestId?: string | undefined;
|
|
32
41
|
}
|
|
33
42
|
/**
|
|
34
43
|
* The path an event reports for one request to an endpoint.
|
|
@@ -31,7 +31,7 @@ export class SimPayload2RequestContextBuilder {
|
|
|
31
31
|
sourceIp: simAwsProxiedSourceIp,
|
|
32
32
|
userAgent: request.headers.get("user-agent") ?? "",
|
|
33
33
|
},
|
|
34
|
-
requestId: randomUUID(),
|
|
34
|
+
requestId: endpoint.requestId ?? randomUUID(),
|
|
35
35
|
routeKey: endpoint.routeKey,
|
|
36
36
|
stage: endpoint.stage,
|
|
37
37
|
time: simProxyEventTime(at),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AsyncMappedFactory } from "@kensio/part-factory";
|
|
2
2
|
import type { SimPayload2Event } from "../../../serve/payload-2/sim-payload-2-event.type.js";
|
|
3
3
|
import type { SimAws } from "../../aws/sim-aws.js";
|
|
4
|
+
import type { SimHttpApiAccessLogSettingsInput } from "./stage/access-log/sim-http-api-access-log-settings.type.js";
|
|
4
5
|
import type { SimHttpApiRouteSettings, SimHttpApiRouteSettingsMap } from "./stage/settings/sim-http-api-route-settings.type.js";
|
|
5
6
|
import type { SimHttpApi } from "./sim-http-api.js";
|
|
6
7
|
import { type SimHttpApiProxyAuthorizer } from "./sim-http-api-proxy-authorization.js";
|
|
@@ -47,6 +48,11 @@ export interface SimHttpApiLambdaProxyInput {
|
|
|
47
48
|
readonly defaultRouteSettings: SimHttpApiRouteSettings | undefined;
|
|
48
49
|
/** The throttles those stages apply to the route keys they name. */
|
|
49
50
|
readonly routeSettings: SimHttpApiRouteSettingsMap | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Where those stages write an access log line per request, or undefined for
|
|
53
|
+
* stages that log nothing.
|
|
54
|
+
*/
|
|
55
|
+
readonly accessLogSettings: SimHttpApiAccessLogSettingsInput | undefined;
|
|
50
56
|
/**
|
|
51
57
|
* Whether the function grants the API permission to invoke it, which it
|
|
52
58
|
* needs before any route serves anything.
|
|
@@ -42,6 +42,7 @@ export const simHttpApiLambdaProxyFactory = new AsyncMappedFactory(() => ({
|
|
|
42
42
|
stageVariables: {},
|
|
43
43
|
defaultRouteSettings: undefined,
|
|
44
44
|
routeSettings: undefined,
|
|
45
|
+
accessLogSettings: undefined,
|
|
45
46
|
invokePermission: true,
|
|
46
47
|
}), async (input, simAws) => {
|
|
47
48
|
const simLambda = simAws.account(input.functionAccountId).lambda();
|
|
@@ -107,6 +108,7 @@ export const simHttpApiLambdaProxyFactory = new AsyncMappedFactory(() => ({
|
|
|
107
108
|
StageVariables: input.stageVariables,
|
|
108
109
|
DefaultRouteSettings: input.defaultRouteSettings,
|
|
109
110
|
RouteSettings: input.routeSettings,
|
|
111
|
+
AccessLogSettings: input.accessLogSettings,
|
|
110
112
|
},
|
|
111
113
|
})));
|
|
112
114
|
// An id CreateApi allocated is an API the store holds, so this is only
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Substitute a stage's access log format into the line one request writes.
|
|
3
|
+
*
|
|
4
|
+
* Everything outside a `$context` reference is copied through, which is what
|
|
5
|
+
* carries the punctuation of a JSON format string into the log group. A
|
|
6
|
+
* reference this simulation has no value for renders as a dash.
|
|
7
|
+
*/
|
|
8
|
+
export declare function simHttpApiAccessLogLine(format: string, variables: ReadonlyMap<string, string>): string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a variable with no value renders as.
|
|
3
|
+
*
|
|
4
|
+
* Real API Gateway writes a single dash where a `$context` variable has
|
|
5
|
+
* nothing behind it, such as `$context.integrationStatus` on a request no
|
|
6
|
+
* integration ran for. AWS publishes the variables and leaves this rendering
|
|
7
|
+
* undocumented, so it is what the service was observed to do.
|
|
8
|
+
*/
|
|
9
|
+
const noValue = "-";
|
|
10
|
+
/**
|
|
11
|
+
* A `$context` reference, which is the name after the prefix and may carry
|
|
12
|
+
* dots of its own, as `$context.identity.sourceIp` does.
|
|
13
|
+
*
|
|
14
|
+
* The name is matched as one run of word characters and dots. Written as a
|
|
15
|
+
* repeated group it would nest two quantifiers, which is a shape a scanner
|
|
16
|
+
* flags however the input is bounded, and this matches the same names.
|
|
17
|
+
*/
|
|
18
|
+
const contextReference = /\$context\.[A-Za-z0-9_.]+/g;
|
|
19
|
+
/**
|
|
20
|
+
* Substitute a stage's access log format into the line one request writes.
|
|
21
|
+
*
|
|
22
|
+
* Everything outside a `$context` reference is copied through, which is what
|
|
23
|
+
* carries the punctuation of a JSON format string into the log group. A
|
|
24
|
+
* reference this simulation has no value for renders as a dash.
|
|
25
|
+
*/
|
|
26
|
+
export function simHttpApiAccessLogLine(format, variables) {
|
|
27
|
+
return format.replaceAll(contextReference, (reference) => {
|
|
28
|
+
// A trailing dot belongs to the text around the reference rather than to
|
|
29
|
+
// the name, as in a format ending one variable with a full stop. It is put
|
|
30
|
+
// back after the value, so the punctuation survives the substitution.
|
|
31
|
+
const written = reference.slice("$context.".length);
|
|
32
|
+
const name = written.replace(/\.+$/, "");
|
|
33
|
+
const punctuation = written.slice(name.length);
|
|
34
|
+
return (variables.get(name) ?? noValue) + punctuation;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { SimPayload2JwtAuthorizer, SimPayload2LambdaAuthorizer } from "../../../../../serve/payload-2/sim-payload-2-event.type.js";
|
|
2
|
+
/**
|
|
3
|
+
* Everything one served request contributes to its access log line.
|
|
4
|
+
*
|
|
5
|
+
* A request refused before an integration ran fills in what it knows and
|
|
6
|
+
* leaves the rest out. That is the case the access log exists for: a Lambda
|
|
7
|
+
* authorizer denial, an absent identity source and a throttled request each
|
|
8
|
+
* produce a line describing a request no handler ever saw.
|
|
9
|
+
*/
|
|
10
|
+
export interface SimHttpApiAccessLogRequest {
|
|
11
|
+
readonly requestId: string;
|
|
12
|
+
/** The simulated instant the request arrived. */
|
|
13
|
+
readonly at: Date;
|
|
14
|
+
readonly accountId: string;
|
|
15
|
+
readonly apiId: string;
|
|
16
|
+
readonly domainName: string;
|
|
17
|
+
readonly domainPrefix: string;
|
|
18
|
+
readonly stage: string;
|
|
19
|
+
readonly routeKey: string;
|
|
20
|
+
readonly method: string;
|
|
21
|
+
readonly path: string;
|
|
22
|
+
readonly protocol: string;
|
|
23
|
+
readonly sourceIp: string;
|
|
24
|
+
readonly userAgent: string;
|
|
25
|
+
readonly status: number;
|
|
26
|
+
readonly responseLength: number;
|
|
27
|
+
/** Milliseconds of simulated time the whole request took. */
|
|
28
|
+
readonly responseLatency: number;
|
|
29
|
+
/**
|
|
30
|
+
* The status the integrated function's own code returned, which is what
|
|
31
|
+
* `$context.integration.status` reports. Absent where no integration ran.
|
|
32
|
+
*/
|
|
33
|
+
readonly integrationStatus?: number | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* The status Lambda answered the invocation with, which is what
|
|
36
|
+
* `$context.integrationStatus` reports for a Lambda proxy integration. It is
|
|
37
|
+
* 200 for an invocation that reached the handler, whatever the handler then
|
|
38
|
+
* returned.
|
|
39
|
+
*/
|
|
40
|
+
readonly lambdaInvokeStatus?: number | undefined;
|
|
41
|
+
readonly integrationLatency?: number | undefined;
|
|
42
|
+
readonly integrationErrorMessage?: string | undefined;
|
|
43
|
+
/** The message an authorizer refusal leaves behind, where it left one. */
|
|
44
|
+
readonly authorizerError?: string | undefined;
|
|
45
|
+
/** The message the endpoint answered with, such as `Forbidden`. */
|
|
46
|
+
readonly errorMessage?: string | undefined;
|
|
47
|
+
/** The base path an API mapping matched, for a custom domain request. */
|
|
48
|
+
readonly basePathMatched?: string | undefined;
|
|
49
|
+
/** What a `JWT` route's authorizer accepted, where one did. */
|
|
50
|
+
readonly jwt?: SimPayload2JwtAuthorizer | undefined;
|
|
51
|
+
/** What a `CUSTOM` route's Lambda authorizer passed on, where one did. */
|
|
52
|
+
readonly lambda?: SimPayload2LambdaAuthorizer | null | undefined;
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SimHttpApiAccessLogSettingsView } from "./sim-http-api-access-log-settings.type.js";
|
|
2
|
+
/**
|
|
3
|
+
* Where one stage writes its access log, and the line it writes there.
|
|
4
|
+
*
|
|
5
|
+
* The destination is held as the ARN the stage was created with and as the
|
|
6
|
+
* account, region and group that ARN resolves to. A log group in another
|
|
7
|
+
* Account is written to in that Account, the way an integration invokes the
|
|
8
|
+
* function its own URI names.
|
|
9
|
+
*/
|
|
10
|
+
export declare class SimHttpApiAccessLogSettings {
|
|
11
|
+
readonly destinationArn: string;
|
|
12
|
+
readonly format: string;
|
|
13
|
+
readonly accountId: string;
|
|
14
|
+
readonly regionName: string;
|
|
15
|
+
readonly logGroupName: string;
|
|
16
|
+
private constructor();
|
|
17
|
+
/**
|
|
18
|
+
* Read settings from a destination ARN and a format, or answer with nothing
|
|
19
|
+
* where the ARN names no log group.
|
|
20
|
+
*/
|
|
21
|
+
static from(destinationArn: string, format: string): SimHttpApiAccessLogSettings | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* What CreateStage and GetStages report of these settings.
|
|
24
|
+
*/
|
|
25
|
+
view(): SimHttpApiAccessLogSettingsView;
|
|
26
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { simLogsParsedLogGroupArn } from "../../../../logs/group/sim-logs-arn.js";
|
|
2
|
+
/**
|
|
3
|
+
* Where one stage writes its access log, and the line it writes there.
|
|
4
|
+
*
|
|
5
|
+
* The destination is held as the ARN the stage was created with and as the
|
|
6
|
+
* account, region and group that ARN resolves to. A log group in another
|
|
7
|
+
* Account is written to in that Account, the way an integration invokes the
|
|
8
|
+
* function its own URI names.
|
|
9
|
+
*/
|
|
10
|
+
export class SimHttpApiAccessLogSettings {
|
|
11
|
+
destinationArn;
|
|
12
|
+
format;
|
|
13
|
+
accountId;
|
|
14
|
+
regionName;
|
|
15
|
+
logGroupName;
|
|
16
|
+
constructor(properties) {
|
|
17
|
+
this.destinationArn = properties.destinationArn;
|
|
18
|
+
this.format = properties.format;
|
|
19
|
+
this.accountId = properties.accountId;
|
|
20
|
+
this.regionName = properties.regionName;
|
|
21
|
+
this.logGroupName = properties.logGroupName;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read settings from a destination ARN and a format, or answer with nothing
|
|
25
|
+
* where the ARN names no log group.
|
|
26
|
+
*/
|
|
27
|
+
static from(destinationArn, format) {
|
|
28
|
+
const parsed = simLogsParsedLogGroupArn(destinationArn);
|
|
29
|
+
if (parsed === undefined) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
return new SimHttpApiAccessLogSettings({
|
|
33
|
+
destinationArn,
|
|
34
|
+
format,
|
|
35
|
+
...parsed,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* What CreateStage and GetStages report of these settings.
|
|
40
|
+
*/
|
|
41
|
+
view() {
|
|
42
|
+
return { DestinationArn: this.destinationArn, Format: this.format };
|
|
43
|
+
}
|
|
44
|
+
}
|
package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-settings.type.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `AccessLogSettings` a stage is created with.
|
|
3
|
+
*
|
|
4
|
+
* `DestinationArn` names a CloudWatch Logs log group. HTTP APIs accept no
|
|
5
|
+
* other destination, and a Kinesis Data Firehose delivery stream is a REST API
|
|
6
|
+
* option that this shape leaves out.
|
|
7
|
+
*
|
|
8
|
+
* `Format` is the line written per request, with `$context` variables
|
|
9
|
+
* substituted from the request that produced it.
|
|
10
|
+
*/
|
|
11
|
+
export interface SimHttpApiAccessLogSettingsInput {
|
|
12
|
+
readonly DestinationArn?: string | undefined;
|
|
13
|
+
readonly Format?: string | undefined;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* What a stage reports of the access log settings it was created with.
|
|
17
|
+
*/
|
|
18
|
+
export interface SimHttpApiAccessLogSettingsView {
|
|
19
|
+
DestinationArn: string;
|
|
20
|
+
Format: string;
|
|
21
|
+
}
|
package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-settings.type.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/service/apigatewayv2/api/stage/access-log/sim-http-api-access-log-stream-name.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SimClock } from "../../../../../util/clock/sim-clock.js";
|
|
2
|
+
/**
|
|
3
|
+
* The stream a stage's access log events are written to.
|
|
4
|
+
*
|
|
5
|
+
* Real API Gateway rolls access log streams over time and appends an
|
|
6
|
+
* identifier this simulation has no counterpart for. The hour is what decides
|
|
7
|
+
* the stream here, dated from the simulation's clock, so a test that froze
|
|
8
|
+
* time gets one stream and a predictable name for it. The shape is chosen for
|
|
9
|
+
* the simulation rather than copied from an observed account, and a test
|
|
10
|
+
* reading its lines back should filter the log group rather than name the
|
|
11
|
+
* stream.
|
|
12
|
+
*/
|
|
13
|
+
export declare function simHttpApiAccessLogStreamName(clock: SimClock): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function twoDigits(value) {
|
|
2
|
+
return String(value).padStart(2, "0");
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* The stream a stage's access log events are written to.
|
|
6
|
+
*
|
|
7
|
+
* Real API Gateway rolls access log streams over time and appends an
|
|
8
|
+
* identifier this simulation has no counterpart for. The hour is what decides
|
|
9
|
+
* the stream here, dated from the simulation's clock, so a test that froze
|
|
10
|
+
* time gets one stream and a predictable name for it. The shape is chosen for
|
|
11
|
+
* the simulation rather than copied from an observed account, and a test
|
|
12
|
+
* reading its lines back should filter the log group rather than name the
|
|
13
|
+
* stream.
|
|
14
|
+
*/
|
|
15
|
+
export function simHttpApiAccessLogStreamName(clock) {
|
|
16
|
+
const at = clock.now();
|
|
17
|
+
return [
|
|
18
|
+
String(at.getUTCFullYear()),
|
|
19
|
+
twoDigits(at.getUTCMonth() + 1),
|
|
20
|
+
twoDigits(at.getUTCDate()),
|
|
21
|
+
twoDigits(at.getUTCHours()),
|
|
22
|
+
].join("-");
|
|
23
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SimHttpApiAccessLogRequest } from "./sim-http-api-access-log-request.js";
|
|
2
|
+
/**
|
|
3
|
+
* The `$context` variables one request answers, keyed by the name that follows
|
|
4
|
+
* `$context.`.
|
|
5
|
+
*
|
|
6
|
+
* A variable this simulation has no value for is left out of the map. The
|
|
7
|
+
* substitution writes `-` for it, which is what real API Gateway writes for a
|
|
8
|
+
* variable with no value. That rendering is what the service was observed to
|
|
9
|
+
* do rather than something AWS publishes.
|
|
10
|
+
*
|
|
11
|
+
* `$context.extendedRequestId` and `$context.integration.latency` are
|
|
12
|
+
* documented as equivalents of the flat names, and carry the same values here.
|
|
13
|
+
* `$context.integrationStatus` is the status Lambda answered the invocation
|
|
14
|
+
* with, and `$context.integration.status` the one the handler's own code
|
|
15
|
+
* returned, which is the distinction AWS draws between the two.
|
|
16
|
+
*/
|
|
17
|
+
export declare function simHttpApiAccessLogVariables(request: SimHttpApiAccessLogRequest): ReadonlyMap<string, string>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { simProxyEventTime } from "../../../../../serve/proxy/sim-proxy-event-time.js";
|
|
2
|
+
function numberOrUndefined(value) {
|
|
3
|
+
return value === undefined ? undefined : String(value);
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* The `$context` variables one request answers, keyed by the name that follows
|
|
7
|
+
* `$context.`.
|
|
8
|
+
*
|
|
9
|
+
* A variable this simulation has no value for is left out of the map. The
|
|
10
|
+
* substitution writes `-` for it, which is what real API Gateway writes for a
|
|
11
|
+
* variable with no value. That rendering is what the service was observed to
|
|
12
|
+
* do rather than something AWS publishes.
|
|
13
|
+
*
|
|
14
|
+
* `$context.extendedRequestId` and `$context.integration.latency` are
|
|
15
|
+
* documented as equivalents of the flat names, and carry the same values here.
|
|
16
|
+
* `$context.integrationStatus` is the status Lambda answered the invocation
|
|
17
|
+
* with, and `$context.integration.status` the one the handler's own code
|
|
18
|
+
* returned, which is the distinction AWS draws between the two.
|
|
19
|
+
*/
|
|
20
|
+
export function simHttpApiAccessLogVariables(request) {
|
|
21
|
+
const variables = new Map([
|
|
22
|
+
["accountId", request.accountId],
|
|
23
|
+
["apiId", request.apiId],
|
|
24
|
+
["domainName", request.domainName],
|
|
25
|
+
["domainPrefix", request.domainPrefix],
|
|
26
|
+
["stage", request.stage],
|
|
27
|
+
["routeKey", request.routeKey],
|
|
28
|
+
["httpMethod", request.method],
|
|
29
|
+
["path", request.path],
|
|
30
|
+
["protocol", request.protocol],
|
|
31
|
+
["requestId", request.requestId],
|
|
32
|
+
["extendedRequestId", request.requestId],
|
|
33
|
+
["requestTime", simProxyEventTime(request.at)],
|
|
34
|
+
["requestTimeEpoch", String(request.at.getTime())],
|
|
35
|
+
["status", String(request.status)],
|
|
36
|
+
["responseLength", String(request.responseLength)],
|
|
37
|
+
["responseLatency", String(request.responseLatency)],
|
|
38
|
+
["identity.sourceIp", request.sourceIp],
|
|
39
|
+
["identity.userAgent", request.userAgent],
|
|
40
|
+
["integrationStatus", numberOrUndefined(request.lambdaInvokeStatus)],
|
|
41
|
+
[
|
|
42
|
+
"integration.integrationStatus",
|
|
43
|
+
numberOrUndefined(request.lambdaInvokeStatus),
|
|
44
|
+
],
|
|
45
|
+
["integrationLatency", numberOrUndefined(request.integrationLatency)],
|
|
46
|
+
["integration.latency", numberOrUndefined(request.integrationLatency)],
|
|
47
|
+
["integration.status", numberOrUndefined(request.integrationStatus)],
|
|
48
|
+
["integrationErrorMessage", request.integrationErrorMessage],
|
|
49
|
+
["integration.error", request.integrationErrorMessage],
|
|
50
|
+
["authorizer.error", request.authorizerError],
|
|
51
|
+
["error.message", request.errorMessage],
|
|
52
|
+
["customDomain.basePathMatched", request.basePathMatched],
|
|
53
|
+
]);
|
|
54
|
+
addQuotedMessage(variables, request);
|
|
55
|
+
addAuthorizerProperties(variables, request);
|
|
56
|
+
return new Map([...variables].flatMap(([name, value]) => value === undefined ? [] : [[name, value]]));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* `$context.error.messageString` is the quoted form of the message, which is
|
|
60
|
+
* what a JSON format string uses to keep its own quoting intact.
|
|
61
|
+
*/
|
|
62
|
+
function addQuotedMessage(variables, request) {
|
|
63
|
+
if (request.errorMessage !== undefined) {
|
|
64
|
+
variables.set("error.messageString", `"${request.errorMessage}"`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The claims a `JWT` route's authorizer accepted and the context map a
|
|
69
|
+
* `CUSTOM` route's authorizer returned.
|
|
70
|
+
*
|
|
71
|
+
* Both are reached by naming the property. `$context.authorizer.claims` and
|
|
72
|
+
* `$context.authorizer` name no property, and AWS documents the first of those
|
|
73
|
+
* as returning null, so neither is given a value here.
|
|
74
|
+
*/
|
|
75
|
+
function addAuthorizerProperties(variables, request) {
|
|
76
|
+
const claims = Object.entries(request.jwt?.claims ?? {});
|
|
77
|
+
const authorizerContext = Object.entries(request.lambda ?? {});
|
|
78
|
+
for (const [claim, value] of claims) {
|
|
79
|
+
variables.set(`authorizer.claims.${claim}`, value);
|
|
80
|
+
}
|
|
81
|
+
for (const [key, value] of authorizerContext) {
|
|
82
|
+
if (value !== null && typeof value !== "object") {
|
|
83
|
+
variables.set(`authorizer.${key}`, String(value));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { SimHttpApiAccessLogSettings } from "./access-log/sim-http-api-access-log-settings.js";
|
|
2
|
+
import type { SimHttpApiAccessLogSettingsView } from "./access-log/sim-http-api-access-log-settings.type.js";
|
|
1
3
|
import type { SimHttpApiRouteSettingsView } from "./settings/sim-http-api-route-settings.type.js";
|
|
2
4
|
import type { SimHttpApiStageRouteSettings } from "./settings/sim-http-api-stage-route-settings.js";
|
|
3
5
|
/**
|
|
@@ -12,6 +14,7 @@ interface SimHttpApiStageProperties {
|
|
|
12
14
|
readonly description?: string | undefined;
|
|
13
15
|
readonly createdDate: Date;
|
|
14
16
|
readonly routeSettings?: SimHttpApiStageRouteSettings | undefined;
|
|
17
|
+
readonly accessLogSettings?: SimHttpApiAccessLogSettings | undefined;
|
|
15
18
|
}
|
|
16
19
|
/**
|
|
17
20
|
* Minimal structural stage view, as the Create and Get commands return.
|
|
@@ -22,6 +25,7 @@ export interface SimHttpApiStageView extends SimHttpApiRouteSettingsView {
|
|
|
22
25
|
CreatedDate: Date;
|
|
23
26
|
StageVariables?: Record<string, string>;
|
|
24
27
|
Description?: string;
|
|
28
|
+
AccessLogSettings?: SimHttpApiAccessLogSettingsView;
|
|
25
29
|
}
|
|
26
30
|
/**
|
|
27
31
|
* A simulated HTTP API stage.
|
|
@@ -41,6 +45,11 @@ export declare class SimHttpApiStage {
|
|
|
41
45
|
* that was given no route settings and so throttles nothing.
|
|
42
46
|
*/
|
|
43
47
|
readonly routeSettings?: SimHttpApiStageRouteSettings | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Where this stage writes an access log line per request, or undefined for a
|
|
50
|
+
* stage that was given no access log settings and so logs nothing.
|
|
51
|
+
*/
|
|
52
|
+
readonly accessLogSettings?: SimHttpApiAccessLogSettings | undefined;
|
|
44
53
|
constructor(properties: SimHttpApiStageProperties);
|
|
45
54
|
/**
|
|
46
55
|
* Whether this stage's throttle serves one more request to a route key now.
|
|
@@ -21,6 +21,11 @@ export class SimHttpApiStage {
|
|
|
21
21
|
* that was given no route settings and so throttles nothing.
|
|
22
22
|
*/
|
|
23
23
|
routeSettings;
|
|
24
|
+
/**
|
|
25
|
+
* Where this stage writes an access log line per request, or undefined for a
|
|
26
|
+
* stage that was given no access log settings and so logs nothing.
|
|
27
|
+
*/
|
|
28
|
+
accessLogSettings;
|
|
24
29
|
constructor(properties) {
|
|
25
30
|
this.stageName = properties.stageName;
|
|
26
31
|
this.autoDeploy = properties.autoDeploy;
|
|
@@ -28,6 +33,7 @@ export class SimHttpApiStage {
|
|
|
28
33
|
this.description = properties.description;
|
|
29
34
|
this.createdDate = properties.createdDate;
|
|
30
35
|
this.routeSettings = properties.routeSettings;
|
|
36
|
+
this.accessLogSettings = properties.accessLogSettings;
|
|
31
37
|
}
|
|
32
38
|
/**
|
|
33
39
|
* Whether this stage's throttle serves one more request to a route key now.
|
|
@@ -57,6 +63,9 @@ export class SimHttpApiStage {
|
|
|
57
63
|
if (this.description !== undefined) {
|
|
58
64
|
view.Description = this.description;
|
|
59
65
|
}
|
|
66
|
+
if (this.accessLogSettings !== undefined) {
|
|
67
|
+
view.AccessLogSettings = this.accessLogSettings.view();
|
|
68
|
+
}
|
|
60
69
|
return view;
|
|
61
70
|
}
|
|
62
71
|
}
|
package/dist/service/apigatewayv2/cfn/stage/sim-cfn-http-api-access-log-settings-properties.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { SimCfnResource } from "../../../cloudformation/resource/sim-cfn-resource.js";
|
|
2
|
+
import type { SimCfnTemplateValue } from "../../../cloudformation/template/value/sim-cfn-template-value.js";
|
|
3
|
+
import type { SimHttpApiAccessLogSettingsInput } from "../../api/stage/access-log/sim-http-api-access-log-settings.type.js";
|
|
4
|
+
import type { SimCfnApiGatewayV2PropertyParser } from "../sim-cfn-api-gateway-v2-property-parser.js";
|
|
5
|
+
interface SimCfnHttpApiAccessLogSettingsPropertiesProperties {
|
|
6
|
+
readonly resource: SimCfnResource;
|
|
7
|
+
readonly propertyParser: SimCfnApiGatewayV2PropertyParser;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Reads the `AccessLogSettings` of an AWS::ApiGatewayV2::Stage.
|
|
11
|
+
*
|
|
12
|
+
* `DestinationArn` reaches the template as a `Fn::GetAtt` on the log group's
|
|
13
|
+
* `Arn`, which CDK emits and which resolves to the form ending in `:*`. The
|
|
14
|
+
* form without it, as `DescribeLogGroups` reports, names the same group.
|
|
15
|
+
*/
|
|
16
|
+
export declare class SimCfnHttpApiAccessLogSettingsProperties {
|
|
17
|
+
#private;
|
|
18
|
+
constructor(properties: SimCfnHttpApiAccessLogSettingsPropertiesProperties);
|
|
19
|
+
/**
|
|
20
|
+
* Read the `AccessLogSettings` a stage was declared with.
|
|
21
|
+
*/
|
|
22
|
+
settings(value: SimCfnTemplateValue | undefined, label: string): SimHttpApiAccessLogSettingsInput | undefined;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
package/dist/service/apigatewayv2/cfn/stage/sim-cfn-http-api-access-log-settings-properties.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads the `AccessLogSettings` of an AWS::ApiGatewayV2::Stage.
|
|
3
|
+
*
|
|
4
|
+
* `DestinationArn` reaches the template as a `Fn::GetAtt` on the log group's
|
|
5
|
+
* `Arn`, which CDK emits and which resolves to the form ending in `:*`. The
|
|
6
|
+
* form without it, as `DescribeLogGroups` reports, names the same group.
|
|
7
|
+
*/
|
|
8
|
+
export class SimCfnHttpApiAccessLogSettingsProperties {
|
|
9
|
+
#resource;
|
|
10
|
+
#propertyParser;
|
|
11
|
+
constructor(properties) {
|
|
12
|
+
this.#resource = properties.resource;
|
|
13
|
+
this.#propertyParser = properties.propertyParser;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Read the `AccessLogSettings` a stage was declared with.
|
|
17
|
+
*/
|
|
18
|
+
settings(value, label) {
|
|
19
|
+
const record = this.#propertyParser.optionalRecord(this.#resource, value, label);
|
|
20
|
+
if (record === undefined) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
const destinationArn = this.#propertyParser.optionalString(this.#resource, record["DestinationArn"], `${label}.DestinationArn`);
|
|
24
|
+
const format = this.#propertyParser.optionalString(this.#resource, record["Format"], `${label}.Format`);
|
|
25
|
+
return {
|
|
26
|
+
...(destinationArn !== undefined && { DestinationArn: destinationArn }),
|
|
27
|
+
...(format !== undefined && { Format: format }),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -14,6 +14,7 @@ export declare class SimCfnHttpApiStageProperties {
|
|
|
14
14
|
private readonly properties;
|
|
15
15
|
private readonly propertyParser;
|
|
16
16
|
private readonly routeSettingsParser;
|
|
17
|
+
private readonly accessLogSettingsParser;
|
|
17
18
|
constructor(properties: SimCfnHttpApiStagePropertiesProperties);
|
|
18
19
|
/**
|
|
19
20
|
* The API this stage belongs to, which a template reaches with a `Ref` on
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { SimCfnApiGatewayV2PropertyParser } from "../sim-cfn-api-gateway-v2-property-parser.js";
|
|
2
|
+
import { SimCfnHttpApiAccessLogSettingsProperties } from "./sim-cfn-http-api-access-log-settings-properties.js";
|
|
2
3
|
import { SimCfnHttpApiRouteSettingsProperties } from "./sim-cfn-http-api-route-settings-properties.js";
|
|
3
4
|
/**
|
|
4
5
|
* The AWS::ApiGatewayV2::Stage properties this simulation deploys.
|
|
5
6
|
*
|
|
6
|
-
* `DeploymentId
|
|
7
|
-
*
|
|
8
|
-
* is modelled, and a stage that looked logged to the template and logged
|
|
9
|
-
* nothing when serving is the failure worth recording.
|
|
7
|
+
* `DeploymentId` and `Tags` are left out, so a template carrying one is
|
|
8
|
+
* recorded and the stage is created without it. Neither is modelled.
|
|
10
9
|
*/
|
|
11
10
|
const simulatedProperties = [
|
|
12
11
|
"ApiId",
|
|
@@ -16,6 +15,7 @@ const simulatedProperties = [
|
|
|
16
15
|
"Description",
|
|
17
16
|
"DefaultRouteSettings",
|
|
18
17
|
"RouteSettings",
|
|
18
|
+
"AccessLogSettings",
|
|
19
19
|
];
|
|
20
20
|
/**
|
|
21
21
|
* Reads AWS::ApiGatewayV2::Stage CloudFormation properties into the CreateStage
|
|
@@ -29,6 +29,7 @@ export class SimCfnHttpApiStageProperties {
|
|
|
29
29
|
simulated: simulatedProperties,
|
|
30
30
|
});
|
|
31
31
|
routeSettingsParser;
|
|
32
|
+
accessLogSettingsParser;
|
|
32
33
|
constructor(properties) {
|
|
33
34
|
this.resource = properties.resource;
|
|
34
35
|
this.properties = properties.properties;
|
|
@@ -36,6 +37,10 @@ export class SimCfnHttpApiStageProperties {
|
|
|
36
37
|
resource: this.resource,
|
|
37
38
|
propertyParser: this.propertyParser,
|
|
38
39
|
});
|
|
40
|
+
this.accessLogSettingsParser = new SimCfnHttpApiAccessLogSettingsProperties({
|
|
41
|
+
resource: this.resource,
|
|
42
|
+
propertyParser: this.propertyParser,
|
|
43
|
+
});
|
|
39
44
|
this.propertyParser.ignoreUnsimulated(this.resource, this.properties);
|
|
40
45
|
}
|
|
41
46
|
/**
|
|
@@ -68,6 +73,7 @@ export class SimCfnHttpApiStageProperties {
|
|
|
68
73
|
Description: this.propertyParser.optionalString(this.resource, this.properties["Description"], "Description"),
|
|
69
74
|
DefaultRouteSettings: this.routeSettingsParser.settings(this.properties["DefaultRouteSettings"], "DefaultRouteSettings"),
|
|
70
75
|
RouteSettings: this.routeSettingsParser.settingsMap(this.properties["RouteSettings"], "RouteSettings"),
|
|
76
|
+
AccessLogSettings: this.accessLogSettingsParser.settings(this.properties["AccessLogSettings"], "AccessLogSettings"),
|
|
71
77
|
};
|
|
72
78
|
}
|
|
73
79
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SimHttpApiAccessLogSettings } from "../../api/stage/access-log/sim-http-api-access-log-settings.js";
|
|
2
|
+
import type { SimApiGatewayV2UnsimulatedInput } from "../sim-api-gateway-v2-unsimulated-input.js";
|
|
3
|
+
import type { SimCreateStageCommandInput } from "./stage.command.js";
|
|
4
|
+
/**
|
|
5
|
+
* Reads the access log settings a CreateStage input asks for.
|
|
6
|
+
*
|
|
7
|
+
* Both members are required together. AWS types each as optional and a stage
|
|
8
|
+
* carrying one alone has either nowhere to write or nothing to write, so the
|
|
9
|
+
* pair is refused rather than half applied.
|
|
10
|
+
*
|
|
11
|
+
* `DestinationArn` has to name a CloudWatch Logs log group. HTTP APIs accept
|
|
12
|
+
* no other destination, and a Kinesis Data Firehose delivery stream, which a
|
|
13
|
+
* REST API stage may name, is refused here by the same check.
|
|
14
|
+
*/
|
|
15
|
+
export declare function simHttpApiAccessLogSettings(input: SimCreateStageCommandInput, unsimulated: SimApiGatewayV2UnsimulatedInput): SimHttpApiAccessLogSettings | undefined;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { SimHttpApiAccessLogSettings } from "../../api/stage/access-log/sim-http-api-access-log-settings.js";
|
|
2
|
+
import { SimApiGatewayV2BadRequest } from "../../error/sim-api-gateway-v2.error.js";
|
|
3
|
+
/** The `AccessLogSettings` members an HTTP API stage takes. */
|
|
4
|
+
const acceptedAccessLogSettings = ["DestinationArn", "Format"];
|
|
5
|
+
/**
|
|
6
|
+
* Reads the access log settings a CreateStage input asks for.
|
|
7
|
+
*
|
|
8
|
+
* Both members are required together. AWS types each as optional and a stage
|
|
9
|
+
* carrying one alone has either nowhere to write or nothing to write, so the
|
|
10
|
+
* pair is refused rather than half applied.
|
|
11
|
+
*
|
|
12
|
+
* `DestinationArn` has to name a CloudWatch Logs log group. HTTP APIs accept
|
|
13
|
+
* no other destination, and a Kinesis Data Firehose delivery stream, which a
|
|
14
|
+
* REST API stage may name, is refused here by the same check.
|
|
15
|
+
*/
|
|
16
|
+
export function simHttpApiAccessLogSettings(input, unsimulated) {
|
|
17
|
+
const settings = input.AccessLogSettings;
|
|
18
|
+
if (settings === undefined) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
unsimulated.refuseUnaccepted(settings, acceptedAccessLogSettings, "AccessLogSettings.");
|
|
22
|
+
const { DestinationArn: destinationArn, Format: format } = settings;
|
|
23
|
+
if (destinationArn === undefined || format === undefined) {
|
|
24
|
+
throw new SimApiGatewayV2BadRequest("CreateStage AccessLogSettings requires both DestinationArn and Format");
|
|
25
|
+
}
|
|
26
|
+
const accessLogSettings = SimHttpApiAccessLogSettings.from(destinationArn, format);
|
|
27
|
+
if (accessLogSettings === undefined) {
|
|
28
|
+
throw new SimApiGatewayV2BadRequest(`CreateStage AccessLogSettings DestinationArn '${destinationArn}' is ` +
|
|
29
|
+
`not a CloudWatch Logs log group ARN. An HTTP API stage writes its ` +
|
|
30
|
+
`access log to a log group and to nothing else.`);
|
|
31
|
+
}
|
|
32
|
+
return accessLogSettings;
|
|
33
|
+
}
|