diff --git a/DEPRECATIONS.md b/DEPRECATIONS.md index d3e4825d20..7e6cbfdb49 100644 --- a/DEPRECATIONS.md +++ b/DEPRECATIONS.md @@ -18,7 +18,9 @@ The following is a list of deprecations, according to the [Deprecation Policy](h | DEPPS12 | Database option `allowPublicExplain` defaults to `false` | [#7519](https://github.com/parse-community/parse-server/issues/7519) | 8.5.0 (2025) | 9.0.0 (2026) | changed | - | | DEPPS13 | Config option `enableInsecureAuthAdapters` defaults to `false` | [#9667](https://github.com/parse-community/parse-server/pull/9667) | 8.0.0 (2025) | 9.0.0 (2026) | changed | - | | DEPPS14 | Config option `pages.encodePageParamHeaders` defaults to `true` | [#10063](https://github.com/parse-community/parse-server/issues/10063) | 9.4.0 (2026) | 10.0.0 (2027) | deprecated | - | -| DEPPS15 | Config option `readOnlyMasterKeyIps` defaults to `['127.0.0.1', '::1']` | [#10115](https://github.com/parse-community/parse-server/pull/10115) | 9.5.0 (2026) | 10.0.0 (2027) | deprecated | - | +| DEPPS15 | Config option `readOnlyMasterKeyIps` defaults to `['127.0.0.1', '::1']` | [#10115](https://github.com/parse-community/parse-server/pull/10115) | 9.5.0 (2026) | 10.0.0 (2027) | deprecated | - | +| DEPPS16 | Remove config option `mountPlayground` | [#10110](https://github.com/parse-community/parse-server/issues/10110) | 9.5.0 (2026) | 10.0.0 (2027) | deprecated | - | +| DEPPS17 | Remove config option `playgroundPath` | [#10110](https://github.com/parse-community/parse-server/issues/10110) | 9.5.0 (2026) | 10.0.0 (2027) | deprecated | - | [i_deprecation]: ## "The version and date of the deprecation." [i_change]: ## "The version and date of the planned change." diff --git a/spec/Deprecator.spec.js b/spec/Deprecator.spec.js index 210a503fb8..7fe925c3fc 100644 --- a/spec/Deprecator.spec.js +++ b/spec/Deprecator.spec.js @@ -103,4 +103,50 @@ describe('Deprecator', () => { }) ); }); + + it('logs deprecation for removed key when option is set', async () => { + deprecations = [{ optionKey: 'exampleKey', changeNewKey: '', solution: 'Use something else.' }]; + + spyOn(Deprecator, '_getDeprecations').and.callFake(() => deprecations); + const logger = require('../lib/logger').logger; + const logSpy = spyOn(logger, 'warn').and.callFake(() => {}); + + await reconfigureServer({ exampleKey: true }); + expect(logSpy).toHaveBeenCalledWith( + `DeprecationWarning: The Parse Server option '${deprecations[0].optionKey}' is deprecated and will be removed in a future version. ${deprecations[0].solution}` + ); + }); + + it('does not log deprecation for removed key when option is not set', async () => { + deprecations = [{ optionKey: 'exampleKey', changeNewKey: '', solution: 'Use something else.' }]; + + spyOn(Deprecator, '_getDeprecations').and.callFake(() => deprecations); + const logSpy = spyOn(Deprecator, '_logOption').and.callFake(() => {}); + + await reconfigureServer(); + expect(logSpy).not.toHaveBeenCalled(); + }); + + it('logs deprecation for mountPlayground when set', async () => { + const logSpy = spyOn(Deprecator, '_logOption').and.callFake(() => {}); + + await reconfigureServer({ mountPlayground: true, mountGraphQL: true }); + expect(logSpy).toHaveBeenCalledWith( + jasmine.objectContaining({ + optionKey: 'mountPlayground', + changeNewKey: '', + }) + ); + }); + + it('does not log deprecation for mountPlayground when not set', async () => { + const logSpy = spyOn(Deprecator, '_logOption').and.callFake(() => {}); + + await reconfigureServer(); + expect(logSpy).not.toHaveBeenCalledWith( + jasmine.objectContaining({ + optionKey: 'mountPlayground', + }) + ); + }); }); diff --git a/src/Deprecator/Deprecations.js b/src/Deprecator/Deprecations.js index 9093018f48..60e37e6efb 100644 --- a/src/Deprecator/Deprecations.js +++ b/src/Deprecator/Deprecations.js @@ -31,4 +31,14 @@ module.exports = [ changeNewDefault: '["127.0.0.1", "::1"]', solution: "Set 'readOnlyMasterKeyIps' to the IP addresses that should be allowed to use the read-only master key, or to '[\"127.0.0.1\", \"::1\"]' to restrict access to localhost.", }, + { + optionKey: 'mountPlayground', + changeNewKey: '', + solution: "Use Parse Dashboard as GraphQL IDE or configure a third-party GraphQL client such as Apollo Sandbox, GraphiQL, or Insomnia with custom request headers.", + }, + { + optionKey: 'playgroundPath', + changeNewKey: '', + solution: "Use Parse Dashboard as GraphQL IDE or configure a third-party GraphQL client such as Apollo Sandbox, GraphiQL, or Insomnia with custom request headers.", + }, ]; diff --git a/src/Deprecator/Deprecator.js b/src/Deprecator/Deprecator.js index 4744efbdd8..afbd215e0f 100644 --- a/src/Deprecator/Deprecator.js +++ b/src/Deprecator/Deprecator.js @@ -20,11 +20,17 @@ class Deprecator { const solution = deprecation.solution; const optionKey = deprecation.optionKey; const changeNewDefault = deprecation.changeNewDefault; + const changeNewKey = deprecation.changeNewKey; // If default will change, only throw a warning if option is not set if (changeNewDefault != null && Utils.getNestedProperty(options, optionKey) == null) { Deprecator._logOption({ optionKey, changeNewDefault, solution }); } + + // If key will be removed or renamed, only throw a warning if option is set + if (changeNewKey != null && Utils.getNestedProperty(options, optionKey) != null) { + Deprecator._logOption({ optionKey, changeNewKey, solution }); + } } } @@ -107,7 +113,7 @@ class Deprecator { // Compose message let output = `DeprecationWarning: The Parse Server ${type} '${key}' `; - output += changeNewKey ? `is deprecated and will be ${keyAction} in a future version.` : ''; + output += changeNewKey != null ? `is deprecated and will be ${keyAction} in a future version.` : ''; output += changeNewDefault ? `default will change to '${changeNewDefault}' in a future version.` : ''; diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index f265f57c99..05d469f4cf 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -404,7 +404,7 @@ module.exports.ParseServerOptions = { }, mountPlayground: { env: 'PARSE_SERVER_MOUNT_PLAYGROUND', - help: 'Mounts the GraphQL Playground which exposes the master key in the browser - never use this option in production', + help: 'Deprecated. Mounts the GraphQL Playground which is deprecated and will be removed in a future version. The playground exposes the master key in the browser. Use Parse Dashboard as GraphQL IDE or configure a third-party GraphQL client with custom request headers.', action: parsers.booleanParser, default: false, }, @@ -429,7 +429,7 @@ module.exports.ParseServerOptions = { }, playgroundPath: { env: 'PARSE_SERVER_PLAYGROUND_PATH', - help: 'Mount path for the GraphQL Playground, defaults to /playground', + help: 'Deprecated. Mount path for the GraphQL Playground. The playground is deprecated and will be removed in a future version.', default: '/playground', }, port: { diff --git a/src/Options/docs.js b/src/Options/docs.js index 8278838340..4e7a050d8b 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -77,11 +77,11 @@ * @property {Union} middleware middleware for express server, can be string or function * @property {Boolean} mountGraphQL Mounts the GraphQL endpoint * @property {String} mountPath Mount path for the server, defaults to /parse - * @property {Boolean} mountPlayground Mounts the GraphQL Playground which exposes the master key in the browser - never use this option in production + * @property {Boolean} mountPlayground Deprecated. Mounts the GraphQL Playground which is deprecated and will be removed in a future version. The playground exposes the master key in the browser. Use Parse Dashboard as GraphQL IDE or configure a third-party GraphQL client with custom request headers. * @property {Number} objectIdSize Sets the number of characters in generated object id's, default 10 * @property {PagesOptions} pages The options for pages such as password reset and email verification. * @property {PasswordPolicyOptions} passwordPolicy The password policy for enforcing password related rules. - * @property {String} playgroundPath Mount path for the GraphQL Playground, defaults to /playground + * @property {String} playgroundPath Deprecated. Mount path for the GraphQL Playground. The playground is deprecated and will be removed in a future version. * @property {Number} port The port to run the ParseServer, defaults to 1337. * @property {Boolean} preserveFileName Enable (or disable) the addition of a unique hash to the file names * @property {Boolean} preventLoginWithUnverifiedEmail Set to `true` to prevent a user from logging in if the email has not yet been verified and email verification is required. Supports a function with a return value of `true` or `false` for conditional prevention. The function receives a request object that includes `createdWith` to indicate whether the invocation is for `signup` or `login` and the used auth provider.

The `createdWith` values per scenario:Default is `false`.
Requires option `verifyUserEmails: true`. diff --git a/src/Options/index.js b/src/Options/index.js index 96c94f9df1..11126653de 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -342,11 +342,11 @@ export interface ParseServerOptions { :ENV: PARSE_SERVER_GRAPHQL_PUBLIC_INTROSPECTION :DEFAULT: false */ graphQLPublicIntrospection: ?boolean; - /* Mounts the GraphQL Playground which exposes the master key in the browser - never use this option in production + /* Deprecated. Mounts the GraphQL Playground which is deprecated and will be removed in a future version. The playground exposes the master key in the browser. Use Parse Dashboard as GraphQL IDE or configure a third-party GraphQL client with custom request headers. :ENV: PARSE_SERVER_MOUNT_PLAYGROUND :DEFAULT: false */ mountPlayground: ?boolean; - /* Mount path for the GraphQL Playground, defaults to /playground + /* Deprecated. Mount path for the GraphQL Playground. The playground is deprecated and will be removed in a future version. :ENV: PARSE_SERVER_PLAYGROUND_PATH :DEFAULT: /playground */ playgroundPath: ?string; diff --git a/src/ParseServer.ts b/src/ParseServer.ts index e1672aff5c..8bd120022e 100644 --- a/src/ParseServer.ts +++ b/src/ParseServer.ts @@ -460,7 +460,7 @@ class ParseServer { if (options.mountPlayground) { parseGraphQLServer.applyPlayground(app); logging.getLogger().warn( - 'GraphQL Playground is enabled and exposes the master key in the browser. The playground is a developer tool and should not be used in production. Use Parse Dashboard for production environments.' + 'GraphQL Playground is deprecated and will be removed in a future version. It exposes the master key in the browser. Use Parse Dashboard as GraphQL IDE or configure a third-party GraphQL client with custom request headers.' ); } }