@volter/world-host 3.0.11 → 3.0.13

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.
@@ -17,7 +17,7 @@
17
17
  import { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
18
18
  import { assertStateRemovable, serveHttp, stateDirName, withAncestryLock, withStateRemoval } from '@volter/world-core/runtime';
19
19
  import { dirname, join, resolve } from 'node:path';
20
- import { assertWorldStateRemovable, resolveCatalog, CONSOLE_BASE, consoleRedirect, initWorld, LocalBranches, loadWorldConfig, localWorldOrigin, mountWorld, pathOfWorld, worldOriginLabel, serveConsoleApart, siteOfHost, worldDoorUnderConsole, TOKEN_HEADER, worldOfHost } from '@volter/world-runtime';
20
+ import { assertWorldStateRemovable, resolveCatalog, CONSOLE_BASE, consoleRedirect, followParentPins, initWorld, LocalBranches, loadWorldConfig, localWorldOrigin, mountWorld, pathOfWorld, worldOriginLabel, serveConsoleApart, siteOfHost, worldDoorUnderConsole, TOKEN_HEADER, worldOfHost } from '@volter/world-runtime';
21
21
  import { issuerKeys, trustableIssuer } from '@volter/world-access';
22
22
  export { CONSOLE_BASE };
23
23
  const NAME = /^[a-z0-9][a-z0-9._-]{0,63}$/i;
@@ -130,6 +130,20 @@ export async function createWorldHost(options) {
130
130
  const config = loadWorldConfig(join(w.root, '.volter', 'world.json'), w.root).config;
131
131
  return mountWorld(config.id, { root: w.root, branches: (served) => branches.doorsFor(served), ...(browserOrigin ? { browserOrigin } : {}), ...(sitesOrigin ? { sitesOrigin } : {}), ...(passIssuers.length ? { passIssuers } : {}) });
132
132
  };
133
+ // a branch beside its parent takes the parent's twin versions before it mounts (followParentPins), parents first: a
134
+ // branch of a branch follows its parent only once that parent has followed its own
135
+ const fromOf = new Map(found.map((w) => { try {
136
+ return [w.name, JSON.parse(readFileSync(join(w.root, stateDirName(), 'branch.json'), 'utf8')).from];
137
+ }
138
+ catch {
139
+ return [w.name, undefined];
140
+ } }));
141
+ const depth = (name, seen = new Set()) => { const up = fromOf.get(name); return up && fromOf.has(up) && !seen.has(up) ? 1 + depth(up, seen.add(name)) : 0; };
142
+ for (const w of [...found].sort((a, b) => depth(a.name) - depth(b.name))) {
143
+ const parent = found.find((p) => p.name === fromOf.get(w.name));
144
+ if (parent)
145
+ followParentPins(parent.root, w.root);
146
+ }
133
147
  for (const w of found)
134
148
  byServed.set(w.name, await mount(w));
135
149
  const host = options.host ?? '127.0.0.1';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/world-host",
3
- "version": "3.0.11",
3
+ "version": "3.0.13",
4
4
  "description": "The hosted remote: worlds under one URL, each holding the canonical history of a real vendor account and its sealed credential — what a local world clones from and pushes to.",
5
5
  "keywords": [
6
6
  "twin",
@@ -27,11 +27,11 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@volter/world-access": "3.0.1",
30
- "@volter/world-core": "3.0.11",
31
- "@volter/world-runtime": "3.0.11"
30
+ "@volter/world-core": "3.0.13",
31
+ "@volter/world-runtime": "3.0.13"
32
32
  },
33
33
  "peerDependencies": {
34
- "@volter/world-console": "3.0.6"
34
+ "@volter/world-console": "3.0.8"
35
35
  },
36
36
  "peerDependenciesMeta": {
37
37
  "@volter/world-console": {
@@ -39,7 +39,7 @@
39
39
  }
40
40
  },
41
41
  "devDependencies": {
42
- "@volter/world-console": "3.0.6"
42
+ "@volter/world-console": "3.0.8"
43
43
  },
44
44
  "exports": {
45
45
  ".": {
package/src/twins-host.ts CHANGED
@@ -17,7 +17,7 @@
17
17
  import { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
18
18
  import { assertStateRemovable, serveHttp, stateDirName, withAncestryLock, withStateRemoval } from '@volter/world-core/runtime';
19
19
  import { dirname, join, resolve } from 'node:path';
20
- import { assertWorldStateRemovable, resolveCatalog, CONSOLE_BASE, consoleRedirect, initWorld, LocalBranches, loadWorldConfig, localWorldOrigin, mountWorld, pathOfWorld, worldOriginLabel, serveConsoleApart, siteOfHost, worldDoorUnderConsole, TOKEN_HEADER, worldOfHost, type ConsoleMount, type MountedWorld } from '@volter/world-runtime';
20
+ import { assertWorldStateRemovable, resolveCatalog, CONSOLE_BASE, consoleRedirect, followParentPins, initWorld, LocalBranches, loadWorldConfig, localWorldOrigin, mountWorld, pathOfWorld, worldOriginLabel, serveConsoleApart, siteOfHost, worldDoorUnderConsole, TOKEN_HEADER, worldOfHost, type ConsoleMount, type MountedWorld } from '@volter/world-runtime';
21
21
 
22
22
  import { issuerKeys, trustableIssuer, type TrustedIssuer } from '@volter/world-access';
23
23
 
@@ -138,6 +138,14 @@ export async function createWorldHost(options: WorldHostOptions): Promise<WorldH
138
138
  const config = loadWorldConfig(join(w.root, '.volter', 'world.json'), w.root).config;
139
139
  return mountWorld(config.id, { root: w.root, branches: (served) => branches.doorsFor(served), ...(browserOrigin ? { browserOrigin } : {}), ...(sitesOrigin ? { sitesOrigin } : {}), ...(passIssuers.length ? { passIssuers } : {}) });
140
140
  };
141
+ // a branch beside its parent takes the parent's twin versions before it mounts (followParentPins), parents first: a
142
+ // branch of a branch follows its parent only once that parent has followed its own
143
+ const fromOf = new Map(found.map((w) => { try { return [w.name, (JSON.parse(readFileSync(join(w.root, stateDirName(), 'branch.json'), 'utf8')) as { from?: string }).from] as const; } catch { return [w.name, undefined] as const; } }));
144
+ const depth = (name: string, seen = new Set<string>()): number => { const up = fromOf.get(name); return up && fromOf.has(up) && !seen.has(up) ? 1 + depth(up, seen.add(name)) : 0; };
145
+ for (const w of [...found].sort((a, b) => depth(a.name) - depth(b.name))) {
146
+ const parent = found.find((p) => p.name === fromOf.get(w.name));
147
+ if (parent) followParentPins(parent.root, w.root);
148
+ }
141
149
  for (const w of found) byServed.set(w.name, await mount(w));
142
150
  const host = options.host ?? '127.0.0.1';
143
151
  let url = '';