@konker.dev/neverthrow-r-middleware 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +26 -0
- package/dist/handler.d.ts +3 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +2 -0
- package/dist/handler.js.map +1 -0
- package/dist/http/HttpApiError.d.ts +16 -0
- package/dist/http/HttpApiError.d.ts.map +1 -0
- package/dist/http/HttpApiError.js +60 -0
- package/dist/http/HttpApiError.js.map +1 -0
- package/dist/http/HttpApiError.test.d.ts +2 -0
- package/dist/http/HttpApiError.test.d.ts.map +1 -0
- package/dist/http/HttpApiError.test.js +45 -0
- package/dist/http/HttpApiError.test.js.map +1 -0
- package/dist/http/Rec.d.ts +13 -0
- package/dist/http/Rec.d.ts.map +1 -0
- package/dist/http/Rec.js +2 -0
- package/dist/http/Rec.js.map +1 -0
- package/dist/http/RequestResponseHandler.d.ts +7 -0
- package/dist/http/RequestResponseHandler.d.ts.map +1 -0
- package/dist/http/RequestResponseHandler.js +2 -0
- package/dist/http/RequestResponseHandler.js.map +1 -0
- package/dist/http/RequestW.d.ts +14 -0
- package/dist/http/RequestW.d.ts.map +1 -0
- package/dist/http/RequestW.js +17 -0
- package/dist/http/RequestW.js.map +1 -0
- package/dist/http/RequestW.test.d.ts +2 -0
- package/dist/http/RequestW.test.d.ts.map +1 -0
- package/dist/http/RequestW.test.js +26 -0
- package/dist/http/RequestW.test.js.map +1 -0
- package/dist/http/ResponseW.d.ts +11 -0
- package/dist/http/ResponseW.d.ts.map +1 -0
- package/dist/http/ResponseW.js +14 -0
- package/dist/http/ResponseW.js.map +1 -0
- package/dist/http/ResponseW.test.d.ts +2 -0
- package/dist/http/ResponseW.test.d.ts.map +1 -0
- package/dist/http/ResponseW.test.js +23 -0
- package/dist/http/ResponseW.test.js.map +1 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.d.ts +14 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.d.ts.map +1 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.js +26 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.js.map +1 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.test.d.ts +2 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.test.d.ts.map +1 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.test.js +76 -0
- package/dist/http/contrib/apiGatewayProxyEventV2Adapter.test.js.map +1 -0
- package/dist/http/contrib/base64BodyDecoder.d.ts +7 -0
- package/dist/http/contrib/base64BodyDecoder.d.ts.map +1 -0
- package/dist/http/contrib/base64BodyDecoder.js +15 -0
- package/dist/http/contrib/base64BodyDecoder.js.map +1 -0
- package/dist/http/contrib/base64BodyDecoder.test.d.ts +2 -0
- package/dist/http/contrib/base64BodyDecoder.test.d.ts.map +1 -0
- package/dist/http/contrib/base64BodyDecoder.test.js +47 -0
- package/dist/http/contrib/base64BodyDecoder.test.js.map +1 -0
- package/dist/http/contrib/basicAuthAuthenticator.d.ts +17 -0
- package/dist/http/contrib/basicAuthAuthenticator.d.ts.map +1 -0
- package/dist/http/contrib/basicAuthAuthenticator.js +30 -0
- package/dist/http/contrib/basicAuthAuthenticator.js.map +1 -0
- package/dist/http/contrib/basicAuthAuthenticator.test.d.ts +2 -0
- package/dist/http/contrib/basicAuthAuthenticator.test.d.ts.map +1 -0
- package/dist/http/contrib/basicAuthAuthenticator.test.js +64 -0
- package/dist/http/contrib/basicAuthAuthenticator.test.js.map +1 -0
- package/dist/http/contrib/basicAuthDecoder.d.ts +13 -0
- package/dist/http/contrib/basicAuthDecoder.d.ts.map +1 -0
- package/dist/http/contrib/basicAuthDecoder.js +23 -0
- package/dist/http/contrib/basicAuthDecoder.js.map +1 -0
- package/dist/http/contrib/basicAuthDecoder.test.d.ts +2 -0
- package/dist/http/contrib/basicAuthDecoder.test.d.ts.map +1 -0
- package/dist/http/contrib/basicAuthDecoder.test.js +31 -0
- package/dist/http/contrib/basicAuthDecoder.test.js.map +1 -0
- package/dist/http/contrib/bodyValidator.d.ts +11 -0
- package/dist/http/contrib/bodyValidator.d.ts.map +1 -0
- package/dist/http/contrib/bodyValidator.js +15 -0
- package/dist/http/contrib/bodyValidator.js.map +1 -0
- package/dist/http/contrib/bodyValidator.test.d.ts +2 -0
- package/dist/http/contrib/bodyValidator.test.d.ts.map +1 -0
- package/dist/http/contrib/bodyValidator.test.js +58 -0
- package/dist/http/contrib/bodyValidator.test.js.map +1 -0
- package/dist/http/contrib/envValidator.d.ts +10 -0
- package/dist/http/contrib/envValidator.d.ts.map +1 -0
- package/dist/http/contrib/envValidator.js +12 -0
- package/dist/http/contrib/envValidator.js.map +1 -0
- package/dist/http/contrib/envValidator.test.d.ts +2 -0
- package/dist/http/contrib/envValidator.test.d.ts.map +1 -0
- package/dist/http/contrib/envValidator.test.js +49 -0
- package/dist/http/contrib/envValidator.test.js.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.d.ts +13 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.d.ts.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.js +22 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.js.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.test.d.ts +2 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.test.d.ts.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.test.js +39 -0
- package/dist/http/contrib/headerSignatureAuthorizer/index.test.js.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.d.ts +4 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.d.ts.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.js +13 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.js.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.test.d.ts +2 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.test.d.ts.map +1 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.test.js +9 -0
- package/dist/http/contrib/headerSignatureAuthorizer/lib.test.js.map +1 -0
- package/dist/http/contrib/headersNormalizer/index.d.ts +9 -0
- package/dist/http/contrib/headersNormalizer/index.d.ts.map +1 -0
- package/dist/http/contrib/headersNormalizer/index.js +8 -0
- package/dist/http/contrib/headersNormalizer/index.js.map +1 -0
- package/dist/http/contrib/headersNormalizer/index.test.d.ts +2 -0
- package/dist/http/contrib/headersNormalizer/index.test.d.ts.map +1 -0
- package/dist/http/contrib/headersNormalizer/index.test.js +38 -0
- package/dist/http/contrib/headersNormalizer/index.test.js.map +1 -0
- package/dist/http/contrib/headersNormalizer/lib.d.ts +11 -0
- package/dist/http/contrib/headersNormalizer/lib.d.ts.map +1 -0
- package/dist/http/contrib/headersNormalizer/lib.js +64 -0
- package/dist/http/contrib/headersNormalizer/lib.js.map +1 -0
- package/dist/http/contrib/headersNormalizer/lib.test.d.ts +2 -0
- package/dist/http/contrib/headersNormalizer/lib.test.d.ts.map +1 -0
- package/dist/http/contrib/headersNormalizer/lib.test.js +35 -0
- package/dist/http/contrib/headersNormalizer/lib.test.js.map +1 -0
- package/dist/http/contrib/headersNormalizer/types.d.ts +10 -0
- package/dist/http/contrib/headersNormalizer/types.d.ts.map +1 -0
- package/dist/http/contrib/headersNormalizer/types.js +2 -0
- package/dist/http/contrib/headersNormalizer/types.js.map +1 -0
- package/dist/http/contrib/headersValidator.d.ts +12 -0
- package/dist/http/contrib/headersValidator.d.ts.map +1 -0
- package/dist/http/contrib/headersValidator.js +15 -0
- package/dist/http/contrib/headersValidator.js.map +1 -0
- package/dist/http/contrib/headersValidator.test.d.ts +2 -0
- package/dist/http/contrib/headersValidator.test.d.ts.map +1 -0
- package/dist/http/contrib/headersValidator.test.js +46 -0
- package/dist/http/contrib/headersValidator.test.js.map +1 -0
- package/dist/http/contrib/helmetJsHeaders.d.ts +5 -0
- package/dist/http/contrib/helmetJsHeaders.d.ts.map +1 -0
- package/dist/http/contrib/helmetJsHeaders.js +25 -0
- package/dist/http/contrib/helmetJsHeaders.js.map +1 -0
- package/dist/http/contrib/helmetJsHeaders.test.d.ts +2 -0
- package/dist/http/contrib/helmetJsHeaders.test.d.ts.map +1 -0
- package/dist/http/contrib/helmetJsHeaders.test.js +18 -0
- package/dist/http/contrib/helmetJsHeaders.test.js.map +1 -0
- package/dist/http/contrib/honoAdapter.d.ts +16 -0
- package/dist/http/contrib/honoAdapter.d.ts.map +1 -0
- package/dist/http/contrib/honoAdapter.js +28 -0
- package/dist/http/contrib/honoAdapter.js.map +1 -0
- package/dist/http/contrib/honoAdapter.test.d.ts +2 -0
- package/dist/http/contrib/honoAdapter.test.d.ts.map +1 -0
- package/dist/http/contrib/honoAdapter.test.js +75 -0
- package/dist/http/contrib/honoAdapter.test.js.map +1 -0
- package/dist/http/contrib/identity.d.ts +4 -0
- package/dist/http/contrib/identity.d.ts.map +1 -0
- package/dist/http/contrib/identity.js +3 -0
- package/dist/http/contrib/identity.js.map +1 -0
- package/dist/http/contrib/identity.test.d.ts +2 -0
- package/dist/http/contrib/identity.test.d.ts.map +1 -0
- package/dist/http/contrib/identity.test.js +12 -0
- package/dist/http/contrib/identity.test.js.map +1 -0
- package/dist/http/contrib/index.d.ts +25 -0
- package/dist/http/contrib/index.d.ts.map +1 -0
- package/dist/http/contrib/index.js +25 -0
- package/dist/http/contrib/index.js.map +1 -0
- package/dist/http/contrib/jsonBodyParserRequest.d.ts +10 -0
- package/dist/http/contrib/jsonBodyParserRequest.d.ts.map +1 -0
- package/dist/http/contrib/jsonBodyParserRequest.js +22 -0
- package/dist/http/contrib/jsonBodyParserRequest.js.map +1 -0
- package/dist/http/contrib/jsonBodyParserRequest.test.d.ts +2 -0
- package/dist/http/contrib/jsonBodyParserRequest.test.d.ts.map +1 -0
- package/dist/http/contrib/jsonBodyParserRequest.test.js +37 -0
- package/dist/http/contrib/jsonBodyParserRequest.test.js.map +1 -0
- package/dist/http/contrib/jsonBodySerializerResponse.d.ts +9 -0
- package/dist/http/contrib/jsonBodySerializerResponse.d.ts.map +1 -0
- package/dist/http/contrib/jsonBodySerializerResponse.js +15 -0
- package/dist/http/contrib/jsonBodySerializerResponse.js.map +1 -0
- package/dist/http/contrib/jsonBodySerializerResponse.test.d.ts +2 -0
- package/dist/http/contrib/jsonBodySerializerResponse.test.d.ts.map +1 -0
- package/dist/http/contrib/jsonBodySerializerResponse.test.js +31 -0
- package/dist/http/contrib/jsonBodySerializerResponse.test.js.map +1 -0
- package/dist/http/contrib/jwtAuthenticator.d.ts +15 -0
- package/dist/http/contrib/jwtAuthenticator.d.ts.map +1 -0
- package/dist/http/contrib/jwtAuthenticator.js +28 -0
- package/dist/http/contrib/jwtAuthenticator.js.map +1 -0
- package/dist/http/contrib/jwtAuthenticator.test.d.ts +2 -0
- package/dist/http/contrib/jwtAuthenticator.test.d.ts.map +1 -0
- package/dist/http/contrib/jwtAuthenticator.test.js +88 -0
- package/dist/http/contrib/jwtAuthenticator.test.js.map +1 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.d.ts +15 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.d.ts.map +1 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.js +28 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.js.map +1 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.test.d.ts +2 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.test.d.ts.map +1 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.test.js +88 -0
- package/dist/http/contrib/jwtAuthenticatorRsa.test.js.map +1 -0
- package/dist/http/contrib/jwtDecoder.d.ts +13 -0
- package/dist/http/contrib/jwtDecoder.d.ts.map +1 -0
- package/dist/http/contrib/jwtDecoder.js +23 -0
- package/dist/http/contrib/jwtDecoder.js.map +1 -0
- package/dist/http/contrib/jwtDecoder.test.d.ts +2 -0
- package/dist/http/contrib/jwtDecoder.test.d.ts.map +1 -0
- package/dist/http/contrib/jwtDecoder.test.js +76 -0
- package/dist/http/contrib/jwtDecoder.test.js.map +1 -0
- package/dist/http/contrib/pathParametersValidator.d.ts +12 -0
- package/dist/http/contrib/pathParametersValidator.d.ts.map +1 -0
- package/dist/http/contrib/pathParametersValidator.js +15 -0
- package/dist/http/contrib/pathParametersValidator.js.map +1 -0
- package/dist/http/contrib/pathParametersValidator.test.d.ts +2 -0
- package/dist/http/contrib/pathParametersValidator.test.d.ts.map +1 -0
- package/dist/http/contrib/pathParametersValidator.test.js +46 -0
- package/dist/http/contrib/pathParametersValidator.test.js.map +1 -0
- package/dist/http/contrib/pathTokenAuthorizer.d.ts +13 -0
- package/dist/http/contrib/pathTokenAuthorizer.d.ts.map +1 -0
- package/dist/http/contrib/pathTokenAuthorizer.js +19 -0
- package/dist/http/contrib/pathTokenAuthorizer.js.map +1 -0
- package/dist/http/contrib/pathTokenAuthorizer.test.d.ts +2 -0
- package/dist/http/contrib/pathTokenAuthorizer.test.d.ts.map +1 -0
- package/dist/http/contrib/pathTokenAuthorizer.test.js +29 -0
- package/dist/http/contrib/pathTokenAuthorizer.test.js.map +1 -0
- package/dist/http/contrib/queryStringValidator.d.ts +12 -0
- package/dist/http/contrib/queryStringValidator.d.ts.map +1 -0
- package/dist/http/contrib/queryStringValidator.js +15 -0
- package/dist/http/contrib/queryStringValidator.js.map +1 -0
- package/dist/http/contrib/queryStringValidator.test.d.ts +2 -0
- package/dist/http/contrib/queryStringValidator.test.d.ts.map +1 -0
- package/dist/http/contrib/queryStringValidator.test.js +46 -0
- package/dist/http/contrib/queryStringValidator.test.js.map +1 -0
- package/dist/http/contrib/requestResponseLogger.d.ts +5 -0
- package/dist/http/contrib/requestResponseLogger.d.ts.map +1 -0
- package/dist/http/contrib/requestResponseLogger.js +8 -0
- package/dist/http/contrib/requestResponseLogger.js.map +1 -0
- package/dist/http/contrib/requestResponseLogger.test.d.ts +2 -0
- package/dist/http/contrib/requestResponseLogger.test.d.ts.map +1 -0
- package/dist/http/contrib/requestResponseLogger.test.js +18 -0
- package/dist/http/contrib/requestResponseLogger.test.js.map +1 -0
- package/dist/http/contrib/responseProcessor.d.ts +8 -0
- package/dist/http/contrib/responseProcessor.d.ts.map +1 -0
- package/dist/http/contrib/responseProcessor.js +16 -0
- package/dist/http/contrib/responseProcessor.js.map +1 -0
- package/dist/http/contrib/responseProcessor.test.d.ts +2 -0
- package/dist/http/contrib/responseProcessor.test.d.ts.map +1 -0
- package/dist/http/contrib/responseProcessor.test.js +29 -0
- package/dist/http/contrib/responseProcessor.test.js.map +1 -0
- package/dist/http/contrib/standardRequestResponseAdapter.d.ts +16 -0
- package/dist/http/contrib/standardRequestResponseAdapter.d.ts.map +1 -0
- package/dist/http/contrib/standardRequestResponseAdapter.js +27 -0
- package/dist/http/contrib/standardRequestResponseAdapter.js.map +1 -0
- package/dist/http/contrib/standardRequestResponseAdapter.test.d.ts +2 -0
- package/dist/http/contrib/standardRequestResponseAdapter.test.d.ts.map +1 -0
- package/dist/http/contrib/standardRequestResponseAdapter.test.js +85 -0
- package/dist/http/contrib/standardRequestResponseAdapter.test.js.map +1 -0
- package/dist/http/contrib/trivial.d.ts +5 -0
- package/dist/http/contrib/trivial.d.ts.map +1 -0
- package/dist/http/contrib/trivial.js +9 -0
- package/dist/http/contrib/trivial.js.map +1 -0
- package/dist/http/contrib/trivial.test.d.ts +2 -0
- package/dist/http/contrib/trivial.test.d.ts.map +1 -0
- package/dist/http/contrib/trivial.test.js +14 -0
- package/dist/http/contrib/trivial.test.js.map +1 -0
- package/dist/http/index.d.ts +6 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +6 -0
- package/dist/http/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/Logger.d.ts +23 -0
- package/dist/lib/Logger.d.ts.map +1 -0
- package/dist/lib/Logger.js +30 -0
- package/dist/lib/Logger.js.map +1 -0
- package/dist/lib/Logger.test.d.ts +2 -0
- package/dist/lib/Logger.test.d.ts.map +1 -0
- package/dist/lib/Logger.test.js +54 -0
- package/dist/lib/Logger.test.js.map +1 -0
- package/dist/lib/MiddlewareError.d.ts +10 -0
- package/dist/lib/MiddlewareError.d.ts.map +1 -0
- package/dist/lib/MiddlewareError.js +20 -0
- package/dist/lib/MiddlewareError.js.map +1 -0
- package/dist/lib/MiddlewareError.test.d.ts +2 -0
- package/dist/lib/MiddlewareError.test.d.ts.map +1 -0
- package/dist/lib/MiddlewareError.test.js +55 -0
- package/dist/lib/MiddlewareError.test.js.map +1 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +4 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/utils.d.ts +7 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +11 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/utils.test.d.ts +2 -0
- package/dist/lib/utils.test.d.ts.map +1 -0
- package/dist/lib/utils.test.js +47 -0
- package/dist/lib/utils.test.js.map +1 -0
- package/dist/test/kitchen-sink.test.d.ts +2 -0
- package/dist/test/kitchen-sink.test.d.ts.map +1 -0
- package/dist/test/kitchen-sink.test.js +76 -0
- package/dist/test/kitchen-sink.test.js.map +1 -0
- package/dist/test/round-trip.test.d.ts +2 -0
- package/dist/test/round-trip.test.d.ts.map +1 -0
- package/dist/test/round-trip.test.js +75 -0
- package/dist/test/round-trip.test.js.map +1 -0
- package/dist/test/test-common.d.ts +17 -0
- package/dist/test/test-common.d.ts.map +1 -0
- package/dist/test/test-common.js +25 -0
- package/dist/test/test-common.js.map +1 -0
- package/package.json +265 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { errR, okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
2
|
+
import * as helpers from '@konker.dev/neverthrow-r-auth-utils/helpers';
|
|
3
|
+
import { TEST_JWT_NOW_MS } from '@konker.dev/neverthrow-r-auth-utils/test/fixtures/jwt';
|
|
4
|
+
import { TEST_RSA_KEY_PUBLIC } from '@konker.dev/neverthrow-r-auth-utils/test/fixtures/test-jwt-rsa-keys';
|
|
5
|
+
import { TEST_TOKEN_RSA, TEST_TOKEN_RSA_STRING_PAYLOAD, } from '@konker.dev/neverthrow-r-auth-utils/test/fixtures/test-jwt-tokens-rsa';
|
|
6
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
7
|
+
import { recordingLogger, sampleRequestW } from '../../test/test-common.js';
|
|
8
|
+
import { makeRequestW } from '../RequestW.js';
|
|
9
|
+
import { EMPTY_RESPONSE_W } from '../ResponseW.js';
|
|
10
|
+
import { middleware as jwtAuthenticatorRsa } from './jwtAuthenticatorRsa.js';
|
|
11
|
+
describe('jwtAuthenticatorRsa', () => {
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
vi.restoreAllMocks();
|
|
14
|
+
});
|
|
15
|
+
it('authenticates a valid RSA JWT', async () => {
|
|
16
|
+
vi.spyOn(Date, 'now').mockReturnValue(TEST_JWT_NOW_MS);
|
|
17
|
+
const { logger } = recordingLogger();
|
|
18
|
+
const wrapped = jwtAuthenticatorRsa()((req) => okAsyncR({
|
|
19
|
+
...EMPTY_RESPONSE_W,
|
|
20
|
+
body: req.userId,
|
|
21
|
+
}));
|
|
22
|
+
const input = makeRequestW(sampleRequestW, {
|
|
23
|
+
headers: { authorization: `Bearer ${TEST_TOKEN_RSA}` },
|
|
24
|
+
headersNormalizerRequestRaw: { Authorization: `Bearer ${TEST_TOKEN_RSA}` },
|
|
25
|
+
});
|
|
26
|
+
const result = await wrapped(input)({
|
|
27
|
+
logger,
|
|
28
|
+
issuer: 'test-iss',
|
|
29
|
+
rsaPublicKey: TEST_RSA_KEY_PUBLIC,
|
|
30
|
+
});
|
|
31
|
+
expect(result.isOk() && result.value.body).toBe('test-sub');
|
|
32
|
+
});
|
|
33
|
+
it('returns a 401 HttpApiError for an invalid RSA JWT', async () => {
|
|
34
|
+
const { logger } = recordingLogger();
|
|
35
|
+
const wrapped = jwtAuthenticatorRsa()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
36
|
+
const input = makeRequestW(sampleRequestW, {
|
|
37
|
+
headers: { authorization: 'Bearer banana' },
|
|
38
|
+
headersNormalizerRequestRaw: { Authorization: 'Bearer banana' },
|
|
39
|
+
});
|
|
40
|
+
const result = await wrapped(input)({
|
|
41
|
+
logger,
|
|
42
|
+
issuer: 'test-iss',
|
|
43
|
+
rsaPublicKey: TEST_RSA_KEY_PUBLIC,
|
|
44
|
+
});
|
|
45
|
+
expect(result.isErr() && result.error.statusCode).toBe(401);
|
|
46
|
+
});
|
|
47
|
+
it('returns a 401 HttpApiError when the auth header is missing', async () => {
|
|
48
|
+
const { logger } = recordingLogger();
|
|
49
|
+
const wrapped = jwtAuthenticatorRsa()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
50
|
+
const input = makeRequestW(sampleRequestW, {
|
|
51
|
+
headers: {},
|
|
52
|
+
headersNormalizerRequestRaw: {},
|
|
53
|
+
});
|
|
54
|
+
const result = await wrapped(input)({
|
|
55
|
+
logger,
|
|
56
|
+
issuer: 'test-iss',
|
|
57
|
+
rsaPublicKey: TEST_RSA_KEY_PUBLIC,
|
|
58
|
+
});
|
|
59
|
+
expect(result.isErr() && result.error.statusCode).toBe(401);
|
|
60
|
+
});
|
|
61
|
+
it('returns a 401 HttpApiError when RSA verification returns unverified', async () => {
|
|
62
|
+
vi.spyOn(Date, 'now').mockReturnValue(TEST_JWT_NOW_MS);
|
|
63
|
+
const { logger } = recordingLogger();
|
|
64
|
+
const wrapped = jwtAuthenticatorRsa()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
65
|
+
const input = makeRequestW(sampleRequestW, {
|
|
66
|
+
headers: { authorization: `Bearer ${TEST_TOKEN_RSA_STRING_PAYLOAD}` },
|
|
67
|
+
headersNormalizerRequestRaw: { Authorization: `Bearer ${TEST_TOKEN_RSA_STRING_PAYLOAD}` },
|
|
68
|
+
});
|
|
69
|
+
const result = await wrapped(input)({
|
|
70
|
+
logger,
|
|
71
|
+
issuer: 'test-iss',
|
|
72
|
+
rsaPublicKey: TEST_RSA_KEY_PUBLIC,
|
|
73
|
+
});
|
|
74
|
+
expect(result.isErr() && result.error.statusCode).toBe(401);
|
|
75
|
+
});
|
|
76
|
+
it('stringifies non-Error bearer extraction failures for RSA auth', async () => {
|
|
77
|
+
vi.spyOn(helpers, 'extractBearerToken').mockReturnValue(errR('boom'));
|
|
78
|
+
const { logger } = recordingLogger();
|
|
79
|
+
const wrapped = jwtAuthenticatorRsa()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
80
|
+
const result = await wrapped(makeRequestW(sampleRequestW, { headers: {}, headersNormalizerRequestRaw: {} }))({
|
|
81
|
+
logger,
|
|
82
|
+
issuer: 'test-iss',
|
|
83
|
+
rsaPublicKey: TEST_RSA_KEY_PUBLIC,
|
|
84
|
+
});
|
|
85
|
+
expect(result.isErr() && result.error.message).toContain('boom');
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
//# sourceMappingURL=jwtAuthenticatorRsa.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwtAuthenticatorRsa.test.js","sourceRoot":"","sources":["../../../src/http/contrib/jwtAuthenticatorRsa.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Handler } from '../../handler.js';
|
|
2
|
+
import type { WithLogger } from '../../lib/Logger.js';
|
|
3
|
+
import type { HttpApiError } from '../HttpApiError.js';
|
|
4
|
+
import type { Override, Rec } from '../RequestResponseHandler.js';
|
|
5
|
+
import { type RequestW } from '../RequestW.js';
|
|
6
|
+
import type { ResponseW } from '../ResponseW.js';
|
|
7
|
+
import type { WithNormalizedInputHeaders } from './headersNormalizer/types.js';
|
|
8
|
+
export declare const TAG = "jwtDecoder";
|
|
9
|
+
export type WithUserId = {
|
|
10
|
+
readonly userId: string | undefined;
|
|
11
|
+
};
|
|
12
|
+
export declare const middleware: () => <I extends Rec, O extends Rec, E, R>(wrapped: Handler<RequestW<Override<I & WithNormalizedInputHeaders, WithUserId>>, R, ResponseW<O>, E>) => Handler<RequestW<I & WithNormalizedInputHeaders>, R & WithLogger, ResponseW<O>, E | HttpApiError>;
|
|
13
|
+
//# sourceMappingURL=jwtDecoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwtDecoder.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/jwtDecoder.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE/E,eAAO,MAAM,GAAG,eAAe,CAAC;AAEhC,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,UAAU,SAEpB,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EACjC,SAAS,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,0BAA0B,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KACnG,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,0BAA0B,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,YAAY,CAsBlG,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { extractBearerToken } from '@konker.dev/neverthrow-r-auth-utils/helpers';
|
|
2
|
+
import { jwtDecodeToken } from '@konker.dev/neverthrow-r-auth-utils/jwt';
|
|
3
|
+
import { errAsync } from 'neverthrow';
|
|
4
|
+
import { toHttpApiError } from '../HttpApiError.js';
|
|
5
|
+
import { makeRequestW } from '../RequestW.js';
|
|
6
|
+
export const TAG = 'jwtDecoder';
|
|
7
|
+
export const middleware = () => (wrapped) => (i) => (r) => {
|
|
8
|
+
r.logger.debug(`[${TAG}] IN`);
|
|
9
|
+
const decoded = extractBearerToken(i.headers.authorization)(undefined)
|
|
10
|
+
.andThen((token) => jwtDecodeToken(token)(undefined))
|
|
11
|
+
.mapErr((e) => toHttpApiError(e, 401, `Invalid JWT credentials: ${e instanceof Error ? e.message : String(e)}`));
|
|
12
|
+
if (decoded.isErr()) {
|
|
13
|
+
r.logger.error(decoded.error);
|
|
14
|
+
return errAsync(decoded.error);
|
|
15
|
+
}
|
|
16
|
+
return wrapped(makeRequestW(i, {
|
|
17
|
+
userId: typeof decoded.value.sub === 'string' ? decoded.value.sub : undefined,
|
|
18
|
+
}))(r).map((res) => {
|
|
19
|
+
r.logger.debug(`[${TAG}] OUT`);
|
|
20
|
+
return res;
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=jwtDecoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwtDecoder.js","sourceRoot":"","sources":["../../../src/http/contrib/jwtDecoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKtC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAiB,MAAM,gBAAgB,CAAC;AAI7D,MAAM,CAAC,MAAM,GAAG,GAAG,YAAY,CAAC;AAMhC,MAAM,CAAC,MAAM,UAAU,GACrB,GAAG,EAAE,CACL,CACE,OAAoG,EACD,EAAE,CACvG,CAAC,CAAC,EAAE,EAAE,CACN,CAAC,CAAC,EAAE,EAAE;IACJ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IAE9B,MAAM,OAAO,GAAG,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC;SACnE,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC;SACpD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,4BAA4B,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEnH,IAAI,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QACpB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,OAAO,CACZ,YAAY,CAAC,CAAC,EAAE;QACd,MAAM,EAAE,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;KAC9E,CAAC,CACH,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACf,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;QAC/B,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwtDecoder.test.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/jwtDecoder.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { errR, okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
2
|
+
import * as helpers from '@konker.dev/neverthrow-r-auth-utils/helpers';
|
|
3
|
+
import { TEST_JWT_NOW_MS } from '@konker.dev/neverthrow-r-auth-utils/test/fixtures/jwt';
|
|
4
|
+
import { TEST_TOKEN, TEST_TOKEN_MISSING_SUBJECT, } from '@konker.dev/neverthrow-r-auth-utils/test/fixtures/test-jwt-tokens';
|
|
5
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
6
|
+
import { recordingLogger, sampleRequestW } from '../../test/test-common.js';
|
|
7
|
+
import { makeRequestW } from '../RequestW.js';
|
|
8
|
+
import { EMPTY_RESPONSE_W } from '../ResponseW.js';
|
|
9
|
+
import { middleware as jwtDecoder } from './jwtDecoder.js';
|
|
10
|
+
describe('jwtDecoder', () => {
|
|
11
|
+
const authorization = `Bearer ${TEST_TOKEN}`;
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
vi.restoreAllMocks();
|
|
14
|
+
});
|
|
15
|
+
it('extracts the userId from a valid JWT', async () => {
|
|
16
|
+
vi.spyOn(Date, 'now').mockReturnValue(TEST_JWT_NOW_MS);
|
|
17
|
+
const { logger } = recordingLogger();
|
|
18
|
+
const wrapped = jwtDecoder()((req) => okAsyncR({
|
|
19
|
+
...EMPTY_RESPONSE_W,
|
|
20
|
+
body: req.userId,
|
|
21
|
+
}));
|
|
22
|
+
const input = makeRequestW(sampleRequestW, {
|
|
23
|
+
headers: { authorization },
|
|
24
|
+
headersNormalizerRequestRaw: { Authorization: authorization },
|
|
25
|
+
});
|
|
26
|
+
const result = await wrapped(input)({ logger });
|
|
27
|
+
expect(result.isOk() && result.value.body).toBe('test-sub');
|
|
28
|
+
});
|
|
29
|
+
it('returns a 401 HttpApiError for an invalid JWT', async () => {
|
|
30
|
+
const { logger } = recordingLogger();
|
|
31
|
+
const wrapped = jwtDecoder()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
32
|
+
const input = makeRequestW(sampleRequestW, {
|
|
33
|
+
headers: { authorization: 'Bearer banana' },
|
|
34
|
+
headersNormalizerRequestRaw: { Authorization: 'Bearer banana' },
|
|
35
|
+
});
|
|
36
|
+
const result = await wrapped(input)({ logger });
|
|
37
|
+
expect(result.isErr() && result.error.statusCode).toBe(401);
|
|
38
|
+
});
|
|
39
|
+
it('returns a 401 HttpApiError when the auth header is missing', async () => {
|
|
40
|
+
const { logger } = recordingLogger();
|
|
41
|
+
const wrapped = jwtDecoder()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
42
|
+
const input = makeRequestW(sampleRequestW, {
|
|
43
|
+
headers: {},
|
|
44
|
+
headersNormalizerRequestRaw: {},
|
|
45
|
+
});
|
|
46
|
+
const result = await wrapped(input)({ logger });
|
|
47
|
+
expect(result.isErr() && result.error.statusCode).toBe(401);
|
|
48
|
+
});
|
|
49
|
+
it('returns userId undefined when the decoded token has no object sub', async () => {
|
|
50
|
+
vi.spyOn(Date, 'now').mockReturnValue(TEST_JWT_NOW_MS);
|
|
51
|
+
const { logger } = recordingLogger();
|
|
52
|
+
const wrapped = jwtDecoder()((req) => okAsyncR({
|
|
53
|
+
...EMPTY_RESPONSE_W,
|
|
54
|
+
body: req.userId,
|
|
55
|
+
}));
|
|
56
|
+
const input = makeRequestW(sampleRequestW, {
|
|
57
|
+
headers: { authorization: `Bearer ${TEST_TOKEN_MISSING_SUBJECT}` },
|
|
58
|
+
headersNormalizerRequestRaw: { Authorization: `Bearer ${TEST_TOKEN_MISSING_SUBJECT}` },
|
|
59
|
+
});
|
|
60
|
+
const result = await wrapped(input)({ logger });
|
|
61
|
+
expect(result.isOk()).toBe(true);
|
|
62
|
+
if (result.isOk()) {
|
|
63
|
+
expect(result.value.body).toBeUndefined();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
it('stringifies non-Error bearer extraction failures', async () => {
|
|
67
|
+
vi.spyOn(helpers, 'extractBearerToken').mockReturnValue(errR('boom'));
|
|
68
|
+
const { logger } = recordingLogger();
|
|
69
|
+
const wrapped = jwtDecoder()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
70
|
+
const result = await wrapped(makeRequestW(sampleRequestW, { headers: {}, headersNormalizerRequestRaw: {} }))({
|
|
71
|
+
logger,
|
|
72
|
+
});
|
|
73
|
+
expect(result.isErr() && result.error.message).toContain('boom');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=jwtDecoder.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwtDecoder.test.js","sourceRoot":"","sources":["../../../src/http/contrib/jwtDecoder.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
import type { WithLogger } from '../../lib/Logger.js';
|
|
3
|
+
import type { MiddlewareError } from '../../lib/MiddlewareError.js';
|
|
4
|
+
import type { Override, Rec, RequestResponseHandler } from '../RequestResponseHandler.js';
|
|
5
|
+
import { type RequestW } from '../RequestW.js';
|
|
6
|
+
export declare const TAG = "pathParametersValidator";
|
|
7
|
+
export type WithValidatedPathParameters<V> = {
|
|
8
|
+
readonly pathParameters: V;
|
|
9
|
+
readonly pathParametersValidatorRaw: RequestW['pathParameters'];
|
|
10
|
+
};
|
|
11
|
+
export declare const middleware: <V>(schema: StandardSchemaV1<unknown, V>) => <I extends Rec, O extends Rec, E, R>(wrapped: RequestResponseHandler<Override<I, WithValidatedPathParameters<V>>, R, O, E>) => RequestResponseHandler<I, R & WithLogger, O, E | MiddlewareError>;
|
|
12
|
+
//# sourceMappingURL=pathParametersValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathParametersValidator.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/pathParametersValidator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC1F,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG7D,eAAO,MAAM,GAAG,4BAA4B,CAAC;AAE7C,MAAM,MAAM,2BAA2B,CAAC,CAAC,IAAI;IAC3C,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC;IAC3B,QAAQ,CAAC,0BAA0B,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;CACjE,CAAC;AAKF,eAAO,MAAM,UAAU,GACpB,CAAC,EAAE,QAAQ,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,MACvC,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EACjC,SAAS,sBAAsB,CAAC,QAAQ,CAAC,CAAC,EAAE,2BAA2B,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KACpF,sBAAsB,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,CAAC,GAAG,eAAe,CAgBhE,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { andThenAsync, mapAsync, mapErrAsync } from '@konker.dev/neverthrow-r/async';
|
|
2
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
3
|
+
import { pipe } from '@konker.dev/neverthrow-r/pipe';
|
|
4
|
+
import { andThenParseAsyncR } from '@konker.dev/neverthrow-r-schema/async';
|
|
5
|
+
import { tapLogger } from '../../lib/Logger.js';
|
|
6
|
+
import { middlewareError } from '../../lib/MiddlewareError.js';
|
|
7
|
+
import { makeRequestW } from '../RequestW.js';
|
|
8
|
+
import { makeResponseW } from '../ResponseW.js';
|
|
9
|
+
export const TAG = 'pathParametersValidator';
|
|
10
|
+
const toMiddlewareError = (error) => middlewareError(error.message, error.cause === undefined ? error.issues : [error.cause, ...error.issues]);
|
|
11
|
+
export const middleware = (schema) => (wrapped) => (i) => pipe(okAsyncR(i.pathParameters), tapLogger('debug', `[${TAG}] IN`), andThenParseAsyncR(schema, { message: 'Path parameters validation failed' }), mapErrAsync(toMiddlewareError), mapAsync((validatedPathParameters) => makeRequestW(i, {
|
|
12
|
+
pathParameters: validatedPathParameters,
|
|
13
|
+
pathParametersValidatorRaw: i.pathParameters,
|
|
14
|
+
})), andThenAsync(wrapped), mapAsync((res) => makeResponseW(res)), tapLogger('debug', `[${TAG}] OUT`));
|
|
15
|
+
//# sourceMappingURL=pathParametersValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathParametersValidator.js","sourceRoot":"","sources":["../../../src/http/contrib/pathParametersValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AACrF,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAK3E,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,YAAY,EAAiB,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,CAAC,MAAM,GAAG,GAAG,yBAAyB,CAAC;AAO7C,MAAM,iBAAiB,GAAG,CAAC,KAA4B,EAAmB,EAAE,CAC1E,eAAe,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;AAE5G,MAAM,CAAC,MAAM,UAAU,GACrB,CAAI,MAAoC,EAAE,EAAE,CAC5C,CACE,OAAqF,EAClB,EAAE,CACvE,CAAC,CAAc,EAAE,EAAE,CACjB,IAAI,CACF,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,EAC1B,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC,EACjC,kBAAkB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC,EAC5E,WAAW,CAAC,iBAAiB,CAAC,EAC9B,QAAQ,CAAC,CAAC,uBAAuB,EAAE,EAAE,CACnC,YAAY,CAAC,CAAC,EAAE;IACd,cAAc,EAAE,uBAAuB;IACvC,0BAA0B,EAAE,CAAC,CAAC,cAAc;CAC7C,CAAC,CACH,EACD,YAAY,CAAC,OAAO,CAAC,EACrB,QAAQ,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,EACrC,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,CACnC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathParametersValidator.test.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/pathParametersValidator.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { recordingLogger, sampleRequestW } from '../../test/test-common.js';
|
|
5
|
+
import { makeRequestW } from '../RequestW.js';
|
|
6
|
+
import { EMPTY_RESPONSE_W } from '../ResponseW.js';
|
|
7
|
+
import { middleware as pathParametersValidator } from './pathParametersValidator.js';
|
|
8
|
+
describe('pathParametersValidator', () => {
|
|
9
|
+
const schema = z.object({
|
|
10
|
+
slug: z.literal('hello'),
|
|
11
|
+
page: z.coerce.number(),
|
|
12
|
+
});
|
|
13
|
+
it('validates and replaces path parameters', async () => {
|
|
14
|
+
const { logger } = recordingLogger();
|
|
15
|
+
const wrapped = pathParametersValidator(schema)((req) => okAsyncR({
|
|
16
|
+
...EMPTY_RESPONSE_W,
|
|
17
|
+
body: req.pathParameters,
|
|
18
|
+
}));
|
|
19
|
+
const input = makeRequestW(sampleRequestW, { pathParameters: { slug: 'hello', page: '2' } });
|
|
20
|
+
const result = await wrapped(input)({ logger });
|
|
21
|
+
expect(result.isOk() && result.value.body).toEqual({ slug: 'hello', page: 2 });
|
|
22
|
+
});
|
|
23
|
+
it('returns a MiddlewareError when path parameters fail validation', async () => {
|
|
24
|
+
const { logger } = recordingLogger();
|
|
25
|
+
const wrapped = pathParametersValidator(schema)(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
26
|
+
const input = makeRequestW(sampleRequestW, { pathParameters: { slug: 'nope', page: '2' } });
|
|
27
|
+
const result = await wrapped(input)({ logger });
|
|
28
|
+
expect(result.isErr() && result.error.message).toBe('Path parameters validation failed');
|
|
29
|
+
});
|
|
30
|
+
it('keeps a thrown validator cause in internal details', async () => {
|
|
31
|
+
const schema = {
|
|
32
|
+
'~standard': {
|
|
33
|
+
version: 1,
|
|
34
|
+
vendor: 'fixture',
|
|
35
|
+
validate: () => {
|
|
36
|
+
throw new Error('validator exploded');
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
const { logger } = recordingLogger();
|
|
41
|
+
const wrapped = pathParametersValidator(schema)(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
42
|
+
const result = await wrapped(makeRequestW(sampleRequestW, { pathParameters: { slug: 'x' } }))({ logger });
|
|
43
|
+
expect(result.isErr() && result.error.internal?.length).toBeGreaterThan(0);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=pathParametersValidator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathParametersValidator.test.js","sourceRoot":"","sources":["../../../src/http/contrib/pathParametersValidator.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Handler } from '../../handler.js';
|
|
2
|
+
import type { WithLogger } from '../../lib/Logger.js';
|
|
3
|
+
import { HttpApiError } from '../HttpApiError.js';
|
|
4
|
+
import type { Rec } from '../Rec.js';
|
|
5
|
+
import { type RequestW } from '../RequestW.js';
|
|
6
|
+
import type { ResponseW } from '../ResponseW.js';
|
|
7
|
+
export declare const TAG = "pathTokenAuthorizer";
|
|
8
|
+
export type PathTokenAuthorizerDeps = {
|
|
9
|
+
readonly secretTokenEnvName: string;
|
|
10
|
+
readonly pathParamName: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const middleware: () => <I extends Rec, O extends Rec, E, R>(wrapped: Handler<RequestW<I>, R, ResponseW<O>, E>) => Handler<RequestW<I>, R & WithLogger & PathTokenAuthorizerDeps, ResponseW<O>, E | HttpApiError>;
|
|
13
|
+
//# sourceMappingURL=pathTokenAuthorizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathTokenAuthorizer.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/pathTokenAuthorizer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,eAAO,MAAM,GAAG,wBAAwB,CAAC;AAEzC,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,UAAU,SAEpB,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EACjC,SAAS,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAChD,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,GAAG,uBAAuB,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,YAAY,CAiB/F,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { errAsync } from 'neverthrow';
|
|
2
|
+
import { HttpApiError } from '../HttpApiError.js';
|
|
3
|
+
import {} from '../RequestW.js';
|
|
4
|
+
export const TAG = 'pathTokenAuthorizer';
|
|
5
|
+
export const middleware = () => (wrapped) => (i) => (r) => {
|
|
6
|
+
r.logger.debug(`[${TAG}] IN`);
|
|
7
|
+
const secret = process.env[r.secretTokenEnvName];
|
|
8
|
+
const actual = i.pathParameters?.[r.pathParamName];
|
|
9
|
+
if (!secret || actual !== secret) {
|
|
10
|
+
const error = new HttpApiError({ statusCode: 401, message: 'Invalid token' });
|
|
11
|
+
r.logger.error(error);
|
|
12
|
+
return errAsync(error);
|
|
13
|
+
}
|
|
14
|
+
return wrapped(i)(r).map((res) => {
|
|
15
|
+
r.logger.debug(`[${TAG}] OUT`);
|
|
16
|
+
return res;
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=pathTokenAuthorizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathTokenAuthorizer.js","sourceRoot":"","sources":["../../../src/http/contrib/pathTokenAuthorizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAiB,MAAM,gBAAgB,CAAC;AAG/C,MAAM,CAAC,MAAM,GAAG,GAAG,qBAAqB,CAAC;AAOzC,MAAM,CAAC,MAAM,UAAU,GACrB,GAAG,EAAE,CACL,CACE,OAAiD,EAC+C,EAAE,CACpG,CAAC,CAAC,EAAE,EAAE,CACN,CAAC,CAAC,EAAE,EAAE;IACJ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IAE9B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IACnD,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC;QAC9E,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACtB,OAAO,QAAQ,CAA6B,KAAK,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAC/B,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;QAC/B,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathTokenAuthorizer.test.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/pathTokenAuthorizer.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { recordingLogger, sampleRequestW } from '../../test/test-common.js';
|
|
4
|
+
import { makeRequestW } from '../RequestW.js';
|
|
5
|
+
import { EMPTY_RESPONSE_W } from '../ResponseW.js';
|
|
6
|
+
import { middleware as pathTokenAuthorizer } from './pathTokenAuthorizer.js';
|
|
7
|
+
describe('pathTokenAuthorizer', () => {
|
|
8
|
+
it('authorizes when the path token matches the configured env var', async () => {
|
|
9
|
+
const oldEnv = process.env;
|
|
10
|
+
process.env = { ...oldEnv, TEST_SECRET_TOKEN: 'secret-token' };
|
|
11
|
+
const { logger } = recordingLogger();
|
|
12
|
+
const wrapped = pathTokenAuthorizer()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
13
|
+
const input = makeRequestW(sampleRequestW, { pathParameters: { token: 'secret-token' } });
|
|
14
|
+
const result = await wrapped(input)({ logger, pathParamName: 'token', secretTokenEnvName: 'TEST_SECRET_TOKEN' });
|
|
15
|
+
process.env = oldEnv;
|
|
16
|
+
expect(result.isOk()).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
it('returns a 401 HttpApiError when the token does not match', async () => {
|
|
19
|
+
const oldEnv = process.env;
|
|
20
|
+
process.env = { ...oldEnv, TEST_SECRET_TOKEN: 'secret-token' };
|
|
21
|
+
const { logger } = recordingLogger();
|
|
22
|
+
const wrapped = pathTokenAuthorizer()(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
23
|
+
const input = makeRequestW(sampleRequestW, { pathParameters: { token: 'bad-token' } });
|
|
24
|
+
const result = await wrapped(input)({ logger, pathParamName: 'token', secretTokenEnvName: 'TEST_SECRET_TOKEN' });
|
|
25
|
+
process.env = oldEnv;
|
|
26
|
+
expect(result.isErr() && result.error.statusCode).toBe(401);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=pathTokenAuthorizer.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathTokenAuthorizer.test.js","sourceRoot":"","sources":["../../../src/http/contrib/pathTokenAuthorizer.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAkB,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,UAAU,IAAI,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE7E,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;QAC3B,OAAO,CAAC,GAAG,GAAG,EAAE,GAAG,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC;QAC/D,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAY,gBAAgB,CAAC,CAAC,CAAC;QACnF,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,EAAE,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC;QAC1F,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACjH,OAAO,CAAC,GAAG,GAAG,MAAM,CAAC;QAErB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;QAC3B,OAAO,CAAC,GAAG,GAAG,EAAE,GAAG,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC;QAC/D,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAY,gBAAgB,CAAC,CAAC,CAAC;QACnF,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,EAAE,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;QACvF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACjH,OAAO,CAAC,GAAG,GAAG,MAAM,CAAC;QAErB,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
import type { WithLogger } from '../../lib/Logger.js';
|
|
3
|
+
import type { MiddlewareError } from '../../lib/MiddlewareError.js';
|
|
4
|
+
import type { Override, Rec, RequestResponseHandler } from '../RequestResponseHandler.js';
|
|
5
|
+
import { type RequestW } from '../RequestW.js';
|
|
6
|
+
export declare const TAG = "queryStringValidator";
|
|
7
|
+
export type WithValidatedQueryStringParameters<V> = {
|
|
8
|
+
readonly queryStringParameters: V;
|
|
9
|
+
readonly queryStringValidatorRaw: RequestW['queryStringParameters'];
|
|
10
|
+
};
|
|
11
|
+
export declare const middleware: <V>(schema: StandardSchemaV1<unknown, V>) => <I extends Rec, O extends Rec, E, R>(wrapped: RequestResponseHandler<Override<I, WithValidatedQueryStringParameters<V>>, R, O, E>) => RequestResponseHandler<I, R & WithLogger, O, E | MiddlewareError>;
|
|
12
|
+
//# sourceMappingURL=queryStringValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryStringValidator.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/queryStringValidator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC1F,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG7D,eAAO,MAAM,GAAG,yBAAyB,CAAC;AAE1C,MAAM,MAAM,kCAAkC,CAAC,CAAC,IAAI;IAClD,QAAQ,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAClC,QAAQ,CAAC,uBAAuB,EAAE,QAAQ,CAAC,uBAAuB,CAAC,CAAC;CACrE,CAAC;AAKF,eAAO,MAAM,UAAU,GACpB,CAAC,EAAE,QAAQ,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,MACvC,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EACjC,SAAS,sBAAsB,CAAC,QAAQ,CAAC,CAAC,EAAE,kCAAkC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAC3F,sBAAsB,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,CAAC,GAAG,eAAe,CAgBhE,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { andThenAsync, mapAsync, mapErrAsync } from '@konker.dev/neverthrow-r/async';
|
|
2
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
3
|
+
import { pipe } from '@konker.dev/neverthrow-r/pipe';
|
|
4
|
+
import { andThenParseAsyncR } from '@konker.dev/neverthrow-r-schema/async';
|
|
5
|
+
import { tapLogger } from '../../lib/Logger.js';
|
|
6
|
+
import { middlewareError } from '../../lib/MiddlewareError.js';
|
|
7
|
+
import { makeRequestW } from '../RequestW.js';
|
|
8
|
+
import { makeResponseW } from '../ResponseW.js';
|
|
9
|
+
export const TAG = 'queryStringValidator';
|
|
10
|
+
const toMiddlewareError = (error) => middlewareError(error.message, error.cause === undefined ? error.issues : [error.cause, ...error.issues]);
|
|
11
|
+
export const middleware = (schema) => (wrapped) => (i) => pipe(okAsyncR(i.queryStringParameters), tapLogger('debug', `[${TAG}] IN`), andThenParseAsyncR(schema, { message: 'Query string validation failed' }), mapErrAsync(toMiddlewareError), mapAsync((validatedQueryStringParameters) => makeRequestW(i, {
|
|
12
|
+
queryStringParameters: validatedQueryStringParameters,
|
|
13
|
+
queryStringValidatorRaw: i.queryStringParameters,
|
|
14
|
+
})), andThenAsync(wrapped), mapAsync((res) => makeResponseW(res)), tapLogger('debug', `[${TAG}] OUT`));
|
|
15
|
+
//# sourceMappingURL=queryStringValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryStringValidator.js","sourceRoot":"","sources":["../../../src/http/contrib/queryStringValidator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AACrF,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAK3E,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,YAAY,EAAiB,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,CAAC,MAAM,GAAG,GAAG,sBAAsB,CAAC;AAO1C,MAAM,iBAAiB,GAAG,CAAC,KAA4B,EAAmB,EAAE,CAC1E,eAAe,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;AAE5G,MAAM,CAAC,MAAM,UAAU,GACrB,CAAI,MAAoC,EAAE,EAAE,CAC5C,CACE,OAA4F,EACzB,EAAE,CACvE,CAAC,CAAc,EAAE,EAAE,CACjB,IAAI,CACF,QAAQ,CAAC,CAAC,CAAC,qBAAqB,CAAC,EACjC,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC,EACjC,kBAAkB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,gCAAgC,EAAE,CAAC,EACzE,WAAW,CAAC,iBAAiB,CAAC,EAC9B,QAAQ,CAAC,CAAC,8BAA8B,EAAE,EAAE,CAC1C,YAAY,CAAC,CAAC,EAAE;IACd,qBAAqB,EAAE,8BAA8B;IACrD,uBAAuB,EAAE,CAAC,CAAC,qBAAqB;CACjD,CAAC,CACH,EACD,YAAY,CAAC,OAAO,CAAC,EACrB,QAAQ,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,EACrC,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,CACnC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryStringValidator.test.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/queryStringValidator.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { recordingLogger, sampleRequestW } from '../../test/test-common.js';
|
|
5
|
+
import { makeRequestW } from '../RequestW.js';
|
|
6
|
+
import { EMPTY_RESPONSE_W } from '../ResponseW.js';
|
|
7
|
+
import { middleware as queryStringValidator } from './queryStringValidator.js';
|
|
8
|
+
describe('queryStringValidator', () => {
|
|
9
|
+
const schema = z.object({
|
|
10
|
+
foo: z.literal('bar'),
|
|
11
|
+
page: z.coerce.number(),
|
|
12
|
+
});
|
|
13
|
+
it('validates and replaces query string parameters', async () => {
|
|
14
|
+
const { logger } = recordingLogger();
|
|
15
|
+
const wrapped = queryStringValidator(schema)((req) => okAsyncR({
|
|
16
|
+
...EMPTY_RESPONSE_W,
|
|
17
|
+
body: req.queryStringParameters,
|
|
18
|
+
}));
|
|
19
|
+
const input = makeRequestW(sampleRequestW, { queryStringParameters: { foo: 'bar', page: '3' } });
|
|
20
|
+
const result = await wrapped(input)({ logger });
|
|
21
|
+
expect(result.isOk() && result.value.body).toEqual({ foo: 'bar', page: 3 });
|
|
22
|
+
});
|
|
23
|
+
it('returns a MiddlewareError when query string validation fails', async () => {
|
|
24
|
+
const { logger } = recordingLogger();
|
|
25
|
+
const wrapped = queryStringValidator(schema)(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
26
|
+
const input = makeRequestW(sampleRequestW, { queryStringParameters: { foo: 'nope', page: '3' } });
|
|
27
|
+
const result = await wrapped(input)({ logger });
|
|
28
|
+
expect(result.isErr() && result.error.message).toBe('Query string validation failed');
|
|
29
|
+
});
|
|
30
|
+
it('keeps a thrown validator cause in internal details', async () => {
|
|
31
|
+
const schema = {
|
|
32
|
+
'~standard': {
|
|
33
|
+
version: 1,
|
|
34
|
+
vendor: 'fixture',
|
|
35
|
+
validate: () => {
|
|
36
|
+
throw new Error('validator exploded');
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
const { logger } = recordingLogger();
|
|
41
|
+
const wrapped = queryStringValidator(schema)(() => okAsyncR(EMPTY_RESPONSE_W));
|
|
42
|
+
const result = await wrapped(makeRequestW(sampleRequestW, { queryStringParameters: { foo: 'x' } }))({ logger });
|
|
43
|
+
expect(result.isErr() && result.error.internal?.length).toBeGreaterThan(0);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=queryStringValidator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryStringValidator.test.js","sourceRoot":"","sources":["../../../src/http/contrib/queryStringValidator.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AAEjE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAkB,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAE/E,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QACtB,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;QACrB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE;KACxB,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CACnD,QAAQ,CAAY;YAClB,GAAG,gBAAgB;YACnB,IAAI,EAAE,GAAG,CAAC,qBAAqB;SACnB,CAAC,CAChB,CAAC;QACF,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,EAAE,EAAE,qBAAqB,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACjG,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAEhD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAY,gBAAgB,CAAC,CAAC,CAAC;QAC1F,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,EAAE,EAAE,qBAAqB,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QAClG,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAEhD,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,MAAM,GAAsC;YAChD,WAAW,EAAE;gBACX,OAAO,EAAE,CAAC;gBACV,MAAM,EAAE,SAAS;gBACjB,QAAQ,EAAE,GAAG,EAAE;oBACb,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;gBACxC,CAAC;aACF;SACF,CAAC;QACF,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAY,gBAAgB,CAAC,CAAC,CAAC;QAC1F,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,cAAc,EAAE,EAAE,qBAAqB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAEhH,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { WithLogger } from '../../lib/Logger.js';
|
|
2
|
+
import type { Rec, RequestResponseHandler } from '../RequestResponseHandler.js';
|
|
3
|
+
export declare const TAG = "requestResponseLogger";
|
|
4
|
+
export declare const middleware: () => <I extends Rec, O extends Rec, E, R>(wrapped: RequestResponseHandler<I, R, O, E>) => RequestResponseHandler<I, R & WithLogger, O, E>;
|
|
5
|
+
//# sourceMappingURL=requestResponseLogger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestResponseLogger.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/requestResponseLogger.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,GAAG,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAGhF,eAAO,MAAM,GAAG,0BAA0B,CAAC;AAE3C,eAAO,MAAM,UAAU,SAEpB,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,CAAC,EACjC,SAAS,sBAAsB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAC1C,sBAAsB,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,CAAC,CAS9C,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { andThenAsync } from '@konker.dev/neverthrow-r/async';
|
|
2
|
+
import { okAsyncR } from '@konker.dev/neverthrow-r/constructors';
|
|
3
|
+
import { pipe } from '@konker.dev/neverthrow-r/pipe';
|
|
4
|
+
import { tapLogger, tapLoggerWith } from '../../lib/Logger.js';
|
|
5
|
+
import {} from '../RequestW.js';
|
|
6
|
+
export const TAG = 'requestResponseLogger';
|
|
7
|
+
export const middleware = () => (wrapped) => (i) => pipe(okAsyncR(i), tapLogger('debug', `[${TAG}] IN`), tapLoggerWith('info', (req) => [`[${TAG}] REQUEST`, req]), andThenAsync(wrapped), tapLoggerWith('info', (res) => [`[${TAG}] RESPONSE`, res]), tapLogger('debug', `[${TAG}] OUT`));
|
|
8
|
+
//# sourceMappingURL=requestResponseLogger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestResponseLogger.js","sourceRoot":"","sources":["../../../src/http/contrib/requestResponseLogger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAC;AAGrD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,EAAiB,MAAM,gBAAgB,CAAC;AAE/C,MAAM,CAAC,MAAM,GAAG,GAAG,uBAAuB,CAAC;AAE3C,MAAM,CAAC,MAAM,UAAU,GACrB,GAAG,EAAE,CACL,CACE,OAA2C,EACM,EAAE,CACrD,CAAC,CAAc,EAAE,EAAE,CACjB,IAAI,CACF,QAAQ,CAAC,CAAC,CAAC,EACX,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC,EACjC,aAAa,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,WAAW,EAAE,GAAG,CAAC,CAAC,EACzD,YAAY,CAAC,OAAO,CAAC,EACrB,aAAa,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,YAAY,EAAE,GAAG,CAAC,CAAC,EAC1D,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,CACnC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestResponseLogger.test.d.ts","sourceRoot":"","sources":["../../../src/http/contrib/requestResponseLogger.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { echoHandler, recordingLogger, sampleRequestW } from '../../test/test-common.js';
|
|
3
|
+
import { middleware as requestResponseLogger, TAG } from './requestResponseLogger.js';
|
|
4
|
+
describe('requestResponseLogger', () => {
|
|
5
|
+
it('emits IN/REQUEST/RESPONSE/OUT in order', async () => {
|
|
6
|
+
const { calls, logger } = recordingLogger();
|
|
7
|
+
const wrapped = requestResponseLogger()(echoHandler());
|
|
8
|
+
const result = await wrapped(sampleRequestW)({ logger });
|
|
9
|
+
expect(result.isOk() && result.value.statusCode).toBe(200);
|
|
10
|
+
expect(calls.map((c) => ({ level: c.level, label: c.args[0] }))).toEqual([
|
|
11
|
+
{ level: 'debug', label: `[${TAG}] IN` },
|
|
12
|
+
{ level: 'info', label: `[${TAG}] REQUEST` },
|
|
13
|
+
{ level: 'info', label: `[${TAG}] RESPONSE` },
|
|
14
|
+
{ level: 'debug', label: `[${TAG}] OUT` },
|
|
15
|
+
]);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=requestResponseLogger.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestResponseLogger.test.js","sourceRoot":"","sources":["../../../src/http/contrib/requestResponseLogger.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACzF,OAAO,EAAE,UAAU,IAAI,qBAAqB,EAAE,GAAG,EAAE,MAAM,4BAA4B,CAAC;AAEtF,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAEzD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3D,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YACvE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,MAAM,EAAE;YACxC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,GAAG,WAAW,EAAE;YAC5C,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,GAAG,YAAY,EAAE;YAC7C,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO,EAAE;SAC1C,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|