From f75fad7b7a7fd92cf3877594e8842c4ecce39f0f Mon Sep 17 00:00:00 2001 From: Lucas Coratger <73360179+coratgerl@users.noreply.github.com> Date: Sat, 6 Dec 2025 09:23:18 +0100 Subject: [PATCH 1/7] feat: Add option to change log levels of username already exists message --- resources/buildConfigDefinitions.js | 2 ++ spec/ParseUser.spec.js | 53 +++++++++++++++++++++++++++++ src/Config.js | 16 +++++++++ src/Options/Definitions.js | 15 ++++++++ src/Options/docs.js | 6 ++++ src/Options/index.js | 10 ++++++ src/middlewares.js | 13 ++++++- types/Options/index.d.ts | 4 +++ 8 files changed, 118 insertions(+), 1 deletion(-) diff --git a/resources/buildConfigDefinitions.js b/resources/buildConfigDefinitions.js index 0b7dcdac3d..2733016fba 100644 --- a/resources/buildConfigDefinitions.js +++ b/resources/buildConfigDefinitions.js @@ -25,6 +25,7 @@ const nestedOptionTypes = [ 'SecurityOptions', 'SchemaOptions', 'LogLevels', + 'LogEvents', ]; /** The prefix of environment variables for nested options. */ @@ -39,6 +40,7 @@ const nestedOptionEnvPrefix = { LogClientEvent: 'PARSE_SERVER_DATABASE_LOG_CLIENT_EVENTS_', LogLevel: 'PARSE_SERVER_LOG_LEVEL_', LogLevels: 'PARSE_SERVER_LOG_LEVELS_', + LogEvents: 'PARSE_SERVER_LOG_EVENTS_', PagesCustomUrlsOptions: 'PARSE_SERVER_PAGES_CUSTOM_URL_', PagesOptions: 'PARSE_SERVER_PAGES_', PagesRoute: 'PARSE_SERVER_PAGES_ROUTE_', diff --git a/spec/ParseUser.spec.js b/spec/ParseUser.spec.js index 0380589057..a3743f75d8 100644 --- a/spec/ParseUser.spec.js +++ b/spec/ParseUser.spec.js @@ -81,6 +81,59 @@ describe('Parse.User testing', () => { } }); + it('logs username taken with configured log level', async () => { + await reconfigureServer({ logEvents: { usernameAlreadyExists: 'warn' } }); + const logger = require('../lib/logger').default; + loggerErrorSpy = spyOn(logger, 'error').and.callThrough(); + const loggerWarnSpy = spyOn(logger, 'warn').and.callThrough(); + + const user = new Parse.User(); + user.setUsername('dupUser'); + user.setPassword('pass'); + await user.signUp(); + + const user2 = new Parse.User(); + user2.setUsername('dupUser'); + user2.setPassword('pass2'); + + expect(loggerWarnSpy).not.toHaveBeenCalled(); + + try { + await user2.signUp(); + fail('should have thrown'); + } catch (e) { + expect(e.code).toBe(Parse.Error.USERNAME_TAKEN); + } + + expect(loggerWarnSpy).toHaveBeenCalledTimes(1); + expect(loggerErrorSpy.calls.count()).toBe(0); + }); + + it('can silence username taken log event', async () => { + await reconfigureServer({ logEvents: { usernameAlreadyExists: 'silent' } }); + const logger = require('../lib/logger').default; + loggerErrorSpy = spyOn(logger, 'error').and.callThrough(); + const loggerWarnSpy = spyOn(logger, 'warn').and.callThrough(); + + const user = new Parse.User(); + user.setUsername('dupUser'); + user.setPassword('pass'); + await user.signUp(); + + const user2 = new Parse.User(); + user2.setUsername('dupUser'); + user2.setPassword('pass2'); + try { + await user2.signUp(); + fail('should have thrown'); + } catch (e) { + expect(e.code).toBe(Parse.Error.USERNAME_TAKEN); + } + + expect(loggerWarnSpy).not.toHaveBeenCalled(); + expect(loggerErrorSpy.calls.count()).toBe(0); + }); + it('user login with context', async () => { let hit = 0; const context = { foo: 'bar' }; diff --git a/src/Config.js b/src/Config.js index 241edf9771..9e982a3b82 100644 --- a/src/Config.js +++ b/src/Config.js @@ -14,6 +14,7 @@ import { FileUploadOptions, IdempotencyOptions, LogLevels, + LogEvents, PagesOptions, ParseServerOptions, SchemaOptions, @@ -128,6 +129,7 @@ export class Config { requestKeywordDenylist, allowExpiredAuthDataToken, logLevels, + logEvents, rateLimit, databaseOptions, extendSessionOnUse, @@ -170,6 +172,7 @@ export class Config { this.validateRequestKeywordDenylist(requestKeywordDenylist); this.validateRateLimit(rateLimit); this.validateLogLevels(logLevels); + this.validateLogEvents(logEvents); this.validateDatabaseOptions(databaseOptions); this.validateCustomPages(customPages); this.validateAllowClientClassCreation(allowClientClassCreation); @@ -641,6 +644,19 @@ export class Config { } } + static validateLogEvents(logEvents) { + for (const key of Object.keys(LogEvents)) { + if (logEvents[key]) { + // We validate that each configured event uses a valid log *level* (same list as logLevels). + if (validLogLevels.indexOf(logEvents[key]) === -1) { + throw `'${key}' must be one of ${JSON.stringify(validLogLevels)}`; + } + } else { + logEvents[key] = LogEvents[key].default; + } + } + } + static validateDatabaseOptions(databaseOptions) { if (databaseOptions == undefined) { return; diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 66c1d8bcea..0aa2962b95 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -352,6 +352,13 @@ module.exports.ParseServerOptions = { action: parsers.objectParser, type: 'LiveQueryServerOptions', }, + logEvents: { + env: 'PARSE_SERVER_LOG_EVENTS', + help: '(Optional) Overrides the log levels used by specific log events.', + action: parsers.objectParser, + type: 'LogEvents', + default: {}, + }, loggerAdapter: { env: 'PARSE_SERVER_LOGGER_ADAPTER', help: 'Adapter module for the logging sub-system', @@ -1507,3 +1514,11 @@ module.exports.LogLevels = { default: 'info', }, }; +module.exports.LogEvents = { + usernameAlreadyExists: { + env: 'PARSE_SERVER_LOG_EVENTS_USERNAME_ALREADY_EXISTS', + help: + 'Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values.', + default: 'error', + }, +}; diff --git a/src/Options/docs.js b/src/Options/docs.js index 9569239ef7..5283309ae3 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -63,6 +63,7 @@ * @property {Boolean} jsonLogs Log as structured JSON objects * @property {LiveQueryOptions} liveQuery parse-server's LiveQuery configuration object * @property {LiveQueryServerOptions} liveQueryServerOptions Live query server configuration options (will start the liveQuery server) + * @property {LogEvents} logEvents (Optional) Overrides the log levels used by specific log events. * @property {Adapter} loggerAdapter Adapter module for the logging sub-system * @property {String} logLevel Sets the level for logs * @property {LogLevels} logLevels (Optional) Overrides the log levels used internally by Parse Server to log events. @@ -329,3 +330,8 @@ * @property {String} triggerBeforeError Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on error. Default is `error`. See [LogLevel](LogLevel.html) for available values. * @property {String} triggerBeforeSuccess Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. See [LogLevel](LogLevel.html) for available values. */ + +/** + * @interface LogEvents + * @property {String} usernameAlreadyExists Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values. + */ diff --git a/src/Options/index.js b/src/Options/index.js index cdeb7cd846..4f33ad98a6 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -98,6 +98,9 @@ export interface ParseServerOptions { /* (Optional) Overrides the log levels used internally by Parse Server to log events. :DEFAULT: {} */ logLevels: ?LogLevels; + /* (Optional) Overrides the log levels used by specific log events. + :DEFAULT: {} */ + logEvents: ?LogEvents; /* Maximum number of logs to keep. If not set, no logs will be removed. This can be a number of files or number of days. If using days, add 'd' as the suffix. (default: null) */ maxLogFiles: ?NumberOrString; /* Disables console output @@ -790,3 +793,10 @@ export interface LogLevels { */ cloudFunctionError: ?string; } + +export interface LogEvents { + /* Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values. + :DEFAULT: error + */ + usernameAlreadyExists: ?string; +} diff --git a/src/middlewares.js b/src/middlewares.js index 2fedce8f08..12c8ba979b 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -466,6 +466,7 @@ export function handleParseErrors(err, req, res, next) { if (req.config && req.config.enableExpressErrorHandler) { return next(err); } + const usernameAlreadyExistsLevel = req.config?.logEvents?.usernameAlreadyExists || 'error'; let httpStatus; // TODO: fill out this mapping switch (err.code) { @@ -480,7 +481,17 @@ export function handleParseErrors(err, req, res, next) { } res.status(httpStatus); res.json({ code: err.code, error: err.message }); - log.error('Parse error: ', err); + if (err.code === Parse.Error.USERNAME_TAKEN) { + if (usernameAlreadyExistsLevel !== 'silent') { + const loggerMethod = + typeof log[usernameAlreadyExistsLevel] === 'function' + ? log[usernameAlreadyExistsLevel].bind(log) + : log.error.bind(log); + loggerMethod('Parse error: ', err); + } + } else { + log.error('Parse error: ', err); + } } else if (err.status && err.message) { res.status(err.status); res.json({ error: err.message }); diff --git a/types/Options/index.d.ts b/types/Options/index.d.ts index ad11050648..cc17583c4d 100644 --- a/types/Options/index.d.ts +++ b/types/Options/index.d.ts @@ -47,6 +47,7 @@ export interface ParseServerOptions { verbose?: boolean; logLevel?: string; logLevels?: LogLevels; + logEvents?: LogEvents; maxLogFiles?: NumberOrString; silent?: boolean; databaseURI: string; @@ -298,4 +299,7 @@ export interface LogLevels { cloudFunctionSuccess?: string; cloudFunctionError?: string; } +export interface LogEvents { + usernameAlreadyExists?: string; +} export {}; From cd24f6db690dbe222204827ea0db7ade4dc9843f Mon Sep 17 00:00:00 2001 From: Lucas Coratger <73360179+coratgerl@users.noreply.github.com> Date: Mon, 8 Dec 2025 08:27:52 +0100 Subject: [PATCH 2/7] fix: feedbacks --- resources/buildConfigDefinitions.js | 1 - src/Config.js | 5 ++--- src/Options/Definitions.js | 6 ++---- src/Options/docs.js | 6 +----- src/Options/index.js | 5 +---- src/middlewares.js | 3 ++- types/Options/index.d.ts | 4 +--- 7 files changed, 9 insertions(+), 21 deletions(-) diff --git a/resources/buildConfigDefinitions.js b/resources/buildConfigDefinitions.js index 2733016fba..2814394735 100644 --- a/resources/buildConfigDefinitions.js +++ b/resources/buildConfigDefinitions.js @@ -40,7 +40,6 @@ const nestedOptionEnvPrefix = { LogClientEvent: 'PARSE_SERVER_DATABASE_LOG_CLIENT_EVENTS_', LogLevel: 'PARSE_SERVER_LOG_LEVEL_', LogLevels: 'PARSE_SERVER_LOG_LEVELS_', - LogEvents: 'PARSE_SERVER_LOG_EVENTS_', PagesCustomUrlsOptions: 'PARSE_SERVER_PAGES_CUSTOM_URL_', PagesOptions: 'PARSE_SERVER_PAGES_', PagesRoute: 'PARSE_SERVER_PAGES_ROUTE_', diff --git a/src/Config.js b/src/Config.js index 9e982a3b82..3e218c6e19 100644 --- a/src/Config.js +++ b/src/Config.js @@ -14,7 +14,6 @@ import { FileUploadOptions, IdempotencyOptions, LogLevels, - LogEvents, PagesOptions, ParseServerOptions, SchemaOptions, @@ -645,14 +644,14 @@ export class Config { } static validateLogEvents(logEvents) { - for (const key of Object.keys(LogEvents)) { + for (const key of Object.keys(LogLevels)) { if (logEvents[key]) { // We validate that each configured event uses a valid log *level* (same list as logLevels). if (validLogLevels.indexOf(logEvents[key]) === -1) { throw `'${key}' must be one of ${JSON.stringify(validLogLevels)}`; } } else { - logEvents[key] = LogEvents[key].default; + logEvents[key] = LogLevels[key].default; } } } diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 0aa2962b95..3d0a7d2085 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -356,7 +356,7 @@ module.exports.ParseServerOptions = { env: 'PARSE_SERVER_LOG_EVENTS', help: '(Optional) Overrides the log levels used by specific log events.', action: parsers.objectParser, - type: 'LogEvents', + type: 'LogLevels', default: {}, }, loggerAdapter: { @@ -1513,10 +1513,8 @@ module.exports.LogLevels = { 'Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. See [LogLevel](LogLevel.html) for available values.', default: 'info', }, -}; -module.exports.LogEvents = { usernameAlreadyExists: { - env: 'PARSE_SERVER_LOG_EVENTS_USERNAME_ALREADY_EXISTS', + env: 'PARSE_SERVER_LOG_LEVELS_USERNAME_ALREADY_EXISTS', help: 'Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values.', default: 'error', diff --git a/src/Options/docs.js b/src/Options/docs.js index 5283309ae3..ac9abc603d 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -63,7 +63,7 @@ * @property {Boolean} jsonLogs Log as structured JSON objects * @property {LiveQueryOptions} liveQuery parse-server's LiveQuery configuration object * @property {LiveQueryServerOptions} liveQueryServerOptions Live query server configuration options (will start the liveQuery server) - * @property {LogEvents} logEvents (Optional) Overrides the log levels used by specific log events. + * @property {LogLevels} logEvents (Optional) Overrides the log levels used by specific log events. * @property {Adapter} loggerAdapter Adapter module for the logging sub-system * @property {String} logLevel Sets the level for logs * @property {LogLevels} logLevels (Optional) Overrides the log levels used internally by Parse Server to log events. @@ -329,9 +329,5 @@ * @property {String} triggerAfter Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterFind`, `afterLogout`. Default is `info`. See [LogLevel](LogLevel.html) for available values. * @property {String} triggerBeforeError Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on error. Default is `error`. See [LogLevel](LogLevel.html) for available values. * @property {String} triggerBeforeSuccess Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. See [LogLevel](LogLevel.html) for available values. - */ - -/** - * @interface LogEvents * @property {String} usernameAlreadyExists Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values. */ diff --git a/src/Options/index.js b/src/Options/index.js index 4f33ad98a6..f442c6b643 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -100,7 +100,7 @@ export interface ParseServerOptions { logLevels: ?LogLevels; /* (Optional) Overrides the log levels used by specific log events. :DEFAULT: {} */ - logEvents: ?LogEvents; + logEvents: ?LogLevels; /* Maximum number of logs to keep. If not set, no logs will be removed. This can be a number of files or number of days. If using days, add 'd' as the suffix. (default: null) */ maxLogFiles: ?NumberOrString; /* Disables console output @@ -792,9 +792,6 @@ export interface LogLevels { :DEFAULT: error */ cloudFunctionError: ?string; -} - -export interface LogEvents { /* Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values. :DEFAULT: error */ diff --git a/src/middlewares.js b/src/middlewares.js index 12c8ba979b..edcf96bca6 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -466,7 +466,8 @@ export function handleParseErrors(err, req, res, next) { if (req.config && req.config.enableExpressErrorHandler) { return next(err); } - const usernameAlreadyExistsLevel = req.config?.logEvents?.usernameAlreadyExists || 'error'; + const usernameAlreadyExistsLevel = + req.config?.logEvents?.usernameAlreadyExists || 'info'; let httpStatus; // TODO: fill out this mapping switch (err.code) { diff --git a/types/Options/index.d.ts b/types/Options/index.d.ts index cc17583c4d..e6618e65bf 100644 --- a/types/Options/index.d.ts +++ b/types/Options/index.d.ts @@ -47,7 +47,7 @@ export interface ParseServerOptions { verbose?: boolean; logLevel?: string; logLevels?: LogLevels; - logEvents?: LogEvents; + logEvents?: LogLevels; maxLogFiles?: NumberOrString; silent?: boolean; databaseURI: string; @@ -298,8 +298,6 @@ export interface LogLevels { triggerBeforeError?: string; cloudFunctionSuccess?: string; cloudFunctionError?: string; -} -export interface LogEvents { usernameAlreadyExists?: string; } export {}; From 4526b0a3e700381e90f4b7ad2ab999a7e103ad43 Mon Sep 17 00:00:00 2001 From: Lucas Coratger <73360179+coratgerl@users.noreply.github.com> Date: Mon, 8 Dec 2025 08:28:56 +0100 Subject: [PATCH 3/7] fix: remove log events --- resources/buildConfigDefinitions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/buildConfigDefinitions.js b/resources/buildConfigDefinitions.js index 2814394735..0b7dcdac3d 100644 --- a/resources/buildConfigDefinitions.js +++ b/resources/buildConfigDefinitions.js @@ -25,7 +25,6 @@ const nestedOptionTypes = [ 'SecurityOptions', 'SchemaOptions', 'LogLevels', - 'LogEvents', ]; /** The prefix of environment variables for nested options. */ From 5087a15284e5284d31a57c0403d4600bf7073864 Mon Sep 17 00:00:00 2001 From: Lucas Coratger <73360179+coratgerl@users.noreply.github.com> Date: Tue, 9 Dec 2025 08:12:57 +0100 Subject: [PATCH 4/7] fix: feedbacks --- spec/ParseUser.spec.js | 4 ++-- src/Config.js | 15 --------------- src/Options/Definitions.js | 7 ------- src/Options/docs.js | 1 - src/Options/index.js | 3 --- src/middlewares.js | 2 +- types/Options/index.d.ts | 1 - 7 files changed, 3 insertions(+), 30 deletions(-) diff --git a/spec/ParseUser.spec.js b/spec/ParseUser.spec.js index a3743f75d8..48c457cf32 100644 --- a/spec/ParseUser.spec.js +++ b/spec/ParseUser.spec.js @@ -82,7 +82,7 @@ describe('Parse.User testing', () => { }); it('logs username taken with configured log level', async () => { - await reconfigureServer({ logEvents: { usernameAlreadyExists: 'warn' } }); + await reconfigureServer({ logLevels: { usernameAlreadyExists: 'warn' } }); const logger = require('../lib/logger').default; loggerErrorSpy = spyOn(logger, 'error').and.callThrough(); const loggerWarnSpy = spyOn(logger, 'warn').and.callThrough(); @@ -110,7 +110,7 @@ describe('Parse.User testing', () => { }); it('can silence username taken log event', async () => { - await reconfigureServer({ logEvents: { usernameAlreadyExists: 'silent' } }); + await reconfigureServer({ logLevels: { usernameAlreadyExists: 'silent' } }); const logger = require('../lib/logger').default; loggerErrorSpy = spyOn(logger, 'error').and.callThrough(); const loggerWarnSpy = spyOn(logger, 'warn').and.callThrough(); diff --git a/src/Config.js b/src/Config.js index 3e218c6e19..241edf9771 100644 --- a/src/Config.js +++ b/src/Config.js @@ -128,7 +128,6 @@ export class Config { requestKeywordDenylist, allowExpiredAuthDataToken, logLevels, - logEvents, rateLimit, databaseOptions, extendSessionOnUse, @@ -171,7 +170,6 @@ export class Config { this.validateRequestKeywordDenylist(requestKeywordDenylist); this.validateRateLimit(rateLimit); this.validateLogLevels(logLevels); - this.validateLogEvents(logEvents); this.validateDatabaseOptions(databaseOptions); this.validateCustomPages(customPages); this.validateAllowClientClassCreation(allowClientClassCreation); @@ -643,19 +641,6 @@ export class Config { } } - static validateLogEvents(logEvents) { - for (const key of Object.keys(LogLevels)) { - if (logEvents[key]) { - // We validate that each configured event uses a valid log *level* (same list as logLevels). - if (validLogLevels.indexOf(logEvents[key]) === -1) { - throw `'${key}' must be one of ${JSON.stringify(validLogLevels)}`; - } - } else { - logEvents[key] = LogLevels[key].default; - } - } - } - static validateDatabaseOptions(databaseOptions) { if (databaseOptions == undefined) { return; diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 3d0a7d2085..4eb3ed330c 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -352,13 +352,6 @@ module.exports.ParseServerOptions = { action: parsers.objectParser, type: 'LiveQueryServerOptions', }, - logEvents: { - env: 'PARSE_SERVER_LOG_EVENTS', - help: '(Optional) Overrides the log levels used by specific log events.', - action: parsers.objectParser, - type: 'LogLevels', - default: {}, - }, loggerAdapter: { env: 'PARSE_SERVER_LOGGER_ADAPTER', help: 'Adapter module for the logging sub-system', diff --git a/src/Options/docs.js b/src/Options/docs.js index ac9abc603d..c90772cbf0 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -63,7 +63,6 @@ * @property {Boolean} jsonLogs Log as structured JSON objects * @property {LiveQueryOptions} liveQuery parse-server's LiveQuery configuration object * @property {LiveQueryServerOptions} liveQueryServerOptions Live query server configuration options (will start the liveQuery server) - * @property {LogLevels} logEvents (Optional) Overrides the log levels used by specific log events. * @property {Adapter} loggerAdapter Adapter module for the logging sub-system * @property {String} logLevel Sets the level for logs * @property {LogLevels} logLevels (Optional) Overrides the log levels used internally by Parse Server to log events. diff --git a/src/Options/index.js b/src/Options/index.js index f442c6b643..4bbe11db59 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -98,9 +98,6 @@ export interface ParseServerOptions { /* (Optional) Overrides the log levels used internally by Parse Server to log events. :DEFAULT: {} */ logLevels: ?LogLevels; - /* (Optional) Overrides the log levels used by specific log events. - :DEFAULT: {} */ - logEvents: ?LogLevels; /* Maximum number of logs to keep. If not set, no logs will be removed. This can be a number of files or number of days. If using days, add 'd' as the suffix. (default: null) */ maxLogFiles: ?NumberOrString; /* Disables console output diff --git a/src/middlewares.js b/src/middlewares.js index edcf96bca6..b10af3c778 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -467,7 +467,7 @@ export function handleParseErrors(err, req, res, next) { return next(err); } const usernameAlreadyExistsLevel = - req.config?.logEvents?.usernameAlreadyExists || 'info'; + req.config?.logLevels?.usernameAlreadyExists || 'info'; let httpStatus; // TODO: fill out this mapping switch (err.code) { diff --git a/types/Options/index.d.ts b/types/Options/index.d.ts index e6618e65bf..c841c6b202 100644 --- a/types/Options/index.d.ts +++ b/types/Options/index.d.ts @@ -47,7 +47,6 @@ export interface ParseServerOptions { verbose?: boolean; logLevel?: string; logLevels?: LogLevels; - logEvents?: LogLevels; maxLogFiles?: NumberOrString; silent?: boolean; databaseURI: string; From b71c7d8228f01632a2319042d8e27285aef36e86 Mon Sep 17 00:00:00 2001 From: Lucas Coratger <73360179+coratgerl@users.noreply.github.com> Date: Tue, 9 Dec 2025 21:14:09 +0100 Subject: [PATCH 5/7] fix: feedbacks --- spec/ParseUser.spec.js | 4 ++-- src/Options/Definitions.js | 2 +- src/Options/docs.js | 2 +- src/Options/index.js | 2 +- src/middlewares.js | 10 +++++----- types/Options/index.d.ts | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/spec/ParseUser.spec.js b/spec/ParseUser.spec.js index 48c457cf32..aaae271332 100644 --- a/spec/ParseUser.spec.js +++ b/spec/ParseUser.spec.js @@ -82,7 +82,7 @@ describe('Parse.User testing', () => { }); it('logs username taken with configured log level', async () => { - await reconfigureServer({ logLevels: { usernameAlreadyExists: 'warn' } }); + await reconfigureServer({ logLevels: { signupUsernameTaken: 'warn' } }); const logger = require('../lib/logger').default; loggerErrorSpy = spyOn(logger, 'error').and.callThrough(); const loggerWarnSpy = spyOn(logger, 'warn').and.callThrough(); @@ -110,7 +110,7 @@ describe('Parse.User testing', () => { }); it('can silence username taken log event', async () => { - await reconfigureServer({ logLevels: { usernameAlreadyExists: 'silent' } }); + await reconfigureServer({ logLevels: { signupUsernameTaken: 'silent' } }); const logger = require('../lib/logger').default; loggerErrorSpy = spyOn(logger, 'error').and.callThrough(); const loggerWarnSpy = spyOn(logger, 'warn').and.callThrough(); diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 4eb3ed330c..47b65ff817 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -1506,7 +1506,7 @@ module.exports.LogLevels = { 'Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. See [LogLevel](LogLevel.html) for available values.', default: 'info', }, - usernameAlreadyExists: { + signupUsernameTaken: { env: 'PARSE_SERVER_LOG_LEVELS_USERNAME_ALREADY_EXISTS', help: 'Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values.', diff --git a/src/Options/docs.js b/src/Options/docs.js index c90772cbf0..51f3556c25 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -328,5 +328,5 @@ * @property {String} triggerAfter Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterFind`, `afterLogout`. Default is `info`. See [LogLevel](LogLevel.html) for available values. * @property {String} triggerBeforeError Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on error. Default is `error`. See [LogLevel](LogLevel.html) for available values. * @property {String} triggerBeforeSuccess Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. See [LogLevel](LogLevel.html) for available values. - * @property {String} usernameAlreadyExists Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values. + * @property {String} signupUsernameTaken Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values. */ diff --git a/src/Options/index.js b/src/Options/index.js index 4bbe11db59..5ee6912274 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -792,5 +792,5 @@ export interface LogLevels { /* Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values. :DEFAULT: error */ - usernameAlreadyExists: ?string; + signupUsernameTaken: ?string; } diff --git a/src/middlewares.js b/src/middlewares.js index b10af3c778..1f4d8a0013 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -466,8 +466,8 @@ export function handleParseErrors(err, req, res, next) { if (req.config && req.config.enableExpressErrorHandler) { return next(err); } - const usernameAlreadyExistsLevel = - req.config?.logLevels?.usernameAlreadyExists || 'info'; + const signupUsernameTakenLevel = + req.config?.logLevels?.signupUsernameTaken || 'info'; let httpStatus; // TODO: fill out this mapping switch (err.code) { @@ -483,10 +483,10 @@ export function handleParseErrors(err, req, res, next) { res.status(httpStatus); res.json({ code: err.code, error: err.message }); if (err.code === Parse.Error.USERNAME_TAKEN) { - if (usernameAlreadyExistsLevel !== 'silent') { + if (signupUsernameTakenLevel !== 'silent') { const loggerMethod = - typeof log[usernameAlreadyExistsLevel] === 'function' - ? log[usernameAlreadyExistsLevel].bind(log) + typeof log[signupUsernameTakenLevel] === 'function' + ? log[signupUsernameTakenLevel].bind(log) : log.error.bind(log); loggerMethod('Parse error: ', err); } diff --git a/types/Options/index.d.ts b/types/Options/index.d.ts index c841c6b202..409dc97248 100644 --- a/types/Options/index.d.ts +++ b/types/Options/index.d.ts @@ -297,6 +297,6 @@ export interface LogLevels { triggerBeforeError?: string; cloudFunctionSuccess?: string; cloudFunctionError?: string; - usernameAlreadyExists?: string; + signupUsernameTaken?: string; } export {}; From 86a04804cac299502b3121daf2c71f88b0f165e9 Mon Sep 17 00:00:00 2001 From: Lucas Coratger <73360179+coratgerl@users.noreply.github.com> Date: Thu, 11 Dec 2025 09:26:30 +0100 Subject: [PATCH 6/7] fix: run definitions --- src/Options/Definitions.js | 12 ++++++------ src/Options/docs.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 47b65ff817..d5a47141a6 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -1488,6 +1488,12 @@ module.exports.LogLevels = { 'Log level used by the Cloud Code Functions on success. Default is `info`. See [LogLevel](LogLevel.html) for available values.', default: 'info', }, + signupUsernameTaken: { + env: 'PARSE_SERVER_LOG_LEVELS_SIGNUP_USERNAME_TAKEN', + help: + 'Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values.', + default: 'error', + }, triggerAfter: { env: 'PARSE_SERVER_LOG_LEVELS_TRIGGER_AFTER', help: @@ -1506,10 +1512,4 @@ module.exports.LogLevels = { 'Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. See [LogLevel](LogLevel.html) for available values.', default: 'info', }, - signupUsernameTaken: { - env: 'PARSE_SERVER_LOG_LEVELS_USERNAME_ALREADY_EXISTS', - help: - 'Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values.', - default: 'error', - }, }; diff --git a/src/Options/docs.js b/src/Options/docs.js index 51f3556c25..0d508e0443 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -325,8 +325,8 @@ * @interface LogLevels * @property {String} cloudFunctionError Log level used by the Cloud Code Functions on error. Default is `error`. See [LogLevel](LogLevel.html) for available values. * @property {String} cloudFunctionSuccess Log level used by the Cloud Code Functions on success. Default is `info`. See [LogLevel](LogLevel.html) for available values. + * @property {String} signupUsernameTaken Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values. * @property {String} triggerAfter Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterFind`, `afterLogout`. Default is `info`. See [LogLevel](LogLevel.html) for available values. * @property {String} triggerBeforeError Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on error. Default is `error`. See [LogLevel](LogLevel.html) for available values. * @property {String} triggerBeforeSuccess Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. See [LogLevel](LogLevel.html) for available values. - * @property {String} signupUsernameTaken Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values. */ From 042286459c7c2de528cd23237eec446099b5aaec Mon Sep 17 00:00:00 2001 From: Lucas Coratger <73360179+coratgerl@users.noreply.github.com> Date: Thu, 11 Dec 2025 11:00:26 +0100 Subject: [PATCH 7/7] fix: default --- src/Options/Definitions.js | 4 ++-- src/Options/docs.js | 2 +- src/Options/index.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index d5a47141a6..687901a70d 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -1491,8 +1491,8 @@ module.exports.LogLevels = { signupUsernameTaken: { env: 'PARSE_SERVER_LOG_LEVELS_SIGNUP_USERNAME_TAKEN', help: - 'Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values.', - default: 'error', + 'Log level used when a sign-up fails because the username already exists. Default is `info`. See [LogLevel](LogLevel.html) for available values.', + default: 'info', }, triggerAfter: { env: 'PARSE_SERVER_LOG_LEVELS_TRIGGER_AFTER', diff --git a/src/Options/docs.js b/src/Options/docs.js index 0d508e0443..4de7054187 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -325,7 +325,7 @@ * @interface LogLevels * @property {String} cloudFunctionError Log level used by the Cloud Code Functions on error. Default is `error`. See [LogLevel](LogLevel.html) for available values. * @property {String} cloudFunctionSuccess Log level used by the Cloud Code Functions on success. Default is `info`. See [LogLevel](LogLevel.html) for available values. - * @property {String} signupUsernameTaken Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values. + * @property {String} signupUsernameTaken Log level used when a sign-up fails because the username already exists. Default is `info`. See [LogLevel](LogLevel.html) for available values. * @property {String} triggerAfter Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterFind`, `afterLogout`. Default is `info`. See [LogLevel](LogLevel.html) for available values. * @property {String} triggerBeforeError Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on error. Default is `error`. See [LogLevel](LogLevel.html) for available values. * @property {String} triggerBeforeSuccess Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. See [LogLevel](LogLevel.html) for available values. diff --git a/src/Options/index.js b/src/Options/index.js index 5ee6912274..0175abff9e 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -789,8 +789,8 @@ export interface LogLevels { :DEFAULT: error */ cloudFunctionError: ?string; - /* Log level used when a sign-up fails because the username already exists. Default is `error`. See [LogLevel](LogLevel.html) for available values. - :DEFAULT: error + /* Log level used when a sign-up fails because the username already exists. Default is `info`. See [LogLevel](LogLevel.html) for available values. + :DEFAULT: info */ signupUsernameTaken: ?string; }