@serve.zone/gitops 2.13.1

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.
Files changed (258) hide show
  1. package/.smartconfig.json +114 -0
  2. package/binary/gitops.ts +4 -0
  3. package/changelog.md +185 -0
  4. package/cli.child.js +4 -0
  5. package/cli.js +4 -0
  6. package/cli.ts.js +5 -0
  7. package/deno.json +10 -0
  8. package/dist_serve/bundle.js +36362 -0
  9. package/dist_serve/index.html +33 -0
  10. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  11. package/dist_ts/00_commitinfo_data.js +9 -0
  12. package/dist_ts/cache/classes.cache.cleaner.d.ts +23 -0
  13. package/dist_ts/cache/classes.cache.cleaner.js +61 -0
  14. package/dist_ts/cache/classes.cached.document.d.ts +30 -0
  15. package/dist_ts/cache/classes.cached.document.js +101 -0
  16. package/dist_ts/cache/classes.cachedb.d.ts +22 -0
  17. package/dist_ts/cache/classes.cachedb.js +58 -0
  18. package/dist_ts/cache/classes.secrets.scan.service.d.ts +51 -0
  19. package/dist_ts/cache/classes.secrets.scan.service.js +237 -0
  20. package/dist_ts/cache/documents/classes.cached.project.d.ts +13 -0
  21. package/dist_ts/cache/documents/classes.cached.project.js +101 -0
  22. package/dist_ts/cache/documents/classes.cached.secret.d.ts +24 -0
  23. package/dist_ts/cache/documents/classes.cached.secret.js +158 -0
  24. package/dist_ts/cache/documents/index.d.ts +2 -0
  25. package/dist_ts/cache/documents/index.js +3 -0
  26. package/dist_ts/cache/index.d.ts +7 -0
  27. package/dist_ts/cache/index.js +6 -0
  28. package/dist_ts/classes/actionlog.d.ts +19 -0
  29. package/dist_ts/classes/actionlog.js +44 -0
  30. package/dist_ts/classes/connectionmanager.d.ts +57 -0
  31. package/dist_ts/classes/connectionmanager.js +247 -0
  32. package/dist_ts/classes/gitopsapp.d.ts +30 -0
  33. package/dist_ts/classes/gitopsapp.js +101 -0
  34. package/dist_ts/classes/jobmanager.d.ts +47 -0
  35. package/dist_ts/classes/jobmanager.js +301 -0
  36. package/dist_ts/classes/jobrunners/autobookstackdocs.runner.d.ts +29 -0
  37. package/dist_ts/classes/jobrunners/autobookstackdocs.runner.js +361 -0
  38. package/dist_ts/classes/jobrunners/base.jobrunner.d.ts +14 -0
  39. package/dist_ts/classes/jobrunners/base.jobrunner.js +3 -0
  40. package/dist_ts/classes/jobrunners/index.d.ts +5 -0
  41. package/dist_ts/classes/jobrunners/index.js +14 -0
  42. package/dist_ts/classes/managedsecrets.manager.d.ts +47 -0
  43. package/dist_ts/classes/managedsecrets.manager.js +247 -0
  44. package/dist_ts/classes/syncmanager.d.ts +189 -0
  45. package/dist_ts/classes/syncmanager.js +1787 -0
  46. package/dist_ts/index.d.ts +6 -0
  47. package/dist_ts/index.js +32 -0
  48. package/dist_ts/logging.d.ts +49 -0
  49. package/dist_ts/logging.js +134 -0
  50. package/dist_ts/opsserver/classes.opsserver.d.ts +25 -0
  51. package/dist_ts/opsserver/classes.opsserver.js +70 -0
  52. package/dist_ts/opsserver/handlers/actionlog.handler.d.ts +9 -0
  53. package/dist_ts/opsserver/handlers/actionlog.handler.js +24 -0
  54. package/dist_ts/opsserver/handlers/actions.handler.d.ts +9 -0
  55. package/dist_ts/opsserver/handlers/actions.handler.js +38 -0
  56. package/dist_ts/opsserver/handlers/admin.handler.d.ts +19 -0
  57. package/dist_ts/opsserver/handlers/admin.handler.js +96 -0
  58. package/dist_ts/opsserver/handlers/connections.handler.d.ts +10 -0
  59. package/dist_ts/opsserver/handlers/connections.handler.js +109 -0
  60. package/dist_ts/opsserver/handlers/groups.handler.d.ts +9 -0
  61. package/dist_ts/opsserver/handlers/groups.handler.js +24 -0
  62. package/dist_ts/opsserver/handlers/index.d.ts +13 -0
  63. package/dist_ts/opsserver/handlers/index.js +14 -0
  64. package/dist_ts/opsserver/handlers/jobs.handler.d.ts +16 -0
  65. package/dist_ts/opsserver/handlers/jobs.handler.js +146 -0
  66. package/dist_ts/opsserver/handlers/logs.handler.d.ts +9 -0
  67. package/dist_ts/opsserver/handlers/logs.handler.js +21 -0
  68. package/dist_ts/opsserver/handlers/managedsecrets.handler.d.ts +11 -0
  69. package/dist_ts/opsserver/handlers/managedsecrets.handler.js +110 -0
  70. package/dist_ts/opsserver/handlers/pipelines.handler.d.ts +31 -0
  71. package/dist_ts/opsserver/handlers/pipelines.handler.js +204 -0
  72. package/dist_ts/opsserver/handlers/projects.handler.d.ts +9 -0
  73. package/dist_ts/opsserver/handlers/projects.handler.js +24 -0
  74. package/dist_ts/opsserver/handlers/secrets.handler.d.ts +10 -0
  75. package/dist_ts/opsserver/handlers/secrets.handler.js +171 -0
  76. package/dist_ts/opsserver/handlers/sync.handler.d.ts +16 -0
  77. package/dist_ts/opsserver/handlers/sync.handler.js +166 -0
  78. package/dist_ts/opsserver/handlers/webhook.handler.d.ts +7 -0
  79. package/dist_ts/opsserver/handlers/webhook.handler.js +55 -0
  80. package/dist_ts/opsserver/helpers/guards.d.ts +5 -0
  81. package/dist_ts/opsserver/helpers/guards.js +12 -0
  82. package/dist_ts/opsserver/index.d.ts +1 -0
  83. package/dist_ts/opsserver/index.js +2 -0
  84. package/dist_ts/paths.d.ts +9 -0
  85. package/dist_ts/paths.js +13 -0
  86. package/dist_ts/plugins.d.ts +25 -0
  87. package/dist_ts/plugins.js +32 -0
  88. package/dist_ts/providers/classes.baseprovider.d.ts +51 -0
  89. package/dist_ts/providers/classes.baseprovider.js +17 -0
  90. package/dist_ts/providers/classes.giteaprovider.d.ts +40 -0
  91. package/dist_ts/providers/classes.giteaprovider.js +224 -0
  92. package/dist_ts/providers/classes.gitlabprovider.d.ts +39 -0
  93. package/dist_ts/providers/classes.gitlabprovider.js +207 -0
  94. package/dist_ts/providers/index.d.ts +3 -0
  95. package/dist_ts/providers/index.js +4 -0
  96. package/dist_ts/storage/classes.storagemanager.d.ts +33 -0
  97. package/dist_ts/storage/classes.storagemanager.js +135 -0
  98. package/dist_ts/storage/index.d.ts +2 -0
  99. package/dist_ts/storage/index.js +2 -0
  100. package/dist_ts/timers.d.ts +4 -0
  101. package/dist_ts/timers.js +24 -0
  102. package/dist_ts_bundled/bundle.d.ts +4 -0
  103. package/dist_ts_bundled/bundle.js +12 -0
  104. package/dist_ts_interfaces/data/actionlog.d.ts +12 -0
  105. package/dist_ts_interfaces/data/actionlog.js +2 -0
  106. package/dist_ts_interfaces/data/branch.d.ts +8 -0
  107. package/dist_ts_interfaces/data/branch.js +2 -0
  108. package/dist_ts_interfaces/data/connection.d.ts +12 -0
  109. package/dist_ts_interfaces/data/connection.js +2 -0
  110. package/dist_ts_interfaces/data/group.d.ts +10 -0
  111. package/dist_ts_interfaces/data/group.js +2 -0
  112. package/dist_ts_interfaces/data/identity.d.ts +7 -0
  113. package/dist_ts_interfaces/data/identity.js +2 -0
  114. package/dist_ts_interfaces/data/index.d.ts +11 -0
  115. package/dist_ts_interfaces/data/index.js +12 -0
  116. package/dist_ts_interfaces/data/job.d.ts +37 -0
  117. package/dist_ts_interfaces/data/job.js +2 -0
  118. package/dist_ts_interfaces/data/managedsecret.d.ts +37 -0
  119. package/dist_ts_interfaces/data/managedsecret.js +2 -0
  120. package/dist_ts_interfaces/data/pipeline.d.ts +22 -0
  121. package/dist_ts_interfaces/data/pipeline.js +2 -0
  122. package/dist_ts_interfaces/data/project.d.ts +12 -0
  123. package/dist_ts_interfaces/data/project.js +2 -0
  124. package/dist_ts_interfaces/data/secret.d.ts +11 -0
  125. package/dist_ts_interfaces/data/secret.js +2 -0
  126. package/dist_ts_interfaces/data/sync.d.ts +34 -0
  127. package/dist_ts_interfaces/data/sync.js +2 -0
  128. package/dist_ts_interfaces/index.d.ts +5 -0
  129. package/dist_ts_interfaces/index.js +8 -0
  130. package/dist_ts_interfaces/plugins.d.ts +2 -0
  131. package/dist_ts_interfaces/plugins.js +4 -0
  132. package/dist_ts_interfaces/requests/actionlog.d.ts +15 -0
  133. package/dist_ts_interfaces/requests/actionlog.js +3 -0
  134. package/dist_ts_interfaces/requests/actions.d.ts +31 -0
  135. package/dist_ts_interfaces/requests/actions.js +3 -0
  136. package/dist_ts_interfaces/requests/admin.d.ts +31 -0
  137. package/dist_ts_interfaces/requests/admin.js +3 -0
  138. package/dist_ts_interfaces/requests/connections.d.ts +71 -0
  139. package/dist_ts_interfaces/requests/connections.js +3 -0
  140. package/dist_ts_interfaces/requests/groups.d.ts +14 -0
  141. package/dist_ts_interfaces/requests/groups.js +3 -0
  142. package/dist_ts_interfaces/requests/index.d.ts +13 -0
  143. package/dist_ts_interfaces/requests/index.js +14 -0
  144. package/dist_ts_interfaces/requests/jobs.d.ts +86 -0
  145. package/dist_ts_interfaces/requests/jobs.js +3 -0
  146. package/dist_ts_interfaces/requests/logs.d.ts +14 -0
  147. package/dist_ts_interfaces/requests/logs.js +3 -0
  148. package/dist_ts_interfaces/requests/managedsecrets.d.ts +84 -0
  149. package/dist_ts_interfaces/requests/managedsecrets.js +3 -0
  150. package/dist_ts_interfaces/requests/pipelines.d.ts +55 -0
  151. package/dist_ts_interfaces/requests/pipelines.js +3 -0
  152. package/dist_ts_interfaces/requests/projects.d.ts +14 -0
  153. package/dist_ts_interfaces/requests/projects.js +3 -0
  154. package/dist_ts_interfaces/requests/secrets.d.ts +72 -0
  155. package/dist_ts_interfaces/requests/secrets.js +3 -0
  156. package/dist_ts_interfaces/requests/sync.d.ts +120 -0
  157. package/dist_ts_interfaces/requests/sync.js +3 -0
  158. package/dist_ts_interfaces/requests/webhook.d.ts +13 -0
  159. package/dist_ts_interfaces/requests/webhook.js +3 -0
  160. package/license +21 -0
  161. package/package.json +81 -0
  162. package/readme.md +177 -0
  163. package/readme.todo.md +3 -0
  164. package/ts/00_commitinfo_data.ts +8 -0
  165. package/ts/cache/classes.cache.cleaner.ts +69 -0
  166. package/ts/cache/classes.cached.document.ts +57 -0
  167. package/ts/cache/classes.cachedb.ts +72 -0
  168. package/ts/cache/classes.secrets.scan.service.ts +267 -0
  169. package/ts/cache/documents/classes.cached.project.ts +32 -0
  170. package/ts/cache/documents/classes.cached.secret.ts +81 -0
  171. package/ts/cache/documents/index.ts +2 -0
  172. package/ts/cache/index.ts +7 -0
  173. package/ts/classes/actionlog.ts +57 -0
  174. package/ts/classes/connectionmanager.ts +263 -0
  175. package/ts/classes/gitopsapp.ts +128 -0
  176. package/ts/classes/jobmanager.ts +337 -0
  177. package/ts/classes/jobrunners/autobookstackdocs.runner.ts +435 -0
  178. package/ts/classes/jobrunners/base.jobrunner.ts +16 -0
  179. package/ts/classes/jobrunners/index.ts +17 -0
  180. package/ts/classes/managedsecrets.manager.ts +322 -0
  181. package/ts/classes/syncmanager.ts +2117 -0
  182. package/ts/index.ts +37 -0
  183. package/ts/logging.ts +162 -0
  184. package/ts/opsserver/classes.opsserver.ts +86 -0
  185. package/ts/opsserver/handlers/actionlog.handler.ts +30 -0
  186. package/ts/opsserver/handlers/actions.handler.ts +50 -0
  187. package/ts/opsserver/handlers/admin.handler.ts +122 -0
  188. package/ts/opsserver/handlers/connections.handler.ts +162 -0
  189. package/ts/opsserver/handlers/groups.handler.ts +32 -0
  190. package/ts/opsserver/handlers/index.ts +13 -0
  191. package/ts/opsserver/handlers/jobs.handler.ts +189 -0
  192. package/ts/opsserver/handlers/logs.handler.ts +29 -0
  193. package/ts/opsserver/handlers/managedsecrets.handler.ts +158 -0
  194. package/ts/opsserver/handlers/pipelines.handler.ts +281 -0
  195. package/ts/opsserver/handlers/projects.handler.ts +32 -0
  196. package/ts/opsserver/handlers/secrets.handler.ts +224 -0
  197. package/ts/opsserver/handlers/sync.handler.ts +224 -0
  198. package/ts/opsserver/handlers/webhook.handler.ts +62 -0
  199. package/ts/opsserver/helpers/guards.ts +16 -0
  200. package/ts/opsserver/index.ts +1 -0
  201. package/ts/paths.ts +19 -0
  202. package/ts/plugins.ts +38 -0
  203. package/ts/providers/classes.baseprovider.ts +99 -0
  204. package/ts/providers/classes.giteaprovider.ts +279 -0
  205. package/ts/providers/classes.gitlabprovider.ts +265 -0
  206. package/ts/providers/index.ts +3 -0
  207. package/ts/storage/classes.storagemanager.ts +144 -0
  208. package/ts/storage/index.ts +2 -0
  209. package/ts/timers.ts +34 -0
  210. package/ts_interfaces/data/actionlog.ts +13 -0
  211. package/ts_interfaces/data/branch.ts +9 -0
  212. package/ts_interfaces/data/connection.ts +13 -0
  213. package/ts_interfaces/data/group.ts +10 -0
  214. package/ts_interfaces/data/identity.ts +7 -0
  215. package/ts_interfaces/data/index.ts +11 -0
  216. package/ts_interfaces/data/job.ts +42 -0
  217. package/ts_interfaces/data/managedsecret.ts +41 -0
  218. package/ts_interfaces/data/pipeline.ts +32 -0
  219. package/ts_interfaces/data/project.ts +12 -0
  220. package/ts_interfaces/data/secret.ts +11 -0
  221. package/ts_interfaces/data/sync.ts +37 -0
  222. package/ts_interfaces/index.ts +9 -0
  223. package/ts_interfaces/plugins.ts +6 -0
  224. package/ts_interfaces/requests/actionlog.ts +19 -0
  225. package/ts_interfaces/requests/actions.ts +39 -0
  226. package/ts_interfaces/requests/admin.ts +43 -0
  227. package/ts_interfaces/requests/connections.ts +95 -0
  228. package/ts_interfaces/requests/groups.ts +18 -0
  229. package/ts_interfaces/requests/index.ts +13 -0
  230. package/ts_interfaces/requests/jobs.ts +118 -0
  231. package/ts_interfaces/requests/logs.ts +18 -0
  232. package/ts_interfaces/requests/managedsecrets.ts +112 -0
  233. package/ts_interfaces/requests/pipelines.ts +71 -0
  234. package/ts_interfaces/requests/projects.ts +18 -0
  235. package/ts_interfaces/requests/secrets.ts +92 -0
  236. package/ts_interfaces/requests/sync.ts +157 -0
  237. package/ts_interfaces/requests/webhook.ts +18 -0
  238. package/ts_web/00_commitinfo_data.ts +8 -0
  239. package/ts_web/appstate.ts +1251 -0
  240. package/ts_web/elements/gitops-dashboard.ts +350 -0
  241. package/ts_web/elements/index.ts +10 -0
  242. package/ts_web/elements/shared/css.ts +29 -0
  243. package/ts_web/elements/shared/index.ts +1 -0
  244. package/ts_web/elements/views/actionlog/index.ts +101 -0
  245. package/ts_web/elements/views/actions/index.ts +209 -0
  246. package/ts_web/elements/views/buildlog/index.ts +196 -0
  247. package/ts_web/elements/views/connections/index.ts +260 -0
  248. package/ts_web/elements/views/groups/index.ts +134 -0
  249. package/ts_web/elements/views/jobs/index.ts +424 -0
  250. package/ts_web/elements/views/managedsecrets/index.ts +502 -0
  251. package/ts_web/elements/views/overview/index.ts +86 -0
  252. package/ts_web/elements/views/pipelines/index.ts +561 -0
  253. package/ts_web/elements/views/projects/index.ts +149 -0
  254. package/ts_web/elements/views/secrets/index.ts +310 -0
  255. package/ts_web/elements/views/sync/index.ts +512 -0
  256. package/ts_web/index.ts +7 -0
  257. package/ts_web/plugins.ts +15 -0
  258. package/tsconfig.json +15 -0
package/ts/index.ts ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Main exports and CLI entry point for GitOps
3
+ */
4
+
5
+ export { GitopsApp } from './classes/gitopsapp.js';
6
+ export { logger } from './logging.js';
7
+
8
+ import { GitopsApp } from './classes/gitopsapp.js';
9
+ import { logger } from './logging.js';
10
+
11
+ export async function runCli(): Promise<void> {
12
+ const args = process.argv.slice(2);
13
+ const command = args[0] || 'server';
14
+
15
+ switch (command) {
16
+ case 'server': {
17
+ const port = parseInt(process.env.GITOPS_PORT || '3000', 10);
18
+ const app = new GitopsApp();
19
+ await app.start(port);
20
+
21
+ // Handle graceful shutdown
22
+ const shutdown = async () => {
23
+ logger.info('Shutting down...');
24
+ await app.stop();
25
+ process.exit(0);
26
+ };
27
+
28
+ process.once('SIGINT', shutdown);
29
+ process.once('SIGTERM', shutdown);
30
+ break;
31
+ }
32
+ default:
33
+ logger.error(`Unknown command: ${command}`);
34
+ logger.info('Usage: gitops [server]');
35
+ process.exit(1);
36
+ }
37
+ }
package/ts/logging.ts ADDED
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Logging utilities for GitOps
3
+ */
4
+
5
+ import type { ISyncLogEntry } from '../ts_interfaces/data/sync.js';
6
+ import type { IJobLogEntry } from '../ts_interfaces/data/job.js';
7
+
8
+ type LogLevel = 'info' | 'success' | 'warn' | 'error' | 'debug';
9
+
10
+ const SYNC_LOG_MAX = 500;
11
+ const JOB_LOG_MAX = 500;
12
+
13
+ class Logger {
14
+ private debugMode = false;
15
+ private syncLogBuffer: ISyncLogEntry[] = [];
16
+ private broadcastFn?: (entry: ISyncLogEntry) => void;
17
+ private jobLogBuffer: IJobLogEntry[] = [];
18
+ private jobBroadcastFn?: (entry: IJobLogEntry) => void;
19
+
20
+ constructor() {
21
+ this.debugMode = process.argv.includes('--debug') || process.env.DEBUG === 'true';
22
+ }
23
+
24
+ /**
25
+ * Set the broadcast function used to push sync log entries to connected clients.
26
+ */
27
+ setBroadcastFn(fn: (entry: ISyncLogEntry) => void): void {
28
+ this.broadcastFn = fn;
29
+ }
30
+
31
+ /**
32
+ * Log a sync-related message to both the console and the ring buffer.
33
+ * Also broadcasts to connected frontends via TypedSocket if available.
34
+ */
35
+ syncLog(level: ISyncLogEntry['level'], message: string, source?: string): void {
36
+ // Also log to console
37
+ this.log(level, message);
38
+
39
+ const entry: ISyncLogEntry = {
40
+ timestamp: Date.now(),
41
+ level,
42
+ message,
43
+ source,
44
+ };
45
+
46
+ this.syncLogBuffer.push(entry);
47
+ if (this.syncLogBuffer.length > SYNC_LOG_MAX) {
48
+ this.syncLogBuffer.splice(0, this.syncLogBuffer.length - SYNC_LOG_MAX);
49
+ }
50
+
51
+ if (this.broadcastFn) {
52
+ this.broadcastFn(entry);
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Get recent sync log entries.
58
+ */
59
+ getSyncLogs(limit = 100): ISyncLogEntry[] {
60
+ return this.syncLogBuffer.slice(-limit);
61
+ }
62
+
63
+ /**
64
+ * Set the broadcast function used to push job log entries to connected clients.
65
+ */
66
+ setJobBroadcastFn(fn: (entry: IJobLogEntry) => void): void {
67
+ this.jobBroadcastFn = fn;
68
+ }
69
+
70
+ /**
71
+ * Log a job-related message to both the console and the ring buffer.
72
+ * Also broadcasts to connected frontends via TypedSocket if available.
73
+ */
74
+ jobLog(level: IJobLogEntry['level'], message: string, source?: string): void {
75
+ this.log(level, message);
76
+
77
+ const entry: IJobLogEntry = {
78
+ timestamp: Date.now(),
79
+ level,
80
+ message,
81
+ source,
82
+ };
83
+
84
+ this.jobLogBuffer.push(entry);
85
+ if (this.jobLogBuffer.length > JOB_LOG_MAX) {
86
+ this.jobLogBuffer.splice(0, this.jobLogBuffer.length - JOB_LOG_MAX);
87
+ }
88
+
89
+ if (this.jobBroadcastFn) {
90
+ this.jobBroadcastFn(entry);
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Get recent job log entries.
96
+ */
97
+ getJobLogs(limit = 100): IJobLogEntry[] {
98
+ return this.jobLogBuffer.slice(-limit);
99
+ }
100
+
101
+ log(level: LogLevel, message: string, ...args: unknown[]): void {
102
+ const prefix = this.getPrefix(level);
103
+ const formattedMessage = `${prefix} ${message}`;
104
+
105
+ switch (level) {
106
+ case 'error':
107
+ console.error(formattedMessage, ...args);
108
+ break;
109
+ case 'warn':
110
+ console.warn(formattedMessage, ...args);
111
+ break;
112
+ case 'debug':
113
+ if (this.debugMode) {
114
+ console.log(formattedMessage, ...args);
115
+ }
116
+ break;
117
+ default:
118
+ console.log(formattedMessage, ...args);
119
+ }
120
+ }
121
+
122
+ info(message: string, ...args: unknown[]): void {
123
+ this.log('info', message, ...args);
124
+ }
125
+
126
+ success(message: string, ...args: unknown[]): void {
127
+ this.log('success', message, ...args);
128
+ }
129
+
130
+ warn(message: string, ...args: unknown[]): void {
131
+ this.log('warn', message, ...args);
132
+ }
133
+
134
+ error(message: string, ...args: unknown[]): void {
135
+ this.log('error', message, ...args);
136
+ }
137
+
138
+ debug(message: string, ...args: unknown[]): void {
139
+ this.log('debug', message, ...args);
140
+ }
141
+
142
+ private getPrefix(level: LogLevel): string {
143
+ const colors: Record<LogLevel, string> = {
144
+ info: '\x1b[36m',
145
+ success: '\x1b[32m',
146
+ warn: '\x1b[33m',
147
+ error: '\x1b[31m',
148
+ debug: '\x1b[90m',
149
+ };
150
+ const reset = '\x1b[0m';
151
+ const icons: Record<LogLevel, string> = {
152
+ info: 'i',
153
+ success: '+',
154
+ warn: '!',
155
+ error: 'x',
156
+ debug: '*',
157
+ };
158
+ return `${colors[level]}[${icons[level]}]${reset}`;
159
+ }
160
+ }
161
+
162
+ export const logger = new Logger();
@@ -0,0 +1,86 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { logger } from '../logging.js';
3
+ import type { GitopsApp } from '../classes/gitopsapp.js';
4
+ import * as handlers from './handlers/index.js';
5
+
6
+ const distServeDir = plugins.path.join(
7
+ plugins.path.dirname(plugins.nodeUrl.fileURLToPath(import.meta.url)),
8
+ '../../dist_serve',
9
+ );
10
+
11
+ export class OpsServer {
12
+ public gitopsAppRef: GitopsApp;
13
+ public typedrouter = new plugins.typedrequest.TypedRouter();
14
+ public server!: plugins.typedserver.utilityservers.UtilityWebsiteServer;
15
+
16
+ // Handler instances
17
+ public adminHandler!: handlers.AdminHandler;
18
+ public connectionsHandler!: handlers.ConnectionsHandler;
19
+ public projectsHandler!: handlers.ProjectsHandler;
20
+ public groupsHandler!: handlers.GroupsHandler;
21
+ public secretsHandler!: handlers.SecretsHandler;
22
+ public pipelinesHandler!: handlers.PipelinesHandler;
23
+ public logsHandler!: handlers.LogsHandler;
24
+ public webhookHandler!: handlers.WebhookHandler;
25
+ public actionsHandler!: handlers.ActionsHandler;
26
+ public actionLogHandler!: handlers.ActionLogHandler;
27
+ public syncHandler!: handlers.SyncHandler;
28
+ public managedSecretsHandler!: handlers.ManagedSecretsHandler;
29
+ public jobsHandler!: handlers.JobsHandler;
30
+
31
+ constructor(gitopsAppRef: GitopsApp) {
32
+ this.gitopsAppRef = gitopsAppRef;
33
+ }
34
+
35
+ public async start(port = 3000) {
36
+ // Create webhook handler before server so routes register via addCustomRoutes
37
+ this.webhookHandler = new handlers.WebhookHandler(this);
38
+
39
+ this.server = new plugins.typedserver.utilityservers.UtilityWebsiteServer({
40
+ domain: 'localhost',
41
+ feedMetadata: undefined,
42
+ serveDir: distServeDir,
43
+ noCache: true,
44
+ addCustomRoutes: async (typedserver) => {
45
+ this.webhookHandler.registerRoutes(typedserver);
46
+ },
47
+ });
48
+
49
+ // Chain typedrouters
50
+ this.server.typedrouter.addTypedRouter(this.typedrouter);
51
+
52
+ // Set up all handlers
53
+ await this.setupHandlers();
54
+
55
+ await this.server.start(port);
56
+ logger.success(`OpsServer started on http://localhost:${port}`);
57
+ }
58
+
59
+ private async setupHandlers(): Promise<void> {
60
+ // AdminHandler requires async initialization for JWT key generation
61
+ this.adminHandler = new handlers.AdminHandler(this);
62
+ await this.adminHandler.initialize();
63
+
64
+ // All other handlers self-register in their constructors
65
+ this.connectionsHandler = new handlers.ConnectionsHandler(this);
66
+ this.projectsHandler = new handlers.ProjectsHandler(this);
67
+ this.groupsHandler = new handlers.GroupsHandler(this);
68
+ this.secretsHandler = new handlers.SecretsHandler(this);
69
+ this.pipelinesHandler = new handlers.PipelinesHandler(this);
70
+ this.logsHandler = new handlers.LogsHandler(this);
71
+ this.actionsHandler = new handlers.ActionsHandler(this);
72
+ this.actionLogHandler = new handlers.ActionLogHandler(this);
73
+ this.syncHandler = new handlers.SyncHandler(this);
74
+ this.managedSecretsHandler = new handlers.ManagedSecretsHandler(this);
75
+ this.jobsHandler = new handlers.JobsHandler(this);
76
+
77
+ logger.success('OpsServer TypedRequest handlers initialized');
78
+ }
79
+
80
+ public async stop() {
81
+ if (this.server) {
82
+ await this.server.stop();
83
+ logger.success('OpsServer stopped');
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,30 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { OpsServer } from '../classes.opsserver.js';
3
+ import * as interfaces from '../../../ts_interfaces/index.js';
4
+ import { requireValidIdentity } from '../helpers/guards.js';
5
+
6
+ export class ActionLogHandler {
7
+ public typedrouter = new plugins.typedrequest.TypedRouter();
8
+
9
+ constructor(private opsServerRef: OpsServer) {
10
+ this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
11
+ this.registerHandlers();
12
+ }
13
+
14
+ private registerHandlers(): void {
15
+ this.typedrouter.addTypedHandler(
16
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetActionLog>(
17
+ 'getActionLog',
18
+ async (dataArg) => {
19
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
20
+ const result = await this.opsServerRef.gitopsAppRef.actionLog.query({
21
+ limit: dataArg.limit,
22
+ offset: dataArg.offset,
23
+ entityType: dataArg.entityType,
24
+ });
25
+ return result;
26
+ },
27
+ ),
28
+ );
29
+ }
30
+ }
@@ -0,0 +1,50 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { OpsServer } from '../classes.opsserver.js';
3
+ import * as interfaces from '../../../ts_interfaces/index.js';
4
+ import { requireValidIdentity } from '../helpers/guards.js';
5
+
6
+ export class ActionsHandler {
7
+ public typedrouter = new plugins.typedrequest.TypedRouter();
8
+
9
+ constructor(private opsServerRef: OpsServer) {
10
+ this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
11
+ this.registerHandlers();
12
+ }
13
+
14
+ private registerHandlers(): void {
15
+ // Force scan secrets
16
+ this.typedrouter.addTypedHandler(
17
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ForceScanSecrets>(
18
+ 'forceScanSecrets',
19
+ async (dataArg) => {
20
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
21
+ const scanService = this.opsServerRef.gitopsAppRef.secretsScanService;
22
+ const result = await scanService.fullScan();
23
+ return {
24
+ ok: true,
25
+ connectionsScanned: result.connectionsScanned,
26
+ secretsFound: result.secretsFound,
27
+ errors: result.errors,
28
+ durationMs: result.durationMs,
29
+ };
30
+ },
31
+ ),
32
+ );
33
+
34
+ // Get scan status
35
+ this.typedrouter.addTypedHandler(
36
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetScanStatus>(
37
+ 'getScanStatus',
38
+ async (dataArg) => {
39
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
40
+ const scanService = this.opsServerRef.gitopsAppRef.secretsScanService;
41
+ return {
42
+ lastScanTimestamp: scanService.lastScanTimestamp,
43
+ isScanning: scanService.isScanning,
44
+ lastResult: scanService.lastScanResult,
45
+ };
46
+ },
47
+ ),
48
+ );
49
+ }
50
+ }
@@ -0,0 +1,122 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import { logger } from '../../logging.js';
3
+ import type { OpsServer } from '../classes.opsserver.js';
4
+ import * as interfaces from '../../../ts_interfaces/index.js';
5
+
6
+ export interface IJwtData {
7
+ userId: string;
8
+ status: 'loggedIn' | 'loggedOut';
9
+ expiresAt: number;
10
+ }
11
+
12
+ export class AdminHandler {
13
+ public typedrouter = new plugins.typedrequest.TypedRouter();
14
+ public smartjwtInstance!: plugins.smartjwt.SmartJwt<IJwtData>;
15
+
16
+ constructor(private opsServerRef: OpsServer) {
17
+ this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
18
+ }
19
+
20
+ public async initialize(): Promise<void> {
21
+ this.smartjwtInstance = new plugins.smartjwt.SmartJwt();
22
+ await this.smartjwtInstance.init();
23
+ await this.smartjwtInstance.createNewKeyPair();
24
+ this.registerHandlers();
25
+ }
26
+
27
+ private registerHandlers(): void {
28
+ // Login
29
+ this.typedrouter.addTypedHandler(
30
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_AdminLogin>(
31
+ 'adminLogin',
32
+ async (dataArg) => {
33
+ const expectedUsername = process.env.GITOPS_ADMIN_USERNAME || 'admin';
34
+ const expectedPassword = process.env.GITOPS_ADMIN_PASSWORD || 'admin';
35
+
36
+ if (dataArg.username !== expectedUsername || dataArg.password !== expectedPassword) {
37
+ throw new plugins.typedrequest.TypedResponseError('Invalid credentials');
38
+ }
39
+
40
+ const expiresAt = Date.now() + 24 * 3600 * 1000;
41
+ const userId = 'admin';
42
+ const jwt = await this.smartjwtInstance.createJWT({
43
+ userId,
44
+ status: 'loggedIn',
45
+ expiresAt,
46
+ });
47
+
48
+ logger.info(`User logged in: ${dataArg.username}`);
49
+
50
+ return {
51
+ identity: {
52
+ jwt,
53
+ userId,
54
+ username: dataArg.username,
55
+ expiresAt,
56
+ role: 'admin' as const,
57
+ },
58
+ };
59
+ },
60
+ ),
61
+ );
62
+
63
+ // Logout
64
+ this.typedrouter.addTypedHandler(
65
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_AdminLogout>(
66
+ 'adminLogout',
67
+ async (_dataArg) => {
68
+ return { ok: true };
69
+ },
70
+ ),
71
+ );
72
+
73
+ // Verify Identity
74
+ this.typedrouter.addTypedHandler(
75
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_VerifyIdentity>(
76
+ 'verifyIdentity',
77
+ async (dataArg) => {
78
+ if (!dataArg.identity?.jwt) {
79
+ return { valid: false };
80
+ }
81
+ try {
82
+ const jwtData = await this.smartjwtInstance.verifyJWTAndGetData(dataArg.identity.jwt);
83
+ if (jwtData.expiresAt < Date.now()) return { valid: false };
84
+ if (jwtData.status !== 'loggedIn') return { valid: false };
85
+ return {
86
+ valid: true,
87
+ identity: {
88
+ jwt: dataArg.identity.jwt,
89
+ userId: jwtData.userId,
90
+ username: dataArg.identity.username,
91
+ expiresAt: jwtData.expiresAt,
92
+ role: dataArg.identity.role,
93
+ },
94
+ };
95
+ } catch {
96
+ return { valid: false };
97
+ }
98
+ },
99
+ ),
100
+ );
101
+ }
102
+
103
+ // Guard for valid identity
104
+ public validIdentityGuard = new plugins.smartguard.Guard<{
105
+ identity: interfaces.data.IIdentity;
106
+ }>(
107
+ async (dataArg) => {
108
+ if (!dataArg.identity?.jwt) return false;
109
+ try {
110
+ const jwtData = await this.smartjwtInstance.verifyJWTAndGetData(dataArg.identity.jwt);
111
+ if (jwtData.expiresAt < Date.now()) return false;
112
+ if (jwtData.status !== 'loggedIn') return false;
113
+ if (dataArg.identity.expiresAt !== jwtData.expiresAt) return false;
114
+ if (dataArg.identity.userId !== jwtData.userId) return false;
115
+ return true;
116
+ } catch {
117
+ return false;
118
+ }
119
+ },
120
+ { failedHint: 'identity is not valid', name: 'validIdentityGuard' },
121
+ );
122
+ }
@@ -0,0 +1,162 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { OpsServer } from '../classes.opsserver.js';
3
+ import * as interfaces from '../../../ts_interfaces/index.js';
4
+ import { requireValidIdentity } from '../helpers/guards.js';
5
+
6
+ export class ConnectionsHandler {
7
+ public typedrouter = new plugins.typedrequest.TypedRouter();
8
+
9
+ constructor(private opsServerRef: OpsServer) {
10
+ this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
11
+ this.registerHandlers();
12
+ }
13
+
14
+ private get actionLog() {
15
+ return this.opsServerRef.gitopsAppRef.actionLog;
16
+ }
17
+
18
+ private registerHandlers(): void {
19
+ // Get all connections
20
+ this.typedrouter.addTypedHandler(
21
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetConnections>(
22
+ 'getConnections',
23
+ async (dataArg) => {
24
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
25
+ const connections = this.opsServerRef.gitopsAppRef.connectionManager.getConnections();
26
+ return { connections };
27
+ },
28
+ ),
29
+ );
30
+
31
+ // Create connection
32
+ this.typedrouter.addTypedHandler(
33
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateConnection>(
34
+ 'createConnection',
35
+ async (dataArg) => {
36
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
37
+ const connection = await this.opsServerRef.gitopsAppRef.connectionManager.createConnection(
38
+ dataArg.name,
39
+ dataArg.providerType,
40
+ dataArg.baseUrl,
41
+ dataArg.token,
42
+ dataArg.groupFilter,
43
+ );
44
+ this.actionLog.append({
45
+ actionType: 'create',
46
+ entityType: 'connection',
47
+ entityId: connection.id,
48
+ entityName: connection.name,
49
+ details: `Created ${dataArg.providerType} connection "${dataArg.name}" (${dataArg.baseUrl})`,
50
+ username: dataArg.identity.username,
51
+ });
52
+ return { connection };
53
+ },
54
+ ),
55
+ );
56
+
57
+ // Update connection
58
+ this.typedrouter.addTypedHandler(
59
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateConnection>(
60
+ 'updateConnection',
61
+ async (dataArg) => {
62
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
63
+ const connection = await this.opsServerRef.gitopsAppRef.connectionManager.updateConnection(
64
+ dataArg.connectionId,
65
+ {
66
+ name: dataArg.name,
67
+ baseUrl: dataArg.baseUrl,
68
+ token: dataArg.token,
69
+ groupFilter: dataArg.groupFilter,
70
+ },
71
+ );
72
+ const fields = [
73
+ dataArg.name && 'name',
74
+ dataArg.baseUrl && 'baseUrl',
75
+ dataArg.token && 'token',
76
+ dataArg.groupFilter !== undefined && 'groupFilter',
77
+ ].filter(Boolean).join(', ');
78
+ this.actionLog.append({
79
+ actionType: 'update',
80
+ entityType: 'connection',
81
+ entityId: dataArg.connectionId,
82
+ entityName: connection.name,
83
+ details: `Updated connection "${connection.name}" (fields: ${fields})`,
84
+ username: dataArg.identity.username,
85
+ });
86
+ return { connection };
87
+ },
88
+ ),
89
+ );
90
+
91
+ // Pause/resume connection
92
+ this.typedrouter.addTypedHandler(
93
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_PauseConnection>(
94
+ 'pauseConnection',
95
+ async (dataArg) => {
96
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
97
+ const connection = await this.opsServerRef.gitopsAppRef.connectionManager.pauseConnection(
98
+ dataArg.connectionId,
99
+ dataArg.paused,
100
+ );
101
+ this.actionLog.append({
102
+ actionType: dataArg.paused ? 'pause' : 'resume',
103
+ entityType: 'connection',
104
+ entityId: dataArg.connectionId,
105
+ entityName: connection.name,
106
+ details: `${dataArg.paused ? 'Paused' : 'Resumed'} connection "${connection.name}"`,
107
+ username: dataArg.identity.username,
108
+ });
109
+ return { connection };
110
+ },
111
+ ),
112
+ );
113
+
114
+ // Test connection
115
+ this.typedrouter.addTypedHandler(
116
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_TestConnection>(
117
+ 'testConnection',
118
+ async (dataArg) => {
119
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
120
+ const result = await this.opsServerRef.gitopsAppRef.connectionManager.testConnection(
121
+ dataArg.connectionId,
122
+ );
123
+ const conn = this.opsServerRef.gitopsAppRef.connectionManager.getConnections()
124
+ .find((c) => c.id === dataArg.connectionId);
125
+ this.actionLog.append({
126
+ actionType: 'test',
127
+ entityType: 'connection',
128
+ entityId: dataArg.connectionId,
129
+ entityName: conn?.name || dataArg.connectionId,
130
+ details: `Tested connection: ${result.ok ? 'success' : `failed — ${result.error || 'unknown error'}`}`,
131
+ username: dataArg.identity.username,
132
+ });
133
+ return result;
134
+ },
135
+ ),
136
+ );
137
+
138
+ // Delete connection
139
+ this.typedrouter.addTypedHandler(
140
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteConnection>(
141
+ 'deleteConnection',
142
+ async (dataArg) => {
143
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
144
+ const conn = this.opsServerRef.gitopsAppRef.connectionManager.getConnections()
145
+ .find((c) => c.id === dataArg.connectionId);
146
+ await this.opsServerRef.gitopsAppRef.connectionManager.deleteConnection(
147
+ dataArg.connectionId,
148
+ );
149
+ this.actionLog.append({
150
+ actionType: 'delete',
151
+ entityType: 'connection',
152
+ entityId: dataArg.connectionId,
153
+ entityName: conn?.name || dataArg.connectionId,
154
+ details: `Deleted connection "${conn?.name || dataArg.connectionId}"`,
155
+ username: dataArg.identity.username,
156
+ });
157
+ return { ok: true };
158
+ },
159
+ ),
160
+ );
161
+ }
162
+ }
@@ -0,0 +1,32 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { OpsServer } from '../classes.opsserver.js';
3
+ import * as interfaces from '../../../ts_interfaces/index.js';
4
+ import { requireValidIdentity } from '../helpers/guards.js';
5
+
6
+ export class GroupsHandler {
7
+ public typedrouter = new plugins.typedrequest.TypedRouter();
8
+
9
+ constructor(private opsServerRef: OpsServer) {
10
+ this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
11
+ this.registerHandlers();
12
+ }
13
+
14
+ private registerHandlers(): void {
15
+ this.typedrouter.addTypedHandler(
16
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetGroups>(
17
+ 'getGroups',
18
+ async (dataArg) => {
19
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
20
+ const provider = this.opsServerRef.gitopsAppRef.connectionManager.getProvider(
21
+ dataArg.connectionId,
22
+ );
23
+ const groups = await provider.getGroups({
24
+ search: dataArg.search,
25
+ page: dataArg.page,
26
+ });
27
+ return { groups };
28
+ },
29
+ ),
30
+ );
31
+ }
32
+ }