feat(config): unify startup mode and server selection

This commit is contained in:
2026-09-05 22:52:14 +08:00
parent 239af0aa39
commit facceeae9b
26 changed files with 204 additions and 240 deletions
@@ -7,12 +7,12 @@ import {
resolveLocalStartup,
type LocalStartupContext,
} from '../../YouleNexus/assets/framework/config/local-startup.ts';
import { PROFILES } from '../../YouleNexus/assets/framework/config/profiles.ts';
import { STARTUP_CONFIG } from '../../YouleNexus/assets/framework/config/profiles.ts';
import type { ResolveRuntimeConfigOptions, RuntimeConfig } from '../../YouleNexus/assets/framework/config/runtime-config.ts';
import type { ConfigFetcher } from '../../YouleNexus/assets/framework/config/remote-config.ts';
import { BUILD_IDENTITY } from '../../YouleNexus/assets/framework/config/sources/defaults.ts';
function options(search = '?profile=local'): ResolveRuntimeConfigOptions & {
function options(search = ''): ResolveRuntimeConfigOptions & {
fetcher: ConfigFetcher & { calls: number };
} {
const fetcher = {
@@ -22,7 +22,7 @@ function options(search = '?profile=local'): ResolveRuntimeConfigOptions & {
return { player_server_tcp: 'remote.example:3088' };
},
};
return { mode: 'debug', hostKind: 'h5', win: {}, search, fetcher };
return { hostKind: 'h5', win: {}, search, fetcher };
}
test('local debug fetches remote config before choosing authoritative local servers', async () => {
@@ -32,7 +32,7 @@ test('local debug fetches remote config before choosing authoritative local serv
assert.equal(context.hostKind, 'h5');
assert.equal(context.profile, 'local');
assert.equal(context.config.identity.gameid, BUILD_IDENTITY.gameid);
assert.deepEqual(context.config.servers, PROFILES.local!.servers);
assert.deepEqual(context.config.servers, STARTUP_CONFIG.localServers);
assert.equal(input.fetcher.calls, 1);
assert.equal(context.config.source, 'remote');
assert.equal(Object.isFrozen(context), true);
@@ -40,7 +40,8 @@ test('local debug fetches remote config before choosing authoritative local serv
test('rejects non-local startup modes and hosts before fetching', async () => {
const cases: Array<[Partial<ResolveRuntimeConfigOptions>, RegExp]> = [
[{ mode: 'release' }, /mode.*debug/i],
[{ startupConfig: {...STARTUP_CONFIG, mode:'release'} }, /mode.*debug/i],
[{ startupConfig: {...STARTUP_CONFIG, useLocalServer:false} }, /useLocalServer/i],
[{ hostKind: 'native-settings' }, /hostKind.*h5/i],
[{ hostKind: 'uAgent_3' }, /hostKind.*h5/i],
];
@@ -52,21 +53,11 @@ test('rejects non-local startup modes and hosts before fetching', async () => {
}
});
test('requires exactly one local profile and only an optional single debug mode', async () => {
const cases: Array<[string, RegExp]> = [
['', /profile/i],
['?profile=prod', /profile/i],
['?profile=staging', /profile/i],
['?profile=local&profile=local', /profile/i],
['?profile=local&mode=release', /mode.*debug/i],
['?profile=local&mode=debug&mode=debug', /mode/i],
];
for (const [search, expected] of cases) {
const input = options(search);
await assert.rejects(resolveLocalStartup(input), expected);
assert.equal(input.fetcher.calls, 0);
test('ignores conflicting and duplicate mode/profile queries', async () => {
for (const search of ['', '?profile=prod', '?profile=local&profile=unknown&mode=release&mode=other']) {
const input=options(search); const result=await resolveLocalStartup(input);
assert.deepEqual(result.config.servers,STARTUP_CONFIG.localServers); assert.equal(input.fetcher.calls,1);
}
await resolveLocalStartup(options('?profile=local&mode=debug'));
});
test('rejects gameconfig and ambiguous identity controls before fetching', async () => {
@@ -105,12 +96,13 @@ function validContext(): LocalStartupContext {
hostKind: 'h5',
profile: 'local',
config: {
startupConfig: STARTUP_CONFIG,
mode: 'debug',
isDebugger: true,
identity: BUILD_IDENTITY,
servers: PROFILES.local!.servers!,
servers: STARTUP_CONFIG.localServers,
source: 'remote',
gameserver: PROFILES.local!.gameserver,
gameserver: STARTUP_CONFIG.gameserver,
...remoteFixture(BUILD_IDENTITY),
},
};
@@ -172,3 +164,13 @@ test('connection target must be a valid URL from the authoritative local profile
assert.throws(() => assertLocalConnectionTarget(context, url), expected);
}
});
test('local consumers validate the injected source snapshot and its exact targets', async () => {
const startupConfig={...STARTUP_CONFIG,gameserver:'https://fixture.example/config.txt',localServers:['ws://[::1]:4300']};
const context=await resolveLocalStartup({...options(),startupConfig});
assertLocalConnectionTarget(context,'ws://[::1]:4300');
assert.throws(()=>assertLocalConnectionTarget(context,STARTUP_CONFIG.localServers[0]),/target/);
for (const patch of [{mode:'release'}, {useLocalServer:false}, {localServers:['ws://elsewhere:3088']}, {gameserver:'https://other.example/config.txt'}]) {
assert.throws(()=>assertLocalStartupContext({...context,config:{...context.config,startupConfig:{...context.config.startupConfig,...patch}}} as any),/mode|useLocalServer|localServers|gameserver/);
}
});