fix: render HWPOD native Web runtime config

This commit is contained in:
pikastech
2026-07-21 09:01:06 +02:00
parent f40f6ada34
commit 896ab3763a
4 changed files with 57 additions and 45 deletions
+2 -1
View File
@@ -197,7 +197,7 @@ lanes:
bindHost: 0.0.0.0
probeHost: 127.0.0.1
port: 5174
runtimeConfig:
runtimeConfig: &hwlabV03NativeCloudWebRuntimeConfig
displayTime:
timeZone: Asia/Shanghai
locale: zh-CN
@@ -259,6 +259,7 @@ lanes:
bindHost: 0.0.0.0
probeHost: 127.0.0.1
port: 5175
runtimeConfig: *hwlabV03NativeCloudWebRuntimeConfig
accessProfile:
id: hwpod-native-l1
allowedNavIds:
@@ -69,6 +69,8 @@ test("L1 HWPOD spec registry resolves PostgreSQL authority and frozen built-ins
expect(native!.healthTimeoutMs).toBe(6000);
expect(native!.web.accessProfile).toEqual({ id: "hwpod-native-l1", allowedNavIds: ["admin.hwpodGroups"], startPath: "/hwpods/devices" });
const env = hwlabHwpodNativeDevelopmentEnvironment(native!);
expect(JSON.parse(env.HWPOD_WEB_RUNTIME_CONFIG!)).toEqual(native!.web.runtimeConfig);
expect(native!.web.runtimeConfig).toEqual(hwlabRuntimeLaneSpecForNode("v03", "NC01").nativeDevelopment!.workbench.web.runtimeConfig);
expect(JSON.parse(env.HWPOD_WEB_ACCESS_PROFILE_JSON!)).toEqual(native!.web.accessProfile);
expect(native!.specRegistry.builtInConfigRefs).toHaveLength(1);
const resolved = resolveConfigRef(native!.specRegistry.builtInConfigRefs[0], "HWPOD built-in spec");
+1
View File
@@ -342,6 +342,7 @@ export function hwlabHwpodNativeDevelopmentEnvironment(native: NonNullable<Hwlab
HWPOD_WEB_BIND_HOST: native.web.bindHost,
HWPOD_WEB_PROBE_HOST: native.web.probeHost,
HWPOD_WEB_PORT: String(native.web.port),
HWPOD_WEB_RUNTIME_CONFIG: JSON.stringify(native.web.runtimeConfig),
HWPOD_WEB_ACCESS_PROFILE_JSON: JSON.stringify(native.web.accessProfile),
HWPOD_NATIVE_API_URL: `http://${native.api.probeHost}:${native.api.port}`,
};
+52 -44
View File
@@ -687,6 +687,18 @@ export interface HwlabRuntimeSourceWorkspaceHostDependenciesSpec {
};
}
export interface HwlabRuntimeNativeCloudWebRuntimeConfigSpec {
readonly displayTime: { readonly timeZone: string; readonly locale: string; readonly label: string };
readonly workbench: {
readonly realtimeFeatures: { readonly liveKafkaSse: boolean; readonly kafkaRefreshReplay: boolean; readonly projectionRealtime: boolean };
readonly debugCapabilities: {
readonly isolatedKafka: boolean;
readonly rawHwlabEventWindow: { readonly enabled: boolean; readonly maxEntries: number; readonly maxRetainedBytes: number };
};
readonly traceTimeline: { readonly autoExpandRunning: boolean; readonly autoCollapseTerminal: boolean };
};
}
export interface HwlabRuntimeNativeDevelopmentSpec {
readonly tasktree?: {
readonly publicExposure: HwlabRuntimeNativePublicExposureSpec;
@@ -745,17 +757,7 @@ export interface HwlabRuntimeNativeDevelopmentSpec {
readonly bindHost: string;
readonly probeHost: string;
readonly port: number;
readonly runtimeConfig: {
readonly displayTime: { readonly timeZone: string; readonly locale: string; readonly label: string };
readonly workbench: {
readonly realtimeFeatures: { readonly liveKafkaSse: boolean; readonly kafkaRefreshReplay: boolean; readonly projectionRealtime: boolean };
readonly debugCapabilities: {
readonly isolatedKafka: boolean;
readonly rawHwlabEventWindow: { readonly enabled: boolean; readonly maxEntries: number; readonly maxRetainedBytes: number };
};
readonly traceTimeline: { readonly autoExpandRunning: boolean; readonly autoCollapseTerminal: boolean };
};
};
readonly runtimeConfig: HwlabRuntimeNativeCloudWebRuntimeConfigSpec;
};
};
readonly hwpod?: {
@@ -791,6 +793,7 @@ export interface HwlabRuntimeNativeDevelopmentSpec {
readonly bindHost: string;
readonly probeHost: string;
readonly port: number;
readonly runtimeConfig: HwlabRuntimeNativeCloudWebRuntimeConfigSpec;
readonly accessProfile: { readonly id: string; readonly allowedNavIds: readonly string[]; readonly startPath: string };
};
};
@@ -1631,17 +1634,10 @@ function nativeDevelopmentConfig(value: unknown, path: string): HwlabRuntimeNati
const api = asRecord(workbench.api, `${path}.workbench.api`);
const worker = asRecord(workbench.worker, `${path}.workbench.worker`);
const web = asRecord(workbench.web, `${path}.workbench.web`);
const runtimeConfig = asRecord(web.runtimeConfig, `${path}.workbench.web.runtimeConfig`);
const displayTime = asRecord(runtimeConfig.displayTime, `${path}.workbench.web.runtimeConfig.displayTime`);
const workbenchRuntime = asRecord(runtimeConfig.workbench, `${path}.workbench.web.runtimeConfig.workbench`);
const realtimeFeatures = asRecord(workbenchRuntime.realtimeFeatures, `${path}.workbench.web.runtimeConfig.workbench.realtimeFeatures`);
const refreshReplay = asRecord(kafka.refreshReplay, `${path}.workbench.kafka.refreshReplay`);
const sessionIndex = refreshReplay.sessionIndex === undefined
? undefined
: asRecord(refreshReplay.sessionIndex, `${path}.workbench.kafka.refreshReplay.sessionIndex`);
const debugCapabilities = asRecord(workbenchRuntime.debugCapabilities, `${path}.workbench.web.runtimeConfig.workbench.debugCapabilities`);
const rawHwlabEventWindow = asRecord(debugCapabilities.rawHwlabEventWindow, `${path}.workbench.web.runtimeConfig.workbench.debugCapabilities.rawHwlabEventWindow`);
const traceTimeline = asRecord(workbenchRuntime.traceTimeline, `${path}.workbench.web.runtimeConfig.workbench.traceTimeline`);
return {
...(raw.tasktree === undefined ? {} : { tasktree: nativeTaskTreeConfig(raw.tasktree, `${path}.tasktree`) }),
workbench: {
@@ -1694,32 +1690,7 @@ function nativeDevelopmentConfig(value: unknown, path: string): HwlabRuntimeNati
bindHost: stringField(web, "bindHost", `${path}.workbench.web`),
probeHost: stringField(web, "probeHost", `${path}.workbench.web`),
port: numberField(web, "port", `${path}.workbench.web`),
runtimeConfig: {
displayTime: {
timeZone: stringField(displayTime, "timeZone", `${path}.workbench.web.runtimeConfig.displayTime`),
locale: stringField(displayTime, "locale", `${path}.workbench.web.runtimeConfig.displayTime`),
label: stringField(displayTime, "label", `${path}.workbench.web.runtimeConfig.displayTime`),
},
workbench: {
realtimeFeatures: {
liveKafkaSse: booleanField(realtimeFeatures, "liveKafkaSse", `${path}.workbench.web.runtimeConfig.workbench.realtimeFeatures`),
kafkaRefreshReplay: booleanField(realtimeFeatures, "kafkaRefreshReplay", `${path}.workbench.web.runtimeConfig.workbench.realtimeFeatures`),
projectionRealtime: booleanField(realtimeFeatures, "projectionRealtime", `${path}.workbench.web.runtimeConfig.workbench.realtimeFeatures`),
},
debugCapabilities: {
isolatedKafka: booleanField(debugCapabilities, "isolatedKafka", `${path}.workbench.web.runtimeConfig.workbench.debugCapabilities`),
rawHwlabEventWindow: {
enabled: booleanField(rawHwlabEventWindow, "enabled", `${path}.workbench.web.runtimeConfig.workbench.debugCapabilities.rawHwlabEventWindow`),
maxEntries: numberField(rawHwlabEventWindow, "maxEntries", `${path}.workbench.web.runtimeConfig.workbench.debugCapabilities.rawHwlabEventWindow`),
maxRetainedBytes: numberField(rawHwlabEventWindow, "maxRetainedBytes", `${path}.workbench.web.runtimeConfig.workbench.debugCapabilities.rawHwlabEventWindow`),
},
},
traceTimeline: {
autoExpandRunning: booleanField(traceTimeline, "autoExpandRunning", `${path}.workbench.web.runtimeConfig.workbench.traceTimeline`),
autoCollapseTerminal: booleanField(traceTimeline, "autoCollapseTerminal", `${path}.workbench.web.runtimeConfig.workbench.traceTimeline`),
},
},
},
runtimeConfig: nativeCloudWebRuntimeConfig(web.runtimeConfig, `${path}.workbench.web.runtimeConfig`),
},
},
...(raw.hwpod === undefined ? {} : { hwpod: nativeHwpodConfig(raw.hwpod, `${path}.hwpod`) }),
@@ -1778,6 +1749,7 @@ function nativeHwpodConfig(value: unknown, path: string): NonNullable<HwlabRunti
bindHost: stringField(web, "bindHost", `${path}.web`),
probeHost: stringField(web, "probeHost", `${path}.web`),
port: numberField(web, "port", `${path}.web`),
runtimeConfig: nativeCloudWebRuntimeConfig(web.runtimeConfig, `${path}.web.runtimeConfig`),
accessProfile: {
id: stringField(accessProfile, "id", `${path}.web.accessProfile`),
allowedNavIds,
@@ -1787,6 +1759,42 @@ function nativeHwpodConfig(value: unknown, path: string): NonNullable<HwlabRunti
};
}
function nativeCloudWebRuntimeConfig(value: unknown, path: string): HwlabRuntimeNativeCloudWebRuntimeConfigSpec {
const runtimeConfig = asRecord(value, path);
const displayTime = asRecord(runtimeConfig.displayTime, `${path}.displayTime`);
const workbench = asRecord(runtimeConfig.workbench, `${path}.workbench`);
const realtimeFeatures = asRecord(workbench.realtimeFeatures, `${path}.workbench.realtimeFeatures`);
const debugCapabilities = asRecord(workbench.debugCapabilities, `${path}.workbench.debugCapabilities`);
const rawHwlabEventWindow = asRecord(debugCapabilities.rawHwlabEventWindow, `${path}.workbench.debugCapabilities.rawHwlabEventWindow`);
const traceTimeline = asRecord(workbench.traceTimeline, `${path}.workbench.traceTimeline`);
return {
displayTime: {
timeZone: stringField(displayTime, "timeZone", `${path}.displayTime`),
locale: stringField(displayTime, "locale", `${path}.displayTime`),
label: stringField(displayTime, "label", `${path}.displayTime`),
},
workbench: {
realtimeFeatures: {
liveKafkaSse: booleanField(realtimeFeatures, "liveKafkaSse", `${path}.workbench.realtimeFeatures`),
kafkaRefreshReplay: booleanField(realtimeFeatures, "kafkaRefreshReplay", `${path}.workbench.realtimeFeatures`),
projectionRealtime: booleanField(realtimeFeatures, "projectionRealtime", `${path}.workbench.realtimeFeatures`),
},
debugCapabilities: {
isolatedKafka: booleanField(debugCapabilities, "isolatedKafka", `${path}.workbench.debugCapabilities`),
rawHwlabEventWindow: {
enabled: booleanField(rawHwlabEventWindow, "enabled", `${path}.workbench.debugCapabilities.rawHwlabEventWindow`),
maxEntries: numberField(rawHwlabEventWindow, "maxEntries", `${path}.workbench.debugCapabilities.rawHwlabEventWindow`),
maxRetainedBytes: numberField(rawHwlabEventWindow, "maxRetainedBytes", `${path}.workbench.debugCapabilities.rawHwlabEventWindow`),
},
},
traceTimeline: {
autoExpandRunning: booleanField(traceTimeline, "autoExpandRunning", `${path}.workbench.traceTimeline`),
autoCollapseTerminal: booleanField(traceTimeline, "autoCollapseTerminal", `${path}.workbench.traceTimeline`),
},
},
};
}
function nativeTaskTreeConfig(value: unknown, path: string): NonNullable<HwlabRuntimeNativeDevelopmentSpec["tasktree"]> {
const raw = asRecord(value, path);
const api = asRecord(raw.api, `${path}.api`);