@volter/world-runtime 2.0.0
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/LICENSE +202 -0
- package/dist/known-external-services.json +1108 -0
- package/dist/src/ancestry.d.ts +2 -0
- package/dist/src/ancestry.js +42 -0
- package/dist/src/app-url.d.ts +47 -0
- package/dist/src/app-url.js +239 -0
- package/dist/src/attach.d.ts +48 -0
- package/dist/src/attach.js +87 -0
- package/dist/src/branch.d.ts +20 -0
- package/dist/src/branch.js +65 -0
- package/dist/src/browser-proxy-cli.d.ts +2 -0
- package/dist/src/browser-proxy-cli.js +41 -0
- package/dist/src/ca-trust.d.ts +5 -0
- package/dist/src/ca-trust.js +64 -0
- package/dist/src/catalog.d.ts +31 -0
- package/dist/src/catalog.js +148 -0
- package/dist/src/changeset.d.ts +142 -0
- package/dist/src/changeset.js +570 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +1262 -0
- package/dist/src/command-lifetime.d.ts +15 -0
- package/dist/src/command-lifetime.js +98 -0
- package/dist/src/configs.d.ts +18 -0
- package/dist/src/configs.js +119 -0
- package/dist/src/console-apart.d.ts +38 -0
- package/dist/src/console-apart.js +107 -0
- package/dist/src/consumers.d.ts +46 -0
- package/dist/src/consumers.js +200 -0
- package/dist/src/covers.d.ts +183 -0
- package/dist/src/covers.js +800 -0
- package/dist/src/fixture-env.d.ts +42 -0
- package/dist/src/fixture-env.js +221 -0
- package/dist/src/host-cli.d.ts +2 -0
- package/dist/src/host-cli.js +92 -0
- package/dist/src/host-fault-fixture.d.ts +32 -0
- package/dist/src/host-fault-fixture.js +100 -0
- package/dist/src/host-worker.d.ts +1 -0
- package/dist/src/host-worker.js +23 -0
- package/dist/src/host.d.ts +38 -0
- package/dist/src/host.js +135 -0
- package/dist/src/index.d.ts +48 -0
- package/dist/src/index.js +35 -0
- package/dist/src/infra-cli.d.ts +2 -0
- package/dist/src/infra-cli.js +136 -0
- package/dist/src/init.d.ts +227 -0
- package/dist/src/init.js +1117 -0
- package/dist/src/inject-map.d.ts +34 -0
- package/dist/src/inject-map.js +56 -0
- package/dist/src/lifecycle-record.d.ts +47 -0
- package/dist/src/lifecycle-record.js +196 -0
- package/dist/src/origin.d.ts +31 -0
- package/dist/src/origin.js +139 -0
- package/dist/src/pack-facts.d.ts +75 -0
- package/dist/src/pack-facts.js +98 -0
- package/dist/src/pglite-backing.d.ts +21 -0
- package/dist/src/pglite-backing.js +158 -0
- package/dist/src/pglite-host.mjs +147 -0
- package/dist/src/placeholder.d.ts +20 -0
- package/dist/src/placeholder.js +100 -0
- package/dist/src/prerequisites.d.ts +21 -0
- package/dist/src/prerequisites.js +49 -0
- package/dist/src/process-groups.d.ts +4 -0
- package/dist/src/process-groups.js +49 -0
- package/dist/src/project-inspect.d.ts +109 -0
- package/dist/src/project-inspect.js +827 -0
- package/dist/src/proxy-daemon.d.ts +2 -0
- package/dist/src/proxy-daemon.js +18 -0
- package/dist/src/redirect-proxy.d.ts +105 -0
- package/dist/src/redirect-proxy.js +665 -0
- package/dist/src/reflect.d.ts +74 -0
- package/dist/src/reflect.js +392 -0
- package/dist/src/resources.d.ts +26 -0
- package/dist/src/resources.js +22 -0
- package/dist/src/root.d.ts +114 -0
- package/dist/src/root.js +312 -0
- package/dist/src/run-task-worker.d.ts +1 -0
- package/dist/src/run-task-worker.js +38 -0
- package/dist/src/run-task.d.ts +18 -0
- package/dist/src/run-task.js +48 -0
- package/dist/src/runtime-test-support.d.ts +59 -0
- package/dist/src/runtime-test-support.js +205 -0
- package/dist/src/runtime.d.ts +256 -0
- package/dist/src/runtime.js +3502 -0
- package/dist/src/schema.d.ts +449 -0
- package/dist/src/schema.js +605 -0
- package/dist/src/serve.d.ts +30 -0
- package/dist/src/serve.js +82 -0
- package/dist/src/served-world.d.ts +194 -0
- package/dist/src/served-world.js +986 -0
- package/dist/src/service-exit.d.ts +46 -0
- package/dist/src/service-exit.js +195 -0
- package/dist/src/service-recorder.d.ts +1 -0
- package/dist/src/service-recorder.js +121 -0
- package/dist/src/sibling.d.ts +1 -0
- package/dist/src/sibling.js +9 -0
- package/dist/src/signals.d.ts +1 -0
- package/dist/src/signals.js +11 -0
- package/dist/src/storage-capacity.d.ts +8 -0
- package/dist/src/storage-capacity.js +61 -0
- package/dist/src/tail.d.ts +30 -0
- package/dist/src/tail.js +160 -0
- package/dist/src/tcp-port.d.ts +2 -0
- package/dist/src/tcp-port.js +36 -0
- package/dist/src/up-task-worker.d.ts +1 -0
- package/dist/src/up-task-worker.js +61 -0
- package/dist/src/up-task.d.ts +17 -0
- package/dist/src/up-task.js +49 -0
- package/dist/src/websocket-relay.d.ts +3 -0
- package/dist/src/websocket-relay.js +40 -0
- package/known-external-services.json +1108 -0
- package/package.json +83 -0
- package/src/ancestry.ts +36 -0
- package/src/app-url.ts +253 -0
- package/src/attach.ts +117 -0
- package/src/branch.ts +63 -0
- package/src/browser-proxy-cli.ts +44 -0
- package/src/ca-trust.ts +57 -0
- package/src/catalog.ts +156 -0
- package/src/changeset.ts +627 -0
- package/src/cli.ts +1111 -0
- package/src/command-lifetime.ts +79 -0
- package/src/configs.ts +110 -0
- package/src/console-apart.ts +90 -0
- package/src/consumers.ts +185 -0
- package/src/covers.ts +934 -0
- package/src/fixture-env.ts +230 -0
- package/src/host-cli.ts +90 -0
- package/src/host-worker.ts +23 -0
- package/src/host.ts +169 -0
- package/src/index.ts +171 -0
- package/src/infra-cli.ts +133 -0
- package/src/init.ts +1316 -0
- package/src/inject-map.ts +72 -0
- package/src/lifecycle-record.ts +168 -0
- package/src/origin.ts +134 -0
- package/src/pack-facts.ts +128 -0
- package/src/pglite-backing.ts +141 -0
- package/src/pglite-host.mjs +147 -0
- package/src/placeholder.ts +89 -0
- package/src/prerequisites.ts +66 -0
- package/src/process-groups.ts +33 -0
- package/src/project-inspect.ts +770 -0
- package/src/proxy-daemon.ts +21 -0
- package/src/redirect-proxy.ts +684 -0
- package/src/reflect.ts +440 -0
- package/src/resources.ts +22 -0
- package/src/root.ts +290 -0
- package/src/run-task-worker.ts +27 -0
- package/src/run-task.ts +44 -0
- package/src/runtime-test-support.ts +208 -0
- package/src/runtime.ts +3357 -0
- package/src/schema.ts +922 -0
- package/src/serve.ts +102 -0
- package/src/served-world.ts +812 -0
- package/src/service-exit.ts +175 -0
- package/src/service-recorder.ts +89 -0
- package/src/sibling.ts +10 -0
- package/src/signals.ts +10 -0
- package/src/storage-capacity.ts +60 -0
- package/src/tail.ts +205 -0
- package/src/tcp-port.ts +35 -0
- package/src/up-task-worker.ts +40 -0
- package/src/up-task.ts +45 -0
- package/src/websocket-relay.ts +32 -0
package/dist/src/host.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
// Co-located twin host — run many twins in ONE process instead of one OS process
|
|
10
|
+
// per twin. The twin core is a pure, transport-agnostic handler (see a pack's
|
|
11
|
+
// `handle<Vendor>TwinRequest`), so nothing requires a process per twin; this host
|
|
12
|
+
// mounts N of them behind their own ports/URLs (the world env + instance.json are
|
|
13
|
+
// byte-identical to the spawned path — only the process model changes).
|
|
14
|
+
//
|
|
15
|
+
// Isolation is a DIAL, not a binary (the runtime stays minimal — this is still just
|
|
16
|
+
// "bring services up / tear them down", one child process):
|
|
17
|
+
// - 'shared' : all twins share one event loop + heap. Lightest. A thrown request
|
|
18
|
+
// handler is isolated (Bun.serve returns 500; siblings serve on), but a
|
|
19
|
+
// CPU hog / OOM / process.exit in one twin hits all. Default for CI/dev.
|
|
20
|
+
// - 'worker' : one Worker thread per twin → own event loop + own heap, independently
|
|
21
|
+
// isolated. A sibling can spin, leak, or hard-exit without taking the
|
|
22
|
+
// host down — but a crashed twin stays down (doctor red), it is never
|
|
23
|
+
// respawned. Still ONE OS process to the orchestrator.
|
|
24
|
+
// ('process' isolation — one OS process per twin — is the world runtime's existing
|
|
25
|
+
// spawn path; it remains the oracle and the choice for share/sealed/hosted worlds.)
|
|
26
|
+
//
|
|
27
|
+
// ARCHITECTURE: the runtime never imports vendor packs. A twin is named by a module
|
|
28
|
+
// SPECIFIER + export resolved with dynamic import() at boot, so this host (and the
|
|
29
|
+
// world config that drives it) stays vendor-agnostic — exactly like `bin` spawning.
|
|
30
|
+
import { Worker } from 'node:worker_threads';
|
|
31
|
+
import { siblingScript } from "./sibling.js";
|
|
32
|
+
import { pathToFileURL } from 'node:url';
|
|
33
|
+
async function loadFactory(spec) {
|
|
34
|
+
const mod = (await import(__rewriteRelativeImportExtension(spec.module)));
|
|
35
|
+
const factory = mod[spec.export];
|
|
36
|
+
if (typeof factory !== 'function') {
|
|
37
|
+
throw new Error(`Twin "${spec.id}": ${spec.module} has no factory export "${spec.export}"`);
|
|
38
|
+
}
|
|
39
|
+
return factory;
|
|
40
|
+
}
|
|
41
|
+
const workerEntry = () => pathToFileURL(siblingScript(import.meta.url, 'host-worker'));
|
|
42
|
+
/** Per-twin stop budget inside host.stop(). Must stay comfortably under downWorld's 5s
|
|
43
|
+
* SIGTERM→SIGKILL grace (DOWN_GRACE_MS_DEFAULT): the host must reach process.exit(0) even
|
|
44
|
+
* when a twin's stop hangs, or the whole co-located world dies by SIGKILL. */
|
|
45
|
+
const STOP_TIMEOUT_MS = 3000;
|
|
46
|
+
/**
|
|
47
|
+
* Start a co-located host. Resolves once every twin is listening. The returned `stop()`
|
|
48
|
+
* tears the whole host down (all servers / all workers).
|
|
49
|
+
*
|
|
50
|
+
* `onEvent` is an optional observability hook (logged by the CLI) — it surfaces a twin
|
|
51
|
+
* worker crashing (and being given up on), and stray rejections swallowed in shared mode,
|
|
52
|
+
* so a degraded twin is never a silent fake-success.
|
|
53
|
+
*/
|
|
54
|
+
export async function startColocatedHost(specs, options = {}) {
|
|
55
|
+
const isolation = options.isolation ?? 'shared';
|
|
56
|
+
const onEvent = options.onEvent ?? (() => { });
|
|
57
|
+
const ports = {};
|
|
58
|
+
for (const spec of specs)
|
|
59
|
+
ports[spec.id] = spec.port;
|
|
60
|
+
if (isolation === 'shared') {
|
|
61
|
+
// Keep one twin's stray async rejection / uncaught throw from killing every other twin in
|
|
62
|
+
// the shared process. (A thrown *request* handler is already contained by Bun.serve → 500.)
|
|
63
|
+
// We log and attribute rather than exit — state stays consistent because every kernel write
|
|
64
|
+
// is atomic (temp→rename) and root-keyed, so a swallowed error can't corrupt a sibling.
|
|
65
|
+
const onRejection = (reason) => onEvent({ twin: '(host)', kind: 'unhandledRejection', detail: String(reason) });
|
|
66
|
+
const onUncaught = (err) => onEvent({ twin: '(host)', kind: 'uncaughtException', detail: String(err) });
|
|
67
|
+
process.on('unhandledRejection', onRejection);
|
|
68
|
+
process.on('uncaughtException', onUncaught);
|
|
69
|
+
const servers = [];
|
|
70
|
+
for (const spec of specs) {
|
|
71
|
+
const factory = await loadFactory(spec);
|
|
72
|
+
servers.push(await factory({ port: spec.port, root: spec.root, readOnly: spec.readOnly, ...(spec.scenarioPath !== undefined ? { scenarioPath: spec.scenarioPath } : {}) }));
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
isolation,
|
|
76
|
+
ports,
|
|
77
|
+
stop: async () => {
|
|
78
|
+
process.off('unhandledRejection', onRejection);
|
|
79
|
+
process.off('uncaughtException', onUncaught);
|
|
80
|
+
// EVERY stop is invoked, IN PARALLEL, each under its own timeout, and no outcome —
|
|
81
|
+
// rejection, hang, or slowness — can prevent the others or wedge host.stop() itself.
|
|
82
|
+
// The awaited-sequential first cut re-created the SIGKILL escalation it was fixing
|
|
83
|
+
// through a new door (§9 round two H2, 2026-08-31: one pending/throwing stop — fly's
|
|
84
|
+
// cleanup throws on a failed container removal — left siblings unstopped and the host
|
|
85
|
+
// ignoring SIGTERM forever). The bound stays under downWorld's 5s SIGKILL grace.
|
|
86
|
+
await Promise.allSettled(servers.map((s) => Promise.race([
|
|
87
|
+
Promise.resolve().then(() => s.stop()),
|
|
88
|
+
new Promise((resolveTimeout) => setTimeout(resolveTimeout, STOP_TIMEOUT_MS).unref?.()),
|
|
89
|
+
])));
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
// worker isolation — one Worker thread per twin, given up on crash — never respawned.
|
|
94
|
+
const stopping = { value: false };
|
|
95
|
+
const workers = new Map();
|
|
96
|
+
const spawnWorker = (spec) => new Promise((resolveReady, rejectReady) => {
|
|
97
|
+
const worker = new Worker(workerEntry(), { workerData: spec });
|
|
98
|
+
// Pure observability, symmetric with `gaveup` below — NOT a supervision hook. Fired exactly
|
|
99
|
+
// once per spawnWorker() call (there's no counter/timer/keep-alive here), so it doubles as a
|
|
100
|
+
// direct tamper guard: a stealth respawn re-adding `spawnWorker(spec)` in the exit handler
|
|
101
|
+
// below would emit a 2nd `spawn` for the same twin, which the isolation test asserts against.
|
|
102
|
+
onEvent({ twin: spec.id, kind: 'spawn', detail: 'worker started' });
|
|
103
|
+
let ready = false;
|
|
104
|
+
worker.on('message', (msg) => {
|
|
105
|
+
if (msg?.type === 'ready') {
|
|
106
|
+
ready = true;
|
|
107
|
+
resolveReady();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
worker.on('error', (err) => {
|
|
111
|
+
onEvent({ twin: spec.id, kind: 'error', detail: String(err) });
|
|
112
|
+
if (!ready)
|
|
113
|
+
rejectReady(err);
|
|
114
|
+
});
|
|
115
|
+
worker.on('exit', (code) => {
|
|
116
|
+
workers.delete(spec.id);
|
|
117
|
+
if (stopping.value || code === 0)
|
|
118
|
+
return;
|
|
119
|
+
// Minimal-primitive doctrine: no keep-alive supervisor. A crashed worker is NOT
|
|
120
|
+
// respawned — record the give-up (host-cli persists it → doctor red) and stay dead.
|
|
121
|
+
onEvent({ twin: spec.id, kind: 'gaveup', detail: `exit code ${code} — not restarted`, exits: 1 });
|
|
122
|
+
});
|
|
123
|
+
workers.set(spec.id, worker);
|
|
124
|
+
});
|
|
125
|
+
for (const spec of specs)
|
|
126
|
+
await spawnWorker(spec);
|
|
127
|
+
return {
|
|
128
|
+
isolation,
|
|
129
|
+
ports,
|
|
130
|
+
stop: async () => {
|
|
131
|
+
stopping.value = true;
|
|
132
|
+
await Promise.all([...workers.values()].map((w) => w.terminate()));
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type { WorldConfig, WorldInstance, WorldIsolation, WorldMode, WorldServiceConfig, WorldServiceType, WorldExternalServiceConfig, WorldExternalDiscover, WorldExternalDiscoverSource, WorldExternalReadyWhen, WorldRunOutcome, WorldRunRecord, WorldResourceRequirements, WorldManifestV2, WorldSelection, WorldSelectionSelector, WorldUsage, } from './schema.js';
|
|
2
|
+
export { DEFAULT_WORLD_SELECTION, LEGACY_WORLD_SELECTION, WORLD_SCHEMA_VERSION, WORLD_USAGES, worldConfigDocument, worldSelectionIncludes } from './schema.js';
|
|
3
|
+
export { loadWorldConfig, migrateWorldConfig, resolveConfigPath, writeWorldConfig } from './configs.js';
|
|
4
|
+
export type { WorldConfigMigration } from './configs.js';
|
|
5
|
+
export { upWorld, downWorld, pruneWorlds, listWorlds, statusWorld, doctorWorld, runWithWorldEnv, attachWorld, retireWorldConsumers, activateScript, shellWorld, worldShellEnv, ensureWorldProxy, runProxyDaemon, runWorld, shareWorld, shareWorldServices, unshareWorld, urlsWorld, urlWorld, } from './runtime.js';
|
|
6
|
+
export type { WorldCleanupEntry } from './runtime.js';
|
|
7
|
+
export { worldResourceReport } from './resources.js';
|
|
8
|
+
export { appUrlFile, appUrlUnsetMessage, detectAppUrl, readAppUrl, setAppUrl } from './app-url.js';
|
|
9
|
+
export type { AppUrlRecord, AppUrlSource } from './app-url.js';
|
|
10
|
+
export { tailWorldActions } from './tail.js';
|
|
11
|
+
export type { TailWorldOptions } from './tail.js';
|
|
12
|
+
export { pushWorldChangeset, rebaseWorldChangeset, approveWorldChangeset, createWorldChangeset, diffWorld, EPHEMERAL_VERIFY_TARGET, findWorldChangeset, listWorldChangesets, listWorldMarks, markWorld, MARK_NOTE_MAX, replayWorldChangeset, resolveBaseMarker, statusWorldChangeset, verifyWorldChangeset, worldChangesetsDir, worldLedgers, worldMarksDir, } from './changeset.js';
|
|
13
|
+
export type { NotedMarker, PushWorldOptions, PushWorldOutcome, RebaseWorldOutcome, ApproveWorldOutcome, ChangesetLocation, VerifyWorldOutcome, WorldRootOptions } from './changeset.js';
|
|
14
|
+
export { checkLocalExecution, checkPrerequisites, formatPrerequisiteChecks, } from './prerequisites.js';
|
|
15
|
+
export { inspectProject, formatProjectInspection, projectDependencies, projectEnvNames, SDK_TWINS, workspaceDirs } from './project-inspect.js';
|
|
16
|
+
export type { ProjectInspection } from './project-inspect.js';
|
|
17
|
+
export { fakeEnvValue, fakeGoogleOAuthClientJson, fakeGoogleServiceAccountJson, isGoogleOAuthClientEnvName, isGoogleServiceAccountEnvName } from './fixture-env.js';
|
|
18
|
+
export type { FakeServiceAccountOptions } from './fixture-env.js';
|
|
19
|
+
export { coverWorld, detectRepoVendors, envNameVendor, formatCoverageReport, injectorVendorKeysFor, isCredentialShapedEnvName, worldTwinInventory, } from './covers.js';
|
|
20
|
+
export type { CoverageReport, CoverageRow, CoverageStatus, CoverageOptions, RepoVendorSignals } from './covers.js';
|
|
21
|
+
export { formatInitReport, initWorld, packCatalog, planWorldInit, renderEnvFile, writeWorldInit } from './init.js';
|
|
22
|
+
export { STATE_GITIGNORE } from './init.js';
|
|
23
|
+
export { clockFile } from './runtime.js';
|
|
24
|
+
export { checkoutCatalog, findInstalledPackage, installedCatalog, resolveCatalog, resolveServicePackage, twinPackageName, TWIN_PACKAGE_PREFIX, type Catalog, type CatalogKind, packCli, packEntry } from './catalog.js';
|
|
25
|
+
export { MINT_ENV } from './schema.js';
|
|
26
|
+
export type { EnvDisposition, InitEnvRow, InitInfraStub, InitOptions, InitPlan, InitResult, InitVendorPlan, InitWiring, } from './init.js';
|
|
27
|
+
export { deriveWorldManifest, findWorldRefFile, isRemoteWorldRef, resolveWorldRef, WORLD_REF_FILE, worldManifest, } from './attach.js';
|
|
28
|
+
export type { ResolvedWorldRef, WorldManifest, WorldRefSource } from './attach.js';
|
|
29
|
+
export { parseSni, readReflectRoutes, reflectRoutesPath, reflectManifestPath, readReflectManifest, writeReflectManifest, clearReflectManifest, composeOverrideForReflect, splitDockerComposeArgs, dockerComposeWithOverride, CA_TRUST_ENV, ATTACHED_CA_PATH, startReflectFront, startReflectResolver, writeReflectRoutes, } from './reflect.js';
|
|
30
|
+
export type { ReflectFrontHandle, ReflectFrontOptions, ReflectManifest, ReflectResolverHandle, ReflectResolverOptions } from './reflect.js';
|
|
31
|
+
export type { PrerequisiteCheck, PrerequisiteId, } from './prerequisites.js';
|
|
32
|
+
export { startColocatedHost } from './host.js';
|
|
33
|
+
export type { ColocatedTwinSpec, ColocatedHost, HostIsolation } from './host.js';
|
|
34
|
+
export { advertiseWorldManifest, fetchRemoteManifest, MANIFEST_PATH, remoteAttachEnv, startManifestServer, } from './serve.js';
|
|
35
|
+
export type { ManifestServerHandle, ManifestServerOptions } from './serve.js';
|
|
36
|
+
export { resetWorld, seedEntryFor, seedWorld } from './placeholder.js';
|
|
37
|
+
export type { SeedWorldOptions, SeedWorldOutcome } from './placeholder.js';
|
|
38
|
+
export { fetchFromOrigin, worldOrigin } from './origin.js';
|
|
39
|
+
export type { FetchOptions, FetchOutcome } from './origin.js';
|
|
40
|
+
export { branchWorld, checkoutWorld } from './branch.js';
|
|
41
|
+
export type { BranchOptions } from './branch.js';
|
|
42
|
+
export { deployWorld, refreshTwin, adaptersFor, credentialPath, credentialPayloadFrom, deployTwin, loadWorldChecks, materializeRoots, rootForControlRoot, sealTwinCredential, sealedCredentialInfo, setTwinRoot, userKekPath } from './root.js';
|
|
43
|
+
export type { DeployTwinOutcome, MaterializedRoot } from './root.js';
|
|
44
|
+
export { landReceipts, mountWorld, readServeRecord, refreshSchedule, servedName, serveWorld, TOKEN_HEADER, WorldDoors } from './served-world.js';
|
|
45
|
+
export type { DoorHost, MountedWorld, ServeRecord, WorldLayout } from './served-world.js';
|
|
46
|
+
export type { ServedWorld } from './served-world.js';
|
|
47
|
+
export { CONSOLE_BASE, consoleRedirect, serveConsoleApart, serveConsoleFor, type ConsoleMount } from './console-apart.js';
|
|
48
|
+
export { assertWorldStateRemovable } from './ancestry.js';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export { DEFAULT_WORLD_SELECTION, LEGACY_WORLD_SELECTION, WORLD_SCHEMA_VERSION, WORLD_USAGES, worldConfigDocument, worldSelectionIncludes } from "./schema.js";
|
|
2
|
+
export { loadWorldConfig, migrateWorldConfig, resolveConfigPath, writeWorldConfig } from "./configs.js";
|
|
3
|
+
export { upWorld, downWorld, pruneWorlds, listWorlds, statusWorld, doctorWorld, runWithWorldEnv, attachWorld, retireWorldConsumers, activateScript, shellWorld, worldShellEnv, ensureWorldProxy, runProxyDaemon, runWorld, shareWorld, shareWorldServices, unshareWorld, urlsWorld, urlWorld, } from "./runtime.js";
|
|
4
|
+
export { worldResourceReport } from "./resources.js";
|
|
5
|
+
// `volter-world app-url` — the recorded, queryable app endpoint of an instance (see app-url.ts).
|
|
6
|
+
export { appUrlFile, appUrlUnsetMessage, detectAppUrl, readAppUrl, setAppUrl } from "./app-url.js";
|
|
7
|
+
export { tailWorldActions } from "./tail.js";
|
|
8
|
+
// the changeset primitive + the diff verb (docs/concepts/the-model.md v0) and the operational-PR
|
|
9
|
+
// contract over it (v1: verify/approve/status). World-side glue only — markers, deltas, content
|
|
10
|
+
// hashing, replay, verifier evaluation and approval binding live in @volter/world-core's control plane.
|
|
11
|
+
export { pushWorldChangeset, rebaseWorldChangeset, approveWorldChangeset, createWorldChangeset, diffWorld, EPHEMERAL_VERIFY_TARGET, findWorldChangeset, listWorldChangesets, listWorldMarks, markWorld, MARK_NOTE_MAX, replayWorldChangeset, resolveBaseMarker, statusWorldChangeset, verifyWorldChangeset, worldChangesetsDir, worldLedgers, worldMarksDir, } from "./changeset.js";
|
|
12
|
+
export { checkLocalExecution, checkPrerequisites, formatPrerequisiteChecks, } from "./prerequisites.js";
|
|
13
|
+
export { inspectProject, formatProjectInspection, projectDependencies, projectEnvNames, SDK_TWINS, workspaceDirs } from "./project-inspect.js";
|
|
14
|
+
// Structurally valid fake credentials for world configs (fixture env) — see fixture-env.ts
|
|
15
|
+
// for the pattern (a fake a client SDK parses/signs with must be structurally real).
|
|
16
|
+
export { fakeEnvValue, fakeGoogleOAuthClientJson, fakeGoogleServiceAccountJson, isGoogleOAuthClientEnvName, isGoogleServiceAccountEnvName } from "./fixture-env.js";
|
|
17
|
+
export { coverWorld, detectRepoVendors, envNameVendor, formatCoverageReport, injectorVendorKeysFor, isCredentialShapedEnvName, worldTwinInventory, } from "./covers.js";
|
|
18
|
+
// `volter-world init` — the deterministic front door: detect the repo's vendors (covers), emit a
|
|
19
|
+
// world config + env file OUTSIDE the repo (fixture-env), and prove the emission with `covers`.
|
|
20
|
+
export { formatInitReport, initWorld, packCatalog, planWorldInit, renderEnvFile, writeWorldInit } from "./init.js";
|
|
21
|
+
export { STATE_GITIGNORE } from "./init.js";
|
|
22
|
+
export { clockFile } from "./runtime.js";
|
|
23
|
+
export { checkoutCatalog, findInstalledPackage, installedCatalog, resolveCatalog, resolveServicePackage, twinPackageName, TWIN_PACKAGE_PREFIX, packCli, packEntry } from "./catalog.js";
|
|
24
|
+
export { MINT_ENV } from "./schema.js";
|
|
25
|
+
export { deriveWorldManifest, findWorldRefFile, isRemoteWorldRef, resolveWorldRef, WORLD_REF_FILE, worldManifest, } from "./attach.js";
|
|
26
|
+
export { parseSni, readReflectRoutes, reflectRoutesPath, reflectManifestPath, readReflectManifest, writeReflectManifest, clearReflectManifest, composeOverrideForReflect, splitDockerComposeArgs, dockerComposeWithOverride, CA_TRUST_ENV, ATTACHED_CA_PATH, startReflectFront, startReflectResolver, writeReflectRoutes, } from "./reflect.js";
|
|
27
|
+
export { startColocatedHost } from "./host.js";
|
|
28
|
+
export { advertiseWorldManifest, fetchRemoteManifest, MANIFEST_PATH, remoteAttachEnv, startManifestServer, } from "./serve.js";
|
|
29
|
+
export { resetWorld, seedEntryFor, seedWorld } from "./placeholder.js";
|
|
30
|
+
export { fetchFromOrigin, worldOrigin } from "./origin.js";
|
|
31
|
+
export { branchWorld, checkoutWorld } from "./branch.js";
|
|
32
|
+
export { deployWorld, refreshTwin, adaptersFor, credentialPath, credentialPayloadFrom, deployTwin, loadWorldChecks, materializeRoots, rootForControlRoot, sealTwinCredential, sealedCredentialInfo, setTwinRoot, userKekPath } from "./root.js";
|
|
33
|
+
export { landReceipts, mountWorld, readServeRecord, refreshSchedule, servedName, serveWorld, TOKEN_HEADER, WorldDoors } from "./served-world.js";
|
|
34
|
+
export { CONSOLE_BASE, consoleRedirect, serveConsoleApart, serveConsoleFor } from "./console-apart.js";
|
|
35
|
+
export { assertWorldStateRemovable } from "./ancestry.js";
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Private implementation for infrastructure emitted by `volter-world init`. World configs invoke
|
|
3
|
+
// this declared service; application agents never operate or diagnose its backing mechanism.
|
|
4
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { spawnSync } from 'node:child_process';
|
|
7
|
+
import { infraConnections, parseInfraDefinition } from "./pglite-backing.js";
|
|
8
|
+
const phase = process.argv[2];
|
|
9
|
+
if (phase !== 'up' && phase !== 'status' && phase !== 'down') {
|
|
10
|
+
process.stderr.write('managed infrastructure: expected up, status, or down\n');
|
|
11
|
+
process.exit(2);
|
|
12
|
+
}
|
|
13
|
+
const worldConfig = process.env.VOLTER_WORLD_CONFIG;
|
|
14
|
+
const worldData = process.env.VOLTER_WORLD_DATA;
|
|
15
|
+
if (!worldConfig || !worldData) {
|
|
16
|
+
process.stderr.write('managed infrastructure: missing World lifecycle context\n');
|
|
17
|
+
process.exit(2);
|
|
18
|
+
}
|
|
19
|
+
const definition = join(dirname(worldConfig), 'world.infrastructure.yml');
|
|
20
|
+
if (!existsSync(definition)) {
|
|
21
|
+
process.stderr.write('managed infrastructure: declared definition is missing\n');
|
|
22
|
+
process.exit(2);
|
|
23
|
+
}
|
|
24
|
+
const base = ['compose', '-f', definition];
|
|
25
|
+
const run = (args) => spawnSync('docker', [...base, ...args], {
|
|
26
|
+
encoding: 'utf8',
|
|
27
|
+
env: { ...process.env, VOLTER_WORLD_DATA: worldData },
|
|
28
|
+
timeout: 120_000,
|
|
29
|
+
});
|
|
30
|
+
const classify = (raw) => /no space left on device|enospc/iu.test(raw)
|
|
31
|
+
? 'insufficient writable storage'
|
|
32
|
+
: /out of memory|cannot allocate memory|killed/iu.test(raw)
|
|
33
|
+
? 'insufficient memory'
|
|
34
|
+
: /cannot connect|not running|daemon/iu.test(raw)
|
|
35
|
+
? 'local execution capacity is unavailable'
|
|
36
|
+
: 'managed infrastructure operation failed';
|
|
37
|
+
const fail = (result) => {
|
|
38
|
+
const raw = `${result.stdout ?? ''}\n${result.stderr ?? ''}`.trim();
|
|
39
|
+
process.stderr.write(`managed infrastructure ${phase} failed: ${classify(raw)}\n`);
|
|
40
|
+
process.exit(result.status && result.status > 0 ? result.status : 1);
|
|
41
|
+
};
|
|
42
|
+
// ---- backing selection ------------------------------------------------------
|
|
43
|
+
// The declared service contract (up/status/down) is the boundary; WHICH
|
|
44
|
+
// runtime answers it is private and chosen here, per machine, at each phase:
|
|
45
|
+
// 1. VOLTER_WORLD_INFRA_BACKING=docker|pglite — explicit, for tests/operators;
|
|
46
|
+
// 2. a working container runtime — the compose path, byte-identical to before;
|
|
47
|
+
// 3. no container runtime + a postgres-only definition — the PGlite backing
|
|
48
|
+
// (pglite-host.ts), announced loudly;
|
|
49
|
+
// 4. otherwise the honest refusal naming what this machine cannot serve.
|
|
50
|
+
function selectBacking() {
|
|
51
|
+
const forced = process.env.VOLTER_WORLD_INFRA_BACKING;
|
|
52
|
+
if (forced === 'docker' || forced === 'pglite')
|
|
53
|
+
return forced;
|
|
54
|
+
if (forced !== undefined) {
|
|
55
|
+
process.stderr.write(`managed infrastructure: VOLTER_WORLD_INFRA_BACKING must be docker or pglite (got ${JSON.stringify(forced)})\n`);
|
|
56
|
+
process.exit(2);
|
|
57
|
+
}
|
|
58
|
+
const probe = spawnSync('docker', ['info', '--format', '{{.ServerVersion}}'], { encoding: 'utf8', timeout: 10_000 });
|
|
59
|
+
if (probe.status === 0)
|
|
60
|
+
return 'docker';
|
|
61
|
+
// Absence of a container runtime (no binary, no daemon) is a capability
|
|
62
|
+
// difference: swap backings. A PRESENT runtime failing on resources stays
|
|
63
|
+
// on the docker path so the real capacity problem is classified and
|
|
64
|
+
// surfaced — a full disk starves every backing equally.
|
|
65
|
+
if (probe.error !== undefined)
|
|
66
|
+
return 'pglite';
|
|
67
|
+
const reason = classify(`${probe.stdout ?? ''}\n${probe.stderr ?? ''}`);
|
|
68
|
+
return reason === 'local execution capacity is unavailable' ? 'pglite' : 'docker';
|
|
69
|
+
}
|
|
70
|
+
async function runPglite() {
|
|
71
|
+
const { unsupportedKinds, pgliteUp, pgliteStatus, pgliteDown } = await import("./pglite-backing.js");
|
|
72
|
+
const services = parseInfraDefinition(readFileSync(definition, 'utf8'));
|
|
73
|
+
if (services.length === 0) {
|
|
74
|
+
process.stderr.write('managed infrastructure: the declared definition names no services\n');
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
const unsupported = unsupportedKinds(services);
|
|
78
|
+
if (unsupported.length > 0) {
|
|
79
|
+
process.stderr.write(`managed infrastructure ${phase} failed: local execution capacity is unavailable (no container runtime, and the containerless backing cannot serve: ${unsupported.join(', ')})\n`);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
if (phase === 'up') {
|
|
83
|
+
process.stdout.write('managed infrastructure backing: pglite (no container runtime)\n');
|
|
84
|
+
try {
|
|
85
|
+
await pgliteUp(services, worldData);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
process.stderr.write(`managed infrastructure up failed: ${String(error.message ?? error)}\n`);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
process.stdout.write('managed infrastructure ready\n');
|
|
92
|
+
process.exit(0);
|
|
93
|
+
}
|
|
94
|
+
if (phase === 'status') {
|
|
95
|
+
const status = await pgliteStatus(services, worldData);
|
|
96
|
+
if (!status.ok) {
|
|
97
|
+
process.stderr.write(`managed infrastructure status failed: ${status.ready}/${services.length} declared services are ready\n`);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
process.stdout.write(`${JSON.stringify({ ok: true, services: services.length, connections: infraConnections(services, process.env) })}\n`);
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
103
|
+
await pgliteDown(services, worldData);
|
|
104
|
+
process.stdout.write('managed infrastructure stopped\n');
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
if (selectBacking() === 'pglite') {
|
|
108
|
+
await runPglite();
|
|
109
|
+
}
|
|
110
|
+
if (phase === 'up') {
|
|
111
|
+
const result = run(['up', '-d', '--wait']);
|
|
112
|
+
if (result.status !== 0)
|
|
113
|
+
fail(result);
|
|
114
|
+
process.stdout.write('managed infrastructure ready\n');
|
|
115
|
+
}
|
|
116
|
+
else if (phase === 'status') {
|
|
117
|
+
const expected = run(['config', '--services']);
|
|
118
|
+
if (expected.status !== 0)
|
|
119
|
+
fail(expected);
|
|
120
|
+
const running = run(['ps', '--status', 'running', '--services']);
|
|
121
|
+
if (running.status !== 0)
|
|
122
|
+
fail(running);
|
|
123
|
+
const expectedNames = expected.stdout.split(/\s+/u).filter(Boolean).sort();
|
|
124
|
+
const runningNames = running.stdout.split(/\s+/u).filter(Boolean).sort();
|
|
125
|
+
if (expectedNames.length === 0 || expectedNames.join('\0') !== runningNames.join('\0')) {
|
|
126
|
+
process.stderr.write(`managed infrastructure status failed: ${runningNames.length}/${expectedNames.length} declared services are ready\n`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
process.stdout.write(`${JSON.stringify({ ok: true, services: expectedNames.length, connections: infraConnections(parseInfraDefinition(readFileSync(definition, 'utf8')), process.env) })}\n`);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
const result = run(['down', '--remove-orphans']);
|
|
133
|
+
if (result.status !== 0)
|
|
134
|
+
fail(result);
|
|
135
|
+
process.stdout.write('managed infrastructure stopped\n');
|
|
136
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { type CoverageReport } from './covers.js';
|
|
2
|
+
import { type WorldConfig, type WorldServiceConfig } from './schema.js';
|
|
3
|
+
/** How a twin service in the emitted world is reached by the app's traffic. */
|
|
4
|
+
export type InitWiring =
|
|
5
|
+
/** the injector redirects the vendor's real hosts; `injectEnv` is a var it genuinely reads */
|
|
6
|
+
'injector'
|
|
7
|
+
/** no injector entry, but the SDK reads a documented endpoint env var (INNGEST_BASE_URL, …) */
|
|
8
|
+
| 'app-read'
|
|
9
|
+
/** no injector entry and no endpoint env: the SDK is pointed at the twin by explicit client config */
|
|
10
|
+
| 'explicit-config'
|
|
11
|
+
/** detected vendor with no `packages/twin/<vendor>` pack in the catalog — nothing to emit */
|
|
12
|
+
| 'no-pack';
|
|
13
|
+
export type InitVendorPlan = {
|
|
14
|
+
vendor: string;
|
|
15
|
+
/** the catalog pack backing it, or null for 'no-pack' */
|
|
16
|
+
pack: string | null;
|
|
17
|
+
/** how the repo betrayed it, verbatim from the coverage proof's detection */
|
|
18
|
+
detectedVia: string[];
|
|
19
|
+
wiring: InitWiring;
|
|
20
|
+
/** the emitted service, or null when nothing could be emitted */
|
|
21
|
+
service: WorldServiceConfig | null;
|
|
22
|
+
/** why this wiring — printed in the report and embedded in the service's `//` note */
|
|
23
|
+
note: string;
|
|
24
|
+
};
|
|
25
|
+
/** What `init` did with one env NAME found in the repo's example env files. */
|
|
26
|
+
export type EnvDisposition =
|
|
27
|
+
/** credential-shaped → replaced by a structurally valid fake (never the committed value) */
|
|
28
|
+
'faked'
|
|
29
|
+
/** non-credential app config → the example value copied verbatim */
|
|
30
|
+
| 'kept'
|
|
31
|
+
/** infra connection string → points at a World-managed infrastructure service */
|
|
32
|
+
| 'compose'
|
|
33
|
+
/** infra connection string → a documented placeholder the operator fills in */
|
|
34
|
+
| 'placeholder'
|
|
35
|
+
/** neither credential-shaped nor valued: the operator has to decide */
|
|
36
|
+
| 'unknown';
|
|
37
|
+
export type InitEnvRow = {
|
|
38
|
+
name: string;
|
|
39
|
+
disposition: EnvDisposition;
|
|
40
|
+
/** repo-relative env file the name came from */
|
|
41
|
+
source: string;
|
|
42
|
+
reason: string;
|
|
43
|
+
/** an example key with no value: declared, and left unset in the World so the app's own env files provide it */
|
|
44
|
+
unset?: true;
|
|
45
|
+
};
|
|
46
|
+
/** An example env name that is EMPTY yet read directly by production source. This does not pretend
|
|
47
|
+
* to know the app's validator; it is ranked separately because it may stop the app before listen. */
|
|
48
|
+
export type InitBootRisk = {
|
|
49
|
+
name: string;
|
|
50
|
+
/** example env file carrying the empty value */
|
|
51
|
+
source: string;
|
|
52
|
+
/** production source reads (`path:line`) */
|
|
53
|
+
readAt: string[];
|
|
54
|
+
};
|
|
55
|
+
/** Infra the repo signals through its env (Postgres, MySQL, Redis, …) but that no twin models:
|
|
56
|
+
* emitted as a DOCUMENTED `external`-service stub the operator fills in and moves into `services`. */
|
|
57
|
+
export type InitInfraStub = {
|
|
58
|
+
kind: string;
|
|
59
|
+
/** the env names that betrayed it */
|
|
60
|
+
signals: string[];
|
|
61
|
+
/** the stub object written under the config's `//infra` key */
|
|
62
|
+
stub: Record<string, unknown>;
|
|
63
|
+
};
|
|
64
|
+
/** One service in the private managed-infrastructure definition — detected infra `init` can
|
|
65
|
+
* declare under the World lifecycle instead of leaving a placeholder for an operator. */
|
|
66
|
+
export type InitComposeService = {
|
|
67
|
+
kind: string;
|
|
68
|
+
image: string;
|
|
69
|
+
/** deterministic host port, derived from the world name (see composePort) */
|
|
70
|
+
hostPort: number;
|
|
71
|
+
containerPort: number;
|
|
72
|
+
memoryMiB: number;
|
|
73
|
+
/** compose volume key, or null (the on-disk docker volume is `<project>_<key>` — the compose
|
|
74
|
+
* project name carries the world name, so volumes are named per world) */
|
|
75
|
+
volume: string | null;
|
|
76
|
+
/** the connection URL emitted for every env name that signalled this kind */
|
|
77
|
+
url: string;
|
|
78
|
+
/** the env names that betrayed it */
|
|
79
|
+
signals: string[];
|
|
80
|
+
};
|
|
81
|
+
export type InitPlan = {
|
|
82
|
+
name: string;
|
|
83
|
+
repo: string;
|
|
84
|
+
out: string;
|
|
85
|
+
/** the world lives in the app repo (`<repo>/.volter`), not in a pilot directory elsewhere */
|
|
86
|
+
inRepo: boolean;
|
|
87
|
+
/** where the twins came from: this checkout, or the packages installed above the root */
|
|
88
|
+
catalog: 'checkout' | 'installed';
|
|
89
|
+
configPath: string;
|
|
90
|
+
envPath: string;
|
|
91
|
+
config: WorldConfig;
|
|
92
|
+
/** the env block, identical to the config's `env` — `app.env` is rendered from this same map */
|
|
93
|
+
env: Record<string, string>;
|
|
94
|
+
vendors: InitVendorPlan[];
|
|
95
|
+
envRows: InitEnvRow[];
|
|
96
|
+
envSources: string[];
|
|
97
|
+
/** empty example values read by production source — prominent warning, not vendor-coverage fact */
|
|
98
|
+
bootRisks: InitBootRisk[];
|
|
99
|
+
infra: InitInfraStub[];
|
|
100
|
+
/** the services emitted into the private managed-infrastructure definition */
|
|
101
|
+
compose: InitComposeService[];
|
|
102
|
+
/** private managed-infrastructure definition, or null when no detected infra has a recipe */
|
|
103
|
+
composePath: string | null;
|
|
104
|
+
/** external-service-shaped signals with no vendor mapping AND no standing registry
|
|
105
|
+
* acknowledgment — the real worklist (registry-acknowledged signals are partitioned into
|
|
106
|
+
* `acknowledgedExternal` below, never silently dropped). */
|
|
107
|
+
unknown: string[];
|
|
108
|
+
/** signals the packless-vendor registry carries a STANDING acknowledgment for (census-
|
|
109
|
+
* adjudicated acceptable) — separated from `unknown` so the worklist stays real, but
|
|
110
|
+
* never silently dropped: each carries its recorded reason. */
|
|
111
|
+
acknowledgedExternal: Array<{
|
|
112
|
+
name: string;
|
|
113
|
+
reason: string;
|
|
114
|
+
}>;
|
|
115
|
+
/** pack `defaults/` files copied into the world dir (TWIN-PROGRAMMING-MODEL: default
|
|
116
|
+
* reasonable — visible starter seeds/handlers, ownership transfers on copy). */
|
|
117
|
+
defaultsCopies: Array<{
|
|
118
|
+
vendor: string;
|
|
119
|
+
kind: 'handlers' | 'seed';
|
|
120
|
+
from: string;
|
|
121
|
+
to: string;
|
|
122
|
+
}>;
|
|
123
|
+
/** emitted when any pack ships a default seed: the one explicit entry point + story skeleton */
|
|
124
|
+
seedEntry: {
|
|
125
|
+
entryPath: string;
|
|
126
|
+
storyPath: string;
|
|
127
|
+
} | null;
|
|
128
|
+
/** Explicit wiring for new default seeds when the existing entry point is operator-owned. */
|
|
129
|
+
seedAdditions: Array<{
|
|
130
|
+
vendor: string;
|
|
131
|
+
import: string;
|
|
132
|
+
call: string;
|
|
133
|
+
}>;
|
|
134
|
+
/**
|
|
135
|
+
* THE ONE DOCUMENTED EXCEPTION TO BYTE-IDENTICAL OUTPUT. Every other byte `init` emits is a pure
|
|
136
|
+
* function of (repo, catalog, world name). These names hold FRESHLY MINTED cryptographic material
|
|
137
|
+
* — today, the real throwaway RSA key inside a Google service-account JSON, which google-auth-
|
|
138
|
+
* library signs its assertion with locally before the twin ever sees a request (see fixture-env.ts).
|
|
139
|
+
* It is non-deterministic BY CONSTRUCTION: a throwaway key that never changes is a committed key,
|
|
140
|
+
* and fixture-env's whole rule is that keys are minted per process and never committed. So init
|
|
141
|
+
* names them here (and in the report, and in a comment in the env file) instead of quietly
|
|
142
|
+
* breaking the determinism claim — an operator diffing two pilots knows exactly which lines may
|
|
143
|
+
* legitimately differ, and every other line differing is a real change.
|
|
144
|
+
*
|
|
145
|
+
* Scope of the exception, exactly: fixture-env mints ONCE PER PROCESS and reuses it, so two inits
|
|
146
|
+
* in the SAME process (a room initing several repos in one run) are byte-identical even here.
|
|
147
|
+
* Only separate invocations differ. Both halves are pinned in init.test.ts.
|
|
148
|
+
*/
|
|
149
|
+
mintedEnv: string[];
|
|
150
|
+
};
|
|
151
|
+
export type InitResult = {
|
|
152
|
+
plan: InitPlan;
|
|
153
|
+
coverage: CoverageReport;
|
|
154
|
+
/** the vendor-coverage proof's verdict — `init`'s exit code IS this; bootRisks stay separate */
|
|
155
|
+
ok: boolean;
|
|
156
|
+
/** the exact commands to run next; `init` never runs them itself */
|
|
157
|
+
next: string[];
|
|
158
|
+
};
|
|
159
|
+
export type InitOptions = {
|
|
160
|
+
/** the WORLD root: where the emitted config boots from, and where the catalog is resolved —
|
|
161
|
+
* this checkout's `packages/twin` when init runs here, else the `@volter/twin-<vendor>`
|
|
162
|
+
* packages installed above it (docs/concepts/worlds.md#the-config-and-the-running-world). Defaults to the
|
|
163
|
+
* application repo. */
|
|
164
|
+
root?: string;
|
|
165
|
+
out?: string;
|
|
166
|
+
force?: boolean;
|
|
167
|
+
allowUnknown?: boolean;
|
|
168
|
+
acknowledge?: Record<string, string>;
|
|
169
|
+
/** The twins, named outright instead of detected from the repo (a bare world: `init --bare
|
|
170
|
+
* <org>/<world> --twins a,b`). */
|
|
171
|
+
vendors?: string[];
|
|
172
|
+
/** A world with no app: served as `/<org>/<world>/`. */
|
|
173
|
+
bare?: string;
|
|
174
|
+
};
|
|
175
|
+
/** The twins available at `root`, sorted — a deterministic input (catalog.ts: this checkout's
|
|
176
|
+
* `packages/twin/<vendor>/` dirs, or the `@volter/twin-<vendor>` packages installed above root). */
|
|
177
|
+
export declare function packCatalog(root: string): string[];
|
|
178
|
+
/**
|
|
179
|
+
* The REAL endpoint env names for packs the injector cannot intercept — the other half of
|
|
180
|
+
* `scripts/vendor-hosts.test.ts`'s descriptor hostsNone ruling. That allowlist states WHY each pack
|
|
181
|
+
* has no VENDOR_HOSTS entry; this table states WHAT to wire instead, using the env var the vendor's
|
|
182
|
+
* own SDK documents. Every entry is grounded in the SDK, not invented:
|
|
183
|
+
*
|
|
184
|
+
* inngest `INNGEST_BASE_URL` (+ `INNGEST_EVENT_API_BASE_URL` for the event API)
|
|
185
|
+
* — inngest@4's own apiBaseUrl/eventBaseUrl getters.
|
|
186
|
+
* ai-gateway `AI_GATEWAY_BASE_URL` — `@ai-sdk/gateway`'s baseURL env.
|
|
187
|
+
* supabase `SUPABASE_MGMT_TWIN_URL` — the MANAGEMENT (control-plane) twin only,
|
|
188
|
+
* which is what this pack is; the DATA plane is the real local Supabase
|
|
189
|
+
* stack and is emitted as an infra stub, not faked.
|
|
190
|
+
* livekit `LIVEKIT_URL` as a ws:// template — the media plane is a WebSocket
|
|
191
|
+
* URL the SDK takes as its first constructor argument.
|
|
192
|
+
*
|
|
193
|
+
* A pack that is base-URL-configurable but has NO conventional env var (algolia, pinecone,
|
|
194
|
+
* replicate, fal, twilio, sendblue, figma, notion) is deliberately ABSENT: it gets a service
|
|
195
|
+
* with no endpoint env at all, and the proof reports it UNINTERCEPTABLE. Inventing a
|
|
196
|
+
* `<VENDOR>_BASE_URL` for it would make `covers` call the world covered (any app-read env counts)
|
|
197
|
+
* while the app, which reads no such var, still talks to the real vendor — the exact class of lie
|
|
198
|
+
* the proof exists to catch.
|
|
199
|
+
*/
|
|
200
|
+
export declare const APP_READ_ENDPOINT_ENV: Record<string, {
|
|
201
|
+
injectEnv?: string;
|
|
202
|
+
injectEnvTemplates?: Record<string, string>;
|
|
203
|
+
note: string;
|
|
204
|
+
}>;
|
|
205
|
+
/** Render the private managed-infrastructure definition — deterministic, with no absolute paths.
|
|
206
|
+
* Only meaningful when `plan.compose` is non-empty (writeWorldInit skips it otherwise). */
|
|
207
|
+
export declare function renderComposeFile(plan: InitPlan): string;
|
|
208
|
+
export declare function planWorldInit(name: string, repoPath: string, options?: InitOptions): InitPlan;
|
|
209
|
+
/** The `app.env` rendering of the SAME map the config's `env` block holds — a dotenv for anything
|
|
210
|
+
* attached to the World (a shell, app process, or CI step), annotated with the
|
|
211
|
+
* disposition of every name so the file explains itself. Both artifacts are rendered from one map
|
|
212
|
+
* in one call, so they cannot drift. */
|
|
213
|
+
export declare function renderEnvFile(plan: InitPlan): string;
|
|
214
|
+
/** Write the plan's two artifacts. Byte-identical for the same repo + catalog: sorted keys, no
|
|
215
|
+
* timestamps, no absolute paths inside the files. */
|
|
216
|
+
/** What `.volter/.gitignore` says: the story is committed, the running state never is. */
|
|
217
|
+
export declare const STATE_GITIGNORE = "# Volter: the world's running state and live env \u2014 never committed. world.json, handlers/ and seeds/ are the story.\nworlds/\ncurrent\n*.env\ncredentials/\ntoken\n";
|
|
218
|
+
export declare function writeWorldInit(plan: InitPlan, options?: {
|
|
219
|
+
force?: boolean;
|
|
220
|
+
}): void;
|
|
221
|
+
/**
|
|
222
|
+
* Plan, emit, and PROVE. The coverage proof runs against the just-written config (by path, so it
|
|
223
|
+
* reads exactly the bytes on disk rather than the in-memory plan) — `ok` is the proof's verdict and
|
|
224
|
+
* the caller's exit code. Deliberately does NOT boot the world.
|
|
225
|
+
*/
|
|
226
|
+
export declare function initWorld(name: string, repoPath: string, options?: InitOptions): InitResult;
|
|
227
|
+
export declare function formatInitReport(result: InitResult): string;
|