@push.rocks/smartlinuxrepo 0.0.0-stage → 0.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 (131) hide show
  1. package/.smartconfig.json +64 -0
  2. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  3. package/dist_ts/00_commitinfo_data.js +9 -0
  4. package/dist_ts/alpine/apkindex.d.ts +39 -0
  5. package/dist_ts/alpine/apkindex.js +211 -0
  6. package/dist_ts/alpine/pkginfo.d.ts +45 -0
  7. package/dist_ts/alpine/pkginfo.js +159 -0
  8. package/dist_ts/alpine/reader.d.ts +20 -0
  9. package/dist_ts/alpine/reader.js +89 -0
  10. package/dist_ts/arch/builder.d.ts +41 -0
  11. package/dist_ts/arch/builder.js +234 -0
  12. package/dist_ts/arch/reader.d.ts +16 -0
  13. package/dist_ts/arch/reader.js +271 -0
  14. package/dist_ts/arch/signer.d.ts +21 -0
  15. package/dist_ts/arch/signer.js +66 -0
  16. package/dist_ts/arch/vercmp.d.ts +12 -0
  17. package/dist_ts/arch/vercmp.js +170 -0
  18. package/dist_ts/debian/control.d.ts +22 -0
  19. package/dist_ts/debian/control.js +137 -0
  20. package/dist_ts/debian/gostring.d.ts +26 -0
  21. package/dist_ts/debian/gostring.js +145 -0
  22. package/dist_ts/debian/indexbuilder.d.ts +47 -0
  23. package/dist_ts/debian/indexbuilder.js +299 -0
  24. package/dist_ts/debian/mailaddress.d.ts +12 -0
  25. package/dist_ts/debian/mailaddress.js +736 -0
  26. package/dist_ts/debian/reader.d.ts +30 -0
  27. package/dist_ts/debian/reader.js +110 -0
  28. package/dist_ts/index.d.ts +23 -0
  29. package/dist_ts/index.js +18 -0
  30. package/dist_ts/plugins.d.ts +8 -0
  31. package/dist_ts/plugins.js +11 -0
  32. package/dist_ts/readers/ar.d.ts +31 -0
  33. package/dist_ts/readers/ar.js +87 -0
  34. package/dist_ts/readers/bytes.d.ts +58 -0
  35. package/dist_ts/readers/bytes.js +147 -0
  36. package/dist_ts/readers/bytesource.d.ts +40 -0
  37. package/dist_ts/readers/bytesource.js +154 -0
  38. package/dist_ts/readers/decompress.d.ts +43 -0
  39. package/dist_ts/readers/decompress.js +269 -0
  40. package/dist_ts/readers/gzipmember.d.ts +32 -0
  41. package/dist_ts/readers/gzipmember.js +176 -0
  42. package/dist_ts/readers/tar.d.ts +85 -0
  43. package/dist_ts/readers/tar.js +731 -0
  44. package/dist_ts/readers/text.d.ts +16 -0
  45. package/dist_ts/readers/text.js +96 -0
  46. package/dist_ts/rpm/builder.d.ts +28 -0
  47. package/dist_ts/rpm/builder.js +208 -0
  48. package/dist_ts/rpm/header.d.ts +138 -0
  49. package/dist_ts/rpm/header.js +546 -0
  50. package/dist_ts/rpm/reader.d.ts +20 -0
  51. package/dist_ts/rpm/reader.js +306 -0
  52. package/dist_ts/rpm/repoconfig.d.ts +15 -0
  53. package/dist_ts/rpm/repoconfig.js +38 -0
  54. package/dist_ts/rpm/repodata.d.ts +44 -0
  55. package/dist_ts/rpm/repodata.js +148 -0
  56. package/dist_ts/rpm/sign.d.ts +30 -0
  57. package/dist_ts/rpm/sign.js +183 -0
  58. package/dist_ts/rpm/updates.d.ts +38 -0
  59. package/dist_ts/rpm/updates.js +265 -0
  60. package/dist_ts/rpm/xml.d.ts +18 -0
  61. package/dist_ts/rpm/xml.js +90 -0
  62. package/dist_ts/shared/architecture.d.ts +8 -0
  63. package/dist_ts/shared/architecture.js +17 -0
  64. package/dist_ts/shared/errors.d.ts +38 -0
  65. package/dist_ts/shared/errors.js +22 -0
  66. package/dist_ts/shared/gopath.d.ts +13 -0
  67. package/dist_ts/shared/gopath.js +53 -0
  68. package/dist_ts/shared/gostrings.d.ts +14 -0
  69. package/dist_ts/shared/gostrings.js +29 -0
  70. package/dist_ts/shared/limits.d.ts +47 -0
  71. package/dist_ts/shared/limits.js +57 -0
  72. package/dist_ts/shared/types.d.ts +213 -0
  73. package/dist_ts/shared/types.js +13 -0
  74. package/dist_ts/shared/url.d.ts +18 -0
  75. package/dist_ts/shared/url.js +371 -0
  76. package/dist_ts/shared/validation.d.ts +21 -0
  77. package/dist_ts/shared/validation.js +58 -0
  78. package/dist_ts/signing/keys.d.ts +36 -0
  79. package/dist_ts/signing/keys.js +89 -0
  80. package/dist_ts/signing/openpgpframing.d.ts +33 -0
  81. package/dist_ts/signing/openpgpframing.js +93 -0
  82. package/dist_ts/signing/signers.d.ts +63 -0
  83. package/dist_ts/signing/signers.js +248 -0
  84. package/dist_ts/writers/gotar.d.ts +43 -0
  85. package/dist_ts/writers/gotar.js +218 -0
  86. package/license.md +19 -0
  87. package/package.json +56 -3
  88. package/readme.md +176 -0
  89. package/ts/00_commitinfo_data.ts +8 -0
  90. package/ts/alpine/apkindex.ts +241 -0
  91. package/ts/alpine/pkginfo.ts +183 -0
  92. package/ts/alpine/reader.ts +96 -0
  93. package/ts/arch/builder.ts +283 -0
  94. package/ts/arch/reader.ts +307 -0
  95. package/ts/arch/signer.ts +70 -0
  96. package/ts/arch/vercmp.ts +188 -0
  97. package/ts/debian/control.ts +150 -0
  98. package/ts/debian/gostring.ts +150 -0
  99. package/ts/debian/indexbuilder.ts +355 -0
  100. package/ts/debian/mailaddress.ts +754 -0
  101. package/ts/debian/reader.ts +126 -0
  102. package/ts/index.ts +46 -0
  103. package/ts/plugins.ts +13 -0
  104. package/ts/readers/ar.ts +102 -0
  105. package/ts/readers/bytes.ts +182 -0
  106. package/ts/readers/bytesource.ts +164 -0
  107. package/ts/readers/decompress.ts +332 -0
  108. package/ts/readers/gzipmember.ts +209 -0
  109. package/ts/readers/tar.ts +835 -0
  110. package/ts/readers/text.ts +91 -0
  111. package/ts/rpm/builder.ts +253 -0
  112. package/ts/rpm/header.ts +628 -0
  113. package/ts/rpm/reader.ts +317 -0
  114. package/ts/rpm/repoconfig.ts +45 -0
  115. package/ts/rpm/repodata.ts +219 -0
  116. package/ts/rpm/sign.ts +200 -0
  117. package/ts/rpm/updates.ts +314 -0
  118. package/ts/rpm/xml.ts +101 -0
  119. package/ts/shared/architecture.ts +16 -0
  120. package/ts/shared/errors.ts +78 -0
  121. package/ts/shared/gopath.ts +54 -0
  122. package/ts/shared/gostrings.ts +31 -0
  123. package/ts/shared/limits.ts +93 -0
  124. package/ts/shared/types.ts +251 -0
  125. package/ts/shared/url.ts +387 -0
  126. package/ts/shared/validation.ts +71 -0
  127. package/ts/signing/keys.ts +110 -0
  128. package/ts/signing/openpgpframing.ts +115 -0
  129. package/ts/signing/signers.ts +315 -0
  130. package/ts/writers/gotar.ts +256 -0
  131. package/README.md +0 -3
@@ -0,0 +1,78 @@
1
+ import type { ILinuxPackageLimits } from './limits.js';
2
+
3
+ /**
4
+ * Stable error codes.
5
+ * - `limit-exceeded`: an `ILinuxPackageLimits` bound was crossed (`detail.limit` names it).
6
+ * - `unsupported-compression`: a compression the format does not allow.
7
+ * - `malformed-archive`: broken container structure (ar, tar, gzip, xz, zstd framing or data).
8
+ * - `malformed-header`: a broken package header (RPM lead and headers).
9
+ * - `missing-field` / `invalid-field`: package metadata that is absent or not acceptable.
10
+ * - `unsupported-package-format`: input that is not the expected package format, or uses a form of it
11
+ * the codec does not read (the data of a sparse tar entry).
12
+ * - `truncated`: only a clean early end of input.
13
+ * - `digest-mismatch`: a digest the package carries does not match its bytes.
14
+ * - `invalid-input`: a bad argument from the caller.
15
+ * - `invalid-key`: a key the codec cannot use.
16
+ * - `signing-failed`: a codec signer failed, or a signer returned something that is not signature bytes.
17
+ *
18
+ * The codec never wraps an error it did not raise: an error from the caller's
19
+ * source or from a caller-supplied signer propagates unchanged. An underlying
20
+ * error the codec reacts to is kept in the standard `cause`.
21
+ */
22
+ export type TLinuxRepoErrorCode =
23
+ | 'limit-exceeded'
24
+ | 'unsupported-compression'
25
+ | 'malformed-archive'
26
+ | 'malformed-header'
27
+ | 'missing-field'
28
+ | 'invalid-field'
29
+ | 'unsupported-package-format'
30
+ | 'truncated'
31
+ | 'digest-mismatch'
32
+ | 'invalid-input'
33
+ | 'invalid-key'
34
+ | 'signing-failed';
35
+
36
+ /** Names the field, structure or limit an error is about. */
37
+ export interface ILinuxRepoErrorDetail {
38
+ field?: string;
39
+ limit?: keyof ILinuxPackageLimits;
40
+ value?: number | string;
41
+ }
42
+
43
+ export class LinuxRepoError extends Error {
44
+ public readonly code: TLinuxRepoErrorCode;
45
+ public readonly detail: Readonly<ILinuxRepoErrorDetail>;
46
+
47
+ constructor(
48
+ codeArg: TLinuxRepoErrorCode,
49
+ messageArg: string,
50
+ detailArg: ILinuxRepoErrorDetail = {},
51
+ optionsArg?: { cause?: unknown },
52
+ ) {
53
+ super(
54
+ messageArg,
55
+ optionsArg !== undefined && 'cause' in optionsArg ? { cause: optionsArg.cause } : undefined,
56
+ );
57
+ this.name = 'LinuxRepoError';
58
+ this.code = codeArg;
59
+ this.detail = Object.freeze({ ...detailArg });
60
+ }
61
+ }
62
+
63
+ /** Builds the `limit-exceeded` error for one limit. */
64
+ export function limitExceeded(
65
+ limitArg: keyof ILinuxPackageLimits,
66
+ maximumArg: number,
67
+ whatArg: string,
68
+ ): LinuxRepoError {
69
+ return new LinuxRepoError('limit-exceeded', `${whatArg} exceeds ${limitArg} (${maximumArg})`, {
70
+ limit: limitArg,
71
+ value: maximumArg,
72
+ });
73
+ }
74
+
75
+ /** Builds the `truncated` error for a structure the input ended inside. */
76
+ export function truncated(whatArg: string): LinuxRepoError {
77
+ return new LinuxRepoError('truncated', `input ended inside ${whatArg}`, { field: whatArg });
78
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Go 1.27 `path` semantics (slash-separated paths) the codec mirrors where
3
+ * Gitea 28.2.0 output depends on them.
4
+ */
5
+
6
+ /** Go `path.Clean` (`src/path/path.go:72`). */
7
+ export function goPathClean(pathArg: string): string {
8
+ if (pathArg === '') {
9
+ return '.';
10
+ }
11
+ const rooted = pathArg.startsWith('/');
12
+ const parts: string[] = [];
13
+ for (const element of pathArg.split('/')) {
14
+ if (element === '' || element === '.') {
15
+ continue;
16
+ }
17
+ if (element === '..') {
18
+ if (parts.length > 0 && parts[parts.length - 1] !== '..') {
19
+ parts.pop();
20
+ } else if (!rooted) {
21
+ parts.push('..');
22
+ }
23
+ continue;
24
+ }
25
+ parts.push(element);
26
+ }
27
+ const joined = parts.join('/');
28
+ if (rooted) {
29
+ return `/${joined}`;
30
+ }
31
+ return joined === '' ? '.' : joined;
32
+ }
33
+
34
+ /**
35
+ * Go `path.Join` (`src/path/path.go:155`): empty elements are ignored, the
36
+ * result is cleaned, and all-empty input gives `''`.
37
+ */
38
+ export function goPathJoin(elementsArg: string[]): string {
39
+ const joined = elementsArg.filter((element) => element !== '').join('/');
40
+ return joined === '' ? '' : goPathClean(joined);
41
+ }
42
+
43
+ /** Go `path.Base` (`src/path/path.go:192`). */
44
+ export function goPathBase(pathArg: string): string {
45
+ if (pathArg === '') {
46
+ return '.';
47
+ }
48
+ let path = pathArg.replace(/\/+$/, '');
49
+ const slash = path.lastIndexOf('/');
50
+ if (slash >= 0) {
51
+ path = path.slice(slash + 1);
52
+ }
53
+ return path === '' ? '/' : path;
54
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Go standard-library string semantics the Arch and Alpine readers mirror, so
3
+ * derived values match Gitea 28.2.0 (`modules/packages/{arch,alpine}/metadata.go`).
4
+ */
5
+
6
+ /**
7
+ * Go `strings.TrimSpace`: trims Unicode `White_Space` (Go `unicode.IsSpace`).
8
+ * Unlike `String.prototype.trim` it keeps U+FEFF and trims U+0085.
9
+ */
10
+ export function goTrimSpace(valueArg: string): string {
11
+ return valueArg.replace(GO_SPACE_START, '').replace(GO_SPACE_END, '');
12
+ }
13
+
14
+ const GO_SPACE_CLASS = '[\\t\\n\\v\\f\\r \\u0085\\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000]';
15
+ const GO_SPACE_START = new RegExp(`^${GO_SPACE_CLASS}+`);
16
+ const GO_SPACE_END = new RegExp(`${GO_SPACE_CLASS}+$`);
17
+
18
+ /**
19
+ * Go `strconv.ParseInt(value, 10, 64)`: an optional sign and ASCII digits,
20
+ * within int64. Returns `null` where Go returns an error.
21
+ */
22
+ export function goParseInt64(valueArg: string): bigint | null {
23
+ if (!/^[+-]?[0-9]+$/.test(valueArg)) {
24
+ return null;
25
+ }
26
+ const value = BigInt(valueArg);
27
+ if (value > 0x7fffffffffffffffn || value < -0x8000000000000000n) {
28
+ return null;
29
+ }
30
+ return value;
31
+ }
@@ -0,0 +1,93 @@
1
+ import { LinuxRepoError } from './errors.js';
2
+
3
+ /**
4
+ * Hard bounds for reading a package. Callers override them per call with a
5
+ * `Partial`; every value is a positive safe integer. The defaults accept
6
+ * everything a stock Gitea 28.2.0 stores except a deb control member that
7
+ * decompresses past 32 MiB (see `DEFAULT_LINUX_PACKAGE_LIMITS`); an override
8
+ * below a default may refuse packages Gitea accepts.
9
+ */
10
+ export interface ILinuxPackageLimits {
11
+ /** The whole package input, in bytes. */
12
+ maxPackageBytes: number;
13
+ /**
14
+ * One buffered metadata unit, in bytes: the apk control gzip member, the deb
15
+ * control member, or the RPM signature header plus main header.
16
+ */
17
+ maxMetadataBytes: number;
18
+ /** The decompressed deb `control.tar`, the apk control tar, or Arch's `.PKGINFO`, in bytes. */
19
+ maxDecompressedMetadataBytes: number;
20
+ /** The decompressed Arch payload walked for the file list, in bytes. */
21
+ maxPayloadBytes: number;
22
+ /** Tar or ar entries per archive, and values per multi-valued metadata field. */
23
+ maxEntries: number;
24
+ /** Total bytes of Arch file names. */
25
+ maxFileListBytes: number;
26
+ /**
27
+ * One tar header chain (the header blocks plus PAX records and GNU long
28
+ * names), or one metadata line, in bytes. RPM headers count under
29
+ * `maxMetadataBytes`, not here.
30
+ */
31
+ maxHeaderBytes: number;
32
+ }
33
+
34
+ const KiB = 1024;
35
+ const MiB = 1024 * KiB;
36
+ const GiB = 1024 * MiB;
37
+
38
+ /**
39
+ * The default limits. They accept anything a stock Gitea 28.2.0 stores in
40
+ * practice (Gitea has no package size cap), with one exception:
41
+ * - `maxDecompressedMetadataBytes` is Gitea's 32 MiB deb control bound, but
42
+ * Gitea cuts the decompressed stream there and keeps a `control` found
43
+ * before the cut, where the codec refuses the member with `limit-exceeded`;
44
+ * - `maxEntries` and `maxFileListBytes` are Gitea's Arch file-list caps
45
+ * (Alpine's 1024 `.PKGINFO` values fold into `maxEntries`);
46
+ * - `maxHeaderBytes` covers a full PAX + GNU long name + GNU long link chain at
47
+ * Go `archive/tar`'s 1 MiB per special record, and Gitea's 64 KiB line limit.
48
+ */
49
+ export const DEFAULT_LINUX_PACKAGE_LIMITS: Readonly<ILinuxPackageLimits> = Object.freeze({
50
+ maxPackageBytes: 8 * GiB,
51
+ maxMetadataBytes: 64 * MiB,
52
+ maxDecompressedMetadataBytes: 32 * MiB,
53
+ maxPayloadBytes: 16 * GiB,
54
+ maxEntries: 100_000,
55
+ maxFileListBytes: 16 * MiB,
56
+ maxHeaderBytes: 4 * MiB,
57
+ });
58
+
59
+ const LIMIT_KEYS = Object.keys(DEFAULT_LINUX_PACKAGE_LIMITS) as Array<keyof ILinuxPackageLimits>;
60
+
61
+ /**
62
+ * Merges per-call overrides over the defaults. Unknown keys and values that
63
+ * are not positive safe integers are refused with `invalid-input`.
64
+ */
65
+ export function resolveLinuxPackageLimits(
66
+ overrides?: Partial<ILinuxPackageLimits>,
67
+ ): Readonly<ILinuxPackageLimits> {
68
+ if (overrides === undefined) {
69
+ return DEFAULT_LINUX_PACKAGE_LIMITS;
70
+ }
71
+ if (overrides === null || typeof overrides !== 'object' || Array.isArray(overrides)) {
72
+ throw new LinuxRepoError('invalid-input', 'limits must be an object', { field: 'limits' });
73
+ }
74
+ const resolved: ILinuxPackageLimits = { ...DEFAULT_LINUX_PACKAGE_LIMITS };
75
+ for (const key of Object.keys(overrides)) {
76
+ if (!(LIMIT_KEYS as string[]).includes(key)) {
77
+ throw new LinuxRepoError('invalid-input', `unknown limit "${key}"`, { field: 'limits', value: key });
78
+ }
79
+ const limitKey = key as keyof ILinuxPackageLimits;
80
+ const value = overrides[limitKey];
81
+ if (value === undefined) {
82
+ continue;
83
+ }
84
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value <= 0) {
85
+ throw new LinuxRepoError('invalid-input', `limit ${limitKey} must be a positive safe integer`, {
86
+ field: 'limits',
87
+ limit: limitKey,
88
+ });
89
+ }
90
+ resolved[limitKey] = value;
91
+ }
92
+ return Object.freeze(resolved);
93
+ }
@@ -0,0 +1,251 @@
1
+ /**
2
+ * The persisted record shapes of `@push.rocks/smartlinuxrepo`.
3
+ *
4
+ * Records are public API: every field is plain JSON (strings,
5
+ * integers within `Number.MAX_SAFE_INTEGER`, booleans, arrays and objects; no
6
+ * `Date`, no `Uint8Array`). Hashes are lowercase hex. Every 1.0.0 key is
7
+ * required and always present, using Gitea's zero values (`''`, `0`, `[]`);
8
+ * keys added in a later minor are optional because older persisted records lack
9
+ * them. Changing a shape needs a major release. The union is not closed: a
10
+ * later minor may add a fifth format.
11
+ */
12
+
13
+ /** The package formats the codec reads and indexes. */
14
+ export type TLinuxPackageFormat = 'alpine' | 'debian' | 'rpm' | 'arch';
15
+
16
+ /** Size and digests over the whole package file. */
17
+ export interface ILinuxPackageDigests {
18
+ /** Byte count of the whole file. */
19
+ size: number;
20
+ md5: string;
21
+ sha1: string;
22
+ sha256: string;
23
+ sha512: string;
24
+ }
25
+
26
+ export interface IAlpinePackageDigests extends ILinuxPackageDigests {
27
+ /**
28
+ * SHA-1 of the exact bytes of the gzip member holding `.PKGINFO`. The
29
+ * APKINDEX `C:` value is `'Q1'` plus the base64 of these 20 bytes.
30
+ */
31
+ controlSha1: string;
32
+ }
33
+
34
+ export interface ILinuxPackageRecordBase {
35
+ format: TLinuxPackageFormat;
36
+ name: string;
37
+ /** Gitea's version string (RPM: `V-R`, or `E-V-R` with a dash when the epoch is not `0`). */
38
+ version: string;
39
+ /** The architecture as the package states it (`''` is possible for Alpine). */
40
+ architecture: string;
41
+ /** Gitea's stored file name for the package. */
42
+ fileName: string;
43
+ digests: ILinuxPackageDigests;
44
+ }
45
+
46
+ // ---------------------------------------------------------------- Alpine
47
+
48
+ export interface IAlpinePackageMetadata {
49
+ description: string;
50
+ license: string;
51
+ /** The `.PKGINFO` url when Gitea's URL validation accepts it, else `''`. */
52
+ projectUrl: string;
53
+ maintainer: string;
54
+ packager: string;
55
+ buildDate: number;
56
+ installedSize: number;
57
+ origin: string;
58
+ commit: string;
59
+ installIf: string;
60
+ provides: string[];
61
+ dependencies: string[];
62
+ providerPriority: number;
63
+ }
64
+
65
+ export interface IAlpinePackageRecord extends ILinuxPackageRecordBase {
66
+ format: 'alpine';
67
+ digests: IAlpinePackageDigests;
68
+ metadata: IAlpinePackageMetadata;
69
+ }
70
+
71
+ // ---------------------------------------------------------------- Debian
72
+
73
+ export interface IDebianPackageMetadata {
74
+ /**
75
+ * Gitea's trimmed control stanza, exactly as Gitea 28.2.0 derives it. It is
76
+ * the source of truth for the `Packages` stanza. Index-owned fields a crafted
77
+ * control file carries (`Filename`, `Size`, `MD5sum`, `SHA1`, `SHA256`,
78
+ * `SHA512`) stay in this text; `renderDebianPackagesStanza` strips them
79
+ * because it writes those fields itself.
80
+ */
81
+ control: string;
82
+ /** The name part of the `Maintainer` field, as Gitea derives it. */
83
+ maintainer: string;
84
+ /** The `Homepage` field when Gitea's URL validation accepts it, else `''`. */
85
+ projectUrl: string;
86
+ description: string;
87
+ dependencies: string[];
88
+ }
89
+
90
+ export interface IDebianPackageRecord extends ILinuxPackageRecordBase {
91
+ format: 'debian';
92
+ metadata: IDebianPackageMetadata;
93
+ }
94
+
95
+ // ---------------------------------------------------------------- RPM
96
+
97
+ export interface IRpmDependency {
98
+ name: string;
99
+ flags: '' | 'EQ' | 'LT' | 'GT' | 'LE' | 'GE';
100
+ epoch: string;
101
+ version: string;
102
+ release: string;
103
+ }
104
+
105
+ export interface IRpmFile {
106
+ path: string;
107
+ type: '' | 'dir' | 'ghost';
108
+ isExecutable: boolean;
109
+ }
110
+
111
+ export interface IRpmChangelog {
112
+ author: string;
113
+ date: number;
114
+ text: string;
115
+ }
116
+
117
+ export interface IRpmPackageMetadata {
118
+ epoch: string;
119
+ upstreamVersion: string;
120
+ release: string;
121
+ /** True for a source RPM (lead type). `architecture` stays the ARCH tag, Gitea's identity and path segment. */
122
+ isSourcePackage: boolean;
123
+ summary: string;
124
+ description: string;
125
+ license: string;
126
+ /** The URL tag when Gitea's URL validation accepts it, else `''`. */
127
+ projectUrl: string;
128
+ vendor: string;
129
+ group: string;
130
+ packager: string;
131
+ sourceRpm: string;
132
+ buildHost: string;
133
+ buildTime: number;
134
+ fileTime: number;
135
+ installedSize: number;
136
+ archiveSize: number;
137
+ provides: IRpmDependency[];
138
+ requires: IRpmDependency[];
139
+ conflicts: IRpmDependency[];
140
+ obsoletes: IRpmDependency[];
141
+ files: IRpmFile[];
142
+ changelogs: IRpmChangelog[];
143
+ }
144
+
145
+ export interface IRpmPackageRecord extends ILinuxPackageRecordBase {
146
+ format: 'rpm';
147
+ metadata: IRpmPackageMetadata;
148
+ }
149
+
150
+ /**
151
+ * One RPM errata update (updateinfo `<update>`), plain JSON. Ported from Gitea
152
+ * 28.2.0 `modules/packages/rpm/metadata.go`. Dates are `YYYY-MM-DD HH:MM:SS`
153
+ * (UTC when the codec writes them) or `null`.
154
+ */
155
+ export interface IRpmUpdate {
156
+ id: string;
157
+ from: string;
158
+ status: string;
159
+ type: string;
160
+ version: string;
161
+ title: string;
162
+ severity: string;
163
+ description: string;
164
+ issued: string | null;
165
+ updated: string | null;
166
+ references: IRpmUpdateReference[];
167
+ collections: IRpmUpdateCollection[];
168
+ }
169
+
170
+ export interface IRpmUpdateReference {
171
+ href: string;
172
+ id: string;
173
+ title: string;
174
+ type: string;
175
+ }
176
+
177
+ export interface IRpmUpdateCollection {
178
+ short: string;
179
+ packages: IRpmUpdatePackage[];
180
+ }
181
+
182
+ export interface IRpmUpdatePackage {
183
+ name: string;
184
+ version: string;
185
+ release: string;
186
+ arch: string;
187
+ src: string;
188
+ fileName: string;
189
+ }
190
+
191
+ // ---------------------------------------------------------------- Arch
192
+
193
+ export interface IArchPackageMetadata {
194
+ compression: 'zst' | 'xz' | 'gz';
195
+ base: string;
196
+ description: string;
197
+ /** The `.PKGINFO` url when Gitea's URL validation accepts it, else `''`. */
198
+ projectUrl: string;
199
+ licenses: string[];
200
+ installedSize: number;
201
+ buildDate: number;
202
+ packager: string;
203
+ groups: string[];
204
+ provides: string[];
205
+ replaces: string[];
206
+ depends: string[];
207
+ optDepends: string[];
208
+ makeDepends: string[];
209
+ checkDepends: string[];
210
+ conflicts: string[];
211
+ xdata: string[];
212
+ backup: string[];
213
+ files: string[];
214
+ }
215
+
216
+ export interface IArchPackageRecord extends ILinuxPackageRecordBase {
217
+ format: 'arch';
218
+ metadata: IArchPackageMetadata;
219
+ }
220
+
221
+ // ---------------------------------------------------------------- union
222
+
223
+ export type TLinuxPackageRecord =
224
+ | IAlpinePackageRecord
225
+ | IDebianPackageRecord
226
+ | IRpmPackageRecord
227
+ | IArchPackageRecord;
228
+
229
+ // ---------------------------------------------------------------- index files
230
+
231
+ /**
232
+ * Write order of an index file: every `content` file is written before any
233
+ * `pointer` file (the signed top-level documents that name the content files).
234
+ */
235
+ export type TLinuxIndexFileStage = 'content' | 'pointer';
236
+
237
+ /**
238
+ * One file of a built index set. A builder returns the complete set of files
239
+ * that should exist; any previously written file not in the set is stale.
240
+ */
241
+ export interface ILinuxIndexFile {
242
+ /** Path relative to the format root, in Gitea's layout. */
243
+ path: string;
244
+ bytes: Uint8Array;
245
+ /** Lowercase hex SHA-256 of `bytes`. */
246
+ sha256: string;
247
+ mediaType: string;
248
+ stage: TLinuxIndexFileStage;
249
+ /** Other paths serving the same bytes (Debian `by-hash/<ALGO>/<hex>` for every listed hash). */
250
+ aliases: string[];
251
+ }