
Security News
Nx npm Packages Compromised in Supply Chain Attack Weaponizing AI CLI Tools
Malicious Nx npm versions stole secrets and wallet info using AI CLI tools; Socket’s AI scanner detected the supply chain attack and flagged the malware.
@chcaa/strapi-utils
Advanced tools
A set of utility modules to make it easier to work with strapi.
Run npm install @chcaa/strapi-utils
@chcaa/strapi-utils
contains the following modules:
Strapi's native collection lifecycle hooks are fine when you only care about changes to the collection itself, but if you also need to know when relations have changed, e.g. to update a slug field, it can become a complex task to handle when only using the native hooks.
The @chcaa/strapi-utils/lifecycle.CollectionChangedHook
makes it easy to be notified whenever a collection or it's
relations has changed simply by registering the paths of interest.
Create an instance using let cch = new CollectionChangedHook()
.
This would typically be done in strapi's bootstrap()
startup hook, but could be done anywhere.
The constructor can take an optional options object to configure the registered listeners (can be overwritten pr. listener). The following options can be set:
options:object
onSelf:object
emitBeforeCreate:boolean default=false
should listeners observing their own collection receive beforeCreate
events?emitAfterCreate:boolean default=true
should listeners observing their own collection receive afterCreate
events?emitBeforeUpdate:boolean default=false
should listeners observing their own collection receive beforeUpdate
events?emitAfterUpdate:boolean default=true
should listeners observing their own collection receive afterUpdate
events?emitBeforeDelete:boolean default=false
should listeners observing their own collection receive beforeDelete
events?emitAfterDelete:boolean default=false
should listeners observing their own collection receive afterDelete
events?causedBy:object
includeBeforeState:boolean default=false
include before state of changed entries on afterUpdate events. To e.g. create diffsincludeAfterState:boolean default=false
include after state of changed entries on afterUpdate events. To e.g. create diffs in combination with includeBeforeState
calculateAttributesChanged:boolean default=false
calculate and include which attributes did change on afterUpdate events.
For each entity changed an object with properties matching the entities will be included with true
|false
if the attribute value was changed or not.
If not set explicitly to false
includeBeforeState
and includeAfterState
will be included as wellincludeInferredAfterState:boolean default=false
include inferred after state of changed entries on beforeUpdate
events on listeners observing the collection itself.
The state is inferred using the current state and then strapiEvent.params.data
object.calculateInferredAttributesChanged:boolean, default=false
calculate and include in beforeUpdate
events on listeners observing the collection itself
which inferred attributes would change. The changes are based on comparing the current state with the inferred after state.
NOTE
includeInferredAfterState
andcalculateInferredAttributesChanged
cannot infer changes to component data due to insufficient info in the strapiEvent, for components use theafterState
andcalculateAttributesChanges
in afterXXX events.
HINT
ids
,beforeState
,afterState
andchangedAttributes
arrays are all ordered in the same way so to find the matching object ofbeforeState
,afterState
andchangedAttributes
can be done as:
for (let i = 0; i < ids.length; i ++) { let beforeEntity = causedBy.beforeState[i]; let afterEntity = causedBy.afterState[i]; let attributesChanged = causedBy.attributesChanged[i]; }
Register listeners for each collection to be notified about changes to using:
register(collectionUid, relationsPaths, listener, options)
collectionUid:string
the uid of the collection to be notified about changes torelationPaths:string[]
one or more relation paths to track for changes.listener:function(event:object)
the function to call when changes occur
event.idsAffected:number[]
the ids of the collection objects affected by the changeevent.causedBy:object
an object with information about the changes
relationPath:string
one of the registered paths which resulted in the change eventcollectionUid:string
the uid of the collection which changedids:number[]
: the ids of the collection which changedeventType:string
describes what happened to the affected path in form of one of "afterCreate"
|"afterUpdate"
|"afterDelete"
and equivalent "beforeXXX"
if enabled in options
strapiEvent:object
the strapi-event that triggered this eventoptions:object [optional]
a set of options to configure the listener (overwrites the default options set in the constructor). See the constructor above for detailsAll relational paths must point to a collection but are allowed to have intermediate "components" in their path.
To get notifications about the collection itself register an empty string (""
) along with the
other paths of interest.
In the example below we want to be notified about changes to movies when the movie itself (""
) changes,
directors of the movie ("directors"
) changes or an actor in the cast ("cast.actor"
) changes.
const { CollectionChangedHook } = require('@chcaa/strapi-utils/lifecycle');
let cch = new CollectionChangedHook({ onSelf: { emitBeforeEvents: true }});
cch.register("api::movie.movie", ["", "directors", "cast.actor"], ({ idsAffected, causedBy }) => {
if (causedBy.eventType.startsWith('after')) { // we are also listening for beforeEvents on the path "", but for now we only react on afterXxx
for (let idChunk of _.chunk(idsAffected, 100)) { // use lodash to chunk the ids into sub-arrays of 100 ids each
let entries = await strapi.entityService.findMany('api::movie.movie', {
filters: {
$and: [{ id: { $in: idChunk } }]
},
populate: {
genres: true,
cast: { populate: { actor: true } }
}
});
// do something with the entries
}
}
});
Warning! Prevent Infinite Loops
- Do only modify data of paths not listened to or objects and relations attached to the owning collection identified by
idsAffected
.
Performance Note
Nested paths, especially ones including "components" can cause performance issues on larger datasets as they require a lot of joins for strapi to resolve the relations from the database.
To unregister use:
unregister(collectionUid, relationaths, listener)
collectionUid:string
the uid of the collection to NOT be notified about changes to anymore. E.g. "api::movie.movie"relationPaths:string[]
the relational paths to stop listening tolistener:function
the listener to unregister (must be the same function which was passed to register()
If the listener was registered for the relationPaths ["a", "b"] but only unregisters for ["a"] it will still be notified about changes to "b".
FAQs
Various strapi utils
The npm package @chcaa/strapi-utils receives a total of 0 weekly downloads. As such, @chcaa/strapi-utils popularity was classified as not popular.
We found that @chcaa/strapi-utils 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
Malicious Nx npm versions stole secrets and wallet info using AI CLI tools; Socket’s AI scanner detected the supply chain attack and flagged the malware.
Security News
CISA’s 2025 draft SBOM guidance adds new fields like hashes, licenses, and tool metadata to make software inventories more actionable.
Security News
A clarification on our recent research investigating 60 malicious Ruby gems.