fix(server): config defaults (#11879)

This commit is contained in:
forehalo 2025-04-22 04:26:28 +00:00
parent a1e338efc1
commit f918573ba8
No known key found for this signature in database
GPG Key ID: 56709255DC7EC728
6 changed files with 46 additions and 9 deletions

View File

@ -507,8 +507,7 @@
"properties": {
"name": {
"type": "string",
"description": "A recognizable name for the server. Will be shown when connected with AFFiNE Desktop.\n@default \"AFFiNE Cloud\"",
"default": "AFFiNE Cloud"
"description": "A recognizable name for the server. Will be shown when connected with AFFiNE Desktop.\n@default undefined"
},
"externalUrl": {
"type": "string",
@ -532,7 +531,7 @@
},
"path": {
"type": "string",
"description": "Subpath where the server get deployed if there is.\n@default \"\"\n@environment `AFFINE_SERVER_SUB_PATH`",
"description": "Subpath where the server get deployed if there is one.(e.g. /affine)\n@default \"\"\n@environment `AFFINE_SERVER_SUB_PATH`",
"default": ""
}
}

View File

@ -185,3 +185,28 @@ test('should clone from original config without modifications', t => {
t.not(newConfig.auth.allowSignup, config.auth.allowSignup);
});
test('should override with undefined fields', async t => {
await using module = await createModule({
imports: [ConfigModule],
});
const config = module.get(Config);
const configFactory = module.get(ConfigFactory);
configFactory.override({
copilot: {
providers: {
// @ts-expect-error undefined field
unknown: {
apiKey: '123',
},
},
},
});
// @ts-expect-error undefined field
t.deepEqual(config.copilot.providers.unknown, {
apiKey: '123',
});
});

View File

@ -7,7 +7,7 @@ export const OVERRIDE_CONFIG_TOKEN = Symbol('OVERRIDE_CONFIG_TOKEN');
@Injectable()
export class ConfigFactory {
#original: AppConfig;
readonly #original: AppConfig;
readonly #config: AppConfig;
get config() {
return this.#config;
@ -18,8 +18,8 @@ export class ConfigFactory {
@Optional()
private readonly overrides: DeepPartial<AppConfig> = {}
) {
this.#config = this.loadDefault();
this.#original = structuredClone(this.#config);
this.#original = this.loadDefault();
this.#config = structuredClone(this.#original);
}
clone() {
@ -28,8 +28,8 @@ export class ConfigFactory {
}
override(updates: DeepPartial<AppConfig>) {
override(this.#original, updates);
override(this.#config, updates);
this.#original = structuredClone(this.#config);
}
validate(updates: Array<{ module: string; key: string; value: any }>) {

View File

@ -57,6 +57,10 @@ function typeFromShape(shape: z.ZodType<any>): ConfigType {
return 'array';
case z.ZodObject:
return 'object';
case z.ZodOptional:
case z.ZodNullable:
// @ts-expect-error checked
return typeFromShape(shape.unwrap());
default:
return 'any';
}
@ -251,6 +255,14 @@ export function override(config: AppConfig, update: DeepPartial<AppConfig>) {
return right;
}
// EDGE CASE:
// the right value is primitive and we're still not finding the key in descriptors,
// which means the overrides has keys not defined
// that's where we should return
if (typeof right !== 'object') {
return left;
}
// go deeper
return mergeWith(left, right, (left, right, key) => {
return merge(left, right, path === '' ? key : `${path}.${key}`);

View File

@ -23,7 +23,8 @@ declare global {
defineModuleConfig('server', {
name: {
desc: 'A recognizable name for the server. Will be shown when connected with AFFiNE Desktop.',
default: '',
default: undefined,
shape: z.string().optional(),
},
externalUrl: {
desc: `Base url of AFFiNE server, used for generating external urls.

View File

@ -174,7 +174,7 @@
},
"path": {
"type": "String",
"desc": "Subpath where the server get deployed if there is.",
"desc": "Subpath where the server get deployed if there is one.(e.g. /affine)",
"env": "AFFINE_SERVER_SUB_PATH"
}
},