Token导航 LogoToken导航TokenDH.com
前端设计需要联网github未标认证来源可访问许可证需确认审计异常

neo4j-driver-jsNeo4j 驱动程序 js

Agent Skill

neo4j-driver-js 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

196

周安装

8

GitHub Stars

1

下载量

63
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:neo4j-driver-js(Neo4j 驱动程序 js)
来源仓库:https://github.com/michaelkeevildown/claude-agents-skills
仓库路径:skills/neo4j-driver-js
安装命令:
npx skills add https://github.com/michaelkeevildown/claude-agents-skills --skill neo4j-driver-js
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/michaelkeevildown/claude-agents-skills --skill neo4j-driver-js

简介

neo4j-driver-js 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中整理协作事项。

  • 适用于围绕仓库状态、代码变更或协作流程进行信息梳理的场景。
  • 支持对 GitHub 相关协作数据进行查询、分类和汇总操作。
  • 安装命令为 npx skills add https://github.com/michaelkeevildown/claude-agents-skills --skill neo4j-driver-js。
  • 使用前需确认权限范围、维护状态,注意是否触发联网或文件读写。

SKILL.md

Neo4j JavaScript Driver

When to Use

Use this skill when working with the neo4j-driver package in JavaScript/TypeScript. Covers driver initialization, session management, the impersonation security model, transaction functions with retries, Neo4j type handling (Integer, DateTime, Node, Relationship), and mapping driver results to UI-consumable shapes.


1. Installation

npm install neo4j-driver

2. Driver Initialization

Create a single driver instance for the application lifetime. The driver manages a connection pool internally.

import neo4j, { Driver } from "neo4j-driver";

let driver: Driver | null = null;

export const initDriver = (
  uri: string,
  user: string,
  password: string,
): Driver => {
  driver = neo4j.driver(uri, neo4j.auth.basic(user, password), {
    maxConnectionPoolSize: 50,
    connectionAcquisitionTimeout: 60000, // 60s
    maxTransactionRetryTime: 30000, // 30s
  });
  return driver;
};

export const getDriver = (): Driver => {
  if (!driver)
    throw new Error("Driver not initialized. Call initDriver() first.");
  return driver;
};

export const closeDriver = async (): Promise<void> => {
  if (driver) {
    await driver.close();
    driver = null;
  }
};

Environment Configuration

export const NEO4J_CONFIG = {
  uri: import.meta.env.VITE_NEO4J_URI || "neo4j://localhost:7687",
  user: import.meta.env.VITE_NEO4J_USER || "neo4j",
  password: import.meta.env.VITE_NEO4J_PASSWORD || "password",
  database: import.meta.env.VITE_NEO4J_DATABASE || "neo4j",
};

Verify Connectivity

const driver = initDriver(config.uri, config.user, config.password);
await driver.verifyConnectivity();
console.log("Connected to Neo4j");

3. Session Management

Sessions are lightweight and should be created per unit of work, then closed.

import { Session } from "neo4j-driver";

export const getSession = (mode: "READ" | "WRITE" = "READ"): Session => {
  return getDriver().session({
    database: NEO4J_CONFIG.database,
    defaultAccessMode:
      mode === "READ" ? neo4j.session.READ : neo4j.session.WRITE,
  });
};

Session Helper (Auto-Close)

export const withSession = async <T>(
  fn: (session: Session) => Promise<T>,
  mode: "READ" | "WRITE" = "READ",
): Promise<T> => {
  const session = getSession(mode);
  try {
    return await fn(session);
  } finally {
    await session.close();
  }
};

4. Impersonation (Two-Tier Security)

The application connects as a service account and impersonates the actual user. Neo4j RBAC enforces data-level permissions for the impersonated user.

export const getImpersonatedSession = (userEmail: string): Session => {
  return getDriver().session({
    database: NEO4J_CONFIG.database,
    impersonatedUser: userEmail, // Executes as this user's Neo4j RBAC role
  });
};

export const withImpersonation = async <T>(
  userEmail: string,
  fn: (session: Session) => Promise<T>,
): Promise<T> => {
  const session = getImpersonatedSession(userEmail);
  try {
    return await fn(session);
  } finally {
    await session.close();
  }
};

Usage

// User only sees data their Neo4j role permits
const transactions = await withImpersonation(
  "john.smith@company.com",
  async (session) => {
    const result = await session.run(
      `MATCH (t:Transaction)
       WHERE t.timestamp >= $startDate
       RETURN t ORDER BY t.timestamp DESC LIMIT 100`,
      { startDate },
    );
    return result.records.map((r) => r.get("t").properties);
  },
);

Prerequisites

  • Neo4j Enterprise Edition 5.x
  • Service account with GRANT IMPERSONATE privilege
  • Users created in Neo4j mapped to IdP identities

5. Transaction Functions

Prefer executeRead / executeWrite over raw session.run(). They provide automatic retries for transient errors (network blips, leader changes).

// Read transaction with automatic retries
const persons = await withSession(async (session) => {
  return session.executeRead(async (tx) => {
    const result = await tx.run(
      `MATCH (p:Person {id: $personId})-[:OWNS]->(a:Account)
       RETURN p, collect(a) AS accounts`,
      { personId },
    );
    return result.records.map((record) => ({
      person: record.get("p").properties,
      accounts: record.get("accounts").map((a: any) => a.properties),
    }));
  });
});

// Write transaction with automatic retries
await withSession(async (session) => {
  return session.executeWrite(async (tx) => {
    await tx.run(`CREATE (p:Person $props)`, {
      props: { id: crypto.randomUUID(), name: "Jane Doe" },
    });
  });
}, "WRITE");

6. Neo4j Type Handling

The driver returns Neo4j-specific types that must be converted before use in UI code.

Integer

Neo4j integers are 64-bit. The driver wraps them in neo4j.Integer objects.

import neo4j from "neo4j-driver";

// Check if a value is a Neo4j Integer
if (neo4j.isInt(value)) {
  const jsNumber = value.toNumber(); // Safe for values < Number.MAX_SAFE_INTEGER
  const jsString = value.toString(); // Safe for any value
  const jsBigInt = value.toBigInt(); // Native BigInt
}

DateTime

if (neo4j.isDateTime(value)) {
  const isoString = value.toString(); // ISO 8601 string
  const jsDate = value.toStandardDate(); // JavaScript Date object
}

if (neo4j.isDate(value)) {
  const isoString = value.toString(); // YYYY-MM-DD
}

if (neo4j.isDuration(value)) {
  const str = value.toString(); // ISO 8601 duration
}

Node, Relationship, Path

// Node
record.get("n").identity; // neo4j.Integer (internal ID)
record.get("n").elementId; // string (stable element ID — use this)
record.get("n").labels; // string[]
record.get("n").properties; // Record<string, any>

// Relationship
record.get("r").identity; // neo4j.Integer
record.get("r").elementId; // string
record.get("r").type; // string (relationship type)
record.get("r").startNodeElementId; // string
record.get("r").endNodeElementId; // string
record.get("r").properties; // Record<string, any>

// Path
record.get("path").start; // Node
record.get("path").end; // Node
record.get("path").segments; // Array<{ start, relationship, end }>
record.get("path").length; // number

7. Result-to-UI Data Mapping

Convert Neo4j driver results into shapes that Zustand stores and NVL components expect.

Property Mapping (Handle Neo4j Types)

function mapProperties(
  props: Record<string, unknown>,
): Record<string, unknown> {
  const mapped: Record<string, unknown> = {};
  for (const [key, value] of Object.entries(props)) {
    if (neo4j.isInt(value)) {
      mapped[key] = value.toNumber();
    } else if (neo4j.isDateTime(value) || neo4j.isDate(value)) {
      mapped[key] = value.toString();
    } else if (neo4j.isDuration(value)) {
      mapped[key] = value.toString();
    } else {
      mapped[key] = value;
    }
  }
  return mapped;
}

Neo4j Node → Application GraphNode

interface GraphNode {
  id: string;
  labels: string[];
  properties: Record<string, unknown>;
}

function toGraphNode(neo4jNode: any): GraphNode {
  return {
    id: neo4jNode.elementId,
    labels: neo4jNode.labels,
    properties: mapProperties(neo4jNode.properties),
  };
}

Neo4j Relationship → Application GraphRelationship

interface GraphRelationship {
  id: string;
  type: string;
  source: string;
  target: string;
  properties: Record<string, unknown>;
}

function toGraphRelationship(neo4jRel: any): GraphRelationship {
  return {
    id: neo4jRel.elementId,
    type: neo4jRel.type,
    source: neo4jRel.startNodeElementId,
    target: neo4jRel.endNodeElementId,
    properties: mapProperties(neo4jRel.properties),
  };
}

Full Query → Store Data

export const expandNetwork = async (personId: string, hops: number = 2) => {
  return withSession(async (session) => {
    const result = await session.executeRead(async (tx) => {
      return tx.run(
        `MATCH path = (p:Person {id: $personId})-[*1..${hops}]-(connected)
         RETURN nodes(path) AS nodes, relationships(path) AS rels
         LIMIT 500`,
        { personId },
      );
    });

    const nodesMap = new Map<string, GraphNode>();
    const relsMap = new Map<string, GraphRelationship>();

    for (const record of result.records) {
      for (const node of record.get("nodes")) {
        nodesMap.set(node.elementId, toGraphNode(node));
      }
      for (const rel of record.get("rels")) {
        relsMap.set(rel.elementId, toGraphRelationship(rel));
      }
    }

    return {
      nodes: Array.from(nodesMap.values()),
      relationships: Array.from(relsMap.values()),
    };
  });
};

8. Parameterized Queries

Always use parameters. Never concatenate user input into Cypher strings.

// ✅ Parameterized — safe, enables query plan caching
const result = await session.run(
  `MATCH (p:Person {id: $personId})-[r*1..2]-(connected)
   WHERE connected.timestamp >= $startDate
   RETURN p, r, connected
   LIMIT $limit`,
  { personId: id, startDate: startDate.toISOString(), limit: neo4j.int(100) },
);

// ❌ String interpolation — Cypher injection risk
const result = await session.run(
  `MATCH (p:Person {id: '${id}'})-[r*1..2]-(connected) RETURN p`,
);

9. Error Handling

import { Neo4jError } from "neo4j-driver";

export const handleNeo4jError = (error: unknown): never => {
  if (error instanceof Neo4jError) {
    switch (error.code) {
      case "Neo.ClientError.Security.Unauthorized":
        throw new Error("Invalid Neo4j credentials");
      case "Neo.ClientError.Security.Forbidden":
        throw new Error("User does not have permission for this operation");
      case "Neo.ClientError.Statement.SyntaxError":
        throw new Error(`Invalid Cypher query: ${error.message}`);
      case "Neo.ClientError.Schema.ConstraintValidationFailed":
        throw new Error(`Constraint violation: ${error.message}`);
      case "Neo.TransientError.Transaction.DeadlockDetected":
        throw new Error("Deadlock detected — retry the operation");
      default:
        throw new Error(`Neo4j error [${error.code}]: ${error.message}`);
    }
  }
  throw error;
};

Transient Error Retry

executeRead/executeWrite handle transient retries automatically. If using raw session.run(), catch and retry transient errors:

const isTransientError = (error: unknown): boolean =>
  error instanceof Neo4jError && error.code.startsWith("Neo.TransientError");

10. Connection Lifecycle

// App startup
const driver = initDriver(config.uri, config.user, config.password);
await driver.verifyConnectivity();

// App shutdown (or React cleanup)
useEffect(() => {
  return () => {
    closeDriver();
  };
}, []);

Anti-Patterns

Anti-PatternWhy It FailsFix
Storing the driver in React stateuseState(neo4j.driver(...)) — driver is not serializable, gets recreated on re-renderStore driver in a module-level variable
Creating a new driver per queryBypasses connection pooling, exhausts resourcesCreate one driver at app startup, reuse it
Not closing sessionsConnection pool exhaustion — queries start timing outAlways close in finally or use withSession helper
String concatenation in CypherCypher injection vulnerabilityAlways use parameterized queries
Ignoring neo4j.Integer typetoNumber() silently overflows for values > Number.MAX_SAFE_INTEGERUse toString() for display, toBigInt() for arithmetic on large values
Using record.get('n').identityInternal numeric ID — can change across database restartsUse record.get('n').elementId (stable string identifier)
Not mapping Neo4j types before storing in ZustandZustand stores (and JSON serialization) can't handle neo4j.Integer or neo4j.DateTimeAlways map with toNumber() / toString() before storing
Using session.run() for multi-statement transactionsNo automatic retry on transient errors, no transaction boundaryUse session.executeRead(tx =>...) or session.executeWrite(tx =>...)

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

36.15%
按下载量换算23

Claude

29.84%
按下载量换算19

Cursor

18.82%
按下载量换算12

Gemini CLI

9.17%
按下载量换算6

安全审计

Gen Agent Trust Hub

未通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills