@codeclimbers/server 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. package/README.md +73 -0
  2. package/dist/index.d.ts +4 -0
  3. package/dist/index.js +22 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/src/app.module.d.ts +4 -0
  6. package/dist/src/app.module.js +49 -0
  7. package/dist/src/app.module.js.map +1 -0
  8. package/dist/src/assets/startup.plist.d.ts +1 -0
  9. package/dist/src/assets/startup.plist.js +41 -0
  10. package/dist/src/assets/startup.plist.js.map +1 -0
  11. package/dist/src/common/infrastructure/http/controllers/health.controller.d.ts +5 -0
  12. package/dist/src/common/infrastructure/http/controllers/health.controller.js +29 -0
  13. package/dist/src/common/infrastructure/http/controllers/health.controller.js.map +1 -0
  14. package/dist/src/common/infrastructure/http/middleware/requestlogger.middleware.d.ts +5 -0
  15. package/dist/src/common/infrastructure/http/middleware/requestlogger.middleware.js +27 -0
  16. package/dist/src/common/infrastructure/http/middleware/requestlogger.middleware.js.map +1 -0
  17. package/dist/src/main.d.ts +2 -0
  18. package/dist/src/main.js +44 -0
  19. package/dist/src/main.js.map +1 -0
  20. package/dist/src/sentry.d.ts +1 -0
  21. package/dist/src/sentry.js +13 -0
  22. package/dist/src/sentry.js.map +1 -0
  23. package/dist/src/v1/activities/activities.service.d.ts +21 -0
  24. package/dist/src/v1/activities/activities.service.js +174 -0
  25. package/dist/src/v1/activities/activities.service.js.map +1 -0
  26. package/dist/src/v1/activities/pulse.controller.d.ts +19 -0
  27. package/dist/src/v1/activities/pulse.controller.js +92 -0
  28. package/dist/src/v1/activities/pulse.controller.js.map +1 -0
  29. package/dist/src/v1/activities/wakatimeProxy.controller.d.ts +13 -0
  30. package/dist/src/v1/activities/wakatimeProxy.controller.js +64 -0
  31. package/dist/src/v1/activities/wakatimeProxy.controller.js.map +1 -0
  32. package/dist/src/v1/database/__tests__/knex.test.d.ts +1 -0
  33. package/dist/src/v1/database/__tests__/knex.test.js +18 -0
  34. package/dist/src/v1/database/__tests__/knex.test.js.map +1 -0
  35. package/dist/src/v1/database/__tests__/pulse.repo.test.d.ts +1 -0
  36. package/dist/src/v1/database/__tests__/pulse.repo.test.js +141 -0
  37. package/dist/src/v1/database/__tests__/pulse.repo.test.js.map +1 -0
  38. package/dist/src/v1/database/knex.d.ts +5 -0
  39. package/dist/src/v1/database/knex.js +87 -0
  40. package/dist/src/v1/database/knex.js.map +1 -0
  41. package/dist/src/v1/database/migrations.d.ts +1 -0
  42. package/dist/src/v1/database/migrations.js +16 -0
  43. package/dist/src/v1/database/migrations.js.map +1 -0
  44. package/dist/src/v1/database/pulse.repo.d.ts +17 -0
  45. package/dist/src/v1/database/pulse.repo.js +115 -0
  46. package/dist/src/v1/database/pulse.repo.js.map +1 -0
  47. package/dist/src/v1/database/queries/getCategoryTimeOverview.sql +6 -0
  48. package/dist/src/v1/database/queries/getLongestDayInRangeMinutes.sql +11 -0
  49. package/dist/src/v1/database/queries/getStatusBarDetails.sql +42 -0
  50. package/dist/src/v1/dtos/createWakatimePulse.dto.d.ts +19 -0
  51. package/dist/src/v1/dtos/createWakatimePulse.dto.js +97 -0
  52. package/dist/src/v1/dtos/createWakatimePulse.dto.js.map +1 -0
  53. package/dist/src/v1/dtos/getCategoryTimeOverview.dto.d.ts +4 -0
  54. package/dist/src/v1/dtos/getCategoryTimeOverview.dto.js +25 -0
  55. package/dist/src/v1/dtos/getCategoryTimeOverview.dto.js.map +1 -0
  56. package/dist/src/v1/dtos/getWeekOverview.dto.d.ts +3 -0
  57. package/dist/src/v1/dtos/getWeekOverview.dto.js +21 -0
  58. package/dist/src/v1/dtos/getWeekOverview.dto.js.map +1 -0
  59. package/dist/src/v1/startup/darwinStartup.service.d.ts +8 -0
  60. package/dist/src/v1/startup/darwinStartup.service.js +114 -0
  61. package/dist/src/v1/startup/darwinStartup.service.js.map +1 -0
  62. package/dist/src/v1/startup/linuxStartup.service.d.ts +8 -0
  63. package/dist/src/v1/startup/linuxStartup.service.js +104 -0
  64. package/dist/src/v1/startup/linuxStartup.service.js.map +1 -0
  65. package/dist/src/v1/startup/startup.controller.d.ts +8 -0
  66. package/dist/src/v1/startup/startup.controller.js +46 -0
  67. package/dist/src/v1/startup/startup.controller.js.map +1 -0
  68. package/dist/src/v1/startup/startup.util.d.ts +5 -0
  69. package/dist/src/v1/startup/startup.util.js +19 -0
  70. package/dist/src/v1/startup/startup.util.js.map +1 -0
  71. package/dist/src/v1/startup/startupService.factory.d.ts +9 -0
  72. package/dist/src/v1/startup/startupService.factory.js +41 -0
  73. package/dist/src/v1/startup/startupService.factory.js.map +1 -0
  74. package/dist/src/v1/startup/unsupportedStartup.service.d.ts +6 -0
  75. package/dist/src/v1/startup/unsupportedStartup.service.js +29 -0
  76. package/dist/src/v1/startup/unsupportedStartup.service.js.map +1 -0
  77. package/dist/src/v1/v1.module.d.ts +2 -0
  78. package/dist/src/v1/v1.module.js +41 -0
  79. package/dist/src/v1/v1.module.js.map +1 -0
  80. package/dist/tsconfig.build.tsbuildinfo +1 -0
  81. package/dist/utils/__tests__/activites.util.test.d.ts +1 -0
  82. package/dist/utils/__tests__/activites.util.test.js +18 -0
  83. package/dist/utils/__tests__/activites.util.test.js.map +1 -0
  84. package/dist/utils/__tests__/helpers.util.test.d.ts +1 -0
  85. package/dist/utils/__tests__/helpers.util.test.js +120 -0
  86. package/dist/utils/__tests__/helpers.util.test.js.map +1 -0
  87. package/dist/utils/__tests__/wakatime.util.test.d.ts +1 -0
  88. package/dist/utils/__tests__/wakatime.util.test.js +210 -0
  89. package/dist/utils/__tests__/wakatime.util.test.js.map +1 -0
  90. package/dist/utils/activities.util.d.ts +15 -0
  91. package/dist/utils/activities.util.js +147 -0
  92. package/dist/utils/activities.util.js.map +1 -0
  93. package/dist/utils/allExceptions.filter.d.ts +7 -0
  94. package/dist/utils/allExceptions.filter.js +39 -0
  95. package/dist/utils/allExceptions.filter.js.map +1 -0
  96. package/dist/utils/codeClimberErrors.d.ts +16 -0
  97. package/dist/utils/codeClimberErrors.js +27 -0
  98. package/dist/utils/codeClimberErrors.js.map +1 -0
  99. package/dist/utils/constants.d.ts +1 -0
  100. package/dist/utils/constants.js +5 -0
  101. package/dist/utils/constants.js.map +1 -0
  102. package/dist/utils/environment.util.d.ts +1 -0
  103. package/dist/utils/environment.util.js +6 -0
  104. package/dist/utils/environment.util.js.map +1 -0
  105. package/dist/utils/helpers.util.d.ts +7 -0
  106. package/dist/utils/helpers.util.js +116 -0
  107. package/dist/utils/helpers.util.js.map +1 -0
  108. package/dist/utils/node.util.d.ts +7 -0
  109. package/dist/utils/node.util.js +26 -0
  110. package/dist/utils/node.util.js.map +1 -0
  111. package/dist/utils/sql.util.d.ts +1 -0
  112. package/dist/utils/sql.util.js +11 -0
  113. package/dist/utils/sql.util.js.map +1 -0
  114. package/dist/utils/sqlReader.util.d.ts +5 -0
  115. package/dist/utils/sqlReader.util.js +34 -0
  116. package/dist/utils/sqlReader.util.js.map +1 -0
  117. package/dist/utils/wakatime.util.d.ts +6 -0
  118. package/dist/utils/wakatime.util.js +63 -0
  119. package/dist/utils/wakatime.util.js.map +1 -0
  120. package/index.ts +5 -0
  121. package/jest.config.js +8 -0
  122. package/knexfile.js +14 -0
  123. package/nest-cli.json +15 -0
  124. package/package.json +77 -0
  125. package/src/app.module.ts +37 -0
  126. package/src/assets/startup.plist.ts +36 -0
  127. package/src/common/infrastructure/http/controllers/health.controller.ts +9 -0
  128. package/src/common/infrastructure/http/middleware/requestlogger.middleware.ts +22 -0
  129. package/src/main.ts +51 -0
  130. package/src/sentry.ts +14 -0
  131. package/src/types/activities.api.d.ts +18 -0
  132. package/src/types/time.api.d.ts +23 -0
  133. package/src/types/utils.d.ts +8 -0
  134. package/src/types/wakatimeProxy.api.d.ts +55 -0
  135. package/src/v1/activities/activities.service.ts +213 -0
  136. package/src/v1/activities/pulse.controller.ts +68 -0
  137. package/src/v1/activities/wakatimeProxy.controller.ts +33 -0
  138. package/src/v1/database/__tests__/knex.test.ts +18 -0
  139. package/src/v1/database/__tests__/pulse.repo.test.ts +209 -0
  140. package/src/v1/database/knex.ts +107 -0
  141. package/src/v1/database/migrations.ts +13 -0
  142. package/src/v1/database/models/pulse.d.ts +24 -0
  143. package/src/v1/database/pulse.repo.ts +132 -0
  144. package/src/v1/database/queries/getCategoryTimeOverview.sql +6 -0
  145. package/src/v1/database/queries/getLongestDayInRangeMinutes.sql +11 -0
  146. package/src/v1/database/queries/getStatusBarDetails.sql +42 -0
  147. package/src/v1/dtos/createWakatimePulse.dto.ts +66 -0
  148. package/src/v1/dtos/getCategoryTimeOverview.dto.ts +9 -0
  149. package/src/v1/dtos/getWeekOverview.dto.ts +6 -0
  150. package/src/v1/startup/darwinStartup.service.ts +114 -0
  151. package/src/v1/startup/linuxStartup.service.ts +101 -0
  152. package/src/v1/startup/startup.controller.ts +23 -0
  153. package/src/v1/startup/startup.util.ts +21 -0
  154. package/src/v1/startup/startupService.factory.ts +28 -0
  155. package/src/v1/startup/unsupportedStartup.service.ts +21 -0
  156. package/src/v1/v1.module.ts +28 -0
  157. package/test/app.e2e-spec.ts +24 -0
  158. package/test/jest-e2e.json +9 -0
  159. package/test/jest.globalSetup.js +15 -0
  160. package/test/jest.globalTeardown.js +8 -0
  161. package/tsconfig.build.json +4 -0
  162. package/tsconfig.json +22 -0
  163. package/utils/__tests__/activites.util.test.ts +18 -0
  164. package/utils/__tests__/helpers.util.test.ts +155 -0
  165. package/utils/__tests__/wakatime.util.test.ts +222 -0
  166. package/utils/activities.util.ts +193 -0
  167. package/utils/allExceptions.filter.ts +43 -0
  168. package/utils/codeClimberErrors.ts +32 -0
  169. package/utils/constants.ts +1 -0
  170. package/utils/environment.util.ts +1 -0
  171. package/utils/helpers.util.ts +131 -0
  172. package/utils/node.util.ts +29 -0
  173. package/utils/sql.util.ts +13 -0
  174. package/utils/sqlReader.util.ts +49 -0
  175. package/utils/wakatime.util.ts +78 -0
@@ -0,0 +1 @@
1
+ export declare const PROCESS_NAME = "codeclimbers-server";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROCESS_NAME = void 0;
4
+ exports.PROCESS_NAME = 'codeclimbers-server';
5
+ //# sourceMappingURL=constants.js.map
@@ -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,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isCli = void 0;
4
+ const isCli = () => process.env.CODECLIMBERS_SERVER_APP_CONTEXT === 'cli';
5
+ exports.isCli = isCli;
6
+ //# sourceMappingURL=environment.util.js.map
@@ -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,5 @@
1
+ declare function getFileContentAsString(fileName: string, additionalPath?: string): Promise<string>;
2
+ declare const _default: {
3
+ getFileContentAsString: typeof getFileContentAsString;
4
+ };
5
+ export default _default;
@@ -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
@@ -0,0 +1,5 @@
1
+ // include elements that are shared with the commands project in this file as exports
2
+ export * from './src/main'
3
+ export * as SERVER_CONSTANTS from './utils/constants'
4
+ export * from './utils/environment.util'
5
+ export * from './src/v1/startup/startupService.factory'
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,9 @@
1
+ import { Controller, Get } from '@nestjs/common'
2
+
3
+ @Controller('/health')
4
+ export class HealthController {
5
+ @Get()
6
+ health(): { OK: boolean } {
7
+ return { OK: true }
8
+ }
9
+ }
@@ -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
+ }