diff --git a/.gitignore b/.gitignore index cc006b58..c914036d 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,6 @@ yarn-error.log* # Misc .DS_Store *.pem + + +evault-cache.json \ No newline at end of file diff --git a/infrastructure/control-panel/package.json b/infrastructure/control-panel/package.json index 78ced26d..6f2f7a16 100644 --- a/infrastructure/control-panel/package.json +++ b/infrastructure/control-panel/package.json @@ -50,6 +50,7 @@ "flowbite": "^3.1.2", "flowbite-svelte": "^1.10.7", "flowbite-svelte-icons": "^2.2.1", + "lowdb": "^9.1.0", "lucide-svelte": "^0.539.0", "tailwind-merge": "^3.0.2" } diff --git a/infrastructure/control-panel/src/lib/components/EVaultList.svelte b/infrastructure/control-panel/src/lib/components/EVaultList.svelte new file mode 100644 index 00000000..46dee510 --- /dev/null +++ b/infrastructure/control-panel/src/lib/components/EVaultList.svelte @@ -0,0 +1,143 @@ + + +
+
+

eVault Control Panel

+
+ + + +
+
+ + + {#if cacheStatus} +
+

Cache Status

+
+
+ Last Updated:
+ {new Date(cacheStatus.lastUpdated).toLocaleString()} +
+
+ Status:
+ + {cacheStatus.isStale ? 'Stale' : 'Fresh'} + +
+
+ Cached Items:
+ {cacheStatus.count} eVaults +
+
+
+ {/if} + + + {#if lastRefresh} +
+ Last refresh: {lastRefresh} +
+ {/if} + + +
+ {#if evaults.length === 0} +
+ {loading ? 'Loading eVaults...' : 'No eVaults found'} +
+ {:else} + {#each evaults as evault} +
+

{evault.name || 'Unnamed eVault'}

+
+ Namespace: + {evault.namespace}
+ Pod: + {evault.podName}
+ Status: + + {evault.status} + +
+
+ {/each} + {/if} +
+
diff --git a/infrastructure/control-panel/src/lib/services/cacheService.ts b/infrastructure/control-panel/src/lib/services/cacheService.ts new file mode 100644 index 00000000..1f48faf4 --- /dev/null +++ b/infrastructure/control-panel/src/lib/services/cacheService.ts @@ -0,0 +1,114 @@ +import { Low } from 'lowdb' +import { JSONFile } from 'lowdb/node' +import type { EVault } from '../../routes/api/evaults/+server'; + +// Define the cache data structure +interface CacheData { + evaults: EVault[]; + lastUpdated: number; + isStale: boolean; +} + +// Cache file path (will be created in the project root) +const CACHE_FILE = './evault-cache.json'; + +// Default cache data +const defaultData: CacheData = { + evaults: [], + lastUpdated: 0, + isStale: true +}; + +class CacheService { + private db: Low; + private isInitialized = false; + + constructor() { + // Initialize LowDB with JSON file adapter + const adapter = new JSONFile(CACHE_FILE); + this.db = new Low(adapter, defaultData); + } + + /** + * Initialize the cache service + */ + async init(): Promise { + if (this.isInitialized) return; + + try { + await this.db.read(); + this.isInitialized = true; + console.log('Cache service initialized'); + } catch (error) { + console.warn('Cache file not found, using default data'); + this.db.data = defaultData; + await this.db.write(); + this.isInitialized = true; + } + } + + /** + * Get cached eVaults (fast, returns immediately) + */ + async getCachedEVaults(): Promise { + await this.init(); + return this.db.data.evaults; + } + + /** + * Check if cache is stale (older than 5 minutes) + */ + isCacheStale(): boolean { + const fiveMinutesAgo = Date.now() - (5 * 60 * 1000); + return this.db.data.lastUpdated < fiveMinutesAgo; + } + + /** + * Update cache with fresh data + */ + async updateCache(evaults: EVault[]): Promise { + await this.init(); + + this.db.data = { + evaults, + lastUpdated: Date.now(), + isStale: false + }; + + await this.db.write(); + console.log(`Cache updated with ${evaults.length} eVaults`); + } + + /** + * Mark cache as stale (force refresh on next request) + */ + async markStale(): Promise { + await this.init(); + this.db.data.isStale = true; + await this.db.write(); + } + + /** + * Get cache status + */ + getCacheStatus(): { lastUpdated: number; isStale: boolean; count: number } { + return { + lastUpdated: this.db.data.lastUpdated, + isStale: this.db.data.isStale, + count: this.db.data.evaults.length + }; + } + + /** + * Clear cache + */ + async clearCache(): Promise { + await this.init(); + this.db.data = defaultData; + await this.db.write(); + console.log('Cache cleared'); + } +} + +// Export singleton instance +export const cacheService = new CacheService(); diff --git a/infrastructure/control-panel/src/lib/services/evaultService.ts b/infrastructure/control-panel/src/lib/services/evaultService.ts index 8e0b2961..f0371283 100644 --- a/infrastructure/control-panel/src/lib/services/evaultService.ts +++ b/infrastructure/control-panel/src/lib/services/evaultService.ts @@ -1,7 +1,54 @@ import type { EVault } from '../../routes/api/evaults/+server'; +import { cacheService } from './cacheService'; export class EVaultService { + /** + * Get eVaults with stale-while-revalidate pattern: + * 1. Return cached data immediately (fast) + * 2. Fetch fresh data in background + * 3. Update cache for next request + */ static async getEVaults(): Promise { + try { + // 1. Get cached data immediately (fast response) + const cachedEVaults = await cacheService.getCachedEVaults(); + + // 2. Check if we need to refresh in background + if (cacheService.isCacheStale()) { + // Fire and forget - fetch fresh data in background + this.refreshCacheInBackground(); + } + + // 3. Return cached data immediately + return cachedEVaults; + } catch (error) { + console.error('Error getting cached eVaults:', error); + // Fallback to direct API call if cache fails + return this.fetchEVaultsDirectly(); + } + } + + /** + * Fetch fresh eVaults from API and update cache + * This runs in the background to avoid blocking the UI + */ + private static async refreshCacheInBackground(): Promise { + try { + console.log('šŸ”„ Refreshing eVault cache in background...'); + const freshEVaults = await this.fetchEVaultsDirectly(); + await cacheService.updateCache(freshEVaults); + console.log('āœ… Cache refreshed successfully'); + } catch (error) { + console.error('āŒ Failed to refresh cache:', error); + // Mark cache as stale so we try again next time + await cacheService.markStale(); + } + } + + /** + * Direct API call to fetch eVaults (fallback method) + */ + private static async fetchEVaultsDirectly(): Promise { try { const response = await fetch('/api/evaults'); if (!response.ok) { @@ -10,11 +57,42 @@ export class EVaultService { const data = await response.json(); return data.evaults || []; } catch (error) { - console.error('Error fetching eVaults:', error); + console.error('Error fetching eVaults directly:', error); return []; } } + /** + * Force refresh cache and return fresh data + * Useful for manual refresh buttons + */ + static async forceRefresh(): Promise { + try { + console.log('šŸ”„ Force refreshing eVault cache...'); + const freshEVaults = await this.fetchEVaultsDirectly(); + await cacheService.updateCache(freshEVaults); + return freshEVaults; + } catch (error) { + console.error('Error force refreshing eVaults:', error); + // Return cached data as fallback + return await cacheService.getCachedEVaults(); + } + } + + /** + * Get cache status for debugging/monitoring + */ + static getCacheStatus() { + return cacheService.getCacheStatus(); + } + + /** + * Clear cache (useful for troubleshooting) + */ + static async clearCache(): Promise { + await cacheService.clearCache(); + } + static async getEVaultLogs( namespace: string, podName: string, @@ -60,7 +138,7 @@ export class EVaultService { } return await response.json(); } catch (error) { - console.error('Error fetching eVault metrics:', error); + console.error('Error fetching metrics:', error); return null; } } diff --git a/infrastructure/web3-adapter/src/db/index.d.ts b/infrastructure/web3-adapter/src/db/index.d.ts new file mode 100644 index 00000000..2b35a798 --- /dev/null +++ b/infrastructure/web3-adapter/src/db/index.d.ts @@ -0,0 +1,2 @@ +export * from "./mapping.db"; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/index.d.ts.map b/infrastructure/web3-adapter/src/db/index.d.ts.map new file mode 100644 index 00000000..30c34a3a --- /dev/null +++ b/infrastructure/web3-adapter/src/db/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/index.js b/infrastructure/web3-adapter/src/db/index.js new file mode 100644 index 00000000..c8fda5d5 --- /dev/null +++ b/infrastructure/web3-adapter/src/db/index.js @@ -0,0 +1,18 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./mapping.db"), exports); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/index.js.map b/infrastructure/web3-adapter/src/db/index.js.map new file mode 100644 index 00000000..9cedaaba --- /dev/null +++ b/infrastructure/web3-adapter/src/db/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/mapping.db.d.ts b/infrastructure/web3-adapter/src/db/mapping.db.d.ts new file mode 100644 index 00000000..2e9d5073 --- /dev/null +++ b/infrastructure/web3-adapter/src/db/mapping.db.d.ts @@ -0,0 +1,39 @@ +export declare class MappingDatabase { + private db; + private runAsync; + private getAsync; + private allAsync; + constructor(dbPath: string); + private initialize; + /** + * Store a mapping between local and global IDs + */ + storeMapping(params: { + localId: string; + globalId: string; + }): Promise; + /** + * Get the global ID for a local ID + */ + getGlobalId(localId: string): Promise; + /** + * Get the local ID for a global ID + */ + getLocalId(globalId: string): Promise; + /** + * Delete a mapping + */ + deleteMapping(localId: string): Promise; + /** + * Get all mappings + */ + getAllMappings(): Promise>; + /** + * Close the database connection + */ + close(): void; +} +//# sourceMappingURL=mapping.db.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/mapping.db.d.ts.map b/infrastructure/web3-adapter/src/db/mapping.db.d.ts.map new file mode 100644 index 00000000..5d3658f8 --- /dev/null +++ b/infrastructure/web3-adapter/src/db/mapping.db.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"mapping.db.d.ts","sourceRoot":"","sources":["mapping.db.ts"],"names":[],"mappings":"AAIA,qBAAa,eAAe;IACxB,OAAO,CAAC,EAAE,CAAmB;IAC7B,OAAO,CAAC,QAAQ,CAAoD;IACpE,OAAO,CAAC,QAAQ,CAI2B;IAC3C,OAAO,CAAC,QAAQ,CAI6B;gBAEjC,MAAM,EAAE,MAAM;YAcZ,UAAU;IAexB;;OAEG;IACU,YAAY,CAAC,MAAM,EAAE;QAC9B,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCjB;;OAEG;IACU,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAmBjE;;OAEG;IACU,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAkBjE;;OAEG;IACU,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY1D;;OAEG;IACU,cAAc,IAAI,OAAO,CAClC,KAAK,CAAC;QACF,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;KACpB,CAAC,CACL;IAgBD;;OAEG;IACI,KAAK,IAAI,IAAI;CAOvB"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/mapping.db.js b/infrastructure/web3-adapter/src/db/mapping.db.js new file mode 100644 index 00000000..74e34eca --- /dev/null +++ b/infrastructure/web3-adapter/src/db/mapping.db.js @@ -0,0 +1,132 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.MappingDatabase = void 0; +const node_path_1 = require("node:path"); +const node_util_1 = require("node:util"); +const sqlite3_1 = __importDefault(require("sqlite3")); +class MappingDatabase { + constructor(dbPath) { + // Ensure the directory exists + const fullPath = (0, node_path_1.join)(dbPath, "mappings.db"); + this.db = new sqlite3_1.default.Database(fullPath); + // Promisify database methods + this.runAsync = (0, node_util_1.promisify)(this.db.run.bind(this.db)); + this.getAsync = (0, node_util_1.promisify)(this.db.get.bind(this.db)); + this.allAsync = (0, node_util_1.promisify)(this.db.all.bind(this.db)); + // Initialize the database with the required tables + this.initialize(); + } + async initialize() { + await this.runAsync(` + CREATE TABLE IF NOT EXISTS id_mappings ( + local_id TEXT NOT NULL, + global_id TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (global_id) + ) + `); + await this.runAsync(` + CREATE INDEX IF NOT EXISTS idx_local_id ON id_mappings(local_id) + `); + } + /** + * Store a mapping between local and global IDs + */ + async storeMapping(params) { + // Validate inputs + if (!params.localId || !params.globalId) { + throw new Error("Invalid mapping parameters: all fields are required"); + } + console.log("storing mapping g:l", params.globalId, params.localId); + // Check if mapping already exists + const existingMapping = await this.getGlobalId(params.localId); + if (existingMapping) { + return; + } + await this.runAsync(`INSERT INTO id_mappings (local_id, global_id) + VALUES (?, ?)`, [params.localId, params.globalId]); + const storedMapping = await this.getGlobalId(params.localId); + if (storedMapping !== params.globalId) { + console.log("storedMappingError", storedMapping, params.globalId); + console.error("Failed to store mapping"); + return; + } + } + /** + * Get the global ID for a local ID + */ + async getGlobalId(localId) { + if (!localId) { + return null; + } + try { + const result = await this.getAsync(`SELECT global_id + FROM id_mappings + WHERE local_id = ?`, [localId]); + return result?.global_id ?? null; + } + catch (error) { + console.error("Error getting global ID:", error); + return null; + } + } + /** + * Get the local ID for a global ID + */ + async getLocalId(globalId) { + if (!globalId) { + return null; + } + try { + const result = await this.getAsync(`SELECT local_id + FROM id_mappings + WHERE global_id = ?`, [globalId]); + return result?.local_id ?? null; + } + catch (error) { + return null; + } + } + /** + * Delete a mapping + */ + async deleteMapping(localId) { + if (!localId) { + return; + } + await this.runAsync(`DELETE FROM id_mappings + WHERE local_id = ?`, [localId]); + } + /** + * Get all mappings + */ + async getAllMappings() { + try { + const results = await this.allAsync(`SELECT local_id, global_id + FROM id_mappings`); + return results.map(({ local_id, global_id }) => ({ + localId: local_id, + globalId: global_id, + })); + } + catch (error) { + return []; + } + } + /** + * Close the database connection + */ + close() { + try { + this.db.close(); + } + catch (error) { + console.error("Error closing database connection:", error); + } + } +} +exports.MappingDatabase = MappingDatabase; +//# sourceMappingURL=mapping.db.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/db/mapping.db.js.map b/infrastructure/web3-adapter/src/db/mapping.db.js.map new file mode 100644 index 00000000..0448d0fb --- /dev/null +++ b/infrastructure/web3-adapter/src/db/mapping.db.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mapping.db.js","sourceRoot":"","sources":["mapping.db.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/evault/evault.d.ts b/infrastructure/web3-adapter/src/evault/evault.d.ts new file mode 100644 index 00000000..b21ef228 --- /dev/null +++ b/infrastructure/web3-adapter/src/evault/evault.d.ts @@ -0,0 +1,76 @@ +export interface MetaEnvelope { + id?: string | null; + schemaId: string; + data: Record; + w3id: string; +} +export declare class EVaultClient { + private registryUrl; + private platform; + private clients; + private endpoints; + private tokenInfo; + private isDisposed; + private healthCheckFailures; + private lastHealthCheck; + constructor(registryUrl: string, platform: string); + /** + * Cleanup method to properly dispose of resources + */ + dispose(): void; + /** + * Retry wrapper with exponential backoff + */ + private withRetry; + /** + * Requests a platform token from the registry + * @returns Promise - The platform token + */ + private requestPlatformToken; + /** + * Checks if token needs refresh + */ + private isTokenExpired; + /** + * Ensures we have a valid platform token, requesting one if needed + * @returns Promise - The platform token + */ + private ensurePlatformToken; + private resolveEndpoint; + private ensureClient; + /** + * Check if a cached endpoint is still healthy + */ + private isEndpointHealthy; + /** + * Remove cached client and endpoint for a specific w3id + */ + private removeCachedClient; + /** + * Wrapper for GraphQL requests with timeout handling + */ + private withTimeout; + /** + * Manually trigger a health check for a specific w3id + * Useful for testing or forcing re-resolution + */ + forceHealthCheck(w3id: string): Promise; + /** + * Get health status for all cached endpoints + */ + getHealthStatus(): Record; + /** + * Clear all cached clients (useful for testing or forcing fresh connections) + */ + clearCache(): void; + storeMetaEnvelope(envelope: MetaEnvelope): Promise; + storeReference(referenceId: string, w3id: string): Promise; + fetchMetaEnvelope(id: string, w3id: string): Promise; + updateMetaEnvelopeById(id: string, envelope: MetaEnvelope): Promise; +} +//# sourceMappingURL=evault.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/evault/evault.d.ts.map b/infrastructure/web3-adapter/src/evault/evault.d.ts.map new file mode 100644 index 00000000..e0550ffe --- /dev/null +++ b/infrastructure/web3-adapter/src/evault/evault.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"evault.d.ts","sourceRoot":"","sources":["evault.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IACzB,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IAEjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CAChB;AAqHD,qBAAa,YAAY;IAWjB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,QAAQ;IAXpB,OAAO,CAAC,OAAO,CAAyC;IACxD,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,UAAU,CAAS;IAG3B,OAAO,CAAC,mBAAmB,CAAkC;IAC7D,OAAO,CAAC,eAAe,CAAkC;gBAG7C,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM;IAG5B;;OAEG;IACI,OAAO,IAAI,IAAI;IAWtB;;OAEG;YACW,SAAS;IAoCvB;;;OAGG;YACW,oBAAoB;IAmClC;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB;;;OAGG;YACW,mBAAmB;YAOnB,eAAe;YAoBf,YAAY;IA4C1B;;OAEG;YACW,iBAAiB;IA0D/B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAQ1B;;OAEG;YACW,WAAW;IA0BzB;;;OAGG;IACU,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAyB7D;;OAEG;IACI,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE;QACrC,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,OAAO,CAAC;KACtB,CAAC;IAmBF;;OAEG;IACI,UAAU,IAAI,IAAI;IAQnB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAyB1D,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBhE,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAoBlE,sBAAsB,CACxB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,YAAY,GACvB,OAAO,CAAC,IAAI,CAAC;CA8BnB"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/evault/evault.js b/infrastructure/web3-adapter/src/evault/evault.js new file mode 100644 index 00000000..7ec57a7a --- /dev/null +++ b/infrastructure/web3-adapter/src/evault/evault.js @@ -0,0 +1,431 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.EVaultClient = void 0; +const graphql_request_1 = require("graphql-request"); +const uuid_1 = require("uuid"); +// Configuration constants +const CONFIG = { + REQUEST_TIMEOUT: 30000, // 30 seconds + CONNECTION_TIMEOUT: 10000, // 10 seconds + TOKEN_REFRESH_THRESHOLD: 5 * 60 * 1000, // 5 minutes before expiry + MAX_RETRIES: 3, + RETRY_DELAY: 1000, // 1 second base delay + CONNECTION_POOL_SIZE: 10, + HEALTH_CHECK_TIMEOUT: 5000, // 5 seconds for health check + MAX_HEALTH_CHECK_FAILURES: 3, // Max consecutive failures before re-resolution + GRAPHQL_TIMEOUT: 10000, // 10 seconds for GraphQL requests before considering endpoint unhealthy +}; +const STORE_META_ENVELOPE = ` + mutation StoreMetaEnvelope($input: MetaEnvelopeInput!) { + storeMetaEnvelope(input: $input) { + metaEnvelope { + id + ontology + parsed + } + } + } +`; +const FETCH_META_ENVELOPE = ` + query FetchMetaEnvelope($id: ID!) { + metaEnvelope(id: $id) { + id + ontology + parsed + } + } +`; +const UPDATE_META_ENVELOPE = ` + mutation UpdateMetaEnvelopeById($id: String!, $input: MetaEnvelopeInput!) { + updateMetaEnvelopeById(id: $id, input: $input) { + metaEnvelope { + id + ontology + parsed + } + envelopes { + id + ontology + value + valueType + } + } + } +`; +class EVaultClient { + constructor(registryUrl, platform) { + this.registryUrl = registryUrl; + this.platform = platform; + this.clients = new Map(); + this.endpoints = new Map(); + this.tokenInfo = null; + this.isDisposed = false; + // Health check tracking + this.healthCheckFailures = new Map(); + this.lastHealthCheck = new Map(); + } + /** + * Cleanup method to properly dispose of resources + */ + dispose() { + if (this.isDisposed) + return; + this.isDisposed = true; + this.clients.clear(); + this.endpoints.clear(); + this.healthCheckFailures.clear(); + this.lastHealthCheck.clear(); + this.tokenInfo = null; + } + /** + * Retry wrapper with exponential backoff + */ + async withRetry(operation, maxRetries = CONFIG.MAX_RETRIES) { + let lastError; + for (let attempt = 0; attempt <= maxRetries; attempt++) { + try { + return await operation(); + } + catch (error) { + lastError = error; + // Don't retry on the last attempt + if (attempt === maxRetries) + break; + // Don't retry on certain errors + if (error instanceof Error) { + const isRetryable = !(error.message.includes("401") || + error.message.includes("403") || + error.message.includes("404")); + if (!isRetryable) + break; + } + // Exponential backoff + const delay = CONFIG.RETRY_DELAY * 2 ** attempt; + await new Promise((resolve) => setTimeout(resolve, delay)); + } + } + // biome-ignore lint/style/noNonNullAssertion: + throw lastError; + } + /** + * Requests a platform token from the registry + * @returns Promise - The platform token + */ + async requestPlatformToken() { + try { + const response = await fetch(new URL("/platforms/certification", this.registryUrl).toString(), { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ platform: this.platform }), + }); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = (await response.json()); + const now = Date.now(); + const expiresAt = data.expiresAt || now + 3600000; // Default 1 hour + return { + token: data.token, + expiresAt, + obtainedAt: now, + }; + } + catch (error) { + console.error("Error requesting platform token:", error); + throw new Error("Failed to request platform token"); + } + } + /** + * Checks if token needs refresh + */ + isTokenExpired() { + if (!this.tokenInfo) + return true; + const now = Date.now(); + const timeUntilExpiry = this.tokenInfo.expiresAt - now; + return timeUntilExpiry <= CONFIG.TOKEN_REFRESH_THRESHOLD; + } + /** + * Ensures we have a valid platform token, requesting one if needed + * @returns Promise - The platform token + */ + async ensurePlatformToken() { + if (!this.tokenInfo || this.isTokenExpired()) { + this.tokenInfo = await this.requestPlatformToken(); + } + return this.tokenInfo.token; + } + async resolveEndpoint(w3id) { + try { + const enrichedW3id = w3id.startsWith("@") ? w3id : `@${w3id}`; + console.log("fetching endpoint for :", enrichedW3id); + const response = await fetch(new URL(`/resolve?w3id=${enrichedW3id}`, this.registryUrl).toString()); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + return new URL("/graphql", data.uri).toString(); + } + catch (error) { + console.error("Error resolving eVault endpoint:", error); + throw new Error("Failed to resolve eVault endpoint"); + } + } + async ensureClient(w3id) { + if (this.isDisposed) { + throw new Error("EVaultClient has been disposed"); + } + // Check if we already have a client for this specific w3id + if (this.clients.has(w3id)) { + const client = this.clients.get(w3id); + const endpoint = this.endpoints.get(w3id); + // Check if the cached endpoint is still healthy + if (await this.isEndpointHealthy(w3id, endpoint)) { + console.log('reusing existing client for w3id:', w3id, 'endpoint:', endpoint); + return client; + } + else { + console.log('cached endpoint is unhealthy, removing and re-resolving for w3id:', w3id); + this.removeCachedClient(w3id); + } + } + // Resolve endpoint for this specific w3id + const endpoint = await this.resolveEndpoint(w3id).catch(() => null); + if (!endpoint) + throw new Error("Failed to resolve endpoint"); + // Get platform token and create client with authorization header + const token = await this.ensurePlatformToken(); + const client = new graphql_request_1.GraphQLClient(endpoint, { + headers: { + authorization: `Bearer ${token}`, + }, + }); + // Cache the client and endpoint for this specific w3id + this.clients.set(w3id, client); + this.endpoints.set(w3id, endpoint); + // Initialize health check tracking + this.healthCheckFailures.set(w3id, 0); + this.lastHealthCheck.set(w3id, Date.now()); + console.log('created new client for w3id:', w3id, 'endpoint:', endpoint); + return client; + } + /** + * Check if a cached endpoint is still healthy + */ + async isEndpointHealthy(w3id, endpoint) { + try { + // Extract base URL from GraphQL endpoint + const baseUrl = endpoint.replace('/graphql', ''); + // Check if we should perform health check (avoid too frequent checks) + const now = Date.now(); + const lastCheck = this.lastHealthCheck.get(w3id) || 0; + const timeSinceLastCheck = now - lastCheck; + // Only check every 30 seconds to avoid performance impact + if (timeSinceLastCheck < 30000) { + return true; // Assume healthy if checked recently + } + // Perform health check on the whois endpoint + const healthCheckUrl = `${baseUrl}/whois`; + console.log(`Health checking endpoint for ${w3id}: ${healthCheckUrl}`); + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), CONFIG.HEALTH_CHECK_TIMEOUT); + const response = await fetch(healthCheckUrl, { + method: 'HEAD', + signal: controller.signal, + }); + clearTimeout(timeoutId); + if (response.ok) { + // Reset failure count on success + this.healthCheckFailures.set(w3id, 0); + this.lastHealthCheck.set(w3id, now); + return true; + } + else { + throw new Error(`Health check failed with status: ${response.status}`); + } + } + catch (error) { + console.log(`Health check failed for ${w3id}:`, error instanceof Error ? error.message : 'Unknown error'); + // Increment failure count + const currentFailures = this.healthCheckFailures.get(w3id) || 0; + const newFailures = currentFailures + 1; + this.healthCheckFailures.set(w3id, newFailures); + this.lastHealthCheck.set(w3id, Date.now()); + // If we've had too many consecutive failures, mark as unhealthy + if (newFailures >= CONFIG.MAX_HEALTH_CHECK_FAILURES) { + console.log(`Endpoint for ${w3id} marked as unhealthy after ${newFailures} consecutive failures`); + return false; + } + // Still allow some failures before marking as unhealthy + return true; + } + } + /** + * Remove cached client and endpoint for a specific w3id + */ + removeCachedClient(w3id) { + this.clients.delete(w3id); + this.endpoints.delete(w3id); + this.healthCheckFailures.delete(w3id); + this.lastHealthCheck.delete(w3id); + console.log(`Removed cached client for ${w3id}`); + } + /** + * Wrapper for GraphQL requests with timeout handling + */ + async withTimeout(w3id, operation) { + const controller = new AbortController(); + const timeoutId = setTimeout(() => { + controller.abort(); + console.log(`GraphQL request timeout for ${w3id}, marking endpoint as unhealthy`); + this.removeCachedClient(w3id); + }, CONFIG.GRAPHQL_TIMEOUT); + try { + const result = await operation(); + clearTimeout(timeoutId); + return result; + } + catch (error) { + clearTimeout(timeoutId); + if (error instanceof Error && error.name === 'AbortError') { + throw new Error(`Request timeout after ${CONFIG.GRAPHQL_TIMEOUT}ms`); + } + throw error; + } + } + /** + * Manually trigger a health check for a specific w3id + * Useful for testing or forcing re-resolution + */ + async forceHealthCheck(w3id) { + if (!this.clients.has(w3id)) { + console.log(`No cached client found for ${w3id}`); + return false; + } + const endpoint = this.endpoints.get(w3id); + if (!endpoint) { + console.log(`No cached endpoint found for ${w3id}`); + return false; + } + // Force health check by clearing last check time + this.lastHealthCheck.set(w3id, 0); + const isHealthy = await this.isEndpointHealthy(w3id, endpoint); + if (!isHealthy) { + console.log(`Forced health check failed for ${w3id}, removing cached client`); + this.removeCachedClient(w3id); + } + return isHealthy; + } + /** + * Get health status for all cached endpoints + */ + getHealthStatus() { + const status = {}; + for (const [w3id, endpoint] of this.endpoints) { + const failures = this.healthCheckFailures.get(w3id) || 0; + const lastCheck = this.lastHealthCheck.get(w3id) || 0; + const isHealthy = failures < CONFIG.MAX_HEALTH_CHECK_FAILURES; + status[w3id] = { + endpoint, + failures, + lastCheck, + isHealthy, + }; + } + return status; + } + /** + * Clear all cached clients (useful for testing or forcing fresh connections) + */ + clearCache() { + console.log('Clearing all cached clients and endpoints'); + this.clients.clear(); + this.endpoints.clear(); + this.healthCheckFailures.clear(); + this.lastHealthCheck.clear(); + } + async storeMetaEnvelope(envelope) { + return this.withRetry(async () => { + const client = await this.ensureClient(envelope.w3id).catch(() => { + return null; + }); + if (!client) + return (0, uuid_1.v4)(); + console.log("sending to eVault: ", envelope.w3id); + console.log("sending payload", envelope); + const response = await this.withTimeout(envelope.w3id, () => client.request(STORE_META_ENVELOPE, { + input: { + ontology: envelope.schemaId, + payload: envelope.data, + acl: ["*"], + }, + })).catch(() => null); + if (!response) + return (0, uuid_1.v4)(); + return response.storeMetaEnvelope.metaEnvelope.id; + }); + } + async storeReference(referenceId, w3id) { + return this.withRetry(async () => { + const client = await this.ensureClient(w3id); + const response = await client + .request(STORE_META_ENVELOPE, { + input: { + ontology: "reference", + payload: { + _by_reference: referenceId, + }, + acl: ["*"], + }, + }) + .catch(() => null); + if (!response) { + console.error("Failed to store reference"); + throw new Error("Failed to store reference"); + } + }); + } + async fetchMetaEnvelope(id, w3id) { + return this.withRetry(async () => { + const client = await this.ensureClient(w3id); + try { + const response = await client.request(FETCH_META_ENVELOPE, { + id, + w3id, + }); + return response.metaEnvelope; + } + catch (error) { + console.error("Error fetching meta envelope:", error); + throw error; + } + }); + } + async updateMetaEnvelopeById(id, envelope) { + return this.withRetry(async () => { + console.log("sending to eVault", envelope.w3id); + const client = await this.ensureClient(envelope.w3id).catch(() => null); + if (!client) + throw new Error("Failed to establish client connection"); + try { + const variables = { + id, + input: { + ontology: envelope.schemaId, + payload: envelope.data, + acl: ["*"], + }, + }; + const response = await client.request(UPDATE_META_ENVELOPE, variables); + } + catch (error) { + console.error("Error updating meta envelope:", error); + throw error; + } + }); + } +} +exports.EVaultClient = EVaultClient; +//# sourceMappingURL=evault.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/evault/evault.js.map b/infrastructure/web3-adapter/src/evault/evault.js.map new file mode 100644 index 00000000..27048f44 --- /dev/null +++ b/infrastructure/web3-adapter/src/evault/evault.js.map @@ -0,0 +1 @@ +{"version":3,"file":"evault.js","sourceRoot":"","sources":["evault.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/index.d.ts b/infrastructure/web3-adapter/src/index.d.ts new file mode 100644 index 00000000..c0878637 --- /dev/null +++ b/infrastructure/web3-adapter/src/index.d.ts @@ -0,0 +1,102 @@ +import { MappingDatabase } from "./db"; +import { EVaultClient } from "./evault/evault"; +import type { IMapping } from "./mapper/mapper.types"; +/** + * Standalone function to spin up an eVault + * @param registryUrl - URL of the registry service + * @param provisionerUrl - URL of the provisioner service + * @param verificationCode - Optional verification code, defaults to demo code + * @returns Promise with eVault details (w3id, uri) + */ +export declare function spinUpEVault(registryUrl: string, provisionerUrl: string, verificationCode?: string): Promise<{ + w3id: string; + uri: string; +}>; +/** + * Standalone function to create a group eVault with GroupManifest + * @param registryUrl - URL of the registry service + * @param provisionerUrl - URL of the provisioner service + * @param groupData - Group data for the manifest + * @param verificationCode - Optional verification code, defaults to demo code + * @returns Promise with eVault details (w3id, uri, manifestId) + */ +export declare function createGroupEVault(registryUrl: string, provisionerUrl: string, groupData: { + name: string; + avatar?: string; + description?: string; + members: string[]; + admins: string[]; + owner: string; + charter?: string; +}, verificationCode?: string): Promise<{ + w3id: string; + uri: string; + manifestId: string; +}>; +export declare class Web3Adapter { + private readonly config; + mapping: Record; + mappingDb: MappingDatabase; + evaultClient: EVaultClient; + lockedIds: string[]; + platform: string; + constructor(config: { + schemasPath: string; + dbPath: string; + registryUrl: string; + platform: string; + provisionerUrl?: string; + }); + readPaths(): Promise; + addToLockedIds(id: string): void; + handleChange(props: { + data: Record; + tableName: string; + participants?: string[]; + }): Promise<{ + id: string; + w3id: string; + schemaId: string; + data?: undefined; + } | { + id: string; + w3id: string; + data: Record; + schemaId: string; + } | undefined>; + fromGlobal(props: { + data: Record; + mapping: IMapping; + }): Promise>; + /** + * Spins up an eVault by getting entropy from registry and provisioning it + * @param verificationCode - Optional verification code, defaults to demo code + * @param provisionerUrl - Optional provisioner URL, defaults to config + * @returns Promise with eVault details (w3id, uri) + */ + spinUpEVault(verificationCode?: string, provisionerUrl?: string): Promise<{ + w3id: string; + uri: string; + }>; + /** + * Creates a group eVault with GroupManifest + * @param groupData - Group data for the manifest + * @param verificationCode - Optional verification code, defaults to demo code + * @param provisionerUrl - Optional provisioner URL, defaults to config + * @returns Promise with eVault details (w3id, uri, manifestId) + */ + createGroupEVault(groupData: { + name: string; + avatar?: string; + description?: string; + members: string[]; + admins: string[]; + owner: string; + charter?: string; + }, verificationCode?: string, provisionerUrl?: string): Promise<{ + w3id: string; + uri: string; + manifestId: string; + }>; +} +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/index.d.ts.map b/infrastructure/web3-adapter/src/index.d.ts.map new file mode 100644 index 00000000..6a3ac5c3 --- /dev/null +++ b/infrastructure/web3-adapter/src/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/index.js b/infrastructure/web3-adapter/src/index.js new file mode 100644 index 00000000..bc2b6ad6 --- /dev/null +++ b/infrastructure/web3-adapter/src/index.js @@ -0,0 +1,317 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Web3Adapter = void 0; +exports.spinUpEVault = spinUpEVault; +exports.createGroupEVault = createGroupEVault; +const fs = __importStar(require("node:fs/promises")); +const node_path_1 = __importDefault(require("node:path")); +const axios_1 = __importDefault(require("axios")); +const uuid_1 = require("uuid"); +const db_1 = require("./db"); +const evault_1 = require("./evault/evault"); +const logging_1 = require("./logging"); +const mapper_1 = require("./mapper/mapper"); +/** + * Standalone function to spin up an eVault + * @param registryUrl - URL of the registry service + * @param provisionerUrl - URL of the provisioner service + * @param verificationCode - Optional verification code, defaults to demo code + * @returns Promise with eVault details (w3id, uri) + */ +async function spinUpEVault(registryUrl, provisionerUrl, verificationCode) { + const DEMO_CODE_W3DS = "d66b7138-538a-465f-a6ce-f6985854c3f4"; + const finalVerificationCode = verificationCode || DEMO_CODE_W3DS; + try { + const entropyResponse = await axios_1.default.get(new URL("/entropy", registryUrl).toString()); + const registryEntropy = entropyResponse.data.token; + const namespace = (0, uuid_1.v4)(); + const provisionResponse = await axios_1.default.post(new URL("/provision", provisionerUrl).toString(), { + registryEntropy, + namespace, + verificationId: finalVerificationCode, + publicKey: "0x0000000000000000000000000000000000000000" + }); + if (!provisionResponse.data.success) { + throw new Error(`Failed to provision eVault: ${provisionResponse.data.message || "Unknown error"}`); + } + return { + w3id: provisionResponse.data.w3id, + uri: provisionResponse.data.uri, + }; + } + catch (error) { + if (axios_1.default.isAxiosError(error)) { + throw new Error(`Failed to spin up eVault: ${error.response?.data?.message || error.message}`); + } + throw new Error(`Failed to spin up eVault: ${error instanceof Error ? error.message : "Unknown error"}`); + } +} +/** + * Standalone function to create a group eVault with GroupManifest + * @param registryUrl - URL of the registry service + * @param provisionerUrl - URL of the provisioner service + * @param groupData - Group data for the manifest + * @param verificationCode - Optional verification code, defaults to demo code + * @returns Promise with eVault details (w3id, uri, manifestId) + */ +async function createGroupEVault(registryUrl, provisionerUrl, groupData, verificationCode) { + const DEMO_CODE_W3DS = "d66b7138-538a-465f-a6ce-f6985854c3f4"; + const finalVerificationCode = verificationCode || DEMO_CODE_W3DS; + try { + // Step 1: Spin up the eVault + const evault = await spinUpEVault(registryUrl, provisionerUrl, finalVerificationCode); + // Step 2: Create GroupManifest with exponential backoff + const manifestId = await createGroupManifestWithRetry(registryUrl, evault.w3id, groupData); + return { + w3id: evault.w3id, + uri: evault.uri, + manifestId, + }; + } + catch (error) { + if (axios_1.default.isAxiosError(error)) { + throw new Error(`Failed to create group eVault: ${error.response?.data?.message || error.message}`); + } + throw new Error(`Failed to create group eVault: ${error instanceof Error ? error.message : "Unknown error"}`); + } +} +/** + * Create GroupManifest in eVault with exponential backoff retry mechanism + */ +async function createGroupManifestWithRetry(registryUrl, w3id, groupData, maxRetries = 10) { + const now = new Date().toISOString(); + const groupManifest = { + eName: w3id, + name: groupData.name, + avatar: groupData.avatar, + description: groupData.description, + members: groupData.members, + charter: groupData.charter, + admins: groupData.admins, + owner: groupData.owner, + createdAt: now, + updatedAt: now, + }; + for (let attempt = 1; attempt <= maxRetries; attempt++) { + try { + console.log(`Attempting to create GroupManifest in eVault (attempt ${attempt}/${maxRetries})`); + const response = await axios_1.default.get(new URL(`resolve?w3id=${w3id}`, registryUrl).toString()); + const endpoint = new URL("/graphql", response.data.uri).toString(); + const { GraphQLClient } = await Promise.resolve().then(() => __importStar(require("graphql-request"))); + const client = new GraphQLClient(endpoint); + const STORE_META_ENVELOPE = ` + mutation StoreMetaEnvelope($input: MetaEnvelopeInput!) { + storeMetaEnvelope(input: $input) { + metaEnvelope { + id + ontology + parsed + } + } + } + `; + const result = await client.request(STORE_META_ENVELOPE, { + input: { + ontology: "550e8400-e29b-41d4-a716-446655440001", // GroupManifest schema ID + payload: groupManifest, + acl: ["*"], + }, + }); + const manifestId = result.storeMetaEnvelope.metaEnvelope.id; + console.log("GroupManifest created successfully in eVault:", manifestId); + return manifestId; + } + catch (error) { + console.error(`Failed to create GroupManifest in eVault (attempt ${attempt}/${maxRetries}):`, error); + if (attempt === maxRetries) { + console.error("Max retries reached, giving up on GroupManifest creation"); + throw error; + } + // Wait before retrying (exponential backoff) + const delay = Math.min(1000 * 2 ** (attempt - 1), 10000); + console.log(`Waiting ${delay}ms before retry...`); + await new Promise((resolve) => setTimeout(resolve, delay)); + } + } + throw new Error("Failed to create GroupManifest after all retries"); +} +class Web3Adapter { + constructor(config) { + this.config = config; + this.mapping = {}; + this.lockedIds = []; + this.readPaths(); + this.mappingDb = new db_1.MappingDatabase(config.dbPath); + this.evaultClient = new evault_1.EVaultClient(config.registryUrl, config.platform); + this.platform = config.platform; + } + async readPaths() { + const allRawFiles = await fs.readdir(this.config.schemasPath); + const mappingFiles = allRawFiles.filter((p) => p.endsWith(".json")); + for (const mappingFile of mappingFiles) { + const mappingFileContent = await fs.readFile(node_path_1.default.join(this.config.schemasPath, mappingFile)); + const mappingParsed = JSON.parse(mappingFileContent.toString()); + this.mapping[mappingParsed.tableName] = mappingParsed; + } + } + addToLockedIds(id) { + this.lockedIds.push(id); + console.log("Added", this.lockedIds); + setTimeout(() => { + this.lockedIds = this.lockedIds.filter((f) => f !== id); + }, 15000); + } + async handleChange(props) { + const { data, tableName, participants } = props; + const existingGlobalId = await this.mappingDb.getGlobalId(data.id); + if (!this.mapping[tableName]) + return; + if (this.mapping[tableName].readOnly) { + // early return on mappings which are readonly so as to not + // sync any update to the eVault which is not warranted + return; + } + if (existingGlobalId) { + if (this.lockedIds.includes(existingGlobalId)) + return; + const global = await (0, mapper_1.toGlobal)({ + data, + mapping: this.mapping[tableName], + mappingStore: this.mappingDb, + }); + this.evaultClient + .updateMetaEnvelopeById(existingGlobalId, { + id: existingGlobalId, + w3id: global.ownerEvault, + data: global.data, + schemaId: this.mapping[tableName].schemaId, + }) + .catch(() => console.error("failed to sync update")); + logging_1.logger.info({ + tableName, + id: existingGlobalId, + platform: this.platform, + w3id: global.ownerEvault, + }); + return { + id: existingGlobalId, + w3id: global.ownerEvault, + schemaId: this.mapping[tableName].tableName, + }; + } + const global = await (0, mapper_1.toGlobal)({ + data, + mapping: this.mapping[tableName], + mappingStore: this.mappingDb, + }); + let globalId; + if (global.ownerEvault) { + globalId = await this.evaultClient.storeMetaEnvelope({ + id: null, + w3id: global.ownerEvault, + data: global.data, + schemaId: this.mapping[tableName].schemaId, + }); + console.log("created new meta-env", globalId); + } + else { + return; + } + // Store the mapping + await this.mappingDb.storeMapping({ + localId: data.id, + globalId, + }); + // Handle references for other participants + const otherEvaults = (participants ?? []).filter((i) => i !== global.ownerEvault); + for (const evault of otherEvaults) { + await this.evaultClient.storeReference(`${global.ownerEvault}/${globalId}`, evault); + } + logging_1.logger.info({ + tableName, + id: globalId, + w3id: global.ownerEvault, + platform: this.platform + }); + return { + id: globalId, + w3id: global.ownerEvault, + data: global.data, + schemaId: this.mapping[tableName].schemaId, + }; + } + async fromGlobal(props) { + const { data, mapping } = props; + const local = await (0, mapper_1.fromGlobal)({ + data, + mapping, + mappingStore: this.mappingDb, + }); + return local; + } + /** + * Spins up an eVault by getting entropy from registry and provisioning it + * @param verificationCode - Optional verification code, defaults to demo code + * @param provisionerUrl - Optional provisioner URL, defaults to config + * @returns Promise with eVault details (w3id, uri) + */ + async spinUpEVault(verificationCode, provisionerUrl) { + const finalProvisionerUrl = provisionerUrl || this.config.provisionerUrl; + if (!finalProvisionerUrl) { + throw new Error("Provisioner URL is required. Please provide it in config or as parameter."); + } + return spinUpEVault(this.config.registryUrl, finalProvisionerUrl, verificationCode); + } + /** + * Creates a group eVault with GroupManifest + * @param groupData - Group data for the manifest + * @param verificationCode - Optional verification code, defaults to demo code + * @param provisionerUrl - Optional provisioner URL, defaults to config + * @returns Promise with eVault details (w3id, uri, manifestId) + */ + async createGroupEVault(groupData, verificationCode, provisionerUrl) { + const finalProvisionerUrl = provisionerUrl || this.config.provisionerUrl; + if (!finalProvisionerUrl) { + throw new Error("Provisioner URL is required. Please provide it in config or as parameter."); + } + return createGroupEVault(this.config.registryUrl, finalProvisionerUrl, groupData, verificationCode); + } +} +exports.Web3Adapter = Web3Adapter; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/index.js.map b/infrastructure/web3-adapter/src/index.js.map new file mode 100644 index 00000000..cc83389c --- /dev/null +++ b/infrastructure/web3-adapter/src/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/index.ts b/infrastructure/web3-adapter/src/index.ts index 21be3051..9a37170b 100644 --- a/infrastructure/web3-adapter/src/index.ts +++ b/infrastructure/web3-adapter/src/index.ts @@ -37,6 +37,7 @@ export async function spinUpEVault( registryEntropy, namespace, verificationId: finalVerificationCode, + publicKey: "0x0000000000000000000000000000000000000000" }, ); diff --git a/infrastructure/web3-adapter/src/logging/index.d.ts b/infrastructure/web3-adapter/src/logging/index.d.ts new file mode 100644 index 00000000..7fec87f5 --- /dev/null +++ b/infrastructure/web3-adapter/src/logging/index.d.ts @@ -0,0 +1,3 @@ +export * from "./transport"; +export * from "./logger"; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/index.d.ts.map b/infrastructure/web3-adapter/src/logging/index.d.ts.map new file mode 100644 index 00000000..65a5999e --- /dev/null +++ b/infrastructure/web3-adapter/src/logging/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/index.js b/infrastructure/web3-adapter/src/logging/index.js new file mode 100644 index 00000000..06388ce6 --- /dev/null +++ b/infrastructure/web3-adapter/src/logging/index.js @@ -0,0 +1,19 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./transport"), exports); +__exportStar(require("./logger"), exports); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/index.js.map b/infrastructure/web3-adapter/src/logging/index.js.map new file mode 100644 index 00000000..72bdfc16 --- /dev/null +++ b/infrastructure/web3-adapter/src/logging/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,2CAAyB"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/logger.d.ts b/infrastructure/web3-adapter/src/logging/logger.d.ts new file mode 100644 index 00000000..93d8f742 --- /dev/null +++ b/infrastructure/web3-adapter/src/logging/logger.d.ts @@ -0,0 +1,3 @@ +import pino from "pino"; +export declare const logger: pino.Logger; +//# sourceMappingURL=logger.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/logger.d.ts.map b/infrastructure/web3-adapter/src/logging/logger.d.ts.map new file mode 100644 index 00000000..607ec511 --- /dev/null +++ b/infrastructure/web3-adapter/src/logging/logger.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,eAAO,MAAM,MAAM,6BAAkB,CAAC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/logger.js b/infrastructure/web3-adapter/src/logging/logger.js new file mode 100644 index 00000000..71ce7443 --- /dev/null +++ b/infrastructure/web3-adapter/src/logging/logger.js @@ -0,0 +1,10 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.logger = void 0; +const pino_1 = __importDefault(require("pino")); +const transport_1 = require("./transport"); +exports.logger = (0, pino_1.default)(transport_1.transport); +//# sourceMappingURL=logger.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/logger.js.map b/infrastructure/web3-adapter/src/logging/logger.js.map new file mode 100644 index 00000000..bdbf0d3d --- /dev/null +++ b/infrastructure/web3-adapter/src/logging/logger.js.map @@ -0,0 +1 @@ +{"version":3,"file":"logger.js","sourceRoot":"","sources":["logger.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AACxB,2CAAwC;AAE3B,QAAA,MAAM,GAAG,IAAA,cAAI,EAAC,qBAAS,CAAC,CAAC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/transport.d.ts b/infrastructure/web3-adapter/src/logging/transport.d.ts new file mode 100644 index 00000000..a84a6199 --- /dev/null +++ b/infrastructure/web3-adapter/src/logging/transport.d.ts @@ -0,0 +1,2 @@ +export declare const transport: any; +//# sourceMappingURL=transport.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/transport.d.ts.map b/infrastructure/web3-adapter/src/logging/transport.d.ts.map new file mode 100644 index 00000000..ee79162f --- /dev/null +++ b/infrastructure/web3-adapter/src/logging/transport.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["transport.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,SAAS,KAYpB,CAAC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/transport.js b/infrastructure/web3-adapter/src/logging/transport.js new file mode 100644 index 00000000..f7d515ac --- /dev/null +++ b/infrastructure/web3-adapter/src/logging/transport.js @@ -0,0 +1,25 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.transport = void 0; +const pino_1 = require("pino"); +const dotenv_1 = __importDefault(require("dotenv")); +const path_1 = __importDefault(require("path")); +const envPath = path_1.default.resolve(__dirname, "../../../../.env"); +dotenv_1.default.config({ path: envPath }); +exports.transport = (0, pino_1.transport)({ + target: "pino-loki", + options: { + host: process.env.LOKI_URL, + labels: { + app: "web3-adapter", + }, + basicAuth: { + username: process.env.LOKI_USERNAME || "admin", + password: process.env.LOKI_PASSWORD || "admin", + }, + }, +}); +//# sourceMappingURL=transport.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/logging/transport.js.map b/infrastructure/web3-adapter/src/logging/transport.js.map new file mode 100644 index 00000000..a3ad2ac0 --- /dev/null +++ b/infrastructure/web3-adapter/src/logging/transport.js.map @@ -0,0 +1 @@ +{"version":3,"file":"transport.js","sourceRoot":"","sources":["transport.ts"],"names":[],"mappings":";;;;;;AAAA,+BAAkD;AAElD,oDAA4B;AAC5B,gDAAwB;AAExB,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAA;AAC3D,gBAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAC,CAAC,CAAA;AAElB,QAAA,SAAS,GAAG,IAAA,gBAAa,EAAc;IAChD,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE;QACL,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,QAAkB;QACpC,MAAM,EAAE;YACJ,GAAG,EAAE,cAAc;SACtB;QACD,SAAS,EAAE;YACP,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO;YAC9C,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO;SACjD;KACJ;CACJ,CAAC,CAAC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.d.ts b/infrastructure/web3-adapter/src/mapper/mapper.d.ts new file mode 100644 index 00000000..09a3f57b --- /dev/null +++ b/infrastructure/web3-adapter/src/mapper/mapper.d.ts @@ -0,0 +1,5 @@ +import type { IMapperResponse, IMappingConversionOptions } from "./mapper.types"; +export declare function getValueByPath(obj: Record, path: string): any; +export declare function fromGlobal({ data, mapping, mappingStore, }: IMappingConversionOptions): Promise>; +export declare function toGlobal({ data, mapping, mappingStore, }: IMappingConversionOptions): Promise; +//# sourceMappingURL=mapper.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.d.ts.map b/infrastructure/web3-adapter/src/mapper/mapper.d.ts.map new file mode 100644 index 00000000..22aa9be8 --- /dev/null +++ b/infrastructure/web3-adapter/src/mapper/mapper.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,eAAe,EACf,yBAAyB,EAC5B,MAAM,gBAAgB,CAAC;AAGxB,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,CA2B1E;AAkFD,wBAAsB,UAAU,CAAC,EAC7B,IAAI,EACJ,OAAO,EACP,YAAY,GACf,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC,CAsF3E;AA8BD,wBAAsB,QAAQ,CAAC,EAC3B,IAAI,EACJ,OAAO,EACP,YAAY,GACf,EAAE,yBAAyB,GAAG,OAAO,CAAC,eAAe,CAAC,CAwHtD"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.js b/infrastructure/web3-adapter/src/mapper/mapper.js new file mode 100644 index 00000000..68e27cca --- /dev/null +++ b/infrastructure/web3-adapter/src/mapper/mapper.js @@ -0,0 +1,306 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getValueByPath = getValueByPath; +exports.fromGlobal = fromGlobal; +exports.toGlobal = toGlobal; +// biome-ignore lint/suspicious/noExplicitAny: +function getValueByPath(obj, path) { + // Handle array mapping case (e.g., "images[].src") + if (path.includes("[]")) { + const [arrayPath, fieldPath] = path.split("[]"); + const array = getValueByPath(obj, arrayPath); + if (!Array.isArray(array)) { + return []; + } + // If there's a field path after [], map through the array + if (fieldPath) { + return array.map((item) => getValueByPath(item, fieldPath.slice(1))); // Remove the leading dot + } + return array; + } + // Handle regular path case + const parts = path.split("."); + // biome-ignore lint/suspicious/noExplicitAny: + return parts.reduce((acc, part) => { + if (acc === null || acc === undefined) + return undefined; + return acc[part]; + }, obj); +} +/** + * Extracts the owner eVault from data using the specified path(s). + * Supports fallback paths using the || operator. + * + * @param data - The data object to extract from + * @param ownerEnamePath - The path(s) to extract from. Can be: + * - Single path: "owner.ename" + * - Fallback paths: "path1||path2" (tries path1 first, then path2) + * - Table references: "users(owner.ename)" + * - Fallback with table refs: "users(owner.ename)||users(creator.ename)" + * @returns The owner eVault identifier or null if not found + */ +async function extractOwnerEvault(data, ownerEnamePath) { + if (!ownerEnamePath || ownerEnamePath === "null") { + return null; + } + // Check if the path contains fallback operator (||) + if (ownerEnamePath.includes("||")) { + const paths = ownerEnamePath.split("||").map(path => path.trim()).filter(path => path.length > 0); + if (paths.length < 2) { + console.warn("Invalid fallback path format. Expected 'path1||path2' but got:", ownerEnamePath); + return null; + } + console.log(`Processing fallback paths for owner eVault: [${paths.join(", ")}]`); + // Try each path in order until one succeeds + for (let i = 0; i < paths.length; i++) { + const path = paths[i]; + console.log(`Trying fallback path ${i + 1}/${paths.length}: ${path}`); + const result = await extractOwnerEvaultSinglePath(data, path); + if (result !== null) { + console.log(`āœ… Owner eVault found using fallback path ${i + 1}: ${path}`); + return result; + } + else { + console.log(`āŒ Fallback path ${i + 1} failed: ${path}`); + } + } + // If all paths fail, return null + console.log("āŒ All fallback paths failed for owner eVault"); + return null; + } + // Single path - use existing logic + return await extractOwnerEvaultSinglePath(data, ownerEnamePath); +} +/** + * Helper function to extract owner eVault from a single path. + * This is the original implementation logic for single paths. + */ +async function extractOwnerEvaultSinglePath(data, ownerEnamePath) { + if (!ownerEnamePath.includes("(")) { + return data[ownerEnamePath] || null; + } + const [_, fieldPathRaw] = ownerEnamePath.split("("); + const fieldPath = fieldPathRaw.replace(")", ""); + let value = getValueByPath(data, fieldPath); + if (Array.isArray(value)) + return value[0]; + console.log("OWNER PATH", value); + // Check if value is a string before calling .includes() + if (typeof value === "string" && value.includes("(") && value.includes(")")) { + value = value.split("(")[1].split(")")[0]; + } + return value || null; +} +async function fromGlobal({ data, mapping, mappingStore, }) { + const result = {}; + for (const [localKey, globalPathRaw] of Object.entries(mapping.localToUniversalMap)) { + let value; + const targetKey = localKey; + let tableRef = null; + const internalFnMatch = globalPathRaw.match(/^__(\w+)\((.+)\)$/); + if (internalFnMatch) { + const [, outerFn, innerExpr] = internalFnMatch; + if (outerFn === "date") { + const calcMatch = innerExpr.match(/^calc\((.+)\)$/); + if (calcMatch) { + const calcResult = evaluateCalcExpression(calcMatch[1], data); + value = + calcResult !== undefined + ? new Date(calcResult).toISOString() + : undefined; + } + else { + const rawVal = getValueByPath(data, innerExpr); + if (typeof rawVal === "number") { + value = new Date(rawVal).toISOString(); + } + else if (rawVal?._seconds) { + // Handle Firebase v8 timestamp format + value = new Date(rawVal._seconds * 1000).toISOString(); + } + else if (rawVal?.seconds) { + // Handle Firebase v9+ timestamp format + value = new Date(rawVal.seconds * 1000).toISOString(); + } + else if (rawVal?.toDate && typeof rawVal.toDate === 'function') { + // Handle Firebase Timestamp objects + value = rawVal.toDate().toISOString(); + } + else if (rawVal instanceof Date) { + value = rawVal.toISOString(); + } + else if (typeof rawVal === 'string' && rawVal.includes('UTC')) { + // Handle Firebase timestamp strings like "August 18, 2025 at 10:03:19 AM UTC+5:30" + value = new Date(rawVal).toISOString(); + } + else { + value = undefined; + } + } + } + else if (outerFn === "calc") { + value = evaluateCalcExpression(innerExpr, data); + } + result[targetKey] = value; + continue; + } + let pathRef = globalPathRaw; + if (globalPathRaw.includes("(") && globalPathRaw.includes(")")) { + tableRef = globalPathRaw.split("(")[0]; + } + if (pathRef.includes(",")) { + pathRef = pathRef.split(",")[1]; + } + value = getValueByPath(data, pathRef); + if (tableRef) { + if (Array.isArray(value)) { + value = await Promise.all(value.map(async (v) => { + const localId = await mappingStore.getLocalId(v); + return localId ? `${tableRef}(${localId})` : null; + })); + } + else { + value = await mappingStore.getLocalId(value); + value = value ? `${tableRef}(${value})` : null; + } + } + result[localKey] = value; + } + return { + data: result, + }; +} +function evaluateCalcExpression(expr, +// biome-ignore lint/suspicious/noExplicitAny: +context) { + const tokens = expr + .split(/[^\w.]+/) + .map((t) => t.trim()) + .filter(Boolean); + let resolvedExpr = expr; + for (const token of tokens) { + const value = getValueByPath(context, token); + if (typeof value !== "undefined") { + resolvedExpr = resolvedExpr.replace(new RegExp(`\\b${token.replace(".", "\\.")}\\b`, "g"), value); + } + } + try { + return Function(`use strict"; return (${resolvedExpr})`)(); + } + catch { + return undefined; + } +} +async function toGlobal({ data, mapping, mappingStore, }) { + const result = {}; + for (const [localKey, globalPathRaw] of Object.entries(mapping.localToUniversalMap)) { + // biome-ignore lint/suspicious/noExplicitAny: + let value; + let targetKey = globalPathRaw; + if (globalPathRaw.includes(",")) { + const [_, alias] = globalPathRaw.split(","); + targetKey = alias; + } + if (localKey.includes("[]")) { + const [arrayPath, innerPathRaw] = localKey.split("[]"); + const cleanInnerPath = innerPathRaw.startsWith(".") + ? innerPathRaw.slice(1) + : innerPathRaw; + const array = getValueByPath(data, arrayPath); + value = Array.isArray(array) + ? array.map((item) => getValueByPath(item, cleanInnerPath)) + : undefined; + result[targetKey] = value; + continue; + } + const internalFnMatch = globalPathRaw.match(/^__(\w+)\((.+)\)$/); + if (internalFnMatch) { + const [, outerFn, innerExpr] = internalFnMatch; + if (outerFn === "date") { + const calcMatch = innerExpr.match(/^calc\((.+)\)$/); + if (calcMatch) { + const calcResult = evaluateCalcExpression(calcMatch[1], data); + value = + calcResult !== undefined + ? new Date(calcResult).toISOString() + : undefined; + } + else { + const rawVal = getValueByPath(data, innerExpr); + if (typeof rawVal === "number") { + value = new Date(rawVal).toISOString(); + } + else if (rawVal?._seconds) { + // Handle Firebase v8 timestamp format + value = new Date(rawVal._seconds * 1000).toISOString(); + } + else if (rawVal?.seconds) { + // Handle Firebase v9+ timestamp format + value = new Date(rawVal.seconds * 1000).toISOString(); + } + else if (rawVal?.toDate && typeof rawVal.toDate === 'function') { + // Handle Firebase Timestamp objects + value = rawVal.toDate().toISOString(); + } + else if (rawVal instanceof Date) { + value = rawVal.toISOString(); + } + else if (typeof rawVal === 'string' && rawVal.includes('UTC')) { + // Handle Firebase timestamp strings like "August 18, 2025 at 10:03:19 AM UTC+5:30" + value = new Date(rawVal).toISOString(); + } + else { + value = undefined; + } + } + } + else if (outerFn === "calc") { + value = evaluateCalcExpression(innerExpr, data); + } + result[targetKey] = value; + continue; + } + const relationMatch = globalPathRaw.match(/^(\w+)\((.+?)\)(\[\])?$/); + if (relationMatch) { + const [, tableRef, pathInData, isArray] = relationMatch; + const refValue = getValueByPath(data, pathInData); + if (isArray) { + value = Array.isArray(refValue) + ? refValue.map((v) => `@${v}`) + : []; + } + else { + value = refValue ? `@${refValue}` : undefined; + } + result[targetKey] = value; + continue; + } + let pathRef = globalPathRaw.includes(",") + ? globalPathRaw + : localKey; + let tableRef = null; + if (globalPathRaw.includes("(") && globalPathRaw.includes(")")) { + pathRef = globalPathRaw.split("(")[1].split(")")[0]; + tableRef = globalPathRaw.split("(")[0]; + } + if (globalPathRaw.includes(",")) { + pathRef = pathRef.split(",")[0]; + } + value = getValueByPath(data, pathRef); + if (tableRef) { + if (Array.isArray(value)) { + value = await Promise.all(value.map(async (v) => (await mappingStore.getGlobalId(v)) ?? undefined)); + } + else { + value = (await mappingStore.getGlobalId(value)) ?? undefined; + } + } + result[targetKey] = value; + } + const ownerEvault = await extractOwnerEvault(data, mapping.ownerEnamePath); + return { + ownerEvault, + data: result, + }; +} +//# sourceMappingURL=mapper.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.js.map b/infrastructure/web3-adapter/src/mapper/mapper.js.map new file mode 100644 index 00000000..755559d3 --- /dev/null +++ b/infrastructure/web3-adapter/src/mapper/mapper.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mapper.js","sourceRoot":"","sources":["mapper.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.ts b/infrastructure/web3-adapter/src/mapper/mapper.ts index 55414d63..21c9f13f 100644 --- a/infrastructure/web3-adapter/src/mapper/mapper.ts +++ b/infrastructure/web3-adapter/src/mapper/mapper.ts @@ -33,6 +33,18 @@ export function getValueByPath(obj: Record, path: string): any { }, obj); } +/** + * Extracts the owner eVault from data using the specified path(s). + * Supports fallback paths using the || operator. + * + * @param data - The data object to extract from + * @param ownerEnamePath - The path(s) to extract from. Can be: + * - Single path: "owner.ename" + * - Fallback paths: "path1||path2" (tries path1 first, then path2) + * - Table references: "users(owner.ename)" + * - Fallback with table refs: "users(owner.ename)||users(creator.ename)" + * @returns The owner eVault identifier or null if not found + */ async function extractOwnerEvault( data: Record, ownerEnamePath: string, @@ -40,6 +52,49 @@ async function extractOwnerEvault( if (!ownerEnamePath || ownerEnamePath === "null") { return null; } + + // Check if the path contains fallback operator (||) + if (ownerEnamePath.includes("||")) { + const paths = ownerEnamePath.split("||").map(path => path.trim()).filter(path => path.length > 0); + + if (paths.length < 2) { + console.warn("Invalid fallback path format. Expected 'path1||path2' but got:", ownerEnamePath); + return null; + } + + console.log(`Processing fallback paths for owner eVault: [${paths.join(", ")}]`); + + // Try each path in order until one succeeds + for (let i = 0; i < paths.length; i++) { + const path = paths[i]; + console.log(`Trying fallback path ${i + 1}/${paths.length}: ${path}`); + + const result = await extractOwnerEvaultSinglePath(data, path); + if (result !== null) { + console.log(`āœ… Owner eVault found using fallback path ${i + 1}: ${path}`); + return result; + } else { + console.log(`āŒ Fallback path ${i + 1} failed: ${path}`); + } + } + + // If all paths fail, return null + console.log("āŒ All fallback paths failed for owner eVault"); + return null; + } + + // Single path - use existing logic + return await extractOwnerEvaultSinglePath(data, ownerEnamePath); +} + +/** + * Helper function to extract owner eVault from a single path. + * This is the original implementation logic for single paths. + */ +async function extractOwnerEvaultSinglePath( + data: Record, + ownerEnamePath: string, +): Promise { if (!ownerEnamePath.includes("(")) { return (data[ownerEnamePath] as string) || null; } @@ -49,9 +104,12 @@ async function extractOwnerEvault( let value = getValueByPath(data, fieldPath); if (Array.isArray(value)) return value[0]; console.log("OWNER PATH", value); - if (value.includes("(") && value.includes(")")) { + + // Check if value is a string before calling .includes() + if (typeof value === "string" && value.includes("(") && value.includes(")")) { value = value.split("(")[1].split(")")[0]; } + return (value as string) || null; } diff --git a/infrastructure/web3-adapter/src/mapper/mapper.types.d.ts b/infrastructure/web3-adapter/src/mapper/mapper.types.d.ts new file mode 100644 index 00000000..e233dd4c --- /dev/null +++ b/infrastructure/web3-adapter/src/mapper/mapper.types.d.ts @@ -0,0 +1,47 @@ +import type { MappingDatabase } from "../db"; +export interface IMapping { + /** + * Name of the local table, this would be consumed by other schemas to + * identify relations + */ + tableName: string; + /** + * Schema Identifier for the global schema this table maps to + */ + schemaId: string; + /** + * Path used to determine which eVault owns this entry. + * + * This can be a direct field on the table or a nested path via a foreign table. + * + * - For direct fields, use the field name (e.g. `"ename"`). + * - For nested ownership, use a function-like syntax to reference another table + * and field (e.g. `"user(createdBy.ename)"` means follow the `createdBy` field, + * then resolve `ename` from the `user` table). + * + * Use `tableName(fieldPath)` to reference a field from another table. + * + * @example "ename" — direct reference to a field on the same table + * @example "user(createdBy.ename)" — nested reference via the `user` table + */ + ownerEnamePath: string; + /** + * String to String mapping between what path maps to what global ontology + */ + localToUniversalMap: Record; + /** + * If true, this mapping will not trigger handleChange and will be treated as read-only. + * Useful for entities that should not be synced to eVaults. + */ + readOnly?: boolean; +} +export interface IMappingConversionOptions { + data: Record; + mapping: IMapping; + mappingStore: MappingDatabase; +} +export interface IMapperResponse { + ownerEvault: string | null; + data: Record; +} +//# sourceMappingURL=mapper.types.d.ts.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.types.d.ts.map b/infrastructure/web3-adapter/src/mapper/mapper.types.d.ts.map new file mode 100644 index 00000000..0219bb33 --- /dev/null +++ b/infrastructure/web3-adapter/src/mapper/mapper.types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"mapper.types.d.ts","sourceRoot":"","sources":["mapper.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAE7C,MAAM,WAAW,QAAQ;IACrB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;;;;;;;;;;OAcG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE5C;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,yBAAyB;IACtC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,QAAQ,CAAC;IAClB,YAAY,EAAE,eAAe,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC"} \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.types.js b/infrastructure/web3-adapter/src/mapper/mapper.types.js new file mode 100644 index 00000000..ea11c714 --- /dev/null +++ b/infrastructure/web3-adapter/src/mapper/mapper.types.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=mapper.types.js.map \ No newline at end of file diff --git a/infrastructure/web3-adapter/src/mapper/mapper.types.js.map b/infrastructure/web3-adapter/src/mapper/mapper.types.js.map new file mode 100644 index 00000000..4d49fa79 --- /dev/null +++ b/infrastructure/web3-adapter/src/mapper/mapper.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mapper.types.js","sourceRoot":"","sources":["mapper.types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/platforms/blabsy-w3ds-auth-api/src/controllers/WebhookController.ts b/platforms/blabsy-w3ds-auth-api/src/controllers/WebhookController.ts index 09f66916..17f17541 100644 --- a/platforms/blabsy-w3ds-auth-api/src/controllers/WebhookController.ts +++ b/platforms/blabsy-w3ds-auth-api/src/controllers/WebhookController.ts @@ -46,6 +46,7 @@ type Chat = { type: "direct" | "group"; // Always set by webhook based on participant count name?: string; participants: string[]; + ename?: string; // eVault identifier (w3id) createdAt: Timestamp; updatedAt: Timestamp; lastMessage?: { @@ -111,7 +112,12 @@ export class WebhookController { const local = await adapter.fromGlobal({ data, mapping }); - console.log(local); + console.log("Webhook data received:", { + globalId: id, + tableName, + hasEname: !!local.data.ename, + ename: local.data.ename + }); // Get the local ID from the mapping database const localId = await adapter.mappingDb.getLocalId(id); @@ -285,10 +291,16 @@ export class WebhookController { // Derive type from participant count const type = participants.length > 2 ? "group" : "direct"; + // Log ename processing for debugging + if (data.ename) { + console.log(`Processing chat with ename: ${data.ename}`); + } + return { type, name: data.name, participants, + ename: data.ename || null, // Include eVault identifier if available createdAt: data.createdAt ? Timestamp.fromDate(new Date(data.createdAt)) : now, diff --git a/platforms/blabsy-w3ds-auth-api/src/web3adapter/mappings/chat.mapping.json b/platforms/blabsy-w3ds-auth-api/src/web3adapter/mappings/chat.mapping.json index 69c5f526..5a13ad63 100644 --- a/platforms/blabsy-w3ds-auth-api/src/web3adapter/mappings/chat.mapping.json +++ b/platforms/blabsy-w3ds-auth-api/src/web3adapter/mappings/chat.mapping.json @@ -1,11 +1,12 @@ { "tableName": "chat", "schemaId": "550e8400-e29b-41d4-a716-446655440003", - "participants": "user(participants[])", + "participants": "ename||user(participants[])", "ownerEnamePath": "users(participants[])", "localToUniversalMap": { "name": "name", "type": "type", + "ename": "ename", "admins": "user(admins),admins", "participants": "user(participants[]),participantIds", "lastMessage": "lastMessageId", diff --git a/platforms/blabsy-w3ds-auth-api/src/web3adapter/mappings/message.mapping.json b/platforms/blabsy-w3ds-auth-api/src/web3adapter/mappings/message.mapping.json index 3d683896..55d41d5d 100644 --- a/platforms/blabsy-w3ds-auth-api/src/web3adapter/mappings/message.mapping.json +++ b/platforms/blabsy-w3ds-auth-api/src/web3adapter/mappings/message.mapping.json @@ -1,7 +1,7 @@ { "tableName": "message", "schemaId": "550e8400-e29b-41d4-a716-446655440004", - "ownerEnamePath": "user(senderId)", + "ownerEnamePath": "chat(chat.ename)||user(senderId)", "localToUniversalMap": { "chatId": "chat(chatId),chatId", "senderId": "user(senderId),senderId", diff --git a/platforms/blabsy-w3ds-auth-api/src/web3adapter/watchers/firestoreWatcher.ts b/platforms/blabsy-w3ds-auth-api/src/web3adapter/watchers/firestoreWatcher.ts index 6a05a6c8..ca2a93ff 100644 --- a/platforms/blabsy-w3ds-auth-api/src/web3adapter/watchers/firestoreWatcher.ts +++ b/platforms/blabsy-w3ds-auth-api/src/web3adapter/watchers/firestoreWatcher.ts @@ -5,6 +5,7 @@ import { CollectionReference, CollectionGroup, } from "firebase-admin/firestore"; +import { getFirestore } from "firebase-admin/firestore"; import path from "path"; import dotenv from "dotenv"; import { adapter } from "../../controllers/WebhookController"; @@ -13,6 +14,7 @@ dotenv.config({ path: path.resolve(__dirname, "../../../../../.env") }); export class FirestoreWatcher { private unsubscribe: (() => void) | null = null; private adapter = adapter; + private db: FirebaseFirestore.Firestore; private isProcessing = false; private retryCount = 0; private readonly maxRetries: number = 3; @@ -29,7 +31,9 @@ export class FirestoreWatcher { private readonly collection: | CollectionReference | CollectionGroup - ) {} + ) { + this.db = getFirestore(); + } async start(): Promise { const collectionPath = @@ -214,11 +218,69 @@ export class FirestoreWatcher { const tableName = tableNameRaw.slice(0, tableNameRaw.length - 1); + // If this is a message, fetch and attach the full chat details + let enrichedData: DocumentData & { id: string; chat?: DocumentData } = { ...data, id: doc.id }; + + console.log("----------------") + console.log("----------------") + console.log("----------------") + console.log("tableName", tableName) + console.log("----------------") + console.log("----------------") + console.log("----------------") + console.log("----------------") + + if (tableName === "message" && data.chatId) { + + try { + console.log(`Fetching chat details for message ${doc.id} in chat ${data.chatId}`); + const chatDoc = await this.getChatDetails(data.chatId); + if (chatDoc) { + enrichedData = { + ...enrichedData, + chat: chatDoc + }; + console.log(`āœ… Chat details attached to message ${doc.id}`); + } else { + console.log(`āš ļø Chat not found for message ${doc.id} in chat ${data.chatId}`); + } + } catch (error) { + console.error(`āŒ Error fetching chat details for message ${doc.id}:`, error); + // Continue processing even if chat fetch fails + } + } + await this.adapter .handleChange({ - data: { ...data, id: doc.id }, + data: enrichedData, tableName, }) .catch((e) => console.error(e)); } + + /** + * Fetches the full chat details for a given chat ID + */ + private async getChatDetails(chatId: string): Promise { + try { + // Fetch the chat document using the class's Firestore instance + const chatDoc = await this.db.collection("chats").doc(chatId).get(); + + if (chatDoc.exists) { + const chatData = chatDoc.data(); + if (chatData) { + // Add the chat ID to the data + return { + ...chatData, + id: chatId + }; + } + } + + return null; + } catch (error) { + console.error(`Error fetching chat details for chat ${chatId}:`, error); + return null; + } + } } diff --git a/platforms/cerberus/src/controllers/WebhookController.ts b/platforms/cerberus/src/controllers/WebhookController.ts index e7920670..6abd5167 100644 --- a/platforms/cerberus/src/controllers/WebhookController.ts +++ b/platforms/cerberus/src/controllers/WebhookController.ts @@ -154,6 +154,7 @@ export class WebhookController { group.owner = local.data.owner as string; group.admins = admins; group.participants = participants; + group.ename = local.data.ename as string; // Only update charter if new data is provided, preserve existing if not if (newCharter !== undefined && newCharter !== null) { @@ -187,6 +188,7 @@ export class WebhookController { admins, participants: participants, charter: local.data.charter as string, + ename: local.data.ename as string }); console.log("Created group with ID:", group.id); diff --git a/platforms/cerberus/src/database/entities/Group.ts b/platforms/cerberus/src/database/entities/Group.ts index db0e105c..db4c4fed 100644 --- a/platforms/cerberus/src/database/entities/Group.ts +++ b/platforms/cerberus/src/database/entities/Group.ts @@ -28,6 +28,9 @@ export class Group { @Column("simple-array", { nullable: true }) admins!: string[]; + @Column({ nullable: true}) + ename!: string + @Column({ type: "text", nullable: true }) charter!: string; // Markdown content for the group charter diff --git a/platforms/cerberus/src/migrations/1756065113206-migration.ts b/platforms/cerberus/src/migrations/1756065113206-migration.ts new file mode 100644 index 00000000..47ca43c3 --- /dev/null +++ b/platforms/cerberus/src/migrations/1756065113206-migration.ts @@ -0,0 +1,20 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Migration1756065113206 implements MigrationInterface { + name = 'Migration1756065113206' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "group" ADD "ename" character varying`); + await queryRunner.query(`ALTER TABLE "voting_observations" DROP CONSTRAINT "FK_e413458062c606a628a561ed8b2"`); + await queryRunner.query(`ALTER TABLE "voting_observations" ALTER COLUMN "owner" DROP NOT NULL`); + await queryRunner.query(`ALTER TABLE "voting_observations" ADD CONSTRAINT "FK_e413458062c606a628a561ed8b2" FOREIGN KEY ("owner") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "voting_observations" DROP CONSTRAINT "FK_e413458062c606a628a561ed8b2"`); + await queryRunner.query(`ALTER TABLE "voting_observations" ALTER COLUMN "owner" SET NOT NULL`); + await queryRunner.query(`ALTER TABLE "voting_observations" ADD CONSTRAINT "FK_e413458062c606a628a561ed8b2" FOREIGN KEY ("owner") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "group" DROP COLUMN "ename"`); + } + +} diff --git a/platforms/cerberus/src/services/GroupService.ts b/platforms/cerberus/src/services/GroupService.ts index 65d3d7db..1e044cfb 100644 --- a/platforms/cerberus/src/services/GroupService.ts +++ b/platforms/cerberus/src/services/GroupService.ts @@ -40,22 +40,10 @@ export class GroupService { } async getUserGroups(userId: string): Promise { - console.log("Getting groups for user:", userId); - - // First, let's get all groups and filter manually to debug const allGroups = await this.groupRepository.find({ relations: ['participants'] }); - - console.log("All groups found:", allGroups.length); - allGroups.forEach(group => { - console.log(`Group ${group.id} (${group.name}):`, { - participants: group.participants?.map(p => p.id) || [], - hasUser: group.participants?.some(p => p.id === userId) || false - }); - }); - // Filter groups where user is a participant const userGroups = allGroups.filter(group => group.participants?.some(participant => participant.id === userId) ); diff --git a/platforms/cerberus/src/web3adapter/mappings/group.mapping.json b/platforms/cerberus/src/web3adapter/mappings/group.mapping.json index 82ed8f16..8efc6b5f 100644 --- a/platforms/cerberus/src/web3adapter/mappings/group.mapping.json +++ b/platforms/cerberus/src/web3adapter/mappings/group.mapping.json @@ -12,7 +12,8 @@ "participants": "users(participants[].id),participantIds", "charterSignatures": "charter_signature(charterSignatures[].id),signatureIds", "createdAt": "createdAt", - "updatedAt": "updatedAt" + "updatedAt": "updatedAt", + "ename": "ename" }, "readOnly": true } diff --git a/platforms/eVoting/src/app/(app)/create/page.tsx b/platforms/eVoting/src/app/(app)/create/page.tsx index fca9a2b6..e0c26d96 100644 --- a/platforms/eVoting/src/app/(app)/create/page.tsx +++ b/platforms/eVoting/src/app/(app)/create/page.tsx @@ -29,7 +29,10 @@ const createPollSchema = z.object({ title: z.string().min(1, "Poll title is required"), mode: z.enum(["normal", "point", "rank"]), visibility: z.enum(["public", "private"]), - groupId: z.string().min(1, "Please select a group"), + groupId: z.string().min(1, "Please select a group").refine((val) => { + // This will be validated in the onSubmit function with the actual groups data + return true; + }, "Please select a valid group"), options: z .array(z.string().min(1, "Option cannot be empty")) .min(2, "At least 2 options required"), @@ -70,13 +73,28 @@ export default function CreatePoll() { }, }); + // Helper function to sort groups: chartered first, then by name + const sortGroupsByCharterStatus = (groups: Group[]) => { + return [...groups].sort((a, b) => { + const aChartered = a.charter && a.charter.trim() !== ""; + const bChartered = b.charter && b.charter.trim() !== ""; + + if (aChartered && !bChartered) return -1; + if (!aChartered && bChartered) return 1; + + // If both have same charter status, sort by name + return a.name.localeCompare(b.name); + }); + }; + // Fetch user's groups on component mount useEffect(() => { const fetchGroups = async () => { try { const userGroups = await pollApi.getUserGroups(); - // Ensure groups is always an array - setGroups(Array.isArray(userGroups) ? userGroups : []); + // Ensure groups is always an array and sort by charter status + const sortedGroups = Array.isArray(userGroups) ? sortGroupsByCharterStatus(userGroups) : []; + setGroups(sortedGroups); } catch (error) { console.error("Failed to fetch groups:", error); setGroups([]); // Set empty array on error @@ -128,6 +146,26 @@ export default function CreatePoll() { const onSubmit = async (data: CreatePollForm) => { setIsSubmitting(true); try { + // Validate that the selected group is chartered + const selectedGroup = groups.find(group => group.id === data.groupId); + if (!selectedGroup) { + toast({ + title: "Error", + description: "Please select a valid group", + variant: "destructive", + }); + return; + } + + if (!selectedGroup.charter || selectedGroup.charter.trim() === "") { + toast({ + title: "Error", + description: "Only chartered groups can create polls. Please select a group with a charter.", + variant: "destructive", + }); + return; + } + // Convert local deadline to UTC before sending to backend let utcDeadline: string | undefined; if (data.deadline) { @@ -152,11 +190,18 @@ export default function CreatePoll() { }); router.push("/"); - } catch (error) { + } catch (error: any) { console.error("Failed to create poll:", error); + + // Show specific error message from backend if available + let errorMessage = "Failed to create poll. Please try again."; + if (error?.response?.data?.error) { + errorMessage = error.response.data.error; + } + toast({ title: "Error", - description: "Failed to create poll. Please try again.", + description: errorMessage, variant: "destructive", }); } finally { @@ -197,6 +242,15 @@ export default function CreatePoll() { + {!isLoadingGroups && groups.length > 0 && ( +
+ {(() => { + const charteredCount = groups.filter(group => group.charter && group.charter.trim() !== "").length; + const totalCount = groups.length; + return `${charteredCount} of ${totalCount} groups are chartered`; + })()} +
+ )} +

+ Only chartered groups can create polls. Groups without a charter will be disabled. +

{errors.groupId && (

{errors.groupId.message} diff --git a/platforms/eVoting/src/lib/pollApi.ts b/platforms/eVoting/src/lib/pollApi.ts index 6e7cfebd..5b936160 100644 --- a/platforms/eVoting/src/lib/pollApi.ts +++ b/platforms/eVoting/src/lib/pollApi.ts @@ -53,6 +53,7 @@ export interface Group { owner: string; isPrivate: boolean; visibility: "public" | "private" | "restricted"; + charter?: string; // Markdown content for the group charter createdAt: string; updatedAt: string; } diff --git a/platforms/evoting-api/src/controllers/PollController.ts b/platforms/evoting-api/src/controllers/PollController.ts index ec9bf0f5..4c199ac3 100644 --- a/platforms/evoting-api/src/controllers/PollController.ts +++ b/platforms/evoting-api/src/controllers/PollController.ts @@ -74,6 +74,14 @@ export class PollController { res.status(201).json(poll); } catch (error) { console.error("Error creating poll:", error); + + // Handle specific charter validation error + if (error instanceof Error && error.message === "Only chartered groups can create polls") { + return res.status(400).json({ + error: "Only chartered groups can create polls. Please select a group with a charter." + }); + } + res.status(500).json({ error: "Failed to create poll" }); } }; diff --git a/platforms/evoting-api/src/controllers/WebhookController.ts b/platforms/evoting-api/src/controllers/WebhookController.ts index df93a522..fa151565 100644 --- a/platforms/evoting-api/src/controllers/WebhookController.ts +++ b/platforms/evoting-api/src/controllers/WebhookController.ts @@ -150,6 +150,8 @@ export class WebhookController { group.owner = local.data.owner as string; group.admins = adminIds.map(id => ({ id } as User)); group.participants = participants; + group.charter = local.data.charter as string; + group.ename = local.data.ename as string this.adapter.addToLockedIds(localId); await this.groupService.groupRepository.save(group); @@ -162,9 +164,8 @@ export class WebhookController { local.data.owner as string, adminIds, participants.map(p => p.id), - local.data.charter as string | undefined + local.data.charter as string | undefined, ); - console.log("Created group with ID:", group.id); console.log(group) this.adapter.addToLockedIds(group.id); diff --git a/platforms/evoting-api/src/database/entities/Group.ts b/platforms/evoting-api/src/database/entities/Group.ts index 5c3f7788..6892aa56 100644 --- a/platforms/evoting-api/src/database/entities/Group.ts +++ b/platforms/evoting-api/src/database/entities/Group.ts @@ -58,6 +58,9 @@ export class Group { }) participants!: User[]; + @Column({ nullable: true}) + ename: string + @Column({ nullable: true }) avatarUrl!: string; diff --git a/platforms/evoting-api/src/database/migrations/1756065047421-migration.ts b/platforms/evoting-api/src/database/migrations/1756065047421-migration.ts new file mode 100644 index 00000000..f4864168 --- /dev/null +++ b/platforms/evoting-api/src/database/migrations/1756065047421-migration.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Migration1756065047421 implements MigrationInterface { + name = 'Migration1756065047421' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "group" ADD "ename" character varying`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "group" DROP COLUMN "ename"`); + } + +} diff --git a/platforms/evoting-api/src/services/GroupService.ts b/platforms/evoting-api/src/services/GroupService.ts index 548214bd..f6b2dbbe 100644 --- a/platforms/evoting-api/src/services/GroupService.ts +++ b/platforms/evoting-api/src/services/GroupService.ts @@ -44,7 +44,7 @@ export class GroupService { isPrivate: boolean = false, visibility: "public" | "private" | "restricted" = "public", avatarUrl?: string, - bannerUrl?: string + bannerUrl?: string, ): Promise { const members = await this.userRepository.findBy({ id: In(memberIds), diff --git a/platforms/evoting-api/src/services/PollService.ts b/platforms/evoting-api/src/services/PollService.ts index b8ac5d0e..a4acfa61 100644 --- a/platforms/evoting-api/src/services/PollService.ts +++ b/platforms/evoting-api/src/services/PollService.ts @@ -8,11 +8,13 @@ import { MessageService } from "./MessageService"; export class PollService { private pollRepository: Repository; private userRepository: Repository; + private groupRepository: Repository; private messageService: MessageService; constructor() { this.pollRepository = AppDataSource.getRepository(Poll); this.userRepository = AppDataSource.getRepository(User); + this.groupRepository = AppDataSource.getRepository(Group); this.messageService = new MessageService(); } @@ -30,8 +32,7 @@ export class PollService { let userGroupIds: string[] = []; if (userId) { // Get groups where user is a member, admin, or participant - const groupRepository = AppDataSource.getRepository(Group); - const userGroups = await groupRepository + const userGroups = await this.groupRepository .createQueryBuilder('group') .leftJoin('group.members', 'member') .leftJoin('group.admins', 'admin') @@ -158,6 +159,21 @@ export class PollService { throw new Error("Creator not found"); } + // If a groupId is provided, validate that the group is chartered + if (pollData.groupId) { + const group = await this.groupRepository.findOne({ + where: { id: pollData.groupId } + }); + + if (!group) { + throw new Error("Group not found"); + } + + if (!group.charter || group.charter.trim() === "") { + throw new Error("Only chartered groups can create polls"); + } + } + const pollDataForEntity = { title: pollData.title, mode: pollData.mode as "normal" | "point" | "rank", diff --git a/platforms/evoting-api/src/web3adapter/mappings/group.mapping.json b/platforms/evoting-api/src/web3adapter/mappings/group.mapping.json index b50311d4..7047f0bd 100644 --- a/platforms/evoting-api/src/web3adapter/mappings/group.mapping.json +++ b/platforms/evoting-api/src/web3adapter/mappings/group.mapping.json @@ -9,6 +9,7 @@ "owner": "owner", "admins": "users(admins[].id),adminIds", "charter": "charter", + "ename": "ename", "participants": "users(participants[].id),participantIds", "members": "users(members[].id),memberIds", "isPrivate": "isPrivate", diff --git a/platforms/evoting-api/src/web3adapter/mappings/message.mapping.json b/platforms/evoting-api/src/web3adapter/mappings/message.mapping.json index 563ba58b..88a37b37 100644 --- a/platforms/evoting-api/src/web3adapter/mappings/message.mapping.json +++ b/platforms/evoting-api/src/web3adapter/mappings/message.mapping.json @@ -1,7 +1,7 @@ { "tableName": "messages", "schemaId": "550e8400-e29b-41d4-a716-446655440004", - "ownerEnamePath": "users(group.members[].ename)", + "ownerEnamePath": "groups(group.ename)||users(group.members[].ename)", "ownedJunctionTables": [], "localToUniversalMap": { "text": "content", diff --git a/platforms/group-charter-manager-api/package.json b/platforms/group-charter-manager-api/package.json index ed72b3ac..fef2339e 100644 --- a/platforms/group-charter-manager-api/package.json +++ b/platforms/group-charter-manager-api/package.json @@ -10,7 +10,8 @@ "typeorm": "typeorm-ts-node-commonjs", "migration:generate": "npm run typeorm migration:generate -- -d src/database/data-source.ts", "migration:run": "npm run typeorm migration:run -- -d src/database/data-source.ts", - "migration:revert": "npm run typeorm migration:revert -- -d src/database/data-source.ts" + "migration:revert": "npm run typeorm migration:revert -- -d src/database/data-source.ts", + "migrate:evaults": "ts-node src/scripts/migrate-eVaults.ts" }, "dependencies": { "axios": "^1.6.7", diff --git a/platforms/group-charter-manager-api/src/database/entities/Group.ts b/platforms/group-charter-manager-api/src/database/entities/Group.ts index 48fc7c1e..3daadde9 100644 --- a/platforms/group-charter-manager-api/src/database/entities/Group.ts +++ b/platforms/group-charter-manager-api/src/database/entities/Group.ts @@ -31,6 +31,9 @@ export class Group { @Column({ type: "text", nullable: true }) charter!: string; // Markdown content for the group charter + @Column({ nullable: true }) + ename!: string + @ManyToMany("User") @JoinTable({ name: "group_participants", diff --git a/platforms/group-charter-manager-api/src/database/migrations/1756064053488-migration.ts b/platforms/group-charter-manager-api/src/database/migrations/1756064053488-migration.ts new file mode 100644 index 00000000..b75425d2 --- /dev/null +++ b/platforms/group-charter-manager-api/src/database/migrations/1756064053488-migration.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Migration1756064053488 implements MigrationInterface { + name = 'Migration1756064053488' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "group" ADD "ename" character varying`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "group" DROP COLUMN "ename"`); + } + +} diff --git a/platforms/group-charter-manager-api/src/scripts/migrate-eVaults.ts b/platforms/group-charter-manager-api/src/scripts/migrate-eVaults.ts new file mode 100644 index 00000000..aad5722a --- /dev/null +++ b/platforms/group-charter-manager-api/src/scripts/migrate-eVaults.ts @@ -0,0 +1,178 @@ +#!/usr/bin/env ts-node + +import { AppDataSource } from "../database/data-source"; +import { Group } from "../database/entities/Group"; +import { createGroupEVault } from "../../../../infrastructure/web3-adapter/src/index"; +import path from "path"; +import dotenv from "dotenv"; +import { IsNull } from "typeorm"; + +// Load environment variables +dotenv.config({ path: path.resolve(__dirname, "../../../../../.env") }); + +/** + * Migration script to create eVaults for existing chartered groups + * This script should be run once to migrate existing groups + */ +async function migrateExistingGroupsToEVaults() { + console.log("šŸš€ Starting eVault migration for existing chartered groups..."); + + try { + // Initialize database connection + if (!AppDataSource.isInitialized) { + await AppDataSource.initialize(); + console.log("āœ… Database connection initialized"); + } + + // Get the Group repository + const groupRepository = AppDataSource.getRepository(Group); + + // Find all groups that have charters + const allGroups = await groupRepository.find(); + + // Filter to only include groups with actual charter content and no ename + const groupsNeedingMigration = allGroups.filter(group => + group.charter && + group.charter.trim() !== "" && + (!group.ename || group.ename.trim() === "") + ); + + console.log(`šŸ“Š Found ${groupsNeedingMigration.length} groups that need eVault creation`); + + if (groupsNeedingMigration.length === 0) { + console.log("āœ… No groups need migration. All chartered groups already have eVaults!"); + return; + } + + // Check required environment variables + const registryUrl = process.env.PUBLIC_REGISTRY_URL; + const provisionerUrl = process.env.PUBLIC_PROVISIONER_URL; + + if (!registryUrl || !provisionerUrl) { + throw new Error("Missing required environment variables: PUBLIC_REGISTRY_URL and PUBLIC_PROVISIONER_URL"); + } + + console.log("šŸ”§ Environment variables validated"); + console.log(`šŸ“” Registry URL: ${registryUrl}`); + console.log(`šŸ“” Provisioner URL: ${provisionerUrl}`); + + let successCount = 0; + let errorCount = 0; + const errors: Array<{ groupId: string; error: string }> = []; + + // Process groups in batches to avoid overwhelming the system + const batchSize = 5; + for (let i = 0; i < groupsNeedingMigration.length; i += batchSize) { + const batch = groupsNeedingMigration.slice(i, i + batchSize); + console.log(`\nšŸ“¦ Processing batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(groupsNeedingMigration.length / batchSize)}`); + + // Process batch concurrently + const batchPromises = batch.map(async (group) => { + try { + console.log(`šŸ”§ Creating eVault for group: ${group.name} (${group.id})`); + + // Prepare group data for eVault creation + const groupData = { + name: group.name || "Unnamed Group", + avatar: undefined, // No avatar property in Group entity + description: group.description, + members: group.participants?.map((p: any) => p.id) || [], + admins: group.admins || [], + owner: group.owner, + charter: group.charter + }; + + console.log(`šŸ“‹ Group data prepared:`, { + name: groupData.name, + participants: groupData.members.length, + admins: groupData.admins.length, + hasCharter: !!groupData.charter + }); + + // Create eVault + const evaultResult = await createGroupEVault( + registryUrl, + provisionerUrl, + groupData + ); + + console.log(`āœ… eVault created successfully for group ${group.name}:`, { + w3id: evaultResult.w3id, + uri: evaultResult.uri, + manifestId: evaultResult.manifestId + }); + + // Update the group with the ename + group.ename = evaultResult.w3id; + await groupRepository.save(group); + + console.log(`šŸ’¾ Group ${group.name} updated with ename: ${evaultResult.w3id}`); + successCount++; + + } catch (error: any) { + const errorMessage = error.message || "Unknown error"; + console.error(`āŒ Failed to create eVault for group ${group.name} (${group.id}):`, errorMessage); + + errors.push({ + groupId: group.id, + error: errorMessage + }); + errorCount++; + } + }); + + // Wait for batch to complete + await Promise.all(batchPromises); + + // Add a small delay between batches to be respectful to the eVault service + if (i + batchSize < groupsNeedingMigration.length) { + console.log("ā³ Waiting 2 seconds before next batch..."); + await new Promise(resolve => setTimeout(resolve, 2000)); + } + } + + // Print final summary + console.log("\n" + "=".repeat(60)); + console.log("šŸŽÆ MIGRATION COMPLETE - FINAL SUMMARY"); + console.log("=".repeat(60)); + console.log(`āœ… Successfully migrated: ${successCount} groups`); + console.log(`āŒ Failed migrations: ${errorCount} groups`); + console.log(`šŸ“Š Total groups processed: ${groupsNeedingMigration.length}`); + + if (errors.length > 0) { + console.log("\nāŒ ERRORS ENCOUNTERED:"); + errors.forEach(({ groupId, error }) => { + console.log(` - Group ${groupId}: ${error}`); + }); + } + + if (successCount > 0) { + console.log(`\nšŸŽ‰ Successfully created ${successCount} eVaults!`); + } + + if (errorCount > 0) { + console.log(`\nāš ļø ${errorCount} groups failed migration. Check the errors above and consider re-running the migration.`); + } + + } catch (error) { + console.error("šŸ’„ Migration failed with error:", error); + throw error; + } finally { + // Close database connection + if (AppDataSource.isInitialized) { + await AppDataSource.destroy(); + console.log("šŸ”Œ Database connection closed"); + } + } +} + +// Run the migration +migrateExistingGroupsToEVaults() + .then(() => { + console.log("šŸŽÆ Migration script completed successfully"); + process.exit(0); + }) + .catch((error) => { + console.error("šŸ’„ Migration script failed:", error); + process.exit(1); + }); diff --git a/platforms/group-charter-manager-api/src/services/GroupService.ts b/platforms/group-charter-manager-api/src/services/GroupService.ts index 62235675..f85653f4 100644 --- a/platforms/group-charter-manager-api/src/services/GroupService.ts +++ b/platforms/group-charter-manager-api/src/services/GroupService.ts @@ -60,21 +60,11 @@ export class GroupService { } async getUserGroups(userId: string): Promise { - console.log("Getting groups for user:", userId); - // First, let's get all groups and filter manually to debug const allGroups = await this.groupRepository.find({ relations: ['participants'] }); - console.log("All groups found:", allGroups.length); - allGroups.forEach(group => { - console.log(`Group ${group.id} (${group.name}):`, { - participants: group.participants?.map(p => p.id) || [], - hasUser: group.participants?.some(p => p.id === userId) || false - }); - }); - // Filter groups where user is a participant AND group has at least 3 participants const userGroups = allGroups.filter(group => { const isUserParticipant = group.participants?.some(participant => participant.id === userId); diff --git a/platforms/group-charter-manager-api/src/web3adapter/mappings/group.mapping.json b/platforms/group-charter-manager-api/src/web3adapter/mappings/group.mapping.json index 39bf9380..d4e4dea5 100644 --- a/platforms/group-charter-manager-api/src/web3adapter/mappings/group.mapping.json +++ b/platforms/group-charter-manager-api/src/web3adapter/mappings/group.mapping.json @@ -1,7 +1,7 @@ { "tableName": "groups", "schemaId": "550e8400-e29b-41d4-a716-446655440003", - "ownerEnamePath": "users(participants[].ename)", + "ownerEnamePath": "ename||users(participants[].ename)", "ownedJunctionTables": [], "localToUniversalMap": { "name": "name", @@ -12,6 +12,7 @@ "participants": "users(participants[].id),participantIds", "charterSignatures": "charter_signatures(charterSignatures[].id),signatureIds", "createdAt": "createdAt", - "updatedAt": "updatedAt" + "updatedAt": "updatedAt", + "ename": "ename" } } diff --git a/platforms/group-charter-manager-api/src/web3adapter/mappings/message.mapping.json b/platforms/group-charter-manager-api/src/web3adapter/mappings/message.mapping.json index 0f623a39..ad52c47c 100644 --- a/platforms/group-charter-manager-api/src/web3adapter/mappings/message.mapping.json +++ b/platforms/group-charter-manager-api/src/web3adapter/mappings/message.mapping.json @@ -1,7 +1,7 @@ { "tableName": "messages", "schemaId": "550e8400-e29b-41d4-a716-446655440004", - "ownerEnamePath": "users(sender.ename)", + "ownerEnamePath": "groups(group.ename)||users(sender.ename)", "ownedJunctionTables": [], "localToUniversalMap": { "text": "content", diff --git a/platforms/group-charter-manager-api/src/web3adapter/watchers/subscriber.ts b/platforms/group-charter-manager-api/src/web3adapter/watchers/subscriber.ts index 8fea5770..8c30bb22 100644 --- a/platforms/group-charter-manager-api/src/web3adapter/watchers/subscriber.ts +++ b/platforms/group-charter-manager-api/src/web3adapter/watchers/subscriber.ts @@ -7,6 +7,7 @@ import { ObjectLiteral, } from "typeorm"; import { Web3Adapter } from "../../../../../infrastructure/web3-adapter/src/index"; +import { createGroupEVault } from "../../../../../infrastructure/web3-adapter/src/index"; import path from "path"; import dotenv from "dotenv"; import { AppDataSource } from "../../database/data-source"; @@ -177,6 +178,20 @@ export class PostgresSubscriber implements EntitySubscriberInterface { if (fullEntity) { console.log("āœ… Full entity loaded:", { id: fullEntity.id, tableName: event.metadata.tableName }); + + // Check if this is a Group entity and if charter was just added (not updated) + if (entityName === "Group" && fullEntity.charter && fullEntity.charter.trim() !== "") { + // Check if this group doesn't have an ename yet (meaning eVault wasn't created) + if (!fullEntity.ename) { + console.log("Group just got chartered, spinning up eVault for group:", fullEntity.id); + + // Fire and forget eVault creation + this.spinUpGroupEVault(fullEntity).catch(error => { + console.error("Failed to create eVault for group:", fullEntity.id, error); + }); + } + } + entity = (await this.enrichEntity( fullEntity, event.metadata.tableName, @@ -354,6 +369,55 @@ console.log("hmm?") } } + /** + * Spin up eVault for a newly chartered group + */ + private async spinUpGroupEVault(group: any): Promise { + try { + console.log("Starting eVault creation for group:", group.id); + + // Get environment variables for eVault creation + const registryUrl = process.env.PUBLIC_REGISTRY_URL; + const provisionerUrl = process.env.PUBLIC_PROVISIONER_URL; + + if (!registryUrl || !provisionerUrl) { + throw new Error("Missing required environment variables for eVault creation"); + } + + // Prepare group data for eVault creation + const groupData = { + name: group.name || "Unnamed Group", + avatar: group.avatarUrl, + description: group.description, + members: group.participants?.map((p: any) => p.id) || [], + admins: group.admins || [], + owner: group.owner, + charter: group.charter + }; + + console.log("Creating eVault with data:", groupData); + + // Create the eVault (this is the long-running operation) + const evaultResult = await createGroupEVault( + registryUrl, + provisionerUrl, + groupData + ); + + console.log("eVault created successfully:", evaultResult); + + // Update the group with the ename (w3id) + const groupRepository = AppDataSource.getRepository("Group"); + await groupRepository.update(group.id, { ename: evaultResult.w3id }); + + console.log("Group updated with ename:", evaultResult.w3id); + + } catch (error: any) { + console.error("Error creating eVault for group:", group.id, error); + throw error; // Re-throw to be caught by the caller + } + } + /** * Convert TypeORM entity to plain object */ diff --git a/platforms/group-charter-manager/src/app/charter/[id]/page.tsx b/platforms/group-charter-manager/src/app/charter/[id]/page.tsx index 7138c0e2..44a092dc 100644 --- a/platforms/group-charter-manager/src/app/charter/[id]/page.tsx +++ b/platforms/group-charter-manager/src/app/charter/[id]/page.tsx @@ -32,6 +32,7 @@ interface Group { admins: string[]; participants: any[]; charter?: string; + ename?: string; // eVault identifier (w3id) createdAt: string; updatedAt: string; } @@ -212,6 +213,11 @@ export default function CharterDetail({

{group.name || 'Unnamed Group'}

+ {group.ename && ( +
+ {group.ename} +
+ )}
Group Charter
diff --git a/platforms/group-charter-manager/src/app/page.tsx b/platforms/group-charter-manager/src/app/page.tsx index 5b0496f8..06031ed6 100644 --- a/platforms/group-charter-manager/src/app/page.tsx +++ b/platforms/group-charter-manager/src/app/page.tsx @@ -45,6 +45,7 @@ interface Group { admins: string[]; participants: any[]; charter?: string; + ename?: string; // eVault identifier (w3id) hasSigned?: boolean; // Add signing status field createdAt: string; updatedAt: string; @@ -229,6 +230,11 @@ export default function Dashboard() {

{group.name || 'Unnamed Group'}

+ {group.ename && ( +

+ {group.ename} +

+ )}
{hasCharter ? ( hasSigned ? ( diff --git a/platforms/pictique-api/src/controllers/WebhookController.ts b/platforms/pictique-api/src/controllers/WebhookController.ts index 626a1802..4d1f8ca6 100644 --- a/platforms/pictique-api/src/controllers/WebhookController.ts +++ b/platforms/pictique-api/src/controllers/WebhookController.ts @@ -209,7 +209,6 @@ export class WebhookController { local.data.participants && Array.isArray(local.data.participants) ) { - console.log(local); const participantPromises = local.data.participants.map( async (ref: string) => { if (ref && typeof ref === "string") { @@ -230,6 +229,7 @@ export class WebhookController { chat.name = local.data.name as string; chat.participants = participants; + chat.ename = local.data.ename as string; this.adapter.addToLockedIds(localId); await this.chatService.chatRepository.save(chat); diff --git a/platforms/pictique-api/src/database/entities/Chat.ts b/platforms/pictique-api/src/database/entities/Chat.ts index 5ba1a4f1..61b1e849 100644 --- a/platforms/pictique-api/src/database/entities/Chat.ts +++ b/platforms/pictique-api/src/database/entities/Chat.ts @@ -30,6 +30,9 @@ export class Chat { }) participants!: User[]; + @Column({ nullable: true }) + ename!: string; + @CreateDateColumn() createdAt!: Date; diff --git a/platforms/pictique-api/src/database/migrations/1756066336069-migration.ts b/platforms/pictique-api/src/database/migrations/1756066336069-migration.ts new file mode 100644 index 00000000..d5759bd8 --- /dev/null +++ b/platforms/pictique-api/src/database/migrations/1756066336069-migration.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Migration1756066336069 implements MigrationInterface { + name = 'Migration1756066336069' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat" ADD "ename" character varying`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat" DROP COLUMN "ename"`); + } + +} diff --git a/platforms/pictique-api/src/migrations/1756065162697-migration.ts b/platforms/pictique-api/src/migrations/1756065162697-migration.ts new file mode 100644 index 00000000..fbfa644a --- /dev/null +++ b/platforms/pictique-api/src/migrations/1756065162697-migration.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Migration1756065162697 implements MigrationInterface { + name = 'Migration1756065162697' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat" ADD "ename" character varying`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat" DROP COLUMN "ename"`); + } + +} diff --git a/platforms/pictique-api/src/web3adapter/mappings/chat.mapping.json b/platforms/pictique-api/src/web3adapter/mappings/chat.mapping.json index 0b8bc7d6..4d4371ce 100644 --- a/platforms/pictique-api/src/web3adapter/mappings/chat.mapping.json +++ b/platforms/pictique-api/src/web3adapter/mappings/chat.mapping.json @@ -1,13 +1,14 @@ { "tableName": "chats", "schemaId": "550e8400-e29b-41d4-a716-446655440003", - "ownerEnamePath": "users(participants[].ename)", + "ownerEnamePath": "ename||users(participants[].ename)", "ownedJunctionTables": [], "localToUniversalMap": { "name": "name", "type": "type", "participants": "users(participants[].id),participantIds", "createdAt": "createdAt", - "updatedAt": "updatedAt" + "updatedAt": "updatedAt", + "ename": "ename" } } diff --git a/platforms/pictique-api/src/web3adapter/mappings/message.mapping.json b/platforms/pictique-api/src/web3adapter/mappings/message.mapping.json index e7f495db..ad3e0851 100644 --- a/platforms/pictique-api/src/web3adapter/mappings/message.mapping.json +++ b/platforms/pictique-api/src/web3adapter/mappings/message.mapping.json @@ -1,7 +1,7 @@ { "tableName": "messages", "schemaId": "550e8400-e29b-41d4-a716-446655440004", - "ownerEnamePath": "users(sender.ename)", + "ownerEnamePath": "chats(chat.ename)||users(sender.ename)", "localToUniversalMap": { "chat": "chats(chat.id),chatId", "text": "content",