Skip to content

Commit 5609c14

Browse files
authored
Merge branch 'alpha' into feat/upgrade-monodb-driver
2 parents ade09a7 + 9f1fc7c commit 5609c14

28 files changed

+1418
-95
lines changed

DEPRECATIONS.md

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22

33
The following is a list of deprecations, according to the [Deprecation Policy](https://github.com/parse-community/parse-server/blob/master/CONTRIBUTING.md#deprecation-policy). After a feature becomes deprecated, and giving developers time to adapt to the change, the deprecated feature will eventually be removed, leading to a breaking change. Developer feedback during the deprecation period may postpone or even revoke the introduction of the breaking change.
44

5-
| ID | Change | Issue | Deprecation [ℹ️][i_deprecation] | Planned Removal [ℹ️][i_removal] | Status [ℹ️][i_status] | Notes |
6-
|--------|-------------------------------------------------|----------------------------------------------------------------------|---------------------------------|---------------------------------|-----------------------|-------|
7-
| DEPPS1 | Native MongoDB syntax in aggregation pipeline | [#7338](https://github.com/parse-community/parse-server/issues/7338) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
8-
| DEPPS2 | Config option `directAccess` defaults to `true` | [#6636](https://github.com/parse-community/parse-server/pull/6636) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
9-
| DEPPS3 | Config option `enforcePrivateUsers` defaults to `true` | [#7319](https://github.com/parse-community/parse-server/pull/7319) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
10-
| DEPPS4 | Remove convenience method for http request `Parse.Cloud.httpRequest` | [#7589](https://github.com/parse-community/parse-server/pull/7589) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
11-
| DEPPS5 | Config option `allowClientClassCreation` defaults to `false` | [#7925](https://github.com/parse-community/parse-server/pull/7925) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - |
12-
| DEPPS6 | Auth providers disabled by default | [#7953](https://github.com/parse-community/parse-server/pull/7953) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - |
13-
| DEPPS7 | Remove file trigger syntax `Parse.Cloud.beforeSaveFile((request) => {})` | [#7966](https://github.com/parse-community/parse-server/pull/7966) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - |
14-
| DEPPS8 | Login with expired 3rd party authentication token defaults to `false` | [#7079](https://github.com/parse-community/parse-server/pull/7079) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - |
15-
| DEPPS9 | Rename LiveQuery `fields` option to `keys` | [#8389](https://github.com/parse-community/parse-server/issues/8389) | 6.0.0 (2023) | 7.0.0 (2024) | removed | - |
16-
| DEPPS10 | Encode `Parse.Object` in Cloud Function and remove option `encodeParseObjectInCloudFunction` | [#8634](https://github.com/parse-community/parse-server/issues/8634) | 6.2.0 (2023) | 9.0.0 (2026) | deprecated | - |
17-
| DEPPS11 | Replace `PublicAPIRouter` with `PagesRouter` | [#7625](https://github.com/parse-community/parse-server/issues/7625) | 8.0.0 (2025) | 9.0.0 (2026) | deprecated | - |
5+
| ID | Change | Issue | Deprecation [ℹ️][i_deprecation] | Planned Removal [ℹ️][i_removal] | Status [ℹ️][i_status] | Notes |
6+
|---------|----------------------------------------------------------------------------------------------|----------------------------------------------------------------------|---------------------------------|---------------------------------|-----------------------|-------|
7+
| DEPPS1 | Native MongoDB syntax in aggregation pipeline | [#7338](https://github.com/parse-community/parse-server/issues/7338) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
8+
| DEPPS2 | Config option `directAccess` defaults to `true` | [#6636](https://github.com/parse-community/parse-server/pull/6636) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
9+
| DEPPS3 | Config option `enforcePrivateUsers` defaults to `true` | [#7319](https://github.com/parse-community/parse-server/pull/7319) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
10+
| DEPPS4 | Remove convenience method for http request `Parse.Cloud.httpRequest` | [#7589](https://github.com/parse-community/parse-server/pull/7589) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
11+
| DEPPS5 | Config option `allowClientClassCreation` defaults to `false` | [#7925](https://github.com/parse-community/parse-server/pull/7925) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - |
12+
| DEPPS6 | Auth providers disabled by default | [#7953](https://github.com/parse-community/parse-server/pull/7953) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - |
13+
| DEPPS7 | Remove file trigger syntax `Parse.Cloud.beforeSaveFile((request) => {})` | [#7966](https://github.com/parse-community/parse-server/pull/7966) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - |
14+
| DEPPS8 | Login with expired 3rd party authentication token defaults to `false` | [#7079](https://github.com/parse-community/parse-server/pull/7079) | 5.3.0 (2022) | 7.0.0 (2024) | removed | - |
15+
| DEPPS9 | Rename LiveQuery `fields` option to `keys` | [#8389](https://github.com/parse-community/parse-server/issues/8389) | 6.0.0 (2023) | 7.0.0 (2024) | removed | - |
16+
| DEPPS10 | Encode `Parse.Object` in Cloud Function and remove option `encodeParseObjectInCloudFunction` | [#8634](https://github.com/parse-community/parse-server/issues/8634) | 6.2.0 (2023) | 9.0.0 (2026) | deprecated | - |
17+
| DEPPS11 | Replace `PublicAPIRouter` with `PagesRouter` | [#7625](https://github.com/parse-community/parse-server/issues/7625) | 8.0.0 (2025) | 9.0.0 (2026) | deprecated | - |
18+
| DEPPS12 | Database option `allowPublicExplain` will default to `true` | [#7519](https://github.com/parse-community/parse-server/issues/7519) | 8.5.0 (2025) | 9.0.0 (2026) | deprecated | - |
1819

1920
[i_deprecation]: ## "The version and date of the deprecation."
2021
[i_removal]: ## "The version and date of the planned removal."

changelogs/CHANGELOG_alpha.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,45 @@
1+
# [8.5.0-alpha.6](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.5...8.5.0-alpha.6) (2025-11-08)
2+
3+
4+
### Bug Fixes
5+
6+
* `GridFSBucketAdapter` throws when using some Parse Server specific options in MongoDB database options ([#9915](https://github.com/parse-community/parse-server/issues/9915)) ([d3d4003](https://github.com/parse-community/parse-server/commit/d3d4003570b9872f2b0f5a25fc06ce4c4132860d))
7+
8+
# [8.5.0-alpha.5](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.4...8.5.0-alpha.5) (2025-11-08)
9+
10+
11+
### Features
12+
13+
* Add Parse Server option `allowPublicExplain` to allow `Parse.Query.explain` without master key ([#9890](https://github.com/parse-community/parse-server/issues/9890)) ([4456b02](https://github.com/parse-community/parse-server/commit/4456b02280c2d8dd58b7250e9e67f1a8647b3452))
14+
15+
# [8.5.0-alpha.4](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.3...8.5.0-alpha.4) (2025-11-08)
16+
17+
18+
### Features
19+
20+
* Add MongoDB client event logging via database option `logClientEvents` ([#9914](https://github.com/parse-community/parse-server/issues/9914)) ([b760733](https://github.com/parse-community/parse-server/commit/b760733b98bcfc9c09ac9780066602e1fda108fe))
21+
22+
# [8.5.0-alpha.3](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.2...8.5.0-alpha.3) (2025-11-07)
23+
24+
25+
### Features
26+
27+
* Add support for more MongoDB driver options ([#9911](https://github.com/parse-community/parse-server/issues/9911)) ([cff451e](https://github.com/parse-community/parse-server/commit/cff451eabdc380affa600ed711de66f7bd1d00aa))
28+
29+
# [8.5.0-alpha.2](https://github.com/parse-community/parse-server/compare/8.5.0-alpha.1...8.5.0-alpha.2) (2025-11-07)
30+
31+
32+
### Features
33+
34+
* Add support for MongoDB driver options `serverSelectionTimeoutMS`, `maxIdleTimeMS`, `heartbeatFrequencyMS` ([#9910](https://github.com/parse-community/parse-server/issues/9910)) ([1b661e9](https://github.com/parse-community/parse-server/commit/1b661e98c86a1db79e076a7297cd9199a72ae1ac))
35+
36+
# [8.5.0-alpha.1](https://github.com/parse-community/parse-server/compare/8.4.0...8.5.0-alpha.1) (2025-11-07)
37+
38+
39+
### Features
40+
41+
* Allow option `publicServerURL` to be set dynamically as asynchronous function ([#9803](https://github.com/parse-community/parse-server/issues/9803)) ([460a65c](https://github.com/parse-community/parse-server/commit/460a65cf612f4c86af8038cafcc7e7ffe9eb8440))
42+
143
# [8.4.0-alpha.2](https://github.com/parse-community/parse-server/compare/8.4.0-alpha.1...8.4.0-alpha.2) (2025-11-05)
244

345

jsdoc-conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"theme_opts": {
3131
"default_theme": "dark",
3232
"title": "<img src='https://raw.githubusercontent.com/parse-community/parse-server/alpha/.github/parse-server-logo.png' class='logo'/>",
33-
"create_style": "header, .sidebar-section-title, .sidebar-title { color: #139cee !important } .logo { margin-left : 40px; margin-right: 40px }"
33+
"create_style": "header, .sidebar-section-title, .sidebar-title { color: #139cee !important } .logo { margin-left : 40px; margin-right: 40px; height: auto; max-width: 100%; object-fit: contain; }"
3434
}
3535
},
3636
"markdown": {

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "parse-server",
3-
"version": "8.4.0",
3+
"version": "8.5.0-alpha.6",
44
"description": "An express module providing a Parse-compatible API server",
55
"main": "lib/index.js",
66
"repository": {

resources/buildConfigDefinitions.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,17 @@ const nestedOptionEnvPrefix = {
3636
IdempotencyOptions: 'PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_',
3737
LiveQueryOptions: 'PARSE_SERVER_LIVEQUERY_',
3838
LiveQueryServerOptions: 'PARSE_LIVE_QUERY_SERVER_',
39+
LogClientEvent: 'PARSE_SERVER_DATABASE_LOG_CLIENT_EVENTS_',
40+
LogLevel: 'PARSE_SERVER_LOG_LEVEL_',
41+
LogLevels: 'PARSE_SERVER_LOG_LEVELS_',
3942
PagesCustomUrlsOptions: 'PARSE_SERVER_PAGES_CUSTOM_URL_',
4043
PagesOptions: 'PARSE_SERVER_PAGES_',
4144
PagesRoute: 'PARSE_SERVER_PAGES_ROUTE_',
4245
ParseServerOptions: 'PARSE_SERVER_',
4346
PasswordPolicyOptions: 'PARSE_SERVER_PASSWORD_POLICY_',
44-
SecurityOptions: 'PARSE_SERVER_SECURITY_',
45-
SchemaOptions: 'PARSE_SERVER_SCHEMA_',
46-
LogLevels: 'PARSE_SERVER_LOG_LEVELS_',
4747
RateLimitOptions: 'PARSE_SERVER_RATE_LIMIT_',
48+
SchemaOptions: 'PARSE_SERVER_SCHEMA_',
49+
SecurityOptions: 'PARSE_SERVER_SECURITY_',
4850
};
4951

5052
function last(array) {

spec/GridFSBucketStorageAdapter.spec.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,20 @@ describe_only_db('mongo')('GridFSBucket', () => {
2424
const databaseURI = 'mongodb://localhost:27017/parse';
2525
const gfsAdapter = new GridFSBucketAdapter(databaseURI, {
2626
retryWrites: true,
27-
// these are not supported by the mongo client
27+
// Parse Server-specific options that should be filtered out before passing to MongoDB client
28+
allowPublicExplain: true,
2829
enableSchemaHooks: true,
2930
schemaCacheTtl: 5000,
3031
maxTimeMS: 30000,
32+
disableIndexFieldValidation: true,
33+
logClientEvents: [{ name: 'commandStarted' }],
34+
createIndexUserUsername: true,
35+
createIndexUserUsernameCaseInsensitive: true,
36+
createIndexUserEmail: true,
37+
createIndexUserEmailCaseInsensitive: true,
38+
createIndexUserEmailVerifyToken: true,
39+
createIndexUserPasswordResetToken: true,
40+
createIndexRoleName: true,
3141
});
3242

3343
const db = await gfsAdapter._connect();

spec/MongoStorageAdapter.spec.js

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,4 +824,243 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
824824
expect(roleIndexes.find(idx => idx.name === 'name_1')).toBeDefined();
825825
});
826826
});
827+
828+
describe('logClientEvents', () => {
829+
it('should log MongoDB client events when configured', async () => {
830+
const logger = require('../lib/logger').logger;
831+
const logSpy = spyOn(logger, 'warn');
832+
833+
const logClientEvents = [
834+
{
835+
name: 'serverDescriptionChanged',
836+
keys: ['address'],
837+
logLevel: 'warn',
838+
},
839+
];
840+
841+
const adapter = new MongoStorageAdapter({
842+
uri: databaseURI,
843+
mongoOptions: { logClientEvents },
844+
});
845+
846+
// Connect to trigger event listeners setup
847+
await adapter.connect();
848+
849+
// Manually trigger the event to test the listener
850+
const mockEvent = {
851+
address: 'localhost:27017',
852+
previousDescription: { type: 'Unknown' },
853+
newDescription: { type: 'Standalone' },
854+
};
855+
856+
adapter.client.emit('serverDescriptionChanged', mockEvent);
857+
858+
// Verify the log was called with the correct message
859+
expect(logSpy).toHaveBeenCalledWith(
860+
jasmine.stringMatching(/MongoDB client event serverDescriptionChanged:.*"address":"localhost:27017"/)
861+
);
862+
863+
await adapter.handleShutdown();
864+
});
865+
866+
it('should log entire event when keys are not specified', async () => {
867+
const logger = require('../lib/logger').logger;
868+
const logSpy = spyOn(logger, 'info');
869+
870+
const logClientEvents = [
871+
{
872+
name: 'connectionPoolReady',
873+
logLevel: 'info',
874+
},
875+
];
876+
877+
const adapter = new MongoStorageAdapter({
878+
uri: databaseURI,
879+
mongoOptions: { logClientEvents },
880+
});
881+
882+
await adapter.connect();
883+
884+
const mockEvent = {
885+
address: 'localhost:27017',
886+
options: { maxPoolSize: 100 },
887+
};
888+
889+
adapter.client.emit('connectionPoolReady', mockEvent);
890+
891+
expect(logSpy).toHaveBeenCalledWith(
892+
jasmine.stringMatching(/MongoDB client event connectionPoolReady:.*"address":"localhost:27017".*"options"/)
893+
);
894+
895+
await adapter.handleShutdown();
896+
});
897+
898+
it('should extract nested keys using dot notation', async () => {
899+
const logger = require('../lib/logger').logger;
900+
const logSpy = spyOn(logger, 'warn');
901+
902+
const logClientEvents = [
903+
{
904+
name: 'topologyDescriptionChanged',
905+
keys: ['previousDescription.type', 'newDescription.type', 'newDescription.servers.size'],
906+
logLevel: 'warn',
907+
},
908+
];
909+
910+
const adapter = new MongoStorageAdapter({
911+
uri: databaseURI,
912+
mongoOptions: { logClientEvents },
913+
});
914+
915+
await adapter.connect();
916+
917+
const mockEvent = {
918+
topologyId: 1,
919+
previousDescription: { type: 'Unknown' },
920+
newDescription: {
921+
type: 'ReplicaSetWithPrimary',
922+
servers: { size: 3 },
923+
},
924+
};
925+
926+
adapter.client.emit('topologyDescriptionChanged', mockEvent);
927+
928+
expect(logSpy).toHaveBeenCalledWith(
929+
jasmine.stringMatching(/MongoDB client event topologyDescriptionChanged:.*"previousDescription.type":"Unknown".*"newDescription.type":"ReplicaSetWithPrimary".*"newDescription.servers.size":3/)
930+
);
931+
932+
await adapter.handleShutdown();
933+
});
934+
935+
it('should handle invalid log level gracefully', async () => {
936+
const logger = require('../lib/logger').logger;
937+
const infoSpy = spyOn(logger, 'info');
938+
939+
const logClientEvents = [
940+
{
941+
name: 'connectionPoolReady',
942+
keys: ['address'],
943+
logLevel: 'invalidLogLevel', // Invalid log level
944+
},
945+
];
946+
947+
const adapter = new MongoStorageAdapter({
948+
uri: databaseURI,
949+
mongoOptions: { logClientEvents },
950+
});
951+
952+
await adapter.connect();
953+
954+
const mockEvent = {
955+
address: 'localhost:27017',
956+
};
957+
958+
adapter.client.emit('connectionPoolReady', mockEvent);
959+
960+
// Should fallback to 'info' level
961+
expect(infoSpy).toHaveBeenCalledWith(
962+
jasmine.stringMatching(/MongoDB client event connectionPoolReady:.*"address":"localhost:27017"/)
963+
);
964+
965+
await adapter.handleShutdown();
966+
});
967+
968+
it('should handle Map and Set instances in events', async () => {
969+
const logger = require('../lib/logger').logger;
970+
const warnSpy = spyOn(logger, 'warn');
971+
972+
const logClientEvents = [
973+
{
974+
name: 'customEvent',
975+
logLevel: 'warn',
976+
},
977+
];
978+
979+
const adapter = new MongoStorageAdapter({
980+
uri: databaseURI,
981+
mongoOptions: { logClientEvents },
982+
});
983+
984+
await adapter.connect();
985+
986+
const mockEvent = {
987+
mapData: new Map([['key1', 'value1'], ['key2', 'value2']]),
988+
setData: new Set([1, 2, 3]),
989+
};
990+
991+
adapter.client.emit('customEvent', mockEvent);
992+
993+
// Should serialize Map and Set properly
994+
expect(warnSpy).toHaveBeenCalledWith(
995+
jasmine.stringMatching(/MongoDB client event customEvent:.*"mapData":\{"key1":"value1","key2":"value2"\}.*"setData":\[1,2,3\]/)
996+
);
997+
998+
await adapter.handleShutdown();
999+
});
1000+
1001+
it('should handle missing keys in event object', async () => {
1002+
const logger = require('../lib/logger').logger;
1003+
const infoSpy = spyOn(logger, 'info');
1004+
1005+
const logClientEvents = [
1006+
{
1007+
name: 'testEvent',
1008+
keys: ['nonexistent.nested.key', 'another.missing'],
1009+
logLevel: 'info',
1010+
},
1011+
];
1012+
1013+
const adapter = new MongoStorageAdapter({
1014+
uri: databaseURI,
1015+
mongoOptions: { logClientEvents },
1016+
});
1017+
1018+
await adapter.connect();
1019+
1020+
const mockEvent = {
1021+
actualField: 'value',
1022+
};
1023+
1024+
adapter.client.emit('testEvent', mockEvent);
1025+
1026+
// Should handle missing keys gracefully with undefined values
1027+
expect(infoSpy).toHaveBeenCalledWith(
1028+
jasmine.stringMatching(/MongoDB client event testEvent:/)
1029+
);
1030+
1031+
await adapter.handleShutdown();
1032+
});
1033+
1034+
it('should handle circular references gracefully', async () => {
1035+
const logger = require('../lib/logger').logger;
1036+
const infoSpy = spyOn(logger, 'info');
1037+
1038+
const logClientEvents = [
1039+
{
1040+
name: 'circularEvent',
1041+
logLevel: 'info',
1042+
},
1043+
];
1044+
1045+
const adapter = new MongoStorageAdapter({
1046+
uri: databaseURI,
1047+
mongoOptions: { logClientEvents },
1048+
});
1049+
1050+
await adapter.connect();
1051+
1052+
// Create circular reference
1053+
const mockEvent = { name: 'test' };
1054+
mockEvent.self = mockEvent;
1055+
1056+
adapter.client.emit('circularEvent', mockEvent);
1057+
1058+
// Should handle circular reference with [Circular] marker
1059+
expect(infoSpy).toHaveBeenCalledWith(
1060+
jasmine.stringMatching(/MongoDB client event circularEvent:.*\[Circular\]/)
1061+
);
1062+
1063+
await adapter.handleShutdown();
1064+
});
1065+
});
8271066
});

0 commit comments

Comments
 (0)