-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
feat: Allow option publicServerURL to be set dynamically as asynchronous function
#9803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
mtrezza
merged 24 commits into
parse-community:alpha
from
dblythy:feature/dynamic-publicServerUrl
Nov 7, 2025
+247
−17
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
8d4528e
feature: add dynamic publicServerUrl
dblythy 3f4e350
Update Config.js
dblythy f819fc0
Merge branch 'alpha' into feature/dynamic-publicServerUrl
mtrezza c20b3d0
Update index.spec.js
dblythy 3ac5143
Merge branch 'alpha' into feature/dynamic-publicServerUrl
mtrezza 8153cbb
Merge branch 'alpha' into feature/dynamic-publicServerUrl
mtrezza 7890722
Apply suggestions from code review
mtrezza 9aa8735
Apply suggestions from code review
mtrezza 7ff5df3
Apply suggestions from code review
mtrezza b85ed20
refactor tests
mtrezza 44843e3
add tests
mtrezza e85245a
tmp
mtrezza c17632c
fix
mtrezza f719294
Revert "fix"
mtrezza b76bbf4
Revert "tmp"
mtrezza 7dabfaf
fix
mtrezza d884a60
fix validation
mtrezza 2506eda
fix validation
mtrezza b010721
test
mtrezza 7f759c8
fix
mtrezza d3d6e2b
docs
mtrezza 14e5406
type fix
mtrezza 3511605
error handling
mtrezza b508a3a
docs typo
mtrezza File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -363,7 +363,7 @@ describe('server', () => { | |
|
|
||
| it('should throw when getting invalid mount', done => { | ||
| reconfigureServer({ publicServerURL: 'blabla:/some' }).catch(error => { | ||
| expect(error).toEqual('publicServerURL should be a valid HTTPS URL starting with https://'); | ||
| expect(error).toEqual('The option publicServerURL must be a valid URL starting with http:// or https://.'); | ||
| done(); | ||
| }); | ||
| }); | ||
|
|
@@ -685,4 +685,171 @@ describe('server', () => { | |
| }) | ||
| .catch(done.fail); | ||
| }); | ||
|
|
||
| describe('publicServerURL', () => { | ||
| it('should load publicServerURL', async () => { | ||
| await reconfigureServer({ | ||
| publicServerURL: () => 'https://example.com/1', | ||
| }); | ||
|
|
||
| await new Parse.Object('TestObject').save(); | ||
|
|
||
| const config = Config.get(Parse.applicationId); | ||
| expect(config.publicServerURL).toEqual('https://example.com/1'); | ||
| }); | ||
|
|
||
| it('should load publicServerURL from Promise', async () => { | ||
| await reconfigureServer({ | ||
| publicServerURL: () => Promise.resolve('https://example.com/1'), | ||
| }); | ||
|
|
||
| await new Parse.Object('TestObject').save(); | ||
|
|
||
| const config = Config.get(Parse.applicationId); | ||
| expect(config.publicServerURL).toEqual('https://example.com/1'); | ||
| }); | ||
|
|
||
| it('should handle publicServerURL function throwing error', async () => { | ||
| const errorMessage = 'Failed to get public server URL'; | ||
| await reconfigureServer({ | ||
| publicServerURL: () => { | ||
| throw new Error(errorMessage); | ||
| }, | ||
| }); | ||
|
|
||
| // The error should occur when trying to save an object (which triggers loadKeys in middleware) | ||
| await expectAsync( | ||
| new Parse.Object('TestObject').save() | ||
| ).toBeRejected(); | ||
| }); | ||
|
|
||
| it('should handle publicServerURL Promise rejection', async () => { | ||
| const errorMessage = 'Async fetch of public server URL failed'; | ||
| await reconfigureServer({ | ||
| publicServerURL: () => Promise.reject(new Error(errorMessage)), | ||
| }); | ||
|
|
||
| // The error should occur when trying to save an object (which triggers loadKeys in middleware) | ||
| await expectAsync( | ||
| new Parse.Object('TestObject').save() | ||
| ).toBeRejected(); | ||
| }); | ||
|
|
||
| it('executes publicServerURL function on every config access', async () => { | ||
| let counter = 0; | ||
| await reconfigureServer({ | ||
| publicServerURL: () => { | ||
| counter++; | ||
| return `https://example.com/${counter}`; | ||
| }, | ||
| }); | ||
|
|
||
| // First request - should call the function | ||
| await new Parse.Object('TestObject').save(); | ||
| const config1 = Config.get(Parse.applicationId); | ||
| expect(config1.publicServerURL).toEqual('https://example.com/1'); | ||
| expect(counter).toEqual(1); | ||
|
|
||
| // Second request - should call the function again | ||
| await new Parse.Object('TestObject').save(); | ||
| const config2 = Config.get(Parse.applicationId); | ||
| expect(config2.publicServerURL).toEqual('https://example.com/2'); | ||
| expect(counter).toEqual(2); | ||
|
|
||
| // Third request - should call the function again | ||
| await new Parse.Object('TestObject').save(); | ||
| const config3 = Config.get(Parse.applicationId); | ||
| expect(config3.publicServerURL).toEqual('https://example.com/3'); | ||
| expect(counter).toEqual(3); | ||
| }); | ||
|
|
||
| it('executes publicServerURL function on every password reset email', async () => { | ||
| let counter = 0; | ||
| const emailCalls = []; | ||
|
|
||
| const emailAdapter = MockEmailAdapterWithOptions({ | ||
| sendPasswordResetEmail: ({ link }) => { | ||
| emailCalls.push(link); | ||
| return Promise.resolve(); | ||
| }, | ||
| }); | ||
|
|
||
| await reconfigureServer({ | ||
| appName: 'test-app', | ||
| publicServerURL: () => { | ||
| counter++; | ||
| return `https://example.com/${counter}`; | ||
| }, | ||
| emailAdapter, | ||
| }); | ||
|
|
||
| // Create a user | ||
| const user = new Parse.User(); | ||
| user.setUsername('user'); | ||
| user.setPassword('pass'); | ||
| user.setEmail('[email protected]'); | ||
| await user.signUp(); | ||
|
|
||
| // Should use first publicServerURL | ||
| const counterBefore1 = counter; | ||
| await Parse.User.requestPasswordReset('[email protected]'); | ||
| await jasmine.timeout(); | ||
| expect(emailCalls.length).toEqual(1); | ||
| expect(emailCalls[0]).toContain(`https://example.com/${counterBefore1 + 1}`); | ||
| expect(counter).toBeGreaterThanOrEqual(2); | ||
|
|
||
| // Should use updated publicServerURL | ||
| const counterBefore2 = counter; | ||
| await Parse.User.requestPasswordReset('[email protected]'); | ||
| await jasmine.timeout(); | ||
| expect(emailCalls.length).toEqual(2); | ||
| expect(emailCalls[1]).toContain(`https://example.com/${counterBefore2 + 1}`); | ||
| expect(counterBefore2).toBeGreaterThan(counterBefore1); | ||
| }); | ||
|
|
||
| it('executes publicServerURL function on every verification email', async () => { | ||
| let counter = 0; | ||
| const emailCalls = []; | ||
|
|
||
| const emailAdapter = MockEmailAdapterWithOptions({ | ||
| sendVerificationEmail: ({ link }) => { | ||
| emailCalls.push(link); | ||
| return Promise.resolve(); | ||
| }, | ||
| }); | ||
|
|
||
| await reconfigureServer({ | ||
| appName: 'test-app', | ||
| verifyUserEmails: true, | ||
| publicServerURL: () => { | ||
| counter++; | ||
| return `https://example.com/${counter}`; | ||
| }, | ||
| emailAdapter, | ||
| }); | ||
|
|
||
| // Should trigger verification email with first publicServerURL | ||
| const counterBefore1 = counter; | ||
| const user1 = new Parse.User(); | ||
| user1.setUsername('user1'); | ||
| user1.setPassword('pass1'); | ||
| user1.setEmail('[email protected]'); | ||
| await user1.signUp(); | ||
| await jasmine.timeout(); | ||
| expect(emailCalls.length).toEqual(1); | ||
| expect(emailCalls[0]).toContain(`https://example.com/${counterBefore1 + 1}`); | ||
|
|
||
| // Should trigger verification email with updated publicServerURL | ||
| const counterBefore2 = counter; | ||
| const user2 = new Parse.User(); | ||
| user2.setUsername('user2'); | ||
| user2.setPassword('pass2'); | ||
| user2.setEmail('[email protected]'); | ||
| await user2.signUp(); | ||
| await jasmine.timeout(); | ||
| expect(emailCalls.length).toEqual(2); | ||
| expect(emailCalls[1]).toContain(`https://example.com/${counterBefore2 + 1}`); | ||
| expect(counterBefore2).toBeGreaterThan(counterBefore1); | ||
| }); | ||
| }); | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.