@volter/world-runtime 2.0.44 → 2.0.46

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.
@@ -31,7 +31,7 @@ import { APP_READ_ENDPOINT_ENV } from "./init.js";
31
31
  import { grantOf, presentedSecrets, sameSecret, spentPasses, verifyPass } from '@volter/world-access';
32
32
  import { createHash } from 'node:crypto';
33
33
  import { dirname, join, resolve } from 'node:path';
34
- import { appendActionIfAbsent, branchEntries, branchLogPath, branchMetaPath, changesetContentHash, confirmAction, parentLogPath, readTree, stateDirName, wholeLog, worldNow, parentEntries, rebaseBranch, } from '@volter/world-core';
34
+ import { appendActionIfAbsent, branchEntries, branchLogPath, branchMetaPath, changesetContentHash, confirmAction, parentLogPath, readTree, stateDirName, wholeLog, worldNow, parentEntries, readBranchMeta, rebaseBranch, } from '@volter/world-core';
35
35
  import { approveWorldChangeset, createWorldChangeset, diffWorld, findWorldChangeset, listWorldChangesets, pushWorldChangeset, verifyWorldChangeset, worldChangesetsDir } from "./changeset.js";
36
36
  import { fetchFromOrigin } from "./origin.js";
37
37
  import { CONSOLE_BASE, consoleRedirect, serveConsoleApart } from "./console-apart.js";
@@ -1315,8 +1315,31 @@ export class WorldDoors {
1315
1315
  const store = getActiveWorldStore();
1316
1316
  const key = () => { const t = store.read(tokenPath)?.trim(); if (!t)
1317
1317
  throw new Error(`${this.served} has no origin — PUT /-/${this.served}/origin { url, token }`); return t; };
1318
- if (!name && request.method === 'GET')
1319
- return Response.json({ origin: statusWorld(this.name, this.worldRoot).origin ?? null });
1318
+ if (!name && request.method === 'GET') {
1319
+ const origin = statusWorld(this.name, this.worldRoot).origin ?? null;
1320
+ if (!origin)
1321
+ return Response.json({ origin: null });
1322
+ // git's "ahead, behind" for this World and its origin, from what is here: ahead, the changes not cut and the
1323
+ // changesets not pushed; behind, per twin, what the last fetch brought that this branch has not taken (a pull
1324
+ // rebases onto it). As of the last fetch: what the origin gained since is known at the next one.
1325
+ const changes = diffWorld(this.name, { root: this.worldRoot }).actions.length;
1326
+ const changesets = listWorldChangesets({ root: this.worldRoot, world: this.name }).filter((l) => !l.changeset.applied || l.changeset.applied.outcome === 'refused').length;
1327
+ const behind = {};
1328
+ for (const twin of Object.keys(this.up().services)) {
1329
+ const meta = readBranchMeta(this.stateOf(twin), this.controlRoot(twin));
1330
+ // nothing fetched since the branch took it (a pull, a push or a rebase clears it) is nothing behind
1331
+ const fetched = meta?.fetchedOrigin;
1332
+ const on = meta?.origin ?? meta?.parent;
1333
+ if (!fetched || !on) {
1334
+ behind[twin] = 0;
1335
+ continue;
1336
+ }
1337
+ const gained = fetched.position - on.position;
1338
+ // a same-length history rewritten is drift too, read as the fetch reads it (a path origin has no remote view)
1339
+ behind[twin] = gained > 0 ? gained : (fetched.remoteView ?? fetched.view) !== (on.remoteView ?? on.view) ? 1 : 0;
1340
+ }
1341
+ return Response.json({ origin, ahead: { changes, changesets }, behind, asOf: origin.fetchedAt ?? null });
1342
+ }
1320
1343
  if (!name && request.method === 'PUT') {
1321
1344
  const body = (await request.json());
1322
1345
  const at = /^(https?:\/\/[^/]+)\/([a-z0-9][a-z0-9_-]*\/[a-z0-9][a-z0-9_-]*)\/?$/i.exec(body.url ?? '');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/world-runtime",
3
- "version": "2.0.44",
3
+ "version": "2.0.46",
4
4
  "description": "World configs for twins: boot named local runtimes, allocate ports, generate world.env/instance.json, and run apps against fake-key twin worlds.",
5
5
  "keywords": [
6
6
  "twin",
@@ -67,14 +67,14 @@
67
67
  "node": ">=22.3"
68
68
  },
69
69
  "peerDependencies": {
70
- "@volter/world-core": "2.0.26",
70
+ "@volter/world-core": "2.0.28",
71
71
  "@volter/world-console": "2.0.13"
72
72
  },
73
73
  "dependencies": {
74
74
  "@electric-sql/pglite": "0.5.8",
75
75
  "@electric-sql/pglite-pgvector": "0.0.9",
76
76
  "@volter/world-access": "2.0.2",
77
- "@volter/world-core": "2.0.26",
77
+ "@volter/world-core": "2.0.28",
78
78
  "pg-gateway": "0.3.0-beta.4",
79
79
  "smol-toml": "^1.8.0"
80
80
  },
@@ -84,6 +84,6 @@
84
84
  }
85
85
  },
86
86
  "optionalDependencies": {
87
- "@volter/twin-mongodb": "0.1.26"
87
+ "@volter/twin-mongodb": "0.1.28"
88
88
  }
89
89
  }
@@ -33,7 +33,7 @@ import { createHash } from 'node:crypto';
33
33
  import { dirname, join, resolve } from 'node:path';
34
34
  import {
35
35
  appendActionIfAbsent, branchEntries, branchLogPath, branchMetaPath, changesetContentHash, confirmAction, parentLogPath, readTree, stateDirName, wholeLog, worldNow,
36
- parentEntries, rebaseBranch, type Changeset, type Entry, type Receipt, type RootConfig,
36
+ parentEntries, readBranchMeta, rebaseBranch, type Changeset, type Entry, type Receipt, type RootConfig,
37
37
  } from '@volter/world-core';
38
38
  import { approveWorldChangeset, createWorldChangeset, diffWorld, findWorldChangeset, listWorldChangesets, pushWorldChangeset, verifyWorldChangeset, worldChangesetsDir } from './changeset.ts';
39
39
  import { fetchFromOrigin } from './origin.ts';
@@ -1131,7 +1131,26 @@ export class WorldDoors {
1131
1131
  const tokenPath = join(this.worldRoot, stateDirName(), 'origin.token');
1132
1132
  const store = getActiveWorldStore();
1133
1133
  const key = (): string => { const t = store.read(tokenPath)?.trim(); if (!t) throw new Error(`${this.served} has no origin — PUT /-/${this.served}/origin { url, token }`); return t; };
1134
- if (!name && request.method === 'GET') return Response.json({ origin: statusWorld(this.name, this.worldRoot).origin ?? null });
1134
+ if (!name && request.method === 'GET') {
1135
+ const origin = statusWorld(this.name, this.worldRoot).origin ?? null;
1136
+ if (!origin) return Response.json({ origin: null });
1137
+ // git's "ahead, behind" for this World and its origin, from what is here: ahead, the changes not cut and the
1138
+ // changesets not pushed; behind, per twin, what the last fetch brought that this branch has not taken (a pull
1139
+ // rebases onto it). As of the last fetch: what the origin gained since is known at the next one.
1140
+ const changes = diffWorld(this.name, { root: this.worldRoot }).actions.length;
1141
+ const changesets = listWorldChangesets({ root: this.worldRoot, world: this.name }).filter((l) => !l.changeset.applied || l.changeset.applied.outcome === 'refused').length;
1142
+ const behind: Record<string, number> = {};
1143
+ for (const twin of Object.keys(this.up().services)) {
1144
+ const meta = readBranchMeta(this.stateOf(twin), this.controlRoot(twin));
1145
+ // nothing fetched since the branch took it (a pull, a push or a rebase clears it) is nothing behind
1146
+ const fetched = meta?.fetchedOrigin; const on = meta?.origin ?? meta?.parent;
1147
+ if (!fetched || !on) { behind[twin] = 0; continue; }
1148
+ const gained = fetched.position - on.position;
1149
+ // a same-length history rewritten is drift too, read as the fetch reads it (a path origin has no remote view)
1150
+ behind[twin] = gained > 0 ? gained : (fetched.remoteView ?? fetched.view) !== (on.remoteView ?? on.view) ? 1 : 0;
1151
+ }
1152
+ return Response.json({ origin, ahead: { changes, changesets }, behind, asOf: origin.fetchedAt ?? null });
1153
+ }
1135
1154
  if (!name && request.method === 'PUT') {
1136
1155
  const body = (await request.json()) as { url?: string; token?: string; views?: Record<string, HistoryReference> };
1137
1156
  const at = /^(https?:\/\/[^/]+)\/([a-z0-9][a-z0-9_-]*\/[a-z0-9][a-z0-9_-]*)\/?$/i.exec(body.url ?? '');