@thisisagile/easy-service 17.0.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.
Files changed (56) hide show
  1. package/README.md +282 -0
  2. package/dist/chunk-2XMYNSTI.mjs +11 -0
  3. package/dist/chunk-2XMYNSTI.mjs.map +1 -0
  4. package/dist/chunk-4N72FQFX.mjs +16 -0
  5. package/dist/chunk-4N72FQFX.mjs.map +1 -0
  6. package/dist/chunk-FYPLZQRO.mjs +39 -0
  7. package/dist/chunk-FYPLZQRO.mjs.map +1 -0
  8. package/dist/chunk-W62PBGRF.mjs +31 -0
  9. package/dist/chunk-W62PBGRF.mjs.map +1 -0
  10. package/dist/health/HealthResource.d.ts +5 -0
  11. package/dist/health/HealthResource.mjs +28 -0
  12. package/dist/health/HealthResource.mjs.map +1 -0
  13. package/dist/health/HealthUri.d.ts +5 -0
  14. package/dist/health/HealthUri.mjs +8 -0
  15. package/dist/health/HealthUri.mjs.map +1 -0
  16. package/dist/http/OriginatedError.d.ts +9 -0
  17. package/dist/http/OriginatedError.mjs +21 -0
  18. package/dist/http/OriginatedError.mjs.map +1 -0
  19. package/dist/http/Verb.d.ts +20 -0
  20. package/dist/http/Verb.mjs +22 -0
  21. package/dist/http/Verb.mjs.map +1 -0
  22. package/dist/index.d.ts +10 -0
  23. package/dist/index.js +225 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/index.mjs +11 -0
  26. package/dist/index.mjs.map +1 -0
  27. package/dist/resources/AppProvider.d.ts +9 -0
  28. package/dist/resources/AppProvider.mjs +1 -0
  29. package/dist/resources/AppProvider.mjs.map +1 -0
  30. package/dist/resources/Requires.d.ts +8 -0
  31. package/dist/resources/Requires.mjs +26 -0
  32. package/dist/resources/Requires.mjs.map +1 -0
  33. package/dist/resources/Resource.d.ts +1 -0
  34. package/dist/resources/Resource.mjs +1 -0
  35. package/dist/resources/Resource.mjs.map +1 -0
  36. package/dist/resources/Route.d.ts +24 -0
  37. package/dist/resources/Route.mjs +10 -0
  38. package/dist/resources/Route.mjs.map +1 -0
  39. package/dist/resources/Service.d.ts +15 -0
  40. package/dist/resources/Service.mjs +28 -0
  41. package/dist/resources/Service.mjs.map +1 -0
  42. package/dist/security/Jwt.d.ts +13 -0
  43. package/dist/security/Jwt.mjs +23 -0
  44. package/dist/security/Jwt.mjs.map +1 -0
  45. package/package.json +44 -0
  46. package/src/health/HealthResource.ts +11 -0
  47. package/src/health/HealthUri.ts +6 -0
  48. package/src/http/OriginatedError.ts +17 -0
  49. package/src/http/Verb.ts +32 -0
  50. package/src/index.ts +10 -0
  51. package/src/resources/AppProvider.ts +11 -0
  52. package/src/resources/Requires.ts +32 -0
  53. package/src/resources/Resource.ts +1 -0
  54. package/src/resources/Route.ts +53 -0
  55. package/src/resources/Service.ts +34 -0
  56. package/src/security/Jwt.ts +32 -0
package/dist/index.js ADDED
@@ -0,0 +1,225 @@
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 __decorateClass = (decorators, target, key, kind) => {
20
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
21
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
22
+ if (decorator = decorators[i])
23
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
24
+ if (kind && result)
25
+ __defProp(target, key, result);
26
+ return result;
27
+ };
28
+
29
+ // src/index.ts
30
+ var src_exports = {};
31
+ __export(src_exports, {
32
+ HealthResource: () => HealthResource,
33
+ HealthUri: () => HealthUri,
34
+ Jwt: () => Jwt,
35
+ OriginatedError: () => OriginatedError,
36
+ Requires: () => Requires,
37
+ Service: () => Service,
38
+ del: () => del,
39
+ get: () => get,
40
+ isOriginatedError: () => isOriginatedError,
41
+ patch: () => patch,
42
+ post: () => post,
43
+ put: () => put,
44
+ requires: () => requires,
45
+ route: () => route,
46
+ routes: () => routes,
47
+ search: () => search,
48
+ stream: () => stream,
49
+ toOriginatedError: () => toOriginatedError,
50
+ toVerbOptions: () => toVerbOptions
51
+ });
52
+ module.exports = __toCommonJS(src_exports);
53
+
54
+ // src/health/HealthResource.ts
55
+ var import_easy4 = require("@thisisagile/easy");
56
+
57
+ // src/health/HealthUri.ts
58
+ var import_easy = require("@thisisagile/easy");
59
+ var HealthUri = class _HealthUri extends import_easy.EasyUri {
60
+ static health = import_easy.uri.segment("health");
61
+ static Health = new _HealthUri([_HealthUri.health]);
62
+ };
63
+
64
+ // src/resources/Route.ts
65
+ var import_easy2 = require("@thisisagile/easy");
66
+ var route = (uri2) => (subject) => {
67
+ (0, import_easy2.meta)(subject).set("route", uri2);
68
+ };
69
+ var toRoute = (endpoint, requires2, verb, middleware) => (0, import_easy2.tryTo)(verb).is.defined().map((verb2) => ({ verb: verb2, endpoint, requires: requires2, middleware: middleware ?? [] })).orElse();
70
+ var Router = class {
71
+ constructor(resource) {
72
+ this.resource = resource;
73
+ }
74
+ get route() {
75
+ return (0, import_easy2.meta)(this.resource).get("route");
76
+ }
77
+ get middleware() {
78
+ return (0, import_easy2.meta)(this.resource).get("middleware") ?? [];
79
+ }
80
+ get endpoints() {
81
+ return (0, import_easy2.meta)(this.resource).properties("verb").mapDefined(
82
+ (v) => toRoute(
83
+ this.resource[v.property],
84
+ {
85
+ labCoat: v.get("labCoat") ?? false,
86
+ token: v.get("token") ?? false,
87
+ scope: v.get("scope"),
88
+ uc: v.get("uc")
89
+ },
90
+ v.get("verb"),
91
+ v.get("middleware")
92
+ )
93
+ );
94
+ }
95
+ };
96
+ var routes = (resource) => new Router(resource);
97
+
98
+ // src/http/Verb.ts
99
+ var import_easy3 = require("@thisisagile/easy");
100
+ var toVerbOptions = (options) => ({
101
+ onOk: options?.onOk ?? import_easy3.HttpStatus.Ok,
102
+ onNotFound: options?.onNotFound ?? import_easy3.HttpStatus.NotFound,
103
+ onError: options?.onError ?? import_easy3.HttpStatus.BadRequest,
104
+ type: options?.type ?? import_easy3.ContentType.Json,
105
+ cache: options?.cache ?? import_easy3.CacheControl.disabled()
106
+ });
107
+ var toVerb = (verb, options) => (subject, property) => {
108
+ (0, import_easy3.meta)(subject).property(property).set("verb", { verb, options });
109
+ };
110
+ var get = (options) => toVerb(import_easy3.HttpVerb.Get, options);
111
+ var search = (options) => toVerb(import_easy3.HttpVerb.Get, { onNotFound: import_easy3.HttpStatus.Ok, ...options });
112
+ var put = (options) => toVerb(import_easy3.HttpVerb.Put, options);
113
+ var patch = (options) => toVerb(import_easy3.HttpVerb.Patch, options);
114
+ var post = (options) => toVerb(import_easy3.HttpVerb.Post, { onOk: import_easy3.HttpStatus.Created, ...options });
115
+ var del = (options) => toVerb(import_easy3.HttpVerb.Delete, { onOk: import_easy3.HttpStatus.NoContent, ...options });
116
+ var stream = (options) => toVerb(import_easy3.HttpVerb.Get, { type: import_easy3.ContentType.Stream, ...options });
117
+
118
+ // src/health/HealthResource.ts
119
+ var HealthResource = class {
120
+ ok = () => (0, import_easy4.resolve)({ state: "Service is healthy." });
121
+ };
122
+ __decorateClass([
123
+ get()
124
+ ], HealthResource.prototype, "ok", 2);
125
+ HealthResource = __decorateClass([
126
+ route(HealthUri.Health)
127
+ ], HealthResource);
128
+
129
+ // src/http/OriginatedError.ts
130
+ var import_easy5 = require("@thisisagile/easy");
131
+ var OriginatedError = class extends Error {
132
+ constructor(origin, options) {
133
+ super();
134
+ this.origin = origin;
135
+ this.options = options;
136
+ if ((0, import_easy5.isError)(origin))
137
+ this.stack = origin.stack;
138
+ }
139
+ };
140
+ var isOriginatedError = (e) => (0, import_easy5.isError)(e) && e instanceof OriginatedError;
141
+ var toOriginatedError = (e, options) => isOriginatedError(e) ? e : new OriginatedError(e, options);
142
+
143
+ // src/resources/Requires.ts
144
+ var import_easy6 = require("@thisisagile/easy");
145
+ var Requires = class {
146
+ labCoat = () => (subject, property) => {
147
+ (0, import_easy6.meta)(subject).property(property).set("labCoat", true);
148
+ };
149
+ token = () => (subject, property) => {
150
+ (0, import_easy6.meta)(subject).property(property).set("token", true);
151
+ };
152
+ scope = (scope) => (subject, property) => {
153
+ (0, import_easy6.meta)(subject).property(property).set("token", true);
154
+ (0, import_easy6.meta)(subject).property(property).set("scope", scope);
155
+ };
156
+ useCase = (uc) => (subject, property) => {
157
+ (0, import_easy6.meta)(subject).property(property).set("token", true);
158
+ (0, import_easy6.meta)(subject).property(property).set("uc", uc);
159
+ };
160
+ };
161
+ var requires = new Requires();
162
+
163
+ // src/resources/Service.ts
164
+ var import_easy7 = require("@thisisagile/easy");
165
+ var Service = class extends import_easy7.Enum {
166
+ constructor(name, app, resources = (0, import_easy7.toList)()) {
167
+ super(name);
168
+ this.name = name;
169
+ this.app = app;
170
+ this.resources = resources;
171
+ }
172
+ port = 8080;
173
+ pre = () => [];
174
+ post = () => [];
175
+ with(...resources) {
176
+ return (0, import_easy7.tryTo)(this).accept((t) => t.resources.add(resources.map((r) => new r()))).value;
177
+ }
178
+ atPort(port) {
179
+ return (0, import_easy7.tryTo)(this).accept((t) => t.port = port).value;
180
+ }
181
+ start(message = `Service ${this.name} listening on port ${this.port} with ${this.resources.length} resources.`) {
182
+ (0, import_easy7.tryTo)(this).accept((t) => t.pre().forEach((h) => this.app.use(h))).accept((t) => t.resources.forEach((r) => this.app.route(this, r))).accept((t) => t.post().forEach((h) => this.app.use(h))).accept((t) => t.app.listen(this.port, message));
183
+ }
184
+ };
185
+
186
+ // src/security/Jwt.ts
187
+ var import_jsonwebtoken = require("jsonwebtoken");
188
+ var import_easy8 = require("@thisisagile/easy");
189
+ var Jwt = class _Jwt extends import_easy8.Jwt {
190
+ static of = (a) => new _Jwt(a.jwt);
191
+ get isValid() {
192
+ return (0, import_easy8.tryTo)(() => import_easy8.ctx.env.get("tokenPublicKey") ?? "").map((key) => (0, import_jsonwebtoken.verify)(this.value, key)).map(() => true).orElse() ?? false;
193
+ }
194
+ static sign = (token, options) => (0, import_easy8.tryTo)(() => import_easy8.ctx.env.get("tokenPrivateKey") ?? "").is.not.empty().map(
195
+ (key) => (0, import_jsonwebtoken.sign)(token, key, {
196
+ ...options,
197
+ expiresIn: import_easy8.ctx.env.get("tokenExpiresIn") ?? "1h",
198
+ keyid: import_easy8.ctx.env.get("tokenKeyid") ?? "easy",
199
+ algorithm: import_easy8.ctx.env.get("tokenAlgorithm", "RS256")
200
+ })
201
+ ).map((s) => new _Jwt(s)).value;
202
+ };
203
+ // Annotate the CommonJS export names for ESM import in node:
204
+ 0 && (module.exports = {
205
+ HealthResource,
206
+ HealthUri,
207
+ Jwt,
208
+ OriginatedError,
209
+ Requires,
210
+ Service,
211
+ del,
212
+ get,
213
+ isOriginatedError,
214
+ patch,
215
+ post,
216
+ put,
217
+ requires,
218
+ route,
219
+ routes,
220
+ search,
221
+ stream,
222
+ toOriginatedError,
223
+ toVerbOptions
224
+ });
225
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/health/HealthResource.ts","../src/health/HealthUri.ts","../src/resources/Route.ts","../src/http/Verb.ts","../src/http/OriginatedError.ts","../src/resources/Requires.ts","../src/resources/Service.ts","../src/security/Jwt.ts"],"sourcesContent":["export * from './health/HealthResource';\nexport * from './health/HealthUri';\nexport * from './http/OriginatedError';\nexport * from './http/Verb';\nexport * from './resources/AppProvider';\nexport * from './resources/Requires';\nexport * from './resources/Resource';\nexport * from './resources/Route';\nexport * from './resources/Service';\nexport * from './security/Jwt';\n","import { resolve, Json } from '@thisisagile/easy';\nimport { HealthUri } from './HealthUri';\nimport { Resource } from '../resources/Resource';\nimport { route } from '../resources/Route';\nimport { get } from '../http/Verb';\n\n@route(HealthUri.Health)\nexport class HealthResource implements Resource {\n @get()\n ok = (): Promise<Json> => resolve({ state: 'Service is healthy.' });\n}\n","import { EasyUri, uri } from '@thisisagile/easy';\n\nexport class HealthUri extends EasyUri {\n static readonly health = uri.segment('health');\n static readonly Health = new HealthUri([HealthUri.health]);\n}\n","import { List, meta, Optional, tryTo, Uri, Scope, UseCase, Req } from '@thisisagile/easy';\nimport { Resource } from './Resource';\nimport { RequestHandler } from 'express';\nimport { Verb } from '../http/Verb';\n\nexport const route =\n (uri: Uri): ClassDecorator =>\n (subject: unknown): void => {\n meta(subject).set('route', uri);\n };\n\nexport type Endpoint<T = unknown> = (re: Req) => Promise<T | List<T>>;\nexport type RouteRequires = { token: boolean; labCoat: boolean; scope?: Scope; uc?: UseCase };\nexport type Route = { verb: Verb; endpoint: Endpoint; requires: RouteRequires; middleware: RequestHandler[] };\nexport type Routes = { route: Uri; middleware: RequestHandler[]; endpoints: List<Route> };\n\nconst toRoute = (endpoint: Endpoint, requires: RouteRequires, verb?: Verb, middleware?: RequestHandler[]): Optional<Route> =>\n tryTo(verb)\n .is.defined()\n .map(verb => ({ verb, endpoint, requires, middleware: middleware ?? [] }) as Route)\n .orElse();\n\nclass Router implements Routes {\n constructor(readonly resource: Resource) {}\n\n get route(): Uri {\n return meta(this.resource).get('route');\n }\n\n get middleware(): RequestHandler[] {\n return meta(this.resource).get<RequestHandler[]>('middleware') ?? [];\n }\n\n get endpoints(): List<Route> {\n return meta(this.resource)\n .properties('verb')\n .mapDefined(v =>\n toRoute(\n this.resource[v.property],\n {\n labCoat: v.get<boolean>('labCoat') ?? false,\n token: v.get<boolean>('token') ?? false,\n scope: v.get<Scope>('scope'),\n uc: v.get<UseCase>('uc'),\n },\n v.get<Verb>('verb'),\n v.get<RequestHandler[]>('middleware')\n )\n );\n }\n}\n\nexport const routes = (resource: Resource): Routes => new Router(resource);\n","import { meta, CacheControl, ContentType, HttpStatus, HttpVerb } from '@thisisagile/easy';\n\nexport type VerbOptions = { onOk?: HttpStatus; onNotFound?: HttpStatus; onError?: HttpStatus; type?: ContentType; cache?: CacheControl };\nexport type Verb = { verb: HttpVerb; options: VerbOptions };\n\nexport const toVerbOptions = (options?: VerbOptions): Required<VerbOptions> => ({\n onOk: options?.onOk ?? HttpStatus.Ok,\n onNotFound: options?.onNotFound ?? HttpStatus.NotFound,\n onError: options?.onError ?? HttpStatus.BadRequest,\n type: options?.type ?? ContentType.Json,\n cache: options?.cache ?? CacheControl.disabled(),\n});\n\nconst toVerb =\n <T>(verb: HttpVerb, options?: VerbOptions): PropertyDecorator =>\n (subject: unknown, property: string | symbol): void => {\n meta(subject).property(property).set('verb', { verb, options });\n };\n\nexport const get = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Get, options);\n\nexport const search = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Get, { onNotFound: HttpStatus.Ok, ...options });\n\nexport const put = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Put, options);\n\nexport const patch = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Patch, options);\n\nexport const post = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Post, { onOk: HttpStatus.Created, ...options });\n\nexport const del = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Delete, { onOk: HttpStatus.NoContent, ...options });\n\nexport const stream = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Get, { type: ContentType.Stream, ...options });\n","import { ErrorOrigin, isError } from '@thisisagile/easy';\nimport { VerbOptions } from './Verb';\n\nexport class OriginatedError extends Error {\n constructor(\n readonly origin: ErrorOrigin,\n readonly options?: VerbOptions\n ) {\n super();\n if (isError(origin)) this.stack = origin.stack;\n }\n}\n\nexport const isOriginatedError = (e?: unknown): e is OriginatedError => isError(e) && e instanceof OriginatedError;\n\nexport const toOriginatedError = (e: unknown, options?: VerbOptions): OriginatedError =>\n isOriginatedError(e) ? e : new OriginatedError(e as ErrorOrigin, options);\n","import { meta } from '@thisisagile/easy';\nimport { Scope, UseCase } from '@thisisagile/easy';\n\nexport class Requires {\n readonly labCoat =\n (): PropertyDecorator =>\n (subject: unknown, property: string | symbol): void => {\n meta(subject).property(property).set('labCoat', true);\n };\n\n readonly token =\n (): PropertyDecorator =>\n (subject: unknown, property: string | symbol): void => {\n meta(subject).property(property).set('token', true);\n };\n\n readonly scope =\n (scope: Scope): PropertyDecorator =>\n (subject: unknown, property: string | symbol): void => {\n meta(subject).property(property).set('token', true);\n meta(subject).property(property).set('scope', scope);\n };\n\n readonly useCase =\n (uc: UseCase): PropertyDecorator =>\n (subject: unknown, property: string | symbol): void => {\n meta(subject).property(property).set('token', true);\n meta(subject).property(property).set('uc', uc);\n };\n}\n\nexport const requires = new Requires();\n","import { AppProvider, Handler } from './AppProvider';\nimport { Constructor, Enum, List, toList, tryTo } from '@thisisagile/easy';\nimport { Resource } from './Resource';\n\nexport class Service extends Enum {\n protected port = 8080;\n\n constructor(\n readonly name: string,\n protected app: AppProvider,\n protected resources: List<Resource> = toList()\n ) {\n super(name);\n }\n\n pre = (): Handler[] => [];\n post = (): Handler[] => [];\n\n with(...resources: Constructor<Resource>[]): this {\n return tryTo(this).accept(t => t.resources.add(resources.map(r => new r()))).value;\n }\n\n atPort(port: number): this {\n return tryTo(this).accept(t => (t.port = port)).value;\n }\n\n start(message = `Service ${this.name} listening on port ${this.port} with ${this.resources.length} resources.`): void {\n tryTo(this)\n .accept(t => t.pre().forEach(h => this.app.use(h)))\n .accept(t => t.resources.forEach(r => this.app.route(this, r)))\n .accept(t => t.post().forEach(h => this.app.use(h)))\n .accept(t => t.app.listen(this.port, message));\n }\n}\n","import { Algorithm, sign, verify } from 'jsonwebtoken';\nimport { ctx, Json, OneOrMore, Optional, tryTo, Validatable, Jwt as JwtBase } from '@thisisagile/easy';\n\ninterface SignOptions {\n audience?: Optional<OneOrMore<string>>;\n issuer?: Optional<string>;\n}\nexport class Jwt extends JwtBase implements Validatable {\n static of = (a: { jwt: string }): Jwt => new Jwt(a.jwt);\n\n get isValid(): boolean {\n return (\n tryTo(() => ctx.env.get('tokenPublicKey') ?? '')\n .map(key => verify(this.value, key))\n .map(() => true)\n .orElse() ?? false\n );\n }\n\n static sign = (token: Json, options?: SignOptions): Jwt =>\n tryTo(() => ctx.env.get('tokenPrivateKey') ?? '')\n .is.not.empty()\n .map(key =>\n sign(token, key, {\n ...options,\n expiresIn: ctx.env.get('tokenExpiresIn') ?? '1h',\n keyid: ctx.env.get('tokenKeyid') ?? 'easy',\n algorithm: ctx.env.get('tokenAlgorithm', 'RS256') as Algorithm,\n })\n )\n .map(s => new Jwt(s)).value;\n}\n"],"mappings":"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","names":["import_easy","import_easy","uri","requires","verb","import_easy","import_easy","import_easy","import_easy","import_easy","JwtBase"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,11 @@
1
+ export * from "./health/HealthResource";
2
+ export * from "./health/HealthUri";
3
+ export * from "./http/OriginatedError";
4
+ export * from "./http/Verb";
5
+ export * from "./resources/AppProvider";
6
+ export * from "./resources/Requires";
7
+ export * from "./resources/Resource";
8
+ export * from "./resources/Route";
9
+ export * from "./resources/Service";
10
+ export * from "./security/Jwt";
11
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './health/HealthResource';\nexport * from './health/HealthUri';\nexport * from './http/OriginatedError';\nexport * from './http/Verb';\nexport * from './resources/AppProvider';\nexport * from './resources/Requires';\nexport * from './resources/Resource';\nexport * from './resources/Route';\nexport * from './resources/Service';\nexport * from './security/Jwt';\n"],"mappings":"AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
@@ -0,0 +1,9 @@
1
+ import { Resource } from './Resource';
2
+ import { Service } from './Service';
3
+ import { Func } from '@thisisagile/easy';
4
+ export type Handler = Func<void, any>;
5
+ export interface AppProvider {
6
+ use: (h: Handler) => void;
7
+ route: (s: Service, r: Resource) => void;
8
+ listen: (port: number, message?: string) => void;
9
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=AppProvider.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,8 @@
1
+ import { Scope, UseCase } from '@thisisagile/easy';
2
+ export declare class Requires {
3
+ readonly labCoat: () => PropertyDecorator;
4
+ readonly token: () => PropertyDecorator;
5
+ readonly scope: (scope: Scope) => PropertyDecorator;
6
+ readonly useCase: (uc: UseCase) => PropertyDecorator;
7
+ }
8
+ export declare const requires: Requires;
@@ -0,0 +1,26 @@
1
+ import "../chunk-4N72FQFX.mjs";
2
+
3
+ // src/resources/Requires.ts
4
+ import { meta } from "@thisisagile/easy";
5
+ var Requires = class {
6
+ labCoat = () => (subject, property) => {
7
+ meta(subject).property(property).set("labCoat", true);
8
+ };
9
+ token = () => (subject, property) => {
10
+ meta(subject).property(property).set("token", true);
11
+ };
12
+ scope = (scope) => (subject, property) => {
13
+ meta(subject).property(property).set("token", true);
14
+ meta(subject).property(property).set("scope", scope);
15
+ };
16
+ useCase = (uc) => (subject, property) => {
17
+ meta(subject).property(property).set("token", true);
18
+ meta(subject).property(property).set("uc", uc);
19
+ };
20
+ };
21
+ var requires = new Requires();
22
+ export {
23
+ Requires,
24
+ requires
25
+ };
26
+ //# sourceMappingURL=Requires.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/resources/Requires.ts"],"sourcesContent":["import { meta } from '@thisisagile/easy';\nimport { Scope, UseCase } from '@thisisagile/easy';\n\nexport class Requires {\n readonly labCoat =\n (): PropertyDecorator =>\n (subject: unknown, property: string | symbol): void => {\n meta(subject).property(property).set('labCoat', true);\n };\n\n readonly token =\n (): PropertyDecorator =>\n (subject: unknown, property: string | symbol): void => {\n meta(subject).property(property).set('token', true);\n };\n\n readonly scope =\n (scope: Scope): PropertyDecorator =>\n (subject: unknown, property: string | symbol): void => {\n meta(subject).property(property).set('token', true);\n meta(subject).property(property).set('scope', scope);\n };\n\n readonly useCase =\n (uc: UseCase): PropertyDecorator =>\n (subject: unknown, property: string | symbol): void => {\n meta(subject).property(property).set('token', true);\n meta(subject).property(property).set('uc', uc);\n };\n}\n\nexport const requires = new Requires();\n"],"mappings":";;;AAAA,SAAS,YAAY;AAGd,IAAM,WAAN,MAAe;AAAA,EACX,UACP,MACA,CAAC,SAAkB,aAAoC;AACrD,SAAK,OAAO,EAAE,SAAS,QAAQ,EAAE,IAAI,WAAW,IAAI;AAAA,EACtD;AAAA,EAEO,QACP,MACA,CAAC,SAAkB,aAAoC;AACrD,SAAK,OAAO,EAAE,SAAS,QAAQ,EAAE,IAAI,SAAS,IAAI;AAAA,EACpD;AAAA,EAEO,QACP,CAAC,UACD,CAAC,SAAkB,aAAoC;AACrD,SAAK,OAAO,EAAE,SAAS,QAAQ,EAAE,IAAI,SAAS,IAAI;AAClD,SAAK,OAAO,EAAE,SAAS,QAAQ,EAAE,IAAI,SAAS,KAAK;AAAA,EACrD;AAAA,EAEO,UACP,CAAC,OACD,CAAC,SAAkB,aAAoC;AACrD,SAAK,OAAO,EAAE,SAAS,QAAQ,EAAE,IAAI,SAAS,IAAI;AAClD,SAAK,OAAO,EAAE,SAAS,QAAQ,EAAE,IAAI,MAAM,EAAE;AAAA,EAC/C;AACJ;AAEO,IAAM,WAAW,IAAI,SAAS;","names":[]}
@@ -0,0 +1 @@
1
+ export type Resource = any;
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=Resource.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,24 @@
1
+ import { List, Uri, Scope, UseCase, Req } from '@thisisagile/easy';
2
+ import { Resource } from './Resource';
3
+ import { RequestHandler } from 'express';
4
+ import { Verb } from '../http/Verb';
5
+ export declare const route: (uri: Uri) => ClassDecorator;
6
+ export type Endpoint<T = unknown> = (re: Req) => Promise<T | List<T>>;
7
+ export type RouteRequires = {
8
+ token: boolean;
9
+ labCoat: boolean;
10
+ scope?: Scope;
11
+ uc?: UseCase;
12
+ };
13
+ export type Route = {
14
+ verb: Verb;
15
+ endpoint: Endpoint;
16
+ requires: RouteRequires;
17
+ middleware: RequestHandler[];
18
+ };
19
+ export type Routes = {
20
+ route: Uri;
21
+ middleware: RequestHandler[];
22
+ endpoints: List<Route>;
23
+ };
24
+ export declare const routes: (resource: Resource) => Routes;
@@ -0,0 +1,10 @@
1
+ import {
2
+ route,
3
+ routes
4
+ } from "../chunk-FYPLZQRO.mjs";
5
+ import "../chunk-4N72FQFX.mjs";
6
+ export {
7
+ route,
8
+ routes
9
+ };
10
+ //# sourceMappingURL=Route.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,15 @@
1
+ import { AppProvider, Handler } from './AppProvider';
2
+ import { Constructor, Enum, List } from '@thisisagile/easy';
3
+ import { Resource } from './Resource';
4
+ export declare class Service extends Enum {
5
+ readonly name: string;
6
+ protected app: AppProvider;
7
+ protected resources: List<Resource>;
8
+ protected port: number;
9
+ constructor(name: string, app: AppProvider, resources?: List<Resource>);
10
+ pre: () => Handler[];
11
+ post: () => Handler[];
12
+ with(...resources: Constructor<Resource>[]): this;
13
+ atPort(port: number): this;
14
+ start(message?: string): void;
15
+ }
@@ -0,0 +1,28 @@
1
+ import "../chunk-4N72FQFX.mjs";
2
+
3
+ // src/resources/Service.ts
4
+ import { Enum, toList, tryTo } from "@thisisagile/easy";
5
+ var Service = class extends Enum {
6
+ constructor(name, app, resources = toList()) {
7
+ super(name);
8
+ this.name = name;
9
+ this.app = app;
10
+ this.resources = resources;
11
+ }
12
+ port = 8080;
13
+ pre = () => [];
14
+ post = () => [];
15
+ with(...resources) {
16
+ return tryTo(this).accept((t) => t.resources.add(resources.map((r) => new r()))).value;
17
+ }
18
+ atPort(port) {
19
+ return tryTo(this).accept((t) => t.port = port).value;
20
+ }
21
+ start(message = `Service ${this.name} listening on port ${this.port} with ${this.resources.length} resources.`) {
22
+ tryTo(this).accept((t) => t.pre().forEach((h) => this.app.use(h))).accept((t) => t.resources.forEach((r) => this.app.route(this, r))).accept((t) => t.post().forEach((h) => this.app.use(h))).accept((t) => t.app.listen(this.port, message));
23
+ }
24
+ };
25
+ export {
26
+ Service
27
+ };
28
+ //# sourceMappingURL=Service.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/resources/Service.ts"],"sourcesContent":["import { AppProvider, Handler } from './AppProvider';\nimport { Constructor, Enum, List, toList, tryTo } from '@thisisagile/easy';\nimport { Resource } from './Resource';\n\nexport class Service extends Enum {\n protected port = 8080;\n\n constructor(\n readonly name: string,\n protected app: AppProvider,\n protected resources: List<Resource> = toList()\n ) {\n super(name);\n }\n\n pre = (): Handler[] => [];\n post = (): Handler[] => [];\n\n with(...resources: Constructor<Resource>[]): this {\n return tryTo(this).accept(t => t.resources.add(resources.map(r => new r()))).value;\n }\n\n atPort(port: number): this {\n return tryTo(this).accept(t => (t.port = port)).value;\n }\n\n start(message = `Service ${this.name} listening on port ${this.port} with ${this.resources.length} resources.`): void {\n tryTo(this)\n .accept(t => t.pre().forEach(h => this.app.use(h)))\n .accept(t => t.resources.forEach(r => this.app.route(this, r)))\n .accept(t => t.post().forEach(h => this.app.use(h)))\n .accept(t => t.app.listen(this.port, message));\n }\n}\n"],"mappings":";;;AACA,SAAsB,MAAY,QAAQ,aAAa;AAGhD,IAAM,UAAN,cAAsB,KAAK;AAAA,EAGhC,YACW,MACC,KACA,YAA4B,OAAO,GAC7C;AACA,UAAM,IAAI;AAJD;AACC;AACA;AAAA,EAGZ;AAAA,EARU,OAAO;AAAA,EAUjB,MAAM,MAAiB,CAAC;AAAA,EACxB,OAAO,MAAiB,CAAC;AAAA,EAEzB,QAAQ,WAA0C;AAChD,WAAO,MAAM,IAAI,EAAE,OAAO,OAAK,EAAE,UAAU,IAAI,UAAU,IAAI,OAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;AAAA,EAC/E;AAAA,EAEA,OAAO,MAAoB;AACzB,WAAO,MAAM,IAAI,EAAE,OAAO,OAAM,EAAE,OAAO,IAAK,EAAE;AAAA,EAClD;AAAA,EAEA,MAAM,UAAU,WAAW,KAAK,IAAI,sBAAsB,KAAK,IAAI,SAAS,KAAK,UAAU,MAAM,eAAqB;AACpH,UAAM,IAAI,EACP,OAAO,OAAK,EAAE,IAAI,EAAE,QAAQ,OAAK,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,EACjD,OAAO,OAAK,EAAE,UAAU,QAAQ,OAAK,KAAK,IAAI,MAAM,MAAM,CAAC,CAAC,CAAC,EAC7D,OAAO,OAAK,EAAE,KAAK,EAAE,QAAQ,OAAK,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,EAClD,OAAO,OAAK,EAAE,IAAI,OAAO,KAAK,MAAM,OAAO,CAAC;AAAA,EACjD;AACF;","names":[]}
@@ -0,0 +1,13 @@
1
+ import { Json, OneOrMore, Optional, Validatable, Jwt as JwtBase } from '@thisisagile/easy';
2
+ interface SignOptions {
3
+ audience?: Optional<OneOrMore<string>>;
4
+ issuer?: Optional<string>;
5
+ }
6
+ export declare class Jwt extends JwtBase implements Validatable {
7
+ static of: (a: {
8
+ jwt: string;
9
+ }) => Jwt;
10
+ get isValid(): boolean;
11
+ static sign: (token: Json, options?: SignOptions) => Jwt;
12
+ }
13
+ export {};
@@ -0,0 +1,23 @@
1
+ import "../chunk-4N72FQFX.mjs";
2
+
3
+ // src/security/Jwt.ts
4
+ import { sign, verify } from "jsonwebtoken";
5
+ import { ctx, tryTo, Jwt as JwtBase } from "@thisisagile/easy";
6
+ var Jwt = class _Jwt extends JwtBase {
7
+ static of = (a) => new _Jwt(a.jwt);
8
+ get isValid() {
9
+ return tryTo(() => ctx.env.get("tokenPublicKey") ?? "").map((key) => verify(this.value, key)).map(() => true).orElse() ?? false;
10
+ }
11
+ static sign = (token, options) => tryTo(() => ctx.env.get("tokenPrivateKey") ?? "").is.not.empty().map(
12
+ (key) => sign(token, key, {
13
+ ...options,
14
+ expiresIn: ctx.env.get("tokenExpiresIn") ?? "1h",
15
+ keyid: ctx.env.get("tokenKeyid") ?? "easy",
16
+ algorithm: ctx.env.get("tokenAlgorithm", "RS256")
17
+ })
18
+ ).map((s) => new _Jwt(s)).value;
19
+ };
20
+ export {
21
+ Jwt
22
+ };
23
+ //# sourceMappingURL=Jwt.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/security/Jwt.ts"],"sourcesContent":["import { Algorithm, sign, verify } from 'jsonwebtoken';\nimport { ctx, Json, OneOrMore, Optional, tryTo, Validatable, Jwt as JwtBase } from '@thisisagile/easy';\n\ninterface SignOptions {\n audience?: Optional<OneOrMore<string>>;\n issuer?: Optional<string>;\n}\nexport class Jwt extends JwtBase implements Validatable {\n static of = (a: { jwt: string }): Jwt => new Jwt(a.jwt);\n\n get isValid(): boolean {\n return (\n tryTo(() => ctx.env.get('tokenPublicKey') ?? '')\n .map(key => verify(this.value, key))\n .map(() => true)\n .orElse() ?? false\n );\n }\n\n static sign = (token: Json, options?: SignOptions): Jwt =>\n tryTo(() => ctx.env.get('tokenPrivateKey') ?? '')\n .is.not.empty()\n .map(key =>\n sign(token, key, {\n ...options,\n expiresIn: ctx.env.get('tokenExpiresIn') ?? '1h',\n keyid: ctx.env.get('tokenKeyid') ?? 'easy',\n algorithm: ctx.env.get('tokenAlgorithm', 'RS256') as Algorithm,\n })\n )\n .map(s => new Jwt(s)).value;\n}\n"],"mappings":";;;AAAA,SAAoB,MAAM,cAAc;AACxC,SAAS,KAAgC,OAAoB,OAAO,eAAe;AAM5E,IAAM,MAAN,MAAM,aAAY,QAA+B;AAAA,EACtD,OAAO,KAAK,CAAC,MAA4B,IAAI,KAAI,EAAE,GAAG;AAAA,EAEtD,IAAI,UAAmB;AACrB,WACE,MAAM,MAAM,IAAI,IAAI,IAAI,gBAAgB,KAAK,EAAE,EAC5C,IAAI,SAAO,OAAO,KAAK,OAAO,GAAG,CAAC,EAClC,IAAI,MAAM,IAAI,EACd,OAAO,KAAK;AAAA,EAEnB;AAAA,EAEA,OAAO,OAAO,CAAC,OAAa,YAC1B,MAAM,MAAM,IAAI,IAAI,IAAI,iBAAiB,KAAK,EAAE,EAC7C,GAAG,IAAI,MAAM,EACb;AAAA,IAAI,SACH,KAAK,OAAO,KAAK;AAAA,MACf,GAAG;AAAA,MACH,WAAW,IAAI,IAAI,IAAI,gBAAgB,KAAK;AAAA,MAC5C,OAAO,IAAI,IAAI,IAAI,YAAY,KAAK;AAAA,MACpC,WAAW,IAAI,IAAI,IAAI,kBAAkB,OAAO;AAAA,IAClD,CAAC;AAAA,EACH,EACC,IAAI,OAAK,IAAI,KAAI,CAAC,CAAC,EAAE;AAC5B;","names":[]}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@thisisagile/easy-service",
3
+ "version": "17.0.0",
4
+ "description": "Straightforward library for building domain-driven microservice architectures",
5
+ "author": "Sander Hoogendoorn",
6
+ "license": "MIT",
7
+ "main": "dist/index.js",
8
+ "module": "dist/index.mjs",
9
+ "types": "dist/index.d.ts",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git@github.com:thisisagile/easy.git"
13
+ },
14
+ "keywords": [
15
+ "typescript",
16
+ "microservices",
17
+ "domain-driven-design",
18
+ "evolutionary-architecture"
19
+ ],
20
+ "scripts": {
21
+ "lint": "yarn g:eslint . --ext .js,.jsx,.ts,.tsx --fix",
22
+ "format": "yarn g:prettier --check --write src test *.json",
23
+ "build": "yarn g:tsc",
24
+ "build:tsup": "yarn g:tsup --onSuccess \"yarn g:tsc --emitDeclarationOnly --declaration\"",
25
+ "test": "yarn g:jest --coverage",
26
+ "prepack": "yarn g:copy-readme"
27
+ },
28
+ "sideEffects": false,
29
+ "files": [
30
+ "dist",
31
+ "src"
32
+ ],
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "devDependencies": {
37
+ "@thisisagile/easy-test": "17.0.0",
38
+ "@types/jsonwebtoken": "^9.0.6"
39
+ },
40
+ "dependencies": {
41
+ "@thisisagile/easy": "^17.0.0",
42
+ "jsonwebtoken": "^8.5.1"
43
+ }
44
+ }
@@ -0,0 +1,11 @@
1
+ import { resolve, Json } from '@thisisagile/easy';
2
+ import { HealthUri } from './HealthUri';
3
+ import { Resource } from '../resources/Resource';
4
+ import { route } from '../resources/Route';
5
+ import { get } from '../http/Verb';
6
+
7
+ @route(HealthUri.Health)
8
+ export class HealthResource implements Resource {
9
+ @get()
10
+ ok = (): Promise<Json> => resolve({ state: 'Service is healthy.' });
11
+ }
@@ -0,0 +1,6 @@
1
+ import { EasyUri, uri } from '@thisisagile/easy';
2
+
3
+ export class HealthUri extends EasyUri {
4
+ static readonly health = uri.segment('health');
5
+ static readonly Health = new HealthUri([HealthUri.health]);
6
+ }
@@ -0,0 +1,17 @@
1
+ import { ErrorOrigin, isError } from '@thisisagile/easy';
2
+ import { VerbOptions } from './Verb';
3
+
4
+ export class OriginatedError extends Error {
5
+ constructor(
6
+ readonly origin: ErrorOrigin,
7
+ readonly options?: VerbOptions
8
+ ) {
9
+ super();
10
+ if (isError(origin)) this.stack = origin.stack;
11
+ }
12
+ }
13
+
14
+ export const isOriginatedError = (e?: unknown): e is OriginatedError => isError(e) && e instanceof OriginatedError;
15
+
16
+ export const toOriginatedError = (e: unknown, options?: VerbOptions): OriginatedError =>
17
+ isOriginatedError(e) ? e : new OriginatedError(e as ErrorOrigin, options);
@@ -0,0 +1,32 @@
1
+ import { meta, CacheControl, ContentType, HttpStatus, HttpVerb } from '@thisisagile/easy';
2
+
3
+ export type VerbOptions = { onOk?: HttpStatus; onNotFound?: HttpStatus; onError?: HttpStatus; type?: ContentType; cache?: CacheControl };
4
+ export type Verb = { verb: HttpVerb; options: VerbOptions };
5
+
6
+ export const toVerbOptions = (options?: VerbOptions): Required<VerbOptions> => ({
7
+ onOk: options?.onOk ?? HttpStatus.Ok,
8
+ onNotFound: options?.onNotFound ?? HttpStatus.NotFound,
9
+ onError: options?.onError ?? HttpStatus.BadRequest,
10
+ type: options?.type ?? ContentType.Json,
11
+ cache: options?.cache ?? CacheControl.disabled(),
12
+ });
13
+
14
+ const toVerb =
15
+ <T>(verb: HttpVerb, options?: VerbOptions): PropertyDecorator =>
16
+ (subject: unknown, property: string | symbol): void => {
17
+ meta(subject).property(property).set('verb', { verb, options });
18
+ };
19
+
20
+ export const get = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Get, options);
21
+
22
+ export const search = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Get, { onNotFound: HttpStatus.Ok, ...options });
23
+
24
+ export const put = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Put, options);
25
+
26
+ export const patch = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Patch, options);
27
+
28
+ export const post = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Post, { onOk: HttpStatus.Created, ...options });
29
+
30
+ export const del = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Delete, { onOk: HttpStatus.NoContent, ...options });
31
+
32
+ export const stream = (options?: VerbOptions): PropertyDecorator => toVerb(HttpVerb.Get, { type: ContentType.Stream, ...options });
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ export * from './health/HealthResource';
2
+ export * from './health/HealthUri';
3
+ export * from './http/OriginatedError';
4
+ export * from './http/Verb';
5
+ export * from './resources/AppProvider';
6
+ export * from './resources/Requires';
7
+ export * from './resources/Resource';
8
+ export * from './resources/Route';
9
+ export * from './resources/Service';
10
+ export * from './security/Jwt';
@@ -0,0 +1,11 @@
1
+ import { Resource } from './Resource';
2
+ import { Service } from './Service';
3
+ import { Func } from '@thisisagile/easy';
4
+
5
+ export type Handler = Func<void, any>;
6
+
7
+ export interface AppProvider {
8
+ use: (h: Handler) => void;
9
+ route: (s: Service, r: Resource) => void;
10
+ listen: (port: number, message?: string) => void;
11
+ }