@volter/world-runtime 3.0.163 → 3.0.165
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/ancestry.js +2 -2
- package/dist/src/app-url.d.ts +5 -1
- package/dist/src/app-url.js +14 -1
- package/dist/src/branch.js +28 -8
- package/dist/src/browser-files.d.ts +5 -0
- package/dist/src/browser-files.js +14 -0
- package/dist/src/browsers.d.ts +2 -3
- package/dist/src/browsers.js +4 -4
- package/dist/src/catalog.d.ts +2 -1
- package/dist/src/catalog.js +9 -3
- package/dist/src/changeset.js +1 -1
- package/dist/src/cli-commands.js +71 -18
- package/dist/src/cli-load-clock.d.ts +1 -0
- package/dist/src/cli-load-clock.js +2 -0
- package/dist/src/cli.js +5 -1
- package/dist/src/clickhouse-backing.d.ts +2 -0
- package/dist/src/clickhouse-backing.js +145 -0
- package/dist/src/command-lifetime.d.mts +1 -1
- package/dist/src/command-lifetime.mjs +5 -2
- package/dist/src/configs.js +1 -1
- package/dist/src/consumers.js +1 -1
- package/dist/src/covers.d.ts +4 -2
- package/dist/src/covers.js +8 -4
- package/dist/src/go-mysql-binding.d.ts +19 -0
- package/dist/src/go-mysql-binding.js +51 -0
- package/dist/src/guest-processes.d.mts +1 -1
- package/dist/src/guest-processes.mjs +22 -14
- package/dist/src/host-cli.js +8 -1
- package/dist/src/host-ready.d.ts +16 -2
- package/dist/src/host-ready.js +66 -39
- package/dist/src/host-worker.js +7 -1
- package/dist/src/host.d.ts +26 -0
- package/dist/src/host.js +93 -3
- package/dist/src/infra-definition.d.ts +35 -0
- package/dist/src/infra-definition.js +146 -0
- package/dist/src/infra.d.ts +3 -0
- package/dist/src/infra.js +375 -105
- package/dist/src/init.d.ts +46 -0
- package/dist/src/init.js +446 -19
- package/dist/src/lifecycle-record.d.ts +5 -1
- package/dist/src/lifecycle-record.js +27 -4
- package/dist/src/local-branches.js +1 -1
- package/dist/src/mariadb-bootstrap.d.ts +32 -0
- package/dist/src/mariadb-bootstrap.js +90 -0
- package/dist/src/mariadb-supplier.d.ts +23 -0
- package/dist/src/mariadb-supplier.js +215 -0
- package/dist/src/mongodb-backing.d.ts +4 -0
- package/dist/src/mongodb-backing.js +71 -1
- package/dist/src/native-mariadb-backing.d.ts +13 -0
- package/dist/src/native-mariadb-backing.js +512 -0
- package/dist/src/native-postgres-backing.d.ts +4 -10
- package/dist/src/native-postgres-backing.js +428 -43
- package/dist/src/native-server-inputs.d.ts +16 -0
- package/dist/src/native-server-inputs.js +204 -0
- package/dist/src/origin.js +3 -3
- package/dist/src/original-inputs.d.ts +14 -0
- package/dist/src/original-inputs.js +84 -0
- package/dist/src/pack-facts.d.ts +9 -1
- package/dist/src/pglite-backing.d.ts +41 -17
- package/dist/src/pglite-backing.js +213 -79
- package/dist/src/pglite-host.mjs +482 -10
- package/dist/src/process-groups.d.mts +6 -1
- package/dist/src/process-groups.d.ts +2 -1
- package/dist/src/process-groups.js +1 -1
- package/dist/src/process-groups.mjs +82 -15
- package/dist/src/process-signal.d.mts +2 -2
- package/dist/src/process-signal.mjs +29 -9
- package/dist/src/project-inspect.d.ts +12 -0
- package/dist/src/project-inspect.js +41 -4
- package/dist/src/proxy-env.d.ts +34 -0
- package/dist/src/proxy-env.js +114 -0
- package/dist/src/redirect-proxy.d.ts +1 -31
- package/dist/src/redirect-proxy.js +3 -112
- package/dist/src/redis-backing.d.ts +6 -4
- package/dist/src/redis-backing.js +20 -168
- package/dist/src/runtime.d.ts +1 -0
- package/dist/src/runtime.js +503 -218
- package/dist/src/schema.d.ts +1 -0
- package/dist/src/schema.js +5 -3
- package/dist/src/served-world.js +3 -3
- package/dist/src/twin-backing.d.ts +47 -0
- package/dist/src/twin-backing.js +343 -0
- package/dist/src/up-cli.js +56 -3
- package/package.json +3 -3
- package/src/ancestry.ts +2 -2
- package/src/app-url.ts +9 -2
- package/src/branch.ts +26 -8
- package/src/browser-files.ts +15 -0
- package/src/browsers.ts +4 -4
- package/src/catalog.ts +9 -4
- package/src/changeset.ts +1 -1
- package/src/cli-commands.ts +85 -18
- package/src/cli-load-clock.ts +2 -0
- package/src/cli.ts +5 -1
- package/src/clickhouse-backing.ts +70 -0
- package/src/command-lifetime.d.mts +1 -1
- package/src/command-lifetime.mjs +5 -2
- package/src/configs.ts +1 -1
- package/src/consumers.ts +1 -1
- package/src/covers.ts +9 -4
- package/src/go-mysql-binding.ts +49 -0
- package/src/guest-processes.d.mts +1 -1
- package/src/guest-processes.mjs +22 -14
- package/src/host-cli.ts +7 -1
- package/src/host-ready.ts +62 -31
- package/src/host-worker.ts +6 -2
- package/src/host.ts +88 -6
- package/src/infra-definition.ts +135 -0
- package/src/infra.ts +250 -45
- package/src/init.ts +417 -18
- package/src/lifecycle-record.ts +18 -4
- package/src/local-branches.ts +1 -1
- package/src/mariadb-bootstrap.ts +107 -0
- package/src/mariadb-supplier.ts +199 -0
- package/src/mongodb-backing.ts +59 -1
- package/src/native-mariadb-backing.ts +418 -0
- package/src/native-postgres-backing.ts +353 -41
- package/src/native-server-inputs.ts +169 -0
- package/src/origin.ts +3 -3
- package/src/original-inputs.ts +72 -0
- package/src/pack-facts.ts +1 -1
- package/src/pglite-backing.ts +192 -80
- package/src/pglite-host.mjs +482 -10
- package/src/process-groups.d.mts +6 -1
- package/src/process-groups.mjs +82 -15
- package/src/process-groups.ts +2 -1
- package/src/process-signal.d.mts +2 -2
- package/src/process-signal.mjs +29 -9
- package/src/project-inspect.ts +37 -4
- package/src/proxy-env.ts +128 -0
- package/src/redirect-proxy.ts +3 -125
- package/src/redis-backing.ts +19 -136
- package/src/runtime.ts +342 -107
- package/src/schema.ts +5 -4
- package/src/served-world.ts +3 -3
- package/src/twin-backing.ts +300 -0
- package/src/up-cli.ts +52 -3
package/dist/src/ancestry.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// carry parent-side pins, including clones across checkouts, without a global World registry.
|
|
3
3
|
import { existsSync, readdirSync } from 'node:fs';
|
|
4
4
|
import { join, relative, resolve, sep } from 'node:path';
|
|
5
|
-
import { assertStateRemovable, readBranchMeta, stateDirName, withAncestryLock, withStateRemoval, getActiveWorldStore, worldPaths, worldStateRoot } from '@volter/world-core/runtime';
|
|
5
|
+
import { assertStateRemovable, readBranchMeta, stateDirName, withAncestryLock, withStateRemoval, getActiveWorldStore, worldPaths, worldStateRoot } from '@volter/world-core/runtime-state';
|
|
6
6
|
function checkWorldAncestry(root, path) {
|
|
7
7
|
const base = join(root, stateDirName(), 'worlds');
|
|
8
8
|
if (!existsSync(base))
|
|
@@ -35,7 +35,7 @@ function checkWorldAncestry(root, path) {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
export function assertWorldStateRemovable(root, path) {
|
|
38
|
-
withAncestryLock(() => { checkWorldAncestry(root, path); assertStateRemovable(path); });
|
|
38
|
+
withAncestryLock(() => { checkWorldAncestry(root, path); assertStateRemovable(path); }, { operation: 'removal preflight' });
|
|
39
39
|
}
|
|
40
40
|
export function removeWorldState(root, path, remove) {
|
|
41
41
|
return withStateRemoval(path, remove, () => checkWorldAncestry(root, path));
|
package/dist/src/app-url.d.ts
CHANGED
|
@@ -22,7 +22,11 @@ export declare function setAppUrl(name: string, url: string, options?: {
|
|
|
22
22
|
root?: string;
|
|
23
23
|
via?: Exclude<AppUrlSource, 'service'>;
|
|
24
24
|
detail?: string;
|
|
25
|
-
app?: string;
|
|
25
|
+
app?: string; /** An instrument: filled with how long the World's status and the record's write each took. */
|
|
26
|
+
timings?: {
|
|
27
|
+
statusMs?: number;
|
|
28
|
+
writeMs?: number;
|
|
29
|
+
};
|
|
26
30
|
}): AppUrlRecord;
|
|
27
31
|
/** Record `hosts` as the app's own production hostnames, beside its recorded URL (or its `app` service's). */
|
|
28
32
|
export declare function addAppHosts(name: string, hosts: string[], options?: {
|
package/dist/src/app-url.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
// instance it described.
|
|
22
22
|
import { errorMessage } from "./error-message.js";
|
|
23
23
|
import { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
24
|
-
import { withFileLock } from '@volter/world-core/runtime';
|
|
24
|
+
import { withFileLock } from '@volter/world-core/runtime-state';
|
|
25
25
|
import { join } from 'node:path';
|
|
26
26
|
import { spawnSync } from 'node:child_process';
|
|
27
27
|
import net from 'node:net';
|
|
@@ -89,8 +89,21 @@ function assertHttpUrl(url) {
|
|
|
89
89
|
export function setAppUrl(name, url, options = {}) {
|
|
90
90
|
const root = options.root ?? process.cwd();
|
|
91
91
|
const app = appName(options.app);
|
|
92
|
+
const began = Date.now();
|
|
92
93
|
const status = statusWorld(name, root); // throws "World instance not found" — the loud path
|
|
94
|
+
const statusRead = Date.now();
|
|
95
|
+
if (options.timings)
|
|
96
|
+
options.timings.statusMs = statusRead - began;
|
|
93
97
|
assertHttpUrl(url);
|
|
98
|
+
try {
|
|
99
|
+
return setAppUrlEntry(root, name, app, url, status, options);
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
if (options.timings)
|
|
103
|
+
options.timings.writeMs = Date.now() - statusRead;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function setAppUrlEntry(root, name, app, url, status, options) {
|
|
94
107
|
return writeEntry(root, name, app, (file) => {
|
|
95
108
|
// a new URL keeps the hosts recorded for the app (they name the app, not where it listens)
|
|
96
109
|
const hosts = entryOf(file, app)?.hosts;
|
package/dist/src/branch.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// base running at once share the database port its definition names; run one at a time (the SDK does). `checkout <name>`
|
|
8
8
|
// brings a stopped world back up from its own instance record, state intact.
|
|
9
9
|
import { runInfrastructure } from "./infra.js";
|
|
10
|
-
import { cpSync, existsSync, readdirSync, readFileSync, rmSync } from 'node:fs';
|
|
10
|
+
import { cpSync, existsSync, lstatSync, readdirSync, readFileSync, rmSync } from 'node:fs';
|
|
11
11
|
import { dirname, join, resolve } from 'node:path';
|
|
12
12
|
import { fileURLToPath } from 'node:url';
|
|
13
13
|
import { captureHistory, historyAtInstant, forkTwin, stateGeneration, withHistoryLocks, worldPaths, worldStateRoot } from '@volter/world-core/runtime';
|
|
@@ -48,7 +48,7 @@ export async function branchWorld(base, name, options = {}) {
|
|
|
48
48
|
const position = options.at?.positions?.[service] ?? options.at?.positions?.[state] ?? timed?.position;
|
|
49
49
|
return { state, view, position, generation: stateGeneration(worldPaths(state, fromRoot).dir) };
|
|
50
50
|
}) };
|
|
51
|
-
}));
|
|
51
|
+
}), { operation: 'capture' });
|
|
52
52
|
// the base's managed databases (checked before the branch boots: its database would share the base's port)
|
|
53
53
|
const databases = managedDatabases(from);
|
|
54
54
|
if (databases.length && (options.at?.instant || options.at?.positions || options.at?.views)) {
|
|
@@ -90,32 +90,51 @@ export async function branchWorld(base, name, options = {}) {
|
|
|
90
90
|
return { instance, forked };
|
|
91
91
|
}
|
|
92
92
|
/** The base's containerless managed databases: each PGlite `pglite-<kind>-data`, MongoDB's
|
|
93
|
-
* `mongod-mongodb-data` (pglite-backing.ts), the
|
|
93
|
+
* `mongod-mongodb-data` (pglite-backing.ts), the declared Redis/ClickHouse twin trees, and native PostgreSQL. A stopped World's
|
|
94
94
|
* hosts leave no pid file; a docker-backed World keeps its data under the container's volume, which a branch does not
|
|
95
95
|
* carry. */
|
|
96
96
|
function managedDatabases(from) {
|
|
97
97
|
const data = from.dirs.data;
|
|
98
98
|
if (!existsSync(data))
|
|
99
99
|
return [];
|
|
100
|
-
const known = (name) => /^pglite-[a-z0-9_-]+-data$/.test(name) || name === 'mongod-mongodb-data' ||
|
|
100
|
+
const known = (name) => /^pglite-[a-z0-9_-]+-data$/.test(name) || name === 'mongod-mongodb-data' || ['native-postgres-data', 'native-mariadb-data'].includes(name);
|
|
101
101
|
if (readdirSync(data).some(name => name.endsWith('-data') && !known(name) && !from.services[name])) {
|
|
102
102
|
throw new Error('volter-world branch: unrecognised storage; retain the original World');
|
|
103
103
|
}
|
|
104
|
-
return readdirSync(data).filter((n) => /^pglite-[a-z0-9_-]+-data$/.test(n) || n === 'mongod-mongodb-data' ||
|
|
104
|
+
return readdirSync(data).filter((n) => /^pglite-[a-z0-9_-]+-data$/.test(n) || n === 'mongod-mongodb-data' || ['redis-twin', 'clickhouse-twin', 'native-postgres-data', 'native-mariadb-data'].includes(n));
|
|
105
105
|
}
|
|
106
106
|
/** The pid files of the hosts serving one managed database directory. */
|
|
107
107
|
function hostPidFiles(data, db) {
|
|
108
|
+
if (db === 'native-mariadb-data')
|
|
109
|
+
return readdirSync(data).filter(name => /^native-mariadb\.(?:owner|starting)\.json(?:\.spawn\.json)?$/u.test(name)
|
|
110
|
+
|| /^native-mariadb-tool-.*\.json(?:\.spawn\.json)?$/u.test(name)).map(name => join(data, name));
|
|
108
111
|
if (db === 'native-postgres-data')
|
|
109
112
|
return [join(data, 'native-postgres.owner.json')];
|
|
110
113
|
if (db === 'redis-twin')
|
|
111
114
|
return readdirSync(data).filter((n) => /^redis-twin-\d+\.pid$/.test(n)).map((n) => join(data, n));
|
|
115
|
+
if (db === 'clickhouse-twin')
|
|
116
|
+
return [...new Set(readdirSync(data)
|
|
117
|
+
.filter(n => new RegExp(`^${db}-\\d+\\.pid(?:\\.spawn\\.json)?$`).test(n))
|
|
118
|
+
.map(n => join(data, n.replace(/\.spawn\.json$/, ''))))];
|
|
112
119
|
return [join(data, `${db.slice(0, -'-data'.length)}.pid`)];
|
|
113
120
|
}
|
|
114
121
|
/** A copy of a live database directory is not a consistent one, and the branch's database would answer on the base's
|
|
115
122
|
* port: the base must be stopped first (`volter world branch` stops it, as a branch replaces its base). */
|
|
116
123
|
function refuseLiveDatabases(from, dbs) {
|
|
117
124
|
for (const db of dbs) {
|
|
125
|
+
if (db === 'native-mariadb-data' && (existsSync(join(from.dirs.data, db, 'server.pid')) || existsSync(join(from.dirs.data, db, 'server.sock'))))
|
|
126
|
+
throw new Error(`volter-world branch: ${from.name}'s managed MariaDB retains PID/socket files; verified down is required`);
|
|
127
|
+
if (db === 'native-mariadb-data') {
|
|
128
|
+
const stamp = join(from.dirs.data, db, '.world-policy.json');
|
|
129
|
+
if (!existsSync(stamp) || !lstatSync(stamp).isFile() || existsSync(join(from.dirs.data, db, '.world-initializing.json')))
|
|
130
|
+
throw new Error(`volter-world branch: ${from.name}'s MariaDB has incomplete initialization; original data retained`);
|
|
131
|
+
}
|
|
118
132
|
for (const pidFile of hostPidFiles(from.dirs.data, db)) {
|
|
133
|
+
// Successful managed-twin down removes both receipts. A partial publication or an
|
|
134
|
+
// uncertain retirement must finish there before branch copies this store.
|
|
135
|
+
if (db === 'clickhouse-twin' || db === 'native-mariadb-data') {
|
|
136
|
+
throw new Error(`volter-world branch: ${from.name}'s managed ${db} retains ownership receipts; stop ${from.name} before copying its store`);
|
|
137
|
+
}
|
|
119
138
|
const recorded = existsSync(pidFile) ? readFileSync(pidFile, 'utf8').trim() : '';
|
|
120
139
|
const pid = db === 'native-postgres-data' && recorded ? JSON.parse(recorded).pid : Number(recorded);
|
|
121
140
|
let live = false;
|
|
@@ -137,6 +156,7 @@ function refuseLiveDatabases(from, dbs) {
|
|
|
137
156
|
function requireMatchingBackings(source, child) {
|
|
138
157
|
const kinds = {
|
|
139
158
|
postgres: ['native-postgres-data', 'pglite-postgres-data'],
|
|
159
|
+
mysql: ['native-mariadb-data'],
|
|
140
160
|
mongodb: ['mongod-mongodb-data'],
|
|
141
161
|
};
|
|
142
162
|
for (const [kind, formats] of Object.entries(kinds)) {
|
|
@@ -179,17 +199,17 @@ async function branchManagedDatabases(from, instance, dbs) {
|
|
|
179
199
|
if (!infrastructure)
|
|
180
200
|
throw new Error(`volter-world branch: ${instance.name}'s managed databases have no declared infrastructure service`);
|
|
181
201
|
const launch = { env: externalServiceEnv(infrastructure, instance.dirs, instance.env, config.stripEnv) };
|
|
182
|
-
if (dbs.
|
|
202
|
+
if (dbs.some(directory => ['native-postgres-data', 'native-mariadb-data', 'clickhouse-twin'].includes(directory))) {
|
|
183
203
|
const io = { out: (text) => process.stdout.write(text), err: (text) => process.stderr.write(text) };
|
|
184
204
|
if (await runInfrastructure('down', launch.env, io) !== 0)
|
|
185
|
-
throw new Error('managed
|
|
205
|
+
throw new Error('managed database branch could not stop its new backing');
|
|
186
206
|
for (const db of dbs) {
|
|
187
207
|
const to = join(instance.dirs.data, db);
|
|
188
208
|
rmSync(to, { recursive: true, force: true });
|
|
189
209
|
cpSync(join(from.dirs.data, db), to, { recursive: true });
|
|
190
210
|
}
|
|
191
211
|
if (await runInfrastructure('up', launch.env, io) !== 0)
|
|
192
|
-
throw new Error('managed
|
|
212
|
+
throw new Error('managed database branch could not resume its copied backing');
|
|
193
213
|
return;
|
|
194
214
|
}
|
|
195
215
|
const redisCli = dbs.includes('redis-twin') && redis.length ? redisTwinCli([dirname(fileURLToPath(import.meta.url)), dirname(instance.configPath)]) : undefined;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Instance bookkeeping, alongside the clock; retained at down, discarded at reset. */
|
|
2
|
+
export declare const browsersDir: (data: string) => string;
|
|
3
|
+
/** Empty Worlds need no browser validators or cookie/load machinery. A prior
|
|
4
|
+
* projection still loads the ordinary materializer to remove stale files. */
|
|
5
|
+
export declare function materializeWorldBrowserFiles(data: string, root: string, name: string, main?: string): Promise<void>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getActiveWorldStore, stateDirName } from '@volter/world-core/runtime-state';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
/** Instance bookkeeping, alongside the clock; retained at down, discarded at reset. */
|
|
4
|
+
export const browsersDir = (data) => join(dirname(data), 'browser-records');
|
|
5
|
+
/** Empty Worlds need no browser validators or cookie/load machinery. A prior
|
|
6
|
+
* projection still loads the ordinary materializer to remove stale files. */
|
|
7
|
+
export async function materializeWorldBrowserFiles(data, root, name, main = name) {
|
|
8
|
+
const store = getActiveWorldStore();
|
|
9
|
+
if (!store.list(browsersDir(data)).some(file => file.endsWith('.json'))
|
|
10
|
+
&& store.read(join(root, stateDirName(), 'browsers', '.source.json')) === null)
|
|
11
|
+
return;
|
|
12
|
+
const { materializeBrowserFiles } = await import("./browsers.js");
|
|
13
|
+
materializeBrowserFiles(data, root, name, main);
|
|
14
|
+
}
|
package/dist/src/browsers.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { type BrowserState } from '@volter/world-core';
|
|
1
|
+
import { type BrowserState } from '@volter/world-core/browser-state';
|
|
2
2
|
export type WorldBrowser = {
|
|
3
3
|
name: string;
|
|
4
4
|
state: BrowserState;
|
|
5
5
|
version: string;
|
|
6
6
|
};
|
|
7
|
-
|
|
8
|
-
export declare const browsersDir: (data: string) => string;
|
|
7
|
+
export { browsersDir } from './browser-files.js';
|
|
9
8
|
export declare function worldBrowser(data: string, name: string): WorldBrowser | null;
|
|
10
9
|
export declare function worldBrowsers(data: string): WorldBrowser[];
|
|
11
10
|
export declare function putWorldBrowser(data: string, name: string, state: unknown): WorldBrowser;
|
package/dist/src/browsers.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { assertBrowserName, validateBrowserState } from '@volter/world-core';
|
|
2
|
-
import { getActiveWorldStore, stateDirName } from '@volter/world-core/runtime';
|
|
1
|
+
import { assertBrowserName, validateBrowserState } from '@volter/world-core/browser-state';
|
|
2
|
+
import { getActiveWorldStore, stateDirName } from '@volter/world-core/runtime-state';
|
|
3
3
|
import { createHash, randomUUID } from 'node:crypto';
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
5
|
-
|
|
6
|
-
export
|
|
5
|
+
import { browsersDir } from "./browser-files.js";
|
|
6
|
+
export { browsersDir } from "./browser-files.js";
|
|
7
7
|
const path = (data, name) => { assertBrowserName(name); return join(browsersDir(data), `${name}.json`); };
|
|
8
8
|
const records = new WeakMap();
|
|
9
9
|
export function worldBrowser(data, name) {
|
package/dist/src/catalog.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { installedPackageDir } from '@volter/world-core/runtime';
|
|
1
|
+
import { installedPackageDir } from '@volter/world-core/runtime-state';
|
|
2
2
|
export declare const TWIN_PACKAGE_PREFIX = "@volter/twin-";
|
|
3
3
|
export declare function twinPackageName(vendor: string): string;
|
|
4
4
|
export type CatalogKind = 'checkout' | 'installed';
|
|
@@ -45,6 +45,7 @@ export declare function packFactsFile(dir: string): string | undefined;
|
|
|
45
45
|
export declare function resolveCatalog(root: string, options?: {
|
|
46
46
|
sources?: Readonly<Record<string, string>>;
|
|
47
47
|
vendors?: readonly string[];
|
|
48
|
+
mayBeEmpty?: boolean;
|
|
48
49
|
}): Catalog;
|
|
49
50
|
/** The pack directory a service boots from: its `package` resolved from the world root at boot. */
|
|
50
51
|
export declare function resolveServicePackage(root: string, pkg: string): string;
|
package/dist/src/catalog.js
CHANGED
|
@@ -9,7 +9,7 @@ import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
|
9
9
|
import { spawnSync } from 'node:child_process';
|
|
10
10
|
import { join, resolve } from 'node:path';
|
|
11
11
|
import { overlayPackFacts } from "./pack-facts.js";
|
|
12
|
-
import { installedPackageDir, installedVendorPacks, isDerivedPack, packRepository } from '@volter/world-core/runtime';
|
|
12
|
+
import { installedPackageDir, installedVendorPacks, isDerivedPack, packRepository } from '@volter/world-core/runtime-state';
|
|
13
13
|
export const TWIN_PACKAGE_PREFIX = '@volter/twin-';
|
|
14
14
|
export function twinPackageName(vendor) { return `${TWIN_PACKAGE_PREFIX}${vendor}`; }
|
|
15
15
|
/** A derived (Protocol 3) pack carries the surface derive-pack generated from its spec. */
|
|
@@ -85,7 +85,10 @@ export function checkoutCatalog(root) {
|
|
|
85
85
|
};
|
|
86
86
|
}
|
|
87
87
|
export function installedCatalog(root, options = {}) {
|
|
88
|
-
|
|
88
|
+
// An explicit empty selection needs no package discovery or publisher choice.
|
|
89
|
+
const twins = options.vendors?.length === 0
|
|
90
|
+
? new Map()
|
|
91
|
+
: new Map([...installedVendorPacks(root, options)].filter(([, dir]) => packCli(dir) !== undefined));
|
|
89
92
|
return {
|
|
90
93
|
kind: 'installed',
|
|
91
94
|
root: resolve(root),
|
|
@@ -152,6 +155,8 @@ export function packFactsFile(dir) {
|
|
|
152
155
|
export function resolveCatalog(root, options = {}) {
|
|
153
156
|
const resolved = resolve(root);
|
|
154
157
|
const installed = installedCatalog(resolved, options);
|
|
158
|
+
if (options.vendors?.length === 0)
|
|
159
|
+
return installed;
|
|
155
160
|
const repo = packRepository(resolved);
|
|
156
161
|
const catalog = repo === undefined ? installed : mergedCatalog([checkoutCatalog(repo), installed]);
|
|
157
162
|
for (const vendor of catalog.vendors()) {
|
|
@@ -159,7 +164,8 @@ export function resolveCatalog(root, options = {}) {
|
|
|
159
164
|
if (file)
|
|
160
165
|
overlayPackFactsFile(file);
|
|
161
166
|
}
|
|
162
|
-
|
|
167
|
+
// A World whose application runs beside infrastructure alone has no twin to find (`init --needs`, architecture).
|
|
168
|
+
if (catalog.vendors().length === 0 && !options.mayBeEmpty) {
|
|
163
169
|
throw new Error(`No twins found for ${resolved}: no pack repository and no \`@volter/twin-<vendor>\` package installed above it. `
|
|
164
170
|
+ `Install the twins your app needs (e.g. \`bun add -d @volter/twin-stripe\`) and run init again.`);
|
|
165
171
|
}
|
package/dist/src/changeset.js
CHANGED
|
@@ -586,7 +586,7 @@ export function rebaseWorldChangeset(name, options = {}) {
|
|
|
586
586
|
withHistoryLocks(moved.map(({ st, controlRoot }) => worldPaths(st, controlRoot).dir), () => {
|
|
587
587
|
for (const { st, controlRoot } of moved)
|
|
588
588
|
rebaseBranch(st, controlRoot, { origin: Boolean(readBranchMeta(st, controlRoot)?.origin) });
|
|
589
|
-
});
|
|
589
|
+
}, { operation: 'branch-pointer adjustment' });
|
|
590
590
|
if (!changesetHashMatches(located.changeset))
|
|
591
591
|
throw new Error(`Refusing to rebase changeset "${name}": its stored contentHash does not match its body — the object drifted after authoring`);
|
|
592
592
|
const instance = requireWorld(located.world, root);
|