
Security News
The Changelog Podcast: Practical Steps to Stay Safe on npm
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.
@abcnews/env-utils
Advanced tools
Utilities for identifying aspects of your code's execution environment and respectfully interacting with the DOM
Utilities for identifying aspects of your code's execution environment and respectfully interacting with the DOM.
You can identify the current environment's application, generation and tier (see API for what each of those are).
Each generation has its own assumptions about how and when we should modfy the DOM. Always ask for permission first, and listen for a notifications of that permission being revoked.
npm i @abcnews/env-utils
Assume we're using this module in a article rendered by Presentation Layer News Web on our Preview website
import {
getApplication,
getGeneration,
getTier,
requestDOMPermit,
} from '@abcnews/env-utils';
getApplication();
// > 'pln'
getGeneration();
// > 'pl'
getTier();
// > 'preview'
requestDOMPermit('article').then(() => {
// It is now safe to modify the DOM tree below the <Decoy key="article"> PL compoonent
});
Note: use #start<name> and #end<name> inside a CoreMedia article to create a ranged decoy.
Sometimes developing locally for the PL environment is difficult due to the DOM permit system that requestDOMPermit provides an interface for as it relies on events fired by Presentation Layer and the existence of some specific DOM elements.
There is an additional function exported from the library — mockDecoyActivationEvents — which can be used to mock the decoy events and make testing using a local test page easier.
Example usage:
import {
requestDOMPermit,
mockDecoyActivationEvents,
} from '@abcnews/env-utils';
if (process.env.NODE_ENV === 'development') {
mockDecoyActivationEvents();
}
requestDOMPermit('key').then(/* you have a permit for 'key' */);
You will also need to add the DOM requestDOMPermit expects for decoys to your testing HTML. For example, a ranged decoy with the key 'key':
<div data-component="Decoy" data-key="key" data-clone="true">
<p>
All the stuff between here is inside the decoy and fair game after a DOM
permit is granted.
</p>
</div>
APPLICATIONS, GENERATIONS, & TIERSEnumerated (named) applications, generations and tiers; useful for argument abstraction & logging.
import { APPLICATIONS, GENERATIONS, TIERS } from '@abcnews/env-utils';
console.log(APPLICATIONS);
// > {
// P1M: 'p1m', // Phase 1 Mobile
// P1S: 'p1s', // Phase 1 Standard
// P2: 'p2', // Phase 2
// PLA: 'pla', // Presentation Layer ABC AMP
// PLC: 'plc', // Presentation Layer Core
// PLE: 'ple', // Presentation Layer Everyday
// PLN: 'pln', // Presentation Layer News Web
// }
console.log(GENERATIONS);
// > {
// P1: 'p1', // Phase 1
// P2: 'p2', // Phase 2
// PL: 'pl', // Presentation Layer
// }
console.log(TIERS);
// > {
// LIVE: 'live',
// PREVIEW: 'preview',
// }
getApplication(): string | nullReturn the environment's application (Phase 1 Mobile; Phase 1 Standard; Phase 2; Presentation Layer ABC AMP; Presentation Layer Core; Presentation Layer Everyday; Presentation Layer News Web) as a string value from the APPLICATIONS enum, or null if the application couldn't be determined.
import { APPLICATIONS, getApplication } from '@abcnews/env-utils';
getApplication();
// > 'pln'
getApplication() === APPLICATIONS.PLN;
// > true
Applications are currently determined by success/failure of selecting DOM nodes in the document, which hint at the technology used to render them on the server.
getGeneration(): string | nullReturn the environment's generation (Phase 1; Phase 2; Presentation Layer) as a string value from the GENERATIONS enum, or null if the generation couldn't be determined.
import { GENERATIONS, getGeneration } from '@abcnews/env-utils';
getGeneration();
// > 'pl'
getGeneration() === GENERATIONS.PL;
// > true
Generations are currently determined by categorising detected applications.
getTier(): string | nullReturn the environment's tier (Live; Preview) as a string value from the TIERS enum, or null if the tier couldn't be determined.
import { TIERS, getTier } from '@abcnews/env-utils';
getTier();
// > 'preview'
getTier() === TIERS.PREVIEW;
// > true
Tiers are currently determined by comparing window.location.hostname to domains that tiers are potentially served from.
requestDOMPermit(key: string, onRevokeHandler?: Function): Promise<true|HTMLElement[]>Request a permit to modify the DOM.
This is advised before modifying the DOM on Presentation Layer generation applications (as they are controlled by React, and will almost certainly undo your own changes).
DOM modification is usually safe on older generation applications, but permits should be requested anyway, for the sake of consistency.
The key argument is used by Presentation Layer to activate its respective <Decoy> components.
An optional onRevokeHandler argument can be passed, which will be called if Presentation Layer chooses to deactivate <Decoy>s and restore their orignal DOM.
Note: key values may be any [a-z] string, but the Presentation Layer News Web application provides several pre-determined values, which this library exposes as DECOY_KEYS.
import { DECOY_KEYS, requestDOMPermit } from '@abcnews/env-utils';
requestDOMPermit(DECOY_KEYS.PAGE, () => {
// It is no longer safe to modify the DOM tree below <Decoy listenKey="page"> PL compoonents
}).then(() => {
// It is now safe to modify the DOM tree below <Decoy listenKey="page"> PL compoonents
});
The returned promise resolves differently depending on the GENERATION on which it's running. On Presentation Layer sites the promise will resolve with an array of HTMLElement references for all the nodes where the decoy was activated. On prior generations, it will resolve with true.
The promise will be rejected after 5 seconds if all expected decoys haven't been activated. Additionally, the library will attempt to undo any successful activations by sending another request to PL to deactivate decoys with the given key.
whenDOMReady(): Promise<void>A promise that resolves when the DOM is ready. On Presentation Layer documents the DOM isn't considered ready until after the React tree is rehydrated.
whenOdysseyLoaded(): Promise<window.__ODYSSEY__>A promise that resolves when Odyssey is finished loading. This will resolve with a reference to the Odyssey API.
Everything you need should be in the npm scripts:
npm start
npm test
npm run release
Running tests requires some environment variables be set. The canonical version of these env vars are stored as secrets in GitHub, but if you need them to run tests locally, chat to one of the authors listed below.
FAQs
Utilities for identifying aspects of your code's execution environment and respectfully interacting with the DOM
The npm package @abcnews/env-utils receives a total of 8 weekly downloads. As such, @abcnews/env-utils popularity was classified as not popular.
We found that @abcnews/env-utils demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.

Security News
Experts push back on new claims about AI-driven ransomware, warning that hype and sponsored research are distorting how the threat is understood.

Security News
Ruby's creator Matz assumes control of RubyGems and Bundler repositories while former maintainers agree to step back and transfer all rights to end the dispute.