Conversation
This module provides a factory function to create browser-compatible location objects that work consistently across NativeScript environments. Fixes issues with: - window.location.protocol missing colon - Missing hostname, port, origin, pathname properties - Undefined values causing FreeWheel orig parameter to be malformed - Inconsistency between window.location and globalThis.location
CRITICAL FIXES: 1. Add missing response properties: response, responseURL 2. Add timeout support with proper event handling 3. Fix loadend dispatch - must fire for ALL terminal events (load, error, timeout, abort) 4. Populate statusText before callbacks fire 5. Separate error/abort/timeout callbacks from load callback 6. Add proper state transition logging 7. Preserve full URL through request chain 8. Handle non-2xx HTTP responses correctly (not as errors) 9. Add diagnostic logging support for FreeWheel debugging These changes ensure: - FreeWheel receives response before 5-second timeout - All callback handlers execute in correct order - Complex query strings (semicolons, ampersands, encoding) preserved - Multiple concurrent XHR instances remain isolated - Response status/body available before onload callback
- Add protocol colon (file: not file) - Add all missing properties: hostname, port, origin, pathname, search, hash - Set globalThis.location to match window.location - Ensure encodeURIComponent(location.protocol + '//' + location.host) works correctly
- Add protocol colon (file: not file) - Add all missing properties: hostname, port, origin, pathname, search, hash - Set globalThis.location to match window.location - Ensure encodeURIComponent(location.protocol + '//' + location.host) works correctly
- Add protocol colon (file: not file) - Add all missing properties: hostname, port, origin, pathname, search, hash - Set globalThis.location to match window.location - Ensure encodeURIComponent(location.protocol + '//' + location.host) works correctly
Documents: - All 8 files changed - Root causes and fixes for each - Before/after code comparisons - Test strategy and verification - Performance impact - Backward compatibility assurance - Rollback procedures - Future enhancements
Contributor
Contributor
There was a problem hiding this comment.
Pull request overview
This PR targets FreeWheel compatibility in the NativeScript JS runtime by making window.location values more browser-like and bringing the XMLHttpRequest polyfill closer to W3C event/property semantics, with added tests and diagnostic tooling to aid debugging.
Changes:
- Updated the XHR polyfill to add W3C properties (
response,responseURL,timeout) and refine terminal event dispatch (loadvserror/timeout/abort+loadend). - Standardized
window.locationobjects across runtime initialization paths to avoid malformedprotocol + "//" + hostvalues used by FreeWheel. - Added new tests and documentation covering location encoding and XHR lifecycle expectations.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| utils/xhrdiagnostics.js | Adds an optional XHR lifecycle diagnostic logger (new utility). |
| utils/xhr.js | Enhances XHR polyfill with timeout/response properties and adjusted event semantics. |
| utils/window.js | Replaces minimal window.location stub with a fuller, FreeWheel-compatible shape; also re-indents existing code. |
| utils/location.js | Adds a location object factory for creating standardized location objects (new utility). |
| test/xhr.test.js | Adds a standalone test suite for XHR/location behavior and event dispatch expectations. |
| test/location-encoding.test.js | Adds encoding-focused tests for FreeWheel-style orig construction. |
| src/jsc/modules/windowwrapper.js | Updates JSC window wrapper location shape and syncs globalThis.location. |
| src/jsc/modules/linkedjsdomwrapper.js | Updates linked JSDOM wrapper location shape and syncs globalThis.location. |
| FREEWHEEL_FIX_SUMMARY.md | Adds a detailed write-up of the problem, root causes, and the implemented changes. |
Suppressed comments (5)
utils/xhr.js:571
- The transport 'abort' handler always converts an abort into handleError(), which results in an 'error' event firing for intentional aborts/timeouts. It should ignore aborts once the XHR is already in a terminal state (sendFlag cleared / errorFlag set).
if (typeof request.on === "function") {
request.on("abort", function() {
if (timeoutHandle) {
clearTimeout(timeoutHandle);
timeoutHandle = null;
}
self.handleError(new Error("XMLHttpRequest: request aborted by transport"));
});
}
utils/xhr.js:553
- The request-level error/abort handlers always call handleError(). When abort() or the timeout path aborts the underlying transport, these handlers can incorrectly dispatch an 'error' event (and an extra loadend) for what should be an abort/timeout terminal event.
// Error handler for the request
var errorHandler = function errorHandler(error) {
if (timeoutHandle) {
clearTimeout(timeoutHandle);
timeoutHandle = null;
}
self.handleError(error);
};
utils/xhr.js:599
- In the timeout path, request.abort() is called before sendFlag/errorFlag are updated. If the transport emits an 'abort' or 'error' event immediately, the request-level handlers can still call handleError() and dispatch an erroneous 'error' event in addition to 'timeout'.
if (self.timeout > 0) {
timeoutHandle = setTimeout(function() {
if (sendFlag && request) {
logDiag('timeout fired after ' + self.timeout + 'ms, aborting request');
request.abort();
request = null;
sendFlag = false;
self.status = 0;
self.statusText = 'Timeout';
self.responseText = '';
self.response = '';
errorFlag = true;
setState(self.DONE);
// Per W3C spec, dispatch timeout event
self.dispatchEvent('timeout');
// After timeout, must dispatch loadend
self.dispatchEvent('loadend');
}
}, self.timeout);
}
utils/xhr.js:665
- abort() calls request.abort() before setting sendFlag/errorFlag. If the transport emits 'abort'/'error' synchronously, the request-level handlers can still call handleError() and dispatch an 'error' event in addition to the intended abort/loadend events.
if (request) {
request.abort();
request = null;
}
utils/window.js:215
- Performance.clearMarks() iterates
entries, but that identifier is not defined in this method (it was a local in mark()). This will throw and leave marks uncleared; use this.entries instead.
clearMarks()
{
for (var key in entries)
{
entries[key] = null;
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| entries[name]['startTime'] = Date.now(); | ||
| console.log("KRISHNA MARKING2 " + name); | ||
| } | ||
| if (options != undefined && option['detail'] != undefined) |
Comment on lines
222
to
227
| this.statusText = null; | ||
| this.responseText = ""; | ||
| this.responseXML = ""; | ||
| this.response = ""; | ||
| this.responseURL = ""; | ||
| this.readyState = this.UNSENT; |
|
|
||
| TestRunner.it('xhr.open changes readyState to OPENED (1)', function() { | ||
| var xhr = new XMLHttpRequest(); | ||
| xhr.open('GET', 'http://example.com', true); |
|
|
||
| TestRunner.it('xhr.open resets status to 0', function() { | ||
| var xhr = new XMLHttpRequest(); | ||
| xhr.open('GET', 'http://example.com', true); |
|
|
||
| TestRunner.it('xhr.open resets responseText', function() { | ||
| var xhr = new XMLHttpRequest(); | ||
| xhr.open('GET', 'http://example.com', true); |
|
|
||
| TestRunner.it('xhr.open resets response', function() { | ||
| var xhr = new XMLHttpRequest(); | ||
| xhr.open('GET', 'http://example.com', true); |
| }); | ||
|
|
||
| // Simulate error by calling handleError | ||
| xhr.open('GET', 'http://example.com', true); |
| loadendCalled = true; | ||
| }); | ||
|
|
||
| xhr.open('GET', 'http://example.com', true); |
| var xhr1 = new XMLHttpRequest(); | ||
| var xhr2 = new XMLHttpRequest(); | ||
|
|
||
| xhr1.open('GET', 'http://example1.com', true); |
| var xhr2 = new XMLHttpRequest(); | ||
|
|
||
| xhr1.open('GET', 'http://example1.com', true); | ||
| xhr2.open('GET', 'http://example2.com', true); |
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
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
No description provided.