@gjsify/site 0.64.26-next.312 → 0.64.26

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/README.md CHANGED
@@ -46,6 +46,7 @@ gjsify site build --runtime node # build and run on a specific runtime
46
46
  | `--drafts` | `build`: include blog posts marked `draft: true`. |
47
47
  | `--no-cache` | Ignore the one-hour HTTP response cache. |
48
48
  | `--cache-dir <dir>` | Where the response cache and the image renditions live. Default: `<root>/node_modules/.cache/gjsify-site`. |
49
+ | `--release-tag <tag>` | `build`: take the download links from this GitHub release (`releases/tags/<tag>`) instead of `releases/latest`, which can lag a fresh publish by minutes. Default: `$GJSIFY_SITE_RELEASE_TAG`. |
49
50
  | `--check` | `i18n`: report what is out of date instead of writing it. |
50
51
  | `--runtime <r>` | `gjs` \| `node` \| `bun` \| `deno`. Default: the runtime the CLI itself is on. |
51
52
 
@@ -166,6 +167,11 @@ shared package can derive.
166
167
  `GITHUB_TOKEN` is optional and only raises the API rate limit. When a lookup fails the build
167
168
  warns rather than failing: a release API outage is not a reason to have no page.
168
169
 
170
+ The build logs which release it used (tag, publish date, asset count) and warns when that release's
171
+ version differs from the version the page shows. A deploy triggered by `release: published` should
172
+ pass `--release-tag "$GITHUB_REF_NAME"` (or set `GJSIFY_SITE_RELEASE_TAG`): `releases/latest` can still
173
+ answer with the previous release for a few minutes.
174
+
169
175
  The same thing from a script:
170
176
 
171
177
  ```ts
package/lib/cli.js CHANGED
@@ -22,6 +22,9 @@ Options:
22
22
  --no-cache Ignore the one-hour HTTP response cache
23
23
  --cache-dir <dir> Where to keep the response cache and image renditions
24
24
  (default: <root>/node_modules/.cache/gjsify-site)
25
+ --release-tag <t> build: take the download links from this GitHub release
26
+ instead of \`releases/latest\`, which lags a fresh publish
27
+ (default: $GJSIFY_SITE_RELEASE_TAG)
25
28
  --check i18n: report what is out of date instead of writing it
26
29
  --store <s> listing: cws | edge | amo | all (default: all)
27
30
  --metainfo <path> listing: AppStream metainfo, overriding the configured one
@@ -33,7 +36,8 @@ Options:
33
36
  from this module's own location)
34
37
  -h, --help Show this text
35
38
 
36
- Environment: GITHUB_TOKEN raises the GitHub API rate limit.`;
39
+ Environment: GITHUB_TOKEN raises the GitHub API rate limit.
40
+ GJSIFY_SITE_RELEASE_TAG is the default of --release-tag.`;
37
41
  /** The value after `--name`, or `undefined` when the flag is absent. */
38
42
  function flagValue(flags, name) {
39
43
  const index = flags.indexOf(name);
@@ -59,6 +63,8 @@ async function build(flags) {
59
63
  cacheDir: cacheOption(flags),
60
64
  packageDir: flagValue(flags, '--package-dir'),
61
65
  githubToken: process.env.GITHUB_TOKEN || undefined,
66
+ releaseTag: flagValue(flags, '--release-tag') ?? (process.env.GJSIFY_SITE_RELEASE_TAG || undefined),
67
+ log: (message) => console.log(message),
62
68
  warn: (message) => console.warn(`warning: ${message}`),
63
69
  });
64
70
  console.log(`Built the pages in ${result.languages.length} languages and ${result.screenshots} screenshots`);
@@ -11,5 +11,9 @@ export declare function fetchReleaseRecords(assets: readonly ReleaseAsset[], opt
11
11
  /**
12
12
  * Fetches the latest published (non-draft, non-prerelease) release; `null` when the repository has
13
13
  * none yet, which is a state and not an error. `token` raises the rate limit.
14
+ *
15
+ * With `tag`, fetches exactly that release instead. `releases/latest` lags a fresh publish by
16
+ * minutes, so a deploy triggered by the release itself must be able to name it; a pinned tag that
17
+ * does not exist is an error, not "no release yet".
14
18
  */
15
- export declare function fetchLatestRelease(repository: string, token: string | undefined, options: NetworkOptions): Promise<LatestRelease | null>;
19
+ export declare function fetchLatestRelease(repository: string, token: string | undefined, options: NetworkOptions, tag?: string): Promise<LatestRelease | null>;
@@ -55,8 +55,12 @@ export async function fetchReleaseRecords(assets, options, warn) {
55
55
  /**
56
56
  * Fetches the latest published (non-draft, non-prerelease) release; `null` when the repository has
57
57
  * none yet, which is a state and not an error. `token` raises the rate limit.
58
+ *
59
+ * With `tag`, fetches exactly that release instead. `releases/latest` lags a fresh publish by
60
+ * minutes, so a deploy triggered by the release itself must be able to name it; a pinned tag that
61
+ * does not exist is an error, not "no release yet".
58
62
  */
59
- export async function fetchLatestRelease(repository, token, options) {
63
+ export async function fetchLatestRelease(repository, token, options, tag) {
60
64
  const headers = {
61
65
  Accept: 'application/vnd.github+json',
62
66
  'User-Agent': `${repository.replace('/', '-')}-website`,
@@ -64,11 +68,14 @@ export async function fetchLatestRelease(repository, token, options) {
64
68
  if (token)
65
69
  headers.Authorization = `Bearer ${token}`;
66
70
  try {
67
- return parseLatestRelease(await fetchJson(`https://api.github.com/repos/${repository}/releases/latest`, headers, options));
71
+ return parseLatestRelease(await fetchJson(`https://api.github.com/repos/${repository}/releases/${tag ? `tags/${encodeURIComponent(tag)}` : 'latest'}`, headers, options));
68
72
  }
69
73
  catch (error) {
70
- if (error instanceof HttpError && error.status === 404)
74
+ if (error instanceof HttpError && error.status === 404) {
75
+ if (tag)
76
+ throw new Error(`GitHub has no release tagged ${tag} in ${repository}`);
71
77
  return null;
78
+ }
72
79
  throw error;
73
80
  }
74
81
  }
@@ -9,7 +9,10 @@ export interface LoadOptions {
9
9
  /** Skip every network call (release assets, stats, screenshots hosted elsewhere). */
10
10
  offline?: boolean;
11
11
  githubToken?: string;
12
+ /** Use this release tag instead of `releases/latest`, which lags a fresh publish by minutes. */
13
+ releaseTag?: string;
12
14
  network?: NetworkOptions;
15
+ log?: (message: string) => void;
13
16
  warn?: (message: string) => void;
14
17
  }
15
18
  /** Reads `<dir>/<lang>.po` for every language, trying `pt-BR` and `pt_BR` spellings; missing files are skipped. */
@@ -90,7 +90,7 @@ export async function loadSiteData(options) {
90
90
  if (!options.offline) {
91
91
  const network = options.network ?? {};
92
92
  const [release, flathub, summary] = await Promise.allSettled([
93
- fetchLatestRelease(config.repository, options.githubToken, network),
93
+ fetchLatestRelease(config.repository, options.githubToken, network, options.releaseTag),
94
94
  config.flathub ? fetchFlathubStats(config.flathub, network) : Promise.resolve(undefined),
95
95
  config.flathub ? fetchFlathubSummary(config.flathub, network) : Promise.resolve(undefined),
96
96
  ]);
@@ -98,6 +98,11 @@ export async function loadSiteData(options) {
98
98
  latestRelease = release.value;
99
99
  hasReleases = latestRelease !== null;
100
100
  if (latestRelease) {
101
+ options.log?.(`Using GitHub release ${latestRelease.tag} (published ${latestRelease.publishedAt || 'unknown'}, ${latestRelease.assets.length} assets)${options.releaseTag ? ' as pinned' : ''}`);
102
+ const shown = version || metainfo.releases[0]?.version || '';
103
+ if (shown && latestRelease.tag.replace(/^v/, '') !== shown) {
104
+ warn(`The release ${latestRelease.tag} does not match the version ${shown} the page shows; download links point to ${latestRelease.tag}${options.releaseTag ? '' : ' (releases/latest may lag a fresh publish; pin it with --release-tag)'}`);
105
+ }
101
106
  // A release record is fetched by every site build, not by a person installing.
102
107
  stats.githubDownloads = latestRelease.assets
103
108
  .filter((asset) => recordedArtifact(asset.name) === undefined)
@@ -107,7 +112,7 @@ export async function loadSiteData(options) {
107
112
  }
108
113
  }
109
114
  else {
110
- warn(`Could not fetch the latest GitHub release (${String(release.reason)}); linking to the releases page instead`);
115
+ warn(`Could not fetch the ${options.releaseTag ? `GitHub release ${options.releaseTag}` : 'latest GitHub release'} (${String(release.reason)}); linking to the releases page instead`);
111
116
  }
112
117
  if (flathub.status === 'fulfilled' && flathub.value) {
113
118
  stats.flathubInstalls = flathub.value.installsTotal;
package/lib/site.d.ts CHANGED
@@ -20,6 +20,8 @@ export interface SiteBuildOptions extends SiteTarget {
20
20
  cacheDir?: string | false;
21
21
  /** Raises the GitHub API rate limit. Optional — the public limit is enough for a single build. */
22
22
  githubToken?: string;
23
+ /** Pin the GitHub release the download links come from, instead of `releases/latest`. */
24
+ releaseTag?: string;
23
25
  log?: (message: string) => void;
24
26
  warn?: (message: string) => void;
25
27
  /**
package/lib/site.js CHANGED
@@ -212,7 +212,9 @@ async function buildAppSite(build) {
212
212
  screenshotCacheDir: join(cacheDir ?? defaultCacheDir(target.root), 'screenshots'),
213
213
  offline: options.offline ?? false,
214
214
  githubToken: options.githubToken,
215
+ releaseTag: options.releaseTag,
215
216
  network: cacheDir ? { cacheDir: join(cacheDir, 'http') } : {},
217
+ log: options.log,
216
218
  warn: options.warn,
217
219
  });
218
220
  const images = await processScreenshots(data, target, cacheDir ?? defaultCacheDir(target.root));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/site",
3
- "version": "0.64.26-next.312",
3
+ "version": "0.64.26",
4
4
  "description": "Static landing page generator for a GNOME-style app, rendered from its AppStream metainfo — downloads, screenshots, release notes, support links, no JavaScript required.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -54,26 +54,25 @@
54
54
  "license": "MIT",
55
55
  "dependencies": {
56
56
  "@girs/gdkpixbuf-2.0": "5.4.0",
57
- "@gjsify/console": "0.64.26-next.312",
58
- "@gjsify/crypto": "0.64.26-next.312",
59
- "@gjsify/fs": "0.64.26-next.312",
60
- "@gjsify/module": "0.64.26-next.312",
61
- "@gjsify/os": "0.64.26-next.312",
62
- "@gjsify/path": "0.64.26-next.312",
63
- "@gjsify/process": "0.64.26-next.312",
64
- "@gjsify/url": "0.64.26-next.312",
57
+ "@gjsify/console": "^0.64.26",
58
+ "@gjsify/crypto": "^0.64.26",
59
+ "@gjsify/fs": "^0.64.26",
60
+ "@gjsify/module": "^0.64.26",
61
+ "@gjsify/os": "^0.64.26",
62
+ "@gjsify/path": "^0.64.26",
63
+ "@gjsify/process": "^0.64.26",
64
+ "@gjsify/url": "^0.64.26",
65
65
  "fast-xml-parser": "^5.11.2",
66
66
  "qrcode-generator": "^2.0.4"
67
67
  },
68
68
  "devDependencies": {
69
- "@gjsify/cli": "0.64.26-next.312",
69
+ "@gjsify/cli": "^0.64.26",
70
70
  "@gjsify/node-gi": "file:../../node-gi/node-gi",
71
- "@gjsify/unit": "0.64.26-next.312",
71
+ "@gjsify/unit": "^0.64.26",
72
72
  "@types/node": "^25.9.2",
73
73
  "typescript": "^6.0.3"
74
74
  },
75
75
  "gjsify": {
76
76
  "tier": 2
77
- },
78
- "gitHead": "75fa6155a8f1fa0f7e5d70c43418ae41ecac8c0e"
77
+ }
79
78
  }