@codeclimbers/server 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +73 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/src/app.module.d.ts +4 -0
- package/dist/src/app.module.js +49 -0
- package/dist/src/app.module.js.map +1 -0
- package/dist/src/assets/startup.plist.d.ts +1 -0
- package/dist/src/assets/startup.plist.js +41 -0
- package/dist/src/assets/startup.plist.js.map +1 -0
- package/dist/src/common/infrastructure/http/controllers/health.controller.d.ts +5 -0
- package/dist/src/common/infrastructure/http/controllers/health.controller.js +29 -0
- package/dist/src/common/infrastructure/http/controllers/health.controller.js.map +1 -0
- package/dist/src/common/infrastructure/http/middleware/requestlogger.middleware.d.ts +5 -0
- package/dist/src/common/infrastructure/http/middleware/requestlogger.middleware.js +27 -0
- package/dist/src/common/infrastructure/http/middleware/requestlogger.middleware.js.map +1 -0
- package/dist/src/main.d.ts +2 -0
- package/dist/src/main.js +44 -0
- package/dist/src/main.js.map +1 -0
- package/dist/src/sentry.d.ts +1 -0
- package/dist/src/sentry.js +13 -0
- package/dist/src/sentry.js.map +1 -0
- package/dist/src/v1/activities/activities.service.d.ts +21 -0
- package/dist/src/v1/activities/activities.service.js +174 -0
- package/dist/src/v1/activities/activities.service.js.map +1 -0
- package/dist/src/v1/activities/pulse.controller.d.ts +19 -0
- package/dist/src/v1/activities/pulse.controller.js +92 -0
- package/dist/src/v1/activities/pulse.controller.js.map +1 -0
- package/dist/src/v1/activities/wakatimeProxy.controller.d.ts +13 -0
- package/dist/src/v1/activities/wakatimeProxy.controller.js +64 -0
- package/dist/src/v1/activities/wakatimeProxy.controller.js.map +1 -0
- package/dist/src/v1/database/__tests__/knex.test.d.ts +1 -0
- package/dist/src/v1/database/__tests__/knex.test.js +18 -0
- package/dist/src/v1/database/__tests__/knex.test.js.map +1 -0
- package/dist/src/v1/database/__tests__/pulse.repo.test.d.ts +1 -0
- package/dist/src/v1/database/__tests__/pulse.repo.test.js +141 -0
- package/dist/src/v1/database/__tests__/pulse.repo.test.js.map +1 -0
- package/dist/src/v1/database/knex.d.ts +5 -0
- package/dist/src/v1/database/knex.js +87 -0
- package/dist/src/v1/database/knex.js.map +1 -0
- package/dist/src/v1/database/migrations.d.ts +1 -0
- package/dist/src/v1/database/migrations.js +16 -0
- package/dist/src/v1/database/migrations.js.map +1 -0
- package/dist/src/v1/database/pulse.repo.d.ts +17 -0
- package/dist/src/v1/database/pulse.repo.js +115 -0
- package/dist/src/v1/database/pulse.repo.js.map +1 -0
- package/dist/src/v1/database/queries/getCategoryTimeOverview.sql +6 -0
- package/dist/src/v1/database/queries/getLongestDayInRangeMinutes.sql +11 -0
- package/dist/src/v1/database/queries/getStatusBarDetails.sql +42 -0
- package/dist/src/v1/dtos/createWakatimePulse.dto.d.ts +19 -0
- package/dist/src/v1/dtos/createWakatimePulse.dto.js +97 -0
- package/dist/src/v1/dtos/createWakatimePulse.dto.js.map +1 -0
- package/dist/src/v1/dtos/getCategoryTimeOverview.dto.d.ts +4 -0
- package/dist/src/v1/dtos/getCategoryTimeOverview.dto.js +25 -0
- package/dist/src/v1/dtos/getCategoryTimeOverview.dto.js.map +1 -0
- package/dist/src/v1/dtos/getWeekOverview.dto.d.ts +3 -0
- package/dist/src/v1/dtos/getWeekOverview.dto.js +21 -0
- package/dist/src/v1/dtos/getWeekOverview.dto.js.map +1 -0
- package/dist/src/v1/startup/darwinStartup.service.d.ts +8 -0
- package/dist/src/v1/startup/darwinStartup.service.js +114 -0
- package/dist/src/v1/startup/darwinStartup.service.js.map +1 -0
- package/dist/src/v1/startup/linuxStartup.service.d.ts +8 -0
- package/dist/src/v1/startup/linuxStartup.service.js +104 -0
- package/dist/src/v1/startup/linuxStartup.service.js.map +1 -0
- package/dist/src/v1/startup/startup.controller.d.ts +8 -0
- package/dist/src/v1/startup/startup.controller.js +46 -0
- package/dist/src/v1/startup/startup.controller.js.map +1 -0
- package/dist/src/v1/startup/startup.util.d.ts +5 -0
- package/dist/src/v1/startup/startup.util.js +19 -0
- package/dist/src/v1/startup/startup.util.js.map +1 -0
- package/dist/src/v1/startup/startupService.factory.d.ts +9 -0
- package/dist/src/v1/startup/startupService.factory.js +41 -0
- package/dist/src/v1/startup/startupService.factory.js.map +1 -0
- package/dist/src/v1/startup/unsupportedStartup.service.d.ts +6 -0
- package/dist/src/v1/startup/unsupportedStartup.service.js +29 -0
- package/dist/src/v1/startup/unsupportedStartup.service.js.map +1 -0
- package/dist/src/v1/v1.module.d.ts +2 -0
- package/dist/src/v1/v1.module.js +41 -0
- package/dist/src/v1/v1.module.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/utils/__tests__/activites.util.test.d.ts +1 -0
- package/dist/utils/__tests__/activites.util.test.js +18 -0
- package/dist/utils/__tests__/activites.util.test.js.map +1 -0
- package/dist/utils/__tests__/helpers.util.test.d.ts +1 -0
- package/dist/utils/__tests__/helpers.util.test.js +120 -0
- package/dist/utils/__tests__/helpers.util.test.js.map +1 -0
- package/dist/utils/__tests__/wakatime.util.test.d.ts +1 -0
- package/dist/utils/__tests__/wakatime.util.test.js +210 -0
- package/dist/utils/__tests__/wakatime.util.test.js.map +1 -0
- package/dist/utils/activities.util.d.ts +15 -0
- package/dist/utils/activities.util.js +147 -0
- package/dist/utils/activities.util.js.map +1 -0
- package/dist/utils/allExceptions.filter.d.ts +7 -0
- package/dist/utils/allExceptions.filter.js +39 -0
- package/dist/utils/allExceptions.filter.js.map +1 -0
- package/dist/utils/codeClimberErrors.d.ts +16 -0
- package/dist/utils/codeClimberErrors.js +27 -0
- package/dist/utils/codeClimberErrors.js.map +1 -0
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/constants.js +5 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/environment.util.d.ts +1 -0
- package/dist/utils/environment.util.js +6 -0
- package/dist/utils/environment.util.js.map +1 -0
- package/dist/utils/helpers.util.d.ts +7 -0
- package/dist/utils/helpers.util.js +116 -0
- package/dist/utils/helpers.util.js.map +1 -0
- package/dist/utils/node.util.d.ts +7 -0
- package/dist/utils/node.util.js +26 -0
- package/dist/utils/node.util.js.map +1 -0
- package/dist/utils/sql.util.d.ts +1 -0
- package/dist/utils/sql.util.js +11 -0
- package/dist/utils/sql.util.js.map +1 -0
- package/dist/utils/sqlReader.util.d.ts +5 -0
- package/dist/utils/sqlReader.util.js +34 -0
- package/dist/utils/sqlReader.util.js.map +1 -0
- package/dist/utils/wakatime.util.d.ts +6 -0
- package/dist/utils/wakatime.util.js +63 -0
- package/dist/utils/wakatime.util.js.map +1 -0
- package/index.ts +5 -0
- package/jest.config.js +8 -0
- package/knexfile.js +14 -0
- package/nest-cli.json +15 -0
- package/package.json +77 -0
- package/src/app.module.ts +37 -0
- package/src/assets/startup.plist.ts +36 -0
- package/src/common/infrastructure/http/controllers/health.controller.ts +9 -0
- package/src/common/infrastructure/http/middleware/requestlogger.middleware.ts +22 -0
- package/src/main.ts +51 -0
- package/src/sentry.ts +14 -0
- package/src/types/activities.api.d.ts +18 -0
- package/src/types/time.api.d.ts +23 -0
- package/src/types/utils.d.ts +8 -0
- package/src/types/wakatimeProxy.api.d.ts +55 -0
- package/src/v1/activities/activities.service.ts +213 -0
- package/src/v1/activities/pulse.controller.ts +68 -0
- package/src/v1/activities/wakatimeProxy.controller.ts +33 -0
- package/src/v1/database/__tests__/knex.test.ts +18 -0
- package/src/v1/database/__tests__/pulse.repo.test.ts +209 -0
- package/src/v1/database/knex.ts +107 -0
- package/src/v1/database/migrations.ts +13 -0
- package/src/v1/database/models/pulse.d.ts +24 -0
- package/src/v1/database/pulse.repo.ts +132 -0
- package/src/v1/database/queries/getCategoryTimeOverview.sql +6 -0
- package/src/v1/database/queries/getLongestDayInRangeMinutes.sql +11 -0
- package/src/v1/database/queries/getStatusBarDetails.sql +42 -0
- package/src/v1/dtos/createWakatimePulse.dto.ts +66 -0
- package/src/v1/dtos/getCategoryTimeOverview.dto.ts +9 -0
- package/src/v1/dtos/getWeekOverview.dto.ts +6 -0
- package/src/v1/startup/darwinStartup.service.ts +114 -0
- package/src/v1/startup/linuxStartup.service.ts +101 -0
- package/src/v1/startup/startup.controller.ts +23 -0
- package/src/v1/startup/startup.util.ts +21 -0
- package/src/v1/startup/startupService.factory.ts +28 -0
- package/src/v1/startup/unsupportedStartup.service.ts +21 -0
- package/src/v1/v1.module.ts +28 -0
- package/test/app.e2e-spec.ts +24 -0
- package/test/jest-e2e.json +9 -0
- package/test/jest.globalSetup.js +15 -0
- package/test/jest.globalTeardown.js +8 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +22 -0
- package/utils/__tests__/activites.util.test.ts +18 -0
- package/utils/__tests__/helpers.util.test.ts +155 -0
- package/utils/__tests__/wakatime.util.test.ts +222 -0
- package/utils/activities.util.ts +193 -0
- package/utils/allExceptions.filter.ts +43 -0
- package/utils/codeClimberErrors.ts +32 -0
- package/utils/constants.ts +1 -0
- package/utils/environment.util.ts +1 -0
- package/utils/helpers.util.ts +131 -0
- package/utils/node.util.ts +29 -0
- package/utils/sql.util.ts +13 -0
- package/utils/sqlReader.util.ts +49 -0
- package/utils/wakatime.util.ts +78 -0
@@ -0,0 +1 @@
|
|
1
|
+
export declare const PROCESS_NAME = "codeclimbers-server";
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../utils/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,YAAY,GAAG,qBAAqB,CAAA"}
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const isCli: () => boolean;
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"environment.util.js","sourceRoot":"","sources":["../../utils/environment.util.ts"],"names":[],"mappings":";;;AAAO,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,+BAA+B,KAAK,KAAK,CAAA;AAAnE,QAAA,KAAK,SAA8D"}
|
@@ -0,0 +1,7 @@
|
|
1
|
+
export declare function forOwn<T>(obj: Record<string, T>, iteratee: (value: T, key: string, obj: Record<string, T>) => void): void;
|
2
|
+
export declare function isPlainObject(value: any): boolean;
|
3
|
+
export declare function snakeCase(str: string): string;
|
4
|
+
export declare function camelCase(str: string): string;
|
5
|
+
export declare function maxBy<T>(arr: T[], iteratee: (item: T) => any): T | undefined;
|
6
|
+
export declare function minBy<T>(arr: T[], iteratee: (item: T) => any): T | undefined;
|
7
|
+
export declare function groupBy<T>(arr: T[], key: string): Record<string, T[]>;
|
@@ -0,0 +1,116 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.forOwn = forOwn;
|
4
|
+
exports.isPlainObject = isPlainObject;
|
5
|
+
exports.snakeCase = snakeCase;
|
6
|
+
exports.camelCase = camelCase;
|
7
|
+
exports.maxBy = maxBy;
|
8
|
+
exports.minBy = minBy;
|
9
|
+
exports.groupBy = groupBy;
|
10
|
+
function forOwn(obj, iteratee) {
|
11
|
+
if (obj === null || obj === undefined) {
|
12
|
+
return;
|
13
|
+
}
|
14
|
+
const keys = Object.keys(obj);
|
15
|
+
for (let i = 0; i < keys.length; i++) {
|
16
|
+
const key = keys[i];
|
17
|
+
iteratee(obj[key], key, obj);
|
18
|
+
}
|
19
|
+
}
|
20
|
+
function isPlainObject(value) {
|
21
|
+
if (typeof value !== 'object' || value === null) {
|
22
|
+
return false;
|
23
|
+
}
|
24
|
+
const prototype = Object.getPrototypeOf(value);
|
25
|
+
if (prototype === null) {
|
26
|
+
return true;
|
27
|
+
}
|
28
|
+
const constructor = prototype.constructor;
|
29
|
+
if (typeof constructor !== 'function') {
|
30
|
+
return false;
|
31
|
+
}
|
32
|
+
const constructorString = Function.prototype.toString.call(constructor);
|
33
|
+
return (constructorString.indexOf('[native code]') !== -1 && constructor === Object);
|
34
|
+
}
|
35
|
+
function snakeCase(str) {
|
36
|
+
if (typeof str !== 'string') {
|
37
|
+
return '';
|
38
|
+
}
|
39
|
+
const result = [];
|
40
|
+
let currentWord = '';
|
41
|
+
for (let i = 0; i < str.length; i++) {
|
42
|
+
const char = str[i];
|
43
|
+
const nextChar = str[i + 1];
|
44
|
+
if (char === ' ' || char === '-') {
|
45
|
+
if (currentWord) {
|
46
|
+
result.push(currentWord.toLowerCase());
|
47
|
+
currentWord = '';
|
48
|
+
}
|
49
|
+
}
|
50
|
+
else if (char >= 'A' && char <= 'Z') {
|
51
|
+
if (currentWord && nextChar && !(nextChar >= 'A' && nextChar <= 'Z')) {
|
52
|
+
result.push(currentWord.toLowerCase());
|
53
|
+
currentWord = '';
|
54
|
+
}
|
55
|
+
currentWord += char.toLowerCase();
|
56
|
+
}
|
57
|
+
else {
|
58
|
+
currentWord += char;
|
59
|
+
}
|
60
|
+
}
|
61
|
+
if (currentWord) {
|
62
|
+
result.push(currentWord.toLowerCase());
|
63
|
+
}
|
64
|
+
return result.join('_');
|
65
|
+
}
|
66
|
+
function camelCase(str) {
|
67
|
+
if (typeof str !== 'string') {
|
68
|
+
return '';
|
69
|
+
}
|
70
|
+
const words = str.split(/[\s-_]+/);
|
71
|
+
const result = [];
|
72
|
+
for (let i = 0; i < words.length; i++) {
|
73
|
+
const word = words[i];
|
74
|
+
if (word.length === 0) {
|
75
|
+
continue;
|
76
|
+
}
|
77
|
+
if (i === 0) {
|
78
|
+
result.push(word.toLowerCase());
|
79
|
+
}
|
80
|
+
else {
|
81
|
+
result.push(word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
|
82
|
+
}
|
83
|
+
}
|
84
|
+
return result.join('');
|
85
|
+
}
|
86
|
+
function maxBy(arr, iteratee) {
|
87
|
+
if (!arr || arr.length === 0)
|
88
|
+
return undefined;
|
89
|
+
return arr.reduce((acc, item) => {
|
90
|
+
const value = iteratee(item);
|
91
|
+
if (value > iteratee(acc))
|
92
|
+
return item;
|
93
|
+
return acc;
|
94
|
+
}, arr[0]);
|
95
|
+
}
|
96
|
+
function minBy(arr, iteratee) {
|
97
|
+
if (!arr || arr.length === 0)
|
98
|
+
return undefined;
|
99
|
+
return arr.reduce((acc, item) => {
|
100
|
+
const value = iteratee(item);
|
101
|
+
if (value < iteratee(acc))
|
102
|
+
return item;
|
103
|
+
return acc;
|
104
|
+
}, arr[0]);
|
105
|
+
}
|
106
|
+
function groupBy(arr, key) {
|
107
|
+
return arr.reduce((acc, item) => {
|
108
|
+
const keyValue = item[key];
|
109
|
+
if (!acc[keyValue]) {
|
110
|
+
acc[keyValue] = [];
|
111
|
+
}
|
112
|
+
acc[keyValue].push(item);
|
113
|
+
return acc;
|
114
|
+
}, {});
|
115
|
+
}
|
116
|
+
//# sourceMappingURL=helpers.util.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"helpers.util.js","sourceRoot":"","sources":["../../utils/helpers.util.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,7 @@
|
|
1
|
+
export declare const BIN_PATH: string;
|
2
|
+
export declare const HOME_DIR: string;
|
3
|
+
export declare const CODE_CLIMBER_META_DIR: string;
|
4
|
+
export declare const DB_PATH: string;
|
5
|
+
export declare const APP_DIST_PATH: string;
|
6
|
+
export declare const NODE_PATH: () => string;
|
7
|
+
export declare const initDBDir: () => void;
|
@@ -0,0 +1,26 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.initDBDir = exports.NODE_PATH = exports.APP_DIST_PATH = exports.DB_PATH = exports.CODE_CLIMBER_META_DIR = exports.HOME_DIR = exports.BIN_PATH = void 0;
|
4
|
+
const path = require("node:path");
|
5
|
+
const os = require("node:os");
|
6
|
+
const fs = require("node:fs");
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
8
|
+
exports.BIN_PATH = path.join(__dirname, '..', '..', '..', '..', 'bin');
|
9
|
+
exports.HOME_DIR = os.homedir();
|
10
|
+
exports.CODE_CLIMBER_META_DIR = `${exports.HOME_DIR}/.codeclimbers`;
|
11
|
+
exports.DB_PATH = path.join(exports.CODE_CLIMBER_META_DIR, 'codeclimber.sqlite');
|
12
|
+
exports.APP_DIST_PATH = path.join(__dirname, '..', '..', '..', 'app', 'dist');
|
13
|
+
const NODE_PATH = function () {
|
14
|
+
const result = (0, node_child_process_1.execSync)('which node').toString().trim();
|
15
|
+
const dir = result.slice(0, -5);
|
16
|
+
return dir;
|
17
|
+
};
|
18
|
+
exports.NODE_PATH = NODE_PATH;
|
19
|
+
const initDBDir = () => {
|
20
|
+
if (!fs.existsSync(exports.CODE_CLIMBER_META_DIR)) {
|
21
|
+
fs.mkdirSync(exports.CODE_CLIMBER_META_DIR, { recursive: true });
|
22
|
+
}
|
23
|
+
fs.chmodSync(exports.CODE_CLIMBER_META_DIR, '755');
|
24
|
+
};
|
25
|
+
exports.initDBDir = initDBDir;
|
26
|
+
//# sourceMappingURL=node.util.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"node.util.js","sourceRoot":"","sources":["../../utils/node.util.ts"],"names":[],"mappings":";;;AAAA,kCAAiC;AACjC,8BAA6B;AAC7B,8BAA6B;AAC7B,2DAA6C;AAEhC,QAAA,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;AAC9D,QAAA,QAAQ,GAAG,EAAE,CAAC,OAAO,EAAE,CAAA;AACvB,QAAA,qBAAqB,GAAG,GAAG,gBAAQ,gBAAgB,CAAA;AACnD,QAAA,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,6BAAqB,EAAE,oBAAoB,CAAC,CAAA;AAChE,QAAA,aAAa,GAAG,IAAI,CAAC,IAAI,CACpC,SAAS,EACT,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,MAAM,CACP,CAAA;AACM,MAAM,SAAS,GAAG;IACvB,MAAM,MAAM,GAAG,IAAA,6BAAQ,EAAC,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAA;IACvD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC/B,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAJY,QAAA,SAAS,aAIrB;AAEM,MAAM,SAAS,GAAG,GAAG,EAAE;IAC5B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,6BAAqB,CAAC,EAAE,CAAC;QAC1C,EAAE,CAAC,SAAS,CAAC,6BAAqB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC1D,CAAC;IACD,EAAE,CAAC,SAAS,CAAC,6BAAqB,EAAE,KAAK,CAAC,CAAA;AAC5C,CAAC,CAAA;AALY,QAAA,SAAS,aAKrB"}
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const toSQL: (query: any) => any;
|
@@ -0,0 +1,11 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.toSQL = void 0;
|
4
|
+
const toSQL = (query) => {
|
5
|
+
const { sql, bindings } = query.toSQL();
|
6
|
+
const fullQuery = bindings.reduce((acc, binding) => acc.replace('?', binding instanceof Date ? `'${binding.toISOString()}'` : `'${binding}'`), sql);
|
7
|
+
console.log(fullQuery);
|
8
|
+
return fullQuery;
|
9
|
+
};
|
10
|
+
exports.toSQL = toSQL;
|
11
|
+
//# sourceMappingURL=sql.util.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"sql.util.js","sourceRoot":"","sources":["../../utils/sql.util.ts"],"names":[],"mappings":";;;AAAO,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,EAAE;IAC7B,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAA;IACvC,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAC/B,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CACf,GAAG,CAAC,OAAO,CACT,GAAG,EACH,OAAO,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,OAAO,GAAG,CACxE,EACH,GAAG,CACJ,CAAA;IACD,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACtB,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA;AAZY,QAAA,KAAK,SAYjB"}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
const promises_1 = require("fs/promises");
|
4
|
+
const path_1 = require("path");
|
5
|
+
const cache = {};
|
6
|
+
async function getFileContentAsString(fileName, additionalPath = 'queries') {
|
7
|
+
try {
|
8
|
+
const err = new Error();
|
9
|
+
const stack = err.stack || '';
|
10
|
+
const caller = stack.split('\n')[2] || '';
|
11
|
+
const match = caller.match(/\((?:file:\/\/)?(.*?):\d+:\d+\)$/);
|
12
|
+
if (!match) {
|
13
|
+
throw new Error('Could not determine caller file path');
|
14
|
+
}
|
15
|
+
const callerPath = match[1];
|
16
|
+
const callerDir = (0, path_1.dirname)(callerPath);
|
17
|
+
const cacheKey = `${callerDir}:${additionalPath}:${fileName}`;
|
18
|
+
if (cache[cacheKey]) {
|
19
|
+
return cache[cacheKey];
|
20
|
+
}
|
21
|
+
const resolvedPath = (0, path_1.join)(callerDir, additionalPath, fileName);
|
22
|
+
const content = await (0, promises_1.readFile)(resolvedPath, 'utf8');
|
23
|
+
cache[cacheKey] = content;
|
24
|
+
return content;
|
25
|
+
}
|
26
|
+
catch (error) {
|
27
|
+
console.error('Error reading file:', error);
|
28
|
+
throw error;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
exports.default = {
|
32
|
+
getFileContentAsString,
|
33
|
+
};
|
34
|
+
//# sourceMappingURL=sqlReader.util.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"sqlReader.util.js","sourceRoot":"","sources":["../../utils/sqlReader.util.ts"],"names":[],"mappings":";;AAAA,0CAAsC;AACtC,+BAAoC;AAGpC,MAAM,KAAK,GAA2B,EAAE,CAAA;AAGxC,KAAK,UAAU,sBAAsB,CACnC,QAAgB,EAChB,cAAc,GAAG,SAAS;IAE1B,IAAI,CAAC;QAGH,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE,CAAA;QACvB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAAA;QAE7B,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QAEzC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAA;QAC9D,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;QACzD,CAAC;QACD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QAC3B,MAAM,SAAS,GAAG,IAAA,cAAO,EAAC,UAAU,CAAC,CAAA;QAGrC,MAAM,QAAQ,GAAG,GAAG,SAAS,IAAI,cAAc,IAAI,QAAQ,EAAE,CAAA;QAG7D,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAA;QACxB,CAAC;QAGD,MAAM,YAAY,GAAG,IAAA,WAAI,EAAC,SAAS,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAA;QAE9D,MAAM,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,YAAY,EAAE,MAAM,CAAC,CAAA;QACpD,KAAK,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAA;QACzB,OAAO,OAAO,CAAA;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAA;QAC3C,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED,kBAAe;IACb,sBAAsB;CACvB,CAAA"}
|
@@ -0,0 +1,6 @@
|
|
1
|
+
type IniSection = Record<string, string>;
|
2
|
+
export type IniConfig = Record<string, IniSection>;
|
3
|
+
export declare function parseIni(content: string): IniConfig;
|
4
|
+
export declare function stringifyIni(data: IniConfig): string;
|
5
|
+
export declare function updateSettings(newSettings: Record<string, string>): Promise<void>;
|
6
|
+
export {};
|
@@ -0,0 +1,63 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.parseIni = parseIni;
|
4
|
+
exports.stringifyIni = stringifyIni;
|
5
|
+
exports.updateSettings = updateSettings;
|
6
|
+
const fs = require("fs/promises");
|
7
|
+
const path = require("path");
|
8
|
+
const node_util_1 = require("./node.util");
|
9
|
+
const common_1 = require("@nestjs/common");
|
10
|
+
const filePath = path.join(node_util_1.HOME_DIR, '.wakatime.cfg');
|
11
|
+
function parseIni(content) {
|
12
|
+
const result = {};
|
13
|
+
const lines = content.split('\n');
|
14
|
+
let currentSection = '';
|
15
|
+
for (const line of lines) {
|
16
|
+
const trimmedLine = line.trim();
|
17
|
+
if (trimmedLine.startsWith('[') && trimmedLine.endsWith(']')) {
|
18
|
+
currentSection = trimmedLine.slice(1, -1);
|
19
|
+
result[currentSection] = {};
|
20
|
+
}
|
21
|
+
else if (trimmedLine && currentSection) {
|
22
|
+
const [key, value] = trimmedLine.split('=').map((part) => part.trim());
|
23
|
+
if (key && value) {
|
24
|
+
result[currentSection][key] = value;
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
return result;
|
29
|
+
}
|
30
|
+
function stringifyIni(data) {
|
31
|
+
const entries = Object.entries(data)
|
32
|
+
.map(([section, entries]) => {
|
33
|
+
const sectionContent = Object.entries(entries)
|
34
|
+
.map(([key, value]) => `${key} = ${value}`)
|
35
|
+
.join('\n');
|
36
|
+
return `[${section}]\n${sectionContent}`;
|
37
|
+
})
|
38
|
+
.join('\n\n');
|
39
|
+
return `${entries}\n`;
|
40
|
+
}
|
41
|
+
async function updateSettings(newSettings) {
|
42
|
+
try {
|
43
|
+
let config;
|
44
|
+
try {
|
45
|
+
const data = await fs.readFile(filePath, 'utf8');
|
46
|
+
config = parseIni(data);
|
47
|
+
}
|
48
|
+
catch (error) {
|
49
|
+
config = { settings: {} };
|
50
|
+
}
|
51
|
+
if (!config.settings) {
|
52
|
+
config.settings = {};
|
53
|
+
}
|
54
|
+
Object.assign(config.settings, newSettings);
|
55
|
+
const updatedContent = stringifyIni(config);
|
56
|
+
await fs.writeFile(filePath, updatedContent, 'utf8');
|
57
|
+
common_1.Logger.log('File updated successfully', 'WakatimeUtil');
|
58
|
+
}
|
59
|
+
catch (error) {
|
60
|
+
common_1.Logger.error('Error updating file:', error);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
//# sourceMappingURL=wakatime.util.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"wakatime.util.js","sourceRoot":"","sources":["../../utils/wakatime.util.ts"],"names":[],"mappings":"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"}
|
package/index.ts
ADDED
package/jest.config.js
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
2
|
+
module.exports = {
|
3
|
+
preset: 'ts-jest',
|
4
|
+
testEnvironment: 'node',
|
5
|
+
testMatch: ['**/__tests__/**/*.test.ts'],
|
6
|
+
globalSetup: '<rootDir>/test/jest.globalSetup.js',
|
7
|
+
globalTeardown: '<rootDir>/test/jest.globalTeardown.js',
|
8
|
+
}
|
package/knexfile.js
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module.exports = {
|
2
|
+
client: 'sqlite3',
|
3
|
+
useNullAsDefault: true,
|
4
|
+
connection: {
|
5
|
+
filename: './codeclimber.sqlite',
|
6
|
+
},
|
7
|
+
migrations: {
|
8
|
+
directory: '../../bin/migrations',
|
9
|
+
stub: 'migrations/example/stub.js',
|
10
|
+
},
|
11
|
+
seeds: {
|
12
|
+
directory: '../../bin/seeds',
|
13
|
+
},
|
14
|
+
}
|
package/nest-cli.json
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "https://json.schemastore.org/nest-cli",
|
3
|
+
"collection": "@nestjs/schematics",
|
4
|
+
"sourceRoot": "src",
|
5
|
+
"compilerOptions": {
|
6
|
+
"deleteOutDir": true,
|
7
|
+
"assets": [
|
8
|
+
{
|
9
|
+
"include": "**/*.sql",
|
10
|
+
"watchAssets": true,
|
11
|
+
"outDir": "./dist/src"
|
12
|
+
}
|
13
|
+
]
|
14
|
+
}
|
15
|
+
}
|
package/package.json
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
{
|
2
|
+
"name": "@codeclimbers/server",
|
3
|
+
"version": "0.0.1",
|
4
|
+
"description": "CLI Server",
|
5
|
+
"main": "dist/index.js",
|
6
|
+
"author": {
|
7
|
+
"name": "Paul Hovley",
|
8
|
+
"email": "rphovley@gmail.com"
|
9
|
+
},
|
10
|
+
"licenses": [
|
11
|
+
{
|
12
|
+
"type": "MIT",
|
13
|
+
"url": "https://opensource.org/licenses/MIT"
|
14
|
+
}
|
15
|
+
],
|
16
|
+
"scripts": {
|
17
|
+
"prepublishOnly": "npm run build",
|
18
|
+
"build": "nest build",
|
19
|
+
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
20
|
+
"start": "nest start --watch",
|
21
|
+
"start:noWatch": "nest start",
|
22
|
+
"start:debug": "nest start --debug --watch",
|
23
|
+
"start:prod": "node dist/main",
|
24
|
+
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
25
|
+
"test": "jest --config jest.config.js",
|
26
|
+
"test:watch": "jest --watch",
|
27
|
+
"test:cov": "jest --coverage",
|
28
|
+
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
29
|
+
"test:e2e": "jest --config ./test/jest-e2e.json",
|
30
|
+
"db:migrate": "knex migrate:latest",
|
31
|
+
"db:migrate:make": "knex migrate:make",
|
32
|
+
"db:seed": "knex seed:run",
|
33
|
+
"db:seed:make": "knex seed:make $(date +%s)_${npm_config_name}"
|
34
|
+
},
|
35
|
+
"optionalDependencies": {
|
36
|
+
"node-linux": "^0.1.7",
|
37
|
+
"node-mac": "^1.0.1",
|
38
|
+
"node-windows": "^1.0.0-beta.8"
|
39
|
+
},
|
40
|
+
"dependencies": {
|
41
|
+
"@nestjs/common": "^10.0.0",
|
42
|
+
"@nestjs/core": "^10.0.0",
|
43
|
+
"@nestjs/platform-express": "^10.0.0",
|
44
|
+
"@nestjs/serve-static": "^4.0.2",
|
45
|
+
"@sentry/nestjs": "^8.25.0",
|
46
|
+
"@sentry/profiling-node": "^8.25.0",
|
47
|
+
"class-transformer": "^0.5.1",
|
48
|
+
"class-validator": "^0.14.1",
|
49
|
+
"dayjs": "^1.11.12",
|
50
|
+
"nestjs-knex": "^2.0.0",
|
51
|
+
"reflect-metadata": "^0.2.0",
|
52
|
+
"rxjs": "^7.8.1",
|
53
|
+
"sqlite3": "^5.1.7"
|
54
|
+
},
|
55
|
+
"devDependencies": {
|
56
|
+
"@nestjs/cli": "^10.0.0",
|
57
|
+
"@nestjs/schematics": "^10.0.0",
|
58
|
+
"@nestjs/testing": "^10.0.0",
|
59
|
+
"@types/express": "^4.17.17",
|
60
|
+
"@types/jest": "^29.5.2",
|
61
|
+
"@types/node": "^20.3.1",
|
62
|
+
"@types/supertest": "^6.0.0",
|
63
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
64
|
+
"@typescript-eslint/parser": "^6.0.0",
|
65
|
+
"eslint-config-prettier": "^9.0.0",
|
66
|
+
"eslint-plugin-prettier": "^5.0.0",
|
67
|
+
"jest": "^29.5.0",
|
68
|
+
"prettier": "^3.0.0",
|
69
|
+
"source-map-support": "^0.5.21",
|
70
|
+
"supertest": "^6.3.3",
|
71
|
+
"ts-jest": "^29.1.0",
|
72
|
+
"ts-loader": "^9.4.3",
|
73
|
+
"ts-node": "^10.9.1",
|
74
|
+
"tsconfig-paths": "^4.2.0",
|
75
|
+
"typescript": "^5.1.3"
|
76
|
+
}
|
77
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import { MiddlewareConsumer, Module } from '@nestjs/common'
|
2
|
+
import { V1Module } from './v1/v1.module'
|
3
|
+
import { APP_FILTER, RouterModule } from '@nestjs/core'
|
4
|
+
import { AllExceptionsFilter } from '../utils/allExceptions.filter'
|
5
|
+
import { RequestLoggerMiddleware } from './common/infrastructure/http/middleware/requestlogger.middleware'
|
6
|
+
import { ServeStaticModule } from '@nestjs/serve-static'
|
7
|
+
import { DbModule } from './v1/database/knex'
|
8
|
+
import { SentryModule } from '@sentry/nestjs/setup'
|
9
|
+
import { APP_DIST_PATH } from '../utils/node.util'
|
10
|
+
|
11
|
+
@Module({
|
12
|
+
imports: [
|
13
|
+
SentryModule.forRoot(),
|
14
|
+
DbModule,
|
15
|
+
V1Module,
|
16
|
+
RouterModule.register([
|
17
|
+
{
|
18
|
+
path: '/api/v1',
|
19
|
+
module: V1Module,
|
20
|
+
},
|
21
|
+
]),
|
22
|
+
ServeStaticModule.forRoot({
|
23
|
+
rootPath: APP_DIST_PATH,
|
24
|
+
}),
|
25
|
+
],
|
26
|
+
providers: [
|
27
|
+
{
|
28
|
+
provide: APP_FILTER,
|
29
|
+
useClass: AllExceptionsFilter,
|
30
|
+
},
|
31
|
+
],
|
32
|
+
})
|
33
|
+
export class AppModule {
|
34
|
+
configure(consumer: MiddlewareConsumer): void {
|
35
|
+
consumer.apply(RequestLoggerMiddleware).forRoutes('*')
|
36
|
+
}
|
37
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import { BIN_PATH, HOME_DIR } from '../../utils/node.util'
|
2
|
+
import * as path from 'node:path'
|
3
|
+
|
4
|
+
export const plist = () => {
|
5
|
+
try {
|
6
|
+
const bashScriptPath = path.join(BIN_PATH, 'run.sh')
|
7
|
+
return `
|
8
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
9
|
+
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
10
|
+
<plist version="1.0">
|
11
|
+
<dict>
|
12
|
+
|
13
|
+
<key>Label</key>
|
14
|
+
<string>io.codeclimbers.plist</string>
|
15
|
+
|
16
|
+
<key>ProgramArguments</key>
|
17
|
+
<array>
|
18
|
+
<string>/bin/bash</string>
|
19
|
+
<string>${bashScriptPath}</string>
|
20
|
+
</array>
|
21
|
+
|
22
|
+
<key>KeepAlive</key>
|
23
|
+
<true/>
|
24
|
+
|
25
|
+
<key>StandardOutPath</key>
|
26
|
+
<string>${HOME_DIR}/.codeclimbers/log.out</string>
|
27
|
+
<key>StandardErrorPath</key>
|
28
|
+
<string>${HOME_DIR}/.codeclimbers/log.err</string>
|
29
|
+
|
30
|
+
</dict>
|
31
|
+
</plist>
|
32
|
+
`
|
33
|
+
} catch (error) {
|
34
|
+
console.error(`Error creating plist declaration: ${error.message}`)
|
35
|
+
}
|
36
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { Injectable, Logger, NestMiddleware } from '@nestjs/common'
|
2
|
+
|
3
|
+
import { NextFunction, Request, Response } from 'express'
|
4
|
+
|
5
|
+
@Injectable()
|
6
|
+
export class RequestLoggerMiddleware implements NestMiddleware {
|
7
|
+
use(request: Request, response: Response, next: NextFunction): void {
|
8
|
+
const { ip, method, originalUrl: url } = request
|
9
|
+
const userAgent = request.get('user-agent') || ''
|
10
|
+
|
11
|
+
response.on('close', () => {
|
12
|
+
const { statusCode } = response
|
13
|
+
const contentLength = response.get('content-length')
|
14
|
+
Logger.log(
|
15
|
+
`${method} ${url} ${statusCode} ${contentLength} - ${userAgent} ${ip}`,
|
16
|
+
'requestlogger.middleware',
|
17
|
+
)
|
18
|
+
})
|
19
|
+
|
20
|
+
next()
|
21
|
+
}
|
22
|
+
}
|
package/src/main.ts
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
// Import this first!
|
2
|
+
import './sentry'
|
3
|
+
|
4
|
+
import { NestFactory } from '@nestjs/core'
|
5
|
+
import { AppModule } from './app.module'
|
6
|
+
import { Logger, ValidationPipe } from '@nestjs/common'
|
7
|
+
import { isCli } from '../utils/environment.util'
|
8
|
+
import { PROCESS_NAME } from '../utils/constants'
|
9
|
+
import { updateSettings } from '../utils/wakatime.util'
|
10
|
+
import { startMigrations } from './v1/database/migrations'
|
11
|
+
|
12
|
+
const updatedIniValues: Record<string, string> = {
|
13
|
+
api_key: 'eacb3beb-dad8-4fa1-b6ba-f89de8bf8f4a', // placeholder value
|
14
|
+
api_url: 'http://localhost:14400/api/v1/wakatime',
|
15
|
+
}
|
16
|
+
const shouldShowDebugLogs =
|
17
|
+
process.env.DEBUG === '*' || process.env.NODE_ENV === 'development'
|
18
|
+
|
19
|
+
const traceEnvironment = () => {
|
20
|
+
Logger.log(`Running as: ${process.env.NODE_ENV}`, 'main.ts')
|
21
|
+
Logger.log(`process.env: ${JSON.stringify(process.env)}`, 'main.ts')
|
22
|
+
}
|
23
|
+
|
24
|
+
export async function bootstrap() {
|
25
|
+
const port = process.env.CODECLIMBERS_SERVER_PORT || 14_400
|
26
|
+
const app = await NestFactory.create(AppModule, {
|
27
|
+
logger: shouldShowDebugLogs
|
28
|
+
? ['log', 'debug', 'error', 'verbose', 'warn']
|
29
|
+
: ['error', 'warn'],
|
30
|
+
})
|
31
|
+
traceEnvironment()
|
32
|
+
|
33
|
+
app.enableCors()
|
34
|
+
app.useGlobalPipes(
|
35
|
+
new ValidationPipe({
|
36
|
+
transform: true,
|
37
|
+
transformOptions: {
|
38
|
+
enableImplicitConversion: true,
|
39
|
+
},
|
40
|
+
}),
|
41
|
+
)
|
42
|
+
|
43
|
+
await updateSettings(updatedIniValues)
|
44
|
+
await startMigrations()
|
45
|
+
await app.listen(port)
|
46
|
+
process.title = PROCESS_NAME
|
47
|
+
}
|
48
|
+
|
49
|
+
if (!isCli()) {
|
50
|
+
bootstrap()
|
51
|
+
}
|
package/src/sentry.ts
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
import * as Sentry from '@sentry/nestjs'
|
2
|
+
import { nodeProfilingIntegration } from '@sentry/profiling-node'
|
3
|
+
|
4
|
+
if (process.env.NODE_ENV === 'production') {
|
5
|
+
Sentry.init({
|
6
|
+
dsn: 'https://e885e4c5eeed09d6229c7d7bfdc8d762@o4507772937043968.ingest.us.sentry.io/4507772946022400',
|
7
|
+
integrations: [nodeProfilingIntegration()],
|
8
|
+
// Performance Monitoring
|
9
|
+
tracesSampleRate: 0.1, // Capture 100% of the transactions
|
10
|
+
|
11
|
+
// Set sampling rate for profiling - this is relative to tracesSampleRate
|
12
|
+
profilesSampleRate: 0.1,
|
13
|
+
})
|
14
|
+
}
|