@openapi-typescript-infra/service 6.10.1 → 6.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/bootstrap.js +4 -2
- package/build/bootstrap.js.map +1 -1
- package/package.json +8 -2
- package/.github/workflows/codeql-analysis.yml +0 -77
- package/.github/workflows/nodejs.yml +0 -62
- package/.trunk/configs/.markdownlint.yaml +0 -10
- package/.trunk/configs/.yamllint.yaml +0 -10
- package/.trunk/trunk.yaml +0 -35
- package/.yarn/patches/confit-npm-3.0.0-eade8c7ce1.patch +0 -52
- package/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs +0 -541
- package/.yarn/releases/yarn-3.2.3.cjs +0 -783
- package/.yarnrc.yml +0 -7
- package/CHANGELOG.md +0 -525
- package/SECURITY.md +0 -12
- package/__tests__/config.test.ts +0 -53
- package/__tests__/fake-serv/api/fake-serv.yaml +0 -48
- package/__tests__/fake-serv/config/config.json +0 -13
- package/__tests__/fake-serv/src/handlers/hello.ts +0 -17
- package/__tests__/fake-serv/src/index.ts +0 -36
- package/__tests__/fake-serv/src/routes/error.ts +0 -16
- package/__tests__/fake-serv/src/routes/index.ts +0 -19
- package/__tests__/fake-serv/src/routes/other/world.ts +0 -7
- package/__tests__/fake-serv.test.ts +0 -119
- package/__tests__/vitest.test-setup.ts +0 -15
- package/src/bin/start-service.ts +0 -32
- package/src/bootstrap.ts +0 -160
- package/src/config/index.ts +0 -124
- package/src/config/schema.ts +0 -70
- package/src/config/shortstops.ts +0 -155
- package/src/config/validation.ts +0 -23
- package/src/development/port-finder.ts +0 -67
- package/src/development/repl.ts +0 -131
- package/src/env.ts +0 -29
- package/src/error.ts +0 -47
- package/src/express-app/app.ts +0 -438
- package/src/express-app/index.ts +0 -3
- package/src/express-app/internal-server.ts +0 -43
- package/src/express-app/modules.ts +0 -10
- package/src/express-app/route-loader.ts +0 -40
- package/src/express-app/types.ts +0 -32
- package/src/hook.ts +0 -36
- package/src/index.ts +0 -9
- package/src/openapi.ts +0 -184
- package/src/telemetry/DummyExporter.ts +0 -17
- package/src/telemetry/hook-modules.ts +0 -8
- package/src/telemetry/index.ts +0 -168
- package/src/telemetry/instrumentations.ts +0 -103
- package/src/telemetry/requestLogger.ts +0 -267
- package/src/tsx.d.ts +0 -1
- package/src/types.ts +0 -223
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
import type { RequestHandler, Request, Response, ErrorRequestHandler } from 'express';
|
|
2
|
-
import { getClientIp } from 'request-ip';
|
|
3
|
-
import type { Histogram } from '@opentelemetry/api';
|
|
4
|
-
import cleanStack from 'clean-stack';
|
|
5
|
-
|
|
6
|
-
import { ServiceError } from '../error.js';
|
|
7
|
-
import type { AnyServiceLocals, RequestWithApp, ServiceExpress, ServiceLocals } from '../types.js';
|
|
8
|
-
import type { ServiceHandler } from '../express-app/types.js';
|
|
9
|
-
import type { ConfigurationSchema } from '../config/schema.js';
|
|
10
|
-
import { getNodeEnv } from '../env.js';
|
|
11
|
-
|
|
12
|
-
const LOG_PREFS = Symbol('Logging information');
|
|
13
|
-
const LOGGED_SEMAPHORE = Symbol('Logged semaphore');
|
|
14
|
-
|
|
15
|
-
interface LogPrefs {
|
|
16
|
-
start: [number, number];
|
|
17
|
-
logRequests?: boolean;
|
|
18
|
-
chunks?: Buffer[];
|
|
19
|
-
logged: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
interface WithLogPrefs {
|
|
23
|
-
[LOG_PREFS]: LogPrefs;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
interface WithIdentifiedSession {
|
|
27
|
-
session?: {
|
|
28
|
-
id?: string;
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface ErrorWithStatus extends Error {
|
|
33
|
-
status?: number;
|
|
34
|
-
expected_error?: boolean;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function getBasicInfo(req: Request): [string, Record<string, string | number>] {
|
|
38
|
-
const url = req.originalUrl || req.url;
|
|
39
|
-
|
|
40
|
-
const preInfo: Record<string, string> = {
|
|
41
|
-
ip: getClientIp(req) || '',
|
|
42
|
-
m: req.method,
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
if (req.headers['user-agent']) {
|
|
46
|
-
preInfo.ua = req.headers['user-agent'];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const sessionReq = req as WithIdentifiedSession;
|
|
50
|
-
if (sessionReq.session?.id) {
|
|
51
|
-
preInfo.sid = sessionReq.session.id;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return [url, preInfo];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function finishLog<SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>>(
|
|
58
|
-
app: ServiceExpress<SLocals>,
|
|
59
|
-
error: Error | undefined,
|
|
60
|
-
req: Request,
|
|
61
|
-
res: Response & { [LOGGED_SEMAPHORE]?: boolean },
|
|
62
|
-
histogram: Histogram,
|
|
63
|
-
) {
|
|
64
|
-
if (res[LOGGED_SEMAPHORE]) {
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const prefs = (res.locals as WithLogPrefs)[LOG_PREFS] || {};
|
|
69
|
-
if (prefs.logged) {
|
|
70
|
-
// This happens when error handler runs, but onEnd hasn't fired yet. We only log the first one.
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const { logger, service } = app.locals;
|
|
75
|
-
|
|
76
|
-
let dur = 0;
|
|
77
|
-
if (prefs.start) {
|
|
78
|
-
const hrdur = process.hrtime(prefs.start);
|
|
79
|
-
dur = hrdur[0] + hrdur[1] / 1000000000;
|
|
80
|
-
}
|
|
81
|
-
const [url, preInfo] = getBasicInfo(req);
|
|
82
|
-
|
|
83
|
-
let responseType = 'unknown';
|
|
84
|
-
|
|
85
|
-
if (res.writableFinished) {
|
|
86
|
-
responseType = 'finished';
|
|
87
|
-
} else if (req.aborted) {
|
|
88
|
-
responseType = 'aborted';
|
|
89
|
-
} else if (req.destroyed) {
|
|
90
|
-
responseType = 'destroyed';
|
|
91
|
-
} else if (error) {
|
|
92
|
-
responseType = 'errored';
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const endLog: Record<string, string | string[] | number | undefined> = {
|
|
96
|
-
...preInfo,
|
|
97
|
-
t: 'req',
|
|
98
|
-
r: responseType,
|
|
99
|
-
s: (error as ErrorWithStatus)?.status || res.statusCode || 0,
|
|
100
|
-
dur,
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const path = req.route ? { path: req.route.path } : undefined;
|
|
104
|
-
histogram.record(dur, {
|
|
105
|
-
status_code: endLog.s,
|
|
106
|
-
method: endLog.m,
|
|
107
|
-
...path,
|
|
108
|
-
service: app.locals.name,
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
if (res.locals.user?.id) {
|
|
112
|
-
endLog.u = res.locals.user.id;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
let unexpectedError = false;
|
|
116
|
-
if (error) {
|
|
117
|
-
endLog.e = error.message;
|
|
118
|
-
if (!(error instanceof ServiceError) || error.log_stack) {
|
|
119
|
-
endLog.st = cleanStack(error.stack);
|
|
120
|
-
}
|
|
121
|
-
if (!(error as ErrorWithStatus).expected_error) {
|
|
122
|
-
unexpectedError = true;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (prefs.logRequests) {
|
|
127
|
-
endLog.h = JSON.stringify(req.headers);
|
|
128
|
-
if (Buffer.isBuffer(req.body)) {
|
|
129
|
-
endLog.b = req.body.toString('base64');
|
|
130
|
-
} else if (typeof req.body !== 'string') {
|
|
131
|
-
endLog.b = JSON.stringify(req.body);
|
|
132
|
-
} else if (req.body) {
|
|
133
|
-
endLog.b = req.body;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (prefs.chunks?.length) {
|
|
138
|
-
const bodyString = Buffer.concat(prefs.chunks).toString('utf8');
|
|
139
|
-
if (bodyString) {
|
|
140
|
-
endLog.resBody = bodyString;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
const msg = service.getLogFields?.(req as RequestWithApp<SLocals>, endLog);
|
|
144
|
-
if (msg === false) {
|
|
145
|
-
res[LOGGED_SEMAPHORE] = true;
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
if (unexpectedError) {
|
|
149
|
-
logger.error(endLog, msg || url);
|
|
150
|
-
} else {
|
|
151
|
-
logger.info(endLog, msg || url);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
res[LOGGED_SEMAPHORE] = true;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export function loggerMiddleware<
|
|
158
|
-
SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>,
|
|
159
|
-
>(
|
|
160
|
-
app: ServiceExpress<SLocals>,
|
|
161
|
-
histogram: Histogram,
|
|
162
|
-
config?: ConfigurationSchema['logging'],
|
|
163
|
-
): RequestHandler {
|
|
164
|
-
const nonProd = getNodeEnv() !== 'production';
|
|
165
|
-
const { logger, service } = app.locals;
|
|
166
|
-
return function serviceLogger(req, res, next) {
|
|
167
|
-
const logResponse =
|
|
168
|
-
config?.logResponseBody || (nonProd && req.headers['x-log']?.includes('res'));
|
|
169
|
-
const logRequest = config?.logRequestBody || (nonProd && req.headers['x-log']?.includes('req'));
|
|
170
|
-
const prefs: LogPrefs = {
|
|
171
|
-
start: process.hrtime(),
|
|
172
|
-
logRequests: logRequest,
|
|
173
|
-
chunks: logResponse ? [] : undefined,
|
|
174
|
-
logged: false,
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
(res.locals as WithLogPrefs)[LOG_PREFS] = prefs;
|
|
178
|
-
|
|
179
|
-
if (logResponse) {
|
|
180
|
-
// res is a read-only stream, so the only way to intercept response
|
|
181
|
-
// data is to monkey-patch.
|
|
182
|
-
const oldWrite = res.write;
|
|
183
|
-
const oldEnd = res.end;
|
|
184
|
-
res.write = ((...args: Parameters<(typeof res)['write']>) => {
|
|
185
|
-
if (prefs.chunks) {
|
|
186
|
-
prefs.chunks.push(Buffer.isBuffer(args[0]) ? args[0] : Buffer.from(args[0] as string));
|
|
187
|
-
}
|
|
188
|
-
return (oldWrite as (typeof res)['write']).apply(res, args);
|
|
189
|
-
}) as (typeof res)['write'];
|
|
190
|
-
res.end = ((...args: Parameters<(typeof res)['end']>) => {
|
|
191
|
-
if (args[0] && prefs.chunks) {
|
|
192
|
-
prefs.chunks.push(Buffer.isBuffer(args[0]) ? args[0] : Buffer.from(args[0] as string));
|
|
193
|
-
}
|
|
194
|
-
return oldEnd.apply(res, args);
|
|
195
|
-
}) as (typeof res)['end'];
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (config?.preLog) {
|
|
199
|
-
const [url, preInfo] = getBasicInfo(req);
|
|
200
|
-
const preLog: Record<string, string | string[] | number | undefined> = {
|
|
201
|
-
...preInfo,
|
|
202
|
-
t: 'pre',
|
|
203
|
-
ref: req.headers.referer || undefined,
|
|
204
|
-
sid: (req as WithIdentifiedSession).session?.id,
|
|
205
|
-
c: req.headers.correlationid || undefined,
|
|
206
|
-
};
|
|
207
|
-
const msg = service.getLogFields?.(req as RequestWithApp<SLocals>, preLog);
|
|
208
|
-
if (msg !== false) {
|
|
209
|
-
logger.info(preLog, msg || url);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const logWriter = (err?: Error) => finishLog(app, err, req, res, histogram);
|
|
214
|
-
res.on('finish', logWriter);
|
|
215
|
-
res.on('close', logWriter);
|
|
216
|
-
res.on('error', logWriter);
|
|
217
|
-
next();
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export function errorHandlerMiddleware<
|
|
222
|
-
SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>,
|
|
223
|
-
>(app: ServiceExpress<SLocals>, histogram: Histogram, unnest?: boolean, returnError?: boolean) {
|
|
224
|
-
const svcErrorHandler: ErrorRequestHandler = (error, req, res, next) => {
|
|
225
|
-
let loggable: Partial<ServiceError> = error;
|
|
226
|
-
const body = error.response?.body || error.body;
|
|
227
|
-
if (unnest && body?.domain && body?.code && body?.message) {
|
|
228
|
-
loggable = {
|
|
229
|
-
status: error.status,
|
|
230
|
-
message: body.message,
|
|
231
|
-
domain: body.domain,
|
|
232
|
-
code: body.code,
|
|
233
|
-
display_message: body.display_message,
|
|
234
|
-
...loggable.client_metadata,
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
// Set the status to error, even if we aren't going to render the error.
|
|
238
|
-
res.status(loggable.status || 500);
|
|
239
|
-
if (returnError) {
|
|
240
|
-
finishLog(app, error as Error, req, res, histogram);
|
|
241
|
-
const prefs = (res.locals as WithLogPrefs)[LOG_PREFS];
|
|
242
|
-
prefs.logged = true;
|
|
243
|
-
res.json({
|
|
244
|
-
code: loggable.code,
|
|
245
|
-
message: loggable.message,
|
|
246
|
-
domain: loggable.domain,
|
|
247
|
-
display_message: loggable.display_message,
|
|
248
|
-
...loggable.client_metadata,
|
|
249
|
-
});
|
|
250
|
-
} else {
|
|
251
|
-
next(error);
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
return svcErrorHandler;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
export function notFoundMiddleware() {
|
|
258
|
-
const serviceNotFoundHandler: ServiceHandler = (req, res, next) => {
|
|
259
|
-
const error = new ServiceError(req.app, `Cannot ${req.method} ${req.path}`, {
|
|
260
|
-
status: 404,
|
|
261
|
-
code: 'NotFound',
|
|
262
|
-
domain: 'http',
|
|
263
|
-
});
|
|
264
|
-
next(error);
|
|
265
|
-
};
|
|
266
|
-
return serviceNotFoundHandler as RequestHandler;
|
|
267
|
-
}
|
package/src/tsx.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
declare module 'tsx/esm';
|
package/src/types.ts
DELETED
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import type { Server } from 'node:http';
|
|
2
|
-
import type { REPLServer } from 'node:repl';
|
|
3
|
-
|
|
4
|
-
import type { BaseLogger, Logger } from 'pino';
|
|
5
|
-
import type { Request, Response } from 'express';
|
|
6
|
-
import type { Application } from 'express-serve-static-core';
|
|
7
|
-
import type { middleware } from 'express-openapi-validator';
|
|
8
|
-
import type { Meter } from '@opentelemetry/api';
|
|
9
|
-
import type { NodeSDKConfiguration } from '@opentelemetry/sdk-node';
|
|
10
|
-
import type { ShortstopHandler } from '@sesamecare-oss/confit';
|
|
11
|
-
|
|
12
|
-
import type { ConfigurationSchema } from './config/schema.js';
|
|
13
|
-
|
|
14
|
-
export interface InternalLocals<
|
|
15
|
-
SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>,
|
|
16
|
-
> extends Record<string, unknown> {
|
|
17
|
-
server?: Server;
|
|
18
|
-
mainApp: ServiceExpress<SLocals>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type ServiceLogger = BaseLogger & Pick<Logger, 'isLevelEnabled'>;
|
|
22
|
-
|
|
23
|
-
// Vanilla express wants this to extend Record<string, any> but this is a mistake
|
|
24
|
-
// because you lose type checking on it, even though I get that underneath it truly
|
|
25
|
-
// is Record<string, any>
|
|
26
|
-
export interface ServiceLocals<Config extends ConfigurationSchema = ConfigurationSchema> {
|
|
27
|
-
service: Service;
|
|
28
|
-
name: string;
|
|
29
|
-
version: string;
|
|
30
|
-
logger: ServiceLogger;
|
|
31
|
-
config: Config;
|
|
32
|
-
meter: Meter;
|
|
33
|
-
internalApp: Application<InternalLocals<this>>;
|
|
34
|
-
/**
|
|
35
|
-
* This is the parsed OpenAPI spec we are hosting (if openapi is enabled)
|
|
36
|
-
*/
|
|
37
|
-
openApiSpecification?: ReturnType<typeof JSON.parse>;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface RequestLocals {
|
|
41
|
-
// Set this to true during the request "attachment" and if there is a body,
|
|
42
|
-
// it will be set to the buffer before API and route handlers run.
|
|
43
|
-
rawBody?: Buffer | true;
|
|
44
|
-
logger: ServiceLogger;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export type ServiceExpress<Locals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>> =
|
|
48
|
-
Application<Locals>;
|
|
49
|
-
|
|
50
|
-
export type RequestWithApp<Locals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>> =
|
|
51
|
-
Omit<Request, 'app'> & {
|
|
52
|
-
app: Application<Locals>;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export type ResponseFromApp<
|
|
56
|
-
ResBody = unknown,
|
|
57
|
-
RLocals extends RequestLocals = RequestLocals,
|
|
58
|
-
> = Response<ResBody, RLocals>;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* This is the core type you need to implement to provide a service
|
|
62
|
-
*/
|
|
63
|
-
export interface Service<
|
|
64
|
-
SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>,
|
|
65
|
-
RLocals extends RequestLocals = RequestLocals,
|
|
66
|
-
> {
|
|
67
|
-
name?: string;
|
|
68
|
-
|
|
69
|
-
// Modify options used for application start
|
|
70
|
-
configure?: (
|
|
71
|
-
startOptions: ServiceStartOptions<SLocals, RLocals>,
|
|
72
|
-
options: ServiceOptions,
|
|
73
|
-
) => ServiceOptions;
|
|
74
|
-
|
|
75
|
-
// Run after configuration but before routes are loaded,
|
|
76
|
-
// which is often a good place to add elements to the app locals
|
|
77
|
-
// that are needed during route setup
|
|
78
|
-
attach?: (app: ServiceExpress<SLocals>) => void | Promise<void>;
|
|
79
|
-
|
|
80
|
-
// Called after a server is created but before the server starts listening
|
|
81
|
-
attachServer?: (app: ServiceExpress<SLocals>, server: Server) => void | Promise<void>;
|
|
82
|
-
// Called after the server is listening
|
|
83
|
-
onListening?: (
|
|
84
|
-
app: ServiceExpress<SLocals>,
|
|
85
|
-
info: { port?: number; protocol: 'http' | 'https' },
|
|
86
|
-
) => void | Promise<void>;
|
|
87
|
-
|
|
88
|
-
start(app: ServiceExpress<SLocals>): void | Promise<void>;
|
|
89
|
-
|
|
90
|
-
stop?: (app: ServiceExpress<SLocals>) => void | Promise<void>;
|
|
91
|
-
|
|
92
|
-
healthy?: (app: ServiceExpress<SLocals>) => boolean | Promise<boolean>;
|
|
93
|
-
|
|
94
|
-
// This runs as middleware right BEFORE the body parsers.
|
|
95
|
-
// If you want to run AFTER the body parsers, the current
|
|
96
|
-
// way to do that would be via /routes/index.ts and router.use()
|
|
97
|
-
// in that file.
|
|
98
|
-
onRequest?(req: RequestWithApp<SLocals>, res: Response<unknown, RLocals>): void | Promise<void>;
|
|
99
|
-
|
|
100
|
-
// This runs after body parsing but before routing
|
|
101
|
-
authorize?(
|
|
102
|
-
req: RequestWithApp<SLocals>,
|
|
103
|
-
res: Response<unknown, RLocals>,
|
|
104
|
-
): boolean | Promise<boolean>;
|
|
105
|
-
|
|
106
|
-
// Add or redact any fields for logging. Note this will be called twice per request,
|
|
107
|
-
// once at the start and once at the end. Modify the values directly. Return a
|
|
108
|
-
// string to control the "msg" field of the logs, or return undefined to leave it
|
|
109
|
-
// as the default, which is the request URL. Return false to suppress the log entirely.
|
|
110
|
-
getLogFields?(
|
|
111
|
-
req: RequestWithApp<SLocals>,
|
|
112
|
-
values: Record<string, string | string[] | number | undefined>,
|
|
113
|
-
): string | false | undefined;
|
|
114
|
-
|
|
115
|
-
// The repl is a useful tool for diagnosing issues in non-dev environments.
|
|
116
|
-
// The attachRepl method provides a way to add custom functionality
|
|
117
|
-
// (typically with top level variables) to the repl.
|
|
118
|
-
attachRepl?(app: ServiceExpress<SLocals>, repl: REPLServer): void;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export type ServiceFactory<
|
|
122
|
-
SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>,
|
|
123
|
-
RLocals extends RequestLocals = RequestLocals,
|
|
124
|
-
> = () => Service<SLocals, RLocals>;
|
|
125
|
-
|
|
126
|
-
export interface ServiceStartOptions<
|
|
127
|
-
SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>,
|
|
128
|
-
RLocals extends RequestLocals = RequestLocals,
|
|
129
|
-
> {
|
|
130
|
-
name: string;
|
|
131
|
-
version: string;
|
|
132
|
-
rootDirectory: string;
|
|
133
|
-
|
|
134
|
-
// Defaults to "build", but can be set to "src" to run off non-built source
|
|
135
|
-
codepath?: 'build' | 'src' | 'dist';
|
|
136
|
-
|
|
137
|
-
// NOTE: if you use this, you need to cast it because of a Typescript error:
|
|
138
|
-
// https://github.com/microsoft/TypeScript/issues/22229
|
|
139
|
-
// locals: { stuff } as Partial<MyLocals>
|
|
140
|
-
locals?: Partial<SLocals>;
|
|
141
|
-
|
|
142
|
-
// And finally, the function that creates the service instance
|
|
143
|
-
service: () => Service<SLocals, RLocals>;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export interface DelayLoadServiceStartOptions extends Omit<ServiceStartOptions, 'service'> {
|
|
147
|
-
service: string;
|
|
148
|
-
customizer?:
|
|
149
|
-
| ((options: Partial<NodeSDKConfiguration>) => Partial<NodeSDKConfiguration>)
|
|
150
|
-
| undefined;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Handled by service.configure
|
|
154
|
-
export interface ServiceOptions {
|
|
155
|
-
// Used to resolve code paths flexibly during dev/prod
|
|
156
|
-
codepath?: string;
|
|
157
|
-
// Will be either .ts or .js depending on the runtime environment
|
|
158
|
-
codeExtension?: string;
|
|
159
|
-
|
|
160
|
-
// If you need multiple configuration directories, pass them here
|
|
161
|
-
// in the desired order (later trumps earlier)
|
|
162
|
-
configurationDirectories: string[];
|
|
163
|
-
|
|
164
|
-
// Add or control OpenAPI options such as security handlers
|
|
165
|
-
openApiOptions?: Partial<Parameters<typeof middleware>[0]>;
|
|
166
|
-
|
|
167
|
-
shortstopHandlers: Record<string, ShortstopHandler<string, unknown>>;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export interface ServiceLike<
|
|
171
|
-
SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>,
|
|
172
|
-
> {
|
|
173
|
-
locals: SLocals;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* This type should be used (or extended) to pass "context"
|
|
178
|
-
* into functions not directly wired into the Express request
|
|
179
|
-
* handling flow. It will allow "synthetic" requests to be
|
|
180
|
-
* easily constructed without depending on things they should not,
|
|
181
|
-
* like query strings or body or similar. Most often, you want the
|
|
182
|
-
* logger.
|
|
183
|
-
*/
|
|
184
|
-
export interface RequestLike<
|
|
185
|
-
SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>,
|
|
186
|
-
RLocals extends RequestLocals = RequestLocals,
|
|
187
|
-
> {
|
|
188
|
-
app: ServiceLike<SLocals>;
|
|
189
|
-
res: {
|
|
190
|
-
locals: RLocals;
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Define some utility types to make it easier to put them all
|
|
195
|
-
// in one export. This interface never actually is instantiated.
|
|
196
|
-
// Typically you should export an interface that extends this one
|
|
197
|
-
// and then access all your types through that.
|
|
198
|
-
export interface ServiceTypes<
|
|
199
|
-
SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>,
|
|
200
|
-
RLocals extends RequestLocals = RequestLocals,
|
|
201
|
-
ResBody = unknown,
|
|
202
|
-
> {
|
|
203
|
-
App: ServiceExpress<SLocals>;
|
|
204
|
-
Handler: (
|
|
205
|
-
req: RequestWithApp<SLocals>,
|
|
206
|
-
res: ResponseFromApp<ResBody, RLocals>,
|
|
207
|
-
) => void | Promise<void>;
|
|
208
|
-
Request: RequestWithApp<SLocals>;
|
|
209
|
-
RequestLike: RequestLike<SLocals, RLocals>;
|
|
210
|
-
RequestLocals: RLocals;
|
|
211
|
-
Response: ResponseFromApp<ResBody, RLocals>;
|
|
212
|
-
Service: Service<SLocals, RLocals>;
|
|
213
|
-
ServiceFactory: ServiceFactory<SLocals, RLocals>;
|
|
214
|
-
ServiceLocals: SLocals;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
export type UnwrapServiceConfig<SLocals extends ServiceLocals> =
|
|
218
|
-
SLocals extends ServiceLocals<infer C> ? C : never;
|
|
219
|
-
|
|
220
|
-
// TODO this allows us to clean up the generics by having a loose parameter
|
|
221
|
-
// but using the UnwrapServiceConfig to get the specific type back
|
|
222
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
223
|
-
export type AnyServiceLocals = ServiceLocals<any>;
|