0z2i6v3u5t 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.
- package/.devcontainer/devcontainer.json +4 -0
- package/.devcontainer/setup.sh +11 -0
- package/.dockerignore +2 -0
- package/.github/CONTRIBUTING.md +52 -0
- package/.github/FUNDING.yml +3 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +59 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +43 -0
- package/.github/dependabot.yml +17 -0
- package/.github/workflows/codeql.yml +76 -0
- package/.github/workflows/publish_docs.yml +25 -0
- package/.github/workflows/test.yml +78 -0
- package/.nvmrc +1 -0
- package/.prettierignore +1 -0
- package/.prettierrc +1 -0
- package/.vscode/launch.json +42 -0
- package/CODE_OF_CONDUCT.md +76 -0
- package/Dockerfile +17 -0
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/SECURITY.md +5 -0
- package/__tests__/actions/cacheTest.ts +58 -0
- package/__tests__/actions/randomNumber.ts +26 -0
- package/__tests__/actions/recursiveAction.ts +16 -0
- package/__tests__/actions/sleepTest.ts +24 -0
- package/__tests__/actions/status.ts +17 -0
- package/__tests__/actions/swagger.ts +76 -0
- package/__tests__/actions/validationTest.ts +63 -0
- package/__tests__/cli/cli.ts +126 -0
- package/__tests__/core/api.ts +632 -0
- package/__tests__/core/cache.ts +400 -0
- package/__tests__/core/chatRoom.ts +589 -0
- package/__tests__/core/cli.ts +349 -0
- package/__tests__/core/cluster.ts +132 -0
- package/__tests__/core/config.ts +78 -0
- package/__tests__/core/errors.ts +112 -0
- package/__tests__/core/log.ts +23 -0
- package/__tests__/core/middleware.ts +427 -0
- package/__tests__/core/plugins/partialPlugin.ts +94 -0
- package/__tests__/core/plugins/withPlugin.ts +88 -0
- package/__tests__/core/plugins/withoutPlugin.ts +81 -0
- package/__tests__/core/process.ts +42 -0
- package/__tests__/core/specHelper.ts +330 -0
- package/__tests__/core/staticFile/compression.ts +99 -0
- package/__tests__/core/staticFile/staticFile.ts +180 -0
- package/__tests__/core/tasks/customQueueFunction.ts +67 -0
- package/__tests__/core/tasks/fullWorkerFlow.ts +199 -0
- package/__tests__/core/tasks/tasks.ts +605 -0
- package/__tests__/integration/browser.ts +133 -0
- package/__tests__/integration/ioredis-mock.ts +194 -0
- package/__tests__/integration/sendBuffer.ts +97 -0
- package/__tests__/integration/sendFile.ts +24 -0
- package/__tests__/integration/sharedFingerprint.ts +82 -0
- package/__tests__/integration/taskFlow.ts +110 -0
- package/__tests__/jest.ts +5 -0
- package/__tests__/modules/action.ts +103 -0
- package/__tests__/modules/config.ts +19 -0
- package/__tests__/modules/utils/ensureNoTsHeaderOrSpecFiles.ts +24 -0
- package/__tests__/servers/web/allowedRequestHosts.ts +88 -0
- package/__tests__/servers/web/enableMultiples.ts +83 -0
- package/__tests__/servers/web/fileUpload.ts +79 -0
- package/__tests__/servers/web/jsonp.ts +57 -0
- package/__tests__/servers/web/nonMultiples.ts +83 -0
- package/__tests__/servers/web/rawBody.ts +208 -0
- package/__tests__/servers/web/returnErrorCodes.ts +55 -0
- package/__tests__/servers/web/routes/deepRoutes.ts +96 -0
- package/__tests__/servers/web/routes/routes.ts +579 -0
- package/__tests__/servers/web/routes/veryDeepRoutes.ts +92 -0
- package/__tests__/servers/web/web.ts +1031 -0
- package/__tests__/servers/websocket.ts +795 -0
- package/__tests__/tasks/runAction.ts +37 -0
- package/__tests__/template.ts.example +20 -0
- package/__tests__/testCliCommands/hello.ts +44 -0
- package/__tests__/testPlugin/public/plugin.html +1 -0
- package/__tests__/testPlugin/src/actions/pluginAction.ts +14 -0
- package/__tests__/testPlugin/src/bin/hello.ts +22 -0
- package/__tests__/testPlugin/src/initializers/pluginInitializer.ts +17 -0
- package/__tests__/testPlugin/src/tasks/pluginTask.ts +15 -0
- package/__tests__/testPlugin/tsconfig.json +10 -0
- package/__tests__/utils/utils.ts +492 -0
- package/app.json +23 -0
- package/bin/deploy-docs +39 -0
- package/client/ActionheroWebsocketClient.js +277 -0
- package/docker-compose.yml +73 -0
- package/package.json +24 -0
- package/public/chat.html +194 -0
- package/public/css/cosmo.css +12 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +115 -0
- package/public/javascript/.gitkeep +0 -0
- package/public/linkedSession.html +80 -0
- package/public/logo/actionhero-small.png +0 -0
- package/public/logo/actionhero.png +0 -0
- package/public/pixel.gif +0 -0
- package/public/simple.html +2 -0
- package/public/swagger.html +32 -0
- package/public/websocketLoadTest.html +322 -0
- package/src/actions/cacheTest.ts +58 -0
- package/src/actions/createChatRoom.ts +20 -0
- package/src/actions/randomNumber.ts +17 -0
- package/src/actions/recursiveAction.ts +13 -0
- package/src/actions/sendFile.ts +12 -0
- package/src/actions/sleepTest.ts +40 -0
- package/src/actions/status.ts +73 -0
- package/src/actions/swagger.ts +155 -0
- package/src/actions/validationTest.ts +36 -0
- package/src/bin/actionhero.ts +225 -0
- package/src/bin/methods/actions/list.ts +30 -0
- package/src/bin/methods/console.ts +26 -0
- package/src/bin/methods/generate/action.ts +58 -0
- package/src/bin/methods/generate/cli.ts +51 -0
- package/src/bin/methods/generate/initializer.ts +54 -0
- package/src/bin/methods/generate/plugin.ts +57 -0
- package/src/bin/methods/generate/server.ts +38 -0
- package/src/bin/methods/generate/task.ts +68 -0
- package/src/bin/methods/generate.ts +176 -0
- package/src/bin/methods/task/enqueue.ts +35 -0
- package/src/classes/action.ts +98 -0
- package/src/classes/actionProcessor.ts +463 -0
- package/src/classes/api.ts +51 -0
- package/src/classes/cli.ts +67 -0
- package/src/classes/config.ts +15 -0
- package/src/classes/connection.ts +321 -0
- package/src/classes/exceptionReporter.ts +9 -0
- package/src/classes/initializer.ts +59 -0
- package/src/classes/initializers.ts +5 -0
- package/src/classes/input.ts +9 -0
- package/src/classes/inputs.ts +34 -0
- package/src/classes/process/actionheroVersion.ts +15 -0
- package/src/classes/process/env.ts +16 -0
- package/src/classes/process/id.ts +34 -0
- package/src/classes/process/pid.ts +32 -0
- package/src/classes/process/projectRoot.ts +16 -0
- package/src/classes/process/typescript.ts +47 -0
- package/src/classes/process.ts +479 -0
- package/src/classes/server.ts +251 -0
- package/src/classes/task.ts +87 -0
- package/src/config/api.ts +107 -0
- package/src/config/errors.ts +162 -0
- package/src/config/logger.ts +113 -0
- package/src/config/plugins.ts +37 -0
- package/src/config/redis.ts +78 -0
- package/src/config/routes.ts +44 -0
- package/src/config/tasks.ts +84 -0
- package/src/config/web.ts +136 -0
- package/src/config/websocket.ts +62 -0
- package/src/index.ts +46 -0
- package/src/initializers/actions.ts +125 -0
- package/src/initializers/chatRoom.ts +214 -0
- package/src/initializers/connections.ts +124 -0
- package/src/initializers/exceptions.ts +155 -0
- package/src/initializers/params.ts +52 -0
- package/src/initializers/redis.ts +191 -0
- package/src/initializers/resque.ts +248 -0
- package/src/initializers/routes.ts +229 -0
- package/src/initializers/servers.ts +134 -0
- package/src/initializers/specHelper.ts +195 -0
- package/src/initializers/staticFile.ts +253 -0
- package/src/initializers/tasks.ts +188 -0
- package/src/modules/action.ts +89 -0
- package/src/modules/cache.ts +326 -0
- package/src/modules/chatRoom.ts +321 -0
- package/src/modules/config.ts +246 -0
- package/src/modules/log.ts +62 -0
- package/src/modules/redis.ts +93 -0
- package/src/modules/route.ts +59 -0
- package/src/modules/specHelper.ts +182 -0
- package/src/modules/task.ts +527 -0
- package/src/modules/utils/argv.ts +3 -0
- package/src/modules/utils/arrayStartingMatch.ts +21 -0
- package/src/modules/utils/arrayUnique.ts +15 -0
- package/src/modules/utils/collapseObjectToArray.ts +33 -0
- package/src/modules/utils/deepCopy.ts +3 -0
- package/src/modules/utils/ensureNoTsHeaderOrSpecFiles.ts +19 -0
- package/src/modules/utils/eventLoopDelay.ts +34 -0
- package/src/modules/utils/fileUtils.ts +119 -0
- package/src/modules/utils/filterObjectForLogging.ts +51 -0
- package/src/modules/utils/filterResponseForLogging.ts +53 -0
- package/src/modules/utils/getExternalIPAddress.ts +17 -0
- package/src/modules/utils/hashMerge.ts +63 -0
- package/src/modules/utils/isPlainObject.ts +45 -0
- package/src/modules/utils/isRunning.ts +7 -0
- package/src/modules/utils/parseCookies.ts +20 -0
- package/src/modules/utils/parseHeadersForClientAddress.ts +53 -0
- package/src/modules/utils/parseIPv6URI.ts +24 -0
- package/src/modules/utils/replaceDistWithSrc.ts +9 -0
- package/src/modules/utils/safeGlob.ts +6 -0
- package/src/modules/utils/sleep.ts +8 -0
- package/src/modules/utils/sortGlobalMiddleware.ts +17 -0
- package/src/modules/utils/sourceRelativeLinkPath.ts +29 -0
- package/src/modules/utils.ts +66 -0
- package/src/server.ts +20 -0
- package/src/servers/web.ts +894 -0
- package/src/servers/websocket.ts +304 -0
- package/src/tasks/runAction.ts +29 -0
- package/tea.yaml +9 -0
- package/templates/README.md.template +17 -0
- package/templates/action.ts.template +15 -0
- package/templates/boot.js.template +9 -0
- package/templates/cli.ts.template +15 -0
- package/templates/gitignore.template +23 -0
- package/templates/initializer.ts.template +17 -0
- package/templates/package-plugin.json.template +12 -0
- package/templates/package.json.template +45 -0
- package/templates/projectMap.txt +39 -0
- package/templates/projectServer.ts.template +20 -0
- package/templates/server.ts.template +37 -0
- package/templates/task.ts.template +16 -0
- package/templates/test/action.ts.template +13 -0
- package/templates/test/task.ts.template +20 -0
- package/tsconfig.json +11 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
import { Process, specHelper } from "./../../src/index";
|
2
|
+
import { RunAction } from "../../src/tasks/runAction";
|
3
|
+
|
4
|
+
describe("Test: RunAction", () => {
|
5
|
+
const actionhero = new Process();
|
6
|
+
|
7
|
+
beforeAll(async () => await actionhero.start());
|
8
|
+
afterAll(async () => await actionhero.stop());
|
9
|
+
|
10
|
+
test("can run the task without params", async () => {
|
11
|
+
const { randomNumber } = await specHelper.runTask<RunAction>("runAction", {
|
12
|
+
action: "randomNumber",
|
13
|
+
});
|
14
|
+
expect(randomNumber).toBeGreaterThanOrEqual(0);
|
15
|
+
expect(randomNumber).toBeLessThan(1);
|
16
|
+
});
|
17
|
+
|
18
|
+
test("can run the task with params", async () => {
|
19
|
+
const { cacheTestResults } = await specHelper.runTask<RunAction>(
|
20
|
+
"runAction",
|
21
|
+
{
|
22
|
+
action: "cacheTest",
|
23
|
+
params: { key: "testKey", value: "testValue" },
|
24
|
+
},
|
25
|
+
);
|
26
|
+
expect(cacheTestResults.saveResp).toBe(true);
|
27
|
+
expect(cacheTestResults.deleteResp).toBe(true);
|
28
|
+
});
|
29
|
+
|
30
|
+
test("will throw with errors", async () => {
|
31
|
+
await expect(
|
32
|
+
specHelper.runTask<RunAction>("runAction", {
|
33
|
+
action: "cacheTest",
|
34
|
+
}),
|
35
|
+
).rejects.toThrow(/key is a required parameter for this action/);
|
36
|
+
});
|
37
|
+
});
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { Process, env, id, specHelper } from "actionhero";
|
2
|
+
import { Status } from "../../src/actions/status";
|
3
|
+
|
4
|
+
describe("actionhero Tests", () => {
|
5
|
+
const actionhero = new Process();
|
6
|
+
|
7
|
+
beforeAll(async () => await actionhero.start());
|
8
|
+
afterAll(async () => await actionhero.stop());
|
9
|
+
|
10
|
+
test("should have booted into the test env", () => {
|
11
|
+
expect(process.env.NODE_ENV).toEqual("test");
|
12
|
+
expect(env).toEqual("test");
|
13
|
+
expect(id).toBeTruthy();
|
14
|
+
});
|
15
|
+
|
16
|
+
test("can retrieve server uptime via the status action", async () => {
|
17
|
+
const { uptime } = await specHelper.runAction<Status>("status");
|
18
|
+
expect(uptime).toBeGreaterThan(0);
|
19
|
+
});
|
20
|
+
});
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import { CLI, ParamsFrom } from "./../../src/index";
|
2
|
+
|
3
|
+
export class HelloCliTest extends CLI {
|
4
|
+
name = "hello";
|
5
|
+
description = "I work";
|
6
|
+
inputs = {
|
7
|
+
name: {
|
8
|
+
required: false,
|
9
|
+
requiredValue: true,
|
10
|
+
default: "World",
|
11
|
+
},
|
12
|
+
title: {
|
13
|
+
letter: "t",
|
14
|
+
required: true,
|
15
|
+
default: "Dr.",
|
16
|
+
formatter: (val: string) => {
|
17
|
+
return `${val}.`;
|
18
|
+
},
|
19
|
+
validator: (val: string) => {
|
20
|
+
const parts = val.split(".");
|
21
|
+
if (parts.length > 2) throw new Error("too many periods");
|
22
|
+
},
|
23
|
+
},
|
24
|
+
countries: {
|
25
|
+
variadic: true as true,
|
26
|
+
formatter: (val: string) => `${val}!`,
|
27
|
+
validator: (val: string) => {
|
28
|
+
if (val.length > 0 && val[0].toUpperCase() !== val[0])
|
29
|
+
throw new Error("country not capitalized");
|
30
|
+
},
|
31
|
+
},
|
32
|
+
};
|
33
|
+
|
34
|
+
async run({ params }: { params: Partial<ParamsFrom<HelloCliTest>> }) {
|
35
|
+
const sayHello = (title: string, name: string, countries: string[]) =>
|
36
|
+
console.log(
|
37
|
+
`Hello, ${title} ${name} ${
|
38
|
+
countries ? `(${countries.join(" ")})` : ""
|
39
|
+
}`,
|
40
|
+
);
|
41
|
+
sayHello(params.title!, params.name!, params.countries!);
|
42
|
+
return true;
|
43
|
+
}
|
44
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>PLUGIN!<h1>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { Action } from "../../../../src/index";
|
2
|
+
|
3
|
+
export default class PluginAction extends Action {
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
this.name = "pluginAction";
|
7
|
+
this.description = "pluginAction";
|
8
|
+
this.outputExample = {};
|
9
|
+
}
|
10
|
+
|
11
|
+
async run({ response }) {
|
12
|
+
response.cool = true;
|
13
|
+
}
|
14
|
+
};
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { CLI } from "../../../../src/index";
|
2
|
+
|
3
|
+
export class Hello extends CLI {
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
this.name = "hello";
|
7
|
+
this.description = "I say hello";
|
8
|
+
this.inputs={
|
9
|
+
name: {
|
10
|
+
required: true,
|
11
|
+
description: 'Who we are greeting',
|
12
|
+
letter: 'g',
|
13
|
+
default: 'Actionhero'
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
async run({params}) {
|
19
|
+
console.log(`Hello, ${params.name}`);
|
20
|
+
return true;
|
21
|
+
}
|
22
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { api, Initializer } from "../../../../src/index";
|
2
|
+
|
3
|
+
export class PluginInitializer extends Initializer {
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
this.name = "pluginInitializer";
|
7
|
+
}
|
8
|
+
|
9
|
+
async initialize() {
|
10
|
+
api.pluginInitializer = { here: true };
|
11
|
+
}
|
12
|
+
|
13
|
+
async stop() {
|
14
|
+
// this seems silly, but is needed for testing, as we never clear properties on the API object
|
15
|
+
delete api.pluginInitializer;
|
16
|
+
}
|
17
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { Task } from "../../../../src/index";
|
2
|
+
|
3
|
+
export class PluginTask extends Task {
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
this.name = "pluginTask";
|
7
|
+
this.description = "pluginTask";
|
8
|
+
this.frequency = 0;
|
9
|
+
this.queue = "default";
|
10
|
+
}
|
11
|
+
|
12
|
+
async run(params) {
|
13
|
+
return true;
|
14
|
+
}
|
15
|
+
}
|
@@ -0,0 +1,492 @@
|
|
1
|
+
import * as glob from "glob";
|
2
|
+
import * as path from "path";
|
3
|
+
import { config, utils } from "./../../src/index";
|
4
|
+
|
5
|
+
describe("Utils", () => {
|
6
|
+
describe("util.sleep", () => {
|
7
|
+
test("it sleeps", async () => {
|
8
|
+
const start = new Date().getTime();
|
9
|
+
await utils.sleep(100);
|
10
|
+
const end = new Date().getTime();
|
11
|
+
expect(end - start).toBeGreaterThanOrEqual(99);
|
12
|
+
expect(end - start).toBeLessThan(200);
|
13
|
+
});
|
14
|
+
});
|
15
|
+
|
16
|
+
describe("utils.arrayUnique", () => {
|
17
|
+
test("works", () => {
|
18
|
+
const a = [1, 2, 3, 3, 4, 4, 4, 5, 5, 5];
|
19
|
+
expect(utils.arrayUnique(a)).toEqual([1, 2, 3, 4, 5]);
|
20
|
+
});
|
21
|
+
});
|
22
|
+
|
23
|
+
describe("utils.collapseObjectToArray", () => {
|
24
|
+
test("fails with numerical keys", () => {
|
25
|
+
const o = { 0: "a", 1: "b" };
|
26
|
+
const response = utils.collapseObjectToArray(o);
|
27
|
+
expect(response).toEqual(["a", "b"]);
|
28
|
+
});
|
29
|
+
|
30
|
+
test("fails with non-numerical keys", () => {
|
31
|
+
const o = { a: 1 };
|
32
|
+
const response = utils.collapseObjectToArray(o);
|
33
|
+
expect(response).toEqual(false);
|
34
|
+
});
|
35
|
+
});
|
36
|
+
|
37
|
+
describe("utils.hashMerge", () => {
|
38
|
+
const A = { a: 1, b: 2 };
|
39
|
+
const B = { b: -2, c: 3 };
|
40
|
+
const C = { a: 1, b: { m: 10, n: 11 } };
|
41
|
+
const D = { a: 1, b: { n: 111, o: 22, p: {} } };
|
42
|
+
const E = { b: {} };
|
43
|
+
const N = { b: null } as Record<string, any>;
|
44
|
+
const U = { b: undefined } as Record<string, any>;
|
45
|
+
|
46
|
+
test("simple", () => {
|
47
|
+
const Z = utils.hashMerge(A, B);
|
48
|
+
expect(Z.a).toEqual(1);
|
49
|
+
expect(Z.b).toEqual(-2);
|
50
|
+
expect(Z.c).toEqual(3);
|
51
|
+
});
|
52
|
+
|
53
|
+
test("directional", () => {
|
54
|
+
const Z = utils.hashMerge(B, A);
|
55
|
+
expect(Z.a).toEqual(1);
|
56
|
+
expect(Z.b).toEqual(2);
|
57
|
+
expect(Z.c).toEqual(3);
|
58
|
+
});
|
59
|
+
|
60
|
+
test("nested", () => {
|
61
|
+
const Z = utils.hashMerge(C, D);
|
62
|
+
expect(Z.a).toEqual(1);
|
63
|
+
expect(Z.b.m).toEqual(10);
|
64
|
+
expect(Z.b.n).toEqual(111);
|
65
|
+
expect(Z.b.o).toEqual(22);
|
66
|
+
expect(Z.b.p).toEqual({});
|
67
|
+
});
|
68
|
+
|
69
|
+
test("empty01", () => {
|
70
|
+
const Z = utils.hashMerge(E, D);
|
71
|
+
expect(Z.a).toEqual(1);
|
72
|
+
expect(Z.b.n).toEqual(111);
|
73
|
+
expect(Z.b.o).toEqual(22);
|
74
|
+
expect(Z.b.p).toEqual({});
|
75
|
+
});
|
76
|
+
|
77
|
+
test("empty10", () => {
|
78
|
+
const Z = utils.hashMerge(D, E);
|
79
|
+
expect(Z.a).toEqual(1);
|
80
|
+
expect(Z.b.n).toEqual(111);
|
81
|
+
expect(Z.b.o).toEqual(22);
|
82
|
+
expect(Z.b.p).toEqual({});
|
83
|
+
});
|
84
|
+
|
85
|
+
test("chained", () => {
|
86
|
+
const Z = utils.hashMerge(utils.hashMerge(C, E), D);
|
87
|
+
expect(Z.a).toEqual(1);
|
88
|
+
expect(Z.b.m).toEqual(10);
|
89
|
+
expect(Z.b.n).toEqual(111);
|
90
|
+
expect(Z.b.o).toEqual(22);
|
91
|
+
expect(Z.b.p).toEqual({});
|
92
|
+
});
|
93
|
+
|
94
|
+
test("null", () => {
|
95
|
+
const Z = utils.hashMerge(A, N);
|
96
|
+
expect(Z.a).toEqual(1);
|
97
|
+
expect(Z.b).toBeUndefined();
|
98
|
+
});
|
99
|
+
|
100
|
+
test("undefined", () => {
|
101
|
+
const Z = utils.hashMerge(A, U);
|
102
|
+
expect(Z.a).toEqual(1);
|
103
|
+
expect(Z.b).toEqual(2);
|
104
|
+
});
|
105
|
+
});
|
106
|
+
|
107
|
+
describe("eventLoopDelay", () => {
|
108
|
+
test("works", async () => {
|
109
|
+
const delay = await utils.eventLoopDelay(10000);
|
110
|
+
expect(delay).toBeGreaterThan(0);
|
111
|
+
expect(delay).toBeLessThan(1);
|
112
|
+
});
|
113
|
+
});
|
114
|
+
|
115
|
+
describe("#parseHeadersForClientAddress", () => {
|
116
|
+
test("only x-real-ip, port is null", () => {
|
117
|
+
const headers = {
|
118
|
+
"x-real-ip": "10.11.12.13",
|
119
|
+
};
|
120
|
+
const { ip, port } = utils.parseHeadersForClientAddress(headers);
|
121
|
+
expect(ip).toEqual("10.11.12.13");
|
122
|
+
expect(port).toBeFalsy();
|
123
|
+
});
|
124
|
+
test("load balancer, x-forwarded-for format", () => {
|
125
|
+
const headers = {
|
126
|
+
"x-forwarded-for": "35.36.37.38",
|
127
|
+
"x-forwarded-port": "80",
|
128
|
+
};
|
129
|
+
const { ip, port } = utils.parseHeadersForClientAddress(headers);
|
130
|
+
expect(ip).toEqual("35.36.37.38");
|
131
|
+
expect(port).toEqual("80");
|
132
|
+
});
|
133
|
+
});
|
134
|
+
|
135
|
+
describe("#parseIPv6URI", () => {
|
136
|
+
test("address and port", () => {
|
137
|
+
const uri = "[2604:4480::5]:8080";
|
138
|
+
const parts = utils.parseIPv6URI(uri);
|
139
|
+
expect(parts.host).toEqual("2604:4480::5");
|
140
|
+
expect(parts.port).toEqual(8080);
|
141
|
+
});
|
142
|
+
|
143
|
+
test("address without port", () => {
|
144
|
+
const uri = "2604:4480::5";
|
145
|
+
const parts = utils.parseIPv6URI(uri);
|
146
|
+
expect(parts.host).toEqual("2604:4480::5");
|
147
|
+
expect(parts.port).toEqual(80);
|
148
|
+
});
|
149
|
+
|
150
|
+
test("full uri", () => {
|
151
|
+
const uri = "http://[2604:4480::5]:8080/foo/bar";
|
152
|
+
const parts = utils.parseIPv6URI(uri);
|
153
|
+
expect(parts.host).toEqual("2604:4480::5");
|
154
|
+
expect(parts.port).toEqual(8080);
|
155
|
+
});
|
156
|
+
|
157
|
+
test("failing address", () => {
|
158
|
+
const uri = "[2604:4480:z:5]:80";
|
159
|
+
try {
|
160
|
+
const parts = utils.parseIPv6URI(uri);
|
161
|
+
console.log(parts);
|
162
|
+
} catch (e) {
|
163
|
+
expect(e.message).toEqual("failed to parse address");
|
164
|
+
}
|
165
|
+
});
|
166
|
+
|
167
|
+
test("should parse locally scoped ipv6 URIs without port", () => {
|
168
|
+
const uri = "fe80::1ff:fe23:4567:890a%eth2";
|
169
|
+
const parts = utils.parseIPv6URI(uri);
|
170
|
+
expect(parts.host).toEqual("fe80::1ff:fe23:4567:890a%eth2");
|
171
|
+
expect(parts.port).toEqual(80);
|
172
|
+
});
|
173
|
+
|
174
|
+
test("should parse locally scoped ipv6 URIs with port", () => {
|
175
|
+
const uri = "[fe80::1ff:fe23:4567:890a%eth2]:8080";
|
176
|
+
const parts = utils.parseIPv6URI(uri);
|
177
|
+
expect(parts.host).toEqual("fe80::1ff:fe23:4567:890a%eth2");
|
178
|
+
expect(parts.port).toEqual(8080);
|
179
|
+
});
|
180
|
+
});
|
181
|
+
|
182
|
+
describe("utils.arrayStartingMatch", () => {
|
183
|
+
test("finds matching arrays", () => {
|
184
|
+
const a = [1, 2, 3];
|
185
|
+
const b = [1, 2, 3, 4, 5];
|
186
|
+
const numberResult = utils.arrayStartingMatch(a, b);
|
187
|
+
expect(numberResult).toBe(true);
|
188
|
+
|
189
|
+
const c = ["a", "b", "c"];
|
190
|
+
const d = ["a", "b", "c", "d", "e"];
|
191
|
+
const stringResult = utils.arrayStartingMatch(c, d);
|
192
|
+
expect(stringResult).toBe(true);
|
193
|
+
});
|
194
|
+
|
195
|
+
test("finds non-matching arrays", () => {
|
196
|
+
const a = [1, 3];
|
197
|
+
const b = [1, 2, 3, 4, 5];
|
198
|
+
const numberResult = utils.arrayStartingMatch(a, b);
|
199
|
+
expect(numberResult).toBe(false);
|
200
|
+
|
201
|
+
const c = ["a", "b", "c"];
|
202
|
+
const d = ["a", "b", "d", "e"];
|
203
|
+
const stringResult = utils.arrayStartingMatch(c, d);
|
204
|
+
expect(stringResult).toBe(false);
|
205
|
+
});
|
206
|
+
|
207
|
+
test("does not pass with empty arrays; first", () => {
|
208
|
+
const a: number[] = [];
|
209
|
+
const b = [1, 2, 3, 4, 5];
|
210
|
+
const result = utils.arrayStartingMatch(a, b);
|
211
|
+
expect(result).toBe(false);
|
212
|
+
});
|
213
|
+
|
214
|
+
test("does not pass with empty arrays; second", () => {
|
215
|
+
const a = [1, 2, 3, 4, 5];
|
216
|
+
const b: number[] = [];
|
217
|
+
const result = utils.arrayStartingMatch(a, b);
|
218
|
+
expect(result).toBe(false);
|
219
|
+
});
|
220
|
+
});
|
221
|
+
|
222
|
+
describe("utils.replaceDistWithSrc", () => {
|
223
|
+
test("it replaces paths from dist to src", () => {
|
224
|
+
const p = `${config.general!.paths.action[0]}/new-actions/test.ts`;
|
225
|
+
const withDist = utils.replaceDistWithSrc(p);
|
226
|
+
expect(withDist).toMatch("/src/actions/new-actions/test.ts");
|
227
|
+
});
|
228
|
+
});
|
229
|
+
|
230
|
+
describe("utils.filterObjectForLogging", () => {
|
231
|
+
beforeEach(() => {
|
232
|
+
config.logger!.maxLogArrayLength = 100;
|
233
|
+
expect(config.general!.filteredParams.length).toEqual(0);
|
234
|
+
});
|
235
|
+
|
236
|
+
afterEach(() => {
|
237
|
+
// after each test, empty the array
|
238
|
+
config.general!.filteredParams = [];
|
239
|
+
config.logger!.maxLogArrayLength = 10;
|
240
|
+
});
|
241
|
+
|
242
|
+
const testInput = {
|
243
|
+
p1: 1,
|
244
|
+
p2: "s3cr3t",
|
245
|
+
o1: {
|
246
|
+
o1p1: 1,
|
247
|
+
o1p2: "also-s3cr3t",
|
248
|
+
o2: {
|
249
|
+
o2p1: "this is ok",
|
250
|
+
o2p2: "extremely-s3cr3t",
|
251
|
+
},
|
252
|
+
},
|
253
|
+
o2: {
|
254
|
+
name: "same as o1`s inner object!",
|
255
|
+
o2p1: "nothing secret",
|
256
|
+
},
|
257
|
+
a1: ["a", "b", "c"],
|
258
|
+
a2: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
259
|
+
};
|
260
|
+
|
261
|
+
test("can filter top level params, no matter the type", () => {
|
262
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
263
|
+
(config.general!.filteredParams as string[]).push("p1", "p2", "o2");
|
264
|
+
const filteredParams = utils.filterObjectForLogging(inputs);
|
265
|
+
expect(filteredParams.p1).toEqual("[FILTERED]");
|
266
|
+
expect(filteredParams.p2).toEqual("[FILTERED]");
|
267
|
+
expect(filteredParams.o2).toEqual("[FILTERED]"); // entire object filtered
|
268
|
+
expect(filteredParams.o1).toEqual(testInput.o1); // unchanged
|
269
|
+
expect(filteredParams.a1).toEqual(testInput.a1); // unchanged
|
270
|
+
expect(filteredParams.a2).toEqual(testInput.a2); // unchanged
|
271
|
+
});
|
272
|
+
|
273
|
+
test("will not filter things that do not exist", () => {
|
274
|
+
// Identity
|
275
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
276
|
+
const filteredParams = utils.filterObjectForLogging(inputs);
|
277
|
+
expect(filteredParams).toEqual(testInput);
|
278
|
+
|
279
|
+
(config.general!.filteredParams as string[]).push(
|
280
|
+
"p3",
|
281
|
+
"p4",
|
282
|
+
"o1.o3",
|
283
|
+
"o1.o2.p1",
|
284
|
+
);
|
285
|
+
const filteredParams2 = utils.filterObjectForLogging(inputs);
|
286
|
+
expect(filteredParams2).toEqual(testInput);
|
287
|
+
expect(filteredParams.a1).toEqual(testInput.a1); // unchanged
|
288
|
+
expect(filteredParams.a2).toEqual(testInput.a2); // unchanged
|
289
|
+
});
|
290
|
+
|
291
|
+
test("can filter a single level dot notation", () => {
|
292
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
293
|
+
(config.general!.filteredParams as string[]).push(
|
294
|
+
"p1",
|
295
|
+
"o1.o1p1",
|
296
|
+
"somethingNotExist",
|
297
|
+
);
|
298
|
+
const filteredParams = utils.filterObjectForLogging(inputs);
|
299
|
+
expect(filteredParams.p1).toEqual("[FILTERED]");
|
300
|
+
expect(filteredParams.o1.o1p1).toEqual("[FILTERED]");
|
301
|
+
// Unchanged things
|
302
|
+
expect(filteredParams.p2).toEqual(testInput.p2);
|
303
|
+
expect(filteredParams.o1.o1p2).toEqual(testInput.o1.o1p2);
|
304
|
+
expect(filteredParams.o1.o2).toEqual(testInput.o1.o2);
|
305
|
+
expect(filteredParams.o2).toEqual(testInput.o2);
|
306
|
+
expect(filteredParams.a1).toEqual(testInput.a1);
|
307
|
+
expect(filteredParams.a2).toEqual(testInput.a2);
|
308
|
+
});
|
309
|
+
|
310
|
+
test("can filter two levels deep", () => {
|
311
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
312
|
+
(config.general!.filteredParams as string[]).push(
|
313
|
+
"p2",
|
314
|
+
"o1.o2.o2p1",
|
315
|
+
"o1.o2.notThere",
|
316
|
+
);
|
317
|
+
const filteredParams = utils.filterObjectForLogging(inputs);
|
318
|
+
expect(filteredParams.p2).toEqual("[FILTERED]");
|
319
|
+
expect(filteredParams.o1.o2.o2p1).toEqual("[FILTERED]");
|
320
|
+
// Unchanged things
|
321
|
+
expect(filteredParams.p1).toEqual(testInput.p1);
|
322
|
+
expect(filteredParams.o1.o1p1).toEqual(testInput.o1.o1p1);
|
323
|
+
expect(filteredParams.o1.o2.o2p2).toEqual(testInput.o1.o2.o2p2);
|
324
|
+
expect(filteredParams.a1).toEqual(testInput.a1);
|
325
|
+
expect(filteredParams.a2).toEqual(testInput.a2);
|
326
|
+
});
|
327
|
+
|
328
|
+
test("can filter with a function rather than an array", () => {
|
329
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
330
|
+
config.general!.filteredParams = () => {
|
331
|
+
return ["p1", "p2", "o2"];
|
332
|
+
};
|
333
|
+
|
334
|
+
const filteredParams = utils.filterObjectForLogging(inputs);
|
335
|
+
expect(filteredParams.p1).toEqual("[FILTERED]");
|
336
|
+
expect(filteredParams.p2).toEqual("[FILTERED]");
|
337
|
+
expect(filteredParams.o2).toEqual("[FILTERED]"); // entire object filtered
|
338
|
+
// Unchanged things
|
339
|
+
expect(filteredParams.o1).toEqual(testInput.o1);
|
340
|
+
expect(filteredParams.a1).toEqual(testInput.a1);
|
341
|
+
expect(filteredParams.a2).toEqual(testInput.a2);
|
342
|
+
});
|
343
|
+
|
344
|
+
test("short arrays will be displayed as-is", () => {
|
345
|
+
config.logger!.maxLogArrayLength = 100;
|
346
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
347
|
+
const filteredParams = utils.filterObjectForLogging(inputs);
|
348
|
+
expect(filteredParams.a1).toEqual(testInput.a1);
|
349
|
+
expect(filteredParams.a2).toEqual(testInput.a2);
|
350
|
+
});
|
351
|
+
|
352
|
+
test("long arrays will be collected", () => {
|
353
|
+
config.logger!.maxLogArrayLength = 10;
|
354
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
355
|
+
const filteredParams = utils.filterObjectForLogging(inputs);
|
356
|
+
expect(filteredParams.a1).toEqual(testInput.a1);
|
357
|
+
expect(filteredParams.a2).toEqual("11 items");
|
358
|
+
});
|
359
|
+
});
|
360
|
+
|
361
|
+
describe("utils.filterResponseForLogging", () => {
|
362
|
+
beforeEach(() => {
|
363
|
+
config.logger!.maxLogArrayLength = 100;
|
364
|
+
expect(config.general!.filteredResponse.length).toEqual(0);
|
365
|
+
});
|
366
|
+
|
367
|
+
afterEach(() => {
|
368
|
+
// after each test, empty the array
|
369
|
+
config.general!.filteredResponse = [];
|
370
|
+
config.logger!.maxLogArrayLength = 10;
|
371
|
+
});
|
372
|
+
|
373
|
+
const testInput = {
|
374
|
+
p1: 1,
|
375
|
+
p2: "s3cr3t",
|
376
|
+
o1: {
|
377
|
+
o1p1: 1,
|
378
|
+
o1p2: "also-s3cr3t",
|
379
|
+
o2: {
|
380
|
+
o2p1: "this is ok",
|
381
|
+
o2p2: "extremely-s3cr3t",
|
382
|
+
},
|
383
|
+
},
|
384
|
+
o2: {
|
385
|
+
name: "same as o1`s inner object!",
|
386
|
+
o2p1: "nothing secret",
|
387
|
+
},
|
388
|
+
a1: ["a", "b", "c"],
|
389
|
+
a2: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
390
|
+
};
|
391
|
+
|
392
|
+
test("can filter top level params, no matter the type", () => {
|
393
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
394
|
+
(config.general!.filteredResponse as string[]).push("p1", "p2", "o2");
|
395
|
+
const filteredResponse = utils.filterResponseForLogging(inputs);
|
396
|
+
expect(filteredResponse.p1).toEqual("[FILTERED]");
|
397
|
+
expect(filteredResponse.p2).toEqual("[FILTERED]");
|
398
|
+
expect(filteredResponse.o2).toEqual("[FILTERED]"); // entire object filtered
|
399
|
+
expect(filteredResponse.o1).toEqual(testInput.o1); // unchanged
|
400
|
+
expect(filteredResponse.a1).toEqual(testInput.a1); // unchanged
|
401
|
+
expect(filteredResponse.a2).toEqual(testInput.a2); // unchanged
|
402
|
+
});
|
403
|
+
|
404
|
+
test("will not filter things that do not exist", () => {
|
405
|
+
// Identity
|
406
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
407
|
+
const filteredResponse = utils.filterResponseForLogging(inputs);
|
408
|
+
expect(filteredResponse).toEqual(testInput);
|
409
|
+
|
410
|
+
(config.general!.filteredResponse as string[]).push(
|
411
|
+
"p3",
|
412
|
+
"p4",
|
413
|
+
"o1.o3",
|
414
|
+
"o1.o2.p1",
|
415
|
+
);
|
416
|
+
const filteredResponse2 = utils.filterResponseForLogging(inputs);
|
417
|
+
expect(filteredResponse2).toEqual(testInput);
|
418
|
+
expect(filteredResponse2.a1).toEqual(testInput.a1); // unchanged
|
419
|
+
expect(filteredResponse2.a2).toEqual(testInput.a2); // unchanged
|
420
|
+
});
|
421
|
+
|
422
|
+
test("can filter a single level dot notation", () => {
|
423
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
424
|
+
(config.general!.filteredResponse as string[]).push(
|
425
|
+
"p1",
|
426
|
+
"o1.o1p1",
|
427
|
+
"somethingNotExist",
|
428
|
+
);
|
429
|
+
const filteredResponse = utils.filterResponseForLogging(inputs);
|
430
|
+
expect(filteredResponse.p1).toEqual("[FILTERED]");
|
431
|
+
expect(filteredResponse.o1.o1p1).toEqual("[FILTERED]");
|
432
|
+
// Unchanged things
|
433
|
+
expect(filteredResponse.p2).toEqual(testInput.p2);
|
434
|
+
expect(filteredResponse.o1.o1p2).toEqual(testInput.o1.o1p2);
|
435
|
+
expect(filteredResponse.o1.o2).toEqual(testInput.o1.o2);
|
436
|
+
expect(filteredResponse.o2).toEqual(testInput.o2);
|
437
|
+
expect(filteredResponse.a1).toEqual(testInput.a1);
|
438
|
+
expect(filteredResponse.a2).toEqual(testInput.a2);
|
439
|
+
});
|
440
|
+
|
441
|
+
test("can filter two levels deep", () => {
|
442
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
443
|
+
(config.general!.filteredResponse as string[]).push(
|
444
|
+
"p2",
|
445
|
+
"o1.o2.o2p1",
|
446
|
+
"o1.o2.notThere",
|
447
|
+
);
|
448
|
+
const filteredResponse = utils.filterResponseForLogging(inputs);
|
449
|
+
expect(filteredResponse.p2).toEqual("[FILTERED]");
|
450
|
+
expect(filteredResponse.o1.o2.o2p1).toEqual("[FILTERED]");
|
451
|
+
// Unchanged things
|
452
|
+
expect(filteredResponse.p1).toEqual(testInput.p1);
|
453
|
+
expect(filteredResponse.o1.o1p1).toEqual(testInput.o1.o1p1);
|
454
|
+
expect(filteredResponse.o1.o2.o2p2).toEqual(testInput.o1.o2.o2p2);
|
455
|
+
expect(filteredResponse.a1).toEqual(testInput.a1);
|
456
|
+
expect(filteredResponse.a2).toEqual(testInput.a2);
|
457
|
+
});
|
458
|
+
|
459
|
+
test("can filter with a function rather than an array", () => {
|
460
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
461
|
+
config.general!.filteredResponse = () => {
|
462
|
+
return ["p1", "p2", "o2"];
|
463
|
+
};
|
464
|
+
|
465
|
+
const filteredResponse = utils.filterResponseForLogging(inputs);
|
466
|
+
expect(filteredResponse.p1).toEqual("[FILTERED]");
|
467
|
+
expect(filteredResponse.p2).toEqual("[FILTERED]");
|
468
|
+
expect(filteredResponse.o2).toEqual("[FILTERED]"); // entire object filtered
|
469
|
+
expect(filteredResponse.o1).toEqual(testInput.o1); // unchanged
|
470
|
+
expect(filteredResponse.a1).toEqual(testInput.a1);
|
471
|
+
expect(filteredResponse.a2).toEqual(testInput.a2);
|
472
|
+
});
|
473
|
+
|
474
|
+
test("long arrays will be collected", () => {
|
475
|
+
config.logger!.maxLogArrayLength = 10;
|
476
|
+
const inputs = JSON.parse(JSON.stringify(testInput)); // quick deep Clone
|
477
|
+
const filteredResponse = utils.filterResponseForLogging(inputs);
|
478
|
+
expect(filteredResponse.a1).toEqual(testInput.a1);
|
479
|
+
expect(filteredResponse.a2).toEqual("11 items");
|
480
|
+
});
|
481
|
+
|
482
|
+
test("safeGlobSync to match normal glob.sync", () => {
|
483
|
+
const directory = __dirname; // if it is windows platform includes backslash (\\)
|
484
|
+
const pattern = "/**/*.ts";
|
485
|
+
const normalResult = glob.sync(directory.replace(/\\/g, "/") + pattern); // do not use path.join
|
486
|
+
|
487
|
+
const safeResult = utils.safeGlobSync(path.join(directory, pattern));
|
488
|
+
|
489
|
+
expect(normalResult).toEqual(safeResult);
|
490
|
+
});
|
491
|
+
});
|
492
|
+
});
|