
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
@seihmd/spinel
Advanced tools
Decorator based OGM for Neo4j.
Currently in beta version with several steps left before v1 release
- some additional features
- detailed documentation
- bug fixes
- quality implovement
npm install @seihmd/spinel
// Define Node entity
@NodeEntity('User')
class User {
@Primary()
private id: string; // Entity must have one primary property
@Property()
private name: string;
constructor(id: string, name: string) {
this.id = id;
this.name = name;
}
}
// Define Relationship entity
@RelationshipEntity('FOLLOWS')
class Follows {
@Primary()
private id: string;
constructor(id: string) {
this.id = id;
}
}
graph TD
A(follower) -->|follows| B(user)
// Define Node-Relationship-Node graph
@Graph('user<-follows-follower')
class UserAndFollower {
@GraphNode()
private user: User;
@GraphRelationship()
private follows: Follows;
@GraphNode()
private follower: User;
constructor(user: User, follows: Follows, follower: User) {
this.user = user;
this.follows = follows;
this.follower = follower;
}
}
graph TD
A(follower) -->|:FOLLOWS| B(user)
C(follower) -->|:FOLLOWS| B(user)
@Graph('user')
class UserAndFollowers {
@GraphNode()
private user: User;
@GraphBranch(User, 'user<-[:FOLLOWS]-.')
private followers: User[];
constructor(user: User, followers: User[]) {
this.user = user;
this.followers = followers;
}
}
graph TD
A(:User) -->|:FOLLOWS| B(UserAndFollowers.user)
C(:User) -->|:FOLLOWS| B(UserAndFollowers.user)
A(:User) -->|:FOLLOWS| D(FollowedUser.user)
C(:User) -->|:FOLLOWS| D(FollowedUser.user)
@GraphFragment('-[:FOLLOWS]->user')
class FollowedUser {
@GraphNode()
private user: User;
constructor(user: User) {
this.user = user;
}
}
@Graph('user')
class UserAndFollowers {
@GraphNode()
private user: User;
@GraphBranch(User, 'user<-[:FOLLOWS]-(:User)')
private usersFollowedBySame: FollowedUser[];
constructor(user: User, usersFollowedBySame: FollowedUser[]) {
this.user = user;
this.usersFollowedBySame = usersFollowedBySame;
}
}
Run configure() at the application entry point.
import { configure } from '@seihmd/spinel';
configure({
entities: [User, Follows]
});
By default, Neo4j host, user, and password are read from environment variables:
SPINEL_HOSTSPINEL_USERSPINEL_PASSWORDAlternatively, the values can be set explicitly.
configure({
host: 'neo4j://localhost',
user: 'neo4j',
password: 'pass',
entities: [User, Follows]
});
QueryDriver is the entry point for query execution.
const qd = getQueryDriver();
// Find entities
const users = await qd
.find(User)
.where("user.id IN :userIds") // In WHERE statement, Use capitalCased Entity name
.orderBy("u.id", 'ASC')
.limit(2)
.buildQuery({
userIds: ['1', '2']
})
.run() // User[]
;
// Find graphs
const userAndFollowersList = await qd
.find(UserAndFollowers)
.where("user.id IN :userIds")
.orderBy("u.id", 'ASC')
.limit(2)
.buildQuery({
userIds: ['1', '2']
})
.run() // UserAndFollowers[]
;
const query = await qd
.find(User)
.where("user.id = $userId")
.buildQuery({
userId: '1'
})
.run() // User|null
;
const user = new User();
// Save node entity
await qd.save(user);
// Save graph
const userAndFollowers = new UserAndFollowers(user, [new User()]);
await qd.save(userAndFollowers);
// Detach any relationships having direction `user -> user2`.
await qd.detach(user, user2);
// Detach specified relationship having direction `user -> user2`.
await qd.detach(user, user2, 'FOLLOWS');
// Detach specified relationship having direction `user <- user2`.
await qd.detach(user, user2, 'FOLLOWS', '<-');
// Detach specified relationship regardless direction.
await qd.detach(user, user2, 'FOLLOWS', '-');
// Relationship constructor can also be passed.
await qd.detach(user, user2, Follows);
await qd.delete(user);
.delete() does not support Relationship and Graph.
Use .detach() or .detachDelete() instead.
// DETACH DELETE the node
await qd.detachDelete(user);
// DETACH DELETE entities included in the graph
await qd.detachDelete(userAndFollowers);
Use .transactional().
Rollback is executed When callback throws an error.
await qd.transactional(async (qd: QueryDriver) => {
const userAndFollowers = await qd
.findOne(UserAndFollowers)
.where('uhop.id=$userId')
.buildQuery({
userId: '1',
})
.run();
userAndFollowers.addFollower(new User());
await qd.save(userAndFollowers);
});
@NodeEntity('User', {
unique: ['name']
})
class User {
@Primary()
private id: string;
@Property()
private name: string;
}
@NodeEntity('User')
class User {
@Primary()
private id: string;
@Property({ notNull: true })
private name: string;
}
@NodeEntity('User', {
keys: [['name', 'address']]
})
class User {
@Primary()
private id: string;
@Property()
private name: string;
@Property()
private address: string;
}
Currentry supports btree, text and full-text index types.
@NodeEntity('User', {
indexes: [
{
type: 'btree',
on: ['name'],
},
{
name: 'index_IndexTestNode_arbitrary_name',
type: 'fulltext',
on: ['name', 'description'],
},
],
})
class User {
@Primary()
private id: string;
@Property()
private name: string;
@Property()
private description: string;
}
await qd.syncConstraints();
FAQs
Decorator based OGM for Neo4j
We found that @seihmd/spinel 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
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.