lambder 7.3.1 → 8.1.1
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/CHANGELOG.md +1047 -3
- package/README.md +46 -21
- package/dist/api/LambderApiAnswer.d.ts +18 -22
- package/dist/api/LambderApiAnswer.js +6 -7
- package/dist/api/LambderApiCallContext.d.ts +21 -8
- package/dist/api/LambderApiCallContext.js +22 -4
- package/dist/api/LambderApiDefinition.d.ts +4 -3
- package/dist/api/LambderApiEnvelope.d.ts +14 -9
- package/dist/api/LambderApiEnvelope.js +33 -34
- package/dist/api/LambderApiGuards.d.ts +78 -51
- package/dist/api/LambderApiGuards.js +34 -36
- package/dist/api/LambderApiIdempotency.d.ts +68 -62
- package/dist/api/LambderApiIdempotency.js +214 -151
- package/dist/api/LambderApiOutputValidationError.d.ts +32 -0
- package/dist/api/LambderApiOutputValidationError.js +50 -0
- package/dist/api/LambderApiPipeline.d.ts +47 -38
- package/dist/api/LambderApiPipeline.js +122 -63
- package/dist/api/LambderApiRateLimits.d.ts +201 -54
- package/dist/api/LambderApiRateLimits.js +185 -108
- package/dist/api/LambderApiRequest.d.ts +27 -21
- package/dist/api/LambderApiRequest.js +26 -19
- package/dist/api/LambderApiSignature.d.ts +12 -15
- package/dist/api/LambderApiSignature.js +28 -51
- package/dist/api/LambderApiValidationRefusal.d.ts +9 -9
- package/dist/api/LambderApiValidationRefusal.js +10 -10
- package/dist/build/ContractTypePrinter.d.ts +85 -0
- package/dist/build/ContractTypePrinter.js +402 -0
- package/dist/build/freshProcessVerifier.d.ts +13 -0
- package/dist/build/freshProcessVerifier.js +19 -0
- package/dist/build/moduleLocation.d.ts +11 -0
- package/dist/build/moduleLocation.js +6 -0
- package/dist/build/writeApiContract.d.ts +78 -0
- package/dist/build/writeApiContract.js +302 -0
- package/dist/build/writeApiSignatures.d.ts +114 -0
- package/dist/build/writeApiSignatures.js +217 -0
- package/dist/build/writeFileAtomically.d.ts +8 -0
- package/dist/build/writeFileAtomically.js +22 -0
- package/dist/build.d.ts +14 -0
- package/dist/build.js +11 -0
- package/dist/client/LambderCaller.d.ts +13 -44
- package/dist/client/LambderCaller.js +77 -84
- package/dist/client/LambderReloadLoopBreaker.d.ts +56 -26
- package/dist/client/LambderReloadLoopBreaker.js +90 -46
- package/dist/client/LambderUploadRunner.d.ts +96 -0
- package/dist/client/LambderUploadRunner.js +234 -0
- package/dist/client/lambderFetchTransport.d.ts +4 -1
- package/dist/client/lambderFetchTransport.js +52 -28
- package/dist/client.d.ts +9 -3
- package/dist/client.js +6 -1
- package/dist/core/Lambder.d.ts +143 -79
- package/dist/core/Lambder.js +350 -231
- package/dist/core/LambderContext.d.ts +82 -15
- package/dist/core/LambderContext.js +107 -20
- package/dist/core/LambderCors.d.ts +21 -3
- package/dist/core/LambderCors.js +35 -16
- package/dist/core/LambderCrashHandling.d.ts +40 -0
- package/dist/core/LambderCrashHandling.js +97 -0
- package/dist/core/LambderCreateOptions.d.ts +151 -75
- package/dist/core/LambderCreateOptions.js +16 -23
- package/dist/core/LambderFiles.d.ts +21 -7
- package/dist/core/LambderFiles.js +62 -34
- package/dist/core/LambderIndexHtml.js +12 -11
- package/dist/core/LambderPolicyBuilders.d.ts +17 -5
- package/dist/core/LambderPolicyBuilders.js +17 -5
- package/dist/core/LambderPublicFiles.d.ts +11 -5
- package/dist/core/LambderPublicFiles.js +32 -4
- package/dist/core/LambderRequestPath.d.ts +43 -0
- package/dist/core/LambderRequestPath.js +63 -0
- package/dist/core/LambderResponse.d.ts +26 -5
- package/dist/core/LambderResponse.js +157 -70
- package/dist/core/LambderResponseBuilder.d.ts +49 -4
- package/dist/core/LambderResponseBuilder.js +64 -3
- package/dist/core/LambderRouting.d.ts +2 -3
- package/dist/core/LambderRouting.js +22 -7
- package/dist/core/LambderTemplatingEngine.js +211 -32
- package/dist/index.d.ts +25 -8
- package/dist/index.js +13 -4
- package/dist/invoke/LambderInvokeCaller.d.ts +37 -42
- package/dist/invoke/LambderInvokeCaller.js +76 -66
- package/dist/invoke/LambderInvokeOutcome.d.ts +27 -26
- package/dist/invoke/LambderInvokeOutcome.js +9 -22
- package/dist/invoke/LambderLambdaEvent.d.ts +29 -9
- package/dist/invoke/LambderLambdaEvent.js +40 -22
- package/dist/invoke/lambderHandlerTransport.d.ts +9 -10
- package/dist/invoke/lambderHandlerTransport.js +15 -18
- package/dist/mock/LambderMockApp.d.ts +67 -83
- package/dist/mock/LambderMockApp.js +167 -153
- package/dist/mock/LambderMockBrowserCookies.d.ts +24 -28
- package/dist/mock/LambderMockBrowserCookies.js +24 -28
- package/dist/mock/LambderMockCallRecorder.d.ts +15 -22
- package/dist/mock/LambderMockCallRecorder.js +19 -28
- package/dist/mock/LambderMockCreateOptions.d.ts +42 -24
- package/dist/mock/LambderMockEntryRegistry.d.ts +11 -12
- package/dist/mock/LambderMockEntryRegistry.js +24 -29
- package/dist/mock/LambderMockFailureInjector.d.ts +3 -6
- package/dist/mock/LambderMockFailureInjector.js +3 -6
- package/dist/mock/LambderMockTypes.d.ts +78 -108
- package/dist/mock/lambderMockInvokeTransport.d.ts +11 -13
- package/dist/mock/lambderMockInvokeTransport.js +11 -10
- package/dist/mock/lambderMockMswHandler.d.ts +43 -33
- package/dist/mock/lambderMockMswHandler.js +50 -39
- package/dist/mock/lambderMockUploadMswHandler.d.ts +26 -0
- package/dist/mock/lambderMockUploadMswHandler.js +28 -0
- package/dist/mock.d.ts +4 -1
- package/dist/mock.js +6 -3
- package/dist/session/LambderSessionController.d.ts +108 -89
- package/dist/session/LambderSessionController.js +187 -168
- package/dist/session/LambderSessionCrypto.d.ts +16 -7
- package/dist/session/LambderSessionCrypto.js +26 -12
- package/dist/session/LambderSessionManager.d.ts +124 -46
- package/dist/session/LambderSessionManager.js +262 -137
- package/dist/shared/LambderHtml.d.ts +42 -3
- package/dist/shared/LambderHtml.js +127 -7
- package/dist/shared/LambderHtmlPositions.d.ts +173 -0
- package/dist/shared/LambderHtmlPositions.js +652 -0
- package/dist/shared/LambderI18n.d.ts +10 -11
- package/dist/shared/LambderI18n.js +33 -21
- package/dist/shared/contracts/LambderCache.d.ts +66 -0
- package/dist/shared/contracts/LambderCache.js +11 -0
- package/dist/shared/contracts/LambderFileSource.d.ts +6 -6
- package/dist/shared/contracts/LambderFileSource.js +5 -8
- package/dist/shared/contracts/LambderIdempotencyStore.d.ts +51 -22
- package/dist/shared/contracts/LambderIdempotencyStore.js +4 -5
- package/dist/shared/contracts/LambderRateLimiter.d.ts +27 -15
- package/dist/shared/contracts/LambderRateLimiter.js +4 -5
- package/dist/shared/contracts/LambderSessionStore.d.ts +65 -26
- package/dist/shared/contracts/LambderSessionStore.js +5 -6
- package/dist/shared/contracts/LambderUploadBucket.d.ts +154 -0
- package/dist/shared/contracts/LambderUploadBucket.js +74 -0
- package/dist/shared/transport/LambderApiTransport.d.ts +27 -27
- package/dist/shared/transport/LambderApiTransport.js +7 -7
- package/dist/shared/transport/LambderCookieJar.d.ts +28 -35
- package/dist/shared/transport/LambderCookieJar.js +54 -66
- package/dist/shared/transport/lambderCookieJarTransport.d.ts +11 -13
- package/dist/shared/transport/lambderCookieJarTransport.js +24 -23
- package/dist/shared/util/LambderCallAbort.d.ts +5 -5
- package/dist/shared/util/LambderCallAbort.js +5 -5
- package/dist/shared/util/LambderClientIp.d.ts +27 -11
- package/dist/shared/util/LambderClientIp.js +96 -13
- package/dist/shared/util/LambderContentDisposition.d.ts +10 -0
- package/dist/shared/util/LambderContentDisposition.js +13 -0
- package/dist/shared/util/LambderExpiringMap.d.ts +35 -49
- package/dist/shared/util/LambderExpiringMap.js +41 -57
- package/dist/shared/util/LambderNodeModules.js +6 -7
- package/dist/shared/util/LambderOptionChecks.d.ts +4 -4
- package/dist/shared/util/LambderOptionChecks.js +4 -4
- package/dist/shared/util/LambderResponseBrand.d.ts +5 -5
- package/dist/shared/util/LambderResponseBrand.js +5 -5
- package/dist/shared/util/LambderTextDigest.d.ts +7 -5
- package/dist/shared/util/LambderTextDigest.js +11 -5
- package/dist/shared/util/LambderTypeUtilities.d.ts +7 -8
- package/dist/shared/util/LambderTypeUtilities.js +3 -3
- package/dist/shared/util/boundKeyField.d.ts +20 -0
- package/dist/shared/util/boundKeyField.js +34 -0
- package/dist/shared/util/canonicalJson.d.ts +11 -0
- package/dist/shared/util/canonicalJson.js +28 -0
- package/dist/shared/util/joinKeyFields.d.ts +20 -0
- package/dist/shared/util/joinKeyFields.js +22 -0
- package/dist/shared/wire/LambderAnswerHeaders.d.ts +12 -16
- package/dist/shared/wire/LambderAnswerHeaders.js +12 -16
- package/dist/shared/wire/LambderApiContract.d.ts +98 -53
- package/dist/shared/wire/LambderApiOutcome.d.ts +43 -31
- package/dist/shared/wire/LambderApiOutcome.js +48 -23
- package/dist/shared/wire/LambderApiRefusal.d.ts +45 -27
- package/dist/shared/wire/LambderApiRefusal.js +42 -7
- package/dist/shared/wire/LambderApiSignature.d.ts +18 -22
- package/dist/shared/wire/LambderApiSignature.js +16 -19
- package/dist/shared/wire/LambderCallOptions.d.ts +38 -47
- package/dist/shared/wire/LambderCallOptions.js +9 -11
- package/dist/shared/wire/LambderCompressionCodec.d.ts +29 -34
- package/dist/shared/wire/LambderCompressionCodec.js +31 -36
- package/dist/shared/wire/LambderCompressionOption.d.ts +9 -9
- package/dist/shared/wire/LambderCompressionOption.js +9 -9
- package/dist/shared/wire/LambderCrashDetail.d.ts +12 -15
- package/dist/shared/wire/LambderCrashDetail.js +12 -15
- package/dist/shared/wire/LambderDefaultApiPath.d.ts +6 -0
- package/dist/shared/wire/LambderDefaultApiPath.js +6 -0
- package/dist/shared/wire/LambderHttpStatus.d.ts +6 -7
- package/dist/shared/wire/LambderIdempotencyKeyScope.d.ts +89 -0
- package/dist/shared/wire/LambderIdempotencyKeyScope.js +146 -0
- package/dist/shared/wire/LambderInvokeApiId.d.ts +27 -0
- package/dist/shared/wire/LambderInvokeApiId.js +27 -0
- package/dist/shared/wire/LambderOutcomeAssertions.d.ts +6 -7
- package/dist/shared/wire/LambderOutcomeAssertions.js +6 -7
- package/dist/shared/wire/LambderRequestPayload.d.ts +18 -20
- package/dist/shared/wire/LambderRequestPayload.js +4 -6
- package/dist/shared/wire/LambderUploadObjectFields.d.ts +10 -0
- package/dist/shared/wire/LambderUploadObjectFields.js +24 -0
- package/dist/shared/wire/LambderUploadRefusal.d.ts +9 -0
- package/dist/shared/wire/LambderUploadRefusal.js +18 -0
- package/dist/shared/wire/LambderUploadSchemas.d.ts +12 -0
- package/dist/shared/wire/LambderUploadSchemas.js +30 -0
- package/dist/stores/LambderCacheFiller.d.ts +48 -0
- package/dist/stores/LambderCacheFiller.js +119 -0
- package/dist/stores/LambderCacheKeys.d.ts +26 -0
- package/dist/stores/LambderCacheKeys.js +54 -0
- package/dist/stores/LambderCacheValues.d.ts +45 -0
- package/dist/stores/LambderCacheValues.js +74 -0
- package/dist/stores/LambderDdbCache.d.ts +121 -56
- package/dist/stores/LambderDdbCache.js +528 -225
- package/dist/stores/LambderDdbIdempotencyStore.d.ts +33 -22
- package/dist/stores/LambderDdbIdempotencyStore.js +75 -50
- package/dist/stores/LambderDdbRateLimiter.d.ts +76 -20
- package/dist/stores/LambderDdbRateLimiter.js +151 -39
- package/dist/stores/LambderDdbSdk.d.ts +43 -31
- package/dist/stores/LambderDdbSdk.js +80 -38
- package/dist/stores/LambderDdbSessionStore.d.ts +27 -14
- package/dist/stores/LambderDdbSessionStore.js +119 -47
- package/dist/stores/LambderHttpFileSource.d.ts +15 -6
- package/dist/stores/LambderHttpFileSource.js +15 -13
- package/dist/stores/LambderMemoryCache.d.ts +49 -0
- package/dist/stores/LambderMemoryCache.js +113 -0
- package/dist/stores/LambderMemoryIdempotencyStore.d.ts +13 -12
- package/dist/stores/LambderMemoryIdempotencyStore.js +31 -30
- package/dist/stores/LambderMemoryRateLimiter.d.ts +8 -9
- package/dist/stores/LambderMemoryRateLimiter.js +14 -13
- package/dist/stores/LambderMemorySessionStore.d.ts +14 -11
- package/dist/stores/LambderMemorySessionStore.js +38 -19
- package/dist/stores/LambderMemoryUploadBucket.d.ts +99 -0
- package/dist/stores/LambderMemoryUploadBucket.js +219 -0
- package/dist/stores/LambderS3FileSource.d.ts +21 -6
- package/dist/stores/LambderS3FileSource.js +12 -7
- package/dist/stores/LambderS3UploadBucket.d.ts +73 -0
- package/dist/stores/LambderS3UploadBucket.js +144 -0
- package/dist/stores/LambderSdkInstallHint.d.ts +11 -0
- package/dist/stores/LambderSdkInstallHint.js +14 -0
- package/dist/testing/LambderTestApp.d.ts +23 -25
- package/dist/testing/LambderTestApp.js +22 -24
- package/dist/testing/LambderTestVisitor.d.ts +10 -12
- package/dist/testing/LambderTestVisitor.js +15 -15
- package/dist/testing.d.ts +3 -0
- package/dist/testing.js +2 -0
- package/package.json +26 -3
- package/dist/api/LambderApiPolicyEngine.d.ts +0 -47
- package/dist/api/LambderApiPolicyEngine.js +0 -85
- package/dist/shared/util/LambderKeyFields.d.ts +0 -32
- package/dist/shared/util/LambderKeyFields.js +0 -34
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
* Calling a Lambder app from another lambda, or from any server code that
|
|
3
3
|
* holds AWS credentials and lambda:InvokeFunction on it.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
5
|
+
* Builds the payload-format-2.0 event API Gateway would have built, invokes
|
|
6
|
+
* the function with it directly, and reads the response object Lambder
|
|
7
|
+
* returns. The callee is an unmodified Lambder app, so everything it offers
|
|
8
|
+
* over HTTP (zod validation, the inferred contract, refusals, guards,
|
|
9
|
+
* idempotency keys, Brotli answers, logList, the crash detail its error
|
|
10
|
+
* handler chooses to send) applies unchanged. The callee tells an invoke
|
|
11
|
+
* apart by the event's requestContext.apiId, which no gateway lets a client
|
|
12
|
+
* write, and reads no forwarding header on one, so `clientIp` and `host` are
|
|
13
|
+
* the only address and host it sees. The x-lambder-invoke header is a marker
|
|
14
|
+
* for guards and hooks, never an authorization: the IAM grant is the
|
|
15
|
+
* authorization.
|
|
16
16
|
*
|
|
17
17
|
* Server-only (zlib, the Lambda SDK), so it is exported from the root entry
|
|
18
18
|
* and never from lambder/client. The SDK is an optional peer dependency
|
|
@@ -25,11 +25,13 @@ import { DEFAULT_SESSION_TOKEN_COOKIE_KEY } from "../shared/wire/LambderSessionC
|
|
|
25
25
|
import { readApiSignature } from "../shared/wire/LambderApiSignature.js";
|
|
26
26
|
import { resolveApiOutcome } from "../shared/wire/LambderApiOutcome.js";
|
|
27
27
|
import { mergeGuardInputs, } from "../shared/wire/LambderCallOptions.js";
|
|
28
|
+
import { beginIdempotentAttempt, IDEMPOTENT_ATTEMPT_NOT_SENT } from "../shared/wire/LambderIdempotencyKeyScope.js";
|
|
28
29
|
import { createCallAbort, stopWaitingWhenAborted } from "../shared/util/LambderCallAbort.js";
|
|
29
30
|
import { coerceToError, errorFromCrashDetail } from "../shared/wire/LambderCrashDetail.js";
|
|
30
31
|
import { assertPositiveInteger } from "../shared/util/LambderOptionChecks.js";
|
|
31
32
|
import { resolveCompressionOption } from "../shared/wire/LambderCompressionOption.js";
|
|
32
33
|
import { DEFAULT_INVOKE_REQUEST_COMPRESSION_SETTINGS, DEFAULT_MAX_RESTORED_PAYLOAD_BYTES, compressPayloadBrotli, resolveRequestCompressionMinBytes, } from "../shared/wire/LambderRequestPayload.js";
|
|
34
|
+
import { DEFAULT_API_PATH } from "../shared/wire/LambderDefaultApiPath.js";
|
|
33
35
|
import { buildEnvelopeJson, decodeLambdaHttpResult, localLambdaContext, sessionCookies, synthesizeLambdaHttpEvent, } from "./LambderLambdaEvent.js";
|
|
34
36
|
/**
|
|
35
37
|
* Lambda caps a synchronous invoke's request and its response at about 6MB;
|
|
@@ -65,7 +67,7 @@ export default class LambderInvokeCaller {
|
|
|
65
67
|
this.functionName = functionName;
|
|
66
68
|
this.client = client;
|
|
67
69
|
this.clientConfig = clientConfig;
|
|
68
|
-
this.apiPath = apiPath ??
|
|
70
|
+
this.apiPath = apiPath ?? DEFAULT_API_PATH;
|
|
69
71
|
this.apiVersion = apiVersion;
|
|
70
72
|
this.apiSignatures = apiSignatures;
|
|
71
73
|
this.host = host ?? functionName;
|
|
@@ -88,9 +90,10 @@ export default class LambderInvokeCaller {
|
|
|
88
90
|
const tokenCookieKey = init.sessionTokenCookieKey ?? DEFAULT_SESSION_TOKEN_COOKIE_KEY;
|
|
89
91
|
return synthesizeLambdaHttpEvent({
|
|
90
92
|
method: "POST",
|
|
91
|
-
path: init.apiPath ??
|
|
93
|
+
path: init.apiPath ?? DEFAULT_API_PATH,
|
|
92
94
|
host,
|
|
93
95
|
headers: init.headers,
|
|
96
|
+
contentType: "application/json",
|
|
94
97
|
clientIp: init.clientIp,
|
|
95
98
|
cookies: sessionCookies(init.session, tokenCookieKey),
|
|
96
99
|
body: buildEnvelopeJson({
|
|
@@ -110,10 +113,9 @@ export default class LambderInvokeCaller {
|
|
|
110
113
|
* Lambda would: a thrown error becomes a FunctionError payload. For
|
|
111
114
|
* tests that want the real handlers behind the real envelope.
|
|
112
115
|
*
|
|
113
|
-
* It honours the signal
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* caller's answer. Ignoring it made timeoutMs a no-op here.
|
|
116
|
+
* It honours the signal by ending the wait, as lambderHandlerTransport
|
|
117
|
+
* does: an in-process call cannot be cancelled, so the handler runs to
|
|
118
|
+
* completion regardless, but timeoutMs still frees the caller.
|
|
117
119
|
*/
|
|
118
120
|
static localTransport(handler, context = {}) {
|
|
119
121
|
return async (event, { functionName, signal }) => {
|
|
@@ -148,9 +150,9 @@ export default class LambderInvokeCaller {
|
|
|
148
150
|
}
|
|
149
151
|
async invokeThroughSdk(eventJson, signal) {
|
|
150
152
|
const { LambdaClient, InvokeCommand } = await this.loadSdk();
|
|
151
|
-
// One call is one delivery attempt,
|
|
152
|
-
//
|
|
153
|
-
//
|
|
153
|
+
// One call is one delivery attempt, as LambderApiTransport promises:
|
|
154
|
+
// the SDK's default of 3 would re-invoke a callee that already ran
|
|
155
|
+
// when only the response was lost.
|
|
154
156
|
if (!this.client)
|
|
155
157
|
this.client = new LambdaClient({ maxAttempts: 1, ...this.clientConfig });
|
|
156
158
|
const output = await this.client.send(new InvokeCommand({
|
|
@@ -172,10 +174,10 @@ export default class LambderInvokeCaller {
|
|
|
172
174
|
}
|
|
173
175
|
/** Delivers one event, serialized exactly once; an event over the invoke cap, a rejected transport, or one that answered after the call was given up on, is a failure. */
|
|
174
176
|
async deliverEvent(event, eventJson, options) {
|
|
175
|
-
// Measured here
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
177
|
+
// Measured here so every path that delivers an event is capped: an
|
|
178
|
+
// oversized event would otherwise come back as the SDK's
|
|
179
|
+
// RequestEntityTooLargeException, which classifies as `protocol` and
|
|
180
|
+
// names neither the size nor the cap.
|
|
179
181
|
const bytes = Buffer.byteLength(eventJson, "utf8");
|
|
180
182
|
if (bytes > LAMBDER_INVOKE_MAX_EVENT_BYTES) {
|
|
181
183
|
return { failed: {
|
|
@@ -188,16 +190,15 @@ export default class LambderInvokeCaller {
|
|
|
188
190
|
const abort = createCallAbort({ timeoutMs: options.timeoutMs ?? this.timeoutMs, signal: options.signal });
|
|
189
191
|
try {
|
|
190
192
|
// A call the site has already given up on does not reach the
|
|
191
|
-
// transport: honouring the signal is the transport's obligation
|
|
192
|
-
// and not every transport
|
|
193
|
+
// transport: honouring the signal is the transport's obligation,
|
|
194
|
+
// and not every transport meets it.
|
|
193
195
|
const refused = abort.abortFailure("beforeSending");
|
|
194
196
|
if (refused)
|
|
195
197
|
return { failed: { reason: refused.reason, cause: refused.error, detail: refused.error.message } };
|
|
196
198
|
const sent = await this.transport(event, { functionName: this.functionName, eventJson, signal: abort.signal });
|
|
197
199
|
// An answer that arrives after the abort is not a success: a
|
|
198
|
-
// transport that ignores the signal resolves late, and
|
|
199
|
-
//
|
|
200
|
-
// call site data it had already abandoned.
|
|
200
|
+
// transport that ignores the signal resolves late, and trusting it
|
|
201
|
+
// would hand the call site data it had already abandoned.
|
|
201
202
|
const late = abort.abortFailure("afterAnswering");
|
|
202
203
|
if (late)
|
|
203
204
|
return { failed: { reason: late.reason, cause: late.error, detail: late.error.message } };
|
|
@@ -205,8 +206,8 @@ export default class LambderInvokeCaller {
|
|
|
205
206
|
}
|
|
206
207
|
catch (err) {
|
|
207
208
|
const cause = coerceToError(err, "the invoke failed");
|
|
208
|
-
// The caller's own timeout wins, since only
|
|
209
|
-
// otherwise the rejection says what it was.
|
|
209
|
+
// The caller's own timeout wins, since only the caller knows about
|
|
210
|
+
// it; otherwise the rejection says what it was.
|
|
210
211
|
return { failed: { reason: abort.timedOut() ? 'timeout' : classifyDeliveryFailure(cause), cause } };
|
|
211
212
|
}
|
|
212
213
|
finally {
|
|
@@ -236,9 +237,8 @@ export default class LambderInvokeCaller {
|
|
|
236
237
|
cause,
|
|
237
238
|
});
|
|
238
239
|
// FailureInit's arms mirror the outcome's, so each reason's evidence
|
|
239
|
-
// was already demanded
|
|
240
|
-
//
|
|
241
|
-
// the arm it is rather than written out five times.
|
|
240
|
+
// was already demanded where the reason was chosen; the failure is
|
|
241
|
+
// assembled once here and cast to its arm.
|
|
242
242
|
const failure = {
|
|
243
243
|
ok: false,
|
|
244
244
|
reason: init.reason,
|
|
@@ -282,15 +282,25 @@ export default class LambderInvokeCaller {
|
|
|
282
282
|
for (const entry of logList)
|
|
283
283
|
console.log(`[lambder invoke] ${this.functionName} ${apiName}`, entry);
|
|
284
284
|
}
|
|
285
|
-
/**
|
|
285
|
+
/**
|
|
286
|
+
* One call, one outcome. Never throws; api() is what throws. A key scope
|
|
287
|
+
* is told how the attempt ended, as it is on LambderCaller.
|
|
288
|
+
*/
|
|
286
289
|
async dispatch(apiName, payload, options = {}) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
//
|
|
290
|
-
//
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
290
|
+
const idempotentAttempt = beginIdempotentAttempt(options.idempotencyKey);
|
|
291
|
+
const outcome = await this.dispatchAttempt(apiName, payload, options, idempotentAttempt);
|
|
292
|
+
// Only the first settle counts: an attempt that never left settled
|
|
293
|
+
// itself as not sent.
|
|
294
|
+
idempotentAttempt.settle(outcome);
|
|
295
|
+
return outcome;
|
|
296
|
+
}
|
|
297
|
+
async dispatchAttempt(apiName, payload, options, idempotentAttempt) {
|
|
298
|
+
const idempotencyKey = idempotentAttempt.key;
|
|
299
|
+
// Everything before the event leaves can throw on the caller's own
|
|
300
|
+
// inputs (a provider that rejects, a payload holding a cycle or a
|
|
301
|
+
// BigInt). None of it may escape: apiOutcome() promises an outcome,
|
|
302
|
+
// api() a LambderInvokeError, and onFailure must see every failure,
|
|
303
|
+
// so it becomes an 'unknown' failure.
|
|
294
304
|
let event;
|
|
295
305
|
let eventJson;
|
|
296
306
|
try {
|
|
@@ -303,10 +313,10 @@ export default class LambderInvokeCaller {
|
|
|
303
313
|
? await this.guardInputsProvider(apiName)
|
|
304
314
|
: undefined;
|
|
305
315
|
const guardInputs = mergeGuardInputs(provided, options.guardInputs);
|
|
306
|
-
//
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
//
|
|
316
|
+
// Serialized once: the compression decision needs the JSON, and a
|
|
317
|
+
// plain payload splices that same JSON into the envelope.
|
|
318
|
+
// Compressed when enabled and the JSON reaches the threshold;
|
|
319
|
+
// `compressRequest` overrides both ways.
|
|
310
320
|
const payloadJson = payload !== undefined ? JSON.stringify(payload) : undefined;
|
|
311
321
|
const compressionMinBytes = resolveRequestCompressionMinBytes(options.compressRequest, this.requestCompression);
|
|
312
322
|
const compressed = compressionMinBytes !== null && payloadJson !== undefined
|
|
@@ -317,6 +327,7 @@ export default class LambderInvokeCaller {
|
|
|
317
327
|
path: this.apiPath,
|
|
318
328
|
host: this.host,
|
|
319
329
|
headers: options.headers,
|
|
330
|
+
contentType: "application/json",
|
|
320
331
|
clientIp: options.clientIp,
|
|
321
332
|
cookies: sessionCookies(options.session, this.sessionTokenCookieKey),
|
|
322
333
|
body: buildEnvelopeJson({
|
|
@@ -328,13 +339,16 @@ export default class LambderInvokeCaller {
|
|
|
328
339
|
payloadJson: compressed ? undefined : payloadJson,
|
|
329
340
|
compressed,
|
|
330
341
|
guardInputs,
|
|
331
|
-
idempotencyKey
|
|
342
|
+
idempotencyKey,
|
|
332
343
|
}),
|
|
333
344
|
}, { invoke: true });
|
|
334
345
|
// Serialized once here; the size guard and the SDK transport both use it.
|
|
335
346
|
eventJson = JSON.stringify(event);
|
|
336
347
|
}
|
|
337
348
|
catch (err) {
|
|
349
|
+
// Nothing was sent, so the key was not used: the same as the
|
|
350
|
+
// browser caller's failure before sending.
|
|
351
|
+
idempotentAttempt.settle(IDEMPOTENT_ATTEMPT_NOT_SENT);
|
|
338
352
|
return await this.failureOutcome(apiName, { reason: 'unknown', cause: coerceToError(err, "the call could not be built") });
|
|
339
353
|
}
|
|
340
354
|
const delivery = await this.deliverEvent(event, eventJson, options);
|
|
@@ -357,17 +371,17 @@ export default class LambderInvokeCaller {
|
|
|
357
371
|
json: async () => http.json(),
|
|
358
372
|
text: async () => http.text(),
|
|
359
373
|
});
|
|
360
|
-
// Every answer's logs
|
|
361
|
-
// an envelope
|
|
362
|
-
// callee writes onto the validation body as it does onto a success.
|
|
374
|
+
// Every answer's logs arrive on outcome.logList, whether they came
|
|
375
|
+
// from an envelope, a 500 body or a validation body.
|
|
363
376
|
const logList = outcome.logList ?? [];
|
|
364
377
|
await this.surfaceLogs(apiName, logList);
|
|
365
378
|
// The answer's Set-Cookie values, so a session the callee rotated or
|
|
366
379
|
// cleared is visible to whoever is carrying it.
|
|
367
380
|
const cookies = http.cookies;
|
|
368
|
-
// The declared output, by the callee's own typing: res.api(null)
|
|
369
|
-
// only for an output that allows null or beside a reason (an
|
|
370
|
-
// is a failure below; a message-only null is the
|
|
381
|
+
// The declared output, by the callee's own typing: res.api(null)
|
|
382
|
+
// compiles only for an output that allows null or beside a reason (an
|
|
383
|
+
// errorMessage is a failure below; a message-only null is the
|
|
384
|
+
// callee's contract to keep).
|
|
371
385
|
if (outcome.ok)
|
|
372
386
|
return { ok: true, payload: (outcome.payload ?? null), response: outcome.response, logList, cookies };
|
|
373
387
|
const shared = { status: outcome.status, retryAfterSeconds: outcome.retryAfterSeconds, logList, cookies };
|
|
@@ -395,24 +409,21 @@ export default class LambderInvokeCaller {
|
|
|
395
409
|
}
|
|
396
410
|
return await this.failureOutcome(apiName, {
|
|
397
411
|
...shared,
|
|
398
|
-
reason: outcome.reason,
|
|
399
|
-
errorMessage: outcome.errorMessage,
|
|
412
|
+
...(outcome.reason === 'errorMessage' ? { reason: outcome.reason, errorMessage: outcome.errorMessage } : { reason: outcome.reason }),
|
|
400
413
|
response: outcome.response,
|
|
401
414
|
crash: outcome.response.crash,
|
|
402
415
|
});
|
|
403
416
|
}
|
|
404
417
|
/**
|
|
405
418
|
* Full-fidelity call: resolves to a discriminated LambderInvokeOutcome
|
|
406
|
-
* instead of throwing
|
|
407
|
-
*
|
|
408
|
-
*
|
|
409
|
-
* taken as a type parameter, so a call site cannot replace it by
|
|
410
|
-
* annotating what it assigns to.
|
|
419
|
+
* instead of throwing, for sites that degrade gracefully. The output type
|
|
420
|
+
* comes from the contract rather than a type parameter, so a call site
|
|
421
|
+
* cannot replace it by annotating what it assigns to.
|
|
411
422
|
*/
|
|
412
423
|
async apiOutcome(apiName, ...rest) {
|
|
413
424
|
// The tuple is a conditional type on an unresolved TApiName, so its
|
|
414
|
-
// elements read as unknown
|
|
415
|
-
// the
|
|
425
|
+
// elements read as unknown here; the contract already checked them at
|
|
426
|
+
// the call site.
|
|
416
427
|
const [payload, options] = rest;
|
|
417
428
|
return await this.dispatch(apiName, payload, options);
|
|
418
429
|
}
|
|
@@ -420,10 +431,9 @@ export default class LambderInvokeCaller {
|
|
|
420
431
|
* The declared output, or a thrown LambderInvokeError carrying the
|
|
421
432
|
* outcome. A failed dependency is a failed request: the throw reaches the
|
|
422
433
|
* app's global error handler with the callee's error as its cause. The
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
* arrives.
|
|
434
|
+
* resolver lets a handler answer null only when the output allows it or
|
|
435
|
+
* beside a reason (LambderApiAnswer), so null arrives only for a
|
|
436
|
+
* nullable output.
|
|
427
437
|
*/
|
|
428
438
|
async api(apiName, ...rest) {
|
|
429
439
|
const [payload, options] = rest;
|
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
* rejected delivery means, what Lambda's error payload says, the one-line
|
|
5
5
|
* detail an error message ends with).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Kept apart from LambderInvokeCaller, as shared/wire/LambderApiOutcome.ts is
|
|
8
|
+
* kept apart from the browser caller: this is the vocabulary a CALLER of the
|
|
9
9
|
* caller reads, and a site that only annotates an outcome or narrows an error
|
|
10
|
-
* should not have to read
|
|
11
|
-
* touch
|
|
12
|
-
* answer is in one file.
|
|
10
|
+
* should not have to read the whole class to find it. None of these functions
|
|
11
|
+
* touch the caller's state.
|
|
13
12
|
*/
|
|
14
13
|
import type { LambderApiEnvelopeBody } from "../shared/wire/LambderApiContract.js";
|
|
15
14
|
import type { LambderApiFailureReason, LambderValidationError } from "../shared/wire/LambderApiOutcome.js";
|
|
16
15
|
import type { LambderCrashDetail } from "../shared/wire/LambderCrashDetail.js";
|
|
16
|
+
import type { LambderAppRefusalMessage } from "../shared/wire/LambderApiRefusal.js";
|
|
17
17
|
export type LambderInvokeFailureReason = LambderApiFailureReason | 'crash' | 'protocol' | 'payloadTooLarge';
|
|
18
18
|
/** Lambda's own error payload for a FunctionError invocation. */
|
|
19
19
|
export type LambderInvokeFunctionError = {
|
|
@@ -26,8 +26,8 @@ type LambderInvokeFailureFields = {
|
|
|
26
26
|
ok: false;
|
|
27
27
|
/** HTTP status, when the callee answered. */
|
|
28
28
|
status?: number;
|
|
29
|
-
/** Envelope errorMessage, when the callee provided one. */
|
|
30
|
-
errorMessage?:
|
|
29
|
+
/** Envelope errorMessage, when the callee provided one: always the message object, a plain string having been read as one (refusalMessageOf). */
|
|
30
|
+
errorMessage?: LambderAppRefusalMessage;
|
|
31
31
|
/** Seconds to wait before retrying, from the answer's Retry-After header. */
|
|
32
32
|
retryAfterSeconds?: number;
|
|
33
33
|
/** Always present: the error api() throws for this failure, with the callee's error as its cause when one is known. */
|
|
@@ -53,13 +53,17 @@ export type LambderInvokePayloadTooLargeFailure = LambderInvokeFailureFields & {
|
|
|
53
53
|
/** The event's byte size, so a caller can say by how much it is over. */
|
|
54
54
|
bytes: number;
|
|
55
55
|
};
|
|
56
|
-
/** The callee answered, and the envelope itself says the call is refused. Always carries that envelope. */
|
|
56
|
+
/** The callee answered, and the envelope itself says the call is refused. Always carries that envelope, and an `errorMessage` refusal always carries its message. */
|
|
57
57
|
export type LambderInvokeEnvelopeFailure = LambderInvokeFailureFields & {
|
|
58
|
-
reason: 'versionExpired' | 'sessionExpired' | 'notAuthorized' | 'errorMessage';
|
|
59
58
|
response: LambderApiEnvelopeBody<any>;
|
|
60
59
|
/** The callee's crash detail, when its global error handler sent one (the envelope's `crash` field). */
|
|
61
60
|
crash?: LambderCrashDetail;
|
|
62
|
-
}
|
|
61
|
+
} & ({
|
|
62
|
+
reason: 'versionExpired' | 'sessionExpired' | 'notAuthorized';
|
|
63
|
+
} | {
|
|
64
|
+
reason: 'errorMessage';
|
|
65
|
+
errorMessage: LambderAppRefusalMessage;
|
|
66
|
+
});
|
|
63
67
|
/**
|
|
64
68
|
* Nothing usable came back: the invoke never arrived or was given up on, the
|
|
65
69
|
* Lambda service answered instead of the callee, the callee answered 5xx, or
|
|
@@ -74,13 +78,11 @@ export type LambderInvokeDeliveryFailure = LambderInvokeFailureFields & {
|
|
|
74
78
|
crash?: LambderCrashDetail;
|
|
75
79
|
};
|
|
76
80
|
/**
|
|
77
|
-
* A failed invoke, discriminated by `reason`
|
|
78
|
-
*
|
|
79
|
-
* actually carries: `zodError` after `validation`, `functionError` after
|
|
81
|
+
* A failed invoke, discriminated by `reason` so narrowing to a reason narrows
|
|
82
|
+
* to what it carries: `zodError` after `validation`, `functionError` after
|
|
80
83
|
* `crash`, `bytes` after `payloadTooLarge`, `response` after an envelope
|
|
81
|
-
* reason,
|
|
82
|
-
*
|
|
83
|
-
* discriminated the same way.
|
|
84
|
+
* reason, with no optional chain or `!` for a guaranteed field. The browser
|
|
85
|
+
* caller's LambderApiOutcome is discriminated the same way.
|
|
84
86
|
*
|
|
85
87
|
* `error`, `logList` and `cookies` are on every arm, and `status`,
|
|
86
88
|
* `errorMessage` and `retryAfterSeconds` are there whenever an answer came
|
|
@@ -94,10 +96,10 @@ export type LambderInvokeOutcome<T> = {
|
|
|
94
96
|
logList: unknown[];
|
|
95
97
|
/**
|
|
96
98
|
* The answer's Set-Cookie values. A caller carrying a user's session
|
|
97
|
-
* is the browser for that call
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
99
|
+
* is the browser for that call: a callee that rotated or cleared the
|
|
100
|
+
* session cookies says so here, and a caller that ignores them keeps
|
|
101
|
+
* sending the old token. See reissueSession() on the callee for the
|
|
102
|
+
* tokens themselves.
|
|
101
103
|
*/
|
|
102
104
|
cookies: string[];
|
|
103
105
|
} | LambderInvokeFailure;
|
|
@@ -107,7 +109,7 @@ export type LambderInvokeErrorInit = {
|
|
|
107
109
|
apiName: string;
|
|
108
110
|
functionName: string;
|
|
109
111
|
status?: number;
|
|
110
|
-
errorMessage?:
|
|
112
|
+
errorMessage?: LambderAppRefusalMessage;
|
|
111
113
|
crash?: LambderCrashDetail;
|
|
112
114
|
functionError?: LambderInvokeFunctionError;
|
|
113
115
|
logList: unknown[];
|
|
@@ -130,7 +132,7 @@ export declare class LambderInvokeError extends Error {
|
|
|
130
132
|
readonly apiName: string;
|
|
131
133
|
readonly functionName: string;
|
|
132
134
|
readonly status?: number;
|
|
133
|
-
readonly errorMessage?:
|
|
135
|
+
readonly errorMessage?: LambderAppRefusalMessage;
|
|
134
136
|
readonly crash?: LambderCrashDetail;
|
|
135
137
|
readonly functionError?: LambderInvokeFunctionError;
|
|
136
138
|
readonly logList: unknown[];
|
|
@@ -150,10 +152,9 @@ export declare const isLambderInvokeError: (err: unknown) => err is LambderInvok
|
|
|
150
152
|
* SDK throws its service exceptions (AccessDeniedException,
|
|
151
153
|
* ResourceNotFoundException, RequestEntityTooLargeException and the rest)
|
|
152
154
|
* with a $fault mark and a name ending in "Exception", while a connectivity
|
|
153
|
-
* failure
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
* it to look at their connection instead.
|
|
155
|
+
* failure is a plain Error or TypeError with neither. A service exception is
|
|
156
|
+
* a permission, wiring or size fault to fix; calling it `network` would send
|
|
157
|
+
* the reader to check their connection instead.
|
|
157
158
|
*/
|
|
158
159
|
export declare const classifyDeliveryFailure: (error: Error) => "network" | "protocol";
|
|
159
160
|
/** Lambda's error payload as an Error, with the callee's own name and trace. */
|
|
@@ -4,12 +4,11 @@
|
|
|
4
4
|
* rejected delivery means, what Lambda's error payload says, the one-line
|
|
5
5
|
* detail an error message ends with).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Kept apart from LambderInvokeCaller, as shared/wire/LambderApiOutcome.ts is
|
|
8
|
+
* kept apart from the browser caller: this is the vocabulary a CALLER of the
|
|
9
9
|
* caller reads, and a site that only annotates an outcome or narrows an error
|
|
10
|
-
* should not have to read
|
|
11
|
-
* touch
|
|
12
|
-
* answer is in one file.
|
|
10
|
+
* should not have to read the whole class to find it. None of these functions
|
|
11
|
+
* touch the caller's state.
|
|
13
12
|
*/
|
|
14
13
|
import { isLambderTransportFailure } from "../shared/transport/LambderApiTransport.js";
|
|
15
14
|
/**
|
|
@@ -63,10 +62,9 @@ export const isLambderInvokeError = (err) => err instanceof Error && err.isLambd
|
|
|
63
62
|
* SDK throws its service exceptions (AccessDeniedException,
|
|
64
63
|
* ResourceNotFoundException, RequestEntityTooLargeException and the rest)
|
|
65
64
|
* with a $fault mark and a name ending in "Exception", while a connectivity
|
|
66
|
-
* failure
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* it to look at their connection instead.
|
|
65
|
+
* failure is a plain Error or TypeError with neither. A service exception is
|
|
66
|
+
* a permission, wiring or size fault to fix; calling it `network` would send
|
|
67
|
+
* the reader to check their connection instead.
|
|
70
68
|
*/
|
|
71
69
|
export const classifyDeliveryFailure = (error) => {
|
|
72
70
|
if (isLambderTransportFailure(error))
|
|
@@ -102,19 +100,8 @@ export const describeFailure = (init) => {
|
|
|
102
100
|
return init.crash.message;
|
|
103
101
|
if (init.functionError)
|
|
104
102
|
return `${init.functionError.errorType ?? "FunctionError"}: ${init.functionError.errorMessage ?? "the function failed"}`;
|
|
105
|
-
if (init.errorMessage !== undefined)
|
|
106
|
-
|
|
107
|
-
if (typeof content === "string")
|
|
108
|
-
return content;
|
|
109
|
-
if (typeof init.errorMessage === "string")
|
|
110
|
-
return init.errorMessage;
|
|
111
|
-
try {
|
|
112
|
-
return JSON.stringify(init.errorMessage);
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
return String(init.errorMessage);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
103
|
+
if (init.errorMessage !== undefined)
|
|
104
|
+
return init.errorMessage.content;
|
|
118
105
|
if (init.reason === 'validation')
|
|
119
106
|
return "the callee rejected the input";
|
|
120
107
|
if (init.reason === 'versionExpired')
|
|
@@ -11,7 +11,12 @@
|
|
|
11
11
|
import type { APIGatewayProxyEvent, APIGatewayProxyEventV2, Context } from "aws-lambda";
|
|
12
12
|
import type { LambderHttpEventFormat } from "../core/LambderContext.js";
|
|
13
13
|
import type { LambderCompressedBrotliPayload, LambderCompressedGzipPayload } from "../shared/wire/LambderRequestPayload.js";
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Marks a synthesized request as an invoke, for guards and hooks that want to
|
|
16
|
+
* tell. Not an authorization: over HTTP it is a header any client can send.
|
|
17
|
+
* The server itself tells an invoke by its requestContext.apiId, which no
|
|
18
|
+
* gateway lets a client write (see LAMBDER_INVOKE_API_ID).
|
|
19
|
+
*/
|
|
15
20
|
export declare const LAMBDER_INVOKE_HEADER = "x-lambder-invoke";
|
|
16
21
|
/** The invoking function's name, when the caller runs in Lambda; for the callee's logs. */
|
|
17
22
|
export declare const LAMBDER_INVOKED_BY_HEADER = "x-lambder-invoked-by";
|
|
@@ -33,21 +38,36 @@ export type LambderSynthesizedRequest = {
|
|
|
33
38
|
clientIp?: string;
|
|
34
39
|
cookies?: string[];
|
|
35
40
|
body?: string | Buffer;
|
|
41
|
+
/**
|
|
42
|
+
* The body's type, owned by the event over any Content-Type in `headers`:
|
|
43
|
+
* an API call's envelope is JSON whatever headers a caller forwards, and
|
|
44
|
+
* a server takes a POST to its API path as an API call only when it says
|
|
45
|
+
* so. Left out, a caller's own Content-Type stands, and a body without
|
|
46
|
+
* one is typed by its kind.
|
|
47
|
+
*/
|
|
48
|
+
contentType?: string;
|
|
36
49
|
};
|
|
37
50
|
/**
|
|
38
51
|
* The event API Gateway would deliver for this request: payload format 2.0
|
|
39
|
-
* (an HTTP API,
|
|
40
|
-
* API's. An invoke is always 2.0;
|
|
41
|
-
* that wants the handler to meet
|
|
52
|
+
* (an HTTP API's, whose path arrives decoded) unless `eventFormat: "v1"` asks
|
|
53
|
+
* for the REST API's, whose path arrives as written. An invoke is always 2.0;
|
|
54
|
+
* the other format is for an in-process call that wants the handler to meet
|
|
55
|
+
* the shape its own deployment delivers.
|
|
42
56
|
* `invoke: true` adds the invoke marker headers a server-to-server call
|
|
43
57
|
* carries; a browser-shaped request (the handler transport) leaves them off.
|
|
44
58
|
*
|
|
45
59
|
* The client address is `clientIp` and reaches the callee as the gateway's
|
|
46
|
-
* observed source address
|
|
47
|
-
* requestContext.identity.sourceIp on a REST API event).
|
|
48
|
-
* x-forwarded-for
|
|
49
|
-
*
|
|
50
|
-
*
|
|
60
|
+
* observed source address (requestContext.http.sourceIp, or
|
|
61
|
+
* requestContext.identity.sourceIp on a REST API event). On an invoke it is
|
|
62
|
+
* the only channel, and x-forwarded-for is dropped from the caller's
|
|
63
|
+
* `headers`: a server of this version reads no trusted forwarding header on
|
|
64
|
+
* an event carrying LAMBDER_INVOKE_API_ID, but a callee on Lambder 7.x reads
|
|
65
|
+
* the one it trusts on any event, so a gateway lambda forwarding a browser's
|
|
66
|
+
* headers would hand it a ctx.ip the browser chose. x-forwarded-for is the
|
|
67
|
+
* header a gateway writes and the one such a callee trusts in the common
|
|
68
|
+
* case. A browser-shaped request keeps every header it was given: it stands
|
|
69
|
+
* for what a gateway delivered, and a test that writes a forwarding header
|
|
70
|
+
* on one is exercising the app's own trustedClientIpHeaders.
|
|
51
71
|
*/
|
|
52
72
|
export declare function synthesizeLambdaHttpEvent(request: LambderSynthesizedRequest, options: {
|
|
53
73
|
invoke: boolean;
|