Compare commits

...
5 Commits
8 changed files with 71 additions and 8 deletions
+12
View File
@@ -3,6 +3,7 @@ on:
push:
branches: [release, alpha, beta, next-major, 'release-[0-9]+.x.x']
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches:
- '**'
paths-ignore:
@@ -15,6 +16,7 @@ permissions:
jobs:
check-code-analysis:
name: Code Analysis
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
runs-on: ubuntu-latest
permissions:
actions: read
@@ -36,6 +38,7 @@ jobs:
uses: github/codeql-action/analyze@v2
check-ci:
name: Node Engine Check
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
@@ -52,6 +55,7 @@ jobs:
run: npm run ci:checkNodeEngine
check-lint:
name: Lint
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
@@ -72,6 +76,7 @@ jobs:
- run: npm run lint
check-definitions:
name: Check Definitions
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
@@ -93,6 +98,7 @@ jobs:
run: npm run ci:definitionsCheck
check-circular:
name: Circular Dependencies
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
@@ -113,6 +119,7 @@ jobs:
- run: npm run madge:circular
check-docs:
name: Docs
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
@@ -136,6 +143,7 @@ jobs:
run: npm run docs
check-docker:
name: Docker Build
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
@@ -153,6 +161,7 @@ jobs:
platforms: linux/amd64, linux/arm64/v8
check-lock-file-version:
name: NPM Lock File Version
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
@@ -166,6 +175,7 @@ jobs:
fi
check-types:
name: Check Types
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
@@ -206,6 +216,7 @@ jobs:
NODE_VERSION: 22.12.0
fail-fast: false
name: ${{ matrix.name }}
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
timeout-minutes: 20
runs-on: ubuntu-latest
services:
@@ -260,6 +271,7 @@ jobs:
NODE_VERSION: 24.11.0
fail-fast: false
name: ${{ matrix.name }}
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
timeout-minutes: 20
runs-on: ubuntu-latest
services:
+14
View File
@@ -1,3 +1,17 @@
## [9.10.1-alpha.6](https://github.com/parse-community/parse-server/compare/9.10.1-alpha.5...9.10.1-alpha.6) (2026-07-26)
### Bug Fixes
* `Parse.Query.explain` runs afterFind trigger on query plan results ([#10536](https://github.com/parse-community/parse-server/issues/10536)) ([64d58ff](https://github.com/parse-community/parse-server/commit/64d58ff726b42b45e107e27bc1f3b50be82b3189))
## [9.10.1-alpha.5](https://github.com/parse-community/parse-server/compare/9.10.1-alpha.4...9.10.1-alpha.5) (2026-07-25)
### Bug Fixes
* Server crash from unhandled promise rejection when multiple Cloud Code validator fields fail ([#10540](https://github.com/parse-community/parse-server/issues/10540)) ([90c2778](https://github.com/parse-community/parse-server/commit/90c277894f31be8e64a4b049ad503621cf5f2285))
## [9.10.1-alpha.4](https://github.com/parse-community/parse-server/compare/9.10.1-alpha.3...9.10.1-alpha.4) (2026-07-24)
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "parse-server",
"version": "9.10.1-alpha.4",
"version": "9.10.1-alpha.6",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "parse-server",
"version": "9.10.1-alpha.4",
"version": "9.10.1-alpha.6",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "parse-server",
"version": "9.10.1-alpha.4",
"version": "9.10.1-alpha.6",
"description": "An express module providing a Parse-compatible API server",
"main": "lib/index.js",
"repository": {
+21
View File
@@ -504,6 +504,27 @@ describe('cloud validator', () => {
});
});
it('does not leave an unhandled rejection when multiple fields fail validation (#8826)', async () => {
const rejections = [];
const onUnhandledRejection = reason => rejections.push(reason);
process.on('unhandledRejection', onUnhandledRejection);
try {
Parse.Cloud.define('hello', () => 'Hello world!', {
fields: {
type: { type: String, options: ['Option A', 'Option B'] },
project: { required: true },
},
});
await expectAsync(Parse.Cloud.run('hello', { type: 'Invalid' })).toBeRejectedWith(
jasmine.objectContaining({ code: Parse.Error.VALIDATION_ERROR })
);
await new Promise(resolve => setTimeout(resolve, 100));
expect(rejections).toEqual([]);
} finally {
process.removeListener('unhandledRejection', onUnhandledRejection);
}
});
it('set params options function', done => {
Parse.Cloud.define(
'hello',
+16
View File
@@ -5375,6 +5375,22 @@ describe('Parse.Query testing', () => {
expect(result.executionStats).not.toBeUndefined();
});
it_only_db('mongo')('does not run afterFind on explain results', async () => {
let afterFindCalled = false;
Parse.Cloud.afterFind('AfterFindExplain', () => {
afterFindCalled = true;
return []; // empty return would drop the explain plan if the trigger ran
});
const obj = new Parse.Object('AfterFindExplain');
await obj.save();
const query = new Parse.Query('AfterFindExplain');
query.equalTo('objectId', obj.id);
query.explain();
const result = await query.find({ useMasterKey: true });
expect(result.executionStats).not.toBeUndefined(); // plan passed through untouched
expect(afterFindCalled).toBe(false); // afterFind skipped for explain
});
it('should query with distinct within eachBatch and direct access enabled', async () => {
await reconfigureServer({
directAccess: true,
+2 -2
View File
@@ -1121,8 +1121,8 @@ _UnsafeRestQuery.prototype.runAfterFindTrigger = function () {
if (!hasAfterFindHook) {
return Promise.resolve();
}
// Skip Aggregate and Distinct Queries
if (this.findOptions.pipeline || this.findOptions.distinct) {
// Skip Aggregate, Distinct and Explain Queries
if (this.findOptions.pipeline || this.findOptions.distinct || this.findOptions.explain) {
return Promise.resolve();
}
+3 -3
View File
@@ -823,7 +823,7 @@ async function builtInTriggerValidator(options, request, auth) {
requiredParam(key);
}
} else {
const optionPromises = [];
const optionValidations = [];
for (const key in options.fields) {
const opt = options.fields[key];
let val = params[key];
@@ -858,12 +858,12 @@ async function builtInTriggerValidator(options, request, auth) {
}
}
if (opt.options) {
optionPromises.push(validateOptions(opt, key, val));
optionValidations.push([opt, key, val]);
}
}
}
}
await Promise.all(optionPromises);
await Promise.all(optionValidations.map(([o, k, v]) => validateOptions(o, k, v)));
}
let userRoles = options.requireAnyUserRoles;
let requireAllRoles = options.requireAllUserRoles;