@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
@@ -0,0 +1,13 @@
1
+ export { AdminHandler } from './admin.handler.js';
2
+ export { ConnectionsHandler } from './connections.handler.js';
3
+ export { ProjectsHandler } from './projects.handler.js';
4
+ export { GroupsHandler } from './groups.handler.js';
5
+ export { SecretsHandler } from './secrets.handler.js';
6
+ export { PipelinesHandler } from './pipelines.handler.js';
7
+ export { LogsHandler } from './logs.handler.js';
8
+ export { WebhookHandler } from './webhook.handler.js';
9
+ export { ActionsHandler } from './actions.handler.js';
10
+ export { ActionLogHandler } from './actionlog.handler.js';
11
+ export { SyncHandler } from './sync.handler.js';
12
+ export { ManagedSecretsHandler } from './managedsecrets.handler.js';
13
+ export { JobsHandler } from './jobs.handler.js';
@@ -0,0 +1,189 @@
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
+ import { logger } from '../../logging.js';
6
+
7
+ export class JobsHandler {
8
+ public typedrouter = new plugins.typedrequest.TypedRouter();
9
+
10
+ constructor(private opsServerRef: OpsServer) {
11
+ this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
12
+ this.registerHandlers();
13
+ this.setupBroadcast();
14
+ }
15
+
16
+ /**
17
+ * Wire the logger's job broadcast function to push log entries
18
+ * to all connected frontends via TypedSocket.
19
+ */
20
+ private setupBroadcast(): void {
21
+ logger.setJobBroadcastFn((entry) => {
22
+ try {
23
+ const typedsocket = this.opsServerRef.server?.typedserver?.typedsocket;
24
+ if (!typedsocket) return;
25
+ typedsocket.findAllTargetConnectionsByTag('jobLogClient').then((connections) => {
26
+ for (const conn of connections) {
27
+ typedsocket
28
+ .createTypedRequest<interfaces.requests.IReq_PushJobLog>('pushJobLog', conn)
29
+ .fire({ entry })
30
+ .catch(() => {});
31
+ }
32
+ }).catch(() => {});
33
+ } catch {
34
+ // Server may not be ready yet — ignore
35
+ }
36
+ });
37
+ }
38
+
39
+ private get jobManager() {
40
+ return this.opsServerRef.gitopsAppRef.jobManager;
41
+ }
42
+
43
+ private get actionLog() {
44
+ return this.opsServerRef.gitopsAppRef.actionLog;
45
+ }
46
+
47
+ private registerHandlers(): void {
48
+ // Get all jobs
49
+ this.typedrouter.addTypedHandler(
50
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetJobs>(
51
+ 'getJobs',
52
+ async (dataArg) => {
53
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
54
+ return { jobs: this.jobManager.getJobs() };
55
+ },
56
+ ),
57
+ );
58
+
59
+ // Create job
60
+ this.typedrouter.addTypedHandler(
61
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateJob>(
62
+ 'createJob',
63
+ async (dataArg) => {
64
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
65
+ const job = await this.jobManager.createJob({
66
+ name: dataArg.name,
67
+ jobType: dataArg.jobType,
68
+ intervalMinutes: dataArg.intervalMinutes,
69
+ autoBookstackDocsConfig: dataArg.autoBookstackDocsConfig,
70
+ });
71
+ this.actionLog.append({
72
+ actionType: 'create',
73
+ entityType: 'job',
74
+ entityId: job.id,
75
+ entityName: job.name,
76
+ details: `Created ${job.jobType} job`,
77
+ username: dataArg.identity.username,
78
+ });
79
+ return { job };
80
+ },
81
+ ),
82
+ );
83
+
84
+ // Update job
85
+ this.typedrouter.addTypedHandler(
86
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateJob>(
87
+ 'updateJob',
88
+ async (dataArg) => {
89
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
90
+ const job = await this.jobManager.updateJob(dataArg.jobId, {
91
+ name: dataArg.name,
92
+ intervalMinutes: dataArg.intervalMinutes,
93
+ autoBookstackDocsConfig: dataArg.autoBookstackDocsConfig,
94
+ });
95
+ this.actionLog.append({
96
+ actionType: 'update',
97
+ entityType: 'job',
98
+ entityId: job.id,
99
+ entityName: job.name,
100
+ details: 'Updated job configuration',
101
+ username: dataArg.identity.username,
102
+ });
103
+ return { job };
104
+ },
105
+ ),
106
+ );
107
+
108
+ // Delete job
109
+ this.typedrouter.addTypedHandler(
110
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteJob>(
111
+ 'deleteJob',
112
+ async (dataArg) => {
113
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
114
+ const job = this.jobManager.getJob(dataArg.jobId);
115
+ await this.jobManager.deleteJob(dataArg.jobId);
116
+ this.actionLog.append({
117
+ actionType: 'delete',
118
+ entityType: 'job',
119
+ entityId: dataArg.jobId,
120
+ entityName: job?.name || dataArg.jobId,
121
+ details: 'Deleted job',
122
+ username: dataArg.identity.username,
123
+ });
124
+ return { ok: true };
125
+ },
126
+ ),
127
+ );
128
+
129
+ // Pause/resume job
130
+ this.typedrouter.addTypedHandler(
131
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_PauseJob>(
132
+ 'pauseJob',
133
+ async (dataArg) => {
134
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
135
+ const job = await this.jobManager.pauseJob(dataArg.jobId, dataArg.paused);
136
+ this.actionLog.append({
137
+ actionType: dataArg.paused ? 'pause' : 'resume',
138
+ entityType: 'job',
139
+ entityId: job.id,
140
+ entityName: job.name,
141
+ details: dataArg.paused ? 'Paused job' : 'Resumed job',
142
+ username: dataArg.identity.username,
143
+ });
144
+ return { job };
145
+ },
146
+ ),
147
+ );
148
+
149
+ // Trigger job manually
150
+ this.typedrouter.addTypedHandler(
151
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_TriggerJob>(
152
+ 'triggerJob',
153
+ async (dataArg) => {
154
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
155
+ const job = this.jobManager.getJob(dataArg.jobId);
156
+ if (!job) {
157
+ return { ok: false, message: `Job not found: ${dataArg.jobId}` };
158
+ }
159
+ if (this.jobManager.isJobRunning(dataArg.jobId)) {
160
+ return { ok: false, message: 'Job is already running' };
161
+ }
162
+ // Fire-and-forget
163
+ this.jobManager.executeJob(dataArg.jobId, true).catch(() => {});
164
+ this.actionLog.append({
165
+ actionType: 'run',
166
+ entityType: 'job',
167
+ entityId: job.id,
168
+ entityName: job.name,
169
+ details: 'Manually triggered job execution',
170
+ username: dataArg.identity.username,
171
+ });
172
+ return { ok: true, message: 'Job triggered' };
173
+ },
174
+ ),
175
+ );
176
+
177
+ // Get job logs
178
+ this.typedrouter.addTypedHandler(
179
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetJobLogs>(
180
+ 'getJobLogs',
181
+ async (dataArg) => {
182
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
183
+ const logs = logger.getJobLogs(dataArg.limit || 200);
184
+ return { logs };
185
+ },
186
+ ),
187
+ );
188
+ }
189
+ }
@@ -0,0 +1,29 @@
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 LogsHandler {
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_GetJobLog>(
17
+ 'getJobLog',
18
+ async (dataArg) => {
19
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
20
+ const provider = this.opsServerRef.gitopsAppRef.connectionManager.getProvider(
21
+ dataArg.connectionId,
22
+ );
23
+ const log = await provider.getJobLog(dataArg.projectId, dataArg.jobId);
24
+ return { log };
25
+ },
26
+ ),
27
+ );
28
+ }
29
+ }
@@ -0,0 +1,158 @@
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 ManagedSecretsHandler {
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 get manager() {
19
+ return this.opsServerRef.gitopsAppRef.managedSecretsManager;
20
+ }
21
+
22
+ private registerHandlers(): void {
23
+ // List all managed secrets
24
+ this.typedrouter.addTypedHandler(
25
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetManagedSecrets>(
26
+ 'getManagedSecrets',
27
+ async (dataArg) => {
28
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
29
+ const managedSecrets = await this.manager.getAll();
30
+ return { managedSecrets };
31
+ },
32
+ ),
33
+ );
34
+
35
+ // Get single managed secret
36
+ this.typedrouter.addTypedHandler(
37
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetManagedSecret>(
38
+ 'getManagedSecret',
39
+ async (dataArg) => {
40
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
41
+ const managedSecret = await this.manager.getById(dataArg.managedSecretId);
42
+ if (!managedSecret) throw new Error(`Managed secret not found: ${dataArg.managedSecretId}`);
43
+ return { managedSecret };
44
+ },
45
+ ),
46
+ );
47
+
48
+ // Create managed secret
49
+ this.typedrouter.addTypedHandler(
50
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateManagedSecret>(
51
+ 'createManagedSecret',
52
+ async (dataArg) => {
53
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
54
+ const result = await this.manager.create(
55
+ dataArg.key,
56
+ dataArg.value,
57
+ dataArg.description,
58
+ dataArg.targets,
59
+ );
60
+ this.actionLog.append({
61
+ actionType: 'create',
62
+ entityType: 'managed-secret',
63
+ entityId: result.managedSecret.id,
64
+ entityName: `GITOPS_${dataArg.key}`,
65
+ details: `Created managed secret "${dataArg.key}" with ${dataArg.targets.length} target(s)`,
66
+ username: dataArg.identity.username,
67
+ });
68
+ return result;
69
+ },
70
+ ),
71
+ );
72
+
73
+ // Update managed secret
74
+ this.typedrouter.addTypedHandler(
75
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateManagedSecret>(
76
+ 'updateManagedSecret',
77
+ async (dataArg) => {
78
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
79
+ const result = await this.manager.update(dataArg.managedSecretId, {
80
+ value: dataArg.value,
81
+ description: dataArg.description,
82
+ targets: dataArg.targets,
83
+ });
84
+ this.actionLog.append({
85
+ actionType: 'update',
86
+ entityType: 'managed-secret',
87
+ entityId: dataArg.managedSecretId,
88
+ entityName: `GITOPS_${result.managedSecret.key}`,
89
+ details: `Updated managed secret "${result.managedSecret.key}"`,
90
+ username: dataArg.identity.username,
91
+ });
92
+ return result;
93
+ },
94
+ ),
95
+ );
96
+
97
+ // Delete managed secret
98
+ this.typedrouter.addTypedHandler(
99
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteManagedSecret>(
100
+ 'deleteManagedSecret',
101
+ async (dataArg) => {
102
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
103
+ const secret = await this.manager.getById(dataArg.managedSecretId);
104
+ const result = await this.manager.delete(dataArg.managedSecretId);
105
+ this.actionLog.append({
106
+ actionType: 'delete',
107
+ entityType: 'managed-secret',
108
+ entityId: dataArg.managedSecretId,
109
+ entityName: secret ? `GITOPS_${secret.key}` : dataArg.managedSecretId,
110
+ details: `Deleted managed secret${secret ? ` "${secret.key}"` : ''}`,
111
+ username: dataArg.identity.username,
112
+ });
113
+ return result;
114
+ },
115
+ ),
116
+ );
117
+
118
+ // Push single managed secret
119
+ this.typedrouter.addTypedHandler(
120
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_PushManagedSecret>(
121
+ 'pushManagedSecret',
122
+ async (dataArg) => {
123
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
124
+ const result = await this.manager.pushOne(dataArg.managedSecretId);
125
+ this.actionLog.append({
126
+ actionType: 'push',
127
+ entityType: 'managed-secret',
128
+ entityId: dataArg.managedSecretId,
129
+ entityName: `GITOPS_${result.managedSecret.key}`,
130
+ details: `Pushed managed secret "${result.managedSecret.key}" to ${result.pushResults.length} target(s)`,
131
+ username: dataArg.identity.username,
132
+ });
133
+ return result;
134
+ },
135
+ ),
136
+ );
137
+
138
+ // Push all managed secrets
139
+ this.typedrouter.addTypedHandler(
140
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_PushAllManagedSecrets>(
141
+ 'pushAllManagedSecrets',
142
+ async (dataArg) => {
143
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
144
+ const results = await this.manager.pushAll();
145
+ this.actionLog.append({
146
+ actionType: 'push',
147
+ entityType: 'managed-secret',
148
+ entityId: 'all',
149
+ entityName: 'All managed secrets',
150
+ details: `Pushed ${results.length} managed secret(s) to their targets`,
151
+ username: dataArg.identity.username,
152
+ });
153
+ return { results };
154
+ },
155
+ ),
156
+ );
157
+ }
158
+ }
@@ -0,0 +1,281 @@
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
+ import type { BaseProvider } from '../../providers/classes.baseprovider.js';
6
+
7
+ const TIME_RANGE_MS: Record<string, number> = {
8
+ '1h': 60 * 60 * 1000,
9
+ '6h': 6 * 60 * 60 * 1000,
10
+ '1d': 24 * 60 * 60 * 1000,
11
+ '3d': 3 * 24 * 60 * 60 * 1000,
12
+ '7d': 7 * 24 * 60 * 60 * 1000,
13
+ '30d': 30 * 24 * 60 * 60 * 1000,
14
+ };
15
+
16
+ const STATUS_PRIORITY: Record<string, number> = {
17
+ running: 0,
18
+ pending: 1,
19
+ waiting: 2,
20
+ manual: 3,
21
+ failed: 4,
22
+ canceled: 5,
23
+ success: 6,
24
+ skipped: 7,
25
+ };
26
+
27
+ export class PipelinesHandler {
28
+ public typedrouter = new plugins.typedrequest.TypedRouter();
29
+
30
+ constructor(private opsServerRef: OpsServer) {
31
+ this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
32
+ this.registerHandlers();
33
+ }
34
+
35
+ private get actionLog() {
36
+ return this.opsServerRef.gitopsAppRef.actionLog;
37
+ }
38
+
39
+ private registerHandlers(): void {
40
+ // Get pipelines — supports view modes
41
+ this.typedrouter.addTypedHandler(
42
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetPipelines>(
43
+ 'getPipelines',
44
+ async (dataArg) => {
45
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
46
+ const provider = this.opsServerRef.gitopsAppRef.connectionManager.getProvider(
47
+ dataArg.connectionId,
48
+ );
49
+
50
+ const viewMode = dataArg.viewMode || 'project';
51
+ const timeRange = dataArg.timeRange || '1d';
52
+ const sortBy = dataArg.sortBy || 'created';
53
+
54
+ let pipelines: interfaces.data.IPipeline[];
55
+
56
+ if (viewMode === 'project') {
57
+ if (!dataArg.projectId) return { pipelines: [] };
58
+ pipelines = await provider.getPipelines(dataArg.projectId, {
59
+ page: dataArg.page,
60
+ status: dataArg.status,
61
+ });
62
+ pipelines = this.filterByTimeRange(pipelines, timeRange);
63
+ } else if (viewMode === 'current') {
64
+ pipelines = await this.fetchCurrentPipelines(provider, timeRange);
65
+ } else if (viewMode === 'group') {
66
+ if (!dataArg.groupId) return { pipelines: [] };
67
+ pipelines = await this.fetchGroupPipelines(provider, dataArg.groupId, timeRange);
68
+ } else if (viewMode === 'error') {
69
+ pipelines = await this.fetchErrorPipelines(provider, timeRange);
70
+ } else {
71
+ pipelines = [];
72
+ }
73
+
74
+ return { pipelines: this.sortPipelines(pipelines, sortBy).slice(0, 200) };
75
+ },
76
+ ),
77
+ );
78
+
79
+ // Get pipeline jobs
80
+ this.typedrouter.addTypedHandler(
81
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetPipelineJobs>(
82
+ 'getPipelineJobs',
83
+ async (dataArg) => {
84
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
85
+ const provider = this.opsServerRef.gitopsAppRef.connectionManager.getProvider(
86
+ dataArg.connectionId,
87
+ );
88
+ const jobs = await provider.getPipelineJobs(dataArg.projectId, dataArg.pipelineId);
89
+ return { jobs };
90
+ },
91
+ ),
92
+ );
93
+
94
+ // Retry pipeline
95
+ this.typedrouter.addTypedHandler(
96
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_RetryPipeline>(
97
+ 'retryPipeline',
98
+ async (dataArg) => {
99
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
100
+ const provider = this.opsServerRef.gitopsAppRef.connectionManager.getProvider(
101
+ dataArg.connectionId,
102
+ );
103
+ await provider.retryPipeline(dataArg.projectId, dataArg.pipelineId);
104
+ this.actionLog.append({
105
+ actionType: 'update',
106
+ entityType: 'pipeline',
107
+ entityId: dataArg.pipelineId,
108
+ entityName: `Pipeline #${dataArg.pipelineId}`,
109
+ details: `Retried pipeline #${dataArg.pipelineId} in project ${dataArg.projectId}`,
110
+ username: dataArg.identity.username,
111
+ });
112
+ return { ok: true };
113
+ },
114
+ ),
115
+ );
116
+
117
+ // Cancel pipeline
118
+ this.typedrouter.addTypedHandler(
119
+ new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CancelPipeline>(
120
+ 'cancelPipeline',
121
+ async (dataArg) => {
122
+ await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
123
+ const provider = this.opsServerRef.gitopsAppRef.connectionManager.getProvider(
124
+ dataArg.connectionId,
125
+ );
126
+ await provider.cancelPipeline(dataArg.projectId, dataArg.pipelineId);
127
+ this.actionLog.append({
128
+ actionType: 'delete',
129
+ entityType: 'pipeline',
130
+ entityId: dataArg.pipelineId,
131
+ entityName: `Pipeline #${dataArg.pipelineId}`,
132
+ details: `Cancelled pipeline #${dataArg.pipelineId} in project ${dataArg.projectId}`,
133
+ username: dataArg.identity.username,
134
+ });
135
+ return { ok: true };
136
+ },
137
+ ),
138
+ );
139
+ }
140
+
141
+ // ---------------------------------------------------------------------------
142
+ // View mode helpers
143
+ // ---------------------------------------------------------------------------
144
+
145
+ /**
146
+ * Current mode: running/pending always shown, plus recent pipelines within timeRange.
147
+ * Fetches a generous page of recent pipelines per project (100), then splits into
148
+ * active (running/pending/waiting) and the rest. Active are always shown; the rest
149
+ * is filtered by timeRange.
150
+ */
151
+ private async fetchCurrentPipelines(
152
+ provider: BaseProvider,
153
+ timeRange: string,
154
+ ): Promise<interfaces.data.IPipeline[]> {
155
+ const projects = await provider.getProjects();
156
+ const allPipelines = await this.fetchAggregatedPipelines(provider, projects, { perPage: 100 });
157
+
158
+ // Running/pending pipelines are always shown regardless of time
159
+ const active = allPipelines.filter(
160
+ (p) => p.status === 'running' || p.status === 'pending' || p.status === 'waiting',
161
+ );
162
+ const rest = allPipelines.filter(
163
+ (p) => p.status !== 'running' && p.status !== 'pending' && p.status !== 'waiting',
164
+ );
165
+ const filteredRest = this.filterByTimeRange(rest, timeRange);
166
+
167
+ // Deduplicate (active pipelines may also appear in filtered rest)
168
+ const activeIds = new Set(active.map((p) => `${p.connectionId}:${p.projectId}:${p.id}`));
169
+ const uniqueRest = filteredRest.filter(
170
+ (p) => !activeIds.has(`${p.connectionId}:${p.projectId}:${p.id}`),
171
+ );
172
+
173
+ return [...active, ...uniqueRest];
174
+ }
175
+
176
+ /**
177
+ * Group mode: pipelines from all projects in a group
178
+ */
179
+ private async fetchGroupPipelines(
180
+ provider: BaseProvider,
181
+ groupId: string,
182
+ timeRange: string,
183
+ ): Promise<interfaces.data.IPipeline[]> {
184
+ const projects = await provider.getGroupProjects(groupId);
185
+ const allPipelines = await this.fetchAggregatedPipelines(provider, projects);
186
+ return this.filterByTimeRange(allPipelines, timeRange);
187
+ }
188
+
189
+ /**
190
+ * Error mode: only failed pipelines
191
+ */
192
+ private async fetchErrorPipelines(
193
+ provider: BaseProvider,
194
+ timeRange: string,
195
+ ): Promise<interfaces.data.IPipeline[]> {
196
+ const projects = await provider.getProjects();
197
+ const allPipelines = await this.fetchAggregatedPipelines(provider, projects, { status: 'failed' });
198
+ return this.filterByTimeRange(allPipelines, timeRange);
199
+ }
200
+
201
+ /**
202
+ * Fetch pipelines from multiple projects in parallel (batched)
203
+ */
204
+ private async fetchAggregatedPipelines(
205
+ provider: BaseProvider,
206
+ projects: interfaces.data.IProject[],
207
+ opts?: { status?: string; perPage?: number },
208
+ ): Promise<interfaces.data.IPipeline[]> {
209
+ const BATCH_SIZE = 10;
210
+ const perPage = opts?.perPage || 50;
211
+ const allPipelines: interfaces.data.IPipeline[] = [];
212
+
213
+ for (let i = 0; i < projects.length; i += BATCH_SIZE) {
214
+ const batch = projects.slice(i, i + BATCH_SIZE);
215
+ const results = await Promise.allSettled(
216
+ batch.map(async (project) => {
217
+ const pipelines = await provider.getPipelines(project.id, {
218
+ perPage,
219
+ status: opts?.status,
220
+ });
221
+ // Enrich with proper project name
222
+ return pipelines.map((p) => ({
223
+ ...p,
224
+ projectName: project.fullPath || project.name || p.projectId,
225
+ }));
226
+ }),
227
+ );
228
+ for (let j = 0; j < results.length; j++) {
229
+ const result = results[j];
230
+ if (result.status === 'fulfilled') {
231
+ allPipelines.push(...result.value);
232
+ } else {
233
+ const projectId = batch[j]?.id || 'unknown';
234
+ console.warn(`[PipelinesHandler] Failed to fetch pipelines for project ${projectId}: ${result.reason}`);
235
+ }
236
+ }
237
+ }
238
+
239
+ return allPipelines;
240
+ }
241
+
242
+ // ---------------------------------------------------------------------------
243
+ // Filtering and sorting
244
+ // ---------------------------------------------------------------------------
245
+
246
+ private filterByTimeRange(
247
+ pipelines: interfaces.data.IPipeline[],
248
+ timeRange: string,
249
+ ): interfaces.data.IPipeline[] {
250
+ const cutoffMs = TIME_RANGE_MS[timeRange] || TIME_RANGE_MS['1d'];
251
+ const cutoff = Date.now() - cutoffMs;
252
+ return pipelines.filter((p) => {
253
+ if (!p.createdAt) return false;
254
+ return new Date(p.createdAt).getTime() >= cutoff;
255
+ });
256
+ }
257
+
258
+ private sortPipelines(
259
+ pipelines: interfaces.data.IPipeline[],
260
+ sortBy: string,
261
+ ): interfaces.data.IPipeline[] {
262
+ const sorted = [...pipelines];
263
+ switch (sortBy) {
264
+ case 'duration':
265
+ sorted.sort((a, b) => (b.duration || 0) - (a.duration || 0));
266
+ break;
267
+ case 'status':
268
+ sorted.sort(
269
+ (a, b) => (STATUS_PRIORITY[a.status] ?? 99) - (STATUS_PRIORITY[b.status] ?? 99),
270
+ );
271
+ break;
272
+ case 'created':
273
+ default:
274
+ sorted.sort(
275
+ (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
276
+ );
277
+ break;
278
+ }
279
+ return sorted;
280
+ }
281
+ }