lambder 7.3.1 → 8.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +933 -3
- package/README.md +41 -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/freshProcessVerifier.d.ts +13 -0
- package/dist/build/freshProcessVerifier.js +19 -0
- package/dist/build/writeApiSignatures.d.ts +109 -0
- package/dist/build/writeApiSignatures.js +222 -0
- package/dist/build.d.ts +9 -0
- package/dist/build.js +8 -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/lambderFetchTransport.d.ts +4 -1
- package/dist/client/lambderFetchTransport.js +52 -28
- package/dist/client.d.ts +5 -3
- package/dist/client.js +2 -1
- package/dist/core/Lambder.d.ts +140 -75
- package/dist/core/Lambder.js +347 -227
- 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 +15 -8
- package/dist/index.js +5 -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 +33 -29
- package/dist/mock/lambderMockMswHandler.js +50 -39
- package/dist/mock.d.ts +1 -1
- package/dist/mock.js +2 -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/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/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/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 +107 -32
- package/dist/shared/wire/LambderApiOutcome.d.ts +43 -31
- package/dist/shared/wire/LambderApiOutcome.js +48 -23
- package/dist/shared/wire/LambderApiRefusal.d.ts +39 -27
- package/dist/shared/wire/LambderApiRefusal.js +36 -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/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 +79 -33
- 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/LambderS3FileSource.d.ts +21 -6
- package/dist/stores/LambderS3FileSource.js +12 -7
- package/dist/testing/LambderTestApp.d.ts +21 -23
- 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 +1 -0
- package/dist/testing.js +1 -0
- package/package.json +12 -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
|
@@ -16,9 +16,9 @@ export type LambderApiTransportRequest = {
|
|
|
16
16
|
token: string;
|
|
17
17
|
/**
|
|
18
18
|
* The cookie name the caller reads that token from. A transport that
|
|
19
|
-
* fills the token in itself (the cookie-jar decorator,
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* fills the token in itself (the cookie-jar decorator, with no document
|
|
20
|
+
* to read) needs the same name; taking it from the caller keeps the two
|
|
21
|
+
* from being configured apart.
|
|
22
22
|
*/
|
|
23
23
|
csrfCookieKey?: string;
|
|
24
24
|
siteHost: string;
|
|
@@ -36,10 +36,9 @@ export type LambderApiTransportRequest = {
|
|
|
36
36
|
};
|
|
37
37
|
/**
|
|
38
38
|
* Why a transport could not deliver a call. `network` is the default reading
|
|
39
|
-
* of a rejection: nothing came back. `protocol`
|
|
40
|
-
* callee
|
|
41
|
-
*
|
|
42
|
-
* wiring fault and should not be reported to a developer as flaky
|
|
39
|
+
* of a rejection: nothing came back. `protocol` means the call reached the
|
|
40
|
+
* callee but produced no answer (what came back was not one, or the callee
|
|
41
|
+
* threw): a server or wiring fault, not to be reported as flaky
|
|
43
42
|
* connectivity. `timeout` belongs to the caller, which knows whether its own
|
|
44
43
|
* abort fired.
|
|
45
44
|
*/
|
|
@@ -60,27 +59,28 @@ export declare class LambderTransportFailure extends Error {
|
|
|
60
59
|
export declare const isLambderTransportFailure: (err: unknown) => err is LambderTransportFailure;
|
|
61
60
|
/**
|
|
62
61
|
* Delivers one call and hands back the answer in the accessor form
|
|
63
|
-
* resolveApiOutcome() reads. What a transport owes its caller
|
|
64
|
-
* but this contract stands between a call and a wrong outcome:
|
|
62
|
+
* resolveApiOutcome() reads. What a transport owes its caller:
|
|
65
63
|
*
|
|
66
64
|
* - **Any HTTP status is an answer.** A 4xx or 5xx resolves, status and body
|
|
67
65
|
* included, because resolveApiOutcome() is the one place that reads what a
|
|
68
|
-
* status means.
|
|
69
|
-
*
|
|
66
|
+
* status means. Rejecting on a status would throw away the envelope a
|
|
67
|
+
* refusal, a validation failure or a crash arrived in.
|
|
70
68
|
* - **A rejection is a transport failure.** The caller reports it as
|
|
71
|
-
* `network`
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* `cause`, where the caller's `outcome.error` carries it.
|
|
69
|
+
* `network`, as `timeout` when its own abort fired, or as the reason a
|
|
70
|
+
* thrown LambderTransportFailure names. That failure's `cause` carries the
|
|
71
|
+
* real error through to the caller's `outcome.error`.
|
|
75
72
|
* - **`request.signal` must be honoured**, by rejecting as soon as it aborts.
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* obligation is to stop waiting, not to stop the callee.
|
|
73
|
+
* Without that, the caller's `timeoutMs` and per-call `signal` mean
|
|
74
|
+
* nothing and a call waits as long as the callee takes. Work already begun
|
|
75
|
+
* need not be cancellable (an in-process handler is not); the obligation
|
|
76
|
+
* is to stop waiting, not to stop the callee.
|
|
81
77
|
* - **Timeouts and retries belong to the caller.** A transport starts no
|
|
82
78
|
* clock of its own and retries nothing, so one call is one delivery
|
|
83
79
|
* attempt and an idempotency key means what it says.
|
|
80
|
+
* - **A transport that keeps the session's cookies itself reports its CSRF
|
|
81
|
+
* tokens** on the answer (`csrfTokens`), the one it posted and a read of the
|
|
82
|
+
* one it holds, since the caller otherwise judges a sessionExpired by
|
|
83
|
+
* document.cookie, which such a transport never writes.
|
|
84
84
|
*
|
|
85
85
|
* Four transports ship: fetch (lambderFetchTransport, the browser default),
|
|
86
86
|
* an in-process Lambder handler (lambderHandlerTransport, for tests), the
|
|
@@ -89,16 +89,16 @@ export declare const isLambderTransportFailure: (err: unknown) => err is Lambder
|
|
|
89
89
|
*/
|
|
90
90
|
export type LambderApiTransport = (request: LambderApiTransportRequest) => Promise<LambderApiHttpAnswer>;
|
|
91
91
|
/**
|
|
92
|
-
* The fields of the request envelope, in
|
|
93
|
-
*
|
|
92
|
+
* The fields of the request envelope, in wire order: the one statement of
|
|
93
|
+
* what a call sends, for every sender.
|
|
94
94
|
*
|
|
95
95
|
* Two senders write it. A transport hands the payload over as a value
|
|
96
96
|
* (buildTransportEnvelope, below); LambderInvokeCaller has already serialized
|
|
97
|
-
* its payload to decide
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
97
|
+
* its payload to decide on compression, and splices that JSON onto the end
|
|
98
|
+
* rather than parsing and stringifying it again (buildEnvelopeJson, in
|
|
99
|
+
* invoke/LambderLambdaEvent.ts). The splice builds on this function so a new
|
|
100
|
+
* envelope field cannot reach one sender and miss the other, which nothing on
|
|
101
|
+
* the wire would catch.
|
|
102
102
|
*/
|
|
103
103
|
export declare const buildEnvelopeFields: (fields: {
|
|
104
104
|
apiName: string;
|
|
@@ -15,16 +15,16 @@ export class LambderTransportFailure extends Error {
|
|
|
15
15
|
/** Brand-based type guard, so a duplicate install of the package still matches. */
|
|
16
16
|
export const isLambderTransportFailure = (err) => err instanceof Error && err.isLambderTransportFailure === true;
|
|
17
17
|
/**
|
|
18
|
-
* The fields of the request envelope, in
|
|
19
|
-
*
|
|
18
|
+
* The fields of the request envelope, in wire order: the one statement of
|
|
19
|
+
* what a call sends, for every sender.
|
|
20
20
|
*
|
|
21
21
|
* Two senders write it. A transport hands the payload over as a value
|
|
22
22
|
* (buildTransportEnvelope, below); LambderInvokeCaller has already serialized
|
|
23
|
-
* its payload to decide
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
23
|
+
* its payload to decide on compression, and splices that JSON onto the end
|
|
24
|
+
* rather than parsing and stringifying it again (buildEnvelopeJson, in
|
|
25
|
+
* invoke/LambderLambdaEvent.ts). The splice builds on this function so a new
|
|
26
|
+
* envelope field cannot reach one sender and miss the other, which nothing on
|
|
27
|
+
* the wire would catch.
|
|
28
28
|
*/
|
|
29
29
|
export const buildEnvelopeFields = (fields) => ({
|
|
30
30
|
apiName: fields.apiName,
|
|
@@ -36,28 +36,23 @@ export declare const parseSetCookie: (header: string, now: number, requestPath?:
|
|
|
36
36
|
* in-process handler transport in a Node test, and the mock runtime's direct
|
|
37
37
|
* transport. It stores what an answer's Set-Cookie headers set, honours their
|
|
38
38
|
* expiry and deletion, and hands back the Cookie pairs the next request should
|
|
39
|
-
* carry. One jar is one browser
|
|
39
|
+
* carry. One jar is one browser.
|
|
40
40
|
*
|
|
41
|
-
* The rules
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* hand-rolled jar either trusts `Domain=co.uk` or bans every two-label domain.
|
|
41
|
+
* The rules (domain and path matching, default-path, Max-Age against Expires,
|
|
42
|
+
* Secure, HttpOnly, the __Host-/__Secure- prefixes) are tough-cookie's, the
|
|
43
|
+
* reference RFC 6265 implementation, imported for its public suffix list:
|
|
44
|
+
* counting labels can tell `Domain=com` is a registry suffix but not `co.uk`,
|
|
45
|
+
* so a hand-rolled jar either trusts `Domain=co.uk` or bans every two-label
|
|
46
|
+
* domain.
|
|
48
47
|
*
|
|
49
|
-
* What stays Lambder's is the shape of
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* anything: a jar pointed at a single host is the ordinary case, and refusing
|
|
55
|
-
* to answer it until it can name that host would make the common setup the
|
|
56
|
-
* awkward one.
|
|
48
|
+
* What stays Lambder's is the shape of a transport's questions: Set-Cookie
|
|
49
|
+
* header lists in (storeSetCookies), `name=value` pairs out (cookiePairs),
|
|
50
|
+
* and a target given as host and path, since a transport that never speaks
|
|
51
|
+
* HTTP has no URL. An omitted field matches anything, because a jar pointed
|
|
52
|
+
* at a single host is the ordinary case and should not have to name it.
|
|
57
53
|
*
|
|
58
|
-
* SameSite is stored but never consulted
|
|
59
|
-
* initiate this", and
|
|
60
|
-
* is same-site by construction.
|
|
54
|
+
* SameSite is stored but never consulted: it answers "did another site
|
|
55
|
+
* initiate this", and every transport call is same-site by construction.
|
|
61
56
|
*/
|
|
62
57
|
export declare class LambderCookieJar {
|
|
63
58
|
private readonly jar;
|
|
@@ -76,25 +71,24 @@ export declare class LambderCookieJar {
|
|
|
76
71
|
* came from. Its `host` is the sending host, which every Domain is checked
|
|
77
72
|
* against, and its `path` is the default Path of a cookie that names none.
|
|
78
73
|
*
|
|
79
|
-
* A Domain the sender is not under
|
|
80
|
-
* (RFC 6265 section 5.3 step 6), and so does a Domain
|
|
81
|
-
*
|
|
82
|
-
*
|
|
74
|
+
* A Domain the sender is not under voids the cookie rather than narrowing
|
|
75
|
+
* it (RFC 6265 section 5.3 step 6), and so does a public-suffix Domain.
|
|
76
|
+
* Otherwise evil.example.com could plant a cookie that bank.example.com
|
|
77
|
+
* is handed on the next call.
|
|
83
78
|
*/
|
|
84
79
|
storeSetCookies(headers: readonly string[], request?: LambderCookieTarget): void;
|
|
85
80
|
/** Every live cookie. */
|
|
86
81
|
list(): LambderStoredCookie[];
|
|
87
82
|
/**
|
|
88
83
|
* The Cookie header pairs the next request carries, as `name=value`, in
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
84
|
+
* RFC 6265 section 5.4 order: longest Path first, and among equal paths
|
|
85
|
+
* the one set first. Servers that read only the first value of a repeated
|
|
86
|
+
* name depend on that order, as does any test about which of two
|
|
87
|
+
* same-named cookies wins.
|
|
93
88
|
*
|
|
94
|
-
* Only
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* of the one host its jar talks to.
|
|
89
|
+
* Only cookies whose scope covers the target travel. An omitted target
|
|
90
|
+
* field matches anything, so a caller that cannot name its host still
|
|
91
|
+
* gets the cookies of the one host its jar talks to.
|
|
98
92
|
*/
|
|
99
93
|
cookiePairs(target?: LambderCookieTarget): string[];
|
|
100
94
|
/**
|
|
@@ -107,10 +101,9 @@ export declare class LambderCookieJar {
|
|
|
107
101
|
} & LambderCookieTarget): string | undefined;
|
|
108
102
|
/**
|
|
109
103
|
* The live cookies whose scope reaches this target, in RFC 6265 send
|
|
110
|
-
* order. Delegated to tough-cookie whenever
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* need one and ordered by the same rule.
|
|
104
|
+
* order. Delegated to tough-cookie whenever a host is known, the case
|
|
105
|
+
* worth getting exactly right; with no host, every cookie the jar holds
|
|
106
|
+
* is filtered by the rules that need none and ordered the same way.
|
|
114
107
|
*/
|
|
115
108
|
private matchingCookies;
|
|
116
109
|
/** Number of live cookies. */
|
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
import { Cookie, CookieJar as ToughCookieJar, defaultPath, pathMatch } from "tough-cookie";
|
|
7
7
|
/**
|
|
8
8
|
* Stands in for the host of a jar that was never told one. Every store and
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* can never
|
|
12
|
-
* target by accident.
|
|
9
|
+
* read of such a jar uses it, so the jar behaves consistently as the browser
|
|
10
|
+
* of one unnamed host. `.invalid` is IANA-reserved, so a cookie parked here
|
|
11
|
+
* can never match a real target by accident.
|
|
13
12
|
*/
|
|
14
13
|
const UNNAMED_JAR_HOST = "lambder-cookie-jar.invalid";
|
|
15
14
|
/** The host without its port, lowercased: "App.Test:3000" is "app.test", "[::1]:8080" is "[::1]". */
|
|
@@ -28,12 +27,11 @@ const urlFor = (host, path, secure) => `${secure ? "https" : "http"}://${host}${
|
|
|
28
27
|
/**
|
|
29
28
|
* When a cookie actually dies, as an absolute moment.
|
|
30
29
|
*
|
|
31
|
-
* Max-Age and Expires are stored separately and Max-Age wins, so reading
|
|
32
|
-
* `expires`
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* arrived, which is its creation.
|
|
30
|
+
* Max-Age and Expires are stored separately and Max-Age wins, so reading
|
|
31
|
+
* `expires` alone would call a `Max-Age=0` deletion immortal. The library's
|
|
32
|
+
* expiryTime() resolves Max-Age against whatever moment it is handed (or
|
|
33
|
+
* lastAccessed), so it cannot answer "when does this die" on a fixed clock.
|
|
34
|
+
* A browser measures Max-Age from when the cookie arrived, its creation.
|
|
37
35
|
*/
|
|
38
36
|
const cookieExpiryAt = (cookie, now) => {
|
|
39
37
|
if (typeof cookie.maxAge === "number") {
|
|
@@ -50,8 +48,8 @@ const storedFromCookie = (cookie, now) => {
|
|
|
50
48
|
name: cookie.key ?? "",
|
|
51
49
|
value: cookie.value ?? "",
|
|
52
50
|
domain: hostOnly ? undefined : domain,
|
|
53
|
-
// A jar that never learned a host
|
|
54
|
-
//
|
|
51
|
+
// A jar that never learned a host parks cookies under the stand-in,
|
|
52
|
+
// an implementation detail rather than something it knows.
|
|
55
53
|
...(hostOnly && domain !== undefined && domain !== UNNAMED_JAR_HOST ? { host: domain } : {}),
|
|
56
54
|
path: typeof cookie.path === "string" ? cookie.path : "/",
|
|
57
55
|
expires: expiryAt,
|
|
@@ -68,11 +66,11 @@ export const parseSetCookie = (header, now, requestPath) => {
|
|
|
68
66
|
const parsed = Cookie.parse(header, { loose: false });
|
|
69
67
|
if (!parsed)
|
|
70
68
|
return null;
|
|
71
|
-
// Cookie.parse stamps creation with the real clock, but
|
|
72
|
-
//
|
|
69
|
+
// Cookie.parse stamps creation with the real clock, but Max-Age is
|
|
70
|
+
// measured from the caller's `now`, when this header arrived.
|
|
73
71
|
parsed.creation = new Date(now);
|
|
74
|
-
//
|
|
75
|
-
//
|
|
72
|
+
// Max-Age against Expires on the caller's clock, as the jar resolves it,
|
|
73
|
+
// so a test moving time forward reads the same expiry here.
|
|
76
74
|
return {
|
|
77
75
|
...storedFromCookie(parsed, now),
|
|
78
76
|
// Cookie.parse leaves an absent Path absent; the default-path is the
|
|
@@ -85,28 +83,23 @@ export const parseSetCookie = (header, now, requestPath) => {
|
|
|
85
83
|
* in-process handler transport in a Node test, and the mock runtime's direct
|
|
86
84
|
* transport. It stores what an answer's Set-Cookie headers set, honours their
|
|
87
85
|
* expiry and deletion, and hands back the Cookie pairs the next request should
|
|
88
|
-
* carry. One jar is one browser
|
|
86
|
+
* carry. One jar is one browser.
|
|
89
87
|
*
|
|
90
|
-
* The rules
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* hand-rolled jar either trusts `Domain=co.uk` or bans every two-label domain.
|
|
88
|
+
* The rules (domain and path matching, default-path, Max-Age against Expires,
|
|
89
|
+
* Secure, HttpOnly, the __Host-/__Secure- prefixes) are tough-cookie's, the
|
|
90
|
+
* reference RFC 6265 implementation, imported for its public suffix list:
|
|
91
|
+
* counting labels can tell `Domain=com` is a registry suffix but not `co.uk`,
|
|
92
|
+
* so a hand-rolled jar either trusts `Domain=co.uk` or bans every two-label
|
|
93
|
+
* domain.
|
|
97
94
|
*
|
|
98
|
-
* What stays Lambder's is the shape of
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* anything: a jar pointed at a single host is the ordinary case, and refusing
|
|
104
|
-
* to answer it until it can name that host would make the common setup the
|
|
105
|
-
* awkward one.
|
|
95
|
+
* What stays Lambder's is the shape of a transport's questions: Set-Cookie
|
|
96
|
+
* header lists in (storeSetCookies), `name=value` pairs out (cookiePairs),
|
|
97
|
+
* and a target given as host and path, since a transport that never speaks
|
|
98
|
+
* HTTP has no URL. An omitted field matches anything, because a jar pointed
|
|
99
|
+
* at a single host is the ordinary case and should not have to name it.
|
|
106
100
|
*
|
|
107
|
-
* SameSite is stored but never consulted
|
|
108
|
-
* initiate this", and
|
|
109
|
-
* is same-site by construction.
|
|
101
|
+
* SameSite is stored but never consulted: it answers "did another site
|
|
102
|
+
* initiate this", and every transport call is same-site by construction.
|
|
110
103
|
*/
|
|
111
104
|
export class LambderCookieJar {
|
|
112
105
|
// prefixSecurity "silent" drops a __Host-/__Secure- cookie that breaks its
|
|
@@ -129,25 +122,23 @@ export class LambderCookieJar {
|
|
|
129
122
|
* came from. Its `host` is the sending host, which every Domain is checked
|
|
130
123
|
* against, and its `path` is the default Path of a cookie that names none.
|
|
131
124
|
*
|
|
132
|
-
* A Domain the sender is not under
|
|
133
|
-
* (RFC 6265 section 5.3 step 6), and so does a Domain
|
|
134
|
-
*
|
|
135
|
-
*
|
|
125
|
+
* A Domain the sender is not under voids the cookie rather than narrowing
|
|
126
|
+
* it (RFC 6265 section 5.3 step 6), and so does a public-suffix Domain.
|
|
127
|
+
* Otherwise evil.example.com could plant a cookie that bank.example.com
|
|
128
|
+
* is handed on the next call.
|
|
136
129
|
*/
|
|
137
130
|
storeSetCookies(headers, request = {}) {
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
// the jar held a session it could not use and said nothing.
|
|
131
|
+
// A cookie is judged against the channel it arrived on. Assuming https
|
|
132
|
+
// would accept Secure cookies from a plain-http answer and then never
|
|
133
|
+
// send them, leaving the jar silently holding an unusable session.
|
|
142
134
|
const secure = request.secure !== false;
|
|
143
135
|
const url = urlFor(this.hostFor(request.host), request.path, secure);
|
|
144
136
|
const now = new Date(this.now());
|
|
145
137
|
for (const header of headers) {
|
|
146
|
-
// tough-cookie checks
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
// keep.
|
|
138
|
+
// tough-cookie checks Domain, prefixes and HttpOnly against the
|
|
139
|
+
// URL but leaves Secure to the caller: RFC 6265 lets plain http
|
|
140
|
+
// set one, browsers do not. A cookie this jar would refuse to send
|
|
141
|
+
// is one it refuses to keep.
|
|
151
142
|
if (!secure && Cookie.parse(header, { loose: false })?.secure)
|
|
152
143
|
continue;
|
|
153
144
|
// ignoreError: a cookie a browser would refuse is one this jar
|
|
@@ -166,15 +157,14 @@ export class LambderCookieJar {
|
|
|
166
157
|
}
|
|
167
158
|
/**
|
|
168
159
|
* The Cookie header pairs the next request carries, as `name=value`, in
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
160
|
+
* RFC 6265 section 5.4 order: longest Path first, and among equal paths
|
|
161
|
+
* the one set first. Servers that read only the first value of a repeated
|
|
162
|
+
* name depend on that order, as does any test about which of two
|
|
163
|
+
* same-named cookies wins.
|
|
173
164
|
*
|
|
174
|
-
* Only
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* of the one host its jar talks to.
|
|
165
|
+
* Only cookies whose scope covers the target travel. An omitted target
|
|
166
|
+
* field matches anything, so a caller that cannot name its host still
|
|
167
|
+
* gets the cookies of the one host its jar talks to.
|
|
178
168
|
*/
|
|
179
169
|
cookiePairs(target = {}) {
|
|
180
170
|
return this.matchingCookies(target).map((cookie) => `${cookie.name}=${cookie.value}`);
|
|
@@ -190,10 +180,9 @@ export class LambderCookieJar {
|
|
|
190
180
|
}
|
|
191
181
|
/**
|
|
192
182
|
* The live cookies whose scope reaches this target, in RFC 6265 send
|
|
193
|
-
* order. Delegated to tough-cookie whenever
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
* need one and ordered by the same rule.
|
|
183
|
+
* order. Delegated to tough-cookie whenever a host is known, the case
|
|
184
|
+
* worth getting exactly right; with no host, every cookie the jar holds
|
|
185
|
+
* is filtered by the rules that need none and ordered the same way.
|
|
197
186
|
*/
|
|
198
187
|
matchingCookies(target, includeHttpOnly = true) {
|
|
199
188
|
const secure = target.secure !== false;
|
|
@@ -209,7 +198,7 @@ export class LambderCookieJar {
|
|
|
209
198
|
allPaths: target.path === undefined,
|
|
210
199
|
// tough-cookie returns store order unless asked; RFC 6265
|
|
211
200
|
// order is what a server reading the first of a repeated
|
|
212
|
-
// name
|
|
201
|
+
// name gets.
|
|
213
202
|
sort: true,
|
|
214
203
|
})
|
|
215
204
|
.map((cookie) => storedFromCookie(cookie, this.now()))
|
|
@@ -218,8 +207,8 @@ export class LambderCookieJar {
|
|
|
218
207
|
.filter((cookie) => cookie.expires === undefined || cookie.expires > this.now())
|
|
219
208
|
// tough-cookie treats a loopback or localhost target as a
|
|
220
209
|
// secure context and sends Secure cookies to it over http.
|
|
221
|
-
// This jar takes `secure: false` at its word
|
|
222
|
-
//
|
|
210
|
+
// This jar takes `secure: false` at its word both ways, so
|
|
211
|
+
// what it stores and what it sends agree.
|
|
223
212
|
.filter((cookie) => secure || !cookie.secure);
|
|
224
213
|
}
|
|
225
214
|
return this.list()
|
|
@@ -232,9 +221,8 @@ export class LambderCookieJar {
|
|
|
232
221
|
return false;
|
|
233
222
|
return true;
|
|
234
223
|
})
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
// stored in, which is the order they were created in.
|
|
224
|
+
// Longest path first, as tough-cookie sorts; the sort is stable,
|
|
225
|
+
// so equal paths keep their creation order.
|
|
238
226
|
.sort((a, b) => b.path.length - a.path.length);
|
|
239
227
|
}
|
|
240
228
|
/** Number of live cookies. */
|
|
@@ -3,23 +3,21 @@ import type { LambderCookieJar } from "./LambderCookieJar.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* Makes any transport carry a cookie jar the way a browser carries its
|
|
5
5
|
* cookies: the jar's cookies ride on every request, the answer's Set-Cookie
|
|
6
|
-
* headers land in the jar, and,
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* headers land in the jar, and, as a page's script reads the non-HttpOnly
|
|
7
|
+
* CSRF cookie, the request's `token` is filled from the jar when the caller
|
|
8
|
+
* sent an empty one. This is how a session survives between calls without a
|
|
9
|
+
* browser: in a Node test through lambderHandlerTransport, or in the mock
|
|
10
|
+
* runtime's direct transport.
|
|
11
11
|
*
|
|
12
12
|
* The jar is only as scoped as the host it is told about. An absolute apiPath
|
|
13
13
|
* carries one, `host` names one when the path is relative, and a browser's
|
|
14
|
-
* caller falls back to its page's
|
|
15
|
-
* relative path from a runtime with no location, so nothing there
|
|
16
|
-
* host
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* into.
|
|
14
|
+
* caller falls back to its page's; an in-process or mock transport posts to a
|
|
15
|
+
* relative path from a runtime with no location, so nothing there names the
|
|
16
|
+
* host. Without any of the three the jar is a single host's and refuses
|
|
17
|
+
* Domain cookies it cannot check (see LambderCookieJar), so give `host` (or
|
|
18
|
+
* the jar one) to any jar that more than one host answers into.
|
|
20
19
|
*
|
|
21
|
-
* Its own file
|
|
22
|
-
* transport like its three siblings, and it is the one of them that pulls in
|
|
20
|
+
* Its own file, like its three sibling transports, because it pulls in
|
|
23
21
|
* tough-cookie, which a bundle that never carries a jar should be able to
|
|
24
22
|
* drop.
|
|
25
23
|
*/
|
|
@@ -3,23 +3,21 @@ import { resolveApiPathTarget } from "./LambderApiTransport.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* Makes any transport carry a cookie jar the way a browser carries its
|
|
5
5
|
* cookies: the jar's cookies ride on every request, the answer's Set-Cookie
|
|
6
|
-
* headers land in the jar, and,
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* headers land in the jar, and, as a page's script reads the non-HttpOnly
|
|
7
|
+
* CSRF cookie, the request's `token` is filled from the jar when the caller
|
|
8
|
+
* sent an empty one. This is how a session survives between calls without a
|
|
9
|
+
* browser: in a Node test through lambderHandlerTransport, or in the mock
|
|
10
|
+
* runtime's direct transport.
|
|
11
11
|
*
|
|
12
12
|
* The jar is only as scoped as the host it is told about. An absolute apiPath
|
|
13
13
|
* carries one, `host` names one when the path is relative, and a browser's
|
|
14
|
-
* caller falls back to its page's
|
|
15
|
-
* relative path from a runtime with no location, so nothing there
|
|
16
|
-
* host
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* into.
|
|
14
|
+
* caller falls back to its page's; an in-process or mock transport posts to a
|
|
15
|
+
* relative path from a runtime with no location, so nothing there names the
|
|
16
|
+
* host. Without any of the three the jar is a single host's and refuses
|
|
17
|
+
* Domain cookies it cannot check (see LambderCookieJar), so give `host` (or
|
|
18
|
+
* the jar one) to any jar that more than one host answers into.
|
|
20
19
|
*
|
|
21
|
-
* Its own file
|
|
22
|
-
* transport like its three siblings, and it is the one of them that pulls in
|
|
20
|
+
* Its own file, like its three sibling transports, because it pulls in
|
|
23
21
|
* tough-cookie, which a bundle that never carries a jar should be able to
|
|
24
22
|
* drop.
|
|
25
23
|
*/
|
|
@@ -31,23 +29,23 @@ export const lambderCookieJarTransport = (inner, options) => {
|
|
|
31
29
|
// through setSessionCookieKey.
|
|
32
30
|
const csrfCookieKey = options.csrfCookieKey ?? request.csrfCookieKey ?? DEFAULT_SESSION_CSRF_COOKIE_KEY;
|
|
33
31
|
// Where the call is going. An apiPath that names its own host is a
|
|
34
|
-
// fact about this request and outranks both the `host` option
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
// every cookie to nothing while claiming to scope it.
|
|
32
|
+
// fact about this request and outranks both the `host` option (the
|
|
33
|
+
// fallback for a relative path) and the caller's siteHost (only the
|
|
34
|
+
// page the caller is on). The other way round, a transport pinned to
|
|
35
|
+
// `host: "app.example.com"` would send that host's session to an
|
|
36
|
+
// absolute cross-origin apiPath. siteHost is "" outside a browser, and
|
|
37
|
+
// an empty host would scope every cookie to nothing while claiming to
|
|
38
|
+
// scope it.
|
|
42
39
|
const target = resolveApiPathTarget(request.apiPath);
|
|
43
40
|
const cookieScope = {
|
|
44
41
|
host: target.host ?? options.host ?? (request.siteHost || undefined),
|
|
45
42
|
path: target.path,
|
|
46
43
|
...(target.secure !== undefined ? { secure: target.secure } : {}),
|
|
47
44
|
};
|
|
45
|
+
const postedToken = request.token || options.jar.get(csrfCookieKey, cookieScope) || "";
|
|
48
46
|
const answer = await inner({
|
|
49
47
|
...request,
|
|
50
|
-
token:
|
|
48
|
+
token: postedToken,
|
|
51
49
|
cookies: [...(request.cookies ?? []), ...options.jar.cookiePairs(cookieScope)],
|
|
52
50
|
});
|
|
53
51
|
// The same scope the request was made under, so a Set-Cookie is judged
|
|
@@ -55,6 +53,9 @@ export const lambderCookieJarTransport = (inner, options) => {
|
|
|
55
53
|
// plain-http target is one this jar could never send back.
|
|
56
54
|
if (answer.setCookies?.length)
|
|
57
55
|
options.jar.storeSetCookies(answer.setCookies, cookieScope);
|
|
58
|
-
|
|
56
|
+
// The session lives in the jar, not in document.cookie, so the caller
|
|
57
|
+
// tells a sessionExpired about an older session (a poll sent before a
|
|
58
|
+
// login) by the jar's token, as a page does by its cookie.
|
|
59
|
+
return { ...answer, csrfTokens: { posted: postedToken, held: () => options.jar.get(csrfCookieKey, cookieScope) ?? "" } };
|
|
59
60
|
};
|
|
60
61
|
};
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
* Both give a call a `timeoutMs`, both let the site pass its own AbortSignal,
|
|
6
6
|
* and both have to answer the same three questions: which signal does the
|
|
7
7
|
* transport get, has the call already been given up on before it is sent, and
|
|
8
|
-
* did the answer arrive after it was given up on.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* 300ms and the call site acted on data it had already abandoned.
|
|
8
|
+
* did the answer arrive after it was given up on. One implementation keeps
|
|
9
|
+
* the two from drifting apart: a caller that believed a late answer would
|
|
10
|
+
* report `ok: true` for a call its site had already abandoned.
|
|
12
11
|
*
|
|
13
12
|
* The listener on an external signal is removed in detach() rather than left
|
|
14
13
|
* to `once`: a site's signal usually outlives the call (one controller per
|
|
@@ -53,7 +52,8 @@ export declare const createCallAbort: (options: {
|
|
|
53
52
|
* the callee runs to completion either way, and what the caller's timeout
|
|
54
53
|
* buys is its own answer. Used by lambderHandlerTransport and by
|
|
55
54
|
* LambderInvokeCaller.localTransport, whose in-process calls are the two
|
|
56
|
-
*
|
|
55
|
+
* transports a signal has nothing to cancel, and by the crash reporter's
|
|
56
|
+
* time bound (LambderCrashHandling), where the app's report runs on.
|
|
57
57
|
*
|
|
58
58
|
* The listener is detached on either outcome, for the reason createCallAbort
|
|
59
59
|
* detaches its own.
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
* Both give a call a `timeoutMs`, both let the site pass its own AbortSignal,
|
|
6
6
|
* and both have to answer the same three questions: which signal does the
|
|
7
7
|
* transport get, has the call already been given up on before it is sent, and
|
|
8
|
-
* did the answer arrive after it was given up on.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* 300ms and the call site acted on data it had already abandoned.
|
|
8
|
+
* did the answer arrive after it was given up on. One implementation keeps
|
|
9
|
+
* the two from drifting apart: a caller that believed a late answer would
|
|
10
|
+
* report `ok: true` for a call its site had already abandoned.
|
|
12
11
|
*
|
|
13
12
|
* The listener on an external signal is removed in detach() rather than left
|
|
14
13
|
* to `once`: a site's signal usually outlives the call (one controller per
|
|
@@ -64,7 +63,8 @@ export const createCallAbort = (options) => {
|
|
|
64
63
|
* the callee runs to completion either way, and what the caller's timeout
|
|
65
64
|
* buys is its own answer. Used by lambderHandlerTransport and by
|
|
66
65
|
* LambderInvokeCaller.localTransport, whose in-process calls are the two
|
|
67
|
-
*
|
|
66
|
+
* transports a signal has nothing to cancel, and by the crash reporter's
|
|
67
|
+
* time bound (LambderCrashHandling), where the app's report runs on.
|
|
68
68
|
*
|
|
69
69
|
* The listener is detached on either outcome, for the reason createCallAbort
|
|
70
70
|
* detaches its own.
|