UNPKG

anon-identity

Version:

Decentralized identity framework with DIDs, Verifiable Credentials, and privacy-preserving selective disclosure

238 lines 9.97 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BatchOperations = void 0; const verification_errors_1 = require("./verification-errors"); class BatchOperations { constructor(options = {}) { this.options = options; this.defaultOptions = { maxConcurrency: 10, timeout: 30000, // 30 seconds continueOnError: true }; this.options = { ...this.defaultOptions, ...options }; } /** * Verify multiple presentations in parallel with controlled concurrency */ async batchVerifyPresentations(presentations, verifyFunction) { const results = []; const chunks = this.chunkArray(presentations, this.options.maxConcurrency); for (const chunk of chunks) { const chunkPromises = chunk.map(async (presentation, index) => { const startTime = Date.now(); const presentationIndex = presentations.indexOf(presentation); try { // Apply timeout to individual verification const result = await this.withTimeout(verifyFunction(presentation), this.options.timeout); const processingTime = Date.now() - startTime; return { presentationIndex, presentationId: this.extractPresentationId(presentation), result, processingTime }; } catch (error) { const processingTime = Date.now() - startTime; const verificationError = error instanceof Error ? new verification_errors_1.VerificationError(verification_errors_1.VerificationErrorCode.NETWORK_ERROR, `Batch verification failed: ${error.message}`) : new verification_errors_1.VerificationError(verification_errors_1.VerificationErrorCode.NETWORK_ERROR, 'Unknown batch verification error'); return { presentationIndex, presentationId: this.extractPresentationId(presentation), result: { valid: false, errors: [verificationError], timestamp: new Date() }, processingTime }; } }); try { const chunkResults = await Promise.all(chunkPromises); results.push(...chunkResults); } catch (error) { if (!this.options.continueOnError) { throw error; } // Individual errors are already handled in the map function } } return results.sort((a, b) => a.presentationIndex - b.presentationIndex); } /** * Check multiple credential revocations in parallel */ async batchCheckRevocations(credentialIds, checkFunction) { const results = new Map(); const chunks = this.chunkArray(credentialIds, this.options.maxConcurrency); for (const chunk of chunks) { const chunkPromises = chunk.map(async (credentialId) => { const startTime = Date.now(); try { const isRevoked = await this.withTimeout(checkFunction(credentialId), this.options.timeout); const processingTime = Date.now() - startTime; return { credentialId, result: { credentialId, isRevoked, processingTime } }; } catch (error) { const processingTime = Date.now() - startTime; const verificationError = error instanceof Error ? new verification_errors_1.VerificationError(verification_errors_1.VerificationErrorCode.NETWORK_ERROR, `Revocation check failed: ${error.message}`) : new verification_errors_1.VerificationError(verification_errors_1.VerificationErrorCode.NETWORK_ERROR, 'Unknown revocation check error'); return { credentialId, result: { credentialId, isRevoked: false, // Default to not revoked on error error: verificationError, processingTime } }; } }); try { const chunkResults = await Promise.all(chunkPromises); chunkResults.forEach(({ credentialId, result }) => { results.set(credentialId, result); }); } catch (error) { if (!this.options.continueOnError) { throw error; } } } return results; } /** * Batch verify presentations with revocation checks */ async batchVerifyWithRevocationCheck(presentations, verifyFunction, checkRevocationFunction) { // First, verify all presentations const verificationResults = await this.batchVerifyPresentations(presentations, verifyFunction); // Extract all credential IDs from valid presentations const credentialIds = new Set(); verificationResults.forEach(result => { if (result.result.valid && result.result.credentials) { result.result.credentials.forEach(cred => credentialIds.add(cred.id)); } }); // Batch check revocations const revocationResults = await this.batchCheckRevocations(Array.from(credentialIds), checkRevocationFunction); // Update verification results with revocation status return verificationResults.map(result => { if (!result.result.valid || !result.result.credentials) { return result; } const revokedCredentials = result.result.credentials.filter(cred => { const revocationResult = revocationResults.get(cred.id); return revocationResult?.isRevoked || false; }); if (revokedCredentials.length > 0) { const revokedErrors = revokedCredentials.map(cred => verification_errors_1.VerificationError.revokedCredential(cred.id, cred.issuer)); return { ...result, result: { ...result.result, valid: false, errors: [...(result.result.errors || []), ...revokedErrors] } }; } return result; }); } /** * Get batch operation statistics */ generateBatchStatistics(results) { const total = results.length; const valid = results.filter(r => r.result.valid).length; const invalid = total - valid; const processingTimes = results.map(r => r.processingTime); const averageProcessingTime = processingTimes.reduce((a, b) => a + b, 0) / total; const maxProcessingTime = Math.max(...processingTimes); const minProcessingTime = Math.min(...processingTimes); const errorDistribution = {}; results.forEach(result => { if (result.result.errors) { result.result.errors.forEach(error => { const code = error.code || 'UNKNOWN'; errorDistribution[code] = (errorDistribution[code] || 0) + 1; }); } }); return { total, valid, invalid, averageProcessingTime, maxProcessingTime, minProcessingTime, errorDistribution }; } /** * Filter results by criteria */ filterResults(results, criteria) { return results.filter(result => { if (criteria.validOnly && !result.result.valid) { return false; } if (criteria.maxProcessingTime && result.processingTime > criteria.maxProcessingTime) { return false; } if (criteria.minProcessingTime && result.processingTime < criteria.minProcessingTime) { return false; } if (criteria.excludeErrorCodes && result.result.errors) { const hasExcludedError = result.result.errors.some(error => criteria.excludeErrorCodes.includes(error.code)); if (hasExcludedError) { return false; } } return true; }); } /** * Utility: Add timeout to a promise */ async withTimeout(promise, timeoutMs) { const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error(`Operation timed out after ${timeoutMs}ms`)), timeoutMs); }); return Promise.race([promise, timeoutPromise]); } /** * Utility: Split array into chunks */ chunkArray(array, chunkSize) { const chunks = []; for (let i = 0; i < array.length; i += chunkSize) { chunks.push(array.slice(i, i + chunkSize)); } return chunks; } /** * Extract presentation ID from presentation object */ extractPresentationId(presentation) { // Look for id in various possible locations return presentation.id || presentation.proof?.id || undefined; } } exports.BatchOperations = BatchOperations; //# sourceMappingURL=batch-operations.js.map