@effect-app/infra 1.18.2 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/_cjs/api/Middlewares.cjs +59 -0
- package/_cjs/api/Middlewares.cjs.map +1 -0
- package/_cjs/api/internal/middlewares.cjs +196 -0
- package/_cjs/api/internal/middlewares.cjs.map +1 -0
- package/_cjs/{test.arbs.cjs → test/arbs.cjs} +1 -1
- package/_cjs/test/arbs.cjs.map +1 -0
- package/_cjs/test.cjs +6 -6
- package/_cjs/test.cjs.map +1 -1
- package/dist/api/Middlewares.d.ts +81 -0
- package/dist/api/Middlewares.d.ts.map +1 -0
- package/dist/api/Middlewares.js +51 -0
- package/dist/api/internal/middlewares.d.ts +16 -0
- package/dist/api/internal/middlewares.d.ts.map +1 -0
- package/dist/api/internal/middlewares.js +168 -0
- package/dist/{test.arbs.d.ts → test/arbs.d.ts} +1 -1
- package/dist/test/arbs.d.ts.map +1 -0
- package/dist/test/arbs.js +21 -0
- package/dist/test.d.ts +1 -1
- package/dist/test.js +2 -2
- package/package.json +39 -9
- package/src/api/internal/middlewares.ts +286 -0
- package/src/api/middlewares.ts +102 -0
- package/src/test.ts +2 -2
- package/vitest.config.ts.timestamp-1711656440838-19c636fe320df.mjs +0 -0
- package/vitest.config.ts.timestamp-1711724061890-6ecedb0a07fdd.mjs +0 -0
- package/vitest.config.ts.timestamp-1711743489537-da8d9e5f66c9f.mjs +0 -0
- package/vitest.config.ts.timestamp-1711744615239-dcf257a844e01.mjs +37 -0
- package/_cjs/test.arbs.cjs.map +0 -1
- package/dist/test.arbs.d.ts.map +0 -1
- package/dist/test.arbs.js +0 -21
- /package/src/{test.arbs.ts → test/arbs.ts} +0 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mechanism for extendning behaviour of all handlers on the server.
|
|
3
|
+
*
|
|
4
|
+
* @since 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
import * as crypto from "crypto";
|
|
7
|
+
import { dropUndefined } from "@effect-app/core/utils";
|
|
8
|
+
import { NotLoggedInError } from "@effect-app/infra/errors";
|
|
9
|
+
import * as Middleware from "@effect/platform/HttpMiddleware";
|
|
10
|
+
import * as HttpServerRequest from "@effect/platform/HttpServerRequest";
|
|
11
|
+
import * as ServerResponse from "@effect/platform/HttpServerResponse";
|
|
12
|
+
import { Effect } from "effect-app";
|
|
13
|
+
import { HttpBody, HttpHeaders, HttpServerResponse } from "effect-app/http";
|
|
14
|
+
import * as Either from "effect/Either";
|
|
15
|
+
import * as FiberRef from "effect/FiberRef";
|
|
16
|
+
import { pipe } from "effect/Function";
|
|
17
|
+
import * as HashMap from "effect/HashMap";
|
|
18
|
+
import * as Metric from "effect/Metric";
|
|
19
|
+
export const accessLog = (level = "Info") => Middleware.make((app) => pipe(HttpServerRequest.HttpServerRequest, Effect.flatMap((request) => Effect[`log${level}`](`${request.method} ${request.url}`)), Effect.flatMap(() => app)));
|
|
20
|
+
export const uuidLogAnnotation = (logAnnotationKey = "requestId") => Middleware.make((app) => pipe(Effect.sync(() => crypto.randomUUID()), Effect.flatMap((uuid) => FiberRef.update(FiberRef.currentLogAnnotations, HashMap.set(logAnnotationKey, uuid))), Effect.flatMap(() => app)));
|
|
21
|
+
export const endpointCallsMetric = () => {
|
|
22
|
+
const endpointCalledCounter = Metric.counter("server.endpoint_calls");
|
|
23
|
+
return Middleware.make((app) => Effect.gen(function* (_) {
|
|
24
|
+
const request = yield* _(HttpServerRequest.HttpServerRequest);
|
|
25
|
+
yield* _(Metric.increment(endpointCalledCounter), Effect.tagMetrics("path", request.url));
|
|
26
|
+
return yield* _(app);
|
|
27
|
+
}));
|
|
28
|
+
};
|
|
29
|
+
export const errorLog = Middleware.make((app) => Effect.gen(function* (_) {
|
|
30
|
+
const request = yield* _(HttpServerRequest.HttpServerRequest);
|
|
31
|
+
const response = yield* _(app);
|
|
32
|
+
if (response.status >= 400 && response.status < 500) {
|
|
33
|
+
yield* _(Effect.logWarning(`${request.method.toUpperCase()} ${request.url} client error ${response.status}`));
|
|
34
|
+
}
|
|
35
|
+
else if (response.status >= 500) {
|
|
36
|
+
yield* _(Effect.logError(`${request.method.toUpperCase()} ${request.url} server error ${response.status}`));
|
|
37
|
+
}
|
|
38
|
+
return response;
|
|
39
|
+
}));
|
|
40
|
+
export const toServerResponse = (err) => HttpServerResponse.empty().pipe(HttpServerResponse.setStatus(401), HttpServerResponse.setBody(HttpBody.unsafeJson({ message: err.message })));
|
|
41
|
+
export const basicAuth = (checkCredentials, options) => Middleware.make((app) => Effect.gen(function* (_) {
|
|
42
|
+
const headerName = options?.headerName ?? "Authorization";
|
|
43
|
+
const skippedPaths = options?.skipPaths ?? [];
|
|
44
|
+
const request = yield* _(HttpServerRequest.HttpServerRequest);
|
|
45
|
+
if (skippedPaths.includes(request.url)) {
|
|
46
|
+
return yield* _(app);
|
|
47
|
+
}
|
|
48
|
+
const authHeader = request.headers[headerName.toLowerCase()];
|
|
49
|
+
if (authHeader === undefined) {
|
|
50
|
+
return toServerResponse(new NotLoggedInError(`Expected header ${headerName}`));
|
|
51
|
+
}
|
|
52
|
+
const authorizationParts = authHeader.split(" ");
|
|
53
|
+
if (authorizationParts.length !== 2) {
|
|
54
|
+
return toServerResponse(new NotLoggedInError("Incorrect auhorization scheme. Expected \"Basic <credentials>\""));
|
|
55
|
+
}
|
|
56
|
+
if (authorizationParts[0] !== "Basic") {
|
|
57
|
+
return toServerResponse(new NotLoggedInError(`Incorrect auhorization type. Expected "Basic", got "${authorizationParts[0]}"`));
|
|
58
|
+
}
|
|
59
|
+
const credentialsBuffer = Buffer.from(authorizationParts[1], "base64");
|
|
60
|
+
const credentialsText = credentialsBuffer.toString("utf-8");
|
|
61
|
+
const credentialsParts = credentialsText.split(":");
|
|
62
|
+
if (credentialsParts.length !== 2) {
|
|
63
|
+
return toServerResponse(new NotLoggedInError("Incorrect basic auth credentials format. Expected base64 encoded \"<user>:<pass>\"."));
|
|
64
|
+
}
|
|
65
|
+
const check = yield* _(checkCredentials({
|
|
66
|
+
user: credentialsParts[0],
|
|
67
|
+
password: credentialsParts[1]
|
|
68
|
+
}), Effect.either);
|
|
69
|
+
if (Either.isLeft(check)) {
|
|
70
|
+
return toServerResponse(check.left);
|
|
71
|
+
}
|
|
72
|
+
return yield* _(app);
|
|
73
|
+
}));
|
|
74
|
+
export const cors = (_options) => {
|
|
75
|
+
const DEFAULTS = {
|
|
76
|
+
allowedOrigins: ["*"],
|
|
77
|
+
allowedMethods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"],
|
|
78
|
+
allowedHeaders: [],
|
|
79
|
+
exposedHeaders: [],
|
|
80
|
+
credentials: false
|
|
81
|
+
};
|
|
82
|
+
const options = { ...DEFAULTS, ..._options };
|
|
83
|
+
const isAllowedOrigin = (origin) => {
|
|
84
|
+
return options.allowedOrigins.includes(origin);
|
|
85
|
+
};
|
|
86
|
+
const allowOrigin = (originHeader) => {
|
|
87
|
+
if (options.allowedOrigins.length === 0) {
|
|
88
|
+
return { "Access-Control-Allow-Origin": "*" };
|
|
89
|
+
}
|
|
90
|
+
if (options.allowedOrigins.length === 1) {
|
|
91
|
+
return {
|
|
92
|
+
"Access-Control-Allow-Origin": options.allowedOrigins[0],
|
|
93
|
+
Vary: "Origin"
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (isAllowedOrigin(originHeader)) {
|
|
97
|
+
return {
|
|
98
|
+
"Access-Control-Allow-Origin": originHeader,
|
|
99
|
+
Vary: "Origin"
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return undefined;
|
|
103
|
+
};
|
|
104
|
+
const allowMethods = (() => {
|
|
105
|
+
if (options.allowedMethods.length > 0) {
|
|
106
|
+
return {
|
|
107
|
+
"Access-Control-Allow-Methods": options.allowedMethods.join(", ")
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
})();
|
|
112
|
+
const allowCredentials = (() => {
|
|
113
|
+
if (options.credentials) {
|
|
114
|
+
return { "Access-Control-Allow-Credentials": "true" };
|
|
115
|
+
}
|
|
116
|
+
return undefined;
|
|
117
|
+
})();
|
|
118
|
+
const allowHeaders = (accessControlRequestHeaders) => {
|
|
119
|
+
if (options.allowedHeaders.length === 0 && accessControlRequestHeaders) {
|
|
120
|
+
return {
|
|
121
|
+
Vary: "Access-Control-Request-Headers",
|
|
122
|
+
"Access-Control-Allow-Headers": accessControlRequestHeaders
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (options.allowedHeaders) {
|
|
126
|
+
return {
|
|
127
|
+
"Access-Control-Allow-Headers": options.allowedHeaders.join(",")
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return undefined;
|
|
131
|
+
};
|
|
132
|
+
const exposeHeaders = (() => {
|
|
133
|
+
if (options.exposedHeaders.length > 0) {
|
|
134
|
+
return {
|
|
135
|
+
"Access-Control-Expose-Headers": options.exposedHeaders.join(",")
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
})();
|
|
140
|
+
const maxAge = (() => {
|
|
141
|
+
if (options.maxAge) {
|
|
142
|
+
return { "Access-Control-Max-Age": options.maxAge.toString() };
|
|
143
|
+
}
|
|
144
|
+
return undefined;
|
|
145
|
+
})();
|
|
146
|
+
return Middleware.make((app) => Effect.gen(function* (_) {
|
|
147
|
+
const request = yield* _(HttpServerRequest.HttpServerRequest);
|
|
148
|
+
const origin = request.headers["origin"];
|
|
149
|
+
const accessControlRequestHeaders = request.headers["access-control-request-headers"];
|
|
150
|
+
let corsHeaders = {
|
|
151
|
+
...allowOrigin(origin ?? ""),
|
|
152
|
+
...allowCredentials,
|
|
153
|
+
...exposeHeaders
|
|
154
|
+
};
|
|
155
|
+
if (request.method === "OPTIONS") {
|
|
156
|
+
corsHeaders = {
|
|
157
|
+
...corsHeaders,
|
|
158
|
+
...allowMethods,
|
|
159
|
+
...allowHeaders(accessControlRequestHeaders),
|
|
160
|
+
...maxAge
|
|
161
|
+
};
|
|
162
|
+
return ServerResponse.empty({ status: 204, headers: HttpHeaders.fromInput(dropUndefined(corsHeaders)) });
|
|
163
|
+
}
|
|
164
|
+
const response = yield* _(app);
|
|
165
|
+
return response.pipe(ServerResponse.setHeaders(dropUndefined(corsHeaders)));
|
|
166
|
+
}));
|
|
167
|
+
};
|
|
168
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL2ludGVybmFsL21pZGRsZXdhcmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFDSCxPQUFPLEtBQUssTUFBTSxNQUFNLFFBQVEsQ0FBQTtBQUVoQyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUE7QUFDdEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMEJBQTBCLENBQUE7QUFDM0QsT0FBTyxLQUFLLFVBQVUsTUFBTSxpQ0FBaUMsQ0FBQTtBQUM3RCxPQUFPLEtBQUssaUJBQWlCLE1BQU0sb0NBQW9DLENBQUE7QUFDdkUsT0FBTyxLQUFLLGNBQWMsTUFBTSxxQ0FBcUMsQ0FBQTtBQUNyRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFBO0FBQ25DLE9BQU8sRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLGtCQUFrQixFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDM0UsT0FBTyxLQUFLLE1BQU0sTUFBTSxlQUFlLENBQUE7QUFDdkMsT0FBTyxLQUFLLFFBQVEsTUFBTSxpQkFBaUIsQ0FBQTtBQUMzQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDdEMsT0FBTyxLQUFLLE9BQU8sTUFBTSxnQkFBZ0IsQ0FBQTtBQUN6QyxPQUFPLEtBQUssTUFBTSxNQUFNLGVBQWUsQ0FBQTtBQUd2QyxNQUFNLENBQUMsTUFBTSxTQUFTLEdBQUcsQ0FBQyxRQUFzQyxNQUFNLEVBQUUsRUFBRSxDQUN4RSxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FDdEIsSUFBSSxDQUNGLGlCQUFpQixDQUFDLGlCQUFpQixFQUNuQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxLQUFLLEVBQUUsQ0FBQyxD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
|
|
@@ -8,4 +8,4 @@ export declare function generate<T>(arb: FastCheck.Arbitrary<T>): FastCheck.Valu
|
|
|
8
8
|
* @tsplus getter effect/schema/Arbitrary generate
|
|
9
9
|
*/
|
|
10
10
|
export declare function generateFromArbitrary<T>(arb: A.LazyArbitrary<T>): FastCheck.Value<T>;
|
|
11
|
-
//# sourceMappingURL=
|
|
11
|
+
//# sourceMappingURL=arbs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arbs.d.ts","sourceRoot":"","sources":["../../src/test/arbs.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAG1C,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,mBAAmB,CAAA;AAQ1C;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,sBAEtD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,sBAE/D"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Do not import to frontend
|
|
2
|
+
import { FastCheck } from "@effect/schema";
|
|
3
|
+
import { faker } from "@faker-js/faker";
|
|
4
|
+
import { setFaker } from "effect-app/faker";
|
|
5
|
+
import { Random } from "fast-check";
|
|
6
|
+
import * as rand from "pure-rand";
|
|
7
|
+
const rnd = new Random(rand.congruential32(5));
|
|
8
|
+
setFaker(faker);
|
|
9
|
+
/**
|
|
10
|
+
* @tsplus getter FastCheck generateRandom
|
|
11
|
+
*/
|
|
12
|
+
export function generate(arb) {
|
|
13
|
+
return arb.generate(rnd, undefined);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* @tsplus getter effect/schema/Arbitrary generate
|
|
17
|
+
*/
|
|
18
|
+
export function generateFromArbitrary(arb) {
|
|
19
|
+
return generate(arb(FastCheck));
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJicy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0L2FyYnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsNEJBQTRCO0FBRTVCLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQUMxQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDdkMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGtCQUFrQixDQUFBO0FBRTNDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDbkMsT0FBTyxLQUFLLElBQUksTUFBTSxXQUFXLENBQUE7QUFFakMsTUFBTSxHQUFHLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBO0FBRTlDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUVmOztHQUVHO0FBQ0gsTUFBTSxVQUFVLFFBQVEsQ0FBSSxHQUEyQjtJQUNyRCxPQUFPLEdBQUcsQ0FBQyxRQUFRLENBQUMsR0FBRyxFQUFFLFNBQVMsQ0FBQyxDQUFBO0FBQ3JDLENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sVUFBVSxxQkFBcUIsQ0FBSSxHQUF1QjtJQUM5RCxPQUFPLFFBQVEsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQTtBQUNqQyxDQUFDIn0=
|
package/dist/test.d.ts
CHANGED
|
@@ -11,5 +11,5 @@ export declare const createRandomInstance: <A extends object, I, R>(s: S.Schema<
|
|
|
11
11
|
export declare const createRandomInstanceI: <A extends object, I>(s: S.Schema<A, I, never> & {
|
|
12
12
|
fields: S.Struct.Fields;
|
|
13
13
|
}) => (overrides?: Partial<I>) => A;
|
|
14
|
-
export * from "./test
|
|
14
|
+
export * from "./test/arbs.js";
|
|
15
15
|
//# sourceMappingURL=test.d.ts.map
|
package/dist/test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Arbitrary } from "@effect/schema";
|
|
2
2
|
import { Predicate, S } from "effect-app";
|
|
3
3
|
import { copy } from "effect-app/utils";
|
|
4
|
-
import { generate } from "./test
|
|
4
|
+
import { generate } from "./test/arbs.js";
|
|
5
5
|
const isPropertySignature = (u) => Predicate.hasProperty(u, S.PropertySignatureTypeId);
|
|
6
6
|
const defaults = (fields) => {
|
|
7
7
|
const keys = Object.keys(fields);
|
|
@@ -43,5 +43,5 @@ export const createRandomInstanceI = (s) => {
|
|
|
43
43
|
return decode({ ...encode(v), ...overrides });
|
|
44
44
|
};
|
|
45
45
|
};
|
|
46
|
-
export * from "./test
|
|
46
|
+
export * from "./test/arbs.js";
|
|
47
47
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy90ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQUUxQyxPQUFPLEVBQUUsU0FBUyxFQUFFLENBQUMsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUN6QyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDdkMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBRXpDLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxDQUFVLEVBQThCLEVBQUUsQ0FDckUsU0FBUyxDQUFDLFdBQVcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLHVCQUF1QixDQUFDLENBQUE7QUFFckQsTUFBTSxRQUFRLEdBQUcsQ0FBQyxNQUF1QixFQUFFLEVBQUU7SUFDM0MsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQTtJQUNoQyw4REFBOEQ7SUFDOUQsTUFBTSxHQUFHLEdBQXdCLEVBQUUsQ0FBQTtJQUNuQyxLQUFLLE1BQU0sR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQ3ZCLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUN6QixJQUFJLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDL0IsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQTtZQUNyQixNQUFNLFlBQVksR0FBRyxHQUFHLENBQUMsSUFBSSxLQUFLLDhCQUE4QixDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQTtZQUN6RyxJQUFJLFlBQVksS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDL0IsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFlBQVksRUFBRSxDQUFBO1lBQzNCLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sR0FBRyxDQUFBO0FBQ1osQ0FBQyxDQUFBO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxDQUF5QixDQUFrRCxFQUFFLEVBQUU7SUFDakgsTUFBTSxHQUFHLEdBQUcsUUFBUSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUN2QyxPQUFPLENBQUMsU0FBc0IsRUFBRSxFQUFFO1FBQ2hDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsR0FBRyxHQUFHLENBQUMsS0FBSyxFQUFFLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFBO1FBQ2pELE9BQU8sU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDM0MsQ0FBQyxDQUFBO0FBQ0gsQ0FBQyxDQUFBO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxxQkFBcUIsR0FBRyxDQUFzQixDQUFzRCxFQUFFLEVBQUU7SUFDbkgsTUFBTSxHQUFHLEdBQUcsUUFBUSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUN2QyxNQUFNLE1BQU0sR0FBRyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQzlCLE1BQU0sTUFBTSxHQUFHLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDOUIsT0FBTyxDQUFDLFNBQXNCLEVBQUUsRUFBRTtRQUNoQyxNQUFNLENBQUMsR0FBRyxFQUFFLEdBQUcsR0FBRyxDQUFDLEtBQUssRUFBRSxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQTtRQUNqRCxJQUFJLENBQUMsU0FBUztZQUFFLE9BQU8sQ0FBQyxDQUFBO1FBQ3hCLE9BQU8sTUFBTSxDQUFDLEVBQUUsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxTQUFTLEVBQUUsQ0FBQyxDQUFBO0lBQy9DLENBQUMsQ0FBQTtBQUNILENBQUMsQ0FBQTtBQUVELGNBQWMsZ0JBQWdCLENBQUEifQ==
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-app/infra",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.19.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"pure-rand": "6.1.0",
|
|
20
20
|
"redlock": "^4.2.0",
|
|
21
21
|
"@effect-app/core": "1.10.1",
|
|
22
|
-
"@effect-app/infra-adapters": "1.11.
|
|
23
|
-
"effect-app": "1.
|
|
24
|
-
"
|
|
22
|
+
"@effect-app/infra-adapters": "1.11.3",
|
|
23
|
+
"@effect-app/schema": "1.12.1",
|
|
24
|
+
"effect-app": "1.17.1"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@babel/cli": "^7.25.6",
|
|
@@ -95,6 +95,16 @@
|
|
|
95
95
|
"default": "./_cjs/api/codec.cjs"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
|
+
"./api/middlewares": {
|
|
99
|
+
"import": {
|
|
100
|
+
"types": "./dist/api/middlewares.d.ts",
|
|
101
|
+
"default": "./dist/api/middlewares.js"
|
|
102
|
+
},
|
|
103
|
+
"require": {
|
|
104
|
+
"types": "./dist/api/middlewares.d.ts",
|
|
105
|
+
"default": "./_cjs/api/middlewares.cjs"
|
|
106
|
+
}
|
|
107
|
+
},
|
|
98
108
|
"./api/reportError": {
|
|
99
109
|
"import": {
|
|
100
110
|
"types": "./dist/api/reportError.d.ts",
|
|
@@ -645,14 +655,34 @@
|
|
|
645
655
|
"default": "./_cjs/services/query/new-kid-interpreter.cjs"
|
|
646
656
|
}
|
|
647
657
|
},
|
|
648
|
-
"./test
|
|
658
|
+
"./test": {
|
|
659
|
+
"import": {
|
|
660
|
+
"types": "./dist/test.d.ts",
|
|
661
|
+
"default": "./dist/test.js"
|
|
662
|
+
},
|
|
663
|
+
"require": {
|
|
664
|
+
"types": "./dist/test.d.ts",
|
|
665
|
+
"default": "./_cjs/test.cjs"
|
|
666
|
+
}
|
|
667
|
+
},
|
|
668
|
+
"./test/arbs": {
|
|
669
|
+
"import": {
|
|
670
|
+
"types": "./dist/test/arbs.d.ts",
|
|
671
|
+
"default": "./dist/test/arbs.js"
|
|
672
|
+
},
|
|
673
|
+
"require": {
|
|
674
|
+
"types": "./dist/test/arbs.d.ts",
|
|
675
|
+
"default": "./_cjs/test/arbs.cjs"
|
|
676
|
+
}
|
|
677
|
+
},
|
|
678
|
+
"./vitest": {
|
|
649
679
|
"import": {
|
|
650
|
-
"types": "./dist/
|
|
651
|
-
"default": "./dist/
|
|
680
|
+
"types": "./dist/vitest.d.ts",
|
|
681
|
+
"default": "./dist/vitest.js"
|
|
652
682
|
},
|
|
653
683
|
"require": {
|
|
654
|
-
"types": "./dist/
|
|
655
|
-
"default": "./_cjs/
|
|
684
|
+
"types": "./dist/vitest.d.ts",
|
|
685
|
+
"default": "./_cjs/vitest.cjs"
|
|
656
686
|
}
|
|
657
687
|
}
|
|
658
688
|
},
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mechanism for extendning behaviour of all handlers on the server.
|
|
3
|
+
*
|
|
4
|
+
* @since 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
import * as crypto from "crypto"
|
|
7
|
+
|
|
8
|
+
import { dropUndefined } from "@effect-app/core/utils"
|
|
9
|
+
import { NotLoggedInError } from "@effect-app/infra/errors"
|
|
10
|
+
import * as Middleware from "@effect/platform/HttpMiddleware"
|
|
11
|
+
import * as HttpServerRequest from "@effect/platform/HttpServerRequest"
|
|
12
|
+
import * as ServerResponse from "@effect/platform/HttpServerResponse"
|
|
13
|
+
import { Effect } from "effect-app"
|
|
14
|
+
import { HttpBody, HttpHeaders, HttpServerResponse } from "effect-app/http"
|
|
15
|
+
import * as Either from "effect/Either"
|
|
16
|
+
import * as FiberRef from "effect/FiberRef"
|
|
17
|
+
import { pipe } from "effect/Function"
|
|
18
|
+
import * as HashMap from "effect/HashMap"
|
|
19
|
+
import * as Metric from "effect/Metric"
|
|
20
|
+
import type * as Middlewares from "../middlewares.js"
|
|
21
|
+
|
|
22
|
+
export const accessLog = (level: "Info" | "Warning" | "Debug" = "Info") =>
|
|
23
|
+
Middleware.make((app) =>
|
|
24
|
+
pipe(
|
|
25
|
+
HttpServerRequest.HttpServerRequest,
|
|
26
|
+
Effect.flatMap((request) => Effect[`log${level}`](`${request.method} ${request.url}`)),
|
|
27
|
+
Effect.flatMap(() => app)
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
export const uuidLogAnnotation = (logAnnotationKey = "requestId") =>
|
|
32
|
+
Middleware.make((app) =>
|
|
33
|
+
pipe(
|
|
34
|
+
Effect.sync(() => crypto.randomUUID()),
|
|
35
|
+
Effect.flatMap((uuid) =>
|
|
36
|
+
FiberRef.update(
|
|
37
|
+
FiberRef.currentLogAnnotations,
|
|
38
|
+
HashMap.set<string, unknown>(logAnnotationKey, uuid)
|
|
39
|
+
)
|
|
40
|
+
),
|
|
41
|
+
Effect.flatMap(() => app)
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
export const endpointCallsMetric = () => {
|
|
46
|
+
const endpointCalledCounter = Metric.counter("server.endpoint_calls")
|
|
47
|
+
|
|
48
|
+
return Middleware.make((app) =>
|
|
49
|
+
Effect.gen(function*(_) {
|
|
50
|
+
const request = yield* _(HttpServerRequest.HttpServerRequest)
|
|
51
|
+
|
|
52
|
+
yield* _(
|
|
53
|
+
Metric.increment(endpointCalledCounter),
|
|
54
|
+
Effect.tagMetrics("path", request.url)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return yield* _(app)
|
|
58
|
+
})
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const errorLog = Middleware.make((app) =>
|
|
63
|
+
Effect.gen(function*(_) {
|
|
64
|
+
const request = yield* _(HttpServerRequest.HttpServerRequest)
|
|
65
|
+
|
|
66
|
+
const response = yield* _(app)
|
|
67
|
+
|
|
68
|
+
if (response.status >= 400 && response.status < 500) {
|
|
69
|
+
yield* _(
|
|
70
|
+
Effect.logWarning(
|
|
71
|
+
`${request.method.toUpperCase()} ${request.url} client error ${response.status}`
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
} else if (response.status >= 500) {
|
|
75
|
+
yield* _(
|
|
76
|
+
Effect.logError(
|
|
77
|
+
`${request.method.toUpperCase()} ${request.url} server error ${response.status}`
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return response
|
|
83
|
+
})
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
export const toServerResponse = (err: NotLoggedInError) =>
|
|
87
|
+
HttpServerResponse.empty().pipe(
|
|
88
|
+
HttpServerResponse.setStatus(401),
|
|
89
|
+
HttpServerResponse.setBody(HttpBody.unsafeJson({ message: err.message }))
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
export const basicAuth = <_, R>(
|
|
93
|
+
checkCredentials: (
|
|
94
|
+
credentials: Middlewares.BasicAuthCredentials
|
|
95
|
+
) => Effect<_, NotLoggedInError, R>,
|
|
96
|
+
options?: Partial<{
|
|
97
|
+
headerName: string
|
|
98
|
+
skipPaths: readonly string[]
|
|
99
|
+
}>
|
|
100
|
+
) =>
|
|
101
|
+
Middleware.make((app) =>
|
|
102
|
+
Effect.gen(function*(_) {
|
|
103
|
+
const headerName = options?.headerName ?? "Authorization"
|
|
104
|
+
const skippedPaths = options?.skipPaths ?? []
|
|
105
|
+
const request = yield* _(HttpServerRequest.HttpServerRequest)
|
|
106
|
+
|
|
107
|
+
if (skippedPaths.includes(request.url)) {
|
|
108
|
+
return yield* _(app)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const authHeader = request.headers[headerName.toLowerCase()]
|
|
112
|
+
|
|
113
|
+
if (authHeader === undefined) {
|
|
114
|
+
return toServerResponse(
|
|
115
|
+
new NotLoggedInError(
|
|
116
|
+
`Expected header ${headerName}`
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const authorizationParts = authHeader.split(" ")
|
|
122
|
+
|
|
123
|
+
if (authorizationParts.length !== 2) {
|
|
124
|
+
return toServerResponse(
|
|
125
|
+
new NotLoggedInError(
|
|
126
|
+
"Incorrect auhorization scheme. Expected \"Basic <credentials>\""
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (authorizationParts[0] !== "Basic") {
|
|
132
|
+
return toServerResponse(
|
|
133
|
+
new NotLoggedInError(
|
|
134
|
+
`Incorrect auhorization type. Expected "Basic", got "${authorizationParts[0]}"`
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const credentialsBuffer = Buffer.from(authorizationParts[1]!, "base64")
|
|
140
|
+
const credentialsText = credentialsBuffer.toString("utf-8")
|
|
141
|
+
const credentialsParts = credentialsText.split(":")
|
|
142
|
+
|
|
143
|
+
if (credentialsParts.length !== 2) {
|
|
144
|
+
return toServerResponse(
|
|
145
|
+
new NotLoggedInError(
|
|
146
|
+
"Incorrect basic auth credentials format. Expected base64 encoded \"<user>:<pass>\"."
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const check = yield* _(
|
|
152
|
+
checkCredentials({
|
|
153
|
+
user: credentialsParts[0],
|
|
154
|
+
password: credentialsParts[1]!
|
|
155
|
+
}),
|
|
156
|
+
Effect.either
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
if (Either.isLeft(check)) {
|
|
160
|
+
return toServerResponse(check.left)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return yield* _(app)
|
|
164
|
+
})
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
export const cors = (_options?: Partial<Middlewares.CorsOptions>) => {
|
|
168
|
+
const DEFAULTS = {
|
|
169
|
+
allowedOrigins: ["*"],
|
|
170
|
+
allowedMethods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"],
|
|
171
|
+
allowedHeaders: [],
|
|
172
|
+
exposedHeaders: [],
|
|
173
|
+
credentials: false
|
|
174
|
+
} as const
|
|
175
|
+
|
|
176
|
+
const options = { ...DEFAULTS, ..._options }
|
|
177
|
+
|
|
178
|
+
const isAllowedOrigin = (origin: string) => {
|
|
179
|
+
return options.allowedOrigins.includes(origin)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const allowOrigin = (originHeader: string) => {
|
|
183
|
+
if (options.allowedOrigins.length === 0) {
|
|
184
|
+
return { "Access-Control-Allow-Origin": "*" }
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (options.allowedOrigins.length === 1) {
|
|
188
|
+
return {
|
|
189
|
+
"Access-Control-Allow-Origin": options.allowedOrigins[0],
|
|
190
|
+
Vary: "Origin"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (isAllowedOrigin(originHeader)) {
|
|
195
|
+
return {
|
|
196
|
+
"Access-Control-Allow-Origin": originHeader,
|
|
197
|
+
Vary: "Origin"
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return undefined
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const allowMethods = (() => {
|
|
205
|
+
if (options.allowedMethods.length > 0) {
|
|
206
|
+
return {
|
|
207
|
+
"Access-Control-Allow-Methods": options.allowedMethods.join(", ")
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return undefined
|
|
212
|
+
})()
|
|
213
|
+
|
|
214
|
+
const allowCredentials = (() => {
|
|
215
|
+
if (options.credentials) {
|
|
216
|
+
return { "Access-Control-Allow-Credentials": "true" }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return undefined
|
|
220
|
+
})()
|
|
221
|
+
|
|
222
|
+
const allowHeaders = (accessControlRequestHeaders: string | undefined) => {
|
|
223
|
+
if (options.allowedHeaders.length === 0 && accessControlRequestHeaders) {
|
|
224
|
+
return {
|
|
225
|
+
Vary: "Access-Control-Request-Headers",
|
|
226
|
+
"Access-Control-Allow-Headers": accessControlRequestHeaders
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (options.allowedHeaders) {
|
|
231
|
+
return {
|
|
232
|
+
"Access-Control-Allow-Headers": options.allowedHeaders.join(",")
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return undefined
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const exposeHeaders = (() => {
|
|
240
|
+
if (options.exposedHeaders.length > 0) {
|
|
241
|
+
return {
|
|
242
|
+
"Access-Control-Expose-Headers": options.exposedHeaders.join(",")
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return undefined
|
|
247
|
+
})()
|
|
248
|
+
|
|
249
|
+
const maxAge = (() => {
|
|
250
|
+
if (options.maxAge) {
|
|
251
|
+
return { "Access-Control-Max-Age": options.maxAge.toString() }
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return undefined
|
|
255
|
+
})()
|
|
256
|
+
|
|
257
|
+
return Middleware.make((app) =>
|
|
258
|
+
Effect.gen(function*(_) {
|
|
259
|
+
const request = yield* _(HttpServerRequest.HttpServerRequest)
|
|
260
|
+
|
|
261
|
+
const origin = request.headers["origin"]
|
|
262
|
+
const accessControlRequestHeaders = request.headers["access-control-request-headers"]
|
|
263
|
+
|
|
264
|
+
let corsHeaders = {
|
|
265
|
+
...allowOrigin(origin ?? ""),
|
|
266
|
+
...allowCredentials,
|
|
267
|
+
...exposeHeaders
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (request.method === "OPTIONS") {
|
|
271
|
+
corsHeaders = {
|
|
272
|
+
...corsHeaders,
|
|
273
|
+
...allowMethods,
|
|
274
|
+
...allowHeaders(accessControlRequestHeaders),
|
|
275
|
+
...maxAge
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return ServerResponse.empty({ status: 204, headers: HttpHeaders.fromInput(dropUndefined(corsHeaders)) })
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const response = yield* _(app)
|
|
282
|
+
|
|
283
|
+
return response.pipe(ServerResponse.setHeaders(dropUndefined(corsHeaders)))
|
|
284
|
+
})
|
|
285
|
+
)
|
|
286
|
+
}
|