alexandr 0.3.2 → 0.3.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alexandr",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Run the alexandr workspace runtime locally (npx alexandr up), and develop alexandr apps against a workspace (alexandr app link | dev | build | deploy).",
5
5
  "type": "module",
6
6
  "bin": {
package/src/commands.js CHANGED
@@ -616,6 +616,9 @@ export async function update(flags) {
616
616
  stampUpdaterEnv(inst);
617
617
  }
618
618
  const prevImage = readEnv(inst.dir).ALEXANDR_IMAGE || `${IMAGE_BASE}:latest`;
619
+ // What `.previous-image` said BEFORE this run — restored if the pull fails (see below).
620
+ const pointerPath = path.join(inst.dir, ".previous-image");
621
+ const priorPointer = fs.existsSync(pointerPath) ? fs.readFileSync(pointerPath, "utf8") : null;
619
622
  const base = kernelUrl(kernelPort(inst.dir));
620
623
  const before = (await kVersion(base))?.version ?? "?";
621
624
 
@@ -662,6 +665,21 @@ export async function update(flags) {
662
665
  pull = compose(inst.dir, inst.projectName, ["pull", "kernel"]);
663
666
  }
664
667
  if (pull.status !== 0) {
668
+ // ⚠ PUT THE PIN BACK. The new tag was written into .env before the pull so compose would
669
+ // pull it; a failed pull must not leave the box pointing at an image it does not have —
670
+ // the next `up` would then boot the new version behind the operator's back, which is
671
+ // exactly what the first sidecar press on aos did (2026-09-08). `.previous-image` is
672
+ // restored too, so a later `--rollback` still means what it says.
673
+ setEnv(inst.dir, "ALEXANDR_IMAGE", prevImage);
674
+ if (priorPointer === null) {
675
+ try {
676
+ fs.unlinkSync(pointerPath);
677
+ } catch {
678
+ /* nothing was recorded before this run either */
679
+ }
680
+ } else {
681
+ fs.writeFileSync(pointerPath, priorPointer);
682
+ }
665
683
  fail("Pull failed — check your network / the image tag.", EXIT.RUNTIME);
666
684
  }
667
685
  }
package/src/probe.js CHANGED
@@ -1,7 +1,17 @@
1
1
  // Health/version probing of a running kernel over its loopback port. Uses the
2
2
  // global fetch (Node 18+). All probes are best-effort and never throw.
3
3
 
4
- export const kernelUrl = (port = 3030) => `http://127.0.0.1:${port}`;
4
+ /**
5
+ * Where the kernel answers from HERE. On the host that is the loopback port compose mapped;
6
+ * inside the updater sidecar 127.0.0.1 is the sidecar itself, so the compose file sets
7
+ * `ALEXANDR_KERNEL_URL=http://kernel:3030` (the service name on the project network) — without
8
+ * it the recipe's health wait could not see the kernel from inside and reported `? → ?`
9
+ * (the first sidecar press on aos, 2026-09-08).
10
+ */
11
+ export const kernelUrl = (port = 3030, env = process.env) => {
12
+ const explicit = (env.ALEXANDR_KERNEL_URL || "").trim();
13
+ return explicit ? explicit.replace(/\/+$/, "") : `http://127.0.0.1:${port}`;
14
+ };
5
15
 
6
16
  async function getJson(url, timeoutMs = 2500) {
7
17
  const ctrl = new AbortController();
@@ -48,6 +48,9 @@ services:
48
48
  ALEXANDR_INSTANCE_DIR: ${ALEXANDR_INSTANCE_DIR:-/nonexistent}
49
49
  ALEXANDR_COMPOSE_PROJECT: ${ALEXANDR_COMPOSE_PROJECT:-alexandr}
50
50
  ALEXANDR_UPDATER_SOCKET: /run/alexandr/updater.sock
51
+ # The kernel, by its service name: from inside this container 127.0.0.1 is the sidecar
52
+ # itself, and the recipe's health wait must see the kernel come back.
53
+ ALEXANDR_KERNEL_URL: http://kernel:3030
51
54
  env_file:
52
55
  - path: ./.env
53
56
  required: false # ALEXANDR_CP_URL / ALEXANDR_RELEASES_URL → the feed it reads