@shipfox/api-server 7.0.2 → 8.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +63 -0
- package/README.md +11 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/instrumentation.js +5 -1
- package/dist/instrumentation.js.map +1 -1
- package/dist/modules.d.ts +10 -0
- package/dist/modules.d.ts.map +1 -1
- package/dist/modules.js +30 -5
- package/dist/modules.js.map +1 -1
- package/dist/routes/login-methods.d.ts +5 -0
- package/dist/routes/login-methods.d.ts.map +1 -0
- package/dist/routes/login-methods.js +22 -0
- package/dist/routes/login-methods.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +68 -11
- package/dist/server.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +25 -25
- package/src/auth-token-interoperability.test.ts +52 -0
- package/src/index.ts +7 -1
- package/src/instrumentation.ts +5 -1
- package/src/modules.test.ts +70 -5
- package/src/modules.ts +36 -6
- package/src/routes/login-methods.test.ts +56 -0
- package/src/routes/login-methods.ts +21 -0
- package/src/server.test.ts +26 -6
- package/src/server.ts +52 -14
- package/tsconfig.build.tsbuildinfo +1 -1
package/src/server.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {closeErrorMonitoring, markErrorReported, reportError} from '@shipfox/node-error-monitoring';
|
|
2
2
|
import {closeApp, createApp, listen} from '@shipfox/node-fastify';
|
|
3
3
|
import {
|
|
4
4
|
aggregateLoginMethods,
|
|
@@ -17,6 +17,7 @@ import {logger, shutdownServiceMetrics, startServiceMetrics} from '@shipfox/node
|
|
|
17
17
|
import {closePostgresClient, createPostgresClient} from '@shipfox/node-postgres';
|
|
18
18
|
import {config, parseApiTrustProxy} from './config.js';
|
|
19
19
|
import {createE2eAdminAuthMethod, createE2eRouteGroup} from './e2e.js';
|
|
20
|
+
import {createLoginMethodsRoute} from './routes/login-methods.js';
|
|
20
21
|
|
|
21
22
|
const RUNTIME_FAILURE_HTTP_SHUTDOWN_TIMEOUT_MS = 10_000;
|
|
22
23
|
const ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS = 2_000;
|
|
@@ -46,7 +47,7 @@ export async function createServer(options: CreateServerOptions): Promise<Server
|
|
|
46
47
|
hasActiveServer = true;
|
|
47
48
|
|
|
48
49
|
try {
|
|
49
|
-
aggregateLoginMethods({modules: options.modules});
|
|
50
|
+
const loginMethods = aggregateLoginMethods({modules: options.modules});
|
|
50
51
|
startServiceMetrics({serviceName: 'api'});
|
|
51
52
|
createPostgresClient();
|
|
52
53
|
|
|
@@ -62,7 +63,7 @@ export async function createServer(options: CreateServerOptions): Promise<Server
|
|
|
62
63
|
logger().info('Creating HTTP server');
|
|
63
64
|
await createApp({
|
|
64
65
|
auth: [...auth, ...e2eAuth],
|
|
65
|
-
routes: [...routes, ...mountedE2eRoutes],
|
|
66
|
+
routes: [createLoginMethodsRoute({loginMethods}), ...routes, ...mountedE2eRoutes],
|
|
66
67
|
fastifyOptions: {trustProxy: parseApiTrustProxy(config.API_TRUST_PROXY)},
|
|
67
68
|
});
|
|
68
69
|
|
|
@@ -116,10 +117,24 @@ export async function createServer(options: CreateServerOptions): Promise<Server
|
|
|
116
117
|
() => workersHandle?.stop(),
|
|
117
118
|
() => shutdownServiceMetrics(),
|
|
118
119
|
() => closePostgresClient(),
|
|
119
|
-
async () => {
|
|
120
|
-
await closeErrorMonitoring(ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS);
|
|
121
|
-
},
|
|
122
120
|
]);
|
|
121
|
+
for (const cleanupError of cleanupErrors) {
|
|
122
|
+
logger().error({err: cleanupError}, 'Failed to clean up API server during shutdown');
|
|
123
|
+
reportError(cleanupError, {boundary: 'api.shutdown', operation: 'cleanup'});
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
const errorMonitoringClosed = await closeErrorMonitoring(
|
|
127
|
+
ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS,
|
|
128
|
+
);
|
|
129
|
+
if (!errorMonitoringClosed) {
|
|
130
|
+
logger().error('Timed out closing error monitoring during API shutdown');
|
|
131
|
+
cleanupErrors.push(
|
|
132
|
+
new Error('Timed out closing error monitoring during API shutdown'),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
} catch (error) {
|
|
136
|
+
cleanupErrors.push(error);
|
|
137
|
+
}
|
|
123
138
|
throwCleanupErrors(cleanupErrors, 'Failed to stop API server');
|
|
124
139
|
stopped = true;
|
|
125
140
|
hasActiveServer = false;
|
|
@@ -138,6 +153,7 @@ export async function createServer(options: CreateServerOptions): Promise<Server
|
|
|
138
153
|
]);
|
|
139
154
|
for (const cleanupError of cleanupErrors) {
|
|
140
155
|
logger().error({err: cleanupError, bootError: error}, 'Failed to clean up API server boot');
|
|
156
|
+
reportError(cleanupError, {boundary: 'api.startup', operation: 'cleanup'});
|
|
141
157
|
}
|
|
142
158
|
hasActiveServer = false;
|
|
143
159
|
throw error;
|
|
@@ -168,11 +184,23 @@ export async function runServer(options: RunServerOptions): Promise<ServerHandle
|
|
|
168
184
|
{err: cleanupError, startError: error},
|
|
169
185
|
'Failed to clean up API server startup',
|
|
170
186
|
);
|
|
187
|
+
reportError(cleanupError, {
|
|
188
|
+
boundary: 'api.startup',
|
|
189
|
+
operation: 'cleanup-after-failed-start',
|
|
190
|
+
});
|
|
171
191
|
}
|
|
172
192
|
throw error;
|
|
173
193
|
}
|
|
174
194
|
|
|
175
|
-
const stopAndExit = () =>
|
|
195
|
+
const stopAndExit = () =>
|
|
196
|
+
void handle.stop().then(
|
|
197
|
+
() => process.exit(0),
|
|
198
|
+
(error) => {
|
|
199
|
+
logger().error({err: error}, 'Failed to stop API server after shutdown signal');
|
|
200
|
+
reportError(error, {boundary: 'api.shutdown', operation: 'signal-stop'});
|
|
201
|
+
process.exit(1);
|
|
202
|
+
},
|
|
203
|
+
);
|
|
176
204
|
process.once('SIGTERM', stopAndExit);
|
|
177
205
|
process.once('SIGINT', stopAndExit);
|
|
178
206
|
|
|
@@ -210,7 +238,9 @@ async function runCleanupSteps(steps: CleanupStep[]): Promise<unknown[]> {
|
|
|
210
238
|
function throwCleanupErrors(cleanupErrors: unknown[], message: string): void {
|
|
211
239
|
if (cleanupErrors.length === 0) return;
|
|
212
240
|
if (cleanupErrors.length === 1) throw cleanupErrors[0];
|
|
213
|
-
|
|
241
|
+
const aggregate = new AggregateError(cleanupErrors, message);
|
|
242
|
+
markErrorReported(aggregate);
|
|
243
|
+
throw aggregate;
|
|
214
244
|
}
|
|
215
245
|
|
|
216
246
|
async function handleModuleWorkerFailure(
|
|
@@ -246,11 +276,19 @@ async function handleModuleRuntimeFailure(options: {
|
|
|
246
276
|
onFailure(): void | Promise<void>;
|
|
247
277
|
}): Promise<void> {
|
|
248
278
|
logger().error({err: options.error, ...options.fields}, options.message);
|
|
249
|
-
|
|
279
|
+
reportError(options.error, {
|
|
280
|
+
boundary: 'api.runtime',
|
|
281
|
+
tags: options.fields,
|
|
282
|
+
});
|
|
250
283
|
|
|
251
284
|
try {
|
|
252
285
|
await closeHttpServerAfterRuntimeFailure();
|
|
253
|
-
await closeErrorMonitoring(ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS);
|
|
286
|
+
const errorMonitoringClosed = await closeErrorMonitoring(ERROR_MONITORING_SHUTDOWN_TIMEOUT_MS);
|
|
287
|
+
if (!errorMonitoringClosed) {
|
|
288
|
+
logger().error('Timed out closing error monitoring after module runtime failure');
|
|
289
|
+
}
|
|
290
|
+
} catch (error) {
|
|
291
|
+
logger().error({err: error}, 'Failed to close error monitoring after module runtime failure');
|
|
254
292
|
} finally {
|
|
255
293
|
await options.onFailure();
|
|
256
294
|
}
|
|
@@ -270,13 +308,13 @@ async function closeHttpServerAfterRuntimeFailure(): Promise<void> {
|
|
|
270
308
|
},
|
|
271
309
|
);
|
|
272
310
|
if (result === 'timeout') {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
);
|
|
311
|
+
const error = new Error('Timed out closing HTTP server after module runtime failure');
|
|
312
|
+
logger().error({timeoutMs: RUNTIME_FAILURE_HTTP_SHUTDOWN_TIMEOUT_MS}, error.message);
|
|
313
|
+
reportError(error, {boundary: 'api.runtime', operation: 'close-http-timeout'});
|
|
277
314
|
}
|
|
278
315
|
} catch (error) {
|
|
279
316
|
logger().error({err: error}, 'Failed to close HTTP server after module runtime failure');
|
|
317
|
+
reportError(error, {boundary: 'api.runtime', operation: 'close-http'});
|
|
280
318
|
} finally {
|
|
281
319
|
if (timeoutId) {
|
|
282
320
|
clearTimeout(timeoutId);
|