Skip to content

Commit b8e1af9

Browse files
authored
Shouldn't retry on bad access denied and bad request (#454)
fix(retry): shouldn't retry on bad access denied and bad request Fixed issue because of which client retried for both bad request and access denied. refactor(subscription): add channels and groups to connected status Add current list of channels and groups to connected status.
1 parent fc389df commit b8e1af9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+415
-205
lines changed

.pubnub.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
---
22
changelog:
3+
- date: 2025-04-22
4+
version: v9.5.2
5+
changes:
6+
- type: bug
7+
text: "Fixed issue because of which client retried for both bad request and access denied."
8+
- type: improvement
9+
text: "Add current list of channels and groups to connected status."
310
- date: 2025-04-15
411
version: v9.5.1
512
changes:
@@ -1229,7 +1236,7 @@ supported-platforms:
12291236
- 'Ubuntu 14.04 and up'
12301237
- 'Windows 7 and up'
12311238
version: 'Pubnub Javascript for Node'
1232-
version: '9.5.1'
1239+
version: '9.5.2'
12331240
sdks:
12341241
- full-name: PubNub Javascript SDK
12351242
short-name: Javascript
@@ -1245,7 +1252,7 @@ sdks:
12451252
- distribution-type: source
12461253
distribution-repository: GitHub release
12471254
package-name: pubnub.js
1248-
location: https://github.com/pubnub/javascript/archive/refs/tags/v9.5.1.zip
1255+
location: https://github.com/pubnub/javascript/archive/refs/tags/v9.5.2.zip
12491256
requires:
12501257
- name: 'agentkeepalive'
12511258
min-version: '3.5.2'
@@ -1916,7 +1923,7 @@ sdks:
19161923
- distribution-type: library
19171924
distribution-repository: GitHub release
19181925
package-name: pubnub.js
1919-
location: https://github.com/pubnub/javascript/releases/download/v9.5.1/pubnub.9.5.1.js
1926+
location: https://github.com/pubnub/javascript/releases/download/v9.5.2/pubnub.9.5.2.js
19201927
requires:
19211928
- name: 'agentkeepalive'
19221929
min-version: '3.5.2'

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## v9.5.2
2+
April 22 2025
3+
4+
#### Fixed
5+
- Fixed issue because of which client retried for both bad request and access denied.
6+
7+
#### Modified
8+
- Add current list of channels and groups to connected status.
9+
110
## v9.5.1
211
April 15 2025
312

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ Watch [Getting Started with PubNub JS SDK](https://app.dashcam.io/replay/64ee0d2
2727
npm install pubnub
2828
```
2929
* or download one of our builds from our CDN:
30-
* https://cdn.pubnub.com/sdk/javascript/pubnub.9.5.1.js
31-
* https://cdn.pubnub.com/sdk/javascript/pubnub.9.5.1.min.js
30+
* https://cdn.pubnub.com/sdk/javascript/pubnub.9.5.2.js
31+
* https://cdn.pubnub.com/sdk/javascript/pubnub.9.5.2.min.js
3232
3333
2. Configure your keys:
3434

dist/web/pubnub.js

Lines changed: 122 additions & 55 deletions
Large diffs are not rendered by default.

dist/web/pubnub.min.js

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

lib/core/components/configuration.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ const makeConfiguration = (base, setupCryptoModule) => {
144144
return base.PubNubFile;
145145
},
146146
get version() {
147-
return '9.5.1';
147+
return '9.5.2';
148148
},
149149
getVersion() {
150150
return this.version;

lib/core/components/retryPolicy.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,13 @@ exports.RetryPolicy = RetryPolicy;
203203
* @internal
204204
*/
205205
const isRetriableRequest = (req, res, errorCategory, retryAttempt, maximumRetry, excluded) => {
206-
if (errorCategory && errorCategory === categories_1.default.PNCancelledCategory)
207-
return false;
208-
else if (isExcludedRequest(req, excluded))
206+
if (errorCategory) {
207+
if (errorCategory === categories_1.default.PNCancelledCategory ||
208+
errorCategory === categories_1.default.PNBadRequestCategory ||
209+
errorCategory === categories_1.default.PNAccessDeniedCategory)
210+
return false;
211+
}
212+
if (isExcludedRequest(req, excluded))
209213
return false;
210214
else if (retryAttempt > maximumRetry)
211215
return false;

lib/core/pubnub-common.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -636,11 +636,11 @@ class PubNubCore {
636636
this.subscriptionManager.disconnect();
637637
}
638638
else if (this.eventEngine)
639-
this.eventEngine.dispose();
640-
if (process.env.PRESENCE_MODULE !== 'disabled') {
641-
if (this.presenceEventEngine)
642-
this.presenceEventEngine.dispose();
643-
}
639+
this.eventEngine.unsubscribeAll(isOffline);
640+
}
641+
if (process.env.PRESENCE_MODULE !== 'disabled') {
642+
if (this.presenceEventEngine)
643+
this.presenceEventEngine.leaveAll(isOffline);
644644
}
645645
}
646646
/**
@@ -1417,11 +1417,11 @@ class PubNubCore {
14171417
*
14181418
* @param parameters - List of channels and groups where `leave` event should be sent.
14191419
*/
1420-
leaveAll(parameters) {
1420+
leaveAll(parameters = {}) {
14211421
if (process.env.PRESENCE_MODULE !== 'disabled') {
14221422
if (this.presenceEventEngine)
1423-
this.presenceEventEngine.leaveAll();
1424-
else
1423+
this.presenceEventEngine.leaveAll(parameters.isOffline);
1424+
else if (!parameters.isOffline)
14251425
this.makeUnsubscribe({ channels: parameters.channels, channelGroups: parameters.groups }, () => { });
14261426
}
14271427
else

lib/event-engine/events.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ const core_1 = require("./core");
1414
*
1515
* @internal
1616
*/
17-
exports.subscriptionChange = (0, core_1.createEvent)('SUBSCRIPTION_CHANGED', (channels, groups) => ({
17+
exports.subscriptionChange = (0, core_1.createEvent)('SUBSCRIPTION_CHANGED', (channels, groups, isOffline) => ({
1818
channels,
1919
groups,
20+
isOffline,
2021
}));
2122
/**
2223
* Subscription loop restore.

lib/event-engine/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class EventEngine {
114114
}
115115
}
116116
}
117-
unsubscribeAll() {
117+
unsubscribeAll(isOffline) {
118118
const channelGroups = this.getSubscribedChannels();
119119
const channels = this.getSubscribedChannels();
120120
this.channels = [];
@@ -124,9 +124,9 @@ class EventEngine {
124124
delete this.dependencies.presenceState[objectName];
125125
});
126126
}
127-
this.engine.transition(events.subscriptionChange(this.channels.slice(0), this.groups.slice(0)));
127+
this.engine.transition(events.subscriptionChange(this.channels.slice(0), this.groups.slice(0), isOffline));
128128
if (this.dependencies.leaveAll)
129-
this.dependencies.leaveAll({ channels, groups: channelGroups });
129+
this.dependencies.leaveAll({ channels, groups: channelGroups, isOffline });
130130
}
131131
reconnect({ timetoken, region }) {
132132
const channelGroups = this.getSubscribedChannels();

lib/event-engine/presence/events.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ exports.left = (0, core_1.createEvent)('LEFT', (channels, groups) => ({
5757
*
5858
* @internal
5959
*/
60-
exports.leftAll = (0, core_1.createEvent)('LEFT_ALL', () => ({}));
60+
exports.leftAll = (0, core_1.createEvent)('LEFT_ALL', (isOffline) => ({ isOffline }));
6161
/**
6262
* Presence heartbeat success event.
6363
*

lib/event-engine/presence/presence.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ class PresenceEventEngine {
7777
}
7878
this.engine.transition(events.left(channels !== null && channels !== void 0 ? channels : [], groups !== null && groups !== void 0 ? groups : []));
7979
}
80-
leaveAll() {
81-
this.engine.transition(events.leftAll());
80+
leaveAll(isOffline) {
81+
this.engine.transition(events.leftAll(isOffline));
8282
}
8383
reconnect() {
8484
this.engine.transition(events.reconnect());

lib/event-engine/presence/states/heartbeat_cooldown.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,6 @@ exports.HeartbeatCooldownState.on(events_1.left.type, (context, event) => heartb
3737
exports.HeartbeatCooldownState.on(events_1.disconnect.type, (context, event) => heartbeat_stopped_1.HeartbeatStoppedState.with({ channels: context.channels, groups: context.groups }, [
3838
...(!event.payload.isOffline ? [(0, effects_1.leave)(context.channels, context.groups)] : []),
3939
]));
40-
exports.HeartbeatCooldownState.on(events_1.leftAll.type, (context, _) => heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [(0, effects_1.leave)(context.channels, context.groups)]));
40+
exports.HeartbeatCooldownState.on(events_1.leftAll.type, (context, event) => heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [
41+
...(!event.payload.isOffline ? [(0, effects_1.leave)(context.channels, context.groups)] : []),
42+
]));

lib/event-engine/presence/states/heartbeat_failed.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,6 @@ exports.HeartbeatFailedState.on(events_1.reconnect.type, (context, _) => heartbe
3636
exports.HeartbeatFailedState.on(events_1.disconnect.type, (context, event) => heartbeat_stopped_1.HeartbeatStoppedState.with({ channels: context.channels, groups: context.groups }, [
3737
...(!event.payload.isOffline ? [(0, effects_1.leave)(context.channels, context.groups)] : []),
3838
]));
39-
exports.HeartbeatFailedState.on(events_1.leftAll.type, (context, _) => heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [(0, effects_1.leave)(context.channels, context.groups)]));
39+
exports.HeartbeatFailedState.on(events_1.leftAll.type, (context, event) => heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [
40+
...(!event.payload.isOffline ? [(0, effects_1.leave)(context.channels, context.groups)] : []),
41+
]));

lib/event-engine/presence/states/heartbeating.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ exports.HeartbeatingState.on(events_1.heartbeatFailure.type, (context, event) =>
4242
exports.HeartbeatingState.on(events_1.disconnect.type, (context, event) => heartbeat_stopped_1.HeartbeatStoppedState.with({ channels: context.channels, groups: context.groups }, [
4343
...(!event.payload.isOffline ? [(0, effects_1.leave)(context.channels, context.groups)] : []),
4444
]));
45-
exports.HeartbeatingState.on(events_1.leftAll.type, (context, _) => heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [(0, effects_1.leave)(context.channels, context.groups)]));
45+
exports.HeartbeatingState.on(events_1.leftAll.type, (context, event) => heartbeat_inactive_1.HeartbeatInactiveState.with(undefined, [
46+
...(!event.payload.isOffline ? [(0, effects_1.leave)(context.channels, context.groups)] : []),
47+
]));

lib/event-engine/states/handshake_failed.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,20 @@ const unsubscribed_1 = require("./unsubscribed");
1919
* @internal
2020
*/
2121
exports.HandshakeFailedState = new state_1.State('HANDSHAKE_FAILED');
22-
exports.HandshakeFailedState.on(events_1.subscriptionChange.type, (context, { payload }) => handshaking_1.HandshakingState.with({ channels: payload.channels, groups: payload.groups, cursor: context.cursor }));
22+
exports.HandshakeFailedState.on(events_1.subscriptionChange.type, (context, { payload }) => {
23+
if (payload.channels.length === 0 && payload.groups.length === 0)
24+
return unsubscribed_1.UnsubscribedState.with(undefined);
25+
return handshaking_1.HandshakingState.with({ channels: payload.channels, groups: payload.groups, cursor: context.cursor });
26+
});
2327
exports.HandshakeFailedState.on(events_1.reconnect.type, (context, { payload }) => handshaking_1.HandshakingState.with({
2428
channels: context.channels,
2529
groups: context.groups,
2630
cursor: payload.cursor || context.cursor,
2731
}));
2832
exports.HandshakeFailedState.on(events_1.restore.type, (context, { payload }) => {
2933
var _a, _b;
34+
if (payload.channels.length === 0 && payload.groups.length === 0)
35+
return unsubscribed_1.UnsubscribedState.with(undefined);
3036
return handshaking_1.HandshakingState.with({
3137
channels: payload.channels,
3238
groups: payload.groups,

lib/event-engine/states/handshake_stopped.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,16 @@ const unsubscribed_1 = require("./unsubscribed");
1919
* @internal
2020
*/
2121
exports.HandshakeStoppedState = new state_1.State('HANDSHAKE_STOPPED');
22-
exports.HandshakeStoppedState.on(events_1.subscriptionChange.type, (context, { payload }) => exports.HandshakeStoppedState.with({ channels: payload.channels, groups: payload.groups, cursor: context.cursor }));
22+
exports.HandshakeStoppedState.on(events_1.subscriptionChange.type, (context, { payload }) => {
23+
if (payload.channels.length === 0 && payload.groups.length === 0)
24+
return unsubscribed_1.UnsubscribedState.with(undefined);
25+
return exports.HandshakeStoppedState.with({ channels: payload.channels, groups: payload.groups, cursor: context.cursor });
26+
});
2327
exports.HandshakeStoppedState.on(events_1.reconnect.type, (context, { payload }) => handshaking_1.HandshakingState.with(Object.assign(Object.assign({}, context), { cursor: payload.cursor || context.cursor })));
2428
exports.HandshakeStoppedState.on(events_1.restore.type, (context, { payload }) => {
2529
var _a;
30+
if (payload.channels.length === 0 && payload.groups.length === 0)
31+
return unsubscribed_1.UnsubscribedState.with(undefined);
2632
return exports.HandshakeStoppedState.with({
2733
channels: payload.channels,
2834
groups: payload.groups,

lib/event-engine/states/handshaking.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,22 @@ exports.HandshakingState.on(events_1.subscriptionChange.type, (context, { payloa
3636
return exports.HandshakingState.with({ channels: payload.channels, groups: payload.groups, cursor: context.cursor });
3737
});
3838
exports.HandshakingState.on(events_1.handshakeSuccess.type, (context, { payload }) => {
39-
var _a, _b;
39+
var _a, _b, _c, _d;
4040
return receiving_1.ReceivingState.with({
4141
channels: context.channels,
4242
groups: context.groups,
4343
cursor: {
4444
timetoken: !!((_a = context.cursor) === null || _a === void 0 ? void 0 : _a.timetoken) ? (_b = context.cursor) === null || _b === void 0 ? void 0 : _b.timetoken : payload.timetoken,
4545
region: payload.region,
4646
},
47-
}, [(0, effects_1.emitStatus)({ category: categories_1.default.PNConnectedCategory })]);
47+
}, [
48+
(0, effects_1.emitStatus)({
49+
category: categories_1.default.PNConnectedCategory,
50+
affectedChannels: context.channels.slice(0),
51+
affectedChannelGroups: context.groups.slice(0),
52+
currentTimetoken: !!((_c = context.cursor) === null || _c === void 0 ? void 0 : _c.timetoken) ? (_d = context.cursor) === null || _d === void 0 ? void 0 : _d.timetoken : payload.timetoken,
53+
}),
54+
]);
4855
});
4956
exports.HandshakingState.on(events_1.handshakeFailure.type, (context, event) => {
5057
var _a;
@@ -71,6 +78,8 @@ exports.HandshakingState.on(events_1.disconnect.type, (context, event) => {
7178
});
7279
exports.HandshakingState.on(events_1.restore.type, (context, { payload }) => {
7380
var _a;
81+
if (payload.channels.length === 0 && payload.groups.length === 0)
82+
return unsubscribed_1.UnsubscribedState.with(undefined);
7483
return exports.HandshakingState.with({
7584
channels: payload.channels,
7685
groups: payload.groups,

lib/event-engine/states/receive_failed.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,18 @@ exports.ReceiveFailedState.on(events_1.reconnect.type, (context, { payload }) =>
3030
},
3131
});
3232
});
33-
exports.ReceiveFailedState.on(events_1.subscriptionChange.type, (context, { payload }) => handshaking_1.HandshakingState.with({ channels: payload.channels, groups: payload.groups, cursor: context.cursor }));
34-
exports.ReceiveFailedState.on(events_1.restore.type, (context, { payload }) => handshaking_1.HandshakingState.with({
35-
channels: payload.channels,
36-
groups: payload.groups,
37-
cursor: { timetoken: payload.cursor.timetoken, region: payload.cursor.region || context.cursor.region },
38-
}));
33+
exports.ReceiveFailedState.on(events_1.subscriptionChange.type, (context, { payload }) => {
34+
if (payload.channels.length === 0 && payload.groups.length === 0)
35+
return unsubscribed_1.UnsubscribedState.with(undefined);
36+
return handshaking_1.HandshakingState.with({ channels: payload.channels, groups: payload.groups, cursor: context.cursor });
37+
});
38+
exports.ReceiveFailedState.on(events_1.restore.type, (context, { payload }) => {
39+
if (payload.channels.length === 0 && payload.groups.length === 0)
40+
return unsubscribed_1.UnsubscribedState.with(undefined);
41+
return handshaking_1.HandshakingState.with({
42+
channels: payload.channels,
43+
groups: payload.groups,
44+
cursor: { timetoken: payload.cursor.timetoken, region: payload.cursor.region || context.cursor.region },
45+
});
46+
});
3947
exports.ReceiveFailedState.on(events_1.unsubscribeAll.type, (_) => unsubscribed_1.UnsubscribedState.with(undefined));

lib/event-engine/states/receive_stopped.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,20 @@ const unsubscribed_1 = require("./unsubscribed");
1919
* @internal
2020
*/
2121
exports.ReceiveStoppedState = new state_1.State('RECEIVE_STOPPED');
22-
exports.ReceiveStoppedState.on(events_1.subscriptionChange.type, (context, { payload }) => exports.ReceiveStoppedState.with({ channels: payload.channels, groups: payload.groups, cursor: context.cursor }));
23-
exports.ReceiveStoppedState.on(events_1.restore.type, (context, { payload }) => exports.ReceiveStoppedState.with({
24-
channels: payload.channels,
25-
groups: payload.groups,
26-
cursor: { timetoken: payload.cursor.timetoken, region: payload.cursor.region || context.cursor.region },
27-
}));
22+
exports.ReceiveStoppedState.on(events_1.subscriptionChange.type, (context, { payload }) => {
23+
if (payload.channels.length === 0 && payload.groups.length === 0)
24+
return unsubscribed_1.UnsubscribedState.with(undefined);
25+
return exports.ReceiveStoppedState.with({ channels: payload.channels, groups: payload.groups, cursor: context.cursor });
26+
});
27+
exports.ReceiveStoppedState.on(events_1.restore.type, (context, { payload }) => {
28+
if (payload.channels.length === 0 && payload.groups.length === 0)
29+
return unsubscribed_1.UnsubscribedState.with(undefined);
30+
return exports.ReceiveStoppedState.with({
31+
channels: payload.channels,
32+
groups: payload.groups,
33+
cursor: { timetoken: payload.cursor.timetoken, region: payload.cursor.region || context.cursor.region },
34+
});
35+
});
2836
exports.ReceiveStoppedState.on(events_1.reconnect.type, (context, { payload }) => {
2937
var _a;
3038
return handshaking_1.HandshakingState.with({

0 commit comments

Comments
 (0)