
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
A library to handle your AJAX/SSE DOM contents and to automate your requests, using some contracts.

A library to handle your AJAX/SSE DOM contents and to automate your requests, using some contracts.
anticore is a library to make a very simple bridge between your front-end and your back-end, using some contracts
associating a selector (to match some elements) and a task (a function to make something on the matching elements).
Each time anticore loads a DOM content by an AJAX request or received as a Server-Sent Event, it calls the trigger(fragment) on it.
It implies that: except for the elements already into the document, it acts before its insertion, to improve the performances & the UX (the browser only renders once per view, in opposition to a mutations-based system).
In fact, anticore doesn't insert anything, you need to make some "tree" contracts dedicated to that task, like the generic @anticore-contracts/tree-view or @anticore-contracts/tree-insert
Since it really often helps to understand the concept, you can try it yourself in a few seconds:
on('main.a', element => {
element.querySelector('h1').append('should be a: ', element.className)
})
on('main.b', element => {
element.querySelector('h1').append('should be b: ', element.className)
})
on('main.c', element => {
element.querySelector('h1').append('should be c: ', element.className)
})
on('main', element => {
element.querySelector('h1').append(' AND can be one of a || b || c || my-own: ', element.className)
})
// a very basic view switcher
on('.anticore > main', element => {
const main = document.querySelector('main')
main.replaceWith(element)
})
a into the prompt & press Enterb into the prompt & press Enterc into the prompt & press EnterAlternatively, you can also try this other demo, which includes an SSE example:
anticore-demo (also installable from its repository)
Content based, anticore is a utility used to easily interact with any
DOM server-side rendered (SSR) element, even received in AJAX or SSE.
Of course, it also supports the ServiceWorker rendered elements to work offline.
Contracts oriented, just like an event listener, you can write some contracts to define some process on any element matching a selector when anticore receives it, regardless of how many (various) views needs them.
Automated on demand, by a single function call, during the script initialization, it avoids the need to write any
AJAX request, they are automatically deduced by the anchor/form attributes, on the user interaction related event (click/submit).
Very low front-end, weighing only 4Ko minified without dependency, it provides a strategy to incite you to keep your front code lightest as possible, letting your rendering strategy, and the control to the server side.
The front code is only used as an unobstrusive overlay to improve the user experience and let the client resources available for any other operations.
Reusable, through projects, you have a lot of as generic contracts to cover most of your needs at once... you can also write any project-specific contracts if needed, just based on the selector precision.
Server-side/framework agnostic, no specific server configuration needed, just to receive some DOM contents (HTML, SVG, ...). It can be used in conjunction to your favorite libraries & frameworks.
Easy to maintain, it doesn't chain all the process, each contract, ideally following the single responsibility principle, is simply replaceable/removable without the need to check the entire project.
TrustedTypes support for your own trusted contents.
Lazy load support
Using NPM:
npm i anticore
Or using a CDN:
import anticore, { defaults, on, trigger } from 'https://unpkg.com/anticore@latest/index.js'
A contract is just a query selector associated function, a few like a routing route, where the selector is tested each time anticore receives a new content.
By default, once triggered, anticore triggers the contracts on any element matching a provided selector, event if that element is already in the document or received after.
import { on } from 'anticore'
// a contract example
on('a.query.selector', (matchingElement, serverResponseURL) => {
// processes to apply on the element
})
anticore loads the contents in a <body class="anticore"> (created internally), then you can use that class in your selector to target that
elements, specifically.
For example, we don't want to replace an already embedded element by itself.
import { on } from 'anticore'
// selects an element which is only received after the page load
on('.anticore a.query.selector', (matchingElement, serverResponseURL) => {
// processes to apply on the element
})
A useful selector prefix can also be body:not(.anticore) to only target the elements initially loaded (non AJAX/SSE).
import { on } from 'anticore'
on('body:not(.anticore) a.query.selector', (matchingElement, serverResponseURL) => {
// processes to apply on a loaded element
})
main.js)// your generic contracts
import './contracts/generic/index.js'
// your view contracts
import './contracts/view/index.js'
// register the default contracts, to handle your anchors/forms without target attribute
import 'anticore/defaults.js'
// your tree contracts
import './contracts/tree/index.js'
// applies the contracts on the current document elements
import 'anticore/trigger.js'
view-switcher.js)When you create an AJAX navigation, the most common operation is to replace the current contents by the user requested contents.
To do that, commonly...
XMLHttpRequest/fetch) requests... requiring an abstraction to avoid code repetitions
With anticore, it's really shorter/simpler!
Since the <main> & <title> are unique in a page, you can easily write that process with a unique contract.
import { on } from 'anticore'
// matching any received <main> / <title>
on('.anticore > main, .anticore title', (element, url) => {
// creating a selector based on the element node name
const selector = element.nodeName.toLowerCase()
// retrieving the same embedded element in the document
const current = document.querySelector(selector)
// replacing the embedded element by the new one
current.replaceWith(element)
if (selector === 'title') {
// updating the history
history.pushState({}, element.innerHTML, url)
} else {
window.scrollTo(0, 0)
}
})
Voilà, import it in your main.js and your AJAX navigation is resolved for all your pages, at once!.
Caution: to improve the user experience and the performances, it's recommended to import the "switchers" as very last
contracts, in your main.js.
import { defaults, trigger } from 'anticore'
// non-switching contracts here
import './contracts.js'
// then the view-switcher
import './view-switcher.js'
defaults()
trigger()
Example:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Initial title</title>
<script src="/assets/main.js" type="module"></script>
</head>
<body>
<main>
<h1>Initial title</h1>
<a href="/response">Load the response</a>
</main>
</body>
</html>
response
<title>Response title</title>
<main>
<h1>Response title</h1>
</main>
Resolves to
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Response title</title>
<script src="/assets/main.js" type="module"></script>
</head>
<body>
<main>
<h1>Response title</h1>
</main>
</body>
</html>
Useful to declare a contract to be applied for any element matching the selector, where:
selector: a query selectorlistener: a function to be applied on the matching elements
element: the matching elementurl: the url providing the node (can be empty, e.g. when the nodes are already in the current page)import { on } from 'anticore'
// An listener can be async
on('body', async (element, url) => {
element.append(`Hello world from ${url}`)
})
A on-like method allowing to lazily import a module method to use as a on listener, but on-the-fly.
selector: a query selector{ url }: the current import.metapath: the wanted module pathpicker: an optional function to pick an exported listener from the loaded module
It receives 2 arguments
default: the default module export (or undefined)exports: the named module exportsExample:
when('.anticore main', import.meta, 'view-switcher.js')
Is equivalent to
on('.anticore main', async (element, url) => {
const exports = await import(new URL('view-switcher.js', import.meta.url).toString())
return exports.default(element, url)
})
Or
when('.anticore main', import.meta, 'view-switcher.js', switcher => switcher)
Or
when('.anticore main', import.meta, 'view-switcher.js', (switcher, exports) => exports.default)
A function that wraps 2 contracts
A contract that tells to anticore to fetch the href of any clicked anchor
It uses the following selector
a[href^="http"]:not([download]):not([target]),
a[href^="."]:not([download]):not([target]),
a[href^="/"]:not([download]):not([target])
A contract that tells to anticore to fetch the action of any submitted form
It uses the following selector
form:not([target])
Additionally, before the fetching, it removes the form descendants that have a error class, useful to remove the error messages from a previous submission.
Useful to apply the declared contracts on the provided node, where:
node: the targeted node (element or current document)import { trigger } from 'anticore'
trigger(document)
Useful to parse an existing HTML/SVG source to real DOM nodes, to be able to trigger on it.
It parses the provides source into a <body class="anticore" id="{url}">{source}</body>
import { trigger } from 'anticore'
trigger(parse(source, url))
Useful to create your own DOM content fetchers, where:
request: the Request instanceevent: the event invoking the fetchtarget: the element invoking the fetch (gets a .fetching, until resolved)** If no event is provided, anticore just fetches without DOM parsing, no contracts triggering**
import { fetch } from 'anticore'
fetch(request, event, target) // fetches the contents & triggers the contracts on them
fetch(request) // just fetches
fetch()?Once called, anticore attempts to fetch the response until its resolution.
If the user isn't connected, anticore retries after a delay (1 second by default)
If provided, anticore manages the event like this:
Event.preventDefault() (e.g. from a form validation contract) or if the bubbling is canceled event.cancelBubble.
In that case, anticore just avoids doing anythingfetching class on the element that triggers the eventfetching class on the element that triggers the eventUseful to listen Server-Sent Events, where
url: the URL to listenoptions: the EventSource optionsreviver: a function to parse the DOM nodes from each messageimport { sse } from 'anticore'
const eventSource = sse(url, options, reviver)
Useful to listen events, on any support (touch and/or not)
event: the event typetarget: an EventTargetlistener: a function called each time the event triggersoptions: the addEventListener optionsIt returns a function to remove the listener, without any arguments needed
import { listen } from 'anticore'
const forget = listen(event, target, listener, options)
The V4 is now promise-based, the V3 next() is removed, if you need to await some async operations, just use an async listener.
If your project is defining a strict Content-Security-Policy (CSP) you can need to add the following header/meta, to trust your DOM contents:
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types anticore
FAQs
A library to handle your AJAX/SSE DOM contents and to automate your requests, using some contracts.
We found that anticore demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer 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
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.