@blokjs/shared 0.2.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/CHANGELOG.md +69 -0
- package/__tests__/unit/GlobalError.test.ts +93 -0
- package/__tests__/unit/GlobalLogger.test.ts +77 -0
- package/__tests__/unit/Metrics.test.ts +77 -0
- package/__tests__/unit/NodeBase.test.ts +286 -0
- package/__tests__/unit/Trigger.test.ts +23 -0
- package/__tests__/unit/utils/CpuUsage.test.ts +102 -0
- package/__tests__/unit/utils/Mapper.test.ts +124 -0
- package/__tests__/unit/utils/MemoryUsage.test.ts +121 -0
- package/__tests__/unit/utils/Time.test.ts +60 -0
- package/dist/GlobalError.d.ts +11 -0
- package/dist/GlobalError.js +29 -0
- package/dist/GlobalError.js.map +1 -0
- package/dist/GlobalLogger.d.ts +11 -0
- package/dist/GlobalLogger.js +16 -0
- package/dist/GlobalLogger.js.map +1 -0
- package/dist/Metrics.d.ts +18 -0
- package/dist/Metrics.js +40 -0
- package/dist/Metrics.js.map +1 -0
- package/dist/NodeBase.d.ts +26 -0
- package/dist/NodeBase.js +98 -0
- package/dist/NodeBase.js.map +1 -0
- package/dist/Trigger.d.ts +7 -0
- package/dist/Trigger.js +3 -0
- package/dist/Trigger.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/types/ConfigContext.d.ts +5 -0
- package/dist/types/ConfigContext.js +2 -0
- package/dist/types/ConfigContext.js.map +1 -0
- package/dist/types/Context.d.ts +25 -0
- package/dist/types/Context.js +2 -0
- package/dist/types/Context.js.map +1 -0
- package/dist/types/EnvContext.d.ts +5 -0
- package/dist/types/EnvContext.js +2 -0
- package/dist/types/EnvContext.js.map +1 -0
- package/dist/types/ErrorContext.d.ts +9 -0
- package/dist/types/ErrorContext.js +2 -0
- package/dist/types/ErrorContext.js.map +1 -0
- package/dist/types/FunctionContext.d.ts +4 -0
- package/dist/types/FunctionContext.js +2 -0
- package/dist/types/FunctionContext.js.map +1 -0
- package/dist/types/LoggerContext.d.ts +9 -0
- package/dist/types/LoggerContext.js +2 -0
- package/dist/types/LoggerContext.js.map +1 -0
- package/dist/types/NodeConfigContext.d.ts +5 -0
- package/dist/types/NodeConfigContext.js +2 -0
- package/dist/types/NodeConfigContext.js.map +1 -0
- package/dist/types/ParamsDictionary.d.ts +3 -0
- package/dist/types/ParamsDictionary.js +2 -0
- package/dist/types/ParamsDictionary.js.map +1 -0
- package/dist/types/RequestContext.d.ts +5 -0
- package/dist/types/RequestContext.js +2 -0
- package/dist/types/RequestContext.js.map +1 -0
- package/dist/types/ResponseContext.d.ts +8 -0
- package/dist/types/ResponseContext.js +2 -0
- package/dist/types/ResponseContext.js.map +1 -0
- package/dist/types/Step.d.ts +10 -0
- package/dist/types/Step.js +2 -0
- package/dist/types/Step.js.map +1 -0
- package/dist/types/VarsContext.d.ts +5 -0
- package/dist/types/VarsContext.js +2 -0
- package/dist/types/VarsContext.js.map +1 -0
- package/dist/utils/CpuUsage.d.ts +19 -0
- package/dist/utils/CpuUsage.js +57 -0
- package/dist/utils/CpuUsage.js.map +1 -0
- package/dist/utils/Mapper.d.ts +10 -0
- package/dist/utils/Mapper.js +56 -0
- package/dist/utils/Mapper.js.map +1 -0
- package/dist/utils/MemoryUsage.d.ts +17 -0
- package/dist/utils/MemoryUsage.js +36 -0
- package/dist/utils/MemoryUsage.js.map +1 -0
- package/dist/utils/MetricsBase.d.ts +24 -0
- package/dist/utils/MetricsBase.js +3 -0
- package/dist/utils/MetricsBase.js.map +1 -0
- package/dist/utils/Time.d.ts +10 -0
- package/dist/utils/Time.js +24 -0
- package/dist/utils/Time.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +34 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +29 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import CpuMetrics from "../../../src/utils/CpuUsage";
|
|
4
|
+
|
|
5
|
+
const mockCpuInfo = (idle: number, user: number, sys: number) => [
|
|
6
|
+
{
|
|
7
|
+
model: "Test CPU Model",
|
|
8
|
+
speed: 2400,
|
|
9
|
+
times: { idle, user, sys, nice: 0, irq: 0 },
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
model: "Test CPU Model",
|
|
13
|
+
speed: 2400,
|
|
14
|
+
times: { idle, user, sys, nice: 0, irq: 0 },
|
|
15
|
+
},
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
describe("CpuMetrics", () => {
|
|
19
|
+
let cpu: CpuMetrics;
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
cpu = new CpuMetrics();
|
|
23
|
+
vi.restoreAllMocks();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe("start()", () => {
|
|
27
|
+
it("should capture CPU info (model and count)", () => {
|
|
28
|
+
vi.spyOn(os, "cpus").mockReturnValue(mockCpuInfo(1000, 500, 200) as os.CpuInfo[]);
|
|
29
|
+
cpu.start();
|
|
30
|
+
const metrics = cpu.getMetrics();
|
|
31
|
+
expect(metrics.model).toBe("Test CPU Model");
|
|
32
|
+
expect(metrics.total).toBe(2);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("stop()", () => {
|
|
37
|
+
it("should capture end usage without error", () => {
|
|
38
|
+
vi.spyOn(os, "cpus").mockReturnValue(mockCpuInfo(1000, 500, 200) as os.CpuInfo[]);
|
|
39
|
+
cpu.start();
|
|
40
|
+
cpu.stop();
|
|
41
|
+
// Should not throw
|
|
42
|
+
expect(true).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("getAverage()", () => {
|
|
47
|
+
it("should calculate CPU percentage between start and stop", () => {
|
|
48
|
+
const startCpus = mockCpuInfo(1000, 500, 200);
|
|
49
|
+
const stopCpus = mockCpuInfo(1050, 550, 250);
|
|
50
|
+
|
|
51
|
+
vi.spyOn(os, "cpus")
|
|
52
|
+
.mockReturnValueOnce(startCpus as os.CpuInfo[]) // start -> constructor call
|
|
53
|
+
.mockReturnValueOnce(startCpus as os.CpuInfo[]) // start -> measureCpu
|
|
54
|
+
.mockReturnValueOnce(stopCpus as os.CpuInfo[]) // stop -> measureCpu
|
|
55
|
+
.mockReturnValueOnce(stopCpus as os.CpuInfo[]); // potential extra
|
|
56
|
+
|
|
57
|
+
cpu.start();
|
|
58
|
+
cpu.stop();
|
|
59
|
+
|
|
60
|
+
const metrics = cpu.getMetrics();
|
|
61
|
+
expect(metrics.average).toBeTypeOf("number");
|
|
62
|
+
expect(metrics.average).toBeGreaterThanOrEqual(0);
|
|
63
|
+
expect(metrics.average).toBeLessThanOrEqual(100);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("getMetrics()", () => {
|
|
68
|
+
it("should return correct shape with total, average, usage, model", () => {
|
|
69
|
+
vi.spyOn(os, "cpus").mockReturnValue(mockCpuInfo(1000, 500, 200) as os.CpuInfo[]);
|
|
70
|
+
cpu.start();
|
|
71
|
+
cpu.stop();
|
|
72
|
+
|
|
73
|
+
const metrics = cpu.getMetrics();
|
|
74
|
+
expect(metrics).toHaveProperty("total");
|
|
75
|
+
expect(metrics).toHaveProperty("average");
|
|
76
|
+
expect(metrics).toHaveProperty("usage");
|
|
77
|
+
expect(metrics).toHaveProperty("model");
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe("measureCpu()", () => {
|
|
82
|
+
it("should return idle, total, model, cpus shape", () => {
|
|
83
|
+
vi.spyOn(os, "cpus").mockReturnValue(mockCpuInfo(1000, 500, 200) as os.CpuInfo[]);
|
|
84
|
+
const result = cpu.measureCpu();
|
|
85
|
+
expect(result).toHaveProperty("idle");
|
|
86
|
+
expect(result).toHaveProperty("total");
|
|
87
|
+
expect(result).toHaveProperty("model");
|
|
88
|
+
expect(result).toHaveProperty("cpus");
|
|
89
|
+
expect(result.cpus).toBe(2);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("should aggregate across all CPU cores", () => {
|
|
93
|
+
vi.spyOn(os, "cpus").mockReturnValue(mockCpuInfo(1000, 500, 200) as os.CpuInfo[]);
|
|
94
|
+
const result = cpu.measureCpu();
|
|
95
|
+
// idle is averaged: (1000 + 1000) / 2 = 1000
|
|
96
|
+
expect(result.idle).toBe(1000);
|
|
97
|
+
// total per core: idle + irq + nice + sys + user = 1000 + 0 + 0 + 200 + 500 = 1700
|
|
98
|
+
// averaged: (1700 + 1700) / 2 = 1700
|
|
99
|
+
expect(result.total).toBe(1700);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import type Context from "../../../src/types/Context";
|
|
3
|
+
import mapper from "../../../src/utils/Mapper";
|
|
4
|
+
|
|
5
|
+
function createMockContext(overrides: Partial<Context> = {}): Context {
|
|
6
|
+
return {
|
|
7
|
+
id: "test-id",
|
|
8
|
+
request: { body: {}, headers: {}, query: {}, params: {} },
|
|
9
|
+
response: { data: null, error: null, success: true },
|
|
10
|
+
error: { message: "" },
|
|
11
|
+
logger: { log: vi.fn(), logLevel: vi.fn(), error: vi.fn() },
|
|
12
|
+
config: {},
|
|
13
|
+
func: {},
|
|
14
|
+
vars: {},
|
|
15
|
+
eventLogger: null,
|
|
16
|
+
_PRIVATE_: null,
|
|
17
|
+
...overrides,
|
|
18
|
+
} as Context;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe("Mapper", () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
vi.restoreAllMocks();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe("replaceString()", () => {
|
|
27
|
+
it("should replace ${key} with data value", () => {
|
|
28
|
+
const ctx = createMockContext();
|
|
29
|
+
const data = { name: "John" };
|
|
30
|
+
const result = mapper.replaceString("Hello ${name}", ctx, data);
|
|
31
|
+
expect(result).toBe("Hello John");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should replace multiple placeholders", () => {
|
|
35
|
+
const ctx = createMockContext();
|
|
36
|
+
const data = { first: "John", last: "Doe" };
|
|
37
|
+
const result = mapper.replaceString("${first} ${last}", ctx, data);
|
|
38
|
+
expect(result).toBe("John Doe");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("should handle nested data access via lodash.get", () => {
|
|
42
|
+
const ctx = createMockContext();
|
|
43
|
+
const data = { user: { name: "Alice" } };
|
|
44
|
+
const result = mapper.replaceString("Hi ${user.name}", ctx, data);
|
|
45
|
+
expect(result).toBe("Hi Alice");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should handle no matches (no ${})", () => {
|
|
49
|
+
const ctx = createMockContext();
|
|
50
|
+
const result = mapper.replaceString("plain text", ctx, {});
|
|
51
|
+
expect(result).toBe("plain text");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("should execute js/ prefix expressions", () => {
|
|
55
|
+
const ctx = createMockContext();
|
|
56
|
+
const result = mapper.replaceString("js/1 + 2", ctx, {});
|
|
57
|
+
expect(result).toBe(3);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should pass through non-js strings", () => {
|
|
61
|
+
const ctx = createMockContext();
|
|
62
|
+
const result = mapper.replaceString("hello world", ctx, {});
|
|
63
|
+
expect(result).toBe("hello world");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should handle errors silently in placeholder replacement", () => {
|
|
67
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
68
|
+
const ctx = createMockContext();
|
|
69
|
+
// An expression that throws inside Function()
|
|
70
|
+
const result = mapper.replaceString("${undefinedVar.deep.access}", ctx, {});
|
|
71
|
+
// Should not throw, returns string with attempted replacement
|
|
72
|
+
expect(result).toBeTypeOf("string");
|
|
73
|
+
consoleSpy.mockRestore();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("replaceObjectStrings()", () => {
|
|
78
|
+
it("should replace string values in flat object", () => {
|
|
79
|
+
const ctx = createMockContext();
|
|
80
|
+
const data = { greeting: "World" };
|
|
81
|
+
const obj: Record<string, unknown> = { msg: "Hello ${greeting}" };
|
|
82
|
+
mapper.replaceObjectStrings(obj, ctx, data);
|
|
83
|
+
expect(obj.msg).toBe("Hello World");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should recursively replace nested objects", () => {
|
|
87
|
+
const ctx = createMockContext();
|
|
88
|
+
const data = { val: "replaced" };
|
|
89
|
+
const obj: Record<string, unknown> = {
|
|
90
|
+
level1: {
|
|
91
|
+
level2: "value is ${val}",
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
mapper.replaceObjectStrings(obj, ctx, data);
|
|
95
|
+
expect((obj.level1 as Record<string, unknown>).level2).toBe("value is replaced");
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should skip non-string, non-object values", () => {
|
|
99
|
+
const ctx = createMockContext();
|
|
100
|
+
const obj: Record<string, unknown> = { num: 42, bool: true, str: "keep" };
|
|
101
|
+
mapper.replaceObjectStrings(obj, ctx, {});
|
|
102
|
+
expect(obj.num).toBe(42);
|
|
103
|
+
expect(obj.bool).toBe(true);
|
|
104
|
+
expect(obj.str).toBe("keep");
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe("jsMapper via replaceString", () => {
|
|
109
|
+
it("should access ctx in js/ expressions", () => {
|
|
110
|
+
const ctx = createMockContext({ vars: { count: 5 } });
|
|
111
|
+
const result = mapper.replaceString("js/ctx.vars.count", ctx, {});
|
|
112
|
+
expect(result).toBe(5);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should handle js/ errors silently", () => {
|
|
116
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
117
|
+
const ctx = createMockContext();
|
|
118
|
+
const result = mapper.replaceString('js/throw new Error("fail")', ctx, {});
|
|
119
|
+
// Should return the original string on error
|
|
120
|
+
expect(result).toBe('js/throw new Error("fail")');
|
|
121
|
+
consoleSpy.mockRestore();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import MemoryUsage from "../../../src/utils/MemoryUsage";
|
|
4
|
+
|
|
5
|
+
describe("MemoryUsage", () => {
|
|
6
|
+
let memory: MemoryUsage;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
memory = new MemoryUsage();
|
|
10
|
+
vi.restoreAllMocks();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe("start()", () => {
|
|
14
|
+
it("should increment counter", () => {
|
|
15
|
+
vi.spyOn(process, "memoryUsage").mockReturnValue({
|
|
16
|
+
heapUsed: 50_000_000,
|
|
17
|
+
heapTotal: 100_000_000,
|
|
18
|
+
rss: 200_000_000,
|
|
19
|
+
external: 10_000_000,
|
|
20
|
+
arrayBuffers: 5_000_000,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
memory.start();
|
|
24
|
+
memory.start();
|
|
25
|
+
|
|
26
|
+
const metrics = memory.getMetrics();
|
|
27
|
+
// total is average = total_val / counter, with 2 starts
|
|
28
|
+
expect(metrics.total).toBeTypeOf("number");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should track min value", () => {
|
|
32
|
+
vi.spyOn(process, "memoryUsage")
|
|
33
|
+
.mockReturnValueOnce({ heapUsed: 100_000_000, heapTotal: 0, rss: 0, external: 0, arrayBuffers: 0 })
|
|
34
|
+
.mockReturnValueOnce({ heapUsed: 50_000_000, heapTotal: 0, rss: 0, external: 0, arrayBuffers: 0 });
|
|
35
|
+
|
|
36
|
+
memory.start();
|
|
37
|
+
memory.start();
|
|
38
|
+
|
|
39
|
+
const metrics = memory.getMetrics();
|
|
40
|
+
expect(metrics.min).toBe(50); // 50_000_000 / 1_000_000
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should track max value", () => {
|
|
44
|
+
vi.spyOn(process, "memoryUsage")
|
|
45
|
+
.mockReturnValueOnce({ heapUsed: 50_000_000, heapTotal: 0, rss: 0, external: 0, arrayBuffers: 0 })
|
|
46
|
+
.mockReturnValueOnce({ heapUsed: 100_000_000, heapTotal: 0, rss: 0, external: 0, arrayBuffers: 0 });
|
|
47
|
+
|
|
48
|
+
memory.start();
|
|
49
|
+
memory.start();
|
|
50
|
+
|
|
51
|
+
const metrics = memory.getMetrics();
|
|
52
|
+
expect(metrics.max).toBe(100); // 100_000_000 / 1_000_000
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should set min_val on first call", () => {
|
|
56
|
+
vi.spyOn(process, "memoryUsage").mockReturnValue({
|
|
57
|
+
heapUsed: 75_000_000,
|
|
58
|
+
heapTotal: 0,
|
|
59
|
+
rss: 0,
|
|
60
|
+
external: 0,
|
|
61
|
+
arrayBuffers: 0,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
memory.start();
|
|
65
|
+
|
|
66
|
+
const metrics = memory.getMetrics();
|
|
67
|
+
expect(metrics.min).toBe(75);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe("stop()", () => {
|
|
72
|
+
it("should be a no-op", () => {
|
|
73
|
+
memory.stop();
|
|
74
|
+
// Should not throw or change state
|
|
75
|
+
const metrics = memory.getMetrics();
|
|
76
|
+
expect(metrics.total).toBeNaN(); // 0 / 0
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe("getMetrics()", () => {
|
|
81
|
+
it("should return average, min, max, global_memory, global_free_memory", () => {
|
|
82
|
+
vi.spyOn(process, "memoryUsage").mockReturnValue({
|
|
83
|
+
heapUsed: 50_000_000,
|
|
84
|
+
heapTotal: 0,
|
|
85
|
+
rss: 0,
|
|
86
|
+
external: 0,
|
|
87
|
+
arrayBuffers: 0,
|
|
88
|
+
});
|
|
89
|
+
vi.spyOn(os, "totalmem").mockReturnValue(16_000_000_000);
|
|
90
|
+
vi.spyOn(os, "freemem").mockReturnValue(8_000_000_000);
|
|
91
|
+
|
|
92
|
+
memory.start();
|
|
93
|
+
|
|
94
|
+
const metrics = memory.getMetrics();
|
|
95
|
+
expect(metrics).toHaveProperty("total");
|
|
96
|
+
expect(metrics).toHaveProperty("min");
|
|
97
|
+
expect(metrics).toHaveProperty("max");
|
|
98
|
+
expect(metrics.global_memory).toBe(16000);
|
|
99
|
+
expect(metrics.global_free_memory).toBe(8000);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("clear()", () => {
|
|
104
|
+
it("should reset all values to 0", () => {
|
|
105
|
+
vi.spyOn(process, "memoryUsage").mockReturnValue({
|
|
106
|
+
heapUsed: 50_000_000,
|
|
107
|
+
heapTotal: 0,
|
|
108
|
+
rss: 0,
|
|
109
|
+
external: 0,
|
|
110
|
+
arrayBuffers: 0,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
memory.start();
|
|
114
|
+
memory.clear();
|
|
115
|
+
|
|
116
|
+
const metrics = memory.getMetrics();
|
|
117
|
+
expect(metrics.min).toBe(0);
|
|
118
|
+
expect(metrics.max).toBe(0);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import Time from "../../../src/utils/Time";
|
|
3
|
+
|
|
4
|
+
describe("Time", () => {
|
|
5
|
+
let time: Time;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
time = new Time();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
describe("start()", () => {
|
|
12
|
+
it("should record start time as dayjs format", () => {
|
|
13
|
+
time.start();
|
|
14
|
+
const metrics = time.getMetrics();
|
|
15
|
+
expect(metrics.startTime).toBeTypeOf("string");
|
|
16
|
+
expect(metrics.startTime).not.toBeNull();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("stop()", () => {
|
|
21
|
+
it("should record end time as dayjs format", () => {
|
|
22
|
+
time.start();
|
|
23
|
+
time.stop();
|
|
24
|
+
const metrics = time.getMetrics();
|
|
25
|
+
expect(metrics.endTime).toBeTypeOf("string");
|
|
26
|
+
expect(metrics.endTime).not.toBeNull();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("getMetrics()", () => {
|
|
31
|
+
it("should return startTime, endTime, duration", () => {
|
|
32
|
+
time.start();
|
|
33
|
+
time.stop();
|
|
34
|
+
|
|
35
|
+
const metrics = time.getMetrics();
|
|
36
|
+
expect(metrics).toHaveProperty("startTime");
|
|
37
|
+
expect(metrics).toHaveProperty("endTime");
|
|
38
|
+
expect(metrics).toHaveProperty("duration");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("should have positive duration after start/stop", () => {
|
|
42
|
+
time.start();
|
|
43
|
+
// Small delay to ensure measurable duration
|
|
44
|
+
for (let i = 0; i < 1000; i++) {
|
|
45
|
+
/* spin */
|
|
46
|
+
}
|
|
47
|
+
time.stop();
|
|
48
|
+
|
|
49
|
+
const metrics = time.getMetrics();
|
|
50
|
+
expect(metrics.duration).toBeGreaterThanOrEqual(0);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("should return null times before start", () => {
|
|
54
|
+
const metrics = time.getMetrics();
|
|
55
|
+
expect(metrics.startTime).toBeNull();
|
|
56
|
+
expect(metrics.endTime).toBeNull();
|
|
57
|
+
expect(metrics.duration).toBe(0);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type ErrorContext from "./types/ErrorContext";
|
|
2
|
+
export default class GlobalError extends Error {
|
|
3
|
+
context: ErrorContext;
|
|
4
|
+
constructor(msg: string | undefined);
|
|
5
|
+
setCode(code?: number): void;
|
|
6
|
+
setJson(json?: Record<string, unknown>): void;
|
|
7
|
+
setStack(stack?: string): void;
|
|
8
|
+
setName(name?: string): void;
|
|
9
|
+
hasJson(): boolean;
|
|
10
|
+
toString(): string;
|
|
11
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export default class GlobalError extends Error {
|
|
2
|
+
context = { message: "" };
|
|
3
|
+
constructor(msg) {
|
|
4
|
+
super(msg);
|
|
5
|
+
Object.setPrototypeOf(this, GlobalError.prototype);
|
|
6
|
+
this.context.message = msg;
|
|
7
|
+
}
|
|
8
|
+
setCode(code) {
|
|
9
|
+
this.context.code = code;
|
|
10
|
+
}
|
|
11
|
+
setJson(json) {
|
|
12
|
+
this.context.json = json;
|
|
13
|
+
}
|
|
14
|
+
setStack(stack) {
|
|
15
|
+
this.context.stack = stack;
|
|
16
|
+
}
|
|
17
|
+
setName(name) {
|
|
18
|
+
this.context.name = name;
|
|
19
|
+
}
|
|
20
|
+
hasJson() {
|
|
21
|
+
return this.context.json !== undefined;
|
|
22
|
+
}
|
|
23
|
+
toString() {
|
|
24
|
+
if (this.context.json)
|
|
25
|
+
return JSON.stringify(this.context.json);
|
|
26
|
+
return this.context.message;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=GlobalError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GlobalError.js","sourceRoot":"","sources":["../src/GlobalError.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,KAAK;IACtC,OAAO,GAAiB,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAE/C,YAAY,GAAuB;QAClC,KAAK,CAAC,GAAG,CAAC,CAAC;QACX,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;QAEnD,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,GAAa,CAAC;IACtC,CAAC;IAED,OAAO,CAAC,IAAa;QACpB,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAC1B,CAAC;IACD,OAAO,CAAC,IAA8B;QACrC,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAwB,CAAC;IAC9C,CAAC;IACD,QAAQ,CAAC,KAAc;QACtB,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;IAC5B,CAAC;IACD,OAAO,CAAC,IAAa;QACpB,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,OAAO;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC;IACxC,CAAC;IAEQ,QAAQ;QAChB,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC,OAAO,CAAC,OAAiB,CAAC;IACvC,CAAC;CACD"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type LoggerContext from "./types/LoggerContext";
|
|
2
|
+
export default abstract class GlobalLogger implements LoggerContext {
|
|
3
|
+
protected logs: string[];
|
|
4
|
+
constructor();
|
|
5
|
+
abstract log(message: string): void;
|
|
6
|
+
abstract logLevel(level: string, message: string): void;
|
|
7
|
+
abstract error(message: string, stack: string): void;
|
|
8
|
+
getLogs(): string[];
|
|
9
|
+
getLogsAsText(): string;
|
|
10
|
+
getLogsAsBase64(): string;
|
|
11
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default class GlobalLogger {
|
|
2
|
+
logs;
|
|
3
|
+
constructor() {
|
|
4
|
+
this.logs = [];
|
|
5
|
+
}
|
|
6
|
+
getLogs() {
|
|
7
|
+
return this.logs;
|
|
8
|
+
}
|
|
9
|
+
getLogsAsText() {
|
|
10
|
+
return this.logs.join("\n");
|
|
11
|
+
}
|
|
12
|
+
getLogsAsBase64() {
|
|
13
|
+
return Buffer.from(this.logs.join("\n")).toString("base64");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=GlobalLogger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GlobalLogger.js","sourceRoot":"","sources":["../src/GlobalLogger.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,OAAgB,YAAY;IAC/B,IAAI,CAAW;IAEzB;QACC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;IAChB,CAAC;IAMD,OAAO;QACN,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IAED,aAAa;QACZ,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED,eAAe;QACd,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC7D,CAAC;CACD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CpuUsageType, MemoryUsageType, TimeUsageType } from "./utils/MetricsBase";
|
|
2
|
+
declare class Metrics {
|
|
3
|
+
private cpuUsage;
|
|
4
|
+
private memoryUsage;
|
|
5
|
+
private time;
|
|
6
|
+
constructor();
|
|
7
|
+
start(): void;
|
|
8
|
+
retry(): void;
|
|
9
|
+
stop(): void;
|
|
10
|
+
clear(): void;
|
|
11
|
+
getMetrics(): MetricsType;
|
|
12
|
+
}
|
|
13
|
+
type MetricsType = {
|
|
14
|
+
cpu: CpuUsageType;
|
|
15
|
+
memory: MemoryUsageType;
|
|
16
|
+
time: TimeUsageType;
|
|
17
|
+
};
|
|
18
|
+
export { Metrics, type MetricsType };
|
package/dist/Metrics.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { CpuUsage, Time } from "./utils";
|
|
2
|
+
import MemoryUsage from "./utils/MemoryUsage";
|
|
3
|
+
class Metrics {
|
|
4
|
+
cpuUsage;
|
|
5
|
+
memoryUsage;
|
|
6
|
+
time;
|
|
7
|
+
constructor() {
|
|
8
|
+
this.cpuUsage = new CpuUsage();
|
|
9
|
+
this.memoryUsage = new MemoryUsage();
|
|
10
|
+
this.time = new Time();
|
|
11
|
+
}
|
|
12
|
+
start() {
|
|
13
|
+
this.cpuUsage.start();
|
|
14
|
+
this.memoryUsage.start();
|
|
15
|
+
this.time.start();
|
|
16
|
+
}
|
|
17
|
+
retry() {
|
|
18
|
+
this.memoryUsage.start();
|
|
19
|
+
}
|
|
20
|
+
stop() {
|
|
21
|
+
this.cpuUsage.stop();
|
|
22
|
+
this.time.stop();
|
|
23
|
+
this.memoryUsage.stop();
|
|
24
|
+
}
|
|
25
|
+
clear() {
|
|
26
|
+
this.memoryUsage.clear();
|
|
27
|
+
}
|
|
28
|
+
getMetrics() {
|
|
29
|
+
const cpu = this.cpuUsage.getMetrics();
|
|
30
|
+
const memory = this.memoryUsage.getMetrics();
|
|
31
|
+
const time = this.time.getMetrics();
|
|
32
|
+
return {
|
|
33
|
+
cpu,
|
|
34
|
+
memory: memory,
|
|
35
|
+
time,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export { Metrics };
|
|
40
|
+
//# sourceMappingURL=Metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Metrics.js","sourceRoot":"","sources":["../src/Metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,WAAW,MAAM,qBAAqB,CAAC;AAG9C,MAAM,OAAO;IACJ,QAAQ,CAAW;IACnB,WAAW,CAAc;IACzB,IAAI,CAAO;IAEnB;QACC,IAAI,CAAC,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;IACxB,CAAC;IAEM,KAAK;QACX,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;IAEM,KAAK;QACX,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;IAEM,IAAI;QACV,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACjB,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC;IAEM,KAAK;QACX,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;IAEM,UAAU;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC;QAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QAEpC,OAAO;YACN,GAAG;YACH,MAAM,EAAE,MAAM;YACd,IAAI;SACJ,CAAC;IACH,CAAC;CACD;AAQD,OAAO,EAAE,OAAO,EAAoB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import GlobalError from "./GlobalError";
|
|
2
|
+
import type Context from "./types/Context";
|
|
3
|
+
import type ErrorContext from "./types/ErrorContext";
|
|
4
|
+
import type FunctionContext from "./types/FunctionContext";
|
|
5
|
+
import type ParamsDictionary from "./types/ParamsDictionary";
|
|
6
|
+
import type ResponseContext from "./types/ResponseContext";
|
|
7
|
+
import type Step from "./types/Step";
|
|
8
|
+
import type VarsContext from "./types/VarsContext";
|
|
9
|
+
export default abstract class NodeBase {
|
|
10
|
+
flow: boolean;
|
|
11
|
+
name: string;
|
|
12
|
+
contentType: string;
|
|
13
|
+
active: boolean;
|
|
14
|
+
stop: boolean;
|
|
15
|
+
originalConfig: ParamsDictionary;
|
|
16
|
+
set_var: boolean;
|
|
17
|
+
process(ctx: Context, step?: Step): Promise<ResponseContext>;
|
|
18
|
+
processFlow(ctx: Context): Promise<ResponseContext>;
|
|
19
|
+
abstract run(ctx: Context): Promise<ResponseContext>;
|
|
20
|
+
runSteps(step: Step | Step[], ctx: Context): Promise<Context>;
|
|
21
|
+
runJs(str: string, ctx: Context, data?: ParamsDictionary, func?: FunctionContext, vars?: VarsContext): ParamsDictionary;
|
|
22
|
+
setVar(ctx: Context, vars: VarsContext): void;
|
|
23
|
+
getVar(ctx: Context, name: string): ParamsDictionary | undefined;
|
|
24
|
+
blueprintMapper: (obj: ParamsDictionary, ctx: Context, data?: ParamsDictionary) => string | ParamsDictionary;
|
|
25
|
+
setError(config: ErrorContext): GlobalError;
|
|
26
|
+
}
|
package/dist/NodeBase.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import _ from "lodash";
|
|
2
|
+
import GlobalError from "./GlobalError";
|
|
3
|
+
import mapper from "./utils/Mapper";
|
|
4
|
+
export default class NodeBase {
|
|
5
|
+
flow = false;
|
|
6
|
+
name = "";
|
|
7
|
+
contentType = "";
|
|
8
|
+
active = true;
|
|
9
|
+
stop = false;
|
|
10
|
+
originalConfig = {};
|
|
11
|
+
set_var = false;
|
|
12
|
+
async process(ctx, step) {
|
|
13
|
+
let response = {
|
|
14
|
+
success: true,
|
|
15
|
+
data: null,
|
|
16
|
+
error: null,
|
|
17
|
+
};
|
|
18
|
+
const config = ctx.config;
|
|
19
|
+
this.originalConfig = _.cloneDeep(config[this.name]);
|
|
20
|
+
this.blueprintMapper(config[this.name], ctx);
|
|
21
|
+
response = await this.run(ctx);
|
|
22
|
+
if (response.error)
|
|
23
|
+
throw response.error;
|
|
24
|
+
ctx.response = response;
|
|
25
|
+
return response;
|
|
26
|
+
}
|
|
27
|
+
async processFlow(ctx) {
|
|
28
|
+
let response = {
|
|
29
|
+
success: true,
|
|
30
|
+
data: null,
|
|
31
|
+
error: null,
|
|
32
|
+
};
|
|
33
|
+
try {
|
|
34
|
+
const config = ctx.config;
|
|
35
|
+
this.blueprintMapper(config[this.name], ctx);
|
|
36
|
+
response = await this.run(ctx);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
response.error = this.setError(error);
|
|
40
|
+
response.success = false;
|
|
41
|
+
ctx.response = response;
|
|
42
|
+
}
|
|
43
|
+
return response;
|
|
44
|
+
}
|
|
45
|
+
runSteps(step, ctx) {
|
|
46
|
+
console.error("[Error] runSteps method is not implemented.");
|
|
47
|
+
throw new Error("runSteps method is not implemented.");
|
|
48
|
+
}
|
|
49
|
+
runJs(str, ctx, data = {}, func = {}, vars = {}) {
|
|
50
|
+
return Function("ctx", "data", "func", "vars", `"use strict";return (${str});`)(ctx, data, func, vars);
|
|
51
|
+
}
|
|
52
|
+
setVar(ctx, vars) {
|
|
53
|
+
if (ctx.vars === undefined)
|
|
54
|
+
ctx.vars = {};
|
|
55
|
+
ctx.vars = { ...ctx.vars, ...vars };
|
|
56
|
+
}
|
|
57
|
+
getVar(ctx, name) {
|
|
58
|
+
return ctx.vars?.[name];
|
|
59
|
+
}
|
|
60
|
+
blueprintMapper = (obj, ctx, data) => {
|
|
61
|
+
let newObj = obj;
|
|
62
|
+
try {
|
|
63
|
+
if (typeof obj === "string")
|
|
64
|
+
newObj = mapper.replaceString(obj, ctx, data);
|
|
65
|
+
else
|
|
66
|
+
mapper.replaceObjectStrings(newObj, ctx, data);
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
console.log("MAPPER ERROR", e);
|
|
70
|
+
}
|
|
71
|
+
return newObj;
|
|
72
|
+
};
|
|
73
|
+
setError(config) {
|
|
74
|
+
let errorHandler;
|
|
75
|
+
if (typeof config === "string") {
|
|
76
|
+
errorHandler = new GlobalError(config);
|
|
77
|
+
}
|
|
78
|
+
else if (config.message && Object.keys(config).length === 1) {
|
|
79
|
+
errorHandler = new GlobalError(config.message);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
const err = typeof config === "object" ? JSON.stringify(config) : "Unkwon Error";
|
|
83
|
+
errorHandler = new GlobalError(err);
|
|
84
|
+
if (typeof config === "object") {
|
|
85
|
+
errorHandler.setJson(config);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (config.json)
|
|
89
|
+
errorHandler.setJson(config);
|
|
90
|
+
if (config.stack)
|
|
91
|
+
errorHandler.setStack(config.stack);
|
|
92
|
+
if (config.code)
|
|
93
|
+
errorHandler.setCode(typeof config.code === "number" ? config.code : 500);
|
|
94
|
+
errorHandler.setName(this.name);
|
|
95
|
+
return errorHandler;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=NodeBase.js.map
|