Files
multica/packages/core/config/index.ts
Marcelo Cecin 7985699df9 feat(help): surface the running server version in the Help popover (#4959)
Surface the running server build version in the Help popover so self-hosted
operators can confirm what's deployed and include it in bug reports.

- Backend exposes it via /api/config's server_version (from main.version),
  omitempty so older/unstamped builds omit the field.
- Unstamped "dev" builds are normalized to empty and the row stays hidden.
- The row is suppressed on the managed cloud (frontend host multica.ai) and
  shown only on self-hosted deployments.
- Frontend renders a muted footer row in the Help popover only when the value
  is non-empty; i18n added for en/ja/ko/zh-Hans.
2026-07-14 20:11:52 +08:00

75 lines
2.7 KiB
TypeScript

import { createStore } from "zustand/vanilla";
import { useStore } from "zustand";
interface ConfigState {
cdnDomain: string;
// True when cdnDomain serves private content via time-bounded signed URLs
// (CloudFront signing enabled server-side). Renderers must not treat a raw
// storage URL on that domain as a loadable media source (MUL-3254).
cdnSigned: boolean;
allowSignup: boolean;
googleClientId: string;
daemonServerUrl: string;
daemonAppUrl: string;
// Self-host gate (#3433): when true, every "Create workspace" affordance
// must be hidden. Defaults to false so unknown / older servers behave like
// the managed-cloud case.
workspaceCreationDisabled: boolean;
featureFlags: Record<string, boolean>;
// The running API build version, surfaced in the Help popover so
// self-hosted operators can confirm what's deployed. Empty for dev builds
// or servers older than this feature.
serverVersion: string;
setCdnConfig: (config: { cdnDomain: string; cdnSigned?: boolean }) => void;
setAuthConfig: (config: {
allowSignup: boolean;
googleClientId?: string;
workspaceCreationDisabled?: boolean;
}) => void;
setDaemonConfig: (config: {
daemonServerUrl?: string;
daemonAppUrl?: string;
}) => void;
setFeatureFlags: (flags?: Record<string, boolean>) => void;
setServerVersion: (version?: string) => void;
}
export const configStore = createStore<ConfigState>((set) => ({
cdnDomain: "",
cdnSigned: false,
allowSignup: true,
googleClientId: "",
daemonServerUrl: "",
daemonAppUrl: "",
workspaceCreationDisabled: false,
featureFlags: {},
serverVersion: "",
setCdnConfig: ({ cdnDomain, cdnSigned = false }) => set({ cdnDomain, cdnSigned }),
setAuthConfig: ({ allowSignup, googleClientId = "", workspaceCreationDisabled = false }) =>
set({ allowSignup, googleClientId, workspaceCreationDisabled }),
setDaemonConfig: ({ daemonServerUrl = "", daemonAppUrl = "" }) =>
set({ daemonServerUrl, daemonAppUrl }),
setFeatureFlags: (flags = {}) => set({ featureFlags: { ...flags } }),
setServerVersion: (version = "") => set({ serverVersion: version }),
}));
export function useConfigStore(): ConfigState;
export function useConfigStore<T>(selector: (state: ConfigState) => T): T;
export function useConfigStore<T>(selector?: (state: ConfigState) => T) {
return useStore(configStore, selector as (state: ConfigState) => T);
}
export function featureFlagEnabled(
flags: Readonly<Record<string, boolean>> | undefined,
key: string,
defaultValue = false,
): boolean {
return flags?.[key] ?? defaultValue;
}
export function useFeatureEnabled(key: string, defaultValue = false): boolean {
return useConfigStore((state) =>
featureFlagEnabled(state.featureFlags, key, defaultValue),
);
}