@futdevpro/nts-dynamo 1.15.154 → 1.15.155
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/README.md +28 -24
- package/__documentations/2026-08-22-content-free-process-error-boundary.md +91 -91
- package/build/_services/shared.static-service.d.ts +11 -4
- package/build/_services/shared.static-service.d.ts.map +1 -1
- package/build/_services/shared.static-service.js +26 -6
- package/build/_services/shared.static-service.js.map +1 -1
- package/package.json +15 -9
- package/src/_models/control-models/app-params.control-model.spec.ts +23 -23
- package/src/_models/control-models/app-params.control-model.ts +10 -10
- package/src/_modules/server/index.ts +8 -8
- package/src/_modules/server/safe-diagnostic/safe-diagnostic-cause.type-enum.ts +8 -8
- package/src/_modules/server/safe-diagnostic/safe-diagnostic-stage.type-enum.ts +19 -19
- package/src/_modules/server/safe-diagnostic/safe-diagnostic.control-service.spec.ts +124 -124
- package/src/_modules/server/safe-diagnostic/safe-diagnostic.control-service.ts +99 -99
- package/src/_modules/server/safe-diagnostic/safe-diagnostic.interface.ts +20 -20
- package/src/_services/core/global.service.ts +55 -55
- package/src/_services/server/app-safe-diagnostic.spec.ts +124 -124
- package/src/_services/server/app.server.ts +294 -294
- package/src/_services/shared.static-service.spec.ts +57 -23
- package/src/_services/shared.static-service.ts +48 -19
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
import { DyFM_Log } from '@futdevpro/fsm-dynamo';
|
|
2
|
-
|
|
3
|
-
import { DyNTS_App_Params } from '../../_models/control-models/app-params.control-model';
|
|
4
|
-
import { DyNTS_Http_Settings } from '../../_models/control-models/http-settings.control-model';
|
|
5
|
-
import { DyNTS_GlobalService_Settings } from '../../_models/interfaces/global-service-settings.interface';
|
|
6
|
-
import { DyNTS_GlobalService } from '../core/global.service';
|
|
7
|
-
import { DyNTS_App } from './app.server';
|
|
8
|
-
|
|
9
|
-
class DyNTS_SafeDiagnosticTestApp extends DyNTS_App {
|
|
10
|
-
protected override asyncConstruct(): Promise<void> {
|
|
11
|
-
return Promise.resolve();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/** Supplies the minimal valid application parameters for the boundary test. */
|
|
15
|
-
getAppParams(): DyNTS_App_Params {
|
|
16
|
-
return new DyNTS_App_Params({
|
|
17
|
-
name: 'SafeDiagnosticTestApp',
|
|
18
|
-
version: '1.0.0',
|
|
19
|
-
dbName: 'safe_diagnostic_test',
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** Keeps the test application independent from concrete global services. */
|
|
24
|
-
getGlobalServiceCollection(): DyNTS_GlobalService_Settings {
|
|
25
|
-
return {};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** Keeps the test application independent from a listening HTTP server. */
|
|
29
|
-
getPortSettings(): DyNTS_Http_Settings {
|
|
30
|
-
return new DyNTS_Http_Settings();
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
class DyNTS_FailingBootstrapTestApp extends DyNTS_SafeDiagnosticTestApp {
|
|
35
|
-
protected override asyncConstruct(): Promise<void> {
|
|
36
|
-
return Promise.reject(new Error(DyNTS_FailingBootstrapTestApp.canary));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
static readonly canary: string = 'mongodb://bootstrap-user:bootstrap-secret@private-host.example/database';
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
describe('| DyNTS_App safe process boundary', (): void => {
|
|
43
|
-
const rejectionCanary: string = 'mongodb://rejection-user:rejection-secret@private-host.example/database';
|
|
44
|
-
let originalHandler: typeof DyNTS_GlobalService.globalErrorHandler;
|
|
45
|
-
let initialListeners: NodeJS.UnhandledRejectionListener[];
|
|
46
|
-
|
|
47
|
-
beforeEach((): void => {
|
|
48
|
-
originalHandler = DyNTS_GlobalService.globalErrorHandler;
|
|
49
|
-
initialListeners = process.listeners('unhandledRejection');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
afterEach((): void => {
|
|
53
|
-
DyNTS_GlobalService.globalErrorHandler = originalHandler;
|
|
54
|
-
process.listeners('unhandledRejection').forEach((listener: NodeJS.UnhandledRejectionListener): void => {
|
|
55
|
-
if (!initialListeners.includes(listener)) {
|
|
56
|
-
process.removeListener('unhandledRejection', listener);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('| projects an unhandled rejection before logging or forwarding it', async (): Promise<void> => {
|
|
62
|
-
const logSpy: jasmine.Spy = spyOn(DyFM_Log, 'error');
|
|
63
|
-
const handlerSpy: jasmine.Spy = jasmine.createSpy('globalErrorHandler').and.resolveTo();
|
|
64
|
-
|
|
65
|
-
DyNTS_GlobalService.globalErrorHandler = handlerSpy;
|
|
66
|
-
new DyNTS_SafeDiagnosticTestApp();
|
|
67
|
-
|
|
68
|
-
const addedListeners: NodeJS.UnhandledRejectionListener[] = process
|
|
69
|
-
.listeners('unhandledRejection')
|
|
70
|
-
.filter((listener: NodeJS.UnhandledRejectionListener): boolean => !initialListeners.includes(listener));
|
|
71
|
-
|
|
72
|
-
expect(addedListeners.length).toBe(1);
|
|
73
|
-
addedListeners[0](new Error(rejectionCanary), Promise.resolve());
|
|
74
|
-
await Promise.resolve();
|
|
75
|
-
|
|
76
|
-
const serializedLogs: string = JSON.stringify(logSpy.calls.allArgs());
|
|
77
|
-
const serializedForwardedError: string = JSON.stringify(handlerSpy.calls.mostRecent().args[0]);
|
|
78
|
-
|
|
79
|
-
expect(serializedLogs).toContain('dynts-safe-diagnostic/1');
|
|
80
|
-
expect(serializedForwardedError).toContain('dynts-safe-diagnostic/1');
|
|
81
|
-
expect(serializedForwardedError).toContain('DYNTS-AS0-BASE-UR');
|
|
82
|
-
expect(handlerSpy.calls.mostRecent().args.length).toBe(1);
|
|
83
|
-
expect(serializedLogs).not.toContain(rejectionCanary);
|
|
84
|
-
expect(serializedLogs).not.toContain('rejection-secret');
|
|
85
|
-
expect(serializedForwardedError).not.toContain(rejectionCanary);
|
|
86
|
-
expect(serializedForwardedError).not.toContain('rejection-secret');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('| projects a bootstrap rejection before logging, forwarding and exiting', async (): Promise<void> => {
|
|
90
|
-
const logSpy: jasmine.Spy = spyOn(DyFM_Log, 'error');
|
|
91
|
-
const handlerSpy: jasmine.Spy = jasmine.createSpy('globalErrorHandler').and.resolveTo();
|
|
92
|
-
const exitSpy: jasmine.Spy = spyOn(process, 'exit');
|
|
93
|
-
|
|
94
|
-
DyNTS_GlobalService.globalErrorHandler = handlerSpy;
|
|
95
|
-
new DyNTS_FailingBootstrapTestApp();
|
|
96
|
-
await new Promise<void>((resolve: () => void): NodeJS.Immediate => setImmediate(resolve));
|
|
97
|
-
|
|
98
|
-
const serializedLogs: string = JSON.stringify(logSpy.calls.allArgs());
|
|
99
|
-
const serializedForwardedError: string = JSON.stringify(handlerSpy.calls.mostRecent().args[0]);
|
|
100
|
-
|
|
101
|
-
expect(exitSpy).toHaveBeenCalledOnceWith(1);
|
|
102
|
-
expect(serializedLogs).toContain('dynts-safe-diagnostic/1');
|
|
103
|
-
expect(serializedForwardedError).toContain('dynts-safe-diagnostic/1');
|
|
104
|
-
expect(serializedForwardedError).toContain('DYNTS-AS0-BOOTSTRAP-FAILED');
|
|
105
|
-
expect(handlerSpy.calls.mostRecent().args.length).toBe(1);
|
|
106
|
-
expect(serializedLogs).not.toContain(DyNTS_FailingBootstrapTestApp.canary);
|
|
107
|
-
expect(serializedLogs).not.toContain('bootstrap-secret');
|
|
108
|
-
expect(serializedForwardedError).not.toContain(DyNTS_FailingBootstrapTestApp.canary);
|
|
109
|
-
expect(serializedForwardedError).not.toContain('bootstrap-secret');
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('| projects raw failures in the default global error handler', async (): Promise<void> => {
|
|
113
|
-
const logSpy: jasmine.Spy = spyOn(DyFM_Log, 'error');
|
|
114
|
-
|
|
115
|
-
await DyNTS_GlobalService.setServices({});
|
|
116
|
-
await DyNTS_GlobalService.globalErrorHandler(new Error(rejectionCanary));
|
|
117
|
-
|
|
118
|
-
const serializedLogs: string = JSON.stringify(logSpy.calls.allArgs());
|
|
119
|
-
|
|
120
|
-
expect(serializedLogs).toContain('dynts-safe-diagnostic/1');
|
|
121
|
-
expect(serializedLogs).not.toContain(rejectionCanary);
|
|
122
|
-
expect(serializedLogs).not.toContain('rejection-secret');
|
|
123
|
-
});
|
|
124
|
-
});
|
|
1
|
+
import { DyFM_Log } from '@futdevpro/fsm-dynamo';
|
|
2
|
+
|
|
3
|
+
import { DyNTS_App_Params } from '../../_models/control-models/app-params.control-model';
|
|
4
|
+
import { DyNTS_Http_Settings } from '../../_models/control-models/http-settings.control-model';
|
|
5
|
+
import { DyNTS_GlobalService_Settings } from '../../_models/interfaces/global-service-settings.interface';
|
|
6
|
+
import { DyNTS_GlobalService } from '../core/global.service';
|
|
7
|
+
import { DyNTS_App } from './app.server';
|
|
8
|
+
|
|
9
|
+
class DyNTS_SafeDiagnosticTestApp extends DyNTS_App {
|
|
10
|
+
protected override asyncConstruct(): Promise<void> {
|
|
11
|
+
return Promise.resolve();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Supplies the minimal valid application parameters for the boundary test. */
|
|
15
|
+
getAppParams(): DyNTS_App_Params {
|
|
16
|
+
return new DyNTS_App_Params({
|
|
17
|
+
name: 'SafeDiagnosticTestApp',
|
|
18
|
+
version: '1.0.0',
|
|
19
|
+
dbName: 'safe_diagnostic_test',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Keeps the test application independent from concrete global services. */
|
|
24
|
+
getGlobalServiceCollection(): DyNTS_GlobalService_Settings {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Keeps the test application independent from a listening HTTP server. */
|
|
29
|
+
getPortSettings(): DyNTS_Http_Settings {
|
|
30
|
+
return new DyNTS_Http_Settings();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
class DyNTS_FailingBootstrapTestApp extends DyNTS_SafeDiagnosticTestApp {
|
|
35
|
+
protected override asyncConstruct(): Promise<void> {
|
|
36
|
+
return Promise.reject(new Error(DyNTS_FailingBootstrapTestApp.canary));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static readonly canary: string = 'mongodb://bootstrap-user:bootstrap-secret@private-host.example/database';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
describe('| DyNTS_App safe process boundary', (): void => {
|
|
43
|
+
const rejectionCanary: string = 'mongodb://rejection-user:rejection-secret@private-host.example/database';
|
|
44
|
+
let originalHandler: typeof DyNTS_GlobalService.globalErrorHandler;
|
|
45
|
+
let initialListeners: NodeJS.UnhandledRejectionListener[];
|
|
46
|
+
|
|
47
|
+
beforeEach((): void => {
|
|
48
|
+
originalHandler = DyNTS_GlobalService.globalErrorHandler;
|
|
49
|
+
initialListeners = process.listeners('unhandledRejection');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
afterEach((): void => {
|
|
53
|
+
DyNTS_GlobalService.globalErrorHandler = originalHandler;
|
|
54
|
+
process.listeners('unhandledRejection').forEach((listener: NodeJS.UnhandledRejectionListener): void => {
|
|
55
|
+
if (!initialListeners.includes(listener)) {
|
|
56
|
+
process.removeListener('unhandledRejection', listener);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('| projects an unhandled rejection before logging or forwarding it', async (): Promise<void> => {
|
|
62
|
+
const logSpy: jasmine.Spy = spyOn(DyFM_Log, 'error');
|
|
63
|
+
const handlerSpy: jasmine.Spy = jasmine.createSpy('globalErrorHandler').and.resolveTo();
|
|
64
|
+
|
|
65
|
+
DyNTS_GlobalService.globalErrorHandler = handlerSpy;
|
|
66
|
+
new DyNTS_SafeDiagnosticTestApp();
|
|
67
|
+
|
|
68
|
+
const addedListeners: NodeJS.UnhandledRejectionListener[] = process
|
|
69
|
+
.listeners('unhandledRejection')
|
|
70
|
+
.filter((listener: NodeJS.UnhandledRejectionListener): boolean => !initialListeners.includes(listener));
|
|
71
|
+
|
|
72
|
+
expect(addedListeners.length).toBe(1);
|
|
73
|
+
addedListeners[0](new Error(rejectionCanary), Promise.resolve());
|
|
74
|
+
await Promise.resolve();
|
|
75
|
+
|
|
76
|
+
const serializedLogs: string = JSON.stringify(logSpy.calls.allArgs());
|
|
77
|
+
const serializedForwardedError: string = JSON.stringify(handlerSpy.calls.mostRecent().args[0]);
|
|
78
|
+
|
|
79
|
+
expect(serializedLogs).toContain('dynts-safe-diagnostic/1');
|
|
80
|
+
expect(serializedForwardedError).toContain('dynts-safe-diagnostic/1');
|
|
81
|
+
expect(serializedForwardedError).toContain('DYNTS-AS0-BASE-UR');
|
|
82
|
+
expect(handlerSpy.calls.mostRecent().args.length).toBe(1);
|
|
83
|
+
expect(serializedLogs).not.toContain(rejectionCanary);
|
|
84
|
+
expect(serializedLogs).not.toContain('rejection-secret');
|
|
85
|
+
expect(serializedForwardedError).not.toContain(rejectionCanary);
|
|
86
|
+
expect(serializedForwardedError).not.toContain('rejection-secret');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('| projects a bootstrap rejection before logging, forwarding and exiting', async (): Promise<void> => {
|
|
90
|
+
const logSpy: jasmine.Spy = spyOn(DyFM_Log, 'error');
|
|
91
|
+
const handlerSpy: jasmine.Spy = jasmine.createSpy('globalErrorHandler').and.resolveTo();
|
|
92
|
+
const exitSpy: jasmine.Spy = spyOn(process, 'exit');
|
|
93
|
+
|
|
94
|
+
DyNTS_GlobalService.globalErrorHandler = handlerSpy;
|
|
95
|
+
new DyNTS_FailingBootstrapTestApp();
|
|
96
|
+
await new Promise<void>((resolve: () => void): NodeJS.Immediate => setImmediate(resolve));
|
|
97
|
+
|
|
98
|
+
const serializedLogs: string = JSON.stringify(logSpy.calls.allArgs());
|
|
99
|
+
const serializedForwardedError: string = JSON.stringify(handlerSpy.calls.mostRecent().args[0]);
|
|
100
|
+
|
|
101
|
+
expect(exitSpy).toHaveBeenCalledOnceWith(1);
|
|
102
|
+
expect(serializedLogs).toContain('dynts-safe-diagnostic/1');
|
|
103
|
+
expect(serializedForwardedError).toContain('dynts-safe-diagnostic/1');
|
|
104
|
+
expect(serializedForwardedError).toContain('DYNTS-AS0-BOOTSTRAP-FAILED');
|
|
105
|
+
expect(handlerSpy.calls.mostRecent().args.length).toBe(1);
|
|
106
|
+
expect(serializedLogs).not.toContain(DyNTS_FailingBootstrapTestApp.canary);
|
|
107
|
+
expect(serializedLogs).not.toContain('bootstrap-secret');
|
|
108
|
+
expect(serializedForwardedError).not.toContain(DyNTS_FailingBootstrapTestApp.canary);
|
|
109
|
+
expect(serializedForwardedError).not.toContain('bootstrap-secret');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('| projects raw failures in the default global error handler', async (): Promise<void> => {
|
|
113
|
+
const logSpy: jasmine.Spy = spyOn(DyFM_Log, 'error');
|
|
114
|
+
|
|
115
|
+
await DyNTS_GlobalService.setServices({});
|
|
116
|
+
await DyNTS_GlobalService.globalErrorHandler(new Error(rejectionCanary));
|
|
117
|
+
|
|
118
|
+
const serializedLogs: string = JSON.stringify(logSpy.calls.allArgs());
|
|
119
|
+
|
|
120
|
+
expect(serializedLogs).toContain('dynts-safe-diagnostic/1');
|
|
121
|
+
expect(serializedLogs).not.toContain(rejectionCanary);
|
|
122
|
+
expect(serializedLogs).not.toContain('rejection-secret');
|
|
123
|
+
});
|
|
124
|
+
});
|