Merge branch 'master' into codex/puzzle-clear-template-runtime-fixes
# Conflicts: # .hermes/shared-memory/decision-log.md # .hermes/shared-memory/project-overview.md # docs/【开发运维】本地开发验证与生产运维-2026-05-15.md # scripts/dev.test.ts # server-rs/crates/api-server/src/creation_entry_config.rs # server-rs/crates/api-server/src/wooden_fish.rs # server-rs/crates/module-auth/src/lib.rs # server-rs/crates/spacetime-client/src/wooden_fish.rs # server-rs/crates/spacetime-module/src/auth/procedures.rs # src/components/custom-world-home/creationWorkShelf.ts # src/components/platform-entry/PlatformEntryFlowShellImpl.tsx # src/components/rpg-entry/rpgEntryWorldPresentation.ts # src/services/miniGameDraftGenerationProgress.test.ts # src/services/miniGameDraftGenerationProgress.ts
This commit is contained in:
392
scripts/dev.mjs
392
scripts/dev.mjs
@@ -10,13 +10,17 @@ import {
|
||||
watch,
|
||||
writeFileSync,
|
||||
} from 'node:fs';
|
||||
import {basename, relative, resolve} from 'node:path';
|
||||
import {basename, join, relative, resolve} from 'node:path';
|
||||
import {createInterface} from 'node:readline';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
|
||||
import {
|
||||
formatPortDecision,
|
||||
getLinuxDevPortRangeRegistryPaths,
|
||||
getLinuxDevPortRangeUsername,
|
||||
mapDevPortsToPortRange,
|
||||
normalizePort,
|
||||
reserveLinuxDevPortRange,
|
||||
resolveDevStackPorts,
|
||||
} from './dev-stack-port-utils.mjs';
|
||||
import {
|
||||
@@ -27,6 +31,7 @@ import {
|
||||
} from './dev-utils.mjs';
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
const devStackStatePath = join(repoRoot, '.app/dev-stack.json');
|
||||
const serverRsDir = resolve(repoRoot, 'server-rs');
|
||||
const manifestPath = resolve(serverRsDir, 'Cargo.toml');
|
||||
const modulePath = resolve(serverRsDir, 'crates/spacetime-module');
|
||||
@@ -60,6 +65,7 @@ function usage() {
|
||||
--spacetime-port <port> SpacetimeDB 端口
|
||||
--spacetime-data-dir <path> SpacetimeDB 本地数据目录
|
||||
--database <name> SpacetimeDB 数据库名
|
||||
--port-range <start-end> Linux 用户端口段,手动指定示例 10000-10099;默认自动从 10000-10099 起分配
|
||||
--watch 文件改动后刷新/重启对应模块
|
||||
--no-interactive 关闭交互式手动命令
|
||||
|
||||
@@ -110,6 +116,7 @@ function parseArgs(argv, baseEnv) {
|
||||
spacetimePort: normalizePort(env.SPACETIME_PORT, 3101),
|
||||
spacetimeDataDir: resolve(serverRsDir, '.spacetimedb/local/data'),
|
||||
spacetimeServerUrl: String(env.GENARRATIVE_SPACETIME_SERVER_URL ?? '').trim(),
|
||||
portRangeSpec: String(env.GENARRATIVE_DEV_PORT_RANGE ?? '').trim(),
|
||||
database:
|
||||
readLocalSpacetimeDatabase() ||
|
||||
String(env.GENARRATIVE_SPACETIME_DATABASE ?? '').trim() ||
|
||||
@@ -185,6 +192,10 @@ function parseArgs(argv, baseEnv) {
|
||||
options.database = readValue();
|
||||
explicitOptions.add('database');
|
||||
break;
|
||||
case '--port-range':
|
||||
options.portRangeSpec = readValue();
|
||||
explicitOptions.add('portRangeSpec');
|
||||
break;
|
||||
case '--log':
|
||||
options.apiLog = readValue();
|
||||
break;
|
||||
@@ -246,6 +257,136 @@ function normalizeServiceName(rawName) {
|
||||
throw new Error(`未知模块: ${rawName}`);
|
||||
}
|
||||
|
||||
function resolveDevStackStatePath(root = repoRoot) {
|
||||
return join(root, '.app/dev-stack.json');
|
||||
}
|
||||
|
||||
function buildDevStackSnapshot(runner, updatedAt = new Date().toISOString()) {
|
||||
const services = {};
|
||||
for (const serviceName of SERVICE_NAMES) {
|
||||
services[serviceName] = buildDevStackServiceSnapshot(
|
||||
runner,
|
||||
serviceName,
|
||||
updatedAt,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
command: runner.command ?? 'all',
|
||||
repoRoot,
|
||||
database: runner.options.database,
|
||||
watch: Boolean(runner.options.watch),
|
||||
updatedAt,
|
||||
services,
|
||||
};
|
||||
}
|
||||
|
||||
function buildDevStackServiceSnapshot(runner, serviceName, updatedAt) {
|
||||
const service = runner.services.get(serviceName);
|
||||
const runtime = service?.runtime ?? {};
|
||||
const endpoint = resolveDevStackServiceEndpoint(runner, serviceName);
|
||||
const isReusedSpacetime =
|
||||
serviceName === 'spacetime' && runner.state.spacetimeReused;
|
||||
const runtimeStatus = runtime.status ?? 'idle';
|
||||
const status =
|
||||
runtimeStatus === 'idle' && isReusedSpacetime ? 'reused' : runtimeStatus;
|
||||
const childPid =
|
||||
service?.child && Number.isInteger(service.child.pid)
|
||||
? service.child.pid
|
||||
: null;
|
||||
|
||||
return {
|
||||
status,
|
||||
pid:
|
||||
childPid ??
|
||||
runtime.pid ??
|
||||
(isReusedSpacetime ? (runner.state.spacetimePid ?? null) : null),
|
||||
host: runtime.host ?? endpoint.host,
|
||||
port: runtime.port ?? endpoint.port,
|
||||
url: runtime.url ?? endpoint.url,
|
||||
command: runtime.command ?? resolveDevStackServiceCommand(runner, serviceName),
|
||||
startedAt: runtime.startedAt ?? null,
|
||||
updatedAt: runtime.updatedAt ?? updatedAt,
|
||||
exitCode: runtime.exitCode ?? null,
|
||||
signal: runtime.signal ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
function resolveDevStackServiceEndpoint(runner, serviceName) {
|
||||
const {options, state} = runner;
|
||||
switch (serviceName) {
|
||||
case 'spacetime':
|
||||
return {
|
||||
host: options.spacetimeHost,
|
||||
port: options.spacetimePort,
|
||||
url: state.spacetimeServer,
|
||||
};
|
||||
case 'api-server':
|
||||
return {
|
||||
host: options.apiHost,
|
||||
port: options.apiPort,
|
||||
url: state.apiTarget,
|
||||
};
|
||||
case 'web':
|
||||
return {
|
||||
host: options.webHost,
|
||||
port: options.webPort,
|
||||
url: `http://${resolveClientHost(options.webHost)}:${options.webPort}`,
|
||||
};
|
||||
case 'admin-web':
|
||||
return {
|
||||
host: options.adminWebHost,
|
||||
port: options.adminWebPort,
|
||||
url: `http://${state.adminWebTargetHost}:${options.adminWebPort}/admin/`,
|
||||
};
|
||||
default:
|
||||
return {
|
||||
host: null,
|
||||
port: null,
|
||||
url: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function resolveDevStackServiceCommand(runner, serviceName) {
|
||||
const {options, state} = runner;
|
||||
switch (serviceName) {
|
||||
case 'spacetime':
|
||||
return state.spacetimeReused
|
||||
? `reuse spacetime standalone ${state.spacetimeServer}`
|
||||
: [
|
||||
'spacetime',
|
||||
'start',
|
||||
'--data-dir',
|
||||
options.spacetimeDataDir,
|
||||
'--listen-addr',
|
||||
`${options.spacetimeHost}:${options.spacetimePort}`,
|
||||
'--non-interactive',
|
||||
].join(' ');
|
||||
case 'api-server':
|
||||
return 'cargo run -p api-server --manifest-path server-rs/Cargo.toml';
|
||||
case 'web':
|
||||
return [
|
||||
'node',
|
||||
relative(repoRoot, viteCliPath),
|
||||
`--port=${options.webPort}`,
|
||||
`--host=${options.webHost}`,
|
||||
'--strictPort',
|
||||
].join(' ');
|
||||
case 'admin-web':
|
||||
return [
|
||||
'node',
|
||||
relative(adminWebDir, viteCliPath),
|
||||
`--host=${options.adminWebHost}`,
|
||||
`--port=${options.adminWebPort}`,
|
||||
'--strictPort',
|
||||
].join(' ');
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function requireCommand(command) {
|
||||
const result = spawnSync(command, ['--version'], {
|
||||
cwd: repoRoot,
|
||||
@@ -375,14 +516,37 @@ function ensureRequiredFiles(command) {
|
||||
}
|
||||
|
||||
class DevService {
|
||||
constructor(name, startFn) {
|
||||
constructor(name, startFn, onStateChange = null) {
|
||||
this.name = name;
|
||||
this.startFn = startFn;
|
||||
this.onStateChange = onStateChange;
|
||||
this.child = null;
|
||||
this.children = [];
|
||||
this.logStream = null;
|
||||
this.stopping = false;
|
||||
this.restartTimer = null;
|
||||
this.runtime = {
|
||||
status: 'idle',
|
||||
pid: null,
|
||||
host: null,
|
||||
port: null,
|
||||
url: null,
|
||||
command: null,
|
||||
startedAt: null,
|
||||
updatedAt: null,
|
||||
exitCode: null,
|
||||
signal: null,
|
||||
};
|
||||
}
|
||||
|
||||
updateRuntimeState(patch) {
|
||||
const updatedAt = new Date().toISOString();
|
||||
this.runtime = {
|
||||
...this.runtime,
|
||||
...patch,
|
||||
updatedAt,
|
||||
};
|
||||
this.onStateChange?.();
|
||||
}
|
||||
|
||||
async start() {
|
||||
@@ -390,17 +554,36 @@ class DevService {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.startFn(this);
|
||||
this.updateRuntimeState({status: 'starting', exitCode: null, signal: null});
|
||||
try {
|
||||
await this.startFn(this);
|
||||
} catch (error) {
|
||||
this.updateRuntimeState({status: 'failed', pid: null});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
registerChild(child) {
|
||||
this.child = child;
|
||||
this.updateRuntimeState({
|
||||
status: 'running',
|
||||
pid: Number.isInteger(child.pid) ? child.pid : null,
|
||||
exitCode: null,
|
||||
signal: null,
|
||||
startedAt: this.runtime.startedAt ?? new Date().toISOString(),
|
||||
});
|
||||
child.on('exit', (code, signal) => {
|
||||
if (this.logStream && !this.logStream.destroyed) {
|
||||
this.logStream.end();
|
||||
}
|
||||
|
||||
this.child = null;
|
||||
this.updateRuntimeState({
|
||||
status: this.stopping ? 'stopped' : code === 0 ? 'stopped' : 'failed',
|
||||
pid: null,
|
||||
exitCode: code ?? null,
|
||||
signal: signal ?? null,
|
||||
});
|
||||
if (this.stopping) {
|
||||
this.stopping = false;
|
||||
return;
|
||||
@@ -419,6 +602,9 @@ class DevService {
|
||||
|
||||
const processes = [this.child, ...this.children].filter(Boolean);
|
||||
this.stopping = processes.length > 0;
|
||||
if (processes.length > 0) {
|
||||
this.updateRuntimeState({status: 'stopping'});
|
||||
}
|
||||
this.child = null;
|
||||
this.children = [];
|
||||
|
||||
@@ -431,6 +617,9 @@ class DevService {
|
||||
}
|
||||
this.logStream = null;
|
||||
this.stopping = false;
|
||||
if (processes.length > 0) {
|
||||
this.updateRuntimeState({status: 'stopped', pid: null});
|
||||
}
|
||||
}
|
||||
|
||||
scheduleRestart(delayMs = 250, restartFn = null, actionLabel = '重启') {
|
||||
@@ -550,6 +739,8 @@ class DevRunner {
|
||||
adminWebTargetHost: resolveClientHost(options.adminWebHost),
|
||||
spacetimeServer: initialSpacetimeServer,
|
||||
apiTarget: `http://${resolveClientHost(options.apiHost)}:${options.apiPort}`,
|
||||
portRange: null,
|
||||
portRangeReservation: null,
|
||||
};
|
||||
this.services = new Map();
|
||||
this.watchers = [];
|
||||
@@ -573,10 +764,56 @@ class DevRunner {
|
||||
ensureSpacetimeToolVersionMatchesWorkspace();
|
||||
}
|
||||
|
||||
await this.prepareLinuxPortRange(command);
|
||||
await this.tryReuseExistingSpacetime(command);
|
||||
await this.resolvePorts(command);
|
||||
this.registerServices();
|
||||
this.printSummary(command);
|
||||
this.writeDevStackState();
|
||||
}
|
||||
|
||||
async prepareLinuxPortRange(command) {
|
||||
if (process.platform !== 'linux') {
|
||||
return;
|
||||
}
|
||||
|
||||
const requestedRange = String(this.options.portRangeSpec ?? '').trim();
|
||||
const allocation = await reserveLinuxDevPortRange({
|
||||
env: {
|
||||
...this.baseEnv,
|
||||
GENARRATIVE_DEV_PORT_RANGE: requestedRange,
|
||||
},
|
||||
username: getLinuxDevPortRangeUsername(this.baseEnv),
|
||||
});
|
||||
|
||||
if (!allocation) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.state.portRangeReservation = allocation;
|
||||
this.state.portRange = allocation.range;
|
||||
this.baseEnv.GENARRATIVE_DEV_PORT_RANGE = allocation.range.label;
|
||||
|
||||
const mappedPorts = mapDevPortsToPortRange(allocation.range);
|
||||
if (!mappedPorts) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.explicitOptions.has('webPort')) {
|
||||
this.options.webPort = mappedPorts.webPort;
|
||||
}
|
||||
if (!this.explicitOptions.has('apiPort')) {
|
||||
this.options.apiPort = mappedPorts.apiPort;
|
||||
}
|
||||
if (!this.explicitOptions.has('spacetimePort')) {
|
||||
this.options.spacetimePort = mappedPorts.spacetimePort;
|
||||
}
|
||||
if (!this.explicitOptions.has('adminWebPort')) {
|
||||
this.options.adminWebPort = mappedPorts.adminWebPort;
|
||||
}
|
||||
|
||||
this.state.spacetimeServer = `http://${this.options.spacetimeHost}:${this.options.spacetimePort}`;
|
||||
this.state.apiTarget = `http://${this.state.apiTargetHost}:${this.options.apiPort}`;
|
||||
}
|
||||
|
||||
shouldValidateSpacetimeToolVersion(command) {
|
||||
@@ -627,6 +864,10 @@ class DevRunner {
|
||||
]);
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (!this.isCandidateSpacetimeWithinAssignedRange(candidate)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const pingUrl = buildUrl(candidate, '/v1/ping');
|
||||
if (!pingUrl || !(await isHttpReady(pingUrl))) {
|
||||
continue;
|
||||
@@ -643,6 +884,9 @@ class DevRunner {
|
||||
}
|
||||
this.state.spacetimeServer = candidate;
|
||||
this.state.spacetimeReused = true;
|
||||
this.state.spacetimePid = Number.isInteger(pidState.pid)
|
||||
? pidState.pid
|
||||
: null;
|
||||
const pidLabel = Number.isInteger(pidState.pid) ? ` pid=${pidState.pid}` : '';
|
||||
console.log(`[dev:spacetime] 复用已启动实例${pidLabel}: ${candidate}`);
|
||||
return;
|
||||
@@ -654,6 +898,21 @@ class DevRunner {
|
||||
);
|
||||
}
|
||||
|
||||
isCandidateSpacetimeWithinAssignedRange(candidateUrl) {
|
||||
const range = this.state.portRange;
|
||||
if (!range) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
const url = new URL(candidateUrl);
|
||||
const port = Number(url.port);
|
||||
return Number.isInteger(port) && port >= range.start && port <= range.end;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async resolvePorts(command) {
|
||||
const {options} = this;
|
||||
const portConfig = {};
|
||||
@@ -663,6 +922,7 @@ class DevRunner {
|
||||
portConfig.spacetime = {
|
||||
host: options.spacetimeHost,
|
||||
preferredPort: options.spacetimePort,
|
||||
portRange: this.state.portRange,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -671,6 +931,7 @@ class DevRunner {
|
||||
portConfig.api = {
|
||||
host: options.apiHost,
|
||||
preferredPort: options.apiPort,
|
||||
portRange: this.state.portRange,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -678,6 +939,7 @@ class DevRunner {
|
||||
portConfig.web = {
|
||||
host: options.webHost,
|
||||
preferredPort: options.webPort,
|
||||
portRange: this.state.portRange,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -685,6 +947,7 @@ class DevRunner {
|
||||
portConfig.adminWeb = {
|
||||
host: options.adminWebHost,
|
||||
preferredPort: options.adminWebPort,
|
||||
portRange: this.state.portRange,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -728,19 +991,48 @@ class DevRunner {
|
||||
}
|
||||
|
||||
registerServices() {
|
||||
const onStateChange = () => this.writeDevStackState();
|
||||
this.services.set(
|
||||
'spacetime',
|
||||
new DevService('spacetime', async (service) => this.startSpacetime(service)),
|
||||
new DevService(
|
||||
'spacetime',
|
||||
async (service) => this.startSpacetime(service),
|
||||
onStateChange,
|
||||
),
|
||||
);
|
||||
this.services.set(
|
||||
'api-server',
|
||||
new DevService('api-server', async (service) => this.startApiServer(service)),
|
||||
new DevService(
|
||||
'api-server',
|
||||
async (service) => this.startApiServer(service),
|
||||
onStateChange,
|
||||
),
|
||||
);
|
||||
this.services.set(
|
||||
'web',
|
||||
new DevService('web', async (service) => this.startWeb(service), onStateChange),
|
||||
);
|
||||
this.services.set('web', new DevService('web', async (service) => this.startWeb(service)));
|
||||
this.services.set(
|
||||
'admin-web',
|
||||
new DevService('admin-web', async (service) => this.startAdminWeb(service)),
|
||||
new DevService(
|
||||
'admin-web',
|
||||
async (service) => this.startAdminWeb(service),
|
||||
onStateChange,
|
||||
),
|
||||
);
|
||||
|
||||
if (this.state.spacetimeReused) {
|
||||
const spacetimeService = this.services.get('spacetime');
|
||||
const endpoint = resolveDevStackServiceEndpoint(this, 'spacetime');
|
||||
spacetimeService?.updateRuntimeState({
|
||||
status: 'reused',
|
||||
pid: this.state.spacetimePid ?? null,
|
||||
host: endpoint.host,
|
||||
port: endpoint.port,
|
||||
url: endpoint.url,
|
||||
command: resolveDevStackServiceCommand(this, 'spacetime'),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
printSummary(command) {
|
||||
@@ -748,6 +1040,15 @@ class DevRunner {
|
||||
console.log(`[dev] repo: ${repoRoot}`);
|
||||
console.log(`[dev] command: ${command}`);
|
||||
console.log(`[dev] watch: ${options.watch ? 'on' : 'off'}`);
|
||||
if (state.portRange) {
|
||||
const owner =
|
||||
state.portRangeReservation?.username ||
|
||||
getLinuxDevPortRangeUsername(this.baseEnv);
|
||||
console.log(`[dev] port-range: ${state.portRange.label} (${owner})`);
|
||||
console.log(
|
||||
`[dev] port-range-registry: ${getLinuxDevPortRangeRegistryPaths(this.baseEnv).registryPath}`,
|
||||
);
|
||||
}
|
||||
console.log(`[dev] web: http://127.0.0.1:${options.webPort}`);
|
||||
console.log(`[dev] admin web: http://${state.adminWebTargetHost}:${options.adminWebPort}/admin/`);
|
||||
console.log(`[dev] api-server: ${state.apiTarget}`);
|
||||
@@ -755,6 +1056,16 @@ class DevRunner {
|
||||
console.log(`[dev] database: ${options.database}`);
|
||||
}
|
||||
|
||||
writeDevStackState() {
|
||||
try {
|
||||
ensureParentDir(devStackStatePath);
|
||||
const snapshot = buildDevStackSnapshot(this);
|
||||
writeFileSync(devStackStatePath, `${JSON.stringify(snapshot, null, 2)}\n`, 'utf8');
|
||||
} catch (error) {
|
||||
console.warn(`[dev] 写入 ${devStackStatePath} 失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async startCommand(command) {
|
||||
if (command === 'all') {
|
||||
await this.startSpacetimeForFullStack();
|
||||
@@ -828,6 +1139,17 @@ class DevRunner {
|
||||
);
|
||||
|
||||
console.log(`[dev:spacetime] log: ${logFile}`);
|
||||
service.updateRuntimeState({
|
||||
status: 'starting',
|
||||
pid: null,
|
||||
host: options.spacetimeHost,
|
||||
port: options.spacetimePort,
|
||||
url: this.state.spacetimeServer,
|
||||
command: resolveDevStackServiceCommand(this, 'spacetime'),
|
||||
startedAt: new Date().toISOString(),
|
||||
exitCode: null,
|
||||
signal: null,
|
||||
});
|
||||
const env = {
|
||||
...this.baseEnv,
|
||||
};
|
||||
@@ -881,6 +1203,11 @@ class DevRunner {
|
||||
this.options.spacetimePort = port;
|
||||
this.state.spacetimeServer = `http://${this.options.spacetimeHost}:${port}`;
|
||||
recordSpacetimeUrl(this.options.spacetimeDataDir, this.state.spacetimeServer);
|
||||
this.services.get('spacetime')?.updateRuntimeState({
|
||||
host: this.options.spacetimeHost,
|
||||
port,
|
||||
url: this.state.spacetimeServer,
|
||||
});
|
||||
console.log(`[dev:spacetime] actual: ${this.state.spacetimeServer}`);
|
||||
}
|
||||
|
||||
@@ -977,6 +1304,17 @@ class DevRunner {
|
||||
console.log(
|
||||
`[dev:api-server] SpacetimeDB ${this.options.database} @ ${this.state.spacetimeServer}`,
|
||||
);
|
||||
service.updateRuntimeState({
|
||||
status: 'starting',
|
||||
pid: null,
|
||||
host: this.options.apiHost,
|
||||
port: this.options.apiPort,
|
||||
url: this.state.apiTarget,
|
||||
command: resolveDevStackServiceCommand(this, 'api-server'),
|
||||
startedAt: new Date().toISOString(),
|
||||
exitCode: null,
|
||||
signal: null,
|
||||
});
|
||||
|
||||
const child = spawn(
|
||||
'cargo',
|
||||
@@ -1019,6 +1357,7 @@ class DevRunner {
|
||||
|
||||
startWeb(service) {
|
||||
const apiTarget = this.resolveFrontendApiTarget();
|
||||
const endpoint = resolveDevStackServiceEndpoint(this, 'web');
|
||||
const env = {
|
||||
...this.baseEnv,
|
||||
RUST_SERVER_TARGET: apiTarget,
|
||||
@@ -1029,6 +1368,17 @@ class DevRunner {
|
||||
};
|
||||
|
||||
console.log(`[dev:web] api target: ${apiTarget}`);
|
||||
service.updateRuntimeState({
|
||||
status: 'starting',
|
||||
pid: null,
|
||||
host: endpoint.host,
|
||||
port: endpoint.port,
|
||||
url: endpoint.url,
|
||||
command: resolveDevStackServiceCommand(this, 'web'),
|
||||
startedAt: new Date().toISOString(),
|
||||
exitCode: null,
|
||||
signal: null,
|
||||
});
|
||||
const child = spawn(
|
||||
'node',
|
||||
[
|
||||
@@ -1054,6 +1404,7 @@ class DevRunner {
|
||||
|
||||
startAdminWeb(service) {
|
||||
const apiTarget = this.resolveFrontendApiTarget({admin: true});
|
||||
const endpoint = resolveDevStackServiceEndpoint(this, 'admin-web');
|
||||
const env = {
|
||||
...this.baseEnv,
|
||||
ADMIN_API_TARGET: apiTarget,
|
||||
@@ -1062,6 +1413,17 @@ class DevRunner {
|
||||
};
|
||||
|
||||
console.log(`[dev:admin-web] api target: ${apiTarget}`);
|
||||
service.updateRuntimeState({
|
||||
status: 'starting',
|
||||
pid: null,
|
||||
host: endpoint.host,
|
||||
port: endpoint.port,
|
||||
url: endpoint.url,
|
||||
command: resolveDevStackServiceCommand(this, 'admin-web'),
|
||||
startedAt: new Date().toISOString(),
|
||||
exitCode: null,
|
||||
signal: null,
|
||||
});
|
||||
const child = spawn(
|
||||
'node',
|
||||
[
|
||||
@@ -1685,6 +2047,10 @@ function normalizePath(path) {
|
||||
return path.replace(/\\/gu, '/');
|
||||
}
|
||||
|
||||
function normalizeDirectExecutionPath(path) {
|
||||
return normalizePath(path).replace(/^\/([A-Za-z]:\/)/u, '$1');
|
||||
}
|
||||
|
||||
function safeRealpath(pathValue) {
|
||||
try {
|
||||
return realpathSync(pathValue);
|
||||
@@ -1699,9 +2065,15 @@ function isDirectModuleExecution(argv1, moduleUrl, resolvePath = safeRealpath) {
|
||||
}
|
||||
|
||||
try {
|
||||
return resolvePath(argv1) === resolvePath(fileURLToPath(moduleUrl));
|
||||
return (
|
||||
normalizeDirectExecutionPath(resolvePath(argv1)) ===
|
||||
normalizeDirectExecutionPath(resolvePath(fileURLToPath(moduleUrl)))
|
||||
);
|
||||
} catch {
|
||||
return resolve(argv1) === fileURLToPath(moduleUrl);
|
||||
return (
|
||||
normalizeDirectExecutionPath(resolve(argv1)) ===
|
||||
normalizeDirectExecutionPath(fileURLToPath(moduleUrl))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1752,6 +2124,7 @@ export {
|
||||
assertReusableSpacetimeProcessVersionMatchesWorkspace,
|
||||
assertSpacetimeToolVersionMatchesWorkspace,
|
||||
buildApiServerProcessEnv,
|
||||
buildDevStackSnapshot,
|
||||
buildSpacetimePublishArgs,
|
||||
createDevServerSpawnOptions,
|
||||
createWatchConfigs,
|
||||
@@ -1759,6 +2132,7 @@ export {
|
||||
isDirectModuleExecution,
|
||||
parseSpacetimeToolVersion,
|
||||
parseArgs,
|
||||
resolveDevStackStatePath,
|
||||
shouldAcceptWatchEvent,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user