@volter/world-runtime 2.0.27 → 2.0.28
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/dist/src/root.d.ts +1 -0
- package/dist/src/root.js +6 -6
- package/dist/src/served-world.js +3 -4
- package/package.json +4 -4
- package/src/root.ts +7 -7
- package/src/served-world.ts +3 -4
package/dist/src/root.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare function sealTwinCredential(worldRoot: string, vendor: string, pa
|
|
|
12
12
|
export declare function sealedCredentialInfo(worldRoot: string, vendor: string): {
|
|
13
13
|
placedAt: string;
|
|
14
14
|
fingerprint: string;
|
|
15
|
+
sealedBy: 'vault' | 'key';
|
|
15
16
|
} | null;
|
|
16
17
|
/** The signing secret sealed beside the credential (`{ headers, signingSecret }`), for ingest; null when none. */
|
|
17
18
|
export declare function twinSigningSecret(worldRoot: string, vendor: string): Promise<string | null>;
|
package/dist/src/root.js
CHANGED
|
@@ -11,7 +11,7 @@ import { packEntry } from "./catalog.js";
|
|
|
11
11
|
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
12
12
|
import { homedir } from 'node:os';
|
|
13
13
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
14
|
-
import { authStrategyFor, getActiveWorldStore, getPack,
|
|
14
|
+
import { authStrategyFor, currentSealer, openSealedAt, getActiveWorldStore, getPack, buildRemoteExecute, clearRoot, readRoot, registerStateSystem, stateDirName, stateSystemFor, validateRemoteOrigin, writeRoot, } from '@volter/world-core';
|
|
15
15
|
import { loadWorldConfig, writeWorldConfig } from "./configs.js";
|
|
16
16
|
import { changesetReadiness, collectObservations, foldObservations, loadChecks, openRootCredential, performEntries, rootCustody, protocolStanding } from '@volter/world-core';
|
|
17
17
|
import { findWorldChangeset, listWorldChangesets } from "./changeset.js";
|
|
@@ -31,7 +31,7 @@ export function credentialPath(worldRoot, vendor) {
|
|
|
31
31
|
return join(resolve(worldRoot), stateDirName(), 'credentials', `${vendor}.json`);
|
|
32
32
|
}
|
|
33
33
|
export async function sealTwinCredential(worldRoot, vendor, payload, at = new Date().toISOString()) {
|
|
34
|
-
const sealed = await
|
|
34
|
+
const sealed = await currentSealer().seal(payload, at, vendor);
|
|
35
35
|
getActiveWorldStore().write(credentialPath(worldRoot, vendor), `${JSON.stringify(sealed, null, 2)}\n`, { secret: true });
|
|
36
36
|
return { placedAt: sealed.placedAt, fingerprint: sealed.fingerprint };
|
|
37
37
|
}
|
|
@@ -40,14 +40,14 @@ export function sealedCredentialInfo(worldRoot, vendor) {
|
|
|
40
40
|
if (text === null)
|
|
41
41
|
return null;
|
|
42
42
|
const sealed = JSON.parse(text);
|
|
43
|
-
|
|
43
|
+
// what wraps it: a vault's transit key (v: 2) or a key the host holds (v: 1), so an operator sees what still needs one
|
|
44
|
+
return { placedAt: sealed.placedAt, fingerprint: sealed.fingerprint, sealedBy: sealed.v === 2 ? 'vault' : 'key' };
|
|
44
45
|
}
|
|
45
46
|
/** The signing secret sealed beside the credential (`{ headers, signingSecret }`), for ingest; null when none. */
|
|
46
47
|
export async function twinSigningSecret(worldRoot, vendor) {
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
48
|
+
const payload = await openSealedAt(credentialPath(worldRoot, vendor), vendor);
|
|
49
|
+
if (payload === null)
|
|
49
50
|
return null;
|
|
50
|
-
const payload = await openSealedCredential(sealingKey(), JSON.parse(text), vendor);
|
|
51
51
|
return typeof payload.signingSecret === 'string' && payload.signingSecret.length >= 8 ? payload.signingSecret : null;
|
|
52
52
|
}
|
|
53
53
|
// ── where a root's credential comes from (company decision 0033) ────────────────────────────
|
package/dist/src/served-world.js
CHANGED
|
@@ -26,7 +26,7 @@ import { getActiveWorldStore, withAncestryLock, 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 { blobDigest, getActiveBlobStore, loadCheck, mirrorShellUnder,
|
|
29
|
+
import { blobDigest, openSealedAt, getActiveBlobStore, loadCheck, mirrorShellUnder, readTwinRequestJournal, serveHttp, TWIN_PREFIX_HEADER, validateRemoteOrigin } from '@volter/world-core';
|
|
30
30
|
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';
|
|
@@ -912,10 +912,9 @@ export class WorldDoors {
|
|
|
912
912
|
* token removed and the sealed credential's headers replacing any of the same name. The vendor's
|
|
913
913
|
* answer (status, headers, body) is streamed back as it arrives. */
|
|
914
914
|
async forward(request, url, rest, name, origin) {
|
|
915
|
-
const
|
|
916
|
-
if (
|
|
915
|
+
const credential = await openSealedAt(credentialPath(this.worldRoot, name), name);
|
|
916
|
+
if (credential === null)
|
|
917
917
|
return Response.json({ error: `the ${name} link has no credential sealed` }, { status: 409 });
|
|
918
|
-
const credential = await openSealedCredential(sealingKey(), JSON.parse(sealed), name);
|
|
919
918
|
const base = validateRemoteOrigin(origin);
|
|
920
919
|
const target = new URL(`${base.origin}/${rest}${url.search}`);
|
|
921
920
|
if (target.origin !== base.origin)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/world-runtime",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.28",
|
|
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.
|
|
70
|
+
"@volter/world-core": "2.0.16",
|
|
71
71
|
"@volter/world-console": "2.0.10"
|
|
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.
|
|
77
|
+
"@volter/world-core": "2.0.16",
|
|
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.
|
|
87
|
+
"@volter/twin-mongodb": "0.1.16"
|
|
88
88
|
}
|
|
89
89
|
}
|
package/src/root.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
|
12
12
|
import { homedir } from 'node:os';
|
|
13
13
|
import { basename, dirname, join, relative, resolve } from 'node:path';
|
|
14
14
|
import {
|
|
15
|
-
NO_SECRETS_CHECK, authStrategyFor, getActiveWorldStore, getPack,
|
|
15
|
+
NO_SECRETS_CHECK, authStrategyFor, currentSealer, openSealedAt, getActiveWorldStore, getPack, buildRemoteExecute, clearRoot, observeAppends, readRoot, registerStateSystem, stateDirName, stateSystemFor, type Check, type CredentialPayload, type PerformAction, type PushReport, type RemoteExecute, type RootConfig, type SealedCredential, type TwinAction, validateRemoteOrigin, writeRoot,
|
|
16
16
|
} from '@volter/world-core';
|
|
17
17
|
import { loadWorldConfig, writeWorldConfig } from './configs.ts';
|
|
18
18
|
import { changesetReadiness, collectObservations, type Observation, foldObservations, loadChecks, openRootCredential, performEntries, rootCustody, protocolStanding, userKek, type DeployReport, type ObserveReport } from '@volter/world-core';
|
|
@@ -38,21 +38,21 @@ export function credentialPath(worldRoot: string, vendor: string): string {
|
|
|
38
38
|
return join(resolve(worldRoot), stateDirName(), 'credentials', `${vendor}.json`);
|
|
39
39
|
}
|
|
40
40
|
export async function sealTwinCredential(worldRoot: string, vendor: string, payload: CredentialPayload, at: string = new Date().toISOString()): Promise<{ placedAt: string; fingerprint: string }> {
|
|
41
|
-
const sealed = await
|
|
41
|
+
const sealed = await currentSealer().seal(payload, at, vendor);
|
|
42
42
|
getActiveWorldStore().write(credentialPath(worldRoot, vendor), `${JSON.stringify(sealed, null, 2)}\n`, { secret: true });
|
|
43
43
|
return { placedAt: sealed.placedAt, fingerprint: sealed.fingerprint };
|
|
44
44
|
}
|
|
45
|
-
export function sealedCredentialInfo(worldRoot: string, vendor: string): { placedAt: string; fingerprint: string } | null {
|
|
45
|
+
export function sealedCredentialInfo(worldRoot: string, vendor: string): { placedAt: string; fingerprint: string; sealedBy: 'vault' | 'key' } | null {
|
|
46
46
|
const text = getActiveWorldStore().read(credentialPath(worldRoot, vendor));
|
|
47
47
|
if (text === null) return null;
|
|
48
48
|
const sealed = JSON.parse(text) as SealedCredential;
|
|
49
|
-
|
|
49
|
+
// what wraps it: a vault's transit key (v: 2) or a key the host holds (v: 1), so an operator sees what still needs one
|
|
50
|
+
return { placedAt: sealed.placedAt, fingerprint: sealed.fingerprint, sealedBy: sealed.v === 2 ? 'vault' : 'key' };
|
|
50
51
|
}
|
|
51
52
|
/** The signing secret sealed beside the credential (`{ headers, signingSecret }`), for ingest; null when none. */
|
|
52
53
|
export async function twinSigningSecret(worldRoot: string, vendor: string): Promise<string | null> {
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
const payload = await openSealedCredential(sealingKey(), JSON.parse(text) as SealedCredential, vendor);
|
|
54
|
+
const payload = await openSealedAt(credentialPath(worldRoot, vendor), vendor);
|
|
55
|
+
if (payload === null) return null;
|
|
56
56
|
return typeof payload.signingSecret === 'string' && payload.signingSecret.length >= 8 ? payload.signingSecret : null;
|
|
57
57
|
}
|
|
58
58
|
|
package/src/served-world.ts
CHANGED
|
@@ -26,7 +26,7 @@ import { getActiveWorldStore, withAncestryLock, 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 { blobDigest, getActiveBlobStore, loadCheck, mirrorShellUnder,
|
|
29
|
+
import { blobDigest, openSealedAt, getActiveBlobStore, loadCheck, mirrorShellUnder, readTwinRequestJournal, serveHttp, TWIN_PREFIX_HEADER, validateRemoteOrigin, type SealedCredential, type TwinStreamConnection, type TwinStreamSink } from '@volter/world-core';
|
|
30
30
|
import { APP_READ_ENDPOINT_ENV } from './init.ts';
|
|
31
31
|
import { grantOf, presentedSecrets, sameSecret, spentPasses, verifyPass, type TrustedIssuer, type WorldCredentials } from '@volter/world-access';
|
|
32
32
|
import { createHash } from 'node:crypto';
|
|
@@ -817,9 +817,8 @@ export class WorldDoors {
|
|
|
817
817
|
* token removed and the sealed credential's headers replacing any of the same name. The vendor's
|
|
818
818
|
* answer (status, headers, body) is streamed back as it arrives. */
|
|
819
819
|
private async forward(request: Request, url: URL, rest: string, name: string, origin: string): Promise<Response> {
|
|
820
|
-
const
|
|
821
|
-
if (
|
|
822
|
-
const credential = await openSealedCredential(sealingKey(), JSON.parse(sealed) as SealedCredential, name);
|
|
820
|
+
const credential = await openSealedAt(credentialPath(this.worldRoot, name), name);
|
|
821
|
+
if (credential === null) return Response.json({ error: `the ${name} link has no credential sealed` }, { status: 409 });
|
|
823
822
|
const base = validateRemoteOrigin(origin);
|
|
824
823
|
const target = new URL(`${base.origin}/${rest}${url.search}`);
|
|
825
824
|
if (target.origin !== base.origin) return Response.json({ error: 'the path left the link origin' }, { status: 400 });
|