@serve.zone/gitops 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/changelog.md +17 -0
  2. package/deno.json +1 -1
  3. package/dist_serve/bundle.js +726 -694
  4. package/dist_ts/00_commitinfo_data.js +1 -1
  5. package/dist_ts/classes/connectionmanager.d.ts +5 -1
  6. package/dist_ts/classes/connectionmanager.js +62 -7
  7. package/dist_ts/classes/syncmanager.d.ts +40 -0
  8. package/dist_ts/classes/syncmanager.js +804 -111
  9. package/dist_ts/classes/syncpath.d.ts +13 -0
  10. package/dist_ts/classes/syncpath.js +53 -0
  11. package/dist_ts/opsserver/handlers/connections.handler.js +8 -2
  12. package/dist_ts/opsserver/handlers/sync.handler.js +5 -1
  13. package/dist_ts/providers/classes.baseprovider.d.ts +22 -0
  14. package/dist_ts/providers/classes.baseprovider.js +93 -1
  15. package/dist_ts/providers/classes.giteaprovider.d.ts +18 -1
  16. package/dist_ts/providers/classes.giteaprovider.js +236 -1
  17. package/dist_ts/providers/classes.gitlabprovider.d.ts +16 -1
  18. package/dist_ts/providers/classes.gitlabprovider.js +235 -1
  19. package/dist_ts_interfaces/data/artifact.d.ts +39 -0
  20. package/dist_ts_interfaces/data/artifact.js +2 -0
  21. package/dist_ts_interfaces/data/connection.d.ts +3 -0
  22. package/dist_ts_interfaces/data/index.d.ts +1 -0
  23. package/dist_ts_interfaces/data/index.js +2 -1
  24. package/dist_ts_interfaces/data/sync.d.ts +21 -0
  25. package/dist_ts_interfaces/requests/connections.d.ts +6 -0
  26. package/dist_ts_interfaces/requests/sync.d.ts +4 -0
  27. package/package.json +3 -3
  28. package/readme.md +8 -4
  29. package/ts/00_commitinfo_data.ts +1 -1
  30. package/ts/classes/connectionmanager.ts +61 -6
  31. package/ts/classes/syncmanager.ts +1095 -119
  32. package/ts/classes/syncpath.ts +71 -0
  33. package/ts/opsserver/handlers/connections.handler.ts +9 -0
  34. package/ts/opsserver/handlers/sync.handler.ts +4 -0
  35. package/ts/providers/classes.baseprovider.ts +137 -0
  36. package/ts/providers/classes.giteaprovider.ts +293 -1
  37. package/ts/providers/classes.gitlabprovider.ts +292 -1
  38. package/ts_interfaces/data/artifact.ts +43 -0
  39. package/ts_interfaces/data/connection.ts +3 -0
  40. package/ts_interfaces/data/index.ts +1 -0
  41. package/ts_interfaces/data/sync.ts +22 -0
  42. package/ts_interfaces/requests/connections.ts +6 -0
  43. package/ts_interfaces/requests/sync.ts +4 -0
  44. package/ts_web/00_commitinfo_data.ts +1 -1
  45. package/ts_web/appstate.ts +10 -0
  46. package/ts_web/elements/views/connections/index.ts +26 -0
  47. package/ts_web/elements/views/sync/index.ts +26 -4
@@ -8,6 +8,8 @@ const LEGACY_CONNECTIONS_FILE = './.nogit/connections.json';
8
8
  const CONNECTIONS_PREFIX = '/connections/';
9
9
  const KEYCHAIN_PREFIX = 'keychain:';
10
10
 
11
+ const getRegistryTokenSecretId = (connectionId: string): string => `${connectionId}:registry`;
12
+
11
13
  /**
12
14
  * Manages provider connections — persists each connection as an
13
15
  * individual JSON file via StorageManager. Tokens are stored in
@@ -98,6 +100,18 @@ export class ConnectionManager {
98
100
  // Plaintext token found — auto-migrate to keychain
99
101
  await this.migrateTokenToKeychain(conn);
100
102
  }
103
+ if (conn.registryToken?.startsWith(KEYCHAIN_PREFIX)) {
104
+ const registrySecretId = conn.registryToken.substring(KEYCHAIN_PREFIX.length);
105
+ const realRegistryToken = await this.smartSecret.getSecret(registrySecretId);
106
+ if (realRegistryToken) {
107
+ conn.registryToken = realRegistryToken;
108
+ } else {
109
+ logger.warn(`Could not retrieve registry token for connection ${conn.id} from keychain`);
110
+ conn.registryToken = undefined;
111
+ }
112
+ } else if (conn.registryToken && conn.registryToken !== '***') {
113
+ await this.migrateRegistryTokenToKeychain(conn);
114
+ }
101
115
  this.connections.push(conn);
102
116
  }
103
117
  }
@@ -125,21 +139,53 @@ export class ConnectionManager {
125
139
  }
126
140
  }
127
141
 
142
+ private async migrateRegistryTokenToKeychain(
143
+ conn: interfaces.data.IProviderConnection,
144
+ ): Promise<void> {
145
+ try {
146
+ const secretId = getRegistryTokenSecretId(conn.id);
147
+ await this.smartSecret.setSecret(secretId, conn.registryToken!);
148
+ const jsonConn = {
149
+ ...conn,
150
+ token: `${KEYCHAIN_PREFIX}${conn.id}`,
151
+ registryToken: `${KEYCHAIN_PREFIX}${secretId}`,
152
+ };
153
+ await this.storageManager.setJSON(`${CONNECTIONS_PREFIX}${conn.id}.json`, jsonConn);
154
+ logger.info(`Migrated registry token for connection "${conn.name}" to keychain`);
155
+ } catch (err) {
156
+ logger.warn(`Failed to migrate registry token for ${conn.id} to keychain: ${err}`);
157
+ }
158
+ }
159
+
128
160
  private async persistConnection(conn: interfaces.data.IProviderConnection): Promise<void> {
129
161
  // Store real token in keychain
130
162
  await this.smartSecret.setSecret(conn.id, conn.token);
163
+ if (conn.registryToken) {
164
+ await this.smartSecret.setSecret(getRegistryTokenSecretId(conn.id), conn.registryToken);
165
+ } else {
166
+ await this.smartSecret.deleteSecret(getRegistryTokenSecretId(conn.id));
167
+ }
131
168
  // Save JSON with sentinel value
132
- const jsonConn = { ...conn, token: `${KEYCHAIN_PREFIX}${conn.id}` };
169
+ const jsonConn = {
170
+ ...conn,
171
+ token: `${KEYCHAIN_PREFIX}${conn.id}`,
172
+ registryToken: conn.registryToken ? `${KEYCHAIN_PREFIX}${getRegistryTokenSecretId(conn.id)}` : undefined,
173
+ };
133
174
  await this.storageManager.setJSON(`${CONNECTIONS_PREFIX}${conn.id}.json`, jsonConn);
134
175
  }
135
176
 
136
177
  private async removeConnection(id: string): Promise<void> {
137
178
  await this.smartSecret.deleteSecret(id);
179
+ await this.smartSecret.deleteSecret(getRegistryTokenSecretId(id));
138
180
  await this.storageManager.delete(`${CONNECTIONS_PREFIX}${id}.json`);
139
181
  }
140
182
 
141
183
  getConnections(): interfaces.data.IProviderConnection[] {
142
- return this.connections.map((c) => ({ ...c, token: '***' }));
184
+ return this.connections.map((c) => ({
185
+ ...c,
186
+ token: '***',
187
+ registryToken: c.registryToken ? '***' : undefined,
188
+ }));
143
189
  }
144
190
 
145
191
  getConnection(id: string): interfaces.data.IProviderConnection | undefined {
@@ -152,6 +198,9 @@ export class ConnectionManager {
152
198
  baseUrl: string,
153
199
  token: string,
154
200
  groupFilter?: string,
201
+ registryUrl?: string,
202
+ registryUsername?: string,
203
+ registryToken?: string,
155
204
  ): Promise<interfaces.data.IProviderConnection> {
156
205
  const connection: interfaces.data.IProviderConnection = {
157
206
  id: crypto.randomUUID(),
@@ -162,16 +211,19 @@ export class ConnectionManager {
162
211
  createdAt: Date.now(),
163
212
  status: 'disconnected',
164
213
  groupFilter: groupFilter || undefined,
214
+ registryUrl: registryUrl || undefined,
215
+ registryUsername: registryUsername || undefined,
216
+ registryToken: registryToken || undefined,
165
217
  };
166
218
  this.connections.push(connection);
167
219
  await this.persistConnection(connection);
168
220
  logger.success(`Connection created: ${name} (${providerType})`);
169
- return { ...connection, token: '***' };
221
+ return { ...connection, token: '***', registryToken: connection.registryToken ? '***' : undefined };
170
222
  }
171
223
 
172
224
  async updateConnection(
173
225
  id: string,
174
- updates: { name?: string; baseUrl?: string; token?: string; groupFilter?: string },
226
+ updates: { name?: string; baseUrl?: string; token?: string; groupFilter?: string; registryUrl?: string; registryUsername?: string; registryToken?: string },
175
227
  ): Promise<interfaces.data.IProviderConnection> {
176
228
  const conn = this.connections.find((c) => c.id === id);
177
229
  if (!conn) throw new Error(`Connection not found: ${id}`);
@@ -182,8 +234,11 @@ export class ConnectionManager {
182
234
  conn.groupFilter = updates.groupFilter || undefined;
183
235
  conn.groupFilterId = undefined; // Will be re-resolved on next test
184
236
  }
237
+ if (updates.registryUrl !== undefined) conn.registryUrl = updates.registryUrl || undefined;
238
+ if (updates.registryUsername !== undefined) conn.registryUsername = updates.registryUsername || undefined;
239
+ if (updates.registryToken !== undefined) conn.registryToken = updates.registryToken || undefined;
185
240
  await this.persistConnection(conn);
186
- return { ...conn, token: '***' };
241
+ return { ...conn, token: '***', registryToken: conn.registryToken ? '***' : undefined };
187
242
  }
188
243
 
189
244
  async deleteConnection(id: string): Promise<void> {
@@ -200,7 +255,7 @@ export class ConnectionManager {
200
255
  conn.status = paused ? 'paused' : 'disconnected';
201
256
  await this.persistConnection(conn);
202
257
  logger.info(`Connection ${paused ? 'paused' : 'resumed'}: ${conn.name}`);
203
- return { ...conn, token: '***' };
258
+ return { ...conn, token: '***', registryToken: conn.registryToken ? '***' : undefined };
204
259
  }
205
260
 
206
261
  async testConnection(id: string): Promise<{ ok: boolean; error?: string }> {