Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

# Node cruft
node_modules
.pnpm
dist
build
.cache
turbo
out

# Dependency locks from other ecosystems
package-lock.json
yarn.lock

# Logs & temp
*.log
*.tsbuildinfo
.vscode
.idea
.env
.env.*

# OS junk
.DS_Store
Thumbs.db

# Local-only files
coverage
*.local.*
*.swp
*.swo

# Git stuff
.git
.gitignore

# Prevent docker context pollution from other packages in monorepo
apps/*/node_modules
packages/*/node_modules
22 changes: 0 additions & 22 deletions infrastructure/evault-core/docker-compose.yml

This file was deleted.

65 changes: 35 additions & 30 deletions infrastructure/evault-core/package.json
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
{
"name": "evault-core",
"version": "0.1.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "vitest --config vitest.config.ts"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/json-schema": "^7.0.15",
"@types/node": "^22.13.10",
"dotenv": "^16.5.0",
"testcontainers": "^10.24.2",
"tsx": "^4.19.3",
"typescript": "^5.8.3",
"uuid": "^11.1.0",
"vitest": "^3.0.9"
},
"dependencies": {
"@testcontainers/neo4j": "^10.24.2",
"graphql": "^16.10.0",
"graphql-type-json": "^0.3.2",
"graphql-voyager": "^2.1.0",
"graphql-yoga": "^5.13.4",
"json-schema": "^0.4.0",
"neo4j-driver": "^5.28.1",
"w3id": "workspace:*"
}
"name": "evault-core",
"version": "0.1.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "vitest --config vitest.config.ts",
"build": "tsc",
"dev": "node --watch --import tsx src/evault.ts"
},
"packageManager": "[email protected]",
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/json-schema": "^7.0.15",
"@types/node": "^22.13.10",
"dotenv": "^16.5.0",
"nodemon": "^3.1.9",
"testcontainers": "^10.24.2",
"ts-node": "^10.9.2",
"tsx": "^4.19.3",
"typescript": "^5.8.3",
"uuid": "^11.1.0",
"vitest": "^3.0.9"
},
"dependencies": {
"@testcontainers/neo4j": "^10.24.2",
"graphql": "^16.10.0",
"graphql-type-json": "^0.3.2",
"graphql-voyager": "^2.1.0",
"graphql-yoga": "^5.13.4",
"json-schema": "^0.4.0",
"neo4j-driver": "^5.28.1",
"w3id": "workspace:*"
}
}
107 changes: 98 additions & 9 deletions infrastructure/evault-core/src/db/db.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ import {
* with proper type handling and access control.
*/
export class DbService {
private driver: Driver;

/**
* Creates a new instance of the DbService.
* @param driver - The Neo4j driver instance
*/
constructor(private driver: Driver) {}
constructor(driver: Driver) {
this.driver = driver;
}

/**
* Executes a Cypher query with the given parameters.
Expand Down Expand Up @@ -174,6 +177,59 @@ export class DbService {
});
}

/**
* Finds multiple meta-envelopes by an array of IDs.
* @param ids - Array of MetaEnvelope IDs
* @returns Array of meta-envelopes with envelopes and parsed payload
*/
async findMetaEnvelopesByIds<
T extends Record<string, any> = Record<string, any>,
>(ids: string[]): Promise<MetaEnvelopeResult<T>[]> {
if (!ids.length) return [];

const result = await this.runQuery(
`
MATCH (m:MetaEnvelope)-[:LINKS_TO]->(e:Envelope)
WHERE m.id IN $ids
RETURN m.id AS id, m.ontology AS ontology, m.acl AS acl, collect(e) AS envelopes
`,
{ ids },
);

return result.records.map((record): MetaEnvelopeResult<T> => {
const envelopes = record
.get("envelopes")
.map((node: any): Envelope<T[keyof T]> => {
const props = node.properties;
return {
id: props.id,
ontology: props.ontology,
value: deserializeValue(
props.value,
props.valueType,
) as T[keyof T],
valueType: props.valueType,
};
});

const parsed = envelopes.reduce(
(acc: T, env: Envelope<T[keyof T]>) => {
(acc as any)[env.ontology] = env.value;
return acc;
},
{} as T,
);

return {
id: record.get("id"),
ontology: record.get("ontology"),
acl: record.get("acl"),
envelopes,
parsed,
};
});
}

/**
* Finds a meta-envelope by its ID.
* @param id - The ID of the meta-envelope to find
Expand Down Expand Up @@ -226,20 +282,53 @@ export class DbService {
}

/**
* Finds all meta-envelope IDs for a given ontology.
* Finds all meta-envelopes by ontology with their envelopes and parsed payload.
* @param ontology - The ontology to search for
* @returns Array of meta-envelope IDs
* @returns Array of meta-envelopes
*/
async findMetaEnvelopesByOntology(ontology: string): Promise<string[]> {
async findMetaEnvelopesByOntology<
T extends Record<string, any> = Record<string, any>,
>(ontology: string): Promise<MetaEnvelopeResult<T>[]> {
const result = await this.runQuery(
`
MATCH (m:MetaEnvelope { ontology: $ontology })
RETURN m.id AS id
`,
MATCH (m:MetaEnvelope { ontology: $ontology })-[:LINKS_TO]->(e:Envelope)
RETURN m.id AS id, m.ontology AS ontology, m.acl AS acl, collect(e) AS envelopes
`,
{ ontology },
);

return result.records.map((r) => r.get("id"));
return result.records.map((record) => {
const envelopes = record
.get("envelopes")
.map((node: any): Envelope<T[keyof T]> => {
const properties = node.properties;
return {
id: properties.id,
ontology: properties.ontology,
value: deserializeValue(
properties.value,
properties.valueType,
) as T[keyof T],
valueType: properties.valueType,
};
});

const parsed = envelopes.reduce(
(acc: T, envelope: Envelope<T[keyof T]>) => {
(acc as any)[envelope.ontology] = envelope.value;
return acc;
},
{} as T,
);

return {
id: record.get("id"),
ontology: record.get("ontology"),
acl: record.get("acl"),
envelopes,
parsed,
};
});
}

/**
Expand Down
36 changes: 29 additions & 7 deletions infrastructure/evault-core/src/evault.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
import neo4j from "neo4j-driver";
import { Server } from "http";
import { DbService } from "./db/db.service";
import { GraphQLServer } from "./protocol/graphql-server";
import dotenv from "dotenv";
import path from "path";
import neo4j from "neo4j-driver";

dotenv.config({ path: path.resolve(__dirname, "../../../.env") });

class EVault {
server: Server;

constructor() {
const uri = process.env.NEO4J_URI || "bolt://localhost:7687";
const user = process.env.NEO4J_USER || "neo4j";
const password = process.env.NEO4J_PASSWORD || "neo4j";

const driver = neo4j.driver(uri, neo4j.auth.basic(user, password));
const dbService = new DbService(driver);
const gqlServer = new GraphQLServer(dbService);
this.server = gqlServer.server as Server;
}

async function startEVault() {
const uri = `bolt://localhost:7687`;
const driver = neo4j.driver(uri, neo4j.auth.basic("neo4j", "testpass"));
const dbService = new DbService(driver);
new GraphQLServer(dbService);
start() {
const port = process.env.PORT ?? 4000;
this.server.listen(port, () => {
console.log(`GraphQL Server started on http://localhost:${port}`);
console.log(`Voyager started on http://localhost:${port}`);
});
}
}

startEVault();
const evault = new EVault();
evault.start();
Loading