@volter/world-runtime 3.0.7 → 3.0.8

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.
@@ -26,7 +26,7 @@ import { getActiveWorldStore, withHistoryLocks, captureHistory, historyAtInstant
26
26
  // to `.volter/token` and `.volter/token.read` (0600).
27
27
  // One writer per world by construction: the doors run in this process, serialized per twin.
28
28
  import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync, rmSync } from 'node:fs';
29
- import { CALLER_HEADER, callerForHeader, newTraceparent, parseTraceparent, traceparentForDelivery, readTwinRequestJournalFrom, assertSafeChangesetName, blobDigest, destinationOf, getActiveBlobStore, journalTwinRequest, loadCheck, twinRequestJournalFailures, openSealedAt, readTwinRequestJournal, serveHttp, twinRequestCredentials, TWIN_PREFIX_HEADER, validateRemoteOrigin } from '@volter/world-core/runtime';
29
+ import { CALLER_HEADER, callerForHeader, newTraceparent, parseTraceparent, traceparentForDelivery, readTwinRequestJournalFrom, assertSafeChangesetName, blobDigest, destinationOf, getActiveBlobStore, journalTwinRequest, loadCheck, twinRequestJournalFailures, openSealedAt, readTwinRequestJournal, serveHttp, twinRequestCredentials, TWIN_PREFIX_HEADER, TWIN_SITES_HEADER, validateRemoteOrigin } from '@volter/world-core/runtime';
30
30
  import { APP_READ_ENDPOINT_ENV } from "./init.js";
31
31
  import { packFacts } from "./pack-facts.js";
32
32
  import { grantOf, presentedSecrets, sameSecret, spentPasses, verifyPass } from '@volter/world-access';
@@ -941,6 +941,14 @@ export class WorldDoors {
941
941
  headers.set(TWIN_PREFIX_HEADER, `/${this.served}/${vendor}`);
942
942
  headers.set('x-forwarded-host', url.host);
943
943
  headers.set('x-forwarded-proto', url.protocol.replace(':', ''));
944
+ // where this World shows the hostnames its twins answer, for a page that links one (twinSiteUrl): under its own
945
+ // origin on this machine (siteOfHost); a World without one shows none
946
+ const own = this.host.browserOrigin?.() ?? null;
947
+ const sites = own ? new URL(own) : null;
948
+ if (sites && sites.hostname.endsWith('.localhost'))
949
+ headers.set(TWIN_SITES_HEADER, `${sites.protocol}//{host}.${sites.host}`);
950
+ else
951
+ headers.delete(TWIN_SITES_HEADER);
944
952
  const body = request.method === 'GET' || request.method === 'HEAD' ? undefined : await request.arrayBuffer();
945
953
  const answer = await twin(new Request(`${url.origin}/${tail.join('/')}${url.search}`, { method: request.method, headers, ...(body === undefined ? {} : { body }), redirect: 'manual' }));
946
954
  // an upgrade the twin answered (a tunnel's control or visitor socket) goes back as it is
@@ -985,7 +993,7 @@ export class WorldDoors {
985
993
  // what leaves for the vendor before the seal is applied: no World token in any header it can arrive
986
994
  // under (an SDK's own `Authorization: Bearer` included), no cookie, no routing headers of this World
987
995
  const caller = new Headers(request.headers);
988
- for (const h of [TOKEN_HEADER, TWINS_KEY_HEADER, TWIN_PREFIX_HEADER, CALLER_HEADER, 'host', 'x-forwarded-host', 'x-forwarded-proto', 'cookie'])
996
+ for (const h of [TOKEN_HEADER, TWINS_KEY_HEADER, TWIN_PREFIX_HEADER, TWIN_SITES_HEADER, CALLER_HEADER, 'host', 'x-forwarded-host', 'x-forwarded-proto', 'cookie'])
989
997
  caller.delete(h);
990
998
  // a secret this World minted (`tok_…`, live, revoked or expired) or one that opens it never leaves
991
999
  const authorization = caller.get('authorization');
@@ -1175,10 +1183,6 @@ export class WorldDoors {
1175
1183
  return Response.json(await this.map());
1176
1184
  if (kind === 'timeline' && !name && request.method === 'GET')
1177
1185
  return this.timeline(url);
1178
- // the sites this World's twins answer (a Workers Custom Domain, an R2 public domain), each read in a browser at
1179
- // `<hostname>.<the World's origin>` (siteOfHost)
1180
- if (kind === 'sites' && !name && request.method === 'GET')
1181
- return Response.json({ world: this.served, sites: (await this.claimedHosts(url.origin)).flatMap((c) => c.hosts.map((host) => ({ twin: c.vendor, host }))) });
1182
1186
  if (kind === 'diff' && !name && request.method === 'GET') {
1183
1187
  const delta = diffWorld(this.name, { root: this.worldRoot });
1184
1188
  // what another World pushed here is in its changeset already: never this World's uncut changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/world-runtime",
3
- "version": "3.0.7",
3
+ "version": "3.0.8",
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",
@@ -68,14 +68,14 @@
68
68
  "node": ">=22.3"
69
69
  },
70
70
  "peerDependencies": {
71
- "@volter/world-core": "3.0.7",
72
- "@volter/world-console": "3.0.2"
71
+ "@volter/world-core": "3.0.8",
72
+ "@volter/world-console": "3.0.3"
73
73
  },
74
74
  "dependencies": {
75
75
  "@electric-sql/pglite": "0.5.8",
76
76
  "@electric-sql/pglite-pgvector": "0.0.9",
77
77
  "@volter/world-access": "3.0.1",
78
- "@volter/world-core": "3.0.7",
78
+ "@volter/world-core": "3.0.8",
79
79
  "pg-gateway": "0.3.0-beta.4",
80
80
  "smol-toml": "^1.8.0",
81
81
  "yaml": "2.9.0"
@@ -26,7 +26,7 @@ import { getActiveWorldStore, withHistoryLocks, captureHistory, historyAtInstant
26
26
  // to `.volter/token` and `.volter/token.read` (0600).
27
27
  // One writer per world by construction: the doors run in this process, serialized per twin.
28
28
  import { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync , rmSync} from 'node:fs';
29
- import { CALLER_HEADER, callerForHeader, newTraceparent, parseTraceparent, traceparentForDelivery, readTwinRequestJournalFrom, type TwinRequestJournalCursor, assertSafeChangesetName, blobDigest, destinationOf, getActiveBlobStore, journalTwinRequest, loadCheck, twinRequestJournalFailures, openSealedAt, readTwinRequestJournal, serveHttp, twinRequestCredentials, TWIN_PREFIX_HEADER, validateRemoteOrigin, type SealedCredential, type TwinStreamConnection, type TwinStreamSink } from '@volter/world-core/runtime';
29
+ import { CALLER_HEADER, callerForHeader, newTraceparent, parseTraceparent, traceparentForDelivery, readTwinRequestJournalFrom, type TwinRequestJournalCursor, assertSafeChangesetName, blobDigest, destinationOf, getActiveBlobStore, journalTwinRequest, loadCheck, twinRequestJournalFailures, openSealedAt, readTwinRequestJournal, serveHttp, twinRequestCredentials, TWIN_PREFIX_HEADER, TWIN_SITES_HEADER, validateRemoteOrigin, type SealedCredential, type TwinStreamConnection, type TwinStreamSink } from '@volter/world-core/runtime';
30
30
  import { APP_READ_ENDPOINT_ENV } from './init.ts';
31
31
  import { packFacts } from './pack-facts.ts';
32
32
  import { grantOf, presentedSecrets, sameSecret, spentPasses, verifyPass, type TrustedIssuer, type WorldCredentials } from '@volter/world-access';
@@ -827,6 +827,11 @@ export class WorldDoors {
827
827
  // the twin is mounted under this World's path: live URLs it mints must carry it (twinPublicBase)
828
828
  headers.set(TWIN_PREFIX_HEADER, `/${this.served}/${vendor}`);
829
829
  headers.set('x-forwarded-host', url.host); headers.set('x-forwarded-proto', url.protocol.replace(':', ''));
830
+ // where this World shows the hostnames its twins answer, for a page that links one (twinSiteUrl): under its own
831
+ // origin on this machine (siteOfHost); a World without one shows none
832
+ const own = this.host.browserOrigin?.() ?? null;
833
+ const sites = own ? new URL(own) : null;
834
+ if (sites && sites.hostname.endsWith('.localhost')) headers.set(TWIN_SITES_HEADER, `${sites.protocol}//{host}.${sites.host}`); else headers.delete(TWIN_SITES_HEADER);
830
835
  const body = request.method === 'GET' || request.method === 'HEAD' ? undefined : await request.arrayBuffer();
831
836
  const answer = await twin(new Request(`${url.origin}/${tail.join('/')}${url.search}`, { method: request.method, headers, ...(body === undefined ? {} : { body }), redirect: 'manual' }));
832
837
  // an upgrade the twin answered (a tunnel's control or visitor socket) goes back as it is
@@ -868,7 +873,7 @@ export class WorldDoors {
868
873
  // what leaves for the vendor before the seal is applied: no World token in any header it can arrive
869
874
  // under (an SDK's own `Authorization: Bearer` included), no cookie, no routing headers of this World
870
875
  const caller = new Headers(request.headers);
871
- for (const h of [TOKEN_HEADER, TWINS_KEY_HEADER, TWIN_PREFIX_HEADER, CALLER_HEADER, 'host', 'x-forwarded-host', 'x-forwarded-proto', 'cookie']) caller.delete(h);
876
+ for (const h of [TOKEN_HEADER, TWINS_KEY_HEADER, TWIN_PREFIX_HEADER, TWIN_SITES_HEADER, CALLER_HEADER, 'host', 'x-forwarded-host', 'x-forwarded-proto', 'cookie']) caller.delete(h);
872
877
  // a secret this World minted (`tok_…`, live, revoked or expired) or one that opens it never leaves
873
878
  const authorization = caller.get('authorization');
874
879
  const offered = authorization ? presentedSecrets(new Headers({ authorization }), { token: TOKEN_HEADER, twinsKey: TWINS_KEY_HEADER }) : [];
@@ -1013,9 +1018,6 @@ export class WorldDoors {
1013
1018
  }
1014
1019
  if (kind === 'map' && !name && request.method === 'GET') return Response.json(await this.map());
1015
1020
  if (kind === 'timeline' && !name && request.method === 'GET') return this.timeline(url);
1016
- // the sites this World's twins answer (a Workers Custom Domain, an R2 public domain), each read in a browser at
1017
- // `<hostname>.<the World's origin>` (siteOfHost)
1018
- if (kind === 'sites' && !name && request.method === 'GET') return Response.json({ world: this.served, sites: (await this.claimedHosts(url.origin)).flatMap((c) => c.hosts.map((host) => ({ twin: c.vendor, host }))) });
1019
1021
  if (kind === 'diff' && !name && request.method === 'GET') {
1020
1022
  const delta = diffWorld(this.name, { root: this.worldRoot });
1021
1023
  // what another World pushed here is in its changeset already: never this World's uncut changes