@foss.global/codefeed 4.1.0 → 4.3.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.
@@ -0,0 +1,75 @@
1
+ import * as plugins from './plugins.js';
2
+ import * as validation from './forgeinventory.validation.js';
3
+ /**
4
+ * Reads and drops at most 64 KiB of a response body that carries nothing the
5
+ * caller uses, so its connection can be reused; a longer or failing body is
6
+ * discarded with its connection.
7
+ */
8
+ export declare const discardBody: (bodyArg: AsyncIterable<Uint8Array> | null) => Promise<void>;
9
+ export interface ITransferBoundsOptions {
10
+ /** Wall-clock limit of the whole transfer. */
11
+ limitMs: number;
12
+ /** Longest gap between two chunks of a watched source. */
13
+ idleMs: number;
14
+ /** The code a passed wall-clock or idle limit fails with. */
15
+ timedOutCode: string;
16
+ /** The code a watched source that goes on after the transfer ended fails with. */
17
+ failedCode: string;
18
+ }
19
+ export interface ITransferBounds {
20
+ /** Aborts once the caller aborts, a limit passes or the transfer ends. */
21
+ signal: AbortSignal;
22
+ /** Ends the transfer: clears its timers and aborts `signal`. Idempotent. */
23
+ end: () => void;
24
+ /**
25
+ * The error the transfer fails with: the reason that ended it (`request-aborted`
26
+ * or the timeout code), else `errorArg` when it is a `ForgeInventoryError`,
27
+ * else `fallbackArg`.
28
+ */
29
+ failure: (errorArg: unknown, fallbackArg: string) => validation.ForgeInventoryError;
30
+ /** Runs one step of the transfer; it rejects as soon as the transfer ends, even if the step does not. */
31
+ run: <T>(stepArg: () => Promise<T>) => Promise<T>;
32
+ /** Re-arms the idle limit, before a step that waits on the network without a watched source. */
33
+ touch: () => void;
34
+ /** Passes chunks on and re-arms the idle limit on each one. */
35
+ watch: (sourceArg: AsyncIterable<Uint8Array>) => AsyncGenerator<Uint8Array, void, undefined>;
36
+ }
37
+ /**
38
+ * The bounds of one streamed transfer: the caller's signal, a wall-clock limit
39
+ * and an idle limit that `watch` re-arms on every chunk. Whichever ends it
40
+ * first decides the failure code. Every transfer must be ended with `end`.
41
+ */
42
+ export declare const createTransferBounds: (signalArg: AbortSignal | undefined, optionsArg: ITransferBoundsOptions) => ITransferBounds;
43
+ export interface IHeldBackCodes {
44
+ /** A chunk that is not a `Uint8Array`. */
45
+ invalidChunk: string;
46
+ /** More bytes than the declared size. */
47
+ overrun: string;
48
+ /** Fewer bytes than the declared size. */
49
+ short: string;
50
+ }
51
+ export interface IHeldBackChecks {
52
+ /** Sees every non-empty chunk in order, before it is passed on. */
53
+ inspect?: (chunkArg: Uint8Array) => void;
54
+ /** Runs once exactly `size` bytes have arrived, before the last chunk is passed on; a rejection keeps it back. */
55
+ complete?: () => void | Promise<void>;
56
+ }
57
+ /**
58
+ * Passes the bytes of `sourceArg` on while it counts them. The last chunk is
59
+ * held back until the source has ended with exactly `sizeArg` bytes and
60
+ * `checksArg.complete` has passed, so a consumer never receives a complete
61
+ * body that is wrong; otherwise it throws `codesArg.overrun` as soon as the
62
+ * size is exceeded, `codesArg.short` when the source ends early, or what
63
+ * `complete` threw.
64
+ */
65
+ export declare function heldBackChunks(sourceArg: AsyncIterable<Uint8Array>, sizeArg: number, codesArg: IHeldBackCodes, checksArg?: IHeldBackChecks): AsyncGenerator<Uint8Array, void, undefined>;
66
+ /**
67
+ * The readable stream of one transfer's bytes. It pulls `chunksArg` with
68
+ * backpressure and ends `boundsArg` and calls `onEndArg` as soon as it is
69
+ * destroyed, also while a pull is pending: ending the bounds aborts the
70
+ * request, which closes its connection, and the pending pull's result is
71
+ * dropped. (`Readable.from` waits for a pending pull before it finishes a
72
+ * destroy, so a stalled body would keep its connection until the idle limit.)
73
+ * The stream errors with what `chunksArg` throws.
74
+ */
75
+ export declare const createTransferStream: (boundsArg: ITransferBounds, chunksArg: AsyncGenerator<Uint8Array, void, undefined>, onEndArg?: () => void) => InstanceType<typeof plugins.stream.Readable>;
@@ -0,0 +1,174 @@
1
+ import * as plugins from './plugins.js';
2
+ import * as validation from './forgeinventory.validation.js';
3
+ /** Response bytes read from an unused answer before the rest is discarded. */
4
+ const maxDiscardedResponseBytes = 64 * 1024;
5
+ /**
6
+ * Reads and drops at most 64 KiB of a response body that carries nothing the
7
+ * caller uses, so its connection can be reused; a longer or failing body is
8
+ * discarded with its connection.
9
+ */
10
+ export const discardBody = async (bodyArg) => {
11
+ if (!bodyArg)
12
+ return;
13
+ const chunks = bodyArg[Symbol.asyncIterator]();
14
+ let bytes = 0;
15
+ try {
16
+ while (bytes <= maxDiscardedResponseBytes) {
17
+ const result = await chunks.next();
18
+ if (result.done)
19
+ return;
20
+ bytes += result.value.byteLength;
21
+ }
22
+ }
23
+ catch {
24
+ // The status already decided the outcome.
25
+ }
26
+ finally {
27
+ try {
28
+ await chunks.return?.();
29
+ }
30
+ catch { /* The connection is discarded. */ }
31
+ }
32
+ };
33
+ /**
34
+ * The bounds of one streamed transfer: the caller's signal, a wall-clock limit
35
+ * and an idle limit that `watch` re-arms on every chunk. Whichever ends it
36
+ * first decides the failure code. Every transfer must be ended with `end`.
37
+ */
38
+ export const createTransferBounds = (signalArg, optionsArg) => {
39
+ const controller = new AbortController();
40
+ let reason = null;
41
+ const stop = (reasonArg) => {
42
+ reason ??= reasonArg;
43
+ controller.abort();
44
+ };
45
+ const abort = () => stop('request-aborted');
46
+ if (signalArg?.aborted)
47
+ abort();
48
+ signalArg?.addEventListener('abort', abort, { once: true });
49
+ const deadline = setTimeout(() => stop(optionsArg.timedOutCode), optionsArg.limitMs);
50
+ let idle;
51
+ const rearm = () => {
52
+ clearTimeout(idle);
53
+ if (!controller.signal.aborted)
54
+ idle = setTimeout(() => stop(optionsArg.timedOutCode), optionsArg.idleMs);
55
+ };
56
+ rearm();
57
+ const end = () => {
58
+ clearTimeout(deadline);
59
+ clearTimeout(idle);
60
+ signalArg?.removeEventListener('abort', abort);
61
+ stop('transfer-ended');
62
+ };
63
+ const failure = (errorArg, fallbackArg) => {
64
+ if (reason !== null && reason !== 'transfer-ended')
65
+ return new validation.ForgeInventoryError(reason);
66
+ return errorArg instanceof validation.ForgeInventoryError ? errorArg : new validation.ForgeInventoryError(fallbackArg);
67
+ };
68
+ return {
69
+ signal: controller.signal,
70
+ end,
71
+ failure,
72
+ touch: rearm,
73
+ run: async (stepArg) => {
74
+ if (controller.signal.aborted)
75
+ throw failure(undefined, 'request-aborted');
76
+ let onAbort;
77
+ const aborted = new Promise((_resolve, reject) => {
78
+ onAbort = () => reject(failure(undefined, 'request-aborted'));
79
+ controller.signal.addEventListener('abort', onAbort, { once: true });
80
+ });
81
+ try {
82
+ return await Promise.race([stepArg(), aborted]);
83
+ }
84
+ finally {
85
+ controller.signal.removeEventListener('abort', onAbort);
86
+ }
87
+ },
88
+ watch: async function* (sourceArg) {
89
+ for await (const chunk of sourceArg) {
90
+ if (controller.signal.aborted)
91
+ throw failure(undefined, optionsArg.failedCode);
92
+ rearm();
93
+ yield chunk;
94
+ }
95
+ },
96
+ };
97
+ };
98
+ /**
99
+ * Passes the bytes of `sourceArg` on while it counts them. The last chunk is
100
+ * held back until the source has ended with exactly `sizeArg` bytes and
101
+ * `checksArg.complete` has passed, so a consumer never receives a complete
102
+ * body that is wrong; otherwise it throws `codesArg.overrun` as soon as the
103
+ * size is exceeded, `codesArg.short` when the source ends early, or what
104
+ * `complete` threw.
105
+ */
106
+ export async function* heldBackChunks(sourceArg, sizeArg, codesArg, checksArg = {}) {
107
+ let bytes = 0;
108
+ let held = null;
109
+ for await (const chunk of sourceArg) {
110
+ if (!(chunk instanceof Uint8Array))
111
+ throw new validation.ForgeInventoryError(codesArg.invalidChunk);
112
+ if (chunk.byteLength === 0)
113
+ continue;
114
+ bytes += chunk.byteLength;
115
+ if (bytes > sizeArg)
116
+ throw new validation.ForgeInventoryError(codesArg.overrun);
117
+ checksArg.inspect?.(chunk);
118
+ if (held)
119
+ yield held;
120
+ held = chunk;
121
+ }
122
+ if (bytes !== sizeArg)
123
+ throw new validation.ForgeInventoryError(codesArg.short);
124
+ await checksArg.complete?.();
125
+ if (held)
126
+ yield held;
127
+ }
128
+ /**
129
+ * The readable stream of one transfer's bytes. It pulls `chunksArg` with
130
+ * backpressure and ends `boundsArg` and calls `onEndArg` as soon as it is
131
+ * destroyed, also while a pull is pending: ending the bounds aborts the
132
+ * request, which closes its connection, and the pending pull's result is
133
+ * dropped. (`Readable.from` waits for a pending pull before it finishes a
134
+ * destroy, so a stalled body would keep its connection until the idle limit.)
135
+ * The stream errors with what `chunksArg` throws.
136
+ */
137
+ export const createTransferStream = (boundsArg, chunksArg, onEndArg) => {
138
+ let pulling = false;
139
+ const stream = new plugins.stream.Readable({
140
+ read() {
141
+ if (pulling)
142
+ return;
143
+ pulling = true;
144
+ void (async () => {
145
+ try {
146
+ while (!stream.destroyed) {
147
+ const result = await chunksArg.next();
148
+ if (stream.destroyed)
149
+ return;
150
+ if (result.done)
151
+ return void stream.push(null);
152
+ if (!stream.push(result.value))
153
+ return;
154
+ }
155
+ }
156
+ catch (error) {
157
+ stream.destroy(error);
158
+ }
159
+ finally {
160
+ pulling = false;
161
+ }
162
+ })();
163
+ },
164
+ destroy(errorArg, callbackArg) {
165
+ boundsArg.end();
166
+ onEndArg?.();
167
+ // Runs the generator's cleanup once a pending pull has settled; nothing waits for it.
168
+ chunksArg.return(undefined).catch(() => undefined);
169
+ callbackArg(errorArg);
170
+ },
171
+ });
172
+ return stream;
173
+ };
174
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yZ2VpbnZlbnRvcnkudHJhbnNmZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9mb3JnZWludmVudG9yeS50cmFuc2Zlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEtBQUssVUFBVSxNQUFNLGdDQUFnQyxDQUFDO0FBRTdELDhFQUE4RTtBQUM5RSxNQUFNLHlCQUF5QixHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFFNUM7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLFdBQVcsR0FBRyxLQUFLLEVBQUUsT0FBeUMsRUFBaUIsRUFBRTtJQUM1RixJQUFJLENBQUMsT0FBTztRQUFFLE9BQU87SUFDckIsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDO0lBQy9DLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztJQUNkLElBQUksQ0FBQztRQUNILE9BQU8sS0FBSyxJQUFJLHlCQUF5QixFQUFFLENBQUM7WUFDMUMsTUFBTSxNQUFNLEdBQUcsTUFBTSxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDbkMsSUFBSSxNQUFNLENBQUMsSUFBSTtnQkFBRSxPQUFPO1lBQ3hCLEtBQUssSUFBSSxNQUFNLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQztRQUNuQyxDQUFDO0lBQ0gsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLDBDQUEwQztJQUM1QyxDQUFDO1lBQVMsQ0FBQztRQUNULElBQUksQ0FBQztZQUFDLE1BQU0sTUFBTSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7UUFBQyxDQUFDO1FBQUMsTUFBTSxDQUFDLENBQUMsa0NBQWtDLENBQUMsQ0FBQztJQUMvRSxDQUFDO0FBQ0gsQ0FBQyxDQUFDO0FBZ0NGOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxDQUFDLFNBQWtDLEVB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
@@ -3,11 +3,16 @@ import type { ForgeRequestClient } from './forgeinventory.client.js';
3
3
  type IGitCounts = Omit<plugins.fossInterfaces.data.IForgeSourceGitCounts, 'reportedSizeKiB'>;
4
4
  type ILfsCounts = plugins.fossInterfaces.data.IForgeSourceLfsCounts;
5
5
  type IHead = plugins.fossInterfaces.data.IForgeSourceRepositoryHead;
6
- /** The Git level measure of one repository; `head` is null when the mirror's refs could not be read. */
6
+ type IRefDigests = plugins.fossInterfaces.data.IForgeSourceRefDigests;
7
+ /**
8
+ * The Git level measure of one repository; `head` and `refDigests` are null
9
+ * when the mirror's refs could not be read.
10
+ */
7
11
  export interface IGiteaMirrorMeasure {
8
12
  git: IGitCounts;
9
13
  lfs: ILfsCounts;
10
14
  head: IHead | null;
15
+ refDigests: IRefDigests | null;
11
16
  }
12
17
  export interface IGiteaMirrorSource {
13
18
  /** Instance root without a trailing slash. */
@@ -78,6 +83,16 @@ export declare const giteaCloneUrl: (baseUrlArg: string, ownerArg: string, nameA
78
83
  * repository too large for it fails with `git-workdir-too-small`.
79
84
  */
80
85
  export declare const measureGiteaMirror: (sourceArg: IGiteaMirrorSource) => Promise<IGiteaMirrorMeasure>;
86
+ /**
87
+ * Reads GitManager's ref inventory digest and ref count of each namespace in
88
+ * `refDigestPrefixes`: one `listRefs` page of a single ref per prefix, whose
89
+ * digest and count cover the complete selection. Resolves with null when any
90
+ * read fails, never with a partial set.
91
+ */
92
+ export declare const readRefDigests: (managerArg: Pick<plugins.TGitManager, 'listRefs'>, selectorArg: {
93
+ org: string;
94
+ repo: string;
95
+ }) => Promise<IRefDigests | null>;
81
96
  /**
82
97
  * Asks Gitea's LFS batch API, as a `download`, which referenced objects it
83
98
  * holds: a held object answers with a download action, a missing one with
@@ -167,7 +167,7 @@ export const measureGiteaMirror = async (sourceArg) => {
167
167
  }
168
168
  catch (error) {
169
169
  const failure = stepFailure(error, 'git-workdir-failed', signal);
170
- return { git: failedGit(failure), lfs: failedLfs(failure), head: null };
170
+ return { git: failedGit(failure), lfs: failedLfs(failure), head: null, refDigests: null };
171
171
  }
172
172
  try {
173
173
  return await measureReservedMirror(sourceArg);
@@ -184,7 +184,7 @@ const measureReservedMirror = async (sourceArg) => {
184
184
  directory = await plugins.fs.mkdtemp(plugins.path.join(sourceArg.workDir, 'mirror-'));
185
185
  }
186
186
  catch {
187
- return { git: failedGit('git-workdir-failed'), lfs: failedLfs('git-workdir-failed'), head: null };
187
+ return { git: failedGit('git-workdir-failed'), lfs: failedLfs('git-workdir-failed'), head: null, refDigests: null };
188
188
  }
189
189
  const manager = new GitManager({ dataDir: directory });
190
190
  // The engine serves this measurement alone; stopping it ends the ref, object
@@ -207,17 +207,17 @@ const measureReservedMirror = async (sourceArg) => {
207
207
  }
208
208
  catch (error) {
209
209
  const failure = stepFailure(error, 'git-mirror-failed', signal);
210
- return { git: failedGit(failure), lfs: failedLfs(failure), head: null };
210
+ return { git: failedGit(failure), lfs: failedLfs(failure), head: null, refDigests: null };
211
211
  }
212
- const { git, head } = await measureRefsAndObjects(manager, selector, signal);
212
+ const { git, head, refDigests } = await measureRefsAndObjects(manager, selector, signal);
213
213
  let pointers;
214
214
  try {
215
215
  pointers = await manager.listRepositoryLfsPointers(selector);
216
216
  }
217
217
  catch (error) {
218
- return { git, lfs: failedLfs(stepFailure(error, 'lfs-pointer-scan-failed', signal)), head };
218
+ return { git, lfs: failedLfs(stepFailure(error, 'lfs-pointer-scan-failed', signal)), head, refDigests };
219
219
  }
220
- return { git, lfs: await giteaLfsPresence(sourceArg, pointers), head };
220
+ return { git, lfs: await giteaLfsPresence(sourceArg, pointers), head, refDigests };
221
221
  }
222
222
  finally {
223
223
  signal?.removeEventListener('abort', abort);
@@ -225,6 +225,30 @@ const measureReservedMirror = async (sourceArg) => {
225
225
  await plugins.fs.rm(directory, { recursive: true, force: true });
226
226
  }
227
227
  };
228
+ /** The ref namespaces an import carries, each recorded with its own digest. */
229
+ const refDigestPrefixes = { heads: 'refs/heads/', tags: 'refs/tags/', notes: 'refs/notes/' };
230
+ /**
231
+ * Reads GitManager's ref inventory digest and ref count of each namespace in
232
+ * `refDigestPrefixes`: one `listRefs` page of a single ref per prefix, whose
233
+ * digest and count cover the complete selection. Resolves with null when any
234
+ * read fails, never with a partial set.
235
+ */
236
+ export const readRefDigests = async (managerArg, selectorArg) => {
237
+ const read = async (prefixArg) => {
238
+ const page = await managerArg.listRefs({ ...selectorArg, prefixes: [prefixArg], limit: 1 });
239
+ // Only a cursor can be stale, and a first page sends none.
240
+ return page.status === 'page' ? { inventoryDigest: page.inventoryDigest, refCount: page.refCount } : null;
241
+ };
242
+ try {
243
+ const heads = await read(refDigestPrefixes.heads);
244
+ const tags = await read(refDigestPrefixes.tags);
245
+ const notes = await read(refDigestPrefixes.notes);
246
+ return heads && tags && notes ? { heads, tags, notes } : null;
247
+ }
248
+ catch {
249
+ return null;
250
+ }
251
+ };
228
252
  const measureRefsAndObjects = async (managerArg, selectorArg, signalArg) => {
229
253
  const counts = { branches: 0, tags: 0, pullRequestRefs: 0, otherRefs: 0 };
230
254
  let head = null;
@@ -256,6 +280,8 @@ const measureRefsAndObjects = async (managerArg, selectorArg, signalArg) => {
256
280
  refsFailure = stepFailure(error, 'git-refs-failed', signalArg);
257
281
  }
258
282
  const refs = (valueArg) => refsFailure === null ? complete(valueArg) : partial(0, refsFailure);
283
+ // Nothing writes to the private mirror, so the digests describe the refs just counted.
284
+ const refDigests = refsFailure === null ? await readRefDigests(managerArg, selectorArg) : null;
259
285
  let objects;
260
286
  let objectBytes;
261
287
  try {
@@ -272,6 +298,7 @@ const measureRefsAndObjects = async (managerArg, selectorArg, signalArg) => {
272
298
  objects, objectBytes,
273
299
  },
274
300
  head,
301
+ refDigests,
275
302
  };
276
303
  };
277
304
  /**
@@ -323,4 +350,4 @@ export const giteaLfsPresence = async (sourceArg, pointersArg) => {
323
350
  }
324
351
  return { objects: complete(held), bytes: complete(heldBytes), missingObjects: complete(missing) };
325
352
  };
326
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2l0ZWFzb3VyY2VpbnZlbnRvcnkuZ2l0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvZ2l0ZWFzb3VyY2VpbnZlbnRvcnkuZ2l0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sS0FBSyxVQUFVLE1BQU0sZ0NBQWdDLENBQUM7QUFtQzdELHFDQUFxQztBQUNyQyxNQUFNLFlBQVksR0FBRyxHQUFHLENBQUM7QUFDekIsTUFBTSxZQUFZLEdBQUcsOEJBQThCLENBQUM7QUFFcEQ7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLENBQUMsa0JBQTBCLEVBQVUsRUFBRSxDQUFDLGtCQUFrQixHQUFHLEtBQUssR0FBRyxFQUFFLEdBQUcsR0FBRyxHQUFHLEtBQUssR0FBRyxLQUFLLENBQUM7QUFFaEksK0ZBQStGO0FBQy9GLE1BQU0sZUFBZSxHQUFHLEtBQUssRUFBRSxZQUFvQixFQUFtQixFQUFFO0lBQ3RFLE1BQU0sS0FBSyxHQUFHLE1BQU0sT0FBTyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsWUFBWSxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDdEUsT0FBTyxLQUFLLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUM7QUFDcEMsQ0FBQyxDQUFDO0FBRUY7Ozs7Ozs7R0FPRztBQUNILE1BQU0sT0FBTyxnQkFBZ0I7SUFDbEIsVUFBVSxDQUE0QztJQUMvRCxTQUFTLEdBQUcsRUFBRSxDQUFDO0lBQ2YsdUZBQXVGO0lBQ3ZGLE1BQU0sR0FBa0IsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2pDLGlCQUFpQixHQUFHLElBQUksR0FBRyxFQUFjLENBQUM7SUFFbkQsWUFBWSxZQUFZLEdBQThDLGVBQWU7UUFDbkYsSUFBSSxDQUFDLFVBQVUsR0FBRyxZQUFZLENBQUM7SUFDakMsQ0FBQztJ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
353
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2l0ZWFzb3VyY2VpbnZlbnRvcnkuZ2l0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvZ2l0ZWFzb3VyY2VpbnZlbnRvcnkuZ2l0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sS0FBSyxVQUFVLE1BQU0sZ0NBQWdDLENBQUM7QUF3QzdELHFDQUFxQztBQUNyQyxNQUFNLFlBQVksR0FBRyxHQUFHLENBQUM7QUFDekIsTUFBTSxZQUFZLEdBQUcsOEJBQThCLENBQUM7QUFFcEQ7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLENBQUMsa0JBQTBCLEVBQVUsRUFBRSxDQUFDLGtCQUFrQixHQUFHLEtBQUssR0FBRyxFQUFFLEdBQUcsR0FBRyxHQUFHLEtBQUssR0FBRyxLQUFLLENBQUM7QUFFaEksK0ZBQStGO0FBQy9GLE1BQU0sZUFBZSxHQUFHLEtBQUssRUFBRSxZQUFvQixFQUFtQixFQUFFO0lBQ3RFLE1BQU0sS0FBSyxHQUFHLE1BQU0sT0FBTyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsWUFBWSxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDdEUsT0FBTyxLQUFLLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUM7QUFDcEMsQ0FBQyxDQUFDO0FBRUY7Ozs7Ozs7R0FPRztBQUNILE1BQU0sT0FBTyxnQkFBZ0I7SUFDbEIsVUFBVSxDQUE0QztJQUMvRCxTQUFTLEdBQUcsRUFBRSxDQUFDO0lBQ2YsdUZBQXVGO0lBQ3ZGLE1BQU0sR0FBa0IsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ2pDLGlCQUFpQixHQUFHLElBQUksR0FBRyxFQUFjLENBQUM7SUFFbkQsWUFBWSxZQUFZLEdBQThDLGVBQWU7UUFDbkYsSUFBSSxDQUFDLFVBQVUsR0FBRyxZQUFZLENBQUM7SUFDakMsQ0FBQztJ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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foss.global/codefeed",
3
- "version": "4.1.0",
3
+ "version": "4.3.0",
4
4
  "private": false,
5
5
  "description": "The @foss.global/codefeed module generates commit/activity feeds from forge providers including Gitea and GitManager.",
6
6
  "exports": {
@@ -11,17 +11,14 @@
11
11
  "author": "Task Venture Capital GmbH",
12
12
  "license": "MIT",
13
13
  "devDependencies": {
14
- "@foss.global/forgefixtures": "^0.3.1",
15
- "@git.zone/tsbuild": "^6.0.2",
16
- "@git.zone/tsbundle": "^3.3.0",
17
- "@git.zone/tsrun": "^3.0.3",
18
- "@git.zone/tstest": "^8.0.0",
14
+ "@foss.global/forgefixtures": "^0.5.1",
15
+ "@git.zone/tsrepo": "^2.0.0",
19
16
  "@push.rocks/qenv": "^8.2.1",
20
- "@types/node": "^26.6.4"
17
+ "@types/node": "^26.6.6"
21
18
  },
22
19
  "dependencies": {
23
20
  "@foss.global/gitmanager": "^2.4.0",
24
- "@foss.global/interfaces": "^2.6.0",
21
+ "@foss.global/interfaces": "^2.8.0",
25
22
  "@push.rocks/lik": "^6.4.4",
26
23
  "@push.rocks/smartnpm": "^2.1.3",
27
24
  "@push.rocks/smarttime": "^5.0.1"
@@ -62,8 +59,8 @@
62
59
  "version control"
63
60
  ],
64
61
  "scripts": {
65
- "test": "(tstest test/ --verbose)",
66
- "build": "(tsbuild tsfolders --web --allowimplicitany)",
67
- "buildDocs": "(tsdoc)"
62
+ "test": "(tsrepo test test/ --verbose)",
63
+ "build": "(tsrepo build tsfolders --web --allowimplicitany)",
64
+ "buildDocs": "(tsrepo docs)"
68
65
  }
69
66
  }
package/readme.md CHANGED
@@ -109,9 +109,11 @@ Discovery records each repository's Gitea `id` as a canonical decimal string, an
109
109
 
110
110
  What is measured: users with their account flags, two-factor and SSH/GPG keys; organizations, members, teams, team memberships and repository grants; repositories with their flags, Git refs split into branches, tags, pull request refs and other refs, Git objects and their uncompressed bytes, LFS objects referenced anywhere in history with the bytes Gitea holds and the number it lacks, issues, pull requests, comments, reviews, review comments, labels, milestones, reactions and attachments; releases including drafts, assets and asset bytes; wiki pages; collaborators, team grants, deploy keys, webhooks, branch and tag protections and push mirrors; packages per type with versions, files and bytes; system webhooks, Actions runners, workflows, runs, artifacts and the number of Actions secrets and variables; unadopted repositories.
111
111
 
112
+ Beyond counts, each repository keeps records of what the migration recreates. `releaseRecords` lists every release, drafts and prereleases included, sorted by numeric id: tag name, target commitish, name, body, the draft and prerelease flags, created and published times as Gitea reports them (a draft reports its creation time as published, and its tag does not exist as a Git ref yet), an author snapshot (account id and login; Gitea's placeholder for a deleted account has id `-1`) and its assets sorted by numeric id with id, storage `uuid`, name, size, download count and creation time. Gitea exposes no content digest, so a record carries none; a replaced file carries another id and uuid, and the download count moves with every download, so it never decides whether a release changed. `protections` holds the branch protection rules sorted by rule name (code-unit order) with every restriction Gitea reads back, allowlists included, and the tag protection rules sorted by numeric id with their name pattern and allowlist. `releaseRecords` is null while a release count is not complete, and `protections` is null while either protection count is not; the counts then say why.
113
+
112
114
  Secrets are counted, never named: the report carries no tokens, Actions secret or variable values or names, webhook secrets or mirror remote URLs. Reasons are adapter codes or fixed text, never response bodies or URLs. Gitea has no read that lists user-scoped Actions secrets; that is listed in `limitations`, since they are reissued. User-scoped webhooks, variables and runners are read as that user through the `Sudo` header.
113
115
 
114
- Git-level measures come from a mirror clone of every ref Gitea advertises, `refs/pull/*` included, made with `@foss.global/gitmanager` in a fresh directory below `gitWorkDir` and removed afterwards. The reader's login and token form Basic credentials; the credential reaches Git only through GIT_CONFIG_* entries in the child process environment; it is never in the URL, the command line or any file. The private CA list applies to the clone as well. The mirror's HEAD becomes the repository's `head`: the ref it names as `target` and whether it `resolves`. In a repository that is not `empty`, a HEAD that does not resolve names a missing branch, such as a default branch deleted at the source, and a `target` other than `refs/heads/<defaultBranch>` means Gitea's setting and its Git HEAD disagree. `head` is null when the mirror or its refs could not be read. A detached source HEAD is one such case: GitManager's mirror import requires a symbolic HEAD, so the clone fails with `git-mirror-failed`, and this reader never reports a `target` of null. The mirror's distinct LFS pointers, from every reachable revision, are checked against Gitea in batches of 100: an object with a download action counts as held, one answered with error 404 as missing, and any other answer makes the LFS measures `partial`. A clone that fails or exceeds `gitTimeoutMs` makes every Git and LFS measure of that repository `partial`; only the API-reported size stays complete. A clone starts only once its scratch reservation, twice the reported size plus 64 MiB, fits the free space of the file system that holds `gitWorkDir`, counting the reservations of the clones already in flight from every reader in the process. A clone that does not fit waits for them, in arrival order; one that does not fit even alone makes every Git and LFS measure of its repository `partial` with `git-workdir-too-small`, so the inventory stays incomplete. Size `gitWorkDir` for the largest repositories measured at once.
116
+ Git-level measures come from a mirror clone of every ref Gitea advertises, `refs/pull/*` included, made with `@foss.global/gitmanager` in a fresh directory below `gitWorkDir` and removed afterwards. The reader's login and token form Basic credentials; the credential reaches Git only through GIT_CONFIG_* entries in the child process environment; it is never in the URL, the command line or any file. The private CA list applies to the clone as well. The mirror's HEAD becomes the repository's `head`: the ref it names as `target` and whether it `resolves`. In a repository that is not `empty`, a HEAD that does not resolve names a missing branch, such as a default branch deleted at the source, and a `target` other than `refs/heads/<defaultBranch>` means Gitea's setting and its Git HEAD disagree. `head` is null when the mirror or its refs could not be read. A detached source HEAD is one such case: GitManager's mirror import requires a symbolic HEAD, so the clone fails with `git-mirror-failed`, and this reader never reports a `target` of null. The same mirror records `refDigests`: for each of `refs/heads/`, `refs/tags/` and `refs/notes/`, GitManager's ref `inventoryDigest` (HEAD and the refs under that prefix) and the `refCount` of that selection, read as one single-ref `listRefs` page per prefix; codefeed computes no digest of its own. Any other GitManager repository with the same HEAD and refs under a prefix reports the same digest, so a migration compares them with its native copy. Pull request refs have no digest, and `git.otherRefs - refDigests.notes.refCount` refs lie outside every digested namespace. `refDigests` is null whenever `head` is, or when any of the three reads fails; it is never partial. The mirror's distinct LFS pointers, from every reachable revision, are checked against Gitea in batches of 100: an object with a download action counts as held, one answered with error 404 as missing, and any other answer makes the LFS measures `partial`. A clone that fails or exceeds `gitTimeoutMs` makes every Git and LFS measure of that repository `partial`; only the API-reported size stays complete. A clone starts only once its scratch reservation, twice the reported size plus 64 MiB, fits the free space of the file system that holds `gitWorkDir`, counting the reservations of the clones already in flight from every reader in the process. A clone that does not fit waits for them, in arrival order; one that does not fit even alone makes every Git and LFS measure of its repository `partial` with `git-workdir-too-small`, so the inventory stays incomplete. Size `gitWorkDir` for the largest repositories measured at once.
115
117
 
116
118
  Known gaps that keep an inventory incomplete:
117
119
  - A repository with its issues or pull requests unit disabled hides both through the API, so its issues, pull requests, comments, reviews, reactions and attachments are `notMeasured`. A disabled wiki hides its pages the same way. Labels, milestones, releases and Actions stay readable while their units are disabled.
@@ -120,7 +122,7 @@ Listings page until an empty page or the `x-total-count` total is reached. A tot
120
122
 
121
123
  ### Gitea source transfer
122
124
 
123
- `GiteaSourceTransfer` reads one repository's Git data and LFS objects for the one-time migration, with the same reader credentials as the inventory. It never writes to Gitea: Git is read only through `git-upload-pack`, LFS only through batch `download` requests and their download actions.
125
+ `GiteaSourceTransfer` reads one repository's Git data, LFS objects and release assets for the one-time migration, with the same reader credentials as the inventory. It never writes to Gitea: Git is read only through `git-upload-pack`, LFS only through batch `download` requests and their download actions, release assets only through GETs of their attachment.
124
126
 
125
127
  ```ts
126
128
  import { GitManager } from '@foss.global/gitmanager';
@@ -130,7 +132,8 @@ const source = new GiteaSourceTransfer({
130
132
  baseUrl: 'https://gitea.example.com', // HTTPS only
131
133
  login: readerLogin,
132
134
  token: readerToken, // read it from a file; never pass it on a command line
133
- // caCertificates: [privateCaPem], gitTimeoutMs: 30 * 60 * 1000, requestTimeoutMs: 60_000, maxResponseBytes: 16 * 1024 * 1024, lfsTransferTimeoutMs: 30 * 60 * 1000,
135
+ // caCertificates: [privateCaPem], gitTimeoutMs: 30 * 60 * 1000, requestTimeoutMs: 60_000, maxResponseBytes: 16 * 1024 * 1024,
136
+ // lfsTransferTimeoutMs: 30 * 60 * 1000, releaseAssetTimeoutMs: 30 * 60 * 1000,
134
137
  });
135
138
 
136
139
  // A started GitManager rooted in the caller's own scratch space; codefeed creates no scratch roots.
@@ -147,6 +150,10 @@ if (download.status === 'missing') {
147
150
  } else {
148
151
  await pipeline(download.stream, destination); // errors unless the bytes are exactly the object
149
152
  }
153
+
154
+ // A release asset as the inventory recorded it: { id, uuid, name, size } from releaseRecords[].assets[].
155
+ const asset = await source.downloadReleaseAsset({ owner: 'team', name: 'app', id: '11' }, release.id, recordedAsset, { signal });
156
+ await pipeline(asset.stream, destination); // errors unless exactly `size` bytes of the recorded asset arrived
150
157
  ```
151
158
 
152
159
  A source repository is named by `owner`, `name` and its Gitea repository `id`, a canonical decimal string as the inventory records it; anything else rejects with `invalid-repository`. Git and the LFS API reach a repository only by name, and a name can move to another repository between two reads: Gitea answers a renamed repository's old path with a redirect, and a new repository can take the old name. Every source read is therefore bracketed by an identity read of `GET /api/v1/repositories/{id}`, which must still name `owner/name` (compared case-insensitively, as Gitea does). A repository that was renamed, or whose name now belongs to another repository, rejects with `repository-identity-changed`; a deleted one rejects with `http-404`. A transfer that fails is explained the same way when the identity read shows one of those two causes.
@@ -155,7 +162,9 @@ A source repository is named by `owner`, `name` and its Gitea repository `id`, a
155
162
 
156
163
  While the import runs, GitManager holds `target`: writes to it, such as `initBareRepository`, `restoreRepositoryBundle`, `setDefaultBranch` or a Smart HTTP push, fail with a `GitManagerError` whose code is `repositoryBusy`, and a second import into the same `target` is refused at once (codefeed rejects it with `git-mirror-failed`). Reads, of `target` as of other repositories, proceed.
157
164
 
158
- `downloadLfsObject` sends one batch `download` request with the reader's Basic credentials, then a GET of the action's href with the action's headers only, and then reads the identity; when that read rejects, the stream is destroyed and the call rejects with its code. A missing object resolves as `{ status: 'missing' }`, so a caller can list the missing oids; any other object error rejects with `lfs-object-error-<code>`, such as `lfs-object-error-422` for a size Gitea disagrees with. The returned stream never holds the whole object: it counts and hashes the bytes as they pass and holds back the last chunk until the body ended with exactly `size` bytes whose SHA-256 is `oid`. Otherwise it errors with `lfs-size-overrun`, `lfs-short-body` or `lfs-digest-mismatch`; a `content-length` other than `size` rejects with `lfs-size-mismatch` before streaming. An abort errors it with `request-aborted`, a transfer longer than `lfsTransferTimeoutMs` or idle for `requestTimeoutMs` with `lfs-transfer-timed-out`. Destroying the stream ends the download.
165
+ `downloadLfsObject` sends one batch `download` request with the reader's Basic credentials, then a GET of the action's href with the action's headers only, and then reads the identity; when that read rejects, the stream is destroyed and the call rejects with its code. A missing object resolves as `{ status: 'missing' }`, so a caller can list the missing oids; any other object error rejects with `lfs-object-error-<code>`, such as `lfs-object-error-422` for a size Gitea disagrees with. The returned stream never holds the whole object: it counts and hashes the bytes as they pass and holds back the last chunk until the body ended with exactly `size` bytes whose SHA-256 is `oid`. Otherwise it errors with `lfs-size-overrun`, `lfs-short-body` or `lfs-digest-mismatch`; a `content-length` other than `size` rejects with `lfs-size-mismatch` before streaming. An abort errors it with `request-aborted`, a transfer longer than `lfsTransferTimeoutMs` or idle for `requestTimeoutMs` with `lfs-transfer-timed-out`. Destroying the stream ends the download. The stream fails internally with `lfs-transfer-failed` when body bytes still arrive after the download has ended, which happens only once the stream is destroyed, so a reader of the stream does not see it.
166
+
167
+ `downloadReleaseAsset(repository, releaseId, asset)` takes the release id and the asset's `id`, `uuid`, `name` and `size` as the inventory recorded them; anything else rejects with `release-asset-invalid` before any request. It reads the repository by id, then `GET /api/v1/repos/{owner}/{name}/releases/{releaseId}`, which must still carry an asset with the same id, uuid, name and size; otherwise it rejects with `release-asset-identity-changed` (a deleted release with `http-404`). The download count is not compared. It then GETs `{baseUrl}/attachments/{uuid}` with the reader's `token` authorization: no redirect is followed and no range is asked for, so any answer but 200 rejects, with `http-<status>` or, for a refused redirect, `release-asset-download-failed`, and a `content-length` other than `size` rejects with `release-asset-size-mismatch`. No digest is computed while the bytes stream: the stream counts them and holds back the last chunk until exactly `size` bytes have arrived and both identity reads have passed once more, so a consumer never receives a complete asset that is short, long or no longer the recorded one. Otherwise it errors with `release-asset-size-overrun`, `release-asset-short-body`, `repository-identity-changed` or `release-asset-identity-changed`. Content digests come from the content itself, such as a publisher's `SHA256SUMS` asset or the importer's own hash. An abort errors it with `request-aborted`, a download longer than `releaseAssetTimeoutMs` (default 30 minutes, at most six hours) or idle for `requestTimeoutMs` with `release-asset-transfer-timed-out`. A failed request is explained by the identity reads as for `downloadLfsObject`. Destroying the stream ends the download; the download's connections close with the stream. The stream fails internally with `release-asset-transfer-failed` when body bytes still arrive after the download has ended, which happens only once the stream is destroyed, so a reader of the stream does not see it.
159
168
 
160
169
  ### Git LFS batch client
161
170
 
@@ -176,7 +185,7 @@ const download = await lfs.download({ oid, size }, { signal }); // as for downlo
176
185
  lfs.close(); // optional: idle pooled connections close on their own
177
186
  ```
178
187
 
179
- - `upload` sends one batch `upload` request per `batchSize` objects (at most 100). An object without an `upload` action is already present; for each other one it opens the source, PUTs exactly `size` bytes with the action's headers and `Content-Length: size`, and then calls the `verify` action when the server sent one. The bytes are hashed while they stream and the last chunk is held back, so a source that is not the object is never sent complete (`lfs-size-overrun`, `lfs-short-body`, `lfs-digest-mismatch`). Any object error rejects with `lfs-object-error-<code>`.
188
+ - `upload` sends one batch `upload` request per `batchSize` objects (at most 100). An object without an `upload` action is already present; for each other one it opens the source, PUTs exactly `size` bytes with the action's headers and `Content-Length: size`, and then calls the `verify` action when the server sent one. The bytes are hashed while they stream and the last chunk is held back, so a source that is not the object is never sent complete (`lfs-size-overrun`, `lfs-short-body`, `lfs-digest-mismatch`). Any object error rejects with `lfs-object-error-<code>`. A source that still yields bytes after its upload has ended fails internally with `lfs-transfer-failed`; that happens only once the upload has settled, so the caller does not see it.
180
189
  - Action expiry: `expires_in` (whole seconds after the batch answer arrived) is preferred over `expires_at` (RFC 3339), as the batch API specifies; like the git-lfs client, an `expires_in` of 0 and Go's zero time mean no expiry, and any other malformed value fails with `invalid-lfs-batch`. An upload, verify or download action is used only while it stays valid for the expiry margin, 30 s or `requestTimeoutMs` when that is shorter. Objects are transferred one at a time after their batch answer, so a later object whose action would expire within the margin is asked for again in a batch of its own, once; when the fresh answer is again too short-lived the call fails with `lfs-action-expired`. A verify action that expires during its PUT is asked for the same way; a fresh answer without actions means the server holds the object.
181
190
  - `checkPresence` sends batch `download` requests and downloads nothing: a download action means `held`, error 404 `missing`. It uses no action, so expiry is validated but not enforced there.
182
191
  - The credential is sent only as the `Authorization` header of batch requests to the endpoint, never to action hrefs and never in a URL, error or result; hrefs get the action's headers only. Action headers may not set connection-level fields (`host`, `content-length`, `transfer-encoding` and similar).
@@ -347,7 +356,7 @@ The repo contains:
347
356
  - A mocked pagination test that does not require network.
348
357
  - A GitManager provider mapping test using a local test stub.
349
358
  - A default-deny GitManager public-client mapping test using a local test stub.
350
- - A mocked `GiteaSourceInventory` test, Git-level `GiteaSourceInventory` and `GiteaSourceTransfer` tests against a local HTTPS Git, LFS batch and REST server (needs `openssl` and `git http-backend`), and an opt-in one against a Docker Gitea from `@foss.global/forgefixtures`, run with `FORGEFIXTURES=gitea pnpm test` (Docker required).
359
+ - A mocked `GiteaSourceInventory` test, Git-level `GiteaSourceInventory` and `GiteaSourceTransfer` tests and a release asset download test against a local HTTPS Git, LFS batch, REST and attachment server (needs `openssl` and `git http-backend`), and an opt-in one against a Docker Gitea from `@foss.global/forgefixtures`, run with `FORGEFIXTURES=gitea pnpm test` (Docker required).
351
360
  - An `LfsBatchClient` test against local loopback LFS servers over HTTP and over HTTPS with a private CA.
352
361
 
353
362
  Run tests:
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@foss.global/codefeed',
6
- version: '4.1.0',
6
+ version: '4.3.0',
7
7
  description: 'The @foss.global/codefeed module generates commit/activity feeds from forge providers including Gitea and GitManager.'
8
8
  }