@thisisagile/easy-express 15.8.5 → 15.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/express/AuthError.d.ts +7 -0
  2. package/dist/express/AuthError.js +43 -0
  3. package/dist/express/AuthError.js.map +1 -0
  4. package/dist/express/AuthError.mjs +17 -0
  5. package/dist/express/AuthError.mjs.map +1 -0
  6. package/dist/express/CorrelationHandler.d.ts +2 -0
  7. package/dist/express/CorrelationHandler.js +33 -0
  8. package/dist/express/CorrelationHandler.js.map +1 -0
  9. package/dist/express/CorrelationHandler.mjs +9 -0
  10. package/dist/express/CorrelationHandler.mjs.map +1 -0
  11. package/dist/express/ErrorHandler.d.ts +3 -0
  12. package/dist/express/ErrorHandler.js +41 -0
  13. package/dist/express/ErrorHandler.js.map +1 -0
  14. package/dist/express/ErrorHandler.mjs +33 -0
  15. package/dist/express/ErrorHandler.mjs.map +1 -0
  16. package/dist/express/ExpressProvider.d.ts +17 -0
  17. package/dist/express/ExpressProvider.js +108 -0
  18. package/dist/express/ExpressProvider.js.map +1 -0
  19. package/dist/express/ExpressProvider.mjs +83 -0
  20. package/dist/express/ExpressProvider.mjs.map +1 -0
  21. package/dist/express/NotFoundHandler.d.ts +2 -0
  22. package/dist/express/NotFoundHandler.js +32 -0
  23. package/dist/express/NotFoundHandler.js.map +1 -0
  24. package/dist/express/NotFoundHandler.mjs +8 -0
  25. package/dist/express/NotFoundHandler.mjs.map +1 -0
  26. package/dist/express/RequestContextHandler.d.ts +2 -0
  27. package/dist/express/RequestContextHandler.js +30 -0
  28. package/dist/express/RequestContextHandler.js.map +1 -0
  29. package/dist/express/RequestContextHandler.mjs +6 -0
  30. package/dist/express/RequestContextHandler.mjs.map +1 -0
  31. package/dist/express/SecurityHandler.d.ts +19 -0
  32. package/dist/express/SecurityHandler.js +73 -0
  33. package/dist/express/SecurityHandler.js.map +1 -0
  34. package/dist/express/SecurityHandler.mjs +35 -0
  35. package/dist/express/SecurityHandler.mjs.map +1 -0
  36. package/dist/express/index.d.ts +7 -0
  37. package/dist/express/index.js +35 -0
  38. package/dist/express/index.js.map +1 -0
  39. package/dist/express/index.mjs +8 -0
  40. package/dist/express/index.mjs.map +1 -0
  41. package/dist/index.d.ts +2 -59
  42. package/dist/index.js +25 -1
  43. package/dist/index.js.map +1 -0
  44. package/dist/index.mjs +3 -1
  45. package/dist/index.mjs.map +1 -0
  46. package/dist/types/NamespaceContext.d.ts +7 -0
  47. package/dist/types/NamespaceContext.js +40 -0
  48. package/dist/types/NamespaceContext.js.map +1 -0
  49. package/dist/types/NamespaceContext.mjs +16 -0
  50. package/dist/types/NamespaceContext.mjs.map +1 -0
  51. package/dist/types/index.d.ts +1 -0
  52. package/dist/types/index.js +23 -0
  53. package/dist/types/index.js.map +1 -0
  54. package/dist/types/index.mjs +2 -0
  55. package/dist/types/index.mjs.map +1 -0
  56. package/package.json +4 -4
  57. package/dist/index.d.mts +0 -59
@@ -0,0 +1,7 @@
1
+ import { HttpStatus } from '@thisisagile/easy';
2
+ export declare class AuthError extends Error {
3
+ status: number;
4
+ constructor({ name, status }: HttpStatus);
5
+ }
6
+ export declare const authError: (status: HttpStatus) => AuthError;
7
+ export declare const isAuthError: (e?: unknown) => e is AuthError;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var AuthError_exports = {};
20
+ __export(AuthError_exports, {
21
+ AuthError: () => AuthError,
22
+ authError: () => authError,
23
+ isAuthError: () => isAuthError
24
+ });
25
+ module.exports = __toCommonJS(AuthError_exports);
26
+ var import_easy = require("@thisisagile/easy");
27
+ class AuthError extends Error {
28
+ status;
29
+ constructor({ name, status }) {
30
+ super(name);
31
+ this.name = "AuthenticationError";
32
+ this.status = status;
33
+ }
34
+ }
35
+ const authError = (status) => new AuthError(status);
36
+ const isAuthError = (e) => (0, import_easy.isError)(e) && e.name === "AuthenticationError";
37
+ // Annotate the CommonJS export names for ESM import in node:
38
+ 0 && (module.exports = {
39
+ AuthError,
40
+ authError,
41
+ isAuthError
42
+ });
43
+ //# sourceMappingURL=AuthError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/AuthError.ts"],"sourcesContent":["import { HttpStatus, isError } from '@thisisagile/easy';\n\nexport class AuthError extends Error {\n status: number;\n\n constructor({ name, status }: HttpStatus) {\n super(name);\n this.name = 'AuthenticationError';\n this.status = status;\n }\n}\n\nexport const authError = (status: HttpStatus): AuthError => new AuthError(status);\n\nexport const isAuthError = (e?: unknown): e is AuthError => isError(e) && e.name === 'AuthenticationError';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAoC;AAE7B,MAAM,kBAAkB,MAAM;AAAA,EACnC;AAAA,EAEA,YAAY,EAAE,MAAM,OAAO,GAAe;AACxC,UAAM,IAAI;AACV,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AACF;AAEO,MAAM,YAAY,CAAC,WAAkC,IAAI,UAAU,MAAM;AAEzE,MAAM,cAAc,CAAC,UAAgC,qBAAQ,CAAC,KAAK,EAAE,SAAS;","names":[]}
@@ -0,0 +1,17 @@
1
+ import { isError } from "@thisisagile/easy";
2
+ class AuthError extends Error {
3
+ status;
4
+ constructor({ name, status }) {
5
+ super(name);
6
+ this.name = "AuthenticationError";
7
+ this.status = status;
8
+ }
9
+ }
10
+ const authError = (status) => new AuthError(status);
11
+ const isAuthError = (e) => isError(e) && e.name === "AuthenticationError";
12
+ export {
13
+ AuthError,
14
+ authError,
15
+ isAuthError
16
+ };
17
+ //# sourceMappingURL=AuthError.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/AuthError.ts"],"sourcesContent":["import { HttpStatus, isError } from '@thisisagile/easy';\n\nexport class AuthError extends Error {\n status: number;\n\n constructor({ name, status }: HttpStatus) {\n super(name);\n this.name = 'AuthenticationError';\n this.status = status;\n }\n}\n\nexport const authError = (status: HttpStatus): AuthError => new AuthError(status);\n\nexport const isAuthError = (e?: unknown): e is AuthError => isError(e) && e.name === 'AuthenticationError';\n"],"mappings":"AAAA,SAAqB,eAAe;AAE7B,MAAM,kBAAkB,MAAM;AAAA,EACnC;AAAA,EAEA,YAAY,EAAE,MAAM,OAAO,GAAe;AACxC,UAAM,IAAI;AACV,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AACF;AAEO,MAAM,YAAY,CAAC,WAAkC,IAAI,UAAU,MAAM;AAEzE,MAAM,cAAc,CAAC,MAAgC,QAAQ,CAAC,KAAK,EAAE,SAAS;","names":[]}
@@ -0,0 +1,2 @@
1
+ import express from 'express';
2
+ export declare const correlation: (req: express.Request, res: express.Response, next: express.NextFunction) => void;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var CorrelationHandler_exports = {};
20
+ __export(CorrelationHandler_exports, {
21
+ correlation: () => correlation
22
+ });
23
+ module.exports = __toCommonJS(CorrelationHandler_exports);
24
+ var import_easy = require("@thisisagile/easy");
25
+ const correlation = (req, res, next) => {
26
+ res.setHeader(import_easy.HttpHeader.Correlation, import_easy.ctx.request.correlationId = req?.header(import_easy.HttpHeader.Correlation) ?? (0, import_easy.toUuid)());
27
+ next();
28
+ };
29
+ // Annotate the CommonJS export names for ESM import in node:
30
+ 0 && (module.exports = {
31
+ correlation
32
+ });
33
+ //# sourceMappingURL=CorrelationHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/CorrelationHandler.ts"],"sourcesContent":["import express from 'express';\nimport { ctx, HttpHeader, toUuid } from '@thisisagile/easy';\n\nexport const correlation = (req: express.Request, res: express.Response, next: express.NextFunction): void => {\n res.setHeader(HttpHeader.Correlation, (ctx.request.correlationId = req?.header(HttpHeader.Correlation) ?? toUuid()));\n next();\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAAwC;AAEjC,MAAM,cAAc,CAAC,KAAsB,KAAuB,SAAqC;AAC5G,MAAI,UAAU,uBAAW,aAAc,gBAAI,QAAQ,gBAAgB,KAAK,OAAO,uBAAW,WAAW,SAAK,oBAAO,CAAE;AACnH,OAAK;AACP;","names":[]}
@@ -0,0 +1,9 @@
1
+ import { ctx, HttpHeader, toUuid } from "@thisisagile/easy";
2
+ const correlation = (req, res, next) => {
3
+ res.setHeader(HttpHeader.Correlation, ctx.request.correlationId = req?.header(HttpHeader.Correlation) ?? toUuid());
4
+ next();
5
+ };
6
+ export {
7
+ correlation
8
+ };
9
+ //# sourceMappingURL=CorrelationHandler.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/CorrelationHandler.ts"],"sourcesContent":["import express from 'express';\nimport { ctx, HttpHeader, toUuid } from '@thisisagile/easy';\n\nexport const correlation = (req: express.Request, res: express.Response, next: express.NextFunction): void => {\n res.setHeader(HttpHeader.Correlation, (ctx.request.correlationId = req?.header(HttpHeader.Correlation) ?? toUuid()));\n next();\n};\n"],"mappings":"AACA,SAAS,KAAK,YAAY,cAAc;AAEjC,MAAM,cAAc,CAAC,KAAsB,KAAuB,SAAqC;AAC5G,MAAI,UAAU,WAAW,aAAc,IAAI,QAAQ,gBAAgB,KAAK,OAAO,WAAW,WAAW,KAAK,OAAO,CAAE;AACnH,OAAK;AACP;","names":[]}
@@ -0,0 +1,3 @@
1
+ import express from 'express';
2
+ import { Response } from '@thisisagile/easy';
3
+ export declare const error: (e: Error, req: express.Request, res: express.Response, _next: express.NextFunction) => void;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var ErrorHandler_exports = {};
20
+ __export(ErrorHandler_exports, {
21
+ error: () => error
22
+ });
23
+ module.exports = __toCommonJS(ErrorHandler_exports);
24
+ var import_AuthError = require("./AuthError");
25
+ var import_easy = require("@thisisagile/easy");
26
+ const toResponse = (status, errors = []) => ({
27
+ status,
28
+ body: import_easy.rest.toError(status, errors)
29
+ });
30
+ const toBody = ({ origin, options }) => {
31
+ return (0, import_easy.choose)(origin).type(import_AuthError.isAuthError, (ae) => toResponse((0, import_easy.toHttpStatus)(ae.status), [(0, import_easy.toResult)(ae.message)])).type(import_easy.isDoesNotExist, (e) => toResponse(options?.onNotFound ?? import_easy.HttpStatus.NotFound, [(0, import_easy.toResult)(e.reason ?? e.message)])).type(import_easy.isError, (e) => toResponse(import_easy.HttpStatus.InternalServerError, [(0, import_easy.toResult)(e.message)])).type(import_easy.isResults, (r) => toResponse(options?.onError ?? import_easy.HttpStatus.BadRequest, r.results)).type(import_easy.isResponse, (r) => toResponse(import_easy.HttpStatus.InternalServerError, r.body.error?.errors)).type(import_easy.isException, (e) => toResponse(options?.onError ?? import_easy.HttpStatus.BadRequest, [(0, import_easy.toResult)(e.reason ?? e.message)])).type(import_easy.isText, (t) => toResponse(options?.onError ?? import_easy.HttpStatus.BadRequest, [(0, import_easy.toResult)((0, import_easy.asString)(t))])).else(() => toResponse(import_easy.HttpStatus.InternalServerError, [(0, import_easy.toResult)("Unknown error")]));
32
+ };
33
+ const error = (e, req, res, _next) => {
34
+ let response;
35
+ (0, import_easy.tryTo)(() => (0, import_easy.toOriginatedError)(e)).map((oe) => toBody(oe)).accept((r) => response = r).accept((r) => import_easy.ctx.request.lastError = r.status.isServerError ? r.body.error?.errors[0]?.message : void 0).recover(() => response).accept((r) => res.status(r.status.status).json(r.body));
36
+ };
37
+ // Annotate the CommonJS export names for ESM import in node:
38
+ 0 && (module.exports = {
39
+ error
40
+ });
41
+ //# sourceMappingURL=ErrorHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/ErrorHandler.ts"],"sourcesContent":["import express from 'express';\nimport { isAuthError } from './AuthError';\nimport {\n asString,\n choose,\n ctx,\n HttpStatus,\n isDoesNotExist,\n isError,\n isException,\n isResponse,\n isResults,\n isText,\n OriginatedError,\n Response,\n rest,\n Result,\n toHttpStatus,\n toOriginatedError,\n toResult,\n tryTo,\n} from '@thisisagile/easy';\n\nconst toResponse = (status: HttpStatus, errors: Result[] = []): Response => ({\n status,\n body: rest.toError(status, errors),\n});\n\nconst toBody = ({ origin, options }: OriginatedError): Response => {\n return (\n choose(origin)\n .type(isAuthError, ae => toResponse(toHttpStatus(ae.status), [toResult(ae.message)]))\n .type(isDoesNotExist, e => toResponse(options?.onNotFound ?? HttpStatus.NotFound, [toResult(e.reason ?? e.message)]))\n // This service breaks with an error\n .type(isError, e => toResponse(HttpStatus.InternalServerError, [toResult(e.message)]))\n // This service fails\n .type(isResults, r => toResponse(options?.onError ?? HttpStatus.BadRequest, r.results))\n // Underlying service fails\n .type(isResponse, r => toResponse(HttpStatus.InternalServerError, r.body.error?.errors))\n .type(isException, e => toResponse(options?.onError ?? HttpStatus.BadRequest, [toResult(e.reason ?? e.message)]))\n // This service fails with a string\n .type(isText, t => toResponse(options?.onError ?? HttpStatus.BadRequest, [toResult(asString(t))]))\n .else(() => toResponse(HttpStatus.InternalServerError, [toResult('Unknown error')]))\n );\n};\n\nexport const error = (e: Error, req: express.Request, res: express.Response, _next: express.NextFunction): void => {\n let response: Response;\n tryTo(() => toOriginatedError(e))\n .map(oe => toBody(oe))\n .accept(r => (response = r))\n .accept(r => (ctx.request.lastError = r.status.isServerError ? r.body.error?.errors[0]?.message : undefined))\n .recover(() => response)\n .accept(r => res.status(r.status.status).json(r.body));\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,uBAA4B;AAC5B,kBAmBO;AAEP,MAAM,aAAa,CAAC,QAAoB,SAAmB,CAAC,OAAiB;AAAA,EAC3E;AAAA,EACA,MAAM,iBAAK,QAAQ,QAAQ,MAAM;AACnC;AAEA,MAAM,SAAS,CAAC,EAAE,QAAQ,QAAQ,MAAiC;AACjE,aACE,oBAAO,MAAM,EACV,KAAK,8BAAa,QAAM,eAAW,0BAAa,GAAG,MAAM,GAAG,KAAC,sBAAS,GAAG,OAAO,CAAC,CAAC,CAAC,EACnF,KAAK,4BAAgB,OAAK,WAAW,SAAS,cAAc,uBAAW,UAAU,KAAC,sBAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,EAEnH,KAAK,qBAAS,OAAK,WAAW,uBAAW,qBAAqB,KAAC,sBAAS,EAAE,OAAO,CAAC,CAAC,CAAC,EAEpF,KAAK,uBAAW,OAAK,WAAW,SAAS,WAAW,uBAAW,YAAY,EAAE,OAAO,CAAC,EAErF,KAAK,wBAAY,OAAK,WAAW,uBAAW,qBAAqB,EAAE,KAAK,OAAO,MAAM,CAAC,EACtF,KAAK,yBAAa,OAAK,WAAW,SAAS,WAAW,uBAAW,YAAY,KAAC,sBAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,EAE/G,KAAK,oBAAQ,OAAK,WAAW,SAAS,WAAW,uBAAW,YAAY,KAAC,0BAAS,sBAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAChG,KAAK,MAAM,WAAW,uBAAW,qBAAqB,KAAC,sBAAS,eAAe,CAAC,CAAC,CAAC;AAEzF;AAEO,MAAM,QAAQ,CAAC,GAAU,KAAsB,KAAuB,UAAsC;AACjH,MAAI;AACJ,yBAAM,UAAM,+BAAkB,CAAC,CAAC,EAC7B,IAAI,QAAM,OAAO,EAAE,CAAC,EACpB,OAAO,OAAM,WAAW,CAAE,EAC1B,OAAO,OAAM,gBAAI,QAAQ,YAAY,EAAE,OAAO,gBAAgB,EAAE,KAAK,OAAO,OAAO,CAAC,GAAG,UAAU,MAAU,EAC3G,QAAQ,MAAM,QAAQ,EACtB,OAAO,OAAK,IAAI,OAAO,EAAE,OAAO,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC;AACzD;","names":[]}
@@ -0,0 +1,33 @@
1
+ import { isAuthError } from "./AuthError";
2
+ import {
3
+ asString,
4
+ choose,
5
+ ctx,
6
+ HttpStatus,
7
+ isDoesNotExist,
8
+ isError,
9
+ isException,
10
+ isResponse,
11
+ isResults,
12
+ isText,
13
+ rest,
14
+ toHttpStatus,
15
+ toOriginatedError,
16
+ toResult,
17
+ tryTo
18
+ } from "@thisisagile/easy";
19
+ const toResponse = (status, errors = []) => ({
20
+ status,
21
+ body: rest.toError(status, errors)
22
+ });
23
+ const toBody = ({ origin, options }) => {
24
+ return choose(origin).type(isAuthError, (ae) => toResponse(toHttpStatus(ae.status), [toResult(ae.message)])).type(isDoesNotExist, (e) => toResponse(options?.onNotFound ?? HttpStatus.NotFound, [toResult(e.reason ?? e.message)])).type(isError, (e) => toResponse(HttpStatus.InternalServerError, [toResult(e.message)])).type(isResults, (r) => toResponse(options?.onError ?? HttpStatus.BadRequest, r.results)).type(isResponse, (r) => toResponse(HttpStatus.InternalServerError, r.body.error?.errors)).type(isException, (e) => toResponse(options?.onError ?? HttpStatus.BadRequest, [toResult(e.reason ?? e.message)])).type(isText, (t) => toResponse(options?.onError ?? HttpStatus.BadRequest, [toResult(asString(t))])).else(() => toResponse(HttpStatus.InternalServerError, [toResult("Unknown error")]));
25
+ };
26
+ const error = (e, req, res, _next) => {
27
+ let response;
28
+ tryTo(() => toOriginatedError(e)).map((oe) => toBody(oe)).accept((r) => response = r).accept((r) => ctx.request.lastError = r.status.isServerError ? r.body.error?.errors[0]?.message : void 0).recover(() => response).accept((r) => res.status(r.status.status).json(r.body));
29
+ };
30
+ export {
31
+ error
32
+ };
33
+ //# sourceMappingURL=ErrorHandler.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/ErrorHandler.ts"],"sourcesContent":["import express from 'express';\nimport { isAuthError } from './AuthError';\nimport {\n asString,\n choose,\n ctx,\n HttpStatus,\n isDoesNotExist,\n isError,\n isException,\n isResponse,\n isResults,\n isText,\n OriginatedError,\n Response,\n rest,\n Result,\n toHttpStatus,\n toOriginatedError,\n toResult,\n tryTo,\n} from '@thisisagile/easy';\n\nconst toResponse = (status: HttpStatus, errors: Result[] = []): Response => ({\n status,\n body: rest.toError(status, errors),\n});\n\nconst toBody = ({ origin, options }: OriginatedError): Response => {\n return (\n choose(origin)\n .type(isAuthError, ae => toResponse(toHttpStatus(ae.status), [toResult(ae.message)]))\n .type(isDoesNotExist, e => toResponse(options?.onNotFound ?? HttpStatus.NotFound, [toResult(e.reason ?? e.message)]))\n // This service breaks with an error\n .type(isError, e => toResponse(HttpStatus.InternalServerError, [toResult(e.message)]))\n // This service fails\n .type(isResults, r => toResponse(options?.onError ?? HttpStatus.BadRequest, r.results))\n // Underlying service fails\n .type(isResponse, r => toResponse(HttpStatus.InternalServerError, r.body.error?.errors))\n .type(isException, e => toResponse(options?.onError ?? HttpStatus.BadRequest, [toResult(e.reason ?? e.message)]))\n // This service fails with a string\n .type(isText, t => toResponse(options?.onError ?? HttpStatus.BadRequest, [toResult(asString(t))]))\n .else(() => toResponse(HttpStatus.InternalServerError, [toResult('Unknown error')]))\n );\n};\n\nexport const error = (e: Error, req: express.Request, res: express.Response, _next: express.NextFunction): void => {\n let response: Response;\n tryTo(() => toOriginatedError(e))\n .map(oe => toBody(oe))\n .accept(r => (response = r))\n .accept(r => (ctx.request.lastError = r.status.isServerError ? r.body.error?.errors[0]?.message : undefined))\n .recover(() => response)\n .accept(r => res.status(r.status.status).json(r.body));\n};\n"],"mappings":"AACA,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAM,aAAa,CAAC,QAAoB,SAAmB,CAAC,OAAiB;AAAA,EAC3E;AAAA,EACA,MAAM,KAAK,QAAQ,QAAQ,MAAM;AACnC;AAEA,MAAM,SAAS,CAAC,EAAE,QAAQ,QAAQ,MAAiC;AACjE,SACE,OAAO,MAAM,EACV,KAAK,aAAa,QAAM,WAAW,aAAa,GAAG,MAAM,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,EACnF,KAAK,gBAAgB,OAAK,WAAW,SAAS,cAAc,WAAW,UAAU,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,EAEnH,KAAK,SAAS,OAAK,WAAW,WAAW,qBAAqB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,EAEpF,KAAK,WAAW,OAAK,WAAW,SAAS,WAAW,WAAW,YAAY,EAAE,OAAO,CAAC,EAErF,KAAK,YAAY,OAAK,WAAW,WAAW,qBAAqB,EAAE,KAAK,OAAO,MAAM,CAAC,EACtF,KAAK,aAAa,OAAK,WAAW,SAAS,WAAW,WAAW,YAAY,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,EAE/G,KAAK,QAAQ,OAAK,WAAW,SAAS,WAAW,WAAW,YAAY,CAAC,SAAS,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAChG,KAAK,MAAM,WAAW,WAAW,qBAAqB,CAAC,SAAS,eAAe,CAAC,CAAC,CAAC;AAEzF;AAEO,MAAM,QAAQ,CAAC,GAAU,KAAsB,KAAuB,UAAsC;AACjH,MAAI;AACJ,QAAM,MAAM,kBAAkB,CAAC,CAAC,EAC7B,IAAI,QAAM,OAAO,EAAE,CAAC,EACpB,OAAO,OAAM,WAAW,CAAE,EAC1B,OAAO,OAAM,IAAI,QAAQ,YAAY,EAAE,OAAO,gBAAgB,EAAE,KAAK,OAAO,OAAO,CAAC,GAAG,UAAU,MAAU,EAC3G,QAAQ,MAAM,QAAQ,EACtB,OAAO,OAAK,IAAI,OAAO,EAAE,OAAO,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC;AACzD;","names":[]}
@@ -0,0 +1,17 @@
1
+ import { Express, RequestHandler, Response } from "express";
2
+ import { AppProvider, Endpoint, Handler, Resource, RouteRequires, Service, VerbOptions } from "@thisisagile/easy";
3
+ export type ExpressVerb = "get" | "post" | "put" | "patch" | "delete";
4
+ export declare class ExpressProvider implements AppProvider {
5
+ protected app: Express;
6
+ constructor(app?: Express);
7
+ use: (handler: Handler) => void;
8
+ route: (service: Service, resource: Resource) => void;
9
+ listen: (port: number, message?: string) => void;
10
+ protected addSecurityMiddleware(requires: RouteRequires): RequestHandler[];
11
+ protected handle: (endpoint: Endpoint, options?: VerbOptions) => RequestHandler;
12
+ protected toResponse(res: Response, result: unknown, options: Required<VerbOptions>): void;
13
+ protected json(res: Response, result: unknown, options: Required<VerbOptions>): void;
14
+ protected stream(res: Response, result: unknown): void;
15
+ protected text(res: Response, data: unknown): void;
16
+ }
17
+ export declare const service: (name: string) => Service;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var ExpressProvider_exports = {};
30
+ __export(ExpressProvider_exports, {
31
+ ExpressProvider: () => ExpressProvider,
32
+ service: () => service
33
+ });
34
+ module.exports = __toCommonJS(ExpressProvider_exports);
35
+ var import_express = __toESM(require("express"));
36
+ var import_SecurityHandler = require("./SecurityHandler");
37
+ var import_easy = require("@thisisagile/easy");
38
+ class ExpressProvider {
39
+ constructor(app = (0, import_express.default)()) {
40
+ this.app = app;
41
+ this.app.set("trust proxy", ["loopback", "linklocal", "uniquelocal"]);
42
+ }
43
+ use = (handler) => {
44
+ this.app.use(handler);
45
+ };
46
+ route = (service2, resource) => {
47
+ const { route, endpoints, middleware } = (0, import_easy.routes)(resource);
48
+ const router = import_express.default.Router({ mergeParams: true });
49
+ if (!(0, import_easy.isEmpty)(middleware))
50
+ router.all(route.route(service2.name), middleware);
51
+ endpoints.forEach(({ endpoint, verb, requires, middleware: middleware2 }) => {
52
+ console.log(verb.verb.code, route.route(service2.name));
53
+ router[verb.verb.toString()](
54
+ route.route(service2.name),
55
+ ...this.addSecurityMiddleware(requires),
56
+ ...middleware2,
57
+ this.handle(endpoint, verb.options)
58
+ );
59
+ });
60
+ this.app.use(router);
61
+ };
62
+ listen = (port, message = `Service is listening on port ${port}.`) => {
63
+ this.app.listen(port, () => {
64
+ console.log(message);
65
+ });
66
+ };
67
+ addSecurityMiddleware(requires) {
68
+ const middleware = [];
69
+ if (requires.labCoat)
70
+ middleware.push((0, import_SecurityHandler.checkLabCoat)());
71
+ if (requires.token)
72
+ middleware.push((0, import_SecurityHandler.checkToken)());
73
+ if (requires.scope)
74
+ middleware.push((0, import_SecurityHandler.checkScope)(requires.scope));
75
+ if (requires.uc)
76
+ middleware.push((0, import_SecurityHandler.checkUseCase)(requires.uc));
77
+ return middleware;
78
+ }
79
+ handle = (endpoint, options) => (req, res, next) => endpoint((0, import_easy.toReq)(req)).then((r) => this.toResponse(res, r, (0, import_easy.toVerbOptions)(options))).catch((error) => next((0, import_easy.toOriginatedError)(error, options)));
80
+ toResponse(res, result, options) {
81
+ res.status(options.onOk.status);
82
+ res.type(options.type.code);
83
+ if (options.cache.enabled)
84
+ res.setHeader(options.cache.name, options.cache.value());
85
+ (this[options.type.name] ?? this.json)(res, result, options);
86
+ }
87
+ // Handling responses depending on content type
88
+ json(res, result, options) {
89
+ if (import_easy.HttpStatus.NoContent.equals(options.onOk)) {
90
+ res.send();
91
+ } else {
92
+ res.json(import_easy.rest.toData(options.onOk, (0, import_easy.toList)(result), result?.total, result?.meta));
93
+ }
94
+ }
95
+ stream(res, result) {
96
+ res.end(result);
97
+ }
98
+ text(res, data) {
99
+ res.send(data);
100
+ }
101
+ }
102
+ const service = (name) => new import_easy.Service(name, new ExpressProvider());
103
+ // Annotate the CommonJS export names for ESM import in node:
104
+ 0 && (module.exports = {
105
+ ExpressProvider,
106
+ service
107
+ });
108
+ //# sourceMappingURL=ExpressProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/ExpressProvider.ts"],"sourcesContent":["import express, { Express, NextFunction, Request, RequestHandler, Response } from \"express\";\nimport { checkLabCoat, checkScope, checkToken, checkUseCase } from \"./SecurityHandler\";\nimport {\n AppProvider,\n Endpoint,\n Handler,\n HttpStatus,\n isEmpty,\n PageList,\n Resource,\n rest,\n Route,\n RouteRequires,\n routes,\n Service,\n toList,\n toOriginatedError,\n toReq,\n toVerbOptions,\n VerbOptions\n} from \"@thisisagile/easy\";\n\nexport type ExpressVerb = \"get\" | \"post\" | \"put\" | \"patch\" | \"delete\";\n\nexport class ExpressProvider implements AppProvider {\n constructor(protected app: Express = express()) {\n this.app.set(\"trust proxy\", [\"loopback\", \"linklocal\", \"uniquelocal\"]);\n }\n\n use = (handler: Handler): void => {\n this.app.use(handler);\n };\n\n route = (service: Service, resource: Resource): void => {\n const { route, endpoints, middleware } = routes(resource);\n const router = express.Router({ mergeParams: true });\n if (!isEmpty(middleware)) router.all(route.route(service.name), middleware);\n\n endpoints.forEach(({ endpoint, verb, requires, middleware }: Route) => {\n console.log(verb.verb.code, route.route(service.name));\n router[verb.verb.toString() as ExpressVerb](\n route.route(service.name),\n ...this.addSecurityMiddleware(requires),\n ...middleware,\n this.handle(endpoint, verb.options)\n );\n });\n\n this.app.use(router);\n };\n\n listen = (port: number, message = `Service is listening on port ${port}.`): void => {\n this.app.listen(port, () => {\n console.log(message);\n });\n };\n\n protected addSecurityMiddleware(requires: RouteRequires): RequestHandler[] {\n const middleware: RequestHandler[] = [];\n if (requires.labCoat) middleware.push(checkLabCoat());\n if (requires.token) middleware.push(checkToken());\n if (requires.scope) middleware.push(checkScope(requires.scope));\n if (requires.uc) middleware.push(checkUseCase(requires.uc));\n return middleware;\n }\n\n protected handle =\n (endpoint: Endpoint, options?: VerbOptions): RequestHandler =>\n (req: Request, res: Response, next: NextFunction) =>\n endpoint(toReq(req))\n .then((r: any) => this.toResponse(res, r, toVerbOptions(options)))\n .catch(error => next(toOriginatedError(error, options)));\n\n protected toResponse(res: Response, result: unknown, options: Required<VerbOptions>): void {\n res.status(options.onOk.status);\n res.type(options.type.code);\n if (options.cache.enabled) res.setHeader(options.cache.name, options.cache.value());\n\n ((this as any)[options.type.name] ?? this.json)(res, result, options);\n }\n\n // Handling responses depending on content type\n\n protected json(res: Response, result: unknown, options: Required<VerbOptions>): void {\n if (HttpStatus.NoContent.equals(options.onOk)) {\n res.send();\n } else {\n res.json(rest.toData(options.onOk, toList<any>(result), (result as PageList<any>)?.total, (result as PageList<any>)?.meta));\n }\n }\n\n protected stream(res: Response, result: unknown): void {\n res.end(result);\n }\n\n protected text(res: Response, data: unknown): void {\n res.send(data);\n }\n}\n\nexport const service = (name: string): Service => new Service(name, new ExpressProvider());\n"],"mappings":"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","names":["express","service","middleware"]}
@@ -0,0 +1,83 @@
1
+ import express from "express";
2
+ import { checkLabCoat, checkScope, checkToken, checkUseCase } from "./SecurityHandler";
3
+ import {
4
+ HttpStatus,
5
+ isEmpty,
6
+ rest,
7
+ routes,
8
+ Service,
9
+ toList,
10
+ toOriginatedError,
11
+ toReq,
12
+ toVerbOptions
13
+ } from "@thisisagile/easy";
14
+ class ExpressProvider {
15
+ constructor(app = express()) {
16
+ this.app = app;
17
+ this.app.set("trust proxy", ["loopback", "linklocal", "uniquelocal"]);
18
+ }
19
+ use = (handler) => {
20
+ this.app.use(handler);
21
+ };
22
+ route = (service2, resource) => {
23
+ const { route, endpoints, middleware } = routes(resource);
24
+ const router = express.Router({ mergeParams: true });
25
+ if (!isEmpty(middleware))
26
+ router.all(route.route(service2.name), middleware);
27
+ endpoints.forEach(({ endpoint, verb, requires, middleware: middleware2 }) => {
28
+ console.log(verb.verb.code, route.route(service2.name));
29
+ router[verb.verb.toString()](
30
+ route.route(service2.name),
31
+ ...this.addSecurityMiddleware(requires),
32
+ ...middleware2,
33
+ this.handle(endpoint, verb.options)
34
+ );
35
+ });
36
+ this.app.use(router);
37
+ };
38
+ listen = (port, message = `Service is listening on port ${port}.`) => {
39
+ this.app.listen(port, () => {
40
+ console.log(message);
41
+ });
42
+ };
43
+ addSecurityMiddleware(requires) {
44
+ const middleware = [];
45
+ if (requires.labCoat)
46
+ middleware.push(checkLabCoat());
47
+ if (requires.token)
48
+ middleware.push(checkToken());
49
+ if (requires.scope)
50
+ middleware.push(checkScope(requires.scope));
51
+ if (requires.uc)
52
+ middleware.push(checkUseCase(requires.uc));
53
+ return middleware;
54
+ }
55
+ handle = (endpoint, options) => (req, res, next) => endpoint(toReq(req)).then((r) => this.toResponse(res, r, toVerbOptions(options))).catch((error) => next(toOriginatedError(error, options)));
56
+ toResponse(res, result, options) {
57
+ res.status(options.onOk.status);
58
+ res.type(options.type.code);
59
+ if (options.cache.enabled)
60
+ res.setHeader(options.cache.name, options.cache.value());
61
+ (this[options.type.name] ?? this.json)(res, result, options);
62
+ }
63
+ // Handling responses depending on content type
64
+ json(res, result, options) {
65
+ if (HttpStatus.NoContent.equals(options.onOk)) {
66
+ res.send();
67
+ } else {
68
+ res.json(rest.toData(options.onOk, toList(result), result?.total, result?.meta));
69
+ }
70
+ }
71
+ stream(res, result) {
72
+ res.end(result);
73
+ }
74
+ text(res, data) {
75
+ res.send(data);
76
+ }
77
+ }
78
+ const service = (name) => new Service(name, new ExpressProvider());
79
+ export {
80
+ ExpressProvider,
81
+ service
82
+ };
83
+ //# sourceMappingURL=ExpressProvider.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/ExpressProvider.ts"],"sourcesContent":["import express, { Express, NextFunction, Request, RequestHandler, Response } from \"express\";\nimport { checkLabCoat, checkScope, checkToken, checkUseCase } from \"./SecurityHandler\";\nimport {\n AppProvider,\n Endpoint,\n Handler,\n HttpStatus,\n isEmpty,\n PageList,\n Resource,\n rest,\n Route,\n RouteRequires,\n routes,\n Service,\n toList,\n toOriginatedError,\n toReq,\n toVerbOptions,\n VerbOptions\n} from \"@thisisagile/easy\";\n\nexport type ExpressVerb = \"get\" | \"post\" | \"put\" | \"patch\" | \"delete\";\n\nexport class ExpressProvider implements AppProvider {\n constructor(protected app: Express = express()) {\n this.app.set(\"trust proxy\", [\"loopback\", \"linklocal\", \"uniquelocal\"]);\n }\n\n use = (handler: Handler): void => {\n this.app.use(handler);\n };\n\n route = (service: Service, resource: Resource): void => {\n const { route, endpoints, middleware } = routes(resource);\n const router = express.Router({ mergeParams: true });\n if (!isEmpty(middleware)) router.all(route.route(service.name), middleware);\n\n endpoints.forEach(({ endpoint, verb, requires, middleware }: Route) => {\n console.log(verb.verb.code, route.route(service.name));\n router[verb.verb.toString() as ExpressVerb](\n route.route(service.name),\n ...this.addSecurityMiddleware(requires),\n ...middleware,\n this.handle(endpoint, verb.options)\n );\n });\n\n this.app.use(router);\n };\n\n listen = (port: number, message = `Service is listening on port ${port}.`): void => {\n this.app.listen(port, () => {\n console.log(message);\n });\n };\n\n protected addSecurityMiddleware(requires: RouteRequires): RequestHandler[] {\n const middleware: RequestHandler[] = [];\n if (requires.labCoat) middleware.push(checkLabCoat());\n if (requires.token) middleware.push(checkToken());\n if (requires.scope) middleware.push(checkScope(requires.scope));\n if (requires.uc) middleware.push(checkUseCase(requires.uc));\n return middleware;\n }\n\n protected handle =\n (endpoint: Endpoint, options?: VerbOptions): RequestHandler =>\n (req: Request, res: Response, next: NextFunction) =>\n endpoint(toReq(req))\n .then((r: any) => this.toResponse(res, r, toVerbOptions(options)))\n .catch(error => next(toOriginatedError(error, options)));\n\n protected toResponse(res: Response, result: unknown, options: Required<VerbOptions>): void {\n res.status(options.onOk.status);\n res.type(options.type.code);\n if (options.cache.enabled) res.setHeader(options.cache.name, options.cache.value());\n\n ((this as any)[options.type.name] ?? this.json)(res, result, options);\n }\n\n // Handling responses depending on content type\n\n protected json(res: Response, result: unknown, options: Required<VerbOptions>): void {\n if (HttpStatus.NoContent.equals(options.onOk)) {\n res.send();\n } else {\n res.json(rest.toData(options.onOk, toList<any>(result), (result as PageList<any>)?.total, (result as PageList<any>)?.meta));\n }\n }\n\n protected stream(res: Response, result: unknown): void {\n res.end(result);\n }\n\n protected text(res: Response, data: unknown): void {\n res.send(data);\n }\n}\n\nexport const service = (name: string): Service => new Service(name, new ExpressProvider());\n"],"mappings":"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","names":["service","middleware"]}
@@ -0,0 +1,2 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ export declare const notFound: (req: Request, res: Response, next: NextFunction) => void;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var NotFoundHandler_exports = {};
20
+ __export(NotFoundHandler_exports, {
21
+ notFound: () => notFound
22
+ });
23
+ module.exports = __toCommonJS(NotFoundHandler_exports);
24
+ var import_easy = require("@thisisagile/easy");
25
+ const notFound = (req, res, next) => {
26
+ next((0, import_easy.toOriginatedError)(import_easy.Exception.DoesNotExist));
27
+ };
28
+ // Annotate the CommonJS export names for ESM import in node:
29
+ 0 && (module.exports = {
30
+ notFound
31
+ });
32
+ //# sourceMappingURL=NotFoundHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/NotFoundHandler.ts"],"sourcesContent":["import { NextFunction, Request, Response } from 'express';\nimport { Exception, toOriginatedError } from '@thisisagile/easy';\n\nexport const notFound = (req: Request, res: Response, next: NextFunction): void => {\n next(toOriginatedError(Exception.DoesNotExist));\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAA6C;AAEtC,MAAM,WAAW,CAAC,KAAc,KAAe,SAA6B;AACjF,WAAK,+BAAkB,sBAAU,YAAY,CAAC;AAChD;","names":[]}
@@ -0,0 +1,8 @@
1
+ import { Exception, toOriginatedError } from "@thisisagile/easy";
2
+ const notFound = (req, res, next) => {
3
+ next(toOriginatedError(Exception.DoesNotExist));
4
+ };
5
+ export {
6
+ notFound
7
+ };
8
+ //# sourceMappingURL=NotFoundHandler.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/NotFoundHandler.ts"],"sourcesContent":["import { NextFunction, Request, Response } from 'express';\nimport { Exception, toOriginatedError } from '@thisisagile/easy';\n\nexport const notFound = (req: Request, res: Response, next: NextFunction): void => {\n next(toOriginatedError(Exception.DoesNotExist));\n};\n"],"mappings":"AACA,SAAS,WAAW,yBAAyB;AAEtC,MAAM,WAAW,CAAC,KAAc,KAAe,SAA6B;AACjF,OAAK,kBAAkB,UAAU,YAAY,CAAC;AAChD;","names":[]}
@@ -0,0 +1,2 @@
1
+ import express from 'express';
2
+ export declare const requestContext: (req: express.Request, res: express.Response, next: express.NextFunction) => void;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var RequestContextHandler_exports = {};
20
+ __export(RequestContextHandler_exports, {
21
+ requestContext: () => requestContext
22
+ });
23
+ module.exports = __toCommonJS(RequestContextHandler_exports);
24
+ var import_easy = require("@thisisagile/easy");
25
+ const requestContext = (req, res, next) => import_easy.ctx.request.create(() => next());
26
+ // Annotate the CommonJS export names for ESM import in node:
27
+ 0 && (module.exports = {
28
+ requestContext
29
+ });
30
+ //# sourceMappingURL=RequestContextHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/RequestContextHandler.ts"],"sourcesContent":["import express from 'express';\nimport { ctx } from '@thisisagile/easy';\n\nexport const requestContext = (req: express.Request, res: express.Response, next: express.NextFunction): void => ctx.request.create(() => next());\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAAoB;AAEb,MAAM,iBAAiB,CAAC,KAAsB,KAAuB,SAAqC,gBAAI,QAAQ,OAAO,MAAM,KAAK,CAAC;","names":[]}
@@ -0,0 +1,6 @@
1
+ import { ctx } from "@thisisagile/easy";
2
+ const requestContext = (req, res, next) => ctx.request.create(() => next());
3
+ export {
4
+ requestContext
5
+ };
6
+ //# sourceMappingURL=RequestContextHandler.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/RequestContextHandler.ts"],"sourcesContent":["import express from 'express';\nimport { ctx } from '@thisisagile/easy';\n\nexport const requestContext = (req: express.Request, res: express.Response, next: express.NextFunction): void => ctx.request.create(() => next());\n"],"mappings":"AACA,SAAS,WAAW;AAEb,MAAM,iBAAiB,CAAC,KAAsB,KAAuB,SAAqC,IAAI,QAAQ,OAAO,MAAM,KAAK,CAAC;","names":[]}
@@ -0,0 +1,19 @@
1
+ /// <reference types="node" />
2
+ import express, { Request, RequestHandler } from 'express';
3
+ import { Scope, UseCase } from '@thisisagile/easy';
4
+ type SecretOrKeyProvider = (request: Request, rawJwtToken: any) => Promise<string | Buffer>;
5
+ export interface SecurityOptions {
6
+ jwtStrategyOptions?: {
7
+ secretOrKey?: string | Buffer;
8
+ secretOrKeyProvider?: SecretOrKeyProvider;
9
+ issuer?: string;
10
+ audience?: string;
11
+ algorithms?: string[];
12
+ };
13
+ }
14
+ export declare const checkLabCoat: () => RequestHandler;
15
+ export declare const checkToken: () => RequestHandler;
16
+ export declare const checkScope: (scope: Scope) => RequestHandler;
17
+ export declare const checkUseCase: (uc: UseCase) => RequestHandler;
18
+ export declare const security: ({ jwtStrategyOptions }?: SecurityOptions) => (req: express.Request, res: express.Response, next: express.NextFunction) => void;
19
+ export {};
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var SecurityHandler_exports = {};
30
+ __export(SecurityHandler_exports, {
31
+ checkLabCoat: () => checkLabCoat,
32
+ checkScope: () => checkScope,
33
+ checkToken: () => checkToken,
34
+ checkUseCase: () => checkUseCase,
35
+ security: () => security
36
+ });
37
+ module.exports = __toCommonJS(SecurityHandler_exports);
38
+ var import_passport = __toESM(require("passport"));
39
+ var import_passport_jwt = require("passport-jwt");
40
+ var import_AuthError = require("./AuthError");
41
+ var import_easy = require("@thisisagile/easy");
42
+ const checkLabCoat = () => (req, res, next) => next((0, import_easy.ifFalse)(import_easy.Environment.Dev.equals(import_easy.ctx.env.name), (0, import_AuthError.authError)(import_easy.HttpStatus.Forbidden)));
43
+ const checkToken = () => import_passport.default.authenticate("jwt", { session: false, failWithError: true });
44
+ const checkScope = (scope) => (req, res, next) => next((0, import_easy.ifFalse)(req.user?.scopes?.includes(scope.id), (0, import_AuthError.authError)(import_easy.HttpStatus.Forbidden)));
45
+ const checkUseCase = (uc) => (req, res, next) => next((0, import_easy.ifFalse)(req.user?.usecases?.includes(uc.id), (0, import_AuthError.authError)(import_easy.HttpStatus.Forbidden)));
46
+ const wrapSecretOrKeyProvider = (p) => p ? (request, rawJwtToken, done) => p(request, rawJwtToken).then((t) => done(null, t)).catch((e) => done(e)) : void 0;
47
+ const security = ({ jwtStrategyOptions } = {}) => {
48
+ const jwtConfig = {
49
+ jwtFromRequest: import_passport_jwt.ExtractJwt.fromAuthHeaderAsBearerToken(),
50
+ secretOrKey: jwtStrategyOptions?.secretOrKey ?? (jwtStrategyOptions?.secretOrKeyProvider ? void 0 : import_easy.ctx.env.get("tokenPublicKey")),
51
+ secretOrKeyProvider: wrapSecretOrKeyProvider(jwtStrategyOptions?.secretOrKeyProvider),
52
+ issuer: jwtStrategyOptions?.issuer,
53
+ audience: jwtStrategyOptions?.audience,
54
+ algorithms: jwtStrategyOptions?.algorithms,
55
+ passReqToCallback: true
56
+ };
57
+ const strategy = new import_passport_jwt.Strategy(jwtConfig, (req, payload, done) => {
58
+ import_easy.ctx.request.token = payload;
59
+ import_easy.ctx.request.jwt = import_passport_jwt.ExtractJwt.fromAuthHeaderAsBearerToken()(req) ?? "";
60
+ done(null, payload);
61
+ });
62
+ import_passport.default.use(strategy);
63
+ return import_passport.default.initialize();
64
+ };
65
+ // Annotate the CommonJS export names for ESM import in node:
66
+ 0 && (module.exports = {
67
+ checkLabCoat,
68
+ checkScope,
69
+ checkToken,
70
+ checkUseCase,
71
+ security
72
+ });
73
+ //# sourceMappingURL=SecurityHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/SecurityHandler.ts"],"sourcesContent":["import express, { Request, RequestHandler } from 'express';\nimport passport from 'passport';\nimport passportJwt, { ExtractJwt, Strategy as JwtStrategy, StrategyOptions } from 'passport-jwt';\nimport { authError } from './AuthError';\nimport { ctx, Environment, HttpStatus, ifFalse, Scope, UseCase } from '@thisisagile/easy';\n\ntype SecretOrKeyProvider = (request: Request, rawJwtToken: any) => Promise<string | Buffer>;\n\nexport interface SecurityOptions {\n /** Configuration for verifying JWTs */\n jwtStrategyOptions?: {\n /** The secret (symmetric) or PEM-encoded public key (asymmetric) for verifying the token's signature.\n * REQUIRED unless secretOrKeyProvider is provided. Defaults to JWT_PUBLIC_KEY from the system environment. */\n secretOrKey?: string | Buffer;\n\n /** Should return a secret (symmetric) or PEM-encoded public key (asymmetric) for the given key and request combination.\n * REQUIRED unless secretOrKey is provided. Note it is up to the implementer to decode rawJwtToken. */\n secretOrKeyProvider?: SecretOrKeyProvider;\n\n /** If defined, the token issuer (iss) will be verified against this value. */\n issuer?: string;\n\n /** If defined, the token audience (aud) will be verified against this value. */\n audience?: string;\n\n /** If defined, the token algorithm (alg) must be in this list. */\n algorithms?: string[];\n };\n}\n\nexport const checkLabCoat = (): RequestHandler => (req, res, next) => next(ifFalse(Environment.Dev.equals(ctx.env.name), authError(HttpStatus.Forbidden)));\n\nexport const checkToken = (): RequestHandler => passport.authenticate('jwt', { session: false, failWithError: true });\n\nexport const checkScope =\n (scope: Scope): RequestHandler =>\n (req, res, next) =>\n next(ifFalse((req.user as any)?.scopes?.includes(scope.id), authError(HttpStatus.Forbidden)));\n\nexport const checkUseCase =\n (uc: UseCase): RequestHandler =>\n (req, res, next) =>\n next(ifFalse((req.user as any)?.usecases?.includes(uc.id), authError(HttpStatus.Forbidden)));\n\nconst wrapSecretOrKeyProvider = (p?: SecretOrKeyProvider): passportJwt.SecretOrKeyProvider | undefined =>\n p\n ? (request, rawJwtToken, done) =>\n p(request, rawJwtToken)\n .then(t => done(null, t))\n .catch(e => done(e))\n : undefined;\n\nexport const security = ({ jwtStrategyOptions }: SecurityOptions = {}): ((req: express.Request, res: express.Response, next: express.NextFunction) => void) => {\n const jwtConfig: StrategyOptions = {\n jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n secretOrKey: jwtStrategyOptions?.secretOrKey ?? (jwtStrategyOptions?.secretOrKeyProvider ? undefined : ctx.env.get('tokenPublicKey')),\n secretOrKeyProvider: wrapSecretOrKeyProvider(jwtStrategyOptions?.secretOrKeyProvider),\n issuer: jwtStrategyOptions?.issuer,\n audience: jwtStrategyOptions?.audience,\n algorithms: jwtStrategyOptions?.algorithms,\n passReqToCallback: true,\n };\n\n const strategy = new JwtStrategy(jwtConfig, (req: express.Request, payload: any, done: (err: any, user: any) => void) => {\n ctx.request.token = payload;\n ctx.request.jwt = ExtractJwt.fromAuthHeaderAsBearerToken()(req) ?? '';\n done(null, payload);\n });\n\n passport.use(strategy);\n return passport.initialize();\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,sBAAqB;AACrB,0BAAkF;AAClF,uBAA0B;AAC1B,kBAAsE;AA0B/D,MAAM,eAAe,MAAsB,CAAC,KAAK,KAAK,SAAS,SAAK,qBAAQ,wBAAY,IAAI,OAAO,gBAAI,IAAI,IAAI,OAAG,4BAAU,uBAAW,SAAS,CAAC,CAAC;AAElJ,MAAM,aAAa,MAAsB,gBAAAA,QAAS,aAAa,OAAO,EAAE,SAAS,OAAO,eAAe,KAAK,CAAC;AAE7G,MAAM,aACX,CAAC,UACD,CAAC,KAAK,KAAK,SACT,SAAK,qBAAS,IAAI,MAAc,QAAQ,SAAS,MAAM,EAAE,OAAG,4BAAU,uBAAW,SAAS,CAAC,CAAC;AAEzF,MAAM,eACX,CAAC,OACD,CAAC,KAAK,KAAK,SACT,SAAK,qBAAS,IAAI,MAAc,UAAU,SAAS,GAAG,EAAE,OAAG,4BAAU,uBAAW,SAAS,CAAC,CAAC;AAE/F,MAAM,0BAA0B,CAAC,MAC/B,IACI,CAAC,SAAS,aAAa,SACrB,EAAE,SAAS,WAAW,EACnB,KAAK,OAAK,KAAK,MAAM,CAAC,CAAC,EACvB,MAAM,OAAK,KAAK,CAAC,CAAC,IACvB;AAEC,MAAM,WAAW,CAAC,EAAE,mBAAmB,IAAqB,CAAC,MAA2F;AAC7J,QAAM,YAA6B;AAAA,IACjC,gBAAgB,+BAAW,4BAA4B;AAAA,IACvD,aAAa,oBAAoB,gBAAgB,oBAAoB,sBAAsB,SAAY,gBAAI,IAAI,IAAI,gBAAgB;AAAA,IACnI,qBAAqB,wBAAwB,oBAAoB,mBAAmB;AAAA,IACpF,QAAQ,oBAAoB;AAAA,IAC5B,UAAU,oBAAoB;AAAA,IAC9B,YAAY,oBAAoB;AAAA,IAChC,mBAAmB;AAAA,EACrB;AAEA,QAAM,WAAW,IAAI,oBAAAC,SAAY,WAAW,CAAC,KAAsB,SAAc,SAAwC;AACvH,oBAAI,QAAQ,QAAQ;AACpB,oBAAI,QAAQ,MAAM,+BAAW,4BAA4B,EAAE,GAAG,KAAK;AACnE,SAAK,MAAM,OAAO;AAAA,EACpB,CAAC;AAED,kBAAAD,QAAS,IAAI,QAAQ;AACrB,SAAO,gBAAAA,QAAS,WAAW;AAC7B;","names":["passport","JwtStrategy"]}
@@ -0,0 +1,35 @@
1
+ import passport from "passport";
2
+ import { ExtractJwt, Strategy as JwtStrategy } from "passport-jwt";
3
+ import { authError } from "./AuthError";
4
+ import { ctx, Environment, HttpStatus, ifFalse } from "@thisisagile/easy";
5
+ const checkLabCoat = () => (req, res, next) => next(ifFalse(Environment.Dev.equals(ctx.env.name), authError(HttpStatus.Forbidden)));
6
+ const checkToken = () => passport.authenticate("jwt", { session: false, failWithError: true });
7
+ const checkScope = (scope) => (req, res, next) => next(ifFalse(req.user?.scopes?.includes(scope.id), authError(HttpStatus.Forbidden)));
8
+ const checkUseCase = (uc) => (req, res, next) => next(ifFalse(req.user?.usecases?.includes(uc.id), authError(HttpStatus.Forbidden)));
9
+ const wrapSecretOrKeyProvider = (p) => p ? (request, rawJwtToken, done) => p(request, rawJwtToken).then((t) => done(null, t)).catch((e) => done(e)) : void 0;
10
+ const security = ({ jwtStrategyOptions } = {}) => {
11
+ const jwtConfig = {
12
+ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
13
+ secretOrKey: jwtStrategyOptions?.secretOrKey ?? (jwtStrategyOptions?.secretOrKeyProvider ? void 0 : ctx.env.get("tokenPublicKey")),
14
+ secretOrKeyProvider: wrapSecretOrKeyProvider(jwtStrategyOptions?.secretOrKeyProvider),
15
+ issuer: jwtStrategyOptions?.issuer,
16
+ audience: jwtStrategyOptions?.audience,
17
+ algorithms: jwtStrategyOptions?.algorithms,
18
+ passReqToCallback: true
19
+ };
20
+ const strategy = new JwtStrategy(jwtConfig, (req, payload, done) => {
21
+ ctx.request.token = payload;
22
+ ctx.request.jwt = ExtractJwt.fromAuthHeaderAsBearerToken()(req) ?? "";
23
+ done(null, payload);
24
+ });
25
+ passport.use(strategy);
26
+ return passport.initialize();
27
+ };
28
+ export {
29
+ checkLabCoat,
30
+ checkScope,
31
+ checkToken,
32
+ checkUseCase,
33
+ security
34
+ };
35
+ //# sourceMappingURL=SecurityHandler.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/SecurityHandler.ts"],"sourcesContent":["import express, { Request, RequestHandler } from 'express';\nimport passport from 'passport';\nimport passportJwt, { ExtractJwt, Strategy as JwtStrategy, StrategyOptions } from 'passport-jwt';\nimport { authError } from './AuthError';\nimport { ctx, Environment, HttpStatus, ifFalse, Scope, UseCase } from '@thisisagile/easy';\n\ntype SecretOrKeyProvider = (request: Request, rawJwtToken: any) => Promise<string | Buffer>;\n\nexport interface SecurityOptions {\n /** Configuration for verifying JWTs */\n jwtStrategyOptions?: {\n /** The secret (symmetric) or PEM-encoded public key (asymmetric) for verifying the token's signature.\n * REQUIRED unless secretOrKeyProvider is provided. Defaults to JWT_PUBLIC_KEY from the system environment. */\n secretOrKey?: string | Buffer;\n\n /** Should return a secret (symmetric) or PEM-encoded public key (asymmetric) for the given key and request combination.\n * REQUIRED unless secretOrKey is provided. Note it is up to the implementer to decode rawJwtToken. */\n secretOrKeyProvider?: SecretOrKeyProvider;\n\n /** If defined, the token issuer (iss) will be verified against this value. */\n issuer?: string;\n\n /** If defined, the token audience (aud) will be verified against this value. */\n audience?: string;\n\n /** If defined, the token algorithm (alg) must be in this list. */\n algorithms?: string[];\n };\n}\n\nexport const checkLabCoat = (): RequestHandler => (req, res, next) => next(ifFalse(Environment.Dev.equals(ctx.env.name), authError(HttpStatus.Forbidden)));\n\nexport const checkToken = (): RequestHandler => passport.authenticate('jwt', { session: false, failWithError: true });\n\nexport const checkScope =\n (scope: Scope): RequestHandler =>\n (req, res, next) =>\n next(ifFalse((req.user as any)?.scopes?.includes(scope.id), authError(HttpStatus.Forbidden)));\n\nexport const checkUseCase =\n (uc: UseCase): RequestHandler =>\n (req, res, next) =>\n next(ifFalse((req.user as any)?.usecases?.includes(uc.id), authError(HttpStatus.Forbidden)));\n\nconst wrapSecretOrKeyProvider = (p?: SecretOrKeyProvider): passportJwt.SecretOrKeyProvider | undefined =>\n p\n ? (request, rawJwtToken, done) =>\n p(request, rawJwtToken)\n .then(t => done(null, t))\n .catch(e => done(e))\n : undefined;\n\nexport const security = ({ jwtStrategyOptions }: SecurityOptions = {}): ((req: express.Request, res: express.Response, next: express.NextFunction) => void) => {\n const jwtConfig: StrategyOptions = {\n jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n secretOrKey: jwtStrategyOptions?.secretOrKey ?? (jwtStrategyOptions?.secretOrKeyProvider ? undefined : ctx.env.get('tokenPublicKey')),\n secretOrKeyProvider: wrapSecretOrKeyProvider(jwtStrategyOptions?.secretOrKeyProvider),\n issuer: jwtStrategyOptions?.issuer,\n audience: jwtStrategyOptions?.audience,\n algorithms: jwtStrategyOptions?.algorithms,\n passReqToCallback: true,\n };\n\n const strategy = new JwtStrategy(jwtConfig, (req: express.Request, payload: any, done: (err: any, user: any) => void) => {\n ctx.request.token = payload;\n ctx.request.jwt = ExtractJwt.fromAuthHeaderAsBearerToken()(req) ?? '';\n done(null, payload);\n });\n\n passport.use(strategy);\n return passport.initialize();\n};\n"],"mappings":"AACA,OAAO,cAAc;AACrB,SAAsB,YAAY,YAAY,mBAAoC;AAClF,SAAS,iBAAiB;AAC1B,SAAS,KAAK,aAAa,YAAY,eAA+B;AA0B/D,MAAM,eAAe,MAAsB,CAAC,KAAK,KAAK,SAAS,KAAK,QAAQ,YAAY,IAAI,OAAO,IAAI,IAAI,IAAI,GAAG,UAAU,WAAW,SAAS,CAAC,CAAC;AAElJ,MAAM,aAAa,MAAsB,SAAS,aAAa,OAAO,EAAE,SAAS,OAAO,eAAe,KAAK,CAAC;AAE7G,MAAM,aACX,CAAC,UACD,CAAC,KAAK,KAAK,SACT,KAAK,QAAS,IAAI,MAAc,QAAQ,SAAS,MAAM,EAAE,GAAG,UAAU,WAAW,SAAS,CAAC,CAAC;AAEzF,MAAM,eACX,CAAC,OACD,CAAC,KAAK,KAAK,SACT,KAAK,QAAS,IAAI,MAAc,UAAU,SAAS,GAAG,EAAE,GAAG,UAAU,WAAW,SAAS,CAAC,CAAC;AAE/F,MAAM,0BAA0B,CAAC,MAC/B,IACI,CAAC,SAAS,aAAa,SACrB,EAAE,SAAS,WAAW,EACnB,KAAK,OAAK,KAAK,MAAM,CAAC,CAAC,EACvB,MAAM,OAAK,KAAK,CAAC,CAAC,IACvB;AAEC,MAAM,WAAW,CAAC,EAAE,mBAAmB,IAAqB,CAAC,MAA2F;AAC7J,QAAM,YAA6B;AAAA,IACjC,gBAAgB,WAAW,4BAA4B;AAAA,IACvD,aAAa,oBAAoB,gBAAgB,oBAAoB,sBAAsB,SAAY,IAAI,IAAI,IAAI,gBAAgB;AAAA,IACnI,qBAAqB,wBAAwB,oBAAoB,mBAAmB;AAAA,IACpF,QAAQ,oBAAoB;AAAA,IAC5B,UAAU,oBAAoB;AAAA,IAC9B,YAAY,oBAAoB;AAAA,IAChC,mBAAmB;AAAA,EACrB;AAEA,QAAM,WAAW,IAAI,YAAY,WAAW,CAAC,KAAsB,SAAc,SAAwC;AACvH,QAAI,QAAQ,QAAQ;AACpB,QAAI,QAAQ,MAAM,WAAW,4BAA4B,EAAE,GAAG,KAAK;AACnE,SAAK,MAAM,OAAO;AAAA,EACpB,CAAC;AAED,WAAS,IAAI,QAAQ;AACrB,SAAO,SAAS,WAAW;AAC7B;","names":[]}
@@ -0,0 +1,7 @@
1
+ export * from './AuthError';
2
+ export * from './CorrelationHandler';
3
+ export * from './ErrorHandler';
4
+ export * from './ExpressProvider';
5
+ export * from './NotFoundHandler';
6
+ export * from './RequestContextHandler';
7
+ export * from './SecurityHandler';
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
15
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
+ var express_exports = {};
17
+ module.exports = __toCommonJS(express_exports);
18
+ __reExport(express_exports, require("./AuthError"), module.exports);
19
+ __reExport(express_exports, require("./CorrelationHandler"), module.exports);
20
+ __reExport(express_exports, require("./ErrorHandler"), module.exports);
21
+ __reExport(express_exports, require("./ExpressProvider"), module.exports);
22
+ __reExport(express_exports, require("./NotFoundHandler"), module.exports);
23
+ __reExport(express_exports, require("./RequestContextHandler"), module.exports);
24
+ __reExport(express_exports, require("./SecurityHandler"), module.exports);
25
+ // Annotate the CommonJS export names for ESM import in node:
26
+ 0 && (module.exports = {
27
+ ...require("./AuthError"),
28
+ ...require("./CorrelationHandler"),
29
+ ...require("./ErrorHandler"),
30
+ ...require("./ExpressProvider"),
31
+ ...require("./NotFoundHandler"),
32
+ ...require("./RequestContextHandler"),
33
+ ...require("./SecurityHandler")
34
+ });
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/index.ts"],"sourcesContent":["export * from './AuthError';\nexport * from './CorrelationHandler';\nexport * from './ErrorHandler';\nexport * from './ExpressProvider';\nexport * from './NotFoundHandler';\nexport * from './RequestContextHandler';\nexport * from './SecurityHandler';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,4BAAc,wBAAd;AACA,4BAAc,iCADd;AAEA,4BAAc,2BAFd;AAGA,4BAAc,8BAHd;AAIA,4BAAc,8BAJd;AAKA,4BAAc,oCALd;AAMA,4BAAc,8BANd;","names":[]}
@@ -0,0 +1,8 @@
1
+ export * from "./AuthError";
2
+ export * from "./CorrelationHandler";
3
+ export * from "./ErrorHandler";
4
+ export * from "./ExpressProvider";
5
+ export * from "./NotFoundHandler";
6
+ export * from "./RequestContextHandler";
7
+ export * from "./SecurityHandler";
8
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/express/index.ts"],"sourcesContent":["export * from './AuthError';\nexport * from './CorrelationHandler';\nexport * from './ErrorHandler';\nexport * from './ExpressProvider';\nexport * from './NotFoundHandler';\nexport * from './RequestContextHandler';\nexport * from './SecurityHandler';\n"],"mappings":"AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,59 +1,2 @@
1
- import { HttpStatus, AppProvider, Handler, Service, Resource, RouteRequires, Endpoint, VerbOptions, Scope, UseCase, BaseRequestContext } from '@thisisagile/easy';
2
- import express, { Express, RequestHandler, Response, Request, NextFunction } from 'express';
3
- import * as cls_hooked from 'cls-hooked';
4
-
5
- declare class AuthError extends Error {
6
- status: number;
7
- constructor({ name, status }: HttpStatus);
8
- }
9
- declare const authError: (status: HttpStatus) => AuthError;
10
- declare const isAuthError: (e?: unknown) => e is AuthError;
11
-
12
- declare const correlation: (req: express.Request, res: express.Response, next: express.NextFunction) => void;
13
-
14
- declare const error: (e: Error, req: express.Request, res: express.Response, _next: express.NextFunction) => void;
15
-
16
- type ExpressVerb = "get" | "post" | "put" | "patch" | "delete";
17
- declare class ExpressProvider implements AppProvider {
18
- protected app: Express;
19
- constructor(app?: Express);
20
- use: (handler: Handler) => void;
21
- route: (service: Service, resource: Resource) => void;
22
- listen: (port: number, message?: string) => void;
23
- protected addSecurityMiddleware(requires: RouteRequires): RequestHandler[];
24
- protected handle: (endpoint: Endpoint, options?: VerbOptions) => RequestHandler;
25
- protected toResponse(res: Response, result: unknown, options: Required<VerbOptions>): void;
26
- protected json(res: Response, result: unknown, options: Required<VerbOptions>): void;
27
- protected stream(res: Response, result: unknown): void;
28
- protected text(res: Response, data: unknown): void;
29
- }
30
- declare const service: (name: string) => Service;
31
-
32
- declare const notFound: (req: Request, res: Response, next: NextFunction) => void;
33
-
34
- declare const requestContext: (req: express.Request, res: express.Response, next: express.NextFunction) => void;
35
-
36
- type SecretOrKeyProvider = (request: Request, rawJwtToken: any) => Promise<string | Buffer>;
37
- interface SecurityOptions {
38
- jwtStrategyOptions?: {
39
- secretOrKey?: string | Buffer;
40
- secretOrKeyProvider?: SecretOrKeyProvider;
41
- issuer?: string;
42
- audience?: string;
43
- algorithms?: string[];
44
- };
45
- }
46
- declare const checkLabCoat: () => RequestHandler;
47
- declare const checkToken: () => RequestHandler;
48
- declare const checkScope: (scope: Scope) => RequestHandler;
49
- declare const checkUseCase: (uc: UseCase) => RequestHandler;
50
- declare const security: ({ jwtStrategyOptions }?: SecurityOptions) => (req: express.Request, res: express.Response, next: express.NextFunction) => void;
51
-
52
- declare class NamespaceContext extends BaseRequestContext {
53
- protected readonly namespace: cls_hooked.Namespace<Record<string, any>>;
54
- get<T>(key: string): T;
55
- set<T>(key: string, value: T): T;
56
- readonly create: (f: () => void) => void;
57
- }
58
-
59
- export { AuthError, ExpressProvider, ExpressVerb, NamespaceContext, SecurityOptions, authError, checkLabCoat, checkScope, checkToken, checkUseCase, correlation, error, isAuthError, notFound, requestContext, security, service };
1
+ export * from './express';
2
+ export * from './types';
package/dist/index.js CHANGED
@@ -1 +1,25 @@
1
- "use strict";var B=Object.create;var x=Object.defineProperty;var V=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var U=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var j=(t,e)=>{for(var r in e)x(t,r,{get:e[r],enumerable:!0})},O=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of L(e))!J.call(t,n)&&n!==r&&x(t,n,{get:()=>e[n],enumerable:!(o=V(e,n))||o.enumerable});return t};var w=(t,e,r)=>(r=t!=null?B(U(t)):{},O(e||!t||!t.__esModule?x(r,"default",{value:t,enumerable:!0}):r,t)),D=t=>O(x({},"__esModule",{value:!0}),t);var X={};j(X,{AuthError:()=>R,ExpressProvider:()=>h,NamespaceContext:()=>H,authError:()=>m,checkLabCoat:()=>v,checkScope:()=>S,checkToken:()=>g,checkUseCase:()=>k,correlation:()=>I,error:()=>z,isAuthError:()=>E,notFound:()=>G,requestContext:()=>Q,security:()=>_,service:()=>$});module.exports=D(X);var F=require("@thisisagile/easy"),R=class extends Error{status;constructor({name:e,status:r}){super(e),this.name="AuthenticationError",this.status=r}},m=t=>new R(t),E=t=>(0,F.isError)(t)&&t.name==="AuthenticationError";var d=require("@thisisagile/easy"),I=(t,e,r)=>{e.setHeader(d.HttpHeader.Correlation,d.ctx.request.correlationId=t?.header(d.HttpHeader.Correlation)??(0,d.toUuid)()),r()};var s=require("@thisisagile/easy"),u=(t,e=[])=>({status:t,body:s.rest.toError(t,e)}),M=({origin:t,options:e})=>(0,s.choose)(t).type(E,r=>u((0,s.toHttpStatus)(r.status),[(0,s.toResult)(r.message)])).type(s.isDoesNotExist,r=>u(e?.onNotFound??s.HttpStatus.NotFound,[(0,s.toResult)(r.reason??r.message)])).type(s.isError,r=>u(s.HttpStatus.InternalServerError,[(0,s.toResult)(r.message)])).type(s.isResults,r=>u(e?.onError??s.HttpStatus.BadRequest,r.results)).type(s.isResponse,r=>u(s.HttpStatus.InternalServerError,r.body.error?.errors)).type(s.isException,r=>u(e?.onError??s.HttpStatus.BadRequest,[(0,s.toResult)(r.reason??r.message)])).type(s.isText,r=>u(e?.onError??s.HttpStatus.BadRequest,[(0,s.toResult)((0,s.asString)(r))])).else(()=>u(s.HttpStatus.InternalServerError,[(0,s.toResult)("Unknown error")])),z=(t,e,r,o)=>{let n;(0,s.tryTo)(()=>(0,s.toOriginatedError)(t)).map(i=>M(i)).accept(i=>n=i).accept(i=>s.ctx.request.lastError=i.status.isServerError?i.body.error?.errors[0]?.message:void 0).recover(()=>n).accept(i=>r.status(i.status.status).json(i.body))};var b=w(require("express"));var f=w(require("passport")),l=require("passport-jwt");var p=require("@thisisagile/easy"),v=()=>(t,e,r)=>r((0,p.ifFalse)(p.Environment.Dev.equals(p.ctx.env.name),m(p.HttpStatus.Forbidden))),g=()=>f.default.authenticate("jwt",{session:!1,failWithError:!0}),S=t=>(e,r,o)=>o((0,p.ifFalse)(e.user?.scopes?.includes(t.id),m(p.HttpStatus.Forbidden))),k=t=>(e,r,o)=>o((0,p.ifFalse)(e.user?.usecases?.includes(t.id),m(p.HttpStatus.Forbidden))),W=t=>t?(e,r,o)=>t(e,r).then(n=>o(null,n)).catch(n=>o(n)):void 0,_=({jwtStrategyOptions:t}={})=>{let e={jwtFromRequest:l.ExtractJwt.fromAuthHeaderAsBearerToken(),secretOrKey:t?.secretOrKey??(t?.secretOrKeyProvider?void 0:p.ctx.env.get("tokenPublicKey")),secretOrKeyProvider:W(t?.secretOrKeyProvider),issuer:t?.issuer,audience:t?.audience,algorithms:t?.algorithms,passReqToCallback:!0},r=new l.Strategy(e,(o,n,i)=>{p.ctx.request.token=n,p.ctx.request.jwt=l.ExtractJwt.fromAuthHeaderAsBearerToken()(o)??"",i(null,n)});return f.default.use(r),f.default.initialize()};var a=require("@thisisagile/easy"),h=class{constructor(e=(0,b.default)()){this.app=e;this.app.set("trust proxy",["loopback","linklocal","uniquelocal"])}use=e=>{this.app.use(e)};route=(e,r)=>{let{route:o,endpoints:n,middleware:i}=(0,a.routes)(r),c=b.default.Router({mergeParams:!0});(0,a.isEmpty)(i)||c.all(o.route(e.name),i),n.forEach(({endpoint:K,verb:q,requires:N,middleware:A})=>{console.log(q.verb.code,o.route(e.name)),c[q.verb.toString()](o.route(e.name),...this.addSecurityMiddleware(N),...A,this.handle(K,q.options))}),this.app.use(c)};listen=(e,r=`Service is listening on port ${e}.`)=>{this.app.listen(e,()=>{console.log(r)})};addSecurityMiddleware(e){let r=[];return e.labCoat&&r.push(v()),e.token&&r.push(g()),e.scope&&r.push(S(e.scope)),e.uc&&r.push(k(e.uc)),r}handle=(e,r)=>(o,n,i)=>e((0,a.toReq)(o)).then(c=>this.toResponse(n,c,(0,a.toVerbOptions)(r))).catch(c=>i((0,a.toOriginatedError)(c,r)));toResponse(e,r,o){e.status(o.onOk.status),e.type(o.type.code),o.cache.enabled&&e.setHeader(o.cache.name,o.cache.value()),(this[o.type.name]??this.json)(e,r,o)}json(e,r,o){a.HttpStatus.NoContent.equals(o.onOk)?e.send():e.json(a.rest.toData(o.onOk,(0,a.toList)(r),r?.total,r?.meta))}stream(e,r){e.end(r)}text(e,r){e.send(r)}},$=t=>new a.Service(t,new h);var y=require("@thisisagile/easy"),G=(t,e,r)=>{r((0,y.toOriginatedError)(y.Exception.DoesNotExist))};var P=require("@thisisagile/easy"),Q=(t,e,r)=>P.ctx.request.create(()=>r());var T=require("cls-hooked"),C=require("@thisisagile/easy"),H=class extends C.BaseRequestContext{namespace=(0,T.createNamespace)("context");get(e){return this.namespace.get(e)}set(e,r){return this.namespace.set(e,r)}create=e=>this.namespace.run(e)};0&&(module.exports={AuthError,ExpressProvider,NamespaceContext,authError,checkLabCoat,checkScope,checkToken,checkUseCase,correlation,error,isAuthError,notFound,requestContext,security,service});
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
15
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
+ var src_exports = {};
17
+ module.exports = __toCommonJS(src_exports);
18
+ __reExport(src_exports, require("./express"), module.exports);
19
+ __reExport(src_exports, require("./types"), module.exports);
20
+ // Annotate the CommonJS export names for ESM import in node:
21
+ 0 && (module.exports = {
22
+ ...require("./express"),
23
+ ...require("./types")
24
+ });
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './express';\nexport * from './types';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,wBAAc,sBAAd;AACA,wBAAc,oBADd;","names":[]}
package/dist/index.mjs CHANGED
@@ -1 +1,3 @@
1
- import{isError as P}from"@thisisagile/easy";var l=class extends Error{status;constructor({name:e,status:r}){super(e),this.name="AuthenticationError",this.status=r}},c=t=>new l(t),y=t=>P(t)&&t.name==="AuthenticationError";import{ctx as T,HttpHeader as q,toUuid as C}from"@thisisagile/easy";var xe=(t,e,r)=>{e.setHeader(q.Correlation,T.request.correlationId=t?.header(q.Correlation)??C()),r()};import{asString as K,choose as N,ctx as A,HttpStatus as p,isDoesNotExist as B,isError as V,isException as L,isResponse as U,isResults as J,isText as j,rest as D,toHttpStatus as I,toOriginatedError as M,toResult as u,tryTo as z}from"@thisisagile/easy";var a=(t,e=[])=>({status:t,body:D.toError(t,e)}),W=({origin:t,options:e})=>N(t).type(y,r=>a(I(r.status),[u(r.message)])).type(B,r=>a(e?.onNotFound??p.NotFound,[u(r.reason??r.message)])).type(V,r=>a(p.InternalServerError,[u(r.message)])).type(J,r=>a(e?.onError??p.BadRequest,r.results)).type(U,r=>a(p.InternalServerError,r.body.error?.errors)).type(L,r=>a(e?.onError??p.BadRequest,[u(r.reason??r.message)])).type(j,r=>a(e?.onError??p.BadRequest,[u(K(r))])).else(()=>a(p.InternalServerError,[u("Unknown error")])),ve=(t,e,r,s)=>{let n;z(()=>M(t)).map(o=>W(o)).accept(o=>n=o).accept(o=>A.request.lastError=o.status.isServerError?o.body.error?.errors[0]?.message:void 0).recover(()=>n).accept(o=>r.status(o.status.status).json(o.body))};import b from"express";import x from"passport";import{ExtractJwt as E,Strategy as _}from"passport-jwt";import{ctx as d,Environment as $,HttpStatus as R,ifFalse as f}from"@thisisagile/easy";var v=()=>(t,e,r)=>r(f($.Dev.equals(d.env.name),c(R.Forbidden))),g=()=>x.authenticate("jwt",{session:!1,failWithError:!0}),S=t=>(e,r,s)=>s(f(e.user?.scopes?.includes(t.id),c(R.Forbidden))),k=t=>(e,r,s)=>s(f(e.user?.usecases?.includes(t.id),c(R.Forbidden))),G=t=>t?(e,r,s)=>t(e,r).then(n=>s(null,n)).catch(n=>s(n)):void 0,Te=({jwtStrategyOptions:t}={})=>{let e={jwtFromRequest:E.fromAuthHeaderAsBearerToken(),secretOrKey:t?.secretOrKey??(t?.secretOrKeyProvider?void 0:d.env.get("tokenPublicKey")),secretOrKeyProvider:G(t?.secretOrKeyProvider),issuer:t?.issuer,audience:t?.audience,algorithms:t?.algorithms,passReqToCallback:!0},r=new _(e,(s,n,o)=>{d.request.token=n,d.request.jwt=E.fromAuthHeaderAsBearerToken()(s)??"",o(null,n)});return x.use(r),x.initialize()};import{HttpStatus as Q,isEmpty as X,rest as Y,routes as Z,Service as ee,toList as re,toOriginatedError as te,toReq as se,toVerbOptions as oe}from"@thisisagile/easy";var h=class{constructor(e=b()){this.app=e;this.app.set("trust proxy",["loopback","linklocal","uniquelocal"])}use=e=>{this.app.use(e)};route=(e,r)=>{let{route:s,endpoints:n,middleware:o}=Z(r),i=b.Router({mergeParams:!0});X(o)||i.all(s.route(e.name),o),n.forEach(({endpoint:O,verb:m,requires:w,middleware:F})=>{console.log(m.verb.code,s.route(e.name)),i[m.verb.toString()](s.route(e.name),...this.addSecurityMiddleware(w),...F,this.handle(O,m.options))}),this.app.use(i)};listen=(e,r=`Service is listening on port ${e}.`)=>{this.app.listen(e,()=>{console.log(r)})};addSecurityMiddleware(e){let r=[];return e.labCoat&&r.push(v()),e.token&&r.push(g()),e.scope&&r.push(S(e.scope)),e.uc&&r.push(k(e.uc)),r}handle=(e,r)=>(s,n,o)=>e(se(s)).then(i=>this.toResponse(n,i,oe(r))).catch(i=>o(te(i,r)));toResponse(e,r,s){e.status(s.onOk.status),e.type(s.type.code),s.cache.enabled&&e.setHeader(s.cache.name,s.cache.value()),(this[s.type.name]??this.json)(e,r,s)}json(e,r,s){Q.NoContent.equals(s.onOk)?e.send():e.json(Y.toData(s.onOk,re(r),r?.total,r?.meta))}stream(e,r){e.end(r)}text(e,r){e.send(r)}},Ge=t=>new ee(t,new h);import{Exception as ne,toOriginatedError as ae}from"@thisisagile/easy";var Ye=(t,e,r)=>{r(ae(ne.DoesNotExist))};import{ctx as ie}from"@thisisagile/easy";var rr=(t,e,r)=>ie.request.create(()=>r());import{createNamespace as pe}from"cls-hooked";import{BaseRequestContext as ue}from"@thisisagile/easy";var H=class extends ue{namespace=pe("context");get(e){return this.namespace.get(e)}set(e,r){return this.namespace.set(e,r)}create=e=>this.namespace.run(e)};export{l as AuthError,h as ExpressProvider,H as NamespaceContext,c as authError,v as checkLabCoat,S as checkScope,g as checkToken,k as checkUseCase,xe as correlation,ve as error,y as isAuthError,Ye as notFound,rr as requestContext,Te as security,Ge as service};
1
+ export * from "./express";
2
+ export * from "./types";
3
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './express';\nexport * from './types';\n"],"mappings":"AAAA,cAAc;AACd,cAAc;","names":[]}
@@ -0,0 +1,7 @@
1
+ import { BaseRequestContext } from '@thisisagile/easy';
2
+ export declare class NamespaceContext extends BaseRequestContext {
3
+ protected readonly namespace: import("cls-hooked").Namespace<Record<string, any>>;
4
+ get<T>(key: string): T;
5
+ set<T>(key: string, value: T): T;
6
+ readonly create: (f: () => void) => void;
7
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var NamespaceContext_exports = {};
20
+ __export(NamespaceContext_exports, {
21
+ NamespaceContext: () => NamespaceContext
22
+ });
23
+ module.exports = __toCommonJS(NamespaceContext_exports);
24
+ var import_cls_hooked = require("cls-hooked");
25
+ var import_easy = require("@thisisagile/easy");
26
+ class NamespaceContext extends import_easy.BaseRequestContext {
27
+ namespace = (0, import_cls_hooked.createNamespace)("context");
28
+ get(key) {
29
+ return this.namespace.get(key);
30
+ }
31
+ set(key, value) {
32
+ return this.namespace.set(key, value);
33
+ }
34
+ create = (f) => this.namespace.run(f);
35
+ }
36
+ // Annotate the CommonJS export names for ESM import in node:
37
+ 0 && (module.exports = {
38
+ NamespaceContext
39
+ });
40
+ //# sourceMappingURL=NamespaceContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types/NamespaceContext.ts"],"sourcesContent":["import { createNamespace } from 'cls-hooked';\nimport { BaseRequestContext } from '@thisisagile/easy';\n\nexport class NamespaceContext extends BaseRequestContext {\n protected readonly namespace = createNamespace('context');\n\n public get<T>(key: string): T {\n return this.namespace.get(key) as T;\n }\n\n public set<T>(key: string, value: T): T {\n return this.namespace.set(key, value);\n }\n\n public readonly create = (f: () => void): void => this.namespace.run(f);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAgC;AAChC,kBAAmC;AAE5B,MAAM,yBAAyB,+BAAmB;AAAA,EACpC,gBAAY,mCAAgB,SAAS;AAAA,EAEjD,IAAO,KAAgB;AAC5B,WAAO,KAAK,UAAU,IAAI,GAAG;AAAA,EAC/B;AAAA,EAEO,IAAO,KAAa,OAAa;AACtC,WAAO,KAAK,UAAU,IAAI,KAAK,KAAK;AAAA,EACtC;AAAA,EAEgB,SAAS,CAAC,MAAwB,KAAK,UAAU,IAAI,CAAC;AACxE;","names":[]}
@@ -0,0 +1,16 @@
1
+ import { createNamespace } from "cls-hooked";
2
+ import { BaseRequestContext } from "@thisisagile/easy";
3
+ class NamespaceContext extends BaseRequestContext {
4
+ namespace = createNamespace("context");
5
+ get(key) {
6
+ return this.namespace.get(key);
7
+ }
8
+ set(key, value) {
9
+ return this.namespace.set(key, value);
10
+ }
11
+ create = (f) => this.namespace.run(f);
12
+ }
13
+ export {
14
+ NamespaceContext
15
+ };
16
+ //# sourceMappingURL=NamespaceContext.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types/NamespaceContext.ts"],"sourcesContent":["import { createNamespace } from 'cls-hooked';\nimport { BaseRequestContext } from '@thisisagile/easy';\n\nexport class NamespaceContext extends BaseRequestContext {\n protected readonly namespace = createNamespace('context');\n\n public get<T>(key: string): T {\n return this.namespace.get(key) as T;\n }\n\n public set<T>(key: string, value: T): T {\n return this.namespace.set(key, value);\n }\n\n public readonly create = (f: () => void): void => this.namespace.run(f);\n}\n"],"mappings":"AAAA,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AAE5B,MAAM,yBAAyB,mBAAmB;AAAA,EACpC,YAAY,gBAAgB,SAAS;AAAA,EAEjD,IAAO,KAAgB;AAC5B,WAAO,KAAK,UAAU,IAAI,GAAG;AAAA,EAC/B;AAAA,EAEO,IAAO,KAAa,OAAa;AACtC,WAAO,KAAK,UAAU,IAAI,KAAK,KAAK;AAAA,EACtC;AAAA,EAEgB,SAAS,CAAC,MAAwB,KAAK,UAAU,IAAI,CAAC;AACxE;","names":[]}
@@ -0,0 +1 @@
1
+ export * from './NamespaceContext';
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
15
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
+ var types_exports = {};
17
+ module.exports = __toCommonJS(types_exports);
18
+ __reExport(types_exports, require("./NamespaceContext"), module.exports);
19
+ // Annotate the CommonJS export names for ESM import in node:
20
+ 0 && (module.exports = {
21
+ ...require("./NamespaceContext")
22
+ });
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types/index.ts"],"sourcesContent":["export * from './NamespaceContext';\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,+BAAd;","names":[]}
@@ -0,0 +1,2 @@
1
+ export * from "./NamespaceContext";
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types/index.ts"],"sourcesContent":["export * from './NamespaceContext';\n"],"mappings":"AAAA,cAAc;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thisisagile/easy-express",
3
- "version": "15.8.5",
3
+ "version": "15.8.7",
4
4
  "description": "Straightforward library for building domain-driven microservice architectures",
5
5
  "author": "Sander Hoogendoorn",
6
6
  "license": "MIT",
@@ -21,7 +21,7 @@
21
21
  "lint": "yarn g:eslint . --ext .js,.jsx,.ts,.tsx --fix",
22
22
  "format": "yarn g:prettier --check --write src test *.json",
23
23
  "build": "yarn g:tsc",
24
- "build:tsup": "yarn g:tsup",
24
+ "build:tsup": "yarn g:tsup --onSuccess \"yarn g:tsc --emitDeclarationOnly --declaration\"",
25
25
  "test": "yarn g:jest --coverage",
26
26
  "prepack": "yarn g:copy-readme"
27
27
  },
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "devDependencies": {
36
- "@thisisagile/easy-test": "15.8.5",
36
+ "@thisisagile/easy-test": "15.8.7",
37
37
  "@types/cls-hooked": "^4.3.4",
38
38
  "@types/form-urlencoded": "^4.4.0",
39
39
  "@types/jsonwebtoken": "^9.0.2",
@@ -43,7 +43,7 @@
43
43
  "@types/validator": "^13.7.17"
44
44
  },
45
45
  "dependencies": {
46
- "@thisisagile/easy": "^15.8.5",
46
+ "@thisisagile/easy": "^15.8.7",
47
47
  "@types/express": "^4.17.17",
48
48
  "cls-hooked": "^4.2.2",
49
49
  "express": "^4.18.2",
package/dist/index.d.mts DELETED
@@ -1,59 +0,0 @@
1
- import { HttpStatus, AppProvider, Handler, Service, Resource, RouteRequires, Endpoint, VerbOptions, Scope, UseCase, BaseRequestContext } from '@thisisagile/easy';
2
- import express, { Express, RequestHandler, Response, Request, NextFunction } from 'express';
3
- import * as cls_hooked from 'cls-hooked';
4
-
5
- declare class AuthError extends Error {
6
- status: number;
7
- constructor({ name, status }: HttpStatus);
8
- }
9
- declare const authError: (status: HttpStatus) => AuthError;
10
- declare const isAuthError: (e?: unknown) => e is AuthError;
11
-
12
- declare const correlation: (req: express.Request, res: express.Response, next: express.NextFunction) => void;
13
-
14
- declare const error: (e: Error, req: express.Request, res: express.Response, _next: express.NextFunction) => void;
15
-
16
- type ExpressVerb = "get" | "post" | "put" | "patch" | "delete";
17
- declare class ExpressProvider implements AppProvider {
18
- protected app: Express;
19
- constructor(app?: Express);
20
- use: (handler: Handler) => void;
21
- route: (service: Service, resource: Resource) => void;
22
- listen: (port: number, message?: string) => void;
23
- protected addSecurityMiddleware(requires: RouteRequires): RequestHandler[];
24
- protected handle: (endpoint: Endpoint, options?: VerbOptions) => RequestHandler;
25
- protected toResponse(res: Response, result: unknown, options: Required<VerbOptions>): void;
26
- protected json(res: Response, result: unknown, options: Required<VerbOptions>): void;
27
- protected stream(res: Response, result: unknown): void;
28
- protected text(res: Response, data: unknown): void;
29
- }
30
- declare const service: (name: string) => Service;
31
-
32
- declare const notFound: (req: Request, res: Response, next: NextFunction) => void;
33
-
34
- declare const requestContext: (req: express.Request, res: express.Response, next: express.NextFunction) => void;
35
-
36
- type SecretOrKeyProvider = (request: Request, rawJwtToken: any) => Promise<string | Buffer>;
37
- interface SecurityOptions {
38
- jwtStrategyOptions?: {
39
- secretOrKey?: string | Buffer;
40
- secretOrKeyProvider?: SecretOrKeyProvider;
41
- issuer?: string;
42
- audience?: string;
43
- algorithms?: string[];
44
- };
45
- }
46
- declare const checkLabCoat: () => RequestHandler;
47
- declare const checkToken: () => RequestHandler;
48
- declare const checkScope: (scope: Scope) => RequestHandler;
49
- declare const checkUseCase: (uc: UseCase) => RequestHandler;
50
- declare const security: ({ jwtStrategyOptions }?: SecurityOptions) => (req: express.Request, res: express.Response, next: express.NextFunction) => void;
51
-
52
- declare class NamespaceContext extends BaseRequestContext {
53
- protected readonly namespace: cls_hooked.Namespace<Record<string, any>>;
54
- get<T>(key: string): T;
55
- set<T>(key: string, value: T): T;
56
- readonly create: (f: () => void) => void;
57
- }
58
-
59
- export { AuthError, ExpressProvider, ExpressVerb, NamespaceContext, SecurityOptions, authError, checkLabCoat, checkScope, checkToken, checkUseCase, correlation, error, isAuthError, notFound, requestContext, security, service };