@volter/world-runtime 3.0.117 → 3.0.119

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.
@@ -1,3 +1,4 @@
1
+ import { type WorldNetwork } from '@volter/world-core/network-policy';
1
2
  export declare const WORLD_REF_FILE = ".volter-world";
2
3
  export type WorldRefSource = 'explicit' | 'env' | 'file';
3
4
  export interface ResolvedWorldRef {
@@ -24,6 +25,8 @@ export declare function resolveWorldRef(explicit: string | undefined, options?:
24
25
  /** The manifest (docs/guides/route-a-cli-through-the-world.md): what a world publishes to its attachers. */
25
26
  export interface WorldManifest {
26
27
  name: string;
28
+ /** Declared network grants; attachers intersect these with their caller's ceiling. */
29
+ network?: WorldNetwork;
27
30
  /** vendor host → twin endpoint, exactly the map the injector/proxy redirect */
28
31
  vendors: Record<string, string>;
29
32
  /** session CA (PEM) when the world has one, else null */
@@ -10,6 +10,7 @@ import { existsSync, readFileSync } from 'node:fs';
10
10
  import { dirname, join, resolve } from 'node:path';
11
11
  import { activeVendorMap } from "./redirect-proxy.js";
12
12
  import { statusWorld } from "./runtime.js";
13
+ import { worldNetworkPolicyFromEnv } from '@volter/world-core/network-policy';
13
14
  export const WORLD_REF_FILE = '.volter-world';
14
15
  /** A world reference is remote when it is a URL; every other ref is a local world name. */
15
16
  export function isRemoteWorldRef(ref) {
@@ -53,7 +54,7 @@ export function resolveWorldRef(explicit, options = {}) {
53
54
  // Internal runtime vars are plumbing, not suggested credentials. CA-trust
54
55
  // bundle vars are local renderings of `ca` (they hold machine-local paths), so
55
56
  // a manifest never carries them — an attacher re-renders trust from `ca`.
56
- const MANIFEST_ENV_EXCLUDED = /^(volter_world_|node_options$|twin_inject$|no_proxy$|https?_proxy$|node_extra_ca_certs$|ssl_cert_file$|(aws|curl|requests)_ca_bundle$)/i;
57
+ const MANIFEST_ENV_EXCLUDED = /^(volter_world(?:_|$)|node_options$|twin_inject$|no_proxy$|https?_proxy$|node_extra_ca_certs$|ssl_cert_file$|(aws|curl|requests)_ca_bundle$)/i;
57
58
  /** Derive the manifest from a world's generated env map (the local rendering).
58
59
  * Pure — the CA is inlined only when its file is readable. */
59
60
  export function deriveWorldManifest(name, worldEnv) {
@@ -78,7 +79,9 @@ export function deriveWorldManifest(name, worldEnv) {
78
79
  continue; // rendered as `vendors`, not credentials
79
80
  env[key] = value;
80
81
  }
81
- return { name, vendors, ca, proxy: worldEnv.VOLTER_WORLD_PROXY ?? null, env };
82
+ const policy = worldNetworkPolicyFromEnv(worldEnv);
83
+ const network = policy === undefined ? undefined : (({ version, world, ...permission }) => permission)(policy);
84
+ return { name, vendors, ca, proxy: worldEnv.VOLTER_WORLD_PROXY ?? null, env, ...(network === undefined ? {} : { network }) };
82
85
  }
83
86
  /** The manifest of a local world instance (name resolved against `root` like every other verb). */
84
87
  export function worldManifest(name, root = process.cwd()) {
@@ -940,7 +940,7 @@ export async function main() {
940
940
  const { bridgeTwins } = createRequire(import.meta.url)('@volter/world-core/http-bridge');
941
941
  await bridgeTwins(manifest, manifest.env.VOLTER_TWINS_KEY ?? attachToken ?? '', manifest.ca ?? undefined);
942
942
  const injectPath = createRequire(import.meta.url).resolve('@volter/world-core/inject');
943
- const env = remoteAttachEnv(manifest, { injectPath, ...(caFile === undefined ? {} : { caFile }) });
943
+ const env = remoteAttachEnv(manifest, { injectPath, worldRef: resolved.ref, ...(caFile === undefined ? {} : { caFile }) });
944
944
  // the world's byte-stream doors, bridged to loopback listeners here, beside a command in any language
945
945
  const { bridgeStreams, drainStreams } = createRequire(import.meta.url)('@volter/world-core/stream-bridge');
946
946
  const bridged = manifest.streams ? await bridgeStreams(manifest.streams, manifest.env.VOLTER_TWINS_KEY ?? attachToken ?? '') : { env: {} };
@@ -27,4 +27,6 @@ export declare function fetchRemoteManifest(ref: string, options?: {
27
27
  export declare function remoteAttachEnv(manifest: WorldManifest, options: {
28
28
  caFile?: string;
29
29
  injectPath: string;
30
+ worldRef?: string;
31
+ callerEnv?: Readonly<Record<string, string | undefined>>;
30
32
  }): Record<string, string>;
package/dist/src/serve.js CHANGED
@@ -9,6 +9,7 @@ import { timingSafeEqual } from 'node:crypto';
9
9
  import { createServer as createHttpServer } from 'node:http';
10
10
  import { deriveWorldManifest } from "./attach.js";
11
11
  import { statusWorld } from "./runtime.js";
12
+ import { worldAttachmentNetworkEnv, worldStrictEgress } from '@volter/world-core/network-policy';
12
13
  export const MANIFEST_PATH = '/.well-known/volter-world';
13
14
  /** The manifest a REMOTE attacher sees: every vendor behind the one advertised
14
15
  * door. The serving side keeps routing against its own loopback env. */
@@ -71,7 +72,9 @@ export async function fetchRemoteManifest(ref, options = {}) {
71
72
  /** The env a remote env-attachment exports: vendor twin URLs (the advertised
72
73
  * door), suggested fake credentials, CA trust, and the injector preload. */
73
74
  export function remoteAttachEnv(manifest, options) {
74
- const env = { ...manifest.env };
75
+ const env = { ...manifest.env,
76
+ ...worldAttachmentNetworkEnv(options.worldRef ?? manifest.name, manifest.network, options.callerEnv ?? process.env, worldStrictEgress(manifest.env)),
77
+ };
75
78
  for (const [vendor, origin] of Object.entries(manifest.vendors)) {
76
79
  env[`${vendor.toUpperCase()}_TWIN_URL`] = origin;
77
80
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/world-runtime",
3
- "version": "3.0.117",
3
+ "version": "3.0.119",
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",
@@ -70,14 +70,14 @@
70
70
  "node": ">=22.3"
71
71
  },
72
72
  "peerDependencies": {
73
- "@volter/world-core": "3.0.117",
74
- "@volter/world-console": "3.0.112"
73
+ "@volter/world-core": "3.0.119",
74
+ "@volter/world-console": "3.0.114"
75
75
  },
76
76
  "dependencies": {
77
77
  "@electric-sql/pglite": "0.5.8",
78
78
  "@electric-sql/pglite-pgvector": "0.0.9",
79
79
  "@volter/world-access": "3.0.1",
80
- "@volter/world-core": "3.0.117",
80
+ "@volter/world-core": "3.0.119",
81
81
  "mongodb": "~6.20.0",
82
82
  "pg-gateway": "0.3.0-beta.4",
83
83
  "smol-toml": "^1.8.0",
package/src/attach.ts CHANGED
@@ -10,6 +10,7 @@ import { existsSync, readFileSync } from 'node:fs';
10
10
  import { dirname, join, resolve } from 'node:path';
11
11
  import { activeVendorMap } from './redirect-proxy.ts';
12
12
  import { statusWorld } from './runtime.ts';
13
+ import { worldNetworkPolicyFromEnv, type WorldNetwork } from '@volter/world-core/network-policy';
13
14
 
14
15
  export const WORLD_REF_FILE = '.volter-world';
15
16
 
@@ -67,6 +68,8 @@ export function resolveWorldRef(
67
68
  /** The manifest (docs/guides/route-a-cli-through-the-world.md): what a world publishes to its attachers. */
68
69
  export interface WorldManifest {
69
70
  name: string;
71
+ /** Declared network grants; attachers intersect these with their caller's ceiling. */
72
+ network?: WorldNetwork;
70
73
  /** vendor host → twin endpoint, exactly the map the injector/proxy redirect */
71
74
  vendors: Record<string, string>;
72
75
  /** session CA (PEM) when the world has one, else null */
@@ -85,7 +88,7 @@ export interface WorldManifest {
85
88
  // bundle vars are local renderings of `ca` (they hold machine-local paths), so
86
89
  // a manifest never carries them — an attacher re-renders trust from `ca`.
87
90
  const MANIFEST_ENV_EXCLUDED =
88
- /^(volter_world_|node_options$|twin_inject$|no_proxy$|https?_proxy$|node_extra_ca_certs$|ssl_cert_file$|(aws|curl|requests)_ca_bundle$)/i;
91
+ /^(volter_world(?:_|$)|node_options$|twin_inject$|no_proxy$|https?_proxy$|node_extra_ca_certs$|ssl_cert_file$|(aws|curl|requests)_ca_bundle$)/i;
89
92
 
90
93
  /** Derive the manifest from a world's generated env map (the local rendering).
91
94
  * Pure — the CA is inlined only when its file is readable. */
@@ -107,7 +110,9 @@ export function deriveWorldManifest(name: string, worldEnv: Record<string, strin
107
110
  if (/_TWIN_URL$/.test(key)) continue; // rendered as `vendors`, not credentials
108
111
  env[key] = value;
109
112
  }
110
- return { name, vendors, ca, proxy: worldEnv.VOLTER_WORLD_PROXY ?? null, env };
113
+ const policy = worldNetworkPolicyFromEnv(worldEnv);
114
+ const network = policy === undefined ? undefined : (({ version, world, ...permission }) => permission)(policy);
115
+ return { name, vendors, ca, proxy: worldEnv.VOLTER_WORLD_PROXY ?? null, env, ...(network === undefined ? {} : { network }) };
111
116
  }
112
117
 
113
118
  /** The manifest of a local world instance (name resolved against `root` like every other verb). */
@@ -818,7 +818,7 @@ export async function main(): Promise<void> {
818
818
  const { bridgeTwins } = createRequire(import.meta.url)('@volter/world-core/http-bridge') as { bridgeTwins: (manifest: WorldManifest, key: string, ca?: string) => Promise<unknown[]> };
819
819
  await bridgeTwins(manifest, manifest.env.VOLTER_TWINS_KEY ?? attachToken ?? '', manifest.ca ?? undefined);
820
820
  const injectPath = createRequire(import.meta.url).resolve('@volter/world-core/inject');
821
- const env = remoteAttachEnv(manifest, { injectPath, ...(caFile === undefined ? {} : { caFile }) });
821
+ const env = remoteAttachEnv(manifest, { injectPath, worldRef: resolved.ref, ...(caFile === undefined ? {} : { caFile }) });
822
822
  // the world's byte-stream doors, bridged to loopback listeners here, beside a command in any language
823
823
  const { bridgeStreams, drainStreams } = createRequire(import.meta.url)('@volter/world-core/stream-bridge') as { bridgeStreams: (streams: WorldManifest['streams'], token: string) => Promise<{ env: Record<string, string> }>; drainStreams: (ms?: number) => Promise<void> };
824
824
  const bridged = manifest.streams ? await bridgeStreams(manifest.streams, manifest.env.VOLTER_TWINS_KEY ?? attachToken ?? '') : { env: {} };
package/src/serve.ts CHANGED
@@ -9,6 +9,7 @@ import { timingSafeEqual } from 'node:crypto';
9
9
  import { createServer as createHttpServer, type Server as HttpServer } from 'node:http';
10
10
  import { deriveWorldManifest, type WorldManifest } from './attach.ts';
11
11
  import { statusWorld } from './runtime.ts';
12
+ import { worldAttachmentNetworkEnv, worldStrictEgress } from '@volter/world-core/network-policy';
12
13
 
13
14
  export const MANIFEST_PATH = '/.well-known/volter-world';
14
15
 
@@ -90,9 +91,11 @@ export async function fetchRemoteManifest(ref: string, options: { token?: string
90
91
  * door), suggested fake credentials, CA trust, and the injector preload. */
91
92
  export function remoteAttachEnv(
92
93
  manifest: WorldManifest,
93
- options: { caFile?: string; injectPath: string },
94
+ options: { caFile?: string; injectPath: string; worldRef?: string; callerEnv?: Readonly<Record<string, string | undefined>> },
94
95
  ): Record<string, string> {
95
- const env: Record<string, string> = { ...manifest.env };
96
+ const env: Record<string, string> = { ...manifest.env,
97
+ ...worldAttachmentNetworkEnv(options.worldRef ?? manifest.name, manifest.network, options.callerEnv ?? process.env, worldStrictEgress(manifest.env)),
98
+ };
96
99
  for (const [vendor, origin] of Object.entries(manifest.vendors)) {
97
100
  env[`${vendor.toUpperCase()}_TWIN_URL`] = origin;
98
101
  }