lambder 14.1.1 → 15.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.
Files changed (158) hide show
  1. package/CHANGELOG.md +429 -0
  2. package/README.md +14 -17
  3. package/dist/api/LambderApiDeclarations.d.ts +11 -5
  4. package/dist/api/LambderApiDefinition.d.ts +2 -1
  5. package/dist/api/LambderApiEnvelope.d.ts +2 -2
  6. package/dist/api/LambderApiEnvelope.js +8 -2
  7. package/dist/api/LambderApiGuards.d.ts +44 -5
  8. package/dist/api/LambderApiGuards.js +27 -0
  9. package/dist/api/LambderApiIdempotency.d.ts +14 -7
  10. package/dist/api/LambderApiIdempotency.js +39 -27
  11. package/dist/api/LambderApiPipeline.d.ts +25 -11
  12. package/dist/api/LambderApiPipeline.js +34 -17
  13. package/dist/api/LambderApiRateLimits.d.ts +28 -21
  14. package/dist/api/LambderApiRateLimits.js +55 -35
  15. package/dist/api/LambderApiRefusals.d.ts +10 -4
  16. package/dist/api/LambderApiRefusals.js +31 -5
  17. package/dist/api/LambderApiRequest.d.ts +21 -1
  18. package/dist/api/LambderApiRequest.js +31 -2
  19. package/dist/build/checkApiRefusals.d.ts +8 -3
  20. package/dist/build/checkApiRefusals.js +80 -29
  21. package/dist/build/contractPrinterProcess.d.ts +11 -0
  22. package/dist/build/contractPrinterProcess.js +17 -0
  23. package/dist/build/generateApiFiles.d.ts +26 -5
  24. package/dist/build/generateApiFiles.js +68 -7
  25. package/dist/build/writeApiSchemas.d.ts +109 -0
  26. package/dist/build/writeApiSchemas.js +308 -0
  27. package/dist/build.d.ts +3 -1
  28. package/dist/build.js +2 -0
  29. package/dist/client/LambderCaller.d.ts +25 -11
  30. package/dist/client/LambderCaller.js +57 -49
  31. package/dist/client/LambderUploadRunner.d.ts +55 -27
  32. package/dist/client/LambderUploadRunner.js +89 -34
  33. package/dist/client.d.ts +6 -6
  34. package/dist/client.js +2 -2
  35. package/dist/core/Lambder.d.ts +31 -21
  36. package/dist/core/Lambder.js +79 -23
  37. package/dist/core/LambderCallSummary.d.ts +1 -1
  38. package/dist/core/LambderContext.d.ts +59 -7
  39. package/dist/core/LambderContext.js +31 -15
  40. package/dist/core/LambderCrashHandling.d.ts +5 -0
  41. package/dist/core/LambderCrashHandling.js +11 -1
  42. package/dist/core/LambderCreateOptions.d.ts +28 -17
  43. package/dist/core/LambderCreateOptions.js +14 -7
  44. package/dist/core/LambderResolver.d.ts +3 -2
  45. package/dist/core/LambderResponseBuilder.d.ts +20 -9
  46. package/dist/core/LambderResponseBuilder.js +39 -8
  47. package/dist/core/LambderTemplatingEngine.d.ts +24 -6
  48. package/dist/core/LambderTemplatingEngine.js +23 -3
  49. package/dist/index.d.ts +15 -12
  50. package/dist/index.js +7 -5
  51. package/dist/invoke/LambderInvokeCaller.d.ts +25 -4
  52. package/dist/invoke/LambderInvokeCaller.js +47 -9
  53. package/dist/invoke/LambderInvokeOutcome.d.ts +7 -6
  54. package/dist/mock/LambderMockAdapterDoor.d.ts +40 -0
  55. package/dist/mock/LambderMockAdapterDoor.js +10 -0
  56. package/dist/mock/LambderMockApiSchemas.d.ts +28 -0
  57. package/dist/mock/LambderMockApiSchemas.js +150 -0
  58. package/dist/mock/LambderMockApp.d.ts +56 -48
  59. package/dist/mock/LambderMockApp.js +107 -62
  60. package/dist/mock/LambderMockBrowserCookies.js +18 -5
  61. package/dist/mock/LambderMockCreateOptions.d.ts +51 -4
  62. package/dist/mock/LambderMockFailureInjector.d.ts +12 -3
  63. package/dist/mock/LambderMockFailureInjector.js +12 -8
  64. package/dist/mock/LambderMockTypes.d.ts +8 -4
  65. package/dist/mock/lambderMockInvokeTransport.js +2 -9
  66. package/dist/mock/lambderMockMswHandler.d.ts +19 -13
  67. package/dist/mock/lambderMockMswHandler.js +25 -22
  68. package/dist/mock.d.ts +1 -0
  69. package/dist/secrets/LambderOneShotSecrets.d.ts +1 -1
  70. package/dist/secrets/LambderOneShotSecrets.js +6 -36
  71. package/dist/secrets/LambderPasswordHasher.d.ts +56 -0
  72. package/dist/secrets/LambderPasswordHasher.js +168 -0
  73. package/dist/session/LambderSessionController.d.ts +37 -4
  74. package/dist/session/LambderSessionController.js +36 -6
  75. package/dist/session/LambderSessionManager.d.ts +33 -3
  76. package/dist/session/LambderSessionManager.js +55 -16
  77. package/dist/shared/LambderHtml.d.ts +23 -4
  78. package/dist/shared/LambderHtml.js +17 -5
  79. package/dist/shared/LambderI18n.d.ts +106 -16
  80. package/dist/shared/LambderI18n.js +259 -74
  81. package/dist/shared/contracts/LambderCache.d.ts +14 -1
  82. package/dist/shared/contracts/LambderRateLimiter.d.ts +5 -6
  83. package/dist/shared/transport/LambderApiTransport.d.ts +3 -2
  84. package/dist/shared/util/LambderBackoffTimer.d.ts +24 -13
  85. package/dist/shared/util/LambderBackoffTimer.js +40 -12
  86. package/dist/shared/util/LambderCallAbort.d.ts +22 -6
  87. package/dist/shared/util/LambderCallAbort.js +37 -9
  88. package/dist/shared/util/LambderErrorReportMark.d.ts +4 -0
  89. package/dist/shared/util/LambderErrorReportMark.js +22 -0
  90. package/dist/shared/util/LambderKeyFieldDigest.d.ts +46 -0
  91. package/dist/shared/util/LambderKeyFieldDigest.js +75 -0
  92. package/dist/shared/util/LambderSignedClaims.d.ts +19 -0
  93. package/dist/shared/util/LambderSignedClaims.js +54 -0
  94. package/dist/shared/util/LambderSwappableInstances.d.ts +29 -0
  95. package/dist/shared/util/LambderSwappableInstances.js +54 -0
  96. package/dist/shared/util/LambderTestingDoors.d.ts +6 -2
  97. package/dist/shared/util/LambderTestingDoors.js +6 -2
  98. package/dist/shared/util/LambderTextDigest.d.ts +5 -5
  99. package/dist/shared/util/LambderTextDigest.js +5 -5
  100. package/dist/shared/wire/LambderApiContract.d.ts +1 -1
  101. package/dist/shared/wire/LambderApiOptionEntries.d.ts +9 -1
  102. package/dist/shared/wire/LambderApiOptionEntries.js +15 -0
  103. package/dist/shared/wire/LambderApiOptionValues.d.ts +3 -2
  104. package/dist/shared/wire/LambderApiOutcome.d.ts +37 -19
  105. package/dist/shared/wire/LambderApiOutcome.js +1 -1
  106. package/dist/shared/wire/LambderApiRefusal.d.ts +39 -12
  107. package/dist/shared/wire/LambderApiRefusal.js +3 -3
  108. package/dist/shared/wire/LambderApiSchemaEntries.d.ts +21 -0
  109. package/dist/shared/wire/LambderApiSchemaEntries.js +18 -0
  110. package/dist/shared/wire/LambderCallOptions.d.ts +3 -3
  111. package/dist/shared/wire/LambderCallOutcome.d.ts +2 -1
  112. package/dist/shared/wire/LambderCallOutcome.js +3 -2
  113. package/dist/shared/wire/LambderIdempotencyKeyScope.d.ts +5 -3
  114. package/dist/shared/wire/LambderIdempotencyKeyScope.js +5 -3
  115. package/dist/shared/wire/LambderInvokeApiId.d.ts +3 -3
  116. package/dist/shared/wire/LambderInvokeApiId.js +3 -3
  117. package/dist/shared/wire/LambderOutcomeAssertions.d.ts +7 -6
  118. package/dist/shared/wire/LambderOutcomeAssertions.js +1 -1
  119. package/dist/stores/LambderCacheValues.d.ts +2 -5
  120. package/dist/stores/LambderDdbCache.d.ts +15 -9
  121. package/dist/stores/LambderDdbCache.js +25 -6
  122. package/dist/stores/LambderDdbIdempotencyStore.d.ts +6 -4
  123. package/dist/stores/LambderDdbIdempotencyStore.js +32 -52
  124. package/dist/stores/LambderDdbOneShotSecretStore.d.ts +11 -0
  125. package/dist/stores/LambderDdbOneShotSecretStore.js +17 -5
  126. package/dist/stores/LambderDdbSdk.d.ts +59 -29
  127. package/dist/stores/LambderDdbSdk.js +116 -44
  128. package/dist/stores/LambderDdbSessionStore.d.ts +26 -11
  129. package/dist/stores/LambderDdbSessionStore.js +133 -68
  130. package/dist/stores/LambderMemoryCache.d.ts +2 -2
  131. package/dist/stores/LambderS3FileSource.d.ts +3 -2
  132. package/dist/stores/LambderS3FileSource.js +11 -13
  133. package/dist/stores/LambderS3UploadBucket.d.ts +12 -0
  134. package/dist/stores/LambderS3UploadBucket.js +23 -0
  135. package/dist/stores/LambderStorageBackedCache.d.ts +2 -2
  136. package/dist/stores/LambderStoredText.d.ts +26 -0
  137. package/dist/stores/LambderStoredText.js +25 -0
  138. package/dist/testing/LambderConformanceRunner.d.ts +9 -2
  139. package/dist/testing/LambderConformanceRunner.js +9 -2
  140. package/dist/testing/LambderTestApp.d.ts +65 -7
  141. package/dist/testing/LambderTestApp.js +101 -6
  142. package/dist/testing/LambderTestVisitor.d.ts +43 -12
  143. package/dist/testing/LambderTestVisitor.js +35 -11
  144. package/dist/testing/bootLambdaPackage.d.ts +105 -0
  145. package/dist/testing/bootLambdaPackage.js +265 -0
  146. package/dist/testing/lambdaPackageBootProcess.d.ts +39 -0
  147. package/dist/testing/lambdaPackageBootProcess.js +130 -0
  148. package/dist/testing/lambderCacheConformance.d.ts +26 -0
  149. package/dist/testing/lambderCacheConformance.js +287 -0
  150. package/dist/testing/lambderCacheStorageConformance.d.ts +25 -0
  151. package/dist/testing/lambderCacheStorageConformance.js +159 -0
  152. package/dist/testing/lambderSessionStoreConformance.d.ts +3 -3
  153. package/dist/testing/lambderSessionStoreConformance.js +3 -3
  154. package/dist/testing.d.ts +7 -1
  155. package/dist/testing.js +5 -0
  156. package/package.json +1 -6
  157. package/dist/shared/util/boundKeyField.d.ts +0 -20
  158. package/dist/shared/util/boundKeyField.js +0 -34
@@ -292,9 +292,18 @@ const collectNames = (nodes, slots, conditions) => {
292
292
  }
293
293
  }
294
294
  };
295
+ /** A name list in an error message: quoted and comma-separated, or "none". */
296
+ const listNames = (names) => names.length === 0 ? "none" : names.map((name) => JSON.stringify(name)).join(", ");
297
+ /**
298
+ * A comment-only HTML template, compiled once. TNames is the caller's
299
+ * statement of its slot and condition names, which types render()'s data;
300
+ * left out, any name compiles, and render() checks every key either way.
301
+ */
295
302
  export class LambderTemplatingEngine {
296
303
  nodes;
297
- /** Slot names discovered at compile time (dynamic typing surface). */
304
+ /** Every slot and condition name: what a data key has to be one of. */
305
+ names;
306
+ /** Slot names discovered at compile time. */
298
307
  slotNames;
299
308
  /** Condition names discovered at compile time. */
300
309
  conditionNames;
@@ -306,6 +315,7 @@ export class LambderTemplatingEngine {
306
315
  collectNames(this.nodes, slots, conditions);
307
316
  this.slotNames = [...slots];
308
317
  this.conditionNames = [...conditions];
318
+ this.names = new Set([...slots, ...conditions]);
309
319
  }
310
320
  /** Read and parse a template file (compile once, render many times). */
311
321
  static async fromFile(filePath, options = {}) {
@@ -317,10 +327,20 @@ export class LambderTemplatingEngine {
317
327
  }
318
328
  /** True when the template declares `name` as a slot or condition. */
319
329
  has(name) {
320
- return this.slotNames.includes(name) || this.conditionNames.includes(name);
330
+ return this.names.has(name);
321
331
  }
322
- /** Render with escaped-by-default data; unknown keys ignored, omitted slots keep defaults. */
332
+ /**
333
+ * Render with escaped-by-default data; omitted slots keep their defaults.
334
+ * Throws for a key the template has no slot or condition for, naming it
335
+ * and the template's names.
336
+ */
323
337
  render(data = {}) {
338
+ const unknownKeys = Object.keys(data).filter((key) => !this.names.has(key));
339
+ if (unknownKeys.length > 0) {
340
+ throw new Error(`LambderTemplatingEngine: the data carries ${listNames(unknownKeys)}, which the template has no slot or condition for, ` +
341
+ `so ${unknownKeys.length === 1 ? "its value" : "their values"} would be dropped. Its slots: ${listNames(this.slotNames)}; ` +
342
+ `its conditions: ${listNames(this.conditionNames)}.`);
343
+ }
324
344
  const output = { html: "", firstDataIndex: -1 };
325
345
  renderNodes(this.nodes, data, output);
326
346
  return output.html;
package/dist/index.d.ts CHANGED
@@ -18,7 +18,7 @@ export { LambderCookieJar, parseSetCookie } from "./shared/transport/LambderCook
18
18
  export { LambderExpiringMap, LambderExpiringMapFullError } from "./shared/util/LambderExpiringMap.js";
19
19
  export { LambderBackoffTimer } from "./shared/util/LambderBackoffTimer.js";
20
20
  export type { LambderBackoffTimerOptions } from "./shared/util/LambderBackoffTimer.js";
21
- export { LambderSignedClaims, keyedDigest, randomSecret } from "./shared/util/LambderSignedClaims.js";
21
+ export { LambderSignedClaims, keyedDigest, randomSecret, randomCode } from "./shared/util/LambderSignedClaims.js";
22
22
  export type { LambderSignedClaimsOptions } from "./shared/util/LambderSignedClaims.js";
23
23
  export { constantTimeEquals } from "./shared/util/LambderTextDigest.js";
24
24
  export type { LambderStoredCookie } from "./shared/transport/LambderCookieJar.js";
@@ -28,7 +28,7 @@ export { synthesizeLambdaHttpEvent, decodeLambdaHttpResult, localLambdaContext,
28
28
  export type { LambderSynthesizedRequest, LambderLambdaHttpResult, LambderInvokeSession } from "./invoke/LambderLambdaEvent.js";
29
29
  export { LambderApiPipeline } from "./api/LambderApiPipeline.js";
30
30
  export type { LambderApiPipelineOptions, LambderApiSessionsConfig, LambderApiInputRefusal, LambderApiRunResult, LambderApiExec } from "./api/LambderApiPipeline.js";
31
- export { readApiEnvelope, restoreCompressedPayload } from "./api/LambderApiRequest.js";
31
+ export { readApiEnvelope, readApiEnvelopeText, restoreCompressedPayload } from "./api/LambderApiRequest.js";
32
32
  export type { LambderApiRequest, LambderApiRequestInfo, LambderCompressedPayloadFields, LambderRestorePayloadResult } from "./api/LambderApiRequest.js";
33
33
  export { toHttpAnswer } from "./api/LambderApiAnswer.js";
34
34
  export type { LambderApiAnswer } from "./api/LambderApiAnswer.js";
@@ -54,7 +54,7 @@ export type { LambderInvokeCallerOptions, LambderInvokeCallOptions, LambderInvok
54
54
  export { describeCrash, errorFromCrashDetail } from "./shared/wire/LambderCrashDetail.js";
55
55
  export type { LambderCrashDetail, LambderCrashCause } from "./shared/wire/LambderCrashDetail.js";
56
56
  export { LambderApiRefusal, isLambderApiRefusal, isLambderRefusalCode, refuse, refusalMessageOf, LAMBDER_REFUSAL_CODES } from "./shared/wire/LambderApiRefusal.js";
57
- export type { LambderApiRefusalOptions, LambderRefusalMessage, LambderPlainRefusalMessage, LambderUncheckedRefusalMessage, LambderRefusalCode, LambderRefuseOptions, LambderDeclaredRefuseOptions, LambderDeclaredRefuse, } from "./shared/wire/LambderApiRefusal.js";
57
+ export type { LambderApiRefusalOptions, LambderRefusalMessage, LambderPlainRefusalMessage, LambderRateLimitRefusalData, LambderUncheckedRefusalMessage, LambderRefusalCode, LambderRefuseOptions, LambderDeclaredRefuseOptions, LambderDeclaredRefuse, } from "./shared/wire/LambderApiRefusal.js";
58
58
  export { isObjectPayload } from "./shared/wire/LambderObjectPayload.js";
59
59
  export { default as LambderResponseBuilder } from "./core/LambderResponseBuilder.js";
60
60
  export { default as LambderResolver } from "./core/LambderResolver.js";
@@ -69,12 +69,12 @@ export { LambderWebCrypto, LambderPlainSessionCrypto, isWebCryptoAvailable } fro
69
69
  export type { LambderSessionCrypto } from "./session/LambderSessionCrypto.js";
70
70
  export { LambderDdbSessionStore } from "./stores/LambderDdbSessionStore.js";
71
71
  export type { LambderDdbSessionStoreOptions } from "./stores/LambderDdbSessionStore.js";
72
- export { LambderResponse, finalizeResponse, answerFromResponse, responseFromAnswer, type LambderHttpResponse, type LambderHeadersInput, type LambderFinalizeOptions, type LambderResponseCompressionSettings, type LambderResponseCompressionOption, } from "./core/LambderResponse.js";
72
+ export { LambderResponse, type LambderHttpResponse, type LambderHeadersInput, type LambderResponseCompressionSettings, type LambderResponseCompressionOption, } from "./core/LambderResponse.js";
73
73
  export type { LambderHttpStatusCode, LambderRefusalStatusCode } from "./shared/wire/LambderHttpStatus.js";
74
- export { html, xml, raw, jsonScript, escapeHtml, renderHtmlValue, LambderSafeHtml, type LambderHtmlValue } from "./shared/LambderHtml.js";
74
+ export { html, xml, raw, jsonScript, escapeHtml, renderHtmlValue, LambderSafeHtml, type LambderHtmlValue, type LambderJsonScriptOptions } from "./shared/LambderHtml.js";
75
75
  export { LambderTemplatingEngine } from "./core/LambderTemplatingEngine.js";
76
76
  export type { LambderTemplateData, LambderTemplatingEngineOptions } from "./core/LambderTemplatingEngine.js";
77
- export type { LambderResponseOptions, LambderRawResponseInit, } from "./core/LambderResponseBuilder.js";
77
+ export type { LambderResponseOptions, LambderRawResponseInit, LambderTemplateFileOptions, } from "./core/LambderResponseBuilder.js";
78
78
  export type { LambderRouteMatcher, LambderRouteConditionFn, LambderRouteCondition, LambderPathParamsOf, LambderRoutePath } from "./core/LambderRouting.js";
79
79
  export type { LambderCorsConfig } from "./core/LambderCors.js";
80
80
  export type { LambderCreateOptions, LambderSessionOptions, LambderActionTools, LambderHandler, } from "./core/LambderCreateOptions.js";
@@ -107,9 +107,9 @@ export { compressText, restoreBytes, restoreText, LambderCompressionError, LAMBD
107
107
  export type { LambderRestoreFailure, LambderRestoreBound } from "./shared/wire/LambderCompressionCodec.js";
108
108
  export { LambderSessionDataRefreshError, LambderSessionReadError } from "./session/LambderSessionManager.js";
109
109
  export { LambderSessionNotFoundError, LambderSessionAmbiguousError } from "./session/LambderSessionController.js";
110
- export type { LambderCache, LambderCacheKey, LambderCacheSetOptions, LambderCacheListOptions } from "./shared/contracts/LambderCache.js";
110
+ export type { LambderCache, LambderCacheKey, LambderCacheSetOptions, LambderCacheGetOrSetOptions, LambderCacheListOptions, } from "./shared/contracts/LambderCache.js";
111
111
  export { LambderDdbCache } from "./stores/LambderDdbCache.js";
112
- export type { LambderDdbCacheOptions, LambderDdbCacheGetOrSetOptions, } from "./stores/LambderDdbCache.js";
112
+ export type { LambderDdbCacheOptions } from "./stores/LambderDdbCache.js";
113
113
  export { LambderMemoryCache } from "./stores/LambderMemoryCache.js";
114
114
  export type { LambderMemoryCacheOptions } from "./stores/LambderMemoryCache.js";
115
115
  export { LambderStorageBackedCache } from "./stores/LambderStorageBackedCache.js";
@@ -120,6 +120,8 @@ export type { LambderRateLimiter, LambderRateLimitWindow, LambderRateLimitPolicy
120
120
  export { LambderDdbRateLimiter } from "./stores/LambderDdbRateLimiter.js";
121
121
  export type { LambderDdbRateLimiterOptions } from "./stores/LambderDdbRateLimiter.js";
122
122
  export { LambderMemoryRateLimiter } from "./stores/LambderMemoryRateLimiter.js";
123
+ export { LambderPasswordHasher } from "./secrets/LambderPasswordHasher.js";
124
+ export type { LambderPasswordHasherOptions } from "./secrets/LambderPasswordHasher.js";
123
125
  export { LambderOneShotSecrets } from "./secrets/LambderOneShotSecrets.js";
124
126
  export type { LambderOneShotSecretKind, LambderOneShotSecretsOptions, LambderOneShotIssueResult, LambderOneShotRedeemResult, LambderOneShotCodeKindNames, LambderOneShotTokenKindNames, } from "./secrets/LambderOneShotSecrets.js";
125
127
  export type { LambderOneShotSecretStore, LambderOneShotSecretRecord, LambderOneShotSecretDraft, LambderOneShotSecretShape, LambderOneShotIssueOutcome, } from "./shared/contracts/LambderOneShotSecretStore.js";
@@ -140,16 +142,17 @@ export type { LambderRateLimitKeyBuilder } from "./api/LambderApiRateLimits.js";
140
142
  export type { LambderContextRateLimit, LambderContextRateLimitCheck, LambderRateLimitCheckResult, LambderChargeablePolicyNames, LambderChargeKeyArgs, LambderRateLimitKeyFn, LambderRateLimitPer, LambderRateLimitBudget, LambderRateLimitChargeAt, LambderApiRateLimitPolicyConfig, LambderApiRateLimitsConfig, LambderAllowedPolicyNames, LambderPolicyNamesInputLacks, LambderRateLimitOption, } from "./api/LambderApiRateLimits.js";
141
143
  export type { LambderApiIdempotencyConfig } from "./api/LambderApiIdempotency.js";
142
144
  export type { LambderGuardsOptionValue, LambderRateLimitMessage, LambderRateLimitOverride, LambderRateLimitOptionValue, LambderRefusalsOptionValue, LambderApiIdempotencyOption, } from "./shared/wire/LambderApiOptionValues.js";
143
- export { apiGuardParam, apiGuardParamExportName } from "./shared/wire/LambderApiOptionEntries.js";
145
+ export { apiGuardParam, apiGuardParamExportName, apisWithGuard } from "./shared/wire/LambderApiOptionEntries.js";
144
146
  export type { LambderApiOptionEntries, LambderApiOptionEntry, LambderRateLimitPolicyEntry, LambderGuardDeclarationEntry, LambderApisWithGuard, LambderApisGuardedBy, LambderApisWithMode, LambderGuardParamOf, LambderApiGuardParam, } from "./shared/wire/LambderApiOptionEntries.js";
145
147
  export { createLambderI18n } from "./shared/LambderI18n.js";
146
- export type { LambderLanguageMeta, LambderI18nConfig, LambderI18nInstance, LambderI18nTranslator, LambderI18nExtractParams, LambderI18nDictionaryLoader, LambderI18nCodes, LambderI18nKeys, LambderI18nTranslatorFor, } from "./shared/LambderI18n.js";
148
+ export type { LambderLanguageMeta, LambderI18nConfig, LambderI18nInstance, LambderI18nReadonlyInstance, LambderI18nTranslator, LambderI18nExtractParams, LambderI18nDictionaryLoader, LambderI18nDictionaryEntry, LambderI18nPluralEntry, LambderI18nPluralCategory, LambderI18nCodes, LambderI18nKeys, LambderI18nTranslatorFor, } from "./shared/LambderI18n.js";
147
149
  export type { LambderApiContractShape, LambderApiMode, LambderApiEnvelopeBody, LambderApiSuccessEnvelope, LambderApiRefusalEnvelope, LambderRefusalEnvelopeFields, LambderApiRefusalConfig, LambderContractEntry, LambderGuardNamesIn, LambderContractMode, LambderContractKeysWithMode, LambderContractKeysWithGuard, LambderJsonOf, LambderContractRefusalsOf, LambderContractRefusalMessage, LambderContractRefusals, LambderContractAnyRefusalMessage, LambderContractGuardsOf, LambderContractGuardNames, LambderContractGuardInputsOf, LambderContractGuardInput, LambderContractGuardInputNames, LambderContractRateLimitOf, LambderContractRateLimitNames, LambderContractIdempotencyOf, } from "./shared/wire/LambderApiContract.js";
148
150
  export type { LambderRenderContext, LambderSessionRenderContext, LambderHttpEvent, LambderHttpEventFormat } from "./core/LambderContext.js";
149
- export type { LambderApiAnswerOutcome, LambderApiSuccessOutcome, LambderApiCallFailure, LambderApiValidationFailure, LambderApiEnvelopeFailure, LambderApiHttpAnswer, } from "./shared/wire/LambderApiOutcome.js";
151
+ export type { LambderRenderContextOf, LambderSessionRenderContextOf } from "./core/LambderContext.js";
152
+ export type { LambderApiAnswerOutcome, LambderApiSuccessOutcome, LambderApiFailure, LambderApiCallFailure, LambderApiValidationFailure, LambderApiEnvelopeFailure, LambderApiHttpAnswer, } from "./shared/wire/LambderApiOutcome.js";
150
153
  export { resolveApiOutcome } from "./shared/wire/LambderApiOutcome.js";
151
154
  export { createContext, isV2HttpEvent } from "./core/LambderContext.js";
152
- export type { LambderContextOptions, LambderOriginProof } from "./core/LambderContext.js";
155
+ export type { LambderContextOptions, LambderOriginProof, LambderRequestArrival } from "./core/LambderContext.js";
153
156
  export type { LambderCallSummary, LambderCallSummaryOption } from "./core/LambderCallSummary.js";
154
157
  export type { LambderCallOutcome, LambderCallOutcomeHint } from "./shared/wire/LambderCallOutcome.js";
155
158
  export { COMPRESSED_PAYLOAD_GZ_FIELD, COMPRESSED_PAYLOAD_BR_FIELD, COMPRESSED_PAYLOAD_BYTES_FIELD, DEFAULT_REQUEST_COMPRESSION_SETTINGS, DEFAULT_MAX_RESTORED_PAYLOAD_BYTES, DEFAULT_INVOKE_REQUEST_COMPRESSION_SETTINGS, compressPayloadBrotli, } from "./shared/wire/LambderRequestPayload.js";
package/dist/index.js CHANGED
@@ -13,14 +13,14 @@ export { LambderCookieJar, parseSetCookie } from "./shared/transport/LambderCook
13
13
  export { LambderExpiringMap, LambderExpiringMapFullError } from "./shared/util/LambderExpiringMap.js";
14
14
  // Waiting longer after each failure, once: what the upload runner and an app's own retrying code climb.
15
15
  export { LambderBackoffTimer } from "./shared/util/LambderBackoffTimer.js";
16
- // Signed claims tokens, and the keyed digest and random secret for the secrets an app stores.
17
- export { LambderSignedClaims, keyedDigest, randomSecret } from "./shared/util/LambderSignedClaims.js";
16
+ // Signed claims tokens, and the keyed digest, random secret and random code for the secrets an app stores.
17
+ export { LambderSignedClaims, keyedDigest, randomSecret, randomCode } from "./shared/util/LambderSignedClaims.js";
18
18
  export { constantTimeEquals } from "./shared/util/LambderTextDigest.js";
19
19
  export { lambderHandlerTransport } from "./invoke/lambderHandlerTransport.js";
20
20
  export { synthesizeLambdaHttpEvent, decodeLambdaHttpResult, localLambdaContext, LAMBDER_INVOKE_HEADER, LAMBDER_INVOKED_BY_HEADER, LAMBDER_PARENT_REQUEST_HEADER, LAMBDER_INVOKE_PROTOCOL, } from "./invoke/LambderLambdaEvent.js";
21
21
  // The API core: the request, answer, envelope and pipeline both the server and the mock runtime run
22
22
  export { LambderApiPipeline } from "./api/LambderApiPipeline.js";
23
- export { readApiEnvelope, restoreCompressedPayload } from "./api/LambderApiRequest.js";
23
+ export { readApiEnvelope, readApiEnvelopeText, restoreCompressedPayload } from "./api/LambderApiRequest.js";
24
24
  export { toHttpAnswer } from "./api/LambderApiAnswer.js";
25
25
  export { LambderAnswerHeaders, getAnswerHeader, setAnswerHeader, addAnswerHeader } from "./shared/wire/LambderAnswerHeaders.js";
26
26
  export { createApiCallContext } from "./api/LambderApiCallContext.js";
@@ -50,7 +50,7 @@ export { LambderMemorySessionStore } from "./stores/LambderMemorySessionStore.js
50
50
  export { LambderWebCrypto, LambderPlainSessionCrypto, isWebCryptoAvailable } from "./session/LambderSessionCrypto.js";
51
51
  export { LambderDdbSessionStore } from "./stores/LambderDdbSessionStore.js";
52
52
  // Response model
53
- export { LambderResponse, finalizeResponse, answerFromResponse, responseFromAnswer, } from "./core/LambderResponse.js";
53
+ export { LambderResponse, } from "./core/LambderResponse.js";
54
54
  // Type-safe templating (tagged templates with auto-escaping)
55
55
  export { html, xml, raw, jsonScript, escapeHtml, renderHtmlValue, LambderSafeHtml } from "./shared/LambderHtml.js";
56
56
  // Comment-based HTML templating engine (build-pipeline-safe slots and conditionals, standalone)
@@ -81,6 +81,8 @@ export { LambderStorageBackedCache } from "./stores/LambderStorageBackedCache.js
81
81
  export { RATE_LIMIT_WINDOWS } from "./shared/contracts/LambderRateLimiter.js";
82
82
  export { LambderDdbRateLimiter } from "./stores/LambderDdbRateLimiter.js";
83
83
  export { LambderMemoryRateLimiter } from "./stores/LambderMemoryRateLimiter.js";
84
+ // Passwords at rest: argon2id PHC strings through node:crypto
85
+ export { LambderPasswordHasher } from "./secrets/LambderPasswordHasher.js";
84
86
  // One-shot secrets: codes and tokens handed out once and taken back once, the
85
87
  // store interface they live in, and the DynamoDB and in-memory stores
86
88
  export { LambderOneShotSecrets } from "./secrets/LambderOneShotSecrets.js";
@@ -97,7 +99,7 @@ export { LambderApiRefusalValidationError } from "./api/LambderApiRefusals.js";
97
99
  export { lambderRateLimitKeyBuilder, rateLimitRefusal, DEFAULT_RATE_LIMIT_REFUSAL } from "./api/LambderApiRateLimits.js";
98
100
  // The declared options as plain data: what apiOptionEntries() reports and
99
101
  // writeApiOptions writes, and the readers over the generated tables.
100
- export { apiGuardParam, apiGuardParamExportName } from "./shared/wire/LambderApiOptionEntries.js";
102
+ export { apiGuardParam, apiGuardParamExportName, apisWithGuard } from "./shared/wire/LambderApiOptionEntries.js";
101
103
  // Typed translations (standalone, isomorphic)
102
104
  export { createLambderI18n } from "./shared/LambderI18n.js";
103
105
  export { resolveApiOutcome } from "./shared/wire/LambderApiOutcome.js";
@@ -27,6 +27,7 @@ import { type LambderApiSignatureMap } from "../shared/wire/LambderApiSignatureM
27
27
  import type { LambdaClient, LambdaClientConfig } from "@aws-sdk/client-lambda";
28
28
  import type { LambderApiContractShape, LambderContractRefusalMessage } from "../shared/wire/LambderApiContract.js";
29
29
  import { type LambderCallArgs, type LambderContractOutputOf, type LambderGuardInputsProviderOption, type LambderSharedCallOptions } from "../shared/wire/LambderCallOptions.js";
30
+ import { LAMBDER_BACKEND_SWAP } from "../shared/util/LambderTestingDoors.js";
30
31
  import { type LambderCompressionOption } from "../shared/wire/LambderCompressionOption.js";
31
32
  import { type LambderInvokeSession, type LambderLambdaHttpResult } from "./LambderLambdaEvent.js";
32
33
  /**
@@ -57,7 +58,11 @@ export type LambderInvokeLogListHandler = (apiName: string, logList: unknown[])
57
58
  export type LambderInvokeCallCheck = (name: string, info: {
58
59
  functionName: string;
59
60
  }) => void;
60
- /** The onFailure option: every failed call, once, awaited before api() throws or apiOutcome() returns. */
61
+ /**
62
+ * The onFailure option: every failed call, once, awaited before api() throws
63
+ * or apiOutcome() returns, but for a call its own signal aborted, which is the
64
+ * calling code's choice rather than a failure to report.
65
+ */
61
66
  export type LambderInvokeFailureHandler = (failure: LambderInvokeFailure, info: {
62
67
  apiName: string;
63
68
  functionName: string;
@@ -120,8 +125,11 @@ type LambderInvokeCallerBaseOptions = {
120
125
  /**
121
126
  * Called and awaited for every failed call before api() throws or
122
127
  * apiOutcome() returns, so failures are reported in one place, before the
123
- * lambda answers. A throw inside it is logged and otherwise ignored, so
124
- * apiOutcome() never throws.
128
+ * lambda answers. A call its own signal aborted is not told: the calling
129
+ * code gave it up. A throw inside it is logged and otherwise ignored, so
130
+ * apiOutcome() never throws. The error of a failure it took is marked as
131
+ * reported, so the instance's crash reporting does not report it again
132
+ * when api() throws it up through a handler.
125
133
  */
126
134
  onFailure?: LambderInvokeFailureHandler;
127
135
  /**
@@ -183,6 +191,19 @@ export type LambderInvokeEventInit = {
183
191
  declare class LambderInvokeCallerCore<TContract extends LambderApiContractShape = any, TProvidedGuards extends string = never> {
184
192
  #private;
185
193
  constructor(options: LambderInvokeCallerOptions<TContract, TProvidedGuards>);
194
+ /**
195
+ * Points this caller, in place of the Lambda SDK, at what
196
+ * `lambder/testing` answers its function with: a mock app the test
197
+ * supplied for it, or a transport that fails every call naming the
198
+ * function. Keyed by a symbol no entry point exports; see
199
+ * registerSwappableInstance.
200
+ */
201
+ [LAMBDER_BACKEND_SWAP](twins: {
202
+ invokeTransport(callee: {
203
+ functionName: string;
204
+ apiPath: string;
205
+ }): LambderInvokeTransport;
206
+ }): void;
186
207
  /**
187
208
  * The event api() would send for this call, with a plain payload. For
188
209
  * tests and boot checks that hand a built package an event file.
@@ -238,7 +259,7 @@ export type LambderInvokeGroupCalls<TContract, TProvidedGuards extends string> =
238
259
  };
239
260
  };
240
261
  /**
241
- * A typed client of another Lambder function, over a direct Lambda invoke:
262
+ * A typed client of another Lambder function, over a Lambda invoke:
242
263
  * `caller.email.send(input)` for the callee's endpoint `email.send`,
243
264
  * `.outcome(input)` for its outcome, and `caller.api("email.send", input)`
244
265
  * for code that has the name as a value.
@@ -29,8 +29,11 @@ import { resolveApiOutcome } from "../shared/wire/LambderApiOutcome.js";
29
29
  import { mergeGuardInputs, } from "../shared/wire/LambderCallOptions.js";
30
30
  import { beginIdempotentAttempt, IDEMPOTENT_ATTEMPT_NOT_SENT } from "../shared/wire/LambderIdempotencyKeyScope.js";
31
31
  import { createCallAbort, stopWaitingWhenAborted } from "../shared/util/LambderCallAbort.js";
32
+ import { markErrorReported } from "../shared/util/LambderErrorReportMark.js";
32
33
  import { coerceToError, errorFromCrashDetail } from "../shared/wire/LambderCrashDetail.js";
33
34
  import { assertPositiveInteger } from "../shared/util/LambderOptionChecks.js";
35
+ import { LAMBDER_BACKEND_SWAP } from "../shared/util/LambderTestingDoors.js";
36
+ import { registerSwappableInstance } from "../shared/util/LambderSwappableInstances.js";
34
37
  import { resolveCompressionOption } from "../shared/wire/LambderCompressionOption.js";
35
38
  import { DEFAULT_INVOKE_REQUEST_COMPRESSION_SETTINGS, DEFAULT_MAX_RESTORED_PAYLOAD_BYTES, compressPayloadBrotli, resolveRequestCompressionMinBytes, } from "../shared/wire/LambderRequestPayload.js";
36
39
  import { DEFAULT_API_PATH } from "../shared/wire/LambderDefaultApiPath.js";
@@ -63,6 +66,7 @@ class LambderInvokeCallerCore {
63
66
  #beforeCall;
64
67
  #guardInputsProvider;
65
68
  #sessionTokenCookieKey;
69
+ /** The transport given, or the Lambda SDK; `lambder/testing` replaces the SDK's through the swap door below. */
66
70
  #transport;
67
71
  #clientConfig;
68
72
  #client;
@@ -88,12 +92,26 @@ class LambderInvokeCallerCore {
88
92
  this.#guardInputsProvider = guardInputsProvider;
89
93
  this.#sessionTokenCookieKey = sessionTokenCookieKey ?? DEFAULT_SESSION_TOKEN_COOKIE_KEY;
90
94
  this.#transport = transport ?? ((_event, { eventJson, signal }) => this.#invokeThroughSdk(eventJson, signal));
95
+ // A caller given a transport reaches what the transport reaches, which
96
+ // its author chose; only the SDK path is the test kit's to replace.
97
+ if (!transport)
98
+ registerSwappableInstance(this);
91
99
  // Each group of the callee's contract, as a property:
92
100
  // caller.email.send(input) is caller.api("email.send", input), and
93
101
  // .outcome the apiOutcome.
94
102
  const byName = this;
95
103
  return withApiGroupCalls(this, (apiName, args) => byName.api(apiName, ...args), (apiName, args) => byName.apiOutcome(apiName, ...args));
96
104
  }
105
+ /**
106
+ * Points this caller, in place of the Lambda SDK, at what
107
+ * `lambder/testing` answers its function with: a mock app the test
108
+ * supplied for it, or a transport that fails every call naming the
109
+ * function. Keyed by a symbol no entry point exports; see
110
+ * registerSwappableInstance.
111
+ */
112
+ [LAMBDER_BACKEND_SWAP](twins) {
113
+ this.#transport = twins.invokeTransport({ functionName: this.#functionName, apiPath: this.#apiPath });
114
+ }
97
115
  /**
98
116
  * The event api() would send for this call, with a plain payload. For
99
117
  * tests and boot checks that hand a built package an event file.
@@ -184,7 +202,12 @@ class LambderInvokeCallerCore {
184
202
  }
185
203
  return { functionError: output.FunctionError ?? null, result };
186
204
  }
187
- /** Delivers one event, serialized exactly once; an event over the invoke cap, a rejected transport, or one that answered after the call was given up on, is a failure. */
205
+ /**
206
+ * Delivers one event, serialized exactly once; an event over the invoke
207
+ * cap, a rejected transport, or one that answered after the call was given
208
+ * up on, is a failure. `reachedTransport` says whether the transport was
209
+ * handed the event, since only then may the callee have run.
210
+ */
188
211
  async #deliverEvent(event, eventJson, options) {
189
212
  // Measured here so every path that delivers an event is capped: an
190
213
  // oversized event would otherwise come back as the SDK's
@@ -192,7 +215,7 @@ class LambderInvokeCallerCore {
192
215
  // names neither the size nor the cap.
193
216
  const bytes = Buffer.byteLength(eventJson, "utf8");
194
217
  if (bytes > LAMBDER_INVOKE_MAX_EVENT_BYTES) {
195
- return { failed: {
218
+ return { reachedTransport: false, failed: {
196
219
  reason: 'payloadTooLarge', bytes,
197
220
  detail: `the event is ${bytes} bytes, over the ${LAMBDER_INVOKE_MAX_EVENT_BYTES} byte invoke cap`,
198
221
  } };
@@ -206,21 +229,22 @@ class LambderInvokeCallerCore {
206
229
  // and not every transport meets it.
207
230
  const refused = abort.abortFailure("beforeSending");
208
231
  if (refused)
209
- return { failed: { reason: refused.reason, cause: refused.error, detail: refused.error.message } };
232
+ return { reachedTransport: false, failed: { reason: refused.reason, cause: refused.error, detail: refused.error.message } };
210
233
  const sent = await this.#transport(event, { functionName: this.#functionName, eventJson, signal: abort.signal });
211
234
  // An answer that arrives after the abort is not a success: a
212
235
  // transport that ignores the signal resolves late, and trusting it
213
236
  // would hand the call site data it had already abandoned.
214
237
  const late = abort.abortFailure("afterAnswering");
215
238
  if (late)
216
- return { failed: { reason: late.reason, cause: late.error, detail: late.error.message } };
239
+ return { reachedTransport: true, failed: { reason: late.reason, cause: late.error, detail: late.error.message } };
217
240
  return { sent };
218
241
  }
219
242
  catch (err) {
220
243
  const cause = coerceToError(err, "the invoke failed");
221
- // The caller's own timeout wins, since only the caller knows about
222
- // it; otherwise the rejection says what it was.
223
- return { failed: { reason: abort.timedOut() ? 'timeout' : classifyDeliveryFailure(cause), cause } };
244
+ // The caller's own abort wins, timeout or signal, since only the
245
+ // caller knows which aborted the call; otherwise the rejection
246
+ // says what it was.
247
+ return { reachedTransport: true, failed: { reason: abort.abortReason() ?? classifyDeliveryFailure(cause), cause } };
224
248
  }
225
249
  finally {
226
250
  abort.detach();
@@ -267,11 +291,18 @@ class LambderInvokeCallerCore {
267
291
  ...(init.response !== undefined ? { response: init.response } : {}),
268
292
  };
269
293
  error.outcome = failure;
270
- if (this.#onFailure) {
294
+ // The calling code aborted this call itself, so there is nothing to
295
+ // report: the error still reaches whoever reads the outcome.
296
+ if (this.#onFailure && failure.reason !== 'aborted') {
271
297
  // A reporting hook that breaks must not turn apiOutcome() into a
272
298
  // throwing call, nor replace the failure it was told about.
273
299
  try {
274
300
  await this.#onFailure(failure, { apiName, functionName: this.#functionName });
301
+ // Reported now, so the crash reporting a thrown api() reaches
302
+ // skips it rather than recording the one failure twice. Only
303
+ // once the hook returned: one that threw may have reported
304
+ // nothing, and a duplicate is better than a loss.
305
+ markErrorReported(error);
275
306
  }
276
307
  catch (err) {
277
308
  console.error(`[lambder invoke] onFailure threw for ${this.#functionName} ${apiName}`, err);
@@ -368,8 +399,15 @@ class LambderInvokeCallerCore {
368
399
  return await this.#failureOutcome(apiName, { reason: 'unknown', cause: coerceToError(err, "the call could not be built") });
369
400
  }
370
401
  const delivery = await this.#deliverEvent(event, eventJson, options);
371
- if ("failed" in delivery)
402
+ if ("failed" in delivery) {
403
+ // An event the transport was never handed did not use the key,
404
+ // whatever the failure reads as (an abort reads as aborted or
405
+ // timeout): the same as the browser caller's failure before
406
+ // sending.
407
+ if (!delivery.reachedTransport)
408
+ idempotentAttempt.settle(IDEMPOTENT_ATTEMPT_NOT_SENT);
372
409
  return await this.#failureOutcome(apiName, delivery.failed);
410
+ }
373
411
  if (delivery.sent.functionError) {
374
412
  return await this.#failureOutcome(apiName, { reason: 'crash', functionError: parseFunctionError(delivery.sent.result) });
375
413
  }
@@ -69,14 +69,15 @@ export type LambderInvokeEnvelopeFailure<TMessage extends LambderUncheckedRefusa
69
69
  refusal: TMessage;
70
70
  });
71
71
  /**
72
- * Nothing usable came back: the invoke never arrived or was given up on, the
73
- * Lambda service answered instead of the callee, the callee answered 5xx, or
74
- * something around the call threw. A 5xx carries `response` when the callee
75
- * answered with Lambder's own envelope, which is how a crash detail and a
76
- * logList arrive with it.
72
+ * Nothing usable came back: the invoke never arrived or was given up on (by
73
+ * its timeout, or by the calling code through its signal), the Lambda service
74
+ * answered instead of the callee, the callee answered 5xx, or something
75
+ * around the call threw. A 5xx carries `response` when the callee answered
76
+ * with Lambder's own envelope, which is how a crash detail and a logList
77
+ * arrive with it.
77
78
  */
78
79
  export type LambderInvokeDeliveryFailure<TMessage extends LambderUncheckedRefusalMessage = LambderUncheckedRefusalMessage> = LambderInvokeFailureFields<TMessage> & {
79
- reason: 'network' | 'timeout' | 'server' | 'protocol' | 'unknown';
80
+ reason: 'network' | 'timeout' | 'aborted' | 'server' | 'protocol' | 'unknown';
80
81
  response?: LambderApiRefusalEnvelope;
81
82
  /** The callee's crash detail, when its global error handler sent one (the envelope's `crash` field). */
82
83
  crash?: LambderCrashDetail;
@@ -0,0 +1,40 @@
1
+ import type { LambderApiRequest } from "../api/LambderApiRequest.js";
2
+ /**
3
+ * The key of the door the mock's own adapters open on a LambderMockApp: what
4
+ * an adapter asks of the runtime and tells it beyond handing it a call.
5
+ *
6
+ * A symbol rather than named members, and exported by no entry point: the
7
+ * package's exports map is what a consumer can import, so only an adapter of
8
+ * the package's own (the MSW handler) can name the key, and nothing on the
9
+ * app's typed surface offers an app the adapter's bookkeeping as an API.
10
+ */
11
+ export declare const LAMBDER_MOCK_ADAPTER_DOOR: unique symbol;
12
+ /** What a LambderMockApp answers to LAMBDER_MOCK_ADAPTER_DOOR. */
13
+ export type LambderMockAdapterDoor = {
14
+ /**
15
+ * Whether a call to this name would be answered from the registry, which
16
+ * is what an adapter asks before passing one on. Asked once per request,
17
+ * so not a list to scan.
18
+ *
19
+ * True for every name once a rest entry is registered, since it answers
20
+ * whatever nothing else claimed. That makes a rest entry and the MSW
21
+ * adapter's `onUnmocked: "passthrough"` alternatives rather than layers:
22
+ * with one registered, nothing is handed on to the network.
23
+ */
24
+ hasRegisteredEntry(apiName: string): boolean;
25
+ /**
26
+ * Records a call the adapter handed on instead of answering: the MSW
27
+ * adapter's passthrough. Without it a name the registry does not know
28
+ * leaves no trace at all, and a mistyped endpoint reaches the real
29
+ * network with nothing in the call log or on the subscription to say so,
30
+ * which is the one failure the log exists to make visible.
31
+ */
32
+ notePassthrough(request: LambderApiRequest): void;
33
+ /**
34
+ * Mirrors an answer's non-HttpOnly cookies into document.cookie and
35
+ * remembers them, so reset() expires them again. The direct transport's
36
+ * "document" mode and the MSW adapter both come through the runtime's one
37
+ * mirror, so there is one record of what was planted.
38
+ */
39
+ mirrorCookiesIntoDocument(setCookies: readonly string[]): void;
40
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The key of the door the mock's own adapters open on a LambderMockApp: what
3
+ * an adapter asks of the runtime and tells it beyond handing it a call.
4
+ *
5
+ * A symbol rather than named members, and exported by no entry point: the
6
+ * package's exports map is what a consumer can import, so only an adapter of
7
+ * the package's own (the MSW handler) can name the key, and nothing on the
8
+ * app's typed surface offers an app the adapter's bookkeeping as an API.
9
+ */
10
+ export const LAMBDER_MOCK_ADAPTER_DOOR = Symbol("lambder.mockAdapterDoor");
@@ -0,0 +1,28 @@
1
+ import { z } from "zod";
2
+ import { type LambderApiSchemaEntries } from "../shared/wire/LambderApiSchemaEntries.js";
3
+ /**
4
+ * The generated `apiSchemas` table, as the schemas the mock validates every
5
+ * call's input with and parses every answer through.
6
+ */
7
+ export declare class LambderMockApiSchemas {
8
+ private readonly table;
9
+ private readonly rebuilt;
10
+ constructor(table: LambderApiSchemaEntries);
11
+ /**
12
+ * The schema an entry's input is validated with, as the pipeline takes it
13
+ * at registration: lazy, so it is rebuilt on the first call that reaches
14
+ * it. A name the table does not hold throws here, when the entry is
15
+ * registered, rather than on its first call.
16
+ */
17
+ inputOf(apiName: string): z.ZodType;
18
+ /**
19
+ * An answer a handler returned, parsed through the server's output schema
20
+ * as the server parses its own: what the schema does not declare dropped,
21
+ * its defaults filled. What it rejects, or a parse that throws, is the
22
+ * handler breaking its contract, the error the server crashes with.
23
+ */
24
+ parseOutput(apiName: string, returned: unknown): unknown;
25
+ private assertHeld;
26
+ /** One of an API's schemas, rebuilt the first time it is asked for and kept. */
27
+ private rebuiltSchema;
28
+ }