Merged
Show file tree
Hide file tree
Changes from all 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 numberDiff line numberDiff 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
7 changes: 7 additions & 0 deletions .env.example
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
# Neo4j Configuration
NEO4J_URI=bolt://neo4j:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_secure_password_here

# eVault Configuration
PORT=4000
2 changes: 1 addition & 1 deletion .github/workflows/tests-evault-core.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ on:
pull_request:
branches: [main]
paths:
- 'infrastructure/w3id/**'
- 'infrastructure/evault-core/**'

jobs:
test:
Expand Down
23 changes: 23 additions & 0 deletions docker/Dockerfile.evault
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
FROM node:22-slim AS deps
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
RUN npm i -g corepack@latest
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm turbo prune evault-core --docker --use-gitignore=false
RUN mkdir /out
RUN cp -R ./out/full/* /out/
RUN cp -R ./out/json/* /out/
RUN cp ./out/pnpm-lock.yaml /out/pnpm-lock.yaml
RUN cp -R node_modules/ /out/


FROM node:22-slim AS core-api
WORKDIR /app
RUN npm i -g corepack@latest
COPY --from=deps /out/ /app
EXPOSE 4000
workdir /app/infrastructure/evault-core
CMD ["pnpm", "dev"]
50 changes: 50 additions & 0 deletions evault.docker-compose.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
version: '3.8'

services:
evault:
build:
context: .
dockerfile: ./docker/Dockerfile.evault
ports:
- "4000:4000"
environment:
- NEO4J_URI=${NEO4J_URI}
- NEO4J_USER=${NEO4J_USER}
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
networks:
- graphnet
depends_on:
- neo4j
Comment thread
coodos marked this conversation as resolved.
develop:
watch:
- action: sync+restart
path: ./infrastructure/evault-core/
target: /app/infrastructure/evault-core
ignore:
- node_modules
- action: rebuild
path: ./infrastructure/evault-core/package.json
- action: rebuild
path: ./.env

neo4j:
image: neo4j:5.15
container_name: evault-neo4j
ports:
- "7474:7474" # HTTP
- "7687:7687" # Bolt
environment:
- NEO4J_AUTH=${NEO4J_USER}/${NEO4J_PASSWORD}
volumes:
- neo4j_data:/data
- neo4j_logs:/log
networks:
- graphnet

volumes:
neo4j_data:
neo4j_logs:

networks:
graphnet:
driver: bridge
22 changes: 0 additions & 22 deletions infrastructure/evault-core/docker-compose.yml

This file was deleted.

63 changes: 33 additions & 30 deletions infrastructure/evault-core/package.json
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
{
"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": "pnpm@10.6.5",
"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:*"
}
}
107 changes: 98 additions & 9 deletions infrastructure/evault-core/src/db/db.service.ts
Original file line numberDiff line numberDiff 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 DownExpand 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 DownExpand 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
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 numberDiff line numberDiff 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
7 changes: 7 additions & 0 deletions .env.example
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
# Neo4j Configuration
NEO4J_URI=bolt://neo4j:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_secure_password_here

# eVault Configuration
PORT=4000
2 changes: 1 addition & 1 deletion .github/workflows/tests-evault-core.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ on:
pull_request:
branches: [main]
paths:
- 'infrastructure/w3id/**'
- 'infrastructure/evault-core/**'

jobs:
test:
Expand Down
23 changes: 23 additions & 0 deletions docker/Dockerfile.evault
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
FROM node:22-slim AS deps
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
RUN npm i -g corepack@latest
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm turbo prune evault-core --docker --use-gitignore=false
RUN mkdir /out
RUN cp -R ./out/full/* /out/
RUN cp -R ./out/json/* /out/
RUN cp ./out/pnpm-lock.yaml /out/pnpm-lock.yaml
RUN cp -R node_modules/ /out/


FROM node:22-slim AS core-api
WORKDIR /app
RUN npm i -g corepack@latest
COPY --from=deps /out/ /app
EXPOSE 4000
workdir /app/infrastructure/evault-core
CMD ["pnpm", "dev"]
50 changes: 50 additions & 0 deletions evault.docker-compose.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
version: '3.8'

services:
evault:
build:
context: .
dockerfile: ./docker/Dockerfile.evault
ports:
- "4000:4000"
environment:
- NEO4J_URI=${NEO4J_URI}
- NEO4J_USER=${NEO4J_USER}
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
networks:
- graphnet
depends_on:
- neo4j
Comment thread
coodos marked this conversation as resolved.
develop:
watch:
- action: sync+restart
path: ./infrastructure/evault-core/
target: /app/infrastructure/evault-core
ignore:
- node_modules
- action: rebuild
path: ./infrastructure/evault-core/package.json
- action: rebuild
path: ./.env

neo4j:
image: neo4j:5.15
container_name: evault-neo4j
ports:
- "7474:7474" # HTTP
- "7687:7687" # Bolt
environment:
- NEO4J_AUTH=${NEO4J_USER}/${NEO4J_PASSWORD}
volumes:
- neo4j_data:/data
- neo4j_logs:/log
networks:
- graphnet

volumes:
neo4j_data:
neo4j_logs:

networks:
graphnet:
driver: bridge
22 changes: 0 additions & 22 deletions infrastructure/evault-core/docker-compose.yml

This file was deleted.

63 changes: 33 additions & 30 deletions infrastructure/evault-core/package.json
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
{
"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": "pnpm@10.6.5",
"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:*"
}
}
107 changes: 98 additions & 9 deletions infrastructure/evault-core/src/db/db.service.ts
Original file line numberDiff line numberDiff 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 DownExpand 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 DownExpand 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
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 numberDiff line numberDiff 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
7 changes: 7 additions & 0 deletions .env.example
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
# Neo4j Configuration
NEO4J_URI=bolt://neo4j:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_secure_password_here

# eVault Configuration
PORT=4000
2 changes: 1 addition & 1 deletion .github/workflows/tests-evault-core.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ on:
pull_request:
branches: [main]
paths:
- 'infrastructure/w3id/**'
- 'infrastructure/evault-core/**'

jobs:
test:
Expand Down
23 changes: 23 additions & 0 deletions docker/Dockerfile.evault
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
FROM node:22-slim AS deps
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
RUN npm i -g corepack@latest
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm turbo prune evault-core --docker --use-gitignore=false
RUN mkdir /out
RUN cp -R ./out/full/* /out/
RUN cp -R ./out/json/* /out/
RUN cp ./out/pnpm-lock.yaml /out/pnpm-lock.yaml
RUN cp -R node_modules/ /out/


FROM node:22-slim AS core-api
WORKDIR /app
RUN npm i -g corepack@latest
COPY --from=deps /out/ /app
EXPOSE 4000
workdir /app/infrastructure/evault-core
CMD ["pnpm", "dev"]
50 changes: 50 additions & 0 deletions evault.docker-compose.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
version: '3.8'

services:
evault:
build:
context: .
dockerfile: ./docker/Dockerfile.evault
ports:
- "4000:4000"
environment:
- NEO4J_URI=${NEO4J_URI}
- NEO4J_USER=${NEO4J_USER}
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
networks:
- graphnet
depends_on:
- neo4j
Comment thread
coodos marked this conversation as resolved.
develop:
watch:
- action: sync+restart
path: ./infrastructure/evault-core/
target: /app/infrastructure/evault-core
ignore:
- node_modules
- action: rebuild
path: ./infrastructure/evault-core/package.json
- action: rebuild
path: ./.env

neo4j:
image: neo4j:5.15
container_name: evault-neo4j
ports:
- "7474:7474" # HTTP
- "7687:7687" # Bolt
environment:
- NEO4J_AUTH=${NEO4J_USER}/${NEO4J_PASSWORD}
volumes:
- neo4j_data:/data
- neo4j_logs:/log
networks:
- graphnet

volumes:
neo4j_data:
neo4j_logs:

networks:
graphnet:
driver: bridge
22 changes: 0 additions & 22 deletions infrastructure/evault-core/docker-compose.yml

This file was deleted.

63 changes: 33 additions & 30 deletions infrastructure/evault-core/package.json
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
{
"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": "pnpm@10.6.5",
"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:*"
}
}
107 changes: 98 additions & 9 deletions infrastructure/evault-core/src/db/db.service.ts
Original file line numberDiff line numberDiff 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 DownExpand 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 DownExpand 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
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 numberDiff line numberDiff 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
7 changes: 7 additions & 0 deletions .env.example
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
# Neo4j Configuration
NEO4J_URI=bolt://neo4j:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_secure_password_here

# eVault Configuration
PORT=4000
2 changes: 1 addition & 1 deletion .github/workflows/tests-evault-core.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ on:
pull_request:
branches: [main]
paths:
- 'infrastructure/w3id/**'
- 'infrastructure/evault-core/**'

jobs:
test:
Expand Down
23 changes: 23 additions & 0 deletions docker/Dockerfile.evault
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
FROM node:22-slim AS deps
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
RUN npm i -g corepack@latest
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm turbo prune evault-core --docker --use-gitignore=false
RUN mkdir /out
RUN cp -R ./out/full/* /out/
RUN cp -R ./out/json/* /out/
RUN cp ./out/pnpm-lock.yaml /out/pnpm-lock.yaml
RUN cp -R node_modules/ /out/


FROM node:22-slim AS core-api
WORKDIR /app
RUN npm i -g corepack@latest
COPY --from=deps /out/ /app
EXPOSE 4000
workdir /app/infrastructure/evault-core
CMD ["pnpm", "dev"]
50 changes: 50 additions & 0 deletions evault.docker-compose.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
version: '3.8'

services:
evault:
build:
context: .
dockerfile: ./docker/Dockerfile.evault
ports:
- "4000:4000"
environment:
- NEO4J_URI=${NEO4J_URI}
- NEO4J_USER=${NEO4J_USER}
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
networks:
- graphnet
depends_on:
- neo4j
Comment thread
coodos marked this conversation as resolved.
develop:
watch:
- action: sync+restart
path: ./infrastructure/evault-core/
target: /app/infrastructure/evault-core
ignore:
- node_modules
- action: rebuild
path: ./infrastructure/evault-core/package.json
- action: rebuild
path: ./.env

neo4j:
image: neo4j:5.15
container_name: evault-neo4j
ports:
- "7474:7474" # HTTP
- "7687:7687" # Bolt
environment:
- NEO4J_AUTH=${NEO4J_USER}/${NEO4J_PASSWORD}
volumes:
- neo4j_data:/data
- neo4j_logs:/log
networks:
- graphnet

volumes:
neo4j_data:
neo4j_logs:

networks:
graphnet:
driver: bridge
22 changes: 0 additions & 22 deletions infrastructure/evault-core/docker-compose.yml

This file was deleted.

63 changes: 33 additions & 30 deletions infrastructure/evault-core/package.json
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
{
"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": "pnpm@10.6.5",
"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:*"
}
}
107 changes: 98 additions & 9 deletions infrastructure/evault-core/src/db/db.service.ts
Original file line numberDiff line numberDiff 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 DownExpand 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 DownExpand 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
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 numberDiff line numberDiff 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
7 changes: 7 additions & 0 deletions .env.example
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
# Neo4j Configuration
NEO4J_URI=bolt://neo4j:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_secure_password_here

# eVault Configuration
PORT=4000
2 changes: 1 addition & 1 deletion .github/workflows/tests-evault-core.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ on:
pull_request:
branches: [main]
paths:
- 'infrastructure/w3id/**'
- 'infrastructure/evault-core/**'

jobs:
test:
Expand Down
23 changes: 23 additions & 0 deletions docker/Dockerfile.evault
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
FROM node:22-slim AS deps
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
RUN npm i -g corepack@latest
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm turbo prune evault-core --docker --use-gitignore=false
RUN mkdir /out
RUN cp -R ./out/full/* /out/
RUN cp -R ./out/json/* /out/
RUN cp ./out/pnpm-lock.yaml /out/pnpm-lock.yaml
RUN cp -R node_modules/ /out/


FROM node:22-slim AS core-api
WORKDIR /app
RUN npm i -g corepack@latest
COPY --from=deps /out/ /app
EXPOSE 4000
workdir /app/infrastructure/evault-core
CMD ["pnpm", "dev"]
50 changes: 50 additions & 0 deletions evault.docker-compose.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
version: '3.8'

services:
evault:
build:
context: .
dockerfile: ./docker/Dockerfile.evault
ports:
- "4000:4000"
environment:
- NEO4J_URI=${NEO4J_URI}
- NEO4J_USER=${NEO4J_USER}
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
networks:
- graphnet
depends_on:
- neo4j
Comment thread
coodos marked this conversation as resolved.
develop:
watch:
- action: sync+restart
path: ./infrastructure/evault-core/
target: /app/infrastructure/evault-core
ignore:
- node_modules
- action: rebuild
path: ./infrastructure/evault-core/package.json
- action: rebuild
path: ./.env

neo4j:
image: neo4j:5.15
container_name: evault-neo4j
ports:
- "7474:7474" # HTTP
- "7687:7687" # Bolt
environment:
- NEO4J_AUTH=${NEO4J_USER}/${NEO4J_PASSWORD}
volumes:
- neo4j_data:/data
- neo4j_logs:/log
networks:
- graphnet

volumes:
neo4j_data:
neo4j_logs:

networks:
graphnet:
driver: bridge
22 changes: 0 additions & 22 deletions infrastructure/evault-core/docker-compose.yml

This file was deleted.

63 changes: 33 additions & 30 deletions infrastructure/evault-core/package.json
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
{
"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": "pnpm@10.6.5",
"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:*"
}
}
107 changes: 98 additions & 9 deletions infrastructure/evault-core/src/db/db.service.ts
Original file line numberDiff line numberDiff 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 DownExpand 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 DownExpand 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
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 numberDiff line numberDiff 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
7 changes: 7 additions & 0 deletions .env.example
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
# Neo4j Configuration
NEO4J_URI=bolt://neo4j:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_secure_password_here

# eVault Configuration
PORT=4000
2 changes: 1 addition & 1 deletion .github/workflows/tests-evault-core.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ on:
pull_request:
branches: [main]
paths:
- 'infrastructure/w3id/**'
- 'infrastructure/evault-core/**'

jobs:
test:
Expand Down
23 changes: 23 additions & 0 deletions docker/Dockerfile.evault
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
FROM node:22-slim AS deps
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
RUN npm i -g corepack@latest
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm turbo prune evault-core --docker --use-gitignore=false
RUN mkdir /out
RUN cp -R ./out/full/* /out/
RUN cp -R ./out/json/* /out/
RUN cp ./out/pnpm-lock.yaml /out/pnpm-lock.yaml
RUN cp -R node_modules/ /out/


FROM node:22-slim AS core-api
WORKDIR /app
RUN npm i -g corepack@latest
COPY --from=deps /out/ /app
EXPOSE 4000
workdir /app/infrastructure/evault-core
CMD ["pnpm", "dev"]
50 changes: 50 additions & 0 deletions evault.docker-compose.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
version: '3.8'

services:
evault:
build:
context: .
dockerfile: ./docker/Dockerfile.evault
ports:
- "4000:4000"
environment:
- NEO4J_URI=${NEO4J_URI}
- NEO4J_USER=${NEO4J_USER}
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
networks:
- graphnet
depends_on:
- neo4j
Comment thread
coodos marked this conversation as resolved.
develop:
watch:
- action: sync+restart
path: ./infrastructure/evault-core/
target: /app/infrastructure/evault-core
ignore:
- node_modules
- action: rebuild
path: ./infrastructure/evault-core/package.json
- action: rebuild
path: ./.env

neo4j:
image: neo4j:5.15
container_name: evault-neo4j
ports:
- "7474:7474" # HTTP
- "7687:7687" # Bolt
environment:
- NEO4J_AUTH=${NEO4J_USER}/${NEO4J_PASSWORD}
volumes:
- neo4j_data:/data
- neo4j_logs:/log
networks:
- graphnet

volumes:
neo4j_data:
neo4j_logs:

networks:
graphnet:
driver: bridge
22 changes: 0 additions & 22 deletions infrastructure/evault-core/docker-compose.yml

This file was deleted.

63 changes: 33 additions & 30 deletions infrastructure/evault-core/package.json
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
{
"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": "pnpm@10.6.5",
"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:*"
}
}
107 changes: 98 additions & 9 deletions infrastructure/evault-core/src/db/db.service.ts
Original file line numberDiff line numberDiff 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 DownExpand 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 DownExpand 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
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 numberDiff line numberDiff 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
7 changes: 7 additions & 0 deletions .env.example
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
# Neo4j Configuration
NEO4J_URI=bolt://neo4j:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_secure_password_here

# eVault Configuration
PORT=4000
2 changes: 1 addition & 1 deletion .github/workflows/tests-evault-core.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ on:
pull_request:
branches: [main]
paths:
- 'infrastructure/w3id/**'
- 'infrastructure/evault-core/**'

jobs:
test:
Expand Down
23 changes: 23 additions & 0 deletions docker/Dockerfile.evault
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
FROM node:22-slim AS deps
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
RUN npm i -g corepack@latest
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm turbo prune evault-core --docker --use-gitignore=false
RUN mkdir /out
RUN cp -R ./out/full/* /out/
RUN cp -R ./out/json/* /out/
RUN cp ./out/pnpm-lock.yaml /out/pnpm-lock.yaml
RUN cp -R node_modules/ /out/


FROM node:22-slim AS core-api
WORKDIR /app
RUN npm i -g corepack@latest
COPY --from=deps /out/ /app
EXPOSE 4000
workdir /app/infrastructure/evault-core
CMD ["pnpm", "dev"]
50 changes: 50 additions & 0 deletions evault.docker-compose.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
version: '3.8'

services:
evault:
build:
context: .
dockerfile: ./docker/Dockerfile.evault
ports:
- "4000:4000"
environment:
- NEO4J_URI=${NEO4J_URI}
- NEO4J_USER=${NEO4J_USER}
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
networks:
- graphnet
depends_on:
- neo4j
Comment thread
coodos marked this conversation as resolved.
develop:
watch:
- action: sync+restart
path: ./infrastructure/evault-core/
target: /app/infrastructure/evault-core
ignore:
- node_modules
- action: rebuild
path: ./infrastructure/evault-core/package.json
- action: rebuild
path: ./.env

neo4j:
image: neo4j:5.15
container_name: evault-neo4j
ports:
- "7474:7474" # HTTP
- "7687:7687" # Bolt
environment:
- NEO4J_AUTH=${NEO4J_USER}/${NEO4J_PASSWORD}
volumes:
- neo4j_data:/data
- neo4j_logs:/log
networks:
- graphnet

volumes:
neo4j_data:
neo4j_logs:

networks:
graphnet:
driver: bridge
22 changes: 0 additions & 22 deletions infrastructure/evault-core/docker-compose.yml

This file was deleted.

63 changes: 33 additions & 30 deletions infrastructure/evault-core/package.json
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
{
"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": "pnpm@10.6.5",
"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:*"
}
}
107 changes: 98 additions & 9 deletions infrastructure/evault-core/src/db/db.service.ts
Original file line numberDiff line numberDiff 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 DownExpand 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 DownExpand 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
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 numberDiff line numberDiff 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
7 changes: 7 additions & 0 deletions .env.example
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
# Neo4j Configuration
NEO4J_URI=bolt://neo4j:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_secure_password_here

# eVault Configuration
PORT=4000
2 changes: 1 addition & 1 deletion .github/workflows/tests-evault-core.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ on:
pull_request:
branches: [main]
paths:
- 'infrastructure/w3id/**'
- 'infrastructure/evault-core/**'

jobs:
test:
Expand Down
23 changes: 23 additions & 0 deletions docker/Dockerfile.evault
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
FROM node:22-slim AS deps
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
RUN npm i -g corepack@latest
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm turbo prune evault-core --docker --use-gitignore=false
RUN mkdir /out
RUN cp -R ./out/full/* /out/
RUN cp -R ./out/json/* /out/
RUN cp ./out/pnpm-lock.yaml /out/pnpm-lock.yaml
RUN cp -R node_modules/ /out/


FROM node:22-slim AS core-api
WORKDIR /app
RUN npm i -g corepack@latest
COPY --from=deps /out/ /app
EXPOSE 4000
workdir /app/infrastructure/evault-core
CMD ["pnpm", "dev"]
50 changes: 50 additions & 0 deletions evault.docker-compose.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
version: '3.8'

services:
evault:
build:
context: .
dockerfile: ./docker/Dockerfile.evault
ports:
- "4000:4000"
environment:
- NEO4J_URI=${NEO4J_URI}
- NEO4J_USER=${NEO4J_USER}
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
networks:
- graphnet
depends_on:
- neo4j
Comment thread
coodos marked this conversation as resolved.
develop:
watch:
- action: sync+restart
path: ./infrastructure/evault-core/
target: /app/infrastructure/evault-core
ignore:
- node_modules
- action: rebuild
path: ./infrastructure/evault-core/package.json
- action: rebuild
path: ./.env

neo4j:
image: neo4j:5.15
container_name: evault-neo4j
ports:
- "7474:7474" # HTTP
- "7687:7687" # Bolt
environment:
- NEO4J_AUTH=${NEO4J_USER}/${NEO4J_PASSWORD}
volumes:
- neo4j_data:/data
- neo4j_logs:/log
networks:
- graphnet

volumes:
neo4j_data:
neo4j_logs:

networks:
graphnet:
driver: bridge
22 changes: 0 additions & 22 deletions infrastructure/evault-core/docker-compose.yml

This file was deleted.

63 changes: 33 additions & 30 deletions infrastructure/evault-core/package.json
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
{
"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": "pnpm@10.6.5",
"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:*"
}
}
107 changes: 98 additions & 9 deletions infrastructure/evault-core/src/db/db.service.ts
Original file line numberDiff line numberDiff 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 DownExpand 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 DownExpand 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
Loading