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
11 changes: 8 additions & 3 deletions .pubnub.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
---
changelog:
- date: 2026-07-22
version: v12.0.2
changes:
- type: bug
text: "Fixes issue of getting error while obtain APM safe fetch api."
- date: 2026-07-21
version: v12.0.1
changes:
Expand Down Expand Up @@ -1432,7 +1437,7 @@ supported-platforms:
- 'Ubuntu 14.04 and up'
- 'Windows 7 and up'
version: 'Pubnub Javascript for Node'
version: '12.0.1'
version: '12.0.2'
sdks:
- full-name: PubNub Javascript SDK
short-name: Javascript
Expand All @@ -1448,7 +1453,7 @@ sdks:
- distribution-type: source
distribution-repository: GitHub release
package-name: pubnub.js
location: https://github.com/pubnub/javascript/archive/refs/tags/v12.0.1.zip
location: https://github.com/pubnub/javascript/archive/refs/tags/v12.0.2.zip
requires:
- name: 'agentkeepalive'
min-version: '3.5.2'
Expand Down Expand Up @@ -2119,7 +2124,7 @@ sdks:
- distribution-type: library
distribution-repository: GitHub release
package-name: pubnub.js
location: https://github.com/pubnub/javascript/releases/download/v12.0.1/pubnub.12.0.1.js
location: https://github.com/pubnub/javascript/releases/download/v12.0.2/pubnub.12.0.2.js
requires:
- name: 'agentkeepalive'
min-version: '3.5.2'
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v12.0.2
July 22 2026

#### Fixed
- Fixes issue of getting error while obtain APM safe fetch api.

## v12.0.1
July 21 2026

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,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.12.0.1.js
* https://cdn.pubnub.com/sdk/javascript/pubnub.12.0.1.min.js
* https://cdn.pubnub.com/sdk/javascript/pubnub.12.0.2.js
* https://cdn.pubnub.com/sdk/javascript/pubnub.12.0.2.min.js

> **React Native:** the SDK relies on a global `URL` implementation, which React Native does not
> provide, so it depends on [`react-native-url-polyfill`](https://www.npmjs.com/package/react-native-url-polyfill).
Expand Down
29 changes: 25 additions & 4 deletions dist/web/pubnub.js
Original file line number Diff line number Diff line change
Expand Up @@ -5477,7 +5477,7 @@
return base.PubNubFile;
},
get version() {
return '12.0.1';
return '12.0.2';
},
getVersion() {
return this.version;
Expand Down Expand Up @@ -5948,13 +5948,22 @@
this.logger = logger;
this.transport = transport;
logger.debug('WebTransport', `Create with configuration:\n - transport: ${transport}`);
if (transport === 'fetch' && (!window || !window.fetch)) {
// Check for `fetch` availability directly (works in DOM and DOM-less contexts such as service workers).
// because a bare `window` reference would throw in a service worker, and a partial `window = self` shim can
// define `window` without `fetch`, so probe the actual `fetch` global via `typeof`.
if (transport === 'fetch' && typeof fetch === 'undefined') {
logger.warn('WebTransport', `'${transport}' not supported in this browser. Fallback to the 'xhr' transport.`);
this.transport = 'xhr';
}
if (this.transport !== 'fetch')
return;
// Storing reference on original `fetch` function implementation as protection against APM lib monkey patching.
//
// This is done unconditionally (not gated on `isFetchMonkeyPatched()`): APM libraries can defeat that
// detection by overriding stringification to report `[native code]` while still patching `fetch`, so we
// cannot rely on it to decide whether the workaround is needed. `getOriginalFetch()` itself decides how to
// obtain the reference based on the environment (iframe when a DOM is available, context `fetch` otherwise),
// which keeps construction safe in DOM-less contexts such as MV3 service workers.
WebTransport.originalFetch = WebTransport.getOriginalFetch();
// Check whether `fetch` has been monkey patched or not.
if (this.isFetchMonkeyPatched())
Expand Down Expand Up @@ -6259,6 +6268,12 @@
* @returns Reference to the `fetch` function.
*/
static getOriginalFetch() {
// The iframe-based APM workaround requires a DOM. In DOM-less contexts (e.g. MV3 service workers) there is
// no `document`, and `fetch` cannot be reached through a fresh browsing context — return the context `fetch`
// directly. This is safe there: without a DOM there is no APM page script to monkey patch `fetch` in the
// first place. This environment check is what keeps the unconditional call in the constructor safe.
if (typeof document === 'undefined' || !document.body)
return fetch;
let iframe = document.querySelector('iframe[name="pubnub-context-unpatched-fetch"]');
if (!iframe) {
iframe = document.createElement('iframe');
Expand Down Expand Up @@ -18462,7 +18477,9 @@
authenticationChangeHandler = (auth) => middleware.onTokenChange(auth);
userIdChangeHandler = (userId) => middleware.onUserIdChange(userId);
transport = middleware;
if (configurationCopy.subscriptionWorkerUnsubscribeOfflineClients) {
if (configurationCopy.subscriptionWorkerUnsubscribeOfflineClients &&
typeof window !== 'undefined' &&
window.addEventListener) {
window.addEventListener('pagehide', (event) => {
if (!event.persisted)
middleware.terminate();
Expand Down Expand Up @@ -18512,7 +18529,11 @@
};
}
}
if ((_a = configuration.listenToBrowserNetworkEvents) !== null && _a !== void 0 ? _a : true) {
// `window` is unavailable in DOM-less contexts (e.g. MV3 service workers); only attach network
// listeners when a `window` with event support actually exists.
if (((_a = configuration.listenToBrowserNetworkEvents) !== null && _a !== void 0 ? _a : true) &&
typeof window !== 'undefined' &&
window.addEventListener) {
window.addEventListener('offline', () => {
this.networkDownDetected();
});
Expand Down
2 changes: 1 addition & 1 deletion dist/web/pubnub.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 @@ -174,7 +174,7 @@ const makeConfiguration = (base, setupCryptoModule) => {
return base.PubNubFile;
},
get version() {
return '12.0.1';
return '12.0.2';
},
getVersion() {
return this.version;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pubnub",
"version": "12.0.1",
"version": "12.0.2",
"author": "PubNub <support@pubnub.com>",
"description": "Publish & Subscribe Real-time Messaging with PubNub",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src/core/components/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ export const makeConfiguration = (
return base.PubNubFile;
},
get version(): string {
return '12.0.1';
return '12.0.2';
},
getVersion(): string {
return this.version;
Expand Down
17 changes: 16 additions & 1 deletion src/transport/web-transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ export class WebTransport implements Transport {
) {
logger.debug('WebTransport', `Create with configuration:\n - transport: ${transport}`);

if (transport === 'fetch' && (!window || !window.fetch)) {
// Check for `fetch` availability directly (works in DOM and DOM-less contexts such as service workers).
// because a bare `window` reference would throw in a service worker, and a partial `window = self` shim can
// define `window` without `fetch`, so probe the actual `fetch` global via `typeof`.
if (transport === 'fetch' && typeof fetch === 'undefined') {
logger.warn('WebTransport', `'${transport}' not supported in this browser. Fallback to the 'xhr' transport.`);

this.transport = 'xhr';
Expand All @@ -106,6 +109,12 @@ export class WebTransport implements Transport {
if (this.transport !== 'fetch') return;

// Storing reference on original `fetch` function implementation as protection against APM lib monkey patching.
//
// This is done unconditionally (not gated on `isFetchMonkeyPatched()`): APM libraries can defeat that
// detection by overriding stringification to report `[native code]` while still patching `fetch`, so we
// cannot rely on it to decide whether the workaround is needed. `getOriginalFetch()` itself decides how to
// obtain the reference based on the environment (iframe when a DOM is available, context `fetch` otherwise),
// which keeps construction safe in DOM-less contexts such as MV3 service workers.
WebTransport.originalFetch = WebTransport.getOriginalFetch();

// Check whether `fetch` has been monkey patched or not.
Expand Down Expand Up @@ -431,6 +440,12 @@ export class WebTransport implements Transport {
* @returns Reference to the `fetch` function.
*/
private static getOriginalFetch(): typeof fetch {
// The iframe-based APM workaround requires a DOM. In DOM-less contexts (e.g. MV3 service workers) there is
// no `document`, and `fetch` cannot be reached through a fresh browsing context — return the context `fetch`
// directly. This is safe there: without a DOM there is no APM page script to monkey patch `fetch` in the
// first place. This environment check is what keeps the unconditional call in the constructor safe.
if (typeof document === 'undefined' || !document.body) return fetch;

let iframe = document.querySelector<HTMLIFrameElement>('iframe[name="pubnub-context-unpatched-fetch"]');

if (!iframe) {
Expand Down
14 changes: 12 additions & 2 deletions src/web/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,11 @@ export default class PubNub extends PubNubCore<ArrayBuffer | string, PubNubFileP
userIdChangeHandler = (userId: string) => middleware.onUserIdChange(userId);
transport = middleware;

if (configurationCopy.subscriptionWorkerUnsubscribeOfflineClients) {
if (
configurationCopy.subscriptionWorkerUnsubscribeOfflineClients &&
typeof window !== 'undefined' &&
window.addEventListener
) {
window.addEventListener(
'pagehide',
(event) => {
Expand Down Expand Up @@ -211,7 +215,13 @@ export default class PubNub extends PubNubCore<ArrayBuffer | string, PubNubFileP
}
}

if (configuration.listenToBrowserNetworkEvents ?? true) {
// `window` is unavailable in DOM-less contexts (e.g. MV3 service workers); only attach network
// listeners when a `window` with event support actually exists.
if (
(configuration.listenToBrowserNetworkEvents ?? true) &&
typeof window !== 'undefined' &&
window.addEventListener
) {
window.addEventListener('offline', () => {
this.networkDownDetected();
});
Expand Down
Loading