boo-flash 0.1.3 → 0.1.4

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 (2) hide show
  1. package/dist/app.js +54 -10
  2. package/package.json +1 -1
package/dist/app.js CHANGED
@@ -3434,6 +3434,34 @@ var moduleDirectory = dirname3(fileURLToPath2(import.meta.url));
3434
3434
  function bytes(n) {
3435
3435
  return n >= 1024 ** 3 ? `${(n / 1024 ** 3).toFixed(1)} GiB` : `${(n / 1024 ** 2).toFixed(1)} MiB`;
3436
3436
  }
3437
+ function localTimestamp(value) {
3438
+ const date = new Date(value);
3439
+ if (!Number.isFinite(date.getTime())) throw new Error("Invalid image timestamp.");
3440
+ const part = (number) => String(number).padStart(2, "0");
3441
+ const minutes = -date.getTimezoneOffset();
3442
+ const offset = `${minutes < 0 ? "-" : "+"}${part(Math.floor(Math.abs(minutes) / 60))}:${part(Math.abs(minutes) % 60)}`;
3443
+ return `${date.getFullYear()}-${part(date.getMonth() + 1)}-${part(date.getDate())} ${part(date.getHours())}:${part(date.getMinutes())}:${part(date.getSeconds())} ${offset}`;
3444
+ }
3445
+ function releaseTimestamp(headers) {
3446
+ const values = headers.split(/\r?\n/).flatMap((line) => {
3447
+ const match = /^last-modified:\s*(.*?)\s*$/i.exec(line);
3448
+ return match ? [match[1]] : [];
3449
+ });
3450
+ if (values.length !== 1 || !Number.isFinite(Date.parse(values[0]))) {
3451
+ throw new Error("The Boo release publication time is invalid.");
3452
+ }
3453
+ return new Date(values[0]).toISOString();
3454
+ }
3455
+ function releaseChannel(response) {
3456
+ let separator = response.indexOf("\r\n\r\n");
3457
+ let length = 4;
3458
+ if (separator < 0) {
3459
+ separator = response.indexOf("\n\n");
3460
+ length = 2;
3461
+ }
3462
+ if (separator < 0) throw new Error("The Boo release channel response is invalid.");
3463
+ return { channel: JSON.parse(response.slice(separator + length)), timestamp: releaseTimestamp(response.slice(0, separator)) };
3464
+ }
3437
3465
  async function prepareSafeRemoval(platform3, disk, signal, authorize2, revalidate, update) {
3438
3466
  if (platform3.finalAuthorization) {
3439
3467
  update({ stage: "Authorizing", detail: "Refreshing Linux authorization before safe power-off." });
@@ -3456,7 +3484,21 @@ async function discoverImages(signal) {
3456
3484
  ...fresh ? ["--header", "Cache-Control: no-cache"] : [],
3457
3485
  url
3458
3486
  ], signal, { limit: 1024 ** 2 }));
3459
- const channel = await get(`${releaseOrigin}/channels/main.json`, true);
3487
+ const channelUrl = `${releaseOrigin}/channels/main.json`;
3488
+ const { channel, timestamp } = releaseChannel(await command([
3489
+ "curl",
3490
+ "--fail",
3491
+ "--silent",
3492
+ "--show-error",
3493
+ "--proto",
3494
+ "=https",
3495
+ "--header",
3496
+ "Cache-Control: no-cache",
3497
+ "--suppress-connect-headers",
3498
+ "--dump-header",
3499
+ "-",
3500
+ channelUrl
3501
+ ], signal, { limit: 1024 ** 2 }));
3460
3502
  if (channel?.schema !== 1 || !releaseVersion.test(channel.version) || !/^[a-f0-9]{40}$/.test(channel.revision) || channel.prefix !== `releases/${channel.version}`) {
3461
3503
  throw new Error("The Boo main release channel is invalid.");
3462
3504
  }
@@ -3483,7 +3525,7 @@ async function discoverImages(signal) {
3483
3525
  rawDigest: artifact.raw_sha256
3484
3526
  };
3485
3527
  });
3486
- return { run: build, version: channel.version, revision: channel.revision, images };
3528
+ return { run: build, version: channel.version, revision: channel.revision, timestamp, images };
3487
3529
  }
3488
3530
  async function discoverCandidates(signal) {
3489
3531
  const api = async (path) => JSON.parse(await command(["gh", "api", "--hostname", "github.com", `repos/${repository}/${path}`], signal));
@@ -3500,6 +3542,7 @@ async function discoverCandidates(signal) {
3500
3542
  candidates.push({
3501
3543
  run: run.id,
3502
3544
  revision: match[2],
3545
+ timestamp: new Date(run.created_at).toISOString(),
3503
3546
  images: [{
3504
3547
  profile: match[1],
3505
3548
  id: a.id,
@@ -3507,7 +3550,7 @@ async function discoverCandidates(signal) {
3507
3550
  bytes: a.size_in_bytes,
3508
3551
  digest: a.digest.slice(7)
3509
3552
  }],
3510
- candidate: { number: run.run_number, date: new Date(run.created_at).toISOString().slice(0, 10), title: cleanText(run.display_title ?? "") }
3553
+ candidate: { number: run.run_number, title: cleanText(run.display_title ?? "") }
3511
3554
  });
3512
3555
  if (candidates.length === 10) return candidates;
3513
3556
  }
@@ -3565,7 +3608,7 @@ var FlashBackend = class {
3565
3608
  async catalog(signal) {
3566
3609
  if (!this.demo) return discoverImages(signal);
3567
3610
  await delay(350, void 0, { signal });
3568
- return { run: 149, version: "0.1.0+149", revision: "9b7574859120add5a1a478bc7923aeb1629be4ba", images: profiles.map((profile, index) => ({
3611
+ return { run: 149, version: "0.1.0+149", revision: "9b7574859120add5a1a478bc7923aeb1629be4ba", timestamp: "2026-08-28T14:23:45Z", images: profiles.map((profile, index) => ({
3569
3612
  profile,
3570
3613
  id: index,
3571
3614
  name: `demo-${profile}`,
@@ -3578,8 +3621,9 @@ var FlashBackend = class {
3578
3621
  const catalog = await this.catalog(signal);
3579
3622
  return this.demo === "empty" ? [] : [{
3580
3623
  ...catalog,
3624
+ timestamp: "2026-08-29T01:02:03Z",
3581
3625
  images: [catalog.images[0]],
3582
- candidate: { number: 1, date: "2026-08-28", title: "Simulated candidate" }
3626
+ candidate: { number: 1, title: "Simulated candidate" }
3583
3627
  }];
3584
3628
  }
3585
3629
  async disks(signal, staging = tmpdir4(), unmounted) {
@@ -4047,7 +4091,7 @@ function App(props) {
4047
4091
  if (["up", "left"].includes(key.name)) setCursor((n) => Math.max(0, n - 1));
4048
4092
  if (key.name === "return" && !key.repeated) activate();
4049
4093
  });
4050
- const row = (label, detail, index, danger = false) => (() => {
4094
+ const row = (label, detail, index, danger = false, detailWhenTight = false) => (() => {
4051
4095
  var _el$ = createElement("box"), _el$2 = createElement("text");
4052
4096
  insertNode(_el$, _el$2);
4053
4097
  setProp(_el$, "paddingX", 1);
@@ -4057,7 +4101,7 @@ function App(props) {
4057
4101
  insert(_el$2, label, null);
4058
4102
  insert(_el$, createComponent2(Show, {
4059
4103
  get when() {
4060
- return detail && !tight();
4104
+ return detail && (!tight() || detailWhenTight);
4061
4105
  },
4062
4106
  get children() {
4063
4107
  var _el$3 = createElement("text"), _el$4 = createTextNode(` `);
@@ -4069,7 +4113,7 @@ function App(props) {
4069
4113
  }
4070
4114
  }), null);
4071
4115
  effect((_p$) => {
4072
- var _v$ = detail && !tight() ? compact() ? 2 : 3 : 1, _v$2 = cursor() === index ? palette.selected : palette.panel, _v$3 = danger ? palette.warning : cursor() === index ? palette.accent : palette.foreground, _v$4 = TextAttributes2.BOLD;
4116
+ var _v$ = detail && (!tight() || detailWhenTight) ? compact() ? 2 : 3 : 1, _v$2 = cursor() === index ? palette.selected : palette.panel, _v$3 = danger ? palette.warning : cursor() === index ? palette.accent : palette.foreground, _v$4 = TextAttributes2.BOLD;
4073
4117
  _v$ !== _p$.e && (_p$.e = setProp(_el$, "height", _v$, _p$.e));
4074
4118
  _v$2 !== _p$.t && (_p$.t = setProp(_el$, "backgroundColor", _v$2, _p$.t));
4075
4119
  _v$3 !== _p$.a && (_p$.a = setProp(_el$2, "fg", _v$3, _p$.a));
@@ -4146,7 +4190,7 @@ function App(props) {
4146
4190
  var _el$13 = createElement("text");
4147
4191
  insert(_el$13, (() => {
4148
4192
  var _c$ = memo2(() => !!loading());
4149
- return () => _c$() ? `${spinner()} Finding latest Boo release...` : memo2(() => !!catalog())() ? `Boo ${catalog().version} / ${catalog().revision.slice(0, 7)}` : "Dependencies needed. Enter to set up.";
4193
+ return () => _c$() ? `${spinner()} Finding latest Boo release...` : memo2(() => !!catalog())() ? `Boo ${catalog().version} / ${catalog().revision.slice(0, 7)} / ${localTimestamp(catalog().timestamp)}` : "Dependencies needed. Enter to set up.";
4150
4194
  })());
4151
4195
  effect((_$p) => setProp(_el$13, "fg", palette.muted, _$p));
4152
4196
  return _el$13;
@@ -4285,7 +4329,7 @@ function App(props) {
4285
4329
  get each() {
4286
4330
  return candidates().slice(Math.max(0, cursor() - 2), Math.max(3, cursor() + 1));
4287
4331
  },
4288
- children: (c, index) => row(`${c.images[0].profile.toUpperCase()} ${c.revision.slice(0, 7)} #${c.candidate.number} ${c.candidate.date}`, c.candidate.title, index() + Math.max(0, cursor() - 2))
4332
+ children: (c, index) => row(`${c.images[0].profile.toUpperCase()} ${c.revision.slice(0, 7)} #${c.candidate.number}`, `${localTimestamp(c.timestamp)} ${c.candidate.title}`, index() + Math.max(0, cursor() - 2), false, true)
4289
4333
  }));
4290
4334
  return _el$31;
4291
4335
  })(), (() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "boo-flash",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Flash qualified Boo images to USB drives on macOS and Linux",
5
5
  "license": "MIT",
6
6
  "type": "module",