@grimoire-rs/indexer 0.3.3 → 0.4.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 (89) hide show
  1. package/README.md +137 -2
  2. package/dist/ci.d.ts +6 -1
  3. package/dist/ci.d.ts.map +1 -1
  4. package/dist/ci.js +32 -1
  5. package/dist/ci.js.map +1 -1
  6. package/dist/cli/build.d.ts.map +1 -1
  7. package/dist/cli/build.js +3 -1
  8. package/dist/cli/build.js.map +1 -1
  9. package/dist/cli/ci.d.ts.map +1 -1
  10. package/dist/cli/ci.js +5 -1
  11. package/dist/cli/ci.js.map +1 -1
  12. package/dist/cli/init.d.ts.map +1 -1
  13. package/dist/cli/init.js +17 -3
  14. package/dist/cli/init.js.map +1 -1
  15. package/dist/cli/main.d.ts.map +1 -1
  16. package/dist/cli/main.js +8 -0
  17. package/dist/cli/main.js.map +1 -1
  18. package/dist/cli/ratings.d.ts +3 -0
  19. package/dist/cli/ratings.d.ts.map +1 -0
  20. package/dist/cli/ratings.js +160 -0
  21. package/dist/cli/ratings.js.map +1 -0
  22. package/dist/config.d.ts +19 -0
  23. package/dist/config.d.ts.map +1 -1
  24. package/dist/config.js +47 -1
  25. package/dist/config.js.map +1 -1
  26. package/dist/enrich/index.d.ts.map +1 -1
  27. package/dist/enrich/index.js +74 -1
  28. package/dist/enrich/index.js.map +1 -1
  29. package/dist/ratings/budget.d.ts +16 -0
  30. package/dist/ratings/budget.d.ts.map +1 -0
  31. package/dist/ratings/budget.js +7 -0
  32. package/dist/ratings/budget.js.map +1 -0
  33. package/dist/ratings/config.d.ts +56 -0
  34. package/dist/ratings/config.d.ts.map +1 -0
  35. package/dist/ratings/config.js +86 -0
  36. package/dist/ratings/config.js.map +1 -0
  37. package/dist/ratings/marker.d.ts +105 -0
  38. package/dist/ratings/marker.d.ts.map +1 -0
  39. package/dist/ratings/marker.js +141 -0
  40. package/dist/ratings/marker.js.map +1 -0
  41. package/dist/ratings/provider.d.ts +108 -0
  42. package/dist/ratings/provider.d.ts.map +1 -0
  43. package/dist/ratings/provider.js +202 -0
  44. package/dist/ratings/provider.js.map +1 -0
  45. package/dist/ratings/provider_github.d.ts +3 -0
  46. package/dist/ratings/provider_github.d.ts.map +1 -0
  47. package/dist/ratings/provider_github.js +134 -0
  48. package/dist/ratings/provider_github.js.map +1 -0
  49. package/dist/ratings/provider_gitlab.d.ts +3 -0
  50. package/dist/ratings/provider_gitlab.d.ts.map +1 -0
  51. package/dist/ratings/provider_gitlab.js +152 -0
  52. package/dist/ratings/provider_gitlab.js.map +1 -0
  53. package/dist/ratings/provider_memory.d.ts +28 -0
  54. package/dist/ratings/provider_memory.d.ts.map +1 -0
  55. package/dist/ratings/provider_memory.js +49 -0
  56. package/dist/ratings/provider_memory.js.map +1 -0
  57. package/dist/ratings/reconcile.d.ts +47 -0
  58. package/dist/ratings/reconcile.d.ts.map +1 -0
  59. package/dist/ratings/reconcile.js +133 -0
  60. package/dist/ratings/reconcile.js.map +1 -0
  61. package/dist/ratings/seed.d.ts +60 -0
  62. package/dist/ratings/seed.d.ts.map +1 -0
  63. package/dist/ratings/seed.js +132 -0
  64. package/dist/ratings/seed.js.map +1 -0
  65. package/dist/renderer/astro/components/Catalog.d.ts +2 -0
  66. package/dist/renderer/astro/components/Catalog.js +64 -15
  67. package/dist/renderer/astro/components/Catalog.tsx +104 -17
  68. package/dist/renderer/astro/layouts/Base.astro +7 -0
  69. package/dist/renderer/astro/lib/catalog.d.ts +25 -0
  70. package/dist/renderer/astro/lib/catalog.js +46 -0
  71. package/dist/renderer/astro/lib/catalog.ts +49 -0
  72. package/dist/renderer/astro/pages/p/[...slug].astro +146 -3
  73. package/dist/renderer/index.d.ts.map +1 -1
  74. package/dist/renderer/index.js +101 -2
  75. package/dist/renderer/index.js.map +1 -1
  76. package/dist/renderer/types.d.ts +41 -0
  77. package/dist/renderer/types.d.ts.map +1 -1
  78. package/dist/validate/adapters/http.d.ts +6 -1
  79. package/dist/validate/adapters/http.d.ts.map +1 -1
  80. package/dist/validate/adapters/http.js +5 -1
  81. package/dist/validate/adapters/http.js.map +1 -1
  82. package/package.json +1 -1
  83. package/templates/ci/github-pages.yml +11 -5
  84. package/templates/ci/github-ratings-seed.yml +88 -0
  85. package/templates/ci/github-ratings.yml +51 -0
  86. package/templates/ci/gitlab-ci.yml +3 -3
  87. package/templates/ci/gitlab-ratings-seed.sh +83 -0
  88. package/templates/ci/gitlab-ratings.yml +37 -0
  89. package/templates/gitignore +8 -0
@@ -0,0 +1,160 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright 2026 The Grimoire Authors
3
+ // `grim-indexer ratings` — the tally job. Reads the forge's own upvote
4
+ // counters and writes `.stats.json` beside the checkout for `build` to join.
5
+ //
6
+ // Thin by design, like `enrich`: resolve the configuration, construct the
7
+ // provider, run the reconcile, write the file, print the one log line. Every
8
+ // rule lives in `src/ratings/`.
9
+ import fs from "node:fs";
10
+ import path from "node:path";
11
+ import { CliError, EXIT } from "./exit.js";
12
+ import { parseRef } from "../validate/core/metadata.js";
13
+ /** An environment variable, treating the empty string as unset (CI sets both). */
14
+ function env(name) {
15
+ const value = process.env[name];
16
+ return value === undefined || value === "" ? undefined : value;
17
+ }
18
+ /**
19
+ * Where the bot talks to the forge, who it is, and what it may do.
20
+ *
21
+ * Read from the CI-predefined variables rather than `index.config.json`, so a
22
+ * GHES or self-managed GitLab index needs no extra configuration — and so the
23
+ * credential is never a committed file. `CI_JOB_TOKEN` is deliberately absent:
24
+ * it inherits the triggering user's role, which would satisfy R-1 clause 2 with
25
+ * a human's identity.
26
+ */
27
+ function forgeEnv(provider) {
28
+ const [api, project, token] = provider === "github"
29
+ ? [
30
+ env("GITHUB_GRAPHQL_URL") ?? "https://api.github.com/graphql",
31
+ env("GITHUB_REPOSITORY"),
32
+ env("GRIM_RATINGS_TOKEN") ?? env("GITHUB_TOKEN"),
33
+ ]
34
+ : [
35
+ env("CI_API_GRAPHQL_URL") ??
36
+ (env("CI_SERVER_URL") !== undefined
37
+ ? `${env("CI_SERVER_URL")}/api/graphql`
38
+ : "https://gitlab.com/api/graphql"),
39
+ env("CI_PROJECT_PATH"),
40
+ env("GRIM_RATINGS_TOKEN"),
41
+ ];
42
+ if (project === undefined) {
43
+ throw new CliError(`ratings: cannot tell which ${provider === "github" ? "repository" : "project"} holds the ` +
44
+ `threads — set ${provider === "github" ? "GITHUB_REPOSITORY" : "CI_PROJECT_PATH"}`, EXIT.data);
45
+ }
46
+ if (token === undefined) {
47
+ throw new CliError(`ratings: no credential — set ${provider === "github"
48
+ ? "GITHUB_TOKEN (permissions: discussions: write) or GRIM_RATINGS_TOKEN"
49
+ : "GRIM_RATINGS_TOKEN to a project access token with `api` scope (CI_JOB_TOKEN cannot write reactions)"}`, EXIT.data);
50
+ }
51
+ return { api: api ?? "", project, token };
52
+ }
53
+ /** Every ref in `index/`. The tally runs before `build`, so `all.json` does not exist yet. */
54
+ function desiredRefs(root, findMetadataFiles) {
55
+ const refs = [];
56
+ for (const file of findMetadataFiles(path.join(root, "index"))) {
57
+ let meta;
58
+ try {
59
+ meta = JSON.parse(fs.readFileSync(file, "utf8"));
60
+ }
61
+ catch (err) {
62
+ throw new CliError(`${file}: ${err.message}`, EXIT.data);
63
+ }
64
+ const ref = meta.ref;
65
+ if (typeof ref !== "string" || ref === "")
66
+ continue;
67
+ // The ref is interpolated into a thread body that R-1 later parses back
68
+ // out of that same body. R-1's four clauses constrain *who wrote* the
69
+ // body and *where the thread lives* — none of them constrains what is in
70
+ // it — so an unvalidated ref carrying a newline injects a second, bare,
71
+ // column-0 marker line that the bot itself then authors. Every clause
72
+ // passes, and the forged binding either zeroes a popular package's rating
73
+ // (two claimants) or points every vote for it at the attacker's thread.
74
+ // `parseRef`'s anchored host/repository grammars have no newline in them.
75
+ const parsed = parseRef(ref);
76
+ if (!parsed.ok) {
77
+ throw new CliError(`${file}: ${parsed.reason}`, EXIT.data);
78
+ }
79
+ refs.push(ref);
80
+ }
81
+ return refs;
82
+ }
83
+ export async function ratings(root) {
84
+ const rootDir = path.resolve(root);
85
+ const { loadRatingsConfig } = await import("../ratings/config.js");
86
+ const cfg = await loadRatingsConfig(rootDir);
87
+ if (!cfg) {
88
+ // The block being absent is how ratings are off. Nothing is written, so a
89
+ // published sidecar keeps serving until the operator deletes it (S-016).
90
+ console.log("ratings: no `ratings` block in index.config.json — nothing to tally");
91
+ return EXIT.ok;
92
+ }
93
+ const { loadConfig } = await import("../config.js");
94
+ const site = (await loadConfig(rootDir)).site;
95
+ if (site === undefined || !site.startsWith("https://")) {
96
+ // Not defaulted. `DEFAULT_CONFIG.site` names the first-party index, and
97
+ // seeding from *someone else's* published stats would merge their ratings
98
+ // into this one's sidecar. https because the seed decides every published
99
+ // rating — and refused *here*, before a single thread is created, because
100
+ // the generated deploy job enforces the same rule far too late to help:
101
+ // by then the tally has already written to the forge.
102
+ throw new CliError("ratings: index.config.json needs an explicit https `site` — the seed is read from `<site>/stats.json`", EXIT.data);
103
+ }
104
+ const { trustedBots } = readPolicy(rootDir);
105
+ if (!trustedBots.some((bot) => typeof bot !== "string" && bot.id !== undefined)) {
106
+ // R-1 clause 2 has an account id and no login in hand, so a login-only
107
+ // entry authorizes nothing — every thread would be dropped and the run
108
+ // would publish an empty tally that looked like a healthy one.
109
+ throw new CliError("ratings: index-policy.json has no `trustedBots` entry with an `id` — R-1 would authorize nothing", EXIT.data);
110
+ }
111
+ const forge = forgeEnv(cfg.provider);
112
+ const { findMetadataFiles } = await import("../data/index.js");
113
+ const desired = desiredRefs(rootDir, findMetadataFiles);
114
+ const { loadSeed, mergeStats, statsDocument, STATS_FILE } = await import("../ratings/seed.js");
115
+ // Read before the forge work: it fails the run on anything but a genuine 404,
116
+ // and failing before a single thread is created is the cheaper order.
117
+ const seed = await loadSeed(`${site.replace(/\/+$/, "")}/stats.json`);
118
+ const { createRatingProvider } = await import("../ratings/provider.js");
119
+ const { conflictWarning, logLine, reconcile } = await import("../ratings/reconcile.js");
120
+ const result = await reconcile({
121
+ provider: createRatingProvider(cfg.provider, { ...forge, container: cfg.container, lockThreads: cfg.lockThreads, trustedBots }),
122
+ desired,
123
+ budget: cfg.createBudget,
124
+ seed,
125
+ });
126
+ if (result.starved) {
127
+ throw new CliError("ratings: rate limited before anything could be observed — nothing to publish, " +
128
+ "leaving the previous sidecar in place", EXIT.unavailable);
129
+ }
130
+ for (const conflict of result.conflicts)
131
+ console.error(conflictWarning(conflict));
132
+ const doc = statsDocument(mergeStats(seed, "rating", cfg.provider, result.fresh));
133
+ fs.writeFileSync(path.join(rootDir, STATS_FILE), JSON.stringify(doc, null, 2) + "\n");
134
+ console.log(logLine(result));
135
+ return EXIT.ok;
136
+ }
137
+ /** `index-policy.json`'s `trustedBots` — the same file the contribution gate reads. */
138
+ function readPolicy(root) {
139
+ const file = path.join(root, "index-policy.json");
140
+ let text;
141
+ try {
142
+ text = fs.readFileSync(file, "utf8");
143
+ }
144
+ catch {
145
+ throw new CliError(`ratings: ${file} is required — R-1 reads the bot allowlist out of its \`trustedBots\``, EXIT.data);
146
+ }
147
+ let parsed;
148
+ try {
149
+ parsed = JSON.parse(text);
150
+ }
151
+ catch (err) {
152
+ throw new CliError(`${file}: ${err.message}`, EXIT.data);
153
+ }
154
+ const bots = parsed?.trustedBots;
155
+ if (bots !== undefined && !Array.isArray(bots)) {
156
+ throw new CliError(`${file}: trustedBots must be an array`, EXIT.data);
157
+ }
158
+ return { trustedBots: (bots ?? []) };
159
+ }
160
+ //# sourceMappingURL=ratings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ratings.js","sourceRoot":"","sources":["../../src/cli/ratings.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -100,6 +100,25 @@ export declare const DEFAULT_CONFIG: ResolvedSiteConfig;
100
100
  export declare class SiteConfigError extends Error {
101
101
  constructor(message: string);
102
102
  }
103
+ /**
104
+ * `site` is the strictest of the URL keys, deliberately: it is the only one that
105
+ * is *fetched* as well as published. `<site>/stats.json` is the ratings seed —
106
+ * read by `grim-indexer ratings`, and from the same checkout by the generated
107
+ * deploy job — and whatever that fetch returns is the merge base for every
108
+ * published rating. One policy, here, at load: the verbs, the renderer and the
109
+ * generated shell must not disagree about the same key.
110
+ *
111
+ * No userinfo, because `https://real.example@evil.example/` reads as the real
112
+ * host and fetches from the other. No query or fragment, because
113
+ * `<site>/stats.json` appends to them and quietly fetches something else.
114
+ * Lowercase scheme, because the generated guard matches that literal prefix.
115
+ *
116
+ * TLS is *not* required here: `init --quick` writes `http://localhost:4321` as
117
+ * its deliberate placeholder, and a site with no ratings never fetches
118
+ * anything. `grim-indexer ratings` requires https before it writes to the
119
+ * forge, which is the earliest point that requirement exists.
120
+ */
121
+ export declare function validateSite(value: unknown): void;
103
122
  /**
104
123
  * Read `index.config.json` from `root`. A missing file is not an
105
124
  * error — an index repo that wants the defaults ships no config at all.
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAUA,+DAA+D;AAC/D,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;AAEtD,eAAO,MAAM,cAAc,EAAE,kBAwC5B,CAAC;AAEF,2EAA2E;AAC3E,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAoGD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAelE;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,kBAAkB,CAWpE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAUA,+DAA+D;AAC/D,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;AAEtD,eAAO,MAAM,cAAc,EAAE,kBAwC5B,CAAC;AAEF,2EAA2E;AAC3E,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAwBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAuBjD;AA+ED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAelE;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,kBAAkB,CAWpE"}
package/dist/config.js CHANGED
@@ -73,6 +73,51 @@ function optionalUrl(raw, key) {
73
73
  fail(`${key} must be an http(s) URL`);
74
74
  }
75
75
  }
76
+ /**
77
+ * `site` is the strictest of the URL keys, deliberately: it is the only one that
78
+ * is *fetched* as well as published. `<site>/stats.json` is the ratings seed —
79
+ * read by `grim-indexer ratings`, and from the same checkout by the generated
80
+ * deploy job — and whatever that fetch returns is the merge base for every
81
+ * published rating. One policy, here, at load: the verbs, the renderer and the
82
+ * generated shell must not disagree about the same key.
83
+ *
84
+ * No userinfo, because `https://real.example@evil.example/` reads as the real
85
+ * host and fetches from the other. No query or fragment, because
86
+ * `<site>/stats.json` appends to them and quietly fetches something else.
87
+ * Lowercase scheme, because the generated guard matches that literal prefix.
88
+ *
89
+ * TLS is *not* required here: `init --quick` writes `http://localhost:4321` as
90
+ * its deliberate placeholder, and a site with no ratings never fetches
91
+ * anything. `grim-indexer ratings` requires https before it writes to the
92
+ * forge, which is the earliest point that requirement exists.
93
+ */
94
+ export function validateSite(value) {
95
+ if (value === undefined)
96
+ return;
97
+ if (typeof value !== "string")
98
+ fail("site must be a string");
99
+ // WHATWG `new URL` strips embedded tabs and newlines, so a control character
100
+ // survives into the raw value every consumer uses while the parsed URL looks
101
+ // clean — and a newline in a generated `::error::` line is a workflow command.
102
+ // No `i` flag: one spelling, so the generated shell can match the literal
103
+ // prefix and `grim-indexer ratings` can compare without a case fold.
104
+ if (!/^https?:\/\//.test(value) || /\s/.test(value)) {
105
+ fail("site must be an http(s) URL — lowercase scheme, no whitespace");
106
+ }
107
+ let url;
108
+ try {
109
+ url = new URL(value);
110
+ }
111
+ catch {
112
+ fail("site must be an absolute URL, e.g. https://index.example.com");
113
+ }
114
+ if (url.username !== "" || url.password !== "") {
115
+ fail("site must not carry userinfo — https://user@host reads as one host and fetches another");
116
+ }
117
+ if (url.search !== "" || url.hash !== "") {
118
+ fail("site must be a bare base URL — no query, no fragment");
119
+ }
120
+ }
76
121
  function validate(raw) {
77
122
  if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
78
123
  fail("must contain a JSON object");
@@ -81,9 +126,10 @@ function validate(raw) {
81
126
  for (const key of ["brand", "brandMark", "description", "tagline", "favicon", "footerNote", "customCss"]) {
82
127
  optionalString(cfg, key);
83
128
  }
84
- for (const key of ["site", "docsUrl", "installDocsUrl", "repoUrl"]) {
129
+ for (const key of ["docsUrl", "installDocsUrl", "repoUrl"]) {
85
130
  optionalUrl(cfg, key);
86
131
  }
132
+ validateSite(cfg.site);
87
133
  if (cfg.attribution !== undefined && typeof cfg.attribution !== "boolean") {
88
134
  fail("attribution must be a boolean");
89
135
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/enrich/index.ts"],"names":[],"mappings":"AAuCA,wFAAwF;AACxF,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE9D,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,GAAG,CAAC,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AASD,wBAAgB,SAAS,CAAC,GAAG,SAAS,GAAG,UAAU,CASlD;AAwLD,wBAAsB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAsB5E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/enrich/index.ts"],"names":[],"mappings":"AAuCA,wFAAwF;AACxF,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE9D,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,GAAG,CAAC,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AASD,wBAAgB,SAAS,CAAC,GAAG,SAAS,GAAG,UAAU,CASlD;AAkQD,wBAAsB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAsB5E"}
@@ -41,6 +41,57 @@ export function spawnGrim(bin = "grim") {
41
41
  return JSON.parse(stdout);
42
42
  };
43
43
  }
44
+ /**
45
+ * The curated fields copied straight across from `describe`, in the order
46
+ * they are written to disk. Every one is optional on the wire: a grim older
47
+ * than the annotation work reports the first five and nothing after them,
48
+ * and `compatibility` is null for every kind but a skill. Absent is absent —
49
+ * no placeholder is written for a field the registry did not report.
50
+ */
51
+ const META_KEYS = [
52
+ "title",
53
+ "summary",
54
+ "version",
55
+ "license",
56
+ "created",
57
+ "revision",
58
+ "authors",
59
+ "vendor",
60
+ "url",
61
+ "documentation",
62
+ "compatibility",
63
+ ];
64
+ /**
65
+ * The support channels, in the order `describe` reports them.
66
+ *
67
+ * They come off the *description companion's* manifest rather than the
68
+ * version's, because a maintainer contact belongs to the repository and
69
+ * changes over time. That has no effect on how they are refreshed here:
70
+ * `describe` runs on every pass and is never skipped, so a support link
71
+ * edited without republishing any artifact still lands on the next enrich —
72
+ * it is only the companion *download* and the contents fetch that a digest
73
+ * skips.
74
+ */
75
+ const SUPPORT_CHANNELS = ["issues", "chat", "contact", "security"];
76
+ /**
77
+ * The `support` block, or nothing.
78
+ *
79
+ * A repository publishing no companion reports four nulls, and four nulls
80
+ * are the *absence* of a support block rather than an empty one — writing
81
+ * them would put a key in every sidecar in the index for the sake of the
82
+ * repositories that have nothing to say.
83
+ */
84
+ function mapSupport(raw) {
85
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw))
86
+ return undefined;
87
+ const reported = raw;
88
+ const support = {};
89
+ for (const channel of SUPPORT_CHANNELS) {
90
+ if (reported[channel] != null)
91
+ support[channel] = reported[channel];
92
+ }
93
+ return Object.keys(support).length > 0 ? support : undefined;
94
+ }
44
95
  /**
45
96
  * grim's snake_case `describe` payload -> the camelCase fields the renderer
46
97
  * reads. Key insertion order is the on-disk order, and these sidecars are
@@ -49,10 +100,13 @@ export function spawnGrim(bin = "grim") {
49
100
  */
50
101
  function mapMeta(desc) {
51
102
  const data = {};
52
- for (const key of ["title", "summary", "version", "license", "created"]) {
103
+ for (const key of META_KEYS) {
53
104
  if (desc[key] != null)
54
105
  data[key] = desc[key];
55
106
  }
107
+ const support = mapSupport(desc.support);
108
+ if (support)
109
+ data.support = support;
56
110
  data.keywords = desc.keywords ?? [];
57
111
  data.tags = desc.tags ?? [];
58
112
  data.deprecated = desc.deprecated ?? null; // string | null, always present
@@ -203,6 +257,25 @@ async function enrichOne(run, enrichDir, ref, namespace, name) {
203
257
  data.contentDigest = digest;
204
258
  data.hasContents = written;
205
259
  }
260
+ // Recency is an indexer-side join, not something grim publishes: `describe`
261
+ // runs here per package on every pass, so nothing upstream has to carry a
262
+ // second date. The artifact's own `created` is it whenever there is one —
263
+ // it is the commit date, so a re-publish of the same commit keeps the same
264
+ // answer. An artifact published outside a repository (or with `--no-git`)
265
+ // has none, and then recency is when *this index* first saw the current
266
+ // digest. The digest bookkeeping above is the only state that can answer
267
+ // "first", so the stamp rides with it and is re-taken only when the
268
+ // artifact actually moved — a fresh stamp every run would churn a
269
+ // committed file and date every package to the last enrich.
270
+ const moved = digest !== null && digest !== existing.contentDigest;
271
+ data.updated =
272
+ typeof data.created === "string"
273
+ ? data.created
274
+ : !moved && typeof existing.updated === "string"
275
+ ? existing.updated
276
+ // RFC 3339 UTC to the second. Milliseconds in a committed file are
277
+ // noise nobody reads and a wider diff when the stamp does move.
278
+ : new Date().toISOString().replace(/\.\d+Z$/, "Z");
206
279
  fs.mkdirSync(out, { recursive: true });
207
280
  fs.writeFileSync(dataFile, JSON.stringify(data, null, 1) + "\n");
208
281
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/enrich/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/enrich/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The per-run creation cap, and the order it applies in.
3
+ *
4
+ * The sort is load-bearing, not tidiness: it is what lets run *N+1* resume
5
+ * exactly where run *N* stopped with no cursor file anywhere. `actions/stale`
6
+ * keeps a resume cursor as an optimization; correctness there, as here, never
7
+ * depends on it.
8
+ */
9
+ export interface CreationPlan {
10
+ /** Every ref with no thread yet, sorted. `created=X/Y`'s Y. */
11
+ missing: string[];
12
+ /** The prefix of `missing` this run may create. */
13
+ batch: string[];
14
+ }
15
+ export declare function planCreations(desired: Iterable<string>, observed: ReadonlySet<string>, budget: number): CreationPlan;
16
+ //# sourceMappingURL=budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../../src/ratings/budget.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mDAAmD;IACnD,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,EACzB,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,EAC7B,MAAM,EAAE,MAAM,GACb,YAAY,CAGd"}
@@ -0,0 +1,7 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright 2026 The Grimoire Authors
3
+ export function planCreations(desired, observed, budget) {
4
+ const missing = [...new Set(desired)].filter((ref) => !observed.has(ref)).sort();
5
+ return { missing, batch: missing.slice(0, Math.max(0, budget)) };
6
+ }
7
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../src/ratings/budget.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,sCAAsC;AAkBtC,MAAM,UAAU,aAAa,CAC3B,OAAyB,EACzB,QAA6B,EAC7B,MAAc;IAEd,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACjF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;AACnE,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Forges a rating can be collected on. The same two names as CI's [`Forge`],
3
+ * and deliberately a separate type: an index hosted on one forge could tally
4
+ * on the other, and nothing here needs them to move together.
5
+ */
6
+ export type RatingProviderKind = "github" | "gitlab";
7
+ export declare const RATING_PROVIDERS: readonly RatingProviderKind[];
8
+ /** Per-run thread-creation budget when the config names none. */
9
+ export declare const DEFAULT_CREATE_BUDGET = 400;
10
+ /**
11
+ * The `ratings` block, with every gap filled. The block being absent means
12
+ * ratings are off — that is the *absence* of this value, not a variant of it,
13
+ * so every reader gets `undefined` and has nothing to branch on twice.
14
+ */
15
+ export interface RatingsConfig {
16
+ /** Which forge holds the threads. Required — there is no sensible default. */
17
+ provider: RatingProviderKind;
18
+ /**
19
+ * Where threads live: a GitHub Discussions **category** name, or a GitLab
20
+ * **work item type**. Required, and no default is offered — "Ratings" is a
21
+ * category an operator creates, while GitLab's work item types are a closed
22
+ * set, so a default correct on one forge would be wrong on the other.
23
+ */
24
+ container: string;
25
+ /**
26
+ * Threads created per run. Default {@link DEFAULT_CREATE_BUDGET}, which sits
27
+ * under GitHub's 500-per-hour content-creation cap with room for the retries
28
+ * a run may spend. A partial run creates *fewer threads*, never corrupt
29
+ * state, so the only cost of a small budget is more runs to converge.
30
+ */
31
+ createBudget: number;
32
+ /**
33
+ * Lock every thread on creation. **Default `true`**: votes still count,
34
+ * replies are refused.
35
+ *
36
+ * Two things at once. It is the low-moderation default — an operator gets a
37
+ * rating signal without also running a comment forum they have to moderate.
38
+ * And it independently hardens R-1 clause 1: a locked thread cannot receive
39
+ * the forged-marker reply that clause exists to reject, so the marker rule
40
+ * and the lock have to fail together before a stranger's text is counted.
41
+ */
42
+ lockThreads: boolean;
43
+ }
44
+ /**
45
+ * Validate the `ratings` block of an already-parsed config object.
46
+ *
47
+ * Absent (or `null`) ⇒ `undefined` ⇒ ratings off. Unknown keys are ignored,
48
+ * the same forward-compatibility rule `stats.json` itself follows.
49
+ */
50
+ export declare function validateRatings(raw: unknown): RatingsConfig | undefined;
51
+ /**
52
+ * Read the `ratings` block out of `index.config.json`. A missing file, or a
53
+ * file with no `ratings` block, means ratings are off.
54
+ */
55
+ export declare function loadRatingsConfig(root: string): Promise<RatingsConfig | undefined>;
56
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/ratings/config.ts"],"names":[],"mappings":"AAiBA;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAErD,eAAO,MAAM,gBAAgB,EAAE,SAAS,kBAAkB,EAAyB,CAAC;AAEpF,iEAAiE;AACjE,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,QAAQ,EAAE,kBAAkB,CAAC;IAC7B;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;;;;OASG;IACH,WAAW,EAAE,OAAO,CAAC;CACtB;AAMD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,GAAG,SAAS,CAgCvE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAkBxF"}
@@ -0,0 +1,86 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright 2026 The Grimoire Authors
3
+ // The `ratings` block of `index.config.json` — the third independent reader of
4
+ // that file, beside `config.ts` (the site) and `ci.ts` (the pipeline). One
5
+ // loader for all three would couple the renderer, the CI generator and the
6
+ // tally to each other's validation for the sake of one `readFile`; each stays
7
+ // able to fail on its own block and say so in its own words.
8
+ //
9
+ // There is deliberately no `botIds` key here. The author allowlist is
10
+ // `index-policy.json`'s `trustedBots[].id` and nothing else — a second copy of
11
+ // the same ids in a second file is a consistency hazard, not a convenience.
12
+ import fs from "node:fs/promises";
13
+ import path from "node:path";
14
+ import { CONFIG_FILE, SiteConfigError } from "../config.js";
15
+ export const RATING_PROVIDERS = ["github", "gitlab"];
16
+ /** Per-run thread-creation budget when the config names none. */
17
+ export const DEFAULT_CREATE_BUDGET = 400;
18
+ function fail(msg) {
19
+ throw new SiteConfigError(`${CONFIG_FILE}: ratings.${msg}`);
20
+ }
21
+ /**
22
+ * Validate the `ratings` block of an already-parsed config object.
23
+ *
24
+ * Absent (or `null`) ⇒ `undefined` ⇒ ratings off. Unknown keys are ignored,
25
+ * the same forward-compatibility rule `stats.json` itself follows.
26
+ */
27
+ export function validateRatings(raw) {
28
+ if (raw === undefined || raw === null)
29
+ return undefined;
30
+ if (typeof raw !== "object" || Array.isArray(raw)) {
31
+ throw new SiteConfigError(`${CONFIG_FILE}: ratings must be an object`);
32
+ }
33
+ const ratings = raw;
34
+ if (!RATING_PROVIDERS.includes(ratings.provider)) {
35
+ fail(`provider must be one of ${RATING_PROVIDERS.join(", ")}`);
36
+ }
37
+ if (typeof ratings.container !== "string" || ratings.container.trim() === "") {
38
+ fail("container must be a non-empty string - a GitHub Discussions category, or a GitLab work item type");
39
+ }
40
+ if (ratings.createBudget !== undefined) {
41
+ if (typeof ratings.createBudget !== "number" || !Number.isInteger(ratings.createBudget)) {
42
+ fail("createBudget must be a whole number");
43
+ }
44
+ if (ratings.createBudget < 0)
45
+ fail("createBudget must not be negative");
46
+ }
47
+ if (ratings.lockThreads !== undefined && typeof ratings.lockThreads !== "boolean") {
48
+ fail("lockThreads must be a boolean");
49
+ }
50
+ // Built key by key rather than spread: the returned value is the four
51
+ // documented keys and nothing else, so an unknown key is ignored in the
52
+ // strong sense — it cannot reach a consumer that happens to look for it.
53
+ return {
54
+ provider: ratings.provider,
55
+ container: ratings.container,
56
+ createBudget: ratings.createBudget ?? DEFAULT_CREATE_BUDGET,
57
+ lockThreads: ratings.lockThreads ?? true,
58
+ };
59
+ }
60
+ /**
61
+ * Read the `ratings` block out of `index.config.json`. A missing file, or a
62
+ * file with no `ratings` block, means ratings are off.
63
+ */
64
+ export async function loadRatingsConfig(root) {
65
+ let text;
66
+ try {
67
+ text = await fs.readFile(path.join(root, CONFIG_FILE), "utf8");
68
+ }
69
+ catch (err) {
70
+ if (err.code === "ENOENT")
71
+ return undefined;
72
+ throw err;
73
+ }
74
+ let parsed;
75
+ try {
76
+ parsed = JSON.parse(text);
77
+ }
78
+ catch (err) {
79
+ throw new SiteConfigError(`${CONFIG_FILE}: ${err.message}`);
80
+ }
81
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
82
+ throw new SiteConfigError(`${CONFIG_FILE}: must contain a JSON object`);
83
+ }
84
+ return validateRatings(parsed.ratings);
85
+ }
86
+ //# sourceMappingURL=config.js.map