@volter/world 2.0.28 → 2.0.29
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/cli.js +16 -4
- package/dist/src/world.d.ts +3 -1
- package/dist/src/world.js +4 -2
- package/package.json +2 -2
- package/src/cli.ts +13 -3
- package/src/world.ts +4 -2
package/dist/src/cli.js
CHANGED
|
@@ -15,6 +15,7 @@ import { forgetPlatform, forgetToken, platformOrigin, storePlatform, storeToken,
|
|
|
15
15
|
import { parseOriginUrl, World } from "./world.js";
|
|
16
16
|
import { waitForServeShutdown } from "./serve-shutdown.js";
|
|
17
17
|
import { startUpdateCheck } from "./update-notice.js";
|
|
18
|
+
import { withoutVaultSignIn } from '@volter/world-runtime';
|
|
18
19
|
/** Open a URL in the person's browser; a machine without one only loses the convenience. */
|
|
19
20
|
function openInBrowser(url) {
|
|
20
21
|
// an http(s) URL only, and on Windows through the URL handler rather than cmd.exe, which would read `"`, `&` or `%VAR%`
|
|
@@ -608,9 +609,19 @@ async function twinCommand(args) {
|
|
|
608
609
|
world.setTwinRoot(vendor, { url, deploy, ...(value(rest, '--scope') ? { scope: value(rest, '--scope') } : {}), ...(Object.keys(refresh).length ? { refresh } : {}) });
|
|
609
610
|
}
|
|
610
611
|
else if (verb === 'credential') {
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
612
|
+
// what is piped in, else the signed-in vault, else the repo's .env (company decision 0033: no vault required)
|
|
613
|
+
let input = process.stdin.isTTY ? '' : stdinText();
|
|
614
|
+
if (input.trim() === '') {
|
|
615
|
+
if (!world.twin(vendor))
|
|
616
|
+
throw new Error(`volter twin ${vendor} credential: this World has no twin "${vendor}"`);
|
|
617
|
+
const found = await world.rootCredentialInput(vendor);
|
|
618
|
+
for (const note of found.notes)
|
|
619
|
+
process.stderr.write(`${vendor} ${note}\n`);
|
|
620
|
+
if (found.input === null)
|
|
621
|
+
throw new Error(`volter twin ${vendor} credential: no credential found. Pipe one (printf '<token>' | volter twin ${vendor} credential), sign in to a vault holding kv/vendors/${vendor}, or put it in the repo's .env`);
|
|
622
|
+
out(`${vendor} credential from ${found.from}`);
|
|
623
|
+
input = found.input;
|
|
624
|
+
}
|
|
614
625
|
await world.sealTwinCredential(vendor, input);
|
|
615
626
|
}
|
|
616
627
|
else if (verb === 'refresh') {
|
|
@@ -961,7 +972,8 @@ async function installDetectedTwins(app, install) {
|
|
|
961
972
|
throw new Error(`install the twins first: ${command}
|
|
962
973
|
then run volter world init again (or volter world init --install does both)`);
|
|
963
974
|
// one command line built from the checked names above: nothing of anyone's input reaches the shell
|
|
964
|
-
|
|
975
|
+
// a dependency's install script is not Volter's: it never sees the person's vault sign-in
|
|
976
|
+
const ran = spawnSync(command, { cwd: app, stdio: 'inherit', shell: true, windowsHide: true, env: withoutVaultSignIn(process.env) });
|
|
965
977
|
if (ran.status !== 0)
|
|
966
978
|
throw new Error(`${command} failed (exit ${ran.status ?? 'none'})`);
|
|
967
979
|
}
|
package/dist/src/world.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { rebaseChangeset, worldBootMarker, type Changeset, type LedgerDelta, type TwinAction, type WorldMarker, type ApplyReceipt, applyTwinWrite, type TwinResource } from '@volter/world-core';
|
|
2
|
-
import { approveWorldChangeset, createWorldChangeset, downWorld, fetchFromOrigin, pushWorldChangeset, rebaseWorldChangeset, replayWorldChangeset, resetWorld, seedWorld, statusWorldChangeset, verifyWorldChangeset, type ServedWorld, type ViewConsole, type WorldView, type DeployTwinOutcome, type ChangesetLocation, type InitOptions, type InitResult, type WorldInstance } from '@volter/world-runtime';
|
|
2
|
+
import { approveWorldChangeset, createWorldChangeset, downWorld, fetchFromOrigin, pushWorldChangeset, rebaseWorldChangeset, replayWorldChangeset, resetWorld, seedWorld, statusWorldChangeset, verifyWorldChangeset, type ServedWorld, type ViewConsole, type WorldView, rootCredentialInput, type DeployTwinOutcome, type ChangesetLocation, type InitOptions, type InitResult, type WorldInstance } from '@volter/world-runtime';
|
|
3
3
|
import { rebaseBranch, type Receipt, type RootConfig } from '@volter/world-core';
|
|
4
4
|
export type WorldRef = {
|
|
5
5
|
name?: string;
|
|
@@ -296,6 +296,8 @@ export declare class World {
|
|
|
296
296
|
placedAt: string;
|
|
297
297
|
fingerprint: string;
|
|
298
298
|
}>;
|
|
299
|
+
/** A root's credential when none is piped in: the signed-in vault, else the repo's `.env` (decision 0033). */
|
|
300
|
+
rootCredentialInput(vendor: string): ReturnType<typeof rootCredentialInput>;
|
|
299
301
|
/** Refresh one twin from its root now. */
|
|
300
302
|
refreshTwin(vendor: string, opts?: {
|
|
301
303
|
force?: boolean;
|
package/dist/src/world.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { rebaseChangeset, worldBootMarker, listActions, isTwinBookkeeping, pushablePendingActions, pendingActions, applyTwinWrite, twinResources } from '@volter/world-core';
|
|
6
6
|
import { spawnSync } from 'node:child_process';
|
|
7
7
|
import clockForm from '@volter/world-core/world-clock';
|
|
8
|
-
import { activateScript, approveWorldChangeset, branchWorld, clockFile, checkoutWorld, createWorldChangeset, diffWorld, downWorld, fetchFromOrigin, findWorldChangeset, initWorld, listWorldChangesets, listWorldMarks, listWorlds, markWorld, pushWorldChangeset, rebaseWorldChangeset, replayWorldChangeset, resetWorld, runWithWorldEnv, seedWorld, shellWorld, statusWorld, statusWorldChangeset, upWorld, verifyWorldChangeset, worldLedgers, worldOrigin, deployWorld, loadWorldConfig, writeWorldConfig, readServeRecord, refreshTwin, serveWorld, serveWorldView, findInstalledPackage, rootForControlRoot, sealTwinCredential, sealedCredentialInfo, setTwinRoot, credentialPayloadFrom, materializeRoots } from '@volter/world-runtime';
|
|
8
|
+
import { activateScript, approveWorldChangeset, branchWorld, clockFile, checkoutWorld, createWorldChangeset, diffWorld, downWorld, fetchFromOrigin, findWorldChangeset, initWorld, listWorldChangesets, listWorldMarks, listWorlds, markWorld, pushWorldChangeset, rebaseWorldChangeset, replayWorldChangeset, resetWorld, runWithWorldEnv, seedWorld, shellWorld, statusWorld, statusWorldChangeset, upWorld, verifyWorldChangeset, worldLedgers, worldOrigin, deployWorld, loadWorldConfig, writeWorldConfig, readServeRecord, refreshTwin, serveWorld, serveWorldView, findInstalledPackage, rootForControlRoot, sealTwinCredential, sealedCredentialInfo, setTwinRoot, credentialPayloadFrom, rootCredentialInput, withoutVaultSignIn, materializeRoots } from '@volter/world-runtime';
|
|
9
9
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
10
10
|
import { dirname, join, resolve } from 'node:path';
|
|
11
11
|
import { requireToken, storeToken } from "./credentials.js";
|
|
@@ -94,7 +94,7 @@ export class World {
|
|
|
94
94
|
if (opts.install !== false && !twins.every((t) => findInstalledPackage(dir, `@volter/twin-${t}`))) {
|
|
95
95
|
// the runtime's own installer: bun under Bun, npm under Node — never assumed
|
|
96
96
|
const cmd = typeof Bun !== 'undefined' ? ['bun', 'add', '-d'] : ['npm', 'install', '--save-dev'];
|
|
97
|
-
const r = spawnSync(cmd[0], [...cmd.slice(1), ...twins.map((t) => `@volter/twin-${t}`)], { windowsHide: true, cwd: dir, stdio: 'inherit' });
|
|
97
|
+
const r = spawnSync(cmd[0], [...cmd.slice(1), ...twins.map((t) => `@volter/twin-${t}`)], { windowsHide: true, cwd: dir, stdio: 'inherit', env: withoutVaultSignIn(process.env) });
|
|
98
98
|
if (r.status !== 0)
|
|
99
99
|
throw new Error(`installing the twins failed (${cmd.join(' ')} exited ${r.status})`);
|
|
100
100
|
}
|
|
@@ -502,6 +502,8 @@ export class World {
|
|
|
502
502
|
}
|
|
503
503
|
/** Seal the vendor's credential beside the world (a bare token, or a JSON payload). Never readable back. */
|
|
504
504
|
sealTwinCredential(vendor, input) { return sealTwinCredential(this.root, vendor, credentialPayloadFrom(input, vendor)); }
|
|
505
|
+
/** A root's credential when none is piped in: the signed-in vault, else the repo's `.env` (decision 0033). */
|
|
506
|
+
rootCredentialInput(vendor) { return rootCredentialInput(this.root, vendor); }
|
|
505
507
|
/** Refresh one twin from its root now. */
|
|
506
508
|
async refreshTwin(vendor, opts = {}) {
|
|
507
509
|
const { controlRoot, root } = this.rootOf(vendor);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/world",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.29",
|
|
4
4
|
"description": "Run your app against a world of twins. `World` and `Repo` — one method per verb: init, up, run, log, diff, reset, branch, checkout, clone, fetch, changeset, push — and the `volter` command, one client of them.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"volter",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@modelcontextprotocol/sdk": "^1.30.1",
|
|
33
33
|
"@volter/world-core": "2.0.15",
|
|
34
|
-
"@volter/world-runtime": "2.0.
|
|
34
|
+
"@volter/world-runtime": "2.0.27",
|
|
35
35
|
"zod": "^4.6.5"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
package/src/cli.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { parseOriginUrl, World } from './world.ts';
|
|
|
17
17
|
import { waitForServeShutdown } from './serve-shutdown.ts';
|
|
18
18
|
import { startUpdateCheck } from './update-notice.ts';
|
|
19
19
|
import type { ViewConsole } from '@volter/world-runtime';
|
|
20
|
+
import { withoutVaultSignIn } from '@volter/world-runtime';
|
|
20
21
|
|
|
21
22
|
/** Open a URL in the person's browser; a machine without one only loses the convenience. */
|
|
22
23
|
function openInBrowser(url: string): void {
|
|
@@ -440,8 +441,16 @@ async function twinCommand(args: string[]): Promise<void> {
|
|
|
440
441
|
const refresh = { ...(value(rest, '--refresh') ? { every: value(rest, '--refresh')! } : {}), ...(value(rest, '--at-most') ? { atMost: value(rest, '--at-most')! } : {}) };
|
|
441
442
|
world.setTwinRoot(vendor, { url, deploy, ...(value(rest, '--scope') ? { scope: value(rest, '--scope')! } : {}), ...(Object.keys(refresh).length ? { refresh } : {}) });
|
|
442
443
|
} else if (verb === 'credential') {
|
|
443
|
-
|
|
444
|
-
|
|
444
|
+
// what is piped in, else the signed-in vault, else the repo's .env (company decision 0033: no vault required)
|
|
445
|
+
let input = process.stdin.isTTY ? '' : stdinText();
|
|
446
|
+
if (input.trim() === '') {
|
|
447
|
+
if (!world.twin(vendor)) throw new Error(`volter twin ${vendor} credential: this World has no twin "${vendor}"`);
|
|
448
|
+
const found = await world.rootCredentialInput(vendor);
|
|
449
|
+
for (const note of found.notes) process.stderr.write(`${vendor} ${note}\n`);
|
|
450
|
+
if (found.input === null) throw new Error(`volter twin ${vendor} credential: no credential found. Pipe one (printf '<token>' | volter twin ${vendor} credential), sign in to a vault holding kv/vendors/${vendor}, or put it in the repo's .env`);
|
|
451
|
+
out(`${vendor} credential from ${found.from}`);
|
|
452
|
+
input = found.input;
|
|
453
|
+
}
|
|
445
454
|
await world.sealTwinCredential(vendor, input);
|
|
446
455
|
} else if (verb === 'refresh') {
|
|
447
456
|
const r = await world.refreshTwin(vendor, { force: flag(rest, '--force') });
|
|
@@ -703,7 +712,8 @@ async function installDetectedTwins(app: string, install: boolean): Promise<void
|
|
|
703
712
|
if (!yes) throw new Error(`install the twins first: ${command}
|
|
704
713
|
then run volter world init again (or volter world init --install does both)`);
|
|
705
714
|
// one command line built from the checked names above: nothing of anyone's input reaches the shell
|
|
706
|
-
|
|
715
|
+
// a dependency's install script is not Volter's: it never sees the person's vault sign-in
|
|
716
|
+
const ran = spawnSync(command, { cwd: app, stdio: 'inherit', shell: true, windowsHide: true, env: withoutVaultSignIn(process.env) });
|
|
707
717
|
if (ran.status !== 0) throw new Error(`${command} failed (exit ${ran.status ?? 'none'})`);
|
|
708
718
|
}
|
|
709
719
|
|
package/src/world.ts
CHANGED
|
@@ -8,7 +8,7 @@ import clockForm from '@volter/world-core/world-clock';
|
|
|
8
8
|
import {
|
|
9
9
|
activateScript, approveWorldChangeset, branchWorld, clockFile, checkoutWorld, createWorldChangeset, diffWorld, downWorld, fetchFromOrigin, findWorldChangeset, initWorld, listWorldChangesets, listWorldMarks, listWorlds, markWorld, pushWorldChangeset, rebaseWorldChangeset, replayWorldChangeset, resetWorld, runWithWorldEnv, seedWorld, shellWorld,
|
|
10
10
|
statusWorld, statusWorldChangeset, upWorld, verifyWorldChangeset, worldLedgers, worldOrigin,
|
|
11
|
-
deployWorld, loadWorldConfig, writeWorldConfig, readServeRecord, refreshTwin, serveWorld, serveWorldView, findInstalledPackage, type ServedWorld, type ViewConsole, type WorldView, rootForControlRoot, sealTwinCredential, sealedCredentialInfo, setTwinRoot, credentialPayloadFrom,
|
|
11
|
+
deployWorld, loadWorldConfig, writeWorldConfig, readServeRecord, refreshTwin, serveWorld, serveWorldView, findInstalledPackage, type ServedWorld, type ViewConsole, type WorldView, rootForControlRoot, sealTwinCredential, sealedCredentialInfo, setTwinRoot, credentialPayloadFrom, rootCredentialInput, withoutVaultSignIn,
|
|
12
12
|
type DeployTwinOutcome, type MaterializedRoot,
|
|
13
13
|
type ChangesetLocation, type InitOptions, type InitResult, type WorldInstance, materializeRoots } from '@volter/world-runtime';
|
|
14
14
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
@@ -108,7 +108,7 @@ export class World {
|
|
|
108
108
|
if (opts.install !== false && !twins.every((t) => findInstalledPackage(dir, `@volter/twin-${t}`))) {
|
|
109
109
|
// the runtime's own installer: bun under Bun, npm under Node — never assumed
|
|
110
110
|
const cmd = typeof Bun !== 'undefined' ? ['bun', 'add', '-d'] : ['npm', 'install', '--save-dev'];
|
|
111
|
-
const r = spawnSync(cmd[0]!, [...cmd.slice(1), ...twins.map((t) => `@volter/twin-${t}`)], { windowsHide: true, cwd: dir, stdio: 'inherit' });
|
|
111
|
+
const r = spawnSync(cmd[0]!, [...cmd.slice(1), ...twins.map((t) => `@volter/twin-${t}`)], { windowsHide: true, cwd: dir, stdio: 'inherit', env: withoutVaultSignIn(process.env) });
|
|
112
112
|
if (r.status !== 0) throw new Error(`installing the twins failed (${cmd.join(' ')} exited ${r.status})`);
|
|
113
113
|
}
|
|
114
114
|
const name = served.split('/')[1]!;
|
|
@@ -461,6 +461,8 @@ export class World {
|
|
|
461
461
|
}
|
|
462
462
|
/** Seal the vendor's credential beside the world (a bare token, or a JSON payload). Never readable back. */
|
|
463
463
|
sealTwinCredential(vendor: string, input: string): Promise<{ placedAt: string; fingerprint: string }> { return sealTwinCredential(this.root, vendor, credentialPayloadFrom(input, vendor)); }
|
|
464
|
+
/** A root's credential when none is piped in: the signed-in vault, else the repo's `.env` (decision 0033). */
|
|
465
|
+
rootCredentialInput(vendor: string): ReturnType<typeof rootCredentialInput> { return rootCredentialInput(this.root, vendor); }
|
|
464
466
|
/** Refresh one twin from its root now. */
|
|
465
467
|
async refreshTwin(vendor: string, opts: { force?: boolean } = {}): Promise<{ refreshed: boolean; reason?: string; report?: { observed: number; appended: number; unchanged: number; removed: number } }> {
|
|
466
468
|
const { controlRoot, root } = this.rootOf(vendor);
|