@foss.global/codefeed 5.1.0 → 5.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.
package/changelog.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026-11-11 - 5.3.0
4
+
5
+ ### Fixes
6
+
7
+ - return package metadata documents in a canonical form instead of the bytes Gitea served (giteasourcetransfer)
8
+ - Gitea 28 writes a JSON object held in a map in a new key order on every read: one unchanged crate version's sparse index line came back in 6 byte sequences over 40 reads (its `features`), and npm version documents hold maps too. The SHA-256 5.2.0 returned beside `npm-version`, `swift-release` and `cargo-index-entry` documents therefore changed from read to read, and it covered state the inventory records apart (a Cargo `yanked`, an npm `deprecated`), so a recorded digest could never match a later one (S10b ruling 2026-11-11, D1 and D2).
9
+ - `readPackageDocument` now returns those documents as `canonicalPackageDocument` writes them, with the SHA-256 of the canonical bytes; the served bytes are not returned. `swift-manifest` stays verbatim.
10
+ - Upgrade: no consumer of 5.2.0's `readPackageDocument` exists; a digest recorded from it must be read again.
11
+
12
+ ### Features
13
+
14
+ - export `canonicalPackageDocument(kind, bytes)`, the canonical form and SHA-256 of a JSON package document, for consumers to compare their own documents with what they read (giteasourcetransfer)
15
+ - Decode as UTF-8 (fatal) and parse a JSON object; remove the top-level `yanked` of a Cargo index entry or `deprecated` of an npm version document; write it compact with object keys sorted by code point at every depth, arrays in order and strings and integers as `JSON.stringify` writes them. A number that is not a safe integer, or a document that is not a JSON object, rejects with `document-not-canonical`.
16
+ - read a Swift release's alternate manifests (giteasourcetransfer)
17
+ - `readPackageDocument(package, version, 'swift-manifest', { swiftVersion })` reads `Package@swift-<v>.swift` through `?swift-version=` without following a redirect and resolves `null` only on Gitea's 303 to the release's own `Package.swift`, its answer for a version it holds no manifest for. Another redirect rejects with `swift-manifest-redirect-unexpected`, another status with `http-<status>`, a version Gitea would not key a manifest by with `swift-version-invalid` before any request. `Package.swift` itself must still answer 200.
18
+ - read a crate's description (giteasourcetransfer)
19
+ - The new kind `cargo-description` returns `{"description":…}` from the crate's entry in the Cargo search (`q=<name>`, the exact name, paged, at most 200 pages of 50, then `cargo-search-over-bound`). Gitea describes only the version with the highest id there, so `max_version` must be the requested version, else `package-document-missing`.
20
+ - `ForgeRequestClient.requestBytesOrRedirect` returns a redirect (status and `Location`) instead of refusing it, never following it; the transports take `redirect: 'return'` for it (forgeinventory)
21
+
22
+ ### Tests
23
+
24
+ - Check against @foss.global/forgefixtures ^1.0.0 on Gitea 28.2.0 that every JSON document read is canonical and recomputes to its digest, that an archive with an alternate and a nested manifest serves the alternate one and redirects for the nested one, that the crate description belongs to the latest version only, and, with the fixture's state snapshots, that the alternate manifest, redirect and search reads change nothing but the administrator token's `access_token.updated_unix`, no download count included (giteasourceinventory, giteasourcetransfer)
25
+ - Check the canonical form (code-point key order at every depth, arrays in order, the kind's state member only, unsafe numbers, invalid UTF-8 and non-objects), the search paging, exact name, latest-version rule and bound, and the manifest redirect rules (relative and absolute `Location`, another release, another status, the default manifest) against a local HTTPS server, and the fetch transport's redirect modes (giteasourcetransfer, forgeinventory)
26
+
27
+ ## 2026-11-11 - 5.2.0
28
+
29
+ ### Features
30
+
31
+ - inventory packages one unit per package when the run selects the package class, with their distinct content (giteasourceinventory)
32
+ - `discover(signal, { classes: ['packages'] })` lists every package from `/admin/packages` as `discovery.packages`, and `units()` adds a `package` unit per package; without the class nothing changes and the package class is unread. An unknown class rejects with `invalid-options`.
33
+ - A package unit records an `IForgeSourcePackageInventory`: owner id, linked repository, every version and each distinct file content once with its files, from the v1 package API. Container index candidates (a file list of exactly `manifest.json`) are read by digest from the registry, checked by SHA-256 and the index or manifest-list media type (`unexpected-manifest-shape` otherwise), and record their `references`; no other manifest is read. npm packages record every served dist-tag, a derived `latest` included, and each version's deprecation; Cargo versions their yank from the sparse index.
34
+ - A unit is whole or failed, never truncated: a listing that does not finish, `npm-version-missing`, `cargo-index-incomplete`, `package-identity-changed` and `unit-over-bound` (over `forgeSourceInventoryUnitMaxBytes` of UTF-8 JSON) fail it.
35
+ - `composeGiteaSourceInventory` adds `packages` and `totals.packageContent` exactly when discovery lists packages, an empty list included; `composeGiteaPackageContent` is exported as the pure function behind the content figures. Unit kinds are dispatched exhaustively; an unknown kind fails as `unit-kind-unsupported`.
36
+ - Every read is a GET; reading an index counts a download of its version, an accepted read stamp (S10 ruling, Addenda 1 and 2).
37
+ - require @foss.global/interfaces ^3.2.1
38
+ - read package content for the migration (giteasourcetransfer)
39
+ - `readContainerManifest` returns a manifest's exact bytes and `Content-Type`, checked against its digest; `downloadContainerBlob` streams a config or layer verified by SHA-256 and size.
40
+ - `downloadPackageFile` streams a generic file, npm tarball, Swift archive or crate, and `readPackageDocument` returns an npm version document, Swift release metadata or `Package.swift`, or a crate version's sparse index line, with its SHA-256; both are bracketed by identity reads of the version (`package-version-identity-changed`, `http-404`). The new option `packageTransferTimeoutMs` bounds a download.
41
+ - `ForgeRequestClient.requestBytes` reads a body as the bytes that arrived with the declared media type (forgeinventory)
42
+
43
+ ### Tests
44
+
45
+ - Check every package record field for field against @foss.global/forgefixtures ^1.0.0 on Gitea 28.2.0, the distinct content against an independent computation, every transfer read, and, with the fixture's state snapshots, that the package inventory and transfer reads change nothing but `package_version.download_count` (once per lead-file read) and the administrator token's `access_token.updated_unix` (giteasourceinventory, giteasourcetransfer)
46
+ - Check the package class selection, index candidates, `unexpected-manifest-shape`, `unit-over-bound`, the npm, Cargo and listing failures, composition and the pure content function against a mocked Gitea, and the package transfer's digest, size, media type and identity checks against a local HTTPS server (giteasourceinventory, giteasourcetransfer)
47
+
3
48
  ## 2026-11-11 - 5.1.0
4
49
 
5
50
  ### Features
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@foss.global/codefeed',
6
- version: '5.1.0',
6
+ version: '5.3.0',
7
7
  description: 'The @foss.global/codefeed module generates commit/activity feeds from forge providers including Gitea and GitManager.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx1QkFBdUI7SUFDN0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLHVIQUF1SDtDQUNySSxDQUFBIn0=
@@ -32,6 +32,17 @@ export interface IGiteaSourceInventoryOptions {
32
32
  requestTimeoutMs?: number;
33
33
  maxResponseBytes?: number;
34
34
  }
35
+ /** A class of source data a run measures only when its discovery selects it. */
36
+ export type TGiteaSourceInventoryClass = 'packages';
37
+ export interface IGiteaSourceDiscoveryOptions {
38
+ /**
39
+ * Classes beside the instance, owners and repositories to list for
40
+ * measurement. `packages` lists every package, so `units` measures one unit
41
+ * per package; without it, discovery carries no `packages` and the package
42
+ * class is unread.
43
+ */
44
+ classes?: readonly TGiteaSourceInventoryClass[];
45
+ }
35
46
  export interface IGiteaSourceMeasureOptions {
36
47
  signal?: AbortSignal;
37
48
  /** Units measured at the same time. Requests within one unit are sequential. */
@@ -53,9 +64,10 @@ export type TGiteaSourceRepositoryLookup = {
53
64
  export declare const giteaSourceInventoryLimitations: readonly string[];
54
65
  /**
55
66
  * Authenticated, read-only inventory of a Gitea instance, read with a site
56
- * administrator's token: GET requests to its REST API, a mirror clone of every
57
- * repository for refs, objects and LFS pointers, and LFS batch `download`
58
- * requests that check which referenced objects Gitea holds. It counts secrets
67
+ * administrator's token: GET requests to its REST API and package registries,
68
+ * a mirror clone of every repository for refs, objects and LFS pointers, and
69
+ * LFS batch `download` requests that check which referenced objects Gitea
70
+ * holds. It counts secrets
59
71
  * and variables without retaining their values, and reports every read that
60
72
  * did not finish as a partial or unmeasured value instead of a count.
61
73
  */
@@ -68,12 +80,18 @@ export declare class GiteaSourceInventory {
68
80
  get metrics(): IForgeRequestMetrics;
69
81
  /**
70
82
  * Identifies the source and its reader and lists every owner and repository
71
- * with its id. Rejects unless the token belongs to a site administrator; a listing that
72
- * does not finish, or that lists a repository id twice, is reported in
73
- * `incompleteReasons`.
83
+ * with its id, and with `classes: ['packages']` every package from the
84
+ * administrator package listing (`packages`, absent otherwise). Rejects
85
+ * unless the token belongs to a site administrator, and rejects an unknown
86
+ * class with `invalid-options`; a listing that does not finish, or that
87
+ * lists a repository id twice, is reported in `incompleteReasons`.
88
+ */
89
+ discover(signalArg?: AbortSignal, optionsArg?: IGiteaSourceDiscoveryOptions): Promise<IDiscovery>;
90
+ /**
91
+ * Every unit a run over this discovery measures: the instance, then owners,
92
+ * then repositories, then the packages discovery lists when it selected
93
+ * them.
74
94
  */
75
- discover(signalArg?: AbortSignal): Promise<IDiscovery>;
76
- /** Every unit a run over this discovery measures: the instance, then owners, then repositories. */
77
95
  units(discoveryArg: IDiscovery): TUnit[];
78
96
  /**
79
97
  * Reads a repository by its id through `GET /repositories/{id}`, which
@@ -87,7 +105,11 @@ export declare class GiteaSourceInventory {
87
105
  /**
88
106
  * Measures one unit. Never rejects: a unit whose primary record cannot be
89
107
  * read is `failed`, and so is a repository unit carrying an id that its name
90
- * no longer answers with (`repository-identity-changed`).
108
+ * no longer answers with (`repository-identity-changed`). A package unit is
109
+ * read whole or fails, never partly: a listing that does not finish, an
110
+ * index that is not what its file list promises (`unexpected-manifest-shape`)
111
+ * and a result over `forgeSourceInventoryUnitMaxBytes` of UTF-8 JSON
112
+ * (`unit-over-bound`) fail it, and its record is never truncated.
91
113
  */
92
114
  measureUnit(unitArg: TUnit, signalArg?: AbortSignal): Promise<TUnitResult>;
93
115
  /**
@@ -104,6 +126,10 @@ export declare class GiteaSourceInventory {
104
126
  * repositories measured with one id, owner repository counts that disagree
105
127
  * with discovery, and every partial or unmeasured value make the inventory
106
128
  * incomplete, with reasons aggregated per subject kind, path and reason.
129
+ * `packages` and `totals.packageContent` (`composeGiteaPackageContent`) are
130
+ * present exactly when discovery lists packages, an empty list included; a
131
+ * package without a record is left out, never truncated, and makes its
132
+ * content measures partial.
107
133
  */
108
134
  export declare const composeGiteaSourceInventory: (discoveryArg: IDiscovery, resultsArg: TUnitResult[], generatorsArg: plugins.fossInterfaces.data.IForgeSourceInventoryGenerator[]) => IInventory;
109
135
  export {};