Skip to content

Commit abc2fb6

Browse files
Feat/docker compose and docs (#101)
* chore: stash dockerfile progress * fix: getEnvelopesByOntology thing * chore: fix tests * Update infrastructure/evault-core/src/protocol/vault-access-guard.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * chore: remove unused import * chore: remove package * chore: fix pnpm lock * chore: fix workflow * chore: fix port in dockerfile --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 6fdb407 commit abc2fb6

File tree

17 files changed

+650
-287
lines changed

17 files changed

+650
-287
lines changed

.dockerignore

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
# Node cruft
3+
node_modules
4+
.pnpm
5+
dist
6+
build
7+
.cache
8+
turbo
9+
out
10+
11+
# Dependency locks from other ecosystems
12+
package-lock.json
13+
yarn.lock
14+
15+
# Logs & temp
16+
*.log
17+
*.tsbuildinfo
18+
.vscode
19+
.idea
20+
.env
21+
.env.*
22+
23+
# OS junk
24+
.DS_Store
25+
Thumbs.db
26+
27+
# Local-only files
28+
coverage
29+
*.local.*
30+
*.swp
31+
*.swo
32+
33+
# Git stuff
34+
.git
35+
.gitignore
36+
37+
# Prevent docker context pollution from other packages in monorepo
38+
apps/*/node_modules
39+
packages/*/node_modules

.env.example

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Neo4j Configuration
2+
NEO4J_URI=bolt://neo4j:7687
3+
NEO4J_USER=neo4j
4+
NEO4J_PASSWORD=your_secure_password_here
5+
6+
# eVault Configuration
7+
PORT=4000

.github/workflows/tests-evault-core.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
pull_request:
99
branches: [main]
1010
paths:
11-
- 'infrastructure/w3id/**'
11+
- 'infrastructure/evault-core/**'
1212

1313
jobs:
1414
test:

docker/Dockerfile.evault

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
FROM node:22-slim AS deps
2+
ENV PNPM_HOME="/pnpm"
3+
ENV PATH="$PNPM_HOME:$PATH"
4+
RUN corepack enable
5+
COPY . /app
6+
WORKDIR /app
7+
RUN npm i -g corepack@latest
8+
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
9+
RUN pnpm turbo prune evault-core --docker --use-gitignore=false
10+
RUN mkdir /out
11+
RUN cp -R ./out/full/* /out/
12+
RUN cp -R ./out/json/* /out/
13+
RUN cp ./out/pnpm-lock.yaml /out/pnpm-lock.yaml
14+
RUN cp -R node_modules/ /out/
15+
16+
17+
FROM node:22-slim AS core-api
18+
WORKDIR /app
19+
RUN npm i -g corepack@latest
20+
COPY --from=deps /out/ /app
21+
EXPOSE 4000
22+
workdir /app/infrastructure/evault-core
23+
CMD ["pnpm", "dev"]

evault.docker-compose.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
version: '3.8'
2+
3+
services:
4+
evault:
5+
build:
6+
context: .
7+
dockerfile: ./docker/Dockerfile.evault
8+
ports:
9+
- "4000:4000"
10+
environment:
11+
- NEO4J_URI=${NEO4J_URI}
12+
- NEO4J_USER=${NEO4J_USER}
13+
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
14+
networks:
15+
- graphnet
16+
depends_on:
17+
- neo4j
18+
develop:
19+
watch:
20+
- action: sync+restart
21+
path: ./infrastructure/evault-core/
22+
target: /app/infrastructure/evault-core
23+
ignore:
24+
- node_modules
25+
- action: rebuild
26+
path: ./infrastructure/evault-core/package.json
27+
- action: rebuild
28+
path: ./.env
29+
30+
neo4j:
31+
image: neo4j:5.15
32+
container_name: evault-neo4j
33+
ports:
34+
- "7474:7474" # HTTP
35+
- "7687:7687" # Bolt
36+
environment:
37+
- NEO4J_AUTH=${NEO4J_USER}/${NEO4J_PASSWORD}
38+
volumes:
39+
- neo4j_data:/data
40+
- neo4j_logs:/log
41+
networks:
42+
- graphnet
43+
44+
volumes:
45+
neo4j_data:
46+
neo4j_logs:
47+
48+
networks:
49+
graphnet:
50+
driver: bridge

infrastructure/evault-core/docker-compose.yml

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
11
{
2-
"name": "evault-core",
3-
"version": "0.1.0",
4-
"description": "",
5-
"main": "index.js",
6-
"scripts": {
7-
"test": "vitest --config vitest.config.ts"
8-
},
9-
"keywords": [],
10-
"author": "",
11-
"license": "ISC",
12-
"devDependencies": {
13-
"@types/json-schema": "^7.0.15",
14-
"@types/node": "^22.13.10",
15-
"dotenv": "^16.5.0",
16-
"testcontainers": "^10.24.2",
17-
"tsx": "^4.19.3",
18-
"typescript": "^5.8.3",
19-
"uuid": "^11.1.0",
20-
"vitest": "^3.0.9"
21-
},
22-
"dependencies": {
23-
"@testcontainers/neo4j": "^10.24.2",
24-
"graphql": "^16.10.0",
25-
"graphql-type-json": "^0.3.2",
26-
"graphql-voyager": "^2.1.0",
27-
"graphql-yoga": "^5.13.4",
28-
"json-schema": "^0.4.0",
29-
"neo4j-driver": "^5.28.1",
30-
"w3id": "workspace:*"
31-
}
2+
"name": "evault-core",
3+
"version": "0.1.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "vitest --config vitest.config.ts",
8+
"build": "tsc",
9+
"dev": "node --watch --import tsx src/evault.ts"
10+
},
11+
"packageManager": "[email protected]",
12+
"keywords": [],
13+
"author": "",
14+
"license": "ISC",
15+
"devDependencies": {
16+
"@types/json-schema": "^7.0.15",
17+
"@types/node": "^22.13.10",
18+
"dotenv": "^16.5.0",
19+
"testcontainers": "^10.24.2",
20+
"tsx": "^4.19.3",
21+
"typescript": "^5.8.3",
22+
"uuid": "^11.1.0",
23+
"vitest": "^3.0.9"
24+
},
25+
"dependencies": {
26+
"@testcontainers/neo4j": "^10.24.2",
27+
"graphql": "^16.10.0",
28+
"graphql-type-json": "^0.3.2",
29+
"graphql-voyager": "^2.1.0",
30+
"graphql-yoga": "^5.13.4",
31+
"json-schema": "^0.4.0",
32+
"neo4j-driver": "^5.28.1",
33+
"w3id": "workspace:*"
34+
}
3235
}

infrastructure/evault-core/src/db/db.service.ts

Lines changed: 98 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ import {
1616
* with proper type handling and access control.
1717
*/
1818
export class DbService {
19+
private driver: Driver;
20+
1921
/**
2022
* Creates a new instance of the DbService.
21-
* @param driver - The Neo4j driver instance
2223
*/
23-
constructor(private driver: Driver) {}
24+
constructor(driver: Driver) {
25+
this.driver = driver;
26+
}
2427

2528
/**
2629
* Executes a Cypher query with the given parameters.
@@ -174,6 +177,59 @@ export class DbService {
174177
});
175178
}
176179

180+
/**
181+
* Finds multiple meta-envelopes by an array of IDs.
182+
* @param ids - Array of MetaEnvelope IDs
183+
* @returns Array of meta-envelopes with envelopes and parsed payload
184+
*/
185+
async findMetaEnvelopesByIds<
186+
T extends Record<string, any> = Record<string, any>,
187+
>(ids: string[]): Promise<MetaEnvelopeResult<T>[]> {
188+
if (!ids.length) return [];
189+
190+
const result = await this.runQuery(
191+
`
192+
MATCH (m:MetaEnvelope)-[:LINKS_TO]->(e:Envelope)
193+
WHERE m.id IN $ids
194+
RETURN m.id AS id, m.ontology AS ontology, m.acl AS acl, collect(e) AS envelopes
195+
`,
196+
{ ids },
197+
);
198+
199+
return result.records.map((record): MetaEnvelopeResult<T> => {
200+
const envelopes = record
201+
.get("envelopes")
202+
.map((node: any): Envelope<T[keyof T]> => {
203+
const props = node.properties;
204+
return {
205+
id: props.id,
206+
ontology: props.ontology,
207+
value: deserializeValue(
208+
props.value,
209+
props.valueType,
210+
) as T[keyof T],
211+
valueType: props.valueType,
212+
};
213+
});
214+
215+
const parsed = envelopes.reduce(
216+
(acc: T, env: Envelope<T[keyof T]>) => {
217+
(acc as any)[env.ontology] = env.value;
218+
return acc;
219+
},
220+
{} as T,
221+
);
222+
223+
return {
224+
id: record.get("id"),
225+
ontology: record.get("ontology"),
226+
acl: record.get("acl"),
227+
envelopes,
228+
parsed,
229+
};
230+
});
231+
}
232+
177233
/**
178234
* Finds a meta-envelope by its ID.
179235
* @param id - The ID of the meta-envelope to find
@@ -226,20 +282,53 @@ export class DbService {
226282
}
227283

228284
/**
229-
* Finds all meta-envelope IDs for a given ontology.
285+
* Finds all meta-envelopes by ontology with their envelopes and parsed payload.
230286
* @param ontology - The ontology to search for
231-
* @returns Array of meta-envelope IDs
287+
* @returns Array of meta-envelopes
232288
*/
233-
async findMetaEnvelopesByOntology(ontology: string): Promise<string[]> {
289+
async findMetaEnvelopesByOntology<
290+
T extends Record<string, any> = Record<string, any>,
291+
>(ontology: string): Promise<MetaEnvelopeResult<T>[]> {
234292
const result = await this.runQuery(
235293
`
236-
MATCH (m:MetaEnvelope { ontology: $ontology })
237-
RETURN m.id AS id
238-
`,
294+
MATCH (m:MetaEnvelope { ontology: $ontology })-[:LINKS_TO]->(e:Envelope)
295+
RETURN m.id AS id, m.ontology AS ontology, m.acl AS acl, collect(e) AS envelopes
296+
`,
239297
{ ontology },
240298
);
241299

242-
return result.records.map((r) => r.get("id"));
300+
return result.records.map((record) => {
301+
const envelopes = record
302+
.get("envelopes")
303+
.map((node: any): Envelope<T[keyof T]> => {
304+
const properties = node.properties;
305+
return {
306+
id: properties.id,
307+
ontology: properties.ontology,
308+
value: deserializeValue(
309+
properties.value,
310+
properties.valueType,
311+
) as T[keyof T],
312+
valueType: properties.valueType,
313+
};
314+
});
315+
316+
const parsed = envelopes.reduce(
317+
(acc: T, envelope: Envelope<T[keyof T]>) => {
318+
(acc as any)[envelope.ontology] = envelope.value;
319+
return acc;
320+
},
321+
{} as T,
322+
);
323+
324+
return {
325+
id: record.get("id"),
326+
ontology: record.get("ontology"),
327+
acl: record.get("acl"),
328+
envelopes,
329+
parsed,
330+
};
331+
});
243332
}
244333

245334
/**

0 commit comments

Comments
 (0)