fix(config): resolve remote hierarchy in memory for every profile

This commit is contained in:
2026-09-05 21:21:24 +08:00
parent 62328b6fd6
commit 053302c5df
27 changed files with 286 additions and 143 deletions
@@ -12,7 +12,7 @@ function returning(value: unknown): ConfigFetcher & { calls: string[] } {
};
}
const REMOTE = { data: { urlserver: ['5.5.5.5:5000', '5.5.5.5:5000'] } };
const REMOTE = { player_server_tcp: ['5.5.5.5:5000', '5.5.5.5:5000'] };
test('h5:只读 query 身份,不访问原生宿主,并生成严格 remote 配置', async () => {
const fetcher = returning(REMOTE);
@@ -133,16 +133,17 @@ test('uAgent_3:拒绝宿主提供的非法身份字段类型', async () => {
);
});
test('显式 local debug:direct 字段不靠 null 推断,完整服务器来自 profile', async () => {
test('显式 local debug:远程配置保留内存,连接服务器来自 profile', async () => {
const fetcher = returning(REMOTE);
const result = await resolveRuntimeConfig({
mode: 'debug', hostKind: 'h5', win: {}, search: '?profile=local', fetcher,
});
assert.equal(result.source, 'direct');
assert.equal(result.gameserver, null);
assert.equal(result.rawConfig, null);
assert.equal(result.source, 'remote');
assert.ok(result.gameserver);
assert.equal(result.rawConfig, REMOTE);
assert.strictEqual(result.remoteConfig.raw, result.rawConfig);
assert.deepEqual(result.servers, ['ws://127.0.0.1:3088']);
assert.deepEqual(fetcher.calls, []);
assert.equal(fetcher.calls.length, 1);
});
test('远程抓取失败显式报错,不降级 direct', async () => {
@@ -152,3 +153,39 @@ test('远程抓取失败显式报错,不降级 direct', async () => {
/远程配置抓取失败/,
);
});
test('release ignores local profile but still fetches and selects remote servers', async () => {
const fetcher = returning(REMOTE);
const result = await resolveRuntimeConfig({ mode: 'release', hostKind: 'h5', win: {}, search: '?profile=local', fetcher });
assert.equal(fetcher.calls.length, 1);
assert.deepEqual(result.servers, ['ws://5.5.5.5:5000', 'ws://5.5.5.5:5000']);
assert.equal(result.isDebugger, false);
});
test('JSON parse errors retain their classification through the runtime boundary', async () => {
const { ConfigParseError } = await import('../../YouleNexus/assets/framework/config/remote-config.ts');
const error = new ConfigParseError('invalid JSON');
const fetcher = { async fetch() { throw error; } };
await assert.rejects(resolveRuntimeConfig({ mode: 'debug', hostKind: 'h5', win: {}, search: '?profile=local', fetcher }),
actual => actual === error);
});
test('local consumes explicit loopback targets after valid remote JSON even when remote candidates are absent', async () => {
const raw = { visitor_server_tcp: 'unused.example:1234', notice: 'kept' };
const fetcher = returning(raw);
const result = await resolveRuntimeConfig({ mode: 'debug', hostKind: 'h5', win: {}, search: '?profile=local', fetcher });
assert.equal(fetcher.calls.length, 1);
assert.deepEqual(result.servers, ['ws://127.0.0.1:3088']);
assert.strictEqual(result.rawConfig, raw);
assert.equal(result.remoteConfig.getValue('notice'), 'kept');
});
test('remote profiles reject missing game/player addresses without selecting visitor', async () => {
for (const mode of ['debug', 'release'] as const) {
const fetcher = returning({ visitor_server_tcp: 'unused.example:1234' });
await assert.rejects(resolveRuntimeConfig({ mode, hostKind: 'h5', win: {}, search: '', fetcher }), /game_server_tcp\/player_server_tcp/);
assert.equal(fetcher.calls.length, 1);
}
});