@foss.global/gitmanager 1.5.0 → 1.7.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.
package/ts/models.ts CHANGED
@@ -75,6 +75,10 @@ export interface IGitManagerRepositoryArchiveRequest
75
75
  objectId: string;
76
76
  }
77
77
 
78
+ export interface IGitManagerRepositoryArchiveOptions {
79
+ signal?: AbortSignal;
80
+ }
81
+
78
82
  export interface IGitManagerRepositoryArchive
79
83
  extends IGitManagerRepositorySelector {
80
84
  objectId: string;
@@ -182,6 +186,32 @@ export interface IGitManagerStatus {
182
186
  smartHttp?: IGitManagerSmartHttpStatus;
183
187
  }
184
188
 
189
+ export interface IGitManagerReadinessOptions {
190
+ timeoutMs?: number;
191
+ signal?: AbortSignal;
192
+ }
193
+
194
+ export type TGitManagerReadinessFailureReason =
195
+ | 'not_running'
196
+ | 'starting'
197
+ | 'stopping'
198
+ | 'aborted'
199
+ | 'timeout'
200
+ | 'unavailable';
201
+
202
+ export type TGitManagerReadinessResult =
203
+ | {
204
+ ready: true;
205
+ status: 'ready';
206
+ durationMs: number;
207
+ }
208
+ | {
209
+ ready: false;
210
+ status: 'unavailable';
211
+ reason: TGitManagerReadinessFailureReason;
212
+ durationMs: number;
213
+ };
214
+
185
215
  export type {
186
216
  IGitManagerCommitDetail,
187
217
  IGitManagerCommitRequest,
package/ts/plugins.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  // node native scope
2
2
  import * as childProcess from 'node:child_process';
3
+ import * as crypto from 'node:crypto';
3
4
  import { EventEmitter } from 'node:events';
5
+ import * as http from 'node:http';
4
6
  import * as path from 'node:path';
5
7
  import * as stream from 'node:stream';
6
8
  import * as url from 'node:url';
7
9
 
8
- export { childProcess, EventEmitter, path, stream, url };
10
+ export { childProcess, crypto, EventEmitter, http, path, stream, url };
9
11
 
10
12
  // @push.rocks scope
11
13
  import * as smartrust from '@push.rocks/smartrust';
@@ -19,6 +19,7 @@ import type {
19
19
  IGitManagerSmartHttpRepositoryProtectedRefs,
20
20
  IGitManagerRepositoryBundle,
21
21
  IGitManagerRepositoryArchive,
22
+ IGitManagerRepositoryArchiveOptions,
22
23
  IGitManagerRepositoryArchiveRequest,
23
24
  IGitManagerRepositoryLfsPointer,
24
25
  IGitManagerRepositoryServiceRequest,
@@ -36,6 +37,21 @@ import type {
36
37
  IRustGitManagerRepositoryServiceDescriptor,
37
38
  } from './models.js';
38
39
 
40
+ type TRepositoryArchiveCancelStatus =
41
+ | 'cancelled'
42
+ | 'completed'
43
+ | 'failed'
44
+ | 'not_found';
45
+
46
+ interface IRepositoryArchiveOperationRequest {
47
+ operationId: string;
48
+ request: IGitManagerRepositoryArchiveRequest;
49
+ }
50
+
51
+ interface IRepositoryArchiveCancelRequest {
52
+ operationId: string;
53
+ }
54
+
39
55
  type TGitManagerCommands = {
40
56
  start: { params: { config: IRustGitManagerConfig }; result: Record<string, never> };
41
57
  stop: { params: Record<string, never>; result: Record<string, never> };
@@ -48,7 +64,8 @@ type TGitManagerCommands = {
48
64
  refreshMirror: { params: IGitManagerRepositorySelector; result: IGitManagerRepositoryInfo };
49
65
  verifyRepository: { params: IGitManagerRepositorySelector; result: IGitManagerRepositoryInfo };
50
66
  createRepositoryBundle: { params: IGitManagerRepositorySelector; result: IGitManagerRepositoryBundle };
51
- createRepositoryArchive: { params: IGitManagerRepositoryArchiveRequest; result: IGitManagerRepositoryArchive };
67
+ createRepositoryArchive: { params: IRepositoryArchiveOperationRequest; result: IGitManagerRepositoryArchive };
68
+ cancelRepositoryArchive: { params: IRepositoryArchiveCancelRequest; result: { status: TRepositoryArchiveCancelStatus } };
52
69
  prepareRepositoryService: { params: IGitManagerRepositoryServiceRequest; result: IRustGitManagerRepositoryServiceDescriptor };
53
70
  restoreRepositoryBundle: { params: IGitManagerRestoreBundleRequest; result: IGitManagerRepositoryInfo };
54
71
  listRepositories: { params: Record<string, never>; result: IGitManagerRepositoryInfo[] };
@@ -122,6 +139,10 @@ export class RustGitManagerBridge extends plugins.EventEmitter {
122
139
  this.bridge.kill();
123
140
  }
124
141
 
142
+ public async terminate(): Promise<void> {
143
+ await this.bridge.terminate();
144
+ }
145
+
125
146
  public get running(): boolean {
126
147
  return this.bridge.running;
127
148
  }
@@ -134,8 +155,10 @@ export class RustGitManagerBridge extends plugins.EventEmitter {
134
155
  await this.bridge.sendCommand('stop', {});
135
156
  }
136
157
 
137
- public async getStatus(): Promise<IGitManagerStatus> {
138
- return this.bridge.sendCommand('getStatus', {});
158
+ public async getStatus(
159
+ optionsArg?: plugins.smartrust.IRustBridgeRequestOptions,
160
+ ): Promise<IGitManagerStatus> {
161
+ return this.bridge.sendCommand('getStatus', {}, optionsArg);
139
162
  }
140
163
 
141
164
  public async setSmartHttpRepositoryAccess(accessArg: IGitManagerSmartHttpRepositoryAccess): Promise<void> {
@@ -181,10 +204,52 @@ export class RustGitManagerBridge extends plugins.EventEmitter {
181
204
 
182
205
  public async createRepositoryArchive(
183
206
  requestArg: IGitManagerRepositoryArchiveRequest,
207
+ optionsArg: IGitManagerRepositoryArchiveOptions = {},
184
208
  ): Promise<IGitManagerRepositoryArchive> {
185
- const result = await this.bridge.sendCommand('createRepositoryArchive', requestArg, {
209
+ if (optionsArg.signal?.aborted) {
210
+ throw optionsArg.signal.reason ?? new Error('Repository archive creation was aborted.');
211
+ }
212
+ const operationId = plugins.crypto.randomUUID();
213
+ const archivePromise = this.bridge.sendCommand('createRepositoryArchive', {
214
+ operationId,
215
+ request: requestArg,
216
+ }, {
186
217
  timeoutMs: 65 * 60 * 1000,
187
218
  });
219
+ let cancelPromise:
220
+ | Promise<{ status: TRepositoryArchiveCancelStatus }>
221
+ | undefined;
222
+ const cancelArchive = (): void => {
223
+ cancelPromise ??= this.bridge.sendCommand('cancelRepositoryArchive', {
224
+ operationId,
225
+ }, {
226
+ timeoutMs: 65 * 60 * 1000,
227
+ });
228
+ };
229
+ optionsArg.signal?.addEventListener('abort', cancelArchive, { once: true });
230
+ if (optionsArg.signal?.aborted) {
231
+ cancelArchive();
232
+ }
233
+
234
+ let result: IGitManagerRepositoryArchive;
235
+ try {
236
+ result = await archivePromise;
237
+ if (cancelPromise) {
238
+ await cancelPromise.catch(() => undefined);
239
+ }
240
+ } catch (archiveError) {
241
+ if (!cancelPromise) {
242
+ throw archiveError;
243
+ }
244
+ const cancellation = await cancelPromise;
245
+ if (cancellation.status === 'cancelled') {
246
+ throw optionsArg.signal?.reason
247
+ ?? new Error('Repository archive creation was aborted.');
248
+ }
249
+ throw archiveError;
250
+ } finally {
251
+ optionsArg.signal?.removeEventListener('abort', cancelArchive);
252
+ }
188
253
  for (const [field, value] of [
189
254
  ['sizeBytes', result.sizeBytes],
190
255
  ['extractedSizeBytes', result.extractedSizeBytes],