Skip to content

Commit bee8794

Browse files
authored
Compress publish POST body (#450)
feat(publish): compress publish POST body Compress the published payload if sent by POST. feat(request): explicit `Accept-Encoding` header Explicitly add `gzip, deflate` to the `Accept-Encoding` header.
1 parent f1397e8 commit bee8794

36 files changed

+225
-65
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-10
4+
version: v9.4.0
5+
changes:
6+
- type: feature
7+
text: "Compress the published payload if sent by POST."
8+
- type: feature
9+
text: "Explicitly add `gzip, deflate` to the `Accept-Encoding` header."
310
- date: 2025-03-31
411
version: v9.3.2
512
changes:
@@ -1202,7 +1209,7 @@ supported-platforms:
12021209
- 'Ubuntu 14.04 and up'
12031210
- 'Windows 7 and up'
12041211
version: 'Pubnub Javascript for Node'
1205-
version: '9.3.2'
1212+
version: '9.4.0'
12061213
sdks:
12071214
- full-name: PubNub Javascript SDK
12081215
short-name: Javascript
@@ -1218,7 +1225,7 @@ sdks:
12181225
- distribution-type: source
12191226
distribution-repository: GitHub release
12201227
package-name: pubnub.js
1221-
location: https://github.com/pubnub/javascript/archive/refs/tags/v9.3.2.zip
1228+
location: https://github.com/pubnub/javascript/archive/refs/tags/v9.4.0.zip
12221229
requires:
12231230
- name: 'agentkeepalive'
12241231
min-version: '3.5.2'
@@ -1889,7 +1896,7 @@ sdks:
18891896
- distribution-type: library
18901897
distribution-repository: GitHub release
18911898
package-name: pubnub.js
1892-
location: https://github.com/pubnub/javascript/releases/download/v9.3.2/pubnub.9.3.2.js
1899+
location: https://github.com/pubnub/javascript/releases/download/v9.4.0/pubnub.9.4.0.js
18931900
requires:
18941901
- name: 'agentkeepalive'
18951902
min-version: '3.5.2'

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## v9.4.0
2+
April 10 2025
3+
4+
#### Added
5+
- Compress the published payload if sent by POST.
6+
- Explicitly add `gzip, deflate` to the `Accept-Encoding` header.
7+
18
## v9.3.2
29
March 31 2025
310

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.3.2.js
31-
* https://cdn.pubnub.com/sdk/javascript/pubnub.9.3.2.min.js
30+
* https://cdn.pubnub.com/sdk/javascript/pubnub.9.4.0.js
31+
* https://cdn.pubnub.com/sdk/javascript/pubnub.9.4.0.min.js
3232
3333
2. Configure your keys:
3434

dist/web/pubnub.js

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3939,7 +3939,7 @@
39393939
return base.PubNubFile;
39403940
},
39413941
get version() {
3942-
return '9.3.2';
3942+
return '9.4.0';
39433943
},
39443944
getVersion() {
39453945
return this.version;
@@ -4604,8 +4604,20 @@
46044604
body = formData;
46054605
}
46064606
// Handle regular body payload (if passed).
4607-
else if (req.body && (typeof req.body === 'string' || req.body instanceof ArrayBuffer))
4608-
body = req.body;
4607+
else if (req.body && (typeof req.body === 'string' || req.body instanceof ArrayBuffer)) {
4608+
// Compressing body if browser has native support.
4609+
if (req.compressible && typeof CompressionStream !== 'undefined') {
4610+
const bodyStream = new ReadableStream({
4611+
start(controller) {
4612+
controller.enqueue(typeof req.body === 'string' ? WebTransport.encoder.encode(req.body) : req.body);
4613+
controller.close();
4614+
},
4615+
});
4616+
body = yield new Response(bodyStream.pipeThrough(new CompressionStream('deflate'))).arrayBuffer();
4617+
}
4618+
else
4619+
body = req.body;
4620+
}
46094621
if (req.queryParameters && Object.keys(req.queryParameters).length !== 0)
46104622
path = `${path}?${queryStringFromObject(req.queryParameters)}`;
46114623
return {
@@ -4683,6 +4695,12 @@
46834695
return fetch;
46844696
}
46854697
}
4698+
/**
4699+
* Request body decoder.
4700+
*
4701+
* @internal
4702+
*/
4703+
WebTransport.encoder = new TextEncoder();
46864704
/**
46874705
* Service {@link ArrayBuffer} response decoder.
46884706
*
@@ -6092,12 +6110,13 @@
60926110
* @returns Request object which can be processed using platform-specific requirements.
60936111
*/
60946112
request() {
6095-
var _a, _b, _c, _d;
6113+
var _a, _b, _c, _d, _e, _f;
60966114
const request = {
60976115
method: (_b = (_a = this.params) === null || _a === void 0 ? void 0 : _a.method) !== null && _b !== void 0 ? _b : TransportMethod.GET,
60986116
path: this.path,
60996117
queryParameters: this.queryParameters,
61006118
cancellable: (_d = (_c = this.params) === null || _c === void 0 ? void 0 : _c.cancellable) !== null && _d !== void 0 ? _d : false,
6119+
compressible: (_f = (_e = this.params) === null || _e === void 0 ? void 0 : _e.compressible) !== null && _f !== void 0 ? _f : false,
61016120
timeout: 10,
61026121
identifier: this.requestIdentifier,
61036122
};
@@ -6121,7 +6140,8 @@
61216140
* @returns Key/value headers which should be used with request.
61226141
*/
61236142
get headers() {
6124-
return undefined;
6143+
var _a, _b;
6144+
return Object.assign({ 'Accept-Encoding': 'gzip, deflate' }, (((_b = (_a = this.params) === null || _a === void 0 ? void 0 : _a.compressible) !== null && _b !== void 0 ? _b : false) ? { 'Content-Encoding': 'deflate' } : {}));
61256145
}
61266146
/**
61276147
* Target REST API endpoint request path getter.
@@ -6595,7 +6615,8 @@
65956615
});
65966616
}
65976617
get headers() {
6598-
return { accept: 'text/javascript' };
6618+
var _a;
6619+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { accept: 'text/javascript' });
65996620
}
66006621
// --------------------------------------------------------
66016622
// ------------------ Envelope parsing --------------------
@@ -8705,11 +8726,11 @@
87058726
*/
87068727
constructor(parameters) {
87078728
var _a;
8708-
var _b;
8709-
super({ method: parameters.sendByPost ? TransportMethod.POST : TransportMethod.GET });
8729+
const sendByPost = (_a = parameters.sendByPost) !== null && _a !== void 0 ? _a : SEND_BY_POST;
8730+
super({ method: sendByPost ? TransportMethod.POST : TransportMethod.GET, compressible: sendByPost });
87108731
this.parameters = parameters;
87118732
// Apply default request parameters.
8712-
(_a = (_b = this.parameters).sendByPost) !== null && _a !== void 0 ? _a : (_b.sendByPost = SEND_BY_POST);
8733+
this.parameters.sendByPost = sendByPost;
87138734
}
87148735
operation() {
87158736
return RequestOperation$1.PNPublishOperation;
@@ -8749,9 +8770,10 @@
87498770
return query;
87508771
}
87518772
get headers() {
8773+
var _a;
87528774
if (!this.parameters.sendByPost)
87538775
return undefined;
8754-
return { 'Content-Type': 'application/json' };
8776+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { 'Content-Type': 'application/json' });
87558777
}
87568778
get body() {
87578779
return this.prepareMessagePayload(this.parameters.message);
@@ -9734,7 +9756,8 @@
97349756
return `/v1/message-actions/${subscribeKey}/channel/${encodeString(channel)}/message/${messageTimetoken}`;
97359757
}
97369758
get headers() {
9737-
return { 'Content-Type': 'application/json' };
9759+
var _a;
9760+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { 'Content-Type': 'application/json' });
97389761
}
97399762
get body() {
97409763
return JSON.stringify(this.parameters.action);
@@ -10028,7 +10051,8 @@
1002810051
return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/generate-upload-url`;
1002910052
}
1003010053
get headers() {
10031-
return { 'Content-Type': 'application/json' };
10054+
var _a;
10055+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { 'Content-Type': 'application/json' });
1003210056
}
1003310057
get body() {
1003410058
return JSON.stringify({ name: this.parameters.name });
@@ -11860,11 +11884,12 @@
1186011884
return 'Data cannot be empty';
1186111885
}
1186211886
get headers() {
11887+
var _a;
1186311888
if (this.parameters.ifMatchesEtag) {
11864-
return { 'If-Match': this.parameters.ifMatchesEtag };
11889+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { 'If-Match': this.parameters.ifMatchesEtag });
1186511890
}
1186611891
else {
11867-
return undefined;
11892+
return super.headers;
1186811893
}
1186911894
}
1187011895
get path() {
@@ -12232,11 +12257,12 @@
1223212257
return 'Data cannot be empty';
1223312258
}
1223412259
get headers() {
12260+
var _a;
1223512261
if (this.parameters.ifMatchesEtag) {
12236-
return { 'If-Match': this.parameters.ifMatchesEtag };
12262+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { 'If-Match': this.parameters.ifMatchesEtag });
1223712263
}
1223812264
else {
12239-
return undefined;
12265+
return super.headers;
1224012266
}
1224112267
}
1224212268
get path() {

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.

dist/web/pubnub.worker.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,6 +1536,7 @@
15361536
headers: {},
15371537
timeout: 10,
15381538
cancellable: false,
1539+
compressible: false,
15391540
identifier: query.requestid,
15401541
},
15411542
};

dist/web/pubnub.worker.min.js

Lines changed: 1 addition & 1 deletion
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
@@ -124,7 +124,7 @@ const makeConfiguration = (base, setupCryptoModule) => {
124124
return base.PubNubFile;
125125
},
126126
get version() {
127-
return '9.3.2';
127+
return '9.4.0';
128128
},
129129
getVersion() {
130130
return this.version;

lib/core/components/request.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,13 @@ class AbstractRequest {
101101
* @returns Request object which can be processed using platform-specific requirements.
102102
*/
103103
request() {
104-
var _a, _b, _c, _d;
104+
var _a, _b, _c, _d, _e, _f;
105105
const request = {
106106
method: (_b = (_a = this.params) === null || _a === void 0 ? void 0 : _a.method) !== null && _b !== void 0 ? _b : transport_request_1.TransportMethod.GET,
107107
path: this.path,
108108
queryParameters: this.queryParameters,
109109
cancellable: (_d = (_c = this.params) === null || _c === void 0 ? void 0 : _c.cancellable) !== null && _d !== void 0 ? _d : false,
110+
compressible: (_f = (_e = this.params) === null || _e === void 0 ? void 0 : _e.compressible) !== null && _f !== void 0 ? _f : false,
110111
timeout: 10,
111112
identifier: this.requestIdentifier,
112113
};
@@ -130,7 +131,8 @@ class AbstractRequest {
130131
* @returns Key/value headers which should be used with request.
131132
*/
132133
get headers() {
133-
return undefined;
134+
var _a, _b;
135+
return Object.assign({ 'Accept-Encoding': 'gzip, deflate' }, (((_b = (_a = this.params) === null || _a === void 0 ? void 0 : _a.compressible) !== null && _b !== void 0 ? _b : false) ? { 'Content-Encoding': 'deflate' } : {}));
134136
}
135137
/**
136138
* Target REST API endpoint request path getter.

lib/core/endpoints/access_manager/grant_token.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ class GrantTokenRequest extends request_1.AbstractRequest {
8282
return `/v3/pam/${this.parameters.keySet.subscribeKey}/grant`;
8383
}
8484
get headers() {
85-
return { 'Content-Type': 'application/json' };
85+
var _a;
86+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { 'Content-Type': 'application/json' });
8687
}
8788
get body() {
8889
const { ttl, meta } = this.parameters;

lib/core/endpoints/actions/add_message_action.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ class AddMessageActionRequest extends request_1.AbstractRequest {
6666
return `/v1/message-actions/${subscribeKey}/channel/${(0, utils_1.encodeString)(channel)}/message/${messageTimetoken}`;
6767
}
6868
get headers() {
69-
return { 'Content-Type': 'application/json' };
69+
var _a;
70+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { 'Content-Type': 'application/json' });
7071
}
7172
get body() {
7273
return JSON.stringify(this.parameters.action);

lib/core/endpoints/file_upload/generate_upload_url.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ class GenerateFileUploadUrlRequest extends request_1.AbstractRequest {
5858
return `/v1/files/${subscribeKey}/channels/${(0, utils_1.encodeString)(channel)}/generate-upload-url`;
5959
}
6060
get headers() {
61-
return { 'Content-Type': 'application/json' };
61+
var _a;
62+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { 'Content-Type': 'application/json' });
6263
}
6364
get body() {
6465
return JSON.stringify({ name: this.parameters.name });

lib/core/endpoints/objects/channel/set.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,12 @@ class SetChannelMetadataRequest extends request_1.AbstractRequest {
4747
return 'Data cannot be empty';
4848
}
4949
get headers() {
50+
var _a;
5051
if (this.parameters.ifMatchesEtag) {
51-
return { 'If-Match': this.parameters.ifMatchesEtag };
52+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { 'If-Match': this.parameters.ifMatchesEtag });
5253
}
5354
else {
54-
return undefined;
55+
return super.headers;
5556
}
5657
}
5758
get path() {

lib/core/endpoints/objects/uuid/set.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@ class SetUUIDMetadataRequest extends request_1.AbstractRequest {
5050
return 'Data cannot be empty';
5151
}
5252
get headers() {
53+
var _a;
5354
if (this.parameters.ifMatchesEtag) {
54-
return { 'If-Match': this.parameters.ifMatchesEtag };
55+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { 'If-Match': this.parameters.ifMatchesEtag });
5556
}
5657
else {
57-
return undefined;
58+
return super.headers;
5859
}
5960
}
6061
get path() {

lib/core/endpoints/publish.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ class PublishRequest extends request_1.AbstractRequest {
4646
*/
4747
constructor(parameters) {
4848
var _a;
49-
var _b;
50-
super({ method: parameters.sendByPost ? transport_request_1.TransportMethod.POST : transport_request_1.TransportMethod.GET });
49+
const sendByPost = (_a = parameters.sendByPost) !== null && _a !== void 0 ? _a : SEND_BY_POST;
50+
super({ method: sendByPost ? transport_request_1.TransportMethod.POST : transport_request_1.TransportMethod.GET, compressible: sendByPost });
5151
this.parameters = parameters;
5252
// Apply default request parameters.
53-
(_a = (_b = this.parameters).sendByPost) !== null && _a !== void 0 ? _a : (_b.sendByPost = SEND_BY_POST);
53+
this.parameters.sendByPost = sendByPost;
5454
}
5555
operation() {
5656
return operations_1.default.PNPublishOperation;
@@ -90,9 +90,10 @@ class PublishRequest extends request_1.AbstractRequest {
9090
return query;
9191
}
9292
get headers() {
93+
var _a;
9394
if (!this.parameters.sendByPost)
9495
return undefined;
95-
return { 'Content-Type': 'application/json' };
96+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { 'Content-Type': 'application/json' });
9697
}
9798
get body() {
9899
return this.prepareMessagePayload(this.parameters.message);

lib/core/endpoints/subscribe.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ class BaseSubscribeRequest extends request_1.AbstractRequest {
176176
});
177177
}
178178
get headers() {
179-
return { accept: 'text/javascript' };
179+
var _a;
180+
return Object.assign(Object.assign({}, ((_a = super.headers) !== null && _a !== void 0 ? _a : {})), { accept: 'text/javascript' });
180181
}
181182
// --------------------------------------------------------
182183
// ------------------ Envelope parsing --------------------

lib/transport/node-transport.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const https_1 = require("https");
5757
const http_1 = require("http");
5858
const form_data_1 = __importDefault(require("form-data"));
5959
const buffer_1 = require("buffer");
60+
const zlib = __importStar(require("zlib"));
6061
const pubnub_api_error_1 = require("../errors/pubnub-api-error");
6162
const utils_1 = require("../core/utils");
6263
/**
@@ -178,8 +179,10 @@ class NodeTransport {
178179
headers = formData.getHeaders(headers !== null && headers !== void 0 ? headers : {});
179180
}
180181
// Handle regular body payload (if passed).
181-
else if (req.body && (typeof req.body === 'string' || req.body instanceof ArrayBuffer))
182-
body = req.body;
182+
else if (req.body && (typeof req.body === 'string' || req.body instanceof ArrayBuffer)) {
183+
// Compressing body (if required).
184+
body = req.compressible ? zlib.deflateSync(req.body) : req.body;
185+
}
183186
if (req.queryParameters && Object.keys(req.queryParameters).length !== 0)
184187
path = `${path}?${(0, utils_1.queryStringFromObject)(req.queryParameters)}`;
185188
return new node_fetch_1.Request(`${req.origin}${path}`, {

0 commit comments

Comments
 (0)