@effect-app/infra 1.18.3 → 1.20.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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @effect-app/infra
2
2
 
3
+ ## 1.20.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 71cef1a: add SSE middleware
8
+
9
+ ## 1.19.0
10
+
11
+ ### Minor Changes
12
+
13
+ - a40d2bf: port middlewares
14
+
3
15
  ## 1.18.3
4
16
 
5
17
  ### Patch Changes
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.makeSSE = void 0;
7
+ var _setupRequest = require("@effect-app/infra/api/setupRequest");
8
+ var _errorReporter = require("@effect-app/infra/errorReporter");
9
+ var _effectApp = require("effect-app");
10
+ var _http = require("effect-app/http");
11
+ // Tell the client to retry every 10 seconds if connectivity is lost
12
+ const setRetry = _effectApp.Stream.succeed("retry: 10000");
13
+ const keepAlive = _effectApp.Stream.schedule(_effectApp.Effect.succeed(":keep-alive"), _effectApp.Schedule.fixed(_effectApp.Duration.seconds(15)));
14
+ const makeSSE = (events, schema) => _effectApp.Effect.gen(function* () {
15
+ yield* _effectApp.Effect.logInfo("$ start listening to events");
16
+ const enc = new TextEncoder();
17
+ const eventStream = _effectApp.Stream.map(events, _ => `id: ${_.evt.id}\ndata: ${JSON.stringify(_effectApp.S.encodeSync(schema)(_.evt))}`);
18
+ const stream = (0, _effectApp.pipe)(setRetry, _effectApp.Stream.merge(keepAlive), _effectApp.Stream.merge(eventStream), _effectApp.Stream.map(_ => enc.encode(_ + "\n\n")));
19
+ const ctx = yield* _effectApp.Effect.context();
20
+ const res = _http.HttpServerResponse.stream(stream.pipe(_effectApp.Stream.tapErrorCause((0, _errorReporter.reportError)("Request")), _effectApp.Stream.provideContext(ctx)), {
21
+ contentType: "text/event-stream",
22
+ headers: _http.HttpHeaders.fromInput({
23
+ "content-type": "text/event-stream",
24
+ "cache-control": "no-cache",
25
+ "x-accel-buffering": "no",
26
+ "connection": "keep-alive" // if (req.httpVersion !== "2.0")
27
+ })
28
+ });
29
+ return res;
30
+ }).pipe(_effectApp.Effect.tapErrorCause((0, _errorReporter.reportError)("Request")), _ => (0, _setupRequest.setupRequestContext)(_, "events"));
31
+ exports.makeSSE = makeSSE;
32
+ //# sourceMappingURL=events.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.cjs","names":["_setupRequest","require","_errorReporter","_effectApp","_http","setRetry","Stream","succeed","keepAlive","schedule","Effect","Schedule","fixed","Duration","seconds","makeSSE","events","schema","gen","logInfo","enc","TextEncoder","eventStream","map","_","evt","id","JSON","stringify","S","encodeSync","stream","pipe","merge","encode","ctx","context","res","HttpServerResponse","tapErrorCause","reportError","provideContext","contentType","headers","HttpHeaders","fromInput","setupRequestContext","exports"],"sources":["../../../src/api/internal/events.ts"],"sourcesContent":[null],"mappings":";;;;;;AAAA,IAAAA,aAAA,GAAAC,OAAA;AACA,IAAAC,cAAA,GAAAD,OAAA;AACA,IAAAE,UAAA,GAAAF,OAAA;AACA,IAAAG,KAAA,GAAAH,OAAA;AAEA;AACA,MAAMI,QAAQ,GAAGC,iBAAM,CAACC,OAAO,CAAC,cAAc,CAAC;AAC/C,MAAMC,SAAS,GAAGF,iBAAM,CAACG,QAAQ,CAACC,iBAAM,CAACH,OAAO,CAAC,aAAa,CAAC,EAAEI,mBAAQ,CAACC,KAAK,CAACC,mBAAQ,CAACC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAE/F,MAAMC,OAAO,GAAGA,CAAiCC,MAAyD,EAAEC,MAAuB,KAAKP,iBAAM,CAClJQ,GAAG,CAAC,aAAS;EACZ,OAAOR,iBAAM,CAACS,OAAO,CAAC,6BAA6B,CAAC;EAEpD,MAAMC,GAAG,GAAG,IAAIC,WAAW,EAAE;EAE7B,MAAMC,WAAW,GAAGhB,iBAAM,CAACiB,GAAG,CAC5BP,MAAM,EACLQ,CAAC,IAAK,OAAOA,CAAC,CAACC,GAAG,CAACC,EAAE,WAAWC,IAAI,CAACC,SAAS,CAACC,YAAC,CAACC,UAAU,CAACb,MAAM,CAAC,CAACO,CAAC,CAACC,GAAG,CAAC,CAAC,EAAE,CAC/E;EAED,MAAMM,MAAM,GAAG,IAAAC,eAAI,EACjB3B,QAAQ,EACRC,iBAAM,CAAC2B,KAAK,CAACzB,SAAS,CAAC,EACvBF,iBAAM,CAAC2B,KAAK,CAACX,WAAW,CAAC,EACzBhB,iBAAM,CAACiB,GAAG,CAAEC,CAAC,IAAKJ,GAAG,CAACc,MAAM,CAACV,CAAC,GAAG,MAAM,CAAC,CAAC,CAC1C;EAED,MAAMW,GAAG,GAAG,OAAOzB,iBAAM,CAAC0B,OAAO,EAAK;EACtC,MAAMC,GAAG,GAAGC,wBAAkB,CAACP,MAAM,CACnCA,MAAM,CACHC,IAAI,CACH1B,iBAAM,CAACiC,aAAa,CAAC,IAAAC,0BAAW,EAAC,SAAS,CAAC,CAAC,EAC5ClC,iBAAM,CAACmC,cAAc,CAACN,GAAG,CAAC,CAC3B,EACH;IACEO,WAAW,EAAE,mBAAmB;IAChCC,OAAO,EAAEC,iBAAW,CAACC,SAAS,CAAC;MAC7B,cAAc,EAAE,mBAAmB;MACnC,eAAe,EAAE,UAAU;MAC3B,mBAAmB,EAAE,IAAI;MACzB,YAAY,EAAE,YAAY,CAAC;KAC5B;GACF,CACF;EACD,OAAOR,GAAG;AACZ,CAAC,CAAC,CACDL,IAAI,CAACtB,iBAAM,CAAC6B,aAAa,CAAC,IAAAC,0BAAW,EAAC,SAAS,CAAC,CAAC,EAAGhB,CAAC,IAAK,IAAAsB,iCAAmB,EAACtB,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAAuB,OAAA,CAAAhC,OAAA,GAAAA,OAAA","ignoreList":[]}
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.uuidLogAnnotation = exports.toServerResponse = exports.errorLog = exports.endpointCallsMetric = exports.cors = exports.basicAuth = exports.accessLog = void 0;
7
+ var crypto = _interopRequireWildcard(require("crypto"));
8
+ var _utils = require("@effect-app/core/utils");
9
+ var _errors = require("@effect-app/infra/errors");
10
+ var Middleware = _interopRequireWildcard(require("@effect/platform/HttpMiddleware"));
11
+ var HttpServerRequest = _interopRequireWildcard(require("@effect/platform/HttpServerRequest"));
12
+ var ServerResponse = _interopRequireWildcard(require("@effect/platform/HttpServerResponse"));
13
+ var _effectApp = require("effect-app");
14
+ var _http = require("effect-app/http");
15
+ var Either = _interopRequireWildcard(require("effect/Either"));
16
+ var FiberRef = _interopRequireWildcard(require("effect/FiberRef"));
17
+ var _Function = require("effect/Function");
18
+ var HashMap = _interopRequireWildcard(require("effect/HashMap"));
19
+ var Metric = _interopRequireWildcard(require("effect/Metric"));
20
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
21
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
22
+ /**
23
+ * Mechanism for extendning behaviour of all handlers on the server.
24
+ *
25
+ * @since 1.0.0
26
+ */
27
+
28
+ const accessLog = (level = "Info") => Middleware.make(app => (0, _Function.pipe)(HttpServerRequest.HttpServerRequest, _effectApp.Effect.flatMap(request => _effectApp.Effect[`log${level}`](`${request.method} ${request.url}`)), _effectApp.Effect.flatMap(() => app)));
29
+ exports.accessLog = accessLog;
30
+ const uuidLogAnnotation = (logAnnotationKey = "requestId") => Middleware.make(app => (0, _Function.pipe)(_effectApp.Effect.sync(() => crypto.randomUUID()), _effectApp.Effect.flatMap(uuid => FiberRef.update(FiberRef.currentLogAnnotations, HashMap.set(logAnnotationKey, uuid))), _effectApp.Effect.flatMap(() => app)));
31
+ exports.uuidLogAnnotation = uuidLogAnnotation;
32
+ const endpointCallsMetric = () => {
33
+ const endpointCalledCounter = Metric.counter("server.endpoint_calls");
34
+ return Middleware.make(app => _effectApp.Effect.gen(function* (_) {
35
+ const request = yield* _(HttpServerRequest.HttpServerRequest);
36
+ yield* _(Metric.increment(endpointCalledCounter), _effectApp.Effect.tagMetrics("path", request.url));
37
+ return yield* _(app);
38
+ }));
39
+ };
40
+ exports.endpointCallsMetric = endpointCallsMetric;
41
+ const errorLog = exports.errorLog = Middleware.make(app => _effectApp.Effect.gen(function* (_) {
42
+ const request = yield* _(HttpServerRequest.HttpServerRequest);
43
+ const response = yield* _(app);
44
+ if (response.status >= 400 && response.status < 500) {
45
+ yield* _(_effectApp.Effect.logWarning(`${request.method.toUpperCase()} ${request.url} client error ${response.status}`));
46
+ } else if (response.status >= 500) {
47
+ yield* _(_effectApp.Effect.logError(`${request.method.toUpperCase()} ${request.url} server error ${response.status}`));
48
+ }
49
+ return response;
50
+ }));
51
+ const toServerResponse = err => _http.HttpServerResponse.empty().pipe(_http.HttpServerResponse.setStatus(401), _http.HttpServerResponse.setBody(_http.HttpBody.unsafeJson({
52
+ message: err.message
53
+ })));
54
+ exports.toServerResponse = toServerResponse;
55
+ const basicAuth = (checkCredentials, options) => Middleware.make(app => _effectApp.Effect.gen(function* (_) {
56
+ const headerName = options?.headerName ?? "Authorization";
57
+ const skippedPaths = options?.skipPaths ?? [];
58
+ const request = yield* _(HttpServerRequest.HttpServerRequest);
59
+ if (skippedPaths.includes(request.url)) {
60
+ return yield* _(app);
61
+ }
62
+ const authHeader = request.headers[headerName.toLowerCase()];
63
+ if (authHeader === undefined) {
64
+ return toServerResponse(new _errors.NotLoggedInError(`Expected header ${headerName}`));
65
+ }
66
+ const authorizationParts = authHeader.split(" ");
67
+ if (authorizationParts.length !== 2) {
68
+ return toServerResponse(new _errors.NotLoggedInError("Incorrect auhorization scheme. Expected \"Basic <credentials>\""));
69
+ }
70
+ if (authorizationParts[0] !== "Basic") {
71
+ return toServerResponse(new _errors.NotLoggedInError(`Incorrect auhorization type. Expected "Basic", got "${authorizationParts[0]}"`));
72
+ }
73
+ const credentialsBuffer = Buffer.from(authorizationParts[1], "base64");
74
+ const credentialsText = credentialsBuffer.toString("utf-8");
75
+ const credentialsParts = credentialsText.split(":");
76
+ if (credentialsParts.length !== 2) {
77
+ return toServerResponse(new _errors.NotLoggedInError("Incorrect basic auth credentials format. Expected base64 encoded \"<user>:<pass>\"."));
78
+ }
79
+ const check = yield* _(checkCredentials({
80
+ user: credentialsParts[0],
81
+ password: credentialsParts[1]
82
+ }), _effectApp.Effect.either);
83
+ if (Either.isLeft(check)) {
84
+ return toServerResponse(check.left);
85
+ }
86
+ return yield* _(app);
87
+ }));
88
+ exports.basicAuth = basicAuth;
89
+ const cors = _options => {
90
+ const DEFAULTS = {
91
+ allowedOrigins: ["*"],
92
+ allowedMethods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"],
93
+ allowedHeaders: [],
94
+ exposedHeaders: [],
95
+ credentials: false
96
+ };
97
+ const options = {
98
+ ...DEFAULTS,
99
+ ..._options
100
+ };
101
+ const isAllowedOrigin = origin => {
102
+ return options.allowedOrigins.includes(origin);
103
+ };
104
+ const allowOrigin = originHeader => {
105
+ if (options.allowedOrigins.length === 0) {
106
+ return {
107
+ "Access-Control-Allow-Origin": "*"
108
+ };
109
+ }
110
+ if (options.allowedOrigins.length === 1) {
111
+ return {
112
+ "Access-Control-Allow-Origin": options.allowedOrigins[0],
113
+ Vary: "Origin"
114
+ };
115
+ }
116
+ if (isAllowedOrigin(originHeader)) {
117
+ return {
118
+ "Access-Control-Allow-Origin": originHeader,
119
+ Vary: "Origin"
120
+ };
121
+ }
122
+ return undefined;
123
+ };
124
+ const allowMethods = (() => {
125
+ if (options.allowedMethods.length > 0) {
126
+ return {
127
+ "Access-Control-Allow-Methods": options.allowedMethods.join(", ")
128
+ };
129
+ }
130
+ return undefined;
131
+ })();
132
+ const allowCredentials = (() => {
133
+ if (options.credentials) {
134
+ return {
135
+ "Access-Control-Allow-Credentials": "true"
136
+ };
137
+ }
138
+ return undefined;
139
+ })();
140
+ const allowHeaders = accessControlRequestHeaders => {
141
+ if (options.allowedHeaders.length === 0 && accessControlRequestHeaders) {
142
+ return {
143
+ Vary: "Access-Control-Request-Headers",
144
+ "Access-Control-Allow-Headers": accessControlRequestHeaders
145
+ };
146
+ }
147
+ if (options.allowedHeaders) {
148
+ return {
149
+ "Access-Control-Allow-Headers": options.allowedHeaders.join(",")
150
+ };
151
+ }
152
+ return undefined;
153
+ };
154
+ const exposeHeaders = (() => {
155
+ if (options.exposedHeaders.length > 0) {
156
+ return {
157
+ "Access-Control-Expose-Headers": options.exposedHeaders.join(",")
158
+ };
159
+ }
160
+ return undefined;
161
+ })();
162
+ const maxAge = (() => {
163
+ if (options.maxAge) {
164
+ return {
165
+ "Access-Control-Max-Age": options.maxAge.toString()
166
+ };
167
+ }
168
+ return undefined;
169
+ })();
170
+ return Middleware.make(app => _effectApp.Effect.gen(function* (_) {
171
+ const request = yield* _(HttpServerRequest.HttpServerRequest);
172
+ const origin = request.headers["origin"];
173
+ const accessControlRequestHeaders = request.headers["access-control-request-headers"];
174
+ let corsHeaders = {
175
+ ...allowOrigin(origin ?? ""),
176
+ ...allowCredentials,
177
+ ...exposeHeaders
178
+ };
179
+ if (request.method === "OPTIONS") {
180
+ corsHeaders = {
181
+ ...corsHeaders,
182
+ ...allowMethods,
183
+ ...allowHeaders(accessControlRequestHeaders),
184
+ ...maxAge
185
+ };
186
+ return ServerResponse.empty({
187
+ status: 204,
188
+ headers: _http.HttpHeaders.fromInput((0, _utils.dropUndefined)(corsHeaders))
189
+ });
190
+ }
191
+ const response = yield* _(app);
192
+ return response.pipe(ServerResponse.setHeaders((0, _utils.dropUndefined)(corsHeaders)));
193
+ }));
194
+ };
195
+ exports.cors = cors;
196
+ //# sourceMappingURL=middlewares.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middlewares.cjs","names":["crypto","_interopRequireWildcard","require","_utils","_errors","Middleware","HttpServerRequest","ServerResponse","_effectApp","_http","Either","FiberRef","_Function","HashMap","Metric","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","accessLog","level","make","app","pipe","Effect","flatMap","request","method","url","exports","uuidLogAnnotation","logAnnotationKey","sync","randomUUID","uuid","update","currentLogAnnotations","endpointCallsMetric","endpointCalledCounter","counter","gen","_","increment","tagMetrics","errorLog","response","status","logWarning","toUpperCase","logError","toServerResponse","err","HttpServerResponse","empty","setStatus","setBody","HttpBody","unsafeJson","message","basicAuth","checkCredentials","options","headerName","skippedPaths","skipPaths","includes","authHeader","headers","toLowerCase","undefined","NotLoggedInError","authorizationParts","split","length","credentialsBuffer","Buffer","from","credentialsText","toString","credentialsParts","check","user","password","either","isLeft","left","cors","_options","DEFAULTS","allowedOrigins","allowedMethods","allowedHeaders","exposedHeaders","credentials","isAllowedOrigin","origin","allowOrigin","originHeader","Vary","allowMethods","join","allowCredentials","allowHeaders","accessControlRequestHeaders","exposeHeaders","maxAge","corsHeaders","HttpHeaders","fromInput","dropUndefined","setHeaders"],"sources":["../../../src/api/internal/middlewares.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _exportNames = {
7
+ accessLog: true,
8
+ uuidLogAnnotation: true,
9
+ endpointCallsMetric: true,
10
+ errorLog: true,
11
+ basicAuth: true,
12
+ cors: true
13
+ };
14
+ exports.uuidLogAnnotation = exports.errorLog = exports.endpointCallsMetric = exports.cors = exports.basicAuth = exports.accessLog = void 0;
15
+ var internal = _interopRequireWildcard(require("./internal/middlewares.cjs"));
16
+ var _events = require("./internal/events.cjs");
17
+ Object.keys(_events).forEach(function (key) {
18
+ if (key === "default" || key === "__esModule") return;
19
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
20
+ if (key in exports && exports[key] === _events[key]) return;
21
+ Object.defineProperty(exports, key, {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _events[key];
25
+ }
26
+ });
27
+ });
28
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
29
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
30
+ /**
31
+ * Add access logs for handled requests. The log runs before each request.
32
+ * Optionally configure log level using the first argument. The default log level
33
+ * is `Debug`.
34
+ *
35
+ * @category logging
36
+ * @since 1.0.0
37
+ */
38
+ const accessLog = exports.accessLog = internal.accessLog;
39
+ /**
40
+ * Annotate request logs using generated UUID. The default annotation key is `requestId`.
41
+ * The annotation key is configurable using the first argument.
42
+ *
43
+ * Note that in order to apply the annotation also for access logging, you should
44
+ * make sure the `accessLog` middleware is plugged after the `uuidLogAnnotation`.
45
+ *
46
+ * @category logging
47
+ * @since 1.0.0
48
+ */
49
+ const uuidLogAnnotation = exports.uuidLogAnnotation = internal.uuidLogAnnotation;
50
+ /**
51
+ * Measure how many times each endpoint was called in a
52
+ * `server.endpoint_calls` counter metrics.
53
+ *
54
+ * @category metrics
55
+ * @since 1.0.0
56
+ */
57
+ const endpointCallsMetric = exports.endpointCallsMetric = internal.endpointCallsMetric;
58
+ /**
59
+ * Logs out a handler failure.
60
+ *
61
+ * @category logging
62
+ * @since 1.0.0
63
+ */
64
+ const errorLog = exports.errorLog = internal.errorLog;
65
+ /**
66
+ * Basic auth middleware.
67
+ *
68
+ * @category authorization
69
+ * @since 1.0.0
70
+ */
71
+ const basicAuth = exports.basicAuth = internal.basicAuth;
72
+ /**
73
+ * Basic auth middleware.
74
+ *
75
+ * @category authorization
76
+ * @since 1.0.0
77
+ */
78
+ const cors = exports.cors = internal.cors;
79
+ //# sourceMappingURL=middlewares.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middlewares.cjs","names":["internal","_interopRequireWildcard","require","_events","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","n","__proto__","a","getOwnPropertyDescriptor","u","i","set","accessLog","uuidLogAnnotation","endpointCallsMetric","errorLog","basicAuth","cors"],"sources":["../../src/api/middlewares.ts"],"sourcesContent":[null],"mappings":";;;;;;;;;;;;;;AAQA,IAAAA,QAAA,GAAAC,uBAAA,CAAAC,OAAA;AAEA,IAAAC,OAAA,GAAAD,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAF,OAAA,EAAAG,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAJ,OAAA,CAAAI,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAZ,OAAA,CAAAI,GAAA;IAAA;EAAA;AAAA;AAAoC,SAAAS,yBAAAC,CAAA,6BAAAC,OAAA,mBAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAF,wBAAA,YAAAA,CAAAC,CAAA,WAAAA,CAAA,GAAAG,CAAA,GAAAD,CAAA,KAAAF,CAAA;AAAA,SAAAhB,wBAAAgB,CAAA,EAAAE,CAAA,SAAAA,CAAA,IAAAF,CAAA,IAAAA,CAAA,CAAAI,UAAA,SAAAJ,CAAA,eAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,WAAAK,OAAA,EAAAL,CAAA,QAAAG,CAAA,GAAAJ,wBAAA,CAAAG,CAAA,OAAAC,CAAA,IAAAA,CAAA,CAAAG,GAAA,CAAAN,CAAA,UAAAG,CAAA,CAAAL,GAAA,CAAAE,CAAA,OAAAO,CAAA,KAAAC,SAAA,UAAAC,CAAA,GAAAtB,MAAA,CAAAS,cAAA,IAAAT,MAAA,CAAAuB,wBAAA,WAAAC,CAAA,IAAAX,CAAA,oBAAAW,CAAA,OAAAnB,cAAA,CAAAC,IAAA,CAAAO,CAAA,EAAAW,CAAA,SAAAC,CAAA,GAAAH,CAAA,GAAAtB,MAAA,CAAAuB,wBAAA,CAAAV,CAAA,EAAAW,CAAA,UAAAC,CAAA,KAAAA,CAAA,CAAAd,GAAA,IAAAc,CAAA,CAAAC,GAAA,IAAA1B,MAAA,CAAAS,cAAA,CAAAW,CAAA,EAAAI,CAAA,EAAAC,CAAA,IAAAL,CAAA,CAAAI,CAAA,IAAAX,CAAA,CAAAW,CAAA,YAAAJ,CAAA,CAAAF,OAAA,GAAAL,CAAA,EAAAG,CAAA,IAAAA,CAAA,CAAAU,GAAA,CAAAb,CAAA,EAAAO,CAAA,GAAAA,CAAA;AAEpC;;;;;;;;AAQO,MAAMO,SAAS,GAAAnB,OAAA,CAAAmB,SAAA,GAEqC/B,QAAQ,CAAC+B,SAAS;AAE7E;;;;;;;;;;AAUO,MAAMC,iBAAiB,GAAApB,OAAA,CAAAoB,iBAAA,GAE6BhC,QAAQ,CAACgC,iBAAiB;AAErF;;;;;;;AAOO,MAAMC,mBAAmB,GAAArB,OAAA,CAAAqB,mBAAA,GAEPjC,QAAQ,CAACiC,mBAAmB;AAErD;;;;;;AAMO,MAAMC,QAAQ,GAAAtB,OAAA,CAAAsB,QAAA,GAAwDlC,QAAQ,CAACkC,QAAQ;AAW9F;;;;;;AAMO,MAAMC,SAAS,GAAAvB,OAAA,CAAAuB,SAAA,GAQ6CnC,QAAQ,CAACmC,SAAS;AAerF;;;;;;AAMO,MAAMC,IAAI,GAAAxB,OAAA,CAAAwB,IAAA,GAE0CpC,QAAQ,CAACoC,IAAI","ignoreList":[]}
@@ -0,0 +1,9 @@
1
+ import { Effect, S, Stream } from "effect-app";
2
+ import { HttpServerResponse } from "effect-app/http";
3
+ export declare const makeSSE: <A extends {
4
+ id: any;
5
+ }, E, R, SI>(events: Stream.Stream<{
6
+ evt: A;
7
+ namespace: string;
8
+ }, E, R>, schema: S.Schema<A, SI>) => Effect.Effect<HttpServerResponse.HttpServerResponse, never, import("../../services/RequestContextContainer.js").RequestContextContainer | import("../../services/Store/ContextMapContainer.js").ContextMapContainer | Exclude<Exclude<R, import("effect/Tracer").ParentSpan>, never>>;
9
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/api/internal/events.ts"],"names":[],"mappings":"AAEA,OAAO,EAAY,MAAM,EAAQ,CAAC,EAAY,MAAM,EAAE,MAAM,YAAY,CAAA;AACxE,OAAO,EAAe,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAMjE,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,EAAE,CAAC,EAAC,CAAC,EAAE,EAAE,UAAU,MAAM,CAAC,MAAM,CAAC;IAAE,GAAG,EAAE,CAAC,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,0RAqC5C,CAAA"}
@@ -0,0 +1,28 @@
1
+ import { setupRequestContext } from "@effect-app/infra/api/setupRequest";
2
+ import { reportError } from "@effect-app/infra/errorReporter";
3
+ import { Duration, Effect, pipe, S, Schedule, Stream } from "effect-app";
4
+ import { HttpHeaders, HttpServerResponse } from "effect-app/http";
5
+ // Tell the client to retry every 10 seconds if connectivity is lost
6
+ const setRetry = Stream.succeed("retry: 10000");
7
+ const keepAlive = Stream.schedule(Effect.succeed(":keep-alive"), Schedule.fixed(Duration.seconds(15)));
8
+ export const makeSSE = (events, schema) => Effect
9
+ .gen(function* () {
10
+ yield* Effect.logInfo("$ start listening to events");
11
+ const enc = new TextEncoder();
12
+ const eventStream = Stream.map(events, (_) => `id: ${_.evt.id}\ndata: ${JSON.stringify(S.encodeSync(schema)(_.evt))}`);
13
+ const stream = pipe(setRetry, Stream.merge(keepAlive), Stream.merge(eventStream), Stream.map((_) => enc.encode(_ + "\n\n")));
14
+ const ctx = yield* Effect.context();
15
+ const res = HttpServerResponse.stream(stream
16
+ .pipe(Stream.tapErrorCause(reportError("Request")), Stream.provideContext(ctx)), {
17
+ contentType: "text/event-stream",
18
+ headers: HttpHeaders.fromInput({
19
+ "content-type": "text/event-stream",
20
+ "cache-control": "no-cache",
21
+ "x-accel-buffering": "no",
22
+ "connection": "keep-alive" // if (req.httpVersion !== "2.0")
23
+ })
24
+ });
25
+ return res;
26
+ })
27
+ .pipe(Effect.tapErrorCause(reportError("Request")), (_) => setupRequestContext(_, "events"));
28
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwaS9pbnRlcm5hbC9ldmVudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sb0NBQW9DLENBQUE7QUFDeEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlDQUFpQyxDQUFBO0FBQzdELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUN4RSxPQUFPLEVBQUUsV0FBVyxFQUFFLGtCQUFrQixFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFFakUsb0VBQW9FO0FBQ3BFLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUE7QUFDL0MsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFFdEcsTUFBTSxDQUFDLE1BQU0sT0FBTyxHQUFHLENBQWlDLE1BQXlELEVBQUUsTUFBdUIsRUFBRSxFQUFFLENBQUMsTUFBTTtLQUNsSixHQUFHLENBQUMsUUFBUSxDQUFDO0lBQ1osS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyw2QkFBNkIsQ0FBQyxDQUFBO0lBRXBELE1BQU0sR0FBRyxHQUFHLElBQUksV0FBVyxFQUFFLENBQUE7SUFFN0IsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FDNUIsTUFBTSxFQUNOLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxXQUFXLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUMvRSxDQUFBO0lBRUQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUNqQixRQUFRLEVBQ1IsTUFBTSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsRUFDdkIsTUFBTSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsRUFDekIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FDMUMsQ0FBQTtJQUVELE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUssQ0FBQTtJQUN0QyxNQUFNLEdBQUcsR0FBRyxrQkFBa0IsQ0FBQyxNQUFNLENBQ25DLE1BQU07U0FDSCxJQUFJLENBQ0gsTUFBTSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUMsRUFDNUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxHQUFHLENBQUMsQ0FDM0IsRUFDSDtRQUNFLFdBQVcsRUFBRSxtQkFBbUI7UUFDaEMsT0FBTyxFQUFFLFdBQVcsQ0FBQyxTQUFTLENBQUM7WUFDN0IsY0FBYyxFQUFFLG1CQUFtQjtZQUNuQyxlQUFlLEVBQUUsVUFBVTtZQUMzQixtQkFBbUIsRUFBRSxJQUFJO1lBQ3pCLFlBQVksRUFBRSxZQUFZLENBQUMsaUNBQWlDO1NBQzdELENBQUM7S0FDSCxDQUNGLENBQUE7SUFDRCxPQUFPLEdBQUcsQ0FBQTtBQUNaLENBQUMsQ0FBQztLQUNELElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQSJ9
@@ -0,0 +1,16 @@
1
+ import { NotLoggedInError } from "@effect-app/infra/errors";
2
+ import * as HttpServerRequest from "@effect/platform/HttpServerRequest";
3
+ import * as ServerResponse from "@effect/platform/HttpServerResponse";
4
+ import { Effect } from "effect-app";
5
+ import type * as Middlewares from "../middlewares.js";
6
+ export declare const accessLog: (level?: "Info" | "Warning" | "Debug") => <E, R>(app: import("@effect/platform/HttpApp").Default<E, R>) => Effect.Effect<ServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R>;
7
+ export declare const uuidLogAnnotation: (logAnnotationKey?: string) => <E, R>(app: import("@effect/platform/HttpApp").Default<E, R>) => Effect.Effect<ServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R>;
8
+ export declare const endpointCallsMetric: () => <E, R>(app: import("@effect/platform/HttpApp").Default<E, R>) => Effect.Effect<ServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R>;
9
+ export declare const errorLog: <E, R>(app: import("@effect/platform/HttpApp").Default<E, R>) => Effect.Effect<ServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R>;
10
+ export declare const toServerResponse: (err: NotLoggedInError) => ServerResponse.HttpServerResponse;
11
+ export declare const basicAuth: <_, R>(checkCredentials: (credentials: Middlewares.BasicAuthCredentials) => Effect<_, NotLoggedInError, R>, options?: Partial<{
12
+ headerName: string;
13
+ skipPaths: readonly string[];
14
+ }>) => <E, R_1>(app: import("@effect/platform/HttpApp").Default<E, R_1>) => Effect.Effect<ServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R | R_1>;
15
+ export declare const cors: (_options?: Partial<Middlewares.CorsOptions>) => <E, R>(app: import("@effect/platform/HttpApp").Default<E, R>) => Effect.Effect<ServerResponse.HttpServerResponse, E, HttpServerRequest.HttpServerRequest | R>;
16
+ //# sourceMappingURL=middlewares.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middlewares.d.ts","sourceRoot":"","sources":["../../../src/api/internal/middlewares.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAE3D,OAAO,KAAK,iBAAiB,MAAM,oCAAoC,CAAA;AACvE,OAAO,KAAK,cAAc,MAAM,qCAAqC,CAAA;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAOnC,OAAO,KAAK,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAErD,eAAO,MAAM,SAAS,WAAW,MAAM,GAAG,SAAS,GAAG,OAAO,kKAO1D,CAAA;AAEH,eAAO,MAAM,iBAAiB,8LAY3B,CAAA;AAEH,eAAO,MAAM,mBAAmB,qKAe/B,CAAA;AAED,eAAO,MAAM,QAAQ,+JAsBpB,CAAA;AAED,eAAO,MAAM,gBAAgB,QAAS,gBAAgB,sCAInD,CAAA;AAEH,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,CAAC,oBACV,CAChB,WAAW,EAAE,WAAW,CAAC,oBAAoB,KAC1C,MAAM,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,YACzB,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;CAC7B,CAAC,4KAkED,CAAA;AAEH,eAAO,MAAM,IAAI,cAAe,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,kKAuH/D,CAAA"}
@@ -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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
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Mechanism for extendning behaviour of all handlers on the server.
3
+ *
4
+ * @since 1.0.0
5
+ */
6
+ import type * as App from "@effect/platform/HttpApp";
7
+ import type { Effect } from "effect-app";
8
+ import type { NotLoggedInError } from "../errors.js";
9
+ export * from "./internal/events.js";
10
+ /**
11
+ * Add access logs for handled requests. The log runs before each request.
12
+ * Optionally configure log level using the first argument. The default log level
13
+ * is `Debug`.
14
+ *
15
+ * @category logging
16
+ * @since 1.0.0
17
+ */
18
+ export declare const accessLog: (level?: "Info" | "Warning" | "Debug") => <R, E>(app: App.Default<R, E>) => App.Default<R, E>;
19
+ /**
20
+ * Annotate request logs using generated UUID. The default annotation key is `requestId`.
21
+ * The annotation key is configurable using the first argument.
22
+ *
23
+ * Note that in order to apply the annotation also for access logging, you should
24
+ * make sure the `accessLog` middleware is plugged after the `uuidLogAnnotation`.
25
+ *
26
+ * @category logging
27
+ * @since 1.0.0
28
+ */
29
+ export declare const uuidLogAnnotation: (logAnnotationKey?: string) => <R, E>(app: App.Default<R, E>) => App.Default<R, E>;
30
+ /**
31
+ * Measure how many times each endpoint was called in a
32
+ * `server.endpoint_calls` counter metrics.
33
+ *
34
+ * @category metrics
35
+ * @since 1.0.0
36
+ */
37
+ export declare const endpointCallsMetric: () => <R, E>(app: App.Default<R, E>) => App.Default<R, E>;
38
+ /**
39
+ * Logs out a handler failure.
40
+ *
41
+ * @category logging
42
+ * @since 1.0.0
43
+ */
44
+ export declare const errorLog: <R, E>(app: App.Default<R, E>) => App.Default<R, E>;
45
+ /**
46
+ * @category models
47
+ * @since 1.0.0
48
+ */
49
+ export interface BasicAuthCredentials {
50
+ user: string;
51
+ password: string;
52
+ }
53
+ /**
54
+ * Basic auth middleware.
55
+ *
56
+ * @category authorization
57
+ * @since 1.0.0
58
+ */
59
+ export declare const basicAuth: <R2, _>(checkCredentials: (credentials: BasicAuthCredentials) => Effect<_, NotLoggedInError, R2>, options?: Partial<{
60
+ headerName: string;
61
+ skipPaths: readonly string[];
62
+ }>) => <R1, E>(app: App.Default<E, R1>) => App.Default<E, R1 | R2>;
63
+ /**
64
+ * @category models
65
+ * @since 1.0.0
66
+ */
67
+ export interface CorsOptions {
68
+ allowedOrigins: readonly string[];
69
+ allowedMethods: readonly string[];
70
+ allowedHeaders: readonly string[];
71
+ exposedHeaders: readonly string[];
72
+ maxAge: number;
73
+ credentials: boolean;
74
+ }
75
+ /**
76
+ * Basic auth middleware.
77
+ *
78
+ * @category authorization
79
+ * @since 1.0.0
80
+ */
81
+ export declare const cors: (options?: Partial<CorsOptions>) => <R, E>(app: App.Default<R, E>) => App.Default<R, E>;
82
+ //# sourceMappingURL=middlewares.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middlewares.d.ts","sourceRoot":"","sources":["../../src/api/middlewares.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,KAAK,GAAG,MAAM,0BAA0B,CAAA;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAGpD,cAAc,sBAAsB,CAAA;AAEpC;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,EAAE,CACtB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,KACjC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAsB,CAAA;AAE7E;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,EAAE,CAC9B,gBAAgB,CAAC,EAAE,MAAM,KACtB,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAA8B,CAAA;AAErF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,EAC3C,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KACnB,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAgC,CAAA;AAErD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAqB,CAAA;AAE9F;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,EAC5B,gBAAgB,EAAE,CAChB,WAAW,EAAE,oBAAoB,KAC9B,MAAM,CAAC,CAAC,EAAE,gBAAgB,EAAE,EAAE,CAAC,EACpC,OAAO,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;CAC7B,CAAC,KACC,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAsB,CAAA;AAErF;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,OAAO,CAAA;CACrB;AAED;;;;;GAKG;AACH,eAAO,MAAM,IAAI,EAAE,CACjB,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,KAC3B,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAiB,CAAA"}
@@ -0,0 +1,52 @@
1
+ import * as internal from "./internal/middlewares.js";
2
+ export * from "./internal/events.js";
3
+ /**
4
+ * Add access logs for handled requests. The log runs before each request.
5
+ * Optionally configure log level using the first argument. The default log level
6
+ * is `Debug`.
7
+ *
8
+ * @category logging
9
+ * @since 1.0.0
10
+ */
11
+ export const accessLog = internal.accessLog;
12
+ /**
13
+ * Annotate request logs using generated UUID. The default annotation key is `requestId`.
14
+ * The annotation key is configurable using the first argument.
15
+ *
16
+ * Note that in order to apply the annotation also for access logging, you should
17
+ * make sure the `accessLog` middleware is plugged after the `uuidLogAnnotation`.
18
+ *
19
+ * @category logging
20
+ * @since 1.0.0
21
+ */
22
+ export const uuidLogAnnotation = internal.uuidLogAnnotation;
23
+ /**
24
+ * Measure how many times each endpoint was called in a
25
+ * `server.endpoint_calls` counter metrics.
26
+ *
27
+ * @category metrics
28
+ * @since 1.0.0
29
+ */
30
+ export const endpointCallsMetric = internal.endpointCallsMetric;
31
+ /**
32
+ * Logs out a handler failure.
33
+ *
34
+ * @category logging
35
+ * @since 1.0.0
36
+ */
37
+ export const errorLog = internal.errorLog;
38
+ /**
39
+ * Basic auth middleware.
40
+ *
41
+ * @category authorization
42
+ * @since 1.0.0
43
+ */
44
+ export const basicAuth = internal.basicAuth;
45
+ /**
46
+ * Basic auth middleware.
47
+ *
48
+ * @category authorization
49
+ * @since 1.0.0
50
+ */
51
+ export const cors = internal.cors;
52
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL21pZGRsZXdhcmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLE9BQU8sS0FBSyxRQUFRLE1BQU0sMkJBQTJCLENBQUE7QUFFckQsY0FBYyxzQkFBc0IsQ0FBQTtBQUVwQzs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUVxQyxRQUFRLENBQUMsU0FBUyxDQUFBO0FBRTdFOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUU2QixRQUFRLENBQUMsaUJBQWlCLENBQUE7QUFFckY7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBRVAsUUFBUSxDQUFDLG1CQUFtQixDQUFBO0FBRXJEOzs7OztHQUtHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sUUFBUSxHQUF3RCxRQUFRLENBQUMsUUFBUSxDQUFBO0FBVzlGOzs7OztHQUtHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQVE2QyxRQUFRLENBQUMsU0FBUyxDQUFBO0FBZXJGOzs7OztHQUtHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sSUFBSSxHQUUwQyxRQUFRLENBQUMsSUFBSSxDQUFBIn0=
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/infra",
3
- "version": "1.18.3",
3
+ "version": "1.20.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -18,10 +18,10 @@
18
18
  "proper-lockfile": "^4.1.2",
19
19
  "pure-rand": "6.1.0",
20
20
  "redlock": "^4.2.0",
21
- "@effect-app/core": "1.10.1",
22
21
  "@effect-app/infra-adapters": "1.11.3",
22
+ "@effect-app/schema": "1.12.1",
23
23
  "effect-app": "1.17.1",
24
- "@effect-app/schema": "1.12.1"
24
+ "@effect-app/core": "1.10.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",
@@ -0,0 +1,47 @@
1
+ import { setupRequestContext } from "@effect-app/infra/api/setupRequest"
2
+ import { reportError } from "@effect-app/infra/errorReporter"
3
+ import { Duration, Effect, pipe, S, Schedule, Stream } from "effect-app"
4
+ import { HttpHeaders, HttpServerResponse } from "effect-app/http"
5
+
6
+ // Tell the client to retry every 10 seconds if connectivity is lost
7
+ const setRetry = Stream.succeed("retry: 10000")
8
+ const keepAlive = Stream.schedule(Effect.succeed(":keep-alive"), Schedule.fixed(Duration.seconds(15)))
9
+
10
+ export const makeSSE = <A extends { id: any }, E,R, SI>(events: Stream.Stream<{ evt: A, namespace: string}, E, R>, schema: S.Schema<A, SI>) => Effect
11
+ .gen(function*() {
12
+ yield* Effect.logInfo("$ start listening to events")
13
+
14
+ const enc = new TextEncoder()
15
+
16
+ const eventStream = Stream.map(
17
+ events,
18
+ (_) => `id: ${_.evt.id}\ndata: ${JSON.stringify(S.encodeSync(schema)(_.evt))}`
19
+ )
20
+
21
+ const stream = pipe(
22
+ setRetry,
23
+ Stream.merge(keepAlive),
24
+ Stream.merge(eventStream),
25
+ Stream.map((_) => enc.encode(_ + "\n\n"))
26
+ )
27
+
28
+ const ctx = yield* Effect.context<R>()
29
+ const res = HttpServerResponse.stream(
30
+ stream
31
+ .pipe(
32
+ Stream.tapErrorCause(reportError("Request")),
33
+ Stream.provideContext(ctx)
34
+ ),
35
+ {
36
+ contentType: "text/event-stream",
37
+ headers: HttpHeaders.fromInput({
38
+ "content-type": "text/event-stream",
39
+ "cache-control": "no-cache",
40
+ "x-accel-buffering": "no",
41
+ "connection": "keep-alive" // if (req.httpVersion !== "2.0")
42
+ })
43
+ }
44
+ )
45
+ return res
46
+ })
47
+ .pipe(Effect.tapErrorCause(reportError("Request")), (_) => setupRequestContext(_, "events"))
@@ -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
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Mechanism for extendning behaviour of all handlers on the server.
3
+ *
4
+ * @since 1.0.0
5
+ */
6
+ import type * as App from "@effect/platform/HttpApp"
7
+ import type { Effect } from "effect-app"
8
+ import type { NotLoggedInError } from "../errors.js"
9
+ import * as internal from "./internal/middlewares.js"
10
+
11
+ export * from "./internal/events.js"
12
+
13
+ /**
14
+ * Add access logs for handled requests. The log runs before each request.
15
+ * Optionally configure log level using the first argument. The default log level
16
+ * is `Debug`.
17
+ *
18
+ * @category logging
19
+ * @since 1.0.0
20
+ */
21
+ export const accessLog: (
22
+ level?: "Info" | "Warning" | "Debug"
23
+ ) => <R, E>(app: App.Default<R, E>) => App.Default<R, E> = internal.accessLog
24
+
25
+ /**
26
+ * Annotate request logs using generated UUID. The default annotation key is `requestId`.
27
+ * The annotation key is configurable using the first argument.
28
+ *
29
+ * Note that in order to apply the annotation also for access logging, you should
30
+ * make sure the `accessLog` middleware is plugged after the `uuidLogAnnotation`.
31
+ *
32
+ * @category logging
33
+ * @since 1.0.0
34
+ */
35
+ export const uuidLogAnnotation: (
36
+ logAnnotationKey?: string
37
+ ) => <R, E>(app: App.Default<R, E>) => App.Default<R, E> = internal.uuidLogAnnotation
38
+
39
+ /**
40
+ * Measure how many times each endpoint was called in a
41
+ * `server.endpoint_calls` counter metrics.
42
+ *
43
+ * @category metrics
44
+ * @since 1.0.0
45
+ */
46
+ export const endpointCallsMetric: () => <R, E>(
47
+ app: App.Default<R, E>
48
+ ) => App.Default<R, E> = internal.endpointCallsMetric
49
+
50
+ /**
51
+ * Logs out a handler failure.
52
+ *
53
+ * @category logging
54
+ * @since 1.0.0
55
+ */
56
+ export const errorLog: <R, E>(app: App.Default<R, E>) => App.Default<R, E> = internal.errorLog
57
+
58
+ /**
59
+ * @category models
60
+ * @since 1.0.0
61
+ */
62
+ export interface BasicAuthCredentials {
63
+ user: string
64
+ password: string
65
+ }
66
+
67
+ /**
68
+ * Basic auth middleware.
69
+ *
70
+ * @category authorization
71
+ * @since 1.0.0
72
+ */
73
+ export const basicAuth: <R2, _>(
74
+ checkCredentials: (
75
+ credentials: BasicAuthCredentials
76
+ ) => Effect<_, NotLoggedInError, R2>,
77
+ options?: Partial<{
78
+ headerName: string
79
+ skipPaths: readonly string[]
80
+ }>
81
+ ) => <R1, E>(app: App.Default<E, R1>) => App.Default<E, R1 | R2> = internal.basicAuth
82
+
83
+ /**
84
+ * @category models
85
+ * @since 1.0.0
86
+ */
87
+ export interface CorsOptions {
88
+ allowedOrigins: readonly string[]
89
+ allowedMethods: readonly string[]
90
+ allowedHeaders: readonly string[]
91
+ exposedHeaders: readonly string[]
92
+ maxAge: number
93
+ credentials: boolean
94
+ }
95
+
96
+ /**
97
+ * Basic auth middleware.
98
+ *
99
+ * @category authorization
100
+ * @since 1.0.0
101
+ */
102
+ export const cors: (
103
+ options?: Partial<CorsOptions>
104
+ ) => <R, E>(app: App.Default<R, E>) => App.Default<R, E> = internal.cors
@@ -0,0 +1,37 @@
1
+ // packages/infra/vitest.config.ts
2
+ import { defineConfig } from "file:///Users/patrickroza/pj/effect-app/libs/node_modules/.pnpm/vite@5.2.6_@types+node@20.11.30/node_modules/vite/dist/node/index.js";
3
+
4
+ // vite.config.base.ts
5
+ import path from "path";
6
+ import fs from "fs";
7
+ var __vite_injected_original_dirname = "/Users/patrickroza/pj/effect-app/libs";
8
+ function makeConfig(dirName) {
9
+ const prefix = path.resolve(__vite_injected_original_dirname, "packages");
10
+ const packages = fs.readdirSync(prefix).map((f) => prefix + "/" + f).filter((f) => fs.lstatSync(f).isDirectory());
11
+ const cfg = {
12
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
13
+ //plugins: [autoImport],
14
+ test: {
15
+ include: ["./test/**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
16
+ reporters: "verbose",
17
+ globals: true
18
+ },
19
+ resolve: {
20
+ alias: packages.reduce((acc, cur) => {
21
+ acc[JSON.parse(fs.readFileSync(cur + "/package.json", "utf-8")).name] = path.resolve(cur, cur.endsWith("core") ? "dist" : "src");
22
+ return acc;
23
+ }, {})
24
+ // "@effect-app/core/Prelude": path.join(__dirname, "packages/core/src/Prelude.code.ts")
25
+ }
26
+ };
27
+ console.log(cfg);
28
+ return cfg;
29
+ }
30
+
31
+ // packages/infra/vitest.config.ts
32
+ var __vite_injected_original_dirname2 = "/Users/patrickroza/pj/effect-app/libs/packages/infra";
33
+ var vitest_config_default = defineConfig(makeConfig(__vite_injected_original_dirname2));
34
+ export {
35
+ vitest_config_default as default
36
+ };
37
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsicGFja2FnZXMvaW5mcmEvdml0ZXN0LmNvbmZpZy50cyIsICJ2aXRlLmNvbmZpZy5iYXNlLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlicy9wYWNrYWdlcy9pbmZyYVwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlicy9wYWNrYWdlcy9pbmZyYS92aXRlc3QuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9wYXRyaWNrcm96YS9wai9lZmZlY3QtYXBwL2xpYnMvcGFja2FnZXMvaW5mcmEvdml0ZXN0LmNvbmZpZy50c1wiOy8vLyA8cmVmZXJlbmNlIHR5cGVzPVwidml0ZXN0XCIgLz5cbmltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gXCJ2aXRlXCJcbmltcG9ydCBtYWtlQ29uZmlnIGZyb20gXCIuLi8uLi92aXRlLmNvbmZpZy5iYXNlXCJcblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKG1ha2VDb25maWcoX19kaXJuYW1lKSlcbiIsICJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlic1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL3BhdHJpY2tyb3phL3BqL2VmZmVjdC1hcHAvbGlicy92aXRlLmNvbmZpZy5iYXNlLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9wYXRyaWNrcm96YS9wai9lZmZlY3QtYXBwL2xpYnMvdml0ZS5jb25maWcuYmFzZS50c1wiOy8vLyA8cmVmZXJlbmNlIHR5cGVzPVwidml0ZXN0XCIgLz5cbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCJcbmltcG9ydCBmcyBmcm9tIFwiZnNcIlxuaW1wb3J0IEF1dG9JbXBvcnQgZnJvbSBcInVucGx1Z2luLWF1dG8taW1wb3J0L3ZpdGVcIlxuaW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSBcInZpdGVzdC9jb25maWdcIlxuXG4vLyBjb25zdCBhdXRvSW1wb3J0ID0gQXV0b0ltcG9ydCh7XG4vLyAgIGR0czogXCIuL3Rlc3QvYXV0by1pbXBvcnRzLmQudHNcIixcbi8vICAgLy8gaW5jbHVkZTogW1xuLy8gICAvLyAgIC9cXC50ZXN0XFwuW3RqXXN4PyQvIC8vIC50cywgLnRzeCwgLmpzLCAuanN4XG4vLyAgIC8vIF0sXG4vLyAgIGltcG9ydHM6IFtcbi8vICAgICBcInZpdGVzdFwiXG4vLyAgIF1cbi8vIH0pXG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIG1ha2VDb25maWcoZGlyTmFtZT86IHN0cmluZykge1xuICBjb25zdCBwcmVmaXggPSBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCBcInBhY2thZ2VzXCIpXG4gIGNvbnN0IHBhY2thZ2VzID0gZnMucmVhZGRpclN5bmMocHJlZml4KS5tYXAoZiA9PiBwcmVmaXggKyBcIi9cIiArIGYpLmZpbHRlcihmID0+IGZzLmxzdGF0U3luYyhmKS5pc0RpcmVjdG9yeSgpIClcbiAgY29uc3QgY2ZnID0ge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdmFyLXJlcXVpcmVzXG4gICAgLy9wbHVnaW5zOiBbYXV0b0ltcG9ydF0sXG4gICAgdGVzdDoge1xuICAgICAgaW5jbHVkZTogIFtcIi4vdGVzdC8qKi8qLnRlc3Que2pzLG1qcyxjanMsdHMsbXRzLGN0cyxqc3gsdHN4fVwiXSxcbiAgICAgIHJlcG9ydGVyczogXCJ2ZXJib3NlXCIsXG4gICAgICBnbG9iYWxzOiB0cnVlXG4gICAgfSxcbiAgICByZXNvbHZlOiB7XG4gICAgICBhbGlhczogcGFja2FnZXMucmVkdWNlKChhY2MsIGN1cikgPT4geyAvLyB3b3JrYXJvdW5kIGZvciAvUHJlbHVkZSBpc3N1ZVxuICAgICAgYWNjW0pTT04ucGFyc2UoZnMucmVhZEZpbGVTeW5jKGN1ciArIFwiL3BhY2thZ2UuanNvblwiLCBcInV0Zi04XCIpKS5uYW1lXSA9IHBhdGgucmVzb2x2ZShjdXIsIGN1ci5lbmRzV2l0aChcImNvcmVcIikgPyBcImRpc3RcIiA6IFwic3JjXCIpXG4gICAgICByZXR1cm4gYWNjXG4gICAgfSwgeyB9KSAvLyBcIkBlZmZlY3QtYXBwL2NvcmUvUHJlbHVkZVwiOiBwYXRoLmpvaW4oX19kaXJuYW1lLCBcInBhY2thZ2VzL2NvcmUvc3JjL1ByZWx1ZGUuY29kZS50c1wiKVxuICB9XG4gIH1cbiAgY29uc29sZS5sb2coY2ZnKVxuICByZXR1cm4gY2ZnXG59XG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQ0EsU0FBUyxvQkFBb0I7OztBQ0E3QixPQUFPLFVBQVU7QUFDakIsT0FBTyxRQUFRO0FBRmYsSUFBTSxtQ0FBbUM7QUFnQjFCLFNBQVIsV0FBNEIsU0FBa0I7QUFDbkQsUUFBTSxTQUFTLEtBQUssUUFBUSxrQ0FBVyxVQUFVO0FBQ2pELFFBQU0sV0FBVyxHQUFHLFlBQVksTUFBTSxFQUFFLElBQUksT0FBSyxTQUFTLE1BQU0sQ0FBQyxFQUFFLE9BQU8sT0FBSyxHQUFHLFVBQVUsQ0FBQyxFQUFFLFlBQVksQ0FBRTtBQUM3RyxRQUFNLE1BQU07QUFBQTtBQUFBO0FBQUEsSUFHVixNQUFNO0FBQUEsTUFDSixTQUFVLENBQUMsa0RBQWtEO0FBQUEsTUFDN0QsV0FBVztBQUFBLE1BQ1gsU0FBUztBQUFBLElBQ1g7QUFBQSxJQUNBLFNBQVM7QUFBQSxNQUNQLE9BQU8sU0FBUyxPQUFPLENBQUMsS0FBSyxRQUFRO0FBQ3JDLFlBQUksS0FBSyxNQUFNLEdBQUcsYUFBYSxNQUFNLGlCQUFpQixPQUFPLENBQUMsRUFBRSxJQUFJLElBQUksS0FBSyxRQUFRLEtBQUssSUFBSSxTQUFTLE1BQU0sSUFBSSxTQUFTLEtBQUs7QUFDL0gsZUFBTztBQUFBLE1BQ1QsR0FBRyxDQUFFLENBQUM7QUFBQTtBQUFBLElBQ1I7QUFBQSxFQUNBO0FBQ0EsVUFBUSxJQUFJLEdBQUc7QUFDZixTQUFPO0FBQ1Q7OztBRHBDQSxJQUFNQSxvQ0FBbUM7QUFJekMsSUFBTyx3QkFBUSxhQUFhLFdBQVdDLGlDQUFTLENBQUM7IiwKICAibmFtZXMiOiBbIl9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lIiwgIl9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lIl0KfQo=