lambder 9.0.2 → 10.0.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 +195 -0
- package/README.md +29 -14
- package/dist/api/LambderApiDefinition.d.ts +9 -0
- package/dist/api/LambderApiEnvelope.d.ts +22 -10
- package/dist/api/LambderApiEnvelope.js +57 -22
- package/dist/api/LambderApiGuards.d.ts +77 -22
- package/dist/api/LambderApiGuards.js +13 -1
- package/dist/api/LambderApiIdempotency.js +4 -4
- package/dist/api/LambderApiOutputValidationError.d.ts +10 -4
- package/dist/api/LambderApiOutputValidationError.js +14 -6
- package/dist/api/LambderApiPipeline.d.ts +2 -1
- package/dist/api/LambderApiPipeline.js +10 -2
- package/dist/api/LambderApiRateLimits.d.ts +15 -11
- package/dist/api/LambderApiRateLimits.js +31 -7
- package/dist/api/LambderApiRefusals.d.ts +204 -0
- package/dist/api/LambderApiRefusals.js +223 -0
- package/dist/api/LambderApiSignature.d.ts +13 -4
- package/dist/api/LambderApiSignature.js +21 -4
- package/dist/build/writeApiOptions.js +7 -5
- package/dist/client/LambderCaller.d.ts +28 -17
- package/dist/client/LambderCaller.js +19 -15
- package/dist/client/LambderUploadRunner.d.ts +5 -5
- package/dist/client/LambderUploadRunner.js +25 -16
- package/dist/client.d.ts +6 -5
- package/dist/client.js +2 -1
- package/dist/core/Lambder.d.ts +121 -23
- package/dist/core/Lambder.js +105 -51
- package/dist/core/LambderContext.d.ts +1 -1
- package/dist/core/LambderContext.js +5 -0
- package/dist/core/LambderCreateOptions.d.ts +58 -15
- package/dist/core/LambderCreateOptions.js +10 -0
- package/dist/core/LambderPolicyBuilders.d.ts +11 -8
- package/dist/core/LambderPolicyBuilders.js +10 -8
- package/dist/core/LambderResolver.d.ts +1 -1
- package/dist/core/LambderResolver.js +1 -1
- package/dist/core/LambderResponseBuilder.d.ts +11 -9
- package/dist/core/LambderResponseBuilder.js +12 -11
- package/dist/index.d.ts +13 -9
- package/dist/index.js +6 -2
- package/dist/invoke/LambderInvokeCaller.d.ts +5 -6
- package/dist/invoke/LambderInvokeCaller.js +13 -12
- package/dist/invoke/LambderInvokeOutcome.d.ts +32 -23
- package/dist/invoke/LambderInvokeOutcome.js +4 -4
- package/dist/mock/LambderMockApp.d.ts +86 -24
- package/dist/mock/LambderMockApp.js +108 -16
- package/dist/mock/LambderMockCallRecorder.js +6 -3
- package/dist/mock/LambderMockCreateOptions.d.ts +4 -5
- package/dist/mock/LambderMockFailureInjector.d.ts +9 -2
- package/dist/mock/LambderMockFailureInjector.js +18 -4
- package/dist/mock/LambderMockTypes.d.ts +34 -11
- package/dist/mock.d.ts +4 -3
- package/dist/mock.js +4 -3
- package/dist/shared/contracts/LambderUploadBucket.d.ts +18 -3
- package/dist/shared/contracts/LambderUploadBucket.js +2 -2
- package/dist/shared/util/LambderTypeUtilities.d.ts +11 -0
- package/dist/shared/wire/LambderApiContract.d.ts +96 -31
- package/dist/shared/wire/LambderApiOptionEntries.d.ts +19 -12
- package/dist/shared/wire/LambderApiOptionValues.d.ts +15 -6
- package/dist/shared/wire/LambderApiOptionValues.js +3 -3
- package/dist/shared/wire/LambderApiOutcome.d.ts +49 -27
- package/dist/shared/wire/LambderApiOutcome.js +28 -11
- package/dist/shared/wire/LambderApiRefusal.d.ts +127 -42
- package/dist/shared/wire/LambderApiRefusal.js +15 -7
- package/dist/shared/wire/LambderCrashDetail.d.ts +1 -1
- package/dist/shared/wire/LambderCrashDetail.js +1 -1
- package/dist/shared/wire/LambderHttpStatus.d.ts +6 -0
- package/dist/shared/wire/LambderIdempotencyKeyScope.d.ts +3 -2
- package/dist/shared/wire/LambderIdempotencyKeyScope.js +5 -5
- package/dist/shared/wire/LambderObjectPayload.d.ts +15 -0
- package/dist/shared/wire/LambderObjectPayload.js +24 -0
- package/dist/shared/wire/LambderOutcomeAssertions.d.ts +52 -7
- package/dist/shared/wire/LambderOutcomeAssertions.js +34 -8
- package/dist/shared/wire/LambderUploadObjectFields.d.ts +10 -1
- package/dist/shared/wire/LambderUploadObjectFields.js +22 -1
- package/dist/shared/wire/LambderUploadSchemas.d.ts +8 -2
- package/dist/shared/wire/LambderUploadSchemas.js +18 -7
- package/dist/stores/LambderMemoryUploadBucket.d.ts +21 -7
- package/dist/stores/LambderMemoryUploadBucket.js +60 -12
- package/dist/stores/LambderS3UploadBucket.d.ts +22 -3
- package/dist/stores/LambderS3UploadBucket.js +51 -4
- package/dist/testing/LambderTestApp.d.ts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LambderResponse } from "./LambderResponse.js";
|
|
2
|
-
import {
|
|
2
|
+
import { plainRefusalEnvelope } from "../api/LambderApiEnvelope.js";
|
|
3
3
|
/**
|
|
4
4
|
* Builds the responses of routes, hooks and error handlers. An API handler
|
|
5
5
|
* never holds one: it returns its output or refuses, and writes headers and
|
|
@@ -92,7 +92,7 @@ export default class LambderResponseBuilder {
|
|
|
92
92
|
}
|
|
93
93
|
;
|
|
94
94
|
versionExpired(options) {
|
|
95
|
-
return this.
|
|
95
|
+
return this.apiRefusal({ versionExpired: true }, options);
|
|
96
96
|
}
|
|
97
97
|
;
|
|
98
98
|
fileBase64(fileBase64, mimeType, options) {
|
|
@@ -135,16 +135,17 @@ export default class LambderResponseBuilder {
|
|
|
135
135
|
}
|
|
136
136
|
;
|
|
137
137
|
/**
|
|
138
|
-
* An API
|
|
139
|
-
* handler or
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
138
|
+
* An API call answered from outside its handler: what a hook, a fallback,
|
|
139
|
+
* the input validation handler or the global error handler answers with.
|
|
140
|
+
* It is always a refusal (a refusal message, or one of the versionExpired,
|
|
141
|
+
* sessionExpired and notAuthorized flags) with a null payload, so a
|
|
142
|
+
* caller's success is only ever the handler's parsed output. Its message
|
|
143
|
+
* carries a framework code or none, and no data, since it answers outside
|
|
144
|
+
* any one endpoint's declared refusals. The logList channel is what the
|
|
145
|
+
* request accumulated unless the config names its own.
|
|
144
146
|
*/
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return this.json(envelope, options);
|
|
147
|
+
apiRefusal(config, options) {
|
|
148
|
+
return this.json(plainRefusalEnvelope(this.apiVersion, config, "res.apiRefusal()", this.ctx?.logList), options);
|
|
148
149
|
}
|
|
149
150
|
;
|
|
150
151
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -38,18 +38,20 @@ export { apiNameKeyOf, lookupApiSignature, readApiSignature, API_SIGNATURE_HEX_L
|
|
|
38
38
|
export type { LambderApiSignatureMap } from "./shared/wire/LambderApiSignatureMap.js";
|
|
39
39
|
export { RELOAD_LOOP_WINDOW_MS } from "./client/LambderReloadLoopBreaker.js";
|
|
40
40
|
export { compareDottedVersions, isDottedVersion } from "./shared/wire/LambderVersionOrder.js";
|
|
41
|
-
export {
|
|
42
|
-
export type {
|
|
41
|
+
export { successEnvelope, refusalEnvelope, plainRefusalEnvelope, envelopeAnswer, refusalAnswer, validationAnswer, apiNotFoundAnswer, sessionExpiredAnswer, versionExpiredAnswer, invalidPayloadAnswer, crashAnswer, API_ANSWER_CONTENT_TYPE, } from "./api/LambderApiEnvelope.js";
|
|
42
|
+
export type { LambderValidationAnswerBody } from "./api/LambderApiEnvelope.js";
|
|
43
43
|
export { LambderApiValidationRefusal, isLambderApiValidationRefusal } from "./api/LambderApiValidationRefusal.js";
|
|
44
44
|
export { LambderApiOutputValidationError } from "./api/LambderApiOutputValidationError.js";
|
|
45
|
+
export { checkedRefusal } from "./api/LambderApiRefusals.js";
|
|
45
46
|
export { LambderInvokeError, isLambderInvokeError } from "./invoke/LambderInvokeOutcome.js";
|
|
46
47
|
export type { LambderInvokeOutcome, LambderInvokeFailure, LambderInvokeValidationFailure, LambderInvokeCrashFailure, LambderInvokePayloadTooLargeFailure, LambderInvokeEnvelopeFailure, LambderInvokeDeliveryFailure, LambderInvokeFailureReason, LambderInvokeFunctionError, } from "./invoke/LambderInvokeOutcome.js";
|
|
47
48
|
export { default as LambderInvokeCaller, LAMBDER_INVOKE_MAX_EVENT_BYTES, } from "./invoke/LambderInvokeCaller.js";
|
|
48
49
|
export type { LambderInvokeCallerOptions, LambderInvokeCallOptions, LambderInvokeFailureHandler, LambderInvokeLogListHandler, LambderInvokeTransport, LambderInvokeTransportResult, LambderInvokeRequestInit, LambderInvokeEventInit, } from "./invoke/LambderInvokeCaller.js";
|
|
49
50
|
export { describeCrash, errorFromCrashDetail } from "./shared/wire/LambderCrashDetail.js";
|
|
50
51
|
export type { LambderCrashDetail, LambderCrashCause } from "./shared/wire/LambderCrashDetail.js";
|
|
51
|
-
export { LambderApiRefusal, isLambderApiRefusal, refuse, refusalMessageOf, LAMBDER_REFUSAL_CODES } from "./shared/wire/LambderApiRefusal.js";
|
|
52
|
-
export type { LambderApiRefusalOptions, LambderRefusalMessage,
|
|
52
|
+
export { LambderApiRefusal, isLambderApiRefusal, isLambderRefusalCode, refuse, refusalMessageOf, LAMBDER_REFUSAL_CODES } from "./shared/wire/LambderApiRefusal.js";
|
|
53
|
+
export type { LambderApiRefusalOptions, LambderRefusalMessage, LambderPlainRefusalMessage, LambderUncheckedRefusalMessage, LambderRefusalCode, LambderRefuseOptions, LambderDeclaredRefuseOptions, LambderDeclaredRefuse, } from "./shared/wire/LambderApiRefusal.js";
|
|
54
|
+
export { isObjectPayload } from "./shared/wire/LambderObjectPayload.js";
|
|
53
55
|
export { default as LambderResponseBuilder } from "./core/LambderResponseBuilder.js";
|
|
54
56
|
export { default as LambderResolver } from "./core/LambderResolver.js";
|
|
55
57
|
export { default as LambderSessionManager } from "./session/LambderSessionManager.js";
|
|
@@ -64,7 +66,7 @@ export type { LambderSessionCrypto } from "./session/LambderSessionCrypto.js";
|
|
|
64
66
|
export { LambderDdbSessionStore } from "./stores/LambderDdbSessionStore.js";
|
|
65
67
|
export type { LambderDdbSessionStoreOptions } from "./stores/LambderDdbSessionStore.js";
|
|
66
68
|
export { LambderResponse, finalizeResponse, answerFromResponse, responseFromAnswer, type LambderHttpResponse, type LambderHeadersInput, type LambderFinalizeOptions, type LambderResponseCompressionSettings, type LambderResponseCompressionOption, } from "./core/LambderResponse.js";
|
|
67
|
-
export type { LambderHttpStatusCode } from "./shared/wire/LambderHttpStatus.js";
|
|
69
|
+
export type { LambderHttpStatusCode, LambderRefusalStatusCode } from "./shared/wire/LambderHttpStatus.js";
|
|
68
70
|
export { html, xml, raw, jsonScript, escapeHtml, renderHtmlValue, LambderSafeHtml, type LambderHtmlValue } from "./shared/LambderHtml.js";
|
|
69
71
|
export { LambderTemplatingEngine } from "./core/LambderTemplatingEngine.js";
|
|
70
72
|
export type { LambderTemplateData, LambderTemplatingEngineOptions } from "./core/LambderTemplatingEngine.js";
|
|
@@ -88,7 +90,7 @@ export type { LambderS3UploadBucketOptions } from "./stores/LambderS3UploadBucke
|
|
|
88
90
|
export { LambderMemoryUploadBucket } from "./stores/LambderMemoryUploadBucket.js";
|
|
89
91
|
export type { LambderMemoryUploadBucketOptions, LambderMemoryUploadObject } from "./stores/LambderMemoryUploadBucket.js";
|
|
90
92
|
export { checkUploadRule } from "./shared/contracts/LambderUploadBucket.js";
|
|
91
|
-
export type { LambderUploadBucket, LambderUploadRule, LambderUploadFileFacts, LambderUploadTicket, LambderUploadVerdict, LambderUploadRuleVerdict, LambderUploadObjectOptions, LambderUploadContentDisposition, } from "./shared/contracts/LambderUploadBucket.js";
|
|
93
|
+
export type { LambderUploadBucket, LambderUploadRule, LambderUploadFileFacts, LambderUploadTicket, LambderUploadMethod, LambderUploadVerdict, LambderUploadRuleVerdict, LambderUploadObjectOptions, LambderUploadContentDisposition, } from "./shared/contracts/LambderUploadBucket.js";
|
|
92
94
|
export { LambderUploadFileFactsSchema, LambderUploadTicketSchema } from "./shared/wire/LambderUploadSchemas.js";
|
|
93
95
|
export { refuseUnacceptedUpload } from "./shared/wire/LambderUploadRefusal.js";
|
|
94
96
|
export { LambderUploadRunner, LambderUploadError } from "./client/LambderUploadRunner.js";
|
|
@@ -123,17 +125,19 @@ export type { LambderDdbIdempotencyStoreOptions } from "./stores/LambderDdbIdemp
|
|
|
123
125
|
export { LambderMemoryIdempotencyStore } from "./stores/LambderMemoryIdempotencyStore.js";
|
|
124
126
|
export { lambderGuard, lambderRateLimitKey } from "./core/LambderPolicyBuilders.js";
|
|
125
127
|
export { lambderGuardBuilder } from "./api/LambderApiGuards.js";
|
|
126
|
-
export type { LambderGuardBuilder, LambderApiGuard, LambderGuardMeta, LambderGuardMetaMap, LambderGuardRunAt, LambderAllowedGuardNames, LambderParamlessGuardNames, LambderGuardsOption, LambderGuardDataOf, LambderGuardInputsOf, } from "./api/LambderApiGuards.js";
|
|
128
|
+
export type { LambderGuardBuilder, LambderApiGuard, LambderGuardMeta, LambderGuardMetaMap, LambderGuardRunAt, LambderAllowedGuardNames, LambderParamlessGuardNames, LambderGuardsOption, LambderGuardDataOf, LambderGuardInputsOf, LambderGuardRefusals, LambderGuardRefusalNamesOf, } from "./api/LambderApiGuards.js";
|
|
129
|
+
export { LambderApiRefusalValidationError } from "./api/LambderApiRefusals.js";
|
|
130
|
+
export type { LambderRefusalDeclaration, LambderRefusalVocabulary, LambderApiAllowedRefusal, LambderApiAllowedRefusals, LambderEndpointRefusals, LambderRefusalsOption, LambderRefusalNamesIn, LambderHandlerRefusalsOf, LambderWireRefusalsOf, } from "./api/LambderApiRefusals.js";
|
|
127
131
|
export { lambderRateLimitKeyBuilder, rateLimitRefusal, DEFAULT_RATE_LIMIT_REFUSAL } from "./api/LambderApiRateLimits.js";
|
|
128
132
|
export type { LambderRateLimitKeyBuilder } from "./api/LambderApiRateLimits.js";
|
|
129
133
|
export type { LambderContextRateLimit, LambderContextRateLimitCheck, LambderRateLimitCheckResult, LambderChargeablePolicyNames, LambderChargeKeyArgs, LambderRateLimitKeyFn, LambderRateLimitPer, LambderRateLimitBudget, LambderRateLimitChargeAt, LambderApiRateLimitPolicyConfig, LambderApiRateLimitsConfig, LambderAllowedPolicyNames, LambderRateLimitOption, } from "./api/LambderApiRateLimits.js";
|
|
130
134
|
export type { LambderApiIdempotencyConfig } from "./api/LambderApiIdempotency.js";
|
|
131
|
-
export type { LambderGuardsOptionValue, LambderRateLimitOverride, LambderRateLimitOptionValue, LambderApiIdempotencyOption, } from "./shared/wire/LambderApiOptionValues.js";
|
|
135
|
+
export type { LambderGuardsOptionValue, LambderRateLimitMessage, LambderRateLimitOverride, LambderRateLimitOptionValue, LambderRefusalsOptionValue, LambderApiIdempotencyOption, } from "./shared/wire/LambderApiOptionValues.js";
|
|
132
136
|
export { apiGuardParam } from "./shared/wire/LambderApiOptionEntries.js";
|
|
133
137
|
export type { LambderApiOptionEntries, LambderApiOptionEntry, LambderRateLimitPolicyEntry, LambderGuardDeclarationEntry, LambderApisWithGuard, LambderApisGuardedBy, LambderApisWithMode, LambderGuardParamOf, } from "./shared/wire/LambderApiOptionEntries.js";
|
|
134
138
|
export { createLambderI18n } from "./shared/LambderI18n.js";
|
|
135
139
|
export type { LambderLanguageMeta, LambderI18nConfig, LambderI18nInstance, LambderI18nTranslator, LambderI18nExtractParams, LambderI18nDictionaryLoader, LambderI18nCodes, LambderI18nKeys, LambderI18nTranslatorFor, } from "./shared/LambderI18n.js";
|
|
136
|
-
export type { LambderApiContractShape, LambderApiMode, LambderApiEnvelopeBody,
|
|
140
|
+
export type { LambderApiContractShape, LambderApiMode, LambderApiEnvelopeBody, LambderApiSuccessEnvelope, LambderApiRefusalEnvelope, LambderRefusalEnvelopeFields, LambderApiRefusalConfig, LambderContractEntry, LambderMergeContract, LambderGuardNamesIn, LambderContractMode, LambderContractKeysWithMode, LambderContractKeysWithGuard, LambderJsonOf, LambderContractRefusalsOf, LambderContractRefusalMessage, LambderContractRefusals, LambderContractAnyRefusalMessage, LambderContractGuardsOf, LambderContractGuardNames, LambderContractGuardInputsOf, LambderContractGuardInput, LambderContractGuardInputNames, LambderContractRateLimitOf, LambderContractRateLimitNames, LambderContractIdempotencyOf, } from "./shared/wire/LambderApiContract.js";
|
|
137
141
|
export type { LambderRenderContext, LambderSessionRenderContext, LambderHttpEvent, LambderHttpEventFormat } from "./core/LambderContext.js";
|
|
138
142
|
export type { LambderApiAnswerOutcome, LambderApiSuccessOutcome, LambderApiCallFailure, LambderApiValidationFailure, LambderApiEnvelopeFailure, LambderApiHttpAnswer, } from "./shared/wire/LambderApiOutcome.js";
|
|
139
143
|
export { resolveApiOutcome } from "./shared/wire/LambderApiOutcome.js";
|
package/dist/index.js
CHANGED
|
@@ -27,16 +27,18 @@ export { apiSignatureOf } from "./api/LambderApiSignature.js";
|
|
|
27
27
|
export { apiNameKeyOf, lookupApiSignature, readApiSignature, API_SIGNATURE_HEX_LENGTH, extensibleEnum } from "./shared/wire/LambderApiSignatureMap.js";
|
|
28
28
|
export { RELOAD_LOOP_WINDOW_MS } from "./client/LambderReloadLoopBreaker.js";
|
|
29
29
|
export { compareDottedVersions, isDottedVersion } from "./shared/wire/LambderVersionOrder.js";
|
|
30
|
-
export {
|
|
30
|
+
export { successEnvelope, refusalEnvelope, plainRefusalEnvelope, envelopeAnswer, refusalAnswer, validationAnswer, apiNotFoundAnswer, sessionExpiredAnswer, versionExpiredAnswer, invalidPayloadAnswer, crashAnswer, API_ANSWER_CONTENT_TYPE, } from "./api/LambderApiEnvelope.js";
|
|
31
31
|
export { LambderApiValidationRefusal, isLambderApiValidationRefusal } from "./api/LambderApiValidationRefusal.js";
|
|
32
32
|
export { LambderApiOutputValidationError } from "./api/LambderApiOutputValidationError.js";
|
|
33
|
+
export { checkedRefusal } from "./api/LambderApiRefusals.js";
|
|
33
34
|
// Calling a Lambder app from another lambda (server-only: the Lambda SDK, zlib)
|
|
34
35
|
export { LambderInvokeError, isLambderInvokeError } from "./invoke/LambderInvokeOutcome.js";
|
|
35
36
|
export { default as LambderInvokeCaller, LAMBDER_INVOKE_MAX_EVENT_BYTES, } from "./invoke/LambderInvokeCaller.js";
|
|
36
37
|
// A crash described for a caller allowed to see it (the envelope's `crash` field)
|
|
37
38
|
export { describeCrash, errorFromCrashDetail } from "./shared/wire/LambderCrashDetail.js";
|
|
38
39
|
// Typed API refusals (isomorphic: shared code may throw them from anywhere)
|
|
39
|
-
export { LambderApiRefusal, isLambderApiRefusal, refuse, refusalMessageOf, LAMBDER_REFUSAL_CODES } from "./shared/wire/LambderApiRefusal.js";
|
|
40
|
+
export { LambderApiRefusal, isLambderApiRefusal, isLambderRefusalCode, refuse, refusalMessageOf, LAMBDER_REFUSAL_CODES } from "./shared/wire/LambderApiRefusal.js";
|
|
41
|
+
export { isObjectPayload } from "./shared/wire/LambderObjectPayload.js";
|
|
40
42
|
export { default as LambderResponseBuilder } from "./core/LambderResponseBuilder.js";
|
|
41
43
|
export { default as LambderResolver } from "./core/LambderResolver.js";
|
|
42
44
|
export { default as LambderSessionManager } from "./session/LambderSessionManager.js";
|
|
@@ -86,6 +88,8 @@ export { LambderMemoryIdempotencyStore } from "./stores/LambderMemoryIdempotency
|
|
|
86
88
|
// Declarative per-API policies: guards
|
|
87
89
|
export { lambderGuard, lambderRateLimitKey } from "./core/LambderPolicyBuilders.js";
|
|
88
90
|
export { lambderGuardBuilder } from "./api/LambderApiGuards.js";
|
|
91
|
+
// Declarative per-API policies: declared refusals
|
|
92
|
+
export { LambderApiRefusalValidationError } from "./api/LambderApiRefusals.js";
|
|
89
93
|
// Declarative per-API policies: rate limits
|
|
90
94
|
export { lambderRateLimitKeyBuilder, rateLimitRefusal, DEFAULT_RATE_LIMIT_REFUSAL } from "./api/LambderApiRateLimits.js";
|
|
91
95
|
// The declared options as plain data: what apiOptionEntries() reports and
|
|
@@ -24,7 +24,7 @@ import type { APIGatewayProxyEventV2, Context } from "aws-lambda";
|
|
|
24
24
|
import { type LambderInvokeFailure, type LambderInvokeOutcome } from "./LambderInvokeOutcome.js";
|
|
25
25
|
import { type LambderApiSignatureMap } from "../shared/wire/LambderApiSignatureMap.js";
|
|
26
26
|
import type { LambdaClient, LambdaClientConfig } from "@aws-sdk/client-lambda";
|
|
27
|
-
import type { LambderApiContractShape } from "../shared/wire/LambderApiContract.js";
|
|
27
|
+
import type { LambderApiContractShape, LambderContractRefusalMessage } from "../shared/wire/LambderApiContract.js";
|
|
28
28
|
import { type LambderCallArgs, type LambderContractOutputOf, type LambderGuardInputsProviderOption, type LambderSharedCallOptions } from "../shared/wire/LambderCallOptions.js";
|
|
29
29
|
import { type LambderCompressionOption } from "../shared/wire/LambderCompressionOption.js";
|
|
30
30
|
import { type LambderInvokeSession, type LambderLambdaHttpResult } from "./LambderLambdaEvent.js";
|
|
@@ -214,14 +214,13 @@ export default class LambderInvokeCaller<TContract extends LambderApiContractSha
|
|
|
214
214
|
* comes from the contract rather than a type parameter, so a call site
|
|
215
215
|
* cannot replace it by annotating what it assigns to.
|
|
216
216
|
*/
|
|
217
|
-
apiOutcome<TApiName extends keyof TContract & string = string>(apiName: TApiName, ...rest: LambderCallArgs<TContract, TApiName, TProvidedGuards, LambderInvokeCallOptions>): Promise<LambderInvokeOutcome<LambderContractOutputOf<TContract, TApiName>>>;
|
|
217
|
+
apiOutcome<TApiName extends keyof TContract & string = string>(apiName: TApiName, ...rest: LambderCallArgs<TContract, TApiName, TProvidedGuards, LambderInvokeCallOptions>): Promise<LambderInvokeOutcome<LambderContractOutputOf<TContract, TApiName>, LambderContractRefusalMessage<TContract, TApiName>>>;
|
|
218
218
|
/**
|
|
219
219
|
* The declared output, or a thrown LambderInvokeError carrying the
|
|
220
220
|
* outcome. A failed dependency is a failed request: the throw reaches the
|
|
221
|
-
* app's global error handler with the callee's error as its cause.
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
* nullable output.
|
|
221
|
+
* app's global error handler with the callee's error as its cause. Only
|
|
222
|
+
* the callee handler's own output reads as a success, so what this
|
|
223
|
+
* returns is always the contract's output.
|
|
225
224
|
*/
|
|
226
225
|
api<TApiName extends keyof TContract & string = string>(apiName: TApiName, ...rest: LambderCallArgs<TContract, TApiName, TProvidedGuards, LambderInvokeCallOptions>): Promise<LambderContractOutputOf<TContract, TApiName>>;
|
|
227
226
|
/**
|
|
@@ -227,7 +227,7 @@ export default class LambderInvokeCaller {
|
|
|
227
227
|
apiName,
|
|
228
228
|
functionName: this.functionName,
|
|
229
229
|
status: init.status,
|
|
230
|
-
|
|
230
|
+
refusal: init.refusal,
|
|
231
231
|
crash: init.crash,
|
|
232
232
|
functionError: init.functionError,
|
|
233
233
|
logList,
|
|
@@ -246,7 +246,7 @@ export default class LambderInvokeCaller {
|
|
|
246
246
|
logList,
|
|
247
247
|
cookies: init.cookies ?? [],
|
|
248
248
|
...(init.status !== undefined ? { status: init.status } : {}),
|
|
249
|
-
...(init.
|
|
249
|
+
...(init.refusal !== undefined ? { refusal: init.refusal } : {}),
|
|
250
250
|
...(init.retryAfterSeconds !== undefined ? { retryAfterSeconds: init.retryAfterSeconds } : {}),
|
|
251
251
|
...(init.zodError !== undefined ? { zodError: init.zodError } : {}),
|
|
252
252
|
...(init.crash !== undefined ? { crash: init.crash } : {}),
|
|
@@ -288,6 +288,9 @@ export default class LambderInvokeCaller {
|
|
|
288
288
|
*/
|
|
289
289
|
async dispatch(apiName, payload, options = {}) {
|
|
290
290
|
const idempotentAttempt = beginIdempotentAttempt(options.idempotencyKey);
|
|
291
|
+
// The reader cannot check a refusal's code against declarations it
|
|
292
|
+
// does not have; the callee never sends one its endpoint did not
|
|
293
|
+
// declare, which is what the endpoint's message type stands for.
|
|
291
294
|
const outcome = await this.dispatchAttempt(apiName, payload, options, idempotentAttempt);
|
|
292
295
|
// Only the first settle counts: an attempt that never left settled
|
|
293
296
|
// itself as not sent.
|
|
@@ -378,11 +381,10 @@ export default class LambderInvokeCaller {
|
|
|
378
381
|
// The answer's Set-Cookie values, so a session the callee rotated or
|
|
379
382
|
// cleared is visible to whoever is carrying it.
|
|
380
383
|
const cookies = http.cookies;
|
|
381
|
-
// The
|
|
382
|
-
//
|
|
383
|
-
// allows null.
|
|
384
|
+
// The callee handler's output: only a handler's answer reads as a
|
|
385
|
+
// success, and an output is always an object or an array.
|
|
384
386
|
if (outcome.ok)
|
|
385
|
-
return { ok: true, payload:
|
|
387
|
+
return { ok: true, payload: outcome.payload, response: outcome.response, logList, cookies };
|
|
386
388
|
const shared = { status: outcome.status, retryAfterSeconds: outcome.retryAfterSeconds, logList, cookies };
|
|
387
389
|
// Each failure reason carries different evidence, and the outcome
|
|
388
390
|
// union says which: a rejected input has its issues and no envelope,
|
|
@@ -399,7 +401,7 @@ export default class LambderInvokeCaller {
|
|
|
399
401
|
return await this.failureOutcome(apiName, {
|
|
400
402
|
...shared,
|
|
401
403
|
reason: 'server',
|
|
402
|
-
|
|
404
|
+
refusal: outcome.refusal,
|
|
403
405
|
response: outcome.response,
|
|
404
406
|
crash: outcome.response?.crash,
|
|
405
407
|
cause: outcome.error,
|
|
@@ -408,7 +410,7 @@ export default class LambderInvokeCaller {
|
|
|
408
410
|
}
|
|
409
411
|
return await this.failureOutcome(apiName, {
|
|
410
412
|
...shared,
|
|
411
|
-
...(outcome.reason === '
|
|
413
|
+
...(outcome.reason === 'refusal' ? { reason: outcome.reason, refusal: outcome.refusal } : { reason: outcome.reason }),
|
|
412
414
|
response: outcome.response,
|
|
413
415
|
crash: outcome.response.crash,
|
|
414
416
|
});
|
|
@@ -429,10 +431,9 @@ export default class LambderInvokeCaller {
|
|
|
429
431
|
/**
|
|
430
432
|
* The declared output, or a thrown LambderInvokeError carrying the
|
|
431
433
|
* outcome. A failed dependency is a failed request: the throw reaches the
|
|
432
|
-
* app's global error handler with the callee's error as its cause.
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
* nullable output.
|
|
434
|
+
* app's global error handler with the callee's error as its cause. Only
|
|
435
|
+
* the callee handler's own output reads as a success, so what this
|
|
436
|
+
* returns is always the contract's output.
|
|
436
437
|
*/
|
|
437
438
|
async api(apiName, ...rest) {
|
|
438
439
|
const [payload, options] = rest;
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
* should not have to read the whole class to find it. None of these functions
|
|
11
11
|
* touch the caller's state.
|
|
12
12
|
*/
|
|
13
|
-
import type {
|
|
13
|
+
import type { LambderApiRefusalEnvelope, LambderApiSuccessEnvelope } from "../shared/wire/LambderApiContract.js";
|
|
14
14
|
import type { LambderApiFailureReason, LambderValidationError } from "../shared/wire/LambderApiOutcome.js";
|
|
15
15
|
import type { LambderCrashDetail } from "../shared/wire/LambderCrashDetail.js";
|
|
16
|
-
import type {
|
|
16
|
+
import type { LambderUncheckedRefusalMessage } 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 = {
|
|
@@ -21,13 +21,17 @@ export type LambderInvokeFunctionError = {
|
|
|
21
21
|
errorMessage?: string;
|
|
22
22
|
trace?: string[];
|
|
23
23
|
};
|
|
24
|
-
/**
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* What every invoke failure carries, whatever went wrong. TMessage is the
|
|
26
|
+
* refusal message the endpoint can answer with (LambderContractRefusalMessage),
|
|
27
|
+
* on every arm, as on the browser caller's outcome.
|
|
28
|
+
*/
|
|
29
|
+
type LambderInvokeFailureFields<TMessage extends LambderUncheckedRefusalMessage> = {
|
|
26
30
|
ok: false;
|
|
27
31
|
/** HTTP status, when the callee answered. */
|
|
28
32
|
status?: number;
|
|
29
|
-
/**
|
|
30
|
-
|
|
33
|
+
/** The envelope's refusal, when the callee provided one: always the message object, a plain string having been read as one (refusalMessageOf). */
|
|
34
|
+
refusal?: TMessage;
|
|
31
35
|
/** Seconds to wait before retrying, from the answer's Retry-After header. */
|
|
32
36
|
retryAfterSeconds?: number;
|
|
33
37
|
/** Always present: the error api() throws for this failure, with the callee's error as its cause when one is known. */
|
|
@@ -38,31 +42,31 @@ type LambderInvokeFailureFields = {
|
|
|
38
42
|
cookies: string[];
|
|
39
43
|
};
|
|
40
44
|
/** HTTP 422: the callee rejected the input against the API's schema. Always carries the issues. */
|
|
41
|
-
export type LambderInvokeValidationFailure = LambderInvokeFailureFields & {
|
|
45
|
+
export type LambderInvokeValidationFailure<TMessage extends LambderUncheckedRefusalMessage = LambderUncheckedRefusalMessage> = LambderInvokeFailureFields<TMessage> & {
|
|
42
46
|
reason: 'validation';
|
|
43
47
|
zodError: LambderValidationError;
|
|
44
48
|
};
|
|
45
49
|
/** Lambda reported a FunctionError: the callee failed outside the framework (an init failure, a timeout, out of memory). Always carries the runtime's error payload. */
|
|
46
|
-
export type LambderInvokeCrashFailure = LambderInvokeFailureFields & {
|
|
50
|
+
export type LambderInvokeCrashFailure<TMessage extends LambderUncheckedRefusalMessage = LambderUncheckedRefusalMessage> = LambderInvokeFailureFields<TMessage> & {
|
|
47
51
|
reason: 'crash';
|
|
48
52
|
functionError: LambderInvokeFunctionError;
|
|
49
53
|
};
|
|
50
54
|
/** Refused before sending: the serialized event is over the invoke cap. Always carries its size. */
|
|
51
|
-
export type LambderInvokePayloadTooLargeFailure = LambderInvokeFailureFields & {
|
|
55
|
+
export type LambderInvokePayloadTooLargeFailure<TMessage extends LambderUncheckedRefusalMessage = LambderUncheckedRefusalMessage> = LambderInvokeFailureFields<TMessage> & {
|
|
52
56
|
reason: 'payloadTooLarge';
|
|
53
57
|
/** The event's byte size, so a caller can say by how much it is over. */
|
|
54
58
|
bytes: number;
|
|
55
59
|
};
|
|
56
|
-
/** The callee answered, and the envelope itself says the call is refused. Always carries that envelope, and
|
|
57
|
-
export type LambderInvokeEnvelopeFailure = LambderInvokeFailureFields & {
|
|
58
|
-
response:
|
|
60
|
+
/** The callee answered, and the envelope itself says the call is refused. Always carries that envelope, and a `refusal` failure always carries the refusal. */
|
|
61
|
+
export type LambderInvokeEnvelopeFailure<TMessage extends LambderUncheckedRefusalMessage = LambderUncheckedRefusalMessage> = LambderInvokeFailureFields<TMessage> & {
|
|
62
|
+
response: LambderApiRefusalEnvelope;
|
|
59
63
|
/** The callee's crash detail, when its global error handler sent one (the envelope's `crash` field). */
|
|
60
64
|
crash?: LambderCrashDetail;
|
|
61
65
|
} & ({
|
|
62
66
|
reason: 'versionExpired' | 'sessionExpired' | 'notAuthorized';
|
|
63
67
|
} | {
|
|
64
|
-
reason: '
|
|
65
|
-
|
|
68
|
+
reason: 'refusal';
|
|
69
|
+
refusal: TMessage;
|
|
66
70
|
});
|
|
67
71
|
/**
|
|
68
72
|
* Nothing usable came back: the invoke never arrived or was given up on, the
|
|
@@ -71,9 +75,9 @@ export type LambderInvokeEnvelopeFailure = LambderInvokeFailureFields & {
|
|
|
71
75
|
* answered with Lambder's own envelope, which is how a crash detail and a
|
|
72
76
|
* logList arrive with it.
|
|
73
77
|
*/
|
|
74
|
-
export type LambderInvokeDeliveryFailure = LambderInvokeFailureFields & {
|
|
78
|
+
export type LambderInvokeDeliveryFailure<TMessage extends LambderUncheckedRefusalMessage = LambderUncheckedRefusalMessage> = LambderInvokeFailureFields<TMessage> & {
|
|
75
79
|
reason: 'network' | 'timeout' | 'server' | 'protocol' | 'unknown';
|
|
76
|
-
response?:
|
|
80
|
+
response?: LambderApiRefusalEnvelope;
|
|
77
81
|
/** The callee's crash detail, when its global error handler sent one (the envelope's `crash` field). */
|
|
78
82
|
crash?: LambderCrashDetail;
|
|
79
83
|
};
|
|
@@ -85,14 +89,19 @@ export type LambderInvokeDeliveryFailure = LambderInvokeFailureFields & {
|
|
|
85
89
|
* caller's LambderApiOutcome is discriminated the same way.
|
|
86
90
|
*
|
|
87
91
|
* `error`, `logList` and `cookies` are on every arm, and `status`,
|
|
88
|
-
* `
|
|
92
|
+
* `refusal` and `retryAfterSeconds` are there whenever an answer came
|
|
89
93
|
* back to read them from.
|
|
90
94
|
*/
|
|
91
|
-
export type LambderInvokeFailure = LambderInvokeValidationFailure | LambderInvokeCrashFailure | LambderInvokePayloadTooLargeFailure | LambderInvokeEnvelopeFailure | LambderInvokeDeliveryFailure
|
|
92
|
-
|
|
95
|
+
export type LambderInvokeFailure<TMessage extends LambderUncheckedRefusalMessage = LambderUncheckedRefusalMessage> = LambderInvokeValidationFailure<TMessage> | LambderInvokeCrashFailure<TMessage> | LambderInvokePayloadTooLargeFailure<TMessage> | LambderInvokeEnvelopeFailure<TMessage> | LambderInvokeDeliveryFailure<TMessage>;
|
|
96
|
+
/**
|
|
97
|
+
* An invoke's result: the callee handler's output on success (never null,
|
|
98
|
+
* an output being an object or an array), or a failure whose refusal
|
|
99
|
+
* narrows on the codes the endpoint declares.
|
|
100
|
+
*/
|
|
101
|
+
export type LambderInvokeOutcome<T, TMessage extends LambderUncheckedRefusalMessage = LambderUncheckedRefusalMessage> = {
|
|
93
102
|
ok: true;
|
|
94
103
|
payload: T;
|
|
95
|
-
response:
|
|
104
|
+
response: LambderApiSuccessEnvelope<T>;
|
|
96
105
|
logList: unknown[];
|
|
97
106
|
/**
|
|
98
107
|
* The answer's Set-Cookie values. A caller carrying a user's session
|
|
@@ -102,14 +111,14 @@ export type LambderInvokeOutcome<T> = {
|
|
|
102
111
|
* tokens themselves.
|
|
103
112
|
*/
|
|
104
113
|
cookies: string[];
|
|
105
|
-
} | LambderInvokeFailure
|
|
114
|
+
} | LambderInvokeFailure<TMessage>;
|
|
106
115
|
export type LambderInvokeErrorInit = {
|
|
107
116
|
message: string;
|
|
108
117
|
reason: LambderInvokeFailureReason;
|
|
109
118
|
apiName: string;
|
|
110
119
|
functionName: string;
|
|
111
120
|
status?: number;
|
|
112
|
-
|
|
121
|
+
refusal?: LambderUncheckedRefusalMessage;
|
|
113
122
|
crash?: LambderCrashDetail;
|
|
114
123
|
functionError?: LambderInvokeFunctionError;
|
|
115
124
|
logList: unknown[];
|
|
@@ -132,7 +141,7 @@ export declare class LambderInvokeError extends Error {
|
|
|
132
141
|
readonly apiName: string;
|
|
133
142
|
readonly functionName: string;
|
|
134
143
|
readonly status?: number;
|
|
135
|
-
readonly
|
|
144
|
+
readonly refusal?: LambderUncheckedRefusalMessage;
|
|
136
145
|
readonly crash?: LambderCrashDetail;
|
|
137
146
|
readonly functionError?: LambderInvokeFunctionError;
|
|
138
147
|
readonly logList: unknown[];
|
|
@@ -25,7 +25,7 @@ export class LambderInvokeError extends Error {
|
|
|
25
25
|
apiName;
|
|
26
26
|
functionName;
|
|
27
27
|
status;
|
|
28
|
-
|
|
28
|
+
refusal;
|
|
29
29
|
crash;
|
|
30
30
|
functionError;
|
|
31
31
|
logList;
|
|
@@ -41,7 +41,7 @@ export class LambderInvokeError extends Error {
|
|
|
41
41
|
this.apiName = init.apiName;
|
|
42
42
|
this.functionName = init.functionName;
|
|
43
43
|
this.status = init.status;
|
|
44
|
-
this.
|
|
44
|
+
this.refusal = init.refusal;
|
|
45
45
|
this.crash = init.crash;
|
|
46
46
|
this.functionError = init.functionError;
|
|
47
47
|
this.logList = init.logList;
|
|
@@ -100,8 +100,8 @@ export const describeFailure = (init) => {
|
|
|
100
100
|
return init.crash.message;
|
|
101
101
|
if (init.functionError)
|
|
102
102
|
return `${init.functionError.errorType ?? "FunctionError"}: ${init.functionError.errorMessage ?? "the function failed"}`;
|
|
103
|
-
if (init.
|
|
104
|
-
return init.
|
|
103
|
+
if (init.refusal !== undefined)
|
|
104
|
+
return init.refusal.content;
|
|
105
105
|
if (init.reason === 'validation')
|
|
106
106
|
return "the callee rejected the input";
|
|
107
107
|
if (init.reason === 'versionExpired')
|
|
@@ -2,6 +2,8 @@ import type { z } from "zod";
|
|
|
2
2
|
import type { LambderApiContractShape } from "../shared/wire/LambderApiContract.js";
|
|
3
3
|
import { type LambderApiRequest } from "../api/LambderApiRequest.js";
|
|
4
4
|
import { type LambderApiAnswer } from "../api/LambderApiAnswer.js";
|
|
5
|
+
import { type LambderDeclaredRefuse, type LambderRefusalMessage } from "../shared/wire/LambderApiRefusal.js";
|
|
6
|
+
import { type LambderDeclaredVocabulary, type LambderHandlerRefusalsOf, type LambderRefusalVocabulary, type LambderRefusalVocabularyChecks } from "../api/LambderApiRefusals.js";
|
|
5
7
|
import { type LambderApiTransport, type LambderApiTransportRequest } from "../shared/transport/LambderApiTransport.js";
|
|
6
8
|
import { LambderCookieJar } from "../shared/transport/LambderCookieJar.js";
|
|
7
9
|
import { type LambderApiGuard, type LambderGuardBuilder } from "../api/LambderApiGuards.js";
|
|
@@ -11,7 +13,7 @@ import { LambderMemorySessionStore } from "../stores/LambderMemorySessionStore.j
|
|
|
11
13
|
import LambderSessionManager, { type LambderCreatedSession } from "../session/LambderSessionManager.js";
|
|
12
14
|
import type { LambderMockAppOptions, LambderMockIdempotencyOptions, LambderMockTransport, LambderMockTransportOptions } from "./LambderMockCreateOptions.js";
|
|
13
15
|
import type { LambderApiOptionEntry, LambderGuardDeclarationEntry } from "../shared/wire/LambderApiOptionEntries.js";
|
|
14
|
-
import type { LambderMockCallContext, LambderMockCallRecord, LambderMockEntry, LambderMockEntryInput, LambderMockFailure, LambderMockFailureReason, LambderMockHandler, LambderMockLatency, LambderMockListener, LambderMockPublicNames, LambderMockRateLimitPolicies, LambderMockRegistryCheck, LambderMockRestEntry, LambderMockSessionCallContext, LambderMockSessionNames, LambderMockSlice, LambderMockOverride } from "./LambderMockTypes.js";
|
|
16
|
+
import type { LambderMockCallContext, LambderMockCallRecord, LambderMockEntry, LambderMockEntryInput, LambderMockFailure, LambderMockFailureReason, LambderMockHandler, LambderMockLatency, LambderMockListener, LambderMockPublicNames, LambderMockRateLimitPolicies, LambderMockRegistryCheck, LambderMockRestEntry, LambderMockSessionCallContext, LambderMockSessionNames, LambderMockSlice, LambderMockOverride, LambderMockRefusalsOf } from "./LambderMockTypes.js";
|
|
15
17
|
/**
|
|
16
18
|
* The mock runtime: the API core (LambderApiPipeline, the same class the
|
|
17
19
|
* Lambda server runs) over memory stores, with typed mock handlers and mock
|
|
@@ -26,8 +28,10 @@ import type { LambderMockCallContext, LambderMockCallRecord, LambderMockEntry, L
|
|
|
26
28
|
* which fixes the contract and session types first so everything else is
|
|
27
29
|
* inferred from the options. `TDerived` is true for a mock created with the
|
|
28
30
|
* generated `apiOptions` table, whose entries are their handlers alone.
|
|
31
|
+
* `TVocabulary` and `TCodesRequired` are the refusal vocabulary the init
|
|
32
|
+
* declared (declareRefusals), which types every handler's ctx.refuse.
|
|
29
33
|
*/
|
|
30
|
-
export declare class LambderMockApp<C extends LambderApiContractShape, S = any, G extends Record<string, LambderApiGuard<any, any, any>> = {}, TDerived extends boolean = false> {
|
|
34
|
+
export declare class LambderMockApp<C extends LambderApiContractShape, S = any, G extends Record<string, LambderApiGuard<any, any, any>> = {}, TDerived extends boolean = false, TVocabulary extends LambderRefusalVocabulary = never, TCodesRequired extends boolean = false> {
|
|
31
35
|
readonly apiVersion: string | null;
|
|
32
36
|
/** The memory stores, for assertions and reset; null for a subsystem that is off or backed by a store of yours. */
|
|
33
37
|
readonly sessionStore: LambderMemorySessionStore<S> | null;
|
|
@@ -65,9 +69,17 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
65
69
|
private readonly registry;
|
|
66
70
|
/** The server's declared options per API, when create() was given the generated table; the entries' declarations come from here. */
|
|
67
71
|
private readonly apiOptions;
|
|
72
|
+
/** The server's guard declarations, when create() was given the generated table: the refusal codes a declared guard adds to an entry. */
|
|
73
|
+
private readonly guardDeclarations;
|
|
74
|
+
/** The server's refusal vocabulary, when create() was given the generated table: whether each code an entry may refuse with carries data. */
|
|
75
|
+
private readonly refusalVocabulary;
|
|
76
|
+
/** Whether every refusal an entry answers with has to name a code, as the server's declareRefusals() requireCodes. */
|
|
77
|
+
private readonly requireRefusalCodes;
|
|
68
78
|
/** The jars the runtime owns and what it planted in document.cookie (see LambderMockBrowserCookies). */
|
|
69
79
|
private readonly browserCookies;
|
|
70
|
-
constructor(options: LambderMockAppOptions<C, S, G, LambderMockRateLimitPolicies<S>, boolean | LambderMockIdempotencyOptions<S>, {}, Record<string, LambderApiOptionEntry> | undefined
|
|
80
|
+
constructor(options: LambderMockAppOptions<C, S, G, LambderMockRateLimitPolicies<S>, boolean | LambderMockIdempotencyOptions<S>, {}, Record<string, LambderApiOptionEntry> | undefined>,
|
|
81
|
+
/** The vocabulary the init declared, or null: what initLambderMock().declareRefusals() passes on. */
|
|
82
|
+
declared?: LambderDeclaredVocabulary<TVocabulary, TCodesRequired> | null);
|
|
71
83
|
/**
|
|
72
84
|
* The registration-time checks every entry goes through, mocked or not:
|
|
73
85
|
* the ones the server runs on a definition, and the mock's own "a session
|
|
@@ -87,13 +99,23 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
87
99
|
* the compiler did not see.
|
|
88
100
|
*/
|
|
89
101
|
private declaredOptionsOf;
|
|
102
|
+
/**
|
|
103
|
+
* The codes an entry may refuse with, read off the generated tables (its
|
|
104
|
+
* own from apiOptions, its guards' from guardDeclarations), each resolved
|
|
105
|
+
* through the vocabulary the init declared, exactly as the server
|
|
106
|
+
* resolves its own: schema, status and flag. An entry that declares
|
|
107
|
+
* guards needs the guardDeclarations table, and one with any code needs
|
|
108
|
+
* the vocabulary; a code the tables name that the vocabulary lacks means
|
|
109
|
+
* the two describe different servers.
|
|
110
|
+
*/
|
|
111
|
+
private declaredRefusalsOf;
|
|
90
112
|
/** The mode the apiOptions table gives a name, or null without a table or for a name it does not hold. */
|
|
91
113
|
private declaredModeOf;
|
|
92
114
|
private buildEntry;
|
|
93
115
|
/** A mock for a public endpoint: a handler, or the handler with the endpoint's declarations restated. */
|
|
94
|
-
publicApi<K extends LambderMockPublicNames<C>, TInputSchema extends z.ZodType = z.ZodType>(name: K, entry: LambderMockEntryInput<C, K, S, G, TInputSchema, TDerived>): LambderMockEntry<C, K>;
|
|
116
|
+
publicApi<K extends LambderMockPublicNames<C>, TInputSchema extends z.ZodType = z.ZodType>(name: K, entry: LambderMockEntryInput<C, K, S, G, TInputSchema, TDerived, TVocabulary, TCodesRequired>): LambderMockEntry<C, K>;
|
|
95
117
|
/** A mock for a session endpoint: the pipeline fetches the session before the handler runs, and refuses without one. */
|
|
96
|
-
sessionApi<K extends LambderMockSessionNames<C>, TInputSchema extends z.ZodType = z.ZodType>(name: K, entry: LambderMockEntryInput<C, K, S, G, TInputSchema, TDerived>): LambderMockEntry<C, K>;
|
|
118
|
+
sessionApi<K extends LambderMockSessionNames<C>, TInputSchema extends z.ZodType = z.ZodType>(name: K, entry: LambderMockEntryInput<C, K, S, G, TInputSchema, TDerived, TVocabulary, TCodesRequired>): LambderMockEntry<C, K>;
|
|
97
119
|
/**
|
|
98
120
|
* A public endpoint deliberately left without a mock; a call answers the
|
|
99
121
|
* notMocked refusal carrying the reason.
|
|
@@ -162,7 +184,7 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
162
184
|
* an override one `it` scoped cannot drop the one a describe put in place
|
|
163
185
|
* around it.
|
|
164
186
|
*/
|
|
165
|
-
override<K extends keyof C & string>(name: K, handler: LambderMockHandler<C, K, S, G>): LambderMockOverride;
|
|
187
|
+
override<K extends keyof C & string>(name: K, handler: LambderMockHandler<C, K, S, G, TVocabulary, TCodesRequired>): LambderMockOverride;
|
|
166
188
|
/** Puts every overridden handler back, however deeply they were stacked. */
|
|
167
189
|
restoreOverrides(): void;
|
|
168
190
|
/** The registered endpoint names. */
|
|
@@ -188,10 +210,10 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
188
210
|
* restore, and for a session endpoint the session read).
|
|
189
211
|
*/
|
|
190
212
|
private restNotMockedEntry;
|
|
191
|
-
/** The next call to the endpoint fails this way; several calls queue in order. */
|
|
192
|
-
failNext
|
|
213
|
+
/** The next call to the endpoint fails this way; several calls queue in order. An injected refusal names one of the endpoint's declared codes, its data as a handler raises it (see LambderMockRefusalsOf), and is checked and sent as a real one is. */
|
|
214
|
+
failNext<K extends keyof C & string>(apiName: K, failure: LambderMockFailure<LambderRefusalMessage<LambderMockRefusalsOf<C, K, TVocabulary>>> | LambderMockFailureReason): void;
|
|
193
215
|
/** Every call to the endpoint fails this way until cleared with null. */
|
|
194
|
-
setFailure
|
|
216
|
+
setFailure<K extends keyof C & string>(apiName: K, failure: LambderMockFailure<LambderRefusalMessage<LambderMockRefusalsOf<C, K, TVocabulary>>> | LambderMockFailureReason | null): void;
|
|
195
217
|
/** Every call rejects at the transport, as with no network at all. */
|
|
196
218
|
setOffline(offline: boolean): void;
|
|
197
219
|
setLatency(latency: LambderMockLatency): void;
|
|
@@ -313,22 +335,55 @@ export declare class LambderMockApp<C extends LambderApiContractShape, S = any,
|
|
|
313
335
|
}, options?: LambderMockTransportOptions): LambderMockTransport;
|
|
314
336
|
}
|
|
315
337
|
/**
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
* ```ts
|
|
323
|
-
* const mock = initLambderMock<ApiContractType, SessionData>();
|
|
324
|
-
* const mockApp = mock.create({
|
|
325
|
-
* apiVersion: "1.4.0",
|
|
326
|
-
* sessions: true,
|
|
327
|
-
* guards: { tenant: mock.guard({ guardInput: z.object({ tenantId: z.uuid() }), session: true, handler: ... }) },
|
|
328
|
-
* });
|
|
329
|
-
* ```
|
|
338
|
+
* The mock's entry point: fixes the contract and session types, and hands
|
|
339
|
+
* out the builders and create() that share them. `declareRefusals()` binds
|
|
340
|
+
* the server's refusal vocabulary too, the same object the server's init
|
|
341
|
+
* declares, so a mock handler's ctx.refuse takes a code's data in the
|
|
342
|
+
* schema's input form and the mock parses it exactly as the server does.
|
|
330
343
|
*/
|
|
331
344
|
export declare const initLambderMock: <C extends LambderApiContractShape, S = any>() => {
|
|
345
|
+
/**
|
|
346
|
+
* Declares the server's refusal vocabulary on the mock: the same object,
|
|
347
|
+
* and the same `requireCodes`, the server's init declares, imported from
|
|
348
|
+
* shared code (codes, zod schemas, statuses and flags hold nothing
|
|
349
|
+
* secret). Given, every refusal an entry answers with is checked and sent
|
|
350
|
+
* as the server would send it: the code among the codes the tables give
|
|
351
|
+
* the entry, its data parsed through the code's schema from the input
|
|
352
|
+
* form, and the declaration's status and flag. An entry whose tables name
|
|
353
|
+
* a code needs it.
|
|
354
|
+
*/
|
|
355
|
+
declareRefusals<const TVocabulary extends LambderRefusalVocabulary, const TRequireCodes extends boolean = false>(refusals: TVocabulary & LambderRefusalVocabularyChecks<TVocabulary>, options?: {
|
|
356
|
+
requireCodes?: TRequireCodes;
|
|
357
|
+
}): {
|
|
358
|
+
/** Builds a mock guard: the server guard's shape, the handler seeing the mock's contexts. */
|
|
359
|
+
guard: LambderGuardBuilder<LambderMockCallContext<S>, LambderMockSessionCallContext<S>>;
|
|
360
|
+
/**
|
|
361
|
+
* Builds a mock rate-limit key, the counterpart of `guard`. Bound to the
|
|
362
|
+
* mock's own call context, because the server's lambderRateLimitKey() is
|
|
363
|
+
* bound to the render context and a handler written with it compiles here
|
|
364
|
+
* while reading fields the mock context does not have.
|
|
365
|
+
*/
|
|
366
|
+
rateLimitKey: import("../api/LambderApiRateLimits.js").LambderRateLimitKeyBuilder<LambderMockCallContext<S>>;
|
|
367
|
+
/**
|
|
368
|
+
* refuse() typed to the vocabulary the mock declared, for a mock guard or
|
|
369
|
+
* a helper of the mock with no endpoint in hand: `code` is one of its
|
|
370
|
+
* codes and `data` the schema's input form, parsed as the server parses
|
|
371
|
+
* it. The free refuse() where the mock declared none.
|
|
372
|
+
*/
|
|
373
|
+
refuse: [TVocabulary] extends [never] ? (content: string, options?: import("../shared/wire/LambderApiRefusal.js").LambderRefuseOptions) => never : LambderDeclaredRefuse<LambderHandlerRefusalsOf<TVocabulary, keyof TVocabulary & string>, TRequireCodes>;
|
|
374
|
+
/**
|
|
375
|
+
* The mock app, with the guard map and the rate-limit policies inferred
|
|
376
|
+
* from the options.
|
|
377
|
+
*
|
|
378
|
+
* `const` on each of them pins a restatement to the contract, at a cost:
|
|
379
|
+
* inferring a generic from an object literal switches excess-property
|
|
380
|
+
* checking off for the whole literal, nested objects included, so a typo
|
|
381
|
+
* inside `rateLimits.policies` or `idempotency` would compile and be
|
|
382
|
+
* dropped. `I` exists for the same reason `P` does, and
|
|
383
|
+
* LambderMockSurplusKeys puts the error back on the key.
|
|
384
|
+
*/
|
|
385
|
+
create<const G extends Record<string, LambderApiGuard<any, any, any, LambderMockCallContext<S>, LambderMockSessionCallContext<S>>> = {}, const P extends LambderMockRateLimitPolicies<S> = {}, I extends boolean | LambderMockIdempotencyOptions<S> = boolean | LambderMockIdempotencyOptions<S>, const D extends Record<string, LambderGuardDeclarationEntry> = {}, const A extends Record<string, LambderApiOptionEntry> | undefined = undefined>(options: LambderMockAppOptions<C, S, G, P, I, D, A>): LambderMockApp<C, S, G, [A] extends [undefined] ? false : true, TVocabulary, TRequireCodes>;
|
|
386
|
+
};
|
|
332
387
|
/** Builds a mock guard: the server guard's shape, the handler seeing the mock's contexts. */
|
|
333
388
|
guard: LambderGuardBuilder<LambderMockCallContext<S>, LambderMockSessionCallContext<S>>;
|
|
334
389
|
/**
|
|
@@ -338,6 +393,13 @@ export declare const initLambderMock: <C extends LambderApiContractShape, S = an
|
|
|
338
393
|
* while reading fields the mock context does not have.
|
|
339
394
|
*/
|
|
340
395
|
rateLimitKey: import("../api/LambderApiRateLimits.js").LambderRateLimitKeyBuilder<LambderMockCallContext<S>>;
|
|
396
|
+
/**
|
|
397
|
+
* refuse() typed to the vocabulary the mock declared, for a mock guard or
|
|
398
|
+
* a helper of the mock with no endpoint in hand: `code` is one of its
|
|
399
|
+
* codes and `data` the schema's input form, parsed as the server parses
|
|
400
|
+
* it. The free refuse() where the mock declared none.
|
|
401
|
+
*/
|
|
402
|
+
refuse: (content: string, options?: import("../shared/wire/LambderApiRefusal.js").LambderRefuseOptions) => never;
|
|
341
403
|
/**
|
|
342
404
|
* The mock app, with the guard map and the rate-limit policies inferred
|
|
343
405
|
* from the options.
|
|
@@ -349,5 +411,5 @@ export declare const initLambderMock: <C extends LambderApiContractShape, S = an
|
|
|
349
411
|
* dropped. `I` exists for the same reason `P` does, and
|
|
350
412
|
* LambderMockSurplusKeys puts the error back on the key.
|
|
351
413
|
*/
|
|
352
|
-
create<const G extends Record<string, LambderApiGuard<any, any, any, LambderMockCallContext<S>, LambderMockSessionCallContext<S>>> = {}, const P extends LambderMockRateLimitPolicies<S> = {}, I extends boolean | LambderMockIdempotencyOptions<S> = boolean | LambderMockIdempotencyOptions<S>, const D extends Record<string, LambderGuardDeclarationEntry> = {}, const A extends Record<string, LambderApiOptionEntry> | undefined = undefined>(options: LambderMockAppOptions<C, S, G, P, I, D, A>): LambderMockApp<C, S, G, [A] extends [undefined] ? false : true>;
|
|
414
|
+
create<const G extends Record<string, LambderApiGuard<any, any, any, LambderMockCallContext<S>, LambderMockSessionCallContext<S>>> = {}, const P extends LambderMockRateLimitPolicies<S> = {}, I extends boolean | LambderMockIdempotencyOptions<S> = boolean | LambderMockIdempotencyOptions<S>, const D extends Record<string, LambderGuardDeclarationEntry> = {}, const A extends Record<string, LambderApiOptionEntry> | undefined = undefined>(options: LambderMockAppOptions<C, S, G, P, I, D, A>): LambderMockApp<C, S, G, [A] extends [undefined] ? false : true, never, false>;
|
|
353
415
|
};
|