@openapi-typescript-infra/service 1.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 (121) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc.js +14 -0
  3. package/.github/workflows/codeql-analysis.yml +74 -0
  4. package/.github/workflows/nodejs.yml +23 -0
  5. package/.github/workflows/npmpublish.yml +35 -0
  6. package/.husky/pre-commit +6 -0
  7. package/.prettierrc.js +14 -0
  8. package/@types/config.d.ts +56 -0
  9. package/CHANGELOG.md +5 -0
  10. package/LICENSE +21 -0
  11. package/README.md +28 -0
  12. package/SECURITY.md +12 -0
  13. package/__tests__/config.test.ts +31 -0
  14. package/__tests__/fake-serv/api/fake-serv.yaml +48 -0
  15. package/__tests__/fake-serv/config/config.json +15 -0
  16. package/__tests__/fake-serv/src/handlers/hello.ts +10 -0
  17. package/__tests__/fake-serv/src/index.ts +29 -0
  18. package/__tests__/fake-serv/src/routes/error.ts +13 -0
  19. package/__tests__/fake-serv/src/routes/index.ts +22 -0
  20. package/__tests__/fake-serv/src/routes/other/world.ts +7 -0
  21. package/__tests__/fake-serv.test.ts +74 -0
  22. package/build/bin/start-service.d.ts +2 -0
  23. package/build/bin/start-service.js +31 -0
  24. package/build/bin/start-service.js.map +1 -0
  25. package/build/bootstrap.d.ts +16 -0
  26. package/build/bootstrap.js +90 -0
  27. package/build/bootstrap.js.map +1 -0
  28. package/build/config/index.d.ts +10 -0
  29. package/build/config/index.js +98 -0
  30. package/build/config/index.js.map +1 -0
  31. package/build/config/schema.d.ts +48 -0
  32. package/build/config/schema.js +3 -0
  33. package/build/config/schema.js.map +1 -0
  34. package/build/config/shortstops.d.ts +31 -0
  35. package/build/config/shortstops.js +109 -0
  36. package/build/config/shortstops.js.map +1 -0
  37. package/build/config/types.d.ts +3 -0
  38. package/build/config/types.js +3 -0
  39. package/build/config/types.js.map +1 -0
  40. package/build/development/port-finder.d.ts +1 -0
  41. package/build/development/port-finder.js +41 -0
  42. package/build/development/port-finder.js.map +1 -0
  43. package/build/development/repl.d.ts +2 -0
  44. package/build/development/repl.js +29 -0
  45. package/build/development/repl.js.map +1 -0
  46. package/build/env.d.ts +2 -0
  47. package/build/env.js +19 -0
  48. package/build/env.js.map +1 -0
  49. package/build/error.d.ts +25 -0
  50. package/build/error.js +28 -0
  51. package/build/error.js.map +1 -0
  52. package/build/express-app/app.d.ts +6 -0
  53. package/build/express-app/app.js +327 -0
  54. package/build/express-app/app.js.map +1 -0
  55. package/build/express-app/index.d.ts +2 -0
  56. package/build/express-app/index.js +19 -0
  57. package/build/express-app/index.js.map +1 -0
  58. package/build/express-app/internal-server.d.ts +3 -0
  59. package/build/express-app/internal-server.js +34 -0
  60. package/build/express-app/internal-server.js.map +1 -0
  61. package/build/express-app/route-loader.d.ts +2 -0
  62. package/build/express-app/route-loader.js +46 -0
  63. package/build/express-app/route-loader.js.map +1 -0
  64. package/build/express-app/types.d.ts +14 -0
  65. package/build/express-app/types.js +3 -0
  66. package/build/express-app/types.js.map +1 -0
  67. package/build/index.d.ts +8 -0
  68. package/build/index.js +25 -0
  69. package/build/index.js.map +1 -0
  70. package/build/openapi.d.ts +5 -0
  71. package/build/openapi.js +78 -0
  72. package/build/openapi.js.map +1 -0
  73. package/build/service-calls/index.d.ts +16 -0
  74. package/build/service-calls/index.js +85 -0
  75. package/build/service-calls/index.js.map +1 -0
  76. package/build/telemetry/fetchInstrumentation.d.ts +50 -0
  77. package/build/telemetry/fetchInstrumentation.js +144 -0
  78. package/build/telemetry/fetchInstrumentation.js.map +1 -0
  79. package/build/telemetry/index.d.ts +6 -0
  80. package/build/telemetry/index.js +80 -0
  81. package/build/telemetry/index.js.map +1 -0
  82. package/build/telemetry/instrumentations.d.ts +29 -0
  83. package/build/telemetry/instrumentations.js +47 -0
  84. package/build/telemetry/instrumentations.js.map +1 -0
  85. package/build/telemetry/requestLogger.d.ts +6 -0
  86. package/build/telemetry/requestLogger.js +144 -0
  87. package/build/telemetry/requestLogger.js.map +1 -0
  88. package/build/tsconfig.build.tsbuildinfo +1 -0
  89. package/build/types.d.ts +77 -0
  90. package/build/types.js +3 -0
  91. package/build/types.js.map +1 -0
  92. package/config/config.json +31 -0
  93. package/config/development.json +11 -0
  94. package/config/test.json +5 -0
  95. package/jest.config.js +14 -0
  96. package/package.json +111 -0
  97. package/src/bin/start-service.ts +28 -0
  98. package/src/bootstrap.ts +112 -0
  99. package/src/config/index.ts +115 -0
  100. package/src/config/schema.ts +66 -0
  101. package/src/config/shortstops.ts +118 -0
  102. package/src/config/types.ts +5 -0
  103. package/src/development/port-finder.ts +40 -0
  104. package/src/development/repl.ts +24 -0
  105. package/src/env.ts +14 -0
  106. package/src/error.ts +44 -0
  107. package/src/express-app/app.ts +399 -0
  108. package/src/express-app/index.ts +2 -0
  109. package/src/express-app/internal-server.ts +31 -0
  110. package/src/express-app/route-loader.ts +48 -0
  111. package/src/express-app/types.ts +31 -0
  112. package/src/index.ts +8 -0
  113. package/src/openapi.ts +67 -0
  114. package/src/service-calls/index.ts +129 -0
  115. package/src/telemetry/fetchInstrumentation.ts +209 -0
  116. package/src/telemetry/index.ts +69 -0
  117. package/src/telemetry/instrumentations.ts +54 -0
  118. package/src/telemetry/requestLogger.ts +193 -0
  119. package/src/types.ts +139 -0
  120. package/tsconfig.build.json +10 -0
  121. package/tsconfig.json +36 -0
@@ -0,0 +1,327 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.listen = exports.shutdownApp = exports.startApp = void 0;
7
+ const assert_1 = __importDefault(require("assert"));
8
+ const http_1 = __importDefault(require("http"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const express_1 = __importDefault(require("express"));
11
+ const pino_1 = require("pino");
12
+ const cookie_parser_1 = __importDefault(require("cookie-parser"));
13
+ const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
14
+ const api_metrics_1 = require("@opentelemetry/api-metrics");
15
+ const exporter_prometheus_1 = require("@opentelemetry/exporter-prometheus");
16
+ const terminus_1 = require("@godaddy/terminus");
17
+ const index_1 = require("../config/index");
18
+ const port_finder_1 = require("../development/port-finder");
19
+ const openapi_1 = require("../openapi");
20
+ const requestLogger_1 = require("../telemetry/requestLogger");
21
+ const env_1 = require("../env");
22
+ const route_loader_1 = require("./route-loader");
23
+ const internal_server_1 = require("./internal-server");
24
+ const METRICS_KEY = Symbol('PrometheusMetricsInfo');
25
+ async function enableMetrics(app, name) {
26
+ const meterProvider = new sdk_metrics_1.MeterProvider();
27
+ api_metrics_1.metrics.setGlobalMeterProvider(meterProvider);
28
+ app.locals.meter = meterProvider.getMeter(name);
29
+ const metricsConfig = app.locals.config.get('server:metrics');
30
+ const value = { meterProvider };
31
+ if (metricsConfig?.enabled) {
32
+ const finalConfig = {
33
+ ...metricsConfig,
34
+ preventServerStart: true,
35
+ };
36
+ // There is what I would consider a bug in OpenTelemetry metrics
37
+ // wherein adding metrics BEFORE the metricReader is added results
38
+ // in those metrics screaming into the void. So, we need to add
39
+ // this up front and then just tie it to the internal express
40
+ // app if and when "listen" is called.
41
+ const exporter = new exporter_prometheus_1.PrometheusExporter(finalConfig);
42
+ meterProvider.addMetricReader(exporter);
43
+ value.exporter = exporter;
44
+ }
45
+ else {
46
+ app.locals.logger.info('No metrics will be exported');
47
+ }
48
+ // Squirrel it away for later
49
+ Object.defineProperty(app.locals, METRICS_KEY, {
50
+ value,
51
+ enumerable: false,
52
+ configurable: true,
53
+ });
54
+ }
55
+ async function endMetrics(app) {
56
+ const { internalApp, logger } = app.locals;
57
+ const meterProvider = internalApp?.locals.meterProvider;
58
+ await meterProvider?.shutdown();
59
+ logger.info('Metrics shutdown');
60
+ }
61
+ async function startApp(startOptions) {
62
+ const { service, rootDirectory, codepath = 'build', name, } = startOptions;
63
+ const shouldPrettyPrint = (0, env_1.isDev)() && !process.env.NO_PRETTY_LOGS;
64
+ const destination = pino_1.pino.destination({
65
+ dest: process.env.LOG_TO_FILE || process.stdout.fd,
66
+ minLength: process.env.LOG_BUFFER ? Number(process.env.LOG_BUFFER) : undefined,
67
+ });
68
+ const logger = shouldPrettyPrint
69
+ ? (0, pino_1.pino)({
70
+ transport: {
71
+ destination,
72
+ target: 'pino-pretty',
73
+ options: {
74
+ colorize: true,
75
+ },
76
+ },
77
+ })
78
+ : (0, pino_1.pino)({
79
+ formatters: {
80
+ level(label) {
81
+ return { level: label };
82
+ },
83
+ },
84
+ }, destination);
85
+ const serviceImpl = service();
86
+ (0, assert_1.default)(serviceImpl?.start, 'Service function did not return a conforming object');
87
+ const baseOptions = {
88
+ configurationDirectories: [path_1.default.resolve(rootDirectory, './config')],
89
+ };
90
+ const options = serviceImpl.configure?.(startOptions, baseOptions) || baseOptions;
91
+ const config = await (0, index_1.loadConfiguration)({
92
+ name,
93
+ configurationDirectories: options.configurationDirectories,
94
+ rootDirectory,
95
+ });
96
+ const logging = config.get('logging');
97
+ logger.level = logging?.level || 'info';
98
+ // Concentrate the Typescript ugliness...
99
+ const app = (0, express_1.default)();
100
+ const routing = config.get('routing');
101
+ app.disable('x-powered-by');
102
+ if (routing?.etag !== true) {
103
+ app.disable('etag');
104
+ }
105
+ Object.assign(app.locals, { services: {} }, startOptions.locals, {
106
+ service: serviceImpl,
107
+ logger,
108
+ config,
109
+ name,
110
+ });
111
+ try {
112
+ await enableMetrics(app, name);
113
+ }
114
+ catch (error) {
115
+ logger.error(error, 'Could not enable metrics.');
116
+ throw error;
117
+ }
118
+ if (config.get('trustProxy')) {
119
+ app.set('trust proxy', config.get('trustProxy'));
120
+ }
121
+ app.use((0, requestLogger_1.loggerMiddleware)(app, logging?.logRequestBody, logging?.logResponseBody));
122
+ // Allow the service to add locals, etc. We put this before the body parsers
123
+ // so that the req can decide whether to save the raw request body or not.
124
+ const attachServiceLocals = (req, res, next) => {
125
+ res.locals.logger = logger;
126
+ let maybePromise;
127
+ try {
128
+ maybePromise = serviceImpl.onRequest?.(req, res);
129
+ }
130
+ catch (error) {
131
+ next(error);
132
+ }
133
+ if (maybePromise) {
134
+ maybePromise.catch(next).then(next);
135
+ }
136
+ else {
137
+ next();
138
+ }
139
+ };
140
+ app.use(attachServiceLocals);
141
+ if (routing?.cookieParser) {
142
+ app.use((0, cookie_parser_1.default)());
143
+ }
144
+ if (routing?.bodyParsers?.json) {
145
+ app.use(express_1.default.json({
146
+ verify(req, res, buf) {
147
+ const locals = res.locals;
148
+ if (locals?.rawBody === true) {
149
+ locals.rawBody = buf;
150
+ }
151
+ },
152
+ }));
153
+ }
154
+ if (routing?.bodyParsers?.form) {
155
+ app.use(express_1.default.urlencoded());
156
+ }
157
+ if (serviceImpl.authorize) {
158
+ const authorize = (req, res, next) => {
159
+ let maybePromise;
160
+ try {
161
+ maybePromise = serviceImpl.authorize?.(req, res);
162
+ }
163
+ catch (error) {
164
+ next(error);
165
+ }
166
+ if (maybePromise && typeof maybePromise !== 'boolean') {
167
+ maybePromise
168
+ .then((val) => {
169
+ if (val === false) {
170
+ return;
171
+ }
172
+ next();
173
+ })
174
+ .catch(next);
175
+ }
176
+ else if (maybePromise !== false) {
177
+ next();
178
+ }
179
+ };
180
+ app.use(authorize);
181
+ }
182
+ if (routing?.static?.enabled) {
183
+ const localdir = path_1.default.resolve(rootDirectory, routing?.static?.path || 'public');
184
+ if (routing.static.mountPath) {
185
+ app.use(routing.static.mountPath, express_1.default.static(localdir));
186
+ }
187
+ else {
188
+ app.use(express_1.default.static(localdir));
189
+ }
190
+ }
191
+ if (routing?.freezeQuery) {
192
+ app.use((req, res, next) => {
193
+ // Express 5 re-parses the query string every time. This causes problems with
194
+ // various libraries, namely the express OpenAPI parser. So we "freeze it" in place
195
+ // here, which runs right before the routing validation logic does. Note that this
196
+ // means the app middleware will see the unfrozen one, which is intentional. If the
197
+ // app wants to modify or freeze the query itself, this shouldn't get in the way.
198
+ const { query } = req;
199
+ if (query) {
200
+ Object.defineProperty(req, 'query', {
201
+ configurable: true,
202
+ enumerable: true,
203
+ value: query,
204
+ });
205
+ }
206
+ next();
207
+ });
208
+ }
209
+ if (routing?.routes) {
210
+ await (0, route_loader_1.loadRoutes)(app, path_1.default.resolve(rootDirectory, codepath, config.get('routing:routes') || 'routes'), codepath === 'build' ? '**/*.js' : '**/*.ts');
211
+ }
212
+ if (routing?.openapi) {
213
+ app.use((0, openapi_1.openApi)(app, rootDirectory, codepath, options.openApiOptions));
214
+ }
215
+ // Putting this here allows more flexible middleware insertion
216
+ await serviceImpl.start(app);
217
+ const { notFound, errors } = routing?.finalHandlers || {};
218
+ if (notFound) {
219
+ app.use((0, requestLogger_1.notFoundMiddleware)());
220
+ }
221
+ if (errors?.enabled) {
222
+ app.use((0, requestLogger_1.errorHandlerMiddleware)(app, errors?.unnest, errors?.render));
223
+ }
224
+ return app;
225
+ }
226
+ exports.startApp = startApp;
227
+ async function shutdownApp(app) {
228
+ const { logger } = app.locals;
229
+ try {
230
+ await app.locals.service.stop?.(app);
231
+ await endMetrics(app);
232
+ logger.info('App shutdown complete');
233
+ }
234
+ catch (error) {
235
+ logger.warn(error, 'Shutdown failed');
236
+ }
237
+ logger.flush?.();
238
+ }
239
+ exports.shutdownApp = shutdownApp;
240
+ async function listen(app, shutdownHandler) {
241
+ let port = app.locals.config.get('server:port');
242
+ if (port === 0) {
243
+ port = await (0, port_finder_1.findPort)(8001);
244
+ }
245
+ const { service, logger } = app.locals;
246
+ const server = http_1.default.createServer(app);
247
+ let shutdownInProgress = false;
248
+ (0, terminus_1.createTerminus)(server, {
249
+ timeout: 15000,
250
+ useExit0: true,
251
+ // https://github.com/godaddy/terminus#how-to-set-terminus-up-with-kubernetes
252
+ beforeShutdown() {
253
+ if (shutdownInProgress) {
254
+ return Promise.resolve();
255
+ }
256
+ shutdownInProgress = true;
257
+ if (app.locals.internalApp) {
258
+ app.locals.internalApp.locals.server?.close();
259
+ }
260
+ logger.info('Graceful shutdown beginning');
261
+ return new Promise((accept) => {
262
+ setTimeout(accept, 10000);
263
+ });
264
+ },
265
+ onShutdown() {
266
+ return Promise.resolve()
267
+ .then(() => service.stop?.(app))
268
+ .then(() => endMetrics(app))
269
+ .then(shutdownHandler || Promise.resolve)
270
+ .then(() => logger.info('Graceful shutdown complete'))
271
+ .catch((error) => logger.error(error, 'Error terminating tracing'))
272
+ .then(() => logger.flush?.());
273
+ },
274
+ logger: (msg, e) => {
275
+ logger.error(e, msg);
276
+ },
277
+ });
278
+ server.on('close', () => {
279
+ if (!shutdownInProgress) {
280
+ shutdownInProgress = true;
281
+ app.locals.logger.info('Shutdown requested');
282
+ if (app.locals.internalApp) {
283
+ app.locals.internalApp.locals.server?.close();
284
+ }
285
+ shutdownApp(app);
286
+ }
287
+ });
288
+ const metricInfo = app.locals[METRICS_KEY];
289
+ delete app.locals[METRICS_KEY];
290
+ // TODO handle rejection/error?
291
+ const listenPromise = new Promise((accept) => {
292
+ server.listen(port, () => {
293
+ const { locals } = app;
294
+ locals.logger.info({ port, service: locals.name }, 'express listening');
295
+ const serverConfig = locals.config.get('server');
296
+ // Ok now start the internal port if we have one.
297
+ if (serverConfig?.internalPort) {
298
+ (0, internal_server_1.startInternalApp)(app, serverConfig.internalPort)
299
+ .then((internalApp) => {
300
+ locals.internalApp = internalApp;
301
+ internalApp.locals.meterProvider = metricInfo.meterProvider;
302
+ locals.logger.info({ port: serverConfig.internalPort }, 'Internal metadata server started');
303
+ })
304
+ .then(() => {
305
+ if (metricInfo.exporter) {
306
+ locals.internalApp.get('/metrics', metricInfo.exporter.getMetricsRequestHandler.bind(metricInfo.exporter));
307
+ locals.logger.info('Metrics exporter started');
308
+ }
309
+ else {
310
+ locals.logger.info('No metrics will be exported');
311
+ }
312
+ accept();
313
+ })
314
+ .catch((error) => {
315
+ locals.logger.warn(error, 'Failed to start internal metadata app');
316
+ });
317
+ }
318
+ else {
319
+ accept();
320
+ }
321
+ });
322
+ });
323
+ await listenPromise;
324
+ return server;
325
+ }
326
+ exports.listen = listen;
327
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/express-app/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './app';
2
+ export * from './types';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./app"), exports);
18
+ __exportStar(require("./types"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/express-app/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wCAAsB;AACtB,0CAAwB"}
@@ -0,0 +1,3 @@
1
+ import type { Application } from 'express-serve-static-core';
2
+ import { InternalLocals, ServiceExpress } from '../types';
3
+ export declare function startInternalApp(mainApp: ServiceExpress, port: number): Promise<Application<InternalLocals>>;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.startInternalApp = void 0;
7
+ const express_1 = __importDefault(require("express"));
8
+ async function startInternalApp(mainApp, port) {
9
+ const app = (0, express_1.default)();
10
+ app.locals.mainApp = mainApp;
11
+ app.get('/health', async (req, res) => {
12
+ if (mainApp.locals.service?.healthy) {
13
+ try {
14
+ const ok = await mainApp.locals.service.healthy(mainApp);
15
+ res.sendStatus(ok ? 204 : 500);
16
+ }
17
+ catch (error) {
18
+ mainApp.locals.logger.error(error, 'Health check failed');
19
+ }
20
+ }
21
+ else {
22
+ res.sendStatus(204);
23
+ }
24
+ });
25
+ const listenPromise = new Promise((accept) => {
26
+ app.locals.server = app.listen(port, () => {
27
+ accept();
28
+ });
29
+ });
30
+ await listenPromise;
31
+ return app;
32
+ }
33
+ exports.startInternalApp = startInternalApp;
34
+ //# sourceMappingURL=internal-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-server.js","sourceRoot":"","sources":["../../src/express-app/internal-server.ts"],"names":[],"mappings":";;;;;;AAAA,sDAA8B;AAKvB,KAAK,UAAU,gBAAgB,CAAC,OAAuB,EAAE,IAAY;IAC1E,MAAM,GAAG,GAAG,IAAA,iBAAO,GAA4C,CAAC;IAChE,GAAG,CAAC,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IAE7B,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACpC,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE;YACnC,IAAI;gBACF,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBACzD,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;aAChC;YAAC,OAAO,KAAK,EAAE;gBACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,qBAAqB,CAAC,CAAC;aAC3D;SACF;aAAM;YACL,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SACrB;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,IAAI,OAAO,CAAO,CAAC,MAAM,EAAE,EAAE;QACjD,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;YACxC,MAAM,EAAE,CAAC;QACX,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,aAAa,CAAC;IACpB,OAAO,GAAG,CAAC;AACb,CAAC;AAzBD,4CAyBC"}
@@ -0,0 +1,2 @@
1
+ import type { ServiceExpress } from '../types';
2
+ export declare function loadRoutes(app: ServiceExpress, routingDir: string, pattern: string): Promise<void>;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadRoutes = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const glob_1 = require("glob");
9
+ const express_1 = __importDefault(require("express"));
10
+ async function loadRoutes(app, routingDir, pattern) {
11
+ const files = await new Promise((accept, reject) => {
12
+ (0, glob_1.glob)(pattern, {
13
+ nodir: true,
14
+ strict: true,
15
+ cwd: routingDir,
16
+ }, (error, matches) => (error ? reject(error) : accept(matches)));
17
+ });
18
+ await Promise.all(files.map(async (filename) => {
19
+ const routeBase = path_1.default.dirname(filename);
20
+ const modulePath = path_1.default.resolve(routingDir, filename);
21
+ // Need to use require for loading .ts files
22
+ // eslint-disable-next-line import/no-dynamic-require, global-require, @typescript-eslint/no-var-requires
23
+ const module = require(modulePath);
24
+ const mounter = module.default || module.route;
25
+ if (typeof mounter === 'function') {
26
+ const childRouter = express_1.default.Router();
27
+ mounter(childRouter, app);
28
+ const pathParts = [''];
29
+ if (routeBase !== '.') {
30
+ pathParts.push(routeBase);
31
+ }
32
+ const fn = path_1.default.parse(path_1.default.basename(filename)).name;
33
+ if (fn.toLowerCase() !== 'index') {
34
+ pathParts.push(fn);
35
+ }
36
+ const finalPath = pathParts.join('/') || '/';
37
+ app.locals.logger.debug({ path: finalPath, source: filename }, 'Registering route');
38
+ app.use(finalPath, childRouter);
39
+ }
40
+ else {
41
+ app.locals.logger.warn({ filename }, 'Route file had no default export');
42
+ }
43
+ }));
44
+ }
45
+ exports.loadRoutes = loadRoutes;
46
+ //# sourceMappingURL=route-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-loader.js","sourceRoot":"","sources":["../../src/express-app/route-loader.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AAExB,+BAA4B;AAC5B,sDAA8B;AAIvB,KAAK,UAAU,UAAU,CAAC,GAAmB,EAAE,UAAkB,EAAE,OAAe;IACvF,MAAM,KAAK,GAAa,MAAM,IAAI,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE;QAC3D,IAAA,WAAI,EACF,OAAO,EACP;YACE,KAAK,EAAE,IAAI;YACX,MAAM,EAAE,IAAI;YACZ,GAAG,EAAE,UAAU;SAChB,EACD,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAC9D,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,GAAG,CACf,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;QAC3B,MAAM,SAAS,GAAG,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,UAAU,GAAG,cAAI,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACtD,4CAA4C;QAC5C,yGAAyG;QACzG,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC;QAC/C,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE;YACjC,MAAM,WAAW,GAAG,iBAAO,CAAC,MAAM,EAAE,CAAC;YACrC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;YAC1B,MAAM,SAAS,GAAG,CAAC,EAAE,CAAC,CAAC;YACvB,IAAI,SAAS,KAAK,GAAG,EAAE;gBACrB,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;aAC3B;YACD,MAAM,EAAE,GAAG,cAAI,CAAC,KAAK,CAAC,cAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;YACpD,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,OAAO,EAAE;gBAChC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aACpB;YACD,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;YAC7C,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,mBAAmB,CAAC,CAAC;YACpF,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;SACjC;aAAM;YACL,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,kCAAkC,CAAC,CAAC;SAC1E;IACH,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAxCD,gCAwCC"}
@@ -0,0 +1,14 @@
1
+ import type { NextFunction, Response } from 'express';
2
+ import type { RequestLocals, RequestWithApp, ServiceLocals } from '../types';
3
+ export type ServiceHandler<SLocals extends ServiceLocals = ServiceLocals, RLocals extends RequestLocals = RequestLocals, ResBody = unknown, RetType = unknown> = (req: RequestWithApp<SLocals>, res: Response<ResBody, RLocals>, next: NextFunction) => RetType | Promise<RetType>;
4
+ export interface ServiceRouter<SLocals extends ServiceLocals = ServiceLocals, RLocals extends RequestLocals = RequestLocals> {
5
+ all(path: string, ...handlers: ServiceHandler<SLocals, RLocals>[]): void;
6
+ get(path: string, ...handlers: ServiceHandler<SLocals, RLocals>[]): void;
7
+ post(path: string, ...handlers: ServiceHandler<SLocals, RLocals>[]): void;
8
+ put(path: string, ...handlers: ServiceHandler<SLocals, RLocals>[]): void;
9
+ delete(path: string, ...handlers: ServiceHandler<SLocals, RLocals>[]): void;
10
+ patch(path: string, ...handlers: ServiceHandler<SLocals, RLocals>[]): void;
11
+ options(path: string, ...handlers: ServiceHandler<SLocals, RLocals>[]): void;
12
+ head(path: string, ...handlers: ServiceHandler<SLocals, RLocals>[]): void;
13
+ use(...handlers: ServiceHandler<SLocals, RLocals>[]): void;
14
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/express-app/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ export * from './telemetry';
2
+ export * from './service-calls';
3
+ export * from './express-app';
4
+ export * from './types';
5
+ export * from './env';
6
+ export * from './config';
7
+ export * from './error';
8
+ export * from './bootstrap';
package/build/index.js ADDED
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./telemetry"), exports);
18
+ __exportStar(require("./service-calls"), exports);
19
+ __exportStar(require("./express-app"), exports);
20
+ __exportStar(require("./types"), exports);
21
+ __exportStar(require("./env"), exports);
22
+ __exportStar(require("./config"), exports);
23
+ __exportStar(require("./error"), exports);
24
+ __exportStar(require("./bootstrap"), exports);
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,kDAAgC;AAChC,gDAA8B;AAC9B,0CAAwB;AACxB,wCAAsB;AACtB,2CAAyB;AACzB,0CAAwB;AACxB,8CAA4B"}
@@ -0,0 +1,5 @@
1
+ import * as OpenApiValidator from 'express-openapi-validator';
2
+ import type { ServiceExpress } from './types';
3
+ type OAPIOpts = Parameters<typeof OpenApiValidator.middleware>[0];
4
+ export declare function openApi(app: ServiceExpress, rootDirectory: string, codepath: string, openApiOptions?: Partial<OAPIOpts>): import("express-openapi-validator/dist/framework/types").OpenApiRequestHandler[];
5
+ export {};
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.openApi = void 0;
30
+ const path_1 = __importDefault(require("path"));
31
+ const lodash_1 = __importDefault(require("lodash"));
32
+ const OpenApiValidator = __importStar(require("express-openapi-validator"));
33
+ const notImplementedHandler = (req, res) => {
34
+ res.status(501).json({
35
+ code: 'NotImplemented',
36
+ domain: 'http',
37
+ message: 'This method is not yet implemented',
38
+ });
39
+ };
40
+ function openApi(app, rootDirectory, codepath, openApiOptions) {
41
+ const apiSpec = path_1.default.resolve(rootDirectory, `./api/${app.locals.name}.yaml`);
42
+ app.locals.logger.debug({ apiSpec, codepath }, 'Serving OpenAPI');
43
+ const defaultOptions = {
44
+ apiSpec,
45
+ ignoreUndocumented: true,
46
+ validateRequests: {
47
+ allowUnknownQueryParameters: true,
48
+ coerceTypes: 'array',
49
+ },
50
+ operationHandlers: {
51
+ basePath: path_1.default.resolve(rootDirectory, `${codepath}/handlers`),
52
+ resolver(basePath, route) {
53
+ const pathKey = route.openApiRoute.substring(route.basePath.length);
54
+ const modulePath = path_1.default.join(basePath, pathKey);
55
+ try {
56
+ // eslint-disable-next-line import/no-dynamic-require, global-require, @typescript-eslint/no-var-requires
57
+ const module = require(modulePath);
58
+ const method = Object.keys(module).find((m) => m.toUpperCase() === route.method);
59
+ if (!method) {
60
+ throw new Error(`Could not find a [${route.method}] function in ${modulePath} when trying to route [${route.method} ${route.expressRoute}].`);
61
+ }
62
+ return module[method];
63
+ }
64
+ catch (error) {
65
+ app.locals.logger.error({
66
+ error: error.message,
67
+ pathKey,
68
+ modulePath: path_1.default.relative(rootDirectory, modulePath),
69
+ }, 'Failed to load API method handler');
70
+ return notImplementedHandler;
71
+ }
72
+ },
73
+ },
74
+ };
75
+ return OpenApiValidator.middleware(lodash_1.default.defaultsDeep(defaultOptions, openApiOptions || {}));
76
+ }
77
+ exports.openApi = openApi;
78
+ //# sourceMappingURL=openapi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.js","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAAwB;AAExB,oDAAuB;AACvB,4EAA8D;AAK9D,MAAM,qBAAqB,GAAY,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IAClD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,oCAAoC;KAC9C,CAAC,CAAC;AACL,CAAC,CAAC;AAIF,SAAgB,OAAO,CACrB,GAAmB,EACnB,aAAqB,EACrB,QAAgB,EAChB,cAAkC;IAElC,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,aAAa,EAAE,SAAS,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,CAAC;IAC7E,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,iBAAiB,CAAC,CAAC;IAElE,MAAM,cAAc,GAAa;QAC/B,OAAO;QACP,kBAAkB,EAAE,IAAI;QACxB,gBAAgB,EAAE;YAChB,2BAA2B,EAAE,IAAI;YACjC,WAAW,EAAE,OAAO;SACrB;QACD,iBAAiB,EAAE;YACjB,QAAQ,EAAE,cAAI,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,QAAQ,WAAW,CAAC;YAC7D,QAAQ,CAAC,QAAgB,EAAE,KAAuE;gBAChG,MAAM,OAAO,GAAG,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACpE,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAEhD,IAAI;oBACF,yGAAyG;oBACzG,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;oBACnC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC;oBACjF,IAAI,CAAC,MAAM,EAAE;wBACX,MAAM,IAAI,KAAK,CACb,qBAAqB,KAAK,CAAC,MAAM,iBAAiB,UAAU,0BAA0B,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,CAC7H,CAAC;qBACH;oBACD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;iBACvB;gBAAC,OAAO,KAAK,EAAE;oBACd,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CACrB;wBACE,KAAK,EAAG,KAAe,CAAC,OAAO;wBAC/B,OAAO;wBACP,UAAU,EAAE,cAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,UAAU,CAAC;qBACrD,EACD,mCAAmC,CACpC,CAAC;oBACF,OAAO,qBAAqB,CAAC;iBAC9B;YACH,CAAC;SACF;KACF,CAAC;IAEF,OAAO,gBAAgB,CAAC,UAAU,CAAC,gBAAC,CAAC,YAAY,CAAC,cAAc,EAAE,cAAc,IAAI,EAAE,CAAC,CAAC,CAAC;AAC3F,CAAC;AAhDD,0BAgDC"}
@@ -0,0 +1,16 @@
1
+ import type { FetchConfig, RestApiResponse } from 'rest-api-support';
2
+ import { ServiceErrorSpec } from '../error';
3
+ import type { ServiceExpress, ServiceLike, ServiceLocals } from '../types';
4
+ /**
5
+ * Return a factory that will make instances of an OpenAPI/Swagger client for each request
6
+ */
7
+ export declare function createServiceInterface<ServiceType>(service: ServiceExpress, name: string, Implementation: {
8
+ new (c: FetchConfig): ServiceType;
9
+ }): ServiceType;
10
+ interface SpecWithMessage extends ServiceErrorSpec {
11
+ message?: string;
12
+ }
13
+ export declare function throwOrGetResponse<SLocals extends ServiceLocals, AppType extends ServiceLike<SLocals>, ResType extends RestApiResponse<number, SuccessResponseType>, SuccessResponseType>(app: AppType, exec: () => Promise<ResType>, errorSpec?: SpecWithMessage): Promise<Extract<ResType, {
14
+ responseType: 'response';
15
+ }>>;
16
+ export {};