Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions .pubnub.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
---
changelog:
- date: 2025-02-26
version: v8.9.1
changes:
- type: bug
text: "Fix issue because of which code doesn't handle edge case when `fetch` reject with empty object and not `Error`."
- type: improvement
text: "Remove `-pnpres` channels and groups from presence `leave` and `heartbeat` requests."
- date: 2025-02-18
version: v8.9.0
changes:
Expand Down Expand Up @@ -1144,7 +1151,7 @@ supported-platforms:
- 'Ubuntu 14.04 and up'
- 'Windows 7 and up'
version: 'Pubnub Javascript for Node'
version: '8.9.0'
version: '8.9.1'
sdks:
- full-name: PubNub Javascript SDK
short-name: Javascript
Expand All @@ -1160,7 +1167,7 @@ sdks:
- distribution-type: source
distribution-repository: GitHub release
package-name: pubnub.js
location: https://github.com/pubnub/javascript/archive/refs/tags/v8.9.0.zip
location: https://github.com/pubnub/javascript/archive/refs/tags/v8.9.1.zip
requires:
- name: 'agentkeepalive'
min-version: '3.5.2'
Expand Down Expand Up @@ -1831,7 +1838,7 @@ sdks:
- distribution-type: library
distribution-repository: GitHub release
package-name: pubnub.js
location: https://github.com/pubnub/javascript/releases/download/v8.9.0/pubnub.8.9.0.js
location: https://github.com/pubnub/javascript/releases/download/v8.9.1/pubnub.8.9.1.js
requires:
- name: 'agentkeepalive'
min-version: '3.5.2'
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## v8.9.1
February 26 2025

#### Fixed
- Fix issue because of which code doesn't handle edge case when `fetch` reject with empty object and not `Error`.

#### Modified
- Remove `-pnpres` channels and groups from presence `leave` and `heartbeat` requests.

## v8.9.0
February 18 2025

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ Watch [Getting Started with PubNub JS SDK](https://app.dashcam.io/replay/64ee0d2
npm install pubnub
```
* or download one of our builds from our CDN:
* https://cdn.pubnub.com/sdk/javascript/pubnub.8.9.0.js
* https://cdn.pubnub.com/sdk/javascript/pubnub.8.9.0.min.js
* https://cdn.pubnub.com/sdk/javascript/pubnub.8.9.1.js
* https://cdn.pubnub.com/sdk/javascript/pubnub.8.9.1.min.js

2. Configure your keys:

Expand Down
113 changes: 94 additions & 19 deletions dist/web/pubnub.js
Original file line number Diff line number Diff line change
Expand Up @@ -2890,7 +2890,7 @@
*
* @param errorOrResponse - `Error` or service error response object from which error information
* should be extracted.
* @param data - Preprocessed service error response.
* @param [data] - Preprocessed service error response.
*
* @returns `PubNubAPIError` object with known error category and additional information (if
* available).
Expand Down Expand Up @@ -2969,7 +2969,7 @@
*
* @param response - Service error response object from which error information should be
* extracted.
* @param data - Preprocessed service error response.
* @param [data] - Preprocessed service error response.
*
* @returns `PubNubAPIError` object with known error category and additional information (if
* available).
Expand All @@ -2990,6 +2990,11 @@
category = StatusCategory$1.PNAccessDeniedCategory;
message = 'Access denied';
}
if (typeof response === 'object' && Object.keys(response).length === 0) {
category = StatusCategory$1.PNMalformedResponseCategory;
message = 'Malformed response (network issues)';
status = 400;
}
// Try to get more information about error from service response.
if (data && data.byteLength > 0) {
const decoded = new TextDecoder().decode(data);
Expand Down Expand Up @@ -3042,7 +3047,7 @@
* @param message - Short API call error description.
* @param category - Error category.
* @param statusCode - Response HTTP status code.
* @param errorData - Error information.
* @param [errorData] - Error information.
*/
constructor(message, category, statusCode, errorData) {
super(message);
Expand All @@ -3065,19 +3070,58 @@
operation,
statusCode: this.statusCode,
errorData: this.errorData,
// @ts-expect-error Inner helper for JSON.stringify.
toJSON: function () {
let normalizedErrorData;
const errorData = this.errorData;
if (errorData) {
try {
if (typeof errorData === 'object') {
const errorObject = Object.assign(Object.assign(Object.assign(Object.assign({}, ('name' in errorData ? { name: errorData.name } : {})), ('message' in errorData ? { message: errorData.message } : {})), ('stack' in errorData ? { stack: errorData.stack } : {})), errorData);
normalizedErrorData = JSON.parse(JSON.stringify(errorObject, PubNubAPIError.circularReplacer()));
}
else
normalizedErrorData = errorData;
}
catch (_) {
normalizedErrorData = { error: 'Could not serialize the error object' };
}
}
// Make sure to exclude `toJSON` function from the final object.
const _a = this, status = __rest(_a, ["toJSON"]);
return JSON.stringify(Object.assign(Object.assign({}, status), { errorData: normalizedErrorData }));
},
};
}
/**
* Convert API error object to PubNub client error object.
*
* @param operation - Request operation during which error happened.
* @param message - Custom error message.
* @param [message] - Custom error message.
*
* @returns Client-facing pre-formatted endpoint call error.
*/
toPubNubError(operation, message) {
return new PubNubError(message !== null && message !== void 0 ? message : this.message, this.toStatus(operation));
}
/**
* Function which handles circular references in serialized JSON.
*
* @returns Circular reference replacer function.
*
* @internal
*/
static circularReplacer() {
const visited = new WeakSet();
return function (_, value) {
if (typeof value === 'object' && value !== null) {
if (visited.has(value))
return '[Circular]';
visited.add(value);
}
return value;
};
}
}

/**
Expand Down Expand Up @@ -3759,7 +3803,7 @@
return base.PubNubFile;
},
get version() {
return '8.9.0';
return '8.9.1';
},
getVersion() {
return this.version;
Expand Down Expand Up @@ -4273,10 +4317,9 @@
let fetchError = error;
if (typeof error === 'string') {
const errorMessage = error.toLowerCase();
if (errorMessage.includes('timeout') || !errorMessage.includes('cancel'))
fetchError = new Error(error);
else if (errorMessage.includes('cancel'))
fetchError = new DOMException('Aborted', 'AbortError');
fetchError = new Error(error);
if (!errorMessage.includes('timeout') && errorMessage.includes('cancel'))
fetchError.name = 'AbortError';
}
throw PubNubAPIError.create(fetchError);
});
Expand Down Expand Up @@ -5036,7 +5079,8 @@
if (status.category === StatusCategory$1.PNTimeoutCategory) {
this.startSubscribeLoop();
}
else if (status.category === StatusCategory$1.PNNetworkIssuesCategory) {
else if (status.category === StatusCategory$1.PNNetworkIssuesCategory ||
status.category === StatusCategory$1.PNMalformedResponseCategory) {
this.disconnect();
if (status.error && this.configuration.autoNetworkDetection && this.isOnline) {
this.isOnline = false;
Expand All @@ -5058,14 +5102,11 @@
this.listenerManager.announceStatus(reconnectedAnnounce);
});
this.reconnectionManager.startPolling();
this.listenerManager.announceStatus(status);
this.listenerManager.announceStatus(Object.assign(Object.assign({}, status), { category: StatusCategory$1.PNNetworkIssuesCategory }));
}
else if (status.category === StatusCategory$1.PNBadRequestCategory ||
status.category == StatusCategory$1.PNMalformedResponseCategory) {
const category = this.isOnline ? StatusCategory$1.PNDisconnectedUnexpectedlyCategory : status.category;
this.isOnline = false;
this.disconnect();
this.listenerManager.announceStatus(Object.assign(Object.assign({}, status), { category }));
else if (status.category === StatusCategory$1.PNBadRequestCategory) {
this.stopHeartbeatTimer();
this.listenerManager.announceStatus(status);
}
else
this.listenerManager.announceStatus(status);
Expand Down Expand Up @@ -13319,7 +13360,22 @@
*/
makeUnsubscribe(parameters, callback) {
{
this.sendRequest(new PresenceLeaveRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })), callback);
// Filtering out presence channels and groups.
let { channels, channelGroups } = parameters;
if (channelGroups)
channelGroups = channelGroups.filter((channelGroup) => !channelGroup.endsWith('-pnpres'));
if (channels)
channels = channels.filter((channel) => !channel.endsWith('-pnpres'));
// Complete immediately request only for presence channels.
if ((channelGroups !== null && channelGroups !== void 0 ? channelGroups : []).length === 0 && (channels !== null && channels !== void 0 ? channels : []).length === 0) {
return callback({
error: false,
operation: RequestOperation$1.PNUnsubscribeOperation,
category: StatusCategory$1.PNAcknowledgmentCategory,
statusCode: 200,
});
}
this.sendRequest(new PresenceLeaveRequest({ channels, channelGroups, keySet: this._configuration.keySet }), callback);
}
}
/**
Expand Down Expand Up @@ -13670,7 +13726,26 @@
heartbeat(parameters, callback) {
return __awaiter(this, void 0, void 0, function* () {
{
const request = new HeartbeatRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet }));
// Filtering out presence channels and groups.
let { channels, channelGroups } = parameters;
if (channelGroups)
channelGroups = channelGroups.filter((channelGroup) => !channelGroup.endsWith('-pnpres'));
if (channels)
channels = channels.filter((channel) => !channel.endsWith('-pnpres'));
// Complete immediately request only for presence channels.
if ((channelGroups !== null && channelGroups !== void 0 ? channelGroups : []).length === 0 && (channels !== null && channels !== void 0 ? channels : []).length === 0) {
const responseStatus = {
error: false,
operation: RequestOperation$1.PNHeartbeatOperation,
category: StatusCategory$1.PNAcknowledgmentCategory,
statusCode: 200,
};
if (callback)
return callback(responseStatus, {});
return Promise.resolve(responseStatus);
}
const request = new HeartbeatRequest(Object.assign(Object.assign({}, parameters), { channels,
channelGroups, keySet: this._configuration.keySet }));
if (callback)
return this.sendRequest(request, callback);
return this.sendRequest(request);
Expand Down
4 changes: 2 additions & 2 deletions dist/web/pubnub.min.js

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions dist/web/pubnub.worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -550,10 +550,9 @@
let fetchError = error;
if (typeof error === 'string') {
const errorMessage = error.toLowerCase();
if (errorMessage.includes('timeout') || !errorMessage.includes('cancel'))
fetchError = new Error(error);
else if (errorMessage.includes('cancel'))
fetchError = new DOMException('Aborted', 'AbortError');
fetchError = new Error(error);
if (!errorMessage.includes('timeout') && errorMessage.includes('cancel'))
fetchError.name = 'AbortError';
}
failure(clients, fetchError);
});
Expand Down Expand Up @@ -1089,9 +1088,10 @@
message = error.message;
name = error.name;
}
if (message.toLowerCase().includes('timeout'))
const errorMessage = message.toLowerCase();
if (errorMessage.includes('timeout'))
type = 'TIMEOUT';
else if (name === 'AbortError' || message.toLowerCase().includes('cancel')) {
else if (name === 'AbortError' || errorMessage.includes('aborted') || errorMessage.includes('cancel')) {
message = 'Request aborted';
type = 'ABORTED';
}
Expand Down
2 changes: 1 addition & 1 deletion dist/web/pubnub.worker.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/core/components/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const makeConfiguration = (base, setupCryptoModule) => {
return base.PubNubFile;
},
get version() {
return '8.9.0';
return '8.9.1';
},
getVersion() {
return this.version;
Expand Down
14 changes: 6 additions & 8 deletions lib/core/components/subscription-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,8 @@ class SubscriptionManager {
if (status.category === categories_1.default.PNTimeoutCategory) {
this.startSubscribeLoop();
}
else if (status.category === categories_1.default.PNNetworkIssuesCategory) {
else if (status.category === categories_1.default.PNNetworkIssuesCategory ||
status.category === categories_1.default.PNMalformedResponseCategory) {
this.disconnect();
if (status.error && this.configuration.autoNetworkDetection && this.isOnline) {
this.isOnline = false;
Expand All @@ -253,14 +254,11 @@ class SubscriptionManager {
this.listenerManager.announceStatus(reconnectedAnnounce);
});
this.reconnectionManager.startPolling();
this.listenerManager.announceStatus(status);
this.listenerManager.announceStatus(Object.assign(Object.assign({}, status), { category: categories_1.default.PNNetworkIssuesCategory }));
}
else if (status.category === categories_1.default.PNBadRequestCategory ||
status.category == categories_1.default.PNMalformedResponseCategory) {
const category = this.isOnline ? categories_1.default.PNDisconnectedUnexpectedlyCategory : status.category;
this.isOnline = false;
this.disconnect();
this.listenerManager.announceStatus(Object.assign(Object.assign({}, status), { category }));
else if (status.category === categories_1.default.PNBadRequestCategory) {
this.stopHeartbeatTimer();
this.listenerManager.announceStatus(status);
}
else
this.listenerManager.announceStatus(status);
Expand Down
38 changes: 36 additions & 2 deletions lib/core/pubnub-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,22 @@ class PubNubCore {
*/
makeUnsubscribe(parameters, callback) {
if (process.env.PRESENCE_MODULE !== 'disabled') {
this.sendRequest(new leave_1.PresenceLeaveRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet })), callback);
// Filtering out presence channels and groups.
let { channels, channelGroups } = parameters;
if (channelGroups)
channelGroups = channelGroups.filter((channelGroup) => !channelGroup.endsWith('-pnpres'));
if (channels)
channels = channels.filter((channel) => !channel.endsWith('-pnpres'));
// Complete immediately request only for presence channels.
if ((channelGroups !== null && channelGroups !== void 0 ? channelGroups : []).length === 0 && (channels !== null && channels !== void 0 ? channels : []).length === 0) {
return callback({
error: false,
operation: operations_1.default.PNUnsubscribeOperation,
category: categories_1.default.PNAcknowledgmentCategory,
statusCode: 200,
});
}
this.sendRequest(new leave_1.PresenceLeaveRequest({ channels, channelGroups, keySet: this._configuration.keySet }), callback);
}
else
throw new Error('Unsubscription error: presence module disabled');
Expand Down Expand Up @@ -1284,7 +1299,26 @@ class PubNubCore {
heartbeat(parameters, callback) {
return __awaiter(this, void 0, void 0, function* () {
if (process.env.PRESENCE_MODULE !== 'disabled') {
const request = new heartbeat_1.HeartbeatRequest(Object.assign(Object.assign({}, parameters), { keySet: this._configuration.keySet }));
// Filtering out presence channels and groups.
let { channels, channelGroups } = parameters;
if (channelGroups)
channelGroups = channelGroups.filter((channelGroup) => !channelGroup.endsWith('-pnpres'));
if (channels)
channels = channels.filter((channel) => !channel.endsWith('-pnpres'));
// Complete immediately request only for presence channels.
if ((channelGroups !== null && channelGroups !== void 0 ? channelGroups : []).length === 0 && (channels !== null && channels !== void 0 ? channels : []).length === 0) {
const responseStatus = {
error: false,
operation: operations_1.default.PNHeartbeatOperation,
category: categories_1.default.PNAcknowledgmentCategory,
statusCode: 200,
};
if (callback)
return callback(responseStatus, {});
return Promise.resolve(responseStatus);
}
const request = new heartbeat_1.HeartbeatRequest(Object.assign(Object.assign({}, parameters), { channels,
channelGroups, keySet: this._configuration.keySet }));
if (callback)
return this.sendRequest(request, callback);
return this.sendRequest(request);
Expand Down
Loading
Loading